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
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
));
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
) {
39 m
= ((MethodType
) itype
).method_symbol
;
40 } else if (itype is ObjectType
) {
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"));
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
) {
75 instance
= unary
.inner
;
76 } else if (instance is CCodeIdentifier
|| instance is CCodeMemberAccess
) {
77 instance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
);
79 // if instance is e.g. a function call, we can't take the address of the expression
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
)));
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;
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
;
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
);
149 LocalVariable ret_temp_var
= null;
150 if (itype
.get_return_type () is VoidType
) {
151 ccomma
.append_expression (ccall_expr
);
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
)));
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
));
171 ccomma
.append_expression (new
CCodeAssignment (get_cvalue (unary
.inner
), cassign_comma
));
174 if (!(itype
.get_return_type () is VoidType
)) {
175 ccomma
.append_expression (get_variable_cexpression (ret_temp_var
.name
));
181 if (param
.ctype
!= null) {
182 cexpr
= new
CCodeCastExpression (cexpr
, param
.ctype
);
187 ccall
.add_argument (cexpr
);
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
);
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
));
210 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
)));
214 ccomma
.append_expression (ccall_expr
);
216 ccomma
.append_expression (get_variable_cexpression (temp_var
.name
));
221 if (expr
.parent_node is ExpressionStatement
) {
222 ccode
.add_expression (ccall_expr
);
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
);