Files
one/generator.v
2026-02-08 08:47:13 +01:00

362 lines
8.5 KiB
V

module main
import strings
import os
struct Generator {
mut:
symbols SymbolTable
out strings.Builder
}
fn mangle_var(name string) string {
return 'one_var_${name}'
}
fn mangle_func(name string, class_name ?string) string {
if name == 'main' {return 'main'}
mut mangled_name := 'one_func_${name}'
if class_name != none {
mangled_name += '_${class_name}'
}
return mangled_name
}
fn mangle_struct(name string) string {
return 'one_class_${name}'
}
fn get_type_format(type string) string {
if type.contains('*') {
return 'p'
}
return match type {
'int', 'bool' {'d'}
'real' {'f'}
'string' {'s'}
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 {
astkcount := typ.count('*')
clean := typ.replace('*', '')
return match clean {
'real' {'float'}
'int' {'int32_t'}
'string' {'OneString'}
else {clean}
} + '*'.repeat(astkcount)
}
fn (mut g Generator) mangle_if_class(name string) string {
astkcount := name.count('*')
noptr := name.replace('*', '')
if g.symbols.lookup_class(noptr) != none {
return 'struct ${mangle_struct(noptr)}' + '*'.repeat(astkcount)
}
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 member.type != 'string' && 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.write_string('printf("%${format}')
if member.is_immutable {
g.out.write_string(' (immutable) ')
}
g.out.write_string('\\n", s.${member.name}')
if member.type == 'string' {
g.out.write_string('.string')
}
g.out.writeln(');')
}
}
g.out.writeln('for(int i=0; i<indent; i++) printf(" ");')
g.out.writeln('printf("}\");')
g.out.writeln('}')
}
fn (mut g Generator) gen_stmt(stmt Stmt) {
match stmt {
VarDecl {
c_type := g.mangle_if_class(g.get_c_type(stmt.type))
if stmt.const {
g.out.write_string('const ')
}
g.out.write_string('${c_type} ${mangle_var(stmt.name)} = ')
g.gen_expr(stmt.value)
g.out.writeln(';')
}
ExprStmt {
g.gen_expr(stmt.expr)
g.out.writeln(';')
}
ReturnStmt {
g.out.write_string('return ')
g.gen_expr(stmt.expr)
g.out.writeln(';')
}
Block {
g.out.writeln('{')
for inner_stmt in stmt.stmts {
g.gen_stmt(inner_stmt)
}
g.out.writeln('}')
}
FuncDecl {
c_type := g.mangle_if_class(g.get_c_type(stmt.ret_type))
g.out.write_string('${c_type} ${mangle_func(stmt.name, stmt.class_name)}(')
for param in stmt.params {
g.gen_stmt(param)
if param != stmt.params[stmt.params.len-1]{
g.out.write_string(', ')
}
}
g.out.write_string(') ')
g.gen_stmt(stmt.block)
}
Param {
c_type := g.mangle_if_class(g.get_c_type(stmt.type))
g.out.write_string('${c_type} ${mangle_var(stmt.name)}')
}
ClassDecl {
g.out.writeln('struct ${mangle_struct(stmt.name)} {')
for member in stmt.members {
g.gen_expr(member)
g.out.writeln(';')
}
g.out.writeln('};')
g.gen_class_print_func(stmt)
}
IfStmt {
g.out.write_string('if (')
g.gen_expr(stmt.condition)
g.out.write_string(') ')
g.gen_stmt(stmt.block)
}
ElseStmt {
g.out.write_string('else ')
g.gen_stmt(stmt.block)
}
ElifStmt {
g.out.write_string('else if (')
g.gen_expr(stmt.condition)
g.out.write_string(') ')
g.gen_stmt(stmt.block)
}
WhileLoop {
g.out.write_string('while (')
g.gen_expr(stmt.guard)
g.out.write_string(') ')
g.gen_stmt(stmt.block)
}
}
}
fn (mut g Generator) gen_expr(expr Expr) {
match expr {
RefExpr {
g.out.write_string('(&')
g.gen_expr(expr.expr)
g.out.write_string(')')
}
DerefExpr {
g.out.write_string('(*')
g.gen_expr(expr.expr)
g.out.write_string(')')
}
RealLiteral {
g.out.write_string(expr.val.str())
}
IntegerLiteral {
g.out.write_string(expr.val.str())
}
BoolLiteral {
g.out.write_string(expr.val.str())
}
StringLiteral {
g.out.write_string('(OneString){\"${expr.val}\", ${expr.val.len}}')
}
Variable {
g.out.write_string(mangle_var(expr.name))
}
UnaryExpr {
if expr.op_on_left {
g.out.write_string('(${expr.op}')
g.gen_expr(expr.expr)
g.out.write_string(')')
} else {
g.out.write_string('(')
g.gen_expr(expr.expr)
g.out.write_string('${expr.op})')
}
}
BinaryExpr {
g.out.write_string('(')
g.gen_expr(expr.left)
g.out.write_string(' ${expr.op} ')
g.gen_expr(expr.right)
g.out.write_string(')')
}
PrintExpr {
mut i := 0;
for i < expr.exprs.len {
inner_expr := expr.exprs[i];
expr_type := expr.types[i];
if expr_type != 'string' && g.symbols.lookup_class(expr_type) != none {
class_name := mangle_struct(expr_type)
g.out.write_string('print_${class_name}(')
g.gen_expr(inner_expr)
g.out.write_string(', 0);')
} else {
g.out.write_string('printf(\"')
format := get_type_format(expr_type)
g.out.write_string('%${format}')
g.out.write_string('\", ')
g.gen_expr(inner_expr)
if expr_type == 'string' {
g.out.write_string('.string')
}
g.out.write_string(');')
}
i++;
if i < expr.exprs.len {
g.out.write_string('printf(\" \");')
}
}
g.out.write_string('printf(\"\\n\")')
}
TypeCast {
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(')')
}
ParenExpr {
g.out.write_string('(')
g.gen_expr(expr.expr)
g.out.write_string(')')
}
FnCall {
g.out.write_string('${mangle_func(expr.name, none)}(')
for arg in expr.args {
g.gen_expr(arg)
if arg != expr.args[expr.args.len-1]{
g.out.write_string(', ')
}
}
g.out.write_string(')')
}
MethodCall {
g.out.write_string('${mangle_func(expr.method, expr.from_type)}(')
g.out.write_string('&')
g.gen_expr(expr.from)
if expr.args.len > 0 {
g.out.write_string(', ')
}
for arg in expr.args {
g.gen_expr(arg)
if arg != expr.args[expr.args.len-1]{
g.out.write_string(', ')
}
}
g.out.write_string(')')
}
ClassMember {
c_type := g.mangle_if_class(g.get_c_type(expr.type))
g.out.write_string('${c_type} ${expr.name}')
}
ClassInstantiation {
g.out.write_string('(struct ${mangle_struct(expr.name)}){')
for m_expr in expr.member_values {
g.gen_expr(m_expr)
if m_expr != expr.member_values[expr.member_values.len - 1] {
g.out.write_string(', ')
}
}
g.out.write_string('}')
}
MemberAccess {
g.gen_expr(expr.from)
match expr.from_type.count('*') {
0 {g.out.write_string('.')}
1 {g.out.write_string('->')}
else {panic("Tried accessing member from an object of type ${expr.from_type}")}
}
g.out.write_string('${expr.member}')
}
else {panic("Unimplemented expression")}
}
}
fn (mut g Generator) gen_c(program []Stmt) string {
g.out.writeln('#include <stdio.h>')
g.out.writeln('#include <stdbool.h>')
g.out.writeln('#include <stdint.h>')
g.out.writeln('typedef struct {\nchar* string;\nint len;\n} OneString;')
for stmt in program {
g.gen_stmt(stmt)
}
return g.out.str()
}
fn compile(c_code string, output_name string, keep_c bool, compiler string) {
c_file := 'middle_c.c'
os.write_file(c_file, c_code) or {
eprintln('Failed to write C file: $err')
return
}
cmd := match compiler {
'clang' {'clang ${c_file} -o ${output_name} -O2'}
'gcc' {'gcc ${c_file} -o ${output_name} -O2'}
else {panic("Invalid compiler")}
}
println('Executing: ${cmd}')
result := os.execute(cmd)
if result.exit_code != 0 {
eprintln('${compiler} Compilation Failed:')
eprintln(result.output)
} else {
println('Compilation successful! Binary created: $output_name')
if !keep_c {
os.rm(c_file) or { }
}
}
}