tanta roba, wip scope

This commit is contained in:
uan
2026-02-03 23:07:33 +01:00
parent fbae7bc5d5
commit 969de6a59b
5 changed files with 474 additions and 19 deletions

415
parser.v Normal file
View File

@@ -0,0 +1,415 @@
module main
import term
// ------------------------------------------- Symbol Table
type SymbolInfo = VarSymbolInfo | FuncSymbolInfo
struct VarSymbolInfo {
type string
}
struct FuncSymbolInfo {
type string
}
struct SymbolTable {
mut:
variable_scopes []map[string]VarSymbolInfo
functions map[string]FuncSymbolInfo
}
fn (mut s SymbolTable) define_var(name string, typ string) {
$if debug {
dump(s.variable_scopes.len)
}
if s.variable_scopes.len == 0 {
parse_error('No scope available')
}
if name in s.variable_scopes[s.variable_scopes.len-1] {
parse_error('Variable ${name} already defined in this scope')
}
s.variable_scopes[s.variable_scopes.len-1][name] = VarSymbolInfo{type: typ}
}
fn (mut s SymbolTable) lookup_var(name string) ?VarSymbolInfo {
$if debug {
dump(s.variable_scopes.len)
}
if s.variable_scopes.len == 0 {return none}
for variables in s.variable_scopes.reverse() {
if name in variables {
return variables[name]
}
}
return none
}
fn (mut s SymbolTable) define_func(name string, typ string) {
s.functions[name] = FuncSymbolInfo{type: typ}
}
fn (mut s SymbolTable) lookup_func(name string) ?FuncSymbolInfo {
if name in s.functions {
return s.functions[name]
}
return none
}
fn (mut s SymbolTable) is_in_global_scope() bool {
println("scope count: ${s.variable_scopes.len}")
return s.variable_scopes.len == 1
}
// ------------------------------------------- Expressions
type Expr = VoidExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | Variable | TypeExpr | Function
struct VoidExpr {}
struct BinaryExpr {
left Expr
op string
right Expr
}
struct IntegerLiteral {
val i32
}
struct RealLiteral {
val f32
}
struct BoolLiteral {
val bool
}
struct Variable {
name string
}
struct TypeExpr {
name string
}
struct Function {
name string
}
// ------------------------------------------- Statements
type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | FuncDecl
struct VarDecl {
name string
value Expr
type string
}
struct FuncDecl {
name string
ret_type string
block Block
}
struct ExprStmt {
expr Expr
}
struct ReturnStmt {
value Expr
}
struct Block {
stmts []Stmt
}
// ------------------------------------------- Parser
struct Parser {
tokens []Token
mut:
symbols SymbolTable
pos int
statements []Stmt
}
fn (mut p Parser) peek() Token {
return p.tokens[p.pos]
}
fn (mut p Parser) next() Token {
token := p.tokens[p.pos]
p.pos++
return token
}
fn (mut p Parser) expect(type TokenType) {
if p.peek().type != type {
parse_error('Expected ${str_from_toktype(type)}, got ${str_from_toktype(p.peek().type)}')
}
p.next()
}
// ------------------------------------------- Debug
fn (mut p Parser) dump_token() {
$if debug {
dump(p.peek())
}
}
fn (mut p Parser) dump_stmt() {
$if debug {
if p.statements.len > 0 {
dump(p.statements[p.statements.len-1])
}
}
}
@[noreturn]
fn parse_error(str string) {
eprintln(term.red("Parse Error: " + str))
panic("")
}
// ------------------------------------------- Expressions
fn (mut p Parser) parse_primary() Expr {
token := p.next()
p.dump_token()
return match token.type {
.integer {IntegerLiteral{token.text.int()}}
.real {RealLiteral{token.text.f32()}}
.boolean {BoolLiteral{token.text == 'true'}}
.identifier {Variable{token.text}}
.type {TypeExpr{token.text}}
.kw_fn {Function{token.text}}
else {parse_error("Unexpected Token")}
}
}
fn (mut p Parser) parse_expr() Expr {
mut left := p.parse_primary()
match p.peek().type {
.plus {return p.parse_binary(left, '+')}
.minus {return p.parse_binary(left, '-')}
.star {return p.parse_binary(left, '*')}
.slash {return p.parse_binary(left, '/')}
.equals {return p.parse_binary(left, '=')}
else {return left}
}
}
fn (mut p Parser) parse_binary(left Expr, op string) BinaryExpr {
p.next()
right := p.parse_expr()
return BinaryExpr{left, op, right}
}
fn (mut p Parser) get_expr_type(expr Expr) string {
return match expr {
IntegerLiteral {'int'}
RealLiteral {'real'}
BoolLiteral {'bool'}
VoidExpr {'void'}
BinaryExpr {
left_t := p.get_expr_type(expr.left)
right_t := p.get_expr_type(expr.right)
if left_t != right_t {
parse_error ('Type mismatch in expression: ${left_t} and ${right_t}')
}
left_t
}
Variable {
p.dump_stmt()
info := p.symbols.lookup_var(expr.name) or {
parse_error("Undefined variable ${expr.name}")
}
return info.type
}
else {"Tried getting type of unexpected Expr"}
}
}
// ------------------------------------------- Statements
fn (mut p Parser) get_return_stmts_recursive(block Block) []ReturnStmt {
mut returns := []ReturnStmt{}
for stmt in block.stmts {
if stmt is ReturnStmt {
returns << stmt
}
if stmt is Block {
returns << p.get_return_stmts_recursive(stmt)
}
}
return returns
}
fn (mut p Parser) parse_statement() Stmt {
match p.peek().type {
.kw_let {return p.parse_var_decl()}
.kw_return {return p.parse_return_stmt()}
.kw_fn {return p.parse_func_decl()}
.lbracket {return p.parse_block()}
else {return p.parse_expr_stmt()}
}
}
fn (mut p Parser) parse_var_decl() VarDecl {
p.expect(.kw_let)
name_tok := p.next()
if name_tok.type != .identifier {
parse_error("Expected variable name after let")
}
type_tok := p.next()
if type_tok.type != .type {
parse_error("Expected variable type after name")
}
p.expect(.equals)
val := p.parse_expr()
if type_tok.text == 'void' {
parse_error("Cannot declare a variable of type void")
}
if p.get_expr_type(val) != type_tok.text {
parse_error("Mismatch between declared type (${type_tok.text}) and actual type (${p.get_expr_type(val)})")
}
p.expect(.semicolon)
p.symbols.define_var(name_tok.text, type_tok.text)
return VarDecl {
name: name_tok.text
value: val
type: type_tok.text
}
}
fn (mut p Parser) parse_func_decl() FuncDecl {
if !p.symbols.is_in_global_scope() {parse_error("Tried to define a function in a non-global scope")}
p.expect(.kw_fn)
name_tok := p.next()
if name_tok.type != .identifier {
parse_error("Expected variable name after let")
}
p.expect(.lparen)
p.expect(.rparen)
type_tok := p.next()
if type_tok.type != .type {
parse_error("Expected variable type after name")
}
block := p.parse_block()
return_stmts := p.get_return_stmts_recursive(block)
for return_stmt in return_stmts {
if p.get_expr_type(return_stmt.value) != type_tok.text {
parse_error("Mismatch between declared return type (${type_tok.text}) \
and actual return type (${p.get_expr_type(return_stmt.value)})")
}
}
p.symbols.define_func(name_tok.text, type_tok.text)
return FuncDecl {
name: name_tok.text
ret_type: type_tok.text
block: block
}
}
fn (mut p Parser) parse_return_stmt() ReturnStmt {
p.expect(.kw_return)
token := p.peek()
p.dump_token()
mut expr := Expr{}
expr = match token.type {
.integer {IntegerLiteral{token.text.int()}}
.real {RealLiteral{token.text.f32()}}
.boolean {BoolLiteral{token.text == 'true'}}
.identifier {Variable{token.text}}
.semicolon {VoidExpr{}}
else {parse_error("Unexpected Token")}
}
p.next()
if !(expr is VoidExpr) {
p.expect(.semicolon)
}
return ReturnStmt {
value: expr
}
}
fn (mut p Parser) parse_expr_stmt() ExprStmt {
expr := p.parse_expr()
p.expect(.semicolon)
return ExprStmt {
expr: expr
}
}
fn (mut p Parser) parse_block() Block {
p.expect(.lbracket)
mut statements := []Stmt{}
p.symbols.variable_scopes << map[string]VarSymbolInfo{}
$if debug {
println("entering scope")
}
for p.peek().type != .rbracket && p.peek().type != .eof {
statements << p.parse_statement()
}
p.expect(.rbracket)
return_stmts := (statements.filter(it is ReturnStmt).map(it as ReturnStmt))
if return_stmts.len > 0 && (return_stmts.len > 1 || Stmt(return_stmts[0]) != statements[statements.len - 1]) {
parse_error("Unexpected use of return. Unreachable code")
}
p.symbols.variable_scopes.delete_last()
$if debug {
println("exiting scope")
}
return Block {
stmts: statements
}
}
fn (mut p Parser) parse_program() []Stmt {
p.symbols.variable_scopes << map[string]VarSymbolInfo{}
for p.peek().type != .eof {
p.statements << p.parse_statement()
}
p.symbols.variable_scopes.delete_last()
return p.statements
}