362 lines
8.5 KiB
V
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 { }
|
|
}
|
|
}
|
|
}
|