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 public 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
);
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
);
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
) {
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
;
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");
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
);
108 // passing array as out/ref
109 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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
));
117 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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");
142 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
143 target_expr
= new CCodeMemberAccess
.pointer (inst
, target_cname
);
145 target_expr
= new
CCodeMemberAccess (inst
, target_cname
);
148 target_expr
= new
CCodeIdentifier (target_cname
);
152 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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");
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
));
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 ();
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
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
);
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
258 foreach (int pos
in cparam_map
.get_keys ()) {
259 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
266 function
.add_parameter (cparam_map
.get (min_pos
));
273 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
276 if (m
.binding
== MemberBinding
.INSTANCE
) {
279 arg
= new
CCodeIdentifier ("self");
281 // use first delegate parameter as instance
282 arg
= new
CCodeIdentifier ((d_params
.get (0).ccodenode as CCodeFormalParameter
).name
);
285 carg_map
.set (get_param_pos (m
.cinstance_parameter_position
), arg
);
288 foreach (FormalParameter param
in m
.get_parameters ()) {
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
));
303 } else if (d_params
.get (i
).no_array_length
) {
304 clength
= new
CCodeConstant ("-1");
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
);
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
325 foreach (int pos
in carg_map
.get_keys ()) {
326 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
333 ccall
.add_argument (carg_map
.get (min_pos
));
337 var block
= new
CCodeBlock ();
338 if (m
.return_type is VoidType
) {
339 block
.add_statement (new
CCodeExpressionStatement (ccall
));
341 block
.add_statement (new
CCodeReturnStatement (ccall
));
346 source_type_member_declaration
.append (function
.copy ());
348 function
.block
= block
;
349 source_type_member_definition
.append (function
);