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 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 (get_ccode_upper_case_name (base_class
, null))));
55 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class
, null))));
57 set_cvalue (expr
, new CCodeMemberAccess
.pointer (vcast
, get_ccode_vfunc_name (m
)));
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 (get_ccode_lower_case_name (current_class
), get_ccode_lower_case_name (base_iface
));
63 set_cvalue (expr
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), get_ccode_vfunc_name (m
)));
68 if (m
.base_method
!= null) {
69 if (!method_has_wrapper (m
.base_method
)) {
70 var base_class
= (Class
) m
.base_method
.parent_symbol
;
71 var vclass
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (base_class
))));
72 vclass
.add_argument (pub_inst
);
73 set_cvalue (expr
, new CCodeMemberAccess
.pointer (vclass
, get_ccode_vfunc_name (m
)));
75 set_cvalue (expr
, new
CCodeIdentifier (get_ccode_name (m
.base_method
)));
77 } else if (m
.base_interface_method
!= null) {
78 set_cvalue (expr
, new
CCodeIdentifier (get_ccode_name (m
.base_interface_method
)));
79 } else if (m is CreationMethod
) {
80 set_cvalue (expr
, new
CCodeIdentifier (get_ccode_real_name (m
)));
82 set_cvalue (expr
, new
CCodeIdentifier (get_ccode_name (m
)));
85 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
86 if (m
.binding
== MemberBinding
.STATIC
) {
87 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
88 } else if (m
.is_async_callback
) {
89 if (current_method
.closure
) {
90 var block
= ((Method
) m
.parent_symbol
).body
;
91 set_delegate_target (expr
, new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), "_async_data_"));
93 set_delegate_target (expr
, new
CCodeIdentifier ("_data_"));
95 } else if (expr
.inner
!= null && !expr
.prototype_access
) {
96 // expr.inner is null in the special case of referencing the method in a constant initializer
97 var delegate_target
= (CCodeExpression
) get_ccodenode (expr
.inner
);
98 delegate_type
= expr
.target_type as DelegateType
;
99 if ((expr
.value_type
.value_owned
|| (delegate_type
!= null && delegate_type
.is_called_once
)) && expr
.inner
.value_type
.data_type
!= null && is_reference_counting (expr
.inner
.value_type
.data_type
)) {
100 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (expr
.inner
.value_type
, expr
.source_reference
));
101 ref_call
.add_argument (delegate_target
);
102 delegate_target
= ref_call
;
103 set_delegate_target_destroy_notify (expr
, get_destroy_func_expression (expr
.inner
.value_type
));
105 set_delegate_target (expr
, delegate_target
);
107 } else if (expr
.symbol_reference is ArrayLengthField
) {
108 if (expr
.value_type is ArrayType
&& !(expr
.parent_node is ElementAccess
)) {
109 Report
.error (expr
.source_reference
, "unsupported use of length field of multi-dimensional array");
111 set_cvalue (expr
, get_array_length_cexpression (expr
.inner
, 1));
112 } else if (expr
.symbol_reference is Field
) {
113 var field
= (Field
) expr
.symbol_reference
;
115 expr
.target_value
= get_field_cvalue (field
, expr
.inner
!= null ? expr
.inner
.target_value
: null);
117 expr
.target_value
= load_field (field
, expr
.inner
!= null ? expr
.inner
.target_value
: null);
119 } else if (expr
.symbol_reference is EnumValue
) {
120 var ev
= (EnumValue
) expr
.symbol_reference
;
122 generate_enum_declaration ((Enum
) ev
.parent_symbol
, cfile
);
124 set_cvalue (expr
, new
CCodeConstant (get_ccode_name (ev
)));
125 } else if (expr
.symbol_reference is Constant
) {
126 var c
= (Constant
) expr
.symbol_reference
;
128 generate_constant_declaration (c
, cfile
,
129 c
.source_reference
!= null && expr
.source_reference
!= null &&
130 c
.source_reference
.file
== expr
.source_reference
.file
);
132 string fn
= c
.get_full_name ();
133 if (fn
== "GLib.Log.FILE") {
134 string s
= Path
.get_basename (expr
.source_reference
.file
.filename
);
135 set_cvalue (expr
, new
CCodeConstant ("\"%s\"".printf (s
)));
136 } else if (fn
== "GLib.Log.LINE") {
137 int i
= expr
.source_reference
.begin
.line
;
138 set_cvalue (expr
, new
CCodeConstant ("%d".printf (i
)));
139 } else if (fn
== "GLib.Log.METHOD") {
141 if (current_method
!= null) {
142 s
= current_method
.get_full_name ();
144 set_cvalue (expr
, new
CCodeConstant ("\"%s\"".printf (s
)));
146 set_cvalue (expr
, new
CCodeIdentifier (get_ccode_name (c
)));
149 if (array_type
!= null) {
150 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_N_ELEMENTS"));
151 ccall
.add_argument (new
CCodeIdentifier (get_ccode_name (c
)));
152 append_array_length (expr
, ccall
);
154 } else if (expr
.symbol_reference is Property
) {
155 var prop
= (Property
) expr
.symbol_reference
;
157 if (!(prop is DynamicProperty
)) {
158 generate_property_accessor_declaration (prop
.get_accessor
, cfile
);
160 if (!prop
.external
&& prop
.external_package
) {
161 // internal VAPI properties
162 // only add them once per source file
163 if (add_generated_external_symbol (prop
)) {
164 visit_property (prop
);
169 if (expr
.inner is BaseAccess
) {
170 var base_prop
= prop
;
171 if (prop
.base_property
!= null) {
172 base_prop
= prop
.base_property
;
173 } else if (prop
.base_interface_property
!= null) {
174 base_prop
= prop
.base_interface_property
;
176 if (base_prop
.parent_symbol is Class
) {
177 var base_class
= (Class
) base_prop
.parent_symbol
;
178 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class
, null))));
179 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class
, null))));
181 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "get_%s".printf (prop
.name
)));
182 ccall
.add_argument (get_cvalue (expr
.inner
));
183 if (prop
.property_type
.is_real_non_null_struct_type ()) {
184 var temp_value
= (GLibValue
) create_temp_value (prop
.get_accessor
.value_type
, false, expr
);
185 expr
.target_value
= load_temp_value (temp_value
);
186 var ctemp
= get_cvalue_ (temp_value
);
187 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
188 ccode
.add_expression (ccall
);
190 set_cvalue (expr
, ccall
);
192 } else if (base_prop
.parent_symbol is Interface
) {
193 var base_iface
= (Interface
) base_prop
.parent_symbol
;
194 string parent_iface_var
= "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class
), get_ccode_lower_case_name (base_iface
));
196 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), "get_%s".printf (prop
.name
)));
197 ccall
.add_argument (get_cvalue (expr
.inner
));
198 if (prop
.property_type
.is_real_non_null_struct_type ()) {
199 var temp_value
= (GLibValue
) create_temp_value (prop
.get_accessor
.value_type
, false, expr
);
200 expr
.target_value
= load_temp_value (temp_value
);
201 var ctemp
= get_cvalue_ (temp_value
);
202 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
203 ccode
.add_expression (ccall
);
205 set_cvalue (expr
, ccall
);
208 } else if (prop
.binding
== MemberBinding
.INSTANCE
&&
209 prop
.get_accessor
.automatic_body
&&
210 !prop
.get_accessor
.value_type
.value_owned
&&
211 current_type_symbol
== prop
.parent_symbol
&&
212 current_type_symbol is Class
&&
213 prop
.base_property
== null &&
214 prop
.base_interface_property
== null &&
215 !(prop
.property_type is ArrayType
|| prop
.property_type is DelegateType
)) {
216 CCodeExpression inst
;
217 inst
= new CCodeMemberAccess
.pointer (pub_inst
, "priv");
218 set_cvalue (expr
, new CCodeMemberAccess
.pointer (inst
, get_ccode_name (prop
.field
)));
219 } else if (!get_ccode_no_accessor_method (prop
)) {
221 if (prop is DynamicProperty
) {
222 getter_cname
= get_dynamic_property_getter_cname ((DynamicProperty
) prop
);
224 getter_cname
= get_ccode_name (prop
.get_accessor
);
226 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (getter_cname
));
228 if (prop
.binding
== MemberBinding
.INSTANCE
) {
229 if (prop
.parent_symbol is Struct
&& !((Struct
) prop
.parent_symbol
).is_simple_type ()) {
230 // we need to pass struct instance by reference
231 var instance
= expr
.inner
.target_value
;
232 if (!get_lvalue (instance
)) {
233 instance
= store_temp_value (instance
, expr
);
235 pub_inst
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue_ (instance
));
238 ccall
.add_argument (pub_inst
);
241 bool prop_is_real_non_null_struct_type
= prop
.property_type
.is_real_non_null_struct_type ();
242 var temp_value
= (GLibValue
) create_temp_value (prop
.get_accessor
.value_type
, prop_is_real_non_null_struct_type
, expr
);
243 expr
.target_value
= load_temp_value (temp_value
);
244 var ctemp
= get_cvalue_ (temp_value
);
246 // Property access to real struct types is handled differently
247 // The value is returned by out parameter
248 if (prop_is_real_non_null_struct_type
) {
249 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
250 ccode
.add_expression (ccall
);
252 ccode
.add_assignment (ctemp
, ccall
);
254 array_type
= prop
.property_type as ArrayType
;
255 if (array_type
!= null) {
256 if (get_ccode_array_null_terminated (prop
)) {
257 requires_array_length
= true;
258 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
259 len_call
.add_argument (ctemp
);
261 ccode
.add_assignment (temp_value
.array_length_cvalues
[0], len_call
);
262 } else if (get_ccode_array_length (prop
)) {
263 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
264 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_length_cvalue (temp_value
, dim
)));
268 delegate_type
= prop
.property_type as DelegateType
;
269 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
270 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_delegate_target_cvalue (temp_value
)));
275 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_get"));
276 ccall
.add_argument (pub_inst
);
278 // property name is second argument of g_object_get
279 ccall
.add_argument (get_property_canonical_cconstant (prop
));
281 // g_object_get always returns owned values
282 // therefore, property getters of properties
283 // without accessor methods need to be marked as owned
284 if (!prop
.get_accessor
.value_type
.value_owned
) {
285 // only report error for types where there actually
286 // is a difference between `owned' and `unowned'
287 var owned_value_type
= prop
.get_accessor
.value_type
.copy ();
288 owned_value_type
.value_owned
= true;
289 if (requires_copy (owned_value_type
)) {
290 Report
.error (prop
.get_accessor
.source_reference
, "unowned return value for getter of property `%s' not supported without accessor".printf (prop
.get_full_name ()));
294 if (expr
.value_type
.is_real_struct_type ()) {
295 // gobject allocates structs on heap
296 expr
.value_type
.nullable
= true;
299 var temp_var
= get_temp_variable (expr
.value_type
);
300 var ctemp
= get_variable_cexpression (temp_var
.name
);
301 emit_temp_var (temp_var
);
302 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
303 ccall
.add_argument (new
CCodeConstant ("NULL"));
304 ccode
.add_expression (ccall
);
305 set_cvalue (expr
, ctemp
);
307 expr
.target_value
.value_type
= expr
.value_type
;
308 expr
.target_value
= store_temp_value (expr
.target_value
, expr
);
309 } else if (expr
.symbol_reference is LocalVariable
) {
310 var local
= (LocalVariable
) expr
.symbol_reference
;
312 if (expr
.parent_node is ReturnStatement
&&
313 current_return_type
.value_owned
&&
314 local
.variable_type
.value_owned
&&
316 !variable_accessible_in_finally (local
) &&
317 !(local
.variable_type is ArrayType
&& ((ArrayType
) local
.variable_type
).inline_allocated
)) {
318 /* return expression is local variable taking ownership and
319 * current method is transferring ownership */
321 // don't ref expression
322 expr
.value_type
.value_owned
= true;
324 // don't unref variable
325 local
.active
= false;
327 var glib_value
= (GLibValue
) get_local_cvalue (local
);
328 expr
.target_value
= glib_value
;
329 if (glib_value
.delegate_target_cvalue
== null) {
330 glib_value
.delegate_target_cvalue
= new
CCodeConstant ("NULL");
332 if (glib_value
.delegate_target_destroy_notify_cvalue
== null) {
333 glib_value
.delegate_target_destroy_notify_cvalue
= new
CCodeConstant ("NULL");
337 expr
.target_value
= get_local_cvalue (local
);
339 expr
.target_value
= load_local (local
);
342 } else if (expr
.symbol_reference is Parameter
) {
343 var param
= (Parameter
) expr
.symbol_reference
;
345 expr
.target_value
= get_parameter_cvalue (param
);
347 expr
.target_value
= load_parameter (param
);
352 /* Returns lvalue access to the given local variable */
353 public override TargetValue
get_local_cvalue (LocalVariable local
) {
354 var result
= new
GLibValue (local
.variable_type
.copy ());
355 result
.lvalue
= true;
357 var array_type
= local
.variable_type as ArrayType
;
358 var delegate_type
= local
.variable_type as DelegateType
;
359 if (local
.is_result
) {
360 // used in postconditions
361 // structs are returned as out parameter
362 if (local
.variable_type
!= null && local
.variable_type
.is_real_non_null_struct_type ()) {
363 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("result"));
365 result
.cvalue
= new
CCodeIdentifier ("result");
367 if (array_type
!= null && !array_type
.fixed_length
&& ((current_method
!= null && get_ccode_array_length (current_method
)) || current_property_accessor
!= null)) {
368 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
369 result
.append_array_length_cvalue (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_array_length_cname ("result", dim
))));
372 } else if (local
.captured
) {
373 // captured variables are stored on the heap
374 var block
= (Block
) local
.parent_symbol
;
375 result
.cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_local_cname (local
));
376 if (array_type
!= null && !array_type
.fixed_length
) {
377 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
378 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
)));
380 if (array_type
.rank
== 1) {
381 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
)));
383 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
384 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
)));
385 if (delegate_type
.is_disposable ()) {
386 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
)));
390 result
.cvalue
= get_local_cexpression (local
);
391 if (array_type
!= null && !array_type
.fixed_length
) {
392 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
393 result
.append_array_length_cvalue (get_variable_cexpression (get_array_length_cname (get_local_cname (local
), dim
)));
395 if (array_type
.rank
== 1) {
396 result
.array_size_cvalue
= get_variable_cexpression (get_array_size_cname (get_local_cname (local
)));
398 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
399 if (is_in_coroutine ()) {
400 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), get_delegate_target_cname (get_local_cname (local
)));
401 if (local
.variable_type
.value_owned
) {
402 result
.delegate_target_destroy_notify_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), get_delegate_target_destroy_notify_cname (get_local_cname (local
)));
405 result
.delegate_target_cvalue
= new
CCodeIdentifier (get_delegate_target_cname (get_local_cname (local
)));
406 if (local
.variable_type
.value_owned
) {
407 result
.delegate_target_destroy_notify_cvalue
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_local_cname (local
)));
416 /* Returns access values to the given parameter */
417 public override TargetValue
get_parameter_cvalue (Parameter param
) {
418 var result
= new
GLibValue (param
.variable_type
.copy ());
419 result
.lvalue
= true;
420 result
.array_null_terminated
= get_ccode_array_null_terminated (param
);
421 if (get_ccode_array_length_expr (param
) != null) {
422 result
.array_length_cexpr
= new
CCodeConstant (get_ccode_array_length_expr (param
));
424 result
.ctype
= get_ccode_type (param
);
426 var array_type
= result
.value_type as ArrayType
;
427 var delegate_type
= result
.value_type as DelegateType
;
429 bool is_unowned_delegate
= delegate_type
!= null && !param
.variable_type
.value_owned
;
430 if ((param
.captured
|| is_in_coroutine ()) && !is_unowned_delegate
) {
431 result
.value_type
.value_owned
= true;
434 if (param
.name
== "this") {
435 if (is_in_coroutine ()) {
437 result
.cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "self");
439 var st
= result
.value_type
.data_type as Struct
;
440 if (st
!= null && !st
.is_simple_type ()) {
441 result
.cvalue
= new
CCodeIdentifier ("(*self)");
443 result
.cvalue
= new
CCodeIdentifier ("self");
447 string name
= param
.name
;
449 if (param
.captured
) {
450 // captured variables are stored on the heap
451 var block
= param
.parent_symbol as Block
;
453 block
= ((Method
) param
.parent_symbol
).body
;
455 result
.cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_variable_cname (param
.name
));
456 if (array_type
!= null && get_ccode_array_length (param
)) {
457 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
458 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
)));
460 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
461 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_ccode_delegate_target_name (param
));
462 if (result
.value_type
.is_disposable ()) {
463 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
)));
466 } else if (is_in_coroutine ()) {
468 result
.cvalue
= get_variable_cexpression (param
.name
);
469 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
470 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), get_ccode_delegate_target_name (param
));
471 if (delegate_type
.is_disposable ()) {
472 result
.delegate_target_destroy_notify_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
476 var type_as_struct
= result
.value_type
.data_type as Struct
;
478 if (param
.direction
== ParameterDirection
.OUT
) {
479 name
= "_vala_%s".printf (name
);
482 if (param
.direction
== ParameterDirection
.REF
||
483 (param
.direction
== ParameterDirection
.IN
&& type_as_struct
!= null && !type_as_struct
.is_simple_type () && !result
.value_type
.nullable
)) {
484 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier (get_variable_cname (name
)));
486 // Property setters of non simple structs shall replace all occurrences
487 // of the "value" formal parameter with a dereferencing version of that
489 if (current_property_accessor
!= null &&
490 current_property_accessor
.writable
&&
491 current_property_accessor
.value_parameter
== param
&&
492 current_property_accessor
.prop
.property_type
.is_real_struct_type () &&
493 !current_property_accessor
.prop
.property_type
.nullable
) {
494 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("value"));
496 result
.cvalue
= get_variable_cexpression (name
);
499 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
500 var target_cname
= get_ccode_delegate_target_name (param
);
501 if (param
.direction
== ParameterDirection
.OUT
) {
502 target_cname
= "_vala_%s".printf (target_cname
);
504 CCodeExpression target_expr
= new
CCodeIdentifier (target_cname
);
505 CCodeExpression delegate_target_destroy_notify
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (name
)));
506 if (param
.direction
== ParameterDirection
.REF
) {
507 // accessing argument of ref param
508 target_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_expr
);
509 delegate_target_destroy_notify
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, delegate_target_destroy_notify
);
511 result
.delegate_target_cvalue
= target_expr
;
512 if (result
.value_type
.is_disposable ()) {
513 result
.delegate_target_destroy_notify_cvalue
= delegate_target_destroy_notify
;
517 if (!param
.captured
&& array_type
!= null) {
518 if (get_ccode_array_length (param
) && !get_ccode_array_null_terminated (param
)) {
519 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
520 CCodeExpression length_expr
= get_variable_cexpression (get_parameter_array_length_cname (param
, dim
));
521 if (param
.direction
== ParameterDirection
.OUT
) {
522 length_expr
= get_variable_cexpression (get_array_length_cname (get_variable_cname (name
), dim
));
523 } else if (param
.direction
== ParameterDirection
.REF
) {
524 // accessing argument of ref param
525 length_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, length_expr
);
527 result
.append_array_length_cvalue (length_expr
);
536 /* Returns lvalue access to the given field */
537 public override TargetValue
get_field_cvalue (Field field
, TargetValue? instance
) {
538 var value_type
= field
.variable_type
.copy ();
540 var result
= new
GLibValue (value_type
);
541 if (instance
!= null) {
542 result
.actual_value_type
= field
.variable_type
.get_actual_type (instance
.value_type
, null, field
);
544 result
.lvalue
= true;
545 result
.array_null_terminated
= get_ccode_array_null_terminated (field
);
546 if (get_ccode_array_length_expr (field
) != null) {
547 result
.array_length_cexpr
= new
CCodeConstant (get_ccode_array_length_expr (field
));
549 result
.ctype
= get_ccode_type (field
);
551 var array_type
= result
.value_type as ArrayType
;
552 var delegate_type
= result
.value_type as DelegateType
;
553 if (field
.binding
== MemberBinding
.INSTANCE
) {
554 CCodeExpression pub_inst
= null;
556 if (instance
!= null) {
557 pub_inst
= get_cvalue_ (instance
);
560 var instance_target_type
= get_data_type_for_symbol ((TypeSymbol
) field
.parent_symbol
);
562 var cl
= instance_target_type
.data_type as Class
;
563 bool is_gtypeinstance
= ((instance_target_type
.data_type
== cl
) && (cl
== null || !cl
.is_compact
));
565 CCodeExpression inst
;
566 if (is_gtypeinstance
&& field
.access
== SymbolAccessibility
.PRIVATE
) {
567 inst
= new CCodeMemberAccess
.pointer (pub_inst
, "priv");
570 generate_class_struct_declaration (cl
, cfile
);
576 // FIXME Report this with proper source-reference on the vala side!
577 Report
.error (field
.source_reference
, "Invalid access to instance member `%s'".printf (field
.get_full_name ()));
578 result
.cvalue
= new
CCodeInvalidExpression ();
582 if (instance_target_type
.data_type
.is_reference_type () || (instance
!= null && instance
.value_type is PointerType
)) {
583 result
.cvalue
= new CCodeMemberAccess
.pointer (inst
, get_ccode_name (field
));
585 result
.cvalue
= new
CCodeMemberAccess (inst
, get_ccode_name (field
));
588 if (array_type
!= null && get_ccode_array_length (field
)) {
589 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
590 CCodeExpression length_expr
= null;
593 if (get_ccode_array_length_name (field
) != null) {
594 length_cname
= get_ccode_array_length_name (field
);
596 length_cname
= get_array_length_cname (get_ccode_name (field
), dim
);
599 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
600 length_expr
= new CCodeMemberAccess
.pointer (inst
, length_cname
);
602 length_expr
= new
CCodeMemberAccess (inst
, length_cname
);
605 result
.append_array_length_cvalue (length_expr
);
607 if (array_type
.rank
== 1 && field
.is_internal_symbol ()) {
608 string size_cname
= get_array_size_cname (get_ccode_name (field
));
610 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
611 set_array_size_cvalue (result
, new CCodeMemberAccess
.pointer (inst
, size_cname
));
613 set_array_size_cvalue (result
, new
CCodeMemberAccess (inst
, size_cname
));
616 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
&& get_ccode_delegate_target (field
)) {
617 string target_cname
= get_ccode_delegate_target_name (field
);
618 string target_destroy_notify_cname
= get_delegate_target_destroy_notify_cname (get_ccode_name (field
));
620 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
621 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (inst
, target_cname
);
622 if (result
.value_type
.is_disposable ()){
623 result
.delegate_target_destroy_notify_cvalue
= new CCodeMemberAccess
.pointer (inst
, target_destroy_notify_cname
);
626 result
.delegate_target_cvalue
= new
CCodeMemberAccess (inst
, target_cname
);
627 if (result
.value_type
.is_disposable ()) {
628 result
.delegate_target_destroy_notify_cvalue
= new
CCodeMemberAccess (inst
, target_destroy_notify_cname
);
632 } else if (field
.binding
== MemberBinding
.CLASS
) {
633 var cl
= (Class
) field
.parent_symbol
;
634 var cast
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_upper_case_name (cl
, null) + "_CLASS"));
636 CCodeExpression klass
;
637 if (instance
== null) {
638 if (get_this_type () == null) {
639 // Accessing the field from a static or class constructor
640 klass
= new
CCodeIdentifier ("klass");
642 // Accessing the field from within an instance method
643 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
644 k
.add_argument (new
CCodeIdentifier ("self"));
648 // Accessing the field of an instance
649 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
650 k
.add_argument (get_cvalue_ (instance
));
653 cast
.add_argument (klass
);
655 if (field
.access
== SymbolAccessibility
.PRIVATE
) {
656 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (get_ccode_upper_case_name (cl
))));
657 ccall
.add_argument (klass
);
658 result
.cvalue
= new CCodeMemberAccess
.pointer (ccall
, get_ccode_name (field
));
660 result
.cvalue
= new CCodeMemberAccess
.pointer (cast
, get_ccode_name (field
));
664 generate_field_declaration (field
, cfile
);
666 result
.cvalue
= new
CCodeIdentifier (get_ccode_name (field
));
668 if (array_type
!= null && get_ccode_array_length (field
)) {
669 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
671 if (get_ccode_array_length_name (field
) != null) {
672 length_cname
= get_ccode_array_length_name (field
);
674 length_cname
= get_array_length_cname (get_ccode_name (field
), dim
);
677 result
.append_array_length_cvalue (new
CCodeIdentifier (length_cname
));
679 if (array_type
.rank
== 1 && field
.is_internal_symbol ()) {
680 set_array_size_cvalue (result
, new
CCodeIdentifier (get_array_size_cname (get_ccode_name (field
))));
682 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
&& get_ccode_delegate_target (field
)) {
683 result
.delegate_target_cvalue
= new
CCodeIdentifier (get_ccode_delegate_target_name (field
));
684 if (result
.value_type
.is_disposable ()) {
685 result
.delegate_target_destroy_notify_cvalue
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_ccode_name (field
)));
693 public override TargetValue
load_variable (Variable variable
, TargetValue value
) {
694 var result
= (GLibValue
) value
;
695 var array_type
= result
.value_type as ArrayType
;
696 var delegate_type
= result
.value_type as DelegateType
;
697 if (array_type
!= null) {
698 if (array_type
.fixed_length
) {
699 result
.array_length_cvalues
= null;
700 result
.append_array_length_cvalue (get_ccodenode (array_type
.length
));
701 result
.lvalue
= false;
702 } else if (get_ccode_array_null_terminated (variable
)) {
703 requires_array_length
= true;
704 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
705 len_call
.add_argument (result
.cvalue
);
707 result
.array_length_cvalues
= null;
708 result
.append_array_length_cvalue (len_call
);
709 result
.lvalue
= false;
710 } else if (get_ccode_array_length_expr (variable
) != null) {
711 var length_expr
= new
CCodeConstant (get_ccode_array_length_expr (variable
));
713 result
.array_length_cvalues
= null;
714 result
.append_array_length_cvalue (length_expr
);
715 result
.lvalue
= false;
716 } else if (!get_ccode_array_length (variable
)) {
717 result
.array_length_cvalues
= null;
718 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
719 result
.append_array_length_cvalue (new
CCodeConstant ("-1"));
721 result
.lvalue
= false;
722 } else if (get_ccode_array_length_type (variable
) != null) {
723 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
724 // cast if variable does not use int for array length
725 result
.array_length_cvalues
[dim
- 1] = new
CCodeCastExpression (result
.array_length_cvalues
[dim
- 1], "gint");
727 result
.lvalue
= false;
729 result
.array_size_cvalue
= null;
730 } else if (delegate_type
!= null) {
731 if (!delegate_type
.delegate_symbol
.has_target
|| !get_ccode_delegate_target (variable
)) {
732 result
.delegate_target_cvalue
= new
CCodeConstant ("NULL");
735 result
.delegate_target_destroy_notify_cvalue
= new
CCodeConstant ("NULL");
736 result
.lvalue
= false;
738 result
.value_type
.value_owned
= false;
740 bool use_temp
= true;
741 if (!is_lvalue_access_allowed (result
.value_type
)) {
742 // special handling for types such as va_list
745 if (variable is Parameter
&& variable
.name
== "this") {
748 if (variable
.single_assignment
&& !result
.value_type
.is_real_non_null_struct_type ()) {
749 // no need to copy values from variables that are assigned exactly once
750 // as there is no risk of modification
751 // except for structs that are always passed by reference
754 var local
= variable as LocalVariable
;
755 if (local
!= null && local
.name
[0] == '.') {
756 // already a temporary variable generated internally
757 // and safe to access without temporary variable
762 result
= (GLibValue
) store_temp_value (result
, variable
);
768 /* Returns unowned access to the given local variable */
769 public override TargetValue
load_local (LocalVariable local
) {
770 return load_variable (local
, get_local_cvalue (local
));
773 /* Returns unowned access to the given parameter */
774 public override TargetValue
load_parameter (Parameter param
) {
775 return load_variable (param
, get_parameter_cvalue (param
));
778 /* Convenience method returning access to "this" */
779 public override TargetValue
load_this_parameter (TypeSymbol sym
) {
780 var param
= new
Parameter ("this", get_data_type_for_symbol (sym
));
781 return load_parameter (param
);
784 /* Returns unowned access to the given field */
785 public override TargetValue
load_field (Field field
, TargetValue? instance
) {
786 return load_variable (field
, get_field_cvalue (field
, instance
));