summaryrefslogtreecommitdiff
path: root/vala/valacodegenerator.vala
diff options
context:
space:
mode:
authorJürg Billeter <j@bitron.ch>2007-05-02 09:42:00 +0000
committerJürg Billeter <juergbi@src.gnome.org>2007-05-02 09:42:00 +0000
commitf8387ad143f1884f8f5f89bd5389605624f4c34f (patch)
treee75e563fc9535200ec146af72962e80778359ae4 /vala/valacodegenerator.vala
parent9db973114ee1449c1764404163ecc8294f8e73d2 (diff)
downloadvala-f8387ad143f1884f8f5f89bd5389605624f4c34f.tar.gz
Move contents of vala-pkg to trunk
2007-05-02 Jürg Billeter <j@bitron.ch> * Move contents of vala-pkg to trunk svn path=/trunk/; revision=300
Diffstat (limited to 'vala/valacodegenerator.vala')
-rw-r--r--vala/valacodegenerator.vala4177
1 files changed, 4177 insertions, 0 deletions
diff --git a/vala/valacodegenerator.vala b/vala/valacodegenerator.vala
new file mode 100644
index 000000000..8a8807142
--- /dev/null
+++ b/vala/valacodegenerator.vala
@@ -0,0 +1,4177 @@
+/* valacodegenerator.vala
+ *
+ * Copyright (C) 2006-2007 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 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 <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Code visitor generating C Code.
+ */
+public class Vala.CodeGenerator : CodeVisitor {
+ /**
+ * Specifies whether automatic memory management is active.
+ */
+ public bool memory_management { get; set; }
+
+ private CodeContext context;
+
+ Symbol root_symbol;
+ Symbol current_symbol;
+ Symbol current_type_symbol;
+ Class current_class;
+ TypeReference current_return_type;
+
+ CCodeFragment header_begin;
+ CCodeFragment header_type_declaration;
+ CCodeFragment header_type_definition;
+ CCodeFragment header_type_member_declaration;
+ CCodeFragment source_begin;
+ CCodeFragment source_include_directives;
+ CCodeFragment source_type_member_declaration;
+ CCodeFragment source_signal_marshaller_declaration;
+ CCodeFragment source_type_member_definition;
+ CCodeFragment instance_init_fragment;
+ CCodeFragment instance_dispose_fragment;
+ CCodeFragment source_signal_marshaller_definition;
+ CCodeFragment module_init_fragment;
+
+ CCodeStruct instance_struct;
+ CCodeStruct type_struct;
+ CCodeStruct instance_priv_struct;
+ CCodeEnum prop_enum;
+ CCodeEnum cenum;
+ CCodeFunction function;
+ CCodeBlock block;
+
+ /* all temporary variables */
+ List<VariableDeclarator> temp_vars;
+ /* temporary variables that own their content */
+ List<VariableDeclarator> temp_ref_vars;
+ /* cache to check whether a certain marshaller has been created yet */
+ HashTable<string,bool> user_marshal_list;
+ /* (constant) hash table with all predefined marshallers */
+ HashTable<string,bool> predefined_marshal_list;
+
+ private int next_temp_var_id = 0;
+ private bool in_creation_method = false;
+
+ TypeReference bool_type;
+ TypeReference char_type;
+ TypeReference unichar_type;
+ TypeReference short_type;
+ TypeReference ushort_type;
+ TypeReference int_type;
+ TypeReference uint_type;
+ TypeReference long_type;
+ TypeReference ulong_type;
+ TypeReference int64_type;
+ TypeReference uint64_type;
+ TypeReference string_type;
+ TypeReference float_type;
+ TypeReference double_type;
+ DataType list_type;
+ DataType slist_type;
+ TypeReference mutex_type;
+ DataType type_module_type;
+
+ private bool in_plugin = false;
+ private string module_init_param_name;
+
+ private bool string_h_needed;
+
+ public CodeGenerator (bool manage_memory = true) {
+ memory_management = manage_memory;
+ }
+
+ construct {
+ predefined_marshal_list = new HashTable (str_hash, str_equal);
+ predefined_marshal_list.insert ("VOID:VOID", true);
+ predefined_marshal_list.insert ("VOID:BOOLEAN", true);
+ predefined_marshal_list.insert ("VOID:CHAR", true);
+ predefined_marshal_list.insert ("VOID:UCHAR", true);
+ predefined_marshal_list.insert ("VOID:INT", true);
+ predefined_marshal_list.insert ("VOID:UINT", true);
+ predefined_marshal_list.insert ("VOID:LONG", true);
+ predefined_marshal_list.insert ("VOID:ULONG", true);
+ predefined_marshal_list.insert ("VOID:ENUM", true);
+ predefined_marshal_list.insert ("VOID:FLAGS", true);
+ predefined_marshal_list.insert ("VOID:FLOAT", true);
+ predefined_marshal_list.insert ("VOID:DOUBLE", true);
+ predefined_marshal_list.insert ("VOID:STRING", true);
+ predefined_marshal_list.insert ("VOID:POINTER", true);
+ predefined_marshal_list.insert ("VOID:OBJECT", true);
+ predefined_marshal_list.insert ("STRING:OBJECT,POINTER", true);
+ predefined_marshal_list.insert ("VOID:UINT,POINTER", true);
+ predefined_marshal_list.insert ("BOOLEAN:FLAGS", true);
+ }
+
+ /**
+ * Generate and emit C code for the specified code context.
+ *
+ * @param context a code context
+ */
+ public void emit (CodeContext! context) {
+ this.context = context;
+
+ context.find_header_cycles ();
+
+ root_symbol = context.get_root ();
+
+ bool_type = new TypeReference ();
+ bool_type.data_type = (DataType) root_symbol.lookup ("bool").node;
+
+ char_type = new TypeReference ();
+ char_type.data_type = (DataType) root_symbol.lookup ("char").node;
+
+ unichar_type = new TypeReference ();
+ unichar_type.data_type = (DataType) root_symbol.lookup ("unichar").node;
+
+ short_type = new TypeReference ();
+ short_type.data_type = (DataType) root_symbol.lookup ("short").node;
+
+ ushort_type = new TypeReference ();
+ ushort_type.data_type = (DataType) root_symbol.lookup ("ushort").node;
+
+ int_type = new TypeReference ();
+ int_type.data_type = (DataType) root_symbol.lookup ("int").node;
+
+ uint_type = new TypeReference ();
+ uint_type.data_type = (DataType) root_symbol.lookup ("uint").node;
+
+ long_type = new TypeReference ();
+ long_type.data_type = (DataType) root_symbol.lookup ("long").node;
+
+ ulong_type = new TypeReference ();
+ ulong_type.data_type = (DataType) root_symbol.lookup ("ulong").node;
+
+ int64_type = new TypeReference ();
+ int64_type.data_type = (DataType) root_symbol.lookup ("int64").node;
+
+ uint64_type = new TypeReference ();
+ uint64_type.data_type = (DataType) root_symbol.lookup ("uint64").node;
+
+ float_type = new TypeReference ();
+ float_type.data_type = (DataType) root_symbol.lookup ("float").node;
+
+ double_type = new TypeReference ();
+ double_type.data_type = (DataType) root_symbol.lookup ("double").node;
+
+ string_type = new TypeReference ();
+ string_type.data_type = (DataType) root_symbol.lookup ("string").node;
+
+ var glib_ns = root_symbol.lookup ("GLib");
+
+ list_type = (DataType) glib_ns.lookup ("List").node;
+ slist_type = (DataType) glib_ns.lookup ("SList").node;
+
+ mutex_type = new TypeReference ();
+ mutex_type.data_type = (DataType) glib_ns.lookup ("Mutex").node;
+
+ type_module_type = (DataType) glib_ns.lookup ("TypeModule").node;
+
+ if (context.module_init_method != null) {
+ module_init_fragment = new CCodeFragment ();
+ foreach (FormalParameter parameter in context.module_init_method.get_parameters ()) {
+ if (parameter.type_reference.data_type == type_module_type) {
+ in_plugin = true;
+ module_init_param_name = parameter.name;
+ break;
+ }
+ }
+ }
+
+ /* we're only interested in non-pkg source files */
+ var source_files = context.get_source_files ();
+ foreach (SourceFile file in source_files) {
+ if (!file.pkg) {
+ file.accept (this);
+ }
+ }
+ }
+
+ private ref CCodeIncludeDirective get_internal_include (string! filename) {
+ return new CCodeIncludeDirective (filename, context.library == null);
+ }
+
+ public override void visit_begin_source_file (SourceFile! source_file) {
+ header_begin = new CCodeFragment ();
+ header_type_declaration = new CCodeFragment ();
+ header_type_definition = new CCodeFragment ();
+ header_type_member_declaration = new CCodeFragment ();
+ source_begin = new CCodeFragment ();
+ source_include_directives = new CCodeFragment ();
+ source_type_member_declaration = new CCodeFragment ();
+ source_type_member_definition = new CCodeFragment ();
+ source_signal_marshaller_definition = new CCodeFragment ();
+ source_signal_marshaller_declaration = new CCodeFragment ();
+
+ user_marshal_list = new HashTable (str_hash, str_equal);
+
+ next_temp_var_id = 0;
+
+ string_h_needed = false;
+
+ header_begin.append (new CCodeIncludeDirective ("glib.h"));
+ header_begin.append (new CCodeIncludeDirective ("glib-object.h"));
+ source_include_directives.append (new CCodeIncludeDirective (source_file.get_cheader_filename (), true));
+
+ ref List<weak string> used_includes = null;
+ used_includes.append ("glib.h");
+ used_includes.append ("glib-object.h");
+ used_includes.append (source_file.get_cheader_filename ());
+
+ foreach (string filename1 in source_file.get_header_external_includes ()) {
+ if (used_includes.find_custom (filename1, strcmp) == null) {
+ header_begin.append (new CCodeIncludeDirective (filename1));
+ used_includes.append (filename1);
+ }
+ }
+ foreach (string filename2 in source_file.get_header_internal_includes ()) {
+ if (used_includes.find_custom (filename2, strcmp) == null) {
+ header_begin.append (get_internal_include (filename2));
+ used_includes.append (filename2);
+ }
+ }
+ foreach (string filename3 in source_file.get_source_external_includes ()) {
+ if (used_includes.find_custom (filename3, strcmp) == null) {
+ source_include_directives.append (new CCodeIncludeDirective (filename3));
+ used_includes.append (filename3);
+ }
+ }
+ foreach (string filename4 in source_file.get_source_internal_includes ()) {
+ if (used_includes.find_custom (filename4, strcmp) == null) {
+ source_include_directives.append (get_internal_include (filename4));
+ used_includes.append (filename4);
+ }
+ }
+ if (source_file.is_cycle_head) {
+ foreach (SourceFile cycle_file in source_file.cycle.files) {
+ var namespaces = cycle_file.get_namespaces ();
+ foreach (Namespace ns in namespaces) {
+ var structs = ns.get_structs ();
+ foreach (Struct st in structs) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (st.get_cname ()), new CCodeVariableDeclarator (st.get_cname ())));
+ }
+ var classes = ns.get_classes ();
+ foreach (Class cl in classes) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (cl.get_cname ()), new CCodeVariableDeclarator (cl.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%sClass".printf (cl.get_cname ()), new CCodeVariableDeclarator ("%sClass".printf (cl.get_cname ()))));
+ }
+ var ifaces = ns.get_interfaces ();
+ foreach (Interface iface in ifaces) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), new CCodeVariableDeclarator (iface.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_type_cname ()), new CCodeVariableDeclarator (iface.get_type_cname ())));
+ }
+ }
+ }
+ }
+
+ /* generate hardcoded "well-known" macros */
+ source_begin.append (new CCodeMacroReplacement ("VALA_FREE_CHECKED(o,f)", "((o) == NULL ? NULL : ((o) = (f (o), NULL)))"));
+ source_begin.append (new CCodeMacroReplacement ("VALA_FREE_UNCHECKED(o,f)", "((o) = (f (o), NULL))"));
+ }
+
+ private static ref string get_define_for_filename (string! filename) {
+ var define = new String ("__");
+
+ var i = filename;
+ while (i.len () > 0) {
+ var c = i.get_char ();
+ if (c.isalnum () && c < 0x80) {
+ define.append_unichar (c.toupper ());
+ } else {
+ define.append_c ('_');
+ }
+
+ i = i.next_char ();
+ }
+
+ define.append ("__");
+
+ return define.str;
+ }
+
+ public override void visit_end_source_file (SourceFile! source_file) {
+ var header_define = get_define_for_filename (source_file.get_cheader_filename ());
+
+ if (string_h_needed) {
+ source_include_directives.append (new CCodeIncludeDirective ("string.h"));
+ }
+
+ CCodeComment comment = null;
+ if (source_file.comment != null) {
+ comment = new CCodeComment (source_file.comment);
+ }
+
+ var writer = new CCodeWriter (source_file.get_cheader_filename ());
+ if (comment != null) {
+ comment.write (writer);
+ }
+ writer.write_newline ();
+ var once = new CCodeOnceSection (header_define);
+ once.append (new CCodeNewline ());
+ once.append (header_begin);
+ once.append (new CCodeNewline ());
+ once.append (new CCodeIdentifier ("G_BEGIN_DECLS"));
+ once.append (new CCodeNewline ());
+ once.append (new CCodeNewline ());
+ once.append (header_type_declaration);
+ once.append (new CCodeNewline ());
+ once.append (header_type_definition);
+ once.append (new CCodeNewline ());
+ once.append (header_type_member_declaration);
+ once.append (new CCodeNewline ());
+ once.append (new CCodeIdentifier ("G_END_DECLS"));
+ once.append (new CCodeNewline ());
+ once.append (new CCodeNewline ());
+ once.write (writer);
+ writer.close ();
+
+ writer = new CCodeWriter (source_file.get_csource_filename ());
+ if (comment != null) {
+ comment.write (writer);
+ }
+ source_begin.write (writer);
+ writer.write_newline ();
+ source_include_directives.write (writer);
+ writer.write_newline ();
+ source_type_member_declaration.write (writer);
+ writer.write_newline ();
+ source_signal_marshaller_declaration.write (writer);
+ writer.write_newline ();
+ source_type_member_definition.write (writer);
+ writer.write_newline ();
+ source_signal_marshaller_definition.write (writer);
+ writer.write_newline ();
+ writer.close ();
+
+ header_begin = null;
+ header_type_declaration = null;
+ header_type_definition = null;
+ header_type_member_declaration = null;
+ source_begin = null;
+ source_include_directives = null;
+ source_type_member_declaration = null;
+ source_type_member_definition = null;
+ source_signal_marshaller_definition = null;
+ source_signal_marshaller_declaration = null;
+ }
+
+ public override void visit_begin_class (Class! cl) {
+ current_symbol = cl.symbol;
+ current_type_symbol = cl.symbol;
+ current_class = cl;
+
+ if (cl.is_static) {
+ return;
+ }
+
+ instance_struct = new CCodeStruct ("_%s".printf (cl.get_cname ()));
+ type_struct = new CCodeStruct ("_%sClass".printf (cl.get_cname ()));
+ instance_priv_struct = new CCodeStruct ("_%sPrivate".printf (cl.get_cname ()));
+ prop_enum = new CCodeEnum ();
+ prop_enum.add_value ("%s_DUMMY_PROPERTY".printf (cl.get_upper_case_cname (null)), null);
+ instance_init_fragment = new CCodeFragment ();
+ instance_dispose_fragment = new CCodeFragment ();
+
+
+ header_type_declaration.append (new CCodeNewline ());
+ var macro = "(%s_get_type ())".printf (cl.get_lower_case_cname (null));
+ header_type_declaration.append (new CCodeMacroReplacement (cl.get_upper_case_cname ("TYPE_"), macro));
+
+ macro = "(G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, %s))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
+ header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (cl.get_upper_case_cname (null)), macro));
+
+ macro = "(G_TYPE_CHECK_CLASS_CAST ((klass), %s, %sClass))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
+ header_type_declaration.append (new CCodeMacroReplacement ("%s_CLASS(klass)".printf (cl.get_upper_case_cname (null)), macro));
+
+ macro = "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))".printf (cl.get_upper_case_cname ("TYPE_"));
+ header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (cl.get_upper_case_cname ("IS_")), macro));
+
+ macro = "(G_TYPE_CHECK_CLASS_TYPE ((klass), %s))".printf (cl.get_upper_case_cname ("TYPE_"));
+ header_type_declaration.append (new CCodeMacroReplacement ("%s_CLASS(klass)".printf (cl.get_upper_case_cname ("IS_")), macro));
+
+ macro = "(G_TYPE_INSTANCE_GET_CLASS ((obj), %s, %sClass))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
+ header_type_declaration.append (new CCodeMacroReplacement ("%s_GET_CLASS(obj)".printf (cl.get_upper_case_cname (null)), macro));
+ header_type_declaration.append (new CCodeNewline ());
+
+
+ if (cl.source_reference.file.cycle == null) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (instance_struct.name), new CCodeVariableDeclarator (cl.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (type_struct.name), new CCodeVariableDeclarator ("%sClass".printf (cl.get_cname ()))));
+ }
+ header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (instance_priv_struct.name), new CCodeVariableDeclarator ("%sPrivate".printf (cl.get_cname ()))));
+
+ instance_struct.add_field (cl.base_class.get_cname (), "parent");
+ instance_struct.add_field ("%sPrivate *".printf (cl.get_cname ()), "priv");
+ type_struct.add_field ("%sClass".printf (cl.base_class.get_cname ()), "parent");
+
+ if (cl.source_reference.comment != null) {
+ header_type_definition.append (new CCodeComment (cl.source_reference.comment));
+ }
+ header_type_definition.append (instance_struct);
+ header_type_definition.append (type_struct);
+ source_type_member_declaration.append (instance_priv_struct);
+ macro = "(G_TYPE_INSTANCE_GET_PRIVATE ((o), %s, %sPrivate))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
+ source_type_member_declaration.append (new CCodeMacroReplacement ("%s_GET_PRIVATE(o)".printf (cl.get_upper_case_cname (null)), macro));
+ source_type_member_declaration.append (prop_enum);
+ }
+
+ public override void visit_end_class (Class! cl) {
+ if (!cl.is_static) {
+ add_get_property_function (cl);
+ add_set_property_function (cl);
+ add_class_init_function (cl);
+
+ foreach (TypeReference base_type in cl.get_base_types ()) {
+ if (base_type.data_type is Interface) {
+ add_interface_init_function (cl, (Interface) base_type.data_type);
+ }
+ }
+
+ add_instance_init_function (cl);
+ if (memory_management && cl.get_fields () != null) {
+ add_dispose_function (cl);
+ }
+
+ var type_fun = new ClassRegisterFunction (cl);
+ type_fun.init_from_type (in_plugin);
+ header_type_member_declaration.append (type_fun.get_declaration ());
+ source_type_member_definition.append (type_fun.get_definition ());
+
+ if (in_plugin) {
+ // FIXME resolve potential dependency issues, i.e. base types have to be registered before derived types
+ var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (cl.get_lower_case_cname (null))));
+ register_call.add_argument (new CCodeIdentifier (module_init_param_name));
+ module_init_fragment.append (new CCodeExpressionStatement (register_call));
+ }
+ }
+
+ current_type_symbol = null;
+ current_class = null;
+ instance_dispose_fragment = null;
+ }
+
+ private void add_class_init_function (Class! cl) {
+ var class_init = new CCodeFunction ("%s_class_init".printf (cl.get_lower_case_cname (null)), "void");
+ class_init.add_parameter (new CCodeFormalParameter ("klass", "%sClass *".printf (cl.get_cname ())));
+ class_init.modifiers = CCodeModifiers.STATIC;
+
+ var init_block = new CCodeBlock ();
+ class_init.block = init_block;
+
+ ref CCodeFunctionCall ccall;
+
+ /* save pointer to parent class */
+ var parent_decl = new CCodeDeclaration ("gpointer");
+ var parent_var_decl = new CCodeVariableDeclarator ("%s_parent_class".printf (cl.get_lower_case_cname (null)));
+ parent_var_decl.initializer = new CCodeConstant ("NULL");
+ parent_decl.add_declarator (parent_var_decl);
+ parent_decl.modifiers = CCodeModifiers.STATIC;
+ source_type_member_declaration.append (parent_decl);
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
+ ccall.add_argument (new CCodeIdentifier ("klass"));
+ var parent_assignment = new CCodeAssignment (new CCodeIdentifier ("%s_parent_class".printf (cl.get_lower_case_cname (null))), ccall);
+ init_block.add_statement (new CCodeExpressionStatement (parent_assignment));
+
+ /* add struct for private fields */
+ if (cl.has_private_fields) {
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_add_private"));
+ ccall.add_argument (new CCodeIdentifier ("klass"));
+ ccall.add_argument (new CCodeConstant ("sizeof (%sPrivate)".printf (cl.get_cname ())));
+ init_block.add_statement (new CCodeExpressionStatement (ccall));
+ }
+
+ /* set property handlers */
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+ ccall.add_argument (new CCodeIdentifier ("klass"));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccall, "get_property"), new CCodeIdentifier ("%s_get_property".printf (cl.get_lower_case_cname (null))))));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccall, "set_property"), new CCodeIdentifier ("%s_set_property".printf (cl.get_lower_case_cname (null))))));
+
+ /* set constructor */
+ if (cl.constructor != null) {
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+ ccast.add_argument (new CCodeIdentifier ("klass"));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "constructor"), new CCodeIdentifier ("%s_constructor".printf (cl.get_lower_case_cname (null))))));
+ }
+
+ /* set dispose function */
+ if (memory_management && cl.get_fields () != null) {
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+ ccast.add_argument (new CCodeIdentifier ("klass"));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "dispose"), new CCodeIdentifier ("%s_dispose".printf (cl.get_lower_case_cname (null))))));
+ }
+
+ /* connect overridden methods */
+ var methods = cl.get_methods ();
+ foreach (Method m in methods) {
+ if (m.base_method == null) {
+ continue;
+ }
+ var base_type = m.base_method.symbol.parent_symbol.node;
+
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (((Class) base_type).get_upper_case_cname (null))));
+ ccast.add_argument (new CCodeIdentifier ("klass"));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, m.name), new CCodeIdentifier (m.get_real_cname ()))));
+ }
+
+ /* create destroy_func properties for generic types */
+ foreach (TypeParameter type_param in cl.get_type_parameters ()) {
+ string func_name = "%s_destroy_func".printf (type_param.name.down ());
+ var func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
+ string enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
+ var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
+ cinst.add_argument (ccall);
+ cinst.add_argument (new CCodeConstant (enum_value));
+ var cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
+ cspec.add_argument (func_name_constant);
+ cspec.add_argument (new CCodeConstant ("\"destroy func\""));
+ cspec.add_argument (new CCodeConstant ("\"destroy func\""));
+ cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
+ cinst.add_argument (cspec);
+ init_block.add_statement (new CCodeExpressionStatement (cinst));
+ prop_enum.add_value (enum_value, null);
+
+ instance_priv_struct.add_field ("GDestroyNotify", func_name);
+ }
+
+ /* create properties */
+ var props = cl.get_properties ();
+ foreach (Property prop in props) {
+ if (prop.overrides || prop.base_interface_property != null) {
+ var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_override_property"));
+ cinst.add_argument (ccall);
+ cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
+ cinst.add_argument (prop.get_canonical_cconstant ());
+
+ init_block.add_statement (new CCodeExpressionStatement (cinst));
+ } else {
+ var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
+ cinst.add_argument (ccall);
+ cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
+ cinst.add_argument (get_param_spec (prop));
+
+ init_block.add_statement (new CCodeExpressionStatement (cinst));
+ }
+ }
+
+ /* create signals */
+ foreach (Signal sig in cl.get_signals ()) {
+ init_block.add_statement (new CCodeExpressionStatement (get_signal_creation (sig, cl)));
+ }
+
+ source_type_member_definition.append (class_init);
+ }
+
+ private void add_interface_init_function (Class! cl, Interface! iface) {
+ var iface_init = new CCodeFunction ("%s_%s_interface_init".printf (cl.get_lower_case_cname (null), iface.get_lower_case_cname (null)), "void");
+ iface_init.add_parameter (new CCodeFormalParameter ("iface", "%s *".printf (iface.get_type_cname ())));
+ iface_init.modifiers = CCodeModifiers.STATIC;
+
+ var init_block = new CCodeBlock ();
+ iface_init.block = init_block;
+
+ ref CCodeFunctionCall ccall;
+
+ /* save pointer to parent vtable */
+ string parent_iface_var = "%s_%s_parent_iface".printf (cl.get_lower_case_cname (null), iface.get_lower_case_cname (null));
+ var parent_decl = new CCodeDeclaration (iface.get_type_cname () + "*");
+ var parent_var_decl = new CCodeVariableDeclarator (parent_iface_var);
+ parent_var_decl.initializer = new CCodeConstant ("NULL");
+ parent_decl.add_declarator (parent_var_decl);
+ parent_decl.modifiers = CCodeModifiers.STATIC;
+ source_type_member_declaration.append (parent_decl);
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_interface_peek_parent"));
+ ccall.add_argument (new CCodeIdentifier ("iface"));
+ var parent_assignment = new CCodeAssignment (new CCodeIdentifier (parent_iface_var), ccall);
+ init_block.add_statement (new CCodeExpressionStatement (parent_assignment));
+
+ var methods = cl.get_methods ();
+ foreach (Method m in methods) {
+ if (m.base_interface_method == null) {
+ continue;
+ }
+
+ var base_type = m.base_interface_method.symbol.parent_symbol.node;
+ if (base_type != iface) {
+ continue;
+ }
+
+ var ciface = new CCodeIdentifier ("iface");
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, m.name), new CCodeIdentifier (m.get_real_cname ()))));
+ }
+
+ source_type_member_definition.append (iface_init);
+ }
+
+ private void add_instance_init_function (Class! cl) {
+ var instance_init = new CCodeFunction ("%s_init".printf (cl.get_lower_case_cname (null)), "void");
+ instance_init.add_parameter (new CCodeFormalParameter ("self", "%s *".printf (cl.get_cname ())));
+ instance_init.modifiers = CCodeModifiers.STATIC;
+
+ var init_block = new CCodeBlock ();
+ instance_init.block = init_block;
+
+ if (cl.has_private_fields) {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (cl.get_upper_case_cname (null))));
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), ccall)));
+ }
+
+ init_block.add_statement (instance_init_fragment);
+
+ var init_sym = cl.symbol.lookup ("init");
+ if (init_sym != null) {
+ var init_fun = (Method) init_sym.node;
+ init_block.add_statement (init_fun.body.ccodenode);
+ }
+
+ source_type_member_definition.append (instance_init);
+ }
+
+ private void add_dispose_function (Class! cl) {
+ function = new CCodeFunction ("%s_dispose".printf (cl.get_lower_case_cname (null)), "void");
+ function.modifiers = CCodeModifiers.STATIC;
+
+ function.add_parameter (new CCodeFormalParameter ("obj", "GObject *"));
+
+ source_type_member_declaration.append (function.copy ());
+
+
+ var cblock = new CCodeBlock ();
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccall.add_argument (new CCodeIdentifier ("obj"));
+
+ var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+
+ cblock.add_statement (cdecl);
+
+ cblock.add_statement (instance_dispose_fragment);
+
+ cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator ("klass"));
+ cblock.add_statement (cdecl);
+
+ cdecl = new CCodeDeclaration ("GObjectClass *");
+ cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class"));
+ cblock.add_statement (cdecl);
+
+
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek"));
+ ccall.add_argument (new CCodeIdentifier (cl.get_upper_case_cname ("TYPE_")));
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null))));
+ ccast.add_argument (ccall);
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("klass"), ccast)));
+
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
+ ccall.add_argument (new CCodeIdentifier ("klass"));
+ ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+ ccast.add_argument (ccall);
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast)));
+
+
+ ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "dispose"));
+ ccall.add_argument (new CCodeIdentifier ("obj"));
+ cblock.add_statement (new CCodeExpressionStatement (ccall));
+
+
+ function.block = cblock;
+
+ source_type_member_definition.append (function);
+ }
+
+ private ref CCodeIdentifier! get_value_setter_function (TypeReference! type_reference) {
+ if (type_reference.data_type is Class || type_reference.data_type is Interface) {
+ return new CCodeIdentifier ("g_value_set_object");
+ } else if (type_reference.data_type == string_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_string");
+ } else if (type_reference.data_type == int_type.data_type
+ || type_reference.data_type is Enum) {
+ return new CCodeIdentifier ("g_value_set_int");
+ } else if (type_reference.data_type == uint_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_uint");
+ } else if (type_reference.data_type == long_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_long");
+ } else if (type_reference.data_type == ulong_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_ulong");
+ } else if (type_reference.data_type == bool_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_boolean");
+ } else if (type_reference.data_type == float_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_float");
+ } else if (type_reference.data_type == double_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_double");
+ } else {
+ return new CCodeIdentifier ("g_value_set_pointer");
+ }
+ }
+
+ private void add_get_property_function (Class! cl) {
+ var get_prop = new CCodeFunction ("%s_get_property".printf (cl.get_lower_case_cname (null)), "void");
+ get_prop.modifiers = CCodeModifiers.STATIC;
+ get_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
+ get_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
+ get_prop.add_parameter (new CCodeFormalParameter ("value", "GValue *"));
+ get_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
+
+ var block = new CCodeBlock ();
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccall.add_argument (new CCodeIdentifier ("object"));
+ var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+ block.add_statement (cdecl);
+
+ var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
+ var props = cl.get_properties ();
+ foreach (Property prop in props) {
+ if (prop.get_accessor == null || prop.is_abstract) {
+ continue;
+ }
+
+ bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
+
+ string prefix = cl.get_lower_case_cname (null);
+ if (is_virtual) {
+ prefix += "_real";
+ }
+
+ var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ()));
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name)));
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ var csetcall = new CCodeFunctionCall ();
+ csetcall.call = get_value_setter_function (prop.type_reference);
+ csetcall.add_argument (new CCodeIdentifier ("value"));
+ csetcall.add_argument (ccall);
+ ccase.add_statement (new CCodeExpressionStatement (csetcall));
+ ccase.add_statement (new CCodeBreakStatement ());
+ cswitch.add_case (ccase);
+ }
+ block.add_statement (cswitch);
+
+ get_prop.block = block;
+
+ source_type_member_definition.append (get_prop);
+ }
+
+ private void add_set_property_function (Class! cl) {
+ var set_prop = new CCodeFunction ("%s_set_property".printf (cl.get_lower_case_cname (null)), "void");
+ set_prop.modifiers = CCodeModifiers.STATIC;
+ set_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
+ set_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
+ set_prop.add_parameter (new CCodeFormalParameter ("value", "const GValue *"));
+ set_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
+
+ var block = new CCodeBlock ();
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccall.add_argument (new CCodeIdentifier ("object"));
+ var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+ block.add_statement (cdecl);
+
+ var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
+ var props = cl.get_properties ();
+ foreach (Property prop in props) {
+ if (prop.set_accessor == null || prop.is_abstract) {
+ continue;
+ }
+
+ bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
+
+ string prefix = cl.get_lower_case_cname (null);
+ if (is_virtual) {
+ prefix += "_real";
+ }
+
+ var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ()));
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_set_%s".printf (prefix, prop.name)));
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ var cgetcall = new CCodeFunctionCall ();
+ if (prop.type_reference.data_type is Class || prop.type_reference.data_type is Interface) {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_object");
+ } else if (prop.type_reference.type_name == "string") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_string");
+ } else if (prop.type_reference.type_name == "int" || prop.type_reference.data_type is Enum) {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_int");
+ } else if (prop.type_reference.type_name == "uint") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_uint");
+ } else if (prop.type_reference.type_name == "long") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_long");
+ } else if (prop.type_reference.type_name == "ulong") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_ulong");
+ } else if (prop.type_reference.type_name == "bool") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_boolean");
+ } else if (prop.type_reference.type_name == "float") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_float");
+ } else if (prop.type_reference.type_name == "double") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_double");
+ } else {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_pointer");
+ }
+ cgetcall.add_argument (new CCodeIdentifier ("value"));
+ ccall.add_argument (cgetcall);
+ ccase.add_statement (new CCodeExpressionStatement (ccall));
+ ccase.add_statement (new CCodeBreakStatement ());
+ cswitch.add_case (ccase);
+ }
+ block.add_statement (cswitch);
+
+ /* destroy func properties for generic types */
+ foreach (TypeParameter type_param in cl.get_type_parameters ()) {
+ string func_name = "%s_destroy_func".printf (type_param.name.down ());
+ string enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
+
+ var ccase = new CCodeCaseStatement (new CCodeIdentifier (enum_value));
+ var cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+ var cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
+ cgetcall.add_argument (new CCodeIdentifier ("value"));
+ ccase.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
+ ccase.add_statement (new CCodeBreakStatement ());
+ cswitch.add_case (ccase);
+ }
+
+ set_prop.block = block;
+
+ source_type_member_definition.append (set_prop);
+ }
+
+ public override void visit_begin_struct (Struct! st) {
+ current_type_symbol = st.symbol;
+
+ instance_struct = new CCodeStruct ("_%s".printf (st.get_cname ()));
+
+ if (st.source_reference.file.cycle == null) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (st.get_cname ()), new CCodeVariableDeclarator (st.get_cname ())));
+ }
+
+ if (st.source_reference.comment != null) {
+ header_type_definition.append (new CCodeComment (st.source_reference.comment));
+ }
+ header_type_definition.append (instance_struct);
+ }
+
+ public override void visit_end_struct (Struct! st) {
+ current_type_symbol = null;
+ }
+
+ public override void visit_begin_interface (Interface! iface) {
+ current_symbol = iface.symbol;
+ current_type_symbol = iface.symbol;
+
+ if (iface.is_static) {
+ return;
+ }
+
+ type_struct = new CCodeStruct ("_%s".printf (iface.get_type_cname ()));
+
+ header_type_declaration.append (new CCodeNewline ());
+ var macro = "(%s_get_type ())".printf (iface.get_lower_case_cname (null));
+ header_type_declaration.append (new CCodeMacroReplacement (iface.get_upper_case_cname ("TYPE_"), macro));
+
+ macro = "(G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, %s))".printf (iface.get_upper_case_cname ("TYPE_"), iface.get_cname ());
+ header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (iface.get_upper_case_cname (null)), macro));
+
+ macro = "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))".printf (iface.get_upper_case_cname ("TYPE_"));
+ header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (iface.get_upper_case_cname ("IS_")), macro));
+
+ macro = "(G_TYPE_INSTANCE_GET_INTERFACE ((obj), %s, %s))".printf (iface.get_upper_case_cname ("TYPE_"), iface.get_type_cname ());
+ header_type_declaration.append (new CCodeMacroReplacement ("%s_GET_INTERFACE(obj)".printf (iface.get_upper_case_cname (null)), macro));
+ header_type_declaration.append (new CCodeNewline ());
+
+
+ if (iface.source_reference.file.cycle == null) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), new CCodeVariableDeclarator (iface.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (type_struct.name), new CCodeVariableDeclarator (iface.get_type_cname ())));
+ }
+
+ type_struct.add_field ("GTypeInterface", "parent");
+
+ if (iface.source_reference.comment != null) {
+ header_type_definition.append (new CCodeComment (iface.source_reference.comment));
+ }
+ header_type_definition.append (type_struct);
+ }
+
+ public override void visit_end_interface (Interface! iface) {
+ if (!iface.is_static) {
+ add_interface_base_init_function (iface);
+
+ var type_fun = new InterfaceRegisterFunction (iface);
+ type_fun.init_from_type ();
+ header_type_member_declaration.append (type_fun.get_declaration ());
+ source_type_member_definition.append (type_fun.get_definition ());
+ }
+
+ current_type_symbol = null;
+ }
+
+ private ref CCodeFunctionCall! get_param_spec (Property! prop) {
+ var cspec = new CCodeFunctionCall ();
+ cspec.add_argument (prop.get_canonical_cconstant ());
+ cspec.add_argument (new CCodeConstant ("\"foo\""));
+ cspec.add_argument (new CCodeConstant ("\"bar\""));
+ if (prop.type_reference.data_type is Class || prop.type_reference.data_type is Interface) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_object");
+ cspec.add_argument (new CCodeIdentifier (prop.type_reference.data_type.get_upper_case_cname ("TYPE_")));
+ } else if (prop.type_reference.data_type == string_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_string");
+ cspec.add_argument (new CCodeConstant ("NULL"));
+ } else if (prop.type_reference.data_type == int_type.data_type
+ || prop.type_reference.data_type is Enum) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_int");
+ cspec.add_argument (new CCodeConstant ("G_MININT"));
+ cspec.add_argument (new CCodeConstant ("G_MAXINT"));
+ cspec.add_argument (new CCodeConstant ("0"));
+ } else if (prop.type_reference.data_type == uint_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_uint");
+ cspec.add_argument (new CCodeConstant ("0"));
+ cspec.add_argument (new CCodeConstant ("G_MAXUINT"));
+ cspec.add_argument (new CCodeConstant ("0U"));
+ } else if (prop.type_reference.data_type == long_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_long");
+ cspec.add_argument (new CCodeConstant ("G_MINLONG"));
+ cspec.add_argument (new CCodeConstant ("G_MAXLONG"));
+ cspec.add_argument (new CCodeConstant ("0L"));
+ } else if (prop.type_reference.data_type == ulong_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_ulong");
+ cspec.add_argument (new CCodeConstant ("0"));
+ cspec.add_argument (new CCodeConstant ("G_MAXULONG"));
+ cspec.add_argument (new CCodeConstant ("0UL"));
+ } else if (prop.type_reference.data_type == bool_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_boolean");
+ cspec.add_argument (new CCodeConstant ("FALSE"));
+ } else if (prop.type_reference.data_type == float_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_float");
+ cspec.add_argument (new CCodeConstant ("-G_MAXFLOAT"));
+ cspec.add_argument (new CCodeConstant ("G_MAXFLOAT"));
+ cspec.add_argument (new CCodeConstant ("0.0F"));
+ } else if (prop.type_reference.data_type == double_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_double");
+ cspec.add_argument (new CCodeConstant ("-G_MAXDOUBLE"));
+ cspec.add_argument (new CCodeConstant ("G_MAXDOUBLE"));
+ cspec.add_argument (new CCodeConstant ("0.0"));
+ } else {
+ cspec.call = new CCodeIdentifier ("g_param_spec_pointer");
+ }
+
+ var pflags = "G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB";
+ if (prop.get_accessor != null) {
+ pflags = "%s%s".printf (pflags, " | G_PARAM_READABLE");
+ }
+ if (prop.set_accessor != null) {
+ pflags = "%s%s".printf (pflags, " | G_PARAM_WRITABLE");
+ if (prop.set_accessor.construction) {
+ if (prop.set_accessor.writable) {
+ pflags = "%s%s".printf (pflags, " | G_PARAM_CONSTRUCT");
+ } else {
+ pflags = "%s%s".printf (pflags, " | G_PARAM_CONSTRUCT_ONLY");
+ }
+ }
+ }
+ cspec.add_argument (new CCodeConstant (pflags));
+
+ return cspec;
+ }
+
+ private ref CCodeFunctionCall! get_signal_creation (Signal! sig, DataType! type) {
+ var csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new"));
+ csignew.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name)));
+ csignew.add_argument (new CCodeIdentifier (type.get_upper_case_cname ("TYPE_")));
+ csignew.add_argument (new CCodeConstant ("G_SIGNAL_RUN_LAST"));
+ csignew.add_argument (new CCodeConstant ("0"));
+ csignew.add_argument (new CCodeConstant ("NULL"));
+ csignew.add_argument (new CCodeConstant ("NULL"));
+
+ string marshaller = get_signal_marshaller_function (sig);
+
+ var marshal_arg = new CCodeIdentifier (marshaller);
+ csignew.add_argument (marshal_arg);
+
+ var params = sig.get_parameters ();
+ var params_len = params.length ();
+ if (sig.return_type.type_parameter != null) {
+ csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
+ } else if (sig.return_type.data_type == null) {
+ csignew.add_argument (new CCodeConstant ("G_TYPE_NONE"));
+ } else {
+ csignew.add_argument (new CCodeConstant (sig.return_type.data_type.get_type_id ()));
+ }
+ csignew.add_argument (new CCodeConstant ("%d".printf (params_len)));
+ foreach (FormalParameter param in params) {
+ if (param.type_reference.type_parameter != null) {
+ csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
+ } else {
+ csignew.add_argument (new CCodeConstant (param.type_reference.data_type.get_type_id ()));
+ }
+ }
+
+ marshal_arg.name = marshaller;
+
+ return csignew;
+ }
+
+ private void add_interface_base_init_function (Interface! iface) {
+ var base_init = new CCodeFunction ("%s_base_init".printf (iface.get_lower_case_cname (null)), "void");
+ base_init.add_parameter (new CCodeFormalParameter ("iface", "%sIface *".printf (iface.get_cname ())));
+ base_init.modifiers = CCodeModifiers.STATIC;
+
+ var init_block = new CCodeBlock ();
+
+ /* make sure not to run the initialization code twice */
+ base_init.block = new CCodeBlock ();
+ var decl = new CCodeDeclaration (bool_type.get_cname ());
+ decl.modifiers |= CCodeModifiers.STATIC;
+ decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("initialized", new CCodeConstant ("FALSE")));
+ base_init.block.add_statement (decl);
+ var cif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("initialized")), init_block);
+ base_init.block.add_statement (cif);
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("initialized"), new CCodeConstant ("TRUE"))));
+
+ /* create properties */
+ var props = iface.get_properties ();
+ foreach (Property prop in props) {
+ var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_interface_install_property"));
+ cinst.add_argument (new CCodeIdentifier ("iface"));
+ cinst.add_argument (get_param_spec (prop));
+
+ init_block.add_statement (new CCodeExpressionStatement (cinst));
+ }
+
+ /* create signals */
+ foreach (Signal sig in iface.get_signals ()) {
+ init_block.add_statement (new CCodeExpressionStatement (get_signal_creation (sig, iface)));
+ }
+
+ source_type_member_definition.append (base_init);
+ }
+
+ public override void visit_begin_enum (Enum! en) {
+ cenum = new CCodeEnum (en.get_cname ());
+
+ if (en.source_reference.comment != null) {
+ header_type_definition.append (new CCodeComment (en.source_reference.comment));
+ }
+ header_type_definition.append (cenum);
+ }
+
+ public override void visit_enum_value (EnumValue! ev) {
+ string val;
+ if (ev.value is LiteralExpression) {
+ var lit = ((LiteralExpression) ev.value).literal;
+ if (lit is IntegerLiteral) {
+ val = ((IntegerLiteral) lit).value;
+ }
+ }
+ cenum.add_value (ev.get_cname (), val);
+ }
+
+ public override void visit_begin_flags (Flags! fl) {
+ cenum = new CCodeEnum (fl.get_cname ());
+
+ if (fl.source_reference.comment != null) {
+ header_type_definition.append (new CCodeComment (fl.source_reference.comment));
+ }
+ header_type_definition.append (cenum);
+ }
+
+ public override void visit_flags_value (FlagsValue! fv) {
+ string val;
+ if (fv.value is LiteralExpression) {
+ var lit = ((LiteralExpression) fv.value).literal;
+ if (lit is IntegerLiteral) {
+ val = ((IntegerLiteral) lit).value;
+ }
+ }
+ cenum.add_value (fv.get_cname (), val);
+ }
+
+ public override void visit_end_callback (Callback! cb) {
+ var cfundecl = new CCodeFunctionDeclarator (cb.get_cname ());
+ foreach (FormalParameter param in cb.get_parameters ()) {
+ cfundecl.add_parameter ((CCodeFormalParameter) param.ccodenode);
+ }
+
+ var ctypedef = new CCodeTypeDefinition (cb.return_type.get_cname (), cfundecl);
+
+ if (cb.access != MemberAccessibility.PRIVATE) {
+ header_type_declaration.append (ctypedef);
+ } else {
+ source_type_member_declaration.append (ctypedef);
+ }
+ }
+
+ public override void visit_member (Member! m) {
+ /* stuff meant for all lockable members */
+ if (m is Lockable && ((Lockable)m).get_lock_used ()) {
+ instance_priv_struct.add_field (mutex_type.get_cname (), get_symbol_lock_name (m.symbol));
+
+ instance_init_fragment.append (
+ new CCodeExpressionStatement (
+ new CCodeAssignment (
+ new CCodeMemberAccess.pointer (
+ new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"),
+ get_symbol_lock_name (m.symbol)),
+ new CCodeFunctionCall (new CCodeIdentifier (((Struct)mutex_type.data_type).default_construction_method.get_cname ())))));
+
+ var fc = new CCodeFunctionCall (new CCodeIdentifier ("VALA_FREE_CHECKED"));
+ fc.add_argument (
+ new CCodeMemberAccess.pointer (
+ new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"),
+ get_symbol_lock_name (m.symbol)));
+ fc.add_argument (new CCodeIdentifier (mutex_type.data_type.get_free_function ()));
+ if (instance_dispose_fragment != null) {
+ instance_dispose_fragment.append (new CCodeExpressionStatement (fc));
+ }
+ }
+ }
+
+ public override void visit_constant (Constant! c) {
+ if (c.symbol.parent_symbol.node is DataType) {
+ var t = (DataType) c.symbol.parent_symbol.node;
+ var cdecl = new CCodeDeclaration (c.type_reference.get_const_cname ());
+ var arr = "";
+ if (c.type_reference.data_type is Array) {
+ arr = "[]";
+ }
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s%s".printf (c.get_cname (), arr), (CCodeExpression) c.initializer.ccodenode));
+ cdecl.modifiers = CCodeModifiers.STATIC;
+
+ if (c.access != MemberAccessibility.PRIVATE) {
+ header_type_member_declaration.append (cdecl);
+ } else {
+ source_type_member_declaration.append (cdecl);
+ }
+ }
+ }
+
+ public override void visit_field (Field! f) {
+ CCodeExpression lhs = null;
+ CCodeStruct st = null;
+
+ if (f.access != MemberAccessibility.PRIVATE) {
+ st = instance_struct;
+ if (f.instance) {
+ lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
+ }
+ } else if (f.access == MemberAccessibility.PRIVATE) {
+ if (f.instance) {
+ st = instance_priv_struct;
+ lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ());
+ } else {
+ if (f.symbol.parent_symbol.node is DataType) {
+ var t = (DataType) f.symbol.parent_symbol.node;
+ var cdecl = new CCodeDeclaration (f.type_reference.get_cname ());
+ var var_decl = new CCodeVariableDeclarator (f.get_cname ());
+ if (f.initializer != null) {
+ var_decl.initializer = (CCodeExpression) f.initializer.ccodenode;
+ }
+ cdecl.add_declarator (var_decl);
+ cdecl.modifiers = CCodeModifiers.STATIC;
+ source_type_member_declaration.append (cdecl);
+ }
+ }
+ }
+
+ if (f.instance) {
+ st.add_field (f.type_reference.get_cname (), f.get_cname ());
+ if (f.type_reference.data_type is Array && !f.no_array_length) {
+ // create fields to store array dimensions
+ var arr = (Array) f.type_reference.data_type;
+
+ for (int dim = 1; dim <= arr.rank; dim++) {
+ var len_type = new TypeReference ();
+ len_type.data_type = int_type.data_type;
+
+ st.add_field (len_type.get_cname (), get_array_length_cname (f.name, dim));
+ }
+ }
+
+ if (f.initializer != null) {
+ instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, (CCodeExpression) f.initializer.ccodenode)));
+
+ if (f.type_reference.data_type is Array && !f.no_array_length &&
+ f.initializer is ArrayCreationExpression) {
+ var ma = new MemberAccess.simple (f.name);
+ ma.symbol_reference = f.symbol;
+
+ var array_len_lhs = get_array_length_cexpression (ma, 1);
+ var sizes = ((ArrayCreationExpression) f.initializer).get_sizes ();
+ var size = (Expression) sizes.data;
+ instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (array_len_lhs, (CCodeExpression) size.ccodenode)));
+ }
+ }
+
+ if (f.type_reference.takes_ownership && instance_dispose_fragment != null) {
+ instance_dispose_fragment.append (new CCodeExpressionStatement (get_unref_expression (lhs, f.type_reference)));
+ }
+ }
+ }
+
+ public override void visit_begin_method (Method! m) {
+ current_symbol = m.symbol;
+ current_return_type = m.return_type;
+ }
+
+ private ref CCodeStatement create_method_type_check_statement (Method! m, DataType! t, bool non_null, string! var_name) {
+ return create_type_check_statement (m, m.return_type.data_type, t, non_null, var_name);
+ }
+
+ private ref CCodeStatement create_property_type_check_statement (Property! prop, bool getter, DataType! t, bool non_null, string! var_name) {
+ if (getter) {
+ return create_type_check_statement (prop, prop.type_reference.data_type, t, non_null, var_name);
+ } else {
+ return create_type_check_statement (prop, null, t, non_null, var_name);
+ }
+ }
+
+ private ref CCodeStatement create_type_check_statement (CodeNode! method_node, DataType ret_type, DataType! t, bool non_null, string! var_name) {
+ var ccheck = new CCodeFunctionCall ();
+
+ if (t is Class || t is Interface) {
+ var ctype_check = new CCodeFunctionCall (new CCodeIdentifier (t.get_upper_case_cname ("IS_")));
+ ctype_check.add_argument (new CCodeIdentifier (var_name));
+
+ ref 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 == null) {
+ /* void function */
+ ccheck.call = new CCodeIdentifier ("g_return_if_fail");
+ } else {
+ ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
+
+ if (ret_type.is_reference_type () || ret_type is Pointer) {
+ ccheck.add_argument (new CCodeConstant ("NULL"));
+ } else if (ret_type.get_default_value () != null) {
+ ccheck.add_argument (new CCodeConstant (ret_type.get_default_value ()));
+ } else {
+ Report.warning (method_node.source_reference, "not supported return type for runtime type checks");
+ return new CCodeExpressionStatement (new CCodeConstant ("0"));
+ }
+ }
+
+ return new CCodeExpressionStatement (ccheck);
+ }
+
+ private DataType find_parent_type (CodeNode node) {
+ var sym = node.symbol;
+ while (sym != null) {
+ if (sym.node is DataType) {
+ return (DataType) sym.node;
+ }
+ sym = sym.parent_symbol;
+ }
+ return null;
+ }
+
+ private ref string! get_array_length_cname (string! array_cname, int dim) {
+ return "%s_length%d".printf (array_cname, dim);
+ }
+
+ public override void visit_end_method (Method! m) {
+ current_symbol = current_symbol.parent_symbol;
+ current_return_type = null;
+
+ if (current_type_symbol != null && current_type_symbol.node is Interface) {
+ var iface = (Interface) current_type_symbol.node;
+ if (iface.is_static) {
+ return;
+ }
+ }
+
+ if (current_symbol.parent_symbol != null &&
+ current_symbol.parent_symbol.node is Method) {
+ /* lambda expressions produce nested methods */
+ var up_method = (Method) current_symbol.parent_symbol.node;
+ current_return_type = up_method.return_type;
+ }
+
+ function = new CCodeFunction (m.get_real_cname (), m.return_type.get_cname ());
+ CCodeFunctionDeclarator vdeclarator = null;
+
+ CCodeFormalParameter instance_param = null;
+
+ if (m.instance) {
+ var this_type = new TypeReference ();
+ this_type.data_type = find_parent_type (m);
+ if (m.base_interface_method != null) {
+ var base_type = new TypeReference ();
+ base_type.data_type = (DataType) m.base_interface_method.symbol.parent_symbol.node;
+ instance_param = new CCodeFormalParameter ("base", base_type.get_cname ());
+ } else if (m.overrides) {
+ var base_type = new TypeReference ();
+ base_type.data_type = (DataType) m.base_method.symbol.parent_symbol.node;
+ instance_param = new CCodeFormalParameter ("base", base_type.get_cname ());
+ } else {
+ if (m.instance_by_reference) {
+ instance_param = new CCodeFormalParameter ("*self", this_type.get_cname ());
+ } else {
+ instance_param = new CCodeFormalParameter ("self", this_type.get_cname ());
+ }
+ }
+ if (!m.instance_last) {
+ function.add_parameter (instance_param);
+ }
+
+ if (m.is_abstract || m.is_virtual) {
+ var vdecl = new CCodeDeclaration (m.return_type.get_cname ());
+ vdeclarator = new CCodeFunctionDeclarator (m.name);
+ vdecl.add_declarator (vdeclarator);
+ type_struct.add_declaration (vdecl);
+
+ vdeclarator.add_parameter (instance_param);
+ }
+ }
+
+ if (m is CreationMethod && current_class != null) {
+ // memory management for generic types
+ foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
+ var cparam = new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify");
+ function.add_parameter (cparam);
+ }
+ }
+
+ var params = m.get_parameters ();
+ foreach (FormalParameter param in params) {
+ if (!param.no_array_length && param.type_reference.data_type is Array) {
+ var arr = (Array) param.type_reference.data_type;
+
+ var length_ctype = "int";
+ if (param.type_reference.is_out) {
+ length_ctype = "int*";
+ }
+
+ for (int dim = 1; dim <= arr.rank; dim++) {
+ var cparam = new CCodeFormalParameter (get_array_length_cname (param.name, dim), length_ctype);
+ function.add_parameter (cparam);
+ if (vdeclarator != null) {
+ vdeclarator.add_parameter (cparam);
+ }
+ }
+ }
+
+ function.add_parameter ((CCodeFormalParameter) param.ccodenode);
+ if (vdeclarator != null) {
+ vdeclarator.add_parameter ((CCodeFormalParameter) param.ccodenode);
+ }
+ }
+
+ if (m.instance && m.instance_last) {
+ function.add_parameter (instance_param);
+ }
+
+ /* real function declaration and definition not needed
+ * for abstract methods */
+ if (!m.is_abstract) {
+ if (m.access != MemberAccessibility.PRIVATE && 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;
+
+ var cinit = new CCodeFragment ();
+ function.block.prepend_statement (cinit);
+
+ if (m.symbol.parent_symbol.node is Class) {
+ var cl = (Class) m.symbol.parent_symbol.node;
+ if (m.overrides || m.base_interface_method != null) {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccall.add_argument (new CCodeIdentifier ("base"));
+
+ var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+
+ cinit.append (cdecl);
+ } else if (m.instance) {
+ cinit.append (create_method_type_check_statement (m, cl, true, "self"));
+ }
+ }
+ foreach (FormalParameter param in m.get_parameters ()) {
+ var t = param.type_reference.data_type;
+ if (t != null && t.is_reference_type () && !param.type_reference.is_out) {
+ var type_check = create_method_type_check_statement (m, t, param.type_reference.non_null, param.name);
+ if (type_check != null) {
+ cinit.append (type_check);
+ }
+ }
+ }
+
+ 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 (current_class != null) {
+ int n_params = ((CreationMethod) m).n_construction_params;
+ n_params += (int) current_class.get_type_parameters ().length ();
+
+ // 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);
+
+ /* destroy func properties for generic types */
+ foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
+ string func_name = "%s_destroy_func".printf (type_param.name.down ());
+ var func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
+
+ // this property is used as a construction parameter
+ var cpointer = new CCodeIdentifier ("__params_it");
+
+ var ccomma = new CCodeCommaExpression ();
+ // set name in array for current parameter
+ var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name");
+ ccomma.append_expression (new CCodeAssignment (cnamemember, func_name_constant));
+ var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value"));
+
+ // initialize GValue in array for current parameter
+ var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
+ cvalueinit.add_argument (gvaluearg);
+ cvalueinit.add_argument (new CCodeIdentifier ("G_TYPE_POINTER"));
+ ccomma.append_expression (cvalueinit);
+
+ // set GValue for current parameter
+ var cvalueset = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
+ cvalueset.add_argument (gvaluearg);
+ cvalueset.add_argument (new CCodeIdentifier (func_name));
+ ccomma.append_expression (cvalueset);
+
+ // move pointer to next parameter in array
+ ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer));
+
+ cinit.append (new CCodeExpressionStatement (ccomma));
+ }
+ } else {
+ var st = (Struct) m.symbol.parent_symbol.node;
+ var cdecl = new CCodeDeclaration (st.get_cname () + "*");
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+ ccall.add_argument (new CCodeConstant (st.get_cname ()));
+ ccall.add_argument (new CCodeConstant ("1"));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+ cinit.append (cdecl);
+ }
+ }
+
+ if (context.module_init_method == m && in_plugin) {
+ // GTypeModule-based plug-in, register types
+ cinit.append (module_init_fragment);
+ }
+ }
+ }
+
+ if (m.is_abstract || m.is_virtual) {
+ var vfunc = new CCodeFunction (m.get_cname (), m.return_type.get_cname ());
+
+ var this_type = new TypeReference ();
+ this_type.data_type = (DataType) m.symbol.parent_symbol.node;
+
+ var cparam = new CCodeFormalParameter ("self", this_type.get_cname ());
+ vfunc.add_parameter (cparam);
+
+ var vblock = new CCodeBlock ();
+
+ CCodeFunctionCall vcast = null;
+ if (m.symbol.parent_symbol.node is Interface) {
+ var iface = (Interface) m.symbol.parent_symbol.node;
+
+ vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
+ } else {
+ var cl = (Class) m.symbol.parent_symbol.node;
+
+ 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.name));
+ vcall.add_argument (new CCodeIdentifier ("self"));
+
+ var params = m.get_parameters ();
+ foreach (FormalParameter param in params) {
+ vfunc.add_parameter ((CCodeFormalParameter) param.ccodenode);
+ vcall.add_argument (new CCodeIdentifier (param.name));
+ }
+
+ if (m.return_type.data_type == null) {
+ vblock.add_statement (new CCodeExpressionStatement (vcall));
+ } else {
+ /* pass method return value */
+ vblock.add_statement (new CCodeReturnStatement (vcall));
+ }
+
+ header_type_member_declaration.append (vfunc.copy ());
+
+ vfunc.block = vblock;
+
+ source_type_member_definition.append (vfunc);
+ }
+
+ if (m is CreationMethod) {
+ 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.add_parameter (new CCodeFormalParameter ("argc", "int"));
+ cmain.add_parameter (new CCodeFormalParameter ("argv", "char **"));
+ var main_block = new CCodeBlock ();
+ main_block.add_statement (new CCodeExpressionStatement (new CCodeFunctionCall (new CCodeIdentifier ("g_type_init"))));
+ var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
+ if (args_parameter) {
+ main_call.add_argument (new CCodeIdentifier ("argc"));
+ main_call.add_argument (new CCodeIdentifier ("argv"));
+ }
+ if (return_value) {
+ main_block.add_statement (new CCodeReturnStatement (main_call));
+ } else {
+ // method returns void, always use 0 as exit code
+ main_block.add_statement (new CCodeExpressionStatement (main_call));
+ main_block.add_statement (new CCodeReturnStatement (new CCodeConstant ("0")));
+ }
+ cmain.block = main_block;
+ source_type_member_definition.append (cmain);
+ }
+ }
+
+ public override void visit_begin_creation_method (CreationMethod! m) {
+ current_symbol = m.symbol;
+ current_return_type = m.return_type;
+ in_creation_method = true;
+ }
+
+ public override void visit_end_creation_method (CreationMethod! m) {
+ if (current_class != null && m.body != null) {
+ add_object_creation ((CCodeBlock) m.body.ccodenode);
+ }
+
+ in_creation_method = false;
+
+ visit_end_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.length () == 0) {
+ // method may have no parameters
+ args_parameter = false;
+ return true;
+ }
+
+ if (params.length () > 1) {
+ // method must not have more than one parameter
+ return false;
+ }
+
+ var param = (FormalParameter) params.data;
+
+ if (param.type_reference.is_out) {
+ // parameter must not be an out parameter
+ return false;
+ }
+
+ if (!(param.type_reference.data_type is Array)) {
+ // parameter must be an array
+ return false;
+ }
+
+ var array_type = (Array) param.type_reference.data_type;
+ if (array_type.element_type != string_type.data_type) {
+ // parameter must be an array of strings
+ return false;
+ }
+
+ args_parameter = true;
+ return true;
+ }
+
+ public override void visit_formal_parameter (FormalParameter! p) {
+ if (!p.ellipsis) {
+ p.ccodenode = new CCodeFormalParameter (p.name, p.type_reference.get_cname (false, !p.type_reference.takes_ownership));
+ }
+ }
+
+ public override void visit_end_property (Property! prop) {
+ prop_enum.add_value (prop.get_upper_case_cname (), null);
+ }
+
+ public override void visit_begin_property_accessor (PropertyAccessor! acc) {
+ var prop = (Property) acc.symbol.parent_symbol.node;
+
+ if (acc.readable) {
+ current_return_type = prop.type_reference;
+ } else {
+ // void
+ current_return_type = new TypeReference ();
+ }
+ }
+
+ public override void visit_end_property_accessor (PropertyAccessor! acc) {
+ var prop = (Property) acc.symbol.parent_symbol.node;
+
+ current_return_type = null;
+
+ var t = (DataType) prop.symbol.parent_symbol.node;
+
+ var this_type = new TypeReference ();
+ this_type.data_type = t;
+ var cselfparam = new CCodeFormalParameter ("self", this_type.get_cname ());
+ var cvalueparam = new CCodeFormalParameter ("value", prop.type_reference.get_cname (false, true));
+
+ if (prop.is_abstract || prop.is_virtual) {
+ if (acc.readable) {
+ function = new CCodeFunction ("%s_get_%s".printf (t.get_lower_case_cname (null), prop.name), prop.type_reference.get_cname ());
+ } else {
+ function = new CCodeFunction ("%s_set_%s".printf (t.get_lower_case_cname (null), prop.name), "void");
+ }
+ function.add_parameter (cselfparam);
+ if (acc.writable || acc.construction) {
+ function.add_parameter (cvalueparam);
+ }
+
+ header_type_member_declaration.append (function.copy ());
+
+ var block = new CCodeBlock ();
+ function.block = block;
+
+ if (acc.readable) {
+ // declare temporary variable to save the property value
+ var decl = new CCodeDeclaration (prop.type_reference.get_cname ());
+ decl.add_declarator (new CCodeVariableDeclarator ("value"));
+ block.add_statement (decl);
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
+
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+ ccast.add_argument (new CCodeIdentifier ("self"));
+ ccall.add_argument (ccast);
+
+ // property name is second argument of g_object_get
+ ccall.add_argument (prop.get_canonical_cconstant ());
+
+ ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
+
+ ccall.add_argument (new CCodeConstant ("NULL"));
+
+ block.add_statement (new CCodeExpressionStatement (ccall));
+ block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value")));
+ } else {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
+
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+ ccast.add_argument (new CCodeIdentifier ("self"));
+ ccall.add_argument (ccast);
+
+ // property name is second argument of g_object_set
+ ccall.add_argument (prop.get_canonical_cconstant ());
+
+ ccall.add_argument (new CCodeIdentifier ("value"));
+
+ ccall.add_argument (new CCodeConstant ("NULL"));
+
+ block.add_statement (new CCodeExpressionStatement (ccall));
+ }
+
+ source_type_member_definition.append (function);
+ }
+
+ if (!prop.is_abstract) {
+ bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
+
+ string prefix = t.get_lower_case_cname (null);
+ if (is_virtual) {
+ prefix += "_real";
+ }
+ if (acc.readable) {
+ function = new CCodeFunction ("%s_get_%s".printf (prefix, prop.name), prop.type_reference.get_cname ());
+ } else {
+ function = new CCodeFunction ("%s_set_%s".printf (prefix, prop.name), "void");
+ }
+ if (is_virtual) {
+ function.modifiers |= CCodeModifiers.STATIC;
+ }
+ function.add_parameter (cselfparam);
+ if (acc.writable || acc.construction) {
+ function.add_parameter (cvalueparam);
+ }
+
+ if (!is_virtual) {
+ header_type_member_declaration.append (function.copy ());
+ }
+
+ if (acc.body != null) {
+ function.block = (CCodeBlock) acc.body.ccodenode;
+
+ function.block.prepend_statement (create_property_type_check_statement (prop, acc.readable, t, true, "self"));
+ }
+
+ source_type_member_definition.append (function);
+ }
+ }
+
+ private string get_marshaller_type_name (TypeReference t) {
+ if (t.type_parameter != null) {
+ return ("POINTER");
+ } else if (t.data_type == null) {
+ return ("VOID");
+ } else {
+ return t.data_type.get_marshaller_type_name ();
+ }
+ }
+
+ private ref string get_signal_marshaller_function (Signal! sig, string prefix = null) {
+ var signature = get_signal_signature (sig);
+ string ret;
+ var params = sig.get_parameters ();
+
+ if (prefix == null) {
+ // FIXME remove equality check with cast in next revision
+ if (predefined_marshal_list.lookup (signature) != (bool) null) {
+ prefix = "g_cclosure_marshal";
+ } else {
+ prefix = "g_cclosure_user_marshal";
+ }
+ }
+
+ ret = "%s_%s_".printf (prefix, get_marshaller_type_name (sig.return_type));
+
+ if (params == null) {
+ ret = ret + "_VOID";
+ } else {
+ foreach (FormalParameter p in params) {
+ ret = "%s_%s".printf (ret, get_marshaller_type_name (p.type_reference));
+ }
+ }
+
+ return ret;
+ }
+
+ private string get_value_type_name_from_type_reference (TypeReference! t) {
+ if (t.type_parameter != null) {
+ return "gpointer";
+ } else if (t.data_type == null) {
+ return "void";
+ } else if (t.data_type is Class || t.data_type is Interface) {
+ return "GObject *";
+ } else if (t.data_type is Struct) {
+ if (((Struct) t.data_type).is_reference_type ()) {
+ return "gpointer";
+ } else {
+ return t.data_type.get_cname ();
+ }
+ } else if (t.data_type is Enum) {
+ return "gint";
+ } else if (t.data_type is Flags) {
+ return "guint";
+ } else if (t.data_type is Array) {
+ return "gpointer";
+ }
+
+ return null;
+ }
+
+ private ref string get_signal_signature (Signal! sig) {
+ string signature;
+ var params = sig.get_parameters ();
+
+ signature = "%s:".printf (get_marshaller_type_name (sig.return_type));
+ if (params == null) {
+ signature = signature + "VOID";
+ } else {
+ bool first = true;
+ foreach (FormalParameter p in params) {
+ if (first) {
+ signature = signature + get_marshaller_type_name (p.type_reference);
+ first = false;
+ } else {
+ signature = "%s,%s".printf (signature, get_marshaller_type_name (p.type_reference));
+ }
+ }
+ }
+
+ return signature;
+ }
+
+ public override void visit_end_signal (Signal! sig) {
+ string signature;
+ var params = sig.get_parameters ();
+ int n_params, i;
+
+ /* check whether a signal with the same signature already exists for this source file (or predefined) */
+ signature = get_signal_signature (sig);
+ // FIXME remove equality checks with cast in next revision
+ if (predefined_marshal_list.lookup (signature) != (bool) null || user_marshal_list.lookup (signature) != (bool) null) {
+ return;
+ }
+
+ var signal_marshaller = new CCodeFunction (get_signal_marshaller_function (sig), "void");
+ signal_marshaller.modifiers = CCodeModifiers.STATIC;
+
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("closure", "GClosure *"));
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("return_value", "GValue *"));
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("n_param_values", "guint"));
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("param_values", "const GValue *"));
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("invocation_hint", "gpointer"));
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("marshal_data", "gpointer"));
+
+ source_signal_marshaller_declaration.append (signal_marshaller.copy ());
+
+ var marshaller_body = new CCodeBlock ();
+
+ var callback_decl = new CCodeFunctionDeclarator (get_signal_marshaller_function (sig, "GMarshalFunc"));
+ callback_decl.add_parameter (new CCodeFormalParameter ("data1", "gpointer"));
+ n_params = 1;
+ foreach (FormalParameter p in params) {
+ callback_decl.add_parameter (new CCodeFormalParameter ("arg_%d".printf (n_params), get_value_type_name_from_type_reference (p.type_reference)));
+ n_params++;
+ }
+ callback_decl.add_parameter (new CCodeFormalParameter ("data2", "gpointer"));
+ marshaller_body.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (sig.return_type), callback_decl));
+
+ var var_decl = new CCodeDeclaration (get_signal_marshaller_function (sig, "GMarshalFunc"));
+ var_decl.modifiers = CCodeModifiers.REGISTER;
+ var_decl.add_declarator (new CCodeVariableDeclarator ("callback"));
+ marshaller_body.add_statement (var_decl);
+
+ var_decl = new CCodeDeclaration ("GCClosure *");
+ var_decl.modifiers = CCodeModifiers.REGISTER;
+ var_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")));
+ marshaller_body.add_statement (var_decl);
+
+ var_decl = new CCodeDeclaration ("gpointer");
+ var_decl.modifiers = CCodeModifiers.REGISTER;
+ var_decl.add_declarator (new CCodeVariableDeclarator ("data1"));
+ var_decl.add_declarator (new CCodeVariableDeclarator ("data2"));
+ marshaller_body.add_statement (var_decl);
+
+ CCodeFunctionCall fc;
+
+ if (sig.return_type.data_type != null) {
+ var_decl = new CCodeDeclaration (get_value_type_name_from_type_reference (sig.return_type));
+ var_decl.add_declarator (new CCodeVariableDeclarator ("v_return"));
+ marshaller_body.add_statement (var_decl);
+
+ fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
+ fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("return_value"), new CCodeConstant ("NULL")));
+ marshaller_body.add_statement (new CCodeExpressionStatement (fc));
+ }
+
+ fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
+ fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("n_param_values"), new CCodeConstant (n_params.to_string())));
+ marshaller_body.add_statement (new CCodeExpressionStatement (fc));
+
+ var data = new CCodeMemberAccess (new CCodeIdentifier ("closure"), "data", true);
+ var param = new CCodeMemberAccess (new CCodeMemberAccess (new CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
+ var cond = new CCodeFunctionCall (new CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
+ cond.add_argument (new CCodeIdentifier ("closure"));
+ var true_block = new CCodeBlock ();
+ true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), data)));
+ true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), param)));
+ var false_block = new CCodeBlock ();
+ false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), param)));
+ false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), data)));
+ marshaller_body.add_statement (new CCodeIfStatement (cond, true_block, false_block));
+
+ var c_assign = new CCodeAssignment (new CCodeIdentifier ("callback"), new CCodeCastExpression (new CCodeConditionalExpression (new CCodeIdentifier ("marshal_data"), new CCodeIdentifier ("marshal_data"), new CCodeMemberAccess (new CCodeIdentifier ("cc"), "callback", true)), get_signal_marshaller_function (sig, "GMarshalFunc")));
+ marshaller_body.add_statement (new CCodeExpressionStatement (c_assign));
+
+ fc = new CCodeFunctionCall (new CCodeIdentifier ("callback"));
+ fc.add_argument (new CCodeIdentifier ("data1"));
+ i = 1;
+ foreach (FormalParameter p in params) {
+ string get_value_function;
+ if (p.type_reference.type_parameter != null) {
+ get_value_function = "g_value_get_pointer";
+ } else {
+ get_value_function = p.type_reference.data_type.get_get_value_function ();
+ }
+ var inner_fc = new CCodeFunctionCall (new CCodeIdentifier (get_value_function));
+ inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
+ fc.add_argument (inner_fc);
+ i++;
+ }
+ fc.add_argument (new CCodeIdentifier ("data2"));
+
+ if (sig.return_type.data_type != null) {
+ marshaller_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("v_return"), fc)));
+
+ CCodeFunctionCall set_fc;
+ if (sig.return_type.type_parameter != null) {
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
+ } else if (sig.return_type.data_type is Class || sig.return_type.data_type is Interface) {
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_object"));
+ } else if (sig.return_type.data_type == string_type.data_type) {
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_string"));
+ } else {
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier (sig.return_type.data_type.get_set_value_function ()));
+ }
+ set_fc.add_argument (new CCodeIdentifier ("return_value"));
+ set_fc.add_argument (new CCodeIdentifier ("v_return"));
+
+ marshaller_body.add_statement (new CCodeExpressionStatement (set_fc));
+ } else {
+ marshaller_body.add_statement (new CCodeExpressionStatement (fc));
+ }
+
+ signal_marshaller.block = marshaller_body;
+
+ source_signal_marshaller_definition.append (signal_marshaller);
+ user_marshal_list.insert (signature, true);
+ }
+
+ public override void visit_end_constructor (Constructor! c) {
+ var cl = (Class) c.symbol.parent_symbol.node;
+
+ function = new CCodeFunction ("%s_constructor".printf (cl.get_lower_case_cname (null)), "GObject *");
+ function.modifiers = CCodeModifiers.STATIC;
+
+ function.add_parameter (new CCodeFormalParameter ("type", "GType"));
+ function.add_parameter (new CCodeFormalParameter ("n_construct_properties", "guint"));
+ function.add_parameter (new CCodeFormalParameter ("construct_properties", "GObjectConstructParam *"));
+
+ source_type_member_declaration.append (function.copy ());
+
+
+ var cblock = new CCodeBlock ();
+ var cdecl = new CCodeDeclaration ("GObject *");
+ cdecl.add_declarator (new CCodeVariableDeclarator ("obj"));
+ cblock.add_statement (cdecl);
+
+ cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator ("klass"));
+ cblock.add_statement (cdecl);
+
+ cdecl = new CCodeDeclaration ("GObjectClass *");
+ cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class"));
+ cblock.add_statement (cdecl);
+
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek"));
+ ccall.add_argument (new CCodeIdentifier (cl.get_upper_case_cname ("TYPE_")));
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null))));
+ ccast.add_argument (ccall);
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("klass"), ccast)));
+
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
+ ccall.add_argument (new CCodeIdentifier ("klass"));
+ ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+ ccast.add_argument (ccall);
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast)));
+
+
+ ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
+ ccall.add_argument (new CCodeIdentifier ("type"));
+ ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
+ ccall.add_argument (new CCodeIdentifier ("construct_properties"));
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("obj"), ccall)));
+
+
+ ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccall.add_argument (new CCodeIdentifier ("obj"));
+
+ cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+
+ cblock.add_statement (cdecl);
+
+
+ cblock.add_statement (c.body.ccodenode);
+
+ cblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("obj")));
+
+ function.block = cblock;
+
+ if (c.source_reference.comment != null) {
+ source_type_member_definition.append (new CCodeComment (c.source_reference.comment));
+ }
+ source_type_member_definition.append (function);
+ }
+
+ public override void visit_begin_block (Block! b) {
+ current_symbol = b.symbol;
+ }
+
+ private void add_object_creation (CCodeBlock! b) {
+ var cl = (Class) current_type_symbol.node;
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
+ ccall.add_argument (new CCodeConstant (cl.get_type_id ()));
+ ccall.add_argument (new CCodeConstant ("__params_it - __params"));
+ ccall.add_argument (new CCodeConstant ("__params"));
+
+ 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);
+ }
+
+ public override void visit_end_block (Block! b) {
+ var local_vars = b.get_local_variables ();
+ foreach (VariableDeclarator decl in local_vars) {
+ decl.symbol.active = false;
+ }
+
+ var cblock = new CCodeBlock ();
+
+ foreach (Statement stmt in b.get_statements ()) {
+ var src = stmt.source_reference;
+ if (src != null && src.comment != null) {
+ cblock.add_statement (new CCodeComment (src.comment));
+ }
+
+ if (stmt.ccodenode is CCodeFragment) {
+ foreach (CCodeStatement cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
+ cblock.add_statement (cstmt);
+ }
+ } else {
+ cblock.add_statement ((CCodeStatement) stmt.ccodenode);
+ }
+ }
+
+ if (memory_management) {
+ foreach (VariableDeclarator decl in local_vars) {
+ if (decl.type_reference.takes_ownership) {
+ cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference)));
+ }
+ }
+ }
+
+ b.ccodenode = cblock;
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_empty_statement (EmptyStatement! stmt) {
+ stmt.ccodenode = new CCodeEmptyStatement ();
+ }
+
+ private bool struct_has_instance_fields (Struct! st) {
+ foreach (Field f in st.get_fields ()) {
+ if (f.instance) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public override void visit_declaration_statement (DeclarationStatement! stmt) {
+ /* split declaration statement as var declarators
+ * might have different types */
+
+ var cfrag = new CCodeFragment ();
+
+ foreach (VariableDeclarator decl in stmt.declaration.get_variable_declarators ()) {
+ var cdecl = new CCodeDeclaration (decl.type_reference.get_cname (false, !decl.type_reference.takes_ownership));
+
+ cdecl.add_declarator ((CCodeVariableDeclarator) decl.ccodenode);
+
+ cfrag.append (cdecl);
+
+ /* try to initialize uninitialized variables */
+ if (decl.initializer == null && decl.type_reference.data_type is Struct) {
+ if (decl.type_reference.data_type.is_reference_type ()) {
+ ((CCodeVariableDeclarator) decl.ccodenode).initializer = new CCodeConstant ("NULL");
+ } else if (decl.type_reference.data_type.get_default_value () != null) {
+ ((CCodeVariableDeclarator) decl.ccodenode).initializer = new CCodeConstant (decl.type_reference.data_type.get_default_value ());
+ } else if (decl.type_reference.data_type is Struct &&
+ struct_has_instance_fields ((Struct) decl.type_reference.data_type)) {
+ var st = (Struct) decl.type_reference.data_type;
+
+ /* memset needs string.h */
+ string_h_needed = true;
+
+ var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+ czero.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (decl.name)));
+ czero.add_argument (new CCodeConstant ("0"));
+ czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (decl.type_reference.get_cname ())));
+
+ cfrag.append (new CCodeExpressionStatement (czero));
+ } else {
+ Report.warning (decl.source_reference, "unable to initialize a variable of type `%s'".printf (decl.type_reference.data_type.symbol.get_full_name ()));
+ }
+ }
+ }
+
+ stmt.ccodenode = cfrag;
+
+ foreach (VariableDeclarator decl in stmt.declaration.get_variable_declarators ()) {
+ if (decl.initializer != null) {
+ create_temp_decl (stmt, decl.initializer.temp_vars);
+ }
+ }
+
+ create_temp_decl (stmt, temp_vars);
+ temp_vars = null;
+ }
+
+ public override void visit_variable_declarator (VariableDeclarator! decl) {
+ if (decl.type_reference.data_type is Array) {
+ // create variables to store array dimensions
+ var arr = (Array) decl.type_reference.data_type;
+
+ for (int dim = 1; dim <= arr.rank; dim++) {
+ var len_decl = new VariableDeclarator (get_array_length_cname (decl.name, dim));
+ len_decl.type_reference = new TypeReference ();
+ len_decl.type_reference.data_type = int_type.data_type;
+
+ temp_vars.prepend (len_decl);
+ }
+ }
+
+ CCodeExpression rhs = null;
+ if (decl.initializer != null) {
+ rhs = (CCodeExpression) decl.initializer.ccodenode;
+
+ if (decl.type_reference.data_type != null
+ && decl.initializer.static_type.data_type != null
+ && decl.type_reference.data_type.is_reference_type ()
+ && decl.initializer.static_type.data_type != decl.type_reference.data_type) {
+ // FIXME: use C cast if debugging disabled
+ rhs = new InstanceCast (rhs, decl.type_reference.data_type);
+ }
+
+ if (decl.type_reference.data_type is Array) {
+ var ccomma = new CCodeCommaExpression ();
+
+ var temp_decl = get_temp_variable_declarator (decl.type_reference);
+ temp_vars.prepend (temp_decl);
+ ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), rhs));
+
+ var lhs_array_len = new CCodeIdentifier (get_array_length_cname (decl.name, 1));
+ var rhs_array_len = get_array_length_cexpression (decl.initializer, 1);
+ ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
+
+ ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
+
+ rhs = ccomma;
+ }
+ } else if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) {
+ rhs = new CCodeConstant ("NULL");
+ }
+
+ decl.ccodenode = new CCodeVariableDeclarator.with_initializer (decl.name, rhs);
+
+ decl.symbol.active = true;
+ }
+
+ public override void visit_end_initializer_list (InitializerList! list) {
+ if (list.expected_type != null && list.expected_type.data_type is Array) {
+ /* TODO */
+ } else {
+ var clist = new CCodeInitializerList ();
+ foreach (Expression expr in list.get_initializers ()) {
+ clist.append ((CCodeExpression) expr.ccodenode);
+ }
+ list.ccodenode = clist;
+ }
+ }
+
+ private ref VariableDeclarator get_temp_variable_declarator (TypeReference! type, bool takes_ownership = true) {
+ var decl = new VariableDeclarator ("__temp%d".printf (next_temp_var_id));
+ decl.type_reference = type.copy ();
+ decl.type_reference.reference_to_value_type = false;
+ decl.type_reference.is_out = false;
+ decl.type_reference.takes_ownership = takes_ownership;
+
+ next_temp_var_id++;
+
+ return decl;
+ }
+
+ private CCodeExpression get_destroy_func_expression (TypeReference! type) {
+ if (type.data_type != null) {
+ string unref_function;
+ if (type.data_type.is_reference_counting ()) {
+ unref_function = type.data_type.get_unref_function ();
+ } else {
+ unref_function = type.data_type.get_free_function ();
+ }
+ return new CCodeIdentifier (unref_function);
+ } else if (type.type_parameter != null && current_class != null) {
+ string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ());
+ return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+ } else {
+ return new CCodeConstant ("NULL");
+ }
+ }
+
+ private ref CCodeExpression get_unref_expression (CCodeExpression! cvar, TypeReference! type) {
+ /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
+
+ /* can be simplified to
+ * foo = (unref (foo), NULL)
+ * if foo is of static type non-null
+ */
+
+ if (type.is_null) {
+ return new CCodeConstant ("NULL");
+ }
+
+ var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
+ if (type.data_type == null) {
+ if (current_class == null) {
+ return new CCodeConstant ("NULL");
+ }
+
+ // unref functions are optional for type parameters
+ var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
+ cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
+ }
+
+ var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
+ ccall.add_argument (cvar);
+
+ /* set freed references to NULL to prevent further use */
+ var ccomma = new CCodeCommaExpression ();
+
+ // TODO cleanup
+ if (type.data_type != null && !type.data_type.is_reference_counting ()) {
+ string unref_function = type.data_type.get_free_function ();
+ if (unref_function == "g_list_free") {
+ bool is_ref = false;
+ bool is_class = false;
+ bool is_interface = false;
+
+ foreach (TypeReference type_arg in type.get_type_arguments ()) {
+ is_ref |= type_arg.takes_ownership;
+ is_class |= type_arg.data_type is Class;
+ is_interface |= type_arg.data_type is Interface;
+ }
+
+ if (is_ref) {
+ var cunrefcall = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
+ cunrefcall.add_argument (cvar);
+ if (is_class || is_interface) {
+ cunrefcall.add_argument (new CCodeIdentifier ("(GFunc) g_object_unref"));
+ } else {
+ cunrefcall.add_argument (new CCodeIdentifier ("(GFunc) g_free"));
+ }
+ cunrefcall.add_argument (new CCodeConstant ("NULL"));
+ ccomma.append_expression (cunrefcall);
+ }
+ } else if (unref_function == "g_string_free") {
+ ccall.add_argument (new CCodeConstant ("TRUE"));
+ }
+ }
+
+ ccomma.append_expression (ccall);
+ ccomma.append_expression (new CCodeConstant ("NULL"));
+
+ var cassign = new CCodeAssignment (cvar, ccomma);
+
+ // g_free (NULL) is allowed
+ if (type.non_null || (type.data_type != null && !type.data_type.is_reference_counting () && type.data_type.get_free_function () == "g_free")) {
+ return new CCodeParenthesizedExpression (cassign);
+ }
+
+ return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), new CCodeParenthesizedExpression (cassign));
+ }
+
+ public override void visit_end_full_expression (Expression! expr) {
+ if (!memory_management) {
+ temp_vars = null;
+ temp_ref_vars = null;
+ return;
+ }
+
+ /* expr is a full expression, i.e. an initializer, the
+ * expression in an expression statement, the controlling
+ * expression in if, while, for, or foreach statements
+ *
+ * we unref temporary variables at the end of a full
+ * expression
+ */
+
+ /* can't automatically deep copy lists yet, so do it
+ * manually for now
+ * replace with
+ * expr.temp_vars = temp_vars;
+ * when deep list copying works
+ */
+ expr.temp_vars = null;
+ foreach (VariableDeclarator decl1 in temp_vars) {
+ expr.temp_vars.append (decl1);
+ }
+ temp_vars = null;
+
+ if (temp_ref_vars == null) {
+ /* nothing to do without temporary variables */
+ return;
+ }
+
+ var full_expr_decl = get_temp_variable_declarator (expr.static_type);
+ expr.temp_vars.append (full_expr_decl);
+
+ var expr_list = new CCodeCommaExpression ();
+ expr_list.append_expression (new CCodeAssignment (new CCodeIdentifier (full_expr_decl.name), (CCodeExpression) expr.ccodenode));
+
+ foreach (VariableDeclarator decl in temp_ref_vars) {
+ expr_list.append_expression (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference));
+ }
+
+ expr_list.append_expression (new CCodeIdentifier (full_expr_decl.name));
+
+ expr.ccodenode = expr_list;
+
+ temp_ref_vars = null;
+ }
+
+ private void append_temp_decl (CCodeFragment! cfrag, List<VariableDeclarator> temp_vars) {
+ foreach (VariableDeclarator decl in temp_vars) {
+ var cdecl = new CCodeDeclaration (decl.type_reference.get_cname (true, !decl.type_reference.takes_ownership));
+
+ var vardecl = new CCodeVariableDeclarator (decl.name);
+ cdecl.add_declarator (vardecl);
+
+ if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) {
+ vardecl.initializer = new CCodeConstant ("NULL");
+ }
+
+ cfrag.append (cdecl);
+ }
+ }
+
+ public override void visit_expression_statement (ExpressionStatement! stmt) {
+ stmt.ccodenode = new CCodeExpressionStatement ((CCodeExpression) stmt.expression.ccodenode);
+
+ /* free temporary objects */
+ if (!memory_management) {
+ temp_vars = null;
+ temp_ref_vars = null;
+ return;
+ }
+
+ if (temp_vars == null) {
+ /* nothing to do without temporary variables */
+ return;
+ }
+
+ var cfrag = new CCodeFragment ();
+ append_temp_decl (cfrag, temp_vars);
+
+ cfrag.append (stmt.ccodenode);
+
+ foreach (VariableDeclarator decl in temp_ref_vars) {
+ cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference)));
+ }
+
+ stmt.ccodenode = cfrag;
+
+ temp_vars = null;
+ temp_ref_vars = null;
+ }
+
+ private void create_temp_decl (Statement! stmt, List<VariableDeclarator> temp_vars) {
+ /* declare temporary variables */
+
+ if (temp_vars == null) {
+ /* nothing to do without temporary variables */
+ return;
+ }
+
+ var cfrag = new CCodeFragment ();
+ append_temp_decl (cfrag, temp_vars);
+
+ cfrag.append (stmt.ccodenode);
+
+ stmt.ccodenode = cfrag;
+ }
+
+ public override void visit_if_statement (IfStatement! stmt) {
+ if (stmt.false_statement != null) {
+ stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode);
+ } else {
+ stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode);
+ }
+
+ create_temp_decl (stmt, stmt.condition.temp_vars);
+ }
+
+ public override void visit_switch_statement (SwitchStatement! stmt) {
+ // we need a temporary variable to save the property value
+ var temp_decl = get_temp_variable_declarator (stmt.expression.static_type);
+ stmt.expression.temp_vars.prepend (temp_decl);
+
+ var ctemp = new CCodeIdentifier (temp_decl.name);
+
+ var cinit = new CCodeAssignment (ctemp, (CCodeExpression) stmt.expression.ccodenode);
+
+ var cswitchblock = new CCodeFragment ();
+ cswitchblock.append (new CCodeExpressionStatement (cinit));
+ stmt.ccodenode = cswitchblock;
+
+ create_temp_decl (stmt, stmt.expression.temp_vars);
+
+ List<weak Statement> default_statements = null;
+
+ // generate nested if statements
+ ref CCodeStatement ctopstmt = null;
+ CCodeIfStatement coldif = null;
+ foreach (SwitchSection section in stmt.get_sections ()) {
+ if (section.has_default_label ()) {
+ default_statements = section.get_statements ();
+ } else {
+ CCodeBinaryExpression cor = null;
+ foreach (SwitchLabel label in section.get_labels ()) {
+ var ccmp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, (CCodeExpression) label.expression.ccodenode);
+ if (cor == null) {
+ cor = ccmp;
+ } else {
+ cor = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cor, ccmp);
+ }
+ }
+
+ var cblock = new CCodeBlock ();
+ foreach (Statement body_stmt in section.get_statements ()) {
+ if (body_stmt.ccodenode is CCodeFragment) {
+ foreach (CCodeStatement cstmt in ((CCodeFragment) body_stmt.ccodenode).get_children ()) {
+ cblock.add_statement (cstmt);
+ }
+ } else {
+ cblock.add_statement ((CCodeStatement) body_stmt.ccodenode);
+ }
+ }
+
+ var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
+
+ var cif = new CCodeIfStatement (cor, cdo);
+ if (coldif != null) {
+ coldif.false_statement = cif;
+ } else {
+ ctopstmt = cif;
+ }
+ coldif = cif;
+ }
+ }
+
+ if (default_statements != null) {
+ var cblock = new CCodeBlock ();
+ foreach (Statement body_stmt in default_statements) {
+ cblock.add_statement ((CCodeStatement) body_stmt.ccodenode);
+ }
+
+ var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
+
+ if (coldif == null) {
+ // there is only one section and that section
+ // contains a default label
+ ctopstmt = cdo;
+ } else {
+ coldif.false_statement = cdo;
+ }
+ }
+
+ cswitchblock.append (ctopstmt);
+ }
+
+ public override void visit_while_statement (WhileStatement! stmt) {
+ stmt.ccodenode = new CCodeWhileStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
+
+ create_temp_decl (stmt, stmt.condition.temp_vars);
+ }
+
+ public override void visit_do_statement (DoStatement! stmt) {
+ stmt.ccodenode = new CCodeDoStatement ((CCodeStatement) stmt.body.ccodenode, (CCodeExpression) stmt.condition.ccodenode);
+
+ create_temp_decl (stmt, stmt.condition.temp_vars);
+ }
+
+ public override void visit_for_statement (ForStatement! stmt) {
+ var cfor = new CCodeForStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
+ stmt.ccodenode = cfor;
+
+ foreach (Expression init_expr in stmt.get_initializer ()) {
+ cfor.add_initializer ((CCodeExpression) init_expr.ccodenode);
+ create_temp_decl (stmt, init_expr.temp_vars);
+ }
+
+ foreach (Expression it_expr in stmt.get_iterator ()) {
+ cfor.add_iterator ((CCodeExpression) it_expr.ccodenode);
+ create_temp_decl (stmt, it_expr.temp_vars);
+ }
+
+ create_temp_decl (stmt, stmt.condition.temp_vars);
+ }
+
+ public override void visit_end_foreach_statement (ForeachStatement! stmt) {
+ var cblock = new CCodeBlock ();
+ CCodeForStatement cfor;
+ VariableDeclarator collection_backup = get_temp_variable_declarator (stmt.collection.static_type);
+
+ stmt.collection.temp_vars.prepend (collection_backup);
+ var cfrag = new CCodeFragment ();
+ append_temp_decl (cfrag, stmt.collection.temp_vars);
+ cblock.add_statement (cfrag);
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode)));
+
+ stmt.ccodenode = cblock;
+
+ if (stmt.collection.static_type.data_type is Array) {
+ var arr = (Array) stmt.collection.static_type.data_type;
+
+ var array_len = get_array_length_cexpression (stmt.collection, 1);
+
+ /* the array has no length parameter i.e. is NULL-terminated array */
+ if (array_len is CCodeConstant) {
+ var it_name = "%s_it".printf (stmt.variable_name);
+
+ var citdecl = new CCodeDeclaration (stmt.collection.static_type.get_cname ());
+ citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
+ cblock.add_statement (citdecl);
+
+ var cbody = new CCodeBlock ();
+
+ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeIdentifier ("*%s".printf (it_name))));
+ cbody.add_statement (cdecl);
+
+ cbody.add_statement (stmt.body.ccodenode);
+
+ var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("*%s".printf (it_name)), new CCodeConstant ("NULL"));
+
+ var cfor = new CCodeForStatement (ccond, cbody);
+
+ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name)));
+
+ cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
+ cblock.add_statement (cfor);
+ /* the array has a length parameter */
+ } else {
+ var it_name = (stmt.variable_name + "_it");
+
+ var citdecl = new CCodeDeclaration ("int");
+ citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
+ cblock.add_statement (citdecl);
+
+ var cbody = new CCodeBlock ();
+
+ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name))));
+ cbody.add_statement (cdecl);
+
+ cbody.add_statement (stmt.body.ccodenode);
+
+ var ccond_ind1 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, array_len, new CCodeConstant ("-1"));
+ var ccond_ind2 = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (it_name), array_len);
+ var ccond_ind = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_ind1, ccond_ind2);
+
+ /* only check for null if the containers elements are of reference-type */
+ CCodeBinaryExpression ccond;
+ if (arr.element_type.is_reference_type ()) {
+ var ccond_term1 = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, array_len, new CCodeConstant ("-1"));
+ var ccond_term2 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name)), new CCodeConstant ("NULL"));
+ var ccond_term = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_term1, ccond_term2);
+
+ ccond = new CCodeBinaryExpression (CCodeBinaryOperator.OR, new CCodeParenthesizedExpression (ccond_ind), new CCodeParenthesizedExpression (ccond_term));
+ } else {
+ ccond = ccond_ind;
+ }
+
+ var cfor = new CCodeForStatement (ccond, cbody);
+ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeConstant ("0")));
+ cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
+ cblock.add_statement (cfor);
+ }
+ } else if (stmt.collection.static_type.data_type == list_type ||
+ stmt.collection.static_type.data_type == slist_type) {
+ var it_name = "%s_it".printf (stmt.variable_name);
+
+ var citdecl = new CCodeDeclaration (stmt.collection.static_type.get_cname ());
+ citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
+ cblock.add_statement (citdecl);
+
+ var cbody = new CCodeBlock ();
+
+ CCodeExpression element_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "data");
+
+ /* cast pointer to actual type if appropriate */
+ if (stmt.type_reference.data_type is Struct) {
+ var st = (Struct) stmt.type_reference.data_type;
+ if (st == uint_type.data_type) {
+ var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
+ cconv.add_argument (element_expr);
+ element_expr = cconv;
+ } else if (st == bool_type.data_type || st.is_integer_type ()) {
+ var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
+ cconv.add_argument (element_expr);
+ element_expr = cconv;
+ }
+ }
+
+ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
+ cbody.add_statement (cdecl);
+
+ cbody.add_statement (stmt.body.ccodenode);
+
+ var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (it_name), new CCodeConstant ("NULL"));
+
+ var cfor = new CCodeForStatement (ccond, cbody);
+
+ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name)));
+
+ cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "next")));
+ cblock.add_statement (cfor);
+ }
+
+ if (memory_management && stmt.collection.static_type.transfers_ownership) {
+ cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (collection_backup.name), stmt.collection.static_type)));
+ }
+ }
+
+ public override void visit_break_statement (BreakStatement! stmt) {
+ stmt.ccodenode = new CCodeBreakStatement ();
+ }
+
+ public override void visit_continue_statement (ContinueStatement! stmt) {
+ stmt.ccodenode = new CCodeContinueStatement ();
+ }
+
+ private void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop) {
+ var b = (Block) sym.node;
+
+ var local_vars = b.get_local_variables ();
+ foreach (VariableDeclarator decl in local_vars) {
+ if (decl.symbol.active && decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) {
+ cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference)));
+ }
+ }
+
+ if (sym.parent_symbol.node is Block) {
+ append_local_free (sym.parent_symbol, cfrag, stop_at_loop);
+ }
+ }
+
+ private void create_local_free (Statement stmt) {
+ if (!memory_management) {
+ return;
+ }
+
+ var cfrag = new CCodeFragment ();
+
+ append_local_free (current_symbol, cfrag, false);
+
+ cfrag.append (stmt.ccodenode);
+ stmt.ccodenode = cfrag;
+ }
+
+ private bool append_local_free_expr (Symbol sym, CCodeCommaExpression ccomma, bool stop_at_loop) {
+ var found = false;
+
+ var b = (Block) sym.node;
+
+ var local_vars = b.get_local_variables ();
+ foreach (VariableDeclarator decl in local_vars) {
+ if (decl.symbol.active && decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) {
+ found = true;
+ ccomma.append_expression (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference));
+ }
+ }
+
+ if (sym.parent_symbol.node is Block) {
+ found = found || append_local_free_expr (sym.parent_symbol, ccomma, stop_at_loop);
+ }
+
+ return found;
+ }
+
+ private void create_local_free_expr (Expression expr) {
+ if (!memory_management) {
+ return;
+ }
+
+ var return_expr_decl = get_temp_variable_declarator (expr.static_type);
+
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (return_expr_decl.name), (CCodeExpression) expr.ccodenode));
+
+ if (!append_local_free_expr (current_symbol, ccomma, false)) {
+ /* no local variables need to be freed */
+ return;
+ }
+
+ ccomma.append_expression (new CCodeIdentifier (return_expr_decl.name));
+
+ expr.ccodenode = ccomma;
+ expr.temp_vars.append (return_expr_decl);
+ }
+
+ public override void visit_begin_return_statement (ReturnStatement! stmt) {
+ if (stmt.return_expression != null) {
+ // avoid unnecessary ref/unref pair
+ if (stmt.return_expression.ref_missing &&
+ stmt.return_expression.symbol_reference != null &&
+ stmt.return_expression.symbol_reference.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) stmt.return_expression.symbol_reference.node;
+ if (decl.type_reference.takes_ownership) {
+ /* return expression is local variable taking ownership and
+ * current method is transferring ownership */
+
+ stmt.return_expression.ref_sink = true;
+
+ // don't ref expression
+ stmt.return_expression.ref_missing = false;
+ }
+ }
+ }
+ }
+
+ public override void visit_end_return_statement (ReturnStatement! stmt) {
+ if (stmt.return_expression == null) {
+ stmt.ccodenode = new CCodeReturnStatement ();
+
+ create_local_free (stmt);
+ } else {
+ Symbol return_expression_symbol = null;
+
+ // avoid unnecessary ref/unref pair
+ if (stmt.return_expression.ref_sink &&
+ stmt.return_expression.symbol_reference != null &&
+ stmt.return_expression.symbol_reference.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) stmt.return_expression.symbol_reference.node;
+ if (decl.type_reference.takes_ownership) {
+ /* return expression is local variable taking ownership and
+ * current method is transferring ownership */
+
+ // don't unref expression
+ return_expression_symbol = decl.symbol;
+ return_expression_symbol.active = false;
+ }
+ }
+
+ create_local_free_expr (stmt.return_expression);
+
+ if (stmt.return_expression.static_type != null &&
+ stmt.return_expression.static_type.data_type != current_return_type.data_type) {
+ /* cast required */
+ if (current_return_type.data_type is Class || current_return_type.data_type is Interface) {
+ stmt.return_expression.ccodenode = new InstanceCast ((CCodeExpression) stmt.return_expression.ccodenode, current_return_type.data_type);
+ }
+ }
+
+ stmt.ccodenode = new CCodeReturnStatement ((CCodeExpression) stmt.return_expression.ccodenode);
+
+ create_temp_decl (stmt, stmt.return_expression.temp_vars);
+
+ if (return_expression_symbol != null) {
+ return_expression_symbol.active = true;
+ }
+ }
+ }
+
+ private ref string get_symbol_lock_name (Symbol! sym) {
+ return "__lock_%s".printf (sym.name);
+ }
+
+ /**
+ * Visit operation called for lock statements.
+ *
+ * @param stmt a lock statement
+ */
+ public override void visit_lock_statement (LockStatement! stmt) {
+ var cn = new CCodeFragment ();
+ CCodeExpression l = null;
+ CCodeFunctionCall fc;
+ var inner_node = ((MemberAccess)stmt.resource).inner;
+
+ if (inner_node == null) {
+ l = new CCodeIdentifier ("self");
+ } else if (stmt.resource.symbol_reference.parent_symbol.node != current_class) {
+ l = new CCodeFunctionCall (new CCodeIdentifier (((DataType) stmt.resource.symbol_reference.parent_symbol.node).get_upper_case_cname ()));
+ ((CCodeFunctionCall) l).add_argument ((CCodeExpression)inner_node.ccodenode);
+ } else {
+ l = (CCodeExpression)inner_node.ccodenode;
+ }
+ l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (stmt.resource.symbol_reference));
+
+ fc = new CCodeFunctionCall (new CCodeIdentifier (((Method)mutex_type.data_type.symbol.lookup ("lock").node).get_cname ()));
+ fc.add_argument (l);
+ cn.append (new CCodeExpressionStatement (fc));
+
+ cn.append (stmt.body.ccodenode);
+
+ fc = new CCodeFunctionCall (new CCodeIdentifier (((Method)mutex_type.data_type.symbol.lookup ("unlock").node).get_cname ()));
+ fc.add_argument (l);
+ cn.append (new CCodeExpressionStatement (fc));
+
+ stmt.ccodenode = cn;
+ }
+
+ /**
+ * Visit operations called for array creation expresions.
+ *
+ * @param expr an array creation expression
+ */
+ public override void visit_end_array_creation_expression (ArrayCreationExpression! expr) {
+ /* FIXME: rank > 1 not supported yet */
+ if (expr.rank > 1) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Creating arrays with rank greater than 1 is not supported yet");
+ }
+
+ var sizes = expr.get_sizes ();
+ var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+ gnew.add_argument (new CCodeIdentifier (expr.element_type.get_cname ()));
+ /* FIXME: had to add Expression cast due to possible compiler bug */
+ gnew.add_argument ((CCodeExpression) ((Expression) sizes.first ().data).ccodenode);
+
+ if (expr.initializer_list != null) {
+ var ce = new CCodeCommaExpression ();
+ var temp_var = get_temp_variable_declarator (expr.static_type);
+ var name_cnode = new CCodeIdentifier (temp_var.name);
+ int i = 0;
+
+ temp_vars.prepend (temp_var);
+
+ /* FIXME: had to add Expression cast due to possible compiler bug */
+ ce.append_expression (new CCodeAssignment (name_cnode, gnew));
+
+ foreach (Expression e in expr.initializer_list.get_initializers ()) {
+ ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode));
+ i++;
+ }
+
+ ce.append_expression (name_cnode);
+
+ expr.ccodenode = ce;
+ } else {
+ expr.ccodenode = gnew;
+ }
+ }
+
+ public override void visit_boolean_literal (BooleanLiteral! expr) {
+ expr.ccodenode = new CCodeConstant (expr.value ? "TRUE" : "FALSE");
+ }
+
+ public override void visit_character_literal (CharacterLiteral! expr) {
+ if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
+ expr.ccodenode = new CCodeConstant (expr.value);
+ } else {
+ expr.ccodenode = new CCodeConstant ("%uU".printf (expr.get_char ()));
+ }
+ }
+
+ public override void visit_integer_literal (IntegerLiteral! expr) {
+ expr.ccodenode = new CCodeConstant (expr.value);
+ }
+
+ public override void visit_real_literal (RealLiteral! expr) {
+ expr.ccodenode = new CCodeConstant (expr.value);
+ }
+
+ public override void visit_string_literal (StringLiteral! expr) {
+ expr.ccodenode = new CCodeConstant (expr.value);
+ }
+
+ public override void visit_null_literal (NullLiteral! expr) {
+ expr.ccodenode = new CCodeConstant ("NULL");
+ }
+
+ public override void visit_literal_expression (LiteralExpression! expr) {
+ expr.ccodenode = expr.literal.ccodenode;
+
+ visit_expression (expr);
+ }
+
+ private void process_cmember (MemberAccess! expr, CCodeExpression pub_inst, DataType base_type) {
+ if (expr.symbol_reference.node is Method) {
+ var m = (Method) expr.symbol_reference.node;
+
+ if (expr.inner is BaseAccess) {
+ if (m.base_interface_method != null) {
+ var base_iface = (Interface) m.base_interface_method.symbol.parent_symbol.node;
+ string parent_iface_var = "%s_%s_parent_iface".printf (current_class.get_lower_case_cname (null), base_iface.get_lower_case_cname (null));
+
+ expr.ccodenode = new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), m.name);
+ return;
+ } else if (m.base_method != null) {
+ var base_class = (Class) m.base_method.symbol.parent_symbol.node;
+ var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
+ vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
+
+ expr.ccodenode = new CCodeMemberAccess.pointer (vcast, m.name);
+ return;
+ }
+ }
+
+ if (m.base_interface_method != null) {
+ expr.ccodenode = new CCodeIdentifier (m.base_interface_method.get_cname ());
+ } else if (m.base_method != null) {
+ expr.ccodenode = new CCodeIdentifier (m.base_method.get_cname ());
+ } else {
+ expr.ccodenode = new CCodeIdentifier (m.get_cname ());
+ }
+ } else if (expr.symbol_reference.node is ArrayLengthField) {
+ expr.ccodenode = get_array_length_cexpression (expr.inner, 1);
+ } else if (expr.symbol_reference.node is Field) {
+ var f = (Field) expr.symbol_reference.node;
+ if (f.instance) {
+ ref CCodeExpression typed_inst;
+ if (f.symbol.parent_symbol.node != base_type) {
+ // FIXME: use C cast if debugging disabled
+ typed_inst = new CCodeFunctionCall (new CCodeIdentifier (((DataType) f.symbol.parent_symbol.node).get_upper_case_cname (null)));
+ ((CCodeFunctionCall) typed_inst).add_argument (pub_inst);
+ } else {
+ typed_inst = pub_inst;
+ }
+ ref CCodeExpression inst;
+ if (f.access == MemberAccessibility.PRIVATE) {
+ inst = new CCodeMemberAccess.pointer (typed_inst, "priv");
+ } else {
+ inst = typed_inst;
+ }
+ if (((DataType) f.symbol.parent_symbol.node).is_reference_type ()) {
+ expr.ccodenode = new CCodeMemberAccess.pointer (inst, f.get_cname ());
+ } else {
+ expr.ccodenode = new CCodeMemberAccess (inst, f.get_cname ());
+ }
+ } else {
+ expr.ccodenode = new CCodeIdentifier (f.get_cname ());
+ }
+ } else if (expr.symbol_reference.node is Constant) {
+ var c = (Constant) expr.symbol_reference.node;
+ expr.ccodenode = new CCodeIdentifier (c.get_cname ());
+ } else if (expr.symbol_reference.node is Property) {
+ var prop = (Property) expr.symbol_reference.node;
+
+ if (!prop.no_accessor_method) {
+ var base_property = prop;
+ if (prop.base_property != null) {
+ base_property = prop.base_property;
+ } else if (prop.base_interface_property != null) {
+ base_property = prop.base_interface_property;
+ }
+ var base_property_type = (DataType) base_property.symbol.parent_symbol.node;
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (base_property_type.get_lower_case_cname (null), base_property.name)));
+
+ /* explicitly use strong reference as ccast
+ * gets unrefed at the end of the inner block
+ */
+ ref CCodeExpression typed_pub_inst = pub_inst;
+
+ /* cast if necessary */
+ if (base_property_type != base_type) {
+ // FIXME: use C cast if debugging disabled
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier (base_property_type.get_upper_case_cname (null)));
+ ccast.add_argument (pub_inst);
+ typed_pub_inst = ccast;
+ }
+
+ ccall.add_argument (typed_pub_inst);
+ expr.ccodenode = ccall;
+ } else {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
+
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+ ccast.add_argument (pub_inst);
+ ccall.add_argument (ccast);
+
+ // property name is second argument of g_object_get
+ ccall.add_argument (prop.get_canonical_cconstant ());
+
+
+ // we need a temporary variable to save the property value
+ var temp_decl = get_temp_variable_declarator (expr.static_type);
+ temp_vars.prepend (temp_decl);
+
+ var ctemp = new CCodeIdentifier (temp_decl.name);
+ ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
+
+
+ ccall.add_argument (new CCodeConstant ("NULL"));
+
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (ccall);
+ ccomma.append_expression (ctemp);
+ expr.ccodenode = ccomma;
+ }
+ } else if (expr.symbol_reference.node is EnumValue) {
+ var ev = (EnumValue) expr.symbol_reference.node;
+ expr.ccodenode = new CCodeConstant (ev.get_cname ());
+ } else if (expr.symbol_reference.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) expr.symbol_reference.node;
+ expr.ccodenode = new CCodeIdentifier (decl.name);
+ } else if (expr.symbol_reference.node is FormalParameter) {
+ var p = (FormalParameter) expr.symbol_reference.node;
+ if (p.name == "this") {
+ expr.ccodenode = pub_inst;
+ } else {
+ if (p.type_reference.is_out || p.type_reference.reference_to_value_type) {
+ expr.ccodenode = new CCodeIdentifier ("(*%s)".printf (p.name));
+ } else {
+ expr.ccodenode = new CCodeIdentifier (p.name);
+ }
+ }
+ } else if (expr.symbol_reference.node is Signal) {
+ var sig = (Signal) expr.symbol_reference.node;
+ var cl = (DataType) sig.symbol.parent_symbol.node;
+
+ if (sig.has_emitter) {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_%s".printf (cl.get_lower_case_cname (null), sig.name)));
+
+ /* explicitly use strong reference as ccast
+ * gets unrefed at the end of the inner block
+ */
+ ref CCodeExpression typed_pub_inst = pub_inst;
+
+ /* cast if necessary */
+ if (cl != base_type) {
+ // FIXME: use C cast if debugging disabled
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccast.add_argument (pub_inst);
+ typed_pub_inst = ccast;
+ }
+
+ ccall.add_argument (typed_pub_inst);
+ expr.ccodenode = ccall;
+ } else {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
+
+ // FIXME: use C cast if debugging disabled
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+ ccast.add_argument (pub_inst);
+ ccall.add_argument (ccast);
+
+ ccall.add_argument (sig.get_canonical_cconstant ());
+
+ expr.ccodenode = ccall;
+ }
+ }
+ }
+
+ public override void visit_parenthesized_expression (ParenthesizedExpression! expr) {
+ expr.ccodenode = new CCodeParenthesizedExpression ((CCodeExpression) expr.inner.ccodenode);
+
+ visit_expression (expr);
+ }
+
+ public override void visit_member_access (MemberAccess! expr) {
+ CCodeExpression pub_inst = null;
+ DataType base_type = null;
+
+ if (expr.inner == null) {
+ pub_inst = new CCodeIdentifier ("self");
+
+ if (current_type_symbol != null) {
+ /* base type is available if this is a type method */
+ base_type = (DataType) current_type_symbol.node;
+
+ if (!base_type.is_reference_type ()) {
+ pub_inst = new CCodeIdentifier ("(*self)");
+ }
+ }
+ } else {
+ pub_inst = (CCodeExpression) expr.inner.ccodenode;
+
+ if (expr.inner.static_type != null) {
+ base_type = expr.inner.static_type.data_type;
+ }
+ }
+
+ process_cmember (expr, pub_inst, base_type);
+
+ visit_expression (expr);
+ }
+
+ private ref CCodeExpression! get_array_length_cexpression (Expression! array_expr, int dim) {
+ bool is_out = false;
+
+ if (array_expr is UnaryExpression) {
+ var unary_expr = (UnaryExpression) array_expr;
+ if (unary_expr.operator == UnaryOperator.OUT) {
+ array_expr = unary_expr.inner;
+ is_out = true;
+ }
+ }
+
+ if (array_expr is ArrayCreationExpression) {
+ var size = ((ArrayCreationExpression) array_expr).get_sizes ();
+ var length_expr = (Expression) size.nth_data (dim - 1);
+ return (CCodeExpression) length_expr.ccodenode;
+ } else if (array_expr.symbol_reference != null) {
+ if (array_expr.symbol_reference.node is FormalParameter) {
+ var param = (FormalParameter) array_expr.symbol_reference.node;
+ if (!param.no_array_length) {
+ var length_expr = new CCodeIdentifier (get_array_length_cname (param.name, dim));
+ if (is_out) {
+ return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
+ } else {
+ return length_expr;
+ }
+ }
+ } else if (array_expr.symbol_reference.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) array_expr.symbol_reference.node;
+ var length_expr = new CCodeIdentifier (get_array_length_cname (decl.name, dim));
+ if (is_out) {
+ return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
+ } else {
+ return length_expr;
+ }
+ } else if (array_expr.symbol_reference.node is Field) {
+ var field = (Field) array_expr.symbol_reference.node;
+ if (!field.no_array_length) {
+ var length_cname = get_array_length_cname (field.name, dim);
+
+ var ma = (MemberAccess) array_expr;
+
+ CCodeExpression pub_inst = null;
+ DataType base_type = null;
+ CCodeExpression length_expr = null;
+
+ if (ma.inner == null) {
+ pub_inst = new CCodeIdentifier ("self");
+
+ if (current_type_symbol != null) {
+ /* base type is available if this is a type method */
+ base_type = (DataType) current_type_symbol.node;
+ }
+ } else {
+ pub_inst = (CCodeExpression) ma.inner.ccodenode;
+
+ if (ma.inner.static_type != null) {
+ base_type = ma.inner.static_type.data_type;
+ }
+ }
+
+ if (field.instance) {
+ ref CCodeExpression typed_inst;
+ if (field.symbol.parent_symbol.node != base_type) {
+ // FIXME: use C cast if debugging disabled
+ typed_inst = new CCodeFunctionCall (new CCodeIdentifier (((DataType) field.symbol.parent_symbol.node).get_upper_case_cname (null)));
+ ((CCodeFunctionCall) typed_inst).add_argument (pub_inst);
+ } else {
+ typed_inst = pub_inst;
+ }
+ ref CCodeExpression inst;
+ if (field.access == MemberAccessibility.PRIVATE) {
+ inst = new CCodeMemberAccess.pointer (typed_inst, "priv");
+ } else {
+ inst = typed_inst;
+ }
+ if (((DataType) field.symbol.parent_symbol.node).is_reference_type ()) {
+ length_expr = new CCodeMemberAccess.pointer (inst, length_cname);
+ } else {
+ length_expr = new CCodeMemberAccess (inst, length_cname);
+ }
+ } else {
+ length_expr = new CCodeIdentifier (length_cname);
+ }
+
+ if (is_out) {
+ return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
+ } else {
+ return length_expr;
+ }
+ }
+ }
+ }
+
+ /* if we reach this point we were not able to get the explicit length of the array
+ * this is not allowed for an array of non-reference-type structs
+ */
+ if (((Array)array_expr.static_type.data_type).element_type is Struct) {
+ var s = (Struct)((Array)array_expr.static_type.data_type).element_type;
+ if (!s.is_reference_type ()) {
+ array_expr.error = true;
+ Report.error (array_expr.source_reference, "arrays of value-type structs with no explicit length parameter are not supported");
+ }
+ }
+
+ if (!is_out) {
+ return new CCodeConstant ("-1");
+ } else {
+ return new CCodeConstant ("NULL");
+ }
+ }
+
+ public override void visit_end_invocation_expression (InvocationExpression! expr) {
+ var ccall = new CCodeFunctionCall ((CCodeExpression) expr.call.ccodenode);
+
+ Method m = null;
+ List<weak FormalParameter> params;
+
+ if (!(expr.call is MemberAccess)) {
+ expr.error = true;
+ Report.error (expr.source_reference, "unsupported method invocation");
+ return;
+ }
+
+ var ma = (MemberAccess) expr.call;
+
+ if (expr.call.symbol_reference.node is Invokable) {
+ var i = (Invokable) expr.call.symbol_reference.node;
+ params = i.get_parameters ();
+
+ if (i is Method) {
+ m = (Method) i;
+ } else if (i is Signal) {
+ ccall = (CCodeFunctionCall) expr.call.ccodenode;
+ }
+ }
+
+ if (m is ArrayResizeMethod) {
+ var array = (Array) m.symbol.parent_symbol.node;
+ ccall.add_argument (new CCodeIdentifier (array.get_cname ()));
+ }
+
+ /* explicitly use strong reference as ccall gets unrefed
+ * at end of inner block
+ */
+ ref CCodeExpression instance;
+ if (m != null && m.instance) {
+ var base_method = m;
+ if (m.base_interface_method != null) {
+ base_method = m.base_interface_method;
+ } else if (m.base_method != null) {
+ base_method = m.base_method;
+ }
+
+ var req_cast = false;
+ if (ma.inner == null) {
+ instance = new CCodeIdentifier ("self");
+ /* require casts for overriden and inherited methods */
+ req_cast = m.overrides || m.base_interface_method != null || (m.symbol.parent_symbol != current_type_symbol);
+ } else {
+ instance = (CCodeExpression) ma.inner.ccodenode;
+ /* reqiure casts if the type of the used instance is
+ * different than the type which declared the method */
+ req_cast = base_method.symbol.parent_symbol.node != ma.inner.static_type.data_type;
+ }
+
+ if (m.instance_by_reference && (ma.inner != null || m.symbol.parent_symbol != current_type_symbol)) {
+ instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance);
+ }
+
+ if (req_cast && ((DataType) m.symbol.parent_symbol.node).is_reference_type ()) {
+ // FIXME: use C cast if debugging disabled
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (((DataType) base_method.symbol.parent_symbol.node).get_upper_case_cname (null)));
+ ccall.add_argument (instance);
+ instance = ccall;
+ }
+
+ if (!m.instance_last) {
+ ccall.add_argument (instance);
+ }
+ }
+
+ bool ellipsis = false;
+
+ var i = 1;
+ weak List<weak FormalParameter> params_it = params;
+ foreach (Expression arg in expr.get_argument_list ()) {
+ /* explicitly use strong reference as ccall gets
+ * unrefed at end of inner block
+ */
+ ref CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
+ if (params_it != null) {
+ var param = (FormalParameter) params_it.data;
+ ellipsis = param.ellipsis;
+ if (!ellipsis) {
+ if (param.type_reference.data_type != null
+ && param.type_reference.data_type.is_reference_type ()
+ && arg.static_type.data_type != null) {
+ if (!param.no_array_length && param.type_reference.data_type is Array) {
+ var arr = (Array) param.type_reference.data_type;
+ for (int dim = 1; dim <= arr.rank; dim++) {
+ ccall.add_argument (get_array_length_cexpression (arg, dim));
+ }
+ }
+ if (param.type_reference.data_type != arg.static_type.data_type) {
+ // FIXME: use C cast if debugging disabled
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (param.type_reference.data_type.get_upper_case_cname (null)));
+ ccall.add_argument (cexpr);
+ cexpr = ccall;
+ }
+ } else if (param.type_reference.data_type is Callback) {
+ cexpr = new CCodeCastExpression (cexpr, param.type_reference.data_type.get_cname ());
+ } else if (param.type_reference.data_type == null
+ && arg.static_type.data_type is Struct) {
+ /* convert integer to pointer if this is a generic method parameter */
+ var st = (Struct) arg.static_type.data_type;
+ if (st == bool_type.data_type || st.is_integer_type ()) {
+ var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GINT_TO_POINTER"));
+ cconv.add_argument (cexpr);
+ cexpr = cconv;
+ }
+ }
+ }
+ }
+
+ ccall.add_argument (cexpr);
+ i++;
+
+ if (params_it != null) {
+ params_it = params_it.next;
+ }
+ }
+ while (params_it != null) {
+ var param = (FormalParameter) params_it.data;
+
+ if (param.ellipsis) {
+ ellipsis = true;
+ break;
+ }
+
+ if (param.default_expression == null) {
+ Report.error (expr.source_reference, "no default expression for argument %d".printf (i));
+ return;
+ }
+
+ /* evaluate default expression here as the code
+ * generator might not have visited the formal
+ * parameter yet */
+ param.default_expression.accept (this);
+
+ if (!param.no_array_length && param.type_reference != null &&
+ param.type_reference.data_type is Array) {
+ var arr = (Array) param.type_reference.data_type;
+ for (int dim = 1; dim <= arr.rank; dim++) {
+ ccall.add_argument (get_array_length_cexpression (param.default_expression, dim));
+ }
+ }
+
+ ccall.add_argument ((CCodeExpression) param.default_expression.ccodenode);
+ i++;
+
+ params_it = params_it.next;
+ }
+
+ if (m != null && m.instance && m.instance_last) {
+ ccall.add_argument (instance);
+ } else if (ellipsis) {
+ /* ensure variable argument list ends with NULL
+ * except when using printf-style arguments */
+ if (m == null || !m.printf_format) {
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+ }
+
+ if (m != null && m.instance && m.returns_modified_pointer) {
+ expr.ccodenode = new CCodeAssignment (instance, ccall);
+ } else {
+ /* cast pointer to actual type if this is a generic method return value */
+ if (m != null && m.return_type.type_parameter != null && expr.static_type.data_type != null) {
+ if (expr.static_type.data_type is Struct) {
+ var st = (Struct) expr.static_type.data_type;
+ if (st == uint_type.data_type) {
+ var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
+ cconv.add_argument (ccall);
+ ccall = cconv;
+ } else if (st == bool_type.data_type || st.is_integer_type ()) {
+ var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
+ cconv.add_argument (ccall);
+ ccall = cconv;
+ }
+ }
+ }
+
+ expr.ccodenode = ccall;
+
+ visit_expression (expr);
+ }
+
+ if (m is ArrayResizeMethod) {
+ // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
+ var new_size = (CCodeExpression) ((CodeNode) expr.get_argument_list ().data).ccodenode;
+
+ var temp_decl = get_temp_variable_declarator (int_type);
+ var temp_ref = new CCodeIdentifier (temp_decl.name);
+
+ temp_vars.prepend (temp_decl);
+
+ /* memset needs string.h */
+ string_h_needed = true;
+
+ var clen = get_array_length_cexpression (ma.inner, 1);
+ var celems = (CCodeExpression)ma.inner.ccodenode;
+ var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (ma.inner.static_type.data_type.get_cname ()));
+ var cdelta = new CCodeParenthesizedExpression (new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, temp_ref, clen));
+ var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, temp_ref, clen);
+
+ var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+ czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, celems, clen));
+ czero.add_argument (new CCodeConstant ("0"));
+ czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cdelta));
+
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (new CCodeAssignment (temp_ref, new_size));
+ ccomma.append_expression ((CCodeExpression) expr.ccodenode);
+ ccomma.append_expression (new CCodeConditionalExpression (ccheck, czero, new CCodeConstant ("NULL")));
+ ccomma.append_expression (new CCodeAssignment (get_array_length_cexpression (ma.inner, 1), temp_ref));
+
+ expr.ccodenode = ccomma;
+ }
+ }
+
+ public override void visit_element_access (ElementAccess! expr)
+ {
+ List<weak Expression> indices = expr.get_indices ();
+ int rank = indices.length ();
+
+ if (rank == 1) {
+ /* FIXME: had to add Expression cast due to possible compiler bug */
+ expr.ccodenode = new CCodeElementAccess ((CCodeExpression)expr.container.ccodenode, (CCodeExpression)((Expression)indices.first ().data).ccodenode);
+ } else {
+ expr.error = true;
+ Report.error (expr.source_reference, "Arrays with more then one dimension are not supported yet");
+ return;
+ }
+
+ visit_expression (expr);
+ }
+
+ public override void visit_base_access (BaseAccess! expr) {
+ expr.ccodenode = new InstanceCast (new CCodeIdentifier ("self"), expr.static_type.data_type);
+ }
+
+ public override void visit_postfix_expression (PostfixExpression! expr) {
+ MemberAccess ma = find_property_access (expr.inner);
+ if (ma != null) {
+ // property postfix expression
+ var prop = (Property) ma.symbol_reference.node;
+
+ var ccomma = new CCodeCommaExpression ();
+
+ // assign current value to temp variable
+ var temp_decl = get_temp_variable_declarator (prop.type_reference);
+ temp_vars.prepend (temp_decl);
+ ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), (CCodeExpression) expr.inner.ccodenode));
+
+ // increment/decrement property
+ var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
+ var cexpr = new CCodeBinaryExpression (op, new CCodeIdentifier (temp_decl.name), new CCodeConstant ("1"));
+ var ccall = get_property_set_call (prop, ma, cexpr);
+ ccomma.append_expression (ccall);
+
+ // return previous value
+ ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
+
+ expr.ccodenode = ccomma;
+ return;
+ }
+
+ var op = expr.increment ? CCodeUnaryOperator.POSTFIX_INCREMENT : CCodeUnaryOperator.POSTFIX_DECREMENT;
+
+ expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
+
+ visit_expression (expr);
+ }
+
+ private MemberAccess find_property_access (Expression! expr) {
+ if (expr is ParenthesizedExpression) {
+ var pe = (ParenthesizedExpression) expr;
+ return find_property_access (pe.inner);
+ }
+
+ if (!(expr is MemberAccess)) {
+ return null;
+ }
+
+ var ma = (MemberAccess) expr;
+ if (ma.symbol_reference.node is Property) {
+ return ma;
+ }
+
+ return null;
+ }
+
+ private ref CCodeExpression get_ref_expression (Expression! expr) {
+ /* (temp = expr, temp == NULL ? NULL : ref (temp))
+ *
+ * can be simplified to
+ * ref (expr)
+ * if static type of expr is non-null
+ */
+
+ if (expr.static_type.data_type == null &&
+ expr.static_type.type_parameter != null) {
+ Report.warning (expr.source_reference, "Missing generics support for memory management");
+ return (CCodeExpression) expr.ccodenode;
+ }
+
+ string ref_function;
+ if (expr.static_type.data_type.is_reference_counting ()) {
+ ref_function = expr.static_type.data_type.get_ref_function ();
+ } else {
+ if (expr.static_type.data_type != string_type.data_type) {
+ // duplicating non-reference counted structs may cause side-effects (and performance issues)
+ Report.warning (expr.source_reference, "duplicating %s instance, use weak variable or explicitly invoke copy method".printf (expr.static_type.data_type.name));
+ }
+ ref_function = expr.static_type.data_type.get_dup_function ();
+ }
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (ref_function));
+
+ if (expr.static_type.non_null) {
+ ccall.add_argument ((CCodeExpression) expr.ccodenode);
+
+ return ccall;
+ } else {
+ var decl = get_temp_variable_declarator (expr.static_type, false);
+ temp_vars.prepend (decl);
+
+ var ctemp = new CCodeIdentifier (decl.name);
+
+ var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL"));
+
+ ccall.add_argument (ctemp);
+
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (new CCodeAssignment (ctemp, (CCodeExpression) expr.ccodenode));
+
+ if (ref_function == "g_list_copy") {
+ bool is_ref = false;
+ bool is_class = false;
+ bool is_interface = false;
+
+ foreach (TypeReference type_arg in expr.static_type.get_type_arguments ()) {
+ is_ref |= type_arg.takes_ownership;
+ is_class |= type_arg.data_type is Class;
+ is_interface |= type_arg.data_type is Interface;
+ }
+
+ if (is_ref && (is_class || is_interface)) {
+ var crefcall = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
+
+ crefcall.add_argument (ctemp);
+ crefcall.add_argument (new CCodeIdentifier ("(GFunc) g_object_ref"));
+ crefcall.add_argument (new CCodeConstant ("NULL"));
+
+ ccomma.append_expression (crefcall);
+ }
+ }
+
+ ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), ccall));
+
+ return ccomma;
+ }
+ }
+
+ private void visit_expression (Expression! expr) {
+ if (expr.static_type != null &&
+ expr.static_type.transfers_ownership &&
+ expr.static_type.floating_reference) {
+ /* constructor of GInitiallyUnowned subtype
+ * returns floating reference, sink it
+ */
+ var csink = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref_sink"));
+ csink.add_argument ((CCodeExpression) expr.ccodenode);
+
+ expr.ccodenode = csink;
+ }
+
+ if (expr.ref_leaked) {
+ var decl = get_temp_variable_declarator (expr.static_type);
+ temp_vars.prepend (decl);
+ temp_ref_vars.prepend (decl);
+ expr.ccodenode = new CCodeParenthesizedExpression (new CCodeAssignment (new CCodeIdentifier (decl.name), (CCodeExpression) expr.ccodenode));
+ } else if (expr.ref_missing) {
+ expr.ccodenode = get_ref_expression (expr);
+ }
+ }
+
+ public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) {
+ if (expr.symbol_reference == null) {
+ // no creation method
+ if (expr.type_reference.data_type is Class) {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_new"));
+
+ ccall.add_argument (new CCodeConstant (expr.type_reference.data_type.get_type_id ()));
+
+ ccall.add_argument (new CCodeConstant ("NULL"));
+
+ expr.ccodenode = ccall;
+ } else if (expr.type_reference.data_type == list_type ||
+ expr.type_reference.data_type == slist_type) {
+ // NULL is an empty list
+ expr.ccodenode = new CCodeConstant ("NULL");
+ } else {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+
+ ccall.add_argument (new CCodeConstant (expr.type_reference.data_type.get_cname ()));
+
+ ccall.add_argument (new CCodeConstant ("1"));
+
+ expr.ccodenode = ccall;
+ }
+ } else {
+ // use creation method
+ var m = (Method) expr.symbol_reference.node;
+ var params = m.get_parameters ();
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
+
+ if (expr.type_reference.data_type is Class) {
+ foreach (TypeReference type_arg in expr.type_reference.get_type_arguments ()) {
+ if (type_arg.takes_ownership) {
+ ccall.add_argument (get_destroy_func_expression (type_arg));
+ } else {
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+ }
+ }
+
+ bool ellipsis = false;
+
+ int i = 1;
+ weak List<weak FormalParameter> params_it = params;
+ foreach (Expression arg in expr.get_argument_list ()) {
+ /* explicitly use strong reference as ccall gets
+ * unrefed at end of inner block
+ */
+ ref CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
+ if (params_it != null) {
+ var param = (FormalParameter) params_it.data;
+ ellipsis = param.ellipsis;
+ if (!param.ellipsis
+ && param.type_reference.data_type != null
+ && param.type_reference.data_type.is_reference_type ()
+ && arg.static_type.data_type != null
+ && param.type_reference.data_type != arg.static_type.data_type) {
+ // FIXME: use C cast if debugging disabled
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (param.type_reference.data_type.get_upper_case_cname (null)));
+ ccall.add_argument (cexpr);
+ cexpr = ccall;
+ }
+ }
+
+ ccall.add_argument (cexpr);
+ i++;
+
+ if (params_it != null) {
+ params_it = params_it.next;
+ }
+ }
+ while (params_it != null) {
+ var param = (FormalParameter) params_it.data;
+
+ if (param.ellipsis) {
+ ellipsis = true;
+ break;
+ }
+
+ if (param.default_expression == null) {
+ Report.error (expr.source_reference, "no default expression for argument %d".printf (i));
+ return;
+ }
+
+ /* evaluate default expression here as the code
+ * generator might not have visited the formal
+ * parameter yet */
+ param.default_expression.accept (this);
+
+ ccall.add_argument ((CCodeExpression) param.default_expression.ccodenode);
+ i++;
+
+ params_it = params_it.next;
+ }
+
+ if (ellipsis) {
+ // ensure variable argument list ends with NULL
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+
+ expr.ccodenode = ccall;
+ }
+
+ visit_expression (expr);
+ }
+
+ public override void visit_typeof_expression (TypeofExpression! expr) {
+ expr.ccodenode = new CCodeIdentifier (expr.type_reference.data_type.get_type_id ());
+ }
+
+ public override void visit_unary_expression (UnaryExpression! expr) {
+ CCodeUnaryOperator op;
+ if (expr.operator == UnaryOperator.PLUS) {
+ op = CCodeUnaryOperator.PLUS;
+ } else if (expr.operator == UnaryOperator.MINUS) {
+ op = CCodeUnaryOperator.MINUS;
+ } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
+ op = CCodeUnaryOperator.LOGICAL_NEGATION;
+ } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
+ op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
+ } else if (expr.operator == UnaryOperator.INCREMENT) {
+ op = CCodeUnaryOperator.PREFIX_INCREMENT;
+ } else if (expr.operator == UnaryOperator.DECREMENT) {
+ op = CCodeUnaryOperator.PREFIX_DECREMENT;
+ } else if (expr.operator == UnaryOperator.REF) {
+ op = CCodeUnaryOperator.ADDRESS_OF;
+ } else if (expr.operator == UnaryOperator.OUT) {
+ op = CCodeUnaryOperator.ADDRESS_OF;
+ }
+ expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
+
+ visit_expression (expr);
+ }
+
+ public override void visit_cast_expression (CastExpression! expr) {
+ if (expr.type_reference.data_type is Class || expr.type_reference.data_type is Interface) {
+ // GObject cast
+ expr.ccodenode = new InstanceCast ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.data_type);
+ } else {
+ expr.ccodenode = new CCodeCastExpression ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.get_cname ());
+ }
+
+ visit_expression (expr);
+ }
+
+ public override void visit_pointer_indirection (PointerIndirection! expr) {
+ expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, (CCodeExpression) expr.inner.ccodenode);
+ }
+
+ public override void visit_addressof_expression (AddressofExpression! expr) {
+ expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, (CCodeExpression) expr.inner.ccodenode);
+ }
+
+ public override void visit_reference_transfer_expression (ReferenceTransferExpression! expr) {
+ /* (tmp = var, var = null, tmp) */
+ var ccomma = new CCodeCommaExpression ();
+ var temp_decl = get_temp_variable_declarator (expr.static_type);
+ temp_vars.prepend (temp_decl);
+ var cvar = new CCodeIdentifier (temp_decl.name);
+
+ ccomma.append_expression (new CCodeAssignment (cvar, (CCodeExpression) expr.inner.ccodenode));
+ ccomma.append_expression (new CCodeAssignment ((CCodeExpression) expr.inner.ccodenode, new CCodeConstant ("NULL")));
+ ccomma.append_expression (cvar);
+ expr.ccodenode = ccomma;
+
+ visit_expression (expr);
+ }
+
+ public override void visit_binary_expression (BinaryExpression! expr) {
+ CCodeBinaryOperator op;
+ if (expr.operator == BinaryOperator.PLUS) {
+ op = CCodeBinaryOperator.PLUS;
+ } else if (expr.operator == BinaryOperator.MINUS) {
+ op = CCodeBinaryOperator.MINUS;
+ } else if (expr.operator == BinaryOperator.MUL) {
+ op = CCodeBinaryOperator.MUL;
+ } else if (expr.operator == BinaryOperator.DIV) {
+ op = CCodeBinaryOperator.DIV;
+ } else if (expr.operator == BinaryOperator.MOD) {
+ op = CCodeBinaryOperator.MOD;
+ } else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
+ op = CCodeBinaryOperator.SHIFT_LEFT;
+ } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
+ op = CCodeBinaryOperator.SHIFT_RIGHT;
+ } else if (expr.operator == BinaryOperator.LESS_THAN) {
+ op = CCodeBinaryOperator.LESS_THAN;
+ } else if (expr.operator == BinaryOperator.GREATER_THAN) {
+ op = CCodeBinaryOperator.GREATER_THAN;
+ } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
+ op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
+ } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
+ op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
+ } else if (expr.operator == BinaryOperator.EQUALITY) {
+ op = CCodeBinaryOperator.EQUALITY;
+ } else if (expr.operator == BinaryOperator.INEQUALITY) {
+ op = CCodeBinaryOperator.INEQUALITY;
+ } else if (expr.operator == BinaryOperator.BITWISE_AND) {
+ op = CCodeBinaryOperator.BITWISE_AND;
+ } else if (expr.operator == BinaryOperator.BITWISE_OR) {
+ op = CCodeBinaryOperator.BITWISE_OR;
+ } else if (expr.operator == BinaryOperator.BITWISE_XOR) {
+ op = CCodeBinaryOperator.BITWISE_XOR;
+ } else if (expr.operator == BinaryOperator.AND) {
+ op = CCodeBinaryOperator.AND;
+ } else if (expr.operator == BinaryOperator.OR) {
+ op = CCodeBinaryOperator.OR;
+ }
+
+ var cleft = (CCodeExpression) expr.left.ccodenode;
+ var cright = (CCodeExpression) expr.right.ccodenode;
+
+ if (expr.operator == BinaryOperator.EQUALITY ||
+ expr.operator == BinaryOperator.INEQUALITY) {
+ if (expr.left.static_type != null && expr.right.static_type != null &&
+ expr.left.static_type.data_type is Class && expr.right.static_type.data_type is Class) {
+ var left_cl = (Class) expr.left.static_type.data_type;
+ var right_cl = (Class) expr.right.static_type.data_type;
+
+ if (left_cl != right_cl) {
+ if (left_cl.is_subtype_of (right_cl)) {
+ cleft = new InstanceCast (cleft, right_cl);
+ } else if (right_cl.is_subtype_of (left_cl)) {
+ cright = new InstanceCast (cright, left_cl);
+ }
+ }
+ }
+ }
+
+ expr.ccodenode = new CCodeBinaryExpression (op, cleft, cright);
+
+ visit_expression (expr);
+ }
+
+ public override void visit_type_check (TypeCheck! expr) {
+ var ccheck = new CCodeFunctionCall (new CCodeIdentifier (expr.type_reference.data_type.get_upper_case_cname ("IS_")));
+ ccheck.add_argument ((CCodeExpression) expr.expression.ccodenode);
+ expr.ccodenode = ccheck;
+ }
+
+ public override void visit_conditional_expression (ConditionalExpression! expr) {
+ expr.ccodenode = new CCodeConditionalExpression ((CCodeExpression) expr.condition.ccodenode, (CCodeExpression) expr.true_expression.ccodenode, (CCodeExpression) expr.false_expression.ccodenode);
+ }
+
+ public override void visit_end_lambda_expression (LambdaExpression! l) {
+ l.ccodenode = new CCodeIdentifier (l.method.get_cname ());
+ }
+
+ public override void visit_end_assignment (Assignment! a) {
+ MemberAccess ma = null;
+
+ if (a.left is MemberAccess) {
+ ma = (MemberAccess)a.left;
+ }
+
+ if (a.left.symbol_reference != null && a.left.symbol_reference.node is Property) {
+ var prop = (Property) a.left.symbol_reference.node;
+
+ if (current_class != null && ma.inner == null && in_creation_method) {
+ // this property is used as a construction parameter
+ var cpointer = new CCodeIdentifier ("__params_it");
+
+ var ccomma = new CCodeCommaExpression ();
+ // set name in array for current parameter
+ var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name");
+ var cnameassign = new CCodeAssignment (cnamemember, prop.get_canonical_cconstant ());
+ ccomma.append_expression (cnameassign);
+
+ var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value"));
+
+ // initialize GValue in array for current parameter
+ var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
+ cvalueinit.add_argument (gvaluearg);
+ cvalueinit.add_argument (new CCodeIdentifier (prop.type_reference.data_type.get_type_id ()));
+ ccomma.append_expression (cvalueinit);
+
+ // set GValue for current parameter
+ var cvalueset = new CCodeFunctionCall (get_value_setter_function (prop.type_reference));
+ cvalueset.add_argument (gvaluearg);
+ cvalueset.add_argument ((CCodeExpression) a.right.ccodenode);
+ ccomma.append_expression (cvalueset);
+
+ // move pointer to next parameter in array
+ ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer));
+
+ a.ccodenode = ccomma;
+ } else {
+ ref CCodeExpression cexpr = (CCodeExpression) a.right.ccodenode;
+
+ if (!prop.no_accessor_method
+ && prop.type_reference.data_type != null
+ && prop.type_reference.data_type.is_reference_type ()
+ && a.right.static_type.data_type != null
+ && prop.type_reference.data_type != a.right.static_type.data_type) {
+ /* cast is necessary */
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier (prop.type_reference.data_type.get_upper_case_cname (null)));
+ ccast.add_argument (cexpr);
+ cexpr = ccast;
+ }
+
+ if (a.operator != AssignmentOperator.SIMPLE) {
+ CCodeBinaryOperator cop;
+ if (a.operator == AssignmentOperator.BITWISE_OR) {
+ cop = CCodeBinaryOperator.BITWISE_OR;
+ } else if (a.operator == AssignmentOperator.BITWISE_AND) {
+ cop = CCodeBinaryOperator.BITWISE_AND;
+ } else if (a.operator == AssignmentOperator.BITWISE_XOR) {
+ cop = CCodeBinaryOperator.BITWISE_XOR;
+ } else if (a.operator == AssignmentOperator.ADD) {
+ cop = CCodeBinaryOperator.PLUS;
+ } else if (a.operator == AssignmentOperator.SUB) {
+ cop = CCodeBinaryOperator.MINUS;
+ } else if (a.operator == AssignmentOperator.MUL) {
+ cop = CCodeBinaryOperator.MUL;
+ } else if (a.operator == AssignmentOperator.DIV) {
+ cop = CCodeBinaryOperator.DIV;
+ } else if (a.operator == AssignmentOperator.PERCENT) {
+ cop = CCodeBinaryOperator.MOD;
+ } else if (a.operator == AssignmentOperator.SHIFT_LEFT) {
+ cop = CCodeBinaryOperator.SHIFT_LEFT;
+ } else if (a.operator == AssignmentOperator.SHIFT_RIGHT) {
+ cop = CCodeBinaryOperator.SHIFT_RIGHT;
+ }
+ cexpr = new CCodeBinaryExpression (cop, (CCodeExpression) a.left.ccodenode, new CCodeParenthesizedExpression (cexpr));
+ }
+
+ var ccall = get_property_set_call (prop, ma, cexpr);
+
+ // assignments are expressions, so return the current property value
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (ccall); // update property
+ ccomma.append_expression ((CCodeExpression) ma.ccodenode); // current property value
+
+ a.ccodenode = ccomma;
+ }
+ } else if (a.left.symbol_reference != null && a.left.symbol_reference.node is Signal) {
+ var sig = (Signal) a.left.symbol_reference.node;
+
+ var m = (Method) a.right.symbol_reference.node;
+
+ string connect_func;
+ bool disconnect = false;
+
+ if (a.operator == AssignmentOperator.ADD) {
+ connect_func = "g_signal_connect_object";
+ if (!m.instance) {
+ connect_func = "g_signal_connect";
+ }
+ } else if (a.operator == AssignmentOperator.SUB) {
+ connect_func = "g_signal_handlers_disconnect_matched";
+ disconnect = true;
+ } else {
+ a.error = true;
+ Report.error (a.source_reference, "Specified compound assignment type for signals not supported.");
+ return;
+ }
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
+
+ if (ma.inner != null) {
+ ccall.add_argument ((CCodeExpression) ma.inner.ccodenode);
+ } else {
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ }
+
+ if (!disconnect) {
+ ccall.add_argument (sig.get_canonical_cconstant ());
+ } else {
+ ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
+
+ // get signal id
+ var ccomma = new CCodeCommaExpression ();
+ var temp_decl = get_temp_variable_declarator (uint_type);
+ temp_vars.prepend (temp_decl);
+ var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name"));
+ parse_call.add_argument (sig.get_canonical_cconstant ());
+ var decl_type = (DataType) sig.symbol.parent_symbol.node;
+ parse_call.add_argument (new CCodeIdentifier (decl_type.get_type_id ()));
+ parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_decl.name)));
+ parse_call.add_argument (new CCodeConstant ("NULL"));
+ parse_call.add_argument (new CCodeConstant ("FALSE"));
+ ccomma.append_expression (parse_call);
+ ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
+
+ ccall.add_argument (ccomma);
+
+ ccall.add_argument (new CCodeConstant ("0"));
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+
+ ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (m.get_cname ()), "GCallback"));
+
+ if (m.instance) {
+ if (a.right is MemberAccess) {
+ var right_ma = (MemberAccess) a.right;
+ if (right_ma.inner != null) {
+ ccall.add_argument ((CCodeExpression) right_ma.inner.ccodenode);
+ } else {
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ }
+ } else if (a.right is LambdaExpression) {
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ }
+ if (!disconnect) {
+ ccall.add_argument (new CCodeConstant ("0"));
+ }
+ } else {
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+
+ a.ccodenode = ccall;
+ } else {
+ /* explicitly use strong reference as ccast gets
+ * unrefed at end of inner block
+ */
+ ref CCodeExpression rhs = (CCodeExpression) a.right.ccodenode;
+
+ if (a.left.static_type.data_type != null
+ && a.right.static_type.data_type != null
+ && a.left.static_type.data_type.is_reference_type ()
+ && a.right.static_type.data_type != a.left.static_type.data_type) {
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier (a.left.static_type.data_type.get_upper_case_cname (null)));
+ ccast.add_argument (rhs);
+ rhs = ccast;
+ }
+
+ bool unref_old = (memory_management && a.left.static_type.takes_ownership);
+ bool array = false;
+ if (a.left.static_type.data_type is Array) {
+ array = !(get_array_length_cexpression (a.left, 1) is CCodeConstant);
+ }
+
+ if (unref_old || array) {
+ var ccomma = new CCodeCommaExpression ();
+
+ var temp_decl = get_temp_variable_declarator (a.left.static_type);
+ temp_vars.prepend (temp_decl);
+ ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), rhs));
+ if (unref_old) {
+ /* unref old value */
+ ccomma.append_expression (get_unref_expression ((CCodeExpression) a.left.ccodenode, a.left.static_type));
+ }
+
+ if (array) {
+ var lhs_array_len = get_array_length_cexpression (a.left, 1);
+ var rhs_array_len = get_array_length_cexpression (a.right, 1);
+ ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
+ }
+
+ ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
+
+ rhs = ccomma;
+ }
+
+ var cop = CCodeAssignmentOperator.SIMPLE;
+ if (a.operator == AssignmentOperator.BITWISE_OR) {
+ cop = CCodeAssignmentOperator.BITWISE_OR;
+ } else if (a.operator == AssignmentOperator.BITWISE_AND) {
+ cop = CCodeAssignmentOperator.BITWISE_AND;
+ } else if (a.operator == AssignmentOperator.BITWISE_XOR) {
+ cop = CCodeAssignmentOperator.BITWISE_XOR;
+ } else if (a.operator == AssignmentOperator.ADD) {
+ cop = CCodeAssignmentOperator.ADD;
+ } else if (a.operator == AssignmentOperator.SUB) {
+ cop = CCodeAssignmentOperator.SUB;
+ } else if (a.operator == AssignmentOperator.MUL) {
+ cop = CCodeAssignmentOperator.MUL;
+ } else if (a.operator == AssignmentOperator.DIV) {
+ cop = CCodeAssignmentOperator.DIV;
+ } else if (a.operator == AssignmentOperator.PERCENT) {
+ cop = CCodeAssignmentOperator.PERCENT;
+ } else if (a.operator == AssignmentOperator.SHIFT_LEFT) {
+ cop = CCodeAssignmentOperator.SHIFT_LEFT;
+ } else if (a.operator == AssignmentOperator.SHIFT_RIGHT) {
+ cop = CCodeAssignmentOperator.SHIFT_RIGHT;
+ }
+
+ a.ccodenode = new CCodeAssignment ((CCodeExpression) a.left.ccodenode, rhs, cop);
+ }
+ }
+
+ private ref CCodeFunctionCall get_property_set_call (Property! prop, MemberAccess! ma, CCodeExpression! cexpr) {
+ var cl = (Class) prop.symbol.parent_symbol.node;
+ var set_func = "g_object_set";
+
+ if (!prop.no_accessor_method) {
+ set_func = "%s_set_%s".printf (cl.get_lower_case_cname (null), prop.name);
+ }
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
+
+ /* target instance is first argument */
+ ref CCodeExpression instance;
+ var req_cast = false;
+
+ if (ma.inner == null) {
+ instance = new CCodeIdentifier ("self");
+ /* require casts for inherited properties */
+ req_cast = (prop.symbol.parent_symbol != current_type_symbol);
+ } else {
+ instance = (CCodeExpression) ma.inner.ccodenode;
+ /* require casts if the type of the used instance is
+ * different than the type which declared the property */
+ req_cast = prop.symbol.parent_symbol.node != ma.inner.static_type.data_type;
+ }
+
+ if (req_cast && ((DataType) prop.symbol.parent_symbol.node).is_reference_type ()) {
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier (((DataType) prop.symbol.parent_symbol.node).get_upper_case_cname (null)));
+ ccast.add_argument (instance);
+ instance = ccast;
+ }
+
+ ccall.add_argument (instance);
+
+ if (prop.no_accessor_method) {
+ /* property name is second argument of g_object_set */
+ ccall.add_argument (prop.get_canonical_cconstant ());
+ }
+
+ ccall.add_argument (cexpr);
+
+ if (prop.no_accessor_method) {
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+
+ return ccall;
+ }
+}