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 if (!base_class
.is_compact
) {
72 var vclass
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (base_class
))));
73 vclass
.add_argument (pub_inst
);
74 set_cvalue (expr
, new CCodeMemberAccess
.pointer (vclass
, get_ccode_vfunc_name (m
)));
76 set_cvalue (expr
, new CCodeMemberAccess
.pointer (pub_inst
, get_ccode_vfunc_name (m
)));
79 set_cvalue (expr
, new
CCodeIdentifier (get_ccode_name (m
.base_method
)));
81 } else if (m
.base_interface_method
!= null) {
82 set_cvalue (expr
, new
CCodeIdentifier (get_ccode_name (m
.base_interface_method
)));
83 } else if (m is CreationMethod
) {
84 set_cvalue (expr
, new
CCodeIdentifier (get_ccode_real_name (m
)));
86 set_cvalue (expr
, new
CCodeIdentifier (get_ccode_name (m
)));
89 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
90 if (m
.binding
== MemberBinding
.STATIC
) {
91 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
92 } else if (m
.is_async_callback
) {
93 if (current_method
.closure
) {
94 var block
= ((Method
) m
.parent_symbol
).body
;
95 set_delegate_target (expr
, new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), "_async_data_"));
97 set_delegate_target (expr
, new
CCodeIdentifier ("_data_"));
99 } else if (expr
.inner
!= null && !expr
.prototype_access
) {
100 // expr.inner is null in the special case of referencing the method in a constant initializer
101 var delegate_target
= (CCodeExpression
) get_ccodenode (expr
.inner
);
102 delegate_type
= expr
.target_type as DelegateType
;
103 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
)) {
104 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (expr
.inner
.value_type
, expr
.source_reference
));
105 ref_call
.add_argument (delegate_target
);
106 delegate_target
= ref_call
;
107 set_delegate_target_destroy_notify (expr
, get_destroy_func_expression (expr
.inner
.value_type
));
109 set_delegate_target (expr
, delegate_target
);
111 } else if (expr
.symbol_reference is ArrayLengthField
) {
112 if (expr
.value_type is ArrayType
&& !(expr
.parent_node is ElementAccess
)) {
113 Report
.error (expr
.source_reference
, "unsupported use of length field of multi-dimensional array");
115 set_cvalue (expr
, get_array_length_cexpression (expr
.inner
, 1));
116 } else if (expr
.symbol_reference is Field
) {
117 var field
= (Field
) expr
.symbol_reference
;
119 expr
.target_value
= get_field_cvalue (field
, expr
.inner
!= null ? expr
.inner
.target_value
: null);
121 expr
.target_value
= load_field (field
, expr
.inner
!= null ? expr
.inner
.target_value
: null);
123 } else if (expr
.symbol_reference is EnumValue
) {
124 var ev
= (EnumValue
) expr
.symbol_reference
;
126 generate_enum_declaration ((Enum
) ev
.parent_symbol
, cfile
);
128 set_cvalue (expr
, new
CCodeConstant (get_ccode_name (ev
)));
129 } else if (expr
.symbol_reference is Constant
) {
130 var c
= (Constant
) expr
.symbol_reference
;
132 generate_constant_declaration (c
, cfile
,
133 c
.source_reference
!= null && expr
.source_reference
!= null &&
134 c
.source_reference
.file
== expr
.source_reference
.file
);
136 string fn
= c
.get_full_name ();
137 if (fn
== "GLib.Log.FILE") {
138 string s
= Path
.get_basename (expr
.source_reference
.file
.filename
);
139 set_cvalue (expr
, new
CCodeConstant ("\"%s\"".printf (s
)));
140 } else if (fn
== "GLib.Log.LINE") {
141 int i
= expr
.source_reference
.begin
.line
;
142 set_cvalue (expr
, new
CCodeConstant ("%d".printf (i
)));
143 } else if (fn
== "GLib.Log.METHOD") {
145 if (current_method
!= null) {
146 s
= current_method
.get_full_name ();
148 set_cvalue (expr
, new
CCodeConstant ("\"%s\"".printf (s
)));
150 set_cvalue (expr
, new
CCodeIdentifier (get_ccode_name (c
)));
153 if (array_type
!= null) {
155 for (int i
= 0; i
< array_type
.rank
; i
++) {
156 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_N_ELEMENTS"));
157 ccall
.add_argument (new
CCodeIdentifier (get_ccode_name (c
) + sub
));
158 append_array_length (expr
, ccall
);
162 } else if (expr
.symbol_reference is Property
) {
163 var prop
= (Property
) expr
.symbol_reference
;
165 if (!(prop is DynamicProperty
)) {
166 generate_property_accessor_declaration (prop
.get_accessor
, cfile
);
168 if (!prop
.external
&& prop
.external_package
) {
169 // internal VAPI properties
170 // only add them once per source file
171 if (add_generated_external_symbol (prop
)) {
172 visit_property (prop
);
177 if (expr
.inner is BaseAccess
) {
178 var base_prop
= prop
;
179 if (prop
.base_property
!= null) {
180 base_prop
= prop
.base_property
;
181 } else if (prop
.base_interface_property
!= null) {
182 base_prop
= prop
.base_interface_property
;
184 if (base_prop
.parent_symbol is Class
) {
185 var base_class
= (Class
) base_prop
.parent_symbol
;
186 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class
, null))));
187 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class
, null))));
189 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "get_%s".printf (prop
.name
)));
190 ccall
.add_argument (get_cvalue (expr
.inner
));
191 if (prop
.property_type
.is_real_non_null_struct_type ()) {
192 var temp_value
= (GLibValue
) create_temp_value (prop
.get_accessor
.value_type
, false, expr
);
193 expr
.target_value
= load_temp_value (temp_value
);
194 var ctemp
= get_cvalue_ (temp_value
);
195 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
196 ccode
.add_expression (ccall
);
198 set_cvalue (expr
, ccall
);
200 } else if (base_prop
.parent_symbol is Interface
) {
201 var base_iface
= (Interface
) base_prop
.parent_symbol
;
202 string parent_iface_var
= "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class
), get_ccode_lower_case_name (base_iface
));
204 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), "get_%s".printf (prop
.name
)));
205 ccall
.add_argument (get_cvalue (expr
.inner
));
206 if (prop
.property_type
.is_real_non_null_struct_type ()) {
207 var temp_value
= (GLibValue
) create_temp_value (prop
.get_accessor
.value_type
, false, expr
);
208 expr
.target_value
= load_temp_value (temp_value
);
209 var ctemp
= get_cvalue_ (temp_value
);
210 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
211 ccode
.add_expression (ccall
);
213 set_cvalue (expr
, ccall
);
216 } else if (prop
.binding
== MemberBinding
.INSTANCE
&&
217 prop
.get_accessor
.automatic_body
&&
218 !prop
.get_accessor
.value_type
.value_owned
&&
219 current_type_symbol
== prop
.parent_symbol
&&
220 current_type_symbol is Class
&&
221 prop
.base_property
== null &&
222 prop
.base_interface_property
== null &&
223 !(prop
.property_type is ArrayType
|| prop
.property_type is DelegateType
)) {
224 CCodeExpression inst
;
225 inst
= new CCodeMemberAccess
.pointer (pub_inst
, "priv");
226 set_cvalue (expr
, new CCodeMemberAccess
.pointer (inst
, get_ccode_name (prop
.field
)));
227 } else if (!get_ccode_no_accessor_method (prop
)) {
229 if (prop is DynamicProperty
) {
230 getter_cname
= get_dynamic_property_getter_cname ((DynamicProperty
) prop
);
232 getter_cname
= get_ccode_name (prop
.get_accessor
);
234 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (getter_cname
));
236 if (prop
.binding
== MemberBinding
.INSTANCE
) {
237 if (prop
.parent_symbol is Struct
&& !((Struct
) prop
.parent_symbol
).is_simple_type ()) {
238 // we need to pass struct instance by reference
239 var instance
= expr
.inner
.target_value
;
240 if (!get_lvalue (instance
)) {
241 instance
= store_temp_value (instance
, expr
);
243 pub_inst
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue_ (instance
));
246 ccall
.add_argument (pub_inst
);
249 bool prop_is_real_non_null_struct_type
= prop
.property_type
.is_real_non_null_struct_type ();
250 var temp_value
= (GLibValue
) create_temp_value (prop
.get_accessor
.value_type
, prop_is_real_non_null_struct_type
, expr
);
251 expr
.target_value
= load_temp_value (temp_value
);
252 var ctemp
= get_cvalue_ (temp_value
);
254 // Property access to real struct types is handled differently
255 // The value is returned by out parameter
256 if (prop_is_real_non_null_struct_type
) {
257 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
258 ccode
.add_expression (ccall
);
260 ccode
.add_assignment (ctemp
, ccall
);
262 array_type
= prop
.property_type as ArrayType
;
263 if (array_type
!= null) {
264 if (get_ccode_array_null_terminated (prop
)) {
265 requires_array_length
= true;
266 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
267 len_call
.add_argument (ctemp
);
269 ccode
.add_assignment (temp_value
.array_length_cvalues
[0], len_call
);
270 } else if (get_ccode_array_length (prop
)) {
271 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
272 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_length_cvalue (temp_value
, dim
)));
276 delegate_type
= prop
.property_type as DelegateType
;
277 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
278 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_delegate_target_cvalue (temp_value
)));
283 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_get"));
284 ccall
.add_argument (pub_inst
);
286 // property name is second argument of g_object_get
287 ccall
.add_argument (get_property_canonical_cconstant (prop
));
289 // g_object_get always returns owned values
290 // therefore, property getters of properties
291 // without accessor methods need to be marked as owned
292 if (!prop
.get_accessor
.value_type
.value_owned
) {
293 // only report error for types where there actually
294 // is a difference between `owned' and `unowned'
295 var owned_value_type
= prop
.get_accessor
.value_type
.copy ();
296 owned_value_type
.value_owned
= true;
297 if (requires_copy (owned_value_type
)) {
298 Report
.error (prop
.get_accessor
.source_reference
, "unowned return value for getter of property `%s' not supported without accessor".printf (prop
.get_full_name ()));
302 if (expr
.value_type
.is_real_struct_type ()) {
303 // gobject allocates structs on heap
304 expr
.value_type
.nullable
= true;
307 var temp_var
= get_temp_variable (expr
.value_type
);
308 var ctemp
= get_variable_cexpression (temp_var
.name
);
309 emit_temp_var (temp_var
);
310 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
311 ccall
.add_argument (new
CCodeConstant ("NULL"));
312 ccode
.add_expression (ccall
);
313 set_cvalue (expr
, ctemp
);
315 expr
.target_value
.value_type
= expr
.value_type
;
316 expr
.target_value
= store_temp_value (expr
.target_value
, expr
);
317 } else if (expr
.symbol_reference is LocalVariable
) {
318 var local
= (LocalVariable
) expr
.symbol_reference
;
320 if (expr
.parent_node is ReturnStatement
&&
321 current_return_type
.value_owned
&&
322 local
.variable_type
.value_owned
&&
324 !variable_accessible_in_finally (local
) &&
325 !(local
.variable_type is ArrayType
&& ((ArrayType
) local
.variable_type
).inline_allocated
)) {
326 /* return expression is local variable taking ownership and
327 * current method is transferring ownership */
329 // don't ref expression
330 expr
.value_type
.value_owned
= true;
332 // don't unref variable
333 local
.active
= false;
335 var glib_value
= (GLibValue
) get_local_cvalue (local
);
336 expr
.target_value
= glib_value
;
337 if (glib_value
.delegate_target_cvalue
== null) {
338 glib_value
.delegate_target_cvalue
= new
CCodeConstant ("NULL");
340 if (glib_value
.delegate_target_destroy_notify_cvalue
== null) {
341 glib_value
.delegate_target_destroy_notify_cvalue
= new
CCodeConstant ("NULL");
345 expr
.target_value
= get_local_cvalue (local
);
347 expr
.target_value
= load_local (local
);
350 } else if (expr
.symbol_reference is Parameter
) {
351 var param
= (Parameter
) expr
.symbol_reference
;
353 expr
.target_value
= get_parameter_cvalue (param
);
355 expr
.target_value
= load_parameter (param
);
360 /* Returns lvalue access to the given local variable */
361 public override TargetValue
get_local_cvalue (LocalVariable local
) {
362 var result
= new
GLibValue (local
.variable_type
.copy ());
363 result
.lvalue
= true;
365 var array_type
= local
.variable_type as ArrayType
;
366 var delegate_type
= local
.variable_type as DelegateType
;
367 if (local
.is_result
) {
368 // used in postconditions
369 // structs are returned as out parameter
370 if (local
.variable_type
!= null && local
.variable_type
.is_real_non_null_struct_type ()) {
371 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("result"));
373 result
.cvalue
= new
CCodeIdentifier ("result");
375 if (array_type
!= null && !array_type
.fixed_length
&& ((current_method
!= null && get_ccode_array_length (current_method
)) || current_property_accessor
!= null)) {
376 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
377 result
.append_array_length_cvalue (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_array_length_cname ("result", dim
))));
380 } else if (local
.captured
) {
381 // captured variables are stored on the heap
382 var block
= (Block
) local
.parent_symbol
;
383 result
.cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_local_cname (local
));
384 if (array_type
!= null && !array_type
.fixed_length
) {
385 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
386 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
)));
388 if (array_type
.rank
== 1) {
389 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
)));
391 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
392 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
)));
393 if (delegate_type
.is_disposable ()) {
394 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
)));
398 result
.cvalue
= get_local_cexpression (local
);
399 if (array_type
!= null && !array_type
.fixed_length
) {
400 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
401 result
.append_array_length_cvalue (get_variable_cexpression (get_array_length_cname (get_local_cname (local
), dim
)));
403 if (array_type
.rank
== 1) {
404 result
.array_size_cvalue
= get_variable_cexpression (get_array_size_cname (get_local_cname (local
)));
406 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
407 if (is_in_coroutine ()) {
408 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), get_delegate_target_cname (get_local_cname (local
)));
409 if (local
.variable_type
.is_disposable ()) {
410 result
.delegate_target_destroy_notify_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), get_delegate_target_destroy_notify_cname (get_local_cname (local
)));
413 result
.delegate_target_cvalue
= new
CCodeIdentifier (get_delegate_target_cname (get_local_cname (local
)));
414 if (local
.variable_type
.is_disposable ()) {
415 result
.delegate_target_destroy_notify_cvalue
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_local_cname (local
)));
424 /* Returns access values to the given parameter */
425 public override TargetValue
get_parameter_cvalue (Parameter param
) {
426 var result
= new
GLibValue (param
.variable_type
.copy ());
427 result
.lvalue
= true;
428 result
.array_null_terminated
= get_ccode_array_null_terminated (param
);
429 if (get_ccode_array_length_expr (param
) != null) {
430 result
.array_length_cexpr
= new
CCodeConstant (get_ccode_array_length_expr (param
));
432 result
.ctype
= get_ccode_type (param
);
434 var array_type
= result
.value_type as ArrayType
;
435 var delegate_type
= result
.value_type as DelegateType
;
437 bool is_unowned_delegate
= delegate_type
!= null && !param
.variable_type
.value_owned
;
438 if ((param
.captured
|| is_in_coroutine ()) && !is_unowned_delegate
) {
439 result
.value_type
.value_owned
= true;
442 if (param
.name
== "this") {
443 if (is_in_coroutine ()) {
445 result
.cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "self");
447 var st
= result
.value_type
.data_type as Struct
;
448 if (st
!= null && !st
.is_simple_type ()) {
449 result
.cvalue
= new
CCodeIdentifier ("(*self)");
451 result
.cvalue
= new
CCodeIdentifier ("self");
455 string name
= param
.name
;
457 if (param
.captured
) {
458 // captured variables are stored on the heap
459 var block
= param
.parent_symbol as Block
;
461 block
= ((Method
) param
.parent_symbol
).body
;
463 result
.cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_variable_cname (param
.name
));
464 if (array_type
!= null && get_ccode_array_length (param
)) {
465 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
466 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
)));
468 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
469 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_ccode_delegate_target_name (param
));
470 if (result
.value_type
.is_disposable ()) {
471 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
)));
474 } else if (is_in_coroutine ()) {
476 result
.cvalue
= get_variable_cexpression (param
.name
);
477 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
478 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), get_ccode_delegate_target_name (param
));
479 if (delegate_type
.is_disposable ()) {
480 result
.delegate_target_destroy_notify_cvalue
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
484 var type_as_struct
= result
.value_type
.data_type as Struct
;
486 if (param
.direction
== ParameterDirection
.OUT
) {
487 name
= "_vala_%s".printf (name
);
490 if (param
.direction
== ParameterDirection
.REF
||
491 (param
.direction
== ParameterDirection
.IN
&& type_as_struct
!= null && !type_as_struct
.is_simple_type () && !result
.value_type
.nullable
)) {
492 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier (get_variable_cname (name
)));
494 // Property setters of non simple structs shall replace all occurrences
495 // of the "value" formal parameter with a dereferencing version of that
497 if (current_property_accessor
!= null &&
498 current_property_accessor
.writable
&&
499 current_property_accessor
.value_parameter
== param
&&
500 current_property_accessor
.prop
.property_type
.is_real_struct_type () &&
501 !current_property_accessor
.prop
.property_type
.nullable
) {
502 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("value"));
504 result
.cvalue
= get_variable_cexpression (name
);
507 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
508 var target_cname
= get_ccode_delegate_target_name (param
);
509 if (param
.direction
== ParameterDirection
.OUT
) {
510 target_cname
= "_vala_%s".printf (target_cname
);
512 CCodeExpression target_expr
= new
CCodeIdentifier (target_cname
);
513 CCodeExpression delegate_target_destroy_notify
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (name
)));
514 if (param
.direction
== ParameterDirection
.REF
) {
515 // accessing argument of ref param
516 target_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_expr
);
517 delegate_target_destroy_notify
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, delegate_target_destroy_notify
);
519 result
.delegate_target_cvalue
= target_expr
;
520 if (result
.value_type
.is_disposable ()) {
521 result
.delegate_target_destroy_notify_cvalue
= delegate_target_destroy_notify
;
525 if (!param
.captured
&& array_type
!= null) {
526 if (get_ccode_array_length (param
) && !get_ccode_array_null_terminated (param
)) {
527 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
528 CCodeExpression length_expr
= get_variable_cexpression (get_parameter_array_length_cname (param
, dim
));
529 if (param
.direction
== ParameterDirection
.OUT
) {
530 length_expr
= get_variable_cexpression (get_array_length_cname (get_variable_cname (name
), dim
));
531 } else if (param
.direction
== ParameterDirection
.REF
) {
532 // accessing argument of ref param
533 length_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, length_expr
);
535 result
.append_array_length_cvalue (length_expr
);
544 /* Returns lvalue access to the given field */
545 public override TargetValue
get_field_cvalue (Field field
, TargetValue? instance
) {
546 var value_type
= field
.variable_type
.copy ();
548 var result
= new
GLibValue (value_type
);
549 if (instance
!= null) {
550 result
.actual_value_type
= field
.variable_type
.get_actual_type (instance
.value_type
, null, field
);
552 result
.lvalue
= true;
553 result
.array_null_terminated
= get_ccode_array_null_terminated (field
);
554 if (get_ccode_array_length_expr (field
) != null) {
555 result
.array_length_cexpr
= new
CCodeConstant (get_ccode_array_length_expr (field
));
557 result
.ctype
= get_ccode_type (field
);
559 var array_type
= result
.value_type as ArrayType
;
560 var delegate_type
= result
.value_type as DelegateType
;
561 if (field
.binding
== MemberBinding
.INSTANCE
) {
562 CCodeExpression pub_inst
= null;
564 if (instance
!= null) {
565 pub_inst
= get_cvalue_ (instance
);
568 var instance_target_type
= get_data_type_for_symbol ((TypeSymbol
) field
.parent_symbol
);
570 var cl
= instance_target_type
.data_type as Class
;
571 bool is_gtypeinstance
= ((instance_target_type
.data_type
== cl
) && (cl
== null || !cl
.is_compact
));
573 CCodeExpression inst
;
574 if (is_gtypeinstance
&& field
.access
== SymbolAccessibility
.PRIVATE
) {
575 inst
= new CCodeMemberAccess
.pointer (pub_inst
, "priv");
578 generate_class_struct_declaration (cl
, cfile
);
584 // FIXME Report this with proper source-reference on the vala side!
585 Report
.error (field
.source_reference
, "Invalid access to instance member `%s'".printf (field
.get_full_name ()));
586 result
.cvalue
= new
CCodeInvalidExpression ();
590 if (instance_target_type
.data_type
.is_reference_type () || (instance
!= null && instance
.value_type is PointerType
)) {
591 result
.cvalue
= new CCodeMemberAccess
.pointer (inst
, get_ccode_name (field
));
593 result
.cvalue
= new
CCodeMemberAccess (inst
, get_ccode_name (field
));
596 if (array_type
!= null && get_ccode_array_length (field
)) {
597 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
598 CCodeExpression length_expr
= null;
601 if (get_ccode_array_length_name (field
) != null) {
602 length_cname
= get_ccode_array_length_name (field
);
604 length_cname
= get_array_length_cname (get_ccode_name (field
), dim
);
607 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
608 length_expr
= new CCodeMemberAccess
.pointer (inst
, length_cname
);
610 length_expr
= new
CCodeMemberAccess (inst
, length_cname
);
613 result
.append_array_length_cvalue (length_expr
);
615 if (array_type
.rank
== 1 && field
.is_internal_symbol ()) {
616 string size_cname
= get_array_size_cname (get_ccode_name (field
));
618 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
619 set_array_size_cvalue (result
, new CCodeMemberAccess
.pointer (inst
, size_cname
));
621 set_array_size_cvalue (result
, new
CCodeMemberAccess (inst
, size_cname
));
624 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
&& get_ccode_delegate_target (field
)) {
625 string target_cname
= get_ccode_delegate_target_name (field
);
626 string target_destroy_notify_cname
= get_delegate_target_destroy_notify_cname (get_ccode_name (field
));
628 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
629 result
.delegate_target_cvalue
= new CCodeMemberAccess
.pointer (inst
, target_cname
);
630 if (result
.value_type
.is_disposable ()){
631 result
.delegate_target_destroy_notify_cvalue
= new CCodeMemberAccess
.pointer (inst
, target_destroy_notify_cname
);
634 result
.delegate_target_cvalue
= new
CCodeMemberAccess (inst
, target_cname
);
635 if (result
.value_type
.is_disposable ()) {
636 result
.delegate_target_destroy_notify_cvalue
= new
CCodeMemberAccess (inst
, target_destroy_notify_cname
);
640 } else if (field
.binding
== MemberBinding
.CLASS
) {
641 var cl
= (Class
) field
.parent_symbol
;
642 var cast
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_upper_case_name (cl
, null) + "_CLASS"));
644 CCodeExpression klass
;
645 if (instance
== null) {
646 if (get_this_type () == null) {
647 // Accessing the field from a static or class constructor
648 klass
= new
CCodeIdentifier ("klass");
650 // Accessing the field from within an instance method
651 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
652 k
.add_argument (new
CCodeIdentifier ("self"));
656 // Accessing the field of an instance
657 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
658 k
.add_argument (get_cvalue_ (instance
));
661 cast
.add_argument (klass
);
663 if (field
.access
== SymbolAccessibility
.PRIVATE
) {
664 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (get_ccode_upper_case_name (cl
))));
665 ccall
.add_argument (klass
);
666 result
.cvalue
= new CCodeMemberAccess
.pointer (ccall
, get_ccode_name (field
));
668 result
.cvalue
= new CCodeMemberAccess
.pointer (cast
, get_ccode_name (field
));
672 generate_field_declaration (field
, cfile
);
674 result
.cvalue
= new
CCodeIdentifier (get_ccode_name (field
));
676 if (array_type
!= null && get_ccode_array_length (field
)) {
677 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
679 if (get_ccode_array_length_name (field
) != null) {
680 length_cname
= get_ccode_array_length_name (field
);
682 length_cname
= get_array_length_cname (get_ccode_name (field
), dim
);
685 result
.append_array_length_cvalue (new
CCodeIdentifier (length_cname
));
687 if (array_type
.rank
== 1 && field
.is_internal_symbol ()) {
688 set_array_size_cvalue (result
, new
CCodeIdentifier (get_array_size_cname (get_ccode_name (field
))));
690 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
&& get_ccode_delegate_target (field
)) {
691 result
.delegate_target_cvalue
= new
CCodeIdentifier (get_ccode_delegate_target_name (field
));
692 if (result
.value_type
.is_disposable ()) {
693 result
.delegate_target_destroy_notify_cvalue
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_ccode_name (field
)));
701 public override TargetValue
load_variable (Variable variable
, TargetValue value
) {
702 var result
= (GLibValue
) value
;
703 var array_type
= result
.value_type as ArrayType
;
704 var delegate_type
= result
.value_type as DelegateType
;
705 if (array_type
!= null) {
706 if (array_type
.fixed_length
) {
707 result
.array_length_cvalues
= null;
708 result
.append_array_length_cvalue (get_ccodenode (array_type
.length
));
709 result
.lvalue
= false;
710 } else if (get_ccode_array_null_terminated (variable
)) {
711 requires_array_length
= true;
712 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
713 len_call
.add_argument (result
.cvalue
);
715 result
.array_length_cvalues
= null;
716 result
.append_array_length_cvalue (len_call
);
717 result
.lvalue
= false;
718 } else if (get_ccode_array_length_expr (variable
) != null) {
719 var length_expr
= new
CCodeConstant (get_ccode_array_length_expr (variable
));
721 result
.array_length_cvalues
= null;
722 result
.append_array_length_cvalue (length_expr
);
723 result
.lvalue
= false;
724 } else if (!get_ccode_array_length (variable
)) {
725 result
.array_length_cvalues
= null;
726 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
727 result
.append_array_length_cvalue (new
CCodeConstant ("-1"));
729 result
.lvalue
= false;
730 } else if (get_ccode_array_length_type (variable
) != null) {
731 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
732 // cast if variable does not use int for array length
733 result
.array_length_cvalues
[dim
- 1] = new
CCodeCastExpression (result
.array_length_cvalues
[dim
- 1], "gint");
735 result
.lvalue
= false;
737 result
.array_size_cvalue
= null;
738 } else if (delegate_type
!= null) {
739 if (!delegate_type
.delegate_symbol
.has_target
|| !get_ccode_delegate_target (variable
)) {
740 result
.delegate_target_cvalue
= new
CCodeConstant ("NULL");
743 result
.delegate_target_destroy_notify_cvalue
= new
CCodeConstant ("NULL");
744 result
.lvalue
= false;
746 result
.value_type
.value_owned
= false;
748 bool use_temp
= true;
749 if (!is_lvalue_access_allowed (result
.value_type
)) {
750 // special handling for types such as va_list
753 if (variable is Parameter
) {
754 var param
= (Parameter
) variable
;
755 if (variable
.name
== "this") {
757 } else if ((param
.direction
!= ParameterDirection
.OUT
)
758 && !(param
.variable_type
.is_real_non_null_struct_type ())) {
762 if (variable
.single_assignment
&& !result
.value_type
.is_real_non_null_struct_type ()) {
763 // no need to copy values from variables that are assigned exactly once
764 // as there is no risk of modification
765 // except for structs that are always passed by reference
768 var local
= variable as LocalVariable
;
769 if (local
!= null && local
.name
[0] == '.') {
770 // already a temporary variable generated internally
771 // and safe to access without temporary variable
776 result
= (GLibValue
) store_temp_value (result
, variable
);
782 /* Returns unowned access to the given local variable */
783 public override TargetValue
load_local (LocalVariable local
) {
784 return load_variable (local
, get_local_cvalue (local
));
787 /* Returns unowned access to the given parameter */
788 public override TargetValue
load_parameter (Parameter param
) {
789 return load_variable (param
, get_parameter_cvalue (param
));
792 /* Convenience method returning access to "this" */
793 public override TargetValue
load_this_parameter (TypeSymbol sym
) {
794 var param
= new
Parameter ("this", get_data_type_for_symbol (sym
));
795 return load_parameter (param
);
798 /* Returns unowned access to the given field */
799 public override TargetValue
load_field (Field field
, TargetValue? instance
) {
800 return load_variable (field
, get_field_cvalue (field
, instance
));