module ast import constants { Primitives } import intern { InternPool } import token as _ { Tokenizer, Token, TokenType } pub struct VuaNil {} pub struct VuaBool { value bool } pub struct VuaNumber { value string } pub struct VuaString { value string // string interning } pub struct VuaTable { keys []u32 // string interning values []u32 // index in all tables } pub struct VuaFunction { name u32 // string interning args []u32 // string interning body []Token // slice of tokens representing the function body } pub type VuaValue = VuaNil | VuaBool | VuaNumber | VuaString | VuaTable | VuaFunction @[heap] pub struct Environment { mut: bools []VuaBool ints []VuaNumber decimals []VuaNumber strings []VuaString tables []VuaTable functions map[string]VuaFunction str_pool &InternPool = &InternPool{} pub mut: types map[string]Type = { "string" : TypeAlias{"string", .string}, "number" : TypeAlias{"number", .number}, "decimal" : TypeAlias{"decimal", .decimal}, "bool" : TypeAlias{"bool", .bool}, "table" : TypeAlias{"table", .table}, "function": TypeAlias{"function", .function}, } vars map[string]Var } /// index for bools, ints, decimals, strings, etc pub type EnvironmentIndex = int pub struct Var { name string type string value EnvironmentIndex } pub struct TypeAlias { name string alias Primitives } pub fn (t TypeAlias) str() string { return t.name } pub struct StructDefinition { name string fields map[string]EnvironmentIndex } pub struct UnionDefinition { name string fields map[string]EnvironmentIndex } pub type Type = TypeAlias | StructDefinition | UnionDefinition @[heap] pub struct Parser { input string mut: stack []Token frame u32 max_pos u32 pub mut: env &Environment } /// advances once pub fn (mut p Parser) next() ?Token { panic("TODO") } /// rollback the parser to the previous token pub fn (mut p Parser) rollback() { panic("TODO") } /// extracts the string from the token starting position, might need re parsing pub fn (mut p Parser) save_stash(start u32) string { panic("TODO") } /// expect a string and a token to match against, if either fails, it'll fail pub fn (mut p Parser) expect(s string, tag TokenType) ?(string, Token) { panic("TODO") } /// any token of type .keyword, returns the extracted keyword pub fn (mut p Parser) keyword() ?string { panic("TODO") } /// any token of type .identifier, returns the extracted identifier pub fn (mut p Parser) identifier() ?string { panic("TODO") } pub fn (mut p Parser) expr() !VuaValue { if token := p.next() { match token.tag { .identifier { id := p.save_stash(token.start) if var := p.env.vars[id] { eprintln(var) } else { return error("identifier error") } panic("invalid code path") } .nil, .true, .false, .number, .decimal, .string { return error("expression error") } .keyword { p.rollback() return p.keyword_expr() } else { p.rollback() return error("unsupported type") } } } return error("impossible") } pub fn (mut p Parser) keyword_expr() !VuaValue { keyword := p.keyword() or { return error("invalid keyword") } match keyword { "local" { lhs := p.identifier() or { return error("invalid identifier") } type_name := p.identifier() if type_name == none { p.rollback() } p.expect("=", .operator) or { return error("invalid assignment") } rhs := p.next() or { return error("invalid right hand side of assignment") } match rhs.tag { .number, .decimal, .string, .true, .false, .nil { p.env.vars[p.env.str_pool.intern(lhs)] = Var{ name: lhs, type: match rhs.tag { .true, .false { "bool" } else { rhs.tag.str() } }, value: rhs.start } match rhs.tag { .true { vbool := p.input[rhs.start..rhs.start + 4] assert vbool == "true" return VuaValue(VuaBool{true}) } .false { vbool := p.input[rhs.start..rhs.start + 6] assert vbool == "false" return VuaValue(VuaBool{false}) } .number, .decimal { vnum := p.save_stash(rhs.start) return VuaValue(VuaNumber{vnum}) } .string { // might be impossible with tokens pre allocated vstr := p.save_stash(rhs.start) // dirty trick return VuaValue(VuaString{vstr[1..vstr.len-1]}) } .nil { return VuaValue(VuaNil{}) } else { return error("failed rhs inference") } } } else { return error("invalid rhs type") } } } else { return error("unsupported keyword") } } panic('No expression found') }