Release 0.6.0
[vala-lang.git] / gobject / valaccodedelegatemodule.vala
bloba5a22b47e50a4ba68ce929b46f57681dde04d837
1 /* valaccodedelegatemodule.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using Gee;
27 /**
28 * The link between an assignment and generated code.
30 internal class Vala.CCodeDelegateModule : CCodeArrayModule {
31 public CCodeDelegateModule (CCodeGenerator codegen, CCodeModule? next) {
32 base (codegen, next);
35 public override void visit_delegate (Delegate d) {
36 d.accept_children (codegen);
38 var cfundecl = new CCodeFunctionDeclarator (d.get_cname ());
39 foreach (FormalParameter param in d.get_parameters ()) {
40 cfundecl.add_parameter ((CCodeFormalParameter) param.ccodenode);
42 // handle array parameters
43 if (!param.no_array_length && param.parameter_type is ArrayType) {
44 var array_type = (ArrayType) param.parameter_type;
46 var length_ctype = "int";
47 if (param.direction != ParameterDirection.IN) {
48 length_ctype = "int*";
51 for (int dim = 1; dim <= array_type.rank; dim++) {
52 var cparam = new CCodeFormalParameter (head.get_array_length_cname (param.name, dim), length_ctype);
53 cfundecl.add_parameter (cparam);
57 if (!d.no_array_length && d.return_type is ArrayType) {
58 // return array length if appropriate
59 var array_type = (ArrayType) d.return_type;
61 for (int dim = 1; dim <= array_type.rank; dim++) {
62 var cparam = new CCodeFormalParameter (head.get_array_length_cname ("result", dim), "int*");
63 cfundecl.add_parameter (cparam);
66 if (d.has_target) {
67 var cparam = new CCodeFormalParameter ("user_data", "void*");
68 cfundecl.add_parameter (cparam);
70 if (d.get_error_types ().size > 0) {
71 var cparam = new CCodeFormalParameter ("error", "GError**");
72 cfundecl.add_parameter (cparam);
75 var ctypedef = new CCodeTypeDefinition (d.return_type.get_cname (), cfundecl);
77 if (!d.is_internal_symbol ()) {
78 if (d.source_reference != null && d.source_reference.comment != null) {
79 header_declarations.add_type_declaration (new CCodeComment (d.source_reference.comment));
81 header_declarations.add_type_declaration (ctypedef);
82 } else {
83 if (d.source_reference != null && d.source_reference.comment != null) {
84 source_declarations.add_type_declaration (new CCodeComment (d.source_reference.comment));
86 source_declarations.add_type_declaration (ctypedef);
90 public override string get_delegate_target_cname (string delegate_cname) {
91 return "%s_target".printf (delegate_cname);
94 public override CCodeExpression get_delegate_target_cexpression (Expression delegate_expr) {
95 bool is_out = false;
97 if (delegate_expr is UnaryExpression) {
98 var unary_expr = (UnaryExpression) delegate_expr;
99 if (unary_expr.operator == UnaryOperator.OUT || unary_expr.operator == UnaryOperator.REF) {
100 delegate_expr = unary_expr.inner;
101 is_out = true;
105 if (delegate_expr is MethodCall) {
106 var invocation_expr = (MethodCall) delegate_expr;
107 return invocation_expr.delegate_target;
108 } else if (delegate_expr is LambdaExpression) {
109 if ((current_method != null && current_method.binding == MemberBinding.INSTANCE) || in_constructor) {
110 return new CCodeIdentifier ("self");
111 } else {
112 return new CCodeConstant ("NULL");
114 } else if (delegate_expr.symbol_reference != null) {
115 if (delegate_expr.symbol_reference is FormalParameter) {
116 var param = (FormalParameter) delegate_expr.symbol_reference;
117 CCodeExpression target_expr = new CCodeIdentifier (get_delegate_target_cname (param.name));
118 if (param.direction != ParameterDirection.IN) {
119 // accessing argument of out/ref param
120 target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
122 if (is_out) {
123 // passing array as out/ref
124 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
125 } else {
126 return target_expr;
128 } else if (delegate_expr.symbol_reference is LocalVariable) {
129 var local = (LocalVariable) delegate_expr.symbol_reference;
130 var target_expr = new CCodeIdentifier (get_delegate_target_cname (local.name));
131 if (is_out) {
132 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
133 } else {
134 return target_expr;
136 } else if (delegate_expr.symbol_reference is Field) {
137 var field = (Field) delegate_expr.symbol_reference;
138 var target_cname = get_delegate_target_cname (field.get_cname ());
140 var ma = (MemberAccess) delegate_expr;
142 CCodeExpression target_expr = null;
144 if (field.binding == MemberBinding.INSTANCE) {
145 var instance_expression_type = ma.inner.value_type;
146 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) field.parent_symbol);
148 var pub_inst = (CCodeExpression) get_ccodenode (ma.inner);
149 CCodeExpression typed_inst = transform_expression (pub_inst, instance_expression_type, instance_target_type);
151 CCodeExpression inst;
152 if (field.access == SymbolAccessibility.PRIVATE) {
153 inst = new CCodeMemberAccess.pointer (typed_inst, "priv");
154 } else {
155 inst = typed_inst;
157 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
158 target_expr = new CCodeMemberAccess.pointer (inst, target_cname);
159 } else {
160 target_expr = new CCodeMemberAccess (inst, target_cname);
162 } else {
163 target_expr = new CCodeIdentifier (target_cname);
166 if (is_out) {
167 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
168 } else {
169 return target_expr;
171 } else if (delegate_expr.symbol_reference is Method) {
172 var m = (Method) delegate_expr.symbol_reference;
173 var ma = (MemberAccess) delegate_expr;
174 if (m.binding == MemberBinding.STATIC) {
175 return new CCodeConstant ("NULL");
176 } else {
177 return (CCodeExpression) get_ccodenode (ma.inner);
182 return new CCodeConstant ("NULL");
185 public override string get_delegate_target_destroy_notify_cname (string delegate_cname) {
186 return "%s_target_destroy_notify".printf (delegate_cname);
189 public override CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
190 if (target_type is DelegateType && expression_type is MethodType) {
191 var dt = (DelegateType) target_type;
192 var mt = (MethodType) expression_type;
194 var method = mt.method_symbol;
195 if (method.base_method != null) {
196 method = method.base_method;
197 } else if (method.base_interface_method != null) {
198 method = method.base_interface_method;
201 return new CCodeIdentifier (generate_delegate_wrapper (method, dt.delegate_symbol));
202 } else {
203 return base.get_implicit_cast_expression (source_cexpr, expression_type, target_type, expr);
207 private string generate_delegate_wrapper (Method m, Delegate d) {
208 string delegate_name;
209 var sig = d.parent_symbol as Signal;
210 var dynamic_sig = sig as DynamicSignal;
211 if (dynamic_sig != null) {
212 delegate_name = head.get_dynamic_signal_cname (dynamic_sig);
213 } else if (sig != null) {
214 delegate_name = sig.parent_symbol.get_lower_case_cprefix () + sig.get_cname ();
215 } else {
216 delegate_name = Symbol.camel_case_to_lower_case (d.get_cname ());
219 string wrapper_name = "_%s_%s".printf (m.get_cname (), delegate_name);
221 if (!add_wrapper (wrapper_name)) {
222 // wrapper already defined
223 return wrapper_name;
226 // declaration
228 var function = new CCodeFunction (wrapper_name, m.return_type.get_cname ());
229 function.modifiers = CCodeModifiers.STATIC;
230 m.ccodenode = function;
232 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
234 if (d.has_target) {
235 var cparam = new CCodeFormalParameter ("self", "gpointer");
236 cparam_map.set (get_param_pos (d.cinstance_parameter_position), cparam);
239 var d_params = d.get_parameters ();
240 foreach (FormalParameter param in d_params) {
241 // ensure that C code node has been generated
242 param.accept (codegen);
244 cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
246 // handle array parameters
247 if (!param.no_array_length && param.parameter_type is ArrayType) {
248 var array_type = (ArrayType) param.parameter_type;
250 var length_ctype = "int";
251 if (param.direction != ParameterDirection.IN) {
252 length_ctype = "int*";
255 for (int dim = 1; dim <= array_type.rank; dim++) {
256 var cparam = new CCodeFormalParameter (head.get_array_length_cname (param.name, dim), length_ctype);
257 cparam_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
262 if (!d.no_array_length && d.return_type is ArrayType) {
263 // return array length if appropriate
264 var array_type = (ArrayType) d.return_type;
266 for (int dim = 1; dim <= array_type.rank; dim++) {
267 var cparam = new CCodeFormalParameter (head.get_array_length_cname ("result", dim), "int*");
268 cparam_map.set (get_param_pos (d.carray_length_parameter_position + 0.01 * dim), cparam);
272 if (m.get_error_types ().size > 0) {
273 var cparam = new CCodeFormalParameter ("error", "GError**");
274 cparam_map.set (get_param_pos (-1), cparam);
277 // append C parameters in the right order
278 int last_pos = -1;
279 int min_pos;
280 while (true) {
281 min_pos = -1;
282 foreach (int pos in cparam_map.get_keys ()) {
283 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
284 min_pos = pos;
287 if (min_pos == -1) {
288 break;
290 function.add_parameter (cparam_map.get (min_pos));
291 last_pos = min_pos;
295 // definition
297 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
299 int i = 0;
300 if (m.binding == MemberBinding.INSTANCE) {
301 CCodeExpression arg;
302 if (d.has_target) {
303 arg = new CCodeIdentifier ("self");
304 } else {
305 // use first delegate parameter as instance
306 arg = new CCodeIdentifier ((d_params.get (0).ccodenode as CCodeFormalParameter).name);
307 i = 1;
309 carg_map.set (get_param_pos (m.cinstance_parameter_position), arg);
312 foreach (FormalParameter param in m.get_parameters ()) {
313 CCodeExpression arg;
314 arg = new CCodeIdentifier ((d_params.get (i).ccodenode as CCodeFormalParameter).name);
315 carg_map.set (get_param_pos (param.cparameter_position), arg);
317 // handle array arguments
318 if (!param.no_array_length && param.parameter_type is ArrayType) {
319 var array_type = (ArrayType) param.parameter_type;
320 for (int dim = 1; dim <= array_type.rank; dim++) {
321 CCodeExpression clength;
322 if (d_params.get (i).array_null_terminated) {
323 requires_array_length = true;
324 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
325 len_call.add_argument (new CCodeIdentifier (d_params.get (i).name));
326 clength = len_call;
327 } else if (d_params.get (i).no_array_length) {
328 clength = new CCodeConstant ("-1");
329 } else {
330 clength = new CCodeIdentifier (head.get_array_length_cname (d_params.get (i).name, dim));
332 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), clength);
336 i++;
338 if (!m.no_array_length && m.return_type is ArrayType) {
339 var array_type = (ArrayType) m.return_type;
340 for (int dim = 1; dim <= array_type.rank; dim++) {
341 CCodeExpression clength;
342 if (d.no_array_length) {
343 clength = new CCodeConstant ("NULL");
344 } else {
345 clength = new CCodeIdentifier (head.get_array_length_cname ("result", dim));
347 carg_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), clength);
351 if (m.get_error_types ().size > 0) {
352 carg_map.set (get_param_pos (-1), new CCodeIdentifier ("error"));
355 var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
357 // append C arguments in the right order
358 last_pos = -1;
359 while (true) {
360 min_pos = -1;
361 foreach (int pos in carg_map.get_keys ()) {
362 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
363 min_pos = pos;
366 if (min_pos == -1) {
367 break;
369 ccall.add_argument (carg_map.get (min_pos));
370 last_pos = min_pos;
373 var block = new CCodeBlock ();
374 if (m.return_type is VoidType) {
375 block.add_statement (new CCodeExpressionStatement (ccall));
376 } else {
377 block.add_statement (new CCodeReturnStatement (ccall));
380 // append to file
382 source_declarations.add_type_member_declaration (function.copy ());
384 function.block = block;
385 source_type_member_definition.append (function);
387 return wrapper_name;
390 public override void generate_parameter (FormalParameter param, Map<int,CCodeFormalParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
391 if (!(param.parameter_type is DelegateType || param.parameter_type is MethodType)) {
392 base.generate_parameter (param, cparam_map, carg_map);
393 return;
396 cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
397 if (carg_map != null) {
398 carg_map.set (get_param_pos (param.cparameter_position), new CCodeIdentifier (param.name));
401 if (param.parameter_type is DelegateType) {
402 var deleg_type = (DelegateType) param.parameter_type;
403 var d = deleg_type.delegate_symbol;
404 if (d.has_target) {
405 var cparam = new CCodeFormalParameter (get_delegate_target_cname (param.name), "void*");
406 cparam_map.set (get_param_pos (param.cdelegate_target_parameter_position), cparam);
407 if (carg_map != null) {
408 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));
410 if (deleg_type.value_owned) {
411 cparam = new CCodeFormalParameter (get_delegate_target_destroy_notify_cname (param.name), "GDestroyNotify");
412 cparam_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), cparam);
413 if (carg_map != null) {
414 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), new CCodeIdentifier (cparam.name));
418 } else if (param.parameter_type is MethodType) {
419 var cparam = new CCodeFormalParameter (get_delegate_target_cname (param.name), "void*");
420 cparam_map.set (get_param_pos (param.cdelegate_target_parameter_position), cparam);
421 if (carg_map != null) {
422 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));