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