diff options
Diffstat (limited to 'src/codegen.pry')
| -rw-r--r-- | src/codegen.pry | 1450 |
1 files changed, 1450 insertions, 0 deletions
diff --git a/src/codegen.pry b/src/codegen.pry new file mode 100644 index 0000000..cb054ec --- /dev/null +++ b/src/codegen.pry @@ -0,0 +1,1450 @@ +import "!hashmap.pry"; + +import "llvm.pry"; + +let Variable = struct { + value: LLVMValueRef, + type: LLVMTypeRef, + node: *Node, + node_type: *Node, + stack_level: *i64, +}; + +let Scope = struct { + variables: *HashMap, +}; + +let Environment = struct { + scope_stack: **Scope, + scope_stack_len: i64, + arena: *arena, +}; + +let environment_create_scope = (e: *Environment) => void { + let scope = cast(*Scope, arena_alloc((*e).arena, sizeof(Scope))); + (*scope).variables = hashmap_init(16, (*e).arena); + (*((*e).scope_stack + cast(**Scope, (*e).scope_stack_len))) = scope; + (*e).scope_stack_len = (*e).scope_stack_len + 1; + + return; +}; + +let environment_drop_scope = (e: *Environment) => void { + (*e).scope_stack_len = (*e).scope_stack_len - 1; + + return; +}; + +let environment_get_variable = (e: *Environment, name: *i8) => *Variable { + let i = (*e).scope_stack_len; + let variable = cast(*Variable, null); + + while i > 0 { + i = i - 1; + let scope = *(((*e).scope_stack + cast(**Scope, i))); + assert(scope != cast(*Scope, null)); + let v = cast(*Variable, hashmap_get((*scope).variables, name)); + if v != cast(*Variable, null) { + if variable == cast(*Variable, null) { + variable = v; + }; + let stack_level = cast(*i64, arena_alloc((*e).arena, sizeof(i64))); + (*stack_level) = i; + (*variable).stack_level = stack_level; + }; + }; + + return variable; +}; + +let environment_add_variable = (e: *Environment, name: *i8, variable: *Variable) => void { + /* TODO: Dont allow shadowing if value != value or type != type (across things) */ + let top_scope = *(((*e).scope_stack + cast(**Scope, (*e).scope_stack_len - 1))); + hashmap_put((*top_scope).variables, name, cast(*void, variable)); + + return; +}; + +let environment_set_variable = (e: *Environment, name: *i8, variable: *Variable) => void { + let existing = environment_get_variable(e, name); + (*existing) = (*variable); + + return; +}; + +let environment_init = (alloc: *arena) => *Environment { + let e = cast(*Environment, arena_alloc(alloc, sizeof(Environment))); + (*e).scope_stack = cast(**Scope, arena_alloc(alloc, sizeof(*Scope) * 40)); + (*e).scope_stack_len = 0; + (*e).arena = alloc; + + environment_create_scope(e); + + return e; +}; + +let codegen = struct { + llvm_module: LLVMModuleRef, + llvm_context: LLVMContextRef, + builder: LLVMBuilderRef, + arena: *arena, + environment: *Environment, + + whil_loop_exit: LLVMBasicBlockRef, + whil_block: LLVMBasicBlockRef, + current_function: LLVMValueRef, + current_function_retur_type: *Node, + llvm_target_data: LLVMTargetDataRef, +}; + +let codegen_init = (alloc: *arena) => *codegen { + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllTargets(); + LLVMInitializeAllAsmPrinters(); + LLVMInitializeAllAsmParsers(); + + let module = LLVMModuleCreateWithName("module"); + let context = LLVMGetGlobalContext(); + let builder = LLVMCreateBuilder(); + + let c = cast(*codegen, arena_alloc(alloc, sizeof(codegen))); + + (*c).llvm_module = module; + (*c).llvm_target_data = LLVMGetModuleDataLayout(module); + (*c).llvm_context = context; + (*c).builder = builder; + (*c).arena = alloc; + (*c).environment = environment_init(alloc); + + return c; +}; + +let create_node = (c: *codegen, n: Node) => *Node { + let res = cast(*Node, arena_alloc((*c).arena, sizeof(Node))); + *res = n; + return res; +}; + +let codegen_create_variable = (c: *codegen, variable: Variable) => *Variable { + let v = cast(*Variable, arena_alloc((*c).arena, sizeof(Variable))); + *v = variable; + return v; +}; + +let compare_types = (c: *codegen, a: *Node, b: *Node, is_dereference: bool) => bool { + assert((*a).type >= NODE_TYPE_SIMPLE_TYPE); + assert((*a).type <= NODE_TYPE_STRUCT_TYPE); + assert((*b).type >= NODE_TYPE_SIMPLE_TYPE); + assert((*b).type <= NODE_TYPE_STRUCT_TYPE); + + if (*a).type == NODE_TYPE_SIMPLE_TYPE { + let simple_type_a = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*a).data); + if strcmp(simple_type_a.name, "varargs") { + return true; + }; + }; + + if is_dereference { + assert((*a).type == NODE_TYPE_POINTER_TYPE); + let pointer_type_a = *cast(*NODE_TYPE_POINTER_TYPE_DATA, (*a).data); + a = pointer_type_a.type; + }; + + if (*a).type != (*b).type { + printf("Types do not match: %d != ", (*a).type); + printf("%d\n", (*b).type); + return false; + }; + + if (*a).type == NODE_TYPE_SIMPLE_TYPE { + assert((*b).type == NODE_TYPE_SIMPLE_TYPE); + let simple_type_a = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*a).data); + let simple_type_b = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*b).data); + let eql = strcmp(simple_type_a.name, simple_type_b.name); + if !eql { + printf("Simple types do not match: %s != ", simple_type_a.name); + printf("%s\n", simple_type_b.name); + }; + return eql; + }; + + if (*a).type == NODE_TYPE_FUNCTION_TYPE { + assert((*b).type == NODE_TYPE_FUNCTION_TYPE); + let function_type_a = *cast(*NODE_TYPE_FUNCTION_TYPE_DATA, (*a).data); + let function_type_b = *cast(*NODE_TYPE_FUNCTION_TYPE_DATA, (*b).data); + + + if !compare_types(c, function_type_a.retur_type, function_type_b.retur_type, false) { + printf("Function return types do not match\n"); + return false; + }; + + if function_type_a.parameters_len != function_type_b.parameters_len { + printf("Function parameter lengths do not match\n"); + return false; + }; + + let i = 0; + while i < function_type_a.parameters_len { + let param_a = *(function_type_a.parameters + cast(**Node, i)); + let param_b = *(function_type_b.parameters + cast(**Node, i)); + if !compare_types(c, param_a, param_b, false) { + printf("Function parameter types do not match\n"); + return false; + }; + i = i + 1; + }; + + return true; + }; + + if (*a).type == NODE_TYPE_POINTER_TYPE { + assert((*b).type == NODE_TYPE_POINTER_TYPE); + let pointer_type_a = *cast(*NODE_TYPE_POINTER_TYPE_DATA, (*a).data); + let pointer_type_b = *cast(*NODE_TYPE_POINTER_TYPE_DATA, (*b).data); + if !compare_types(c, pointer_type_a.type, pointer_type_b.type, false) { + printf("Pointer types do not match\n"); + return false; + }; + return true; + }; + + if (*a).type == NODE_TYPE_STRUCT_TYPE { + assert((*b).type == NODE_TYPE_STRUCT_TYPE); + let struc_type_a = *cast(*NODE_TYPE_STRUCT_TYPE_DATA, (*a).data); + let struc_type_b = *cast(*NODE_TYPE_STRUCT_TYPE_DATA, (*b).data); + + if struc_type_a.fields_len != struc_type_b.fields_len { + printf("Struct field lengths do not match\n"); + return false; + }; + + let i = 0; + while i < struc_type_a.fields_len { + let field_a = *(struc_type_a.fields + cast(**Node, i)); + let field_b = *(struc_type_b.fields + cast(**Node, i)); + if !compare_types(c, field_a, field_b, false) { + printf("Struct field types do not match\n"); + return false; + }; + i = i + 1; + }; + + return true; + }; + + return false; +}; + +let codegen_get_llvm_type = (c: *codegen, node: *Node) => *LLVMTypeRef { + assert((*node).type >= NODE_TYPE_SIMPLE_TYPE); + assert((*node).type <= NODE_TYPE_STRUCT_TYPE); + + if (*node).type == NODE_TYPE_SIMPLE_TYPE { + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*node).data); + + if strcmp(simple_type.name, "i8") { + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMInt8Type(); + return r; + }; + + if strcmp(simple_type.name, "i64") { + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMInt64Type(); + return r; + }; + + if strcmp(simple_type.name, "bool") { + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMInt1Type(); + return r; + }; + + if strcmp(simple_type.name, "void") { + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMVoidType(); + return r; + }; + + if strcmp(simple_type.name, "varargs") { /* Hack for varargs (only used for printf) */ + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMPointerType(LLVMInt64Type(), 0); + return r; + }; + + let v = environment_get_variable((*c).environment, simple_type.name); + if (v != cast(*Variable, null)) { + assert((*v).type != cast(LLVMTypeRef, null)); + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = (*v).type; + return r; + }; + + printf("NO SIMPLE TYPE %s!\n", simple_type.name); + assert(false); + }; + + if (*node).type == NODE_TYPE_FUNCTION_TYPE { + let function_type = *cast(*NODE_TYPE_FUNCTION_TYPE_DATA, (*node).data); + let f_retur = function_type.retur_type; + let retur_type = codegen_get_llvm_type(c, f_retur); + assert(retur_type != cast(*LLVMTypeRef, null)); + if (*f_retur).type == NODE_TYPE_FUNCTION_TYPE { + (*retur_type) = LLVMPointerType(*retur_type, 0); + }; + + let paramtypes = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef) * 20)); + let paramtypes_len = 0; + let is_varargs = 0; + + let i = 0; + while i < function_type.parameters_len { + let param = *(function_type.parameters + cast(**Node, i)); + if (*param).type == NODE_TYPE_SIMPLE_TYPE { + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*param).data); + if strcmp(simple_type.name, "varargs") { + is_varargs = 1; + i = i + 1; + continue; + }; + }; + let typ = codegen_get_llvm_type(c, param); + assert(typ != cast(*LLVMTypeRef, null)); + if (*param).type == NODE_TYPE_FUNCTION_TYPE { + *typ = LLVMPointerType(*typ, 0); + }; + + (*(paramtypes + cast(*LLVMTypeRef, paramtypes_len))) = *typ; + paramtypes_len = paramtypes_len + 1; + + i = i + 1; + }; + let function_type = LLVMFunctionType(*retur_type, paramtypes, paramtypes_len, is_varargs); + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = function_type; + return r; + }; + + if (*node).type == NODE_TYPE_POINTER_TYPE { + let pointer_type = *cast(*NODE_TYPE_POINTER_TYPE_DATA, (*node).data); + let inner_type = codegen_get_llvm_type(c, pointer_type.type); + assert(inner_type != cast(*LLVMTypeRef, null)); + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMPointerType(*inner_type, 0); + return r; + }; + + printf("NO TYPEEE BOI %d\n", (*node).type); + assert(false); + + return cast(*LLVMTypeRef, null); +}; + +let codegen_generate_literal = (c: *codegen, literal_val: LLVMValueRef, name: *i8, node: *Node, node_type: *Node) => *Variable { + if name != cast(*i8, null) { + let e = (*c).environment; + if (*e).scope_stack_len == 1 { + let lt = codegen_get_llvm_type(c, node_type); + assert(lt != cast(*LLVMTypeRef, null)); + let v = Variable{}; + v.value = LLVMAddGlobal((*c).llvm_module, *lt, name); + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = node; + v.node_type = node_type; + LLVMSetInitializer(v.value, literal_val); + return codegen_create_variable(c, v); + }; + }; + + + let v = Variable{}; + v.value = literal_val; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = node; + v.node_type = node_type; + return codegen_create_variable(c, v); +}; + +extern codegen_generate_statement = (*codegen, *Node) => i64; +extern codegen_generate_function_call_statement = (*codegen, *Node) => *Variable; +extern codegen_generate_expression_value = (*codegen, *Node, *i8) => *Variable; + +let StructField = struct { + value: LLVMValueRef, + type: *Node, +}; + +let codegen_get_struct_field = (c: *codegen, node: *Node, name: *i8) => *StructField { + let ptr = cast(*Variable, null); + if (*node).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER { + let identifier = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*node).data); + ptr = environment_get_variable((*c).environment, identifier.name); + }; + if (*node).type == NODE_UNARY_EXPRESSION { + let xd = (*cast(*NODE_UNARY_EXPRESSION_DATA, (*node).data)).expression; + ptr = codegen_generate_expression_value(c, xd, ""); + }; + + assert(ptr != cast(*Variable, null)); + + let typ = cast(*Node, null); + let ptr_typ = (*ptr).node_type; + if (*ptr_typ).type == NODE_TYPE_STRUCT_TYPE { + typ = ptr_typ; + }; + if (*ptr_typ).type == NODE_TYPE_POINTER_TYPE { + let pt = *cast(*NODE_TYPE_POINTER_TYPE_DATA, (*ptr_typ).data); + let pt_type = pt.type; + assert((*pt_type).type == NODE_TYPE_SIMPLE_TYPE); + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*pt_type).data); + let v = environment_get_variable((*c).environment, simple_type.name); + assert(v != cast(*Variable, null)); + typ = (*v).node_type; /* TODO: we shouldnt be able to get fields of pointers, we have to dref first */ + }; + if (*ptr_typ).type == NODE_TYPE_SIMPLE_TYPE { + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*ptr_typ).data); + let v = environment_get_variable((*c).environment, simple_type.name); + assert(v != cast(*Variable, null)); + typ = (*v).node_type; + }; + + assert(typ != cast(*Node, null)); + assert((*typ).type == NODE_TYPE_SIMPLE_TYPE); + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*typ).data); + assert((*simple_type.underlying_type).type == NODE_TYPE_STRUCT_TYPE); + let struc_type = *cast(*NODE_TYPE_STRUCT_TYPE_DATA, (*simple_type.underlying_type).data); + + let fieldIndex = cast(*i64, null); + + let i = 0; + while i < struc_type.fields_len { + let field = *(struc_type.fields + cast(**Node, i)); + assert((*field).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); + let field_data = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*field).data); + if strcmp(name, field_data.name) { + let ii = cast(*i64, arena_alloc((*c).arena, sizeof(i64))); + *ii = i; + fieldIndex = ii; + break; + }; + i = i + 1; + }; + + assert(fieldIndex != cast(*i64, null)); + + let zero = LLVMConstInt(LLVMInt32Type(), 0, 0); + let llvmFieldIndex = LLVMConstInt(LLVMInt32Type(), *fieldIndex, 0); + let indices = cast(*LLVMValueRef, arena_alloc((*c).arena, sizeof(LLVMValueRef) * 2)); + (*(indices + cast(*LLVMValueRef, 0))) = zero; + (*(indices + cast(*LLVMValueRef, 1))) = llvmFieldIndex; + + let res = cast(*StructField, arena_alloc((*c).arena, sizeof(StructField))); + + let x = codegen_get_llvm_type(c, typ); + assert(x != cast(*LLVMTypeRef, null)); + (*res).value = LLVMBuildGEP2((*c).builder, *x, (*ptr).value, indices, 2, name); + let no = *(struc_type.fields + cast(**Node, *fieldIndex)); + assert((*no).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); + let no_d = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*no).data); + (*res).type = no_d.type; + + return res; +}; + +let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: *i8) => *Variable { + if ((*expression).type == NODE_PRIMARY_EXPRESSION_NULL) { + let inner_type_data = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*inner_type_data).name = "void"; + let inner_type = Node{}; + inner_type.type = NODE_TYPE_SIMPLE_TYPE; + inner_type.data = cast(*void, inner_type_data); + + let node_type_data = cast(*NODE_TYPE_POINTER_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_POINTER_TYPE_DATA))); + (*node_type_data).type = create_node(c, inner_type); + let node_type = Node{}; + node_type.type = NODE_TYPE_POINTER_TYPE; + node_type.data = cast(*void, node_type_data); + + return codegen_generate_literal(c, LLVMConstNull(LLVMPointerType(LLVMInt8Type(), 0)), name, expression, create_node(c, node_type)); + }; + + if ((*expression).type == NODE_PRIMARY_EXPRESSION_NUMBER) { + let n = (*cast(*NODE_PRIMARY_EXPRESSION_NUMBER_DATA, (*expression).data)).value; + + let node_type = Node{}; + node_type.type = NODE_TYPE_SIMPLE_TYPE; + + let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*d).name = "i64"; + (*d).underlying_type = cast(*Node, null); + node_type.data = cast(*void, d); + + return codegen_generate_literal(c, LLVMConstInt(LLVMInt64Type(), n, 0), name, expression, create_node(c, node_type)); + }; + + if ((*expression).type == NODE_PRIMARY_EXPRESSION_BOOLEAN) { + let b = (*cast(*NODE_PRIMARY_EXPRESSION_BOOLEAN_DATA, (*expression).data)).value; + + let node_type = Node{}; + node_type.type = NODE_TYPE_SIMPLE_TYPE; + + let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*d).name = "bool"; + (*d).underlying_type = cast(*Node, null); + node_type.data = cast(*void, d); + + let int_value = 0; + if b == true { + int_value = 1; + }; + + return codegen_generate_literal(c, LLVMConstInt(LLVMInt1Type(), int_value, 0), name, expression, create_node(c, node_type)); + }; + + if ((*expression).type == NODE_PRIMARY_EXPRESSION_CHAR) { + let ch = cast(i64, (*cast(*NODE_PRIMARY_EXPRESSION_CHAR_DATA, (*expression).data)).value); + + let node_type = Node{}; + node_type.type = NODE_TYPE_SIMPLE_TYPE; + + let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*d).name = "i8"; + (*d).underlying_type = cast(*Node, null); + node_type.data = cast(*void, d); + + return codegen_generate_literal(c, LLVMConstInt(LLVMInt8Type(), cast(i64, ch), 0), name, expression, create_node(c, node_type)); + }; + + if ((*expression).type == NODE_PRIMARY_EXPRESSION_STRING) { + let str = (*cast(*NODE_PRIMARY_EXPRESSION_STRING_DATA, (*expression).data)).value; + + let x = LLVMBuildGlobalStringPtr((*c).builder, str, ""); + + let inner_type_data = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*inner_type_data).name = "i8"; + let inner_type = Node{}; + inner_type.type = NODE_TYPE_SIMPLE_TYPE; + inner_type.data = cast(*void, inner_type_data); + + let node_type_data = cast(*NODE_TYPE_POINTER_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_POINTER_TYPE_DATA))); + (*node_type_data).type = create_node(c, inner_type); + let node_type = Node{}; + node_type.type = NODE_TYPE_POINTER_TYPE; + node_type.data = cast(*void, node_type_data); + + let v = Variable{}; + v.value = x; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = create_node(c, node_type); + + return codegen_create_variable(c, v); + }; + + if ((*expression).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER) { + let identifier = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*expression).data); + let variable = environment_get_variable((*c).environment, identifier.name); + assert(variable != cast(*Variable, null)); + let param_value = (*variable).value; + let v_type = (*variable).node_type; + + let done = false; + if (*v_type).type != NODE_TYPE_FUNCTION_TYPE { + let param_type = codegen_get_llvm_type(c, v_type); + assert(param_type != cast(*LLVMTypeRef, null)); + if (*v_type).type == NODE_TYPE_FUNCTION_TYPE { + (*param_type) = LLVMPointerType(*param_type, 0); + }; + param_value = LLVMBuildLoad2((*c).builder, *param_type, (*variable).value, ""); + done = true; + }; + + if !done { + if (*(*variable).stack_level) != 0 { + let param_type = codegen_get_llvm_type(c, v_type); + assert(param_type != cast(*LLVMTypeRef, null)); + if (*v_type).type == NODE_TYPE_FUNCTION_TYPE { + (*param_type) = LLVMPointerType(*param_type, 0); + }; + param_value = LLVMBuildLoad2((*c).builder, *param_type, (*variable).value, ""); + done = true; + }; + + }; + + return codegen_generate_literal(c, param_value, name, expression, (*variable).node_type); + }; + + if ((*expression).type == NODE_FUNCTION_DEFINITION) { + /* Functions should be declared "globally" */ + let builder_pos = LLVMGetInsertBlock((*c).builder); + + let llvm_param_types = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef) * 20)); + let param_types = cast(**Node, arena_alloc((*c).arena, sizeof(*Node) * 20)); + + let function_definition = *cast(*NODE_FUNCTION_DEFINITION_DATA, (*expression).data); + + let i = 0; + let is_varargs = 0; + while i < function_definition.parameters_len { + let node = *(function_definition.parameters + cast(**Node, i)); + assert((*node).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); + let param = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*node).data); + let param_type = param.type; + if (*param_type).type == NODE_TYPE_SIMPLE_TYPE { + let simple_type = *(cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*param_type).data)); + if strcmp(simple_type.name, "varargs") { + is_varargs = 1; + }; + }; + let llvm_param_type = codegen_get_llvm_type(c, param_type); + assert(llvm_param_type != cast(*LLVMTypeRef, null)); + if (*param_type).type == NODE_TYPE_FUNCTION_TYPE { + (*llvm_param_type) = LLVMPointerType(*llvm_param_type, 0); + }; + + (*(llvm_param_types + cast(*LLVMTypeRef, i))) = *llvm_param_type; + (*(param_types + cast(**Node, i))) = param_type; + i = i + 1; + }; + + let f_ret = function_definition.retur_type; + let retur_type = codegen_get_llvm_type(c, f_ret); + assert(retur_type != cast(*LLVMTypeRef, null)); + if (*f_ret).type == NODE_TYPE_FUNCTION_TYPE { + (*retur_type) = LLVMPointerType(*retur_type, 0); + }; + + let function = cast(LLVMValueRef, null); + if name != cast(*i8, null) { + let v = environment_get_variable((*c).environment, name); + if (v != cast(*Variable, null)) { + function = (*v).value; + }; + }; + if function == cast(LLVMValueRef, null) { + let function_type = LLVMFunctionType(*retur_type, llvm_param_types, i, is_varargs); + let n_name = name; + if name == cast(*i8, null) { + n_name = "unnamed_func"; + }; + function = LLVMAddFunction((*c).llvm_module, n_name, function_type); + }; + + let function_entry = LLVMAppendBasicBlock(function, "entrypoint"); + LLVMPositionBuilderAtEnd((*c).builder, function_entry); + + environment_create_scope((*c).environment); + let last_function = (*c).current_function; + (*c).current_function = function; + let last_function_retur_type = (*c).current_function_retur_type; + (*c).current_function_retur_type = function_definition.retur_type; + + /* TODO: Defer. For now we do at the end */ + + let d = cast(*NODE_TYPE_FUNCTION_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_FUNCTION_TYPE_DATA))); + (*d).parameters = param_types; + (*d).parameters_len = i; + (*d).retur_type = function_definition.retur_type; + let n = Node{}; + let node_type = create_node(c, n); + (*node_type).type = NODE_TYPE_FUNCTION_TYPE; + (*node_type).data = cast(*void, d); + + /* Needed for recursive functions */ + if name != cast(*i8, null) { + let v = Variable{}; + v.value = function; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = node_type; + environment_add_variable((*c).environment, name, codegen_create_variable(c, v)); + }; + + let params = cast(*LLVMValueRef, arena_alloc((*c).arena, sizeof(LLVMValueRef) * function_definition.parameters_len)); + LLVMGetParams(function, params); + + let parameters_index = 0; + while parameters_index < function_definition.parameters_len { + let p = (*(params + cast(*LLVMValueRef, parameters_index))); + let param_node = *(function_definition.parameters + cast(**Node, parameters_index)); + assert((*param_node).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); + let param = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*param_node).data); + let param_type = param.type; + let llvm_param_type = codegen_get_llvm_type(c, param_type); + assert(llvm_param_type != cast(*LLVMTypeRef, null)); + if (*param_type).type == NODE_TYPE_FUNCTION_TYPE { + (*llvm_param_type) = LLVMPointerType(*llvm_param_type, 0); + }; + let alloca = LLVMBuildAlloca((*c).builder, *llvm_param_type, param.name); + LLVMBuildStore((*c).builder, p, alloca); + + let v = Variable{}; + v.value = alloca; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = param_node; + v.node_type = param_type; + environment_add_variable((*c).environment, param.name, codegen_create_variable(c, v)); + parameters_index = parameters_index + 1; + }; + + i = 0; + while i < function_definition.statements_len { + let stmt = *(function_definition.statements + cast(**Node, i)); + + let res = codegen_generate_statement(c, stmt); + assert(res == 0); + + i = i + 1; + }; + + LLVMPositionBuilderAtEnd((*c).builder, builder_pos); + + let v = Variable{}; + v.value = function; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = node_type; + + /* TODO: Move to defer */ + (*c).current_function = last_function; + (*c).current_function_retur_type = last_function_retur_type; + environment_drop_scope((*c).environment); + + return codegen_create_variable(c, v); + }; + + if ((*expression).type == NODE_EQUALITY_EXPRESSION) { + let exp = (*(cast(*NODE_EQUALITY_EXPRESSION_DATA, (*expression).data))); + let lhs_value = codegen_generate_expression_value(c, exp.lhs, cast(*i8, null)); + assert(lhs_value != cast(*Variable, null)); + let rhs_value = codegen_generate_expression_value(c, exp.rhs, cast(*i8, null)); + assert(rhs_value != cast(*Variable, null)); + + assert(compare_types(c, (*lhs_value).node_type, (*rhs_value).node_type, false)); + + let op = -1; + + if exp.typ == EQUALITY_EXPRESSION_TYPE_EQ { + op = LLVMIntEQ; + }; + if exp.typ == EQUALITY_EXPRESSION_TYPE_NE { + op = LLVMIntNE; + }; + if exp.typ == EQUALITY_EXPRESSION_TYPE_GE { + op = LLVMIntSGE; + }; + if exp.typ == EQUALITY_EXPRESSION_TYPE_LE { + op = LLVMIntSLE; + }; + if exp.typ == EQUALITY_EXPRESSION_TYPE_LT { + op = LLVMIntSLT; + }; + if exp.typ == EQUALITY_EXPRESSION_TYPE_GT { + op = LLVMIntSGT; + }; + + assert(op != -1); + + let cmp = LLVMBuildICmp((*c).builder, cast(LLVMIntPredicate, op), (*lhs_value).value, (*rhs_value).value, ""); + + + let node_type = Node{}; + node_type.type = NODE_TYPE_SIMPLE_TYPE; + + let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*d).name = "bool"; + (*d).underlying_type = cast(*Node, null); + node_type.data = cast(*void, d); + + return codegen_generate_literal(c, cmp, name, expression, create_node(c, node_type)); + }; + + if ((*expression).type == NODE_ADDITIVE_EXPRESSION) { + let exp = (*(cast(*NODE_ADDITIVE_EXPRESSION_DATA, (*expression).data))); + let lhs_value = codegen_generate_expression_value(c, exp.lhs, cast(*i8, null)); + assert(lhs_value != cast(*Variable, null)); + let rhs_value = codegen_generate_expression_value(c, exp.rhs, cast(*i8, null)); + assert(rhs_value != cast(*Variable, null)); + + assert(compare_types(c, (*lhs_value).node_type, (*rhs_value).node_type, false)); + + let result = cast(LLVMValueRef, null); + let node_type = Node{}; + node_type.type = NODE_TYPE_SIMPLE_TYPE; + + let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*d).name = "i64"; + (*d).underlying_type = cast(*Node, null); + node_type.data = cast(*void, d); + + let pnode_type = create_node(c, node_type); + + if exp.addition { + let nt = (*lhs_value).node_type; + if (*nt).type == NODE_TYPE_POINTER_TYPE { + let ipt = cast(*NODE_TYPE_POINTER_TYPE_DATA, (*nt).data); + let llvmipt = codegen_get_llvm_type(c, (*ipt).type); + assert(llvmipt != cast(*LLVMTypeRef, null)); + let arr = cast(*LLVMValueRef, arena_alloc((*c).arena, sizeof(LLVMValueRef) * 1)); + (*(arr + cast(*LLVMValueRef, 0))) = (*rhs_value).value; + result = LLVMBuildGEP2((*c).builder, *llvmipt, (*lhs_value).value, arr, 1, ""); + pnode_type = (*lhs_value).node_type; + }; + if (*nt).type != NODE_TYPE_POINTER_TYPE { + result = LLVMBuildAdd((*c).builder, (*lhs_value).value, (*rhs_value).value, ""); + }; + + }; + if !exp.addition { + result = LLVMBuildSub((*c).builder, (*lhs_value).value, (*rhs_value).value, ""); + }; + + return codegen_generate_literal(c, result, name, expression, pnode_type); + }; + + if ((*expression).type == NODE_MULTIPLICATIVE_EXPRESSION) { + let exp = (*(cast(*NODE_MULTIPLICATIVE_EXPRESSION_DATA, (*expression).data))); + let lhs_value = codegen_generate_expression_value(c, exp.lhs, cast(*i8, null)); + assert(lhs_value != cast(*Variable, null)); + let rhs_value = codegen_generate_expression_value(c, exp.rhs, cast(*i8, null)); + assert(rhs_value != cast(*Variable, null)); + + assert(compare_types(c, (*lhs_value).node_type, (*rhs_value).node_type, false)); + + let result = cast(LLVMValueRef, null); + + if exp.typ == MULTIPLICATIVE_EXPRESSION_TYPE_MUL { + result = LLVMBuildMul((*c).builder, (*lhs_value).value, (*rhs_value).value, ""); + }; + if exp.typ == MULTIPLICATIVE_EXPRESSION_TYPE_DIV { + result = LLVMBuildSDiv((*c).builder, (*lhs_value).value, (*rhs_value).value, ""); + }; + if exp.typ == MULTIPLICATIVE_EXPRESSION_TYPE_MOD { + result = LLVMBuildSRem((*c).builder, (*lhs_value).value, (*rhs_value).value, ""); + }; + assert(result != cast(LLVMValueRef, null)); + + return codegen_generate_literal(c, result, name, expression, (*lhs_value).node_type); + }; + + if ((*expression).type == NODE_UNARY_EXPRESSION) { + let exp = (*(cast(*NODE_UNARY_EXPRESSION_DATA, (*expression).data))); + let k = codegen_generate_expression_value(c, exp.expression, cast(*i8, null)); + assert(k != cast(*Variable, null)); + + let r = cast(LLVMValueRef, null); + let typ = (*k).node_type; + + if exp.typ == UNARY_EXPRESSION_TYPE_NOT { + assert((*typ).type == NODE_TYPE_SIMPLE_TYPE); + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*typ).data); + assert(strcmp(simple_type.name, "bool")); + r = LLVMBuildICmp((*c).builder, cast(LLVMIntPredicate, LLVMIntEQ), (*k).value, LLVMConstInt(LLVMInt1Type(), 0, 0), ""); + let node_type = Node{}; + node_type.type = NODE_TYPE_SIMPLE_TYPE; + + let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*d).name = "bool"; + (*d).underlying_type = cast(*Node, null); + node_type.data = cast(*void, d); + typ = create_node(c, node_type); + }; + + if exp.typ == UNARY_EXPRESSION_TYPE_MINUS { + r = LLVMBuildNeg((*c).builder, (*k).value, ""); + let node_type = Node{}; + node_type.type = NODE_TYPE_SIMPLE_TYPE; + + let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*d).name = "i64"; + (*d).underlying_type = cast(*Node, null); + node_type.data = cast(*void, d); + typ = create_node(c, node_type); + }; + + if exp.typ == UNARY_EXPRESSION_TYPE_STAR { + assert((*typ).type == NODE_TYPE_POINTER_TYPE); + let n = (*k).node_type; + typ = (*cast(*NODE_TYPE_POINTER_TYPE_DATA, (*n).data)).type; + let ptr_type = codegen_get_llvm_type(c, typ); + assert(ptr_type != cast(*LLVMTypeRef, null)); + r = LLVMBuildLoad2((*c).builder, *ptr_type, (*k).value, ""); + }; + + return codegen_generate_literal(c, r, name, expression, typ); + }; + + if ((*expression).type == NODE_TYPE_FUNCTION_TYPE) { + let e = *((*c).environment); + assert(e.scope_stack_len == 1); + + let existing = environment_get_variable((*c).environment, name); + if (existing != cast(*Variable, null)) { + return existing; + }; + + let function_type = codegen_get_llvm_type(c, expression); + assert(function_type != cast(*LLVMTypeRef, null)); + let function = LLVMAddFunction((*c).llvm_module, name, *function_type); + let v = Variable{}; + v.value = function; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = expression; + return codegen_create_variable(c, v); + }; + + if ((*expression).type == NODE_FUNCTION_CALL_STATEMENT) { + return codegen_generate_function_call_statement(c, expression); + }; + + if ((*expression).type == NODE_CAST_STATEMENT) { + let exp = *cast(*NODE_CAST_STATEMENT_DATA, (*expression).data); + let val = codegen_generate_expression_value(c, exp.expression, ""); + assert(val != cast(*Variable, null)); + let v = Variable{}; + v.value = (*val).value; /* TODO: Do real casting */ + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = exp.typ; + return codegen_create_variable(c, v); + }; + + if ((*expression).type == NODE_SIZEOF_STATEMENT) { + let exp = *cast(*NODE_SIZEOF_STATEMENT_DATA, (*expression).data); + let typ = codegen_get_llvm_type(c, exp.typ); + assert(typ != cast(*LLVMTypeRef, null)); + let size_in_bytes = LLVMStoreSizeOfType((*c).llvm_target_data, *typ); + let size_val = LLVMConstInt(LLVMInt64Type(), size_in_bytes, 0); + + let node_type = Node{}; + node_type.type = NODE_TYPE_SIMPLE_TYPE; + + let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*d).name = "i64"; + (*d).underlying_type = cast(*Node, null); + node_type.data = cast(*void, d); + + let v = Variable{}; + v.value = size_val; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = create_node(c, node_type); + return codegen_create_variable(c, v); + }; + + if ((*expression).type == NODE_TYPE_STRUCT_TYPE) { + let struc_data = *cast(*NODE_TYPE_STRUCT_TYPE_DATA, (*expression).data); + let dd = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*dd).name = name; + (*dd).underlying_type = expression; + let n = Node{}; + n.type = NODE_TYPE_SIMPLE_TYPE; + n.data = cast(*void, dd); + let simple_type_node = create_node(c, n); + + let struc_type = LLVMStructCreateNamed((*c).llvm_context, name); + + if name != cast(*i8, null) { + let v = Variable{}; + v.value = cast(LLVMValueRef, null); + v.type = struc_type; + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = simple_type_node; + environment_add_variable((*c).environment, name, codegen_create_variable(c, v)); + }; + + let llvm_types = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef) * 20)); + let i = 0; + while i < struc_data.fields_len { + let field = *(struc_data.fields + cast(**Node, i)); + assert((*field).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); + let t = (*cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*field).data)).type; + let lt = codegen_get_llvm_type(c, t); + assert(lt != cast(*LLVMTypeRef, null)); + (*(llvm_types + cast(*LLVMTypeRef, i))) = *lt; + i = i + 1; + }; + + LLVMStructSetBody(struc_type, llvm_types, i, 0); + + let v = Variable{}; + v.value = cast(LLVMValueRef, null); + v.type = struc_type; + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = simple_type_node; + return codegen_create_variable(c, v); + }; + + if ((*expression).type == NODE_TYPE_SIMPLE_TYPE) { + let simple_type_data = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*expression).data); + let typ = codegen_get_llvm_type(c, simple_type_data.underlying_type); + assert(typ != cast(*LLVMTypeRef, null)); + let v = Variable{}; + v.value = cast(LLVMValueRef, null); + v.type = *typ; + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = simple_type_data.underlying_type; + return codegen_create_variable(c, v); + }; + + if ((*expression).type == NODE_STRUCT_INSTANCIATION) { + let struc_data = *cast(*NODE_STRUCT_INSTANCIATION_DATA, (*expression).data); + let v = environment_get_variable((*c).environment, struc_data.typ); + assert(v != cast(*Variable, null)); + return v; + }; + + if ((*expression).type == NODE_FIELD_ACCESS) { + let field_access = *cast(*NODE_FIELD_ACCESS_DATA, (*expression).data); + let x = codegen_get_struct_field(c, field_access.expression, field_access.name); + assert(x != cast(*StructField, null)); + let t = codegen_get_llvm_type(c, (*x).type); + assert(t != cast(*LLVMTypeRef, null)); + let loaded = LLVMBuildLoad2((*c).builder, *t, (*x).value, ""); + let v = Variable{}; + v.value = loaded; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = (*x).type; + return codegen_create_variable(c, v); + }; + + printf("ASSERT 1: %d\n", (*expression).type); + assert(false); + + return cast(*Variable, null); +}; + +let codegen_generate_assignment_statement = (c: *codegen, stmt: *NODE_ASSIGNMENT_STATEMENT_DATA) => i64 { + let lhs = *((*stmt).lhs); + let prhs = (*stmt).rhs; + + if (lhs.type == NODE_PRIMARY_EXPRESSION_IDENTIFIER) { + let identifier = (*cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, lhs.data)).name; + let variable = codegen_generate_expression_value(c, prhs, identifier); + assert(variable != cast(*Variable, null)); + + let env = (*(*c).environment); + if env.scope_stack_len == 1 { + environment_add_variable((*c).environment, identifier, variable); + return 0; + }; + + let ptr = cast(LLVMValueRef, null); + let typ = (*variable).node_type; + + if (*stmt).is_declaration { + let x = codegen_get_llvm_type(c, typ); + assert(x != cast(*LLVMTypeRef, null)); + if (*typ).type == NODE_TYPE_FUNCTION_TYPE { + *x = LLVMPointerType(*x, 0); + }; + ptr = LLVMBuildAlloca((*c).builder, *x, identifier); + }; + if !(*stmt).is_declaration { + let v = environment_get_variable((*c).environment, identifier); + assert(v != cast(*Variable, null)); + ptr = (*v).value; + typ = (*v).node_type; + /* TODO: Do this in more places! (everywhere get_llvm_type or get_variable?) Also check types in return and cmp */ + assert(compare_types(c, typ, (*variable).node_type, (*stmt).is_dereference)); + }; + + if (*stmt).is_dereference { + let ltyp = codegen_get_llvm_type(c, typ); + assert(ltyp != cast(*LLVMTypeRef, null)); + ptr = LLVMBuildLoad2((*c).builder, *ltyp, ptr, ""); + }; + + /* NOTE: structs have a null variable.value */ + if (*variable).value != cast(LLVMValueRef, null) { + LLVMBuildStore((*c).builder, (*variable).value, ptr); + }; + + if (*stmt).is_dereference { + let v = environment_get_variable((*c).environment, identifier); + assert(v != cast(*Variable, null)); + ptr = (*v).value; + }; + + let new_variable = Variable{}; + + new_variable.value = ptr; + new_variable.type = (*variable).type; + new_variable.stack_level = cast(*i64, null); + new_variable.node = (*variable).node; + new_variable.node_type = typ; + + if (*stmt).is_declaration { + environment_add_variable((*c).environment, identifier, codegen_create_variable(c, new_variable)); + }; + if !(*stmt).is_declaration { + environment_set_variable((*c).environment, identifier, codegen_create_variable(c, new_variable)); + }; + + return 0; + }; + + if (lhs.type == NODE_UNARY_EXPRESSION) { + let xd = (*cast(*NODE_UNARY_EXPRESSION_DATA, lhs.data)).expression; + let a = codegen_generate_expression_value(c, xd, cast(*i8, null)); + assert(a != cast(*Variable, null)); + let variable = codegen_generate_expression_value(c, prhs, cast(*i8, null)); + assert(variable != cast(*Variable, null)); + assert(compare_types(c, (*a).node_type, (*variable).node_type, true)); + LLVMBuildStore((*c).builder, (*variable).value, (*a).value); + + return 0; + }; + + if (lhs.type == NODE_FIELD_ACCESS) { + let field_access = (*cast(*NODE_FIELD_ACCESS_DATA, lhs.data)); + let xd = field_access.expression; + let name = field_access.name; + + let x = codegen_get_struct_field(c, xd, name); + assert(x != cast(*StructField, null)); + + let variable = codegen_generate_expression_value(c, prhs, cast(*i8, null)); + assert(compare_types(c, (*x).type, (*variable).node_type, (*stmt).is_dereference)); + LLVMBuildStore((*c).builder, (*variable).value, (*x).value); + + return 0; + }; + + printf("ASSERT 2 %d\n", lhs.type); + assert(false); + return 0; +}; + +let codegen_generate_return_statement = (c: *codegen, stmt: *NODE_RETURN_STATEMENT_DATA) => i64 { + let expression = (*stmt).expression; + + if expression == cast(*Node, null) { + LLVMBuildRetVoid((*c).builder); + return 0; + }; + + let val = codegen_generate_expression_value(c, expression, cast(*i8, null)); + assert(val != cast(*Variable, null)); + + assert(compare_types(c, (*c).current_function_retur_type, (*val).node_type, false)); + + LLVMBuildRet((*c).builder, (*val).value); + + return 0; +}; + +let get_function_return_type = (ic: *codegen, fun: *Node) => *Node { + if (*fun).type == NODE_FUNCTION_DEFINITION { + let d = cast(*NODE_FUNCTION_DEFINITION_DATA, (*fun).data); + return (*d).retur_type; + }; + if (*fun).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER { + let d = cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*fun).data); + let f = environment_get_variable((*ic).environment, (*d).name); + if f == cast(*Variable, null) { + printf("NO variable 2: %s\n", (*d).name); + assert(false); + }; + let f_type = (*f).node_type; + assert((*f_type).type == NODE_TYPE_FUNCTION_TYPE); + return get_function_return_type(ic, f_type); + }; + if (*fun).type == NODE_TYPE_FUNCTION_TYPE { + let d = cast(*NODE_TYPE_FUNCTION_TYPE_DATA, (*fun).data); + return (*d).retur_type; + }; + assert(false); + return cast(*Node, null); +}; + +let codegen_generate_function_call_statement = (c: *codegen, statement: *Node) => *Variable { + assert((*statement).type == NODE_FUNCTION_CALL_STATEMENT); + let stmt = cast(*NODE_FUNCTION_CALL_STATEMENT_DATA, (*statement).data); + let expression = (*stmt).expression; + + let node = statement; + let function = cast(*Variable, null); + + if (*expression).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER { + let ident = (*cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*expression).data)); + function = environment_get_variable((*c).environment, ident.name); + if function == cast(*Variable, null) { + printf("NO variable 1: %s\n", ident.name); + assert(false); + }; + + if LLVMGetValueKind((*function).value) != LLVMFunctionValueKind { + let lt = codegen_get_llvm_type(c, (*function).node_type); + assert(lt != cast(*LLVMTypeRef, null)); + (*function).value = LLVMBuildLoad2((*c).builder, LLVMPointerType(*lt, 0), (*function).value, ""); + node = (*function).node; + }; + }; + if (*expression).type == NODE_FUNCTION_DEFINITION { + function = codegen_generate_expression_value(c, expression, cast(*i8, null)); + }; + + assert(function != cast(*Variable, null)); + assert((*function).node_type != cast(*Node, null)); + let function_type = (*function).node_type; + assert((*function_type).type == NODE_TYPE_FUNCTION_TYPE); + let function_type_data = cast(*NODE_TYPE_FUNCTION_TYPE_DATA, (*function_type).data); + /* assert((*function_type_data).parameters_len == (*stmt).arguments_len); TODO: Varargs */ + + let arguments = cast(*LLVMValueRef, arena_alloc((*c).arena, sizeof(LLVMValueRef) * (*stmt).arguments_len)); + + let i = 0; + while i < (*stmt).arguments_len { + let argument = (*((*stmt).arguments + cast(**Node, i))); + let arg = codegen_generate_expression_value(c, argument, cast(*i8, null)); + assert(arg != cast(*Variable, null)); + let expected_type = *((*function_type_data).parameters + cast(**Node, i)); /* TODO: If varargs we shouldn't do this */ + + assert(compare_types(c, expected_type, (*arg).node_type, false)); + + (*(arguments + cast(*LLVMValueRef, i))) = (*arg).value; + + i = i + 1; + }; + + let function_type = codegen_get_llvm_type(c, (*function).node_type); + assert(function_type != cast(*LLVMTypeRef, null)); + + let res = LLVMBuildCall2((*c).builder, *function_type, (*function).value, arguments, i, ""); + + let function_return_type = get_function_return_type(c, (*function).node_type); + + let v = Variable{}; + + v.value = res; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = node; + v.node_type = function_return_type; + + return codegen_create_variable(c, v); +}; + +let codegen_generate_break_statement = (c: *codegen) => i64 { + assert((*c).whil_loop_exit != cast(LLVMBasicBlockRef, null)); + LLVMBuildBr((*c).builder, (*c).whil_loop_exit); + return 0; +}; + +let codegen_generate_continue_statement = (c: *codegen) => i64 { + assert((*c).whil_block != cast(LLVMBasicBlockRef, null)); + LLVMBuildBr((*c).builder, (*c).whil_block); + return 0; +}; + +let codegen_generate_if_statement = (c: *codegen, statement: *NODE_IF_STATEMENT_DATA) => *void { + let condition_value = codegen_generate_expression_value(c, (*statement).condition, cast(*i8, null)); + assert(condition_value != cast(*Variable, null)); + + let current_block = LLVMGetInsertBlock((*c).builder); + + let then_block = LLVMAppendBasicBlock((*c).current_function, "then_block"); + LLVMPositionBuilderAtEnd((*c).builder, then_block); + + let i = 0; + while i < (*statement).statements_len { + let stmt = (*((*statement).statements + cast(**Node, i))); + let res = codegen_generate_statement(c, stmt); + assert(res == 0); + i = i + 1; + }; + + let merge_block = LLVMAppendBasicBlock((*c).current_function, "merge_block"); + let last_instr = LLVMGetLastInstruction(LLVMGetInsertBlock((*c).builder)); + if last_instr == cast(LLVMValueRef, null) { + LLVMBuildBr((*c).builder, merge_block); + }; + if last_instr != cast(LLVMValueRef, null) { + if LLVMIsATerminatorInst(last_instr) == cast(LLVMValueRef, null) { + LLVMBuildBr((*c).builder, merge_block); + }; + }; + LLVMPositionBuilderAtEnd((*c).builder, current_block); + LLVMBuildCondBr((*c).builder, (*condition_value).value, then_block, merge_block); + LLVMPositionBuilderAtEnd((*c).builder, merge_block); + + return null; +}; + +let codegen_generate_while_statement = (c: *codegen, statement: *NODE_WHILE_STATEMENT_DATA) => *void { + let whil_block = LLVMAppendBasicBlock((*c).current_function, "while_block"); + LLVMBuildBr((*c).builder, whil_block); + LLVMPositionBuilderAtEnd((*c).builder, whil_block); + + let condition_value = codegen_generate_expression_value(c, (*statement).condition, cast(*i8, null)); + assert(condition_value != cast(*Variable, null)); + + let inner_block = LLVMAppendBasicBlock((*c).current_function, "inner_block"); + let outer_block = LLVMAppendBasicBlock((*c).current_function, "outer_block"); + LLVMBuildCondBr((*c).builder, (*condition_value).value, inner_block, outer_block); + + (*c).whil_loop_exit = outer_block; + (*c).whil_block = whil_block; + + LLVMPositionBuilderAtEnd((*c).builder, inner_block); + let i = 0; + while i < (*statement).statements_len { + let stmt = (*((*statement).statements + cast(**Node, i))); + let res = codegen_generate_statement(c, stmt); + assert(res == 0); + i = i + 1; + }; + + LLVMBuildBr((*c).builder, whil_block); + LLVMPositionBuilderAtEnd((*c).builder, outer_block); + + (*c).whil_loop_exit = cast(LLVMBasicBlockRef, null); + (*c).whil_block = cast(LLVMBasicBlockRef, null); + + return null; +}; + +extern codegen_generate = (*codegen, *Node) => i64; + +let codegen_generate_import_declaration = (c: *codegen, statement: *NODE_IMPORT_DECLARATION_DATA) => i64 { + return codegen_generate(c, (*statement).program); +}; + +let codegen_generate_statement = (c: *codegen, statement: *Node) => i64 { + let stmt = *statement; + + if stmt.type == NODE_ASSIGNMENT_STATEMENT { + return codegen_generate_assignment_statement(c, cast(*NODE_ASSIGNMENT_STATEMENT_DATA, stmt.data)); + }; + + if stmt.type == NODE_RETURN_STATEMENT { + return codegen_generate_return_statement(c, cast(*NODE_RETURN_STATEMENT_DATA, stmt.data)); + }; + + if stmt.type == NODE_FUNCTION_CALL_STATEMENT { + codegen_generate_function_call_statement(c, statement); + return 0; + }; + + if stmt.type == NODE_IF_STATEMENT { + codegen_generate_if_statement(c, cast(*NODE_IF_STATEMENT_DATA, stmt.data)); + return 0; + }; + + if stmt.type == NODE_WHILE_STATEMENT { + codegen_generate_while_statement(c, cast(*NODE_WHILE_STATEMENT_DATA, stmt.data)); + return 0; + }; + + if stmt.type == NODE_IMPORT_DECLARATION { + return codegen_generate_import_declaration(c, cast(*NODE_IMPORT_DECLARATION_DATA, stmt.data)); + }; + + if stmt.type == NODE_CONTINUE_STATEMENT { + return codegen_generate_continue_statement(c); + }; + + if stmt.type == NODE_BREAK_STATEMENT { + return codegen_generate_break_statement(c); + }; + + printf("ASSERT 3 %d\n", stmt.type); + assert(false); + + return 0; +}; + +let codegen_generate = (c: *codegen, ast: *Node) => i64 { + assert((*ast).type == NODE_PROGRAM); + + let program = *cast(*NODE_PROGRAM_DATA, (*ast).data); + + let i = 0; + while i < program.statements_len { + let stmt = *(program.statements + cast(**Node, i)); + + let res = codegen_generate_statement(c, stmt); + if res != 0 { + return 1; + }; + + i = i + 1; + }; + + return 0; +}; + +let codegen_compile = (c: *codegen, dump_ir: bool) => i64 { + /* Dump module */ + LLVMDumpModule((*c).llvm_module); + let message = cast(**i8, null); + + if dump_ir { + LLVMPrintModuleToFile((*c).llvm_module, "output.ll", message); + return 0; + }; + + /* Generate code */ + let triple = LLVMGetDefaultTargetTriple(); + let target_ref = cast(*LLVMTargetRef, arena_alloc((*c).arena, sizeof(*LLVMTargetRef))); + let result = LLVMGetTargetFromTriple(triple, target_ref, message); + if result != 0 { + printf("Target output: %s\n", *message); + LLVMDisposeMessage(*message); + }; + let target_machine = LLVMCreateTargetMachine( + *target_ref, + triple, + "", + "", + LLVMCodeGenLevelDefault, + LLVMRelocDefault, + LLVMCodeModelDefault, + ); + LLVMDisposeMessage(triple); + result = LLVMVerifyModule((*c).llvm_module, LLVMAbortProcessAction, message); + if result != 0 { + printf("Verification output: %s\n", *message); + LLVMDisposeMessage(*message); + }; + + /* Generate the object file */ + let filename = "bootstrap_output.o"; + LLVMTargetMachineEmitToFile( + target_machine, + (*c).llvm_module, + filename, + LLVMObjectFile, + cast(**i8, null), + ); + LLVMDisposeTargetMachine(target_machine); + printf("Object file generated: %s\n", filename); + + return 0; +}; + +let codegen_deinit = (c: *codegen) => void { + LLVMDisposeModule((*c).llvm_module); + LLVMShutdown(); + LLVMDisposeBuilder((*c).builder); + return; +}; |