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