89 lines
3.0 KiB
Plaintext
89 lines
3.0 KiB
Plaintext
// Minimal recursive-descent parser for Ny v0 producing JSON IR v0 (MapBox)
|
|
|
|
using "./apps/selfhost/ny-parser-nyash/tokenizer.nyash" as Tokenizer
|
|
include "./apps/selfhost/ny-parser-nyash/tokenizer.nyash"
|
|
|
|
static box ParserV0 {
|
|
init { tokens, pos }
|
|
|
|
parse_program(input) {
|
|
me.tokens = Tokenizer.tokenize(input)
|
|
// Error passthrough
|
|
if me.tokens.as_any().toString().indexOf("\"kind\":\"Error\"") >= 0 {
|
|
return me.tokens
|
|
}
|
|
me.pos = 0
|
|
local stmt = me.parse_stmt()
|
|
if stmt.as_any().toString().indexOf("\"kind\":\"Error\"") >= 0 { return stmt }
|
|
local body = new ArrayBox(); body.push(stmt)
|
|
local prog = new MapBox(); prog.set("version", 0); prog.set("kind", "Program"); prog.set("body", body)
|
|
return prog
|
|
}
|
|
|
|
parse_stmt() {
|
|
local tok = me.peek()
|
|
if tok.get("type") == "RETURN" {
|
|
me.next()
|
|
local expr = me.parse_expr()
|
|
if expr.as_any().toString().indexOf("\"kind\":\"Error\"") >= 0 { return expr }
|
|
local ret = new MapBox(); ret.set("type", "Return"); ret.set("expr", expr)
|
|
return ret
|
|
}
|
|
return me.err("Expected 'return'")
|
|
}
|
|
|
|
parse_expr() {
|
|
local left = me.parse_term()
|
|
loop(true) {
|
|
local t = me.peek(); local ty = t.get("type")
|
|
if ty == "+" || ty == "-" {
|
|
me.next(); local right = me.parse_term()
|
|
left = me.bin(ty, left, right)
|
|
} else { break }
|
|
}
|
|
return left
|
|
}
|
|
|
|
parse_term() {
|
|
local left = me.parse_factor()
|
|
loop(true) {
|
|
local t = me.peek(); local ty = t.get("type")
|
|
if ty == "*" || ty == "/" {
|
|
me.next(); local right = me.parse_factor()
|
|
left = me.bin(ty, left, right)
|
|
} else { break }
|
|
}
|
|
return left
|
|
}
|
|
|
|
parse_factor() {
|
|
local t = me.peek(); local ty = t.get("type")
|
|
if ty == "INT" {
|
|
me.next();
|
|
local node = new MapBox(); node.set("type", "Int"); node.set("value", t.get("value"))
|
|
return node
|
|
}
|
|
if ty == "(" {
|
|
me.next();
|
|
local e = me.parse_expr()
|
|
local r = me.peek(); if r.get("type") != ")" { return me.err(") expected") } else { me.next() }
|
|
return e
|
|
}
|
|
return me.err("factor expected")
|
|
}
|
|
|
|
// helpers
|
|
peek() { return me.tokens.get(me.pos) }
|
|
next() { me.pos = me.pos + 1; return me.tokens.get(me.pos-1) }
|
|
bin(op, lhs, rhs) {
|
|
local m = new MapBox(); m.set("type", "Binary"); m.set("op", op); m.set("lhs", lhs); m.set("rhs", rhs); return m
|
|
}
|
|
err(msg) {
|
|
local err = new MapBox(); err.set("version", 0); err.set("kind", "Error")
|
|
local e = new MapBox(); e.set("message", msg)
|
|
local sp = new MapBox(); sp.set("start", me.pos); sp.set("end", me.pos)
|
|
e.set("span", sp); err.set("error", e)
|
|
return err
|
|
}
|
|
}
|