vua/ast.v
2025-06-24 03:00:44 -05:00

231 lines
4.6 KiB
V

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')
}