about summary refs log tree commit diff
path: root/src/bootstrap/codegen.pry
diff options
context:
space:
mode:
Diffstat (limited to 'src/bootstrap/codegen.pry')
-rw-r--r--src/bootstrap/codegen.pry1450
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;
-};