1
0

parser.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. from itertools import count
  2. from src.zelkelc.ast import types
  3. from src.zelkelc.lexer import token
  4. class ParseError(Exception):
  5. pass
  6. class Parser:
  7. tokens: list[token.Token]
  8. cursor: int
  9. ids: count
  10. def __init__(self, tokens: list[token.Token], cursor: int, ids: count):
  11. self.tokens = tokens
  12. self.cursor = cursor
  13. self.ids = ids
  14. def expect(self, tok: token.Token):
  15. if self.tokens[self.cursor] != tok:
  16. raise ParseError(f"Expected {tok}, but found {self.tokens[self.cursor]}")
  17. self.cursor += 1
  18. def expect_type(self, tok_type: token.Token) -> token.Token:
  19. if type(self.tokens[self.cursor]) is not tok_type:
  20. raise ParseError(
  21. f"Expected {tok_type}, but found {type(self.tokens[self.cursor])}"
  22. )
  23. self.cursor += 1
  24. return self.tokens[self.cursor - 1]
  25. def current(self, tok) -> bool:
  26. return self.cursor < len(self.tokens) and self.tokens[self.cursor] == tok
  27. def current_type(self, tok_type) -> bool:
  28. return (
  29. self.cursor < len(self.tokens)
  30. and type(self.tokens[self.cursor]) is tok_type
  31. )
  32. @staticmethod
  33. def type_to_str(typ: types.Value, is_return_type: bool) -> types.Value:
  34. match typ:
  35. case types.String:
  36. return "str"
  37. case types.Integer64:
  38. return "i64"
  39. case types.Float64:
  40. return "f64"
  41. case types.Void if is_return_type:
  42. return "void"
  43. case _:
  44. raise ParseError(f"Invalid type found in type_to_str: {typ}")
  45. def parse_type(self, is_return_type: bool) -> types.Value:
  46. identifier = self.expect_type(token.Identifier)
  47. match identifier.value:
  48. case "str":
  49. return types.String
  50. case "i64":
  51. return types.Integer64
  52. case "f64":
  53. return types.Float64
  54. case "void" if is_return_type:
  55. return types.Void
  56. case _:
  57. raise ParseError(
  58. f"Invalid type found in parse_type: {identifier.value}"
  59. )
  60. def parse_item(self, path: str = "_main.zk_") -> types.Node:
  61. t = self.tokens[self.cursor]
  62. match t:
  63. case token.Identifier():
  64. match t.value:
  65. case "fn":
  66. return self.parse_function_declaration(path)
  67. case "struct":
  68. return self.parse_struct_declaration(path)
  69. case "class":
  70. return self.parse_class_declaration(path)
  71. case _:
  72. raise ParseError(f"Invalid keyword in global {t.value}")
  73. case token.Pound():
  74. return self.parse_pound()
  75. case _:
  76. raise ParseError(f"Invalid token found while parsing global {t}")
  77. def parse_items(self) -> list[types.Node]:
  78. items = []
  79. while self.cursor < len(self.tokens):
  80. items.append(self.parse_item())
  81. return items
  82. def parse(self):
  83. return self.parse_items()
  84. def take_delimited(self) -> list[token.Token]:
  85. if self.current(token.LParen()):
  86. open_t, _close_t = token.LParen(), token.RParen()
  87. elif self.current(token.LBrace()):
  88. open_t, _close_t = token.LBrace(), token.RBrace()
  89. else:
  90. raise ParseError("Expected '(' or '{' to start delimited token tree")
  91. self.expect(open_t)
  92. depth, start = 1, self.cursor
  93. while depth:
  94. if self.cursor >= len(self.tokens):
  95. raise ParseError("unclosed delimited group")
  96. t = self.tokens[self.cursor]
  97. if isinstance(t, (token.LParen, token.LBrace)):
  98. depth += 1
  99. elif isinstance(t, (token.RParen, token.RBrace)):
  100. depth -= 1
  101. self.cursor += 1
  102. return self.tokens[start : self.cursor - 1]
  103. def parse_pound(self) -> types.Node:
  104. self.expect(token.Pound())
  105. ident = self.expect_type(token.Identifier)
  106. if ident.value == "fn":
  107. return self.parse_macro_definition()
  108. return self.parse_macro_call(ident)
  109. def parse_macro_definition(self) -> types.MacroDefinition:
  110. name = self.expect_type(token.Identifier).value
  111. self.expect(token.LParen())
  112. params: list[tuple[str, str]] = []
  113. while not self.current(token.RParen()):
  114. if params:
  115. self.expect(token.Comma())
  116. self.expect(token.Dollar())
  117. pname = self.expect_type(token.Identifier).value
  118. self.expect(token.Colon())
  119. kind = self.expect_type(token.Identifier).value
  120. if kind not in ("expr", "ident", "type", "tt"):
  121. raise ParseError(f"Unknown macro fragment kind: {kind}")
  122. params.append((pname, kind))
  123. self.expect(token.RParen())
  124. # Body is a { ... } token tree, stored unparsed
  125. body = self.take_delimited()
  126. return types.MacroDefinition(name=name, params=params, body=body)
  127. def parse_macro_call(self, ident: token.Identifier) -> types.MacroCall:
  128. args = self.take_delimited()
  129. return types.MacroCall(name=ident.value, args=args)
  130. def parse_struct_declaration(self, path: str) -> types.StructDeclaration:
  131. self.expect(token.Identifier("struct"))
  132. name = self.expect_type(token.Identifier).value
  133. self.expect(token.LBrace())
  134. members: list[types.MemberDeclaration] = []
  135. while (
  136. self.cursor < len(self.tokens)
  137. and self.tokens[self.cursor] != token.RBrace()
  138. ):
  139. t = self.tokens[self.cursor]
  140. match t:
  141. case token.Identifier():
  142. match t.value:
  143. case "val":
  144. members.append(
  145. self.parse_member_declaration(False, len(members))
  146. )
  147. case "var":
  148. members.append(
  149. self.parse_member_declaration(True, len(members))
  150. )
  151. case _:
  152. raise ParseError(
  153. f"Invalid keyword in struct body {t.value}"
  154. )
  155. case _:
  156. raise ParseError(
  157. f"Invalid token found while parsing class declaration: {t}"
  158. )
  159. self.expect(token.RBrace())
  160. return types.StructDeclaration(name, members, irname=f"{path}.s_{name}")
  161. def parse_member_declaration(
  162. self, mutable: bool, member_idx: int
  163. ) -> types.MemberDeclaration:
  164. if mutable:
  165. self.expect(token.Identifier("var"))
  166. else:
  167. self.expect(token.Identifier("val"))
  168. name = self.expect_type(token.Identifier).value
  169. self.expect(token.Colon())
  170. typ = self.parse_type(False)
  171. return types.MemberDeclaration(name, mutable, typ, real_idx=member_idx)
  172. def parse_class_declaration(self, path: str) -> types.ClassDeclaration:
  173. self.expect(token.Identifier("class"))
  174. name = self.expect_type(token.Identifier).value
  175. self.expect(token.LBrace())
  176. members: list[types.ValueDeclaration] = []
  177. methods: list[types.FunctionDeclaration] = []
  178. while (
  179. self.cursor < len(self.tokens)
  180. and self.tokens[self.cursor] != token.RBrace()
  181. ):
  182. t = self.tokens[self.cursor]
  183. match t:
  184. case token.Identifier():
  185. match t.value:
  186. case "fn":
  187. methods.append(
  188. self.parse_function_declaration(f"{path}.c_{name}")
  189. )
  190. case "val":
  191. members.append(
  192. self.parse_member_declaration(False, len(members))
  193. )
  194. case "var":
  195. members.append(
  196. self.parse_member_declaration(True, len(members))
  197. )
  198. case _:
  199. raise ParseError(f"Invalid keyword in class body {t.value}")
  200. case _:
  201. raise ParseError(
  202. f"Invalid token found while parsing class declaration: {t}"
  203. )
  204. self.expect(token.RBrace())
  205. return types.ClassDeclaration(name, members, methods, irname=f"{path}.c_{name}")
  206. def parse_statement(self, path: str) -> types.Node:
  207. t = self.tokens[self.cursor]
  208. match t:
  209. case token.Identifier():
  210. match t.value:
  211. case "fn":
  212. return self.parse_function_declaration(path)
  213. case "val":
  214. return self.parse_value_declaration(False)
  215. case "var":
  216. return self.parse_value_declaration(True)
  217. case "return":
  218. return self.parse_return()
  219. case _:
  220. raise ParseError(f"Invalid keyword in function body {t.value}")
  221. case token.Pound():
  222. return self.parse_pound()
  223. case _:
  224. # TODO: expression statement
  225. raise ParseError(f"implement expression statement: {t}")
  226. def parse_statements(self, path: str, stop_at_rbrace: bool) -> list[types.Node]:
  227. body = []
  228. while self.cursor < len(self.tokens):
  229. if stop_at_rbrace and self.current(token.RBrace()):
  230. break
  231. body.append(self.parse_statement(path))
  232. return body
  233. def parse_function_declaration(self, path: str) -> types.FunctionDeclaration:
  234. self.expect(token.Identifier("fn"))
  235. name = self.expect_type(token.Identifier).value
  236. self.expect(token.LParen())
  237. args: dict[str, types.Value] = {}
  238. while self.cursor < len(self.tokens) and not self.current(token.RParen()):
  239. arg_name = self.expect_type(token.Identifier).value
  240. self.expect(token.Colon())
  241. typ = self.parse_type(False)
  242. args[arg_name] = typ
  243. if not self.current(token.Comma()):
  244. break
  245. else:
  246. self.expect(token.Comma())
  247. self.expect(token.RParen())
  248. self.expect(token.Arrow())
  249. typ = self.parse_type(True)
  250. self.expect(token.LBrace())
  251. body = self.parse_statements(f"{path}.f_{name}", stop_at_rbrace=True)
  252. self.expect(token.RBrace())
  253. irname = f"{path}.f_{name}_{self.type_to_str(typ, True)}"
  254. if name == "main":
  255. irname = "zkmain"
  256. return types.FunctionDeclaration(
  257. name=name, typ=typ, args=args, body=body, irname=irname
  258. )
  259. def parse_return(self) -> types.ReturnStatement:
  260. self.expect(token.Identifier("return"))
  261. expr: types.Expression | None = None
  262. if not self.current(token.RBrace()):
  263. expr = self.parse_expression()
  264. return types.ReturnStatement(expr)
  265. def parse_value_declaration(self, mutable: bool) -> types.ValueDeclaration:
  266. if mutable:
  267. self.expect(token.Identifier("var"))
  268. else:
  269. self.expect(token.Identifier("val"))
  270. name = self.expect_type(token.Identifier).value
  271. self.expect(token.Colon())
  272. typ = self.parse_type(False)
  273. self.expect(token.Equals())
  274. expr = self.parse_expression()
  275. return types.ValueDeclaration(
  276. name, mutable, typ, expr, irname=f"v_{next(self.ids)}_{name}"
  277. )
  278. def parse_expression(self) -> types.Expression:
  279. return self.parse_binary_expression(0)
  280. def parse_binary_expression(self, min_precedence: int = 0) -> types.Expression:
  281. left = self.parse_unary_expression()
  282. while self.current_type(token.Operator):
  283. op_token = self.tokens[self.cursor]
  284. op = op_token.value
  285. precedence = self._operator_precedence(op)
  286. if precedence < min_precedence:
  287. break
  288. self.cursor += 1
  289. right = self.parse_binary_expression(precedence + 1)
  290. left = types.BinaryExpression(left, right, op, left.typ)
  291. return left
  292. def parse_unary_expression(self) -> types.Expression:
  293. if self.current_type(token.Operator):
  294. op = self.expect_type(token.Operator).value
  295. if op not in ("-", "+"):
  296. raise ParseError(f"Invalid unary operator: {op}")
  297. operand = self.parse_unary_expression()
  298. return types.UnaryExpression(operand, op, operand.typ)
  299. return self.parse_primary_expression()
  300. def parse_primary_expression(self) -> types.Expression | None:
  301. t = self.tokens[self.cursor]
  302. match t:
  303. case token.Identifier():
  304. self.cursor += 1
  305. if self.current(token.LParen()):
  306. self.cursor += 1
  307. args: list[types.Expression] = []
  308. while (
  309. self.cursor < len(self.tokens)
  310. and self.tokens[self.cursor] != token.RParen()
  311. ):
  312. if len(args) != 0:
  313. self.expect(token.Comma())
  314. args.append(self.parse_expression())
  315. self.expect(token.RParen())
  316. return types.PrimaryExpression(
  317. types.FunctionCall(t.value, args, None), types.FunctionCall
  318. )
  319. else:
  320. return types.PrimaryExpression(
  321. types.VariableRef(t.value, None, None), types.VariableRef
  322. )
  323. case token.Integer():
  324. self.cursor += 1
  325. return types.PrimaryExpression(
  326. types.Integer64(t.value), types.Integer64
  327. )
  328. case token.Float():
  329. self.cursor += 1
  330. return types.PrimaryExpression(types.Float64(t.value), types.Float64)
  331. case token.String():
  332. self.cursor += 1
  333. return types.PrimaryExpression(types.String(t.value), types.String)
  334. case token.LParen():
  335. self.expect(token.LParen())
  336. expr = self.parse_expression()
  337. self.expect(token.RParen())
  338. return expr
  339. case token.Interpolated():
  340. self.cursor += 1
  341. return t.node
  342. case _:
  343. return None
  344. def _operator_precedence(self, op: str) -> int:
  345. table = {
  346. "||": 1,
  347. "&&": 2,
  348. "==": 3,
  349. "!=": 3,
  350. "<": 4,
  351. "<=": 4,
  352. ">": 4,
  353. ">=": 4,
  354. "+": 5,
  355. "-": 5,
  356. "*": 6,
  357. "/": 6,
  358. "%": 6,
  359. }
  360. return table.get(op, 0)