]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
dova: Add experimental backend
authorJürg Billeter <j@bitron.ch>
Sat, 5 Jun 2010 08:02:19 +0000 (10:02 +0200)
committerJürg Billeter <j@bitron.ch>
Sat, 5 Jun 2010 08:38:08 +0000 (10:38 +0200)
14 files changed:
ccode/valaccodefunction.vala
codegen/Makefile.am
codegen/valaccodegenerator.vala
codegen/valadovaarraymodule.vala [new file with mode: 0644]
codegen/valadovaassignmentmodule.vala [new file with mode: 0644]
codegen/valadovabasemodule.vala [new file with mode: 0644]
codegen/valadovacontrolflowmodule.vala [new file with mode: 0644]
codegen/valadovadelegatemodule.vala [new file with mode: 0644]
codegen/valadovamemberaccessmodule.vala [new file with mode: 0644]
codegen/valadovamethodcallmodule.vala [new file with mode: 0644]
codegen/valadovamethodmodule.vala [new file with mode: 0644]
codegen/valadovaobjectmodule.vala [new file with mode: 0644]
codegen/valadovastructmodule.vala [new file with mode: 0644]
codegen/valadovavaluemodule.vala [new file with mode: 0644]

index 2b3775ddf037e6dd0b365070d142fc97509f3bab..faac0ec941f0b4c6d164808917e58c6411ea4af4 100644 (file)
@@ -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.
         *
index 511b071090fc350f55dd7681a17dd5dd4363a0ea..c62b6f6eb2a23413dfcaa07b8d161d62a7959a1b 100644 (file)
@@ -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 \
index 4853e70696813741de8e3f10dccc352e21fa1f79..e2155cf74763339a90cf80a3ceca63a48e89ce3c 100644 (file)
@@ -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 (file)
index 0000000..83ddd45
--- /dev/null
@@ -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 (file)
index 0000000..1c400b7
--- /dev/null
@@ -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 (file)
index 0000000..f58a525
--- /dev/null
@@ -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 (file)
index 0000000..6616dcc
--- /dev/null
@@ -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 (file)
index 0000000..c82f4c5
--- /dev/null
@@ -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 (file)
index 0000000..0be4ff2
--- /dev/null
@@ -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 (file)
index 0000000..aca9570
--- /dev/null
@@ -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 (file)
index 0000000..4be1b8d
--- /dev/null
@@ -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 (file)
index 0000000..276cbf5
--- /dev/null
@@ -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 (file)
index 0000000..ba33a1a
--- /dev/null
@@ -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 (file)
index 0000000..ca0d95e
--- /dev/null
@@ -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;
+       }
+}