codegen: Rename append_array_size and get_array_sizes to *_length(s)
[vala-lang.git] / codegen / valaccodememberaccessmodule.vala
blob391f1c30f12ad9a4ed1893736ac3388b94284055
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
20 * Author:
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)) {
46 visit_method (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));
58 return;
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));
64 return;
68 if (m.base_method != null) {
69 if (!method_has_wrapper (m.base_method)) {
70 var inst = pub_inst;
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));
84 } else {
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 ()));
91 } else {
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_"));
102 } else {
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");
133 } else {
134 if (cl != null) {
135 generate_class_struct_declaration (cl, cfile);
137 inst = pub_inst;
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 ()));
141 } else {
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);
148 } else {
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 ());
158 } else {
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 ());
172 } else {
173 string length_cname;
174 if (field.has_array_length_cname) {
175 length_cname = field.get_array_length_cname ();
176 } else {
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);
182 } else {
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;
189 if (expr.lvalue) {
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
194 } else {
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));
206 } else {
207 set_array_size_cvalue (expr.target_value, new CCodeMemberAccess (inst, size_cname));
210 } else {
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"));
222 } else {
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));
228 } else {
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");
245 } else {
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"));
249 klass = k;
251 } else {
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));
255 klass = k;
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 ()));
263 } else {
264 set_cvalue (expr, new CCodeMemberAccess.pointer (cast, field.get_cname ()));
267 } else {
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 ()));
282 } else {
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 ())));
289 } else {
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"));
298 } else {
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") {
327 string s = "";
328 if (current_method != null) {
329 s = current_method.get_full_name ();
331 set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
332 } else {
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);
365 return;
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);
373 return;
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;
394 string getter_cname;
395 if (prop is DynamicProperty) {
396 getter_cname = get_dynamic_property_getter_cname ((DynamicProperty) prop);
397 } else {
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) {
407 // *expr => expr
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);
411 } else {
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)));
421 pub_inst = ccomma;
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);
438 } else {
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);
450 } else {
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"));
462 } else {
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;
494 if (expr.lvalue) {
495 expr.target_value = get_local_cvalue (local);
496 } else {
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 &&
503 !local.captured &&
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;
516 if (expr.lvalue) {
517 expr.target_value = get_parameter_cvalue (param);
518 } else {
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"));
540 } else {
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)));
558 } else {
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)));
571 } else {
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)));
580 return result;
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) {
600 // use closure
601 result.cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "self");
602 } else {
603 var st = current_type_symbol as Struct;
604 if (st != null && !st.is_simple_type ()) {
605 result.cvalue = new CCodeIdentifier ("(*self)");
606 } else {
607 result.cvalue = new CCodeIdentifier ("self");
610 } else {
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;
616 if (block == null) {
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) {
629 // use closure
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)));
635 } else {
636 var type_as_struct = result.value_type.data_type as Struct;
638 if (param.direction == ParameterDirection.OUT) {
639 name = "_" + name;
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)));
645 } else {
646 // Property setters of non simple structs shall replace all occurences
647 // of the "value" formal parameter with a dereferencing version of that
648 // parameter.
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"));
655 } else {
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);
689 return result;
692 TargetValue load_variable (Variable variable, TargetValue value) {
693 return 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);
708 } else {
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) {
733 name = "_" + name;
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);