way better prints yay

This commit is contained in:
uan
2026-02-05 21:48:44 +01:00
parent 5af769acc2
commit 078a300c1f
4 changed files with 135 additions and 33 deletions

View File

@@ -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<indent + 1; i++) printf(" ");')
g.out.write_string('printf("${member.name}: ");')
if g.symbols.lookup_class(member.type) != none {
inner_struct_name := mangle_struct(member.type)
g.out.writeln('print_${inner_struct_name}(s.${member.name}, indent + 1);')
} else {
format := get_type_format(member.type)
g.out.writeln('printf("%${format}\\n", s.${member.name});')
}
}
g.out.writeln('for(int i=0; i<indent; i++) printf(" ");')
g.out.writeln('printf("}\\n");')
g.out.writeln('}')
}
fn (mut g Generator) gen_stmt(stmt Stmt) {
match stmt {
VarDecl {
c_type := mangle_if_struct_type(g.get_c_type(stmt.type))
c_type := g.mangle_if_class(g.get_c_type(stmt.type))
if stmt.const {
g.out.write_string('const ')
}
@@ -63,7 +111,7 @@ fn (mut g Generator) gen_stmt(stmt Stmt) {
}
FuncDecl {
dump(stmt.ret_type)
c_type := mangle_if_struct_type(g.get_c_type(stmt.ret_type))
c_type := g.mangle_if_class(g.get_c_type(stmt.ret_type))
g.out.write_string('${c_type} ${mangle_func(stmt.name)}(')
for param in stmt.params {
g.gen_stmt(param)
@@ -75,7 +123,7 @@ fn (mut g Generator) gen_stmt(stmt Stmt) {
g.gen_stmt(stmt.block)
}
Param {
c_type := mangle_if_struct_type(g.get_c_type(stmt.type))
c_type := g.mangle_if_class(g.get_c_type(stmt.type))
g.out.write_string('${c_type} ${mangle_var(stmt.name)}')
}
ClassDecl {
@@ -85,6 +133,8 @@ fn (mut g Generator) gen_stmt(stmt Stmt) {
g.out.writeln(';')
}
g.out.writeln('};')
g.gen_class_print_func(stmt)
}
}
}
@@ -114,18 +164,28 @@ fn (mut g Generator) gen_expr(expr Expr) {
g.out.write_string(')')
}
PrintExpr {
g.out.write_string('printf(\"%')
format := match expr.type {
'int', 'bool' {'d'}
'real' {'lf'}
else {panic("Tried printing illegal type")}
}
g.out.write_string('${format}\\n\", ')
g.gen_expr(expr.expr)
g.out.write_string(')')
label := g.get_print_label(expr.expr)
if g.symbols.lookup_class(expr.type) != none {
class_name := mangle_struct(expr.type)
if label != "" {
g.out.write_string('printf("${label}: ");')
}
g.out.write_string('print_${class_name}(')
g.gen_expr(expr.expr)
g.out.write_string(', 0)')
} else {
g.out.write_string('printf(\"')
if label != "" {
g.out.write_string('${label}: ')
}
format := get_type_format(expr.type)
g.out.write_string('%${format}\\n\", ')
g.gen_expr(expr.expr)
g.out.write_string(')')
}
}
TypeCast {
c_type := mangle_if_struct_type(g.get_c_type(expr.type))
c_type := g.mangle_if_class(g.get_c_type(expr.type))
g.out.write_string('((${c_type})')
g.gen_expr(expr.expr)
g.out.write_string(')')
@@ -146,7 +206,7 @@ fn (mut g Generator) gen_expr(expr Expr) {
g.out.write_string(')')
}
ClassMember {
c_type := mangle_if_struct_type(g.get_c_type(expr.type))
c_type := g.mangle_if_class(g.get_c_type(expr.type))
g.out.write_string('${c_type} ${expr.name}')
}
ClassInstantiation {
@@ -159,6 +219,10 @@ fn (mut g Generator) gen_expr(expr Expr) {
}
g.out.write_string('}')
}
MemberAccess {
g.gen_expr(expr.from)
g.out.write_string('.${expr.member}')
}
else {panic("Unimplemented expression")}
}
}

View File

@@ -110,7 +110,11 @@ fn toktype_from_kw(kw string) TokenType {
}
fn is_delimiter(c u8, is_inside_number bool) bool {
return " +-*/.,;:%<>()[]{}=\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 {

3
main.v
View File

@@ -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)

View File

@@ -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
}