way better prints yay
This commit is contained in:
98
generator.v
98
generator.v
@@ -5,6 +5,7 @@ import os
|
|||||||
|
|
||||||
struct Generator {
|
struct Generator {
|
||||||
mut:
|
mut:
|
||||||
|
symbols SymbolTable
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,9 +22,23 @@ fn mangle_struct(name string) string {
|
|||||||
return 'one_class_${name}_'
|
return 'one_class_${name}_'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mangle_if_struct_type(name string) string {
|
|
||||||
if name.len < 7 || name[0..6] != 'struct' {return name}
|
fn get_type_format(type string) string {
|
||||||
return 'struct ${mangle_struct(name[7..])}'
|
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 {
|
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) {
|
fn (mut g Generator) gen_stmt(stmt Stmt) {
|
||||||
match stmt {
|
match stmt {
|
||||||
VarDecl {
|
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 {
|
if stmt.const {
|
||||||
g.out.write_string('const ')
|
g.out.write_string('const ')
|
||||||
}
|
}
|
||||||
@@ -63,7 +111,7 @@ fn (mut g Generator) gen_stmt(stmt Stmt) {
|
|||||||
}
|
}
|
||||||
FuncDecl {
|
FuncDecl {
|
||||||
dump(stmt.ret_type)
|
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)}(')
|
g.out.write_string('${c_type} ${mangle_func(stmt.name)}(')
|
||||||
for param in stmt.params {
|
for param in stmt.params {
|
||||||
g.gen_stmt(param)
|
g.gen_stmt(param)
|
||||||
@@ -75,7 +123,7 @@ fn (mut g Generator) gen_stmt(stmt Stmt) {
|
|||||||
g.gen_stmt(stmt.block)
|
g.gen_stmt(stmt.block)
|
||||||
}
|
}
|
||||||
Param {
|
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)}')
|
g.out.write_string('${c_type} ${mangle_var(stmt.name)}')
|
||||||
}
|
}
|
||||||
ClassDecl {
|
ClassDecl {
|
||||||
@@ -85,6 +133,8 @@ fn (mut g Generator) gen_stmt(stmt Stmt) {
|
|||||||
g.out.writeln(';')
|
g.out.writeln(';')
|
||||||
}
|
}
|
||||||
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(')')
|
g.out.write_string(')')
|
||||||
}
|
}
|
||||||
PrintExpr {
|
PrintExpr {
|
||||||
g.out.write_string('printf(\"%')
|
label := g.get_print_label(expr.expr)
|
||||||
format := match expr.type {
|
if g.symbols.lookup_class(expr.type) != none {
|
||||||
'int', 'bool' {'d'}
|
class_name := mangle_struct(expr.type)
|
||||||
'real' {'lf'}
|
if label != "" {
|
||||||
else {panic("Tried printing illegal type")}
|
g.out.write_string('printf("${label}: ");')
|
||||||
}
|
}
|
||||||
g.out.write_string('${format}\\n\", ')
|
g.out.write_string('print_${class_name}(')
|
||||||
g.gen_expr(expr.expr)
|
g.gen_expr(expr.expr)
|
||||||
g.out.write_string(')')
|
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 {
|
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.out.write_string('((${c_type})')
|
||||||
g.gen_expr(expr.expr)
|
g.gen_expr(expr.expr)
|
||||||
g.out.write_string(')')
|
g.out.write_string(')')
|
||||||
@@ -146,7 +206,7 @@ fn (mut g Generator) gen_expr(expr Expr) {
|
|||||||
g.out.write_string(')')
|
g.out.write_string(')')
|
||||||
}
|
}
|
||||||
ClassMember {
|
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}')
|
g.out.write_string('${c_type} ${expr.name}')
|
||||||
}
|
}
|
||||||
ClassInstantiation {
|
ClassInstantiation {
|
||||||
@@ -159,6 +219,10 @@ fn (mut g Generator) gen_expr(expr Expr) {
|
|||||||
}
|
}
|
||||||
g.out.write_string('}')
|
g.out.write_string('}')
|
||||||
}
|
}
|
||||||
|
MemberAccess {
|
||||||
|
g.gen_expr(expr.from)
|
||||||
|
g.out.write_string('.${expr.member}')
|
||||||
|
}
|
||||||
else {panic("Unimplemented expression")}
|
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 {
|
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 {
|
fn is_real(str string) bool {
|
||||||
@@ -142,11 +146,11 @@ fn lex(input string) ?[]Token {
|
|||||||
mut is_inside_number := false
|
mut is_inside_number := false
|
||||||
|
|
||||||
for (right < input.len && left <= right) {
|
for (right < input.len && left <= right) {
|
||||||
|
is_inside_number = input[left].ascii_str().is_int()
|
||||||
if input[right] == `\n` {
|
if input[right] == `\n` {
|
||||||
line++
|
line++
|
||||||
}
|
}
|
||||||
if !is_delimiter(input[right], is_inside_number) {
|
if !is_delimiter(input[right], is_inside_number) {
|
||||||
is_inside_number = input[left].str().is_int()
|
|
||||||
right++
|
right++
|
||||||
}
|
}
|
||||||
if right >= input.len {
|
if right >= input.len {
|
||||||
|
|||||||
3
main.v
3
main.v
@@ -18,7 +18,7 @@ fn main() {
|
|||||||
pos: 0
|
pos: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
statements := parser.parse_program()
|
statements, symbols := parser.parse_program()
|
||||||
|
|
||||||
$if debug {
|
$if debug {
|
||||||
println("-- AST --")
|
println("-- AST --")
|
||||||
@@ -27,6 +27,7 @@ fn main() {
|
|||||||
|
|
||||||
mut generator := Generator{
|
mut generator := Generator{
|
||||||
out: strings.new_builder(100)
|
out: strings.new_builder(100)
|
||||||
|
symbols: symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
out_c := generator.gen_c(statements)
|
out_c := generator.gen_c(statements)
|
||||||
|
|||||||
59
parser.v
59
parser.v
@@ -12,6 +12,7 @@ enum Precedence {
|
|||||||
product // *, /
|
product // *, /
|
||||||
prefix // -x, !x
|
prefix // -x, !x
|
||||||
call // function()
|
call // function()
|
||||||
|
access // .
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p Parser) get_precedence(tok_type TokenType) Precedence {
|
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 }
|
.eq_eq, .not_eq, .less_eq, .greater_eq { .comparison }
|
||||||
.plus, .minus { .sum }
|
.plus, .minus { .sum }
|
||||||
.star, .slash { .product }
|
.star, .slash { .product }
|
||||||
|
.dot { .access }
|
||||||
else { .lowest }
|
else { .lowest }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,6 +41,7 @@ struct FuncSymbolInfo {
|
|||||||
|
|
||||||
struct ClassSymbolInfo {
|
struct ClassSymbolInfo {
|
||||||
name string
|
name string
|
||||||
|
members_info map[string]VarSymbolInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SymbolTable {
|
struct SymbolTable {
|
||||||
@@ -90,8 +93,12 @@ fn (mut s SymbolTable) lookup_func(name string) ?FuncSymbolInfo {
|
|||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s SymbolTable) define_class(name string) {
|
fn (mut s SymbolTable) define_class(name string, members []ClassMember) {
|
||||||
s.structs[name] = ClassSymbolInfo{name: name}
|
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 {
|
fn (mut s SymbolTable) lookup_class(name string) ?ClassSymbolInfo {
|
||||||
@@ -108,7 +115,7 @@ fn (mut s SymbolTable) is_in_global_scope() bool {
|
|||||||
|
|
||||||
// ------------------------------------------- Expressions
|
// ------------------------------------------- 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 {}
|
struct VoidExpr {}
|
||||||
|
|
||||||
@@ -148,6 +155,11 @@ struct ClassMember {
|
|||||||
type string
|
type string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MemberAccess {
|
||||||
|
from Expr
|
||||||
|
member string
|
||||||
|
}
|
||||||
|
|
||||||
struct ClassInstantiation {
|
struct ClassInstantiation {
|
||||||
name string
|
name string
|
||||||
member_values []Expr
|
member_values []Expr
|
||||||
@@ -295,9 +307,16 @@ fn (mut p Parser) parse_primary() Expr {
|
|||||||
fn (mut p Parser) parse_expr(prec Precedence) Expr {
|
fn (mut p Parser) parse_expr(prec Precedence) Expr {
|
||||||
mut expr := p.parse_primary()
|
mut expr := p.parse_primary()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for int(prec) < int(p.get_precedence(p.peek().type)) {
|
for int(prec) < int(p.get_precedence(p.peek().type)) {
|
||||||
op_tok := p.next()
|
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
|
return expr
|
||||||
@@ -307,7 +326,7 @@ fn (mut p Parser) parse_ident(ident string) Expr {
|
|||||||
if p.symbols.lookup_class(ident) != none {
|
if p.symbols.lookup_class(ident) != none {
|
||||||
return match p.peek().type {
|
return match p.peek().type {
|
||||||
.lbracket {p.parse_class_inst(ident)}
|
.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 {
|
fn (mut p Parser) parse_class_member(name string) ClassMember {
|
||||||
p.expect(.identifier)
|
p.expect(.identifier)
|
||||||
|
|
||||||
@@ -330,7 +355,7 @@ fn (mut p Parser) parse_class_member(name string) ClassMember {
|
|||||||
.type {type_tok.text}
|
.type {type_tok.text}
|
||||||
.identifier {
|
.identifier {
|
||||||
p.expect_ident_is_class(type_tok.text)
|
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}")}
|
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 {
|
Variable {
|
||||||
p.dump_stmt()
|
|
||||||
info := p.symbols.lookup_var(expr.name) or {
|
info := p.symbols.lookup_var(expr.name) or {
|
||||||
parse_error("Undefined variable ${expr.name}")
|
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 := p.symbols.lookup_func(expr.name) or {parse_error("Tried to call undefined function ${expr.name}")}
|
||||||
fninfo.type
|
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}
|
ClassInstantiation {expr.name}
|
||||||
else {"Tried getting type of unexpected Expr"}
|
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}
|
.type {type_tok.text}
|
||||||
.identifier {
|
.identifier {
|
||||||
p.expect_ident_is_class(type_tok.text)
|
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}")}
|
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}
|
.type {type_tok.text}
|
||||||
.identifier {
|
.identifier {
|
||||||
p.expect_ident_is_class(type_tok.text)
|
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}")}
|
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}
|
.type {type_tok.text}
|
||||||
.identifier {
|
.identifier {
|
||||||
p.expect_ident_is_class(type_tok.text)
|
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}")}
|
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)
|
members << p.parse_class_member(p.peek().text)
|
||||||
}
|
}
|
||||||
p.expect(.rbracket)
|
p.expect(.rbracket)
|
||||||
p.symbols.define_class(name)
|
p.symbols.define_class(name, members)
|
||||||
return ClassDecl{name: name, members: 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{}
|
p.symbols.variable_scopes << map[string]VarSymbolInfo{}
|
||||||
for p.peek().type != .eof {
|
for p.peek().type != .eof {
|
||||||
p.statements << p.parse_statement()
|
p.statements << p.parse_statement()
|
||||||
@@ -706,7 +739,7 @@ fn (mut p Parser) parse_program() []Stmt {
|
|||||||
$if debug {
|
$if debug {
|
||||||
dump(p.symbols.functions)
|
dump(p.symbols.functions)
|
||||||
}
|
}
|
||||||
return p.statements
|
return p.statements, p.symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user