scope.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. from __future__ import annotations
  2. import src.zelkelc.ast.types as types
  3. from dataclasses import dataclass
  4. from typing import Optional
  5. @dataclass
  6. class SemanticError:
  7. message: str
  8. @dataclass
  9. class StructSignature:
  10. name: str
  11. irname: str
  12. members: dict[str, MemberSignature]
  13. @dataclass
  14. class ClassSignature:
  15. name: str
  16. irname: str
  17. members: dict[str, MemberSignature]
  18. methods: dict[str, list[FunctionSignature]]
  19. @dataclass
  20. class FunctionSignature:
  21. name: str
  22. irname: str
  23. static: bool
  24. typ: types.Value
  25. args: dict[str, types.Value]
  26. @dataclass
  27. class ValueSignature:
  28. name: str
  29. irname: str
  30. mutable: bool
  31. typ: type[types.Integer64] | type[types.String] | type[types.Void]
  32. @dataclass
  33. class MemberSignature:
  34. name: str
  35. irname: str
  36. mutable: bool
  37. typ: type[types.Integer64] | type[types.String] | type[types.Void]
  38. member_idx: int
  39. @dataclass
  40. class Scope:
  41. parent: Optional[Scope]
  42. classes: dict[str, ClassSignature]
  43. structs: dict[str, StructSignature]
  44. functions: dict[str, list[FunctionSignature]]
  45. values: dict[str, ValueSignature]
  46. @staticmethod
  47. def root() -> Scope:
  48. return Scope(
  49. parent=None,
  50. classes={},
  51. structs={},
  52. functions={},
  53. values={},
  54. )
  55. def child(self) -> Scope:
  56. return Scope(
  57. parent=self,
  58. classes=self.classes,
  59. structs=self.structs,
  60. functions=self.functions,
  61. values={},
  62. )
  63. def resolve_variable(self, name: str) -> Optional[ValueSignature]:
  64. current: Optional[Scope] = self
  65. while current is not None:
  66. if name in current.values:
  67. return current.values[name]
  68. current = current.parent
  69. return None
  70. def resolve_function(
  71. self, scope_checker: ScopeChecker, name: str, args: list[types.Expression]
  72. ) -> Optional[FunctionSignature]:
  73. current: Optional[Scope] = self
  74. while current is not None:
  75. overloads = current.functions.get(name)
  76. if overloads:
  77. arg_types = current.expr_args_to_arg_types(scope_checker, args)
  78. if arg_types is None:
  79. return None
  80. return current.resolve_function_by_types(name, arg_types)
  81. current = current.parent
  82. return None
  83. def resolve_function_by_types(
  84. self, name: str, arg_types: list[types.Value]
  85. ) -> Optional[FunctionSignature]:
  86. current: Optional[Scope] = self
  87. while current is not None:
  88. overloads = current.functions.get(name)
  89. if overloads:
  90. for candidate in overloads:
  91. if list(candidate.args.values()) == arg_types:
  92. return candidate
  93. current = current.parent
  94. return None
  95. def expr_args_to_arg_types(
  96. self, scope_checker: ScopeChecker, args: list[types.Expression]
  97. ) -> Optional[list[types.Value]]:
  98. arg_types: list[types.Value] = []
  99. for arg in args:
  100. typ = scope_checker._infer_expression_type(arg, self)
  101. if typ is None:
  102. return None
  103. arg_types.append(typ)
  104. return arg_types
  105. def _ensure_function_overloads(self, name: str) -> list[FunctionSignature]:
  106. if name not in self.functions:
  107. self.functions[name] = []
  108. return self.functions[name]
  109. class ScopeChecker:
  110. global_scope: Scope
  111. errors: list[SemanticError]
  112. def __init__(self):
  113. self.global_scope = Scope.root()
  114. self.errors = []
  115. def check(self, tree: list[types.Node]) -> tuple[Scope, list[SemanticError]]:
  116. self._collect_globals(tree)
  117. for top_level in tree:
  118. match top_level:
  119. case types.FunctionDeclaration():
  120. self._check_function(top_level, self.global_scope)
  121. case types.ClassDeclaration():
  122. for method in top_level.methods:
  123. self._check_function(method, self.global_scope)
  124. case types.StructDeclaration():
  125. continue
  126. case types.InlineIR():
  127. for arg in top_level.args:
  128. self._infer_expression_type(arg, self.global_scope)
  129. case types.MacroCall():
  130. self._error(f"unexpanded macro call #{top_level.name}")
  131. case _:
  132. self._error(f"Unsupported top-level node: {type(top_level)}")
  133. return self.global_scope, self.errors
  134. def _collect_globals(self, tree: list[types.Node]) -> None:
  135. for top_level in tree:
  136. match top_level:
  137. case types.StructDeclaration(name=name, irname=irname, members=members):
  138. if name in self.global_scope.structs:
  139. self._error(f"Struct '{name}' is already declared")
  140. continue
  141. member_table: dict[str, MemberSignature] = {}
  142. for member in members:
  143. if member.name in member_table:
  144. self._error(
  145. f"Duplicate member '{member.name}' in struct '{name}'"
  146. )
  147. continue
  148. member_table[member.name] = MemberSignature(
  149. name=member.name,
  150. irname=f"{irname}.m_{member.name}",
  151. mutable=member.mutable,
  152. typ=member.typ,
  153. member_idx=member.real_idx,
  154. )
  155. self.global_scope.structs[name] = StructSignature(
  156. name=name,
  157. irname=irname,
  158. members=member_table,
  159. )
  160. case types.ClassDeclaration(
  161. name=name, irname=irname, members=members, methods=methods
  162. ):
  163. if name in self.global_scope.classes:
  164. self._error(f"Class '{name}' is already declared")
  165. continue
  166. member_table: dict[str, MemberSignature] = {}
  167. for idx, member in enumerate(members):
  168. if member.name in member_table:
  169. self._error(
  170. f"Duplicate member '{member.name}' in class '{name}'"
  171. )
  172. continue
  173. member_table[member.name] = MemberSignature(
  174. name=member.name,
  175. irname=f"{irname}.m_{member.name}",
  176. mutable=member.mutable,
  177. typ=member.typ,
  178. member_idx=idx,
  179. )
  180. method_table: dict[str, list[FunctionSignature]] = {}
  181. for method in methods:
  182. signature = FunctionSignature(
  183. name=method.name,
  184. irname=method.irname,
  185. static=False,
  186. typ=method.typ,
  187. args=method.args,
  188. )
  189. overloads = method_table.setdefault(method.name, [])
  190. has_duplicate_signature = any(
  191. list(existing.args.values())
  192. == list(signature.args.values())
  193. for existing in overloads
  194. )
  195. if has_duplicate_signature:
  196. self._error(
  197. f"Duplicate method '{method.name}' in class '{name}' "
  198. f"with same argument signature"
  199. )
  200. continue
  201. overloads.append(signature)
  202. self.global_scope.classes[name] = ClassSignature(
  203. name=name,
  204. irname=irname,
  205. members=member_table,
  206. methods=method_table,
  207. )
  208. case types.FunctionDeclaration(name, typ, args, _, irname):
  209. existing = self.global_scope.resolve_function_by_types(
  210. name, list(args.values())
  211. )
  212. if existing is not None:
  213. self._error(
  214. f"Function '{name}' is already defined with following signature '{existing}'"
  215. )
  216. continue
  217. self.global_scope._ensure_function_overloads(name).append(
  218. FunctionSignature(
  219. name=name,
  220. irname=irname,
  221. static=True,
  222. typ=typ,
  223. args=args,
  224. )
  225. )
  226. case types.MacroCall() | types.InlineIR():
  227. continue
  228. case _:
  229. self._error(
  230. f"Unsupported top-level node while collecting symbols: {type(top_level)}"
  231. )
  232. def _check_function(
  233. self, fn: types.FunctionDeclaration, enclosing_scope: Scope
  234. ) -> None:
  235. function_scope = enclosing_scope.child()
  236. for arg_name, arg_type in fn.args.items():
  237. if arg_name in function_scope.values:
  238. self._error(f"Duplicate argument '{arg_name}' in function '{fn.name}'")
  239. continue
  240. function_scope.values[arg_name] = ValueSignature(
  241. name=arg_name,
  242. irname=arg_name,
  243. mutable=False,
  244. typ=arg_type,
  245. )
  246. has_return = False
  247. for child in fn.body:
  248. match child:
  249. case types.ValueDeclaration():
  250. if child.name in function_scope.values:
  251. self._error(
  252. f"Variable '{child.name}' is already defined in function '{fn.name}'"
  253. )
  254. continue
  255. expression_type = self._infer_expression_type(
  256. child.expr, function_scope
  257. )
  258. if expression_type is not None and not self._same_type(
  259. expression_type, child.typ
  260. ):
  261. self._error(
  262. f"Type mismatch for '{child.name}' in function '{fn.name}': "
  263. f"expected {self._type_name(child.typ)}, got {self._type_name(expression_type)}"
  264. )
  265. function_scope.values[child.name] = ValueSignature(
  266. name=child.name,
  267. irname=child.irname,
  268. mutable=child.mutable,
  269. typ=child.typ,
  270. )
  271. case types.ReturnStatement():
  272. has_return = True
  273. if child.expr is None:
  274. if fn.typ is not types.Void:
  275. self._error(
  276. f"Function '{fn.name}' must return {self._type_name(fn.typ)}"
  277. )
  278. continue
  279. return_type = self._infer_expression_type(
  280. child.expr, function_scope
  281. )
  282. if return_type is None:
  283. continue
  284. if fn.typ is types.Void:
  285. self._error(
  286. f"Function '{fn.name}' returns a value, but return type is void"
  287. )
  288. continue
  289. if not self._same_type(return_type, fn.typ):
  290. self._error(
  291. f"Return type mismatch in function '{fn.name}': "
  292. f"expected {self._type_name(fn.typ)}, got {self._type_name(return_type)}"
  293. )
  294. case types.FunctionDeclaration():
  295. existing_nested = function_scope.resolve_function_by_types(
  296. child.name, list(child.args.values())
  297. )
  298. if existing_nested is not None:
  299. self._error(
  300. f"Nested function '{child.name}' is already defined in '{fn.name}'"
  301. )
  302. else:
  303. function_scope._ensure_function_overloads(child.name).append(
  304. FunctionSignature(
  305. name=child.name,
  306. irname=child.irname,
  307. static=True,
  308. typ=child.typ,
  309. args=child.args,
  310. )
  311. )
  312. self._check_function(child, function_scope)
  313. case types.InlineIR():
  314. for arg in child.args:
  315. self._infer_expression_type(arg, function_scope)
  316. case _:
  317. self._error(
  318. f"Unsupported node in function '{fn.name}': {type(child)}"
  319. )
  320. if not has_return and fn.typ is not types.Void:
  321. self._error(f"Function '{fn.name}' has no return statement")
  322. def _infer_expression_type(
  323. self, expr: types.Expression, active_scope: Scope
  324. ) -> Optional[type[types.Integer64] | type[types.String] | type[types.Void]]:
  325. match expr:
  326. case types.PrimaryExpression(types.Integer64()):
  327. return types.Integer64
  328. case types.PrimaryExpression(types.Float64()):
  329. return types.Float64
  330. case types.PrimaryExpression(types.String()):
  331. return types.String
  332. case types.PrimaryExpression(types.VariableRef(name)):
  333. signature = active_scope.resolve_variable(name)
  334. if signature is None:
  335. self._error(f"Unknown variable '{name}'")
  336. return None
  337. expr.value.irname = signature.irname
  338. expr.value.typ = signature.typ
  339. return signature.typ
  340. case types.PrimaryExpression(types.FunctionCall(name, args)):
  341. arg_types = active_scope.expr_args_to_arg_types(self, args)
  342. if arg_types is None:
  343. self._error("Could not get argument types from function call")
  344. return None
  345. signature = active_scope.resolve_function_by_types(name, arg_types)
  346. if signature is None:
  347. self._error(
  348. f"Unknown function '{name}' with given argument signature"
  349. )
  350. return None
  351. expr.value.irname = signature.irname
  352. return signature.typ
  353. case types.UnaryExpression(inner_expr, sign):
  354. inner_type = self._infer_expression_type(inner_expr, active_scope)
  355. if inner_type is None:
  356. return None
  357. if sign in ("+", "-") and inner_type is not types.Integer64:
  358. self._error(
  359. f"Unary operator '{sign}' expects i64, got {self._type_name(inner_type)}"
  360. )
  361. return None
  362. return inner_type
  363. case types.BinaryExpression(left=left, right=right, op=op):
  364. left_type = self._infer_expression_type(left, active_scope)
  365. right_type = self._infer_expression_type(right, active_scope)
  366. if left_type is None or right_type is None:
  367. return None
  368. if not self._same_type(left_type, right_type):
  369. self._error(
  370. f"Binary operator '{op}' type mismatch: "
  371. f"{self._type_name(left_type)} vs {self._type_name(right_type)}"
  372. )
  373. return None
  374. match left_type:
  375. case types.Integer64:
  376. if op not in ["+", "-", "*"]:
  377. self._error(
  378. f"Operator '{op}' does not support {self._type_name(left_type)}"
  379. )
  380. return types.Integer64
  381. case types.Float64:
  382. if op not in ["+", "-", "*", "/"]:
  383. self._error(
  384. f"Operator '{op}' does not support {self._type_name(left_type)}"
  385. )
  386. return types.Float64
  387. case _:
  388. return None
  389. case _:
  390. self._error(f"Unsupported expression type: {type(expr)}")
  391. return None
  392. def _same_type(self, left: object, right: object) -> bool:
  393. return self._type_token(left) == self._type_token(right)
  394. def _type_token(self, typ: object) -> str:
  395. if typ is types.Integer64 or isinstance(typ, types.Integer64):
  396. return "i64"
  397. if typ is types.Float64 or isinstance(typ, types.Float64):
  398. return "f64"
  399. if typ is types.String or isinstance(typ, types.String):
  400. return "str"
  401. if typ is types.Void or isinstance(typ, types.Void):
  402. return "void"
  403. return str(typ)
  404. def _type_name(self, typ: object) -> str:
  405. return self._type_token(typ)
  406. def _error(self, message: str) -> None:
  407. self.errors.append(SemanticError(message))