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 || m is ArrayCopyMethod)) {
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 CCodeExpression? vcast = null;
53 if (m.base_method != null) {
54 unowned Class base_class = (Class) m.base_method.parent_symbol;
55 vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
56 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
57 } else if (m.base_interface_method != null) {
58 unowned Interface base_iface = (Interface) m.base_interface_method.parent_symbol;
59 vcast = get_this_interface_cexpression (base_iface);
62 set_cvalue (expr, new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m)));
67 if (m.base_method != null) {
68 if (get_ccode_no_wrapper (m.base_method)) {
69 unowned Class base_class = (Class) m.base_method.parent_symbol;
70 if (!base_class.is_compact) {
71 var vclass = get_this_class_cexpression (base_class, expr.inner.target_value);
72 set_cvalue (expr, new CCodeMemberAccess.pointer (vclass, get_ccode_vfunc_name (m)));
74 set_cvalue (expr, new CCodeMemberAccess.pointer (pub_inst, get_ccode_vfunc_name (m)));
77 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m.base_method)));
79 } else if (m.base_interface_method != null) {
80 if (get_ccode_no_wrapper (m.base_interface_method)) {
81 unowned Interface base_iface = (Interface) m.base_interface_method.parent_symbol;
82 var vclass = get_this_interface_cexpression (base_iface, expr.inner.target_value);
83 set_cvalue (expr, new CCodeMemberAccess.pointer (vclass, get_ccode_vfunc_name (m)));
85 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m.base_interface_method)));
87 } else if (m is CreationMethod) {
88 set_cvalue (expr, new CCodeIdentifier (get_ccode_real_name (m)));
90 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m)));
93 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
94 if (m.binding == MemberBinding.STATIC) {
95 set_delegate_target (expr, new CCodeConstant ("NULL"));
96 } else if (m.is_async_callback) {
97 if (current_method.closure) {
98 var block = ((Method) m.parent_symbol).body;
99 set_delegate_target (expr, new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_"));
101 set_delegate_target (expr, new CCodeIdentifier ("_data_"));
103 } else if (expr.inner != null && !expr.prototype_access) {
104 // expr.inner is null in the special case of referencing the method in a constant initializer
105 var delegate_target = (CCodeExpression) get_ccodenode (expr.inner);
106 delegate_type = expr.target_type as DelegateType;
107 if ((expr.value_type.value_owned || (delegate_type != null && delegate_type.is_called_once)) && expr.inner.value_type.type_symbol != null && is_reference_counting (expr.inner.value_type.type_symbol)) {
108 var ref_call = new CCodeFunctionCall (get_dup_func_expression (expr.inner.value_type, expr.source_reference));
109 ref_call.add_argument (delegate_target);
110 delegate_target = ref_call;
111 set_delegate_target_destroy_notify (expr, get_destroy_func_expression (expr.inner.value_type));
113 set_delegate_target (expr, delegate_target);
115 } else if (expr.symbol_reference is ArrayLengthField) {
116 set_cvalue (expr, get_array_length_cexpression (expr.inner, 1));
117 } else if (expr.symbol_reference is DelegateTargetField) {
118 CCodeExpression delegate_target_destroy_notify;
119 set_cvalue (expr, get_delegate_target_cexpression (expr.inner, out delegate_target_destroy_notify) ?? new CCodeConstant ("NULL"));
120 } else if (expr.symbol_reference is DelegateDestroyField) {
121 CCodeExpression delegate_target_destroy_notify;
122 get_delegate_target_cexpression (expr.inner, out delegate_target_destroy_notify);
123 set_cvalue (expr, delegate_target_destroy_notify ?? new CCodeConstant ("NULL"));
124 } else if (expr.symbol_reference is GenericDupField) {
125 set_cvalue (expr, get_dup_func_expression (expr.inner.value_type, expr.source_reference));
126 } else if (expr.symbol_reference is GenericDestroyField) {
127 set_cvalue (expr, get_destroy_func_expression (expr.inner.value_type));
128 } else if (expr.symbol_reference is Field) {
129 var field = (Field) expr.symbol_reference;
131 expr.target_value = get_field_cvalue (field, expr.inner != null ? expr.inner.target_value : null);
133 expr.target_value = load_field (field, expr.inner != null ? expr.inner.target_value : null, expr);
135 } else if (expr.symbol_reference is EnumValue) {
136 var ev = (EnumValue) expr.symbol_reference;
138 generate_enum_declaration ((Enum) ev.parent_symbol, cfile);
140 set_cvalue (expr, new CCodeConstant (get_ccode_name (ev)));
141 } else if (expr.symbol_reference is Constant) {
142 var c = (Constant) expr.symbol_reference;
144 generate_constant_declaration (c, cfile,
145 c.source_reference != null && expr.source_reference != null &&
146 c.source_reference.file == expr.source_reference.file);
148 string fn = c.get_full_name ();
149 if (fn == "GLib.Log.FILE") {
150 string s = Path.get_basename (expr.source_reference.file.filename);
151 set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
152 } else if (fn == "GLib.Log.LINE") {
153 int i = expr.source_reference.begin.line;
154 set_cvalue (expr, new CCodeConstant ("%d".printf (i)));
155 } else if (fn == "GLib.Log.METHOD") {
157 if (current_method != null) {
158 s = current_method.get_full_name ();
160 set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
161 } else if (c.type_reference.is_non_null_simple_type ()) {
162 set_cvalue (expr, new CCodeConstant (get_ccode_name (c)));
164 set_cvalue (expr, new CCodeConstantIdentifier (get_ccode_name (c)));
167 if (array_type != null) {
169 for (int i = 0; i < array_type.rank; i++) {
170 CCodeFunctionCall ccall;
171 if (context.profile == Profile.POSIX) {
172 requires_array_n_elements = true;
173 ccall = new CCodeFunctionCall (new CCodeIdentifier ("VALA_N_ELEMENTS"));
175 ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_N_ELEMENTS"));
177 ccall.add_argument (new CCodeIdentifier (get_ccode_name (c) + sub));
178 append_array_length (expr, ccall);
181 ((GLibValue) expr.target_value).non_null = true;
183 } else if (expr.symbol_reference is Property) {
184 var prop = (Property) expr.symbol_reference;
186 if (!(prop is DynamicProperty)) {
187 generate_property_accessor_declaration (prop.get_accessor, cfile);
189 if (!prop.external && prop.external_package) {
190 // internal VAPI properties
191 // only add them once per source file
192 if (add_generated_external_symbol (prop)) {
193 visit_property (prop);
198 if (pub_inst == null && prop.binding == MemberBinding.INSTANCE) {
199 // FIXME Report this with proper source-reference on the vala side!
200 Report.error (prop.source_reference, "Invalid access to instance member `%s'", prop.get_full_name ());
201 set_cvalue (expr, new CCodeInvalidExpression ());
205 unowned Property base_prop = prop;
206 if (prop.base_property != null) {
207 base_prop = prop.base_property;
208 } else if (prop.base_interface_property != null) {
209 base_prop = prop.base_interface_property;
211 if (expr.inner is BaseAccess && (base_prop.is_abstract || base_prop.is_virtual)) {
212 CCodeExpression? vcast = null;
213 if (base_prop.parent_symbol is Class) {
214 unowned Class base_class = (Class) base_prop.parent_symbol;
215 vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
216 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
217 } else if (base_prop.parent_symbol is Interface) {
218 unowned Interface base_iface = (Interface) base_prop.parent_symbol;
219 vcast = get_this_interface_cexpression (base_iface);
222 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
223 ccall.add_argument (get_cvalue (expr.inner));
224 if (prop.property_type.is_real_non_null_struct_type ()) {
225 var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, false, expr);
226 expr.target_value = load_temp_value (temp_value);
227 var ctemp = get_cvalue_ (temp_value);
228 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
229 ccode.add_expression (ccall);
231 set_cvalue (expr, ccall);
234 Report.error (expr.source_reference, "internal: Invalid access to `%s'", base_prop.get_full_name ());
236 } else if (prop.binding == MemberBinding.INSTANCE &&
237 prop.get_accessor.automatic_body &&
238 !prop.get_accessor.value_type.value_owned &&
239 current_type_symbol == prop.parent_symbol &&
240 current_type_symbol is Class &&
241 prop.base_property == null &&
242 prop.base_interface_property == null &&
243 !(prop.property_type is ArrayType || prop.property_type is DelegateType)) {
244 CCodeExpression inst = pub_inst;
245 if (!((Class) current_type_symbol).is_compact) {
246 inst = new CCodeMemberAccess.pointer (inst, "priv");
248 set_cvalue (expr, new CCodeMemberAccess.pointer (inst, get_ccode_name (prop.field)));
249 } else if (!get_ccode_no_accessor_method (prop) && !(prop is DynamicProperty)) {
250 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (prop.get_accessor)));
252 if (prop.binding == MemberBinding.INSTANCE) {
253 if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
254 // we need to pass struct instance by reference
255 var instance = expr.inner.target_value;
256 if (!get_lvalue (instance)) {
257 instance = store_temp_value (instance, expr);
259 pub_inst = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance));
262 ccall.add_argument (pub_inst);
265 bool prop_is_real_non_null_struct_type = prop.property_type.is_real_non_null_struct_type ();
266 bool requires_init = prop.property_type is DelegateType || prop_is_real_non_null_struct_type;
267 var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, requires_init, expr);
268 expr.target_value = load_temp_value (temp_value);
269 var ctemp = get_cvalue_ (temp_value);
271 // Property access to real struct types is handled differently
272 // The value is returned by out parameter
273 if (prop_is_real_non_null_struct_type) {
274 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
275 ccode.add_expression (ccall);
277 array_type = prop.property_type as ArrayType;
278 if (array_type != null) {
279 if (get_ccode_array_null_terminated (prop)) {
280 requires_array_length = true;
281 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
282 len_call.add_argument (ctemp);
284 ccode.add_assignment (ctemp, ccall);
285 ccode.add_assignment (temp_value.array_length_cvalues[0], len_call);
286 } else if (get_ccode_array_length (prop)) {
287 var temp_refs = new ArrayList<CCodeExpression> ();
288 for (int dim = 1; dim <= array_type.rank; dim++) {
289 var length_ctype = get_ccode_array_length_type (prop);
290 var temp_var = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
291 var temp_ref = get_variable_cexpression (temp_var.name);
292 emit_temp_var (temp_var);
293 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
294 temp_refs.add (temp_ref);
297 ccode.add_assignment (ctemp, ccall);
298 for (int dim = 1; dim <= array_type.rank; dim++) {
299 ccode.add_assignment (temp_value.array_length_cvalues[dim - 1], temp_refs.get (dim - 1));
302 ccode.add_assignment (ctemp, ccall);
305 ccode.add_assignment (ctemp, ccall);
307 delegate_type = prop.property_type as DelegateType;
308 if (delegate_type != null && get_ccode_delegate_target (prop) && delegate_type.delegate_symbol.has_target) {
309 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_cvalue (temp_value)));
311 if (temp_value.delegate_target_cvalue != null) {
312 ccode.add_assignment (temp_value.delegate_target_cvalue, new CCodeConstant ("NULL"));
314 if (temp_value.delegate_target_destroy_notify_cvalue != null) {
315 ccode.add_assignment (temp_value.delegate_target_destroy_notify_cvalue, new CCodeConstant ("NULL"));
321 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
322 ccall.add_argument (pub_inst);
324 // property name is second argument of g_object_get
325 ccall.add_argument (get_property_canonical_cconstant (prop));
327 // g_object_get always returns owned values
328 // therefore, property getters of properties
329 // without accessor methods need to be marked as owned
330 if (!(prop is DynamicProperty) && !prop.get_accessor.value_type.value_owned) {
331 // only report error for types where there actually
332 // is a difference between `owned' and `unowned'
333 var owned_value_type = prop.get_accessor.value_type.copy ();
334 owned_value_type.value_owned = true;
335 if (requires_copy (owned_value_type)) {
336 Report.error (prop.get_accessor.source_reference, "unowned return value for getter of property `%s' not supported without accessor", prop.get_full_name ());
340 if (expr.value_type.is_real_struct_type ()) {
341 // gobject allocates structs on heap
342 expr.value_type.nullable = true;
345 var temp_var = get_temp_variable (expr.value_type);
346 var ctemp = get_variable_cexpression (temp_var.name);
347 emit_temp_var (temp_var);
348 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
349 ccall.add_argument (new CCodeConstant ("NULL"));
350 ccode.add_expression (ccall);
351 set_cvalue (expr, ctemp);
354 if (prop.get_accessor.value_type is GenericType) {
355 expr.target_value.value_type = prop.get_accessor.value_type.copy ();
357 expr.target_value.value_type = expr.value_type.copy ();
359 expr.target_value = store_temp_value (expr.target_value, expr);
360 } else if (expr.symbol_reference is LocalVariable) {
361 var local = (LocalVariable) expr.symbol_reference;
363 if (expr.parent_node is ReturnStatement &&
364 current_return_type.value_owned &&
365 local.variable_type.value_owned &&
367 !variable_accessible_in_finally (local) &&
368 !(local.variable_type is ArrayType && ((ArrayType) local.variable_type).inline_allocated)) {
369 /* return expression is local variable taking ownership and
370 * current method is transferring ownership */
372 // don't ref expression
373 expr.value_type.value_owned = true;
375 // don't unref variable
376 local.active = false;
378 var glib_value = (GLibValue) get_local_cvalue (local);
379 expr.target_value = glib_value;
380 if (glib_value.delegate_target_cvalue == null) {
381 glib_value.delegate_target_cvalue = new CCodeConstant ("NULL");
383 if (glib_value.delegate_target_destroy_notify_cvalue == null) {
384 glib_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
388 expr.target_value = get_local_cvalue (local);
390 expr.target_value = load_local (local, expr);
393 } else if (expr.symbol_reference is Parameter) {
394 var param = (Parameter) expr.symbol_reference;
396 expr.target_value = get_parameter_cvalue (param);
398 expr.target_value = load_parameter (param, expr);
402 // Add cast for narrowed type access of variables if needed
403 if (expr.symbol_reference is Variable) {
404 unowned GLibValue cvalue = (GLibValue) expr.target_value;
405 if (!(cvalue.value_type is GenericType) && cvalue.value_type.type_symbol != null
406 && cvalue.value_type.type_symbol != expr.value_type.type_symbol) {
407 cvalue.cvalue = new CCodeCastExpression (cvalue.cvalue, get_ccode_name (expr.value_type));
412 /* Returns lvalue access to the given local variable */
413 public override TargetValue get_local_cvalue (LocalVariable local) {
414 var result = new GLibValue (local.variable_type.copy ());
415 result.lvalue = true;
417 var array_type = local.variable_type as ArrayType;
418 var delegate_type = local.variable_type as DelegateType;
419 if (local.is_result) {
420 // used in postconditions
421 // structs are returned as out parameter
422 if (local.variable_type != null && local.variable_type.is_real_non_null_struct_type ()) {
423 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
425 result.cvalue = new CCodeIdentifier ("result");
427 if (array_type != null && !array_type.fixed_length && ((current_method != null && get_ccode_array_length (current_method)) || current_property_accessor != null)) {
428 for (int dim = 1; dim <= array_type.rank; dim++) {
429 result.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_array_length_cname ("result", dim))));
432 } else if (local.captured) {
433 // captured variables are stored on the heap
434 var block = (Block) local.parent_symbol;
435 result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_local_cname (local));
436 if (array_type != null && !array_type.fixed_length) {
437 for (int dim = 1; dim <= array_type.rank; dim++) {
438 result.append_array_length_cvalue (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_array_length_cname (get_local_cname (local), dim)));
440 if (array_type.rank == 1) {
441 result.array_size_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_array_size_cname (get_local_cname (local)));
443 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
444 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_cname (get_local_cname (local)));
445 if (delegate_type.is_disposable ()) {
446 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_local_cname (local)));
450 result.cvalue = get_local_cexpression (local);
451 if (array_type != null && !array_type.fixed_length) {
452 for (int dim = 1; dim <= array_type.rank; dim++) {
453 result.append_array_length_cvalue (get_variable_cexpression (get_array_length_cname (get_local_cname (local), dim)));
455 if (array_type.rank == 1) {
456 result.array_size_cvalue = get_variable_cexpression (get_array_size_cname (get_local_cname (local)));
458 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
459 if (is_in_coroutine ()) {
460 result.delegate_target_cvalue = get_variable_cexpression (get_delegate_target_cname (get_local_cname (local)));
461 if (local.variable_type.is_disposable ()) {
462 result.delegate_target_destroy_notify_cvalue = get_variable_cexpression (get_delegate_target_destroy_notify_cname (get_local_cname (local)));
465 result.delegate_target_cvalue = new CCodeIdentifier (get_delegate_target_cname (get_local_cname (local)));
466 if (local.variable_type.is_disposable ()) {
467 result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_local_cname (local)));
476 /* Returns access values to the given parameter */
477 public override TargetValue get_parameter_cvalue (Parameter param) {
478 var result = new GLibValue (param.variable_type.copy ());
479 result.lvalue = true;
480 result.array_null_terminated = get_ccode_array_null_terminated (param);
481 if (get_ccode_array_length_expr (param) != null) {
482 result.array_length_cexpr = new CCodeConstant (get_ccode_array_length_expr (param));
484 result.ctype = get_ccode_type (param);
486 var array_type = result.value_type as ArrayType;
487 var delegate_type = result.value_type as DelegateType;
489 bool is_unowned_delegate = delegate_type != null && !param.variable_type.value_owned;
490 if ((param.captured || is_in_coroutine ()) && !is_unowned_delegate) {
491 result.value_type.value_owned = true;
494 if (param.name == "this") {
495 if (is_in_coroutine ()) {
497 result.cvalue = get_this_cexpression ();
499 unowned Struct? st = result.value_type.type_symbol as Struct;
500 if (st != null && !st.is_simple_type ()) {
501 result.cvalue = new CCodeIdentifier ("(*self)");
503 result.cvalue = new CCodeIdentifier ("self");
507 string name = get_ccode_name (param);
509 if (param.captured && !is_in_method_precondition) {
510 // captured variables are stored on the heap
511 var block = param.parent_symbol as Block;
513 block = ((Method) param.parent_symbol).body;
515 result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_name (param));
516 if (array_type != null && get_ccode_array_length (param)) {
517 for (int dim = 1; dim <= array_type.rank; dim++) {
518 result.append_array_length_cvalue (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_array_length_cname (param, dim)));
520 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
521 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_delegate_target_name (param));
522 if (result.value_type.is_disposable ()) {
523 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_delegate_target_destroy_notify_name (param));
526 } else if (is_in_coroutine ()) {
528 result.cvalue = get_parameter_cexpression (param);
529 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
530 result.delegate_target_cvalue = get_variable_cexpression (get_ccode_delegate_target_name (param));
531 if (delegate_type.is_disposable ()) {
532 result.delegate_target_destroy_notify_cvalue = get_variable_cexpression (get_ccode_delegate_target_destroy_notify_name (param));
536 unowned Struct? type_as_struct = result.value_type.type_symbol as Struct;
538 if (param.direction == ParameterDirection.OUT) {
539 name = "_vala_%s".printf (name);
542 if (param.direction == ParameterDirection.REF ||
543 (param.direction == ParameterDirection.IN && type_as_struct != null && !type_as_struct.is_simple_type () && !result.value_type.nullable)) {
544 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (name));
546 result.cvalue = get_variable_cexpression (name);
548 if (get_ccode_delegate_target (param) && delegate_type != null && delegate_type.delegate_symbol.has_target) {
549 var target_cname = get_ccode_delegate_target_name (param);
550 var destroy_cname = get_ccode_delegate_target_destroy_notify_name (param);
551 if (param.direction == ParameterDirection.OUT) {
552 target_cname = "_vala_%s".printf (target_cname);
553 destroy_cname = "_vala_%s".printf (destroy_cname);
555 CCodeExpression target_expr = new CCodeIdentifier (target_cname);
556 CCodeExpression delegate_target_destroy_notify = new CCodeIdentifier (destroy_cname);
557 if (param.direction == ParameterDirection.REF) {
558 // accessing argument of ref param
559 target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
560 delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, delegate_target_destroy_notify);
562 result.delegate_target_cvalue = target_expr;
563 if (result.value_type.is_disposable ()) {
564 result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify;
568 if (!param.captured && array_type != null) {
569 if (get_ccode_array_length (param) && !get_ccode_array_null_terminated (param)) {
570 for (int dim = 1; dim <= array_type.rank; dim++) {
571 CCodeExpression length_expr = get_cexpression (get_variable_array_length_cname (param, dim));
572 if (param.direction == ParameterDirection.OUT) {
573 length_expr = get_cexpression (get_array_length_cname (name, dim));
574 } else if (param.direction == ParameterDirection.REF) {
575 // accessing argument of ref param
576 length_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, length_expr);
578 result.append_array_length_cvalue (length_expr);
587 /* Returns lvalue access to the given field */
588 public override TargetValue get_field_cvalue (Field field, TargetValue? instance) {
589 var value_type = field.variable_type.copy ();
591 var result = new GLibValue (value_type);
592 if (instance != null) {
593 result.actual_value_type = field.variable_type.get_actual_type (instance.value_type, null, field);
595 result.lvalue = true;
596 result.array_null_terminated = get_ccode_array_null_terminated (field);
597 if (get_ccode_array_length_expr (field) != null) {
598 result.array_length_cexpr = new CCodeConstant (get_ccode_array_length_expr (field));
600 result.ctype = get_ccode_type (field);
602 var array_type = result.value_type as ArrayType;
603 if (field.binding == MemberBinding.INSTANCE) {
604 CCodeExpression pub_inst = null;
606 if (instance != null) {
607 pub_inst = get_cvalue_ (instance);
610 var instance_target_type = SemanticAnalyzer.get_data_type_for_symbol (field.parent_symbol);
612 unowned Class? cl = instance_target_type.type_symbol as Class;
613 bool is_gtypeinstance = ((instance_target_type.type_symbol == cl) && (cl == null || !cl.is_compact));
615 CCodeExpression inst;
616 if (is_gtypeinstance && field.access == SymbolAccessibility.PRIVATE) {
617 inst = new CCodeMemberAccess.pointer (pub_inst, "priv");
620 generate_class_struct_declaration (cl, cfile);
626 // FIXME Report this with proper source-reference on the vala side!
627 Report.error (field.source_reference, "Invalid access to instance member `%s'", field.get_full_name ());
628 result.cvalue = new CCodeInvalidExpression ();
632 if (instance_target_type.type_symbol.is_reference_type () || (instance != null && instance.value_type is PointerType)) {
633 result.cvalue = new CCodeMemberAccess.pointer (inst, get_ccode_name (field));
635 result.cvalue = new CCodeMemberAccess (inst, get_ccode_name (field));
638 if (array_type != null && get_ccode_array_length (field)) {
639 for (int dim = 1; dim <= array_type.rank; dim++) {
640 CCodeExpression length_expr = null;
641 string length_cname = get_variable_array_length_cname (field, dim);
643 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
644 length_expr = new CCodeMemberAccess.pointer (inst, length_cname);
646 length_expr = new CCodeMemberAccess (inst, length_cname);
649 result.append_array_length_cvalue (length_expr);
651 if (array_type.rank == 1 && field.is_internal_symbol ()) {
652 string size_cname = get_array_size_cname (get_ccode_name (field));
654 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
655 set_array_size_cvalue (result, new CCodeMemberAccess.pointer (inst, size_cname));
657 set_array_size_cvalue (result, new CCodeMemberAccess (inst, size_cname));
660 } else if (get_ccode_delegate_target (field)) {
661 string target_cname = get_ccode_delegate_target_name (field);
662 string target_destroy_notify_cname = get_ccode_delegate_target_destroy_notify_name (field);
664 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
665 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (inst, target_cname);
666 if (result.value_type.is_disposable ()){
667 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (inst, target_destroy_notify_cname);
670 result.delegate_target_cvalue = new CCodeMemberAccess (inst, target_cname);
671 if (result.value_type.is_disposable ()) {
672 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess (inst, target_destroy_notify_cname);
676 } else if (field.binding == MemberBinding.CLASS) {
677 unowned Class cl = (Class) field.parent_symbol;
678 var cast = get_this_class_cexpression (cl, instance);
679 if (field.access == SymbolAccessibility.PRIVATE) {
680 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function (cl)));
681 ccall.add_argument (cast);
682 result.cvalue = new CCodeMemberAccess.pointer (ccall, get_ccode_name (field));
684 result.cvalue = new CCodeMemberAccess.pointer (cast, get_ccode_name (field));
688 generate_field_declaration (field, cfile);
690 result.cvalue = new CCodeIdentifier (get_ccode_name (field));
692 if (array_type != null && get_ccode_array_length (field)) {
693 for (int dim = 1; dim <= array_type.rank; dim++) {
694 string length_cname = get_variable_array_length_cname (field, dim);
695 result.append_array_length_cvalue (new CCodeIdentifier (length_cname));
697 if (array_type.rank == 1 && field.is_internal_symbol ()) {
698 set_array_size_cvalue (result, new CCodeIdentifier (get_array_size_cname (get_ccode_name (field))));
700 } else if (get_ccode_delegate_target (field)) {
701 result.delegate_target_cvalue = new CCodeIdentifier (get_ccode_delegate_target_name (field));
702 if (result.value_type.is_disposable ()) {
703 result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier (get_ccode_delegate_target_destroy_notify_name (field));
711 public override TargetValue load_variable (Variable variable, TargetValue value, Expression? expr = null) {
712 var result = (GLibValue) value;
713 var array_type = result.value_type as ArrayType;
714 var delegate_type = result.value_type as DelegateType;
715 if (array_type != null) {
716 if (array_type.fixed_length) {
717 result.array_length_cvalues = null;
718 result.append_array_length_cvalue (get_ccodenode (array_type.length));
719 result.lvalue = false;
720 } else if (get_ccode_array_null_terminated (variable)) {
721 requires_array_length = true;
722 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
723 len_call.add_argument (result.cvalue);
725 result.array_length_cvalues = null;
726 result.append_array_length_cvalue (len_call);
727 result.lvalue = false;
728 } else if (get_ccode_array_length_expr (variable) != null) {
729 var length_expr = new CCodeConstant (get_ccode_array_length_expr (variable));
731 result.array_length_cvalues = null;
732 result.append_array_length_cvalue (length_expr);
733 result.lvalue = false;
734 } else if (!get_ccode_array_length (variable)) {
735 result.array_length_cvalues = null;
736 for (int dim = 1; dim <= array_type.rank; dim++) {
737 result.append_array_length_cvalue (new CCodeConstant ("-1"));
739 result.lvalue = false;
740 } else if (get_ccode_array_length_type (variable.variable_type) != get_ccode_array_length_type (array_type)) {
741 for (int dim = 1; dim <= array_type.rank; dim++) {
742 // cast if variable does not use int for array length
743 result.array_length_cvalues[dim - 1] = new CCodeCastExpression (result.array_length_cvalues[dim - 1], get_ccode_array_length_type (array_type));
745 result.lvalue = false;
747 result.array_size_cvalue = null;
748 result.non_null = array_type.inline_allocated;
749 } else if (delegate_type != null) {
750 if (!get_ccode_delegate_target (variable)) {
751 result.delegate_target_cvalue = new CCodeConstant ("NULL");
752 result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
755 result.lvalue = false;
757 result.value_type.value_owned = false;
759 bool use_temp = true;
760 if (!is_lvalue_access_allowed (result.value_type)) {
761 // special handling for types such as va_list
764 if (variable is Parameter) {
765 var param = (Parameter) variable;
766 if (variable.name == "this") {
768 } else if ((param.direction != ParameterDirection.OUT)
769 && !(param.variable_type.is_real_non_null_struct_type ())) {
773 if (variable.single_assignment && !result.value_type.is_real_non_null_struct_type ()) {
774 // no need to copy values from variables that are assigned exactly once
775 // as there is no risk of modification
776 // except for structs that are always passed by reference
779 if (result.value_type.is_non_null_simple_type ()) {
780 // no need to an extra copy of variables that are stack allocated simple types
783 // our implementation of postfix-expressions require temporary variables
784 if (expr is MemberAccess && ((MemberAccess) expr).tainted_access) {
788 var local = variable as LocalVariable;
789 if (local != null && local.name[0] == '.') {
790 // already a temporary variable generated internally
791 // and safe to access without temporary variable
796 result = (GLibValue) store_temp_value (result, variable);
802 /* Returns unowned access to the given local variable */
803 public override TargetValue load_local (LocalVariable local, Expression? expr = null) {
804 return load_variable (local, get_local_cvalue (local), expr);
807 /* Returns unowned access to the given parameter */
808 public override TargetValue load_parameter (Parameter param, Expression? expr = null) {
809 return load_variable (param, get_parameter_cvalue (param), expr);
812 /* Convenience method returning access to "this" */
813 public override TargetValue load_this_parameter (TypeSymbol sym) {
814 var param = new Parameter ("this", SemanticAnalyzer.get_data_type_for_symbol (sym));
815 return load_parameter (param);
818 /* Returns unowned access to the given field */
819 public override TargetValue load_field (Field field, TargetValue? instance, Expression? expr = null) {
820 return load_variable (field, get_field_cvalue (field, instance), expr);