way better prints yay
This commit is contained in:
98
generator.v
98
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<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")}
|
||||
}
|
||||
}
|
||||
|
||||
8
lexer.v
8
lexer.v
@@ -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
3
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)
|
||||
|
||||
59
parser.v
59
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user