mighty

The mighty programming language, compiler and tools (WIP)
Log | Files | Refs

commit b28889d61364fba929d4c9124b6ca3600cfc7a30
parent 64c941a864332e2fa9813345b8885636ff124b5f
Author: citbl <citbl@citbl.org>
Date:   Tue, 26 May 2026 22:37:45 +1000

more parsing

Diffstat:
Mmtcl/ast.lua | 16++++++++++++++++
Mmtcl/parser.lua | 162++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Amtcl/utils.lua | 28++++++++++++++++++++++++++++
3 files changed, 188 insertions(+), 18 deletions(-)

diff --git a/mtcl/ast.lua b/mtcl/ast.lua @@ -14,6 +14,22 @@ function AST:use(lib) } end +function AST:postfix(op, operand) + return { + op = op, + operand = operand, + is_postfix = true, + } +end + +function AST:unary(op, operand) + return { + op = op, + operand = operand, + is_postfix = false, + } +end + function AST:binary(op, lhs, rhs) return { op = op, diff --git a/mtcl/parser.lua b/mtcl/parser.lua @@ -1,5 +1,6 @@ -local parser = { pos = 1, nodes = {} } +local parser = { pos = 1 } local ast = require("ast") +local utils = require("utils") function parser:peek() return self.tokens[self.pos] or 0 @@ -29,13 +30,114 @@ function parser:match_ident() end return current end +----------------------- -function parser:add(ast) - print("(+) adding node: " .. ast.kind) - self.nodes[#self.nodes + 1] = ast +function parser:parse_postfix() + local node = parse_primary() + + while true do + if parser:peek().kind == TK.PLUSPLUS then + return ast.postfix(OPER.POSTINCR, node) + elseif parser:peek().kind == TK.MINUSMINUS then + return ast.postfix(OPER.POSTDECR, node) + elseif parser:peek().kind == TK.L_BRACKET then -- parse inside brackets[] + local index = parser:parse_expression() + parser:expect(TK.R_BRACKET) + return ast.subscript(node, index) + elseif parser:peek().kind == TK.L_PAREN then + -- arguments + local args = parser:parse_arguments() + return ast.call(node, args) + elseif parser:peek().kind == TK.L_BRACE then -- parse name{} we don't hold grammar for this... + else + break + -- todo .member and potentially arrow operators here + end + end +end + +function parser:parse_unary() + local inner = 0 + + if parser:peek().kind == TK.MINUS then + parser:advance() + return ast.unary(OPER.MINUS, parser:parse_unary()) + elseif parser:peek().kind == TK.MINUSMINUS then + parser:advance() + return ast.unary(OPER.PREDECR, parser:parse_unary()) + elseif parser:peek().kind == TK.BANG then + parser:advance() + return ast.unary(OPER.BANG, parser:parse_unary()) + -- TODO add others '~a' '$a' '*a' '^a' '@a' '&a' ? + elseif parser:peek().kind == TK.PLUSPLUS then + parser:advance() + return ast.unary(OPER.PREINCR, parser:parse_unary()) + elseif parser:peek().kind == TK.PLUS then + parser:advance() + return parser:parse_unary() + else + return parser:parse_postfix() + end end -function parser:parse_relational() end +function parser:parse_term() + return parser:parse_unary() +end + +function parser:parse_multiplicative() + local node = parse_term() + + while true do + if parser:peek().kind == TK.STAR then + local rhs = parse_unary() + node = ast.binary(OP_MUL, node, rhs) + elseif parser:peek().kind == TK.SLASH then + local rhs = parse_unary() + node = ast.binary(OP_DIV, node, rhs) + elseif parser:peek().kind == TK.PERCENT then + local rhs = parse_unary() + node = ast.binary(OP_MOD, node, rhs) + else + break + end + end + return node +end + +function parser:parse_additive() + local node = parse_multiplicative() + + while true do + if parser:peek().kind == TK.PLUS then + local rhs = parse_multiplicative() + node = ast.binary(OP.PLUS, node, rhs) + elseif parser:peek().kind == TK.MINUS then + local rhs = parse_multiplicative() + node = ast.binary(OP.MINUS, node, rhs) + else + break + end + end + return node +end + +function parser:parse_relational() + local node = parse_additive() + + while true do + if parse:peek().kind == TK.LT then + local rhs = parser:parse_additive() + node = ast.binary(OP.LT, node, rhs) + elseif parse:peek().kind == TK.LTEQ then + local rhs = parser:parse_additive() + node = ast.binary(OP.LT_EQ, node, rhs) + -- todo more relationals + else + break + end + end + return node +end function parser:parse_equality() local node = parser:parse_relational() @@ -84,10 +186,8 @@ 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") + +function parser:parse_arguments() parser:expect(TK.L_PAREN) -- swallow ( local args = {} while parser:peek().kind ~= TK.R_PAREN do -- call parameters @@ -98,7 +198,18 @@ function parser:parse_call() else break end + parser:advance() end + print(parser:peek().kind) + parser:expect(TK.R_PAREN) + return args +end + +function parser:parse_call() + -- parse ident, parse parameters + local callee = parser:expect(TK.IDENT) + print("parse_call") + local args = parser:parse_arguments() return ast.call(callee, args) end @@ -107,6 +218,7 @@ function parser:parse_statement() local second = parser:nextpeek().kind if first == TK.IDENT then if second == TK.L_PAREN then + print("parsing a call statement") return parser:parse_call() elseif second == TK.IDENT then return parser:parse_var() @@ -127,6 +239,7 @@ function parser:parse_statement() print("parse_statement unhandled keyword yet: " .. kw.lexeme) end end + return { name = "idk" } end function parser:parse_function(is_exported) @@ -161,13 +274,20 @@ function parser:parse_function(is_exported) parser:expect(TK.COLONCOLON, "no rbrace start of function") while parser:peek().lexeme ~= "end" do - -- function body statements + ::continue:: + local tok = parser:peek() + if tok.kind == TK.EOS then + parser:advance() + goto continue + end + -- function body statements' + print("parsing a body statement " .. parser:peek().lexeme) local stmt = parser:parse_statement() statements[#statements + 1] = stmt parser:advance() end local node = ast.func(name, parameters, ret, statements) - parser:add(node) + return node end function parser:parse_use() @@ -177,13 +297,14 @@ function parser:parse_use() self:advance() self:expect(TK.EOS, "use statement found without a end statement \\n|;") local node = ast.use(lib) - parser:add(node) + return node end function unhandled(token, extramsg) print( - token.file - .. " at L" + "\27[33mat " + .. token.file + .. " L" .. token.line .. ":" .. token.col @@ -192,9 +313,11 @@ function unhandled(token, extramsg) .. "\t " .. (extramsg or "") ) + print(" |> " .. debug.traceback() .. "\27[0m") end function parser:parse_program() + local nodes = {} while self:peek() ~= 0 do local token = self:peek() local kind = token.kind @@ -203,17 +326,18 @@ function parser:parse_program() if kind == TK.EOS then -- nothing, advance elseif kind == TK.KEYWORD and word == "use" then - self:parse_use() + nodes[#nodes + 1] = self:parse_use() elseif kind == TK.KEYWORD and word == "fx" then - self:parse_function(true) + nodes[#nodes + 1] = self:parse_function(true) elseif kind == TK.KEYWORD and word == "fn" then - self:parse_function(false) + nodes[#nodes + 1] = self:parse_function(false) else unhandled(token) break end self:advance() end + return nodes end function parser:parse(file, src, tokens) @@ -223,7 +347,9 @@ function parser:parse(file, src, tokens) self.pos = 1 local i = 1 - self:parse_program() + local nodes = self:parse_program() + + utils.print_table(nodes) -- while i <= #tokens do -- local t = tokens[i] diff --git a/mtcl/utils.lua b/mtcl/utils.lua @@ -0,0 +1,28 @@ +local utils = {} + +-- adapted from https://gist.github.com/ripter/4270799 +function utils.print_table(tbl, indent) + if not tbl then + return + end + if not indent then + indent = 0 + end + for k, v in pairs(tbl) do + if k == "line" or k == "col" or k == "file" then + goto pass + end + formatting = string.rep(" ", indent) .. k .. ": " + if type(v) == "table" then + print(formatting) + utils.print_table(v, indent + 1) + elseif type(v) == "boolean" then + print(formatting .. tostring(v)) + else + print(formatting .. v) + end + ::pass:: + end +end + +return utils