[vala/dova: 1/2] Add dova profile
- From: Jürg Billeter <juergbi src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [vala/dova: 1/2] Add dova profile
- Date: Sat, 5 Sep 2009 17:29:53 +0000 (UTC)
commit 132c83f3d0921a93243fbafd4cfc4ee6146a02b2
Author: Jürg Billeter <j bitron ch>
Date: Fri Sep 4 20:26:53 2009 +0200
Add dova profile
ccode/valaccodefunction.vala | 6 +-
codegen/Makefile.am | 10 +
codegen/valaccodegenerator.vala | 13 +
codegen/valadovaarraymodule.vala | 158 +++
codegen/valadovaassignmentmodule.vala | 201 +++
codegen/valadovabasemodule.vala | 2201 +++++++++++++++++++++++++++++++
codegen/valadovacontrolflowmodule.vala | 101 ++
codegen/valadovamemberaccessmodule.vala | 265 ++++
codegen/valadovamethodcallmodule.vala | 270 ++++
codegen/valadovamethodmodule.vala | 84 ++
codegen/valadovaobjectmodule.vala | 1142 ++++++++++++++++
codegen/valadovastructmodule.vala | 90 ++
codegen/valadovavaluemodule.vala | 331 +++++
compiler/valacompiler.vala | 35 +-
vala/valabinaryexpression.vala | 8 +
vala/valacreationmethod.vala | 4 +
vala/valagenerictype.vala | 6 +-
vala/valaintegerliteral.vala | 7 +
vala/valaprofile.vala | 3 +-
vala/valasemanticanalyzer.vala | 7 +-
vala/valastruct.vala | 3 +
vala/valasymbolresolver.vala | 18 +-
22 files changed, 4949 insertions(+), 14 deletions(-)
---
diff --git a/ccode/valaccodefunction.vala b/ccode/valaccodefunction.vala
index 1a9d240..ba3a55d 100644
--- a/ccode/valaccodefunction.vala
+++ b/ccode/valaccodefunction.vala
@@ -62,7 +62,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 8f9401f..49f2f84 100644
--- a/codegen/Makefile.am
+++ b/codegen/Makefile.am
@@ -33,6 +33,16 @@ libvala_la_VALASOURCES = \
valadbusinterfaceregisterfunction.vala \
valadbusmodule.vala \
valadbusservermodule.vala \
+ valadovaarraymodule.vala \
+ valadovaassignmentmodule.vala \
+ valadovabasemodule.vala \
+ valadovacontrolflowmodule.vala \
+ valadovamemberaccessmodule.vala \
+ valadovamethodcallmodule.vala \
+ valadovamethodmodule.vala \
+ valadovaobjectmodule.vala \
+ valadovastructmodule.vala \
+ valadovavaluemodule.vala \
valagerrormodule.vala \
valagirwriter.vala \
valagobjectmodule.vala \
diff --git a/codegen/valaccodegenerator.vala b/codegen/valaccodegenerator.vala
index f66e6dc..b7e651e 100644
--- a/codegen/valaccodegenerator.vala
+++ b/codegen/valaccodegenerator.vala
@@ -54,6 +54,19 @@ 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);
} 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..a0667f2
--- /dev/null
+++ b/codegen/valadovaarraymodule.vala
@@ -0,0 +1,158 @@
+/* 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>
+ */
+
+using Gee;
+
+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);
+
+ Gee.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);
+ }
+
+ public override void generate_parameter (FormalParameter param, CCodeDeclarationSpace decl_space, Map<int,CCodeFormalParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
+ if (!(param.parameter_type is ArrayType)) {
+ base.generate_parameter (param, decl_space, cparam_map, carg_map);
+ return;
+ }
+
+ generate_class_declaration (array_class, decl_space);
+
+ string ctypename = param.parameter_type.get_cname ();
+
+ if (param.direction != ParameterDirection.IN) {
+ ctypename += "*";
+ }
+
+ param.ccodenode = new CCodeFormalParameter (get_variable_cname (param.name), ctypename);
+
+ var array_type = (ArrayType) param.parameter_type;
+
+ generate_type_declaration (array_type.element_type, decl_space);
+
+ cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
+ if (carg_map != null) {
+ carg_map.set (get_param_pos (param.cparameter_position), get_variable_cexpression (param.name));
+ }
+ }
+}
diff --git a/codegen/valadovaassignmentmodule.vala b/codegen/valadovaassignmentmodule.vala
new file mode 100644
index 0000000..2c75905
--- /dev/null
+++ b/codegen/valadovaassignmentmodule.vala
@@ -0,0 +1,201 @@
+/* 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>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * 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..739543b
--- /dev/null
+++ b/codegen/valadovabasemodule.vala
@@ -0,0 +1,2201 @@
+/* valadovabasemodule.vala
+ *
+ * Copyright (C) 2006-2009 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>
+ */
+
+using Gee;
+
+/**
+ * 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 class_init_fragment;
+ 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 */
+ Gee.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;
+
+ 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");
+
+ // MSVC keywords
+ reserved_identifiers.add ("cdecl");
+
+ // reserved for Vala/GObject naming conventions
+ reserved_identifiers.add ("error");
+ reserved_identifiers.add ("result");
+ reserved_identifiers.add ("self");
+ }
+
+ 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");
+
+ 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 ()) {
+ 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 ()) {
+ 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 ()) {
+ 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;
+ bool is_gtypeinstance = (cl != null && !cl.is_compact);
+
+ 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 (is_gtypeinstance && f.access == SymbolAccessibility.PRIVATE) {
+ lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ());
+ } else {
+ lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), 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 ("(*self)");
+ } else {
+ this_access.ccodenode = new CCodeIdentifier ("self");
+ }
+
+ 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);
+
+ if (f.initializer != null) {
+ var rhs = (CCodeExpression) f.initializer.ccodenode;
+ if (!is_constant_ccode_expression (rhs)) {
+ if (f.parent_symbol is Class) {
+ class_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, rhs)));
+
+ append_temp_decl (class_init_fragment, temp_vars);
+ temp_vars.clear ();
+ } else {
+ f.error = true;
+ Report.error (f.source_reference, "Non-constant field initializers not supported in this context");
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ 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, Map<int,CCodeFormalParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
+ }
+
+ 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;
+ } else if (local.variable_type.is_reference_type_or_type_parameter ()) {
+ rhs = new CCodeConstant ("NULL");
+ }
+
+ 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);
+ }
+
+ 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_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 && !in_creation_method) {
+ return new CCodeMemberAccess.pointer (new CCodeIdentifier ("%s_GET_PRIVATE (self)".printf (type.type_parameter.parent_symbol.get_lower_case_cname ().up ())), var_name);
+ } else {
+ return new CCodeIdentifier (var_name);
+ }
+ } else {
+ return new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (type.data_type.get_lower_case_cname ())));
+ }
+ }
+
+ 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 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_destroy_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 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) {
+ 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));
+
+ 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 (((Gee.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, Gee.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.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;
+ } 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");
+ }
+
+ 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 (((Gee.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, Gee.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 virtual bool variable_accessible_in_finally (LocalVariable local) {
+ if (current_try == null) {
+ return false;
+ }
+
+ var sym = current_symbol;
+
+ while (!(sym is Method) && sym.scope.lookup (local.name) == null) {
+ if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) ||
+ (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) {
+
+ return true;
+ }
+
+ sym = sym.parent_symbol;
+ }
+
+ return false;
+ }
+
+ public override void visit_return_statement (ReturnStatement stmt) {
+ // avoid unnecessary ref/unref pair
+ if (stmt.return_expression != null) {
+ var local = stmt.return_expression.symbol_reference as LocalVariable;
+ if (current_return_type.value_owned
+ && local != null && local.variable_type.value_owned && !variable_accessible_in_finally (local)) {
+ /* return expression is local variable taking ownership and
+ * current method is transferring ownership */
+
+ // don't ref expression
+ stmt.return_expression.value_type.value_owned = true;
+ }
+ }
+
+ stmt.accept_children (codegen);
+
+ if (stmt.return_expression == null) {
+ var cfrag = new CCodeFragment ();
+
+ // free local variables
+ append_local_free (current_symbol, cfrag);
+
+ cfrag.append (new CCodeReturnStatement ());
+
+ stmt.ccodenode = cfrag;
+ } else {
+ Symbol return_expression_symbol = null;
+
+ // avoid unnecessary ref/unref pair
+ var local = stmt.return_expression.symbol_reference as LocalVariable;
+ if (current_return_type.value_owned
+ && local != null && local.variable_type.value_owned && !variable_accessible_in_finally (local)) {
+ /* return expression is local variable taking ownership and
+ * current method is transferring ownership */
+
+ // don't unref variable
+ return_expression_symbol = local;
+ return_expression_symbol.active = false;
+ }
+
+ var cfrag = new CCodeFragment ();
+
+ // assign method result to `result'
+ cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), (CCodeExpression) stmt.return_expression.ccodenode)));
+
+ // free local variables
+ append_local_free (current_symbol, cfrag);
+
+ cfrag.append (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+
+ stmt.ccodenode = cfrag;
+
+ create_temp_decl (stmt, stmt.return_expression.temp_vars);
+
+ if (return_expression_symbol != null) {
+ return_expression_symbol.active = true;
+ }
+ }
+ }
+
+ 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 ("self"), 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 (&expr, &temp), 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, cexpr));
+ copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
+
+ 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, Gee.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 (new CCodeIdentifier ("%s_GET_PRIVATE (self)".printf (generic_type.type_parameter.parent_symbol.get_lower_case_cname ().up ())), 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) {
+ 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);
+ }
+
+ var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+
+ bool ellipsis = false;
+
+ int i = 1;
+ int arg_pos;
+ 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);
+ }
+
+ arg_pos = get_param_pos (param.cparameter_position, ellipsis);
+ } else {
+ // default argument position
+ arg_pos = get_param_pos (i, ellipsis);
+ }
+
+ carg_map.set (arg_pos, 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);
+
+ carg_map.set (get_param_pos (param.cparameter_position), (CCodeExpression) param.default_expression.ccodenode);
+ i++;
+ }
+
+ // append C arguments in the right order
+ int last_pos = -1;
+ int min_pos;
+ while (true) {
+ min_pos = -1;
+ foreach (int pos in carg_map.get_keys ()) {
+ if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+ min_pos = pos;
+ }
+ }
+ if (min_pos == -1) {
+ break;
+ }
+ creation_call.add_argument (carg_map.get (min_pos));
+ last_pos = min_pos;
+ }
+
+ 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) {
+ // pass non-simple struct instances always by reference
+ if (!(arg.value_type is NullType) && param.parameter_type.data_type is Struct && !((Struct) param.parameter_type.data_type).is_simple_type ()) {
+ // we already use a reference for arguments of ref, out, and nullable parameters
+ if (param.direction == ParameterDirection.IN && !param.parameter_type.nullable) {
+ 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 (param.parameter_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);
+
+ 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
+ && expression_type.floating_reference) {
+ /* floating reference, sink it.
+ */
+ var cl = expression_type.data_type as ObjectTypeSymbol;
+ var sink_func = (cl != null) ? cl.get_ref_sink_function () : null;
+
+ if (sink_func != null) {
+ var csink = new CCodeFunctionCall (new CCodeIdentifier (sink_func));
+ csink.add_argument (cexpr);
+
+ cexpr = csink;
+ } else {
+ Report.error (null, "type `%s' does not support floating references".printf (expression_type.data_type.name));
+ }
+ }
+
+ 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);
+
+ 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) {
+ var st = type.data_type as Struct;
+ var array_type = type as ArrayType;
+ 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 ());
+ } else if (type.type_parameter != null) {
+ return new CCodeConstant ("NULL");
+ }
+ return null;
+ }
+
+ public int get_param_pos (double param_pos, bool ellipsis = false) {
+ if (!ellipsis) {
+ if (param_pos >= 0) {
+ return (int) (param_pos * 1000);
+ } else {
+ return (int) ((100 + param_pos) * 1000);
+ }
+ } else {
+ if (param_pos >= 0) {
+ return (int) ((100 + param_pos) * 1000);
+ } else {
+ return (int) ((200 + param_pos) * 1000);
+ }
+ }
+ }
+
+ 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..fdb42e9
--- /dev/null
+++ b/codegen/valadovacontrolflowmodule.vala
@@ -0,0 +1,101 @@
+/* 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>
+ */
+
+using GLib;
+using Gee;
+
+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/valadovamemberaccessmodule.vala b/codegen/valadovamemberaccessmodule.vala
new file mode 100644
index 0000000..39def20
--- /dev/null
+++ b/codegen/valadovamemberaccessmodule.vala
@@ -0,0 +1,265 @@
+/* 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;
+ }
+ }
+
+ if (prop.get_accessor.automatic_body &&
+ current_type_symbol == prop.parent_symbol &&
+ prop.base_property == null &&
+ prop.base_interface_property == null) {
+ var priv_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (((Class) prop.parent_symbol).get_upper_case_cname (null))));
+ priv_call.add_argument (pub_inst);
+ var inst = priv_call;
+ expr.ccodenode = new CCodeMemberAccess.pointer (inst, prop.field.get_cname());
+ } else {
+ 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"), "self");
+ } else {
+ var st = current_type_symbol as Struct;
+ if (st != null && (!st.is_simple_type () || current_method is CreationMethod)) {
+ expr.ccodenode = new CCodeIdentifier ("(*self)");
+ } else {
+ expr.ccodenode = new CCodeIdentifier ("self");
+ }
+ }
+ } 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..f4a5941
--- /dev/null
+++ b/codegen/valadovamethodcallmodule.vala
@@ -0,0 +1,270 @@
+/* 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>
+ */
+
+using GLib;
+using Gee;
+
+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;
+ Gee.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;
+ }
+
+ HashMap<int,CCodeExpression> in_arg_map, out_arg_map;
+
+ in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ out_arg_map = in_arg_map;
+
+ if (m is CreationMethod) {
+ var cl = (Class) m.parent_symbol;
+
+ if (cl == current_class) {
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ } else {
+ ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), cl.get_cname () + "*"));
+
+ foreach (DataType base_type in current_class.get_base_types ()) {
+ if (base_type.data_type is Class) {
+ add_generic_type_arguments (ccall, base_type.get_type_arguments (), expr, true);
+ break;
+ }
+ }
+ }
+ } else if (m != null) {
+ 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;
+
+ if (m is ArrayResizeMethod) {
+ var array_type = (ArrayType) ma.inner.value_type;
+ in_arg_map.set (get_param_pos (0), new CCodeIdentifier (array_type.element_type.get_cname ()));
+ }
+
+ CCodeExpression instance = null;
+ if (m != null && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) {
+ 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) {
+ in_arg_map.set (get_param_pos (m.cinstance_parameter_position), new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (((Class) current_class.base_class).get_lower_case_cname ()))));
+ in_arg_map.set (get_param_pos (m.cinstance_parameter_position + 0.01), instance);
+ } else {
+ in_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
+ out_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
+ }
+ }
+
+ bool ellipsis = false;
+
+ int i = 1;
+ int arg_pos;
+ Iterator<FormalParameter> params_it = params.iterator ();
+ foreach (Expression arg in expr.get_argument_list ()) {
+ CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
+
+ var carg_map = in_arg_map;
+
+ if (params_it.next ()) {
+ var param = params_it.get ();
+ ellipsis = param.params_array || param.ellipsis;
+ if (!ellipsis) {
+ if (param.direction == ParameterDirection.OUT) {
+ carg_map = out_arg_map;
+ }
+
+ 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);
+ }
+ }
+ arg_pos = get_param_pos (param.cparameter_position, ellipsis);
+ } else {
+ // default argument position
+ arg_pos = get_param_pos (i, ellipsis);
+ }
+
+ carg_map.set (arg_pos, 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 (ellipsis) {
+ /* ensure variable argument list ends with NULL
+ * except when using printf-style arguments */
+ if (!m.printf_format && !m.scanf_format && m.sentinel != "") {
+ in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (m.sentinel));
+ }
+ }
+
+ // append C arguments in the right order
+
+ int last_pos = -1;
+ int min_pos;
+ while (true) {
+ min_pos = -1;
+ foreach (int pos in out_arg_map.get_keys ()) {
+ if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+ min_pos = pos;
+ }
+ }
+ if (min_pos == -1) {
+ break;
+ }
+ ccall.add_argument (out_arg_map.get (min_pos));
+ last_pos = min_pos;
+ }
+
+ expr.ccodenode = ccall_expr;
+ }
+}
+
diff --git a/codegen/valadovamethodmodule.vala b/codegen/valadovamethodmodule.vala
new file mode 100644
index 0000000..b01841f
--- /dev/null
+++ b/codegen/valadovamethodmodule.vala
@@ -0,0 +1,84 @@
+/* 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>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * 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;
+ }
+
+ public virtual void generate_parameter (FormalParameter param, CCodeDeclarationSpace decl_space, Map<int,CCodeFormalParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
+ if (!param.ellipsis) {
+ string ctypename = param.parameter_type.get_cname ();
+
+ generate_type_declaration (param.parameter_type, decl_space);
+
+ // pass non-simple structs always by reference
+ if (param.parameter_type.data_type is Struct) {
+ var st = (Struct) param.parameter_type.data_type;
+ if (!st.is_simple_type () && param.direction == ParameterDirection.IN) {
+ if (st.use_const && !param.parameter_type.value_owned) {
+ ctypename = "const " + ctypename;
+ }
+
+ if (!param.parameter_type.nullable) {
+ ctypename += "*";
+ }
+ }
+ }
+
+ if (param.direction != ParameterDirection.IN && !(param.parameter_type is GenericType)) {
+ ctypename += "*";
+ }
+
+ param.ccodenode = new CCodeFormalParameter (get_variable_cname (param.name), ctypename);
+ } else {
+ param.ccodenode = new CCodeFormalParameter.with_ellipsis ();
+ }
+
+ cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
+ if (carg_map != null && !param.ellipsis) {
+ carg_map.set (get_param_pos (param.cparameter_position), get_variable_cexpression (param.name));
+ }
+ }
+}
+
diff --git a/codegen/valadovaobjectmodule.vala b/codegen/valadovaobjectmodule.vala
new file mode 100644
index 0000000..ae1b5d6
--- /dev/null
+++ b/codegen/valadovaobjectmodule.vala
@@ -0,0 +1,1142 @@
+/* valadovaobjectmodule.vala
+ *
+ * Copyright (C) 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 Gee;
+
+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;
+ }
+
+ decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (cl.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);
+ }
+
+ 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 *");
+ 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 *"));
+ 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);
+ var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+ generate_cparameters (m, decl_space, cparam_map, 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 (TypeParameter type_param in cl.get_type_parameters ()) {
+ instance_priv_struct.add_field ("DovaType *", "%s_type".printf (type_param.name.down ()));
+ }
+
+ 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_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 (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 ("self", 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 = "((%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_object_offset".printf (cl.get_lower_case_cname ()), new CCodeConstant ("0")));
+ cdecl.modifiers = CCodeModifiers.STATIC;
+ decl_space.add_type_member_declaration (cdecl);
+
+ 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));
+ }
+
+ public override void visit_class (Class cl) {
+ var old_symbol = current_symbol;
+ current_symbol = cl;
+
+ 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);
+
+ 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 *");
+ type_fun.block = new CCodeBlock ();
+
+ var type_init_block = new CCodeBlock ();
+
+ if (cl.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_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);
+
+ var base_type = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (cl.base_class.get_lower_case_cname ())));
+
+ 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 (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, base_type_size, new CCodeConstant ("sizeof (%sTypePrivate)".printf (cl.get_cname ()))));
+
+ type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())), calloc_call)));
+
+ generate_class_declaration (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 base_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_object_size"));
+ base_size.add_argument (base_type);
+
+ type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_%s_object_offset".printf (cl.get_lower_case_cname ())), base_size)));
+
+ var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+ sizeof_call.add_argument (new CCodeIdentifier ("%sPrivate".printf (cl.get_cname ())));
+ 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 (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, base_size, sizeof_call));
+ type_init_block.add_statement (new CCodeExpressionStatement (set_size));
+
+ type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_%s_type_offset".printf (cl.get_lower_case_cname ())), base_type_size)));
+
+ sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+ sizeof_call.add_argument (new CCodeIdentifier ("%sTypePrivate".printf (cl.get_cname ())));
+ 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 CCodeBinaryExpression (CCodeBinaryOperator.PLUS, base_type_size, sizeof_call));
+ 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 ();
+
+ if (cl.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 ref_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_ref"));
+ ref_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, src));
+ function.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), ref_call)));
+
+ source_type_member_definition.append (function);
+ } else {
+ type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (cl.base_class.get_lower_case_cname ())));
+ type_init_call.add_argument (new CCodeIdentifier ("type"));
+ type_init_fun.block.add_statement (new CCodeExpressionStatement (type_init_call));
+ }
+
+ foreach (DataType base_type in cl.get_base_types ()) {
+ 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));
+ }
+ }
+
+ 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_fun.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_fun.block.add_statement (new CCodeExpressionStatement (override_call));
+ }
+ }
+
+ source_type_member_definition.append (type_init_fun);
+
+ cl.accept_children (codegen);
+
+ 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"));
+
+ source_declarations.add_type_member_declaration (value_copy_function.copy ());
+
+ 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 ());
+ }
+
+ current_symbol = old_symbol;
+ }
+
+ 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 (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);
+
+ 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 *");
+ 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 ())));
+ 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 *"));
+ 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 add_interface_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_add_interface"));
+ add_interface_call.add_argument (new CCodeIdentifier ("type"));
+ add_interface_call.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (iface.get_lower_case_cname ()))));
+ 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 ("self", 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 ("self", 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 ("self")));
+
+ if (acc.readable) {
+ var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
+ vcall.add_argument (new CCodeIdentifier ("self"));
+ 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 ("self"));
+ 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"));
+ function.block.prepend_statement (cdecl);
+ }
+
+ 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;
+ }
+
+ decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), 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 *");
+ 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 *"));
+ 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;
+ }
+ }
+
+ var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+ var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+
+ generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, 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 *self".printf (((ObjectTypeSymbol) m.parent_symbol).get_cname ());
+ foreach (var param in m.get_parameters ()) {
+ param_list += ", ";
+ param_list += param.parameter_type.get_cname ();
+ }
+ 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.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;
+ }
+
+ cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+ generate_cparameters (m, decl_space, cparam_map, 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");
+ }
+
+ 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 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;
+
+ var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+ generate_cparameters (m, source_declarations, cparam_map, 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)) {
+ var cdecl = new CCodeDeclaration (m.return_type.get_cname ());
+ cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
+ cinit.append (cdecl);
+ }
+
+ if (m is CreationMethod && m.parent_symbol == current_class && current_class.base_class != null && current_class.base_class.get_full_name () != "Dova.Value") {
+ foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
+ var priv_access = new CCodeIdentifier ("%s_GET_PRIVATE (self)".printf (current_class.get_upper_case_cname ()));
+
+ var param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
+ var assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
+ cinit.append (new CCodeExpressionStatement (assign));
+ }
+ }
+
+ 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.get_cname ());
+ vfunc.block = new CCodeBlock ();
+
+ vfunc.add_parameter (new CCodeFormalParameter ("self", "%s *".printf (((ObjectTypeSymbol) m.parent_symbol).get_cname ())));
+ foreach (FormalParameter param in m.get_parameters ()) {
+ vfunc.add_parameter (new CCodeFormalParameter (param.name, param.parameter_type.get_cname ()));
+ }
+
+ var vcast = get_type_private_from_type ((ObjectTypeSymbol) m.parent_symbol, get_type_from_instance (new CCodeIdentifier ("self")));
+
+ var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, m.vfunc_name));
+ vcall.add_argument (new CCodeIdentifier ("self"));
+ foreach (FormalParameter param in m.get_parameters ()) {
+ vcall.add_argument (new CCodeIdentifier (param.name));
+ }
+ 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.get_cname ());
+ vfunc.block = new CCodeBlock ();
+
+ vfunc.add_parameter (new CCodeFormalParameter ("base_type", "DovaType *"));
+ vfunc.add_parameter (new CCodeFormalParameter ("self", "%s *".printf (((ObjectTypeSymbol) m.parent_symbol).get_cname ())));
+ foreach (FormalParameter param in m.get_parameters ()) {
+ vfunc.add_parameter (new CCodeFormalParameter (param.name, param.parameter_type.get_cname ()));
+ }
+
+ 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 ("self"));
+ foreach (FormalParameter param in m.get_parameters ()) {
+ vcall.add_argument (new CCodeIdentifier (param.name));
+ }
+ 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 *self".printf (((ObjectTypeSymbol) m.parent_symbol).get_cname ());
+ foreach (var param in m.get_parameters ()) {
+ param_list += ", ";
+ param_list += param.parameter_type.get_cname ();
+ }
+ 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.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 main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
+ if (m.get_parameters ().size == 1) {
+ main_call.add_argument (new CCodeIdentifier ("argv"));
+ main_call.add_argument (new CCodeIdentifier ("argc"));
+ }
+ 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 ();
+ }
+
+ if (current_type_symbol is Class) {
+ var vfunc = new CCodeFunction (m.get_cname ());
+
+ var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+ var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+
+ var vblock = new CCodeBlock ();
+
+ var cdecl = new CCodeDeclaration ("%s *".printf (current_type_symbol.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator ("self"));
+ vblock.add_statement (cdecl);
+
+ source_declarations.add_include ("stddef.h");
+
+ var alloc_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_alloc"));
+ alloc_call.add_argument (new CCodeFunctionCall (new CCodeIdentifier (current_class.get_lower_case_cname () + "_type_get")));
+ vblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("self"), new CCodeCastExpression (alloc_call, "%s *".printf (current_type_symbol.get_cname ())))));
+
+ var vcall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
+ vcall.add_argument (new CCodeIdentifier ("self"));
+ vblock.add_statement (new CCodeExpressionStatement (vcall));
+
+ generate_cparameters (m, source_declarations, cparam_map, vfunc, null, carg_map, vcall);
+ CCodeStatement cstmt = new CCodeReturnStatement (new CCodeIdentifier ("self"));
+ 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, Map<int,CCodeFormalParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
+ if (m.parent_symbol is Class && m is CreationMethod) {
+ if (vcall == null) {
+ var instance_param = new CCodeFormalParameter ("self", ((Class) m.parent_symbol).get_cname () + "*");
+ cparam_map.set (get_param_pos (m.cinstance_parameter_position), instance_param);
+ }
+ } else if (m.binding == MemberBinding.INSTANCE || (m.parent_symbol is Struct && m is CreationMethod)) {
+ TypeSymbol parent_type = find_parent_type (m);
+ DataType this_type;
+ if (parent_type is Class) {
+ this_type = new ObjectType ((Class) parent_type);
+ } else if (parent_type is Interface) {
+ this_type = new ObjectType ((Interface) parent_type);
+ } else if (parent_type is Struct) {
+ this_type = new StructValueType ((Struct) parent_type);
+ } else if (parent_type is Enum) {
+ this_type = new EnumValueType ((Enum) parent_type);
+ } else {
+ assert_not_reached ();
+ }
+
+ generate_type_declaration (this_type, decl_space);
+
+ CCodeFormalParameter instance_param = null;
+ 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 ("self", 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 ("self", base_type.get_cname ());
+ } else {
+ if (m.parent_symbol is Struct && m is CreationMethod) {
+ instance_param = new CCodeFormalParameter ("*self", this_type.get_cname ());
+ } else {
+ instance_param = new CCodeFormalParameter ("self", this_type.get_cname ());
+ }
+ }
+ cparam_map.set (get_param_pos (m.cinstance_parameter_position), instance_param);
+ }
+
+ if (m is 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 ()) {
+ cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "DovaType*"));
+ if (carg_map != null) {
+ carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
+ }
+ type_param_index++;
+ }
+ }
+ }
+
+ foreach (FormalParameter param in m.get_parameters ()) {
+ if (param.direction != ParameterDirection.OUT) {
+ if ((direction & 1) == 0) {
+ // no in paramters
+ continue;
+ }
+ } else {
+ if ((direction & 2) == 0) {
+ // no out paramters
+ continue;
+ }
+ }
+
+ generate_parameter (param, decl_space, cparam_map, carg_map);
+ }
+
+ if ((direction & 2) != 0) {
+ if (m.parent_symbol is Class && m is CreationMethod && vcall != null) {
+ func.return_type = ((Class) m.parent_symbol).get_cname () + "*";
+ } else {
+ func.return_type = m.return_type.get_cname ();
+
+ generate_type_declaration (m.return_type, decl_space);
+ }
+ }
+
+ // append C parameters in the right order
+ int last_pos = -1;
+ int min_pos;
+ while (true) {
+ min_pos = -1;
+ foreach (int pos in cparam_map.get_keys ()) {
+ if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+ min_pos = pos;
+ }
+ }
+ if (min_pos == -1) {
+ break;
+ }
+ func.add_parameter (cparam_map.get (min_pos));
+ if (vdeclarator != null) {
+ vdeclarator.add_parameter (cparam_map.get (min_pos));
+ }
+ if (vcall != null) {
+ var arg = carg_map.get (min_pos);
+ if (arg != null) {
+ vcall.add_argument (arg);
+ }
+ }
+ last_pos = min_pos;
+ }
+ }
+
+ 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);
+
+ Gee.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..218634e
--- /dev/null
+++ b/codegen/valadovastructmodule.vala
@@ -0,0 +1,90 @@
+/* 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.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_floating_type ()) {
+ // typedef for 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..ae9bffc
--- /dev/null
+++ b/codegen/valadovavaluemodule.vala
@@ -0,0 +1,331 @@
+/* valadovavaluemodule.vala
+ *
+ * Copyright (C) 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 Gee;
+
+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 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);
+
+ 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));
+
+ 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"));
+
+ if (st.get_fields ().size == 0) {
+ cblock.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);
+ 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);
+ }
+ var dest_field = new CCodeMemberAccess.pointer (dest, f.name);
+
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dest_field, copy)));
+ }
+ }
+ }
+
+ 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");
+
+ var dest_ea = dest as ElementAccess;
+ var src_ea = src as ElementAccess;
+
+ if (dest_ea != null) {
+ dest = dest_ea.container;
+ var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
+ data_call.add_argument ((CCodeExpression) get_ccodenode (dest));
+ cdest = data_call;
+ 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 data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
+ data_call.add_argument ((CCodeExpression) get_ccodenode (src));
+ csrc = data_call;
+ 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"));
+ ccall.add_argument (new CCodeIdentifier ("%s_GET_PRIVATE (self)->%s_type".printf (generic_type.type_parameter.parent_symbol.get_lower_case_cname ().up (), 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;
+ }
+}
diff --git a/compiler/valacompiler.vala b/compiler/valacompiler.vala
index 75a46f8..82e9b70 100644
--- a/compiler/valacompiler.vala
+++ b/compiler/valacompiler.vala
@@ -68,6 +68,7 @@ class Vala.Compiler {
static bool quiet_mode;
static bool verbose_mode;
static string profile;
+ static bool nostdpkg;
private CodeContext context;
@@ -90,6 +91,7 @@ class Vala.Compiler {
{ "debug", 'g', 0, OptionArg.NONE, ref debug, "Produce debug information", null },
{ "thread", 0, 0, OptionArg.NONE, ref thread, "Enable multithreading support", null },
{ "define", 'D', 0, OptionArg.STRING_ARRAY, ref defines, "Define SYMBOL", "SYMBOL..." },
+ { "nostdpkg", 0, 0, OptionArg.NONE, ref nostdpkg, "Do not include standard packages", null },
{ "disable-assert", 0, 0, OptionArg.NONE, ref disable_assert, "Disable assertions", null },
{ "enable-checking", 0, 0, OptionArg.NONE, ref enable_checking, "Enable additional run-time checks", null },
{ "enable-deprecated", 0, 0, OptionArg.NONE, ref deprecated, "Enable deprecated features", null },
@@ -213,6 +215,9 @@ class Vala.Compiler {
context.profile = Profile.GOBJECT;
context.add_define ("GOBJECT");
context.add_define ("VALA_0_7_6_NEW_METHODS");
+ } else if (profile == "dova") {
+ context.profile = Profile.DOVA;
+ context.add_define ("DOVA");
} else {
Report.error (null, "Unknown profile %s".printf (profile));
}
@@ -224,9 +229,11 @@ class Vala.Compiler {
}
if (context.profile == Profile.POSIX) {
- /* default package */
- if (!add_package (context, "posix")) {
- Report.error (null, "posix not found in specified Vala API directories");
+ if (!nostdpkg) {
+ /* default package */
+ if (!add_package (context, "posix")) {
+ Report.error (null, "posix not found in specified Vala API directories");
+ }
}
} else if (context.profile == Profile.GOBJECT) {
int glib_major = 2;
@@ -241,12 +248,21 @@ class Vala.Compiler {
Report.error (null, "This version of valac only supports GLib 2");
}
- /* default packages */
- if (!add_package (context, "glib-2.0")) {
- Report.error (null, "glib-2.0 not found in specified Vala API directories");
+ if (!nostdpkg) {
+ /* default packages */
+ if (!add_package (context, "glib-2.0")) {
+ Report.error (null, "glib-2.0 not found in specified Vala API directories");
+ }
+ if (!add_package (context, "gobject-2.0")) {
+ Report.error (null, "gobject-2.0 not found in specified Vala API directories");
+ }
}
- if (!add_package (context, "gobject-2.0")) {
- Report.error (null, "gobject-2.0 not found in specified Vala API directories");
+ } else if (context.profile == Profile.DOVA) {
+ if (!nostdpkg) {
+ /* default package */
+ if (!add_package (context, "dova-core-0.1")) {
+ Report.error (null, "dova-core-0.1 not found in specified Vala API directories");
+ }
}
}
@@ -277,6 +293,9 @@ class Vala.Compiler {
} else if (context.profile == Profile.GOBJECT) {
// import the GLib namespace by default (namespace of backend-specific standard library)
source_file.add_using_directive (new UsingDirective (new UnresolvedSymbol (null, "GLib", null)));
+ } else if (context.profile == Profile.DOVA) {
+ // import the Dova namespace by default (namespace of backend-specific standard library)
+ source_file.add_using_directive (new UsingDirective (new UnresolvedSymbol (null, "Dova", null)));
}
context.add_source_file (source_file);
diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala
index 54f5890..558cb25 100644
--- a/vala/valabinaryexpression.vala
+++ b/vala/valabinaryexpression.vala
@@ -214,6 +214,14 @@ public class Vala.BinaryExpression : Expression {
&& operator == BinaryOperator.PLUS) {
// string concatenation
+ if (analyzer.context.profile == Profile.DOVA) {
+ var concat_call = new MethodCall (new MemberAccess (left, "concat"));
+ concat_call.add_argument (right);
+ concat_call.target_type = target_type;
+ parent_node.replace_expression (this, concat_call);
+ return concat_call.check (analyzer);
+ }
+
if (right.value_type == null || right.value_type.data_type != analyzer.string_type.data_type) {
error = true;
Report.error (source_reference, "Operands must be strings");
diff --git a/vala/valacreationmethod.vala b/vala/valacreationmethod.vala
index 79cfa8e..f7e8ba3 100644
--- a/vala/valacreationmethod.vala
+++ b/vala/valacreationmethod.vala
@@ -114,6 +114,10 @@ public class Vala.CreationMethod : Method {
string infix = "construct";
+ if (CodeContext.get ().profile == Profile.DOVA) {
+ infix = "init";
+ }
+
if (name == ".new") {
return "%s%s".printf (parent.get_lower_case_cprefix (), infix);
} else {
diff --git a/vala/valagenerictype.vala b/vala/valagenerictype.vala
index aca48a3..d2fb656 100644
--- a/vala/valagenerictype.vala
+++ b/vala/valagenerictype.vala
@@ -1,6 +1,6 @@
/* valagenerictype.vala
*
- * Copyright (C) 2008 Jürg Billeter
+ * Copyright (C) 2008-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
@@ -43,11 +43,15 @@ public class Vala.GenericType : DataType {
}
public override string? get_cname () {
+ if (CodeContext.get ().profile == Profile.GOBJECT) {
if (value_owned) {
return "gpointer";
} else {
return "gconstpointer";
}
+ } else {
+ return "void *";
+ }
}
public override string? get_type_id () {
diff --git a/vala/valaintegerliteral.vala b/vala/valaintegerliteral.vala
index 95fd132..6a84131 100644
--- a/vala/valaintegerliteral.vala
+++ b/vala/valaintegerliteral.vala
@@ -94,6 +94,13 @@ public class Vala.IntegerLiteral : Literal {
} else {
return "long";
}
+ } else if (CodeContext.get ().profile == Profile.DOVA) {
+ // long is 64-bit in Dova profile
+ if (u) {
+ return "ulong";
+ } else {
+ return "long";
+ }
} else {
if (u) {
return "uint64";
diff --git a/vala/valaprofile.vala b/vala/valaprofile.vala
index c3d5591..0b3de8d 100644
--- a/vala/valaprofile.vala
+++ b/vala/valaprofile.vala
@@ -22,5 +22,6 @@
public enum Vala.Profile {
POSIX,
- GOBJECT
+ GOBJECT,
+ DOVA
}
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 032cc4b..95783b1 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -145,16 +145,19 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
- uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
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"));
- int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
+ if (context.profile != Profile.DOVA) {
+ uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
+ int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
+ }
+
var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
if (unichar_struct != null) {
unichar_type = new IntegerType (unichar_struct);
diff --git a/vala/valastruct.vala b/vala/valastruct.vala
index 17ed9ec..b22893e 100644
--- a/vala/valastruct.vala
+++ b/vala/valastruct.vala
@@ -629,6 +629,9 @@ public class Vala.Struct : TypeSymbol {
// used by time_t
return false;
}
+ if (CodeContext.get ().profile == Profile.DOVA) {
+ return true;
+ }
return (boolean_type || integer_type || floating_type
|| get_attribute ("SimpleType") != null);
}
diff --git a/vala/valasymbolresolver.vala b/vala/valasymbolresolver.vala
index 24612f1..e99e61f 100644
--- a/vala/valasymbolresolver.vala
+++ b/vala/valasymbolresolver.vala
@@ -32,6 +32,7 @@ public class Vala.SymbolResolver : CodeVisitor {
Symbol root_symbol;
Scope current_scope;
Gee.List<UsingDirective> current_using_directives;
+ CodeContext context;
/**
* Resolve symbol names in the specified code context.
@@ -39,6 +40,7 @@ public class Vala.SymbolResolver : CodeVisitor {
* @param context a code context
*/
public void resolve (CodeContext context) {
+ this.context = context;
root_symbol = context.root;
current_scope = root_symbol.scope;
@@ -75,6 +77,17 @@ public class Vala.SymbolResolver : CodeVisitor {
}
}
+ if (context.profile == Profile.DOVA) {
+ // all classes derive from Object
+ if (cl.base_class == null) {
+ var object_class = (Class) root_symbol.scope.lookup ("Dova").scope.lookup ("Object");
+ if (cl != object_class) {
+ cl.add_base_type (new ObjectType (object_class));
+ cl.base_class = object_class;
+ }
+ }
+ }
+
current_scope = current_scope.parent_scope;
}
@@ -352,7 +365,10 @@ public class Vala.SymbolResolver : CodeVisitor {
public override void visit_local_variable (LocalVariable local) {
local.accept_children (this);
if (local.variable_type is ReferenceType) {
- local.variable_type.nullable = true;
+ var array_type = local.variable_type as ArrayType;
+ if (array_type == null || !array_type.fixed_length) {
+ local.variable_type.nullable = true;
+ }
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]