codegen: Fix array size variable on assignment
[vala-lang.git] / codegen / valadovamethodcallmodule.vala
blobbb5d4702fa64e4d93e14cd709d589a9cd601ec20
1 /* valadovamethodcallmodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 public class Vala.DovaMethodCallModule : DovaAssignmentModule {
24 public override void visit_method_call (MethodCall expr) {
25 // the bare function call
26 var ccall = new CCodeFunctionCall (get_cvalue (expr.call));
28 Method m = null;
29 Delegate deleg = null;
30 List<Parameter> params;
32 var ma = expr.call as MemberAccess;
34 var itype = expr.call.value_type;
35 params = itype.get_parameters ();
37 if (itype is MethodType) {
38 assert (ma != null);
39 m = ((MethodType) itype).method_symbol;
40 } else if (itype is ObjectType) {
41 // constructor
42 var cl = (Class) ((ObjectType) itype).type_symbol;
43 m = cl.default_construction_method;
44 generate_method_declaration (m, cfile);
45 ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
46 } else if (itype is DelegateType) {
47 deleg = ((DelegateType) itype).delegate_symbol;
48 ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_invoke".printf (deleg.get_lower_case_cname ())));
49 ccall.add_argument (get_cvalue (expr.call));
52 if (m is CreationMethod) {
53 var cl = (Class) m.parent_symbol;
55 if (cl == current_class) {
56 ccall.add_argument (new CCodeIdentifier ("this"));
57 } else {
58 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("this"), cl.get_cname () + "*"));
60 } else if (m != null) {
61 if (m.binding == MemberBinding.INSTANCE) {
62 var instance = get_cvalue (ma.inner);
64 if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
65 var inner_ma = (MemberAccess) ma.inner;
66 instance = get_cvalue (inner_ma.inner);
69 var st = m.parent_symbol as Struct;
70 if (st != null && !st.is_simple_type ()) {
71 // we need to pass struct instance by reference
72 var unary = instance as CCodeUnaryExpression;
73 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
74 // *expr => expr
75 instance = unary.inner;
76 } else if (instance is CCodeIdentifier || instance is CCodeMemberAccess) {
77 instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance);
78 } else {
79 // if instance is e.g. a function call, we can't take the address of the expression
80 // (tmp = expr, &tmp)
81 var ccomma = new CCodeCommaExpression ();
83 var temp_var = get_temp_variable (ma.inner.target_type);
84 emit_temp_var (temp_var);
85 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), instance));
86 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name)));
88 instance = ccomma;
92 if (ma.inner is BaseAccess) {
93 ccall.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (((Class) current_class.base_class).get_lower_case_cname ()))));
95 ccall.add_argument (instance);
98 if (m.binding != MemberBinding.INSTANCE && m.parent_symbol is ObjectTypeSymbol) {
99 // support static methods in generic types
100 var type_symbol = (ObjectTypeSymbol) m.parent_symbol;
101 if (type_symbol.get_type_parameters ().size > 0 && ma.inner is MemberAccess) {
102 var type_ma = (MemberAccess) ma.inner;
103 add_generic_type_arguments (ccall, type_ma.get_type_arguments (), expr);
106 if (m.get_type_parameters ().size > 0) {
107 add_generic_type_arguments (ccall, ma.get_type_arguments (), expr);
111 // the complete call expression, might include casts, comma expressions, and/or assignments
112 CCodeExpression ccall_expr = ccall;
114 bool ellipsis = false;
116 int i = 1;
117 Iterator<Parameter> params_it = params.iterator ();
118 foreach (Expression arg in expr.get_argument_list ()) {
119 CCodeExpression cexpr = get_cvalue (arg);
121 if (params_it.next ()) {
122 var param = params_it.get ();
123 ellipsis = param.params_array || param.ellipsis;
124 if (!ellipsis) {
125 cexpr = handle_struct_argument (param, arg, cexpr);
127 // unref old value for non-null non-weak ref/out arguments
128 // disabled for arrays for now as that requires special handling
129 // (ret_tmp = call (&tmp), var1 = (assign_tmp = dup (tmp), free (var1), assign_tmp), ret_tmp)
130 if (param.direction != ParameterDirection.IN && requires_destroy (arg.value_type)
131 && (param.direction == ParameterDirection.OUT || !param.variable_type.value_owned)
132 && !(param.variable_type is ArrayType)) {
133 var unary = (UnaryExpression) arg;
135 var ccomma = new CCodeCommaExpression ();
137 var temp_var = get_temp_variable (param.variable_type, param.variable_type.value_owned);
138 emit_temp_var (temp_var);
139 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name));
141 if (param.direction == ParameterDirection.REF) {
142 var crefcomma = new CCodeCommaExpression ();
143 crefcomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), get_cvalue (unary.inner)));
144 crefcomma.append_expression (cexpr);
145 cexpr = crefcomma;
148 // call function
149 LocalVariable ret_temp_var = null;
150 if (itype.get_return_type () is VoidType) {
151 ccomma.append_expression (ccall_expr);
152 } else {
153 ret_temp_var = get_temp_variable (itype.get_return_type ());
154 emit_temp_var (ret_temp_var);
155 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (ret_temp_var.name), ccall_expr));
158 var cassign_comma = new CCodeCommaExpression ();
160 var assign_temp_var = get_temp_variable (unary.inner.value_type, unary.inner.value_type.value_owned);
161 emit_temp_var (assign_temp_var);
163 cassign_comma.append_expression (new CCodeAssignment (get_variable_cexpression (assign_temp_var.name), transform_expression (get_variable_cexpression (temp_var.name), param.variable_type, unary.inner.value_type, arg)));
165 // unref old value
166 cassign_comma.append_expression (get_unref_expression (get_cvalue (unary.inner), arg.value_type, arg));
168 cassign_comma.append_expression (get_variable_cexpression (assign_temp_var.name));
170 // assign new value
171 ccomma.append_expression (new CCodeAssignment (get_cvalue (unary.inner), cassign_comma));
173 // return value
174 if (!(itype.get_return_type () is VoidType)) {
175 ccomma.append_expression (get_variable_cexpression (ret_temp_var.name));
178 ccall_expr = ccomma;
181 if (param.ctype != null) {
182 cexpr = new CCodeCastExpression (cexpr, param.ctype);
187 ccall.add_argument (cexpr);
189 i++;
191 if (params_it.next ()) {
192 var param = params_it.get ();
194 /* if there are more parameters than arguments,
195 * the additional parameter is an ellipsis parameter
196 * otherwise there is a bug in the semantic analyzer
198 assert (param.params_array || param.ellipsis);
199 ellipsis = true;
202 if (itype.get_return_type () is GenericType) {
203 var ccomma = new CCodeCommaExpression ();
205 var temp_var = get_temp_variable (expr.value_type);
206 emit_temp_var (temp_var);
207 if (expr.value_type is GenericType) {
208 ccall.add_argument (get_variable_cexpression (temp_var.name));
209 } else {
210 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name)));
213 // call function
214 ccomma.append_expression (ccall_expr);
216 ccomma.append_expression (get_variable_cexpression (temp_var.name));
218 ccall_expr = ccomma;
221 if (expr.parent_node is ExpressionStatement) {
222 ccode.add_expression (ccall_expr);
223 } else {
224 var temp_var = get_temp_variable (expr.value_type);
225 var temp_ref = get_variable_cexpression (temp_var.name);
227 emit_temp_var (temp_var);
229 ccode.add_assignment (temp_ref, ccall_expr);
230 set_cvalue (expr, temp_ref);