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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
28 * The link between an assignment and generated code.
30 internal class Vala
.CCodeDelegateModule
: CCodeArrayModule
{
31 public CCodeDelegateModule (CCodeGenerator codegen
, CCodeModule? 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
);
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
);
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
) {
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
;
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");
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
);
123 // passing array as out/ref
124 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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
));
132 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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");
157 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
158 target_expr
= new CCodeMemberAccess
.pointer (inst
, target_cname
);
160 target_expr
= new
CCodeMemberAccess (inst
, target_cname
);
163 target_expr
= new
CCodeIdentifier (target_cname
);
167 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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");
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
));
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 ();
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
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
);
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
282 foreach (int pos
in cparam_map
.get_keys ()) {
283 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
290 function
.add_parameter (cparam_map
.get (min_pos
));
297 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
300 if (m
.binding
== MemberBinding
.INSTANCE
) {
303 arg
= new
CCodeIdentifier ("self");
305 // use first delegate parameter as instance
306 arg
= new
CCodeIdentifier ((d_params
.get (0).ccodenode as CCodeFormalParameter
).name
);
309 carg_map
.set (get_param_pos (m
.cinstance_parameter_position
), arg
);
312 foreach (FormalParameter param
in m
.get_parameters ()) {
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
));
327 } else if (d_params
.get (i
).no_array_length
) {
328 clength
= new
CCodeConstant ("-1");
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
);
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");
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
361 foreach (int pos
in carg_map
.get_keys ()) {
362 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
369 ccall
.add_argument (carg_map
.get (min_pos
));
373 var block
= new
CCodeBlock ();
374 if (m
.return_type is VoidType
) {
375 block
.add_statement (new
CCodeExpressionStatement (ccall
));
377 block
.add_statement (new
CCodeReturnStatement (ccall
));
382 source_declarations
.add_type_member_declaration (function
.copy ());
384 function
.block
= block
;
385 source_type_member_definition
.append (function
);
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
);
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
;
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
));