Support vfunc_name attribute
[vala-lang.git] / gobject / valaccodedelegatemodule.vala
blob42928fbb6dca2533f2e6b9a441a7bf8a67c7a53d
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 public 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.has_target) {
58 var cparam = new CCodeFormalParameter ("user_data", "void*");
59 cfundecl.add_parameter (cparam);
61 if (d.get_error_types ().size > 0) {
62 var cparam = new CCodeFormalParameter ("error", "GError**");
63 cfundecl.add_parameter (cparam);
66 var ctypedef = new CCodeTypeDefinition (d.return_type.get_cname (), cfundecl);
68 if (!d.is_internal_symbol ()) {
69 header_type_declaration.append (ctypedef);
70 } else {
71 source_type_declaration.append (ctypedef);
75 public override string get_delegate_target_cname (string delegate_cname) {
76 return "%s_target".printf (delegate_cname);
79 public override CCodeExpression get_delegate_target_cexpression (Expression delegate_expr) {
80 bool is_out = false;
82 if (delegate_expr is UnaryExpression) {
83 var unary_expr = (UnaryExpression) delegate_expr;
84 if (unary_expr.operator == UnaryOperator.OUT || unary_expr.operator == UnaryOperator.REF) {
85 delegate_expr = unary_expr.inner;
86 is_out = true;
90 if (delegate_expr is MethodCall) {
91 var invocation_expr = (MethodCall) delegate_expr;
92 return invocation_expr.delegate_target;
93 } else if (delegate_expr is LambdaExpression) {
94 if ((current_method != null && current_method.binding == MemberBinding.INSTANCE) || in_constructor) {
95 return new CCodeIdentifier ("self");
96 } else {
97 return new CCodeConstant ("NULL");
99 } else if (delegate_expr.symbol_reference != null) {
100 if (delegate_expr.symbol_reference is FormalParameter) {
101 var param = (FormalParameter) delegate_expr.symbol_reference;
102 CCodeExpression target_expr = new CCodeIdentifier (get_delegate_target_cname (param.name));
103 if (param.direction != ParameterDirection.IN) {
104 // accessing argument of out/ref param
105 target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
107 if (is_out) {
108 // passing array as out/ref
109 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
110 } else {
111 return target_expr;
113 } else if (delegate_expr.symbol_reference is LocalVariable) {
114 var local = (LocalVariable) delegate_expr.symbol_reference;
115 var target_expr = new CCodeIdentifier (get_delegate_target_cname (local.name));
116 if (is_out) {
117 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
118 } else {
119 return target_expr;
121 } else if (delegate_expr.symbol_reference is Field) {
122 var field = (Field) delegate_expr.symbol_reference;
123 var target_cname = get_delegate_target_cname (field.name);
125 var ma = (MemberAccess) delegate_expr;
127 CCodeExpression target_expr = null;
129 if (field.binding == MemberBinding.INSTANCE) {
130 var instance_expression_type = ma.inner.value_type;
131 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) field.parent_symbol);
133 var pub_inst = (CCodeExpression) get_ccodenode (ma.inner);
134 CCodeExpression typed_inst = transform_expression (pub_inst, instance_expression_type, instance_target_type);
136 CCodeExpression inst;
137 if (field.access == SymbolAccessibility.PRIVATE) {
138 inst = new CCodeMemberAccess.pointer (typed_inst, "priv");
139 } else {
140 inst = typed_inst;
142 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
143 target_expr = new CCodeMemberAccess.pointer (inst, target_cname);
144 } else {
145 target_expr = new CCodeMemberAccess (inst, target_cname);
147 } else {
148 target_expr = new CCodeIdentifier (target_cname);
151 if (is_out) {
152 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
153 } else {
154 return target_expr;
156 } else if (delegate_expr.symbol_reference is Method) {
157 var m = (Method) delegate_expr.symbol_reference;
158 var ma = (MemberAccess) delegate_expr;
159 if (m.binding == MemberBinding.STATIC) {
160 return new CCodeConstant ("NULL");
161 } else {
162 return (CCodeExpression) get_ccodenode (ma.inner);
167 return new CCodeConstant ("NULL");
170 public override string get_delegate_target_destroy_notify_cname (string delegate_cname) {
171 return "%s_target_destroy_notify".printf (delegate_cname);
174 public override CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
175 if (target_type is DelegateType && expression_type is MethodType) {
176 var dt = (DelegateType) target_type;
177 var mt = (MethodType) expression_type;
179 var method = mt.method_symbol;
180 if (method.base_method != null) {
181 method = method.base_method;
182 } else if (method.base_interface_method != null) {
183 method = method.base_interface_method;
186 return new CCodeIdentifier (generate_delegate_wrapper (method, dt.delegate_symbol));
187 } else {
188 return base.get_implicit_cast_expression (source_cexpr, expression_type, target_type, expr);
192 private string generate_delegate_wrapper (Method m, Delegate d) {
193 string delegate_name;
194 var sig = d.parent_symbol as Signal;
195 var dynamic_sig = sig as DynamicSignal;
196 if (dynamic_sig != null) {
197 delegate_name = head.get_dynamic_signal_cname (dynamic_sig);
198 } else if (sig != null) {
199 delegate_name = sig.parent_symbol.get_lower_case_cprefix () + sig.get_cname ();
200 } else {
201 delegate_name = Symbol.camel_case_to_lower_case (d.get_cname ());
204 string wrapper_name = "_%s_%s".printf (m.get_cname (), delegate_name);
206 if (!add_wrapper (wrapper_name)) {
207 // wrapper already defined
208 return wrapper_name;
211 // declaration
213 var function = new CCodeFunction (wrapper_name, m.return_type.get_cname ());
214 function.modifiers = CCodeModifiers.STATIC;
215 m.ccodenode = function;
217 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
219 if (d.has_target) {
220 var cparam = new CCodeFormalParameter ("self", "gpointer");
221 cparam_map.set (get_param_pos (d.cinstance_parameter_position), cparam);
224 var d_params = d.get_parameters ();
225 foreach (FormalParameter param in d_params) {
226 // ensure that C code node has been generated
227 param.accept (codegen);
229 cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
231 // handle array parameters
232 if (!param.no_array_length && param.parameter_type is ArrayType) {
233 var array_type = (ArrayType) param.parameter_type;
235 var length_ctype = "int";
236 if (param.direction != ParameterDirection.IN) {
237 length_ctype = "int*";
240 for (int dim = 1; dim <= array_type.rank; dim++) {
241 var cparam = new CCodeFormalParameter (head.get_array_length_cname (param.name, dim), length_ctype);
242 cparam_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
248 if (m.get_error_types ().size > 0) {
249 var cparam = new CCodeFormalParameter ("error", "GError**");
250 cparam_map.set (get_param_pos (-1), cparam);
253 // append C parameters in the right order
254 int last_pos = -1;
255 int min_pos;
256 while (true) {
257 min_pos = -1;
258 foreach (int pos in cparam_map.get_keys ()) {
259 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
260 min_pos = pos;
263 if (min_pos == -1) {
264 break;
266 function.add_parameter (cparam_map.get (min_pos));
267 last_pos = min_pos;
271 // definition
273 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
275 int i = 0;
276 if (m.binding == MemberBinding.INSTANCE) {
277 CCodeExpression arg;
278 if (d.has_target) {
279 arg = new CCodeIdentifier ("self");
280 } else {
281 // use first delegate parameter as instance
282 arg = new CCodeIdentifier ((d_params.get (0).ccodenode as CCodeFormalParameter).name);
283 i = 1;
285 carg_map.set (get_param_pos (m.cinstance_parameter_position), arg);
288 foreach (FormalParameter param in m.get_parameters ()) {
289 CCodeExpression arg;
290 arg = new CCodeIdentifier ((d_params.get (i).ccodenode as CCodeFormalParameter).name);
291 carg_map.set (get_param_pos (param.cparameter_position), arg);
293 // handle array arguments
294 if (!param.no_array_length && param.parameter_type is ArrayType) {
295 var array_type = (ArrayType) param.parameter_type;
296 for (int dim = 1; dim <= array_type.rank; dim++) {
297 CCodeExpression clength;
298 if (d_params.get (i).array_null_terminated) {
299 requires_array_length = true;
300 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
301 len_call.add_argument (new CCodeIdentifier (d_params.get (i).name));
302 clength = len_call;
303 } else if (d_params.get (i).no_array_length) {
304 clength = new CCodeConstant ("-1");
305 } else {
306 clength = new CCodeIdentifier (head.get_array_length_cname (d_params.get (i).name, dim));
308 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), clength);
312 i++;
315 if (m.get_error_types ().size > 0) {
316 carg_map.set (get_param_pos (-1), new CCodeIdentifier ("error"));
319 var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
321 // append C arguments in the right order
322 last_pos = -1;
323 while (true) {
324 min_pos = -1;
325 foreach (int pos in carg_map.get_keys ()) {
326 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
327 min_pos = pos;
330 if (min_pos == -1) {
331 break;
333 ccall.add_argument (carg_map.get (min_pos));
334 last_pos = min_pos;
337 var block = new CCodeBlock ();
338 if (m.return_type is VoidType) {
339 block.add_statement (new CCodeExpressionStatement (ccall));
340 } else {
341 block.add_statement (new CCodeReturnStatement (ccall));
344 // append to file
346 source_type_member_declaration.append (function.copy ());
348 function.block = block;
349 source_type_member_definition.append (function);
351 return wrapper_name;