diff options
Diffstat (limited to 'src/bootstrap/codegen.pry')
| -rw-r--r-- | src/bootstrap/codegen.pry | 1450 |
1 files changed, 0 insertions, 1450 deletions
diff --git a/src/bootstrap/codegen.pry b/src/bootstrap/codegen.pry deleted file mode 100644 index cb054ec..0000000 --- a/src/bootstrap/codegen.pry +++ /dev/null @@ -1,1450 +0,0 @@ -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; -}; |