From 078a300c1fc25cf3cb12b7aa7c650e64bbfa98f6 Mon Sep 17 00:00:00 2001 From: uan Date: Thu, 5 Feb 2026 21:48:44 +0100 Subject: [PATCH] way better prints yay --- generator.v | 98 +++++++++++++++++++++++++++++++++++++++++++---------- lexer.v | 8 +++-- main.v | 3 +- parser.v | 59 +++++++++++++++++++++++++------- 4 files changed, 135 insertions(+), 33 deletions(-) diff --git a/generator.v b/generator.v index 92d9872..6621b05 100644 --- a/generator.v +++ b/generator.v @@ -5,6 +5,7 @@ import os struct Generator { mut: + symbols SymbolTable out strings.Builder } @@ -21,9 +22,23 @@ fn mangle_struct(name string) string { return 'one_class_${name}_' } -fn mangle_if_struct_type(name string) string { - if name.len < 7 || name[0..6] != 'struct' {return name} - return 'struct ${mangle_struct(name[7..])}' + +fn get_type_format(type string) string { + return match type { + 'int', 'bool' {'d'} + 'real' {'f'} + else {panic("invalid type to print")} + } +} + +fn (mut g Generator) get_print_label(expr Expr) string { + return match expr { + Variable { expr.name } + MemberAccess { + "${g.get_print_label(expr.from)}.${expr.member}" + } + else { "" } + } } fn (mut g Generator) get_c_type(typ string) string { @@ -34,10 +49,43 @@ fn (mut g Generator) get_c_type(typ string) string { } } +fn (mut g Generator) mangle_if_class(name string) string { + if g.symbols.lookup_class(name) != none { + return 'struct ${mangle_struct(name)}' + } + return name +} + +// thank google gemini for this one, I genuinely did not have the mental strength to +// think this at 9pm +fn (mut g Generator) gen_class_print_func(stmt ClassDecl) { + struct_name := mangle_struct(stmt.name) + g.out.writeln('void print_${struct_name}(struct ${struct_name} s, int indent) {') + + g.out.writeln('printf("${stmt.name} {\\n");') + + for member in stmt.members { + g.out.writeln('for(int i=0; i()[]{}=\n".contains(c.ascii_str()) && (c.ascii_str() != '.' || !is_inside_number) + valid_chars := match is_inside_number { + true {" +-*/,;:%<>()[]{}=\n"} + false {". +-*/,;:%<>()[]{}=\n"} + } + return valid_chars.contains(c.ascii_str()) } fn is_real(str string) bool { @@ -142,11 +146,11 @@ fn lex(input string) ?[]Token { mut is_inside_number := false for (right < input.len && left <= right) { + is_inside_number = input[left].ascii_str().is_int() if input[right] == `\n` { line++ } if !is_delimiter(input[right], is_inside_number) { - is_inside_number = input[left].str().is_int() right++ } if right >= input.len { diff --git a/main.v b/main.v index 12bd216..4355516 100644 --- a/main.v +++ b/main.v @@ -18,7 +18,7 @@ fn main() { pos: 0 } - statements := parser.parse_program() + statements, symbols := parser.parse_program() $if debug { println("-- AST --") @@ -27,6 +27,7 @@ fn main() { mut generator := Generator{ out: strings.new_builder(100) + symbols: symbols } out_c := generator.gen_c(statements) diff --git a/parser.v b/parser.v index 90bf666..84d8f4e 100644 --- a/parser.v +++ b/parser.v @@ -12,6 +12,7 @@ enum Precedence { product // *, / prefix // -x, !x call // function() + access // . } fn (p Parser) get_precedence(tok_type TokenType) Precedence { @@ -20,6 +21,7 @@ fn (p Parser) get_precedence(tok_type TokenType) Precedence { .eq_eq, .not_eq, .less_eq, .greater_eq { .comparison } .plus, .minus { .sum } .star, .slash { .product } + .dot { .access } else { .lowest } } } @@ -39,6 +41,7 @@ struct FuncSymbolInfo { struct ClassSymbolInfo { name string + members_info map[string]VarSymbolInfo } struct SymbolTable { @@ -90,8 +93,12 @@ fn (mut s SymbolTable) lookup_func(name string) ?FuncSymbolInfo { return none } -fn (mut s SymbolTable) define_class(name string) { - s.structs[name] = ClassSymbolInfo{name: name} +fn (mut s SymbolTable) define_class(name string, members []ClassMember) { + mut members_info := map[string]VarSymbolInfo{} + for member in members { + members_info[member.name] = VarSymbolInfo{member.type} + } + s.structs[name] = ClassSymbolInfo{name: name, members_info: members_info} } fn (mut s SymbolTable) lookup_class(name string) ?ClassSymbolInfo { @@ -108,7 +115,7 @@ fn (mut s SymbolTable) is_in_global_scope() bool { // ------------------------------------------- Expressions -type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | Variable | TypeExpr | Function | TypeCast | ParenExpr | PrintExpr | FnCall | ClassMember | ClassInstantiation +type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | Variable | TypeExpr | Function | TypeCast | ParenExpr | PrintExpr | FnCall | ClassMember | ClassInstantiation | MemberAccess struct VoidExpr {} @@ -148,6 +155,11 @@ struct ClassMember { type string } +struct MemberAccess { + from Expr + member string +} + struct ClassInstantiation { name string member_values []Expr @@ -295,9 +307,16 @@ fn (mut p Parser) parse_primary() Expr { fn (mut p Parser) parse_expr(prec Precedence) Expr { mut expr := p.parse_primary() + + for int(prec) < int(p.get_precedence(p.peek().type)) { op_tok := p.next() - expr = p.parse_binary(expr, op_tok.text, p.get_precedence(op_tok.type)) + + if op_tok.type == .dot { + expr = p.parse_member_access(expr) + } else { + expr = p.parse_binary(expr, op_tok.text, p.get_precedence(op_tok.type)) + } } return expr @@ -307,7 +326,7 @@ fn (mut p Parser) parse_ident(ident string) Expr { if p.symbols.lookup_class(ident) != none { return match p.peek().type { .lbracket {p.parse_class_inst(ident)} - else {p.parse_type('struct ${ident}')} + else {p.parse_type('${ident}')} } } @@ -322,6 +341,12 @@ fn (mut p Parser) parse_ident(ident string) Expr { } } +fn (mut p Parser) parse_member_access(from Expr) MemberAccess { + member_tok := p.next() + if member_tok.type != .identifier {parse_error("Expected identifier after member access")} + return MemberAccess {from: from, member: member_tok.text} +} + fn (mut p Parser) parse_class_member(name string) ClassMember { p.expect(.identifier) @@ -330,7 +355,7 @@ fn (mut p Parser) parse_class_member(name string) ClassMember { .type {type_tok.text} .identifier { p.expect_ident_is_class(type_tok.text) - 'struct ${type_tok.text}' + type_tok.text } else{parse_error("Expected type after class member ${name} in declaration, got ${p.peek().type}")} } @@ -448,7 +473,6 @@ fn (mut p Parser) get_expr_type(expr Expr) string { } } Variable { - p.dump_stmt() info := p.symbols.lookup_var(expr.name) or { parse_error("Undefined variable ${expr.name}") } @@ -459,6 +483,15 @@ fn (mut p Parser) get_expr_type(expr Expr) string { fninfo := p.symbols.lookup_func(expr.name) or {parse_error("Tried to call undefined function ${expr.name}")} fninfo.type } + MemberAccess { + mut type_from := p.get_expr_type(expr.from) + classinfo := p.symbols.lookup_class(type_from)or{parse_error("Non-existant class ${type_from}")} + if expr.member in classinfo.members_info { + classinfo.members_info[expr.member].type + } else { + parse_error("Undefined class member ${expr.member}") + } + } ClassInstantiation {expr.name} else {"Tried getting type of unexpected Expr"} } @@ -515,7 +548,7 @@ fn (mut p Parser) parse_var_decl(is_const bool) VarDecl { .type {type_tok.text} .identifier { p.expect_ident_is_class(type_tok.text) - 'struct ${type_tok.text}' + type_tok.text } else{parse_error("Expected variable type after name when declaring ${name_tok.text}")} } @@ -569,7 +602,7 @@ fn (mut p Parser) parse_func_decl() FuncDecl { .type {type_tok.text} .identifier { p.expect_ident_is_class(type_tok.text) - 'struct ${type_tok.text}' + type_tok.text } else{parse_error("Expected argument type after name when declaring ${p_name}")} } @@ -594,7 +627,7 @@ fn (mut p Parser) parse_func_decl() FuncDecl { .type {type_tok.text} .identifier { p.expect_ident_is_class(type_tok.text) - 'struct ${type_tok.text}' + type_tok.text } else{parse_error("Expected function return type after name when declaring ${name_tok.text}")} } @@ -632,7 +665,7 @@ fn (mut p Parser) parse_class() ClassDecl { members << p.parse_class_member(p.peek().text) } p.expect(.rbracket) - p.symbols.define_class(name) + p.symbols.define_class(name, members) return ClassDecl{name: name, members: members} } @@ -697,7 +730,7 @@ fn (mut p Parser) parse_block(no_scope bool) Block { } -fn (mut p Parser) parse_program() []Stmt { +fn (mut p Parser) parse_program() ([]Stmt, SymbolTable) { p.symbols.variable_scopes << map[string]VarSymbolInfo{} for p.peek().type != .eof { p.statements << p.parse_statement() @@ -706,7 +739,7 @@ fn (mut p Parser) parse_program() []Stmt { $if debug { dump(p.symbols.functions) } - return p.statements + return p.statements, p.symbols }