1 /* valaccodememberaccessmodule.vala
3 * Copyright (C) 2006-2010 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>
25 public abstract class Vala
.CCodeMemberAccessModule
: CCodeControlFlowModule
{
26 public override void visit_member_access (MemberAccess expr
) {
27 CCodeExpression pub_inst
= null;
29 if (expr
.inner
!= null) {
30 pub_inst
= get_cvalue (expr
.inner
);
33 var array_type
= expr
.value_type as ArrayType
;
34 var delegate_type
= expr
.value_type as DelegateType
;
36 if (expr
.symbol_reference is Method
) {
37 var m
= (Method
) expr
.symbol_reference
;
39 if (!(m is DynamicMethod
|| m is ArrayMoveMethod
|| m is ArrayResizeMethod
)) {
40 generate_method_declaration (m
, cfile
);
42 if (!m
.external
&& m
.external_package
) {
43 // internal VAPI methods
44 // only add them once per source file
45 if (add_generated_external_symbol (m
)) {
51 if (expr
.inner is BaseAccess
) {
52 if (m
.base_method
!= null) {
53 var base_class
= (Class
) m
.base_method
.parent_symbol
;
54 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (base_class
.get_upper_case_cname (null))));
55 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (current_class
.get_lower_case_cname (null))));
57 set_cvalue (expr
, new CCodeMemberAccess
.pointer (vcast
, m
.vfunc_name
));
59 } else if (m
.base_interface_method
!= null) {
60 var base_iface
= (Interface
) m
.base_interface_method
.parent_symbol
;
61 string parent_iface_var
= "%s_%s_parent_iface".printf (current_class
.get_lower_case_cname (null), base_iface
.get_lower_case_cname (null));
63 set_cvalue (expr
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), m
.vfunc_name
));
68 if (m
.base_method
!= null) {
69 if (!method_has_wrapper (m
.base_method
)) {
71 if (expr
.inner
!= null && !expr
.inner
.is_pure ()) {
72 // instance expression has side-effects
73 // store in temp. variable
74 var temp_var
= get_temp_variable (expr
.inner
.value_type
, true, null, false);
75 emit_temp_var (temp_var
);
76 var ctemp
= get_variable_cexpression (temp_var
.name
);
77 inst
= new
CCodeAssignment (ctemp
, pub_inst
);
78 set_cvalue (expr
.inner
, ctemp
);
80 var base_class
= (Class
) m
.base_method
.parent_symbol
;
81 var vclass
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (base_class
.get_upper_case_cname (null))));
82 vclass
.add_argument (inst
);
83 set_cvalue (expr
, new CCodeMemberAccess
.pointer (vclass
, m
.name
));
85 set_cvalue (expr
, new
CCodeIdentifier (m
.base_method
.get_cname ()));
87 } else if (m
.base_interface_method
!= null) {
88 set_cvalue (expr
, new
CCodeIdentifier (m
.base_interface_method
.get_cname ()));
89 } else if (m is CreationMethod
) {
90 set_cvalue (expr
, new
CCodeIdentifier (m
.get_real_cname ()));
92 set_cvalue (expr
, new
CCodeIdentifier (m
.get_cname ()));
95 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
96 if (m
.binding
== MemberBinding
.STATIC
) {
97 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
98 } else if (m
.is_async_callback
) {
99 if (current_method
.closure
) {
100 var block
= ((Method
) m
.parent_symbol
).body
;
101 set_delegate_target (expr
, new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), "_async_data_"));
103 set_delegate_target (expr
, new
CCodeIdentifier ("data"));
105 } else if (expr
.inner
!= null) {
106 // expr.inner is null in the special case of referencing the method in a constant initializer
107 var delegate_target
= (CCodeExpression
) get_ccodenode (expr
.inner
);
108 delegate_type
= expr
.target_type as DelegateType
;
109 if ((expr
.value_type
.value_owned
|| (delegate_type
!= null && delegate_type
.is_called_once
)) && expr
.inner
.value_type
.data_type
!= null && expr
.inner
.value_type
.data_type
.is_reference_counting ()) {
110 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (expr
.inner
.value_type
, expr
.source_reference
));
111 ref_call
.add_argument (delegate_target
);
112 delegate_target
= ref_call
;
113 set_delegate_target_destroy_notify (expr
, get_destroy_func_expression (expr
.inner
.value_type
));
115 set_delegate_target (expr
, delegate_target
);
117 } else if (expr
.symbol_reference is ArrayLengthField
) {
118 if (expr
.value_type is ArrayType
&& !(expr
.parent_node is ElementAccess
)) {
119 Report
.error (expr
.source_reference
, "unsupported use of length field of multi-dimensional array");
121 set_cvalue (expr
, get_array_length_cexpression (expr
.inner
, 1));
122 } else if (expr
.symbol_reference is Field
) {
123 var field
= (Field
) expr
.symbol_reference
;
124 if (field
.binding
== MemberBinding
.INSTANCE
) {
125 var instance_target_type
= get_data_type_for_symbol ((TypeSymbol
) field
.parent_symbol
);
127 var cl
= instance_target_type
.data_type as Class
;
128 bool is_gtypeinstance
= ((instance_target_type
.data_type
== cl
) && (cl
== null || !cl
.is_compact
));
130 CCodeExpression inst
;
131 if (is_gtypeinstance
&& field
.access
== SymbolAccessibility
.PRIVATE
) {
132 inst
= new CCodeMemberAccess
.pointer (pub_inst
, "priv");
135 generate_class_struct_declaration (cl
, cfile
);
139 if (instance_target_type
.data_type
.is_reference_type () || (expr
.inner
!= null && expr
.inner
.value_type is PointerType
)) {
140 set_cvalue (expr
, new CCodeMemberAccess
.pointer (inst
, field
.get_cname ()));
142 if (inst is CCodeCommaExpression
) {
143 var ccomma
= inst as CCodeCommaExpression
;
144 var inner
= ccomma
.get_inner ();
145 var last
= inner
.get (inner
.size
- 1);
146 ccomma
.set_expression (inner
.size
- 1, new
CCodeMemberAccess (last
, field
.get_cname ()));
147 set_cvalue (expr
, ccomma
);
149 set_cvalue (expr
, new
CCodeMemberAccess (inst
, field
.get_cname ()));
153 if (array_type
!= null) {
154 if (field
.array_null_terminated
) {
155 CCodeExpression carray_expr
= null;
156 if (instance_target_type
.data_type
.is_reference_type () || (expr
.inner
!= null && expr
.inner
.value_type is PointerType
)) {
157 carray_expr
= new CCodeMemberAccess
.pointer (inst
, field
.get_cname ());
159 carray_expr
= new
CCodeMemberAccess (inst
, field
.get_cname ());
162 requires_array_length
= true;
163 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
164 len_call
.add_argument (carray_expr
);
165 append_array_length (expr
, len_call
);
166 } else if (!field
.no_array_length
) {
167 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
168 CCodeExpression length_expr
= null;
170 if (field
.has_array_length_cexpr
) {
171 length_expr
= new
CCodeConstant (field
.get_array_length_cexpr ());
174 if (field
.has_array_length_cname
) {
175 length_cname
= field
.get_array_length_cname ();
177 length_cname
= get_array_length_cname (field
.name
, dim
);
180 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
181 length_expr
= new CCodeMemberAccess
.pointer (inst
, length_cname
);
183 length_expr
= new
CCodeMemberAccess (inst
, length_cname
);
186 if (field
.array_length_type
!= null) {
187 // cast if field does not use int for array length
188 var parent_expr
= expr
.parent_node as Expression
;
190 // don't cast if array is used as lvalue
191 } else if (parent_expr
!= null && parent_expr
.symbol_reference is ArrayLengthField
&&
192 parent_expr
.lvalue
) {
193 // don't cast if array length is used as lvalue
195 length_expr
= new
CCodeCastExpression (length_expr
, "gint");
199 append_array_length (expr
, length_expr
);
201 if (array_type
.rank
== 1 && field
.is_internal_symbol ()) {
202 string size_cname
= get_array_size_cname (field
.name
);
204 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
205 set_array_size_cvalue (expr
.target_value
, new CCodeMemberAccess
.pointer (inst
, size_cname
));
207 set_array_size_cvalue (expr
.target_value
, new
CCodeMemberAccess (inst
, size_cname
));
211 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
212 append_array_length (expr
, new
CCodeConstant ("-1"));
215 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
216 string target_cname
= get_delegate_target_cname (field
.get_cname ());
217 string target_destroy_notify_cname
= get_delegate_target_destroy_notify_cname (field
.get_cname ());
219 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
220 if (field
.no_delegate_target
) {
221 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
223 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
224 set_delegate_target (expr
, new CCodeMemberAccess
.pointer (inst
, target_cname
));
225 if (expr
.value_type
.value_owned
) {
226 set_delegate_target_destroy_notify (expr
, new CCodeMemberAccess
.pointer (inst
, target_destroy_notify_cname
));
229 set_delegate_target (expr
, new
CCodeMemberAccess (inst
, target_cname
));
230 if (expr
.value_type
.value_owned
) {
231 set_delegate_target_destroy_notify (expr
, new
CCodeMemberAccess (inst
, target_destroy_notify_cname
));
236 } else if (field
.binding
== MemberBinding
.CLASS
) {
237 var cl
= (Class
) field
.parent_symbol
;
238 var cast
= new
CCodeFunctionCall (new
CCodeIdentifier (cl
.get_upper_case_cname (null) + "_CLASS"));
240 CCodeExpression klass
;
241 if (expr
.inner
== null) {
242 if (in_static_or_class_context
) {
243 // Accessing the field from a static or class constructor
244 klass
= new
CCodeIdentifier ("klass");
246 // Accessing the field from within an instance method
247 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
248 k
.add_argument (new
CCodeIdentifier ("self"));
252 // Accessing the field of an instance
253 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
254 k
.add_argument (get_cvalue (expr
.inner
));
257 cast
.add_argument (klass
);
259 if (field
.access
== SymbolAccessibility
.PRIVATE
) {
260 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (cl
.get_upper_case_cname ())));
261 ccall
.add_argument (klass
);
262 set_cvalue (expr
, new CCodeMemberAccess
.pointer (ccall
, field
.get_cname ()));
264 set_cvalue (expr
, new CCodeMemberAccess
.pointer (cast
, field
.get_cname ()));
268 generate_field_declaration (field
, cfile
);
270 set_cvalue (expr
, new
CCodeIdentifier (field
.get_cname ()));
272 if (array_type
!= null) {
273 if (field
.array_null_terminated
) {
274 requires_array_length
= true;
275 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
276 len_call
.add_argument (new
CCodeIdentifier (field
.get_cname ()));
277 append_array_length (expr
, len_call
);
278 } else if (!field
.no_array_length
) {
279 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
280 if (field
.has_array_length_cexpr
) {
281 append_array_length (expr
, new
CCodeConstant (field
.get_array_length_cexpr ()));
283 append_array_length (expr
, new
CCodeIdentifier (get_array_length_cname (field
.get_cname (), dim
)));
286 if (array_type
.rank
== 1 && field
.is_internal_symbol ()) {
287 set_array_size_cvalue (expr
.target_value
, new
CCodeIdentifier (get_array_size_cname (field
.get_cname ())));
290 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
291 append_array_length (expr
, new
CCodeConstant ("-1"));
294 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
295 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
296 if (field
.no_delegate_target
) {
297 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
299 set_delegate_target (expr
, new
CCodeIdentifier (get_delegate_target_cname (field
.get_cname ())));
300 if (expr
.value_type
.value_owned
) {
301 set_delegate_target_destroy_notify (expr
, new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (field
.get_cname ())));
306 } else if (expr
.symbol_reference is EnumValue
) {
307 var ev
= (EnumValue
) expr
.symbol_reference
;
309 generate_enum_declaration ((Enum
) ev
.parent_symbol
, cfile
);
311 set_cvalue (expr
, new
CCodeConstant (ev
.get_cname ()));
312 } else if (expr
.symbol_reference is Constant
) {
313 var c
= (Constant
) expr
.symbol_reference
;
315 generate_constant_declaration (c
, cfile
,
316 c
.source_reference
!= null && expr
.source_reference
!= null &&
317 c
.source_reference
.file
== expr
.source_reference
.file
);
319 string fn
= c
.get_full_name ();
320 if (fn
== "GLib.Log.FILE") {
321 string s
= Path
.get_basename (expr
.source_reference
.file
.filename
);
322 set_cvalue (expr
, new
CCodeConstant ("\"%s\"".printf (s
)));
323 } else if (fn
== "GLib.Log.LINE") {
324 int i
= expr
.source_reference
.first_line
;
325 set_cvalue (expr
, new
CCodeConstant ("%d".printf (i
)));
326 } else if (fn
== "GLib.Log.METHOD") {
328 if (current_method
!= null) {
329 s
= current_method
.get_full_name ();
331 set_cvalue (expr
, new
CCodeConstant ("\"%s\"".printf (s
)));
333 set_cvalue (expr
, new
CCodeIdentifier (c
.get_cname ()));
336 if (array_type
!= null) {
337 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_N_ELEMENTS"));
338 ccall
.add_argument (new
CCodeIdentifier (c
.get_cname ()));
339 append_array_length (expr
, ccall
);
341 } else if (expr
.symbol_reference is Property
) {
342 var prop
= (Property
) expr
.symbol_reference
;
344 if (!(prop is DynamicProperty
)) {
345 generate_property_accessor_declaration (prop
.get_accessor
, cfile
);
347 if (!prop
.external
&& prop
.external_package
) {
348 // internal VAPI properties
349 // only add them once per source file
350 if (add_generated_external_symbol (prop
)) {
351 visit_property (prop
);
356 if (expr
.inner is BaseAccess
) {
357 if (prop
.base_property
!= null) {
358 var base_class
= (Class
) prop
.base_property
.parent_symbol
;
359 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (base_class
.get_upper_case_cname (null))));
360 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (current_class
.get_lower_case_cname (null))));
362 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "get_%s".printf (prop
.name
)));
363 ccall
.add_argument (get_cvalue (expr
.inner
));
364 set_cvalue (expr
, ccall
);
366 } else if (prop
.base_interface_property
!= null) {
367 var base_iface
= (Interface
) prop
.base_interface_property
.parent_symbol
;
368 string parent_iface_var
= "%s_%s_parent_iface".printf (current_class
.get_lower_case_cname (null), base_iface
.get_lower_case_cname (null));
370 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), "get_%s".printf (prop
.name
)));
371 ccall
.add_argument (get_cvalue (expr
.inner
));
372 set_cvalue (expr
, ccall
);
377 if (prop
.binding
== MemberBinding
.INSTANCE
&&
378 prop
.get_accessor
.automatic_body
&&
379 current_type_symbol
== prop
.parent_symbol
&&
380 current_type_symbol is Class
&&
381 prop
.base_property
== null &&
382 prop
.base_interface_property
== null &&
383 !(prop
.property_type is ArrayType
|| prop
.property_type is DelegateType
)) {
384 CCodeExpression inst
;
385 inst
= new CCodeMemberAccess
.pointer (pub_inst
, "priv");
386 set_cvalue (expr
, new CCodeMemberAccess
.pointer (inst
, prop
.field
.get_cname()));
387 } else if (!prop
.no_accessor_method
) {
388 var base_property
= prop
;
389 if (prop
.base_property
!= null) {
390 base_property
= prop
.base_property
;
391 } else if (prop
.base_interface_property
!= null) {
392 base_property
= prop
.base_interface_property
;
395 if (prop is DynamicProperty
) {
396 getter_cname
= get_dynamic_property_getter_cname ((DynamicProperty
) prop
);
398 getter_cname
= base_property
.get_accessor
.get_cname ();
400 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (getter_cname
));
402 if (prop
.binding
== MemberBinding
.INSTANCE
) {
403 if (prop
.parent_symbol is Struct
) {
404 // we need to pass struct instance by reference
405 var unary
= pub_inst as CCodeUnaryExpression
;
406 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
408 pub_inst
= unary
.inner
;
409 } else if (pub_inst is CCodeIdentifier
|| pub_inst is CCodeMemberAccess
) {
410 pub_inst
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, pub_inst
);
412 // if instance is e.g. a function call, we can't take the address of the expression
413 // (tmp = expr, &tmp)
414 var ccomma
= new
CCodeCommaExpression ();
416 var temp_var
= get_temp_variable (expr
.inner
.target_type
, true, null, false);
417 emit_temp_var (temp_var
);
418 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), pub_inst
));
419 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
)));
425 ccall
.add_argument (pub_inst
);
428 var temp_var
= get_temp_variable (base_property
.get_accessor
.value_type
, base_property
.get_accessor
.value_type
.value_owned
);
429 emit_temp_var (temp_var
);
430 var ctemp
= get_variable_cexpression (temp_var
.name
);
431 set_cvalue (expr
, ctemp
);
433 // Property access to real struct types is handled differently
434 // The value is returned by out parameter
435 if (base_property
.property_type
.is_real_non_null_struct_type ()) {
436 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
437 ccode
.add_expression (ccall
);
439 ccode
.add_assignment (ctemp
, ccall
);
441 array_type
= base_property
.property_type as ArrayType
;
442 if (array_type
!= null && !base_property
.no_array_length
) {
443 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
444 temp_var
= get_temp_variable (int_type
);
445 ctemp
= get_variable_cexpression (temp_var
.name
);
446 emit_temp_var (temp_var
);
447 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
448 append_array_length (expr
, ctemp
);
451 delegate_type
= base_property
.property_type as DelegateType
;
452 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
453 temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
454 ctemp
= get_variable_cexpression (temp_var
.name
);
455 emit_temp_var (temp_var
);
456 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
457 set_delegate_target (expr
, ctemp
);
458 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
463 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_get"));
464 ccall
.add_argument (pub_inst
);
466 // property name is second argument of g_object_get
467 ccall
.add_argument (prop
.get_canonical_cconstant ());
469 // g_object_get always returns owned values
470 // therefore, property getters of properties
471 // without accessor methods need to be marked as owned
472 if (!prop
.get_accessor
.value_type
.value_owned
) {
473 // only report error for types where there actually
474 // is a difference between `owned' and `unowned'
475 var owned_value_type
= prop
.get_accessor
.value_type
.copy ();
476 owned_value_type
.value_owned
= true;
477 if (requires_copy (owned_value_type
)) {
478 Report
.error (prop
.get_accessor
.source_reference
, "unowned return value for getter of property `%s' not supported without accessor".printf (prop
.get_full_name ()));
482 var ccomma
= new
CCodeCommaExpression ();
483 var temp_var
= get_temp_variable (expr
.value_type
);
484 var ctemp
= get_variable_cexpression (temp_var
.name
);
485 emit_temp_var (temp_var
);
486 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
487 ccall
.add_argument (new
CCodeConstant ("NULL"));
488 ccomma
.append_expression (ccall
);
489 ccomma
.append_expression (ctemp
);
490 set_cvalue (expr
, ccomma
);
492 } else if (expr
.symbol_reference is LocalVariable
) {
493 var local
= (LocalVariable
) expr
.symbol_reference
;
495 expr
.target_value
= get_local_cvalue (local
);
497 expr
.target_value
= load_local (local
);
500 if (expr
.parent_node is ReturnStatement
&&
501 current_return_type
.value_owned
&&
502 local
.variable_type
.value_owned
&&
504 !variable_accessible_in_finally (local
)) {
505 /* return expression is local variable taking ownership and
506 * current method is transferring ownership */
508 // don't ref expression
509 expr
.value_type
.value_owned
= true;
511 // don't unref variable
512 local
.active
= false;
514 } else if (expr
.symbol_reference is Parameter
) {
515 var param
= (Parameter
) expr
.symbol_reference
;
517 expr
.target_value
= get_parameter_cvalue (param
);
519 expr
.target_value
= load_parameter (param
);
525 * Returns lvalue access to the given local variable.
527 * @param not_in_coroutine enforces not to be in a coroutine
528 * @return the computed C lvalue
530 public TargetValue
get_local_cvalue (LocalVariable local
, bool not_in_coroutine
= false) {
531 var result
= new
GLibValue (local
.variable_type
.copy ());
533 var array_type
= local
.variable_type as ArrayType
;
534 var delegate_type
= local
.variable_type as DelegateType
;
535 if (local
.is_result
) {
536 // used in postconditions
537 // structs are returned as out parameter
538 if (local
.variable_type
!= null && local
.variable_type
.is_real_non_null_struct_type ()) {
539 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("result"));
541 result
.cvalue
= new
CCodeIdentifier ("result");
543 } else if (local
.captured
) {
544 // captured variables are stored on the heap
545 var block
= (Block
) local
.parent_symbol
;
546 result
.cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_variable_cname (local
.name
));
547 if (array_type
!= null) {
548 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
549 result
.append_array_length_cvalue (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_array_length_cname (get_variable_cname (local
.name
), dim
)));
551 if (array_type
.rank
== 1) {
552 result
.array_size_cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_array_size_cname (get_variable_cname (local
.name
)));
554 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
555 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_delegate_target_cname (get_variable_cname (local
.name
)));
556 result
.delegate_target_destroy_notify_cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_delegate_target_destroy_notify_cname (get_variable_cname (local
.name
)));
559 result
.cvalue
= get_variable_cexpression (local
.name
);
560 if (array_type
!= null) {
561 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
562 result
.append_array_length_cvalue (get_variable_cexpression (get_array_length_cname (get_variable_cname (local
.name
), dim
)));
564 if (array_type
.rank
== 1) {
565 result
.array_size_cvalue
= get_variable_cexpression (get_array_size_cname (get_variable_cname (local
.name
)));
567 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
568 if (is_in_coroutine () && !not_in_coroutine
) {
569 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_delegate_target_cname (get_variable_cname (local
.name
)));
570 result
.delegate_target_destroy_notify_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_delegate_target_destroy_notify_cname (get_variable_cname (local
.name
)));
572 result
.delegate_target_cvalue
= new
CCodeIdentifier (get_delegate_target_cname (get_variable_cname (local
.name
)));
573 if (local
.variable_type
.value_owned
) {
574 result
.delegate_target_destroy_notify_cvalue
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (local
.name
)));
584 * Returns lvalue access to the given local variable.
586 * @param not_in_coroutine enforces not to be in a coroutine
587 * @return the computed C lvalue
589 public TargetValue
get_parameter_cvalue (Parameter param
, bool not_in_coroutine
= false) {
590 var result
= new
GLibValue (param
.variable_type
.copy ());
591 if (param
.captured
|| (is_in_coroutine () && !not_in_coroutine
)) {
592 result
.value_type
.value_owned
= true;
595 var array_type
= result
.value_type as ArrayType
;
596 var delegate_type
= result
.value_type as DelegateType
;
598 if (param
.name
== "this") {
599 if (is_in_coroutine () && !not_in_coroutine
) {
601 result
.cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "self");
603 var st
= current_type_symbol as Struct
;
604 if (st
!= null && !st
.is_simple_type ()) {
605 result
.cvalue
= new
CCodeIdentifier ("(*self)");
607 result
.cvalue
= new
CCodeIdentifier ("self");
611 string name
= param
.name
;
613 if (param
.captured
) {
614 // captured variables are stored on the heap
615 var block
= param
.parent_symbol as Block
;
617 block
= ((Method
) param
.parent_symbol
).body
;
619 result
.cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_variable_cname (param
.name
));
620 if (array_type
!= null) {
621 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
622 result
.append_array_length_cvalue (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_parameter_array_length_cname (param
, dim
)));
624 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
625 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_delegate_target_cname (get_variable_cname (param
.name
)));
626 result
.delegate_target_destroy_notify_cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
628 } else if (is_in_coroutine () && !not_in_coroutine
) {
630 result
.cvalue
= get_variable_cexpression (param
.name
);
631 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
632 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_delegate_target_cname (get_variable_cname (param
.name
)));
633 result
.delegate_target_destroy_notify_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
636 var type_as_struct
= result
.value_type
.data_type as Struct
;
638 if (param
.direction
== ParameterDirection
.OUT
) {
642 if (param
.direction
== ParameterDirection
.REF
||
643 (param
.direction
== ParameterDirection
.IN
&& type_as_struct
!= null && !type_as_struct
.is_simple_type () && !result
.value_type
.nullable
)) {
644 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier (get_variable_cname (name
)));
646 // Property setters of non simple structs shall replace all occurences
647 // of the "value" formal parameter with a dereferencing version of that
649 if (current_property_accessor
!= null &&
650 current_property_accessor
.writable
&&
651 current_property_accessor
.value_parameter
== param
&&
652 current_property_accessor
.prop
.property_type
.is_real_struct_type () &&
653 !current_property_accessor
.prop
.property_type
.nullable
) {
654 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("value"));
656 result
.cvalue
= get_variable_cexpression (name
);
659 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
660 CCodeExpression target_expr
= new
CCodeIdentifier (get_delegate_target_cname (get_variable_cname (name
)));
661 CCodeExpression delegate_target_destroy_notify
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (name
)));
662 if (param
.direction
== ParameterDirection
.REF
) {
663 // accessing argument of ref param
664 target_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_expr
);
665 delegate_target_destroy_notify
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, delegate_target_destroy_notify
);
667 result
.delegate_target_cvalue
= target_expr
;
668 if (result
.value_type
.value_owned
) {
669 result
.delegate_target_destroy_notify_cvalue
= delegate_target_destroy_notify
;
673 if (!param
.captured
&& array_type
!= null) {
674 if (!param
.no_array_length
&& !param
.array_null_terminated
) {
675 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
676 CCodeExpression length_expr
= get_variable_cexpression (get_parameter_array_length_cname (param
, dim
));
677 if (param
.direction
== ParameterDirection
.OUT
) {
678 length_expr
= get_variable_cexpression (get_array_length_cname (get_variable_cname (name
), dim
));
679 } else if (param
.direction
== ParameterDirection
.REF
) {
680 // accessing argument of ref param
681 length_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, length_expr
);
683 result
.append_array_length_cvalue (length_expr
);
692 TargetValue
load_variable (Variable variable
, TargetValue value
) {
697 * Returns lvalue access to the given symbol.
699 * @param not_in_coroutine enforces not to be in a coroutine for local variables and parameters
700 * @param inner instance expression for accessing fields or properties
701 * @return the computed C lvalue
703 public override TargetValue
get_variable_cvalue (Variable variable
, CCodeExpression? inner
= null, bool not_in_coroutine
= false) {
704 if (variable is LocalVariable
) {
705 return get_local_cvalue ((LocalVariable
) variable
, not_in_coroutine
);
706 } else if (variable is Parameter
) {
707 return get_parameter_cvalue ((Parameter
) variable
, not_in_coroutine
);
709 assert_not_reached ();
713 /* Returns unowned access to the given local variable */
714 public override TargetValue
load_local (LocalVariable local
) {
715 var result
= (GLibValue
) get_local_cvalue (local
);
716 if (local
.variable_type is DelegateType
) {
717 result
.delegate_target_destroy_notify_cvalue
= new
CCodeConstant ("NULL");
719 result
.value_type
.value_owned
= false;
720 return load_variable (local
, result
);
723 /* Returns unowned access to the given parameter */
724 public TargetValue
load_parameter (Parameter param
) {
725 var result
= (GLibValue
) get_parameter_cvalue (param
);
726 if (result
.value_type is DelegateType
) {
727 result
.delegate_target_destroy_notify_cvalue
= new
CCodeConstant ("NULL");
729 if (result
.value_type is ArrayType
) {
730 if (param
.array_null_terminated
) {
731 string name
= param
.name
;
732 if (param
.direction
== ParameterDirection
.OUT
) {
735 var carray_expr
= get_variable_cexpression (name
);
736 requires_array_length
= true;
737 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
738 len_call
.add_argument (carray_expr
);
739 result
.append_array_length_cvalue (len_call
);
740 } else if (param
.no_array_length
) {
741 for (int dim
= 1; dim
<= ((ArrayType
) result
.value_type
).rank
; dim
++) {
742 result
.append_array_length_cvalue (new
CCodeConstant ("-1"));
746 result
.value_type
.value_owned
= false;
747 return load_variable (param
, result
);