commit 64c941a864332e2fa9813345b8885636ff124b5f
parent f27e8eb9a680a1d1d70e3ef0e95fa91662d374fa
Author: citbl <citbl@citbl.org>
Date: Tue, 26 May 2026 20:48:40 +1000
parser wip
Diffstat:
2 files changed, 96 insertions(+), 16 deletions(-)
diff --git a/mtcl/ast.lua b/mtcl/ast.lua
@@ -14,6 +14,20 @@ function AST:use(lib)
}
end
+function AST:binary(op, lhs, rhs)
+ return {
+ op = op,
+ lhs = lhs,
+ rhs = rhs,
+ }
+end
+
+-- note the name/callee etc. usually carries the token so we have file/line/col
+-- access via lexeme
+function AST:call(callee, args)
+ return { callee = callee, args = args }
+end
+
function AST:func(name, params, ret, body)
return {
kind = "func",
diff --git a/mtcl/parser.lua b/mtcl/parser.lua
@@ -1,6 +1,5 @@
local parser = { pos = 1, nodes = {} }
local ast = require("ast")
-local node = {}
function parser:peek()
return self.tokens[self.pos] or 0
@@ -36,32 +35,98 @@ function parser:add(ast)
self.nodes[#self.nodes + 1] = ast
end
-function parser:parse_var() print("todo parse_var") end
-function parser:parse_while() print("todo parse_while") end
-function parser:parse_for() print("todo parse_for") end
-function parser:parse_return() print("todo parse_return") end
-function parser:parse_as_cast() print("todo parse_as_cast") end
-function parser:parse_call() print("todo parse_call") end
+function parser:parse_relational() end
+
+function parser:parse_equality()
+ local node = parser:parse_relational()
+
+ while true do
+ if parser:peek().kind == TK.EQEQ then
+ local rhs = parser:parse_relational()
+ node = ast.binary(OP.EQUALITY, node, rhs)
+ -- elseif next == TK.BANGEQ then
+ -- todo inequality
+ else
+ break
+ end
+ end
+ return node
+end
+
+function parser:parse_assignment_expr()
+ local left = parser:parse_equality()
+
+ if parser:peek().kind == TK.EQ then
+ local right = parser:parse_assignment_expr()
+ -- todo check fail assignment target
+ -- todo make binary node
+ end
+
+ return left
+end
+
+function parser:parse_expr()
+ return parser:parse_assignment_expr()
+end
+
+function parser:parse_var()
+ print("todo parse_var")
+end
+function parser:parse_while()
+ print("todo parse_while")
+end
+function parser:parse_for()
+ print("todo parse_for")
+end
+function parser:parse_return()
+ print("todo parse_return")
+end
+function parser:parse_as_cast()
+ print("todo parse_as_cast")
+end
+function parser:parse_call()
+ -- parse ident, parse parameters
+ local callee = parser:expect(TK.IDENT)
+ print("parse_call")
+ parser:expect(TK.L_PAREN) -- swallow (
+ local args = {}
+ while parser:peek().kind ~= TK.R_PAREN do -- call parameters
+ local expr = parser:parse_expr()
+ args[#args + 1] = expr
+ if parser:peek().kind == TK.COMMA then
+ parser:advance()
+ else
+ break
+ end
+ end
+ return ast.call(callee, args)
+end
function parser:parse_statement()
local first = parser:peek().kind
local second = parser:nextpeek().kind
- print("todo parse statement: " .. first)
if first == TK.IDENT then
if second == TK.L_PAREN then
- parser:parse_call()
+ return parser:parse_call()
elseif second == TK.IDENT then
- parser:parse_var()
+ return parser:parse_var()
+ else
+ print("parse_statement unhandled ident start with: " .. second)
end
elseif first == TK.KEYWORD then
local kw = parser:peek()
- if kw.lexeme == "while" then parse:parse_while()
- elseif kw.lexeme == "for" then parse:parse_for()
- elseif kw.lexeme == "return" then parse:parse_return()
- elseif kw.lexeme == "as" then parse:parse_as_cast()
+ if kw.lexeme == "while" then
+ return parser:parse_while()
+ elseif kw.lexeme == "for" then
+ return parser:parse_for()
+ elseif kw.lexeme == "return" then
+ return parser:parse_return()
+ elseif kw.lexeme == "as" then
+ return parser:parse_as_cast()
+ else
+ print("parse_statement unhandled keyword yet: " .. kw.lexeme)
end
end
- parser:advance()
end
function parser:parse_function(is_exported)
@@ -99,8 +164,9 @@ function parser:parse_function(is_exported)
-- function body statements
local stmt = parser:parse_statement()
statements[#statements + 1] = stmt
+ parser:advance()
end
- local node = ast.func(name, params, ret, statements)
+ local node = ast.func(name, parameters, ret, statements)
parser:add(node)
end