[vala] dova: Add experimental backend



commit a29718a46843635e7a2732661faa736032d0f48f
Author: Jürg Billeter <j bitron ch>
Date:   Sat Jun 5 10:02:19 2010 +0200

    dova: Add experimental backend

 ccode/valaccodefunction.vala            |    6 +-
 codegen/Makefile.am                     |   11 +
 codegen/valaccodegenerator.vala         |   14 +
 codegen/valadovaarraymodule.vala        |  130 ++
 codegen/valadovaassignmentmodule.vala   |  198 +++
 codegen/valadovabasemodule.vala         | 2142 +++++++++++++++++++++++++++++++
 codegen/valadovacontrolflowmodule.vala  |   98 ++
 codegen/valadovadelegatemodule.vala     |  210 +++
 codegen/valadovamemberaccessmodule.vala |  255 ++++
 codegen/valadovamethodcallmodule.vala   |  230 ++++
 codegen/valadovamethodmodule.vala       |   46 +
 codegen/valadovaobjectmodule.vala       | 1519 ++++++++++++++++++++++
 codegen/valadovastructmodule.vala       |  101 ++
 codegen/valadovavaluemodule.vala        |  863 +++++++++++++
 14 files changed, 5822 insertions(+), 1 deletions(-)
---
diff --git a/ccode/valaccodefunction.vala b/ccode/valaccodefunction.vala
index 2b3775d..faac0ec 100644
--- a/ccode/valaccodefunction.vala
+++ b/ccode/valaccodefunction.vala
@@ -63,7 +63,11 @@ public class Vala.CCodeFunction : CCodeNode {
 	public void add_parameter (CCodeFormalParameter param) {
 		parameters.add (param);
 	}
-	
+
+	public void insert_parameter (int position, CCodeFormalParameter param) {
+		parameters.insert (position, param);
+	}
+
 	/**
 	 * Returns a copy of this function.
 	 *
diff --git a/codegen/Makefile.am b/codegen/Makefile.am
index 511b071..c62b6f6 100644
--- a/codegen/Makefile.am
+++ b/codegen/Makefile.am
@@ -34,6 +34,17 @@ libvala_la_VALASOURCES = \
 	valadbusinterfaceregisterfunction.vala \
 	valadbusmodule.vala \
 	valadbusservermodule.vala \
+	valadovaarraymodule.vala \
+	valadovaassignmentmodule.vala \
+	valadovabasemodule.vala \
+	valadovacontrolflowmodule.vala \
+	valadovadelegatemodule.vala \
+	valadovamemberaccessmodule.vala \
+	valadovamethodcallmodule.vala \
+	valadovamethodmodule.vala \
+	valadovaobjectmodule.vala \
+	valadovastructmodule.vala \
+	valadovavaluemodule.vala \
 	valaenumregisterfunction.vala \
 	valagerrormodule.vala \
 	valagirwriter.vala \
diff --git a/codegen/valaccodegenerator.vala b/codegen/valaccodegenerator.vala
index 4853e70..e2155cf 100644
--- a/codegen/valaccodegenerator.vala
+++ b/codegen/valaccodegenerator.vala
@@ -53,6 +53,20 @@ public class Vala.CCodeGenerator : CodeGenerator {
 			head = new DBusClientModule (this, head);
 			*/
 			head = new DBusServerModule (this, head);
+		} else if (context.profile == Profile.DOVA) {
+			/* included by inheritance
+			head = new DovaBaseModule (this, head);
+			head = new DovaStructModule (this, head);
+			head = new DovaMethodModule (this, head);
+			head = new DovaControlFlowModule (this, head);
+			head = new DovaMemberAccessModule (this, head);
+			head = new DovaAssignmentModule (this, head);
+			head = new DovaMethodCallModule (this, head);
+			head = new DovaArrayModule (this, head);
+			head = new DovaObjectModule (this, head);
+			head = new DovaValueModule (this, head);
+			*/
+			head = new DovaDelegateModule (this, head);
 		} else {
 			/* included by inheritance
 			head = new CCodeBaseModule (this, head);
diff --git a/codegen/valadovaarraymodule.vala b/codegen/valadovaarraymodule.vala
new file mode 100644
index 0000000..83ddd45
--- /dev/null
+++ b/codegen/valadovaarraymodule.vala
@@ -0,0 +1,130 @@
+/* valadovaarraymodule.vala
+ *
+ * Copyright (C) 2006-2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+internal class Vala.DovaArrayModule : DovaMethodCallModule {
+	public DovaArrayModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	void append_initializer_list (CCodeCommaExpression ce, CCodeExpression name_cnode, InitializerList initializer_list, int rank, ref int i) {
+		foreach (Expression e in initializer_list.get_initializers ()) {
+			if (rank > 1) {
+				append_initializer_list (ce, name_cnode, (InitializerList) e, rank - 1, ref i);
+			} else {
+				ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode));
+				i++;
+			}
+		}
+	}
+
+	public override void visit_array_creation_expression (ArrayCreationExpression expr) {
+		expr.accept_children (codegen);
+
+		var array_type = expr.target_type as ArrayType;
+		if (array_type != null && array_type.fixed_length) {
+			// no heap allocation for fixed-length arrays
+
+			var ce = new CCodeCommaExpression ();
+			var temp_var = get_temp_variable (array_type, true, expr);
+			var name_cnode = new CCodeIdentifier (temp_var.name);
+			int i = 0;
+
+			temp_vars.insert (0, temp_var);
+
+			append_initializer_list (ce, name_cnode, expr.initializer_list, expr.rank, ref i);
+
+			ce.append_expression (name_cnode);
+
+			expr.ccodenode = ce;
+
+			return;
+		}
+
+		generate_method_declaration (array_class.default_construction_method, source_declarations);
+
+		var gnew = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_new"));
+		gnew.add_argument (get_type_id_expression (expr.element_type));
+
+		bool first = true;
+		CCodeExpression cexpr = null;
+
+		// iterate over each dimension
+		foreach (Expression size in expr.get_sizes ()) {
+			CCodeExpression csize = (CCodeExpression) size.ccodenode;
+
+			if (!is_pure_ccode_expression (csize)) {
+				var temp_var = get_temp_variable (int_type, false, expr);
+				var name_cnode = new CCodeIdentifier (temp_var.name);
+				size.ccodenode = name_cnode;
+
+				temp_vars.insert (0, temp_var);
+
+				csize = new CCodeAssignment (name_cnode, csize);
+			}
+
+			if (first) {
+				cexpr = csize;
+				first = false;
+			} else {
+				cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, csize);
+			}
+		}
+
+		gnew.add_argument (cexpr);
+
+		if (expr.initializer_list != null) {
+			var ce = new CCodeCommaExpression ();
+			var temp_var = get_temp_variable (expr.value_type, true, expr);
+			var name_cnode = new CCodeIdentifier (temp_var.name);
+			int i = 0;
+
+			temp_vars.insert (0, temp_var);
+
+			ce.append_expression (new CCodeAssignment (name_cnode, gnew));
+
+			append_initializer_list (ce, name_cnode, expr.initializer_list, expr.rank, ref i);
+
+			ce.append_expression (name_cnode);
+
+			expr.ccodenode = ce;
+		} else {
+			expr.ccodenode = gnew;
+		}
+	}
+
+	public override void visit_element_access (ElementAccess expr) {
+		expr.accept_children (codegen);
+
+		List<Expression> indices = expr.get_indices ();
+		int rank = indices.size;
+
+		var ccontainer = (CCodeExpression) expr.container.ccodenode;
+		var cindex = (CCodeExpression) indices[0].ccodenode;
+
+		// access to element in an array
+		for (int i = 1; i < rank; i++) {
+			var cmul = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cindex, head.get_array_length_cexpression (expr.container, i + 1));
+			cindex = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cmul, (CCodeExpression) indices[i].ccodenode);
+		}
+		expr.ccodenode = new CCodeElementAccess (ccontainer, cindex);
+	}
+}
diff --git a/codegen/valadovaassignmentmodule.vala b/codegen/valadovaassignmentmodule.vala
new file mode 100644
index 0000000..1c400b7
--- /dev/null
+++ b/codegen/valadovaassignmentmodule.vala
@@ -0,0 +1,198 @@
+/* valadovaassignmentmodule.vala
+ *
+ * Copyright (C) 2006-2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+/**
+ * The link between an assignment and generated code.
+ */
+internal class Vala.DovaAssignmentModule : DovaMemberAccessModule {
+	public DovaAssignmentModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	CCodeExpression emit_property_assignment (Assignment assignment) {
+		var ma = assignment.left as MemberAccess;
+
+		var prop = (Property) assignment.left.symbol_reference;
+
+		if (!(prop is DynamicProperty)) {
+			generate_property_accessor_declaration (prop.set_accessor, source_declarations);
+
+			if (!prop.external && prop.external_package) {
+				// internal VAPI properties
+				// only add them once per source file
+				if (add_generated_external_symbol (prop)) {
+					visit_property (prop);
+				}
+			}
+		}
+
+		CCodeExpression cexpr = (CCodeExpression) assignment.right.ccodenode;
+
+		if (assignment.operator != AssignmentOperator.SIMPLE) {
+			CCodeBinaryOperator cop;
+			if (assignment.operator == AssignmentOperator.BITWISE_OR) {
+				cop = CCodeBinaryOperator.BITWISE_OR;
+			} else if (assignment.operator == AssignmentOperator.BITWISE_AND) {
+				cop = CCodeBinaryOperator.BITWISE_AND;
+			} else if (assignment.operator == AssignmentOperator.BITWISE_XOR) {
+				cop = CCodeBinaryOperator.BITWISE_XOR;
+			} else if (assignment.operator == AssignmentOperator.ADD) {
+				cop = CCodeBinaryOperator.PLUS;
+			} else if (assignment.operator == AssignmentOperator.SUB) {
+				cop = CCodeBinaryOperator.MINUS;
+			} else if (assignment.operator == AssignmentOperator.MUL) {
+				cop = CCodeBinaryOperator.MUL;
+			} else if (assignment.operator == AssignmentOperator.DIV) {
+				cop = CCodeBinaryOperator.DIV;
+			} else if (assignment.operator == AssignmentOperator.PERCENT) {
+				cop = CCodeBinaryOperator.MOD;
+			} else if (assignment.operator == AssignmentOperator.SHIFT_LEFT) {
+				cop = CCodeBinaryOperator.SHIFT_LEFT;
+			} else if (assignment.operator == AssignmentOperator.SHIFT_RIGHT) {
+				cop = CCodeBinaryOperator.SHIFT_RIGHT;
+			} else {
+				assert_not_reached ();
+			}
+			cexpr = new CCodeBinaryExpression (cop, (CCodeExpression) get_ccodenode (assignment.left), cexpr);
+		}
+
+		var ccall = get_property_set_call (prop, ma, cexpr, assignment.right);
+
+		// assignments are expressions, so return the current property value, except if we're sure that it can't be used
+		if (!(assignment.parent_node is ExpressionStatement)) {
+			var ccomma = new CCodeCommaExpression ();
+			ccomma.append_expression (ccall); // update property
+			ccomma.append_expression ((CCodeExpression) get_ccodenode (ma)); // current property value
+
+			return ccomma;
+		} else {
+			return ccall;
+		}
+	}
+
+	CCodeExpression emit_simple_assignment (Assignment assignment) {
+		CCodeExpression rhs = (CCodeExpression) assignment.right.ccodenode;
+		CCodeExpression lhs = (CCodeExpression) get_ccodenode (assignment.left);
+		CCodeCommaExpression outer_ccomma = null;
+
+		bool unref_old = requires_destroy (assignment.left.value_type);
+
+		if (unref_old) {
+			var ccomma = new CCodeCommaExpression ();
+
+			if (!is_pure_ccode_expression (lhs)) {
+				/* Assign lhs to temp var to avoid repeating side effect */
+				outer_ccomma = new CCodeCommaExpression ();
+
+				var lhs_value_type = assignment.left.value_type.copy ();
+				string lhs_temp_name = "_tmp%d_".printf (next_temp_var_id++);
+				var lhs_temp = new LocalVariable (lhs_value_type, "*" + lhs_temp_name);
+				temp_vars.insert (0, lhs_temp);
+				outer_ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (lhs_temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, lhs)));
+				lhs = new CCodeParenthesizedExpression (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (lhs_temp_name)));
+			}
+
+			var temp_decl = get_temp_variable (assignment.left.value_type);
+			temp_vars.insert (0, temp_decl);
+			ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_decl.name), rhs));
+			if (unref_old) {
+				/* unref old value */
+				ccomma.append_expression (get_unref_expression (lhs, assignment.left.value_type, assignment.left));
+			}
+
+			ccomma.append_expression (get_variable_cexpression (temp_decl.name));
+
+			rhs = ccomma;
+		}
+
+		var cop = CCodeAssignmentOperator.SIMPLE;
+		if (assignment.operator == AssignmentOperator.BITWISE_OR) {
+			cop = CCodeAssignmentOperator.BITWISE_OR;
+		} else if (assignment.operator == AssignmentOperator.BITWISE_AND) {
+			cop = CCodeAssignmentOperator.BITWISE_AND;
+		} else if (assignment.operator == AssignmentOperator.BITWISE_XOR) {
+			cop = CCodeAssignmentOperator.BITWISE_XOR;
+		} else if (assignment.operator == AssignmentOperator.ADD) {
+			cop = CCodeAssignmentOperator.ADD;
+		} else if (assignment.operator == AssignmentOperator.SUB) {
+			cop = CCodeAssignmentOperator.SUB;
+		} else if (assignment.operator == AssignmentOperator.MUL) {
+			cop = CCodeAssignmentOperator.MUL;
+		} else if (assignment.operator == AssignmentOperator.DIV) {
+			cop = CCodeAssignmentOperator.DIV;
+		} else if (assignment.operator == AssignmentOperator.PERCENT) {
+			cop = CCodeAssignmentOperator.PERCENT;
+		} else if (assignment.operator == AssignmentOperator.SHIFT_LEFT) {
+			cop = CCodeAssignmentOperator.SHIFT_LEFT;
+		} else if (assignment.operator == AssignmentOperator.SHIFT_RIGHT) {
+			cop = CCodeAssignmentOperator.SHIFT_RIGHT;
+		}
+
+		CCodeExpression codenode = new CCodeAssignment (lhs, rhs, cop);
+
+		if (outer_ccomma != null) {
+			outer_ccomma.append_expression (codenode);
+			codenode = outer_ccomma;
+		}
+
+		return codenode;
+	}
+
+	CCodeExpression emit_fixed_length_array_assignment (Assignment assignment, ArrayType array_type) {
+		CCodeExpression rhs = (CCodeExpression) assignment.right.ccodenode;
+		CCodeExpression lhs = (CCodeExpression) get_ccodenode (assignment.left);
+
+		source_declarations.add_include ("string.h");
+
+		// it is necessary to use memcpy for fixed-length (stack-allocated) arrays
+		// simple assignments do not work in C
+		var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+		sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+		var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
+		var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+		ccopy.add_argument (lhs);
+		ccopy.add_argument (rhs);
+		ccopy.add_argument (size);
+
+		return ccopy;
+	}
+
+	public override void visit_assignment (Assignment assignment) {
+		assignment.right.accept (codegen);
+
+		if (assignment.left.error || assignment.right.error) {
+			assignment.error = true;
+			return;
+		}
+
+		if (assignment.left.symbol_reference is Property) {
+			assignment.ccodenode = emit_property_assignment (assignment);
+		} else {
+			var array_type = assignment.left.value_type as ArrayType;
+			if (array_type != null && array_type.fixed_length) {
+				assignment.ccodenode = emit_fixed_length_array_assignment (assignment, array_type);
+			} else {
+				assignment.ccodenode = emit_simple_assignment (assignment);
+			}
+		}
+	}
+}
diff --git a/codegen/valadovabasemodule.vala b/codegen/valadovabasemodule.vala
new file mode 100644
index 0000000..f58a525
--- /dev/null
+++ b/codegen/valadovabasemodule.vala
@@ -0,0 +1,2142 @@
+/* valadovabasemodule.vala
+ *
+ * Copyright (C) 2006-2010  Jürg Billeter
+ * Copyright (C) 2006-2008  Raffaele Sandrini
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ * 	Raffaele Sandrini <raffaele sandrini ch>
+ */
+
+/**
+ * Code visitor generating C Code.
+ */
+internal class Vala.DovaBaseModule : CCodeModule {
+	public CodeContext context { get; set; }
+
+	public Symbol root_symbol;
+	public Symbol current_symbol;
+	public TryStatement current_try;
+
+	public TypeSymbol? current_type_symbol {
+		get {
+			var sym = current_symbol;
+			while (sym != null) {
+				if (sym is TypeSymbol) {
+					return (TypeSymbol) sym;
+				}
+				sym = sym.parent_symbol;
+			}
+			return null;
+		}
+	}
+
+	public Class? current_class {
+		get { return current_type_symbol as Class; }
+	}
+
+	public Method? current_method {
+		get {
+			var sym = current_symbol;
+			while (sym is Block) {
+				sym = sym.parent_symbol;
+			}
+			return sym as Method;
+		}
+	}
+
+	public PropertyAccessor? current_property_accessor {
+		get {
+			var sym = current_symbol;
+			while (sym is Block) {
+				sym = sym.parent_symbol;
+			}
+			return sym as PropertyAccessor;
+		}
+	}
+
+	public DataType? current_return_type {
+		get {
+			var m = current_method;
+			if (m != null) {
+				return m.return_type;
+			}
+
+			var acc = current_property_accessor;
+			if (acc != null) {
+				if (acc.readable) {
+					return acc.value_type;
+				} else {
+					return void_type;
+				}
+			}
+
+			return null;
+		}
+	}
+
+	public CCodeDeclarationSpace header_declarations;
+	public CCodeDeclarationSpace internal_header_declarations;
+	public CCodeDeclarationSpace source_declarations;
+
+	public CCodeFragment source_type_member_definition;
+	public CCodeFragment instance_init_fragment;
+	public CCodeFragment instance_finalize_fragment;
+
+	// code nodes to be inserted before the current statement
+	// used by async method calls in coroutines
+	public CCodeFragment pre_statement_fragment;
+
+	/* all temporary variables */
+	public ArrayList<LocalVariable> temp_vars = new ArrayList<LocalVariable> ();
+	/* temporary variables that own their content */
+	public ArrayList<LocalVariable> temp_ref_vars = new ArrayList<LocalVariable> ();
+	/* (constant) hash table with all reserved identifiers in the generated code */
+	Set<string> reserved_identifiers;
+
+	public int next_temp_var_id = 0;
+	public int next_string_const_id = 0;
+	public bool in_creation_method { get { return current_method is CreationMethod; } }
+	public bool current_method_inner_error = false;
+
+	public DataType void_type = new VoidType ();
+	public DataType bool_type;
+	public DataType char_type;
+	public DataType short_type;
+	public DataType ushort_type;
+	public DataType int_type;
+	public DataType uint_type;
+	public DataType long_type;
+	public DataType ulong_type;
+	public DataType string_type;
+	public DataType float_type;
+	public DataType double_type;
+	public Class object_class;
+	public Class type_class;
+	public Class value_class;
+	public Class array_class;
+	public Class delegate_class;
+
+	Set<Symbol> generated_external_symbols;
+
+	public Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
+
+	public DovaBaseModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+
+		reserved_identifiers = new HashSet<string> (str_hash, str_equal);
+
+		// C99 keywords
+		reserved_identifiers.add ("_Bool");
+		reserved_identifiers.add ("_Complex");
+		reserved_identifiers.add ("_Imaginary");
+		reserved_identifiers.add ("auto");
+		reserved_identifiers.add ("break");
+		reserved_identifiers.add ("case");
+		reserved_identifiers.add ("char");
+		reserved_identifiers.add ("const");
+		reserved_identifiers.add ("continue");
+		reserved_identifiers.add ("default");
+		reserved_identifiers.add ("do");
+		reserved_identifiers.add ("double");
+		reserved_identifiers.add ("else");
+		reserved_identifiers.add ("enum");
+		reserved_identifiers.add ("extern");
+		reserved_identifiers.add ("float");
+		reserved_identifiers.add ("for");
+		reserved_identifiers.add ("goto");
+		reserved_identifiers.add ("if");
+		reserved_identifiers.add ("inline");
+		reserved_identifiers.add ("int");
+		reserved_identifiers.add ("long");
+		reserved_identifiers.add ("register");
+		reserved_identifiers.add ("restrict");
+		reserved_identifiers.add ("return");
+		reserved_identifiers.add ("short");
+		reserved_identifiers.add ("signed");
+		reserved_identifiers.add ("sizeof");
+		reserved_identifiers.add ("static");
+		reserved_identifiers.add ("struct");
+		reserved_identifiers.add ("switch");
+		reserved_identifiers.add ("typedef");
+		reserved_identifiers.add ("union");
+		reserved_identifiers.add ("unsigned");
+		reserved_identifiers.add ("void");
+		reserved_identifiers.add ("volatile");
+		reserved_identifiers.add ("while");
+
+		// reserved for Vala naming conventions
+		reserved_identifiers.add ("error");
+		reserved_identifiers.add ("result");
+		reserved_identifiers.add ("this");
+	}
+
+	public override void emit (CodeContext context) {
+		this.context = context;
+
+		root_symbol = context.root;
+
+		bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
+		char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
+		short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
+		ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
+		int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
+		uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
+		long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
+		ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
+		float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
+		double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
+		string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
+
+		var dova_ns = (Namespace) root_symbol.scope.lookup ("Dova");
+		object_class = (Class) dova_ns.scope.lookup ("Object");
+		type_class = (Class) dova_ns.scope.lookup ("Type");
+		value_class = (Class) dova_ns.scope.lookup ("Value");
+		array_class = (Class) dova_ns.scope.lookup ("Array");
+		delegate_class = (Class) dova_ns.scope.lookup ("Delegate");
+
+		header_declarations = new CCodeDeclarationSpace ();
+		internal_header_declarations = new CCodeDeclarationSpace ();
+
+		/* we're only interested in non-pkg source files */
+		var source_files = context.get_source_files ();
+		foreach (SourceFile file in source_files) {
+			if (!file.external_package) {
+				file.accept (codegen);
+			}
+		}
+
+		// generate C header file for public API
+		if (context.header_filename != null) {
+			var writer = new CCodeWriter (context.header_filename);
+			if (!writer.open (context.version_header)) {
+				Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
+				return;
+			}
+			writer.write_newline ();
+
+			var once = new CCodeOnceSection (get_define_for_filename (writer.filename));
+			once.append (new CCodeNewline ());
+			once.append (header_declarations.include_directives);
+			once.append (new CCodeNewline ());
+
+			once.append (new CCodeNewline ());
+			once.append (header_declarations.type_declaration);
+			once.append (new CCodeNewline ());
+			once.append (header_declarations.type_definition);
+			once.append (new CCodeNewline ());
+			once.append (header_declarations.type_member_declaration);
+			once.append (new CCodeNewline ());
+			once.append (header_declarations.constant_declaration);
+			once.append (new CCodeNewline ());
+
+			once.append (new CCodeNewline ());
+			once.write (writer);
+			writer.close ();
+		}
+
+		// generate C header file for internal API
+		if (context.internal_header_filename != null) {
+			var writer = new CCodeWriter (context.internal_header_filename);
+			if (!writer.open (context.version_header)) {
+				Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
+				return;
+			}
+			writer.write_newline ();
+
+			var once = new CCodeOnceSection (get_define_for_filename (writer.filename));
+			once.append (new CCodeNewline ());
+			once.append (internal_header_declarations.include_directives);
+			once.append (new CCodeNewline ());
+
+			once.append (new CCodeNewline ());
+			once.append (internal_header_declarations.type_declaration);
+			once.append (new CCodeNewline ());
+			once.append (internal_header_declarations.type_definition);
+			once.append (new CCodeNewline ());
+			once.append (internal_header_declarations.type_member_declaration);
+			once.append (new CCodeNewline ());
+			once.append (internal_header_declarations.constant_declaration);
+			once.append (new CCodeNewline ());
+
+			once.append (new CCodeNewline ());
+			once.write (writer);
+			writer.close ();
+		}
+	}
+
+	public override void visit_source_file (SourceFile source_file) {
+		source_declarations = new CCodeDeclarationSpace ();
+		source_type_member_definition = new CCodeFragment ();
+
+		next_temp_var_id = 0;
+		variable_name_map.clear ();
+
+		generated_external_symbols = new HashSet<Symbol> ();
+
+		source_file.accept_children (codegen);
+
+		if (context.report.get_errors () > 0) {
+			return;
+		}
+
+		var writer = new CCodeWriter (source_file.get_csource_filename ());
+		if (!writer.open (context.version_header)) {
+			Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
+			return;
+		}
+		writer.line_directives = context.debug;
+
+		writer.write_newline ();
+		source_declarations.include_directives.write (writer);
+		writer.write_newline ();
+		source_declarations.type_declaration.write_combined (writer);
+		writer.write_newline ();
+		source_declarations.type_definition.write_combined (writer);
+		writer.write_newline ();
+		source_declarations.type_member_declaration.write_declaration (writer);
+		writer.write_newline ();
+		source_declarations.type_member_declaration.write (writer);
+		writer.write_newline ();
+		source_declarations.constant_declaration.write_combined (writer);
+		writer.write_newline ();
+		source_type_member_definition.write (writer);
+		writer.write_newline ();
+		writer.close ();
+
+		source_declarations = null;
+		source_type_member_definition = null;
+	}
+
+	private static string get_define_for_filename (string filename) {
+		var define = new StringBuilder ("__");
+
+		var i = filename;
+		while (i.len () > 0) {
+			var c = i.get_char ();
+			if (c.isalnum  () && c < 0x80) {
+				define.append_unichar (c.toupper ());
+			} else {
+				define.append_c ('_');
+			}
+
+			i = i.next_char ();
+		}
+
+		define.append ("__");
+
+		return define.str;
+	}
+
+	public void generate_enum_declaration (Enum en, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (en, en.get_cname ())) {
+			return;
+		}
+
+		var cenum = new CCodeEnum (en.get_cname ());
+
+		foreach (EnumValue ev in en.get_values ()) {
+			if (ev.value == null) {
+				cenum.add_value (new CCodeEnumValue (ev.get_cname ()));
+			} else {
+				ev.value.accept (codegen);
+				cenum.add_value (new CCodeEnumValue (ev.get_cname (), (CCodeExpression) ev.value.ccodenode));
+			}
+		}
+
+		decl_space.add_type_definition (cenum);
+		decl_space.add_type_definition (new CCodeNewline ());
+	}
+
+	public override void visit_enum (Enum en) {
+		en.accept_children (codegen);
+
+		generate_enum_declaration (en, source_declarations);
+
+		if (!en.is_internal_symbol ()) {
+			generate_enum_declaration (en, header_declarations);
+		}
+		generate_enum_declaration (en, internal_header_declarations);
+	}
+
+	public override void visit_member (Member m) {
+	}
+
+	public void generate_constant_declaration (Constant c, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (c, c.get_cname ())) {
+			return;
+		}
+
+		c.accept_children (codegen);
+
+		if (!c.external) {
+			if (c.initializer is InitializerList) {
+				var cdecl = new CCodeDeclaration (c.type_reference.get_const_cname ());
+				var arr = "";
+				if (c.type_reference is ArrayType) {
+					arr = "[]";
+				}
+				cdecl.add_declarator (new CCodeVariableDeclarator ("%s%s".printf (c.get_cname (), arr), (CCodeExpression) c.initializer.ccodenode));
+				cdecl.modifiers = CCodeModifiers.STATIC;
+
+				decl_space.add_constant_declaration (cdecl);
+			} else {
+				var cdefine = new CCodeMacroReplacement.with_expression (c.get_cname (), (CCodeExpression) c.initializer.ccodenode);
+				decl_space.add_type_member_declaration (cdefine);
+			}
+		}
+	}
+
+	public override void visit_constant (Constant c) {
+		generate_constant_declaration (c, source_declarations);
+
+		if (!c.is_internal_symbol ()) {
+			generate_constant_declaration (c, header_declarations);
+		}
+		generate_constant_declaration (c, internal_header_declarations);
+	}
+
+	public void generate_field_declaration (Field f, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (f, f.get_cname ())) {
+			return;
+		}
+
+		generate_type_declaration (f.field_type, decl_space);
+
+		string field_ctype = f.field_type.get_cname ();
+		if (f.is_volatile) {
+			field_ctype = "volatile " + field_ctype;
+		}
+
+		var cdecl = new CCodeDeclaration (field_ctype);
+		cdecl.add_declarator (new CCodeVariableDeclarator (f.get_cname ()));
+		if (f.is_private_symbol ()) {
+			cdecl.modifiers = CCodeModifiers.STATIC;
+		} else {
+			cdecl.modifiers = CCodeModifiers.EXTERN;
+		}
+		decl_space.add_type_member_declaration (cdecl);
+	}
+
+	public override void visit_field (Field f) {
+		f.accept_children (codegen);
+
+		var cl = f.parent_symbol as Class;
+
+		CCodeExpression lhs = null;
+
+		string field_ctype = f.field_type.get_cname ();
+		if (f.is_volatile) {
+			field_ctype = "volatile " + field_ctype;
+		}
+
+		if (f.binding == MemberBinding.INSTANCE)  {
+			if (cl != null && f.access == SymbolAccessibility.PRIVATE) {
+				var priv_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (cl.get_upper_case_cname (null))));
+				priv_call.add_argument (new CCodeIdentifier ("this"));
+				lhs = new CCodeMemberAccess.pointer (priv_call, f.get_cname ());
+			} else {
+				lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("this"), f.get_cname ());
+			}
+
+			if (f.initializer != null) {
+				var rhs = (CCodeExpression) f.initializer.ccodenode;
+
+				instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, rhs)));
+
+				append_temp_decl (instance_init_fragment, temp_vars);
+				temp_vars.clear ();
+			}
+
+			if (requires_destroy (f.field_type) && instance_finalize_fragment != null) {
+				var this_access = new MemberAccess.simple ("this");
+				this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
+
+				var field_st = f.parent_symbol as Struct;
+				if (field_st != null && !field_st.is_simple_type ()) {
+					this_access.ccodenode = new CCodeIdentifier ("(*this)");
+				} else {
+					this_access.ccodenode = new CCodeIdentifier ("this");
+				}
+
+				var ma = new MemberAccess (this_access, f.name);
+				ma.symbol_reference = f;
+				instance_finalize_fragment.append (new CCodeExpressionStatement (get_unref_expression (lhs, f.field_type, ma)));
+			}
+		} else {
+			generate_field_declaration (f, source_declarations);
+
+			if (!f.is_internal_symbol ()) {
+				generate_field_declaration (f, header_declarations);
+			}
+			generate_field_declaration (f, internal_header_declarations);
+
+			lhs = new CCodeIdentifier (f.get_cname ());
+
+			var var_decl = new CCodeVariableDeclarator (f.get_cname ());
+			var_decl.initializer = default_value_for_type (f.field_type, true);
+
+			if (f.initializer != null) {
+				var init = (CCodeExpression) f.initializer.ccodenode;
+				if (is_constant_ccode_expression (init)) {
+					var_decl.initializer = init;
+				}
+			}
+
+			var var_def = new CCodeDeclaration (field_ctype);
+			var_def.add_declarator (var_decl);
+			if (!f.is_private_symbol ()) {
+				var_def.modifiers = CCodeModifiers.EXTERN;
+			} else {
+				var_def.modifiers = CCodeModifiers.STATIC;
+			}
+			source_declarations.add_type_member_declaration (var_def);
+		}
+	}
+
+	public bool is_constant_ccode_expression (CCodeExpression cexpr) {
+		if (cexpr is CCodeConstant) {
+			return true;
+		} else if (cexpr is CCodeCastExpression) {
+			var ccast = (CCodeCastExpression) cexpr;
+			return is_constant_ccode_expression (ccast.inner);
+		} else if (cexpr is CCodeBinaryExpression) {
+			var cbinary = (CCodeBinaryExpression) cexpr;
+			return is_constant_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
+		}
+
+		var cparenthesized = (cexpr as CCodeParenthesizedExpression);
+		return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
+	}
+
+	/**
+	 * Returns whether the passed cexpr is a pure expression, i.e. an
+	 * expression without side-effects.
+	 */
+	public bool is_pure_ccode_expression (CCodeExpression cexpr) {
+		if (cexpr is CCodeConstant || cexpr is CCodeIdentifier) {
+			return true;
+		} else if (cexpr is CCodeBinaryExpression) {
+			var cbinary = (CCodeBinaryExpression) cexpr;
+			return is_pure_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
+		} else if (cexpr is CCodeUnaryExpression) {
+			var cunary = (CCodeUnaryExpression) cexpr;
+			switch (cunary.operator) {
+			case CCodeUnaryOperator.PREFIX_INCREMENT:
+			case CCodeUnaryOperator.PREFIX_DECREMENT:
+			case CCodeUnaryOperator.POSTFIX_INCREMENT:
+			case CCodeUnaryOperator.POSTFIX_DECREMENT:
+				return false;
+			default:
+				return is_pure_ccode_expression (cunary.inner);
+			}
+		} else if (cexpr is CCodeMemberAccess) {
+			var cma = (CCodeMemberAccess) cexpr;
+			return is_pure_ccode_expression (cma.inner);
+		} else if (cexpr is CCodeElementAccess) {
+			var cea = (CCodeElementAccess) cexpr;
+			return is_pure_ccode_expression (cea.container) && is_pure_ccode_expression (cea.index);
+		} else if (cexpr is CCodeCastExpression) {
+			var ccast = (CCodeCastExpression) cexpr;
+			return is_pure_ccode_expression (ccast.inner);
+		} else if (cexpr is CCodeParenthesizedExpression) {
+			var cparenthesized = (CCodeParenthesizedExpression) cexpr;
+			return is_pure_ccode_expression (cparenthesized.inner);
+		}
+
+		return false;
+	}
+
+	public override void visit_formal_parameter (FormalParameter p) {
+		p.accept_children (codegen);
+	}
+
+	public override void visit_property (Property prop) {
+		int old_next_temp_var_id = next_temp_var_id;
+		var old_temp_vars = temp_vars;
+		var old_temp_ref_vars = temp_ref_vars;
+		var old_variable_name_map = variable_name_map;
+		next_temp_var_id = 0;
+		temp_vars = new ArrayList<LocalVariable> ();
+		temp_ref_vars = new ArrayList<LocalVariable> ();
+		variable_name_map = new HashMap<string,string> (str_hash, str_equal);
+
+		prop.accept_children (codegen);
+
+		next_temp_var_id = old_next_temp_var_id;
+		temp_vars = old_temp_vars;
+		temp_ref_vars = old_temp_ref_vars;
+		variable_name_map = old_variable_name_map;
+	}
+
+	public void generate_type_declaration (DataType type, CCodeDeclarationSpace decl_space) {
+		if (type is ObjectType) {
+			var object_type = (ObjectType) type;
+			if (object_type.type_symbol is Class) {
+				generate_class_declaration ((Class) object_type.type_symbol, decl_space);
+			} else if (object_type.type_symbol is Interface) {
+				generate_interface_declaration ((Interface) object_type.type_symbol, decl_space);
+			}
+		} else if (type is DelegateType) {
+			var deleg_type = (DelegateType) type;
+			var d = deleg_type.delegate_symbol;
+			generate_delegate_declaration (d, decl_space);
+		} else if (type.data_type is Enum) {
+			var en = (Enum) type.data_type;
+			generate_enum_declaration (en, decl_space);
+		} else if (type is ValueType) {
+			var value_type = (ValueType) type;
+			generate_struct_declaration ((Struct) value_type.type_symbol, decl_space);
+		} else if (type is ArrayType) {
+			var array_type = (ArrayType) type;
+			generate_type_declaration (array_type.element_type, decl_space);
+		} else if (type is PointerType) {
+			var pointer_type = (PointerType) type;
+			generate_type_declaration (pointer_type.base_type, decl_space);
+		}
+
+		foreach (DataType type_arg in type.get_type_arguments ()) {
+			generate_type_declaration (type_arg, decl_space);
+		}
+	}
+
+	public virtual void generate_struct_declaration (Struct st, CCodeDeclarationSpace decl_space) {
+	}
+
+	public virtual void generate_delegate_declaration (Delegate d, CCodeDeclarationSpace decl_space) {
+	}
+
+	public virtual void generate_cparameters (Method m, CCodeDeclarationSpace decl_space, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, CCodeFunctionCall? vcall = null) {
+	}
+
+	public virtual void generate_property_accessor_declaration (PropertyAccessor acc, CCodeDeclarationSpace decl_space) {
+	}
+
+	public override void visit_destructor (Destructor d) {
+		bool old_method_inner_error = current_method_inner_error;
+		current_method_inner_error = false;
+
+		d.accept_children (codegen);
+
+		CCodeFragment cfrag = new CCodeFragment ();
+
+		cfrag.append (d.body.ccodenode);
+
+		d.ccodenode = cfrag;
+
+		current_method_inner_error = old_method_inner_error;
+	}
+
+	public override void visit_block (Block b) {
+		var old_symbol = current_symbol;
+		current_symbol = b;
+
+		b.accept_children (codegen);
+
+		var local_vars = b.get_local_variables ();
+		foreach (LocalVariable local in local_vars) {
+			local.active = false;
+		}
+
+		var cblock = new CCodeBlock ();
+
+		foreach (CodeNode stmt in b.get_statements ()) {
+			if (stmt.error) {
+				continue;
+			}
+
+			if (stmt.ccodenode is CCodeFragment) {
+				foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
+					cblock.add_statement (cstmt);
+				}
+			} else {
+				cblock.add_statement (stmt.ccodenode);
+			}
+		}
+
+		foreach (LocalVariable local in local_vars) {
+			if (!local.floating && requires_destroy (local.variable_type)) {
+				var ma = new MemberAccess.simple (local.name);
+				ma.symbol_reference = local;
+				cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
+			}
+		}
+
+		if (b.parent_symbol is Method) {
+			var m = (Method) b.parent_symbol;
+			foreach (FormalParameter param in m.get_parameters ()) {
+				if (requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
+					var ma = new MemberAccess.simple (param.name);
+					ma.symbol_reference = param;
+					cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param.name), param.parameter_type, ma)));
+				}
+			}
+		}
+
+		b.ccodenode = cblock;
+
+		current_symbol = old_symbol;
+	}
+
+	public override void visit_empty_statement (EmptyStatement stmt) {
+		stmt.ccodenode = new CCodeEmptyStatement ();
+	}
+
+	public override void visit_declaration_statement (DeclarationStatement stmt) {
+		stmt.declaration.accept (codegen);
+
+		stmt.ccodenode = stmt.declaration.ccodenode;
+
+		var local = stmt.declaration as LocalVariable;
+		if (local != null && local.initializer != null) {
+			create_temp_decl (stmt, local.initializer.temp_vars);
+		}
+
+		create_temp_decl (stmt, temp_vars);
+		temp_vars.clear ();
+	}
+
+	public CCodeExpression get_variable_cexpression (string name) {
+		return new CCodeIdentifier (get_variable_cname (name));
+	}
+
+	public string get_variable_cname (string name) {
+		if (name[0] == '.') {
+			// compiler-internal variable
+			if (!variable_name_map.contains (name)) {
+				variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
+				next_temp_var_id++;
+			}
+			return variable_name_map.get (name);
+		} else if (reserved_identifiers.contains (name)) {
+			return "_%s_".printf (name);
+		} else {
+			return name;
+		}
+	}
+
+	public override void visit_local_variable (LocalVariable local) {
+		local.accept_children (codegen);
+
+		generate_type_declaration (local.variable_type, source_declarations);
+
+		CCodeExpression rhs = null;
+		if (local.initializer != null && local.initializer.ccodenode != null) {
+			rhs = (CCodeExpression) local.initializer.ccodenode;
+		}
+
+		var cfrag = new CCodeFragment ();
+
+		if (pre_statement_fragment != null) {
+			cfrag.append (pre_statement_fragment);
+			pre_statement_fragment = null;
+		}
+
+		var cvar = new CCodeVariableDeclarator (get_variable_cname (local.name), rhs, local.variable_type.get_cdeclarator_suffix ());
+
+		var cdecl = new CCodeDeclaration (local.variable_type.get_cname ());
+		cdecl.add_declarator (cvar);
+		cfrag.append (cdecl);
+
+		// try to initialize uninitialized variables
+		// initialization not necessary for variables stored in closure
+		if (cvar.initializer == null) {
+			cvar.initializer = default_value_for_type (local.variable_type, true);
+			cvar.init0 = true;
+		}
+
+		if (local.initializer != null && local.initializer.tree_can_fail) {
+			head.add_simple_check (local.initializer, cfrag);
+		}
+
+		local.ccodenode = cfrag;
+
+		local.active = true;
+	}
+
+	public override void visit_initializer_list (InitializerList list) {
+		list.accept_children (codegen);
+
+		if (list.target_type.data_type is Struct) {
+			/* initializer is used as struct initializer */
+			var st = (Struct) list.target_type.data_type;
+
+			var clist = new CCodeInitializerList ();
+
+			var field_it = st.get_fields ().iterator ();
+			foreach (Expression expr in list.get_initializers ()) {
+				Field field = null;
+				while (field == null) {
+					field_it.next ();
+					field = field_it.get ();
+					if (field.binding != MemberBinding.INSTANCE) {
+						// we only initialize instance fields
+						field = null;
+					}
+				}
+
+				var cexpr = (CCodeExpression) expr.ccodenode;
+
+				string ctype = field.get_ctype ();
+				if (ctype != null) {
+					cexpr = new CCodeCastExpression (cexpr, ctype);
+				}
+
+				clist.append (cexpr);
+			}
+
+			list.ccodenode = clist;
+		} else {
+			var clist = new CCodeInitializerList ();
+			foreach (Expression expr in list.get_initializers ()) {
+				clist.append ((CCodeExpression) expr.ccodenode);
+			}
+			list.ccodenode = clist;
+		}
+	}
+
+	public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null) {
+		var var_type = type.copy ();
+		var_type.value_owned = value_owned;
+		var local = new LocalVariable (var_type, "_tmp%d_".printf (next_temp_var_id));
+
+		if (node_reference != null) {
+			local.source_reference = node_reference.source_reference;
+		}
+
+		next_temp_var_id++;
+
+		return local;
+	}
+
+	bool is_in_generic_type (DataType type) {
+		if (type.type_parameter.parent_symbol is TypeSymbol
+		    && (current_method == null || current_method.binding == MemberBinding.INSTANCE)) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	public CCodeExpression get_type_private_from_type (ObjectTypeSymbol type_symbol, CCodeExpression type_expression) {
+		if (type_symbol is Class) {
+			// class
+			return new CCodeCastExpression (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeCastExpression (type_expression, "char *"), new CCodeIdentifier ("_%s_type_offset".printf (((Class) type_symbol).get_lower_case_cname ()))), "%sTypePrivate *".printf (((Class) type_symbol).get_cname ()));
+		} else {
+			// interface
+			var get_interface = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_interface"));
+			get_interface.add_argument (type_expression);
+			get_interface.add_argument (new CCodeIdentifier ("%s_type".printf (((Interface) type_symbol).get_lower_case_cname ())));
+			return new CCodeCastExpression (get_interface, "%sTypePrivate *".printf (((Interface) type_symbol).get_cname ()));
+		}
+	}
+
+	public CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
+		if (type is GenericType) {
+			string var_name = "%s_type".printf (type.type_parameter.name.down ());
+			if (is_in_generic_type (type) && !is_chainup) {
+				return new CCodeMemberAccess.pointer (get_type_private_from_type ((ObjectTypeSymbol) type.type_parameter.parent_symbol, new CCodeMemberAccess.pointer (new CCodeIdentifier ("this"), "type")), var_name);
+			} else {
+				return new CCodeIdentifier (var_name);
+			}
+		} else {
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (type.data_type.get_lower_case_cname ())));
+			var object_type_symbol = type.data_type as ObjectTypeSymbol;
+			if (object_type_symbol != null) {
+				for (int i = 0; i < object_type_symbol.get_type_parameters ().size; i++) {
+					if (type.get_type_arguments ().size == 0) {
+						ccall.add_argument (new CCodeConstant ("NULL"));
+					} else {
+						ccall.add_argument (get_type_id_expression (type.get_type_arguments ().get (i)));
+					}
+				}
+			}
+			return ccall;
+		}
+	}
+
+	public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup = false) {
+		if (type.data_type != null) {
+			string dup_function = "";
+			if (type.data_type.is_reference_counting ()) {
+				dup_function = type.data_type.get_ref_function ();
+			} else if (type is ValueType) {
+				dup_function = type.data_type.get_dup_function ();
+				if (dup_function == null) {
+					dup_function = "";
+				}
+			}
+
+			return new CCodeIdentifier (dup_function);
+		} else if (type.type_parameter != null) {
+			return null;
+		} else if (type is ArrayType) {
+			return new CCodeIdentifier ("dova_object_ref");
+		} else if (type is DelegateType) {
+			return new CCodeIdentifier ("dova_object_ref");
+		} else if (type is PointerType) {
+			var pointer_type = (PointerType) type;
+			return get_dup_func_expression (pointer_type.base_type, source_reference);
+		} else {
+			source_declarations.add_include ("stddef.h");
+			return new CCodeConstant ("NULL");
+		}
+	}
+
+	public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
+		if (type.data_type != null) {
+			string unref_function;
+			if (type is ReferenceType) {
+				if (type.data_type.is_reference_counting ()) {
+					unref_function = type.data_type.get_unref_function ();
+				} else {
+					unref_function = type.data_type.get_free_function ();
+				}
+			} else {
+				if (type.nullable) {
+					unref_function = type.data_type.get_free_function ();
+					if (unref_function == null) {
+						unref_function = "free";
+					}
+				} else {
+					var st = (Struct) type.data_type;
+					unref_function = st.get_copy_function ();
+				}
+			}
+			if (unref_function == null) {
+				source_declarations.add_include ("stddef.h");
+				return new CCodeConstant ("NULL");
+			}
+			return new CCodeIdentifier (unref_function);
+		} else if (type.type_parameter != null && current_type_symbol is Class) {
+			// FIXME ask type for dup/ref function
+			return new CCodeIdentifier ("dova_object_unref");
+		} else if (type is ArrayType) {
+			return new CCodeIdentifier ("dova_object_unref");
+		} else if (type is DelegateType) {
+			return new CCodeIdentifier ("dova_object_unref");
+		} else if (type is PointerType) {
+			return new CCodeIdentifier ("free");
+		} else {
+			source_declarations.add_include ("stddef.h");
+			return new CCodeConstant ("NULL");
+		}
+	}
+
+	public virtual CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression? expr = null) {
+		var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
+
+		if (type is ValueType && !type.nullable) {
+			// normal value type, no null check
+			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
+			ccall.add_argument (new CCodeConstant ("0"));
+			ccall.add_argument (new CCodeConstant ("NULL"));
+			ccall.add_argument (new CCodeConstant ("0"));
+
+			return ccall;
+		}
+
+		/* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
+
+		/* can be simplified to
+		 * foo = (unref (foo), NULL)
+		 * if foo is of static type non-null
+		 */
+
+		source_declarations.add_include ("stddef.h");
+
+		var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
+		if (type.type_parameter != null) {
+			if (!(current_type_symbol is Class) || current_class.is_compact) {
+				return new CCodeConstant ("NULL");
+			}
+
+			// unref functions are optional for type parameters
+			var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
+			cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
+		}
+
+		ccall.add_argument (cvar);
+
+		/* set freed references to NULL to prevent further use */
+		var ccomma = new CCodeCommaExpression ();
+
+		ccomma.append_expression (ccall);
+		ccomma.append_expression (new CCodeConstant ("NULL"));
+
+		var cassign = new CCodeAssignment (cvar, ccomma);
+
+		return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
+	}
+
+	public override void visit_end_full_expression (Expression expr) {
+		/* expr is a full expression, i.e. an initializer, the
+		 * expression in an expression statement, the controlling
+		 * expression in if, while, for, or foreach statements
+		 *
+		 * we unref temporary variables at the end of a full
+		 * expression
+		 */
+
+		/* can't automatically deep copy lists yet, so do it
+		 * manually for now
+		 * replace with
+		 * expr.temp_vars = temp_vars;
+		 * when deep list copying works
+		 */
+		expr.temp_vars.clear ();
+		foreach (LocalVariable local in temp_vars) {
+			expr.temp_vars.add (local);
+		}
+		temp_vars.clear ();
+
+		if (((List<LocalVariable>) temp_ref_vars).size == 0) {
+			/* nothing to do without temporary variables */
+			return;
+		}
+
+		var expr_type = expr.value_type;
+		if (expr.target_type != null) {
+			expr_type = expr.target_type;
+		}
+
+		var full_expr_var = get_temp_variable (expr_type, true, expr);
+		expr.temp_vars.add (full_expr_var);
+
+		var expr_list = new CCodeCommaExpression ();
+		expr_list.append_expression (new CCodeAssignment (get_variable_cexpression (full_expr_var.name), (CCodeExpression) expr.ccodenode));
+
+		foreach (LocalVariable local in temp_ref_vars) {
+			var ma = new MemberAccess.simple (local.name);
+			ma.symbol_reference = local;
+			expr_list.append_expression (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma));
+		}
+
+		expr_list.append_expression (get_variable_cexpression (full_expr_var.name));
+
+		expr.ccodenode = expr_list;
+
+		temp_ref_vars.clear ();
+	}
+
+	public void append_temp_decl (CCodeFragment cfrag, List<LocalVariable> temp_vars) {
+		foreach (LocalVariable local in temp_vars) {
+			var cdecl = new CCodeDeclaration (local.variable_type.get_cname ());
+
+			var vardecl = new CCodeVariableDeclarator (local.name, null, local.variable_type.get_cdeclarator_suffix ());
+			// sets #line
+			local.ccodenode = vardecl;
+			cdecl.add_declarator (vardecl);
+
+			var st = local.variable_type.data_type as Struct;
+			var array_type = local.variable_type as ArrayType;
+
+			if (local.name.has_prefix ("*")) {
+				// do not dereference unintialized variable
+				// initialization is not needed for these special
+				// pointer temp variables
+				// used to avoid side-effects in assignments
+			} else if (local.variable_type is GenericType) {
+				var value_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_value_size"));
+				value_size.add_argument (get_type_id_expression (local.variable_type));
+
+				var alloca_call = new CCodeFunctionCall (new CCodeIdentifier ("alloca"));
+				alloca_call.add_argument (value_size);
+
+				// memset needs string.h
+				source_declarations.add_include ("string.h");
+				var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+				memset_call.add_argument (alloca_call);
+				memset_call.add_argument (new CCodeConstant ("0"));
+				memset_call.add_argument (value_size);
+
+				vardecl.initializer = memset_call;
+				vardecl.init0 = true;
+			} else if (!local.variable_type.nullable &&
+			           (st != null && !st.is_simple_type ()) ||
+			           (array_type != null && array_type.fixed_length)) {
+				// 0-initialize struct with struct initializer { 0 }
+				// necessary as they will be passed by reference
+				var clist = new CCodeInitializerList ();
+				clist.append (new CCodeConstant ("0"));
+
+				vardecl.initializer = clist;
+				vardecl.init0 = true;
+			} else if (local.variable_type.is_reference_type_or_type_parameter () ||
+			       local.variable_type.nullable) {
+				source_declarations.add_include ("stddef.h");
+				vardecl.initializer = new CCodeConstant ("NULL");
+				vardecl.init0 = true;
+			}
+
+			cfrag.append (cdecl);
+		}
+	}
+
+	public override void visit_expression_statement (ExpressionStatement stmt) {
+		stmt.accept_children (codegen);
+
+		if (stmt.expression.error) {
+			stmt.error = true;
+			return;
+		}
+
+		stmt.ccodenode = new CCodeExpressionStatement ((CCodeExpression) stmt.expression.ccodenode);
+
+		if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
+			// simple case, no node breakdown necessary
+
+			var cfrag = new CCodeFragment ();
+
+			cfrag.append (stmt.ccodenode);
+
+			head.add_simple_check (stmt.expression, cfrag);
+
+			stmt.ccodenode = cfrag;
+		}
+
+		/* free temporary objects */
+
+		if (((List<LocalVariable>) temp_vars).size == 0
+		     && pre_statement_fragment == null) {
+			/* nothing to do without temporary variables */
+			return;
+		}
+
+		var cfrag = new CCodeFragment ();
+		append_temp_decl (cfrag, temp_vars);
+
+		if (pre_statement_fragment != null) {
+			cfrag.append (pre_statement_fragment);
+			pre_statement_fragment = null;
+		}
+
+		cfrag.append (stmt.ccodenode);
+
+		foreach (LocalVariable local in temp_ref_vars) {
+			var ma = new MemberAccess.simple (local.name);
+			ma.symbol_reference = local;
+			cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (local.name), local.variable_type, ma)));
+		}
+
+		stmt.ccodenode = cfrag;
+
+		temp_vars.clear ();
+		temp_ref_vars.clear ();
+	}
+
+	public void create_temp_decl (Statement stmt, List<LocalVariable> temp_vars) {
+		/* declare temporary variables */
+
+		if (temp_vars.size == 0) {
+			/* nothing to do without temporary variables */
+			return;
+		}
+
+		var cfrag = new CCodeFragment ();
+		append_temp_decl (cfrag, temp_vars);
+
+		cfrag.append (stmt.ccodenode);
+
+		stmt.ccodenode = cfrag;
+	}
+
+	public virtual void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop = false) {
+		var b = (Block) sym;
+
+		var local_vars = b.get_local_variables ();
+		foreach (LocalVariable local in local_vars) {
+			if (local.active && !local.floating && requires_destroy (local.variable_type)) {
+				var ma = new MemberAccess.simple (local.name);
+				ma.symbol_reference = local;
+				cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
+			}
+		}
+
+		if (stop_at_loop) {
+			if (b.parent_node is Loop ||
+			    b.parent_node is ForeachStatement ||
+			    b.parent_node is SwitchStatement) {
+				return;
+			}
+		}
+
+		if (sym.parent_symbol is Block) {
+			append_local_free (sym.parent_symbol, cfrag, stop_at_loop);
+		} else if (sym.parent_symbol is Method) {
+			append_param_free ((Method) sym.parent_symbol, cfrag);
+		}
+	}
+
+	public void append_error_free (Symbol sym, CCodeFragment cfrag, TryStatement current_try) {
+		var b = (Block) sym;
+
+		var local_vars = b.get_local_variables ();
+		foreach (LocalVariable local in local_vars) {
+			if (local.active && !local.floating && requires_destroy (local.variable_type)) {
+				var ma = new MemberAccess.simple (local.name);
+				ma.symbol_reference = local;
+				cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
+			}
+		}
+
+		if (sym == current_try.body) {
+			return;
+		}
+
+		if (sym.parent_symbol is Block) {
+			append_error_free (sym.parent_symbol, cfrag, current_try);
+		} else if (sym.parent_symbol is Method) {
+			append_param_free ((Method) sym.parent_symbol, cfrag);
+		}
+	}
+
+	private void append_param_free (Method m, CCodeFragment cfrag) {
+		foreach (FormalParameter param in m.get_parameters ()) {
+			if (requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
+				var ma = new MemberAccess.simple (param.name);
+				ma.symbol_reference = param;
+				cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param.name), param.parameter_type, ma)));
+			}
+		}
+	}
+
+	public void create_local_free (CodeNode stmt, bool stop_at_loop = false) {
+		var cfrag = new CCodeFragment ();
+
+		append_local_free (current_symbol, cfrag, stop_at_loop);
+
+		cfrag.append (stmt.ccodenode);
+		stmt.ccodenode = cfrag;
+	}
+
+	public override void visit_return_statement (ReturnStatement stmt) {
+		stmt.accept_children (codegen);
+
+		var cfrag = new CCodeFragment ();
+
+		// free local variables
+		append_local_free (current_symbol, cfrag);
+
+		cfrag.append (new CCodeReturnStatement ((current_return_type is VoidType) ? null : new CCodeIdentifier ("result")));
+
+		stmt.ccodenode = cfrag;
+	}
+
+	public override void visit_delete_statement (DeleteStatement stmt) {
+		stmt.accept_children (codegen);
+
+		var pointer_type = (PointerType) stmt.expression.value_type;
+		DataType type = pointer_type;
+		if (pointer_type.base_type.data_type != null && pointer_type.base_type.data_type.is_reference_type ()) {
+			type = pointer_type.base_type;
+		}
+
+		var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
+		ccall.add_argument ((CCodeExpression) stmt.expression.ccodenode);
+		stmt.ccodenode = new CCodeExpressionStatement (ccall);
+	}
+
+	public override void visit_expression (Expression expr) {
+		if (expr.ccodenode != null && !expr.lvalue) {
+			// memory management, implicit casts, and boxing/unboxing
+			expr.ccodenode = transform_expression ((CCodeExpression) expr.ccodenode, expr.value_type, expr.target_type, expr);
+		}
+	}
+
+	public override void visit_boolean_literal (BooleanLiteral expr) {
+		source_declarations.add_include ("stdbool.h");
+		expr.ccodenode = new CCodeConstant (expr.value ? "true" : "false");
+	}
+
+	public override void visit_character_literal (CharacterLiteral expr) {
+		if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
+			expr.ccodenode = new CCodeConstant (expr.value);
+		} else {
+			expr.ccodenode = new CCodeConstant ("%uU".printf (expr.get_char ()));
+		}
+	}
+
+	public override void visit_integer_literal (IntegerLiteral expr) {
+		expr.ccodenode = new CCodeConstant (expr.value);
+	}
+
+	public override void visit_real_literal (RealLiteral expr) {
+		string c_literal = expr.value;
+		if (c_literal.has_suffix ("d") || c_literal.has_suffix ("D")) {
+			// there is no suffix for double in C
+			c_literal = c_literal.substring (0, c_literal.length - 1);
+		}
+		if (!("." in c_literal || "e" in c_literal || "E" in c_literal)) {
+			// C requires period or exponent part for floating constants
+			if ("f" in c_literal || "F" in c_literal) {
+				c_literal = c_literal.substring (0, c_literal.length - 1) + ".f";
+			} else {
+				c_literal += ".";
+			}
+		}
+		expr.ccodenode = new CCodeConstant (c_literal);
+	}
+
+	public override void visit_string_literal (StringLiteral expr) {
+		var val = new CCodeInitializerList ();
+		val.append (new CCodeConstant ("0"));
+		// FIXME handle escaped characters in scanner/parser and escape them here again for C
+		val.append (new CCodeConstant ((expr.value.size () - 2).to_string ()));
+		val.append (new CCodeConstant (expr.value));
+
+		var cdecl = new CCodeDeclaration ("const string");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_string%d_".printf (next_string_const_id), val));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_constant_declaration (cdecl);
+
+		expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeConstant ("_string%d_".printf (next_string_const_id)));
+
+		next_string_const_id++;
+	}
+
+	public override void visit_null_literal (NullLiteral expr) {
+		source_declarations.add_include ("stddef.h");
+		expr.ccodenode = new CCodeConstant ("NULL");
+	}
+
+	public override void visit_base_access (BaseAccess expr) {
+		generate_type_declaration (expr.value_type, source_declarations);
+		expr.ccodenode = new CCodeCastExpression (new CCodeIdentifier ("this"), expr.value_type.get_cname ());
+	}
+
+	public override void visit_postfix_expression (PostfixExpression expr) {
+		MemberAccess ma = find_property_access (expr.inner);
+		if (ma != null) {
+			// property postfix expression
+			var prop = (Property) ma.symbol_reference;
+
+			var ccomma = new CCodeCommaExpression ();
+
+			// assign current value to temp variable
+			var temp_decl = get_temp_variable (prop.property_type, true, expr);
+			temp_vars.insert (0, temp_decl);
+			ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_decl.name), (CCodeExpression) expr.inner.ccodenode));
+
+			// increment/decrement property
+			var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
+			var cexpr = new CCodeBinaryExpression (op, get_variable_cexpression (temp_decl.name), new CCodeConstant ("1"));
+			var ccall = get_property_set_call (prop, ma, cexpr);
+			ccomma.append_expression (ccall);
+
+			// return previous value
+			ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
+
+			expr.ccodenode = ccomma;
+			return;
+		}
+
+		var op = expr.increment ? CCodeUnaryOperator.POSTFIX_INCREMENT : CCodeUnaryOperator.POSTFIX_DECREMENT;
+
+		expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
+	}
+
+	private MemberAccess? find_property_access (Expression expr) {
+		if (!(expr is MemberAccess)) {
+			return null;
+		}
+
+		var ma = (MemberAccess) expr;
+		if (ma.symbol_reference is Property) {
+			return ma;
+		}
+
+		return null;
+	}
+
+	public bool requires_copy (DataType type) {
+		if (!type.is_disposable ()) {
+			return false;
+		}
+
+		var cl = type.data_type as Class;
+		if (cl != null && cl.is_reference_counting ()
+		    && cl.get_ref_function () == "") {
+			// empty ref_function => no ref necessary
+			return false;
+		}
+
+		if (type.type_parameter != null) {
+			return false;
+		}
+
+		return true;
+	}
+
+	public bool requires_destroy (DataType type) {
+		if (!type.is_disposable ()) {
+			return false;
+		}
+
+		var array_type = type as ArrayType;
+		if (array_type != null && array_type.fixed_length) {
+			return requires_destroy (array_type.element_type);
+		}
+
+		var cl = type.data_type as Class;
+		if (cl != null && cl.is_reference_counting ()
+		    && cl.get_unref_function () == "") {
+			// empty unref_function => no unref necessary
+			return false;
+		}
+
+		if (type.type_parameter != null) {
+			return false;
+		}
+
+		return true;
+	}
+
+	bool is_ref_function_void (DataType type) {
+		var cl = type.data_type as Class;
+		if (cl != null && cl.ref_function_void) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	public virtual CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
+		if (expression_type is ValueType && !expression_type.nullable) {
+			// normal value type, no null check
+			// (copy (&temp, 0, &expr, 0), temp)
+
+			var decl = get_temp_variable (expression_type, false, node);
+			temp_vars.insert (0, decl);
+
+			var ctemp = get_variable_cexpression (decl.name);
+
+			var vt = (ValueType) expression_type;
+			var st = (Struct) vt.type_symbol;
+			var copy_call = new CCodeFunctionCall (new CCodeIdentifier (st.get_copy_function ()));
+			copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
+			copy_call.add_argument (new CCodeConstant ("0"));
+			copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
+			copy_call.add_argument (new CCodeConstant ("0"));
+
+			var ccomma = new CCodeCommaExpression ();
+
+			ccomma.append_expression (copy_call);
+			ccomma.append_expression (ctemp);
+
+			return ccomma;
+		}
+
+		/* (temp = expr, temp == NULL ? NULL : ref (temp))
+		 *
+		 * can be simplified to
+		 * ref (expr)
+		 * if static type of expr is non-null
+		 */
+
+		var dupexpr = get_dup_func_expression (expression_type, node.source_reference);
+
+		if (dupexpr == null) {
+			node.error = true;
+			return null;
+		}
+
+		var ccall = new CCodeFunctionCall (dupexpr);
+
+		if (expr != null && expr.is_non_null ()
+		    && !is_ref_function_void (expression_type)) {
+			// expression is non-null
+			ccall.add_argument ((CCodeExpression) expr.ccodenode);
+
+			return ccall;
+		} else {
+			var decl = get_temp_variable (expression_type, false, node);
+			temp_vars.insert (0, decl);
+
+			var ctemp = get_variable_cexpression (decl.name);
+
+			source_declarations.add_include ("stddef.h");
+			var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL"));
+			if (expression_type.type_parameter != null) {
+				// dup functions are optional for type parameters
+				var cdupisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_dup_func_expression (expression_type, node.source_reference), new CCodeConstant ("NULL"));
+				cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cdupisnull);
+			}
+
+			ccall.add_argument (ctemp);
+
+			var ccomma = new CCodeCommaExpression ();
+			ccomma.append_expression (new CCodeAssignment (ctemp, cexpr));
+
+			var cifnull = new CCodeConstant ("NULL");
+			ccomma.append_expression (new CCodeConditionalExpression (cisnull, cifnull, ccall));
+
+			// repeat temp variable at the end of the comma expression
+			// if the ref function returns void
+			if (is_ref_function_void (expression_type)) {
+				ccomma.append_expression (ctemp);
+			}
+
+			return ccomma;
+		}
+	}
+
+	public virtual void generate_class_declaration (Class cl, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (cl, cl.get_cname ())) {
+			return;
+		}
+	}
+
+	public virtual void generate_interface_declaration (Interface iface, CCodeDeclarationSpace decl_space) {
+	}
+
+	public virtual void generate_method_declaration (Method m, CCodeDeclarationSpace decl_space) {
+	}
+
+	public void add_generic_type_arguments (CCodeFunctionCall ccall, List<DataType> type_args, CodeNode expr, bool is_chainup = false) {
+		foreach (var type_arg in type_args) {
+			if (type_arg is GenericType) {
+				var generic_type = (GenericType) type_arg;
+				string var_name = "%s_type".printf (generic_type.type_parameter.name.down ());
+				if (is_in_generic_type (type_arg) && !is_chainup) {
+					ccall.add_argument (new CCodeMemberAccess.pointer (get_type_private_from_type ((ObjectTypeSymbol) generic_type.type_parameter.parent_symbol, new CCodeMemberAccess.pointer (new CCodeIdentifier ("this"), "type")), var_name));
+				} else {
+					ccall.add_argument (new CCodeIdentifier (var_name));
+				}
+			} else {
+				ccall.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (type_arg.data_type.get_lower_case_cname ()))));
+			}
+		}
+	}
+
+	public override void visit_object_creation_expression (ObjectCreationExpression expr) {
+		expr.accept_children (codegen);
+
+		CCodeExpression instance = null;
+		CCodeExpression creation_expr = null;
+
+		var st = expr.type_reference.data_type as Struct;
+
+		bool struct_by_ref = false;
+		if (st != null && !st.is_boolean_type () && !st.is_integer_type () && !st.is_floating_type ()) {
+			struct_by_ref = true;
+		}
+
+		if (struct_by_ref || expr.get_object_initializer ().size > 0) {
+			// value-type initialization or object creation expression with object initializer
+			var temp_decl = get_temp_variable (expr.type_reference, false, expr);
+			temp_vars.add (temp_decl);
+
+			instance = get_variable_cexpression (get_variable_cname (temp_decl.name));
+		}
+
+		if (expr.symbol_reference == null) {
+			// no creation method
+			if (expr.type_reference.data_type is Struct) {
+				// memset needs string.h
+				source_declarations.add_include ("string.h");
+				var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+				creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
+				creation_call.add_argument (new CCodeConstant ("0"));
+				creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (expr.type_reference.get_cname ())));
+
+				creation_expr = creation_call;
+			}
+		} else if (expr.symbol_reference is Method) {
+			// use creation method
+			var m = (Method) expr.symbol_reference;
+			var params = m.get_parameters ();
+			CCodeFunctionCall creation_call;
+
+			generate_method_declaration (m, source_declarations);
+
+			var cl = expr.type_reference.data_type as Class;
+
+			if (!m.has_new_function) {
+				// use construct function directly
+				creation_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
+				creation_call.add_argument (new CCodeIdentifier (cl.get_type_id ()));
+			} else {
+				creation_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
+			}
+
+			if (struct_by_ref && !(m.cinstance_parameter_position < 0)) {
+				creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
+			}
+
+			generate_type_declaration (expr.type_reference, source_declarations);
+
+			if (cl != null && !cl.is_compact) {
+				add_generic_type_arguments (creation_call, expr.type_reference.get_type_arguments (), expr);
+			}
+
+			bool ellipsis = false;
+
+			int i = 1;
+			Iterator<FormalParameter> params_it = params.iterator ();
+			foreach (Expression arg in expr.get_argument_list ()) {
+				CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
+				FormalParameter param = null;
+				if (params_it.next ()) {
+					param = params_it.get ();
+					ellipsis = param.ellipsis;
+					if (!ellipsis) {
+						cexpr = handle_struct_argument (param, arg, cexpr);
+					}
+				}
+
+				creation_call.add_argument (cexpr);
+
+				i++;
+			}
+			while (params_it.next ()) {
+				var param = params_it.get ();
+
+				if (param.ellipsis) {
+					ellipsis = true;
+					break;
+				}
+
+				if (param.default_expression == null) {
+					Report.error (expr.source_reference, "no default expression for argument %d".printf (i));
+					return;
+				}
+
+				/* evaluate default expression here as the code
+				 * generator might not have visited the formal
+				 * parameter yet */
+				param.default_expression.accept (codegen);
+
+				creation_call.add_argument ((CCodeExpression) param.default_expression.ccodenode);
+				i++;
+			}
+
+			if (struct_by_ref && m.cinstance_parameter_position < 0) {
+				// instance parameter is at the end in a struct creation method
+				creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
+			}
+
+			if (expr.tree_can_fail) {
+				// method can fail
+				current_method_inner_error = true;
+				creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_inner_error_")));
+			}
+
+			if (ellipsis) {
+				/* ensure variable argument list ends with NULL
+				 * except when using printf-style arguments */
+				if (!m.printf_format && !m.scanf_format && m.sentinel != "") {
+					creation_call.add_argument (new CCodeConstant (m.sentinel));
+				}
+			}
+
+			creation_expr = creation_call;
+
+			// cast the return value of the creation method back to the intended type if
+			// it requested a special C return type
+			if (head.get_custom_creturn_type (m) != null) {
+				creation_expr = new CCodeCastExpression (creation_expr, expr.type_reference.get_cname ());
+			}
+		} else {
+			assert (false);
+		}
+
+		if (instance != null) {
+			var ccomma = new CCodeCommaExpression ();
+
+			if (expr.type_reference.data_type is Struct) {
+				ccomma.append_expression (creation_expr);
+			} else {
+				ccomma.append_expression (new CCodeAssignment (instance, creation_expr));
+			}
+
+			foreach (MemberInitializer init in expr.get_object_initializer ()) {
+				if (init.symbol_reference is Field) {
+					var f = (Field) init.symbol_reference;
+					var instance_target_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
+					var typed_inst = transform_expression (instance, expr.type_reference, instance_target_type);
+					CCodeExpression lhs;
+					if (expr.type_reference.data_type is Struct) {
+						lhs = new CCodeMemberAccess (typed_inst, f.get_cname ());
+					} else {
+						lhs = new CCodeMemberAccess.pointer (typed_inst, f.get_cname ());
+					}
+					ccomma.append_expression (new CCodeAssignment (lhs, (CCodeExpression) init.initializer.ccodenode));
+				} else if (init.symbol_reference is Property) {
+					var inst_ma = new MemberAccess.simple ("new");
+					inst_ma.value_type = expr.type_reference;
+					inst_ma.ccodenode = instance;
+					var ma = new MemberAccess (inst_ma, init.name);
+					ccomma.append_expression (get_property_set_call ((Property) init.symbol_reference, ma, (CCodeExpression) init.initializer.ccodenode));
+				}
+			}
+
+			ccomma.append_expression (instance);
+
+			expr.ccodenode = ccomma;
+		} else if (creation_expr != null) {
+			expr.ccodenode = creation_expr;
+		}
+	}
+
+	public CCodeExpression? handle_struct_argument (FormalParameter param, Expression arg, CCodeExpression? cexpr) {
+		if (arg.formal_target_type is GenericType && !(arg.target_type is GenericType)) {
+			// we already use a reference for arguments of ref and out parameters
+			if (param.direction == ParameterDirection.IN) {
+				var unary = cexpr as CCodeUnaryExpression;
+				if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
+					// *expr => expr
+					return unary.inner;
+				} else if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
+					return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
+				} else {
+					// if cexpr is e.g. a function call, we can't take the address of the expression
+					// (tmp = expr, &tmp)
+					var ccomma = new CCodeCommaExpression ();
+
+					var temp_var = get_temp_variable (arg.target_type);
+					temp_vars.insert (0, temp_var);
+					ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), cexpr));
+					ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_var.name)));
+
+					return ccomma;
+				}
+			}
+		}
+
+		return cexpr;
+	}
+
+	public override void visit_sizeof_expression (SizeofExpression expr) {
+		var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+		csizeof.add_argument (new CCodeIdentifier (expr.type_reference.get_cname ()));
+		expr.ccodenode = csizeof;
+	}
+
+	public override void visit_typeof_expression (TypeofExpression expr) {
+		expr.ccodenode = get_type_id_expression (expr.type_reference);
+	}
+
+	public override void visit_unary_expression (UnaryExpression expr) {
+		expr.accept_children (codegen);
+
+		CCodeUnaryOperator op;
+		if (expr.operator == UnaryOperator.PLUS) {
+			op = CCodeUnaryOperator.PLUS;
+		} else if (expr.operator == UnaryOperator.MINUS) {
+			op = CCodeUnaryOperator.MINUS;
+		} else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
+			op = CCodeUnaryOperator.LOGICAL_NEGATION;
+		} else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
+			op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
+		} else if (expr.operator == UnaryOperator.INCREMENT) {
+			op = CCodeUnaryOperator.PREFIX_INCREMENT;
+		} else if (expr.operator == UnaryOperator.DECREMENT) {
+			op = CCodeUnaryOperator.PREFIX_DECREMENT;
+		} else if (expr.operator == UnaryOperator.REF) {
+			op = CCodeUnaryOperator.ADDRESS_OF;
+		} else if (expr.operator == UnaryOperator.OUT) {
+			op = CCodeUnaryOperator.ADDRESS_OF;
+		} else {
+			assert_not_reached ();
+		}
+		expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
+	}
+
+	public override void visit_cast_expression (CastExpression expr) {
+		if (expr.is_silent_cast) {
+			expr.error = true;
+			Report.error (expr.source_reference, "Operation not supported for this type");
+			return;
+		}
+
+		generate_type_declaration (expr.type_reference, source_declarations);
+
+		if (expr.inner.value_type is GenericType && !(expr.type_reference is GenericType)) {
+			// generic types use an extra pointer, dereference that pointer
+			expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeCastExpression ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.get_cname () + "*"));
+		} else {
+			expr.ccodenode = new CCodeCastExpression ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.get_cname ());
+		}
+	}
+
+	public override void visit_pointer_indirection (PointerIndirection expr) {
+		expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, (CCodeExpression) expr.inner.ccodenode);
+	}
+
+	public override void visit_addressof_expression (AddressofExpression expr) {
+		expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, (CCodeExpression) expr.inner.ccodenode);
+	}
+
+	public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
+		expr.accept_children (codegen);
+
+		/* (tmp = var, var = null, tmp) */
+		var ccomma = new CCodeCommaExpression ();
+		var temp_decl = get_temp_variable (expr.value_type, true, expr);
+		temp_vars.insert (0, temp_decl);
+		var cvar = get_variable_cexpression (temp_decl.name);
+
+		ccomma.append_expression (new CCodeAssignment (cvar, (CCodeExpression) expr.inner.ccodenode));
+		ccomma.append_expression (new CCodeAssignment ((CCodeExpression) expr.inner.ccodenode, new CCodeConstant ("NULL")));
+		ccomma.append_expression (cvar);
+		expr.ccodenode = ccomma;
+	}
+
+	public override void visit_binary_expression (BinaryExpression expr) {
+		expr.accept_children (codegen);
+
+		var cleft = (CCodeExpression) expr.left.ccodenode;
+		var cright = (CCodeExpression) expr.right.ccodenode;
+
+		CCodeBinaryOperator op;
+		if (expr.operator == BinaryOperator.PLUS) {
+			op = CCodeBinaryOperator.PLUS;
+		} else if (expr.operator == BinaryOperator.MINUS) {
+			op = CCodeBinaryOperator.MINUS;
+		} else if (expr.operator == BinaryOperator.MUL) {
+			op = CCodeBinaryOperator.MUL;
+		} else if (expr.operator == BinaryOperator.DIV) {
+			op = CCodeBinaryOperator.DIV;
+		} else if (expr.operator == BinaryOperator.MOD) {
+			op = CCodeBinaryOperator.MOD;
+		} else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
+			op = CCodeBinaryOperator.SHIFT_LEFT;
+		} else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
+			op = CCodeBinaryOperator.SHIFT_RIGHT;
+		} else if (expr.operator == BinaryOperator.LESS_THAN) {
+			op = CCodeBinaryOperator.LESS_THAN;
+		} else if (expr.operator == BinaryOperator.GREATER_THAN) {
+			op = CCodeBinaryOperator.GREATER_THAN;
+		} else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
+			op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
+		} else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
+			op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
+		} else if (expr.operator == BinaryOperator.EQUALITY) {
+			op = CCodeBinaryOperator.EQUALITY;
+		} else if (expr.operator == BinaryOperator.INEQUALITY) {
+			op = CCodeBinaryOperator.INEQUALITY;
+		} else if (expr.operator == BinaryOperator.BITWISE_AND) {
+			op = CCodeBinaryOperator.BITWISE_AND;
+		} else if (expr.operator == BinaryOperator.BITWISE_OR) {
+			op = CCodeBinaryOperator.BITWISE_OR;
+		} else if (expr.operator == BinaryOperator.BITWISE_XOR) {
+			op = CCodeBinaryOperator.BITWISE_XOR;
+		} else if (expr.operator == BinaryOperator.AND) {
+			op = CCodeBinaryOperator.AND;
+		} else if (expr.operator == BinaryOperator.OR) {
+			op = CCodeBinaryOperator.OR;
+		} else if (expr.operator == BinaryOperator.IN) {
+			expr.ccodenode = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft);
+			return;
+		} else {
+			assert_not_reached ();
+		}
+
+		if (expr.operator == BinaryOperator.EQUALITY ||
+		    expr.operator == BinaryOperator.INEQUALITY) {
+			var left_type_as_struct = expr.left.value_type.data_type as Struct;
+			var right_type_as_struct = expr.right.value_type.data_type as Struct;
+
+			if (expr.left.value_type.data_type is Class && !((Class) expr.left.value_type.data_type).is_compact &&
+			    expr.right.value_type.data_type is Class && !((Class) expr.right.value_type.data_type).is_compact) {
+				var left_cl = (Class) expr.left.value_type.data_type;
+				var right_cl = (Class) expr.right.value_type.data_type;
+
+				if (left_cl != right_cl) {
+					if (left_cl.is_subtype_of (right_cl)) {
+						cleft = generate_instance_cast (cleft, right_cl);
+					} else if (right_cl.is_subtype_of (left_cl)) {
+						cright = generate_instance_cast (cright, left_cl);
+					}
+				}
+			} else if (left_type_as_struct != null && right_type_as_struct != null) {
+				// FIXME generate and use compare/equal function for real structs
+				if (expr.left.value_type.nullable && expr.right.value_type.nullable) {
+					// FIXME also compare contents, not just address
+				} else if (expr.left.value_type.nullable) {
+					// FIXME check left value is not null
+					cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
+				} else if (expr.right.value_type.nullable) {
+					// FIXME check right value is not null
+					cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
+				}
+			}
+		}
+
+		expr.ccodenode = new CCodeBinaryExpression (op, cleft, cright);
+	}
+
+	public string? get_type_check_function (TypeSymbol type) {
+		var cl = type as Class;
+		if (cl != null && cl.type_check_function != null) {
+			return cl.type_check_function;
+		} else if ((cl != null && cl.is_compact) || type is Struct || type is Enum || type is Delegate) {
+			return null;
+		} else {
+			return type.get_upper_case_cname ("IS_");
+		}
+	}
+
+	CCodeExpression? create_type_check (CCodeNode ccodenode, DataType type) {
+		string type_check_func = get_type_check_function (type.data_type);
+		if (type_check_func == null) {
+			return new CCodeInvalidExpression ();
+		}
+		var ccheck = new CCodeFunctionCall (new CCodeIdentifier (type_check_func));
+		ccheck.add_argument ((CCodeExpression) ccodenode);
+		return ccheck;
+	}
+
+	public override void visit_type_check (TypeCheck expr) {
+		generate_type_declaration (expr.type_reference, source_declarations);
+
+		expr.ccodenode = create_type_check (expr.expression.ccodenode, expr.type_reference);
+		if (expr.ccodenode is CCodeInvalidExpression) {
+			Report.error (expr.source_reference, "type check expressions not supported for compact classes, structs, and enums");
+		}
+	}
+
+	public override void visit_lambda_expression (LambdaExpression l) {
+		// use instance position from delegate
+		var dt = (DelegateType) l.target_type;
+		l.method.cinstance_parameter_position = dt.delegate_symbol.cinstance_parameter_position;
+
+		var old_temp_vars = temp_vars;
+		var old_temp_ref_vars = temp_ref_vars;
+		temp_vars = new ArrayList<LocalVariable> ();
+		temp_ref_vars = new ArrayList<LocalVariable> ();
+
+		l.accept_children (codegen);
+
+		temp_vars = old_temp_vars;
+		temp_ref_vars = old_temp_ref_vars;
+
+		l.ccodenode = new CCodeIdentifier (l.method.get_cname ());
+	}
+
+	// manage memory and implicit casts
+	public CCodeExpression transform_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
+		var cexpr = source_cexpr;
+		if (expression_type == null) {
+			return cexpr;
+		}
+
+
+		if (expression_type.value_owned
+		    && (target_type == null || !target_type.value_owned)) {
+			// value leaked, destroy it
+			var pointer_type = target_type as PointerType;
+			if (pointer_type != null && !(pointer_type.base_type is VoidType)) {
+				// manual memory management for non-void pointers
+				// treat void* special to not leak memory with void* method parameters
+			} else if (requires_destroy (expression_type)) {
+				var decl = get_temp_variable (expression_type, true, expression_type);
+				temp_vars.insert (0, decl);
+				temp_ref_vars.insert (0, decl);
+				cexpr = new CCodeAssignment (get_variable_cexpression (decl.name), cexpr);
+			}
+		}
+
+		if (target_type == null) {
+			// value will be destroyed, no need for implicit casts
+			return cexpr;
+		}
+
+		cexpr = get_implicit_cast_expression (cexpr, expression_type, target_type, expr);
+
+		if (target_type.value_owned && !expression_type.value_owned) {
+			// need to copy value
+			if (requires_copy (target_type) && !(expression_type is NullType)) {
+				CodeNode node = expr;
+				if (node == null) {
+					node = expression_type;
+				}
+				cexpr = get_ref_cexpression (target_type, cexpr, expr, node);
+			}
+		}
+
+		return cexpr;
+	}
+
+	public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
+		var cexpr = source_cexpr;
+
+		if (expression_type.data_type != null && expression_type.data_type == target_type.data_type) {
+			// same type, no cast required
+			return cexpr;
+		}
+
+		if (expression_type is NullType) {
+			// null literal, no cast required when not converting to generic type pointer
+			return cexpr;
+		}
+
+		generate_type_declaration (target_type, source_declarations);
+
+		if (target_type is DelegateType && expression_type is MethodType) {
+			var deleg_type = (DelegateType) target_type;
+			var method_type = (MethodType) expression_type;
+			CCodeExpression delegate_target = new CCodeConstant ("NULL");
+			if (method_type.method_symbol.binding == MemberBinding.INSTANCE) {
+				var ma = (MemberAccess) expr;
+				delegate_target = (CCodeExpression) get_ccodenode (ma.inner);
+			}
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_new".printf (deleg_type.delegate_symbol.get_lower_case_cname ())));
+			ccall.add_argument (delegate_target);
+			ccall.add_argument (source_cexpr);
+			return ccall;
+		}
+
+		var cl = target_type.data_type as Class;
+		var iface = target_type.data_type as Interface;
+		if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
+			// checked cast for strict subtypes of GTypeInstance
+			return generate_instance_cast (cexpr, target_type.data_type);
+		} else if (target_type.data_type != null && expression_type.get_cname () != target_type.get_cname ()) {
+			var st = target_type.data_type as Struct;
+			if (target_type.data_type.is_reference_type () || (st != null && st.is_simple_type ())) {
+				// don't cast non-simple structs
+				return new CCodeCastExpression (cexpr, target_type.get_cname ());
+			} else {
+				return cexpr;
+			}
+		} else {
+			return cexpr;
+		}
+	}
+
+	public CCodeFunctionCall get_property_set_call (Property prop, MemberAccess ma, CCodeExpression cexpr, Expression? rhs = null) {
+		string set_func;
+
+		var base_property = prop;
+		if (prop.base_property != null) {
+			base_property = prop.base_property;
+		} else if (prop.base_interface_property != null) {
+			base_property = prop.base_interface_property;
+		}
+
+		if (prop is DynamicProperty) {
+			set_func = head.get_dynamic_property_setter_cname ((DynamicProperty) prop);
+		} else {
+			generate_property_accessor_declaration (base_property.set_accessor, source_declarations);
+			set_func = base_property.set_accessor.get_cname ();
+		}
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
+
+		if (prop.binding == MemberBinding.INSTANCE) {
+			/* target instance is first argument */
+			ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
+		}
+
+		ccall.add_argument (cexpr);
+
+		return ccall;
+	}
+
+	public bool add_generated_external_symbol (Symbol external_symbol) {
+		return generated_external_symbols.add (external_symbol);
+	}
+
+	public static DataType get_data_type_for_symbol (TypeSymbol sym) {
+		DataType type = null;
+
+		if (sym is Class) {
+			type = new ObjectType ((Class) sym);
+		} else if (sym is Interface) {
+			type = new ObjectType ((Interface) sym);
+		} else if (sym is Struct) {
+			var st = (Struct) sym;
+			if (st.is_boolean_type ()) {
+				type = new BooleanType (st);
+			} else if (st.is_integer_type ()) {
+				type = new IntegerType (st);
+			} else if (st.is_floating_type ()) {
+				type = new FloatingType (st);
+			} else {
+				type = new StructValueType (st);
+			}
+		} else if (sym is Enum) {
+			type = new EnumValueType ((Enum) sym);
+		} else if (sym is ErrorDomain) {
+			type = new ErrorType ((ErrorDomain) sym, null);
+		} else if (sym is ErrorCode) {
+			type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
+		} else {
+			Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
+			return new InvalidType ();
+		}
+
+		return type;
+	}
+
+	public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) {
+		source_declarations.add_include ("stddef.h");
+
+		var st = type.data_type as Struct;
+		var array_type = type as ArrayType;
+		if (type is GenericType) {
+			var value_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_value_size"));
+			value_size.add_argument (get_type_id_expression (type));
+
+			var alloca_call = new CCodeFunctionCall (new CCodeIdentifier ("alloca"));
+			alloca_call.add_argument (value_size);
+
+			// memset needs string.h
+			source_declarations.add_include ("string.h");
+			var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+			memset_call.add_argument (alloca_call);
+			memset_call.add_argument (new CCodeConstant ("0"));
+			memset_call.add_argument (value_size);
+
+			return memset_call;
+		} else if (initializer_expression && !type.nullable &&
+		    ((st != null && !st.is_simple_type ()) ||
+		     (array_type != null && array_type.fixed_length))) {
+			// 0-initialize struct with struct initializer { 0 }
+			// only allowed as initializer expression in C
+			var clist = new CCodeInitializerList ();
+			clist.append (new CCodeConstant ("0"));
+			return clist;
+		} else if ((type.data_type != null && type.data_type.is_reference_type ())
+		           || type.nullable
+		           || type is PointerType || type is DelegateType
+		           || (array_type != null && !array_type.fixed_length)) {
+			return new CCodeConstant ("NULL");
+		} else if (type.data_type != null && type.data_type.get_default_value () != null) {
+			return new CCodeConstant (type.data_type.get_default_value ());
+		}
+		return null;
+	}
+
+	public CCodeNode? get_ccodenode (CodeNode node) {
+		if (node.ccodenode == null) {
+			node.accept (codegen);
+		}
+		return node.ccodenode;
+	}
+
+	public override void visit_class (Class cl) {
+	}
+
+	public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
+		var result = new CCodeFunctionCall (new CCodeIdentifier (type.get_upper_case_cname (null)));
+		result.add_argument (expr);
+		return result;
+	}
+}
diff --git a/codegen/valadovacontrolflowmodule.vala b/codegen/valadovacontrolflowmodule.vala
new file mode 100644
index 0000000..6616dcc
--- /dev/null
+++ b/codegen/valadovacontrolflowmodule.vala
@@ -0,0 +1,98 @@
+/* valadovacontrolflowmodule.vala
+ *
+ * Copyright (C) 2006-2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+internal class Vala.DovaControlFlowModule : DovaMethodModule {
+	public DovaControlFlowModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public override void visit_if_statement (IfStatement stmt) {
+		stmt.accept_children (codegen);
+
+		if (stmt.false_statement != null) {
+			stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode);
+		} else {
+			stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode);
+		}
+
+		create_temp_decl (stmt, stmt.condition.temp_vars);
+	}
+
+	public override void visit_switch_statement (SwitchStatement stmt) {
+		stmt.accept_children (codegen);
+
+		var cswitch = new CCodeSwitchStatement ((CCodeExpression) stmt.expression.ccodenode);
+		stmt.ccodenode = cswitch;
+
+		foreach (SwitchSection section in stmt.get_sections ()) {
+			if (section.has_default_label ()) {
+				cswitch.add_statement (new CCodeLabel ("default"));
+				var cdefaultblock = new CCodeBlock ();
+				cswitch.add_statement (cdefaultblock);
+				foreach (CodeNode default_stmt in section.get_statements ()) {
+					cdefaultblock.add_statement (default_stmt.ccodenode);
+				}
+				continue;
+			}
+
+			foreach (SwitchLabel label in section.get_labels ()) {
+				cswitch.add_statement (new CCodeCaseStatement ((CCodeExpression) label.expression.ccodenode));
+			}
+
+			var cblock = new CCodeBlock ();
+			cswitch.add_statement (cblock);
+			foreach (CodeNode body_stmt in section.get_statements ()) {
+				cblock.add_statement (body_stmt.ccodenode);
+			}
+		}
+
+		create_temp_decl (stmt, stmt.expression.temp_vars);
+	}
+
+	public override void visit_switch_section (SwitchSection section) {
+		visit_block (section);
+	}
+
+	public override void visit_switch_label (SwitchLabel label) {
+		label.accept_children (codegen);
+	}
+
+	public override void visit_loop (Loop stmt) {
+		stmt.accept_children (codegen);
+
+		source_declarations.add_include ("stdbool.h");
+		stmt.ccodenode = new CCodeWhileStatement (new CCodeConstant ("true"), (CCodeStatement) stmt.body.ccodenode);
+	}
+
+	public override void visit_break_statement (BreakStatement stmt) {
+		stmt.ccodenode = new CCodeBreakStatement ();
+
+		create_local_free (stmt, true);
+	}
+
+	public override void visit_continue_statement (ContinueStatement stmt) {
+		stmt.ccodenode = new CCodeContinueStatement ();
+
+		create_local_free (stmt, true);
+	}
+}
+
diff --git a/codegen/valadovadelegatemodule.vala b/codegen/valadovadelegatemodule.vala
new file mode 100644
index 0000000..c82f4c5
--- /dev/null
+++ b/codegen/valadovadelegatemodule.vala
@@ -0,0 +1,210 @@
+/* valadovadelegatemodule.vala
+ *
+ * Copyright (C) 2006-2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ *	Raffaele Sandrini <raffaele sandrini ch>
+ */
+
+/**
+ * The link between a delegate and generated code.
+ */
+internal class Vala.DovaDelegateModule : DovaValueModule {
+	public DovaDelegateModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public override void generate_delegate_declaration (Delegate d, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (d, d.get_cname ())) {
+			return;
+		}
+
+		decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (d.get_cname ()), new CCodeVariableDeclarator (d.get_cname ())));
+
+		generate_class_declaration (type_class, decl_space);
+		generate_method_declaration ((Method) object_class.scope.lookup ("ref"), decl_space);
+		generate_method_declaration ((Method) object_class.scope.lookup ("unref"), decl_space);
+
+		var type_fun = new CCodeFunction ("%s_type_get".printf (d.get_lower_case_cname ()), "DovaType *");
+		decl_space.add_type_member_declaration (type_fun);
+
+		var type_init_fun = new CCodeFunction ("%s_type_init".printf (d.get_lower_case_cname ()));
+		type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		decl_space.add_type_member_declaration (type_init_fun);
+
+		generate_type_declaration (d.return_type, decl_space);
+
+		var function = generate_new_function (d, decl_space);
+		function.block = null;
+		decl_space.add_type_member_declaration (function);
+
+		function = generate_invoke_function (d, decl_space);
+		function.block = null;
+		decl_space.add_type_member_declaration (function);
+	}
+
+	CCodeFunction generate_new_function (Delegate d, CCodeDeclarationSpace decl_space) {
+		var function = new CCodeFunction ("%s_new".printf (d.get_lower_case_cname ()), "%s*".printf (d.get_cname ()));
+		if (d.is_private_symbol ()) {
+			function.modifiers |= CCodeModifiers.STATIC;
+		}
+
+		function.add_parameter (new CCodeFormalParameter ("target", "DovaObject *"));
+		function.add_parameter (new CCodeFormalParameter ("(*method) (void)", "void"));
+
+		function.block = new CCodeBlock ();
+
+		var alloc_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_alloc"));
+		alloc_call.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (d.get_lower_case_cname ()))));
+
+		var cdecl = new CCodeDeclaration ("%s*".printf (d.get_cname ()));
+		cdecl.add_declarator (new CCodeVariableDeclarator ("this", alloc_call));
+		function.block.add_statement (cdecl);
+
+		var init_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_delegate_init"));
+		init_call.add_argument (new CCodeIdentifier ("this"));
+		init_call.add_argument (new CCodeIdentifier ("target"));
+		function.block.add_statement (new CCodeExpressionStatement (init_call));
+
+		var priv = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (d.get_upper_case_cname ())));
+		priv.add_argument (new CCodeIdentifier ("this"));
+		var assignment = new CCodeAssignment (new CCodeMemberAccess.pointer (priv, "method"), new CCodeIdentifier ("method"));
+		function.block.add_statement (new CCodeExpressionStatement (assignment));
+
+		function.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("this")));
+
+		return function;
+	}
+
+	CCodeFunction generate_invoke_function (Delegate d, CCodeDeclarationSpace decl_space) {
+		var function = new CCodeFunction ("%s_invoke".printf (d.get_lower_case_cname ()), d.return_type.get_cname ());
+
+		if (d.is_private_symbol ()) {
+			function.modifiers |= CCodeModifiers.STATIC;
+		}
+
+		function.add_parameter (new CCodeFormalParameter ("this", "%s*".printf (d.get_cname ())));
+
+		string param_list = "";
+
+		foreach (FormalParameter param in d.get_parameters ()) {
+			generate_type_declaration (param.parameter_type, decl_space);
+
+			function.add_parameter (new CCodeFormalParameter (param.name, param.parameter_type.get_cname ()));
+
+			if (param_list != "") {
+				param_list += ", ";
+			}
+			param_list += param.parameter_type.get_cname ();
+		}
+
+		function.block = new CCodeBlock ();
+
+		var get_target = new CCodeFunctionCall (new CCodeIdentifier ("dova_delegate_get_target"));
+		get_target.add_argument (new CCodeIdentifier ("this"));
+
+		var cdecl = new CCodeDeclaration ("DovaObject*");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("target", get_target));
+		function.block.add_statement (cdecl);
+
+		var priv = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (d.get_upper_case_cname ())));
+		priv.add_argument (new CCodeIdentifier ("this"));
+
+		string instance_param_list = "(DovaObject *";
+		if (param_list != "") {
+			instance_param_list += ",";
+			instance_param_list += param_list;
+		}
+		instance_param_list += ")";
+
+		var instance_block = new CCodeBlock ();
+		var instance_call = new CCodeFunctionCall (new CCodeCastExpression (new CCodeMemberAccess.pointer (priv, "method"), "%s (*) %s".printf (d.return_type.get_cname (), instance_param_list)));
+
+		instance_call.add_argument (new CCodeIdentifier ("target"));
+
+		string static_param_list = "(";
+		if (param_list != "") {
+			static_param_list += param_list;
+		} else {
+			static_param_list += "void";
+		}
+		static_param_list += ")";
+
+		var static_block = new CCodeBlock ();
+		var static_call = new CCodeFunctionCall (new CCodeCastExpression (new CCodeMemberAccess.pointer (priv, "method"), "%s (*) %s".printf (d.return_type.get_cname (), static_param_list)));
+
+		foreach (FormalParameter param in d.get_parameters ()) {
+			instance_call.add_argument (new CCodeIdentifier (param.name));
+			static_call.add_argument (new CCodeIdentifier (param.name));
+		}
+
+		if (d.return_type is VoidType) {
+			instance_block.add_statement (new CCodeExpressionStatement (instance_call));
+			static_block.add_statement (new CCodeExpressionStatement (static_call));
+		} else {
+			instance_block.add_statement (new CCodeReturnStatement (instance_call));
+			static_block.add_statement (new CCodeReturnStatement (static_call));
+		}
+
+		function.block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("target"), instance_block, static_block));
+
+		return function;
+	}
+
+	public override void visit_delegate (Delegate d) {
+		d.accept_children (codegen);
+
+		generate_delegate_declaration (d, source_declarations);
+
+		if (!d.is_internal_symbol ()) {
+			generate_delegate_declaration (d, header_declarations);
+		}
+		if (!d.is_private_symbol ()) {
+			generate_delegate_declaration (d, internal_header_declarations);
+		}
+
+		generate_type_get_function (d, delegate_class);
+
+		var instance_priv_struct = new CCodeStruct ("_%sPrivate".printf (d.get_cname ()));
+		var type_priv_struct = new CCodeStruct ("_%sTypePrivate".printf (d.get_cname ()));
+
+		instance_priv_struct.add_field ("void", "(*method) (void)");
+
+		source_declarations.add_type_declaration (new CCodeTypeDefinition ("struct %s".printf (instance_priv_struct.name), new CCodeVariableDeclarator ("%sPrivate".printf (d.get_cname ()))));
+		source_declarations.add_type_definition (instance_priv_struct);
+
+		source_declarations.add_type_declaration (new CCodeTypeDefinition ("struct %s".printf (type_priv_struct.name), new CCodeVariableDeclarator ("%sTypePrivate".printf (d.get_cname ()))));
+		source_declarations.add_type_definition (type_priv_struct);
+
+		string macro = "((%sPrivate *) (((char *) o) + _%s_object_offset))".printf (d.get_cname (), d.get_lower_case_cname ());
+		source_declarations.add_type_member_declaration (new CCodeMacroReplacement ("%s_GET_PRIVATE(o)".printf (d.get_upper_case_cname (null)), macro));
+
+		var cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_%s_object_offset".printf (d.get_lower_case_cname ()), new CCodeConstant ("0")));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_type_member_declaration (cdecl);
+
+		cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_%s_type_offset".printf (d.get_lower_case_cname ()), new CCodeConstant ("0")));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_type_member_declaration (cdecl);
+
+		source_type_member_definition.append (generate_new_function (d, source_declarations));
+		source_type_member_definition.append (generate_invoke_function (d, source_declarations));
+	}
+}
diff --git a/codegen/valadovamemberaccessmodule.vala b/codegen/valadovamemberaccessmodule.vala
new file mode 100644
index 0000000..0be4ff2
--- /dev/null
+++ b/codegen/valadovamemberaccessmodule.vala
@@ -0,0 +1,255 @@
+/* valadovamemberaccessmodule.vala
+ *
+ * Copyright (C) 2006-2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+using GLib;
+
+internal class Vala.DovaMemberAccessModule : DovaControlFlowModule {
+	public DovaMemberAccessModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public override void visit_member_access (MemberAccess expr) {
+		expr.accept_children (codegen);
+
+		CCodeExpression pub_inst = null;
+		DataType base_type = null;
+
+		if (expr.inner != null) {
+			pub_inst = (CCodeExpression) expr.inner.ccodenode;
+
+			if (expr.inner.value_type != null) {
+				base_type = expr.inner.value_type;
+			}
+		}
+
+		if (expr.symbol_reference is Method) {
+			var m = (Method) expr.symbol_reference;
+
+			if (!(m is DynamicMethod)) {
+				generate_method_declaration (m, source_declarations);
+
+				if (!m.external && m.external_package) {
+					// internal VAPI methods
+					// only add them once per source file
+					if (add_generated_external_symbol (m)) {
+						visit_method (m);
+					}
+				}
+			}
+
+			if (expr.inner is BaseAccess) {
+				if (m.base_method != null) {
+					var base_class = (Class) m.base_method.parent_symbol;
+
+					expr.ccodenode = new CCodeIdentifier ("%s_base_%s".printf (base_class.get_lower_case_cname (null), m.name));
+					return;
+				} else if (m.base_interface_method != null) {
+					var base_iface = (Interface) m.base_interface_method.parent_symbol;
+
+					expr.ccodenode = new CCodeIdentifier ("%s_base_%s".printf (base_iface.get_lower_case_cname (null), m.name));
+					return;
+				}
+			}
+
+			if (m.base_method != null) {
+				if (!head.method_has_wrapper (m.base_method)) {
+					var inst = pub_inst;
+					if (expr.inner != null && !expr.inner.is_pure ()) {
+						// instance expression has side-effects
+						// store in temp. variable
+						var temp_var = get_temp_variable (expr.inner.value_type);
+						temp_vars.insert (0, temp_var);
+						var ctemp = new CCodeIdentifier (temp_var.name);
+						inst = new CCodeAssignment (ctemp, pub_inst);
+						expr.inner.ccodenode = ctemp;
+					}
+					var base_class = (Class) m.base_method.parent_symbol;
+					var vclass = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (base_class.get_upper_case_cname (null))));
+					vclass.add_argument (inst);
+					expr.ccodenode = new CCodeMemberAccess.pointer (vclass, m.name);
+				} else {
+					expr.ccodenode = new CCodeIdentifier (m.base_method.get_cname ());
+				}
+			} else if (m.base_interface_method != null) {
+				expr.ccodenode = new CCodeIdentifier (m.base_interface_method.get_cname ());
+			} else if (m is CreationMethod) {
+				expr.ccodenode = new CCodeIdentifier (m.get_real_cname ());
+			} else {
+				expr.ccodenode = new CCodeIdentifier (m.get_cname ());
+			}
+		} else if (expr.symbol_reference is ArrayLengthField) {
+			generate_property_accessor_declaration (((Property) array_class.scope.lookup ("length")).get_accessor, source_declarations);
+
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_length"));
+			ccall.add_argument (pub_inst);
+			expr.ccodenode = ccall;
+		} else if (expr.symbol_reference is Field) {
+			var f = (Field) expr.symbol_reference;
+			if (f.binding == MemberBinding.INSTANCE) {
+				var instance_target_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
+
+				var cl = instance_target_type.data_type as Class;
+				bool dova_priv = false;
+				if (f.access == SymbolAccessibility.PRIVATE &&
+				    (cl.base_class == null || cl.base_class.get_full_name () != "Dova.Value")) {
+					dova_priv = true;
+				}
+
+				CCodeExpression inst;
+				if (dova_priv) {
+					var priv_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (cl.get_upper_case_cname (null))));
+					priv_call.add_argument (pub_inst);
+					inst = priv_call;
+				} else {
+					inst = pub_inst;
+				}
+				if (instance_target_type.data_type.is_reference_type () || (expr.inner != null && expr.inner.value_type is PointerType)) {
+					expr.ccodenode = new CCodeMemberAccess.pointer (inst, f.get_cname ());
+				} else {
+					expr.ccodenode = new CCodeMemberAccess (inst, f.get_cname ());
+				}
+			} else {
+				generate_field_declaration (f, source_declarations);
+
+				expr.ccodenode = new CCodeIdentifier (f.get_cname ());
+			}
+		} else if (expr.symbol_reference is Constant) {
+			var c = (Constant) expr.symbol_reference;
+
+			generate_constant_declaration (c, source_declarations);
+
+			expr.ccodenode = new CCodeIdentifier (c.get_cname ());
+		} else if (expr.symbol_reference is Property) {
+			var prop = (Property) expr.symbol_reference;
+
+			if (!(prop is DynamicProperty)) {
+				generate_property_accessor_declaration (prop.get_accessor, source_declarations);
+
+				if (!prop.external && prop.external_package) {
+					// internal VAPI properties
+					// only add them once per source file
+					if (add_generated_external_symbol (prop)) {
+						visit_property (prop);
+					}
+				}
+			}
+
+			if (expr.inner is BaseAccess) {
+				if (prop.base_property != null) {
+					var base_class = (Class) prop.base_property.parent_symbol;
+					var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
+					vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
+
+					var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
+					ccall.add_argument ((CCodeExpression) expr.inner.ccodenode);
+					expr.ccodenode = ccall;
+					return;
+				} else if (prop.base_interface_property != null) {
+					var base_iface = (Interface) prop.base_interface_property.parent_symbol;
+					string parent_iface_var = "%s_%s_parent_iface".printf (current_class.get_lower_case_cname (null), base_iface.get_lower_case_cname (null));
+
+					var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "get_%s".printf (prop.name)));
+					ccall.add_argument ((CCodeExpression) expr.inner.ccodenode);
+					expr.ccodenode = ccall;
+					return;
+				}
+			}
+
+			var base_property = prop;
+			if (prop.base_property != null) {
+				base_property = prop.base_property;
+			} else if (prop.base_interface_property != null) {
+				base_property = prop.base_interface_property;
+			}
+			string getter_cname;
+			if (prop is DynamicProperty) {
+				getter_cname = head.get_dynamic_property_getter_cname ((DynamicProperty) prop);
+			} else {
+				getter_cname = base_property.get_accessor.get_cname ();
+			}
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier (getter_cname));
+
+			if (prop.binding == MemberBinding.INSTANCE) {
+				ccall.add_argument (pub_inst);
+			}
+
+			expr.ccodenode = ccall;
+		} else if (expr.symbol_reference is EnumValue) {
+			var ev = (EnumValue) expr.symbol_reference;
+
+			generate_enum_declaration ((Enum) ev.parent_symbol, source_declarations);
+
+			expr.ccodenode = new CCodeConstant (ev.get_cname ());
+		} else if (expr.symbol_reference is LocalVariable) {
+			var local = (LocalVariable) expr.symbol_reference;
+			if (local.is_result) {
+				// used in postconditions
+				expr.ccodenode = new CCodeIdentifier ("result");
+			} else {
+				expr.ccodenode = get_variable_cexpression (local.name);
+			}
+		} else if (expr.symbol_reference is FormalParameter) {
+			var p = (FormalParameter) expr.symbol_reference;
+			if (p.name == "this") {
+				if (current_method != null && current_method.coroutine) {
+					// use closure
+					expr.ccodenode = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "this");
+				} else {
+					var st = current_type_symbol as Struct;
+					if (st != null && !st.is_boolean_type () && !st.is_integer_type () && !st.is_floating_type () && (!st.is_simple_type () || current_method is CreationMethod)) {
+						expr.ccodenode = new CCodeIdentifier ("(*this)");
+					} else {
+						expr.ccodenode = new CCodeIdentifier ("this");
+					}
+				}
+			} else {
+				if (current_method != null && current_method.coroutine) {
+					// use closure
+					expr.ccodenode = get_variable_cexpression (p.name);
+				} else {
+					var type_as_struct = p.parameter_type.data_type as Struct;
+					if (p.direction != ParameterDirection.IN
+					    || (type_as_struct != null && !type_as_struct.is_simple_type () && !p.parameter_type.nullable)) {
+						if (p.parameter_type is GenericType) {
+							expr.ccodenode = get_variable_cexpression (p.name);
+						} else {
+							expr.ccodenode = new CCodeIdentifier ("(*%s)".printf (get_variable_cname (p.name)));
+						}
+					} else {
+						// Property setters of non simple structs shall replace all occurences
+						// of the "value" formal parameter with a dereferencing version of that
+						// parameter.
+						if (current_property_accessor != null &&
+						    current_property_accessor.writable &&
+						    current_property_accessor.value_parameter == p &&
+						    current_property_accessor.prop.property_type.is_real_struct_type ()) {
+							expr.ccodenode = new CCodeIdentifier ("(*value)");
+						} else {
+							expr.ccodenode = get_variable_cexpression (p.name);
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
diff --git a/codegen/valadovamethodcallmodule.vala b/codegen/valadovamethodcallmodule.vala
new file mode 100644
index 0000000..aca9570
--- /dev/null
+++ b/codegen/valadovamethodcallmodule.vala
@@ -0,0 +1,230 @@
+/* valadovamethodcallmodule.vala
+ *
+ * Copyright (C) 2006-2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+internal class Vala.DovaMethodCallModule : DovaAssignmentModule {
+	public DovaMethodCallModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public override void visit_method_call (MethodCall expr) {
+		expr.accept_children (codegen);
+
+		// the bare function call
+		var ccall = new CCodeFunctionCall ((CCodeExpression) expr.call.ccodenode);
+
+		Method m = null;
+		Delegate deleg = null;
+		List<FormalParameter> params;
+
+		var ma = expr.call as MemberAccess;
+
+		var itype = expr.call.value_type;
+		params = itype.get_parameters ();
+
+		if (itype is MethodType) {
+			assert (ma != null);
+			m = ((MethodType) itype).method_symbol;
+		} else if (itype is ObjectType) {
+			// constructor
+			var cl = (Class) ((ObjectType) itype).type_symbol;
+			m = cl.default_construction_method;
+			generate_method_declaration (m, source_declarations);
+			ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
+		} else if (itype is DelegateType) {
+			deleg = ((DelegateType) itype).delegate_symbol;
+			ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_invoke".printf (deleg.get_lower_case_cname ())));
+			ccall.add_argument ((CCodeExpression) expr.call.ccodenode);
+		}
+
+		if (m is CreationMethod) {
+			var cl = (Class) m.parent_symbol;
+
+			if (cl == current_class) {
+				ccall.add_argument (new CCodeIdentifier ("this"));
+			} else {
+				ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("this"), cl.get_cname () + "*"));
+			}
+		} else if (m != null) {
+			if (m.binding == MemberBinding.INSTANCE) {
+				var instance = (CCodeExpression) ma.inner.ccodenode;
+
+				if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
+					var inner_ma = (MemberAccess) ma.inner;
+					instance = (CCodeExpression) inner_ma.inner.ccodenode;
+				}
+
+				var st = m.parent_symbol as Struct;
+				if (st != null && !st.is_simple_type ()) {
+					// we need to pass struct instance by reference
+					var unary = instance as CCodeUnaryExpression;
+					if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
+						// *expr => expr
+						instance = unary.inner;
+					} else if (instance is CCodeIdentifier || instance is CCodeMemberAccess) {
+						instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance);
+					} else {
+						// if instance is e.g. a function call, we can't take the address of the expression
+						// (tmp = expr, &tmp)
+						var ccomma = new CCodeCommaExpression ();
+
+						var temp_var = get_temp_variable (ma.inner.target_type);
+						temp_vars.insert (0, temp_var);
+						ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), instance));
+						ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name)));
+
+						instance = ccomma;
+					}
+				}
+
+				if (ma.inner is BaseAccess) {
+					ccall.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (((Class) current_class.base_class).get_lower_case_cname ()))));
+				}
+				ccall.add_argument (instance);
+			}
+
+			if (m.binding != MemberBinding.INSTANCE && m.parent_symbol is ObjectTypeSymbol) {
+				// support static methods in generic types
+				var type_symbol = (ObjectTypeSymbol) m.parent_symbol;
+				if (type_symbol.get_type_parameters ().size > 0 && ma.inner is MemberAccess) {
+					var type_ma = (MemberAccess) ma.inner;
+					add_generic_type_arguments (ccall, type_ma.get_type_arguments (), expr);
+				}
+			}
+			if (m.get_type_parameters ().size > 0) {
+				add_generic_type_arguments (ccall, ma.get_type_arguments (), expr);
+			}
+		}
+
+		// the complete call expression, might include casts, comma expressions, and/or assignments
+		CCodeExpression ccall_expr = ccall;
+
+		bool ellipsis = false;
+
+		int i = 1;
+		Iterator<FormalParameter> params_it = params.iterator ();
+		foreach (Expression arg in expr.get_argument_list ()) {
+			CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
+
+			if (params_it.next ()) {
+				var param = params_it.get ();
+				ellipsis = param.params_array || param.ellipsis;
+				if (!ellipsis) {
+					cexpr = handle_struct_argument (param, arg, cexpr);
+
+					// unref old value for non-null non-weak ref/out arguments
+					// disabled for arrays for now as that requires special handling
+					// (ret_tmp = call (&tmp), var1 = (assign_tmp = dup (tmp), free (var1), assign_tmp), ret_tmp)
+					if (param.direction != ParameterDirection.IN && requires_destroy (arg.value_type)
+					    && (param.direction == ParameterDirection.OUT || !param.parameter_type.value_owned)
+					    && !(param.parameter_type is ArrayType)) {
+						var unary = (UnaryExpression) arg;
+
+						var ccomma = new CCodeCommaExpression ();
+
+						var temp_var = get_temp_variable (param.parameter_type, param.parameter_type.value_owned);
+						temp_vars.insert (0, temp_var);
+						cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name));
+
+						if (param.direction == ParameterDirection.REF) {
+							var crefcomma = new CCodeCommaExpression ();
+							crefcomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), (CCodeExpression) unary.inner.ccodenode));
+							crefcomma.append_expression (cexpr);
+							cexpr = crefcomma;
+						}
+
+						// call function
+						LocalVariable ret_temp_var = null;
+						if (itype.get_return_type () is VoidType) {
+							ccomma.append_expression (ccall_expr);
+						} else {
+							ret_temp_var = get_temp_variable (itype.get_return_type ());
+							temp_vars.insert (0, ret_temp_var);
+							ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (ret_temp_var.name), ccall_expr));
+						}
+
+						var cassign_comma = new CCodeCommaExpression ();
+
+						var assign_temp_var = get_temp_variable (unary.inner.value_type, unary.inner.value_type.value_owned);
+						temp_vars.insert (0, assign_temp_var);
+
+						cassign_comma.append_expression (new CCodeAssignment (get_variable_cexpression (assign_temp_var.name), transform_expression (get_variable_cexpression (temp_var.name), param.parameter_type, unary.inner.value_type, arg)));
+
+						// unref old value
+						cassign_comma.append_expression (get_unref_expression ((CCodeExpression) unary.inner.ccodenode, arg.value_type, arg));
+
+						cassign_comma.append_expression (get_variable_cexpression (assign_temp_var.name));
+
+						// assign new value
+						ccomma.append_expression (new CCodeAssignment ((CCodeExpression) unary.inner.ccodenode, cassign_comma));
+
+						// return value
+						if (!(itype.get_return_type () is VoidType)) {
+							ccomma.append_expression (get_variable_cexpression (ret_temp_var.name));
+						}
+
+						ccall_expr = ccomma;
+					}
+
+					if (param.ctype != null) {
+						cexpr = new CCodeCastExpression (cexpr, param.ctype);
+					}
+				}
+			}
+
+			ccall.add_argument (cexpr);
+
+			i++;
+		}
+		if (params_it.next ()) {
+			var param = params_it.get ();
+
+			/* if there are more parameters than arguments,
+			 * the additional parameter is an ellipsis parameter
+			 * otherwise there is a bug in the semantic analyzer
+			 */
+			assert (param.params_array || param.ellipsis);
+			ellipsis = true;
+		}
+
+		if (m != null && m.return_type is GenericType) {
+			var ccomma = new CCodeCommaExpression ();
+
+			var temp_var = get_temp_variable (expr.value_type);
+			temp_vars.insert (0, temp_var);
+			if (expr.value_type is GenericType) {
+				ccall.add_argument (get_variable_cexpression (temp_var.name));
+			} else {
+				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name)));
+			}
+
+			// call function
+			ccomma.append_expression (ccall_expr);
+
+			ccomma.append_expression (get_variable_cexpression (temp_var.name));
+
+			ccall_expr = ccomma;
+		}
+
+		expr.ccodenode = ccall_expr;
+	}
+}
+
diff --git a/codegen/valadovamethodmodule.vala b/codegen/valadovamethodmodule.vala
new file mode 100644
index 0000000..4be1b8d
--- /dev/null
+++ b/codegen/valadovamethodmodule.vala
@@ -0,0 +1,46 @@
+/* valadovamethodmodule.vala
+ *
+ * Copyright (C) 2007-2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+/**
+ * The link between a method and generated code.
+ */
+internal class Vala.DovaMethodModule : DovaStructModule {
+	public DovaMethodModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public override bool method_has_wrapper (Method method) {
+		return (method.get_attribute ("NoWrapper") == null);
+	}
+
+	public override string? get_custom_creturn_type (Method m) {
+		var attr = m.get_attribute ("CCode");
+		if (attr != null) {
+			string type = attr.get_string ("type");
+			if (type != null) {
+				return type;
+			}
+		}
+		return null;
+	}
+}
+
diff --git a/codegen/valadovaobjectmodule.vala b/codegen/valadovaobjectmodule.vala
new file mode 100644
index 0000000..276cbf5
--- /dev/null
+++ b/codegen/valadovaobjectmodule.vala
@@ -0,0 +1,1519 @@
+/* valadovaobjectmodule.vala
+ *
+ * Copyright (C) 2009-2010  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+internal class Vala.DovaObjectModule : DovaArrayModule {
+	public DovaObjectModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public override void generate_class_declaration (Class cl, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (cl, cl.get_cname ())) {
+			return;
+		}
+
+		if (cl.base_class == null) {
+			decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (cl.get_cname ()), new CCodeVariableDeclarator (cl.get_cname ())));
+		} else {
+			// typedef to base class instead of dummy struct to avoid warnings/casts
+			generate_class_declaration (cl.base_class, decl_space);
+			decl_space.add_type_declaration (new CCodeTypeDefinition (cl.base_class.get_cname (), new CCodeVariableDeclarator (cl.get_cname ())));
+		}
+
+		if (cl.base_class == null) {
+			var instance_struct = new CCodeStruct ("_%s".printf (cl.get_cname ()));
+			instance_struct.add_field ("DovaType *", "type");
+			decl_space.add_type_definition (instance_struct);
+		} else if (cl == type_class) {
+			decl_space.add_include ("stdbool.h");
+
+			var value_copy_function = new CCodeFunction ("dova_type_value_copy");
+			value_copy_function.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+			value_copy_function.add_parameter (new CCodeFormalParameter ("dest", "void *"));
+			value_copy_function.add_parameter (new CCodeFormalParameter ("dest_index", "int32_t"));
+			value_copy_function.add_parameter (new CCodeFormalParameter ("src", "void *"));
+			value_copy_function.add_parameter (new CCodeFormalParameter ("src_index", "int32_t"));
+
+			source_declarations.add_type_member_declaration (value_copy_function);
+
+			var value_equal_function = new CCodeFunction ("dova_type_value_equal", "bool");
+			value_equal_function.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+			value_equal_function.add_parameter (new CCodeFormalParameter ("value", "void *"));
+			value_equal_function.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
+			value_equal_function.add_parameter (new CCodeFormalParameter ("other", "void *"));
+			value_equal_function.add_parameter (new CCodeFormalParameter ("other_index", "int32_t"));
+
+			source_declarations.add_type_member_declaration (value_equal_function);
+
+			var value_hash_function = new CCodeFunction ("dova_type_value_hash", "int32_t");
+			value_hash_function.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+			value_hash_function.add_parameter (new CCodeFormalParameter ("value", "void *"));
+			value_hash_function.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
+
+			source_declarations.add_type_member_declaration (value_hash_function);
+		}
+
+		generate_class_declaration (type_class, decl_space);
+		generate_method_declaration ((Method) object_class.scope.lookup ("ref"), decl_space);
+		generate_method_declaration ((Method) object_class.scope.lookup ("unref"), decl_space);
+
+		var type_fun = new CCodeFunction ("%s_type_get".printf (cl.get_lower_case_cname ()), "DovaType *");
+		foreach (var type_param in cl.get_type_parameters ()) {
+			type_fun.add_parameter (new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType *"));
+		}
+		decl_space.add_type_member_declaration (type_fun);
+
+		var type_init_fun = new CCodeFunction ("%s_type_init".printf (cl.get_lower_case_cname ()));
+		type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		foreach (var type_param in cl.get_type_parameters ()) {
+			type_init_fun.add_parameter (new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType *"));
+		}
+		decl_space.add_type_member_declaration (type_init_fun);
+	}
+
+	void generate_virtual_method_declaration (Method m, CCodeDeclarationSpace decl_space, CCodeStruct type_struct) {
+		if (!m.is_abstract && !m.is_virtual) {
+			return;
+		}
+
+		// add vfunc field to the type struct
+		var vdeclarator = new CCodeFunctionDeclarator (m.vfunc_name);
+
+		generate_cparameters (m, decl_space, new CCodeFunction ("fake"), vdeclarator);
+
+		var vdecl = new CCodeDeclaration (m.return_type.get_cname ());
+		vdecl.add_declarator (vdeclarator);
+		type_struct.add_declaration (vdecl);
+	}
+
+	void generate_class_private_declaration (Class cl, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (cl, cl.get_cname () + "Private")) {
+			return;
+		}
+
+		var instance_priv_struct = new CCodeStruct ("_%sPrivate".printf (cl.get_cname ()));
+		var type_priv_struct = new CCodeStruct ("_%sTypePrivate".printf (cl.get_cname ()));
+
+		foreach (Field f in cl.get_fields ()) {
+			if (f.binding == MemberBinding.INSTANCE)  {
+				generate_type_declaration (f.field_type, decl_space);
+
+				string field_ctype = f.field_type.get_cname ();
+				if (f.is_volatile) {
+					field_ctype = "volatile " + field_ctype;
+				}
+
+				instance_priv_struct.add_field (field_ctype, f.get_cname ());
+			}
+		}
+
+		if (cl.get_full_name () == "Dova.Type") {
+			var vdeclarator = new CCodeFunctionDeclarator ("value_copy");
+			vdeclarator.add_parameter (new CCodeFormalParameter ("dest", "void *"));
+			vdeclarator.add_parameter (new CCodeFormalParameter ("dest_index", "int32_t"));
+			vdeclarator.add_parameter (new CCodeFormalParameter ("src", "void *"));
+			vdeclarator.add_parameter (new CCodeFormalParameter ("src_index", "int32_t"));
+
+			var vdecl = new CCodeDeclaration ("void");
+			vdecl.add_declarator (vdeclarator);
+			instance_priv_struct.add_declaration (vdecl);
+
+			vdeclarator = new CCodeFunctionDeclarator ("value_equal");
+			vdeclarator.add_parameter (new CCodeFormalParameter ("value", "void *"));
+			vdeclarator.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
+			vdeclarator.add_parameter (new CCodeFormalParameter ("other", "void *"));
+			vdeclarator.add_parameter (new CCodeFormalParameter ("other_index", "int32_t"));
+
+			vdecl = new CCodeDeclaration ("bool");
+			vdecl.add_declarator (vdeclarator);
+			instance_priv_struct.add_declaration (vdecl);
+
+			vdeclarator = new CCodeFunctionDeclarator ("value_hash");
+			vdeclarator.add_parameter (new CCodeFormalParameter ("value", "void *"));
+			vdeclarator.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
+
+			vdecl = new CCodeDeclaration ("int32_t");
+			vdecl.add_declarator (vdeclarator);
+			instance_priv_struct.add_declaration (vdecl);
+		}
+
+		foreach (var type_param in cl.get_type_parameters ()) {
+			var type_param_decl = new CCodeDeclaration ("DovaType *");
+			type_param_decl.add_declarator (new CCodeVariableDeclarator ("%s_type".printf (type_param.name.down ())));
+			type_priv_struct.add_declaration (type_param_decl);
+		}
+
+		foreach (Method m in cl.get_methods ()) {
+			generate_virtual_method_declaration (m, decl_space, type_priv_struct);
+		}
+
+		foreach (Property prop in cl.get_properties ()) {
+			if (!prop.is_abstract && !prop.is_virtual) {
+				continue;
+			}
+			generate_type_declaration (prop.property_type, decl_space);
+
+			var t = (ObjectTypeSymbol) prop.parent_symbol;
+
+			var this_type = new ObjectType (t);
+			var cselfparam = new CCodeFormalParameter ("this", this_type.get_cname ());
+			var cvalueparam = new CCodeFormalParameter ("value", prop.property_type.get_cname ());
+
+			if (prop.get_accessor != null) {
+				var vdeclarator = new CCodeFunctionDeclarator ("get_%s".printf (prop.name));
+				vdeclarator.add_parameter (cselfparam);
+				string creturn_type = prop.property_type.get_cname ();
+
+				var vdecl = new CCodeDeclaration (creturn_type);
+				vdecl.add_declarator (vdeclarator);
+				type_priv_struct.add_declaration (vdecl);
+			}
+			if (prop.set_accessor != null) {
+				var vdeclarator = new CCodeFunctionDeclarator ("set_%s".printf (prop.name));
+				vdeclarator.add_parameter (cselfparam);
+				vdeclarator.add_parameter (cvalueparam);
+
+				var vdecl = new CCodeDeclaration ("void");
+				vdecl.add_declarator (vdeclarator);
+				type_priv_struct.add_declaration (vdecl);
+			}
+		}
+
+		decl_space.add_type_declaration (new CCodeTypeDefinition ("struct %s".printf (instance_priv_struct.name), new CCodeVariableDeclarator ("%sPrivate".printf (cl.get_cname ()))));
+		decl_space.add_type_definition (instance_priv_struct);
+
+		decl_space.add_type_declaration (new CCodeTypeDefinition ("struct %s".printf (type_priv_struct.name), new CCodeVariableDeclarator ("%sTypePrivate".printf (cl.get_cname ()))));
+		decl_space.add_type_definition (type_priv_struct);
+
+		string macro;
+		if (cl.base_class == null) {
+			// offset of Object class is 0
+			macro = "((%sPrivate *) o)".printf (cl.get_cname ());
+		} else {
+			var cdecl = new CCodeDeclaration ("int");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_%s_object_offset".printf (cl.get_lower_case_cname ()), new CCodeConstant ("0")));
+			cdecl.modifiers = CCodeModifiers.STATIC;
+			decl_space.add_type_member_declaration (cdecl);
+
+			macro = "((%sPrivate *) (((char *) o) + _%s_object_offset))".printf (cl.get_cname (), cl.get_lower_case_cname ());
+		}
+		decl_space.add_type_member_declaration (new CCodeMacroReplacement ("%s_GET_PRIVATE(o)".printf (cl.get_upper_case_cname (null)), macro));
+
+		var cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_%s_type_offset".printf (cl.get_lower_case_cname ()), new CCodeConstant ("0")));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		decl_space.add_type_member_declaration (cdecl);
+	}
+
+	CCodeFunction create_set_value_copy_function (bool decl_only = false) {
+		var result = new CCodeFunction ("dova_type_set_value_copy");
+		result.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		result.add_parameter (new CCodeFormalParameter ("(*function) (void *dest, int32_t dest_index, void *src, int32_t src_index)", "void"));
+		if (decl_only) {
+			return result;
+		}
+
+		result.block = new CCodeBlock ();
+
+		var priv_call = new CCodeFunctionCall (new CCodeIdentifier ("DOVA_TYPE_GET_PRIVATE"));
+		priv_call.add_argument (new CCodeIdentifier ("type"));
+
+		result.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_call, "value_copy"), new CCodeIdentifier ("function"))));
+		return result;
+	}
+
+	public void declare_set_value_copy_function (CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (type_class, "dova_type_set_value_copy")) {
+			return;
+		}
+		decl_space.add_type_member_declaration (create_set_value_copy_function (true));
+	}
+
+	CCodeFunction create_set_value_equal_function (bool decl_only = false) {
+		var result = new CCodeFunction ("dova_type_set_value_equal");
+		result.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		result.add_parameter (new CCodeFormalParameter ("(*function) (void *value, int32_t value_index, void *other, int32_t other_index)", "bool"));
+		if (decl_only) {
+			return result;
+		}
+
+		result.block = new CCodeBlock ();
+
+		var priv_call = new CCodeFunctionCall (new CCodeIdentifier ("DOVA_TYPE_GET_PRIVATE"));
+		priv_call.add_argument (new CCodeIdentifier ("type"));
+
+		result.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_call, "value_equal"), new CCodeIdentifier ("function"))));
+		return result;
+	}
+
+	public void declare_set_value_equal_function (CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (type_class, "dova_type_set_value_equal")) {
+			return;
+		}
+		decl_space.add_type_member_declaration (create_set_value_equal_function (true));
+	}
+
+	CCodeFunction create_set_value_hash_function (bool decl_only = false) {
+		var result = new CCodeFunction ("dova_type_set_value_hash");
+		result.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		result.add_parameter (new CCodeFormalParameter ("(*function) (void *value, int32_t value_index)", "int32_t"));
+		if (decl_only) {
+			return result;
+		}
+
+		result.block = new CCodeBlock ();
+
+		var priv_call = new CCodeFunctionCall (new CCodeIdentifier ("DOVA_TYPE_GET_PRIVATE"));
+		priv_call.add_argument (new CCodeIdentifier ("type"));
+
+		result.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_call, "value_hash"), new CCodeIdentifier ("function"))));
+		return result;
+	}
+
+	public void declare_set_value_hash_function (CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (type_class, "dova_type_set_value_hash")) {
+			return;
+		}
+		decl_space.add_type_member_declaration (create_set_value_hash_function (true));
+	}
+
+	public CCodeBlock generate_type_get_function (TypeSymbol cl, Class? base_class) {
+		source_declarations.add_include ("stddef.h");
+		// calloc
+		source_declarations.add_include ("stdlib.h");
+
+		var cdecl = new CCodeDeclaration ("DovaType *");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("%s_type".printf (cl.get_lower_case_cname ()), new CCodeConstant ("NULL")));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_type_member_declaration (cdecl);
+
+		var type_fun = new CCodeFunction ("%s_type_get".printf (cl.get_lower_case_cname ()), "DovaType *");
+
+		var object_type_symbol = cl as ObjectTypeSymbol;
+		if (object_type_symbol != null) {
+			foreach (var type_param in object_type_symbol.get_type_parameters ()) {
+				type_fun.add_parameter (new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType *"));
+			}
+		}
+
+		type_fun.block = new CCodeBlock ();
+
+		var type_init_block = new CCodeBlock ();
+
+		if (base_class == null) {
+			// var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+			// sizeof_call.add_argument (new CCodeIdentifier ("DovaObject"));
+
+			var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+			sizeof_call.add_argument (new CCodeIdentifier ("%sPrivate".printf (cl.get_cname ())));
+
+			var calloc_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
+			calloc_call.add_argument (new CCodeConstant ("1"));
+			// calloc_call.add_argument (sizeof_call);
+			// FIXME
+			calloc_call.add_argument (new CCodeConstant ("sizeof (DovaObjectPrivate) + sizeof (DovaTypePrivate) + sizeof (DovaObjectTypePrivate)"));
+
+			type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())), calloc_call)));
+
+			type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_dova_type_object_offset"), sizeof_call)));
+
+			var set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_object_size"));
+			set_size.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
+			set_size.add_argument (sizeof_call);
+			type_init_block.add_statement (new CCodeExpressionStatement (set_size));
+
+			type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_dova_object_type_offset"), new CCodeConstant ("sizeof (DovaObjectPrivate) + sizeof (DovaTypePrivate)"))));
+
+			set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_type_size"));
+			set_size.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
+			set_size.add_argument (new CCodeConstant ("sizeof (DovaObjectPrivate) + sizeof (DovaTypePrivate) + sizeof (DovaObjectTypePrivate)"));
+			type_init_block.add_statement (new CCodeExpressionStatement (set_size));
+
+			type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())), "DovaObject *"), "type"), new CCodeFunctionCall (new CCodeIdentifier ("dova_type_type_get")))));
+		} else {
+			generate_method_declaration ((Method) object_class.scope.lookup ("alloc"), source_declarations);
+			generate_method_declaration ((Method) type_class.scope.lookup ("alloc"), source_declarations);
+
+			var base_type = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (base_class.get_lower_case_cname ())));
+			for (int i = 0; i < base_class.get_type_parameters ().size; i++) {
+				base_type.add_argument (new CCodeConstant ("NULL"));
+			}
+
+			var alloc_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_alloc"));
+			alloc_call.add_argument (base_type);
+			alloc_call.add_argument (new CCodeConstant ("sizeof (%sPrivate)".printf (cl.get_cname ())));
+			alloc_call.add_argument (new CCodeConstant ("sizeof (%sTypePrivate)".printf (cl.get_cname ())));
+			alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ()))));
+			alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_%s_object_offset".printf (cl.get_lower_case_cname ()))));
+			alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_%s_type_offset".printf (cl.get_lower_case_cname ()))));
+
+			type_init_block.add_statement (new CCodeExpressionStatement (alloc_call));
+		}
+
+		var type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (cl.get_lower_case_cname ())));
+		type_init_call.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
+
+		if (object_type_symbol != null) {
+			for (int i = 0; i < object_type_symbol.get_type_parameters ().size; i++) {
+				type_init_call.add_argument (new CCodeConstant ("NULL"));
+			}
+		}
+
+		type_init_block.add_statement (new CCodeExpressionStatement (type_init_call));
+
+		type_fun.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ()))), type_init_block));
+
+		if (object_type_symbol != null && object_type_symbol.get_type_parameters ().size > 0) {
+			// generics
+			var specialized_type_get_block = new CCodeBlock ();
+
+			generate_property_accessor_declaration (((Property) type_class.scope.lookup ("next_type")).get_accessor, source_declarations);
+			generate_method_declaration ((Method) type_class.scope.lookup ("insert_type"), source_declarations);
+
+			var first = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_next_type"));
+			first.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
+
+			cdecl = new CCodeDeclaration ("DovaType *");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("result", first));
+			specialized_type_get_block.add_statement (cdecl);
+
+			var next = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_next_type"));
+			next.add_argument (new CCodeIdentifier ("result"));
+
+			var next_check = new CCodeBlock ();
+			next_check.add_statement (new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeMemberAccess.pointer (get_type_private_from_type (object_type_symbol, new CCodeIdentifier ("result")), "%s_type".printf (object_type_symbol.get_type_parameters ().get (0).name.down ())), new CCodeIdentifier ("%s_type".printf (object_type_symbol.get_type_parameters ().get (0).name.down ()))), new CCodeBreakStatement ()));
+			next_check.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), next)));
+
+			specialized_type_get_block.add_statement (new CCodeWhileStatement (new CCodeIdentifier ("result"), next_check));
+
+			var specialized_type_init_block = new CCodeBlock ();
+
+			generate_method_declaration ((Method) type_class.scope.lookup ("alloc"), source_declarations);
+
+			var base_type = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (base_class.get_lower_case_cname ())));
+			foreach (var type_param in base_class.get_type_parameters ()) {
+				base_type.add_argument (new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
+			}
+
+			var alloc_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_alloc"));
+			alloc_call.add_argument (base_type);
+			alloc_call.add_argument (new CCodeConstant ("sizeof (%sPrivate)".printf (cl.get_cname ())));
+			alloc_call.add_argument (new CCodeConstant ("sizeof (%sTypePrivate)".printf (cl.get_cname ())));
+			alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
+			alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_%s_object_offset".printf (cl.get_lower_case_cname ()))));
+			alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_%s_type_offset".printf (cl.get_lower_case_cname ()))));
+
+			specialized_type_init_block.add_statement (new CCodeExpressionStatement (alloc_call));
+
+			type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (cl.get_lower_case_cname ())));
+			type_init_call.add_argument (new CCodeIdentifier ("result"));
+
+			foreach (var type_param in object_type_symbol.get_type_parameters ()) {
+				type_init_call.add_argument (new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
+			}
+
+			specialized_type_init_block.add_statement (new CCodeExpressionStatement (type_init_call));
+
+			var insert_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_insert_type"));
+			insert_call.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
+			insert_call.add_argument (new CCodeIdentifier ("result"));
+			specialized_type_init_block.add_statement (new CCodeExpressionStatement (insert_call));
+
+			specialized_type_get_block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("result")), specialized_type_init_block));
+
+			specialized_type_get_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+
+			type_fun.block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("%s_type".printf (object_type_symbol.get_type_parameters ().get (0).name.down ())), specialized_type_get_block));
+		}
+
+		type_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ()))));
+
+		source_type_member_definition.append (type_fun);
+
+		var type_init_fun = new CCodeFunction ("%s_type_init".printf (cl.get_lower_case_cname ()));
+		type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		if (object_type_symbol != null) {
+			foreach (var type_param in object_type_symbol.get_type_parameters ()) {
+				type_init_fun.add_parameter (new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType *"));
+			}
+		}
+		type_init_fun.block = new CCodeBlock ();
+
+		if (base_class == null) {
+			var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+			sizeof_call.add_argument (new CCodeIdentifier ("void *"));
+
+			var set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_size"));
+			set_size.add_argument (new CCodeIdentifier ("type"));
+			set_size.add_argument (sizeof_call);
+			type_init_fun.block.add_statement (new CCodeExpressionStatement (set_size));
+
+			declare_set_value_copy_function (source_declarations);
+
+			var value_copy_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_copy"));
+			value_copy_call.add_argument (new CCodeIdentifier ("type"));
+			value_copy_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("dova_object_copy"), "void (*)(void *, int32_t,  void *, int32_t)"));
+			type_init_fun.block.add_statement (new CCodeExpressionStatement (value_copy_call));
+
+			var function = new CCodeFunction ("dova_object_copy", "void");
+			function.modifiers = CCodeModifiers.STATIC;
+			function.add_parameter (new CCodeFormalParameter ("dest", "DovaObject **"));
+			function.add_parameter (new CCodeFormalParameter ("dest_index", "int32_t"));
+			function.add_parameter (new CCodeFormalParameter ("src", "DovaObject **"));
+			function.add_parameter (new CCodeFormalParameter ("src_index", "int32_t"));
+
+			function.block = new CCodeBlock ();
+			var cfrag = new CCodeFragment ();
+			function.block.add_statement (cfrag);
+
+			var dest = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("dest"), new CCodeIdentifier ("dest_index"));
+			var src = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("src"), new CCodeIdentifier ("src_index"));
+
+			var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_unref"));
+			unref_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest));
+			var unref_block = new CCodeBlock ();
+			unref_block.add_statement (new CCodeExpressionStatement (unref_call));
+			unref_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), new CCodeConstant ("NULL"))));
+			function.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), unref_block));
+
+			var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_ref"));
+			ref_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, src));
+			var ref_block = new CCodeBlock ();
+			ref_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), ref_call)));
+			function.block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("src"), ref_block));
+
+			source_type_member_definition.append (function);
+		} else {
+			type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (base_class.get_lower_case_cname ())));
+			type_init_call.add_argument (new CCodeIdentifier ("type"));
+
+			foreach (var type_param in base_class.get_type_parameters ()) {
+				type_init_call.add_argument (new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
+			}
+
+			type_init_fun.block.add_statement (new CCodeExpressionStatement (type_init_call));
+
+			if (object_type_symbol != null) {
+				foreach (var type_param in object_type_symbol.get_type_parameters ()) {
+					type_init_fun.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_type_private_from_type (object_type_symbol, new CCodeIdentifier ("type")), "%s_type".printf (type_param.name.down ())), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())))));
+				}
+			}
+		}
+
+		source_type_member_definition.append (type_init_fun);
+
+		return type_init_fun.block;
+	}
+
+	void add_finalize_function (Class cl) {
+		var function = new CCodeFunction ("%sfinalize".printf (cl.get_lower_case_cprefix ()), "void");
+		function.modifiers = CCodeModifiers.STATIC;
+
+		function.add_parameter (new CCodeFormalParameter ("this", cl.get_cname () + "*"));
+
+		source_declarations.add_type_member_declaration (function.copy ());
+
+
+		var cblock = new CCodeBlock ();
+
+		if (cl.destructor != null) {
+			cblock.add_statement (cl.destructor.ccodenode);
+		}
+
+		cblock.add_statement (instance_finalize_fragment);
+
+		// chain up to finalize function of the base class
+		foreach (DataType base_type in cl.get_base_types ()) {
+			var object_type = (ObjectType) base_type;
+			if (object_type.type_symbol is Class) {
+				var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_base_finalize"));
+				var type_get_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (object_type.type_symbol.get_lower_case_cname ())));
+				foreach (var type_arg in base_type.get_type_arguments ()) {
+					type_get_call.add_argument (get_type_id_expression (type_arg, false));
+				}
+				ccall.add_argument (type_get_call);
+				ccall.add_argument (new CCodeIdentifier ("this"));
+				cblock.add_statement (new CCodeExpressionStatement (ccall));
+			}
+		}
+
+
+		function.block = cblock;
+
+		source_type_member_definition.append (function);
+	}
+
+	public override void visit_class (Class cl) {
+		var old_symbol = current_symbol;
+		var old_instance_finalize_fragment = instance_finalize_fragment;
+		current_symbol = cl;
+		instance_finalize_fragment = new CCodeFragment ();
+
+		generate_class_declaration (cl, source_declarations);
+		generate_class_private_declaration (cl, source_declarations);
+
+		if (!cl.is_internal_symbol ()) {
+			generate_class_declaration (cl, header_declarations);
+		}
+		generate_class_declaration (cl, internal_header_declarations);
+
+		cl.accept_children (codegen);
+
+		var type_init_block = generate_type_get_function (cl, cl.base_class);
+
+		foreach (DataType base_type in cl.get_base_types ()) {
+			var object_type = (ObjectType) base_type;
+			if (object_type.type_symbol is Interface) {
+				generate_interface_declaration ((Interface) object_type.type_symbol, source_declarations);
+
+				var type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (object_type.type_symbol.get_lower_case_cname ())));
+				type_init_call.add_argument (new CCodeIdentifier ("type"));
+				foreach (var type_arg in base_type.get_type_arguments ()) {
+					type_init_call.add_argument (get_type_id_expression (type_arg, true));
+				}
+				type_init_block.add_statement (new CCodeExpressionStatement (type_init_call));
+			}
+		}
+
+		// finalizer
+		if (cl.base_class != null && (cl.get_fields ().size > 0 || cl.destructor != null)) {
+			add_finalize_function (cl);
+
+			generate_method_declaration ((Method) object_class.scope.lookup ("finalize"), source_declarations);
+
+			var override_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_override_finalize"));
+			override_call.add_argument (new CCodeIdentifier ("type"));
+			override_call.add_argument (new CCodeIdentifier ("%sfinalize".printf (cl.get_lower_case_cprefix ())));
+			type_init_block.add_statement (new CCodeExpressionStatement (override_call));
+		}
+
+		foreach (Method m in cl.get_methods ()) {
+			if (m.is_virtual || m.overrides) {
+				var override_call = new CCodeFunctionCall (new CCodeIdentifier ("%soverride_%s".printf (m.base_method.parent_symbol.get_lower_case_cprefix (), m.name)));
+				override_call.add_argument (new CCodeIdentifier ("type"));
+				override_call.add_argument (new CCodeIdentifier (m.get_real_cname ()));
+				type_init_block.add_statement (new CCodeExpressionStatement (override_call));
+			} else if (m.base_interface_method != null) {
+				var override_call = new CCodeFunctionCall (new CCodeIdentifier ("%soverride_%s".printf (m.base_interface_method.parent_symbol.get_lower_case_cprefix (), m.name)));
+				override_call.add_argument (new CCodeIdentifier ("type"));
+				override_call.add_argument (new CCodeIdentifier (m.get_real_cname ()));
+				type_init_block.add_statement (new CCodeExpressionStatement (override_call));
+			}
+		}
+
+		if (cl == type_class) {
+			var priv_call = new CCodeFunctionCall (new CCodeIdentifier ("DOVA_TYPE_GET_PRIVATE"));
+			priv_call.add_argument (new CCodeIdentifier ("type"));
+
+			var value_copy_function = new CCodeFunction ("dova_type_value_copy");
+			value_copy_function.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+			value_copy_function.add_parameter (new CCodeFormalParameter ("dest", "void *"));
+			value_copy_function.add_parameter (new CCodeFormalParameter ("dest_index", "int32_t"));
+			value_copy_function.add_parameter (new CCodeFormalParameter ("src", "void *"));
+			value_copy_function.add_parameter (new CCodeFormalParameter ("src_index", "int32_t"));
+
+			value_copy_function.block = new CCodeBlock ();
+
+			var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (priv_call, "value_copy"));
+			ccall.add_argument (new CCodeIdentifier ("dest"));
+			ccall.add_argument (new CCodeIdentifier ("dest_index"));
+			ccall.add_argument (new CCodeIdentifier ("src"));
+			ccall.add_argument (new CCodeIdentifier ("src_index"));
+			value_copy_function.block.add_statement (new CCodeExpressionStatement (ccall));
+
+			source_type_member_definition.append (value_copy_function);
+
+			declare_set_value_copy_function (source_declarations);
+			declare_set_value_copy_function (header_declarations);
+			declare_set_value_copy_function (internal_header_declarations);
+			source_type_member_definition.append (create_set_value_copy_function ());
+
+			var value_equal_function = new CCodeFunction ("dova_type_value_equal", "bool");
+			value_equal_function.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+			value_equal_function.add_parameter (new CCodeFormalParameter ("value", "void *"));
+			value_equal_function.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
+			value_equal_function.add_parameter (new CCodeFormalParameter ("other", "void *"));
+			value_equal_function.add_parameter (new CCodeFormalParameter ("other_index", "int32_t"));
+
+			value_equal_function.block = new CCodeBlock ();
+
+			ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (priv_call, "value_equal"));
+			ccall.add_argument (new CCodeIdentifier ("value"));
+			ccall.add_argument (new CCodeIdentifier ("value_index"));
+			ccall.add_argument (new CCodeIdentifier ("other"));
+			ccall.add_argument (new CCodeIdentifier ("other_index"));
+			value_equal_function.block.add_statement (new CCodeExpressionStatement (ccall));
+
+			source_type_member_definition.append (value_equal_function);
+
+			declare_set_value_equal_function (source_declarations);
+			declare_set_value_equal_function (header_declarations);
+			declare_set_value_equal_function (internal_header_declarations);
+			source_type_member_definition.append (create_set_value_equal_function ());
+
+			var value_hash_function = new CCodeFunction ("dova_type_value_hash", "int32_t");
+			value_hash_function.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+			value_hash_function.add_parameter (new CCodeFormalParameter ("value", "void *"));
+			value_hash_function.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
+
+			value_hash_function.block = new CCodeBlock ();
+
+			ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (priv_call, "value_hash"));
+			ccall.add_argument (new CCodeIdentifier ("value"));
+			ccall.add_argument (new CCodeIdentifier ("value_index"));
+			value_hash_function.block.add_statement (new CCodeExpressionStatement (ccall));
+
+			source_type_member_definition.append (value_hash_function);
+
+			declare_set_value_hash_function (source_declarations);
+			declare_set_value_hash_function (header_declarations);
+			declare_set_value_hash_function (internal_header_declarations);
+			source_type_member_definition.append (create_set_value_hash_function ());
+		}
+
+		current_symbol = old_symbol;
+		instance_finalize_fragment = old_instance_finalize_fragment;
+	}
+
+	public override void visit_interface (Interface iface) {
+		var old_symbol = current_symbol;
+		current_symbol = iface;
+
+		generate_interface_declaration (iface, source_declarations);
+
+		var type_priv_struct = new CCodeStruct ("_%sTypePrivate".printf (iface.get_cname ()));
+
+		foreach (var type_param in iface.get_type_parameters ()) {
+			var type_param_decl = new CCodeDeclaration ("DovaType *");
+			type_param_decl.add_declarator (new CCodeVariableDeclarator ("%s_type".printf (type_param.name.down ())));
+			type_priv_struct.add_declaration (type_param_decl);
+		}
+
+		foreach (Method m in iface.get_methods ()) {
+			generate_virtual_method_declaration (m, source_declarations, type_priv_struct);
+		}
+
+		source_declarations.add_type_declaration (new CCodeTypeDefinition ("struct %s".printf (type_priv_struct.name), new CCodeVariableDeclarator ("%sTypePrivate".printf (iface.get_cname ()))));
+		source_declarations.add_type_definition (type_priv_struct);
+
+		source_declarations.add_include ("stddef.h");
+		// calloc
+		source_declarations.add_include ("stdlib.h");
+
+		var cdecl = new CCodeDeclaration ("DovaType *");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("%s_type".printf (iface.get_lower_case_cname ()), new CCodeConstant ("NULL")));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_type_member_declaration (cdecl);
+
+		var type_fun = new CCodeFunction ("%s_type_get".printf (iface.get_lower_case_cname ()), "DovaType *");
+		foreach (var type_param in iface.get_type_parameters ()) {
+			type_fun.add_parameter (new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType *"));
+		}
+		type_fun.block = new CCodeBlock ();
+
+		var type_init_block = new CCodeBlock ();
+
+		var calloc_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
+		calloc_call.add_argument (new CCodeConstant ("1"));
+		calloc_call.add_argument (new CCodeConstant ("dova_type_get_type_size (dova_type_type_get ()) + sizeof (%sTypePrivate)".printf (iface.get_cname ())));
+
+		type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_type".printf (iface.get_lower_case_cname ())), calloc_call)));
+
+		var type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (iface.get_lower_case_cname ())));
+		type_init_call.add_argument (new CCodeIdentifier ("%s_type".printf (iface.get_lower_case_cname ())));
+		foreach (var type_param in iface.get_type_parameters ()) {
+			type_init_call.add_argument (new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
+		}
+		type_init_block.add_statement (new CCodeExpressionStatement (type_init_call));
+
+		type_fun.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("%s_type".printf (iface.get_lower_case_cname ()))), type_init_block));
+
+		type_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("%s_type".printf (iface.get_lower_case_cname ()))));
+
+		source_type_member_definition.append (type_fun);
+
+		var type_init_fun = new CCodeFunction ("%s_type_init".printf (iface.get_lower_case_cname ()));
+		type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		foreach (var type_param in iface.get_type_parameters ()) {
+			type_init_fun.add_parameter (new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType *"));
+		}
+		type_init_fun.block = new CCodeBlock ();
+
+		foreach (DataType base_type in iface.get_prerequisites ()) {
+			var object_type = (ObjectType) base_type;
+			if (object_type.type_symbol is Interface) {
+				type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (object_type.type_symbol.get_lower_case_cname ())));
+				type_init_call.add_argument (new CCodeIdentifier ("type"));
+				type_init_fun.block.add_statement (new CCodeExpressionStatement (type_init_call));
+			}
+		}
+
+		var vtable_alloc = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
+		vtable_alloc.add_argument (new CCodeConstant ("1"));
+		vtable_alloc.add_argument (new CCodeConstant ("sizeof (%sTypePrivate)".printf (iface.get_cname ())));
+
+		var type_get_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (iface.get_lower_case_cname ())));
+		foreach (var type_param in iface.get_type_parameters ()) {
+			type_get_call.add_argument (new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
+		}
+
+		var add_interface_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_add_interface"));
+		add_interface_call.add_argument (new CCodeIdentifier ("type"));
+		add_interface_call.add_argument (type_get_call);
+		add_interface_call.add_argument (vtable_alloc);
+		type_init_fun.block.add_statement (new CCodeExpressionStatement (add_interface_call));
+
+		source_type_member_definition.append (type_init_fun);
+
+		iface.accept_children (codegen);
+
+		current_symbol = old_symbol;
+	}
+
+	public override void generate_property_accessor_declaration (PropertyAccessor acc, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (acc.prop, acc.get_cname ())) {
+			return;
+		}
+
+		var prop = (Property) acc.prop;
+
+		generate_type_declaration (acc.value_type, decl_space);
+
+		CCodeFunction function;
+
+		if (acc.readable) {
+			function = new CCodeFunction (acc.get_cname (), acc.value_type.get_cname ());
+		} else {
+			function = new CCodeFunction (acc.get_cname (), "void");
+		}
+
+		if (prop.binding == MemberBinding.INSTANCE) {
+			DataType this_type;
+			if (prop.parent_symbol is Struct) {
+				var st = (Struct) prop.parent_symbol;
+				this_type = SemanticAnalyzer.get_data_type_for_symbol (st);
+			} else {
+				var t = (ObjectTypeSymbol) prop.parent_symbol;
+				this_type = new ObjectType (t);
+			}
+
+			generate_type_declaration (this_type, decl_space);
+			var cselfparam = new CCodeFormalParameter ("this", this_type.get_cname ());
+
+			function.add_parameter (cselfparam);
+		}
+
+		if (acc.writable) {
+			var cvalueparam = new CCodeFormalParameter ("value", acc.value_type.get_cname ());
+			function.add_parameter (cvalueparam);
+		}
+
+		if (prop.is_private_symbol () || acc.access == SymbolAccessibility.PRIVATE) {
+			function.modifiers |= CCodeModifiers.STATIC;
+		}
+		decl_space.add_type_member_declaration (function);
+	}
+
+	public override void visit_property_accessor (PropertyAccessor acc) {
+		var old_symbol = current_symbol;
+		bool old_method_inner_error = current_method_inner_error;
+		current_symbol = acc;
+		current_method_inner_error = false;
+
+		var prop = (Property) acc.prop;
+
+		acc.accept_children (codegen);
+
+		// do not declare overriding properties and interface implementations
+		if (prop.is_abstract || prop.is_virtual
+		    || (prop.base_property == null && prop.base_interface_property == null)) {
+			generate_property_accessor_declaration (acc, source_declarations);
+
+			if (!prop.is_internal_symbol ()
+			    && (acc.access == SymbolAccessibility.PUBLIC
+				|| acc.access == SymbolAccessibility.PROTECTED)) {
+				generate_property_accessor_declaration (acc, header_declarations);
+			}
+			generate_property_accessor_declaration (acc, internal_header_declarations);
+		}
+
+		DataType this_type;
+		if (prop.parent_symbol is Struct) {
+			var st = (Struct) prop.parent_symbol;
+			this_type = SemanticAnalyzer.get_data_type_for_symbol (st);
+		} else {
+			var t = (ObjectTypeSymbol) prop.parent_symbol;
+			this_type = new ObjectType (t);
+		}
+		var cselfparam = new CCodeFormalParameter ("this", this_type.get_cname ());
+		var cvalueparam = new CCodeFormalParameter ("value", acc.value_type.get_cname ());
+
+		string cname = acc.get_cname ();
+
+		if (prop.is_abstract || prop.is_virtual) {
+			CCodeFunction function;
+			if (acc.readable) {
+				function = new CCodeFunction (acc.get_cname (), current_return_type.get_cname ());
+			} else {
+				function = new CCodeFunction (acc.get_cname (), "void");
+			}
+			function.add_parameter (cselfparam);
+			if (acc.writable) {
+				function.add_parameter (cvalueparam);
+			}
+
+			if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
+				// accessor function should be private if the property is an internal symbol
+				function.modifiers |= CCodeModifiers.STATIC;
+			}
+
+			var block = new CCodeBlock ();
+			function.block = block;
+
+			var vcast = get_type_private_from_type ((ObjectTypeSymbol) prop.parent_symbol, get_type_from_instance (new CCodeIdentifier ("this")));
+
+			if (acc.readable) {
+				var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
+				vcall.add_argument (new CCodeIdentifier ("this"));
+				block.add_statement (new CCodeReturnStatement (vcall));
+			} else {
+				var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
+				vcall.add_argument (new CCodeIdentifier ("this"));
+				vcall.add_argument (new CCodeIdentifier ("value"));
+				block.add_statement (new CCodeExpressionStatement (vcall));
+			}
+
+			source_type_member_definition.append (function);
+		}
+
+		if (!prop.is_abstract) {
+			CCodeFunction function;
+			if (acc.writable) {
+				function = new CCodeFunction (cname, "void");
+			} else {
+				function = new CCodeFunction (cname, acc.value_type.get_cname ());
+			}
+
+			if (prop.binding == MemberBinding.INSTANCE) {
+				function.add_parameter (cselfparam);
+			}
+			if (acc.writable) {
+				function.add_parameter (cvalueparam);
+			}
+
+			if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
+				// accessor function should be private if the property is an internal symbol
+				function.modifiers |= CCodeModifiers.STATIC;
+			}
+
+			function.block = (CCodeBlock) acc.body.ccodenode;
+
+			if (acc.readable) {
+				var cdecl = new CCodeDeclaration (acc.value_type.get_cname ());
+				cdecl.add_declarator (new CCodeVariableDeclarator ("result", default_value_for_type (acc.value_type, true)));
+				function.block.prepend_statement (cdecl);
+
+				function.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+			}
+
+			source_type_member_definition.append (function);
+		}
+
+		current_symbol = old_symbol;
+		current_method_inner_error = old_method_inner_error;
+	}
+
+	public override void generate_interface_declaration (Interface iface, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (iface, iface.get_cname ())) {
+			return;
+		}
+
+		// typedef to DovaObject instead of dummy struct to avoid warnings/casts
+		generate_class_declaration (object_class, decl_space);
+		decl_space.add_type_declaration (new CCodeTypeDefinition ("DovaObject", new CCodeVariableDeclarator (iface.get_cname ())));
+
+		generate_class_declaration (type_class, decl_space);
+
+		var type_fun = new CCodeFunction ("%s_type_get".printf (iface.get_lower_case_cname ()), "DovaType *");
+		foreach (var type_param in iface.get_type_parameters ()) {
+			type_fun.add_parameter (new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType *"));
+		}
+		decl_space.add_type_member_declaration (type_fun);
+
+		var type_init_fun = new CCodeFunction ("%s_type_init".printf (iface.get_lower_case_cname ()));
+		type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		foreach (var type_param in iface.get_type_parameters ()) {
+			type_init_fun.add_parameter (new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType *"));
+		}
+		decl_space.add_type_member_declaration (type_init_fun);
+	}
+
+
+	public override bool method_has_wrapper (Method method) {
+		return (method.get_attribute ("NoWrapper") == null);
+	}
+
+	public override string? get_custom_creturn_type (Method m) {
+		var attr = m.get_attribute ("CCode");
+		if (attr != null) {
+			string type = attr.get_string ("type");
+			if (type != null) {
+				return type;
+			}
+		}
+		return null;
+	}
+
+	public override void generate_method_declaration (Method m, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (m, m.get_cname ())) {
+			return;
+		}
+
+		var function = new CCodeFunction (m.get_cname ());
+
+		if (m.is_private_symbol ()) {
+			function.modifiers |= CCodeModifiers.STATIC;
+			if (m.is_inline) {
+				function.modifiers |= CCodeModifiers.INLINE;
+			}
+		}
+
+		generate_cparameters (m, decl_space, function, null, new CCodeFunctionCall (new CCodeIdentifier ("fake")));
+
+		decl_space.add_type_member_declaration (function);
+
+		if (m.is_abstract || m.is_virtual) {
+			var base_func = function.copy ();
+			base_func.name = "%sbase_%s".printf (m.parent_symbol.get_lower_case_cprefix (), m.name);
+			base_func.insert_parameter (0, new CCodeFormalParameter ("base_type", "DovaType *"));
+			decl_space.add_type_member_declaration (base_func);
+
+			string param_list = "(%s *this".printf (((ObjectTypeSymbol) m.parent_symbol).get_cname ());
+			foreach (var param in m.get_parameters ()) {
+				param_list += ", ";
+				param_list += param.parameter_type.get_cname ();
+			}
+			if (m.return_type is GenericType) {
+				param_list += ", void *";
+			}
+			param_list += ")";
+
+			var override_func = new CCodeFunction ("%soverride_%s".printf (m.parent_symbol.get_lower_case_cprefix (), m.name));
+			override_func.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+			override_func.add_parameter (new CCodeFormalParameter ("(*function) %s".printf (param_list), (m.return_type is GenericType) ? "void" : m.return_type.get_cname ()));
+			decl_space.add_type_member_declaration (override_func);
+		}
+
+		if (m is CreationMethod && m.parent_symbol is Class) {
+			generate_class_declaration ((Class) m.parent_symbol, decl_space);
+
+			// _init function
+			function = new CCodeFunction (m.get_real_cname ());
+
+			if (m.is_private_symbol ()) {
+				function.modifiers |= CCodeModifiers.STATIC;
+			}
+
+			generate_cparameters (m, decl_space, function);
+
+			decl_space.add_type_member_declaration (function);
+		}
+	}
+
+	CCodeExpression get_type_from_instance (CCodeExpression instance_expression) {
+		return new CCodeMemberAccess.pointer (new CCodeCastExpression (instance_expression, "DovaObject *"), "type");
+	}
+
+	public override void visit_method (Method m) {
+		var old_symbol = current_symbol;
+		bool old_method_inner_error = current_method_inner_error;
+		int old_next_temp_var_id = next_temp_var_id;
+		var old_temp_vars = temp_vars;
+		var old_temp_ref_vars = temp_ref_vars;
+		var old_variable_name_map = variable_name_map;
+		var old_try = current_try;
+		current_symbol = m;
+		current_method_inner_error = false;
+		next_temp_var_id = 0;
+		temp_vars = new ArrayList<LocalVariable> ();
+		temp_ref_vars = new ArrayList<LocalVariable> ();
+		variable_name_map = new HashMap<string,string> (str_hash, str_equal);
+		current_try = null;
+
+		m.accept_children (codegen);
+
+		current_symbol = old_symbol;
+		current_method_inner_error = old_method_inner_error;
+		next_temp_var_id = old_next_temp_var_id;
+		temp_vars = old_temp_vars;
+		temp_ref_vars = old_temp_ref_vars;
+		variable_name_map = old_variable_name_map;
+		current_try = old_try;
+
+		generate_method_declaration (m, source_declarations);
+
+		if (!m.is_internal_symbol ()) {
+			generate_method_declaration (m, header_declarations);
+		}
+		generate_method_declaration (m, internal_header_declarations);
+
+		var function = new CCodeFunction (m.get_real_cname ());
+		m.ccodenode = function;
+
+		generate_cparameters (m, source_declarations, function);
+
+		// generate *_real_* functions for virtual methods
+		if (!m.is_abstract) {
+			if (m.base_method != null || m.base_interface_method != null) {
+				// declare *_real_* function
+				function.modifiers |= CCodeModifiers.STATIC;
+				source_declarations.add_type_member_declaration (function.copy ());
+			} else if (m.is_private_symbol ()) {
+				function.modifiers |= CCodeModifiers.STATIC;
+			}
+
+			if (m.body != null) {
+				function.block = (CCodeBlock) m.body.ccodenode;
+				function.block.line = function.line;
+
+				var cinit = new CCodeFragment ();
+				function.block.prepend_statement (cinit);
+
+				foreach (FormalParameter param in m.get_parameters ()) {
+					if (param.ellipsis) {
+						break;
+					}
+
+					var t = param.parameter_type.data_type;
+					if (t != null && t.is_reference_type ()) {
+						if (param.direction == ParameterDirection.OUT) {
+							// ensure that the passed reference for output parameter is cleared
+							var a = new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (param.name)), new CCodeConstant ("NULL"));
+							var cblock = new CCodeBlock ();
+							cblock.add_statement (new CCodeExpressionStatement (a));
+
+							var condition = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (param.name), new CCodeConstant ("NULL"));
+							var if_statement = new CCodeIfStatement (condition, cblock);
+							cinit.append (if_statement);
+						}
+					}
+				}
+
+				if (!(m.return_type is VoidType) && !(m.return_type is GenericType)) {
+					var cdecl = new CCodeDeclaration (m.return_type.get_cname ());
+					cdecl.add_declarator (new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true)));
+					cinit.append (cdecl);
+
+					function.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+				}
+
+				var st = m.parent_symbol as Struct;
+				if (m is CreationMethod && st != null && (st.is_boolean_type () || st.is_integer_type () || st.is_floating_type ())) {
+					var cdecl = new CCodeDeclaration (st.get_cname ());
+					cdecl.add_declarator (new CCodeVariableDeclarator ("this", new CCodeConstant ("0")));
+					cinit.append (cdecl);
+
+					function.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("this")));
+				}
+
+				source_type_member_definition.append (function);
+			}
+		}
+
+		if (m.is_abstract || m.is_virtual) {
+			generate_class_declaration ((Class) object_class, source_declarations);
+
+			var vfunc = new CCodeFunction (m.get_cname (), (m.return_type is GenericType) ? "void" : m.return_type.get_cname ());
+			vfunc.block = new CCodeBlock ();
+
+			vfunc.add_parameter (new CCodeFormalParameter ("this", "%s *".printf (((ObjectTypeSymbol) m.parent_symbol).get_cname ())));
+			foreach (FormalParameter param in m.get_parameters ()) {
+				string ctypename = param.parameter_type.get_cname ();
+				if (param.direction != ParameterDirection.IN) {
+					ctypename += "*";
+				}
+				vfunc.add_parameter (new CCodeFormalParameter (param.name, ctypename));
+			}
+			if (m.return_type is GenericType) {
+				vfunc.add_parameter (new CCodeFormalParameter ("result", "void *"));
+			}
+
+			var vcast = get_type_private_from_type ((ObjectTypeSymbol) m.parent_symbol, get_type_from_instance (new CCodeIdentifier ("this")));
+
+			var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, m.vfunc_name));
+			vcall.add_argument (new CCodeIdentifier ("this"));
+			foreach (FormalParameter param in m.get_parameters ()) {
+				vcall.add_argument (new CCodeIdentifier (param.name));
+			}
+			if (m.return_type is GenericType) {
+				vcall.add_argument (new CCodeIdentifier ("result"));
+				vfunc.block.add_statement (new CCodeExpressionStatement (vcall));
+			} else if (m.return_type is VoidType) {
+				vfunc.block.add_statement (new CCodeExpressionStatement (vcall));
+			} else {
+				vfunc.block.add_statement (new CCodeReturnStatement (vcall));
+			}
+
+			source_type_member_definition.append (vfunc);
+
+
+			vfunc = new CCodeFunction ("%sbase_%s".printf (m.parent_symbol.get_lower_case_cprefix (), m.name), (m.return_type is GenericType) ? "void" : m.return_type.get_cname ());
+			vfunc.block = new CCodeBlock ();
+
+			vfunc.add_parameter (new CCodeFormalParameter ("base_type", "DovaType *"));
+			vfunc.add_parameter (new CCodeFormalParameter ("this", "%s *".printf (((ObjectTypeSymbol) m.parent_symbol).get_cname ())));
+			foreach (FormalParameter param in m.get_parameters ()) {
+				string ctypename = param.parameter_type.get_cname ();
+				if (param.direction != ParameterDirection.IN) {
+					ctypename += "*";
+				}
+				vfunc.add_parameter (new CCodeFormalParameter (param.name, ctypename));
+			}
+			if (m.return_type is GenericType) {
+				vfunc.add_parameter (new CCodeFormalParameter ("result", "void *"));
+			}
+
+			var base_type = new CCodeIdentifier ("base_type");
+
+			vcast = get_type_private_from_type ((ObjectTypeSymbol) m.parent_symbol, base_type);
+
+			vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, m.vfunc_name));
+			vcall.add_argument (new CCodeIdentifier ("this"));
+			foreach (FormalParameter param in m.get_parameters ()) {
+				vcall.add_argument (new CCodeIdentifier (param.name));
+			}
+			if (m.return_type is GenericType) {
+				vcall.add_argument (new CCodeIdentifier ("result"));
+				vfunc.block.add_statement (new CCodeExpressionStatement (vcall));
+			} else if (m.return_type is VoidType) {
+				vfunc.block.add_statement (new CCodeExpressionStatement (vcall));
+			} else {
+				vfunc.block.add_statement (new CCodeReturnStatement (vcall));
+			}
+
+			source_type_member_definition.append (vfunc);
+
+
+			string param_list = "(%s *this".printf (((ObjectTypeSymbol) m.parent_symbol).get_cname ());
+			foreach (var param in m.get_parameters ()) {
+				param_list += ", ";
+				param_list += param.parameter_type.get_cname ();
+			}
+			if (m.return_type is GenericType) {
+				param_list += ", void *";
+			}
+			param_list += ")";
+
+			var override_func = new CCodeFunction ("%soverride_%s".printf (m.parent_symbol.get_lower_case_cprefix (), m.name));
+			override_func.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+			override_func.add_parameter (new CCodeFormalParameter ("(*function) %s".printf (param_list), (m.return_type is GenericType) ? "void" : m.return_type.get_cname ()));
+			override_func.block = new CCodeBlock ();
+
+			vcast = get_type_private_from_type ((ObjectTypeSymbol) m.parent_symbol, new CCodeIdentifier ("type"));
+
+			override_func.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (vcast, m.name), new CCodeIdentifier ("function"))));
+
+			source_type_member_definition.append (override_func);
+		}
+
+		if (m.entry_point) {
+			// m is possible entry point, add appropriate startup code
+			var cmain = new CCodeFunction ("main", "int");
+			cmain.line = function.line;
+			cmain.add_parameter (new CCodeFormalParameter ("argc", "int"));
+			cmain.add_parameter (new CCodeFormalParameter ("argv", "char **"));
+			var main_block = new CCodeBlock ();
+
+			var array_creation = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_new"));
+			array_creation.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("string_type_get")));
+			array_creation.add_argument (new CCodeIdentifier ("argc"));
+
+			var cdecl = new CCodeDeclaration ("DovaArray*");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("args", array_creation));
+			main_block.add_statement (cdecl);
+
+			var array_data = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
+			array_data.add_argument (new CCodeIdentifier ("args"));
+
+			cdecl = new CCodeDeclaration ("string**");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("args_data", array_data));
+			main_block.add_statement (cdecl);
+
+			cdecl = new CCodeDeclaration ("int");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("argi"));
+			main_block.add_statement (cdecl);
+
+			var string_creation = new CCodeFunctionCall (new CCodeIdentifier ("string_create_from_cstring"));
+			string_creation.add_argument (new CCodeElementAccess (new CCodeIdentifier ("argv"), new CCodeIdentifier ("argi")));
+
+			var loop_block = new CCodeBlock ();
+			loop_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier ("args_data"), new CCodeIdentifier ("argi")), string_creation)));
+
+			var for_stmt = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("argi"), new CCodeIdentifier ("argc")), loop_block);
+			for_stmt.add_initializer (new CCodeAssignment (new CCodeIdentifier ("argi"), new CCodeConstant ("0")));
+			for_stmt.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("argi")));
+			main_block.add_statement (for_stmt);
+
+			var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
+			if (m.get_parameters ().size == 1) {
+				main_call.add_argument (new CCodeIdentifier ("args"));
+			}
+			if (m.return_type is VoidType) {
+				// method returns void, always use 0 as exit code
+				var main_stmt = new CCodeExpressionStatement (main_call);
+				main_stmt.line = cmain.line;
+				main_block.add_statement (main_stmt);
+				var ret_stmt = new CCodeReturnStatement (new CCodeConstant ("0"));
+				ret_stmt.line = cmain.line;
+				main_block.add_statement (ret_stmt);
+			} else {
+				var main_stmt = new CCodeReturnStatement (main_call);
+				main_stmt.line = cmain.line;
+				main_block.add_statement (main_stmt);
+			}
+			cmain.block = main_block;
+			source_type_member_definition.append (cmain);
+		}
+	}
+
+	public override void visit_creation_method (CreationMethod m) {
+		bool visible = !m.is_private_symbol ();
+
+		head.visit_method (m);
+
+		DataType creturn_type;
+		if (current_type_symbol is Class) {
+			creturn_type = new ObjectType (current_class);
+		} else {
+			creturn_type = new VoidType ();
+		}
+
+		// do not generate _new functions for creation methods of abstract classes
+		if (current_type_symbol is Class && !current_class.is_abstract) {
+			var vfunc = new CCodeFunction (m.get_cname ());
+
+			var vblock = new CCodeBlock ();
+
+			var cdecl = new CCodeDeclaration ("%s *".printf (current_type_symbol.get_cname ()));
+			cdecl.add_declarator (new CCodeVariableDeclarator ("this"));
+			vblock.add_statement (cdecl);
+
+			source_declarations.add_include ("stddef.h");
+
+			var type_get = new CCodeFunctionCall (new CCodeIdentifier (current_class.get_lower_case_cname () + "_type_get"));
+			foreach (var type_param in current_class.get_type_parameters ()) {
+				type_get.add_argument (new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
+			}
+
+			var alloc_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_alloc"));
+			alloc_call.add_argument (type_get);
+			vblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("this"), new CCodeCastExpression (alloc_call, "%s *".printf (current_type_symbol.get_cname ())))));
+
+			// allocate memory for fields of generic types
+			// this is only a temporary measure until this can be allocated inline at the end of the instance
+			// this also won't work for subclasses of classes that have fields of generic types
+			foreach (var f in current_class.get_fields ()) {
+				if (f.binding != MemberBinding.INSTANCE || !(f.field_type is GenericType)) {
+					continue;
+				}
+
+				var generic_type = (GenericType) f.field_type;
+				var type_get_value_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_value_size"));
+				type_get_value_size.add_argument (new CCodeIdentifier ("%s_type".printf (generic_type.type_parameter.name.down ())));
+
+				var calloc_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
+				calloc_call.add_argument (new CCodeConstant ("1"));
+				calloc_call.add_argument (type_get_value_size);
+				var priv_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (current_class.get_upper_case_cname (null))));
+				priv_call.add_argument (new CCodeIdentifier ("this"));
+
+				vblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_call, f.name), calloc_call)));
+			}
+
+			var vcall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
+			vcall.add_argument (new CCodeIdentifier ("this"));
+			vblock.add_statement (new CCodeExpressionStatement (vcall));
+
+			generate_cparameters (m, source_declarations, vfunc, null, vcall);
+			CCodeStatement cstmt = new CCodeReturnStatement (new CCodeIdentifier ("this"));
+			cstmt.line = vfunc.line;
+			vblock.add_statement (cstmt);
+
+			if (!visible) {
+				vfunc.modifiers |= CCodeModifiers.STATIC;
+			}
+
+			source_declarations.add_type_member_declaration (vfunc.copy ());
+
+			vfunc.block = vblock;
+
+			source_type_member_definition.append (vfunc);
+		}
+	}
+
+	private TypeSymbol? find_parent_type (Symbol sym) {
+		while (sym != null) {
+			if (sym is TypeSymbol) {
+				return (TypeSymbol) sym;
+			}
+			sym = sym.parent_symbol;
+		}
+		return null;
+	}
+
+	public override void generate_cparameters (Method m, CCodeDeclarationSpace decl_space, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, CCodeFunctionCall? vcall = null) {
+		CCodeFormalParameter instance_param = null;
+		if (m.parent_symbol is Class && m is CreationMethod) {
+			if (vcall == null) {
+				instance_param = new CCodeFormalParameter ("this", ((Class) m.parent_symbol).get_cname () + "*");
+			}
+		} else if (m.binding == MemberBinding.INSTANCE || (m.parent_symbol is Struct && m is CreationMethod)) {
+			TypeSymbol parent_type = find_parent_type (m);
+			var this_type = get_data_type_for_symbol (parent_type);
+
+			generate_type_declaration (this_type, decl_space);
+
+			if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
+				var base_type = new ObjectType ((Interface) m.base_interface_method.parent_symbol);
+				instance_param = new CCodeFormalParameter ("this", base_type.get_cname ());
+			} else if (m.overrides) {
+				var base_type = new ObjectType ((Class) m.base_method.parent_symbol);
+				generate_type_declaration (base_type, decl_space);
+				instance_param = new CCodeFormalParameter ("this", base_type.get_cname ());
+			} else {
+				if (m.parent_symbol is Struct && m is CreationMethod) {
+					var st = (Struct) m.parent_symbol;
+					if (st.is_boolean_type () || st.is_integer_type () || st.is_floating_type ()) {
+						// use return value
+					} else {
+						instance_param = new CCodeFormalParameter ("*this", this_type.get_cname ());
+					}
+				} else {
+					instance_param = new CCodeFormalParameter ("this", this_type.get_cname ());
+				}
+			}
+		}
+		if (instance_param != null) {
+			func.add_parameter (instance_param);
+			if (vdeclarator != null) {
+				vdeclarator.add_parameter (instance_param);
+			}
+		}
+
+		if (m is CreationMethod) {
+			generate_class_declaration ((Class) type_class, decl_space);
+
+			if (m.parent_symbol is Class) {
+				int type_param_index = 0;
+				var cl = (Class) m.parent_symbol;
+				foreach (TypeParameter type_param in cl.get_type_parameters ()) {
+					var cparam = new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType*");
+					if (vcall != null) {
+						func.add_parameter (cparam);
+					}
+					type_param_index++;
+				}
+			}
+		} else {
+			int type_param_index = 0;
+			foreach (TypeParameter type_param in m.get_type_parameters ()) {
+				var cparam = new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType*");
+				func.add_parameter (cparam);
+				if (vdeclarator != null) {
+					vdeclarator.add_parameter (cparam);
+				}
+				if (vcall != null) {
+					vcall.add_argument (new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
+				}
+				type_param_index++;
+			}
+		}
+
+		foreach (FormalParameter param in m.get_parameters ()) {
+			CCodeFormalParameter cparam;
+			if (!param.ellipsis) {
+				string ctypename = param.parameter_type.get_cname ();
+
+				generate_type_declaration (param.parameter_type, decl_space);
+
+				if (param.direction != ParameterDirection.IN && !(param.parameter_type is GenericType)) {
+					ctypename += "*";
+				}
+
+				cparam = new CCodeFormalParameter (get_variable_cname (param.name), ctypename);
+			} else {
+				cparam = new CCodeFormalParameter.with_ellipsis ();
+			}
+
+			func.add_parameter (cparam);
+			if (vdeclarator != null) {
+				vdeclarator.add_parameter (cparam);
+			}
+			if (vcall != null) {
+				vcall.add_argument (get_variable_cexpression (param.name));
+			}
+		}
+
+		if (m.parent_symbol is Class && m is CreationMethod && vcall != null) {
+			func.return_type = ((Class) m.parent_symbol).get_cname () + "*";
+		} else {
+			if (m.return_type is GenericType) {
+				func.add_parameter (new CCodeFormalParameter ("result", "void *"));
+				if (vdeclarator != null) {
+					vdeclarator.add_parameter (new CCodeFormalParameter ("result", "void *"));
+				}
+			} else {
+				var st = m.parent_symbol as Struct;
+				if (m is CreationMethod && st != null && (st.is_boolean_type () || st.is_integer_type () || st.is_floating_type ())) {
+					func.return_type = st.get_cname ();
+				} else {
+					func.return_type = m.return_type.get_cname ();
+				}
+			}
+
+			generate_type_declaration (m.return_type, decl_space);
+		}
+	}
+
+	public override void visit_element_access (ElementAccess expr) {
+		var array_type = expr.container.value_type as ArrayType;
+		if (array_type != null) {
+			// access to element in an array
+
+			expr.accept_children (codegen);
+
+			List<Expression> indices = expr.get_indices ();
+			var cindex = (CCodeExpression) indices[0].ccodenode;
+
+			if (array_type.inline_allocated) {
+				expr.ccodenode = new CCodeElementAccess ((CCodeExpression) expr.container.ccodenode, cindex);
+			} else {
+				generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
+
+				var ccontainer = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
+				ccontainer.add_argument ((CCodeExpression) expr.container.ccodenode);
+				expr.ccodenode = new CCodeElementAccess (new CCodeCastExpression (ccontainer, "%s*".printf (array_type.element_type.get_cname ())), cindex);
+			}
+		} else {
+			base.visit_element_access (expr);
+		}
+	}
+}
diff --git a/codegen/valadovastructmodule.vala b/codegen/valadovastructmodule.vala
new file mode 100644
index 0000000..ba33a1a
--- /dev/null
+++ b/codegen/valadovastructmodule.vala
@@ -0,0 +1,101 @@
+/* valadovastructmodule.vala
+ *
+ * Copyright (C) 2006-2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+using GLib;
+
+internal class Vala.DovaStructModule : DovaBaseModule {
+	public DovaStructModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public override void generate_struct_declaration (Struct st, CCodeDeclarationSpace decl_space) {
+		if (decl_space.add_symbol_declaration (st, st.get_cname ())) {
+			return;
+		}
+
+		if (st.base_struct != null) {
+			generate_struct_declaration (st.base_struct, decl_space);
+
+			decl_space.add_type_declaration (new CCodeTypeDefinition (st.base_struct.get_cname (), new CCodeVariableDeclarator (st.get_cname ())));
+			return;
+		}
+
+		if (st.is_boolean_type ()) {
+			// typedef for boolean types
+			decl_space.add_include ("stdbool.h");
+			st.set_cname ("bool");
+			return;
+		} else if (st.is_integer_type ()) {
+			// typedef for integral types
+			decl_space.add_include ("stdint.h");
+			st.set_cname ("%sint%d_t".printf (st.signed ? "" : "u", st.width));
+			return;
+		} else if (st.is_decimal_floating_type ()) {
+			// typedef for decimal floating types
+			st.set_cname ("_Decimal%d".printf (st.width));
+			return;
+		} else if (st.is_floating_type ()) {
+			// typedef for generic floating types
+			st.set_cname (st.width == 64 ? "double" : "float");
+			return;
+		}
+
+		var instance_struct = new CCodeStruct ("_%s".printf (st.get_cname ()));
+
+		foreach (Field f in st.get_fields ()) {
+			string field_ctype = f.field_type.get_cname ();
+			if (f.is_volatile) {
+				field_ctype = "volatile " + field_ctype;
+			}
+
+			if (f.binding == MemberBinding.INSTANCE)  {
+				generate_type_declaration (f.field_type, decl_space);
+
+				instance_struct.add_field (field_ctype, f.get_cname () + f.field_type.get_cdeclarator_suffix ());
+			}
+		}
+
+		decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (st.get_cname ()), new CCodeVariableDeclarator (st.get_cname ())));
+
+		decl_space.add_type_definition (instance_struct);
+	}
+
+	public override void visit_struct (Struct st) {
+		var old_symbol = current_symbol;
+		var old_instance_finalize_fragment = instance_finalize_fragment;
+		current_symbol = st;
+		instance_finalize_fragment = new CCodeFragment ();
+
+		generate_struct_declaration (st, source_declarations);
+
+		if (!st.is_internal_symbol ()) {
+			generate_struct_declaration (st, header_declarations);
+		}
+		generate_struct_declaration (st, internal_header_declarations);
+
+		st.accept_children (codegen);
+
+		current_symbol = old_symbol;
+		instance_finalize_fragment = old_instance_finalize_fragment;
+	}
+}
+
diff --git a/codegen/valadovavaluemodule.vala b/codegen/valadovavaluemodule.vala
new file mode 100644
index 0000000..ca0d95e
--- /dev/null
+++ b/codegen/valadovavaluemodule.vala
@@ -0,0 +1,863 @@
+/* valadovavaluemodule.vala
+ *
+ * Copyright (C) 2009-2010  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+internal class Vala.DovaValueModule : DovaObjectModule {
+	public DovaValueModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public override void generate_class_declaration (Class cl, CCodeDeclarationSpace decl_space) {
+		if (cl.base_class == null ||
+		    cl.base_class.get_full_name () != "Dova.Value") {
+			base.generate_class_declaration (cl, decl_space);
+			return;
+		}
+
+		if (decl_space.add_symbol_declaration (cl, cl.get_cname ())) {
+			return;
+		}
+
+		var type_fun = new CCodeFunction ("%s_type_get".printf (cl.get_lower_case_cname ()), "DovaType *");
+		if (cl.access == SymbolAccessibility.PRIVATE) {
+			type_fun.modifiers = CCodeModifiers.STATIC;
+		}
+		decl_space.add_type_member_declaration (type_fun);
+
+		var type_init_fun = new CCodeFunction ("%s_type_init".printf (cl.get_lower_case_cname ()));
+		type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		if (cl.access == SymbolAccessibility.PRIVATE) {
+			type_init_fun.modifiers = CCodeModifiers.STATIC;
+		}
+		decl_space.add_type_member_declaration (type_init_fun);
+
+		var instance_struct = new CCodeStruct ("_%s".printf (cl.get_cname ()));
+
+		foreach (Field f in cl.get_fields ()) {
+			if (f.binding == MemberBinding.INSTANCE)  {
+				generate_type_declaration (f.field_type, decl_space);
+
+				string field_ctype = f.field_type.get_cname ();
+				if (f.is_volatile) {
+					field_ctype = "volatile " + field_ctype;
+				}
+
+				string cname = f.get_cname ();
+				var array_type = f.field_type as ArrayType;
+				if (array_type != null && array_type.inline_allocated) {
+					cname += "[]";
+				}
+
+				instance_struct.add_field (field_ctype, cname);
+			}
+		}
+
+		decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (cl.get_cname ()), new CCodeVariableDeclarator (cl.get_cname ())));
+		decl_space.add_type_definition (instance_struct);
+
+		if (cl.get_full_name () == "string") {
+			generate_method_declaration ((Method) cl.scope.lookup ("ref"), decl_space);
+			generate_method_declaration ((Method) cl.scope.lookup ("unref"), decl_space);
+		}
+	}
+
+	public override void visit_class (Class cl) {
+		if (cl.base_class == null ||
+		    cl.base_class.get_full_name () != "Dova.Value") {
+			base.visit_class (cl);
+			return;
+		}
+
+		var old_symbol = current_symbol;
+		current_symbol = cl;
+
+		generate_class_declaration (cl, source_declarations);
+
+		if (!cl.is_internal_symbol ()) {
+			generate_class_declaration (cl, header_declarations);
+		}
+		generate_class_declaration (cl, internal_header_declarations);
+
+
+		var cdecl = new CCodeDeclaration ("DovaType *");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("%s_type".printf (cl.get_lower_case_cname ()), new CCodeConstant ("NULL")));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_type_member_declaration (cdecl);
+
+		var type_fun = new CCodeFunction ("%s_type_get".printf (cl.get_lower_case_cname ()), "DovaType *");
+		type_fun.block = new CCodeBlock ();
+
+		var type_init_block = new CCodeBlock ();
+
+		generate_method_declaration ((Method) object_class.scope.lookup ("alloc"), source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("base_type")).set_accessor, source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("type_size")).get_accessor, source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("type_size")).set_accessor, source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("value_size")).set_accessor, source_declarations);
+
+		generate_class_declaration ((Class) context.root.scope.lookup ("Dova").scope.lookup ("Value"), source_declarations);
+
+		var base_type = new CCodeFunctionCall (new CCodeIdentifier ("dova_value_type_get"));
+
+		var base_type_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_type_size"));
+		base_type_size.add_argument (base_type);
+
+		var calloc_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
+		calloc_call.add_argument (new CCodeConstant ("1"));
+		calloc_call.add_argument (base_type_size);
+
+		type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())), calloc_call)));
+
+		generate_class_declaration ((Class) object_class, source_declarations);
+
+		type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())), "DovaObject *"), "type"), new CCodeFunctionCall (new CCodeIdentifier ("dova_type_type_get")))));
+
+		var set_base_type = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_base_type"));
+		set_base_type.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
+		set_base_type.add_argument (base_type);
+		type_init_block.add_statement (new CCodeExpressionStatement (set_base_type));
+
+		var set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_type_size"));
+		set_size.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
+		set_size.add_argument (base_type_size);
+		type_init_block.add_statement (new CCodeExpressionStatement (set_size));
+
+		var type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (cl.get_lower_case_cname ())));
+		type_init_call.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
+		type_init_block.add_statement (new CCodeExpressionStatement (type_init_call));
+
+		type_fun.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ()))), type_init_block));
+
+		type_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ()))));
+
+		source_type_member_definition.append (type_fun);
+
+		var type_init_fun = new CCodeFunction ("%s_type_init".printf (cl.get_lower_case_cname ()));
+		type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		type_init_fun.block = new CCodeBlock ();
+
+		type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_value_type_init"));
+		type_init_call.add_argument (new CCodeIdentifier ("type"));
+		type_init_fun.block.add_statement (new CCodeExpressionStatement (type_init_call));
+
+		declare_set_value_copy_function (source_declarations);
+
+		var value_copy_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_copy"));
+		value_copy_call.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
+		value_copy_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("string_copy"), "void (*)(void *, int32_t,  void *, int32_t)"));
+		type_init_fun.block.add_statement (new CCodeExpressionStatement (value_copy_call));
+
+		var function = new CCodeFunction ("string_copy", "void");
+		function.modifiers = CCodeModifiers.STATIC;
+		function.add_parameter (new CCodeFormalParameter ("dest", "string **"));
+		function.add_parameter (new CCodeFormalParameter ("dest_index", "int32_t"));
+		function.add_parameter (new CCodeFormalParameter ("src", "string **"));
+		function.add_parameter (new CCodeFormalParameter ("src_index", "int32_t"));
+
+		function.block = new CCodeBlock ();
+		var cfrag = new CCodeFragment ();
+		function.block.add_statement (cfrag);
+
+		var dest = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("dest"), new CCodeIdentifier ("dest_index"));
+		var src = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("src"), new CCodeIdentifier ("src_index"));
+
+		var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("string_unref"));
+		unref_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest));
+		var unref_block = new CCodeBlock ();
+		unref_block.add_statement (new CCodeExpressionStatement (unref_call));
+		unref_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), new CCodeConstant ("NULL"))));
+		function.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), unref_block));
+
+		var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("string_ref"));
+		ref_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, src));
+		var ref_block = new CCodeBlock ();
+		ref_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), ref_call)));
+		function.block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("src"), ref_block));
+
+		source_type_member_definition.append (function);
+
+		if (cl.scope.lookup ("equal") is Method) {
+			var value_equal_fun = new CCodeFunction ("%s_value_equal".printf (cl.get_lower_case_cname ()), "bool");
+			value_equal_fun.modifiers = CCodeModifiers.STATIC;
+			value_equal_fun.add_parameter (new CCodeFormalParameter ("value", cl.get_cname () + "**"));
+			value_equal_fun.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
+			value_equal_fun.add_parameter (new CCodeFormalParameter ("other", cl.get_cname () + "**"));
+			value_equal_fun.add_parameter (new CCodeFormalParameter ("other_index", "int32_t"));
+			value_equal_fun.block = new CCodeBlock ();
+			var val = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("value"), new CCodeIdentifier ("value_index"));
+			var other = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("other"), new CCodeIdentifier ("other_index"));
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_equal".printf (cl.get_lower_case_cname ())));
+			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, val));
+			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, other));
+			value_equal_fun.block.add_statement (new CCodeReturnStatement (ccall));
+			source_type_member_definition.append (value_equal_fun);
+
+			declare_set_value_equal_function (source_declarations);
+
+			var value_equal_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_equal"));
+			value_equal_call.add_argument (new CCodeIdentifier ("type"));
+			value_equal_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("%s_value_equal".printf (cl.get_lower_case_cname ())), "bool (*)(void *, int32_t,  void *, int32_t)"));
+			type_init_fun.block.add_statement (new CCodeExpressionStatement (value_equal_call));
+		}
+
+		if (cl.scope.lookup ("hash") is Method) {
+			var value_hash_fun = new CCodeFunction ("%s_value_hash".printf (cl.get_lower_case_cname ()), "int32_t");
+			value_hash_fun.modifiers = CCodeModifiers.STATIC;
+			value_hash_fun.add_parameter (new CCodeFormalParameter ("value", cl.get_cname () + "**"));
+			value_hash_fun.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
+			value_hash_fun.block = new CCodeBlock ();
+			var val = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("value"), new CCodeIdentifier ("value_index"));
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_hash".printf (cl.get_lower_case_cname ())));
+			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, val));
+			value_hash_fun.block.add_statement (new CCodeReturnStatement (ccall));
+			source_type_member_definition.append (value_hash_fun);
+
+			declare_set_value_hash_function (source_declarations);
+
+			var value_hash_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_hash"));
+			value_hash_call.add_argument (new CCodeIdentifier ("type"));
+			value_hash_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("%s_value_hash".printf (cl.get_lower_case_cname ())), "int32_t (*)(void *, int32_t)"));
+			type_init_fun.block.add_statement (new CCodeExpressionStatement (value_hash_call));
+		}
+
+		source_type_member_definition.append (type_init_fun);
+
+		cl.accept_children (codegen);
+
+		current_symbol = old_symbol;
+	}
+
+	public override void visit_creation_method (CreationMethod m) {
+		if (current_type_symbol is Class &&
+		    (current_class.base_class == null ||
+		     current_class.base_class.get_full_name () != "Dova.Value")) {
+			base.visit_creation_method (m);
+			return;
+		}
+
+		visit_method (m);
+	}
+
+	public override void generate_struct_declaration (Struct st, CCodeDeclarationSpace decl_space) {
+		base.generate_struct_declaration (st, decl_space);
+
+		if (decl_space.add_symbol_declaration (st, st.get_copy_function ())) {
+			return;
+		}
+
+		decl_space.add_include ("stdint.h");
+
+		generate_class_declaration (type_class, decl_space);
+
+		var type_fun = new CCodeFunction ("%s_type_get".printf (st.get_lower_case_cname ()), "DovaType *");
+		if (st.access == SymbolAccessibility.PRIVATE) {
+			type_fun.modifiers = CCodeModifiers.STATIC;
+		}
+		decl_space.add_type_member_declaration (type_fun);
+
+		var type_init_fun = new CCodeFunction ("%s_type_init".printf (st.get_lower_case_cname ()));
+		type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		if (st.access == SymbolAccessibility.PRIVATE) {
+			type_init_fun.modifiers = CCodeModifiers.STATIC;
+		}
+		decl_space.add_type_member_declaration (type_init_fun);
+
+		var function = new CCodeFunction (st.get_copy_function (), "void");
+		if (st.access == SymbolAccessibility.PRIVATE) {
+			function.modifiers = CCodeModifiers.STATIC;
+		}
+
+		function.add_parameter (new CCodeFormalParameter ("dest", st.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("dest_index", "int32_t"));
+		function.add_parameter (new CCodeFormalParameter ("src", st.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("src_index", "int32_t"));
+
+		decl_space.add_type_member_declaration (function);
+	}
+
+	public override void visit_struct (Struct st) {
+		base.visit_struct (st);
+
+		source_declarations.add_include ("stddef.h");
+		// calloc
+		source_declarations.add_include ("stdlib.h");
+
+		var cdecl = new CCodeDeclaration ("DovaType *");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("%s_type".printf (st.get_lower_case_cname ()), new CCodeConstant ("NULL")));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_type_member_declaration (cdecl);
+
+		var type_fun = new CCodeFunction ("%s_type_get".printf (st.get_lower_case_cname ()), "DovaType *");
+		type_fun.block = new CCodeBlock ();
+
+		var type_init_block = new CCodeBlock ();
+
+		generate_method_declaration ((Method) object_class.scope.lookup ("alloc"), source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("base_type")).get_accessor, source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("base_type")).set_accessor, source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("object_size")).get_accessor, source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("object_size")).set_accessor, source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("type_size")).get_accessor, source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("type_size")).set_accessor, source_declarations);
+		generate_property_accessor_declaration (((Property) type_class.scope.lookup ("value_size")).set_accessor, source_declarations);
+
+		generate_class_declaration ((Class) context.root.scope.lookup ("Dova").scope.lookup ("Value"), source_declarations);
+
+		var base_type = new CCodeFunctionCall (new CCodeIdentifier ("dova_value_type_get"));
+
+		var base_type_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_type_size"));
+		base_type_size.add_argument (base_type);
+
+		var calloc_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
+		calloc_call.add_argument (new CCodeConstant ("1"));
+		calloc_call.add_argument (base_type_size);
+
+		type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())), calloc_call)));
+
+		generate_class_declaration ((Class) object_class, source_declarations);
+
+		type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())), "DovaObject *"), "type"), new CCodeFunctionCall (new CCodeIdentifier ("dova_type_type_get")))));
+
+		var set_base_type = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_base_type"));
+		set_base_type.add_argument (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())));
+		set_base_type.add_argument (base_type);
+		type_init_block.add_statement (new CCodeExpressionStatement (set_base_type));
+
+		var base_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_object_size"));
+		base_size.add_argument (base_type);
+
+		var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+		sizeof_call.add_argument (new CCodeIdentifier (st.get_cname ()));
+		var set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_object_size"));
+		set_size.add_argument (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())));
+		set_size.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, base_size, sizeof_call));
+		type_init_block.add_statement (new CCodeExpressionStatement (set_size));
+
+		set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_size"));
+		set_size.add_argument (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())));
+		set_size.add_argument (sizeof_call);
+		type_init_block.add_statement (new CCodeExpressionStatement (set_size));
+
+		set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_type_size"));
+		set_size.add_argument (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())));
+		set_size.add_argument (base_type_size);
+		type_init_block.add_statement (new CCodeExpressionStatement (set_size));
+
+		var type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (st.get_lower_case_cname ())));
+		type_init_call.add_argument (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())));
+		type_init_block.add_statement (new CCodeExpressionStatement (type_init_call));
+
+		type_fun.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ()))), type_init_block));
+
+		type_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ()))));
+
+		source_type_member_definition.append (type_fun);
+
+		var type_init_fun = new CCodeFunction ("%s_type_init".printf (st.get_lower_case_cname ()));
+		type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
+		type_init_fun.block = new CCodeBlock ();
+
+		type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_value_type_init"));
+		type_init_call.add_argument (new CCodeIdentifier ("type"));
+		type_init_fun.block.add_statement (new CCodeExpressionStatement (type_init_call));
+
+		declare_set_value_copy_function (source_declarations);
+
+		var value_copy_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_copy"));
+		value_copy_call.add_argument (new CCodeIdentifier ("type"));
+		value_copy_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("%s_copy".printf (st.get_lower_case_cname ())), "void (*)(void *, int32_t,  void *, int32_t)"));
+		type_init_fun.block.add_statement (new CCodeExpressionStatement (value_copy_call));
+
+		if (st.scope.lookup ("equal") is Method) {
+			var value_equal_fun = new CCodeFunction ("%s_value_equal".printf (st.get_lower_case_cname ()), "bool");
+			value_equal_fun.modifiers = CCodeModifiers.STATIC;
+			value_equal_fun.add_parameter (new CCodeFormalParameter ("value", st.get_cname () + "*"));
+			value_equal_fun.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
+			value_equal_fun.add_parameter (new CCodeFormalParameter ("other", st.get_cname () + "*"));
+			value_equal_fun.add_parameter (new CCodeFormalParameter ("other_index", "int32_t"));
+			value_equal_fun.block = new CCodeBlock ();
+			var val = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("value"), new CCodeIdentifier ("value_index"));
+			var other = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("other"), new CCodeIdentifier ("other_index"));
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_equal".printf (st.get_lower_case_cname ())));
+			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, val));
+			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, other));
+			value_equal_fun.block.add_statement (new CCodeReturnStatement (ccall));
+			source_type_member_definition.append (value_equal_fun);
+
+			declare_set_value_equal_function (source_declarations);
+
+			var value_equal_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_equal"));
+			value_equal_call.add_argument (new CCodeIdentifier ("type"));
+			value_equal_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("%s_value_equal".printf (st.get_lower_case_cname ())), "bool (*)(void *, int32_t,  void *, int32_t)"));
+			type_init_fun.block.add_statement (new CCodeExpressionStatement (value_equal_call));
+		}
+
+		if (st.scope.lookup ("hash") is Method) {
+			var value_hash_fun = new CCodeFunction ("%s_value_hash".printf (st.get_lower_case_cname ()), "int32_t");
+			value_hash_fun.modifiers = CCodeModifiers.STATIC;
+			value_hash_fun.add_parameter (new CCodeFormalParameter ("value", st.get_cname () + "*"));
+			value_hash_fun.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
+			value_hash_fun.block = new CCodeBlock ();
+			var val = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("value"), new CCodeIdentifier ("value_index"));
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_hash".printf (st.get_lower_case_cname ())));
+			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, val));
+			value_hash_fun.block.add_statement (new CCodeReturnStatement (ccall));
+			source_type_member_definition.append (value_hash_fun);
+
+			declare_set_value_hash_function (source_declarations);
+
+			var value_hash_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_hash"));
+			value_hash_call.add_argument (new CCodeIdentifier ("type"));
+			value_hash_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("%s_value_hash".printf (st.get_lower_case_cname ())), "int32_t (*)(void *, int32_t)"));
+			type_init_fun.block.add_statement (new CCodeExpressionStatement (value_hash_call));
+		}
+
+		source_type_member_definition.append (type_init_fun);
+
+		add_struct_copy_function (st);
+	}
+
+	void add_struct_copy_function (Struct st) {
+		var function = new CCodeFunction (st.get_copy_function (), "void");
+		if (st.access == SymbolAccessibility.PRIVATE) {
+			function.modifiers = CCodeModifiers.STATIC;
+		}
+
+		function.add_parameter (new CCodeFormalParameter ("dest", st.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("dest_index", "int32_t"));
+		function.add_parameter (new CCodeFormalParameter ("src", st.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("src_index", "int32_t"));
+
+		var cblock = new CCodeBlock ();
+		var cfrag = new CCodeFragment ();
+		cblock.add_statement (cfrag);
+
+		var dest = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("dest"), new CCodeIdentifier ("dest_index"));
+		var src = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("src"), new CCodeIdentifier ("src_index"));
+
+		foreach (var f in st.get_fields ()) {
+			if (f.binding == MemberBinding.INSTANCE) {
+				var field = new CCodeMemberAccess.pointer (dest, f.name);
+
+				var array_type = f.field_type as ArrayType;
+				if (array_type != null && array_type.fixed_length) {
+					for (int i = 0; i < array_type.length; i++) {
+						var element = new CCodeElementAccess (field, new CCodeConstant (i.to_string ()));
+
+						if (requires_destroy (array_type.element_type))  {
+							cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (element, array_type.element_type)));
+						}
+					}
+					continue;
+				}
+
+				if (requires_destroy (f.field_type))  {
+					var this_access = new MemberAccess.simple ("this");
+					this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
+					this_access.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest);
+					var ma = new MemberAccess (this_access, f.name);
+					ma.symbol_reference = f;
+					ma.value_type = f.field_type.copy ();
+					cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (field, f.field_type, ma)));
+				}
+			}
+		}
+
+		var copy_block = new CCodeBlock ();
+
+		if (st.get_fields ().size == 0) {
+			copy_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, src))));
+		} else {
+			foreach (var f in st.get_fields ()) {
+				if (f.binding == MemberBinding.INSTANCE) {
+					CCodeExpression copy = new CCodeMemberAccess.pointer (src, f.name);
+					var dest_field = new CCodeMemberAccess.pointer (dest, f.name);
+
+					var array_type = f.field_type as ArrayType;
+					if (array_type != null && array_type.fixed_length) {
+						for (int i = 0; i < array_type.length; i++) {
+							CCodeExpression copy_element = new CCodeElementAccess (copy, new CCodeConstant (i.to_string ()));
+							var dest_field_element = new CCodeElementAccess (dest_field, new CCodeConstant (i.to_string ()));
+
+							if (requires_copy (array_type.element_type))  {
+								copy_element = get_ref_cexpression (array_type.element_type, copy_element, null, f);
+							}
+
+							copy_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dest_field_element, copy_element)));
+						}
+						continue;
+					}
+
+					if (requires_copy (f.field_type))  {
+						var this_access = new MemberAccess.simple ("this");
+						this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
+						this_access.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, src);
+						var ma = new MemberAccess (this_access, f.name);
+						ma.symbol_reference = f;
+						copy = get_ref_cexpression (f.field_type, copy, ma, f);
+					}
+
+					copy_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dest_field, copy)));
+				}
+			}
+		}
+
+		cblock.add_statement (new CCodeIfStatement (new CCodeIdentifier ("src"), copy_block));
+
+		append_temp_decl (cfrag, temp_vars);
+		temp_vars.clear ();
+
+		function.block = cblock;
+
+		source_type_member_definition.append (function);
+	}
+
+	public override void visit_assignment (Assignment assignment) {
+		var generic_type = assignment.left.value_type as GenericType;
+		if (generic_type == null) {
+			base.visit_assignment (assignment);
+			return;
+		}
+
+		var dest = assignment.left;
+		CCodeExpression cdest;
+		CCodeExpression dest_index = new CCodeConstant ("0");
+		var src = assignment.right;
+		CCodeExpression csrc;
+		CCodeExpression src_index = new CCodeConstant ("0");
+
+		if (src is NullLiteral) {
+			// TODO destroy dest
+			assignment.ccodenode = new CCodeConstant ("0");
+			return;
+		}
+
+		var dest_ea = dest as ElementAccess;
+		var src_ea = src as ElementAccess;
+
+		if (dest_ea != null) {
+			dest = dest_ea.container;
+
+			var array_type = dest.value_type as ArrayType;
+			if (array_type != null && !array_type.inline_allocated) {
+				generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
+
+				var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
+				data_call.add_argument ((CCodeExpression) get_ccodenode (dest));
+				cdest = data_call;
+			} else {
+				cdest = (CCodeExpression) get_ccodenode (dest);
+			}
+			dest_index = (CCodeExpression) get_ccodenode (dest_ea.get_indices ().get (0));
+		} else {
+			cdest = (CCodeExpression) get_ccodenode (dest);
+		}
+
+		if (src_ea != null) {
+			src = src_ea.container;
+
+			var array_type = src.value_type as ArrayType;
+			if (array_type != null && !array_type.inline_allocated) {
+				generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
+
+				var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
+				data_call.add_argument ((CCodeExpression) get_ccodenode (src));
+				csrc = data_call;
+			} else {
+				csrc = (CCodeExpression) get_ccodenode (src);
+			}
+			src_index = (CCodeExpression) get_ccodenode (src_ea.get_indices ().get (0));
+		} else {
+			csrc = (CCodeExpression) get_ccodenode (src);
+		}
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_value_copy"));
+		if (generic_type.type_parameter.parent_symbol is TypeSymbol) {
+			// generic type
+			ccall.add_argument (new CCodeMemberAccess.pointer (get_type_private_from_type ((ObjectTypeSymbol) generic_type.type_parameter.parent_symbol, new CCodeMemberAccess.pointer (new CCodeIdentifier ("this"), "type")), "%s_type".printf (generic_type.type_parameter.name.down ())));
+		} else {
+			// generic method
+			ccall.add_argument (new CCodeIdentifier ("%s_type".printf (generic_type.type_parameter.name.down ())));
+		}
+		ccall.add_argument (cdest);
+		ccall.add_argument (dest_index);
+		ccall.add_argument (csrc);
+		ccall.add_argument (src_index);
+		assignment.ccodenode = ccall;
+	}
+
+	public override void visit_binary_expression (BinaryExpression expr) {
+		var generic_type = expr.left.value_type as GenericType;
+		if (generic_type == null) {
+			base.visit_binary_expression (expr);
+			return;
+		}
+
+		CCodeExpression cleft;
+		CCodeExpression left_index = new CCodeConstant ("0");
+		CCodeExpression cright;
+		CCodeExpression right_index = new CCodeConstant ("0");
+
+		var left_ea = expr.left as ElementAccess;
+		var right_ea = expr.right as ElementAccess;
+
+		if (left_ea != null) {
+			generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
+
+			var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
+			data_call.add_argument ((CCodeExpression) get_ccodenode (left_ea.container));
+			cleft = data_call;
+			left_index = (CCodeExpression) get_ccodenode (left_ea.get_indices ().get (0));
+		} else {
+			cleft = (CCodeExpression) get_ccodenode (expr.left);
+		}
+
+		if (right_ea != null) {
+			generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
+
+			var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
+			data_call.add_argument ((CCodeExpression) get_ccodenode (right_ea.container));
+			cright = data_call;
+			right_index = (CCodeExpression) get_ccodenode (right_ea.get_indices ().get (0));
+		} else {
+			cright = (CCodeExpression) get_ccodenode (expr.right);
+		}
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_value_equal"));
+		ccall.add_argument (get_type_id_expression (generic_type));
+		ccall.add_argument (cleft);
+		ccall.add_argument (left_index);
+		ccall.add_argument (cright);
+		ccall.add_argument (right_index);
+
+		if (expr.operator == BinaryOperator.EQUALITY) {
+			expr.ccodenode = ccall;
+		} else {
+			expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
+		}
+	}
+
+	public override void visit_method_call (MethodCall expr) {
+		var ma = expr.call as MemberAccess;
+		if (ma == null || ma.inner == null || !(ma.inner.value_type is GenericType)) {
+			base.visit_method_call (expr);
+			return;
+		}
+
+		// handle method calls on generic types
+
+		expr.accept_children (codegen);
+
+		if (ma.member_name == "hash") {
+			var val = ma.inner;
+			CCodeExpression cval;
+			CCodeExpression val_index = new CCodeConstant ("0");
+
+			var val_ea = val as ElementAccess;
+			if (val_ea != null) {
+				val = val_ea.container;
+
+				generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
+
+				var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
+				data_call.add_argument ((CCodeExpression) get_ccodenode (val));
+				cval = data_call;
+				val_index = (CCodeExpression) get_ccodenode (val_ea.get_indices ().get (0));
+			} else {
+				cval = (CCodeExpression) get_ccodenode (val);
+			}
+
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_value_hash"));
+			ccall.add_argument (get_type_id_expression (ma.inner.value_type));
+			ccall.add_argument (cval);
+			ccall.add_argument (val_index);
+
+			expr.ccodenode = ccall;
+		}
+	}
+
+	public override void visit_list_literal (ListLiteral expr) {
+		expr.accept_children (codegen);
+
+		var array_type = new ArrayType (expr.element_type, 1, expr.source_reference);
+		array_type.inline_allocated = true;
+		array_type.fixed_length = true;
+		array_type.length = expr.get_expressions ().size;
+
+		var ce = new CCodeCommaExpression ();
+		var temp_var = get_temp_variable (array_type, true, expr);
+		var name_cnode = get_variable_cexpression (temp_var.name);
+
+		temp_vars.insert (0, temp_var);
+
+		int i = 0;
+		foreach (Expression e in expr.get_expressions ()) {
+			ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode));
+			i++;
+		}
+
+		ce.append_expression (name_cnode);
+
+		var list_creation = new CCodeFunctionCall (new CCodeIdentifier ("dova_list_new"));
+		list_creation.add_argument (get_type_id_expression (expr.element_type));
+		list_creation.add_argument (new CCodeConstant (array_type.length.to_string ()));
+		list_creation.add_argument (ce);
+
+		expr.ccodenode = list_creation;
+	}
+
+	public override void visit_set_literal (SetLiteral expr) {
+		expr.accept_children (codegen);
+
+		var array_type = new ArrayType (expr.element_type, 1, expr.source_reference);
+		array_type.inline_allocated = true;
+		array_type.fixed_length = true;
+		array_type.length = expr.get_expressions ().size;
+
+		var ce = new CCodeCommaExpression ();
+		var temp_var = get_temp_variable (array_type, true, expr);
+		var name_cnode = get_variable_cexpression (temp_var.name);
+
+		temp_vars.insert (0, temp_var);
+
+		int i = 0;
+		foreach (Expression e in expr.get_expressions ()) {
+			ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode));
+			i++;
+		}
+
+		ce.append_expression (name_cnode);
+
+		var set_creation = new CCodeFunctionCall (new CCodeIdentifier ("dova_set_new"));
+		set_creation.add_argument (get_type_id_expression (expr.element_type));
+		set_creation.add_argument (new CCodeConstant (array_type.length.to_string ()));
+		set_creation.add_argument (ce);
+
+		expr.ccodenode = set_creation;
+	}
+
+	public override void visit_map_literal (MapLiteral expr) {
+		expr.accept_children (codegen);
+
+		var key_array_type = new ArrayType (expr.map_key_type, 1, expr.source_reference);
+		key_array_type.inline_allocated = true;
+		key_array_type.fixed_length = true;
+		key_array_type.length = expr.get_keys ().size;
+
+		var key_ce = new CCodeCommaExpression ();
+		var key_temp_var = get_temp_variable (key_array_type, true, expr);
+		var key_name_cnode = get_variable_cexpression (key_temp_var.name);
+
+		temp_vars.insert (0, key_temp_var);
+
+		var value_array_type = new ArrayType (expr.map_value_type, 1, expr.source_reference);
+		value_array_type.inline_allocated = true;
+		value_array_type.fixed_length = true;
+		value_array_type.length = expr.get_values ().size;
+
+		var value_ce = new CCodeCommaExpression ();
+		var value_temp_var = get_temp_variable (value_array_type, true, expr);
+		var value_name_cnode = get_variable_cexpression (value_temp_var.name);
+
+		temp_vars.insert (0, value_temp_var);
+
+		for (int i = 0; i < expr.get_keys ().size; i++) {
+			key_ce.append_expression (new CCodeAssignment (new CCodeElementAccess (key_name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) expr.get_keys ().get (i).ccodenode));
+			value_ce.append_expression (new CCodeAssignment (new CCodeElementAccess (value_name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) expr.get_values ().get (i).ccodenode));
+		}
+
+		key_ce.append_expression (key_name_cnode);
+		value_ce.append_expression (value_name_cnode);
+
+		var map_creation = new CCodeFunctionCall (new CCodeIdentifier ("dova_map_new"));
+		map_creation.add_argument (get_type_id_expression (expr.map_key_type));
+		map_creation.add_argument (get_type_id_expression (expr.map_value_type));
+		map_creation.add_argument (new CCodeConstant (key_array_type.length.to_string ()));
+		map_creation.add_argument (key_ce);
+		map_creation.add_argument (value_ce);
+
+		expr.ccodenode = map_creation;
+	}
+
+	public override void visit_tuple (Tuple tuple) {
+		tuple.accept_children (codegen);
+
+		var type_array_type = new ArrayType (new PointerType (new VoidType ()), 1, tuple.source_reference);
+		type_array_type.inline_allocated = true;
+		type_array_type.fixed_length = true;
+		type_array_type.length = tuple.get_expressions ().size;
+
+		var type_temp_var = get_temp_variable (type_array_type, true, tuple);
+		var type_name_cnode = get_variable_cexpression (type_temp_var.name);
+		temp_vars.insert (0, type_temp_var);
+
+		var array_type = new ArrayType (new PointerType (new VoidType ()), 1, tuple.source_reference);
+		array_type.inline_allocated = true;
+		array_type.fixed_length = true;
+		array_type.length = tuple.get_expressions ().size;
+
+		var temp_var = get_temp_variable (array_type, true, tuple);
+		var name_cnode = get_variable_cexpression (temp_var.name);
+		temp_vars.insert (0, temp_var);
+
+		var type_ce = new CCodeCommaExpression ();
+		var ce = new CCodeCommaExpression ();
+
+		int i = 0;
+		foreach (Expression e in tuple.get_expressions ()) {
+			var element_type = tuple.value_type.get_type_arguments ().get (i);
+
+			type_ce.append_expression (new CCodeAssignment (new CCodeElementAccess (type_name_cnode, new CCodeConstant (i.to_string ())), get_type_id_expression (element_type)));
+
+			var cexpr = (CCodeExpression) e.ccodenode;
+
+			var unary = cexpr as CCodeUnaryExpression;
+			if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
+				// *expr => expr
+				cexpr = unary.inner;
+			} else if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
+				cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
+			} else {
+				// if cexpr is e.g. a function call, we can't take the address of the expression
+				// tmp = expr, &tmp
+
+				var element_temp_var = get_temp_variable (element_type);
+				temp_vars.insert (0, element_temp_var);
+				ce.append_expression (new CCodeAssignment (get_variable_cexpression (element_temp_var.name), cexpr));
+				cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (element_temp_var.name));
+			}
+
+			ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), cexpr));
+
+			i++;
+		}
+
+		type_ce.append_expression (type_name_cnode);
+		ce.append_expression (name_cnode);
+
+		var tuple_creation = new CCodeFunctionCall (new CCodeIdentifier ("dova_tuple_new"));
+		tuple_creation.add_argument (new CCodeConstant (tuple.get_expressions ().size.to_string ()));
+		tuple_creation.add_argument (type_ce);
+		tuple_creation.add_argument (ce);
+
+		tuple.ccodenode = tuple_creation;
+	}
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]