Add CCodeCreationMethodBinding and CCodeMethodBinding classes
authorJuerg Billeter <j@bitron.ch>
Sat, 19 Apr 2008 06:35:09 +0000 (06:35 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Sat, 19 Apr 2008 06:35:09 +0000 (06:35 +0000)
2008-04-19  Juerg Billeter  <j@bitron.ch>

* gobject/Makefile.am, gobject/valaccodecreationmethodbinding.vala,
  gobject/valaccodegenerator.vala, gobject/valaccodemethodbinding.vala,
  vala/valacreationmethod.vala:

  Add CCodeCreationMethodBinding and CCodeMethodBinding classes

svn path=/trunk/; revision=1261

ChangeLog
gobject/Makefile.am
gobject/valaccodecreationmethodbinding.vala [new file with mode: 0644]
gobject/valaccodegenerator.vala
gobject/valaccodegeneratormethod.vala [deleted file]
gobject/valaccodemethodbinding.vala
vala/valacreationmethod.vala

index 7970b92..8f465da 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2008-04-19  Jürg Billeter  <j@bitron.ch>
 
+       * gobject/Makefile.am, gobject/valaccodecreationmethodbinding.vala,
+         gobject/valaccodegenerator.vala, gobject/valaccodemethodbinding.vala,
+         vala/valacreationmethod.vala:
+
+         Add CCodeCreationMethodBinding and CCodeMethodBinding classes
+
+2008-04-19  Jürg Billeter  <j@bitron.ch>
+
        * vala/valaclass.vala, vala/valainterface.vala, gobject/Makefile.am,
          gobject/valaccodeassignmentbinding.vala,
          gobject/valaccodebinding.vala, gobject/valaccodeclassbinding.vala,
index 1787883..7ab1cc7 100644 (file)
@@ -17,12 +17,12 @@ libvala_la_VALASOURCES = \
        valaccodebinding.vala \
        valaccodeclassbinding.vala \
        valaccodecompiler.vala \
+       valaccodecreationmethodbinding.vala \
        valaccodeelementaccessbinding.vala \
        valaccodeexpressionbinding.vala \
        valaccodegenerator.vala \
        valaccodegeneratorinvocationexpression.vala \
        valaccodegeneratormemberaccess.vala \
-       valaccodegeneratormethod.vala \
        valaccodegeneratorsignal.vala \
        valaccodegeneratorsourcefile.vala \
        valaccodegeneratorstruct.vala \
diff --git a/gobject/valaccodecreationmethodbinding.vala b/gobject/valaccodecreationmethodbinding.vala
new file mode 100644 (file)
index 0000000..a76ac53
--- /dev/null
@@ -0,0 +1,58 @@
+/* valaccodecreationmethodbinding.vala
+ *
+ * Copyright (C) 2007-2008  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;
+using Gee;
+
+/**
+ * The link between a creation method and generated code.
+ */
+public class Vala.CCodeCreationMethodBinding : CCodeMethodBinding {
+       public CreationMethod creation_method { get; set; }
+
+       public CCodeCreationMethodBinding (CCodeGenerator codegen, CreationMethod creation_method) {
+               this.creation_method = creation_method;
+               this.method = creation_method;
+               this.codegen = codegen;
+       }
+
+       public override void emit () {
+               var m = creation_method;
+
+               if (m.body != null && codegen.current_type_symbol is Class && codegen.current_class.is_subtype_of (codegen.gobject_type)) {
+                       int n_params = 0;
+                       foreach (Statement stmt in m.body.get_statements ()) {
+                               if (!(stmt is ExpressionStatement) || ((ExpressionStatement) stmt).assigned_property () == null) {
+                                       m.error = true;
+                                       Report.error (stmt.source_reference, "class creation methods only allow property assignment statements");
+                                       return;
+                               }
+                               if (((ExpressionStatement) stmt).assigned_property ().set_accessor.construction) {
+                                       n_params++;
+                               }
+                       }
+                       m.n_construction_params = n_params;
+               }
+
+               base.emit ();
+       }
+}
index d8e0bcf..40e91dd 100644 (file)
@@ -28,7 +28,7 @@ using Gee;
  * Code visitor generating C Code.
  */
 public class Vala.CCodeGenerator : CodeGenerator {
-       private CodeContext context;
+       public CodeContext context;
        
        public Symbol root_symbol;
        public Symbol current_symbol;
@@ -77,12 +77,12 @@ public class Vala.CCodeGenerator : CodeGenerator {
        /* (constant) hash table with all C keywords */
        public Gee.Set<string> c_keywords;
        
-       private int next_temp_var_id = 0;
+       public int next_temp_var_id = 0;
        private int current_try_id = 0;
        private int next_try_id = 0;
        public bool in_creation_method = false;
        private bool in_constructor = false;
-       private bool current_method_inner_error = false;
+       public bool current_method_inner_error = false;
 
        public DataType bool_type;
        public DataType char_type;
@@ -120,7 +120,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
        public bool in_plugin = false;
        public string module_init_param_name;
        
-       private bool string_h_needed;
+       public bool string_h_needed;
        private bool requires_free_checked;
        private bool requires_array_free;
        private bool requires_array_move;
@@ -693,6 +693,14 @@ public class Vala.CCodeGenerator : CodeGenerator {
                return (null != cparenthesized && is_pure_ccode_expression (cparenthesized.inner));
        }
 
+       public override void visit_method (Method m) {
+               code_binding (m).emit ();
+       }
+
+       public override void visit_creation_method (CreationMethod m) {
+               code_binding (m).emit ();
+       }
+
        public override void visit_formal_parameter (FormalParameter p) {
                p.accept_children (this);
 
@@ -2380,7 +2388,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
                visit_expression (expr);
        }
        
-       private string get_array_length_cname (string array_cname, int dim) {
+       public string get_array_length_cname (string array_cname, int dim) {
                return "%s_length%d".printf (array_cname, dim);
        }
 
@@ -2518,7 +2526,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
                }
        }
        
-       private string get_delegate_target_cname (string delegate_cname) {
+       public string get_delegate_target_cname (string delegate_cname) {
                return "%s_target".printf (delegate_cname);
        }
 
@@ -3573,6 +3581,71 @@ public class Vala.CCodeGenerator : CodeGenerator {
                return type;
        }
 
+       public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) {
+               if ((type.data_type != null && type.data_type.is_reference_type ()) || type is PointerType || type is ArrayType) {
+                       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 ());
+               } else if (type.data_type is Struct && initializer_expression) {
+                       // 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.type_parameter != null) {
+                       return new CCodeConstant ("NULL");
+               } else if (type is ErrorType) {
+                       return new CCodeConstant ("NULL");
+               }
+               return null;
+       }
+       
+       private CCodeStatement create_property_type_check_statement (Property prop, bool check_return_type, Typesymbol t, bool non_null, string var_name) {
+               if (check_return_type) {
+                       return create_type_check_statement (prop, prop.type_reference, t, non_null, var_name);
+               } else {
+                       return create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
+               }
+       }
+
+       public CCodeStatement? create_type_check_statement (CodeNode method_node, DataType ret_type, Typesymbol t, bool non_null, string var_name) {
+               var ccheck = new CCodeFunctionCall ();
+               
+               if ((t is Class && ((Class) t).is_subtype_of (gobject_type)) || (t is Interface && !((Interface) t).declaration_only)) {
+                       var ctype_check = new CCodeFunctionCall (new CCodeIdentifier (t.get_upper_case_cname ("IS_")));
+                       ctype_check.add_argument (new CCodeIdentifier (var_name));
+                       
+                       CCodeExpression cexpr = ctype_check;
+                       if (!non_null) {
+                               var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
+                       
+                               cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cnull, ctype_check);
+                       }
+                       ccheck.add_argument (cexpr);
+               } else if (!non_null) {
+                       return null;
+               } else {
+                       var cnonnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
+                       ccheck.add_argument (cnonnull);
+               }
+               
+               if (ret_type is VoidType) {
+                       /* void function */
+                       ccheck.call = new CCodeIdentifier ("g_return_if_fail");
+               } else {
+                       ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
+
+                       var cdefault = default_value_for_type (ret_type, false);
+                       if (cdefault != null) {
+                               ccheck.add_argument (cdefault);
+                       } else {
+                               return new CCodeExpressionStatement (new CCodeConstant ("0"));
+                       }
+               }
+               
+               return new CCodeExpressionStatement (ccheck);
+       }
+
        public override CodeBinding? create_namespace_binding (Namespace node) {
                return null;
        }
@@ -3622,7 +3695,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
        }
 
        public override CodeBinding? create_creation_method_binding (CreationMethod node) {
-               return null;
+               return new CCodeCreationMethodBinding (this, node);
        }
 
        public override CodeBinding? create_formal_parameter_binding (FormalParameter node) {
diff --git a/gobject/valaccodegeneratormethod.vala b/gobject/valaccodegeneratormethod.vala
deleted file mode 100644 (file)
index d0fb3f9..0000000
+++ /dev/null
@@ -1,854 +0,0 @@
-/* valaccodegeneratormethod.vala
- *
- * Copyright (C) 2006-2008  Jürg Billeter, 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>
- */
-
-using GLib;
-using Gee;
-
-public class Vala.CCodeGenerator {
-       public override void visit_method (Method m) {
-               Method old_method = current_method;
-               DataType old_return_type = current_return_type;
-               bool old_method_inner_error = current_method_inner_error;
-               int old_next_temp_var_id = next_temp_var_id;
-               current_symbol = m;
-               current_method = m;
-               current_return_type = m.return_type;
-               current_method_inner_error = false;
-               next_temp_var_id = 0;
-
-               bool in_gtypeinstance_creation_method = false;
-               bool in_gobject_creation_method = false;
-               bool in_fundamental_creation_method = false;
-
-               var creturn_type = current_return_type;
-
-               if (m is CreationMethod) {
-                       in_creation_method = true;
-                       var cl = current_type_symbol as Class;
-                       if (cl != null && cl.is_subtype_of (gtypeinstance_type)) {
-                               in_gtypeinstance_creation_method = true;
-                               if (cl.base_class == gtypeinstance_type) {
-                                       in_fundamental_creation_method = true;
-                               } else if (cl.is_subtype_of (gobject_type)) {
-                                       in_gobject_creation_method = true;
-                               }
-                       }
-
-                       if (cl != null) {
-                               creturn_type = new ClassType (cl);
-                       }
-               }
-
-               m.accept_children (this);
-
-               if (m is CreationMethod) {
-                       if (in_gobject_creation_method && m.body != null) {
-                               var cblock = new CCodeBlock ();
-                               
-                               foreach (CodeNode stmt in m.body.get_statements ()) {
-                                       if (((ExpressionStatement) stmt).assigned_property ().set_accessor.construction) {
-                                               if (stmt.ccodenode is CCodeFragment) {
-                                                       foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
-                                                               cblock.add_statement (cstmt);
-                                                       }
-                                               } else {
-                                                       cblock.add_statement (stmt.ccodenode);
-                                               }
-                                       }
-                               }
-
-                               add_object_creation (cblock, ((CreationMethod) m).n_construction_params > 0);
-                               
-                               foreach (CodeNode stmt in m.body.get_statements ()) {
-                                       if (!((ExpressionStatement) stmt).assigned_property ().set_accessor.construction) {
-                                               if (stmt.ccodenode is CCodeFragment) {
-                                                       foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
-                                                               cblock.add_statement (cstmt);
-                                                       }
-                                               } else {
-                                                       cblock.add_statement (stmt.ccodenode);
-                                               }
-                                       }
-                               }
-                               
-                               m.body.ccodenode = cblock;
-                       }
-
-                       in_creation_method = false;
-               }
-
-               bool inner_error = current_method_inner_error;
-
-               current_symbol = current_symbol.parent_symbol;
-               current_method = current_method;
-               current_return_type = old_return_type;
-               current_method_inner_error = old_method_inner_error;
-               next_temp_var_id = old_next_temp_var_id;
-
-               if (current_type_symbol != null && current_type_symbol is Interface) {
-                       var iface = (Interface) current_type_symbol;
-                       if (iface.is_static) {
-                               return;
-                       }
-               }
-
-               function = new CCodeFunction (m.get_real_cname (), creturn_type.get_cname ());
-               m.ccodenode = function;
-
-               if (m.is_inline) {
-                       function.modifiers |= CCodeModifiers.INLINE;
-               }
-
-               var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
-
-               CCodeFunctionDeclarator vdeclarator = null;
-
-               if (m.instance || (m.parent_symbol is Struct && m is CreationMethod)) {
-                       Typesymbol parent_type = find_parent_type (m);
-                       DataType this_type;
-                       if (parent_type is Class) {
-                               this_type = new ClassType ((Class) parent_type);
-                       } else if (parent_type is Interface) {
-                               this_type = new InterfaceType ((Interface) parent_type);
-                       } else {
-                               this_type = new ValueType (parent_type);
-                       }
-
-                       CCodeFormalParameter instance_param = null;
-                       if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
-                               var base_type = new InterfaceType ((Interface) m.base_interface_method.parent_symbol);
-                               instance_param = new CCodeFormalParameter ("base", base_type.get_cname ());
-                       } else if (m.overrides) {
-                               var base_type = new ClassType ((Class) m.base_method.parent_symbol);
-                               instance_param = new CCodeFormalParameter ("base", base_type.get_cname ());
-                       } else {
-                               if (m.parent_symbol is Struct && !((Struct) m.parent_symbol).is_simple_type ()) {
-                                       instance_param = new CCodeFormalParameter ("*self", this_type.get_cname ());
-                               } else {
-                                       instance_param = new CCodeFormalParameter ("self", this_type.get_cname ());
-                               }
-                       }
-                       cparam_map.set (get_param_pos (m.cinstance_parameter_position), instance_param);
-
-                       if (m.is_abstract || m.is_virtual) {
-                               var vdecl = new CCodeDeclaration (creturn_type.get_cname ());
-                               vdeclarator = new CCodeFunctionDeclarator (m.vfunc_name);
-                               vdecl.add_declarator (vdeclarator);
-                               type_struct.add_declaration (vdecl);
-                       }
-               }
-
-               if (in_fundamental_creation_method) {
-                       cparam_map.set (get_param_pos (0.1), new CCodeFormalParameter ("type", "GType"));
-               }
-
-               if (in_gobject_creation_method) {
-                       // memory management for generic types
-                       int type_param_index = 0;
-                       foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
-                               cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "GType"));
-                               cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeFormalParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
-                               cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
-                               type_param_index++;
-                       }
-               }
-
-               var params = m.get_parameters ();
-               foreach (FormalParameter param in params) {
-                       if (!param.no_array_length && param.type_reference is ArrayType) {
-                               var array_type = (ArrayType) param.type_reference;
-                               
-                               var length_ctype = "int";
-                               if (param.direction != ParameterDirection.IN) {
-                                       length_ctype = "int*";
-                               }
-                               
-                               for (int dim = 1; dim <= array_type.rank; dim++) {
-                                       var cparam = new CCodeFormalParameter (get_array_length_cname (param.name, dim), length_ctype);
-                                       cparam_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
-                               }
-                       }
-
-                       cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
-
-                       if (param.type_reference is DelegateType) {
-                               var deleg_type = (DelegateType) param.type_reference;
-                               var d = deleg_type.delegate_symbol;
-                               if (d.instance) {
-                                       var cparam = new CCodeFormalParameter (get_delegate_target_cname (param.name), "void*");
-                                       cparam_map.set (get_param_pos (param.cdelegate_target_parameter_position), cparam);
-                               }
-                       }
-               }
-
-               if (!m.no_array_length && creturn_type is ArrayType) {
-                       // return array length if appropriate
-                       var array_type = (ArrayType) creturn_type;
-
-                       for (int dim = 1; dim <= array_type.rank; dim++) {
-                               var cparam = new CCodeFormalParameter (get_array_length_cname ("result", dim), "int*");
-                               cparam_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), cparam);
-                       }
-               } else if (creturn_type is DelegateType) {
-                       // return delegate target if appropriate
-                       var deleg_type = (DelegateType) creturn_type;
-                       var d = deleg_type.delegate_symbol;
-                       if (d.instance) {
-                               var cparam = new CCodeFormalParameter (get_delegate_target_cname ("result"), "void*");
-                               cparam_map.set (get_param_pos (m.cdelegate_target_parameter_position), cparam);
-                       }
-               }
-
-               if (m.get_error_domains ().size > 0) {
-                       var cparam = new CCodeFormalParameter ("error", "GError**");
-                       cparam_map.set (get_param_pos (-1), cparam);
-               }
-
-               // append C parameters in the right order
-               int last_pos = -1;
-               int min_pos;
-               while (true) {
-                       min_pos = -1;
-                       foreach (int pos in cparam_map.get_keys ()) {
-                               if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
-                                       min_pos = pos;
-                               }
-                       }
-                       if (min_pos == -1) {
-                               break;
-                       }
-                       function.add_parameter (cparam_map.get (min_pos));
-                       if (vdeclarator != null) {
-                               vdeclarator.add_parameter (cparam_map.get (min_pos));
-                       }
-                       last_pos = min_pos;
-               }
-
-               bool visible = !m.is_internal_symbol ();
-
-               /* real function declaration and definition not needed
-                * for abstract methods */
-               if (!m.is_abstract) {
-                       if (visible && m.base_method == null && m.base_interface_method == null) {
-                               /* public methods need function declaration in
-                                * header file except virtual/overridden methods */
-                               header_type_member_declaration.append (function.copy ());
-                       } else {
-                               /* declare all other functions in source file to
-                                * avoid dependency on order within source file */
-                               function.modifiers |= CCodeModifiers.STATIC;
-                               source_type_member_declaration.append (function.copy ());
-                       }
-                       
-                       /* Methods imported from a plain C file don't
-                        * have a body, e.g. Vala.Parser.parse_file () */
-                       if (m.body != null) {
-                               function.block = (CCodeBlock) m.body.ccodenode;
-                               function.block.line = function.line;
-
-                               var cinit = new CCodeFragment ();
-                               function.block.prepend_statement (cinit);
-
-                               if (m.parent_symbol is Class) {
-                                       var cl = (Class) m.parent_symbol;
-                                       if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
-                                               Method base_method;
-                                               ReferenceType base_expression_type;
-                                               if (m.overrides) {
-                                                       base_method = m.base_method;
-                                                       base_expression_type = new ClassType ((Class) base_method.parent_symbol);
-                                               } else {
-                                                       base_method = m.base_interface_method;
-                                                       base_expression_type = new InterfaceType ((Interface) base_method.parent_symbol);
-                                               }
-                                               var self_target_type = new ClassType (cl);
-                                               CCodeExpression cself = get_implicit_cast_expression (new CCodeIdentifier ("base"), base_expression_type, self_target_type);
-
-                                               var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
-                                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", cself));
-                                               
-                                               cinit.append (cdecl);
-                                       } else if (m.instance) {
-                                               var ccheckstmt = create_method_type_check_statement (m, creturn_type, cl, true, "self");
-                                               ccheckstmt.line = function.line;
-                                               cinit.append (ccheckstmt);
-                                       }
-                               }
-                               foreach (FormalParameter param in m.get_parameters ()) {
-                                       if (param.ellipsis) {
-                                               break;
-                                       }
-
-                                       var t = param.type_reference.data_type;
-                                       if (t != null && t.is_reference_type ()) {
-                                               if (param.direction != ParameterDirection.OUT) {
-                                                       var type_check = create_method_type_check_statement (m, creturn_type, t, (context.non_null && !param.type_reference.nullable), param.name);
-                                                       if (type_check != null) {
-                                                               type_check.line = function.line;
-                                                               cinit.append (type_check);
-                                                       }
-                                               } else {
-                                                       // ensure that the passed reference for output parameter is cleared
-                                                       var a = new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (param.name)), new CCodeConstant ("NULL"));
-                                                       cinit.append (new CCodeExpressionStatement (a));
-                                               }
-                                       }
-                               }
-
-                               if (inner_error) {
-                                       /* always separate error parameter and inner_error local variable
-                                        * as error may be set to NULL but we're always interested in inner errors
-                                        */
-                                       var cdecl = new CCodeDeclaration ("GError *");
-                                       cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
-                                       cinit.append (cdecl);
-                               }
-
-                               if (m.source_reference != null && m.source_reference.comment != null) {
-                                       source_type_member_definition.append (new CCodeComment (m.source_reference.comment));
-                               }
-                               source_type_member_definition.append (function);
-                               
-                               if (m is CreationMethod) {
-                                       if (in_gobject_creation_method) {
-                                               int n_params = ((CreationMethod) m).n_construction_params;
-
-                                               if (n_params > 0) {
-                                                       // declare construction parameter array
-                                                       var cparamsinit = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
-                                                       cparamsinit.add_argument (new CCodeIdentifier ("GParameter"));
-                                                       cparamsinit.add_argument (new CCodeConstant (n_params.to_string ()));
-                                                       
-                                                       var cdecl = new CCodeDeclaration ("GParameter *");
-                                                       cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("__params", cparamsinit));
-                                                       cinit.append (cdecl);
-                                                       
-                                                       cdecl = new CCodeDeclaration ("GParameter *");
-                                                       cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("__params_it", new CCodeIdentifier ("__params")));
-                                                       cinit.append (cdecl);
-                                               }
-
-                                               /* type, dup func, and destroy func properties for generic types */
-                                               foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
-                                                       string func_name;
-                                                       CCodeMemberAccess cmember;
-                                                       CCodeAssignment cassign;
-
-                                                       func_name = "%s_type".printf (type_param.name.down ());
-                                                       cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
-                                                       cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
-                                                       function.block.add_statement (new CCodeExpressionStatement (cassign));
-
-                                                       func_name = "%s_dup_func".printf (type_param.name.down ());
-                                                       cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
-                                                       cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
-                                                       function.block.add_statement (new CCodeExpressionStatement (cassign));
-
-                                                       func_name = "%s_destroy_func".printf (type_param.name.down ());
-                                                       cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
-                                                       cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
-                                                       function.block.add_statement (new CCodeExpressionStatement (cassign));
-                                               }
-                                       } else if (in_fundamental_creation_method) {
-                                               var cl = (Class) m.parent_symbol;
-                                               var cdecl = new CCodeDeclaration (cl.get_cname () + "*");
-                                               var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
-                                               ccall.add_argument (new CCodeIdentifier ("type"));
-                                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", new CCodeCastExpression (ccall, cl.get_cname () + "*")));
-                                               cinit.append (cdecl);
-                                       } else if (in_gtypeinstance_creation_method) {
-                                               var cl = (Class) m.parent_symbol;
-                                               var cdecl = new CCodeDeclaration (cl.get_cname () + "*");
-                                               var fundamental_class = find_fundamental_class (cl);
-                                               var ccall = new CCodeFunctionCall (new CCodeIdentifier (fundamental_class.default_construction_method.get_cname ()));
-                                               ccall.add_argument (new CCodeIdentifier (cl.get_type_id ()));
-                                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
-                                               cinit.append (cdecl);
-                                       } else if (current_type_symbol is Class) {
-                                               var cl = (Class) m.parent_symbol;
-                                               var cdecl = new CCodeDeclaration (cl.get_cname () + "*");
-                                               var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
-                                               ccall.add_argument (new CCodeIdentifier (cl.get_cname ()));
-                                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
-                                               cinit.append (cdecl);
-                                       } else {
-                                               var st = (Struct) m.parent_symbol;
-
-                                               // memset needs string.h
-                                               string_h_needed = true;
-                                               var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
-                                               czero.add_argument (new CCodeIdentifier ("self"));
-                                               czero.add_argument (new CCodeConstant ("0"));
-                                               czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (st.get_cname ())));
-                                               cinit.append (new CCodeExpressionStatement (czero));
-                                       }
-                               }
-
-                               if (context.module_init_method == m && in_plugin) {
-                                       // GTypeModule-based plug-in, register types
-                                       cinit.append (module_init_fragment);
-                               }
-
-                               foreach (Expression precondition in m.get_preconditions ()) {
-                                       cinit.append (create_precondition_statement (m, creturn_type, precondition));
-                               }
-                       }
-               }
-               
-               if (m.is_abstract || m.is_virtual) {
-                       var vfunc = new CCodeFunction (m.get_cname (), creturn_type.get_cname ());
-                       vfunc.line = function.line;
-
-                       ReferenceType this_type;
-                       if (m.parent_symbol is Class) {
-                               this_type = new ClassType ((Class) m.parent_symbol);
-                       } else {
-                               this_type = new InterfaceType ((Interface) m.parent_symbol);
-                       }
-
-                       cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
-                       var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
-
-                       var cparam = new CCodeFormalParameter ("self", this_type.get_cname ());
-                       cparam_map.set (get_param_pos (m.cinstance_parameter_position), cparam);
-                       
-                       var vblock = new CCodeBlock ();
-
-                       foreach (Expression precondition in m.get_preconditions ()) {
-                               vblock.add_statement (create_precondition_statement (m, creturn_type, precondition));
-                       }
-
-                       CCodeFunctionCall vcast = null;
-                       if (m.parent_symbol is Interface) {
-                               var iface = (Interface) m.parent_symbol;
-
-                               vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
-                       } else {
-                               var cl = (Class) m.parent_symbol;
-
-                               vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
-                       }
-                       vcast.add_argument (new CCodeIdentifier ("self"));
-               
-                       var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, m.vfunc_name));
-                       carg_map.set (get_param_pos (m.cinstance_parameter_position), new CCodeIdentifier ("self"));
-               
-                       var params = m.get_parameters ();
-                       foreach (FormalParameter param in params) {
-                               if (!param.no_array_length && param.type_reference is ArrayType) {
-                                       var array_type = (ArrayType) param.type_reference;
-                                       
-                                       var length_ctype = "int";
-                                       if (param.direction != ParameterDirection.IN) {
-                                               length_ctype = "int*";
-                                       }
-                                       
-                                       for (int dim = 1; dim <= array_type.rank; dim++) {
-                                               var cparam = new CCodeFormalParameter (get_array_length_cname (param.name, dim), length_ctype);
-                                               cparam_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
-                                               carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), new CCodeIdentifier (cparam.name));
-                                       }
-                               }
-
-                               cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
-                               carg_map.set (get_param_pos (param.cparameter_position), new CCodeIdentifier (param.name));
-
-                               if (param.type_reference is DelegateType) {
-                                       var deleg_type = (DelegateType) param.type_reference;
-                                       var d = deleg_type.delegate_symbol;
-                                       if (d.instance) {
-                                               var cparam = new CCodeFormalParameter (get_delegate_target_cname (param.name), "void*");
-                                               cparam_map.set (get_param_pos (param.cdelegate_target_parameter_position), cparam);
-                                               carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));
-                                       }
-                               }
-                       }
-
-                       // return array length if appropriate
-                       if (!m.no_array_length && creturn_type is ArrayType) {
-                               var array_type = (ArrayType) creturn_type;
-
-                               for (int dim = 1; dim <= array_type.rank; dim++) {
-                                       var cparam = new CCodeFormalParameter (get_array_length_cname ("result", dim), "int*");
-                                       cparam_map.set (get_param_pos (m.carray_length_parameter_position), cparam);
-                                       carg_map.set (get_param_pos (m.carray_length_parameter_position), new CCodeIdentifier (cparam.name));
-                               }
-                       } else if (creturn_type is DelegateType) {
-                               // return delegate target if appropriate
-                               var deleg_type = (DelegateType) creturn_type;
-                               var d = deleg_type.delegate_symbol;
-                               if (d.instance) {
-                                       var cparam = new CCodeFormalParameter (get_delegate_target_cname ("result"), "void*");
-                                       cparam_map.set (get_param_pos (m.cdelegate_target_parameter_position), cparam);
-                                       carg_map.set (get_param_pos (m.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));
-                               }
-                       }
-
-                       if (m.get_error_domains ().size > 0) {
-                               var cparam = new CCodeFormalParameter ("error", "GError**");
-                               cparam_map.set (get_param_pos (-1), cparam);
-                               carg_map.set (get_param_pos (-1), new CCodeIdentifier (cparam.name));
-                       }
-
-
-                       // append C parameters and arguments in the right order
-                       int last_pos = -1;
-                       int min_pos;
-                       while (true) {
-                               min_pos = -1;
-                               foreach (int pos in cparam_map.get_keys ()) {
-                                       if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
-                                               min_pos = pos;
-                                       }
-                               }
-                               if (min_pos == -1) {
-                                       break;
-                               }
-                               vfunc.add_parameter (cparam_map.get (min_pos));
-                               vcall.add_argument (carg_map.get (min_pos));
-                               last_pos = min_pos;
-                       }
-
-                       CCodeStatement cstmt;
-                       if (creturn_type is VoidType) {
-                               cstmt = new CCodeExpressionStatement (vcall);
-                       } else if (m.get_postconditions ().size == 0) {
-                               /* pass method return value */
-                               cstmt = new CCodeReturnStatement (vcall);
-                       } else {
-                               /* store method return value for postconditions */
-                               var cdecl = new CCodeDeclaration (creturn_type.get_cname ());
-                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("result", vcall));
-                               cstmt = cdecl;
-                       }
-                       cstmt.line = vfunc.line;
-                       vblock.add_statement (cstmt);
-
-                       if (m.get_postconditions ().size > 0) {
-                               foreach (Expression postcondition in m.get_postconditions ()) {
-                                       vblock.add_statement (create_postcondition_statement (postcondition));
-                               }
-
-                               if (!(creturn_type is VoidType)) {
-                                       var cret_stmt = new CCodeReturnStatement (new CCodeIdentifier ("result"));
-                                       cret_stmt.line = vfunc.line;
-                                       vblock.add_statement (cret_stmt);
-                               }
-                       }
-
-                       if (visible) {
-                               header_type_member_declaration.append (vfunc.copy ());
-                       } else {
-                               vfunc.modifiers |= CCodeModifiers.STATIC;
-                               source_type_member_declaration.append (vfunc.copy ());
-                       }
-                       
-                       vfunc.block = vblock;
-
-                       if (m.is_abstract && m.source_reference != null && m.source_reference.comment != null) {
-                               source_type_member_definition.append (new CCodeComment (m.source_reference.comment));
-                       }
-                       source_type_member_definition.append (vfunc);
-               }
-               
-               if (m is CreationMethod) {
-                       if (((CreationMethod) m).n_construction_params > 0) {
-                               var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier ("__params_it"), new CCodeIdentifier ("__params"));
-                               var cdofreeparam = new CCodeBlock ();
-                               cdofreeparam.add_statement (new CCodeExpressionStatement (new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, new CCodeIdentifier ("__params_it"))));
-                               var cunsetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_unset"));
-                               cunsetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("__params_it"), "value")));
-                               cdofreeparam.add_statement (new CCodeExpressionStatement (cunsetcall));
-                               function.block.add_statement (new CCodeWhileStatement (ccond, cdofreeparam));
-
-                               var cfreeparams = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
-                               cfreeparams.add_argument (new CCodeIdentifier ("__params"));
-                               function.block.add_statement (new CCodeExpressionStatement (cfreeparams));
-                       }
-
-                       if (current_type_symbol is Class) {
-                               var creturn = new CCodeReturnStatement ();
-                               creturn.return_expression = new CCodeIdentifier ("self");
-                               function.block.add_statement (creturn);
-                       }
-               }
-               
-               bool return_value = true;
-               bool args_parameter = true;
-               if (is_possible_entry_point (m, ref return_value, ref args_parameter)) {
-                       // 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 ();
-
-                       if (context.thread) {
-                               var thread_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_thread_init"));
-                               thread_init_call.line = cmain.line;
-                               thread_init_call.add_argument (new CCodeConstant ("NULL"));
-                               main_block.add_statement (new CCodeExpressionStatement (thread_init_call)); 
-                       }
-
-                       var type_init_call = new CCodeExpressionStatement (new CCodeFunctionCall (new CCodeIdentifier ("g_type_init")));
-                       type_init_call.line = cmain.line;
-                       main_block.add_statement (type_init_call);
-
-                       var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
-                       if (args_parameter) {
-                               main_call.add_argument (new CCodeIdentifier ("argv"));
-                               main_call.add_argument (new CCodeIdentifier ("argc"));
-                       }
-                       if (return_value) {
-                               var main_stmt = new CCodeReturnStatement (main_call);
-                               main_stmt.line = cmain.line;
-                               main_block.add_statement (main_stmt);
-                       } else {
-                               // 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);
-                       }
-                       cmain.block = main_block;
-                       source_type_member_definition.append (cmain);
-               }
-       }
-       
-       private CCodeStatement create_method_type_check_statement (Method m, DataType return_type, Typesymbol t, bool non_null, string var_name) {
-               return create_type_check_statement (m, return_type, t, non_null, var_name);
-       }
-       
-       private CCodeStatement create_property_type_check_statement (Property prop, bool check_return_type, Typesymbol t, bool non_null, string var_name) {
-               if (check_return_type) {
-                       return create_type_check_statement (prop, prop.type_reference, t, non_null, var_name);
-               } else {
-                       return create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
-               }
-       }
-
-       private CCodeStatement? create_type_check_statement (CodeNode method_node, DataType ret_type, Typesymbol t, bool non_null, string var_name) {
-               var ccheck = new CCodeFunctionCall ();
-               
-               if ((t is Class && ((Class) t).is_subtype_of (gobject_type)) || (t is Interface && !((Interface) t).declaration_only)) {
-                       var ctype_check = new CCodeFunctionCall (new CCodeIdentifier (t.get_upper_case_cname ("IS_")));
-                       ctype_check.add_argument (new CCodeIdentifier (var_name));
-                       
-                       CCodeExpression cexpr = ctype_check;
-                       if (!non_null) {
-                               var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
-                       
-                               cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cnull, ctype_check);
-                       }
-                       ccheck.add_argument (cexpr);
-               } else if (!non_null) {
-                       return null;
-               } else {
-                       var cnonnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
-                       ccheck.add_argument (cnonnull);
-               }
-               
-               if (ret_type is VoidType) {
-                       /* void function */
-                       ccheck.call = new CCodeIdentifier ("g_return_if_fail");
-               } else {
-                       ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
-
-                       var cdefault = default_value_for_type (ret_type, false);
-                       if (cdefault != null) {
-                               ccheck.add_argument (cdefault);
-                       } else {
-                               return new CCodeExpressionStatement (new CCodeConstant ("0"));
-                       }
-               }
-               
-               return new CCodeExpressionStatement (ccheck);
-       }
-
-       private CCodeStatement create_precondition_statement (CodeNode method_node, DataType ret_type, Expression precondition) {
-               var ccheck = new CCodeFunctionCall ();
-
-               ccheck.add_argument ((CCodeExpression) precondition.ccodenode);
-
-               if (ret_type is VoidType) {
-                       /* void function */
-                       ccheck.call = new CCodeIdentifier ("g_return_if_fail");
-               } else {
-                       ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
-
-                       var cdefault = default_value_for_type (ret_type, false);
-                       if (cdefault != null) {
-                               ccheck.add_argument (cdefault);
-                       } else {
-                               return new CCodeExpressionStatement (new CCodeConstant ("0"));
-                       }
-               }
-               
-               return new CCodeExpressionStatement (ccheck);
-       }
-
-       private CCodeStatement create_postcondition_statement (Expression postcondition) {
-               var cassert = new CCodeFunctionCall (new CCodeIdentifier ("g_assert"));
-
-               cassert.add_argument ((CCodeExpression) postcondition.ccodenode);
-
-               return new CCodeExpressionStatement (cassert);
-       }
-
-       private CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) {
-               if ((type.data_type != null && type.data_type.is_reference_type ()) || type is PointerType || type is ArrayType) {
-                       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 ());
-               } else if (type.data_type is Struct && initializer_expression) {
-                       // 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.type_parameter != null) {
-                       return new CCodeConstant ("NULL");
-               } else if (type is ErrorType) {
-                       return new CCodeConstant ("NULL");
-               }
-               return null;
-       }
-
-       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 visit_creation_method (CreationMethod m) {
-               if (m.body != null && current_type_symbol is Class && current_class.is_subtype_of (gobject_type)) {
-                       int n_params = 0;
-                       foreach (Statement stmt in m.body.get_statements ()) {
-                               if (!(stmt is ExpressionStatement) || ((ExpressionStatement) stmt).assigned_property () == null) {
-                                       m.error = true;
-                                       Report.error (stmt.source_reference, "class creation methods only allow property assignment statements");
-                                       return;
-                               }
-                               if (((ExpressionStatement) stmt).assigned_property ().set_accessor.construction) {
-                                       n_params++;
-                               }
-                       }
-                       m.n_construction_params = n_params;
-               }
-
-               visit_method (m);
-       }
-       
-       private bool is_possible_entry_point (Method m, ref bool return_value, ref bool args_parameter) {
-               if (m.name == null || m.name != "main") {
-                       // method must be called "main"
-                       return false;
-               }
-               
-               if (m.instance) {
-                       // method must be static
-                       return false;
-               }
-               
-               if (m.return_type.data_type == null) {
-                       return_value = false;
-               } else if (m.return_type.data_type == int_type.data_type) {
-                       return_value = true;
-               } else {
-                       // return type must be void or int
-                       return false;
-               }
-               
-               var params = m.get_parameters ();
-               if (params.size == 0) {
-                       // method may have no parameters
-                       args_parameter = false;
-                       return true;
-               }
-
-               if (params.size > 1) {
-                       // method must not have more than one parameter
-                       return false;
-               }
-               
-               Iterator<FormalParameter> params_it = params.iterator ();
-               params_it.next ();
-               var param = params_it.get ();
-
-               if (param.direction == ParameterDirection.OUT) {
-                       // parameter must not be an out parameter
-                       return false;
-               }
-               
-               if (!(param.type_reference is ArrayType)) {
-                       // parameter must be an array
-                       return false;
-               }
-               
-               var array_type = (ArrayType) param.type_reference;
-               if (array_type.element_type.data_type != string_type.data_type) {
-                       // parameter must be an array of strings
-                       return false;
-               }
-               
-               args_parameter = true;
-               return true;
-       }
-
-       private void add_object_creation (CCodeBlock b, bool has_params) {
-               var cl = (Class) current_type_symbol;
-       
-               var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
-               ccall.add_argument (new CCodeConstant (cl.get_type_id ()));
-               if (has_params) {
-                       ccall.add_argument (new CCodeConstant ("__params_it - __params"));
-                       ccall.add_argument (new CCodeConstant ("__params"));
-               } else {
-                       ccall.add_argument (new CCodeConstant ("0"));
-                       ccall.add_argument (new CCodeConstant ("NULL"));
-               }
-               
-               var cdecl = new CCodeVariableDeclarator ("self");
-               cdecl.initializer = ccall;
-               
-               var cdeclaration = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
-               cdeclaration.add_declarator (cdecl);
-               
-               b.add_statement (cdeclaration);
-       }
-
-       private Class find_fundamental_class (Class cl) {
-               var fundamental_class = cl;
-               while (fundamental_class != null && fundamental_class.base_class != gtypeinstance_type) {
-                       fundamental_class = fundamental_class.base_class;
-               }
-               return fundamental_class;
-       }
-}
-
index 5866a1d..c710dd2 100644 (file)
@@ -39,5 +39,746 @@ public class Vala.CCodeMethodBinding : CCodeBinding {
        }
 
        public override void emit () {
+               var m = method;
+
+               Method old_method = codegen.current_method;
+               DataType old_return_type = codegen.current_return_type;
+               bool old_method_inner_error = codegen.current_method_inner_error;
+               int old_next_temp_var_id = codegen.next_temp_var_id;
+               codegen.current_symbol = m;
+               codegen.current_method = m;
+               codegen.current_return_type = m.return_type;
+               codegen.current_method_inner_error = false;
+               codegen.next_temp_var_id = 0;
+
+               bool in_gtypeinstance_creation_method = false;
+               bool in_gobject_creation_method = false;
+               bool in_fundamental_creation_method = false;
+
+               var creturn_type = codegen.current_return_type;
+
+               if (m is CreationMethod) {
+                       codegen.in_creation_method = true;
+                       var cl = codegen.current_type_symbol as Class;
+                       if (cl != null && cl.is_subtype_of (codegen.gtypeinstance_type)) {
+                               in_gtypeinstance_creation_method = true;
+                               if (cl.base_class == codegen.gtypeinstance_type) {
+                                       in_fundamental_creation_method = true;
+                               } else if (cl.is_subtype_of (codegen.gobject_type)) {
+                                       in_gobject_creation_method = true;
+                               }
+                       }
+
+                       if (cl != null) {
+                               creturn_type = new ClassType (cl);
+                       }
+               }
+
+               m.accept_children (codegen);
+
+               if (m is CreationMethod) {
+                       if (in_gobject_creation_method && m.body != null) {
+                               var cblock = new CCodeBlock ();
+                               
+                               foreach (CodeNode stmt in m.body.get_statements ()) {
+                                       if (((ExpressionStatement) stmt).assigned_property ().set_accessor.construction) {
+                                               if (stmt.ccodenode is CCodeFragment) {
+                                                       foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
+                                                               cblock.add_statement (cstmt);
+                                                       }
+                                               } else {
+                                                       cblock.add_statement (stmt.ccodenode);
+                                               }
+                                       }
+                               }
+
+                               add_object_creation (cblock, ((CreationMethod) m).n_construction_params > 0);
+                               
+                               foreach (CodeNode stmt in m.body.get_statements ()) {
+                                       if (!((ExpressionStatement) stmt).assigned_property ().set_accessor.construction) {
+                                               if (stmt.ccodenode is CCodeFragment) {
+                                                       foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
+                                                               cblock.add_statement (cstmt);
+                                                       }
+                                               } else {
+                                                       cblock.add_statement (stmt.ccodenode);
+                                               }
+                                       }
+                               }
+                               
+                               m.body.ccodenode = cblock;
+                       }
+
+                       codegen.in_creation_method = false;
+               }
+
+               bool inner_error = codegen.current_method_inner_error;
+
+               codegen.current_symbol = codegen.current_symbol.parent_symbol;
+               codegen.current_method = old_method;
+               codegen.current_return_type = old_return_type;
+               codegen.current_method_inner_error = old_method_inner_error;
+               codegen.next_temp_var_id = old_next_temp_var_id;
+
+               if (codegen.current_type_symbol is Interface) {
+                       var iface = (Interface) codegen.current_type_symbol;
+                       if (iface.is_static) {
+                               return;
+                       }
+               }
+
+               codegen.function = new CCodeFunction (m.get_real_cname (), creturn_type.get_cname ());
+               m.ccodenode = codegen.function;
+
+               if (m.is_inline) {
+                       codegen.function.modifiers |= CCodeModifiers.INLINE;
+               }
+
+               var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+               CCodeFunctionDeclarator vdeclarator = null;
+
+               if (m.instance || (m.parent_symbol is Struct && m is CreationMethod)) {
+                       Typesymbol parent_type = find_parent_type (m);
+                       DataType this_type;
+                       if (parent_type is Class) {
+                               this_type = new ClassType ((Class) parent_type);
+                       } else if (parent_type is Interface) {
+                               this_type = new InterfaceType ((Interface) parent_type);
+                       } else {
+                               this_type = new ValueType (parent_type);
+                       }
+
+                       CCodeFormalParameter instance_param = null;
+                       if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
+                               var base_type = new InterfaceType ((Interface) m.base_interface_method.parent_symbol);
+                               instance_param = new CCodeFormalParameter ("base", base_type.get_cname ());
+                       } else if (m.overrides) {
+                               var base_type = new ClassType ((Class) m.base_method.parent_symbol);
+                               instance_param = new CCodeFormalParameter ("base", base_type.get_cname ());
+                       } else {
+                               if (m.parent_symbol is Struct && !((Struct) m.parent_symbol).is_simple_type ()) {
+                                       instance_param = new CCodeFormalParameter ("*self", this_type.get_cname ());
+                               } else {
+                                       instance_param = new CCodeFormalParameter ("self", this_type.get_cname ());
+                               }
+                       }
+                       cparam_map.set (codegen.get_param_pos (m.cinstance_parameter_position), instance_param);
+
+                       if (m.is_abstract || m.is_virtual) {
+                               var vdecl = new CCodeDeclaration (creturn_type.get_cname ());
+                               vdeclarator = new CCodeFunctionDeclarator (m.vfunc_name);
+                               vdecl.add_declarator (vdeclarator);
+                               codegen.type_struct.add_declaration (vdecl);
+                       }
+               }
+
+               if (in_fundamental_creation_method) {
+                       cparam_map.set (codegen.get_param_pos (0.1), new CCodeFormalParameter ("type", "GType"));
+               }
+
+               if (in_gobject_creation_method) {
+                       // memory management for generic types
+                       int type_param_index = 0;
+                       foreach (TypeParameter type_param in codegen.current_class.get_type_parameters ()) {
+                               cparam_map.set (codegen.get_param_pos (0.1 * type_param_index + 0.01), new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "GType"));
+                               cparam_map.set (codegen.get_param_pos (0.1 * type_param_index + 0.02), new CCodeFormalParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
+                               cparam_map.set (codegen.get_param_pos (0.1 * type_param_index + 0.03), new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
+                               type_param_index++;
+                       }
+               }
+
+               var params = m.get_parameters ();
+               foreach (FormalParameter param in params) {
+                       if (!param.no_array_length && param.type_reference is ArrayType) {
+                               var array_type = (ArrayType) param.type_reference;
+                               
+                               var length_ctype = "int";
+                               if (param.direction != ParameterDirection.IN) {
+                                       length_ctype = "int*";
+                               }
+                               
+                               for (int dim = 1; dim <= array_type.rank; dim++) {
+                                       var cparam = new CCodeFormalParameter (codegen.get_array_length_cname (param.name, dim), length_ctype);
+                                       cparam_map.set (codegen.get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
+                               }
+                       }
+
+                       cparam_map.set (codegen.get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
+
+                       if (param.type_reference is DelegateType) {
+                               var deleg_type = (DelegateType) param.type_reference;
+                               var d = deleg_type.delegate_symbol;
+                               if (d.instance) {
+                                       var cparam = new CCodeFormalParameter (codegen.get_delegate_target_cname (param.name), "void*");
+                                       cparam_map.set (codegen.get_param_pos (param.cdelegate_target_parameter_position), cparam);
+                               }
+                       }
+               }
+
+               if (!m.no_array_length && creturn_type is ArrayType) {
+                       // return array length if appropriate
+                       var array_type = (ArrayType) creturn_type;
+
+                       for (int dim = 1; dim <= array_type.rank; dim++) {
+                               var cparam = new CCodeFormalParameter (codegen.get_array_length_cname ("result", dim), "int*");
+                               cparam_map.set (codegen.get_param_pos (m.carray_length_parameter_position + 0.01 * dim), cparam);
+                       }
+               } else if (creturn_type is DelegateType) {
+                       // return delegate target if appropriate
+                       var deleg_type = (DelegateType) creturn_type;
+                       var d = deleg_type.delegate_symbol;
+                       if (d.instance) {
+                               var cparam = new CCodeFormalParameter (codegen.get_delegate_target_cname ("result"), "void*");
+                               cparam_map.set (codegen.get_param_pos (m.cdelegate_target_parameter_position), cparam);
+                       }
+               }
+
+               if (m.get_error_domains ().size > 0) {
+                       var cparam = new CCodeFormalParameter ("error", "GError**");
+                       cparam_map.set (codegen.get_param_pos (-1), cparam);
+               }
+
+               // append C parameters in the right order
+               int last_pos = -1;
+               int min_pos;
+               while (true) {
+                       min_pos = -1;
+                       foreach (int pos in cparam_map.get_keys ()) {
+                               if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+                                       min_pos = pos;
+                               }
+                       }
+                       if (min_pos == -1) {
+                               break;
+                       }
+                       codegen.function.add_parameter (cparam_map.get (min_pos));
+                       if (vdeclarator != null) {
+                               vdeclarator.add_parameter (cparam_map.get (min_pos));
+                       }
+                       last_pos = min_pos;
+               }
+
+               bool visible = !m.is_internal_symbol ();
+
+               /* real function declaration and definition not needed
+                * for abstract methods */
+               if (!m.is_abstract) {
+                       if (visible && m.base_method == null && m.base_interface_method == null) {
+                               /* public methods need function declaration in
+                                * header file except virtual/overridden methods */
+                               codegen.header_type_member_declaration.append (codegen.function.copy ());
+                       } else {
+                               /* declare all other functions in source file to
+                                * avoid dependency on order within source file */
+                               codegen.function.modifiers |= CCodeModifiers.STATIC;
+                               codegen.source_type_member_declaration.append (codegen.function.copy ());
+                       }
+                       
+                       /* Methods imported from a plain C file don't
+                        * have a body, e.g. Vala.Parser.parse_file () */
+                       if (m.body != null) {
+                               codegen.function.block = (CCodeBlock) m.body.ccodenode;
+                               codegen.function.block.line = codegen.function.line;
+
+                               var cinit = new CCodeFragment ();
+                               codegen.function.block.prepend_statement (cinit);
+
+                               if (m.parent_symbol is Class) {
+                                       var cl = (Class) m.parent_symbol;
+                                       if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
+                                               Method base_method;
+                                               ReferenceType base_expression_type;
+                                               if (m.overrides) {
+                                                       base_method = m.base_method;
+                                                       base_expression_type = new ClassType ((Class) base_method.parent_symbol);
+                                               } else {
+                                                       base_method = m.base_interface_method;
+                                                       base_expression_type = new InterfaceType ((Interface) base_method.parent_symbol);
+                                               }
+                                               var self_target_type = new ClassType (cl);
+                                               CCodeExpression cself = codegen.get_implicit_cast_expression (new CCodeIdentifier ("base"), base_expression_type, self_target_type);
+
+                                               var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+                                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", cself));
+                                               
+                                               cinit.append (cdecl);
+                                       } else if (m.instance) {
+                                               var ccheckstmt = create_method_type_check_statement (m, creturn_type, cl, true, "self");
+                                               ccheckstmt.line = codegen.function.line;
+                                               cinit.append (ccheckstmt);
+                                       }
+                               }
+                               foreach (FormalParameter param in m.get_parameters ()) {
+                                       if (param.ellipsis) {
+                                               break;
+                                       }
+
+                                       var t = param.type_reference.data_type;
+                                       if (t != null && t.is_reference_type ()) {
+                                               if (param.direction != ParameterDirection.OUT) {
+                                                       var type_check = create_method_type_check_statement (m, creturn_type, t, (codegen.context.non_null && !param.type_reference.nullable), param.name);
+                                                       if (type_check != null) {
+                                                               type_check.line = codegen.function.line;
+                                                               cinit.append (type_check);
+                                                       }
+                                               } else {
+                                                       // ensure that the passed reference for output parameter is cleared
+                                                       var a = new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (param.name)), new CCodeConstant ("NULL"));
+                                                       cinit.append (new CCodeExpressionStatement (a));
+                                               }
+                                       }
+                               }
+
+                               if (inner_error) {
+                                       /* always separate error parameter and inner_error local variable
+                                        * as error may be set to NULL but we're always interested in inner errors
+                                        */
+                                       var cdecl = new CCodeDeclaration ("GError *");
+                                       cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
+                                       cinit.append (cdecl);
+                               }
+
+                               if (m.source_reference != null && m.source_reference.comment != null) {
+                                       codegen.source_type_member_definition.append (new CCodeComment (m.source_reference.comment));
+                               }
+                               codegen.source_type_member_definition.append (codegen.function);
+                               
+                               if (m is CreationMethod) {
+                                       if (in_gobject_creation_method) {
+                                               int n_params = ((CreationMethod) m).n_construction_params;
+
+                                               if (n_params > 0) {
+                                                       // declare construction parameter array
+                                                       var cparamsinit = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+                                                       cparamsinit.add_argument (new CCodeIdentifier ("GParameter"));
+                                                       cparamsinit.add_argument (new CCodeConstant (n_params.to_string ()));
+                                                       
+                                                       var cdecl = new CCodeDeclaration ("GParameter *");
+                                                       cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("__params", cparamsinit));
+                                                       cinit.append (cdecl);
+                                                       
+                                                       cdecl = new CCodeDeclaration ("GParameter *");
+                                                       cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("__params_it", new CCodeIdentifier ("__params")));
+                                                       cinit.append (cdecl);
+                                               }
+
+                                               /* type, dup func, and destroy func properties for generic types */
+                                               foreach (TypeParameter type_param in codegen.current_class.get_type_parameters ()) {
+                                                       string func_name;
+                                                       CCodeMemberAccess cmember;
+                                                       CCodeAssignment cassign;
+
+                                                       func_name = "%s_type".printf (type_param.name.down ());
+                                                       cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+                                                       cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
+                                                       codegen.function.block.add_statement (new CCodeExpressionStatement (cassign));
+
+                                                       func_name = "%s_dup_func".printf (type_param.name.down ());
+                                                       cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+                                                       cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
+                                                       codegen.function.block.add_statement (new CCodeExpressionStatement (cassign));
+
+                                                       func_name = "%s_destroy_func".printf (type_param.name.down ());
+                                                       cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+                                                       cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
+                                                       codegen.function.block.add_statement (new CCodeExpressionStatement (cassign));
+                                               }
+                                       } else if (in_fundamental_creation_method) {
+                                               var cl = (Class) m.parent_symbol;
+                                               var cdecl = new CCodeDeclaration (cl.get_cname () + "*");
+                                               var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
+                                               ccall.add_argument (new CCodeIdentifier ("type"));
+                                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", new CCodeCastExpression (ccall, cl.get_cname () + "*")));
+                                               cinit.append (cdecl);
+                                       } else if (in_gtypeinstance_creation_method) {
+                                               var cl = (Class) m.parent_symbol;
+                                               var cdecl = new CCodeDeclaration (cl.get_cname () + "*");
+                                               var fundamental_class = find_fundamental_class (cl);
+                                               var ccall = new CCodeFunctionCall (new CCodeIdentifier (fundamental_class.default_construction_method.get_cname ()));
+                                               ccall.add_argument (new CCodeIdentifier (cl.get_type_id ()));
+                                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+                                               cinit.append (cdecl);
+                                       } else if (codegen.current_type_symbol is Class) {
+                                               var cl = (Class) m.parent_symbol;
+                                               var cdecl = new CCodeDeclaration (cl.get_cname () + "*");
+                                               var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
+                                               ccall.add_argument (new CCodeIdentifier (cl.get_cname ()));
+                                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+                                               cinit.append (cdecl);
+                                       } else {
+                                               var st = (Struct) m.parent_symbol;
+
+                                               // memset needs string.h
+                                               codegen.string_h_needed = true;
+                                               var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+                                               czero.add_argument (new CCodeIdentifier ("self"));
+                                               czero.add_argument (new CCodeConstant ("0"));
+                                               czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (st.get_cname ())));
+                                               cinit.append (new CCodeExpressionStatement (czero));
+                                       }
+                               }
+
+                               if (codegen.context.module_init_method == m && codegen.in_plugin) {
+                                       // GTypeModule-based plug-in, register types
+                                       cinit.append (codegen.module_init_fragment);
+                               }
+
+                               foreach (Expression precondition in m.get_preconditions ()) {
+                                       cinit.append (create_precondition_statement (m, creturn_type, precondition));
+                               }
+                       }
+               }
+               
+               if (m.is_abstract || m.is_virtual) {
+                       var vfunc = new CCodeFunction (m.get_cname (), creturn_type.get_cname ());
+                       vfunc.line = codegen.function.line;
+
+                       ReferenceType this_type;
+                       if (m.parent_symbol is Class) {
+                               this_type = new ClassType ((Class) m.parent_symbol);
+                       } else {
+                               this_type = new InterfaceType ((Interface) m.parent_symbol);
+                       }
+
+                       cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+                       var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+
+                       var cparam = new CCodeFormalParameter ("self", this_type.get_cname ());
+                       cparam_map.set (codegen.get_param_pos (m.cinstance_parameter_position), cparam);
+                       
+                       var vblock = new CCodeBlock ();
+
+                       foreach (Expression precondition in m.get_preconditions ()) {
+                               vblock.add_statement (create_precondition_statement (m, creturn_type, precondition));
+                       }
+
+                       CCodeFunctionCall vcast = null;
+                       if (m.parent_symbol is Interface) {
+                               var iface = (Interface) m.parent_symbol;
+
+                               vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
+                       } else {
+                               var cl = (Class) m.parent_symbol;
+
+                               vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
+                       }
+                       vcast.add_argument (new CCodeIdentifier ("self"));
+               
+                       var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, m.vfunc_name));
+                       carg_map.set (codegen.get_param_pos (m.cinstance_parameter_position), new CCodeIdentifier ("self"));
+               
+                       var params = m.get_parameters ();
+                       foreach (FormalParameter param in params) {
+                               if (!param.no_array_length && param.type_reference is ArrayType) {
+                                       var array_type = (ArrayType) param.type_reference;
+                                       
+                                       var length_ctype = "int";
+                                       if (param.direction != ParameterDirection.IN) {
+                                               length_ctype = "int*";
+                                       }
+                                       
+                                       for (int dim = 1; dim <= array_type.rank; dim++) {
+                                               var cparam = new CCodeFormalParameter (codegen.get_array_length_cname (param.name, dim), length_ctype);
+                                               cparam_map.set (codegen.get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
+                                               carg_map.set (codegen.get_param_pos (param.carray_length_parameter_position + 0.01 * dim), new CCodeIdentifier (cparam.name));
+                                       }
+                               }
+
+                               cparam_map.set (codegen.get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
+                               carg_map.set (codegen.get_param_pos (param.cparameter_position), new CCodeIdentifier (param.name));
+
+                               if (param.type_reference is DelegateType) {
+                                       var deleg_type = (DelegateType) param.type_reference;
+                                       var d = deleg_type.delegate_symbol;
+                                       if (d.instance) {
+                                               var cparam = new CCodeFormalParameter (codegen.get_delegate_target_cname (param.name), "void*");
+                                               cparam_map.set (codegen.get_param_pos (param.cdelegate_target_parameter_position), cparam);
+                                               carg_map.set (codegen.get_param_pos (param.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));
+                                       }
+                               }
+                       }
+
+                       // return array length if appropriate
+                       if (!m.no_array_length && creturn_type is ArrayType) {
+                               var array_type = (ArrayType) creturn_type;
+
+                               for (int dim = 1; dim <= array_type.rank; dim++) {
+                                       var cparam = new CCodeFormalParameter (codegen.get_array_length_cname ("result", dim), "int*");
+                                       cparam_map.set (codegen.get_param_pos (m.carray_length_parameter_position), cparam);
+                                       carg_map.set (codegen.get_param_pos (m.carray_length_parameter_position), new CCodeIdentifier (cparam.name));
+                               }
+                       } else if (creturn_type is DelegateType) {
+                               // return delegate target if appropriate
+                               var deleg_type = (DelegateType) creturn_type;
+                               var d = deleg_type.delegate_symbol;
+                               if (d.instance) {
+                                       var cparam = new CCodeFormalParameter (codegen.get_delegate_target_cname ("result"), "void*");
+                                       cparam_map.set (codegen.get_param_pos (m.cdelegate_target_parameter_position), cparam);
+                                       carg_map.set (codegen.get_param_pos (m.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));
+                               }
+                       }
+
+                       if (m.get_error_domains ().size > 0) {
+                               var cparam = new CCodeFormalParameter ("error", "GError**");
+                               cparam_map.set (codegen.get_param_pos (-1), cparam);
+                               carg_map.set (codegen.get_param_pos (-1), new CCodeIdentifier (cparam.name));
+                       }
+
+
+                       // append C parameters and arguments in the right order
+                       int last_pos = -1;
+                       int min_pos;
+                       while (true) {
+                               min_pos = -1;
+                               foreach (int pos in cparam_map.get_keys ()) {
+                                       if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+                                               min_pos = pos;
+                                       }
+                               }
+                               if (min_pos == -1) {
+                                       break;
+                               }
+                               vfunc.add_parameter (cparam_map.get (min_pos));
+                               vcall.add_argument (carg_map.get (min_pos));
+                               last_pos = min_pos;
+                       }
+
+                       CCodeStatement cstmt;
+                       if (creturn_type is VoidType) {
+                               cstmt = new CCodeExpressionStatement (vcall);
+                       } else if (m.get_postconditions ().size == 0) {
+                               /* pass method return value */
+                               cstmt = new CCodeReturnStatement (vcall);
+                       } else {
+                               /* store method return value for postconditions */
+                               var cdecl = new CCodeDeclaration (creturn_type.get_cname ());
+                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("result", vcall));
+                               cstmt = cdecl;
+                       }
+                       cstmt.line = vfunc.line;
+                       vblock.add_statement (cstmt);
+
+                       if (m.get_postconditions ().size > 0) {
+                               foreach (Expression postcondition in m.get_postconditions ()) {
+                                       vblock.add_statement (create_postcondition_statement (postcondition));
+                               }
+
+                               if (!(creturn_type is VoidType)) {
+                                       var cret_stmt = new CCodeReturnStatement (new CCodeIdentifier ("result"));
+                                       cret_stmt.line = vfunc.line;
+                                       vblock.add_statement (cret_stmt);
+                               }
+                       }
+
+                       if (visible) {
+                               codegen.header_type_member_declaration.append (vfunc.copy ());
+                       } else {
+                               vfunc.modifiers |= CCodeModifiers.STATIC;
+                               codegen.source_type_member_declaration.append (vfunc.copy ());
+                       }
+                       
+                       vfunc.block = vblock;
+
+                       if (m.is_abstract && m.source_reference != null && m.source_reference.comment != null) {
+                               codegen.source_type_member_definition.append (new CCodeComment (m.source_reference.comment));
+                       }
+                       codegen.source_type_member_definition.append (vfunc);
+               }
+               
+               if (m is CreationMethod) {
+                       if (((CreationMethod) m).n_construction_params > 0) {
+                               var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier ("__params_it"), new CCodeIdentifier ("__params"));
+                               var cdofreeparam = new CCodeBlock ();
+                               cdofreeparam.add_statement (new CCodeExpressionStatement (new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, new CCodeIdentifier ("__params_it"))));
+                               var cunsetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_unset"));
+                               cunsetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("__params_it"), "value")));
+                               cdofreeparam.add_statement (new CCodeExpressionStatement (cunsetcall));
+                               codegen.function.block.add_statement (new CCodeWhileStatement (ccond, cdofreeparam));
+
+                               var cfreeparams = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
+                               cfreeparams.add_argument (new CCodeIdentifier ("__params"));
+                               codegen.function.block.add_statement (new CCodeExpressionStatement (cfreeparams));
+                       }
+
+                       if (codegen.current_type_symbol is Class) {
+                               var creturn = new CCodeReturnStatement ();
+                               creturn.return_expression = new CCodeIdentifier ("self");
+                               codegen.function.block.add_statement (creturn);
+                       }
+               }
+               
+               bool return_value = true;
+               bool args_parameter = true;
+               if (is_possible_entry_point (m, ref return_value, ref args_parameter)) {
+                       // m is possible entry point, add appropriate startup code
+                       var cmain = new CCodeFunction ("main", "int");
+                       cmain.line = codegen.function.line;
+                       cmain.add_parameter (new CCodeFormalParameter ("argc", "int"));
+                       cmain.add_parameter (new CCodeFormalParameter ("argv", "char **"));
+                       var main_block = new CCodeBlock ();
+
+                       if (codegen.context.thread) {
+                               var thread_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_thread_init"));
+                               thread_init_call.line = cmain.line;
+                               thread_init_call.add_argument (new CCodeConstant ("NULL"));
+                               main_block.add_statement (new CCodeExpressionStatement (thread_init_call)); 
+                       }
+
+                       var type_init_call = new CCodeExpressionStatement (new CCodeFunctionCall (new CCodeIdentifier ("g_type_init")));
+                       type_init_call.line = cmain.line;
+                       main_block.add_statement (type_init_call);
+
+                       var main_call = new CCodeFunctionCall (new CCodeIdentifier (codegen.function.name));
+                       if (args_parameter) {
+                               main_call.add_argument (new CCodeIdentifier ("argv"));
+                               main_call.add_argument (new CCodeIdentifier ("argc"));
+                       }
+                       if (return_value) {
+                               var main_stmt = new CCodeReturnStatement (main_call);
+                               main_stmt.line = cmain.line;
+                               main_block.add_statement (main_stmt);
+                       } else {
+                               // 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);
+                       }
+                       cmain.block = main_block;
+                       codegen.source_type_member_definition.append (cmain);
+               }
+       }
+
+       private CCodeStatement create_method_type_check_statement (Method m, DataType return_type, Typesymbol t, bool non_null, string var_name) {
+               return codegen.create_type_check_statement (m, return_type, t, non_null, var_name);
+       }
+
+       private CCodeStatement create_precondition_statement (CodeNode method_node, DataType ret_type, Expression precondition) {
+               var ccheck = new CCodeFunctionCall ();
+
+               ccheck.add_argument ((CCodeExpression) precondition.ccodenode);
+
+               if (ret_type is VoidType) {
+                       /* void function */
+                       ccheck.call = new CCodeIdentifier ("g_return_if_fail");
+               } else {
+                       ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
+
+                       var cdefault = codegen.default_value_for_type (ret_type, false);
+                       if (cdefault != null) {
+                               ccheck.add_argument (cdefault);
+                       } else {
+                               return new CCodeExpressionStatement (new CCodeConstant ("0"));
+                       }
+               }
+               
+               return new CCodeExpressionStatement (ccheck);
+       }
+
+       private CCodeStatement create_postcondition_statement (Expression postcondition) {
+               var cassert = new CCodeFunctionCall (new CCodeIdentifier ("g_assert"));
+
+               cassert.add_argument ((CCodeExpression) postcondition.ccodenode);
+
+               return new CCodeExpressionStatement (cassert);
+       }
+
+       private Typesymbol? find_parent_type (Symbol sym) {
+               while (sym != null) {
+                       if (sym is Typesymbol) {
+                               return (Typesymbol) sym;
+                       }
+                       sym = sym.parent_symbol;
+               }
+               return null;
+       }
+
+       private bool is_possible_entry_point (Method m, ref bool return_value, ref bool args_parameter) {
+               if (m.name == null || m.name != "main") {
+                       // method must be called "main"
+                       return false;
+               }
+               
+               if (m.instance) {
+                       // method must be static
+                       return false;
+               }
+               
+               if (m.return_type.data_type == null) {
+                       return_value = false;
+               } else if (m.return_type.data_type == codegen.int_type.data_type) {
+                       return_value = true;
+               } else {
+                       // return type must be void or int
+                       return false;
+               }
+               
+               var params = m.get_parameters ();
+               if (params.size == 0) {
+                       // method may have no parameters
+                       args_parameter = false;
+                       return true;
+               }
+
+               if (params.size > 1) {
+                       // method must not have more than one parameter
+                       return false;
+               }
+               
+               Iterator<FormalParameter> params_it = params.iterator ();
+               params_it.next ();
+               var param = params_it.get ();
+
+               if (param.direction == ParameterDirection.OUT) {
+                       // parameter must not be an out parameter
+                       return false;
+               }
+               
+               if (!(param.type_reference is ArrayType)) {
+                       // parameter must be an array
+                       return false;
+               }
+               
+               var array_type = (ArrayType) param.type_reference;
+               if (array_type.element_type.data_type != codegen.string_type.data_type) {
+                       // parameter must be an array of strings
+                       return false;
+               }
+               
+               args_parameter = true;
+               return true;
+       }
+
+       private void add_object_creation (CCodeBlock b, bool has_params) {
+               var cl = (Class) codegen.current_type_symbol;
+       
+               var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
+               ccall.add_argument (new CCodeConstant (cl.get_type_id ()));
+               if (has_params) {
+                       ccall.add_argument (new CCodeConstant ("__params_it - __params"));
+                       ccall.add_argument (new CCodeConstant ("__params"));
+               } else {
+                       ccall.add_argument (new CCodeConstant ("0"));
+                       ccall.add_argument (new CCodeConstant ("NULL"));
+               }
+               
+               var cdecl = new CCodeVariableDeclarator ("self");
+               cdecl.initializer = ccall;
+               
+               var cdeclaration = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+               cdeclaration.add_declarator (cdecl);
+               
+               b.add_statement (cdeclaration);
+       }
+
+       private Class find_fundamental_class (Class cl) {
+               var fundamental_class = cl;
+               while (fundamental_class != null && fundamental_class.base_class != codegen.gtypeinstance_type) {
+                       fundamental_class = fundamental_class.base_class;
+               }
+               return fundamental_class;
        }
 }
index 0afd4a4..390e7f7 100644 (file)
@@ -83,4 +83,8 @@ public class Vala.CreationMethod : Method {
                        return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name.offset (".new.".len ()));
                }
        }
+
+       public override CodeBinding? create_code_binding (CodeGenerator codegen) {
+               return codegen.create_creation_method_binding (this);
+       }
 }