Line data Source code
1 : /* valaccodebasemodule.vala
2 : *
3 : * Copyright (C) 2006-2012 Jürg Billeter
4 : * Copyright (C) 2006-2008 Raffaele Sandrini
5 : *
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.
10 :
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.
15 :
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
19 : *
20 : * Author:
21 : * Jürg Billeter <j@bitron.ch>
22 : * Raffaele Sandrini <raffaele@sandrini.ch>
23 : */
24 :
25 :
26 : /**
27 : * Code visitor generating C Code.
28 : */
29 4395 : public abstract class Vala.CCodeBaseModule : CodeGenerator {
30 76941 : public class EmitContext {
31 14615 : public Symbol? current_symbol;
32 29230 : public ArrayList<Symbol> symbol_stack = new ArrayList<Symbol> ();
33 14615 : public TryStatement current_try;
34 : public int current_try_id;
35 : public int next_try_id;
36 14615 : public CatchClause current_catch;
37 14615 : public CCodeFunction ccode;
38 29230 : public ArrayList<CCodeFunction> ccode_stack = new ArrayList<CCodeFunction> ();
39 29230 : public ArrayList<TargetValue> temp_ref_values = new ArrayList<TargetValue> ();
40 : public int next_temp_var_id;
41 : public int current_inner_error_id;
42 : public bool current_method_inner_error;
43 : public bool current_method_return;
44 14615 : public int next_coroutine_state = 1;
45 29230 : public Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
46 29230 : public Map<string,int> closure_variable_count_map = new HashMap<string,int> (str_hash, str_equal);
47 29230 : public Map<LocalVariable,int> closure_variable_clash_map = new HashMap<LocalVariable,int> ();
48 : public bool is_in_method_precondition;
49 :
50 29230 : public EmitContext (Symbol? symbol = null) {
51 26656 : current_symbol = symbol;
52 : }
53 :
54 15869 : public void push_symbol (Symbol symbol) {
55 15869 : symbol_stack.add (current_symbol);
56 15869 : current_symbol = symbol;
57 : }
58 :
59 15869 : public void pop_symbol () {
60 15869 : current_symbol = symbol_stack.remove_at (symbol_stack.size - 1);
61 : }
62 : }
63 :
64 86659 : public CodeContext context { get; set; }
65 :
66 1465 : public Symbol root_symbol;
67 :
68 2930 : public EmitContext emit_context = new EmitContext ();
69 :
70 2930 : List<EmitContext> emit_context_stack = new ArrayList<EmitContext> ();
71 :
72 1465 : public CCodeLineDirective? current_line = null;
73 :
74 2930 : List<CCodeLineDirective> line_directive_stack = new ArrayList<CCodeLineDirective> ();
75 :
76 665624 : public Symbol current_symbol { get { return emit_context.current_symbol; } }
77 :
78 : public TryStatement current_try {
79 1527 : get { return emit_context.current_try; }
80 2938555 : set { emit_context.current_try = value; }
81 : }
82 :
83 : public int current_try_id {
84 175 : get { return emit_context.current_try_id; }
85 328 : set { emit_context.current_try_id = value; }
86 : }
87 :
88 : public int next_try_id {
89 164 : get { return emit_context.next_try_id; }
90 164 : set { emit_context.next_try_id = value; }
91 : }
92 :
93 : public CatchClause current_catch {
94 168 : get { return emit_context.current_catch; }
95 441 : set { emit_context.current_catch = value; }
96 : }
97 :
98 : public int current_inner_error_id {
99 2883 : get { return emit_context.current_inner_error_id; }
100 84 : set { emit_context.current_inner_error_id = value; }
101 : }
102 :
103 : public bool is_in_method_precondition {
104 97 : get { return emit_context.is_in_method_precondition; }
105 28 : set { emit_context.is_in_method_precondition = value; }
106 : }
107 :
108 : public TypeSymbol? current_type_symbol {
109 19850 : get {
110 19850 : var sym = current_symbol;
111 40172 : while (sym != null) {
112 38165 : if (sym is TypeSymbol) {
113 17843 : return (TypeSymbol) sym;
114 : }
115 40268 : sym = sym.parent_symbol;
116 : }
117 19850 : return null;
118 : }
119 : }
120 :
121 : public Class? current_class {
122 14086 : get { return current_type_symbol as Class; }
123 : }
124 :
125 : public Method? current_method {
126 631795 : get {
127 631795 : var sym = current_symbol;
128 2392369 : while (sym is Block) {
129 3521148 : sym = sym.parent_symbol;
130 : }
131 1245765 : return sym as Method;
132 : }
133 : }
134 :
135 : public PropertyAccessor? current_property_accessor {
136 6927 : get {
137 6927 : var sym = current_symbol;
138 16121 : while (sym is Block) {
139 18388 : sym = sym.parent_symbol;
140 : }
141 11161 : return sym as PropertyAccessor;
142 : }
143 : }
144 :
145 : public Constructor? current_constructor {
146 436 : get {
147 436 : var sym = current_symbol;
148 902 : while (sym is Block) {
149 932 : sym = sym.parent_symbol;
150 : }
151 541 : return sym as Constructor;
152 : }
153 : }
154 :
155 : public Destructor? current_destructor {
156 393 : get {
157 393 : var sym = current_symbol;
158 816 : while (sym is Block) {
159 846 : sym = sym.parent_symbol;
160 : }
161 411 : return sym as Destructor;
162 : }
163 : }
164 :
165 : public DataType? current_return_type {
166 15467 : get {
167 15467 : var m = current_method;
168 13075 : if (m != null) {
169 13075 : return m.return_type;
170 : }
171 :
172 2392 : var acc = current_property_accessor;
173 2392 : if (acc != null) {
174 2392 : if (acc.readable) {
175 2390 : return acc.value_type;
176 : } else {
177 2 : return void_type;
178 : }
179 : }
180 :
181 0 : if (is_in_constructor () || is_in_destructor ()) {
182 0 : return void_type;
183 : }
184 :
185 15467 : return null;
186 : }
187 : }
188 :
189 291408 : public bool is_in_coroutine () {
190 291408 : return current_method != null && current_method.coroutine;
191 : }
192 :
193 3396 : public bool is_in_constructor () {
194 3396 : if (current_method != null) {
195 : // make sure to not return true in lambda expression inside constructor
196 3389 : return false;
197 : }
198 480 : var sym = current_symbol;
199 3267 : while (sym != null) {
200 2794 : if (sym is Constructor) {
201 7 : return true;
202 : }
203 5101 : sym = sym.parent_symbol;
204 : }
205 3396 : return false;
206 : }
207 :
208 3431 : public bool is_in_destructor () {
209 3431 : if (current_method != null) {
210 : // make sure to not return true in lambda expression inside constructor
211 3425 : return false;
212 : }
213 477 : var sym = current_symbol;
214 3256 : while (sym != null) {
215 2785 : if (sym is Destructor) {
216 6 : return true;
217 : }
218 5087 : sym = sym.parent_symbol;
219 : }
220 3431 : return false;
221 : }
222 :
223 : public Block? current_closure_block {
224 390 : get {
225 390 : return next_closure_block (current_symbol);
226 : }
227 : }
228 :
229 650 : public unowned Block? next_closure_block (Symbol sym) {
230 1007 : while (true) {
231 1007 : unowned Method method = sym as Method;
232 542 : if (method != null && !method.closure) {
233 : // parent blocks are not captured by this method
234 : break;
235 : }
236 :
237 756 : unowned Block block = sym as Block;
238 756 : if (method == null && block == null) {
239 : // no closure block
240 : break;
241 : }
242 :
243 750 : if (block != null && block.captured) {
244 : // closure block found
245 393 : return block;
246 : }
247 357 : sym = sym.parent_symbol;
248 : }
249 650 : return null;
250 : }
251 :
252 1465 : public CCodeFile header_file;
253 1465 : public CCodeFile internal_header_file;
254 1465 : public CCodeFile cfile;
255 :
256 1465 : public EmitContext class_init_context;
257 1465 : public EmitContext base_init_context;
258 1465 : public EmitContext class_finalize_context;
259 1465 : public EmitContext base_finalize_context;
260 1465 : public EmitContext instance_init_context;
261 1465 : public EmitContext instance_finalize_context;
262 :
263 1465 : public CCodeStruct param_spec_struct;
264 1465 : public CCodeStruct closure_struct;
265 1465 : public CCodeEnum prop_enum;
266 1465 : public CCodeEnum signal_enum;
267 :
268 554147 : public CCodeFunction ccode { get { return emit_context.ccode; } }
269 :
270 : /* temporary variables that own their content */
271 54280 : public ArrayList<TargetValue> temp_ref_values { get { return emit_context.temp_ref_values; } }
272 : /* cache to check whether a certain marshaller has been created yet */
273 1465 : public Set<string> user_marshal_set;
274 : /* (constant) hash table with all predefined marshallers */
275 1465 : public Set<string> predefined_marshal_set;
276 : /* (constant) hash table with all reserved identifiers in the generated code */
277 : public static Set<string> reserved_identifiers;
278 : public static Set<string> reserved_vala_identifiers;
279 :
280 : public int next_temp_var_id {
281 52329 : get { return emit_context.next_temp_var_id; }
282 43971 : set { emit_context.next_temp_var_id = value; }
283 : }
284 :
285 1465 : public int next_regex_id = 0;
286 167 : public bool in_creation_method { get { return current_method is CreationMethod; } }
287 :
288 : public bool current_method_inner_error {
289 5850 : get { return emit_context.current_method_inner_error; }
290 1433 : set { emit_context.current_method_inner_error = value; }
291 : }
292 :
293 : public bool current_method_return {
294 5118 : get { return emit_context.current_method_return; }
295 2863 : set { emit_context.current_method_return = value; }
296 : }
297 :
298 1465 : int next_block_id = 0;
299 2930 : Map<Block,int> block_map = new HashMap<Block,int> ();
300 :
301 : /* count of emitted inner_error variables in methods */
302 2930 : Map<weak Method,int> method_inner_error_var_count = new HashMap<weak Method,int> ();
303 :
304 2930 : public DataType void_type = new VoidType ();
305 1465 : public DataType bool_type;
306 1465 : public DataType char_type;
307 1465 : public DataType uchar_type;
308 1465 : public DataType? unichar_type;
309 1465 : public DataType short_type;
310 1465 : public DataType ushort_type;
311 1465 : public DataType int_type;
312 1465 : public DataType uint_type;
313 1465 : public DataType long_type;
314 1465 : public DataType ulong_type;
315 1465 : public DataType int8_type;
316 1465 : public DataType uint8_type;
317 1465 : public DataType int16_type;
318 1465 : public DataType uint16_type;
319 1465 : public DataType int32_type;
320 1465 : public DataType uint32_type;
321 1465 : public DataType int64_type;
322 1465 : public DataType uint64_type;
323 1465 : public DataType size_t_type;
324 1465 : public DataType ssize_t_type;
325 1465 : public DataType string_type;
326 1465 : public DataType regex_type;
327 1465 : public DataType float_type;
328 1465 : public DataType double_type;
329 1465 : public DataType pointer_type;
330 1465 : public TypeSymbol gtype_type;
331 1465 : public TypeSymbol gobject_type;
332 1465 : public ErrorType gerror_type;
333 1465 : public Class glist_type;
334 1465 : public Class gslist_type;
335 1465 : public Class gnode_type;
336 1465 : public Class gqueue_type;
337 1465 : public Class gvaluearray_type;
338 1465 : public TypeSymbol gstringbuilder_type;
339 1465 : public Class garray_type;
340 1465 : public TypeSymbol gbytearray_type;
341 1465 : public TypeSymbol genericarray_type;
342 1465 : public Class gsequence_type;
343 1465 : public Class gsequence_iter_type;
344 1465 : public TypeSymbol gthreadpool_type;
345 1465 : public DataType gquark_type;
346 1465 : public Struct gvalue_type;
347 1465 : public Class gvariant_type;
348 1465 : public Struct mutex_type;
349 1465 : public Struct gmutex_type;
350 1465 : public Struct grecmutex_type;
351 1465 : public Struct grwlock_type;
352 1465 : public Struct gcond_type;
353 1465 : public Class gsource_type;
354 1465 : public TypeSymbol type_module_type;
355 1465 : public TypeSymbol dbus_proxy_type;
356 1465 : public Class gtk_widget_type;
357 1465 : public DataType delegate_target_type;
358 1465 : public DelegateType delegate_target_destroy_type;
359 1465 : Delegate destroy_notify;
360 1465 : Class gerror;
361 :
362 1465 : public bool in_plugin = false;
363 1465 : public string module_init_param_name;
364 :
365 : public bool requires_assert;
366 : public bool requires_array_free;
367 : public bool requires_array_move;
368 : public bool requires_array_length;
369 : public bool requires_array_n_elements;
370 : public bool requires_clear_mutex;
371 : public bool requires_memdup2;
372 : public bool requires_vala_extern;
373 :
374 1465 : public Set<string> wrappers;
375 1465 : Set<Symbol> generated_external_symbols;
376 :
377 14473 : public Map<string,string> variable_name_map { get { return emit_context.variable_name_map; } }
378 :
379 1465 : public static int ccode_attribute_cache_index = CodeNode.get_attribute_cache_index ();
380 :
381 1465 : protected CCodeBaseModule () {
382 1465 : if (Vala.get_build_version () != Vala.BUILD_VERSION) {
383 0 : Report.error (null, "Integrity check failed (libvala %s doesn't match ccodegen %s)", Vala.get_build_version (), Vala.BUILD_VERSION);
384 : }
385 :
386 1465 : predefined_marshal_set = new HashSet<string> (str_hash, str_equal);
387 1465 : predefined_marshal_set.add ("VOID:VOID");
388 1465 : predefined_marshal_set.add ("VOID:BOOLEAN");
389 1465 : predefined_marshal_set.add ("VOID:CHAR");
390 1465 : predefined_marshal_set.add ("VOID:UCHAR");
391 1465 : predefined_marshal_set.add ("VOID:INT");
392 1465 : predefined_marshal_set.add ("VOID:UINT");
393 1465 : predefined_marshal_set.add ("VOID:LONG");
394 1465 : predefined_marshal_set.add ("VOID:ULONG");
395 1465 : predefined_marshal_set.add ("VOID:ENUM");
396 1465 : predefined_marshal_set.add ("VOID:FLAGS");
397 1465 : predefined_marshal_set.add ("VOID:FLOAT");
398 1465 : predefined_marshal_set.add ("VOID:DOUBLE");
399 1465 : predefined_marshal_set.add ("VOID:STRING");
400 1465 : predefined_marshal_set.add ("VOID:POINTER");
401 1465 : predefined_marshal_set.add ("VOID:OBJECT");
402 1465 : predefined_marshal_set.add ("STRING:OBJECT,POINTER");
403 1465 : predefined_marshal_set.add ("VOID:UINT,POINTER");
404 1465 : predefined_marshal_set.add ("BOOLEAN:FLAGS");
405 1465 : predefined_marshal_set.add ("VOID:BOXED");
406 1465 : predefined_marshal_set.add ("VOID:VARIANT");
407 1465 : predefined_marshal_set.add ("BOOLEAN:BOXED,BOXED");
408 :
409 1465 : init ();
410 : }
411 :
412 : public static void init () {
413 2350 : if (reserved_identifiers != null) {
414 : return;
415 : }
416 :
417 1465 : reserved_identifiers = new HashSet<string> (str_hash, str_equal);
418 :
419 : // C99 keywords
420 1465 : reserved_identifiers.add ("_Bool");
421 1465 : reserved_identifiers.add ("_Complex");
422 1465 : reserved_identifiers.add ("_Imaginary");
423 1465 : reserved_identifiers.add ("asm");
424 1465 : reserved_identifiers.add ("auto");
425 1465 : reserved_identifiers.add ("break");
426 1465 : reserved_identifiers.add ("case");
427 1465 : reserved_identifiers.add ("char");
428 1465 : reserved_identifiers.add ("const");
429 1465 : reserved_identifiers.add ("continue");
430 1465 : reserved_identifiers.add ("default");
431 1465 : reserved_identifiers.add ("do");
432 1465 : reserved_identifiers.add ("double");
433 1465 : reserved_identifiers.add ("else");
434 1465 : reserved_identifiers.add ("enum");
435 1465 : reserved_identifiers.add ("extern");
436 1465 : reserved_identifiers.add ("float");
437 1465 : reserved_identifiers.add ("for");
438 1465 : reserved_identifiers.add ("goto");
439 1465 : reserved_identifiers.add ("if");
440 1465 : reserved_identifiers.add ("inline");
441 1465 : reserved_identifiers.add ("int");
442 1465 : reserved_identifiers.add ("long");
443 1465 : reserved_identifiers.add ("register");
444 1465 : reserved_identifiers.add ("restrict");
445 1465 : reserved_identifiers.add ("return");
446 1465 : reserved_identifiers.add ("short");
447 1465 : reserved_identifiers.add ("signed");
448 1465 : reserved_identifiers.add ("sizeof");
449 1465 : reserved_identifiers.add ("static");
450 1465 : reserved_identifiers.add ("struct");
451 1465 : reserved_identifiers.add ("switch");
452 1465 : reserved_identifiers.add ("typedef");
453 1465 : reserved_identifiers.add ("union");
454 1465 : reserved_identifiers.add ("unsigned");
455 1465 : reserved_identifiers.add ("void");
456 1465 : reserved_identifiers.add ("volatile");
457 1465 : reserved_identifiers.add ("while");
458 :
459 : // C11 keywords
460 1465 : reserved_identifiers.add ("_Alignas");
461 1465 : reserved_identifiers.add ("_Alignof");
462 1465 : reserved_identifiers.add ("_Atomic");
463 1465 : reserved_identifiers.add ("_Generic");
464 1465 : reserved_identifiers.add ("_Noreturn");
465 1465 : reserved_identifiers.add ("_Static_assert");
466 1465 : reserved_identifiers.add ("_Thread_local");
467 :
468 : // MSVC keywords
469 1465 : reserved_identifiers.add ("cdecl");
470 :
471 1465 : reserved_vala_identifiers = new HashSet<string> (str_hash, str_equal);
472 :
473 : // reserved for Vala/GObject naming conventions
474 1465 : reserved_vala_identifiers.add ("error");
475 1465 : reserved_vala_identifiers.add ("result");
476 1465 : reserved_vala_identifiers.add ("self");
477 : }
478 :
479 1770 : public override void emit (CodeContext context) {
480 885 : this.context = context;
481 :
482 885 : ccode_init (context.profile);
483 :
484 1770 : root_symbol = context.root;
485 :
486 885 : bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
487 885 : char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
488 885 : uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
489 885 : short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
490 885 : ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
491 885 : int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
492 885 : uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
493 885 : long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
494 885 : ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
495 885 : int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
496 885 : uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8"));
497 885 : int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16"));
498 885 : uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16"));
499 885 : int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32"));
500 885 : uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32"));
501 885 : int64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int64"));
502 885 : uint64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint64"));
503 885 : size_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("size_t"));
504 885 : ssize_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ssize_t"));
505 885 : float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
506 885 : double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
507 885 : string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
508 885 : var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
509 885 : if (unichar_struct != null) {
510 877 : unichar_type = new IntegerType (unichar_struct);
511 : }
512 :
513 1762 : if (context.profile == Profile.GOBJECT) {
514 877 : var glib_ns = root_symbol.scope.lookup ("GLib");
515 :
516 877 : gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
517 877 : gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
518 877 : gerror_type = new ErrorType (null, null);
519 877 : glist_type = (Class) glib_ns.scope.lookup ("List");
520 877 : gslist_type = (Class) glib_ns.scope.lookup ("SList");
521 877 : gnode_type = (Class) glib_ns.scope.lookup ("Node");
522 877 : gqueue_type = (Class) glib_ns.scope.lookup ("Queue");
523 877 : gvaluearray_type = (Class) glib_ns.scope.lookup ("ValueArray");
524 877 : gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
525 877 : garray_type = (Class) glib_ns.scope.lookup ("Array");
526 877 : gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
527 877 : genericarray_type = (TypeSymbol) glib_ns.scope.lookup ("GenericArray");
528 877 : gsequence_type = (Class) glib_ns.scope.lookup ("Sequence");
529 877 : gsequence_iter_type = (Class) glib_ns.scope.lookup ("SequenceIter");
530 877 : gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
531 :
532 877 : gerror = (Class) glib_ns.scope.lookup ("Error");
533 877 : gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
534 877 : gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
535 877 : gvariant_type = (Class) glib_ns.scope.lookup ("Variant");
536 877 : gsource_type = (Class) glib_ns.scope.lookup ("Source");
537 :
538 877 : gmutex_type = (Struct) glib_ns.scope.lookup ("Mutex");
539 877 : grecmutex_type = (Struct) glib_ns.scope.lookup ("RecMutex");
540 877 : grwlock_type = (Struct) glib_ns.scope.lookup ("RWLock");
541 877 : gcond_type = (Struct) glib_ns.scope.lookup ("Cond");
542 :
543 1754 : mutex_type = grecmutex_type;
544 :
545 877 : type_module_type = (TypeSymbol) glib_ns.scope.lookup ("TypeModule");
546 :
547 877 : regex_type = new ObjectType ((Class) glib_ns.scope.lookup ("Regex"));
548 :
549 877 : if (context.module_init_method != null) {
550 1 : foreach (Parameter parameter in context.module_init_method.get_parameters ()) {
551 1 : if (parameter.variable_type.type_symbol.is_subtype_of (type_module_type)) {
552 1 : in_plugin = true;
553 2 : module_init_param_name = parameter.name;
554 1 : break;
555 :
556 : }
557 : }
558 : }
559 :
560 877 : dbus_proxy_type = (TypeSymbol) glib_ns.scope.lookup ("DBusProxy");
561 :
562 877 : pointer_type = new StructValueType ((Struct) glib_ns.scope.lookup ("pointer"));
563 :
564 1754 : delegate_target_type = pointer_type;
565 877 : destroy_notify = (Delegate) glib_ns.scope.lookup ("DestroyNotify");
566 877 : delegate_target_destroy_type = new DelegateType (destroy_notify);
567 : } else {
568 8 : pointer_type = new PointerType (new VoidType ());
569 :
570 16 : delegate_target_type = pointer_type;
571 8 : destroy_notify = new Delegate ("ValaDestroyNotify", new VoidType ());
572 8 : destroy_notify.add_parameter (new Parameter ("data", new PointerType (new VoidType ())));
573 8 : destroy_notify.has_target = false;
574 8 : destroy_notify.owner = root_symbol.scope;
575 8 : delegate_target_destroy_type = new DelegateType (destroy_notify);
576 : }
577 :
578 885 : var gtk_ns = root_symbol.scope.lookup ("Gtk");
579 885 : if (gtk_ns != null) {
580 10 : gtk_widget_type = (Class) gtk_ns.scope.lookup ("Widget");
581 : }
582 :
583 885 : header_file = new CCodeFile (CCodeFileType.PUBLIC_HEADER);
584 885 : internal_header_file = new CCodeFile (CCodeFileType.INTERNAL_HEADER);
585 :
586 : /* we're only interested in non-pkg source files */
587 27186 : var source_files = context.get_source_files ();
588 8573 : foreach (SourceFile file in source_files) {
589 3844 : if (file.file_type == SourceFileType.SOURCE ||
590 2818 : (context.header_filename != null && file.file_type == SourceFileType.FAST)) {
591 1026 : file.accept (this);
592 : }
593 : }
594 :
595 : // generate symbols file for public API
596 885 : if (context.symbols_filename != null) {
597 0 : var stream = FileStream.open (context.symbols_filename, "w");
598 0 : if (stream == null) {
599 0 : Report.error (null, "unable to open `%s' for writing", context.symbols_filename);
600 0 : this.context = null;
601 0 : return;
602 : }
603 :
604 0 : foreach (string symbol in header_file.get_symbols ()) {
605 0 : stream.puts (symbol);
606 0 : stream.putc ('\n');
607 : }
608 :
609 0 : stream = null;
610 : }
611 :
612 : // generate C header file for public API
613 885 : if (context.header_filename != null) {
614 : bool ret;
615 4 : if (context.profile == Profile.GOBJECT) {
616 4 : header_file.add_include ("glib.h");
617 4 : ret = header_file.store (context.header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
618 : } else {
619 0 : ret = header_file.store (context.header_filename, null, context.version_header, false, "#ifdef __cplusplus\nextern \"C\" {\n#endif", "#ifdef __cplusplus\n}\n#endif");
620 : }
621 4 : if (!ret) {
622 0 : Report.error (null, "unable to open `%s' for writing", context.header_filename);
623 : }
624 : }
625 :
626 : // generate C header file for internal API
627 885 : if (context.internal_header_filename != null) {
628 : bool ret;
629 0 : if (context.profile == Profile.GOBJECT) {
630 0 : internal_header_file.add_include ("glib.h");
631 0 : ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
632 : } else {
633 0 : ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false, "#ifdef __cplusplus\nextern \"C\" {\n#endif", "#ifdef __cplusplus\n}\n#endif");
634 : }
635 0 : if (!ret) {
636 0 : Report.error (null, "unable to open `%s' for writing", context.internal_header_filename);
637 : }
638 : }
639 :
640 885 : this.context = null;
641 : }
642 :
643 15339 : public void push_context (EmitContext emit_context) {
644 15339 : if (this.emit_context != null) {
645 15339 : emit_context_stack.add (this.emit_context);
646 : }
647 :
648 15388 : this.emit_context = emit_context;
649 15339 : if (ccode != null) {
650 2508 : ccode.current_line = current_line;
651 : }
652 : }
653 :
654 15334 : public void pop_context () {
655 15334 : if (emit_context_stack.size > 0) {
656 15334 : this.emit_context = emit_context_stack.remove_at (emit_context_stack.size - 1);
657 15334 : if (ccode != null) {
658 761 : ccode.current_line = current_line;
659 : }
660 : } else {
661 0 : this.emit_context = null;
662 : }
663 : }
664 :
665 63056 : public void push_line (SourceReference? source_reference) {
666 63056 : line_directive_stack.add (current_line);
667 63056 : if (source_reference != null) {
668 62698 : current_line = new CCodeLineDirective (source_reference.file.get_relative_filename (), source_reference.begin.line);
669 62698 : if (ccode != null) {
670 52176 : ccode.current_line = current_line;
671 : }
672 : }
673 : }
674 :
675 63044 : public void pop_line () {
676 63044 : current_line = line_directive_stack.remove_at (line_directive_stack.size - 1);
677 63044 : if (ccode != null) {
678 53073 : ccode.current_line = current_line;
679 : }
680 : }
681 :
682 19764 : public void push_function (CCodeFunction func) {
683 19764 : emit_context.ccode_stack.add (ccode);
684 303094 : emit_context.ccode = func;
685 19764 : ccode.current_line = current_line;
686 : }
687 :
688 9305 : public void pop_function () {
689 9305 : emit_context.ccode = emit_context.ccode_stack.remove_at (emit_context.ccode_stack.size - 1);
690 9305 : if (ccode != null) {
691 1726 : ccode.current_line = current_line;
692 : }
693 : }
694 :
695 170615 : public bool add_symbol_declaration (CCodeFile decl_space, Symbol sym, string name) {
696 170615 : bool in_generated_header = context.header_filename != null
697 57536 : && (decl_space.file_type != CCodeFileType.PUBLIC_HEADER && !sym.is_internal_symbol () && !(sym is Class && ((Class) sym).is_opaque));
698 170615 : if (decl_space.add_declaration (name)) {
699 156060 : return true;
700 : }
701 31393 : if (sym.source_reference != null) {
702 31382 : sym.source_reference.file.used = true;
703 : }
704 31393 : if (sym.anonymous) {
705 170615 : return in_generated_header;
706 : }
707 : // constants with initializer-list are special
708 31392 : if (sym is Constant && ((Constant) sym).value is InitializerList) {
709 14554 : return false;
710 : }
711 : // sealed classes are special
712 31327 : if (!sym.external_package && sym is Class && ((Class) sym).is_sealed) {
713 14554 : return false;
714 : }
715 31297 : if (sym.external_package || in_generated_header
716 14475 : || (sym.is_extern && get_ccode_header_filenames (sym).length > 0)) {
717 : // add feature test macros
718 50515 : foreach (unowned string feature_test_macro in get_ccode_feature_test_macros (sym).split (",")) {
719 1 : decl_space.add_feature_test_macro (feature_test_macro);
720 : }
721 : // add appropriate include file
722 70271 : foreach (unowned string header_filename in get_ccode_header_filenames (sym).split (",")) {
723 19757 : decl_space.add_include (header_filename,
724 19757 : !sym.is_extern && (!sym.external_package || (sym.external_package && sym.from_commandline)));
725 : }
726 : // declaration complete
727 16838 : return true;
728 : } else {
729 : // require declaration
730 14459 : return false;
731 : }
732 : }
733 :
734 146 : public virtual void append_vala_array_free () {
735 : }
736 :
737 2 : public virtual void append_vala_array_move () {
738 : }
739 :
740 35 : public virtual void append_vala_array_length () {
741 : }
742 :
743 22 : public virtual void append_params_array (Method m) {
744 : }
745 :
746 8 : public void append_vala_clear_mutex (string typename, string funcprefix) {
747 : // memset
748 4 : cfile.add_include ("string.h");
749 :
750 4 : var fun = new CCodeFunction ("_vala_clear_" + typename);
751 4 : fun.modifiers = CCodeModifiers.STATIC;
752 4 : fun.add_parameter (new CCodeParameter ("mutex", typename + " *"));
753 :
754 4 : push_function (fun);
755 :
756 4 : ccode.add_declaration (typename, new CCodeVariableDeclarator.zero ("zero_mutex", new CCodeConstant ("{ 0 }")));
757 :
758 4 : var cmp = new CCodeFunctionCall (new CCodeIdentifier ("memcmp"));
759 4 : cmp.add_argument (new CCodeIdentifier ("mutex"));
760 4 : cmp.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("zero_mutex")));
761 4 : cmp.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
762 4 : ccode.open_if (cmp);
763 :
764 4 : var mutex_clear = new CCodeFunctionCall (new CCodeIdentifier (funcprefix + "_clear"));
765 4 : mutex_clear.add_argument (new CCodeIdentifier ("mutex"));
766 4 : ccode.add_expression (mutex_clear);
767 :
768 4 : var mset = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
769 4 : mset.add_argument (new CCodeIdentifier ("mutex"));
770 4 : mset.add_argument (new CCodeConstant ("0"));
771 4 : mset.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
772 4 : ccode.add_expression (mset);
773 :
774 4 : ccode.close ();
775 :
776 4 : pop_function ();
777 :
778 4 : cfile.add_function_declaration (fun);
779 4 : cfile.add_function (fun);
780 : }
781 :
782 38 : void append_vala_memdup2 () {
783 : // g_malloc
784 19 : cfile.add_include ("glib.h");
785 : // memcpy
786 19 : cfile.add_include ("string.h");
787 :
788 19 : var fun = new CCodeFunction ("_vala_memdup2", "gpointer");
789 19 : fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
790 19 : fun.add_parameter (new CCodeParameter ("mem", "gconstpointer"));
791 19 : fun.add_parameter (new CCodeParameter ("byte_size", "gsize"));
792 :
793 19 : push_function (fun);
794 :
795 19 : ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("new_mem"));
796 :
797 19 : ccode.open_if (new CCodeIdentifier ("mem && byte_size != 0"));
798 :
799 19 : var malloc = new CCodeFunctionCall (new CCodeIdentifier ("g_malloc"));
800 19 : malloc.add_argument (new CCodeIdentifier ("byte_size"));
801 19 : ccode.add_assignment (new CCodeIdentifier ("new_mem"), malloc);
802 19 : var mcpy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
803 19 : mcpy.add_argument (new CCodeIdentifier ("new_mem"));
804 19 : mcpy.add_argument (new CCodeIdentifier ("mem"));
805 19 : mcpy.add_argument (new CCodeIdentifier ("byte_size"));
806 19 : ccode.add_expression (mcpy);
807 :
808 19 : ccode.add_else ();
809 :
810 19 : ccode.add_assignment (new CCodeIdentifier ("new_mem"), new CCodeConstant ("NULL"));
811 :
812 19 : ccode.close ();
813 :
814 19 : ccode.add_return (new CCodeIdentifier ("new_mem"));
815 :
816 19 : pop_function ();
817 :
818 19 : cfile.add_function_declaration (fun);
819 19 : cfile.add_function (fun);
820 : }
821 :
822 : /**
823 : * Define a macro hint for exporting a symbol in a portable way.
824 : */
825 2724 : void append_vala_extern_define (CCodeFile decl_space) {
826 1362 : var extern_define = new CCodeIfSection ("!defined(VALA_EXTERN)");
827 :
828 : CCodeIfSection if_section;
829 1362 : if_section = new CCodeIfSection ("defined(_WIN32) || defined(__CYGWIN__)");
830 1362 : extern_define.append (if_section);
831 1362 : if_section.append (new CCodeDefine ("VALA_EXTERN", "__declspec(dllexport) extern"));
832 2724 : if_section = if_section.append_else ("__GNUC__ >= 4");
833 1362 : if_section.append (new CCodeDefine ("VALA_EXTERN", "__attribute__((visibility(\"default\"))) extern"));
834 2724 : if_section = if_section.append_else ();
835 1362 : if_section.append (new CCodeDefine ("VALA_EXTERN", "extern"));
836 :
837 1362 : decl_space.add_define (extern_define);
838 : }
839 :
840 1974 : void append_c_compiler_mitigations (CCodeFile decl_space) {
841 987 : var vala_strict_c = new CCodeIfSection ("!defined(VALA_STRICT_C)");
842 :
843 : CCodeIfSection if_section;
844 987 : if_section = new CCodeIfSection ("!defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 14)");
845 987 : vala_strict_c.append (if_section);
846 987 : if_section.append (new CCodePragma ("GCC", "diagnostic", "warning \"-Wincompatible-pointer-types\""));
847 1974 : if_section = if_section.append_else ("defined(__clang__) && (__clang_major__ >= 16)");
848 987 : if_section.append (new CCodePragma ("clang", "diagnostic", "ignored \"-Wincompatible-function-pointer-types\""));
849 987 : if_section.append (new CCodePragma ("clang", "diagnostic", "ignored \"-Wincompatible-pointer-types\""));
850 :
851 987 : decl_space.add_define (vala_strict_c);
852 : }
853 :
854 2013 : public override void visit_source_file (SourceFile source_file) {
855 1026 : cfile = new CCodeFile (CCodeFileType.SOURCE, source_file);
856 :
857 1026 : user_marshal_set = new HashSet<string> (str_hash, str_equal);
858 :
859 1026 : next_regex_id = 0;
860 :
861 1026 : requires_assert = false;
862 1026 : requires_array_free = false;
863 1026 : requires_array_move = false;
864 1026 : requires_array_length = false;
865 1026 : requires_array_n_elements = false;
866 1026 : requires_clear_mutex = false;
867 1026 : requires_vala_extern = false;
868 :
869 1026 : wrappers = new HashSet<string> (str_hash, str_equal);
870 1026 : generated_external_symbols = new HashSet<Symbol> ();
871 :
872 1026 : source_file.accept_children (this);
873 :
874 1026 : if (context.report.get_errors () > 0) {
875 : return;
876 : }
877 :
878 : /* For fast-vapi, we only wanted the header declarations
879 : * to be emitted, so bail out here without writing the
880 : * C code output.
881 : */
882 987 : if (source_file.file_type == SourceFileType.FAST) {
883 0 : if (requires_vala_extern) {
884 0 : if (context.header_filename != null) {
885 0 : if (!header_file.add_declaration ("VALA_EXTERN")) {
886 0 : append_vala_extern_define (header_file);
887 : }
888 0 : internal_header_file.add_include (source_file.get_cinclude_filename (), true);
889 : }
890 : }
891 0 : return;
892 : }
893 :
894 987 : append_c_compiler_mitigations (cfile);
895 :
896 987 : if (requires_assert) {
897 593 : cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("_vala_assert(expr, msg)", new CCodeConstant ("if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);")));
898 593 : cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("_vala_return_if_fail(expr, msg)", new CCodeConstant ("if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }")));
899 593 : cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("_vala_return_val_if_fail(expr, msg, val)", new CCodeConstant ("if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }")));
900 593 : cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("_vala_warn_if_fail(expr, msg)", new CCodeConstant ("if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);")));
901 : }
902 987 : if (requires_array_free) {
903 146 : append_vala_array_free ();
904 : }
905 987 : if (requires_array_move) {
906 2 : append_vala_array_move ();
907 : }
908 987 : if (requires_array_length) {
909 35 : append_vala_array_length ();
910 : }
911 987 : if (requires_array_n_elements) {
912 1 : cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("VALA_N_ELEMENTS(arr)", new CCodeConstant ("(sizeof (arr) / sizeof ((arr)[0]))")));
913 : }
914 987 : if (requires_clear_mutex) {
915 1 : append_vala_clear_mutex ("GMutex", "g_mutex");
916 1 : append_vala_clear_mutex ("GRecMutex", "g_rec_mutex");
917 1 : append_vala_clear_mutex ("GRWLock", "g_rw_lock");
918 1 : append_vala_clear_mutex ("GCond", "g_cond");
919 : }
920 987 : if (requires_memdup2) {
921 19 : append_vala_memdup2 ();
922 : }
923 987 : if (requires_vala_extern) {
924 801 : if (context.header_filename != null) {
925 122 : if (!header_file.add_declaration ("VALA_EXTERN")) {
926 4 : append_vala_extern_define (header_file);
927 : }
928 122 : cfile.add_include (source_file.get_cinclude_filename (), true);
929 122 : internal_header_file.add_include (source_file.get_cinclude_filename (), true);
930 : } else {
931 679 : if (!cfile.add_declaration ("VALA_EXTERN")) {
932 679 : append_vala_extern_define (cfile);
933 679 : append_vala_extern_define (internal_header_file);
934 : }
935 : }
936 : }
937 :
938 987 : var comments = source_file.get_comments();
939 987 : if (comments != null) {
940 1297 : foreach (Comment comment in comments) {
941 155 : var ccomment = new CCodeComment (comment.content);
942 155 : cfile.add_comment (ccomment);
943 : }
944 : }
945 :
946 987 : if (!cfile.store (source_file.get_csource_filename (), source_file.filename, context.version_header, context.debug)) {
947 0 : Report.error (null, "unable to open `%s' for writing", source_file.get_csource_filename ());
948 : }
949 :
950 987 : cfile = null;
951 : }
952 :
953 7686 : public virtual bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
954 3843 : if (add_symbol_declaration (decl_space, en, get_ccode_name (en))) {
955 3669 : return false;
956 : }
957 :
958 174 : var cenum = new CCodeEnum (get_ccode_name (en));
959 :
960 174 : if (en.version.deprecated) {
961 4 : if (context.profile == Profile.GOBJECT) {
962 4 : decl_space.add_include ("glib.h");
963 : }
964 4 : cenum.modifiers |= CCodeModifiers.DEPRECATED;
965 : }
966 :
967 348 : var current_cfile = cfile;
968 174 : cfile = decl_space;
969 :
970 174 : int flag_shift = 0;
971 944 : foreach (EnumValue ev in en.get_values ()) {
972 : CCodeEnumValue c_ev;
973 385 : if (ev.value == null) {
974 338 : c_ev = new CCodeEnumValue (get_ccode_name (ev));
975 338 : if (en.is_flags) {
976 57 : c_ev.value = new CCodeConstant ("1 << %d".printf (flag_shift));
977 57 : flag_shift += 1;
978 : }
979 : } else {
980 47 : ev.value.emit (this);
981 47 : c_ev = new CCodeEnumValue (get_ccode_name (ev), get_cvalue (ev.value));
982 : }
983 385 : c_ev.modifiers |= (ev.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
984 385 : cenum.add_value (c_ev);
985 : }
986 :
987 348 : cfile = current_cfile;
988 :
989 174 : decl_space.add_type_declaration (cenum);
990 174 : decl_space.add_type_declaration (new CCodeNewline ());
991 :
992 174 : if (context.profile != Profile.GOBJECT || !get_ccode_has_type_id (en)) {
993 32 : return true;
994 : }
995 :
996 142 : decl_space.add_include ("glib-object.h");
997 142 : decl_space.add_type_declaration (new CCodeNewline ());
998 :
999 142 : var fun_name = get_ccode_type_function (en);
1000 :
1001 142 : var macro = "(%s ())".printf (fun_name);
1002 142 : decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (en), macro));
1003 :
1004 142 : var regfun = new CCodeFunction (fun_name, "GType");
1005 142 : regfun.modifiers = CCodeModifiers.CONST;
1006 :
1007 142 : if (en.is_private_symbol ()) {
1008 : // avoid C warning as this function is not always used
1009 4 : regfun.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.UNUSED;
1010 138 : } else if (context.hide_internal && en.is_internal_symbol ()) {
1011 0 : regfun.modifiers |= CCodeModifiers.INTERNAL;
1012 : } else {
1013 138 : regfun.modifiers |= CCodeModifiers.EXTERN;
1014 138 : requires_vala_extern = true;
1015 : }
1016 :
1017 142 : decl_space.add_function_declaration (regfun);
1018 :
1019 142 : return true;
1020 : }
1021 :
1022 82 : public override void visit_enum (Enum en) {
1023 82 : push_line (en.source_reference);
1024 :
1025 82 : if (en.comment != null) {
1026 1 : cfile.add_type_member_definition (new CCodeComment (en.comment.content));
1027 : }
1028 :
1029 82 : generate_enum_declaration (en, cfile);
1030 :
1031 82 : if (!en.is_internal_symbol ()) {
1032 32 : generate_enum_declaration (en, header_file);
1033 : }
1034 82 : if (!en.is_private_symbol ()) {
1035 78 : generate_enum_declaration (en, internal_header_file);
1036 : }
1037 :
1038 82 : en.accept_children (this);
1039 :
1040 82 : pop_line ();
1041 : }
1042 :
1043 2147 : public void visit_member (Symbol m) {
1044 : /* stuff meant for all lockable members */
1045 2172 : if (m is Lockable && ((Lockable) m).lock_used) {
1046 25 : CCodeExpression l = new CCodeIdentifier ("self");
1047 25 : var init_context = class_init_context;
1048 25 : var finalize_context = class_finalize_context;
1049 :
1050 25 : if (m.is_instance_member ()) {
1051 12 : l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (get_ccode_name (m)));
1052 24 : init_context = instance_init_context;
1053 24 : finalize_context = instance_finalize_context;
1054 20 : } else if (m.is_class_member ()) {
1055 7 : var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function ((Class) m.parent_symbol)));
1056 7 : get_class_private_call.add_argument (new CCodeIdentifier ("klass"));
1057 7 : l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (get_ccode_name (m)));
1058 : } else {
1059 6 : l = new CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf (get_ccode_lower_case_name (m.parent_symbol), get_ccode_name (m))));
1060 : }
1061 :
1062 25 : push_context (init_context);
1063 25 : var initf = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.default_construction_method)));
1064 25 : initf.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
1065 25 : ccode.add_expression (initf);
1066 25 : pop_context ();
1067 :
1068 50 : if (finalize_context != null) {
1069 25 : push_context (finalize_context);
1070 25 : var fc = new CCodeFunctionCall (new CCodeIdentifier ("g_rec_mutex_clear"));
1071 25 : fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
1072 25 : ccode.add_expression (fc);
1073 25 : pop_context ();
1074 : }
1075 : }
1076 : }
1077 :
1078 84 : static void constant_array_ranks_sizes (InitializerList initializer_list, int[] sizes, int rank = 0) {
1079 84 : sizes[rank] = int.max (sizes[rank], initializer_list.size);
1080 84 : rank++;
1081 722 : foreach (var expr in initializer_list.get_initializers()) {
1082 319 : if (expr is InitializerList && ((InitializerList) expr).target_type is ArrayType) {
1083 29 : constant_array_ranks_sizes ((InitializerList) expr, sizes, rank);
1084 : }
1085 : }
1086 : }
1087 :
1088 81 : CCodeDeclaratorSuffix? get_constant_declarator_suffix (Constant c) {
1089 81 : unowned ArrayType? array = c.type_reference as ArrayType;
1090 81 : unowned InitializerList? initializer_list = c.value as InitializerList;
1091 81 : if (array == null || initializer_list == null) {
1092 26 : if (c.type_reference.compatible (string_type)) {
1093 1 : return new CCodeDeclaratorSuffix.with_array ();
1094 : }
1095 25 : return null;
1096 : }
1097 :
1098 55 : var lengths = new ArrayList<CCodeExpression> ();
1099 55 : int[] sizes = new int[array.rank];
1100 55 : constant_array_ranks_sizes (initializer_list, sizes);
1101 117 : for (int i = 0; i < array.rank; i++) {
1102 62 : lengths.add (new CCodeConstant ("%d".printf (sizes[i])));
1103 : }
1104 55 : return new CCodeDeclaratorSuffix.with_multi_array (lengths);
1105 : }
1106 :
1107 785 : public void generate_constant_declaration (Constant c, CCodeFile decl_space, bool definition = false) {
1108 785 : if (c.parent_symbol is Block) {
1109 : // local constant
1110 : return;
1111 : }
1112 :
1113 760 : if (add_symbol_declaration (decl_space, c, get_ccode_name (c))) {
1114 : return;
1115 : }
1116 :
1117 464 : if (!c.external && c.value != null) {
1118 228 : generate_type_declaration (c.type_reference, decl_space);
1119 :
1120 228 : c.value.emit (this);
1121 :
1122 228 : var initializer_list = c.value as InitializerList;
1123 456 : if (initializer_list != null) {
1124 65 : var cdecl = new CCodeDeclaration (get_ccode_const_name (c.type_reference));
1125 65 : var cinitializer = get_cvalue (c.value);
1126 65 : if (!definition) {
1127 : // never output value in header
1128 : // special case needed as this method combines declaration and definition
1129 30 : cinitializer = null;
1130 : }
1131 :
1132 65 : cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_name (c), cinitializer, get_constant_declarator_suffix (c)));
1133 65 : if (c.is_private_symbol ()) {
1134 5 : cdecl.modifiers = CCodeModifiers.STATIC;
1135 : } else {
1136 60 : cdecl.modifiers = CCodeModifiers.EXTERN;
1137 60 : requires_vala_extern = true;
1138 : }
1139 :
1140 65 : decl_space.add_constant_declaration (cdecl);
1141 : } else {
1142 165 : if (c.value is StringLiteral && ((StringLiteral) c.value).translate) {
1143 : // translated string constant
1144 2 : var m = (Method) root_symbol.scope.lookup ("GLib").scope.lookup ("_");
1145 2 : add_symbol_declaration (decl_space, m, get_ccode_name (m));
1146 : }
1147 :
1148 163 : var cdefine = new CCodeDefine.with_expression (get_ccode_name (c), get_cvalue (c.value));
1149 163 : decl_space.add_define (cdefine);
1150 : }
1151 : }
1152 : }
1153 :
1154 162 : public override void visit_constant (Constant c) {
1155 162 : push_line (c.source_reference);
1156 :
1157 178 : if (c.parent_symbol is Block) {
1158 : // local constant
1159 :
1160 16 : generate_type_declaration (c.type_reference, cfile);
1161 :
1162 16 : c.value.emit (this);
1163 :
1164 : string type_name;
1165 16 : if (c.type_reference.compatible (string_type)) {
1166 1 : type_name = "const char";
1167 : } else {
1168 15 : type_name = get_ccode_const_name (c.type_reference);
1169 : }
1170 :
1171 16 : var cinitializer = get_cvalue (c.value);
1172 :
1173 16 : ccode.add_declaration (type_name, new CCodeVariableDeclarator (get_ccode_name (c), cinitializer, get_constant_declarator_suffix (c)), CCodeModifiers.STATIC);
1174 : } else {
1175 146 : generate_constant_declaration (c, cfile, true);
1176 :
1177 146 : if (!c.is_internal_symbol ()) {
1178 13 : generate_constant_declaration (c, header_file);
1179 : }
1180 146 : if (!c.is_private_symbol ()) {
1181 70 : generate_constant_declaration (c, internal_header_file);
1182 : }
1183 : }
1184 :
1185 162 : pop_line ();
1186 : }
1187 :
1188 1884 : public void append_field (CCodeStruct ccode_struct, Field f, CCodeFile decl_space) {
1189 1884 : generate_type_declaration (f.variable_type, decl_space);
1190 :
1191 1884 : CCodeModifiers modifiers = (f.is_volatile ? CCodeModifiers.VOLATILE : 0) | (f.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
1192 1884 : ccode_struct.add_field (get_ccode_name (f.variable_type), get_ccode_name (f), modifiers, get_ccode_declarator_suffix (f.variable_type));
1193 :
1194 2018 : if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1195 : // create fields to store array dimensions
1196 134 : var array_type = (ArrayType) f.variable_type;
1197 234 : if (!array_type.fixed_length) {
1198 100 : var length_ctype = get_ccode_array_length_type (f);
1199 202 : for (int dim = 1; dim <= array_type.rank; dim++) {
1200 102 : string length_cname = get_variable_array_length_cname (f, dim);
1201 102 : ccode_struct.add_field (length_ctype, length_cname);
1202 : }
1203 100 : if (array_type.rank == 1 && f.is_internal_symbol ()) {
1204 55 : ccode_struct.add_field (length_ctype, get_array_size_cname (get_ccode_name (f)));
1205 : }
1206 : }
1207 1781 : } else if (get_ccode_delegate_target (f)) {
1208 31 : var delegate_type = (DelegateType) f.variable_type;
1209 31 : if (delegate_type.delegate_symbol.has_target) {
1210 : // create field to store delegate target
1211 31 : ccode_struct.add_field (get_ccode_name (delegate_target_type), get_ccode_delegate_target_name (f));
1212 31 : if (delegate_type.is_disposable ()) {
1213 27 : ccode_struct.add_field (get_ccode_name (delegate_target_destroy_type), get_ccode_delegate_target_destroy_notify_name (f));
1214 : }
1215 : }
1216 : }
1217 : }
1218 :
1219 3051 : public void generate_field_declaration (Field f, CCodeFile decl_space) {
1220 2519 : if (add_symbol_declaration (decl_space, f, get_ccode_name (f))) {
1221 : return;
1222 : }
1223 :
1224 532 : generate_type_declaration (f.variable_type, decl_space);
1225 :
1226 532 : var cdecl = new CCodeDeclaration (get_ccode_name (f.variable_type));
1227 532 : cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type)));
1228 532 : if (f.is_private_symbol ()) {
1229 122 : cdecl.modifiers = CCodeModifiers.STATIC;
1230 : } else {
1231 410 : cdecl.modifiers = CCodeModifiers.EXTERN;
1232 410 : requires_vala_extern = true;
1233 : }
1234 532 : if (f.version.deprecated) {
1235 4 : cdecl.modifiers |= CCodeModifiers.DEPRECATED;
1236 : }
1237 532 : if (f.is_volatile) {
1238 0 : cdecl.modifiers |= CCodeModifiers.VOLATILE;
1239 : }
1240 532 : decl_space.add_type_member_declaration (cdecl);
1241 :
1242 542 : if (f.lock_used) {
1243 : // Declare mutex for static member
1244 10 : var flock = new CCodeDeclaration (get_ccode_name (mutex_type));
1245 10 : var flock_decl = new CCodeVariableDeclarator (get_symbol_lock_name ("%s_%s".printf (get_ccode_lower_case_name (f.parent_symbol), get_ccode_name (f))), new CCodeConstant ("{0}"));
1246 10 : flock.add_declarator (flock_decl);
1247 :
1248 10 : if (f.is_private_symbol ()) {
1249 2 : flock.modifiers = CCodeModifiers.STATIC;
1250 : } else {
1251 8 : flock.modifiers = CCodeModifiers.EXTERN;
1252 8 : requires_vala_extern = true;
1253 : }
1254 10 : decl_space.add_type_member_declaration (flock);
1255 : }
1256 :
1257 594 : if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1258 62 : var array_type = (ArrayType) f.variable_type;
1259 :
1260 110 : if (!array_type.fixed_length) {
1261 48 : var length_ctype = get_ccode_array_length_type (f);
1262 :
1263 96 : for (int dim = 1; dim <= array_type.rank; dim++) {
1264 48 : cdecl = new CCodeDeclaration (length_ctype);
1265 48 : cdecl.add_declarator (new CCodeVariableDeclarator (get_variable_array_length_cname (f, dim)));
1266 48 : if (f.is_private_symbol ()) {
1267 3 : cdecl.modifiers = CCodeModifiers.STATIC;
1268 : } else {
1269 45 : cdecl.modifiers = CCodeModifiers.EXTERN;
1270 45 : requires_vala_extern = true;
1271 : }
1272 48 : decl_space.add_type_member_declaration (cdecl);
1273 : }
1274 : }
1275 474 : } else if (get_ccode_delegate_target (f)) {
1276 4 : var delegate_type = (DelegateType) f.variable_type;
1277 4 : if (delegate_type.delegate_symbol.has_target) {
1278 : // create field to store delegate target
1279 :
1280 4 : cdecl = new CCodeDeclaration (get_ccode_name (delegate_target_type));
1281 4 : cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f)));
1282 4 : if (f.is_private_symbol ()) {
1283 0 : cdecl.modifiers = CCodeModifiers.STATIC;
1284 : } else {
1285 4 : cdecl.modifiers = CCodeModifiers.EXTERN;
1286 4 : requires_vala_extern = true;
1287 : }
1288 4 : decl_space.add_type_member_declaration (cdecl);
1289 :
1290 4 : if (delegate_type.is_disposable ()) {
1291 2 : cdecl = new CCodeDeclaration (get_ccode_name (delegate_target_destroy_type));
1292 2 : cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_destroy_notify_name (f)));
1293 2 : if (f.is_private_symbol ()) {
1294 0 : cdecl.modifiers = CCodeModifiers.STATIC;
1295 : } else {
1296 2 : cdecl.modifiers = CCodeModifiers.EXTERN;
1297 2 : requires_vala_extern = true;
1298 : }
1299 2 : decl_space.add_type_member_declaration (cdecl);
1300 : }
1301 : }
1302 : }
1303 : }
1304 :
1305 3274 : public override void visit_field (Field f) {
1306 1637 : push_line (f.source_reference);
1307 1637 : visit_member (f);
1308 :
1309 1637 : var cl = f.parent_symbol as Class;
1310 1274 : bool is_gtypeinstance = (cl != null && !cl.is_compact);
1311 :
1312 1637 : if (f.binding == MemberBinding.INSTANCE) {
1313 1267 : if (f.initializer != null) {
1314 219 : push_context (instance_init_context);
1315 :
1316 219 : f.initializer.emit (this);
1317 :
1318 219 : if (!is_simple_struct_creation (f, f.initializer)) {
1319 : // otherwise handled in visit_object_creation_expression
1320 219 : store_field (f, new GLibValue (null, new CCodeIdentifier ("self")), f.initializer.target_value, true, f.source_reference);
1321 : }
1322 :
1323 219 : foreach (var value in temp_ref_values) {
1324 0 : ccode.add_expression (destroy_value (value));
1325 : }
1326 :
1327 219 : temp_ref_values.clear ();
1328 :
1329 219 : pop_context ();
1330 : }
1331 :
1332 1267 : if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_destroy (f.variable_type) && instance_finalize_context != null) {
1333 699 : push_context (instance_finalize_context);
1334 699 : ccode.add_expression (destroy_field (f, load_this_parameter ((TypeSymbol) f.parent_symbol)));
1335 699 : pop_context ();
1336 : }
1337 370 : } else if (f.binding == MemberBinding.CLASS) {
1338 13 : if (f.initializer != null) {
1339 9 : push_context (class_init_context);
1340 :
1341 9 : f.initializer.emit (this);
1342 :
1343 9 : store_field (f, null, f.initializer.target_value, true, f.source_reference);
1344 :
1345 9 : foreach (var value in temp_ref_values) {
1346 0 : ccode.add_expression (destroy_value (value));
1347 : }
1348 :
1349 9 : temp_ref_values.clear ();
1350 :
1351 9 : pop_context ();
1352 : }
1353 : } else {
1354 357 : generate_field_declaration (f, cfile);
1355 :
1356 357 : if (!f.is_internal_symbol ()) {
1357 84 : generate_field_declaration (f, header_file);
1358 : }
1359 357 : if (!f.is_private_symbol ()) {
1360 235 : generate_field_declaration (f, internal_header_file);
1361 : }
1362 :
1363 712 : if (!f.external) {
1364 355 : var var_decl = new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type));
1365 355 : var initializer = default_value_for_type (f.variable_type, true);
1366 : // error: initializer element is not constant (-std=c99 -pedantic-errors)
1367 356 : while (initializer is CCodeCastExpression) {
1368 2 : initializer = ((CCodeCastExpression) initializer).inner;
1369 : }
1370 355 : var_decl.initializer = initializer;
1371 :
1372 355 : if (class_init_context != null) {
1373 211 : push_context (class_init_context);
1374 : } else {
1375 144 : push_context (new EmitContext ());
1376 : }
1377 :
1378 440 : if (f.initializer != null) {
1379 85 : f.initializer.emit (this);
1380 :
1381 85 : var init = get_cvalue (f.initializer);
1382 85 : if (is_constant_ccode_expression (init)) {
1383 73 : var_decl.initializer = init;
1384 : }
1385 : }
1386 :
1387 355 : var var_def = new CCodeDeclaration (get_ccode_name (f.variable_type));
1388 355 : var_def.add_declarator (var_decl);
1389 355 : if (!f.is_private_symbol ()) {
1390 233 : var_def.modifiers = CCodeModifiers.EXTERN;
1391 233 : requires_vala_extern = true;
1392 : } else {
1393 122 : var_def.modifiers = CCodeModifiers.STATIC;
1394 : }
1395 355 : if (f.version.deprecated) {
1396 2 : var_def.modifiers |= CCodeModifiers.DEPRECATED;
1397 : }
1398 355 : if (f.is_volatile) {
1399 0 : var_def.modifiers |= CCodeModifiers.VOLATILE;
1400 : }
1401 355 : cfile.add_type_member_declaration (var_def);
1402 :
1403 : /* add array length fields where necessary */
1404 386 : if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1405 31 : var array_type = (ArrayType) f.variable_type;
1406 :
1407 55 : if (!array_type.fixed_length) {
1408 24 : var length_ctype = get_ccode_array_length_type (f);
1409 :
1410 72 : for (int dim = 1; dim <= array_type.rank; dim++) {
1411 24 : var len_def = new CCodeDeclaration (length_ctype);
1412 24 : len_def.add_declarator (new CCodeVariableDeclarator (get_variable_array_length_cname (f, dim), new CCodeConstant ("0")));
1413 24 : if (!f.is_private_symbol ()) {
1414 21 : len_def.modifiers = CCodeModifiers.EXTERN;
1415 21 : requires_vala_extern = true;
1416 : } else {
1417 3 : len_def.modifiers = CCodeModifiers.STATIC;
1418 : }
1419 24 : cfile.add_type_member_declaration (len_def);
1420 : }
1421 :
1422 45 : if (array_type.rank == 1 && f.is_internal_symbol ()) {
1423 21 : var cdecl = new CCodeDeclaration (length_ctype);
1424 21 : cdecl.add_declarator (new CCodeVariableDeclarator (get_array_size_cname (get_ccode_name (f)), new CCodeConstant ("0")));
1425 21 : cdecl.modifiers = CCodeModifiers.STATIC;
1426 21 : cfile.add_type_member_declaration (cdecl);
1427 : }
1428 : }
1429 326 : } else if (get_ccode_delegate_target (f)) {
1430 2 : var delegate_type = (DelegateType) f.variable_type;
1431 4 : if (delegate_type.delegate_symbol.has_target) {
1432 : // create field to store delegate target
1433 :
1434 2 : var target_def = new CCodeDeclaration (get_ccode_name (delegate_target_type));
1435 2 : target_def.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f), new CCodeConstant ("NULL")));
1436 2 : if (!f.is_private_symbol ()) {
1437 2 : target_def.modifiers = CCodeModifiers.EXTERN;
1438 2 : requires_vala_extern = true;
1439 : } else {
1440 0 : target_def.modifiers = CCodeModifiers.STATIC;
1441 : }
1442 2 : cfile.add_type_member_declaration (target_def);
1443 :
1444 3 : if (delegate_type.is_disposable ()) {
1445 1 : var target_destroy_notify_def = new CCodeDeclaration (get_ccode_name (delegate_target_destroy_type));
1446 1 : target_destroy_notify_def.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_destroy_notify_name (f), new CCodeConstant ("NULL")));
1447 1 : if (!f.is_private_symbol ()) {
1448 1 : target_destroy_notify_def.modifiers = CCodeModifiers.EXTERN;
1449 1 : requires_vala_extern = true;
1450 : } else {
1451 0 : target_destroy_notify_def.modifiers = CCodeModifiers.STATIC;
1452 : }
1453 1 : cfile.add_type_member_declaration (target_destroy_notify_def);
1454 :
1455 : }
1456 : }
1457 : }
1458 :
1459 440 : if (f.initializer != null) {
1460 85 : var rhs = get_cvalue (f.initializer);
1461 85 : if (!is_constant_ccode_expression (rhs)) {
1462 12 : if (is_gtypeinstance) {
1463 12 : store_field (f, null, f.initializer.target_value, true, f.source_reference);
1464 : } else {
1465 0 : f.error = true;
1466 0 : Report.error (f.source_reference, "Non-constant field initializers not supported in this context");
1467 0 : return;
1468 : }
1469 : }
1470 : }
1471 :
1472 355 : pop_context ();
1473 : }
1474 : }
1475 :
1476 1637 : pop_line ();
1477 : }
1478 :
1479 453 : public static bool is_constant_ccode_expression (CCodeExpression cexpr) {
1480 453 : if (cexpr is CCodeConstant || cexpr is CCodeConstantIdentifier) {
1481 453 : return true;
1482 32 : } else if (cexpr is CCodeInitializerList) {
1483 453 : return true;
1484 26 : } else if (cexpr is CCodeCastExpression) {
1485 0 : var ccast = (CCodeCastExpression) cexpr;
1486 0 : return is_constant_ccode_expression (ccast.inner);
1487 26 : } else if (cexpr is CCodeUnaryExpression) {
1488 0 : var cunary = (CCodeUnaryExpression) cexpr;
1489 0 : switch (cunary.operator) {
1490 : case CCodeUnaryOperator.PREFIX_INCREMENT:
1491 : case CCodeUnaryOperator.PREFIX_DECREMENT:
1492 : case CCodeUnaryOperator.POSTFIX_INCREMENT:
1493 : case CCodeUnaryOperator.POSTFIX_DECREMENT:
1494 0 : return false;
1495 : default:
1496 0 : break;
1497 : }
1498 0 : return is_constant_ccode_expression (cunary.inner);
1499 26 : } else if (cexpr is CCodeBinaryExpression) {
1500 0 : var cbinary = (CCodeBinaryExpression) cexpr;
1501 0 : return is_constant_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1502 : }
1503 :
1504 26 : var cparenthesized = (cexpr as CCodeParenthesizedExpression);
1505 0 : return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
1506 : }
1507 :
1508 69 : public static bool is_constant_ccode (CodeNode expr) {
1509 69 : if (expr is Constant) {
1510 : // Local constants are not considered constant in C
1511 7 : return !(((Constant) expr).parent_symbol is Block);
1512 62 : } else if (expr is IntegerLiteral) {
1513 51 : return ((IntegerLiteral) expr).is_constant ();
1514 11 : } else if (expr is MemberAccess) {
1515 7 : return is_constant_ccode (((MemberAccess) expr).symbol_reference);
1516 4 : } else if (expr is CastExpression) {
1517 0 : return is_constant_ccode (((CastExpression) expr).inner);
1518 : }
1519 :
1520 62 : return false;
1521 : }
1522 :
1523 : /**
1524 : * Returns whether the passed cexpr is a pure expression, i.e. an
1525 : * expression without side-effects.
1526 : */
1527 0 : public static bool is_pure_ccode_expression (CCodeExpression cexpr) {
1528 0 : if (cexpr is CCodeConstant || cexpr is CCodeIdentifier) {
1529 0 : return true;
1530 0 : } else if (cexpr is CCodeBinaryExpression) {
1531 0 : var cbinary = (CCodeBinaryExpression) cexpr;
1532 0 : return is_pure_ccode_expression (cbinary.left) && is_pure_ccode_expression (cbinary.right);
1533 0 : } else if (cexpr is CCodeUnaryExpression) {
1534 0 : var cunary = (CCodeUnaryExpression) cexpr;
1535 0 : switch (cunary.operator) {
1536 : case CCodeUnaryOperator.PREFIX_INCREMENT:
1537 : case CCodeUnaryOperator.PREFIX_DECREMENT:
1538 : case CCodeUnaryOperator.POSTFIX_INCREMENT:
1539 : case CCodeUnaryOperator.POSTFIX_DECREMENT:
1540 0 : return false;
1541 : default:
1542 0 : return is_pure_ccode_expression (cunary.inner);
1543 : }
1544 0 : } else if (cexpr is CCodeMemberAccess) {
1545 0 : var cma = (CCodeMemberAccess) cexpr;
1546 0 : return is_pure_ccode_expression (cma.inner);
1547 0 : } else if (cexpr is CCodeElementAccess) {
1548 0 : var cea = (CCodeElementAccess) cexpr;
1549 0 : return is_pure_ccode_expression (cea.container) && is_pure_ccode_expression (cea.indices[0]);
1550 0 : } else if (cexpr is CCodeCastExpression) {
1551 0 : var ccast = (CCodeCastExpression) cexpr;
1552 0 : return is_pure_ccode_expression (ccast.inner);
1553 0 : } else if (cexpr is CCodeParenthesizedExpression) {
1554 0 : var cparenthesized = (CCodeParenthesizedExpression) cexpr;
1555 0 : return is_pure_ccode_expression (cparenthesized.inner);
1556 : }
1557 :
1558 0 : return false;
1559 : }
1560 :
1561 510 : public override void visit_property (Property prop) {
1562 510 : visit_member (prop);
1563 :
1564 510 : if (prop.get_accessor != null) {
1565 500 : prop.get_accessor.accept (this);
1566 : }
1567 510 : if (prop.set_accessor != null) {
1568 414 : prop.set_accessor.accept (this);
1569 : }
1570 : }
1571 :
1572 145702 : public void generate_type_declaration (DataType type, CCodeFile decl_space) {
1573 220131 : if (type is ObjectType) {
1574 74429 : var object_type = (ObjectType) type;
1575 144864 : if (object_type.type_symbol is Class) {
1576 70435 : var cl = (Class) object_type.type_symbol;
1577 70435 : generate_class_declaration (cl, decl_space);
1578 70435 : if (!cl.is_compact && cl.has_type_parameters ()) {
1579 4709 : generate_struct_declaration ((Struct) gtype_type, decl_space);
1580 : }
1581 7988 : } else if (object_type.type_symbol is Interface) {
1582 3994 : var iface = (Interface) object_type.type_symbol;
1583 3994 : generate_interface_declaration (iface, decl_space);
1584 3994 : if (iface.has_type_parameters ()) {
1585 45 : generate_struct_declaration ((Struct) gtype_type, decl_space);
1586 : }
1587 : }
1588 74308 : } else if (type is DelegateType) {
1589 3035 : var deleg_type = (DelegateType) type;
1590 3035 : var d = deleg_type.delegate_symbol;
1591 3035 : generate_delegate_declaration (d, decl_space);
1592 3035 : if (d.has_target) {
1593 914 : generate_type_declaration (delegate_target_type, decl_space);
1594 914 : if (deleg_type.is_disposable ()) {
1595 487 : generate_type_declaration (delegate_target_destroy_type, decl_space);
1596 : }
1597 : }
1598 70095 : } else if (type.type_symbol is Enum) {
1599 1857 : var en = (Enum) type.type_symbol;
1600 1857 : generate_enum_declaration (en, decl_space);
1601 97945 : } else if (type is ValueType) {
1602 31564 : var value_type = (ValueType) type;
1603 31564 : generate_struct_declaration ((Struct) value_type.type_symbol, decl_space);
1604 41434 : } else if (type is ArrayType) {
1605 6617 : var array_type = (ArrayType) type;
1606 6617 : generate_type_declaration (array_type.element_type, decl_space);
1607 6617 : if (array_type.length_type != null) {
1608 6617 : generate_type_declaration (array_type.length_type, decl_space);
1609 : }
1610 29820 : } else if (type is ErrorType) {
1611 1620 : var error_type = (ErrorType) type;
1612 1620 : if (error_type.error_domain != null) {
1613 1155 : generate_error_domain_declaration (error_type.error_domain, decl_space);
1614 : } else {
1615 465 : generate_class_declaration (gerror, decl_space);
1616 : }
1617 28571 : } else if (type is PointerType) {
1618 1991 : var pointer_type = (PointerType) type;
1619 1991 : generate_type_declaration (pointer_type.base_type, decl_space);
1620 32343 : } else if (type is MethodType) {
1621 7754 : var method = ((MethodType) type).method_symbol;
1622 7754 : if (method.has_type_parameters () && !get_ccode_simple_generics (method)) {
1623 118 : generate_struct_declaration ((Struct) gtype_type, decl_space);
1624 : }
1625 : }
1626 :
1627 158908 : foreach (DataType type_arg in type.get_type_arguments ()) {
1628 6603 : generate_type_declaration (type_arg, decl_space);
1629 : }
1630 : }
1631 :
1632 5497 : public virtual void generate_class_struct_declaration (Class cl, CCodeFile decl_space) {
1633 : }
1634 :
1635 36904 : public virtual void generate_struct_declaration (Struct st, CCodeFile decl_space) {
1636 : }
1637 :
1638 3318 : public virtual void generate_delegate_declaration (Delegate d, CCodeFile decl_space) {
1639 : }
1640 :
1641 17696 : public virtual void generate_cparameters (Method m, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
1642 : }
1643 :
1644 9097 : public void generate_property_accessor_declaration (PropertyAccessor acc, CCodeFile decl_space) {
1645 7604 : if (add_symbol_declaration (decl_space, acc, get_ccode_name (acc))) {
1646 : return;
1647 : }
1648 :
1649 1493 : var prop = (Property) acc.prop;
1650 :
1651 2214 : bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1652 :
1653 :
1654 : CCodeParameter cvalueparam;
1655 768 : if (returns_real_struct) {
1656 47 : cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (acc.value_type)));
1657 1446 : } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1658 45 : cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (acc.value_type)));
1659 : } else {
1660 1401 : cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1661 : }
1662 1493 : generate_type_declaration (acc.value_type, decl_space);
1663 :
1664 : CCodeFunction function;
1665 1493 : if (acc.readable && !returns_real_struct) {
1666 721 : function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (acc.value_type));
1667 : } else {
1668 772 : function = new CCodeFunction (get_ccode_name (acc), "void");
1669 : }
1670 :
1671 2966 : if (prop.binding == MemberBinding.INSTANCE) {
1672 1473 : var t = (TypeSymbol) prop.parent_symbol;
1673 1473 : var this_type = SemanticAnalyzer.get_data_type_for_symbol (t);
1674 1473 : generate_type_declaration (this_type, decl_space);
1675 1473 : var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1676 1473 : if (t is Struct && !((Struct) t).is_simple_type ()) {
1677 16 : cselfparam.type_name += "*";
1678 : }
1679 :
1680 1473 : function.add_parameter (cselfparam);
1681 : }
1682 :
1683 1493 : if (acc.writable || acc.construction || returns_real_struct) {
1684 772 : function.add_parameter (cvalueparam);
1685 : }
1686 :
1687 1553 : if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1688 60 : var array_type = (ArrayType) acc.value_type;
1689 60 : var length_ctype = get_ccode_array_length_type (prop);
1690 120 : for (int dim = 1; dim <= array_type.rank; dim++) {
1691 89 : function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? length_ctype + "*" : length_ctype));
1692 : }
1693 1473 : } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1694 40 : function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? get_ccode_name (delegate_target_type) + "*" : get_ccode_name (delegate_target_type)));
1695 40 : if (!acc.readable && acc.value_type.value_owned) {
1696 8 : function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), get_ccode_name (delegate_target_destroy_type)));
1697 : }
1698 : }
1699 :
1700 1493 : if (prop.version.deprecated) {
1701 8 : if (context.profile == Profile.GOBJECT) {
1702 8 : decl_space.add_include ("glib.h");
1703 : }
1704 8 : function.modifiers |= CCodeModifiers.DEPRECATED;
1705 : }
1706 :
1707 1493 : if (!prop.is_abstract
1708 1354 : && (prop.is_private_symbol () || (!acc.readable && !acc.writable) || acc.access == SymbolAccessibility.PRIVATE)) {
1709 78 : function.modifiers |= CCodeModifiers.STATIC;
1710 1415 : } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1711 98 : function.modifiers |= CCodeModifiers.INTERNAL;
1712 : } else {
1713 1317 : function.modifiers |= CCodeModifiers.EXTERN;
1714 1317 : requires_vala_extern = true;
1715 : }
1716 1493 : decl_space.add_function_declaration (function);
1717 : }
1718 :
1719 1828 : public override void visit_property_accessor (PropertyAccessor acc) {
1720 914 : push_context (new EmitContext (acc));
1721 914 : push_line (acc.source_reference);
1722 :
1723 914 : var prop = (Property) acc.prop;
1724 :
1725 914 : if (acc.comment != null) {
1726 0 : cfile.add_type_member_definition (new CCodeComment (acc.comment.content));
1727 : }
1728 :
1729 914 : bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1730 :
1731 914 : if (acc.result_var != null) {
1732 0 : acc.result_var.accept (this);
1733 : }
1734 :
1735 914 : var t = (TypeSymbol) prop.parent_symbol;
1736 :
1737 : // do not declare overriding properties and interface implementations
1738 914 : if (prop.is_abstract || prop.is_virtual
1739 813 : || (prop.base_property == null && prop.base_interface_property == null)) {
1740 807 : generate_property_accessor_declaration (acc, cfile);
1741 :
1742 : // do not declare construct-only properties in header files
1743 807 : if (acc.readable || acc.writable) {
1744 799 : if (!prop.is_internal_symbol ()
1745 403 : && (acc.access == SymbolAccessibility.PUBLIC
1746 73 : || acc.access == SymbolAccessibility.PROTECTED)) {
1747 335 : generate_property_accessor_declaration (acc, header_file);
1748 : }
1749 799 : if (!prop.is_private_symbol () && acc.access != SymbolAccessibility.PRIVATE) {
1750 720 : generate_property_accessor_declaration (acc, internal_header_file);
1751 : }
1752 : }
1753 : }
1754 :
1755 914 : if (acc.source_type == SourceFileType.FAST) {
1756 0 : pop_line ();
1757 0 : pop_context ();
1758 0 : return;
1759 : }
1760 :
1761 914 : var this_type = SemanticAnalyzer.get_data_type_for_symbol (t);
1762 914 : var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1763 914 : if (t is Struct && !((Struct) t).is_simple_type ()) {
1764 12 : cselfparam.type_name += "*";
1765 : }
1766 : CCodeParameter cvalueparam;
1767 914 : if (returns_real_struct) {
1768 27 : cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (acc.value_type)));
1769 887 : } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1770 25 : cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (acc.value_type)));
1771 : } else {
1772 862 : cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1773 : }
1774 :
1775 1015 : if (prop.is_abstract || prop.is_virtual) {
1776 : CCodeFunction function;
1777 101 : if (acc.readable && !returns_real_struct) {
1778 50 : function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (current_return_type));
1779 : } else {
1780 51 : function = new CCodeFunction (get_ccode_name (acc), "void");
1781 : }
1782 101 : function.add_parameter (cselfparam);
1783 101 : if (acc.writable || acc.construction || returns_real_struct) {
1784 51 : function.add_parameter (cvalueparam);
1785 : }
1786 :
1787 109 : if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1788 8 : var array_type = (ArrayType) acc.value_type;
1789 8 : var length_ctype = get_ccode_array_length_type (prop);
1790 16 : for (int dim = 1; dim <= array_type.rank; dim++) {
1791 12 : function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? length_ctype + "*": length_ctype));
1792 : }
1793 105 : } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1794 12 : function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? get_ccode_name (delegate_target_type) + "*" : get_ccode_name (delegate_target_type)));
1795 12 : if (!acc.readable && acc.value_type.value_owned) {
1796 4 : function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), get_ccode_name (delegate_target_destroy_type)));
1797 : }
1798 : }
1799 :
1800 101 : if (!prop.is_abstract
1801 36 : && (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE)) {
1802 : // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1803 0 : function.modifiers |= CCodeModifiers.STATIC;
1804 101 : } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1805 2 : function.modifiers |= CCodeModifiers.INTERNAL;
1806 : }
1807 :
1808 101 : push_function (function);
1809 :
1810 101 : if (acc.value_type.is_non_null_simple_type () && default_value_for_type (acc.value_type, false) == null) {
1811 0 : var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (acc.value_type, true));
1812 0 : vardecl.init0 = true;
1813 0 : ccode.add_declaration (get_ccode_name (acc.value_type), vardecl);
1814 : }
1815 :
1816 101 : if (prop.binding == MemberBinding.INSTANCE) {
1817 101 : if (!acc.readable || returns_real_struct) {
1818 51 : create_property_type_check_statement (prop, false, t, true, "self");
1819 : } else {
1820 50 : create_property_type_check_statement (prop, true, t, true, "self");
1821 : }
1822 : }
1823 :
1824 : CCodeExpression vcast;
1825 202 : if (prop.parent_symbol is Interface) {
1826 56 : var iface = (Interface) prop.parent_symbol;
1827 :
1828 56 : vcast = new CCodeIdentifier ("_iface_");
1829 56 : var vcastcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
1830 56 : ((CCodeFunctionCall) vcastcall).add_argument (new CCodeIdentifier ("self"));
1831 56 : ccode.add_declaration ("%s*".printf (get_ccode_type_name (iface)), new CCodeVariableDeclarator ("_iface_"));
1832 56 : ccode.add_assignment (vcast, vcastcall);
1833 : } else {
1834 45 : var cl = (Class) prop.parent_symbol;
1835 86 : if (!cl.is_compact) {
1836 41 : vcast = new CCodeIdentifier ("_klass_");
1837 41 : var vcastcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
1838 41 : ((CCodeFunctionCall) vcastcall).add_argument (new CCodeIdentifier ("self"));
1839 41 : ccode.add_declaration ("%s*".printf (get_ccode_type_name (cl)), new CCodeVariableDeclarator ("_klass_"));
1840 41 : ccode.add_assignment (vcast, vcastcall);
1841 : } else {
1842 4 : vcast = new CCodeIdentifier ("self");
1843 : }
1844 : }
1845 :
1846 202 : if (acc.readable) {
1847 55 : var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
1848 55 : vcall.add_argument (new CCodeIdentifier ("self"));
1849 :
1850 : // check if vfunc pointer is properly set
1851 55 : ccode.open_if (vcall.call);
1852 :
1853 55 : if (returns_real_struct) {
1854 5 : vcall.add_argument (new CCodeIdentifier ("result"));
1855 5 : ccode.add_expression (vcall);
1856 : } else {
1857 54 : if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1858 8 : var array_type = (ArrayType) acc.value_type;
1859 :
1860 12 : for (int dim = 1; dim <= array_type.rank; dim++) {
1861 4 : var len_expr = new CCodeIdentifier (get_array_length_cname ("result", dim));
1862 4 : vcall.add_argument (len_expr);
1863 : }
1864 46 : } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1865 6 : vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("result")));
1866 : }
1867 :
1868 50 : ccode.add_return (vcall);
1869 : }
1870 55 : ccode.close ();
1871 :
1872 55 : if (acc.value_type.is_non_null_simple_type () && default_value_for_type (acc.value_type, false) == null) {
1873 0 : ccode.add_return (new CCodeIdentifier ("result"));
1874 55 : } else if (!(acc.value_type is VoidType)) {
1875 55 : ccode.add_return (default_value_for_type (acc.value_type, false, true));
1876 : }
1877 : } else {
1878 46 : var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
1879 46 : vcall.add_argument (new CCodeIdentifier ("self"));
1880 46 : vcall.add_argument (new CCodeIdentifier ("value"));
1881 :
1882 : // check if vfunc pointer is properly set
1883 46 : ccode.open_if (vcall.call);
1884 :
1885 50 : if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1886 8 : var array_type = (ArrayType) acc.value_type;
1887 :
1888 12 : for (int dim = 1; dim <= array_type.rank; dim++) {
1889 4 : var len_expr = new CCodeIdentifier (get_array_length_cname ("value", dim));
1890 4 : vcall.add_argument (len_expr);
1891 : }
1892 42 : } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1893 6 : vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("value")));
1894 6 : if (!acc.readable && acc.value_type.value_owned) {
1895 4 : vcall.add_argument (new CCodeIdentifier (get_delegate_target_destroy_notify_cname ("value")));
1896 : }
1897 : }
1898 :
1899 46 : ccode.add_expression (vcall);
1900 46 : ccode.close ();
1901 : }
1902 :
1903 101 : pop_function ();
1904 :
1905 101 : cfile.add_function (function);
1906 : }
1907 :
1908 1761 : if (!prop.is_abstract && acc.body != null) {
1909 847 : bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
1910 :
1911 847 : string cname = get_ccode_real_name (acc);
1912 :
1913 : CCodeFunction function;
1914 847 : if (acc.writable || acc.construction || returns_real_struct) {
1915 409 : function = new CCodeFunction (cname, "void");
1916 : } else {
1917 438 : function = new CCodeFunction (cname, get_ccode_name (acc.value_type));
1918 : }
1919 :
1920 847 : ObjectType base_type = null;
1921 847 : if (prop.binding == MemberBinding.INSTANCE) {
1922 837 : if (is_virtual) {
1923 143 : if (prop.base_property != null) {
1924 79 : base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
1925 64 : } else if (prop.base_interface_property != null) {
1926 64 : base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
1927 : }
1928 143 : function.modifiers |= CCodeModifiers.STATIC;
1929 143 : function.add_parameter (new CCodeParameter ("base", get_ccode_name (base_type)));
1930 : } else {
1931 694 : function.add_parameter (cselfparam);
1932 : }
1933 : }
1934 847 : if (acc.writable || acc.construction || returns_real_struct) {
1935 409 : function.add_parameter (cvalueparam);
1936 : }
1937 :
1938 877 : if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1939 30 : var array_type = (ArrayType) acc.value_type;
1940 30 : var length_ctype = get_ccode_array_length_type (prop);
1941 60 : for (int dim = 1; dim <= array_type.rank; dim++) {
1942 43 : function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? length_ctype + "*" : length_ctype));
1943 : }
1944 835 : } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1945 18 : function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? get_ccode_name (delegate_target_type) + "*" : get_ccode_name (delegate_target_type)));
1946 18 : if (!acc.readable && acc.value_type.value_owned) {
1947 4 : function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), get_ccode_name (delegate_target_destroy_type)));
1948 : }
1949 : }
1950 :
1951 847 : if (!is_virtual) {
1952 704 : if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1953 : // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1954 83 : function.modifiers |= CCodeModifiers.STATIC;
1955 621 : } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1956 18 : function.modifiers |= CCodeModifiers.INTERNAL;
1957 : }
1958 : }
1959 :
1960 847 : push_function (function);
1961 :
1962 847 : if (prop.binding == MemberBinding.INSTANCE && !is_virtual) {
1963 694 : if (!acc.readable || returns_real_struct) {
1964 338 : create_property_type_check_statement (prop, false, t, true, "self");
1965 : } else {
1966 356 : create_property_type_check_statement (prop, true, t, true, "self");
1967 : }
1968 : }
1969 :
1970 847 : if (acc.readable && !returns_real_struct) {
1971 : // do not declare result variable if exit block is known to be unreachable
1972 438 : if (acc.return_block == null || acc.return_block.get_predecessors ().size > 0) {
1973 433 : ccode.add_declaration (get_ccode_name (acc.value_type), new CCodeVariableDeclarator ("result"));
1974 : }
1975 : }
1976 :
1977 847 : if (is_virtual) {
1978 143 : ccode.add_declaration (get_ccode_name (this_type), new CCodeVariableDeclarator ("self"));
1979 143 : ccode.add_assignment (new CCodeIdentifier ("self"), get_cvalue_ (transform_value (new GLibValue (base_type, new CCodeIdentifier ("base"), true), this_type, acc)));
1980 : }
1981 :
1982 : // notify on property changes
1983 1121 : if (context.analyzer.is_gobject_property (prop) &&
1984 623 : prop.notify &&
1985 621 : (acc.writable || acc.construction)) {
1986 274 : var notify_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_notify_by_pspec"));
1987 274 : notify_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
1988 274 : notify_call.add_argument (get_param_spec_cexpression (prop));
1989 :
1990 274 : var get_accessor = prop.get_accessor;
1991 538 : if (get_accessor != null && get_accessor.automatic_body) {
1992 264 : var property_type = prop.property_type;
1993 264 : var get_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (get_accessor)));
1994 264 : get_call.add_argument (new CCodeIdentifier (is_virtual ? "base" : "self"));
1995 :
1996 264 : if (property_type is ArrayType && get_ccode_array_length (prop)) {
1997 6 : ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
1998 6 : ccode.add_declaration (get_ccode_array_length_type (prop), new CCodeVariableDeclarator ("old_value_length"));
1999 6 : get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value_length")));
2000 6 : ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2001 6 : ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("old_value"), new CCodeIdentifier ("value")));
2002 320 : } else if (property_type.compatible (string_type)) {
2003 62 : ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2004 62 : ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2005 : CCodeFunctionCall ccall;
2006 62 : if (context.profile == Profile.POSIX) {
2007 0 : cfile.add_include ("string.h");
2008 0 : ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
2009 : } else {
2010 62 : ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
2011 : }
2012 62 : ccall.add_argument (new CCodeIdentifier ("value"));
2013 62 : ccall.add_argument (new CCodeIdentifier ("old_value"));
2014 62 : ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("0")));
2015 214 : } else if (property_type is StructValueType) {
2016 18 : ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2017 18 : if (property_type.nullable) {
2018 3 : ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2019 : } else {
2020 15 : get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value")));
2021 15 : ccode.add_expression (get_call);
2022 : }
2023 18 : var equalfunc = generate_struct_equal_function ((Struct) property_type.type_symbol);
2024 18 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
2025 18 : ccall.add_argument (new CCodeIdentifier ("value"));
2026 18 : if (property_type.nullable) {
2027 3 : ccall.add_argument (new CCodeIdentifier ("old_value"));
2028 : } else {
2029 15 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value")));
2030 : }
2031 18 : ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("TRUE")));
2032 : } else {
2033 178 : ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2034 178 : ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2035 178 : ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("old_value"), new CCodeIdentifier ("value")));
2036 : }
2037 :
2038 264 : acc.body.emit (this);
2039 264 : ccode.add_expression (notify_call);
2040 264 : ccode.close ();
2041 :
2042 285 : if (prop.get_accessor.value_type.is_disposable ()) {
2043 21 : var old_value = new GLibValue (prop.get_accessor.value_type, new CCodeIdentifier ("old_value"), true);
2044 21 : if (property_type is ArrayType && get_ccode_array_length (prop)) {
2045 2 : old_value.append_array_length_cvalue (new CCodeIdentifier ("old_value_length"));
2046 : }
2047 21 : ccode.add_expression (destroy_value (old_value));
2048 : }
2049 : } else {
2050 10 : acc.body.emit (this);
2051 10 : ccode.add_expression (notify_call);
2052 : }
2053 : } else {
2054 573 : acc.body.emit (this);
2055 : }
2056 :
2057 847 : if (current_method_inner_error) {
2058 3 : ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
2059 : }
2060 :
2061 847 : pop_function ();
2062 :
2063 847 : cfile.add_function (function);
2064 : }
2065 :
2066 914 : pop_line ();
2067 914 : pop_context ();
2068 : }
2069 :
2070 17 : public override void visit_destructor (Destructor d) {
2071 17 : if (d.binding == MemberBinding.STATIC && !in_plugin) {
2072 1 : Report.error (d.source_reference, "static destructors are only supported for dynamic types");
2073 1 : d.error = true;
2074 1 : return;
2075 : }
2076 : }
2077 :
2078 1053 : public int get_block_id (Block b) {
2079 1053 : int result = block_map[b];
2080 1053 : if (result == 0) {
2081 82 : result = ++next_block_id;
2082 82 : block_map[b] = result;
2083 : }
2084 : return result;
2085 : }
2086 :
2087 154 : public bool no_implicit_copy (DataType type) {
2088 : // note: implicit copy of array is planned to be forbidden
2089 154 : unowned Class? cl = type.type_symbol as Class;
2090 154 : return (type is DelegateType ||
2091 118 : type is ArrayType ||
2092 98 : (cl != null && !cl.is_immutable && !is_reference_counting (cl) && !get_ccode_is_gboxed (cl)));
2093 : }
2094 :
2095 60 : void capture_parameter (Parameter param, CCodeStruct data, int block_id) {
2096 30 : generate_type_declaration (param.variable_type, cfile);
2097 :
2098 30 : var param_type = param.variable_type.copy ();
2099 30 : if (!param.variable_type.value_owned) {
2100 28 : param_type.value_owned = !no_implicit_copy (param.variable_type);
2101 : }
2102 30 : data.add_field (get_ccode_name (param_type), get_ccode_name (param), 0, get_ccode_declarator_suffix (param_type));
2103 :
2104 : // create copy if necessary as captured variables may need to be kept alive
2105 30 : param.captured = false;
2106 30 : var value = load_parameter (param);
2107 :
2108 30 : var array_type = param.variable_type as ArrayType;
2109 30 : var deleg_type = param.variable_type as DelegateType;
2110 :
2111 31 : if (array_type != null && get_ccode_array_length (param) && !((ArrayType) array_type).fixed_length) {
2112 1 : var length_ctype = get_ccode_array_length_type (param);
2113 2 : for (int dim = 1; dim <= array_type.rank; dim++) {
2114 1 : data.add_field (length_ctype, get_variable_array_length_cname (param, dim));
2115 : }
2116 29 : } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
2117 11 : data.add_field (get_ccode_name (delegate_target_type), get_ccode_delegate_target_name (param));
2118 12 : if (param.variable_type.is_disposable ()) {
2119 1 : data.add_field (get_ccode_name (delegate_target_destroy_type), get_ccode_delegate_target_destroy_notify_name (param));
2120 : // reference transfer for delegates
2121 1 : var lvalue = get_parameter_cvalue (param);
2122 1 : ((GLibValue) value).delegate_target_destroy_notify_cvalue = get_delegate_target_destroy_notify_cvalue (lvalue);
2123 : }
2124 : }
2125 30 : param.captured = true;
2126 :
2127 30 : store_parameter (param, value, true);
2128 : }
2129 :
2130 31228 : public override void visit_block (Block b) {
2131 15614 : emit_context.push_symbol (b);
2132 :
2133 15614 : var local_vars = b.get_local_variables ();
2134 :
2135 15614 : if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
2136 1845 : ccode.open_block ();
2137 : }
2138 :
2139 15614 : if (b.parent_node is TryStatement && b == ((TryStatement) b.parent_node).finally_body) {
2140 : // finally-block with nested error handling
2141 46 : if (((TryStatement) b.parent_node).body.tree_can_fail) {
2142 16 : if (is_in_coroutine ()) {
2143 : // _inner_error0_ gets added to closure_struct in CCodeMethodModule.visit_method()
2144 5 : if (current_inner_error_id > 0
2145 4 : && (!method_inner_error_var_count.contains (current_method)
2146 1 : || method_inner_error_var_count.get (current_method) < current_inner_error_id)) {
2147 : // no initialization necessary, closure struct is zeroed
2148 3 : closure_struct.add_field ("GError*", "_inner_error%d_".printf (current_inner_error_id));
2149 3 : method_inner_error_var_count.set (current_method, current_inner_error_id);
2150 : }
2151 : } else {
2152 11 : ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
2153 : }
2154 : }
2155 : }
2156 :
2157 15696 : if (b.captured) {
2158 82 : var parent_block = next_closure_block (b.parent_symbol);
2159 :
2160 82 : int block_id = get_block_id (b);
2161 82 : string struct_name = "Block%dData".printf (block_id);
2162 :
2163 82 : var data = new CCodeStruct ("_" + struct_name);
2164 82 : data.add_field ("int", "_ref_count_");
2165 82 : if (parent_block != null) {
2166 1 : int parent_block_id = get_block_id (parent_block);
2167 :
2168 1 : data.add_field ("Block%dData *".printf (parent_block_id), "_data%d_".printf (parent_block_id));
2169 : } else {
2170 81 : unowned DataType? this_type = get_this_type ();
2171 81 : if (this_type != null) {
2172 24 : data.add_field (get_ccode_name (this_type), "self");
2173 : }
2174 :
2175 81 : if (current_method != null) {
2176 : // allow capturing generic type parameters
2177 85 : foreach (var type_param in current_method.get_type_parameters ()) {
2178 3 : data.add_field ("GType", get_ccode_type_id (type_param));
2179 3 : data.add_field ("GBoxedCopyFunc", get_ccode_copy_function (type_param));
2180 3 : data.add_field ("GDestroyNotify", get_ccode_destroy_function (type_param));
2181 : }
2182 : }
2183 : }
2184 356 : foreach (var local in local_vars) {
2185 137 : if (local.captured) {
2186 73 : generate_type_declaration (local.variable_type, cfile);
2187 :
2188 73 : data.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
2189 :
2190 77 : if (local.variable_type is ArrayType && !((ArrayType) local.variable_type).fixed_length) {
2191 4 : var array_type = (ArrayType) local.variable_type;
2192 4 : var length_ctype = get_ccode_array_length_type (array_type);
2193 8 : for (int dim = 1; dim <= array_type.rank; dim++) {
2194 4 : data.add_field (length_ctype, get_array_length_cname (get_local_cname (local), dim));
2195 : }
2196 4 : data.add_field (length_ctype, get_array_size_cname (get_local_cname (local)));
2197 69 : } else if (local.variable_type is DelegateType && ((DelegateType) local.variable_type).delegate_symbol.has_target) {
2198 2 : data.add_field (get_ccode_name (delegate_target_type), get_delegate_target_cname (get_local_cname (local)));
2199 2 : if (local.variable_type.is_disposable ()) {
2200 1 : data.add_field (get_ccode_name (delegate_target_destroy_type), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2201 : }
2202 67 : } else if (local.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
2203 0 : Report.error (local.source_reference, "internal: Capturing `va_list' variable `%s' is not allowed", local.get_full_name ());
2204 0 : b.error = true;
2205 : }
2206 : }
2207 : }
2208 :
2209 82 : var data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
2210 82 : data_alloc.add_argument (new CCodeIdentifier (struct_name));
2211 :
2212 82 : if (is_in_coroutine ()) {
2213 9 : closure_struct.add_field (struct_name + "*", "_data%d_".printf (block_id));
2214 : } else {
2215 73 : ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id)));
2216 : }
2217 82 : ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), data_alloc);
2218 :
2219 : // initialize ref_count
2220 82 : ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_ref_count_"), new CCodeIdentifier ("1"));
2221 :
2222 83 : if (parent_block != null) {
2223 1 : int parent_block_id = get_block_id (parent_block);
2224 :
2225 1 : var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (parent_block_id)));
2226 1 : ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id)));
2227 :
2228 1 : ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call);
2229 : } else {
2230 : // skip self assignment in toplevel block of creation methods with chainup as self is not set at the beginning of the method
2231 : // the chainup statement takes care of assigning self in the closure struct
2232 81 : bool in_creation_method_with_chainup = (current_method is CreationMethod && current_class != null && current_class.base_class != null);
2233 :
2234 81 : unowned DataType? this_type = get_this_type ();
2235 100 : if (this_type != null && (!in_creation_method_with_chainup || current_method.body != b)) {
2236 : CCodeExpression instance;
2237 19 : if (is_in_destructor ()) {
2238 : // never increase reference count for self in finalizers to avoid infinite recursion on following unref
2239 1 : instance = new CCodeIdentifier ("self");
2240 : } else {
2241 18 : var ref_call = new CCodeFunctionCall (get_dup_func_expression (this_type, b.source_reference));
2242 18 : ref_call.add_argument (get_this_cexpression ());
2243 36 : instance = ref_call;
2244 : }
2245 :
2246 19 : ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), instance);
2247 : }
2248 :
2249 160 : if (current_method != null) {
2250 : // allow capturing generic type parameters
2251 79 : var data_var = get_variable_cexpression ("_data%d_".printf (block_id));
2252 85 : foreach (var type_param in current_method.get_type_parameters ()) {
2253 3 : var type = get_ccode_type_id (type_param);
2254 3 : var dup_func = get_ccode_copy_function (type_param);
2255 3 : var destroy_func = get_ccode_destroy_function (type_param);
2256 3 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, type), get_variable_cexpression (type));
2257 3 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, dup_func), get_variable_cexpression (dup_func));
2258 3 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, destroy_func), get_variable_cexpression (destroy_func));
2259 : }
2260 : }
2261 : }
2262 :
2263 157 : if (b.parent_symbol is Method) {
2264 150 : var m = (Method) b.parent_symbol;
2265 :
2266 : // parameters are captured with the top-level block of the method
2267 161 : foreach (var param in m.get_parameters ()) {
2268 43 : if (param.captured) {
2269 29 : capture_parameter (param, data, block_id);
2270 :
2271 29 : if (param.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
2272 0 : Report.error (param.source_reference, "internal: Capturing `va_list' parameter `%s' is not allowed", param.get_full_name ());
2273 0 : b.error = true;
2274 : }
2275 : }
2276 : }
2277 :
2278 75 : if (m.coroutine) {
2279 : // capture async data to allow invoking callback from inside closure
2280 9 : data.add_field (get_ccode_name (pointer_type), "_async_data_");
2281 :
2282 : // async method is suspended while waiting for callback,
2283 : // so we never need to care about memory management of async data
2284 9 : ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_async_data_"), new CCodeIdentifier ("_data_"));
2285 : }
2286 8 : } else if (b.parent_symbol is PropertyAccessor) {
2287 1 : var acc = (PropertyAccessor) b.parent_symbol;
2288 :
2289 1 : if (!acc.readable && acc.value_parameter.captured) {
2290 1 : capture_parameter (acc.value_parameter, data, block_id);
2291 : }
2292 7 : } else if (b.parent_symbol is ForeachStatement) {
2293 1 : var stmt = (ForeachStatement) b.parent_symbol;
2294 1 : if (!stmt.use_iterator && stmt.element_variable.captured) {
2295 1 : ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_local_cname (stmt.element_variable)), get_variable_cexpression (get_local_cname (stmt.element_variable)));
2296 : }
2297 : }
2298 :
2299 82 : var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name));
2300 82 : cfile.add_type_declaration (typedef);
2301 82 : cfile.add_type_definition (data);
2302 :
2303 : // create ref/unref functions
2304 82 : var ref_fun = new CCodeFunction ("block%d_data_ref".printf (block_id), struct_name + "*");
2305 82 : ref_fun.add_parameter (new CCodeParameter ("_data%d_".printf (block_id), struct_name + "*"));
2306 82 : ref_fun.modifiers = CCodeModifiers.STATIC;
2307 :
2308 82 : push_function (ref_fun);
2309 :
2310 82 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_inc"));
2311 82 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2312 82 : ccode.add_expression (ccall);
2313 82 : ccode.add_return (new CCodeIdentifier ("_data%d_".printf (block_id)));
2314 :
2315 82 : pop_function ();
2316 :
2317 82 : cfile.add_function_declaration (ref_fun);
2318 82 : cfile.add_function (ref_fun);
2319 :
2320 82 : var unref_fun = new CCodeFunction ("block%d_data_unref".printf (block_id), "void");
2321 82 : unref_fun.add_parameter (new CCodeParameter ("_userdata_", "void *"));
2322 82 : unref_fun.modifiers = CCodeModifiers.STATIC;
2323 :
2324 82 : push_function (unref_fun);
2325 :
2326 82 : ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id), new CCodeCastExpression (new CCodeIdentifier ("_userdata_"), struct_name + "*")));
2327 82 : ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_dec_and_test"));
2328 82 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2329 82 : ccode.open_if (ccall);
2330 :
2331 82 : CCodeExpression outer_block = new CCodeIdentifier ("_data%d_".printf (block_id));
2332 82 : unowned Block parent_closure_block = b;
2333 83 : while (true) {
2334 83 : parent_closure_block = next_closure_block (parent_closure_block.parent_symbol);
2335 83 : if (parent_closure_block == null) {
2336 : break;
2337 : }
2338 1 : int parent_block_id = get_block_id (parent_closure_block);
2339 1 : outer_block = new CCodeMemberAccess.pointer (outer_block, "_data%d_".printf (parent_block_id));
2340 : }
2341 :
2342 82 : var this_type = get_this_type ();
2343 24 : if (this_type != null) {
2344 : // assign "self" for type parameters
2345 24 : ccode.add_declaration(get_ccode_name (this_type), new CCodeVariableDeclarator ("self"));
2346 24 : ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeMemberAccess.pointer (outer_block, "self"));
2347 : }
2348 :
2349 82 : if (current_method != null) {
2350 : // assign captured generic type parameters
2351 86 : foreach (var type_param in current_method.get_type_parameters ()) {
2352 3 : var type = get_ccode_type_id (type_param);
2353 3 : var dup_func = get_ccode_copy_function (type_param);
2354 3 : var destroy_func = get_ccode_destroy_function (type_param);
2355 3 : ccode.add_declaration ("GType", new CCodeVariableDeclarator (type));
2356 3 : ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (dup_func));
2357 3 : ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (destroy_func));
2358 3 : ccode.add_assignment (new CCodeIdentifier (type), new CCodeMemberAccess.pointer (outer_block, type));
2359 3 : ccode.add_assignment (new CCodeIdentifier (dup_func), new CCodeMemberAccess.pointer (outer_block, dup_func));
2360 3 : ccode.add_assignment (new CCodeIdentifier (destroy_func), new CCodeMemberAccess.pointer (outer_block, destroy_func));
2361 : }
2362 : }
2363 :
2364 : // free in reverse order
2365 356 : for (int i = local_vars.size - 1; i >= 0; i--) {
2366 137 : var local = local_vars[i];
2367 137 : if (local.captured) {
2368 73 : if (requires_destroy (local.variable_type)) {
2369 48 : bool old_coroutine = false;
2370 48 : if (current_method != null) {
2371 48 : old_coroutine = current_method.coroutine;
2372 48 : current_method.coroutine = false;
2373 : }
2374 :
2375 48 : ccode.add_expression (destroy_local (local));
2376 :
2377 48 : if (old_coroutine) {
2378 3 : current_method.coroutine = true;
2379 : }
2380 : }
2381 : }
2382 : }
2383 :
2384 157 : if (b.parent_symbol is Method) {
2385 150 : var m = (Method) b.parent_symbol;
2386 :
2387 : // parameters are captured with the top-level block of the method
2388 161 : foreach (var param in m.get_parameters ()) {
2389 72 : if (param.captured) {
2390 29 : var param_type = param.variable_type.copy ();
2391 29 : if (!param_type.value_owned) {
2392 27 : param_type.value_owned = !no_implicit_copy (param_type);
2393 : }
2394 :
2395 29 : if (requires_destroy (param_type)) {
2396 8 : bool old_coroutine = false;
2397 8 : if (m != null) {
2398 8 : old_coroutine = m.coroutine;
2399 8 : m.coroutine = false;
2400 : }
2401 :
2402 8 : ccode.add_expression (destroy_parameter (param));
2403 :
2404 8 : if (old_coroutine) {
2405 2 : m.coroutine = true;
2406 : }
2407 : }
2408 : }
2409 : }
2410 8 : } else if (b.parent_symbol is PropertyAccessor) {
2411 1 : var acc = (PropertyAccessor) b.parent_symbol;
2412 :
2413 2 : if (!acc.readable && acc.value_parameter.captured) {
2414 1 : var param_type = acc.value_parameter.variable_type.copy ();
2415 1 : if (!param_type.value_owned) {
2416 1 : param_type.value_owned = !no_implicit_copy (param_type);
2417 : }
2418 :
2419 1 : if (requires_destroy (param_type)) {
2420 0 : ccode.add_expression (destroy_parameter (acc.value_parameter));
2421 : }
2422 : }
2423 : }
2424 :
2425 : // free parent block and "self" after captured variables
2426 : // because they may require type parameters
2427 83 : if (parent_block != null) {
2428 1 : int parent_block_id = get_block_id (parent_block);
2429 :
2430 1 : var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (parent_block_id)));
2431 1 : unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
2432 1 : ccode.add_expression (unref_call);
2433 1 : ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), new CCodeConstant ("NULL"));
2434 : } else {
2435 105 : this_type = get_this_type ();
2436 81 : if (this_type != null) {
2437 24 : this_type = this_type.copy ();
2438 24 : this_type.value_owned = true;
2439 46 : if (this_type.is_disposable () && !is_in_destructor ()) {
2440 : // reference count for self is not increased in finalizers
2441 22 : var this_value = new GLibValue (this_type, new CCodeIdentifier ("self"), true);
2442 22 : ccode.add_expression (destroy_value (this_value));
2443 : }
2444 : }
2445 : }
2446 :
2447 82 : var data_free = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
2448 82 : data_free.add_argument (new CCodeIdentifier (struct_name));
2449 82 : data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id)));
2450 82 : ccode.add_expression (data_free);
2451 :
2452 82 : ccode.close ();
2453 :
2454 82 : pop_function ();
2455 :
2456 82 : cfile.add_function_declaration (unref_fun);
2457 82 : cfile.add_function (unref_fun);
2458 : }
2459 :
2460 86726 : foreach (Statement stmt in b.get_statements ()) {
2461 35556 : push_line (stmt.source_reference);
2462 35556 : stmt.emit (this);
2463 35556 : pop_line ();
2464 : }
2465 :
2466 15614 : if (!b.unreachable_exit) {
2467 13670 : if (b.parent_symbol is Method) {
2468 3474 : unowned Method m = (Method) b.parent_symbol;
2469 : // check postconditions
2470 3490 : foreach (var postcondition in m.get_postconditions ()) {
2471 8 : create_postcondition_statement (postcondition);
2472 : }
2473 : }
2474 :
2475 : // free in reverse order
2476 25278 : for (int i = local_vars.size - 1; i >= 0; i--) {
2477 5804 : var local = local_vars[i];
2478 5804 : local.active = false;
2479 5804 : if (!local.unreachable && !local.captured && requires_destroy (local.variable_type)) {
2480 3050 : ccode.add_expression (destroy_local (local));
2481 : }
2482 : }
2483 :
2484 17144 : if (b.parent_symbol is Method) {
2485 6948 : var m = (Method) b.parent_symbol;
2486 7722 : foreach (Parameter param in m.get_parameters ()) {
2487 2124 : if (!param.captured && !param.ellipsis && !param.params_array && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
2488 31 : ccode.add_expression (destroy_parameter (param));
2489 2093 : } else if (param.direction == ParameterDirection.OUT && !m.coroutine) {
2490 42 : return_out_parameter (param);
2491 : }
2492 : }
2493 10577 : } else if (b.parent_symbol is PropertyAccessor) {
2494 381 : var acc = (PropertyAccessor) b.parent_symbol;
2495 381 : if (acc.value_parameter != null && !acc.value_parameter.captured && requires_destroy (acc.value_parameter.variable_type)) {
2496 11 : ccode.add_expression (destroy_parameter (acc.value_parameter));
2497 : }
2498 : }
2499 :
2500 13740 : if (b.captured) {
2501 70 : int block_id = get_block_id (b);
2502 :
2503 70 : var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
2504 70 : data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
2505 70 : ccode.add_expression (data_unref);
2506 70 : ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
2507 : }
2508 : }
2509 :
2510 15614 : if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
2511 1845 : ccode.close ();
2512 : }
2513 :
2514 15614 : emit_context.pop_symbol ();
2515 : }
2516 :
2517 6824 : public override void visit_declaration_statement (DeclarationStatement stmt) {
2518 6824 : stmt.declaration.accept (this);
2519 : }
2520 :
2521 108091 : public CCodeExpression get_cexpression (string name) {
2522 108091 : if (is_in_coroutine ()) {
2523 1882 : return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), name);
2524 : } else {
2525 106209 : return new CCodeIdentifier (name);
2526 : }
2527 : }
2528 :
2529 67066 : public CCodeExpression get_local_cexpression (LocalVariable local) {
2530 67066 : return get_cexpression (get_local_cname (local));
2531 : }
2532 :
2533 4731 : public CCodeExpression get_parameter_cexpression (Parameter param) {
2534 4731 : return get_cexpression (get_ccode_name (param));
2535 : }
2536 :
2537 27395 : public CCodeExpression get_variable_cexpression (string name) {
2538 27395 : return get_cexpression (get_variable_cname (name));
2539 : }
2540 :
2541 1922 : public CCodeExpression get_this_cexpression () {
2542 1922 : return get_cexpression ("self");
2543 : }
2544 :
2545 145 : public CCodeExpression get_this_class_cexpression (Class cl, TargetValue? instance = null) {
2546 : CCodeExpression cast;
2547 : CCodeFunctionCall call;
2548 145 : if (instance != null) {
2549 : // Accessing the member of an instance
2550 27 : if (cl.external_package) {
2551 0 : call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_CLASS"));
2552 0 : call.add_argument (get_cvalue_ (instance));
2553 0 : call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
2554 0 : call.add_argument (new CCodeIdentifier (get_ccode_type_name (cl)));
2555 : } else {
2556 27 : call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
2557 27 : call.add_argument (get_cvalue_ (instance));
2558 : }
2559 27 : cast = call;
2560 118 : } else if (get_this_type () != null) {
2561 : // Accessing the member from within an instance method
2562 55 : if (cl.external_package) {
2563 0 : call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_CLASS"));
2564 0 : call.add_argument (get_this_cexpression ());
2565 0 : call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
2566 0 : call.add_argument (new CCodeIdentifier (get_ccode_type_name (cl)));
2567 : } else {
2568 55 : call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
2569 55 : call.add_argument (get_this_cexpression ());
2570 : }
2571 55 : cast = call;
2572 : } else {
2573 : // Accessing the member from a static or class constructor
2574 63 : if (current_class == cl) {
2575 47 : cast = new CCodeIdentifier ("klass");
2576 : } else {
2577 16 : call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (cl)));
2578 16 : call.add_argument (new CCodeIdentifier ("klass"));
2579 16 : cast = call;
2580 : }
2581 : }
2582 145 : return cast;
2583 : }
2584 :
2585 17 : public CCodeExpression get_this_interface_cexpression (Interface iface, TargetValue? instance = null) {
2586 17 : unowned Class? cl = current_class;
2587 17 : if (instance == null && cl != null && cl.implements (iface)) {
2588 1 : return new CCodeIdentifier ("%s_%s_parent_iface".printf (get_ccode_lower_case_name (cl), get_ccode_lower_case_name (iface)));
2589 : }
2590 :
2591 : CCodeExpression cast;
2592 : CCodeFunctionCall call;
2593 16 : if (instance != null) {
2594 9 : if (iface.external_package) {
2595 0 : call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_INTERFACE"));
2596 0 : call.add_argument (get_cvalue_ (instance));
2597 0 : call.add_argument (new CCodeIdentifier (get_ccode_type_id (iface)));
2598 0 : call.add_argument (new CCodeIdentifier (get_ccode_type_name (iface)));
2599 : } else {
2600 9 : call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
2601 9 : call.add_argument (get_cvalue_ (instance));
2602 : }
2603 9 : cast = call;
2604 7 : } else if (get_this_type () != null) {
2605 7 : if (iface.external_package) {
2606 0 : call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_INTERFACE"));
2607 0 : call.add_argument (get_this_cexpression ());
2608 0 : call.add_argument (new CCodeIdentifier (get_ccode_type_id (iface)));
2609 0 : call.add_argument (new CCodeIdentifier (get_ccode_type_name (iface)));
2610 : } else {
2611 7 : call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
2612 7 : call.add_argument (get_this_cexpression ());
2613 : }
2614 7 : cast = call;
2615 : } else {
2616 0 : Report.error (null, "internal: missing instance");
2617 0 : cast = null;
2618 0 : assert_not_reached ();
2619 : }
2620 16 : return cast;
2621 : }
2622 :
2623 2490 : public CCodeExpression get_inner_error_cexpression () {
2624 2490 : return get_cexpression ("_inner_error%d_".printf (current_inner_error_id));
2625 : }
2626 :
2627 86621 : public string get_local_cname (LocalVariable local) {
2628 86621 : var cname = get_variable_cname (local.name);
2629 86621 : if (cname[0].isdigit ()) {
2630 0 : cname = "_%s_".printf (cname);
2631 : }
2632 86621 : if (is_in_coroutine ()) {
2633 970 : var clash_index = emit_context.closure_variable_clash_map.get (local);
2634 970 : if (clash_index > 0) {
2635 18 : cname = "_vala%d_%s".printf (clash_index, cname);
2636 : }
2637 : }
2638 : return cname;
2639 : }
2640 :
2641 114369 : public string get_variable_cname (string name) {
2642 114369 : if (name[0] == '.') {
2643 6587 : if (name == ".result") {
2644 105 : return "result";
2645 : }
2646 : // compiler-internal variable
2647 6482 : if (!variable_name_map.contains (name)) {
2648 1509 : variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
2649 1509 : next_temp_var_id++;
2650 : }
2651 6482 : return variable_name_map.get (name);
2652 107782 : } else if (reserved_identifiers.contains (name) || reserved_vala_identifiers.contains (name)) {
2653 302 : return "_%s_".printf (name);
2654 : } else {
2655 214960 : return name;
2656 : }
2657 : }
2658 :
2659 6851 : public bool is_simple_struct_creation (Variable variable, Expression expr) {
2660 6851 : unowned Struct? st = variable.variable_type.type_symbol as Struct;
2661 6851 : var creation = expr as ObjectCreationExpression;
2662 2023 : if (creation != null && st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list") && !variable.variable_type.nullable &&
2663 260 : variable.variable_type.type_symbol != gvalue_type && creation.get_object_initializer ().size == 0) {
2664 208 : return true;
2665 : } else {
2666 6643 : return false;
2667 : }
2668 : }
2669 :
2670 73 : static bool is_foreach_element_variable (LocalVariable local) {
2671 73 : var block = local.parent_symbol;
2672 73 : if (block != null) {
2673 73 : var stmt = block.parent_symbol as ForeachStatement;
2674 73 : if (stmt != null && !stmt.use_iterator && stmt.element_variable == local) {
2675 1 : return true;
2676 : }
2677 : }
2678 72 : return false;
2679 : }
2680 :
2681 14656 : public override void visit_local_variable (LocalVariable local) {
2682 : /* Declaration */
2683 :
2684 7328 : generate_type_declaration (local.variable_type, cfile);
2685 :
2686 : // captured element variables of foreach statements (without iterator) require local declaration
2687 7328 : var declared = !local.captured || is_foreach_element_variable (local);
2688 73 : if (declared) {
2689 14428 : if (is_in_coroutine ()) {
2690 84 : var count = emit_context.closure_variable_count_map.get (local.name);
2691 84 : if (count > 0) {
2692 4 : emit_context.closure_variable_clash_map.set (local, count);
2693 : }
2694 84 : emit_context.closure_variable_count_map.set (local.name, count + 1);
2695 :
2696 84 : closure_struct.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
2697 : } else {
2698 7172 : var cvar = new CCodeVariableDeclarator (get_local_cname (local), null, get_ccode_declarator_suffix (local.variable_type));
2699 :
2700 : // try to initialize uninitialized variables
2701 : // initialization not necessary for variables stored in closure
2702 7172 : CCodeExpression? size = null;
2703 7172 : if (!requires_memset_init (local, out size)) {
2704 7165 : cvar.initializer = default_value_for_type (local.variable_type, true);
2705 7165 : cvar.init0 = true;
2706 13 : } else if (size != null && local.initializer == null) {
2707 6 : cfile.add_include ("string.h");
2708 6 : var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
2709 6 : memset_call.add_argument (get_variable_cexpression (local.name));
2710 6 : memset_call.add_argument (new CCodeConstant ("0"));
2711 6 : memset_call.add_argument (size);
2712 6 : ccode.add_expression (memset_call);
2713 : }
2714 :
2715 7172 : ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
2716 : }
2717 : }
2718 :
2719 : /* Emit initializer */
2720 7328 : if (local.initializer != null) {
2721 5253 : local.initializer.emit (this);
2722 :
2723 5253 : visit_end_full_expression (local.initializer);
2724 : }
2725 :
2726 :
2727 7328 : CCodeExpression rhs = null;
2728 7328 : if (local.initializer != null && get_cvalue (local.initializer) != null) {
2729 5253 : rhs = get_cvalue (local.initializer);
2730 : }
2731 :
2732 : /* Additional temp variables */
2733 :
2734 7328 : if (declared) {
2735 7824 : if (local.variable_type is ArrayType) {
2736 : // create variables to store array dimensions
2737 568 : var array_type = (ArrayType) local.variable_type;
2738 :
2739 568 : if (!array_type.fixed_length) {
2740 1658 : for (int dim = 1; dim <= array_type.rank; dim++) {
2741 563 : var len_var = new LocalVariable (array_type.length_type.copy (), get_array_length_cname (get_local_cname (local), dim));
2742 563 : len_var.init = local.initializer == null;
2743 563 : emit_temp_var (len_var);
2744 : }
2745 :
2746 1044 : if (array_type.rank == 1) {
2747 512 : var size_var = new LocalVariable (array_type.length_type.copy (), get_array_size_cname (get_local_cname (local)));
2748 512 : size_var.init = local.initializer == null;
2749 512 : emit_temp_var (size_var);
2750 : }
2751 : }
2752 6807 : } else if (local.variable_type is DelegateType) {
2753 119 : var deleg_type = (DelegateType) local.variable_type;
2754 203 : if (deleg_type.delegate_symbol.has_target) {
2755 : // create variable to store delegate target
2756 84 : var target_var = new LocalVariable (delegate_target_type.copy (), get_delegate_target_cname (get_local_cname (local)));
2757 84 : target_var.init = local.initializer == null;
2758 84 : emit_temp_var (target_var);
2759 160 : if (deleg_type.is_disposable ()) {
2760 76 : var target_destroy_notify_var = new LocalVariable (delegate_target_destroy_type.copy (), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2761 76 : target_destroy_notify_var.init = local.initializer == null;
2762 76 : emit_temp_var (target_destroy_notify_var);
2763 : }
2764 : }
2765 : }
2766 : }
2767 :
2768 : /* Store the initializer */
2769 :
2770 7328 : if (rhs != null) {
2771 5253 : if (!is_simple_struct_creation (local, local.initializer)) {
2772 5186 : store_local (local, local.initializer.target_value, true, local.source_reference);
2773 : }
2774 : }
2775 :
2776 7328 : if (local.initializer != null && local.initializer.tree_can_fail) {
2777 185 : add_simple_check (local.initializer);
2778 : }
2779 :
2780 7328 : local.active = true;
2781 : }
2782 :
2783 : /**
2784 : * Create a temporary variable and return lvalue access to it
2785 : */
2786 35131 : public TargetValue create_temp_value (DataType type, bool init, CodeNode node_reference, bool? value_owned = null) {
2787 35131 : if (type is VoidType) {
2788 0 : Report.error (node_reference.source_reference, "internal: 'void' not supported as variable type");
2789 : }
2790 :
2791 35131 : var local = new LocalVariable (type.copy (), "_tmp%d_".printf (next_temp_var_id++), null, node_reference.source_reference);
2792 35131 : local.init = init;
2793 35131 : if (value_owned != null) {
2794 291 : local.variable_type.value_owned = value_owned;
2795 : }
2796 :
2797 35131 : var array_type = local.variable_type as ArrayType;
2798 35131 : var deleg_type = local.variable_type as DelegateType;
2799 :
2800 35131 : emit_temp_var (local);
2801 35131 : if (array_type != null) {
2802 5880 : for (int dim = 1; dim <= array_type.rank; dim++) {
2803 1977 : var len_var = new LocalVariable (array_type.length_type.copy (), get_array_length_cname (local.name, dim), null, node_reference.source_reference);
2804 1977 : len_var.init = init;
2805 1977 : emit_temp_var (len_var);
2806 : }
2807 33305 : } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
2808 100 : var target_var = new LocalVariable (delegate_target_type.copy (), get_delegate_target_cname (local.name), null, node_reference.source_reference);
2809 100 : target_var.init = init;
2810 100 : emit_temp_var (target_var);
2811 122 : if (deleg_type.is_disposable ()) {
2812 22 : var target_destroy_notify_var = new LocalVariable (delegate_target_destroy_type.copy (), get_delegate_target_destroy_notify_cname (local.name), null, node_reference.source_reference);
2813 22 : target_destroy_notify_var.init = init;
2814 22 : emit_temp_var (target_destroy_notify_var);
2815 : }
2816 : }
2817 :
2818 35131 : var value = get_local_cvalue (local);
2819 35131 : set_array_size_cvalue (value, null);
2820 35131 : return value;
2821 : }
2822 :
2823 : /**
2824 : * Load a temporary variable returning unowned or owned rvalue access to it, depending on the ownership of the value type.
2825 : */
2826 29987 : public TargetValue load_temp_value (TargetValue lvalue) {
2827 29987 : var value = ((GLibValue) lvalue).copy ();
2828 29987 : var deleg_type = value.value_type as DelegateType;
2829 312 : if (deleg_type != null) {
2830 312 : if (!deleg_type.delegate_symbol.has_target) {
2831 215 : value.delegate_target_cvalue = new CCodeConstant ("NULL");
2832 215 : ((GLibValue) value).lvalue = false;
2833 97 : } else if (!deleg_type.is_disposable ()) {
2834 78 : value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
2835 78 : ((GLibValue) value).lvalue = false;
2836 : }
2837 : }
2838 312 : return value;
2839 : }
2840 :
2841 : /**
2842 : * Store a value in a temporary variable and return unowned or owned rvalue access to it, depending on the ownership of the given type.
2843 : */
2844 25573 : public TargetValue store_temp_value (TargetValue initializer, CodeNode node_reference, bool? value_owned = null) {
2845 25573 : var lvalue = create_temp_value (initializer.value_type, false, node_reference, value_owned);
2846 25573 : store_value (lvalue, initializer, node_reference.source_reference);
2847 25573 : return load_temp_value (lvalue);
2848 : }
2849 :
2850 376 : bool is_static_field_initializer (CodeNode node) {
2851 376 : if (node is InitializerList) {
2852 184 : return is_static_field_initializer (node.parent_node);
2853 : }
2854 192 : return node is Constant || (node is Field && ((Field) node).binding == MemberBinding.STATIC);
2855 : }
2856 :
2857 1042 : public override void visit_initializer_list (InitializerList list) {
2858 1792 : if (list.target_type.type_symbol is Struct) {
2859 : /* initializer is used as struct initializer */
2860 292 : unowned Struct st = (Struct) list.target_type.type_symbol;
2861 302 : while (st.base_struct != null) {
2862 10 : st = st.base_struct;
2863 : }
2864 :
2865 584 : if (list.parent_node is Constant || list.parent_node is Field || list.parent_node is InitializerList) {
2866 192 : var clist = new CCodeInitializerList ();
2867 :
2868 192 : var field_it = st.get_fields ().iterator ();
2869 2078 : foreach (Expression expr in list.get_initializers ()) {
2870 943 : Field field = null;
2871 1886 : while (field == null) {
2872 943 : field_it.next ();
2873 943 : field = field_it.get ();
2874 943 : if (field.binding != MemberBinding.INSTANCE) {
2875 : // we only initialize instance fields
2876 943 : field = null;
2877 : }
2878 : }
2879 :
2880 943 : var cexpr = get_cvalue (expr);
2881 :
2882 943 : string ctype = get_ccode_type (field);
2883 943 : if (ctype != null) {
2884 117 : cexpr = new CCodeCastExpression (cexpr, ctype);
2885 : }
2886 :
2887 943 : clist.append (cexpr);
2888 :
2889 943 : var array_type = field.variable_type as ArrayType;
2890 957 : if (array_type != null && !array_type.fixed_length && get_ccode_array_length (field) && !get_ccode_array_null_terminated (field)) {
2891 12 : for (int dim = 1; dim <= array_type.rank; dim++) {
2892 6 : clist.append (get_array_length_cvalue (expr.target_value, dim));
2893 : }
2894 6 : if (array_type.rank == 1 && field.is_internal_symbol ()) {
2895 3 : clist.append (get_array_length_cvalue (expr.target_value, 1));
2896 : }
2897 : }
2898 : }
2899 :
2900 192 : if (list.size <= 0) {
2901 2 : clist.append (new CCodeConstant ("0"));
2902 : }
2903 :
2904 192 : if (is_static_field_initializer (list.parent_node)
2905 18 : || (list.parent_node is Expression && ((Expression) list.parent_node).value_type is ArrayType)) {
2906 174 : set_cvalue (list, clist);
2907 : } else {
2908 18 : set_cvalue (list, new CCodeCastExpression (clist, get_ccode_name (list.target_type.type_symbol)));
2909 : }
2910 : } else {
2911 : // used as expression
2912 100 : var instance = create_temp_value (list.value_type, true, list);
2913 :
2914 100 : var field_it = st.get_fields ().iterator ();
2915 410 : foreach (Expression expr in list.get_initializers ()) {
2916 155 : Field field = null;
2917 310 : while (field == null) {
2918 155 : field_it.next ();
2919 155 : field = field_it.get ();
2920 155 : if (field.binding != MemberBinding.INSTANCE) {
2921 : // we only initialize instance fields
2922 155 : field = null;
2923 : }
2924 : }
2925 :
2926 155 : store_field (field, instance, expr.target_value, false, expr.source_reference);
2927 : }
2928 :
2929 100 : list.target_value = instance;
2930 : }
2931 : } else {
2932 750 : var clist = new CCodeInitializerList ();
2933 4630 : foreach (Expression expr in list.get_initializers ()) {
2934 1940 : clist.append (get_cvalue (expr));
2935 : }
2936 750 : set_cvalue (list, clist);
2937 : }
2938 : }
2939 :
2940 6849 : public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null, bool init = false) {
2941 6849 : var var_type = type.copy ();
2942 6849 : var_type.value_owned = value_owned;
2943 6849 : var local = new LocalVariable (var_type, "_tmp%d_".printf (next_temp_var_id));
2944 6849 : local.init = init;
2945 :
2946 6849 : if (node_reference != null) {
2947 711 : local.source_reference = node_reference.source_reference;
2948 : }
2949 :
2950 6849 : next_temp_var_id++;
2951 :
2952 6849 : return local;
2953 : }
2954 :
2955 246 : bool is_in_generic_type (GenericType type) {
2956 246 : if (current_symbol != null && type.type_parameter.parent_symbol is TypeSymbol
2957 133 : && (current_method == null || current_method.binding == MemberBinding.INSTANCE)) {
2958 133 : return true;
2959 : } else {
2960 113 : return false;
2961 : }
2962 : }
2963 :
2964 20 : void require_generic_accessors (Interface iface) {
2965 20 : if (!iface.has_attribute ("GenericAccessors")) {
2966 2 : Report.error (iface.source_reference,
2967 : "missing generic type for interface `%s', add GenericAccessors attribute to interface declaration",
2968 : iface.get_full_name ());
2969 : }
2970 : }
2971 :
2972 266 : CCodeExpression get_generic_type_expression (string identifier, GenericType type, bool is_chainup = false) {
2973 266 : if (type.type_parameter.parent_symbol is Interface) {
2974 20 : unowned Interface iface = (Interface) type.type_parameter.parent_symbol;
2975 20 : require_generic_accessors (iface);
2976 :
2977 20 : var cast_self = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
2978 20 : cast_self.add_argument (get_this_cexpression ());
2979 20 : var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, "get_%s".printf (identifier)));
2980 20 : function_call.add_argument (get_this_cexpression ());
2981 20 : return function_call;
2982 : }
2983 :
2984 246 : if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
2985 101 : return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_this_cexpression (), "priv"), identifier);
2986 : } else {
2987 145 : return get_variable_cexpression (identifier);
2988 : }
2989 : }
2990 :
2991 855 : public CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
2992 855 : if (type is GenericType) {
2993 31 : var type_parameter = ((GenericType) type).type_parameter;
2994 31 : unowned Symbol? parent = type_parameter.owner.owner;
2995 31 : if (parent is Class && ((Class) parent).is_compact) {
2996 1 : Report.error (type.source_reference, "static type-parameter `%s' can not be used in runtime context", type.type_symbol.get_full_name ());
2997 1 : return new CCodeInvalidExpression();
2998 : }
2999 30 : string identifier = get_ccode_type_id (type_parameter);
3000 30 : return get_generic_type_expression (identifier, (GenericType) type, is_chainup);
3001 : } else {
3002 824 : string type_id = get_ccode_type_id (type);
3003 824 : if (type_id == "") {
3004 4 : type_id = "G_TYPE_INVALID";
3005 : } else {
3006 820 : generate_type_declaration (type, cfile);
3007 : }
3008 824 : return new CCodeIdentifier (type_id);
3009 : }
3010 : }
3011 :
3012 6490 : public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup = false) {
3013 3180 : if (type is ErrorType) {
3014 9 : return new CCodeIdentifier ("g_error_copy");
3015 3171 : } else if (type is GenericType) {
3016 89 : var type_parameter = ((GenericType) type).type_parameter;
3017 89 : string identifier = get_ccode_copy_function (type_parameter);
3018 89 : return get_generic_type_expression (identifier, (GenericType) type, is_chainup);
3019 3082 : } else if (type.type_symbol != null) {
3020 : string dup_function;
3021 3082 : unowned Class? cl = type.type_symbol as Class;
3022 3082 : if (is_reference_counting (type.type_symbol)) {
3023 1121 : if (is_ref_function_void (type)) {
3024 1 : dup_function = generate_ref_wrapper ((ObjectType) type);
3025 : } else {
3026 1120 : dup_function = get_ccode_ref_function ((ObjectTypeSymbol) type.type_symbol);
3027 : }
3028 1121 : if (type.type_symbol is Interface && dup_function == null) {
3029 2 : Report.error (source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure", type.type_symbol.get_full_name ());
3030 2 : return new CCodeInvalidExpression();
3031 : }
3032 1961 : } else if (cl != null && cl.is_immutable) {
3033 : // allow duplicates of immutable instances as for example strings
3034 1713 : dup_function = get_ccode_dup_function (type.type_symbol);
3035 1713 : if (dup_function == null) {
3036 0 : dup_function = "";
3037 : }
3038 248 : } else if (get_ccode_is_gboxed (type.type_symbol)) {
3039 : // allow duplicates of gboxed instances
3040 0 : dup_function = generate_dup_func_wrapper (type);
3041 0 : if (dup_function == null) {
3042 0 : dup_function = "";
3043 : }
3044 248 : } else if (type is ValueType) {
3045 247 : dup_function = get_ccode_dup_function (type.type_symbol);
3046 247 : if (dup_function == null && type.nullable) {
3047 171 : dup_function = generate_struct_dup_wrapper ((ValueType) type);
3048 76 : } else if (dup_function == null) {
3049 2 : dup_function = "";
3050 : }
3051 : } else {
3052 : // duplicating non-reference counted objects may cause side-effects (and performance issues)
3053 1 : Report.error (source_reference, "duplicating `%s' instance, use unowned variable or explicitly invoke copy method", type.type_symbol.name);
3054 1 : return new CCodeInvalidExpression();
3055 : }
3056 :
3057 3079 : return new CCodeIdentifier (dup_function);
3058 0 : } else if (type is PointerType) {
3059 0 : var pointer_type = (PointerType) type;
3060 0 : return get_dup_func_expression (pointer_type.base_type, source_reference);
3061 : } else {
3062 0 : return new CCodeConstant ("NULL");
3063 : }
3064 : }
3065 :
3066 7104 : void make_comparable_cexpression (ref DataType left_type, ref CCodeExpression cleft, ref DataType right_type, ref CCodeExpression cright) {
3067 7104 : unowned Struct? left_type_as_struct = left_type.type_symbol as Struct;
3068 7104 : unowned Struct? right_type_as_struct = right_type.type_symbol as Struct;
3069 7104 : unowned ObjectTypeSymbol? left_type_as_object_type = left_type.type_symbol as ObjectTypeSymbol;
3070 7104 : unowned ObjectTypeSymbol? right_type_as_object_type = right_type.type_symbol as ObjectTypeSymbol;
3071 :
3072 7104 : if (left_type_as_object_type != null && (!(left_type_as_object_type is Class) || !((Class) left_type_as_object_type).is_compact)
3073 1033 : && right_type_as_object_type != null && (!(right_type_as_object_type is Class) || !((Class) right_type_as_object_type).is_compact)) {
3074 252 : if (left_type_as_object_type != right_type_as_object_type) {
3075 14 : if (left_type_as_object_type.is_subtype_of (right_type_as_object_type)) {
3076 6 : cleft = generate_instance_cast (cleft, right_type_as_object_type);
3077 8 : } else if (right_type_as_object_type.is_subtype_of (left_type_as_object_type)) {
3078 8 : cright = generate_instance_cast (cright, left_type_as_object_type);
3079 : }
3080 : }
3081 6852 : } else if (left_type_as_struct != null && right_type_as_struct != null) {
3082 3084 : if (left_type is StructValueType) {
3083 : // real structs (uses compare/equal function)
3084 19 : if (!left_type.nullable) {
3085 11 : cleft = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft);
3086 : }
3087 19 : if (!right_type.nullable) {
3088 11 : cright = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cright);
3089 : }
3090 : } else {
3091 : // integer or floating or boolean type
3092 3065 : if (left_type.nullable && right_type.nullable) {
3093 : // FIXME also compare contents, not just address
3094 3029 : } else if (left_type.nullable) {
3095 : // FIXME check left value is not null
3096 0 : cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
3097 3029 : } else if (right_type.nullable) {
3098 : // FIXME check right value is not null
3099 0 : cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
3100 : }
3101 : }
3102 : }
3103 : }
3104 :
3105 44 : private string generate_struct_equal_function (Struct st) {
3106 44 : if (st.base_struct != null) {
3107 5 : return generate_struct_equal_function (st.base_struct);
3108 : }
3109 :
3110 39 : string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (st));
3111 :
3112 39 : if (!add_wrapper (equal_func)) {
3113 : // wrapper already defined
3114 39 : return equal_func;
3115 : }
3116 :
3117 21 : var function = new CCodeFunction (equal_func, get_ccode_name (bool_type));
3118 21 : function.modifiers = CCodeModifiers.STATIC;
3119 :
3120 21 : function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (st))));
3121 21 : function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (st))));
3122 :
3123 21 : push_function (function);
3124 :
3125 : // if (s1 == s2) return TRUE;
3126 21 : {
3127 21 : var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
3128 21 : ccode.open_if (cexp);
3129 21 : ccode.add_return (get_boolean_cconstant (true));
3130 21 : ccode.close ();
3131 : }
3132 : // if (s1 == NULL || s2 == NULL) return FALSE;
3133 21 : {
3134 21 : var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
3135 21 : ccode.open_if (cexp);
3136 21 : ccode.add_return (get_boolean_cconstant (false));
3137 21 : ccode.close ();
3138 :
3139 21 : cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
3140 21 : ccode.open_if (cexp);
3141 21 : ccode.add_return (get_boolean_cconstant (false));
3142 21 : ccode.close ();
3143 : }
3144 :
3145 21 : bool has_instance_fields = false;
3146 71 : foreach (Field f in st.get_fields ()) {
3147 25 : if (f.binding != MemberBinding.INSTANCE) {
3148 : // we only compare instance fields
3149 0 : continue;
3150 : }
3151 :
3152 25 : has_instance_fields = true;
3153 :
3154 : CCodeExpression cexp; // if (cexp) return FALSE;
3155 25 : var s1 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s1"), get_ccode_name (f)); // s1->f
3156 25 : var s2 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s2"), get_ccode_name (f)); // s2->f
3157 :
3158 25 : var variable_type = f.variable_type.copy ();
3159 25 : make_comparable_cexpression (ref variable_type, ref s1, ref variable_type, ref s2);
3160 :
3161 25 : if (!(f.variable_type is NullType) && f.variable_type.compatible (string_type)) {
3162 : CCodeFunctionCall ccall;
3163 7 : if (context.profile == Profile.POSIX) {
3164 0 : cfile.add_include ("string.h");
3165 0 : ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
3166 : } else {
3167 7 : ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
3168 : }
3169 7 : ccall.add_argument (s1);
3170 7 : ccall.add_argument (s2);
3171 14 : cexp = ccall;
3172 18 : } else if (f.variable_type is StructValueType) {
3173 0 : var equalfunc = generate_struct_equal_function (f.variable_type.type_symbol as Struct);
3174 0 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
3175 0 : ccall.add_argument (s1);
3176 0 : ccall.add_argument (s2);
3177 0 : cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
3178 : } else {
3179 18 : cexp = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, s1, s2);
3180 : }
3181 :
3182 25 : ccode.open_if (cexp);
3183 25 : ccode.add_return (get_boolean_cconstant (false));
3184 25 : ccode.close ();
3185 : }
3186 :
3187 21 : if (!has_instance_fields) {
3188 : // either opaque structure or simple type
3189 2 : if (st.is_simple_type ()) {
3190 0 : var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
3191 0 : ccode.add_return (cexp);
3192 : } else {
3193 2 : ccode.add_return (get_boolean_cconstant (false));
3194 : }
3195 : } else {
3196 19 : ccode.add_return (get_boolean_cconstant (true));
3197 : }
3198 :
3199 21 : pop_function ();
3200 :
3201 21 : cfile.add_function_declaration (function);
3202 21 : cfile.add_function (function);
3203 :
3204 21 : return equal_func;
3205 : }
3206 :
3207 51 : private string generate_numeric_equal_function (TypeSymbol sym) {
3208 51 : string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (sym));
3209 :
3210 51 : if (!add_wrapper (equal_func)) {
3211 : // wrapper already defined
3212 51 : return equal_func;
3213 : }
3214 :
3215 33 : var function = new CCodeFunction (equal_func, get_ccode_name (bool_type));
3216 33 : function.modifiers = CCodeModifiers.STATIC;
3217 :
3218 33 : function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (sym))));
3219 33 : function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (sym))));
3220 :
3221 33 : push_function (function);
3222 :
3223 : // if (s1 == s2) return TRUE;
3224 33 : {
3225 33 : var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
3226 33 : ccode.open_if (cexp);
3227 33 : ccode.add_return (get_boolean_cconstant (true));
3228 33 : ccode.close ();
3229 : }
3230 : // if (s1 == NULL || s2 == NULL) return FALSE;
3231 33 : {
3232 33 : var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
3233 33 : ccode.open_if (cexp);
3234 33 : ccode.add_return (get_boolean_cconstant (false));
3235 33 : ccode.close ();
3236 :
3237 33 : cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
3238 33 : ccode.open_if (cexp);
3239 33 : ccode.add_return (get_boolean_cconstant (false));
3240 33 : ccode.close ();
3241 : }
3242 : // return (*s1 == *s2);
3243 33 : {
3244 33 : var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
3245 33 : ccode.add_return (cexp);
3246 : }
3247 :
3248 33 : pop_function ();
3249 :
3250 33 : cfile.add_function_declaration (function);
3251 33 : cfile.add_function (function);
3252 :
3253 33 : return equal_func;
3254 : }
3255 :
3256 1 : string generate_ref_wrapper (ObjectType type) {
3257 1 : string ref_func = "_vala_%s".printf (get_ccode_ref_function (type.object_type_symbol));
3258 :
3259 1 : if (!add_wrapper (ref_func)) {
3260 : // wrapper already defined
3261 1 : return ref_func;
3262 : }
3263 :
3264 1 : var function = new CCodeFunction (ref_func, get_ccode_name (type));
3265 1 : function.modifiers = CCodeModifiers.STATIC;
3266 :
3267 1 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3268 :
3269 1 : push_function (function);
3270 :
3271 1 : ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("self"), new CCodeConstant ("NULL")));
3272 :
3273 1 : var ref_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_ref_function (type.object_type_symbol)));
3274 1 : ref_call.add_argument (new CCodeIdentifier ("self"));
3275 1 : ccode.add_expression (ref_call);
3276 :
3277 1 : ccode.close ();
3278 :
3279 1 : ccode.add_return (new CCodeIdentifier ("self"));
3280 :
3281 1 : pop_function ();
3282 :
3283 1 : cfile.add_function_declaration (function);
3284 1 : cfile.add_function (function);
3285 :
3286 1 : return ref_func;
3287 : }
3288 :
3289 171 : private string generate_struct_dup_wrapper (ValueType value_type) {
3290 171 : string dup_func = "_%sdup".printf (get_ccode_lower_case_prefix (value_type.type_symbol));
3291 :
3292 171 : if (!add_wrapper (dup_func)) {
3293 : // wrapper already defined
3294 171 : return dup_func;
3295 : }
3296 :
3297 51 : var function = new CCodeFunction (dup_func, get_ccode_name (value_type));
3298 51 : function.modifiers = CCodeModifiers.STATIC;
3299 :
3300 51 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (value_type)));
3301 :
3302 51 : push_function (function);
3303 :
3304 102 : if (value_type.type_symbol == gvalue_type) {
3305 3 : var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
3306 3 : dup_call.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
3307 3 : dup_call.add_argument (new CCodeIdentifier ("self"));
3308 :
3309 3 : ccode.add_return (dup_call);
3310 : } else {
3311 48 : ccode.add_declaration (get_ccode_name (value_type), new CCodeVariableDeclarator ("dup"));
3312 :
3313 : CCodeFunctionCall creation_call;
3314 49 : if (context.profile == Profile.POSIX) {
3315 1 : cfile.add_include ("stdlib.h");
3316 1 : creation_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
3317 1 : creation_call.add_argument (new CCodeConstant ("1"));
3318 1 : var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
3319 1 : csizeof.add_argument (new CCodeIdentifier (get_ccode_name (value_type.type_symbol)));
3320 1 : creation_call.add_argument (csizeof);
3321 : } else {
3322 47 : cfile.add_include ("glib.h");
3323 47 : creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
3324 47 : creation_call.add_argument (new CCodeIdentifier (get_ccode_name (value_type.type_symbol)));
3325 47 : creation_call.add_argument (new CCodeConstant ("1"));
3326 : }
3327 48 : ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
3328 :
3329 48 : var st = value_type.type_symbol as Struct;
3330 96 : if (st != null && st.is_disposable ()) {
3331 0 : if (!get_ccode_has_copy_function (st)) {
3332 0 : generate_struct_copy_function (st);
3333 : }
3334 :
3335 0 : var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
3336 0 : copy_call.add_argument (new CCodeIdentifier ("self"));
3337 0 : copy_call.add_argument (new CCodeIdentifier ("dup"));
3338 0 : ccode.add_expression (copy_call);
3339 : } else {
3340 48 : cfile.add_include ("string.h");
3341 :
3342 48 : var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
3343 48 : sizeof_call.add_argument (new CCodeConstant (get_ccode_name (value_type.type_symbol)));
3344 :
3345 48 : var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
3346 48 : copy_call.add_argument (new CCodeIdentifier ("dup"));
3347 48 : copy_call.add_argument (new CCodeIdentifier ("self"));
3348 48 : copy_call.add_argument (sizeof_call);
3349 48 : ccode.add_expression (copy_call);
3350 : }
3351 :
3352 48 : ccode.add_return (new CCodeIdentifier ("dup"));
3353 : }
3354 :
3355 51 : pop_function ();
3356 :
3357 51 : cfile.add_function_declaration (function);
3358 51 : cfile.add_function (function);
3359 :
3360 51 : return dup_func;
3361 : }
3362 :
3363 0 : protected string generate_dup_func_wrapper (DataType type) {
3364 0 : string destroy_func = "_vala_%s_copy".printf (get_ccode_name (type.type_symbol));
3365 :
3366 0 : if (!add_wrapper (destroy_func)) {
3367 : // wrapper already defined
3368 0 : return destroy_func;
3369 : }
3370 :
3371 0 : var function = new CCodeFunction (destroy_func, get_ccode_name (type));
3372 0 : function.modifiers = CCodeModifiers.STATIC;
3373 0 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3374 :
3375 0 : push_function (function);
3376 :
3377 0 : var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
3378 0 : free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (type.type_symbol)));
3379 0 : free_call.add_argument (new CCodeIdentifier ("self"));
3380 :
3381 0 : ccode.add_return (free_call);
3382 :
3383 0 : pop_function ();
3384 :
3385 0 : cfile.add_function_declaration (function);
3386 0 : cfile.add_function (function);
3387 :
3388 0 : return destroy_func;
3389 : }
3390 :
3391 0 : protected string generate_free_function_address_of_wrapper (DataType type) {
3392 0 : string destroy_func = "_vala_%s_free_function_address_of".printf (get_ccode_name (type.type_symbol));
3393 :
3394 0 : if (!add_wrapper (destroy_func)) {
3395 : // wrapper already defined
3396 0 : return destroy_func;
3397 : }
3398 :
3399 0 : var function = new CCodeFunction (destroy_func, "void");
3400 0 : function.modifiers = CCodeModifiers.STATIC;
3401 0 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3402 :
3403 0 : push_function (function);
3404 :
3405 0 : unowned Class? cl = type.type_symbol as Class;
3406 0 : assert (cl != null);
3407 :
3408 0 : var free_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (cl)));
3409 0 : free_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("self")));
3410 :
3411 0 : ccode.add_expression (free_call);
3412 :
3413 0 : pop_function ();
3414 :
3415 0 : cfile.add_function_declaration (function);
3416 0 : cfile.add_function (function);
3417 :
3418 0 : return destroy_func;
3419 : }
3420 :
3421 5 : protected string generate_destroy_function_content_of_wrapper (DataType type) {
3422 : // g_array_set_clear_func has a specific GDestroyNotify where the content of an element is given
3423 5 : string destroy_func = "_vala_%s_free_function_content_of".printf (get_ccode_name (type.type_symbol));
3424 :
3425 5 : if (!add_wrapper (destroy_func)) {
3426 : // wrapper already defined
3427 5 : return destroy_func;
3428 : }
3429 :
3430 3 : var function = new CCodeFunction (destroy_func, "void");
3431 3 : function.modifiers = CCodeModifiers.STATIC;
3432 3 : function.add_parameter (new CCodeParameter ("data", get_ccode_name (pointer_type)));
3433 3 : push_function (function);
3434 :
3435 3 : ccode.add_declaration (get_ccode_name (type), new CCodeVariableDeclarator ("self"));
3436 3 : var cast = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeCastExpression (new CCodeIdentifier ("data"), get_ccode_name (type) + "*"));
3437 3 : ccode.add_assignment (new CCodeIdentifier ("self"), cast);
3438 :
3439 3 : var free_call = new CCodeFunctionCall (get_destroy0_func_expression (type));
3440 3 : free_call.add_argument (new CCodeIdentifier ("self"));
3441 :
3442 3 : ccode.add_expression (free_call);
3443 :
3444 3 : pop_function ();
3445 :
3446 3 : cfile.add_function_declaration (function);
3447 3 : cfile.add_function (function);
3448 :
3449 3 : return destroy_func;
3450 : }
3451 :
3452 49 : protected string generate_free_func_wrapper (DataType type) {
3453 49 : string destroy_func = "_vala_%s_free".printf (get_ccode_name (type.type_symbol));
3454 :
3455 49 : if (!add_wrapper (destroy_func)) {
3456 : // wrapper already defined
3457 49 : return destroy_func;
3458 : }
3459 :
3460 6 : var function = new CCodeFunction (destroy_func, "void");
3461 6 : function.modifiers = CCodeModifiers.STATIC;
3462 6 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3463 :
3464 6 : push_function (function);
3465 :
3466 12 : if (get_ccode_is_gboxed (type.type_symbol) || (gvalue_type != null && type.type_symbol == gvalue_type)) {
3467 6 : var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_free"));
3468 6 : free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (type.type_symbol)));
3469 6 : free_call.add_argument (new CCodeIdentifier ("self"));
3470 :
3471 6 : ccode.add_expression (free_call);
3472 : } else {
3473 0 : unowned Struct? st = type.type_symbol as Struct;
3474 0 : if (st != null && st.is_disposable ()) {
3475 0 : if (!get_ccode_has_destroy_function (st)) {
3476 0 : generate_struct_destroy_function (st);
3477 : }
3478 :
3479 0 : var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (st)));
3480 0 : destroy_call.add_argument (new CCodeIdentifier ("self"));
3481 0 : ccode.add_expression (destroy_call);
3482 : }
3483 :
3484 : CCodeFunctionCall free_call;
3485 0 : if (context.profile == Profile.POSIX) {
3486 0 : cfile.add_include ("stdlib.h");
3487 0 : free_call = new CCodeFunctionCall (new CCodeIdentifier ("free"));
3488 : } else {
3489 0 : cfile.add_include ("glib.h");
3490 0 : free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
3491 : }
3492 0 : free_call.add_argument (new CCodeIdentifier ("self"));
3493 :
3494 0 : ccode.add_expression (free_call);
3495 : }
3496 :
3497 6 : pop_function ();
3498 :
3499 6 : cfile.add_function_declaration (function);
3500 6 : cfile.add_function (function);
3501 :
3502 6 : return destroy_func;
3503 : }
3504 :
3505 73 : public CCodeExpression? get_destroy0_func_expression (DataType type, bool is_chainup = false) {
3506 73 : var element_destroy_func_expression = get_destroy_func_expression (type, is_chainup);
3507 :
3508 140 : if (!(type is GenericType) && element_destroy_func_expression is CCodeIdentifier) {
3509 67 : var freeid = (CCodeIdentifier) element_destroy_func_expression;
3510 67 : string free0_func = "_%s0_".printf (freeid.name);
3511 :
3512 99 : if (add_wrapper (free0_func)) {
3513 32 : var function = new CCodeFunction (free0_func, "void");
3514 32 : function.modifiers = CCodeModifiers.STATIC;
3515 :
3516 32 : function.add_parameter (new CCodeParameter ("var", get_ccode_name (pointer_type)));
3517 :
3518 32 : push_function (function);
3519 :
3520 32 : ccode.add_expression (destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true));
3521 :
3522 32 : pop_function ();
3523 :
3524 32 : cfile.add_function_declaration (function);
3525 32 : cfile.add_function (function);
3526 : }
3527 :
3528 67 : element_destroy_func_expression = new CCodeIdentifier (free0_func);
3529 : }
3530 :
3531 : return element_destroy_func_expression;
3532 : }
3533 :
3534 13933 : public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
3535 13933 : if (context.profile == Profile.GOBJECT && (type.type_symbol == glist_type || type.type_symbol == gslist_type || type.type_symbol == gnode_type || type.type_symbol == gqueue_type)) {
3536 : // create wrapper function to free list elements if necessary
3537 :
3538 50 : bool elements_require_free = false;
3539 50 : bool generic_elements = false;
3540 50 : CCodeExpression element_destroy_func_expression = null;
3541 :
3542 150 : foreach (DataType type_arg in type.get_type_arguments ()) {
3543 50 : elements_require_free = requires_destroy (type_arg);
3544 50 : if (elements_require_free) {
3545 39 : element_destroy_func_expression = get_destroy0_func_expression (type_arg);
3546 39 : generic_elements = (type_arg is GenericType);
3547 : }
3548 : }
3549 :
3550 50 : if (elements_require_free) {
3551 39 : CCodeExpression? cexpr = null;
3552 39 : if (element_destroy_func_expression is CCodeIdentifier || element_destroy_func_expression is CCodeMemberAccess) {
3553 74 : cexpr = new CCodeIdentifier (generate_collection_free_wrapper (type, (generic_elements ? null : element_destroy_func_expression as CCodeIdentifier)));
3554 39 : if (generic_elements) {
3555 : // adding second argument early, instance parameter will be inserted by destroy_value()
3556 4 : cexpr = new CCodeFunctionCall (cexpr);
3557 4 : ((CCodeFunctionCall) cexpr).add_argument (element_destroy_func_expression);
3558 : }
3559 : } else {
3560 0 : Report.error (null, "internal error: No useable element_destroy_function found");
3561 : }
3562 39 : return cexpr;
3563 : } else {
3564 11 : return new CCodeIdentifier (get_ccode_free_function (type.type_symbol));
3565 : }
3566 13883 : } else if (type is ErrorType) {
3567 119 : cfile.add_include ("glib.h");
3568 119 : return new CCodeIdentifier ("g_error_free");
3569 13764 : } else if (type is GenericType) {
3570 147 : var type_parameter = ((GenericType) type).type_parameter;
3571 147 : string identifier = get_ccode_destroy_function (type_parameter);
3572 147 : return get_generic_type_expression (identifier, (GenericType) type, is_chainup);
3573 13617 : } else if (type.type_symbol != null) {
3574 : string unref_function;
3575 12331 : if (type is ReferenceType) {
3576 11683 : if (is_reference_counting (type.type_symbol)) {
3577 6606 : unref_function = get_ccode_unref_function ((ObjectTypeSymbol) type.type_symbol);
3578 6606 : if (type.type_symbol is Interface && unref_function == null) {
3579 2 : Report.error (type.source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure", type.type_symbol.get_full_name ());
3580 2 : return new CCodeInvalidExpression ();
3581 : }
3582 : } else {
3583 5077 : if (get_ccode_is_gboxed (type.type_symbol)) {
3584 0 : unref_function = generate_free_func_wrapper (type);
3585 : } else {
3586 5077 : if (is_free_function_address_of (type)) {
3587 0 : unref_function = generate_free_function_address_of_wrapper (type);
3588 : } else {
3589 5077 : unref_function = get_ccode_free_function (type.type_symbol);
3590 : }
3591 : }
3592 : }
3593 : } else {
3594 648 : if (type.nullable) {
3595 361 : if (get_ccode_is_gboxed (type.type_symbol)) {
3596 0 : unref_function = generate_free_func_wrapper (type);
3597 : } else {
3598 361 : unref_function = get_ccode_free_function (type.type_symbol);
3599 : }
3600 361 : if (unref_function == null) {
3601 248 : if (type.type_symbol is Struct && ((Struct) type.type_symbol).is_disposable ()) {
3602 49 : unref_function = generate_free_func_wrapper (type);
3603 : } else {
3604 199 : if (context.profile == Profile.POSIX) {
3605 4 : cfile.add_include ("stdlib.h");
3606 4 : unref_function = "free";
3607 : } else {
3608 195 : cfile.add_include ("glib.h");
3609 195 : unref_function = "g_free";
3610 : }
3611 : }
3612 : }
3613 287 : } else if (type is EnumValueType) {
3614 0 : unref_function = null;
3615 : } else {
3616 287 : unowned Struct? st = type.type_symbol as Struct;
3617 287 : if (st != null && st.is_disposable ()) {
3618 287 : if (!get_ccode_has_destroy_function (st)) {
3619 0 : generate_struct_destroy_function (st);
3620 : }
3621 287 : unref_function = get_ccode_destroy_function (st);
3622 : } else {
3623 0 : unref_function = null;
3624 : }
3625 : }
3626 : }
3627 12216 : if (unref_function == null) {
3628 0 : return new CCodeConstant ("NULL");
3629 : }
3630 12329 : return new CCodeIdentifier (unref_function);
3631 1286 : } else if (type is ArrayType) {
3632 1271 : if (context.profile == Profile.POSIX) {
3633 57 : cfile.add_include ("stdlib.h");
3634 57 : return new CCodeIdentifier ("free");
3635 : } else {
3636 1214 : cfile.add_include ("glib.h");
3637 1214 : return new CCodeIdentifier ("g_free");
3638 : }
3639 15 : } else if (type is PointerType) {
3640 14 : if (context.profile == Profile.POSIX) {
3641 0 : cfile.add_include ("stdlib.h");
3642 0 : return new CCodeIdentifier ("free");
3643 : } else {
3644 14 : cfile.add_include ("glib.h");
3645 14 : return new CCodeIdentifier ("g_free");
3646 : }
3647 : } else {
3648 1 : return new CCodeConstant ("NULL");
3649 : }
3650 : }
3651 :
3652 39 : private string generate_collection_free_wrapper (DataType collection_type, CCodeIdentifier? element_destroy_func_expression) {
3653 : string destroy_func;
3654 :
3655 39 : string? destroy_func_wrapper = null;
3656 39 : if (element_destroy_func_expression != null) {
3657 35 : destroy_func_wrapper = "_%s_%s".printf (get_ccode_free_function (collection_type.type_symbol), element_destroy_func_expression.name);
3658 35 : if (!add_wrapper (destroy_func_wrapper)) {
3659 : // wrapper already defined
3660 14 : return destroy_func_wrapper;
3661 : }
3662 : }
3663 :
3664 27 : if (collection_type.type_symbol == gnode_type) {
3665 3 : destroy_func = "_g_node_free_all";
3666 3 : if (!add_wrapper (destroy_func)) {
3667 : // wrapper already defined
3668 1 : return destroy_func;
3669 : }
3670 :
3671 2 : var function = new CCodeFunction (destroy_func, "void");
3672 2 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3673 2 : function.add_parameter (new CCodeParameter ("free_func", "GDestroyNotify"));
3674 :
3675 2 : push_function (function);
3676 :
3677 : CCodeFunctionCall element_free_call;
3678 2 : string destroy_node_func = "%s_node".printf (destroy_func);
3679 2 : var wrapper = new CCodeFunction (destroy_node_func, get_ccode_name (bool_type));
3680 2 : wrapper.modifiers = CCodeModifiers.STATIC;
3681 2 : wrapper.add_parameter (new CCodeParameter ("node", get_ccode_name (collection_type)));
3682 2 : wrapper.add_parameter (new CCodeParameter ("free_func", "GDestroyNotify"));
3683 2 : push_function (wrapper);
3684 :
3685 2 : var free_call = new CCodeFunctionCall (new CCodeIdentifier ("free_func"));
3686 2 : free_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier("node"), "data"));
3687 :
3688 2 : var data_isnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeMemberAccess.pointer (new CCodeIdentifier("node"), "data"), new CCodeConstant ("NULL"));
3689 2 : var ccomma_data = new CCodeCommaExpression ();
3690 2 : ccomma_data.append_expression (new CCodeConditionalExpression (data_isnull, new CCodeConstant ("NULL"), free_call));
3691 2 : ccode.add_expression (ccomma_data);
3692 :
3693 2 : ccode.add_return (new CCodeConstant ("FALSE"));
3694 :
3695 2 : pop_function ();
3696 2 : cfile.add_function_declaration (wrapper);
3697 2 : cfile.add_function (wrapper);
3698 :
3699 : /* Now the code to call g_traverse with the above */
3700 2 : element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_node_traverse"));
3701 2 : element_free_call.add_argument (new CCodeIdentifier("self"));
3702 2 : element_free_call.add_argument (new CCodeConstant ("G_POST_ORDER"));
3703 2 : element_free_call.add_argument (new CCodeConstant ("G_TRAVERSE_ALL"));
3704 2 : element_free_call.add_argument (new CCodeConstant ("-1"));
3705 2 : element_free_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (destroy_node_func), "GNodeTraverseFunc"));
3706 2 : element_free_call.add_argument (new CCodeIdentifier ("free_func"));
3707 :
3708 2 : var free_func_isnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("free_func"), new CCodeConstant ("NULL"));
3709 2 : var ccomma = new CCodeCommaExpression ();
3710 2 : ccomma.append_expression (new CCodeConditionalExpression (free_func_isnull, new CCodeConstant ("NULL"), element_free_call));
3711 :
3712 2 : ccode.add_expression (ccomma);
3713 :
3714 2 : var cfreecall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (gnode_type)));
3715 2 : cfreecall.add_argument (new CCodeIdentifier ("self"));
3716 2 : ccode.add_expression (cfreecall);
3717 :
3718 2 : function.modifiers = CCodeModifiers.STATIC;
3719 2 : pop_function ();
3720 :
3721 2 : cfile.add_function_declaration (function);
3722 2 : cfile.add_function (function);
3723 22 : } else if (collection_type.type_symbol == glist_type) {
3724 13 : destroy_func = "g_list_free_full";
3725 9 : } else if (collection_type.type_symbol == gslist_type) {
3726 4 : destroy_func = "g_slist_free_full";
3727 5 : } else if (collection_type.type_symbol == gqueue_type) {
3728 5 : destroy_func = "g_queue_free_full";
3729 : } else {
3730 0 : Report.error (null, "internal error: type of collection not supported");
3731 0 : return "";
3732 : }
3733 :
3734 24 : if (element_destroy_func_expression != null) {
3735 21 : var function = new CCodeFunction (destroy_func_wrapper, "void");
3736 21 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3737 :
3738 21 : push_function (function);
3739 :
3740 21 : var collection_free_call = new CCodeFunctionCall (new CCodeIdentifier (destroy_func));
3741 21 : collection_free_call.add_argument (new CCodeIdentifier ("self"));
3742 21 : collection_free_call.add_argument (new CCodeCastExpression (element_destroy_func_expression, "GDestroyNotify"));
3743 21 : ccode.add_expression (collection_free_call);
3744 :
3745 21 : function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
3746 21 : pop_function ();
3747 :
3748 21 : cfile.add_function_declaration (function);
3749 21 : cfile.add_function (function);
3750 :
3751 21 : return destroy_func_wrapper;
3752 : }
3753 :
3754 3 : return destroy_func;
3755 : }
3756 :
3757 2 : public virtual string? append_struct_array_destroy (Struct st) {
3758 : return null;
3759 : }
3760 :
3761 14 : public virtual string? append_struct_array_free (Struct st) {
3762 : return null;
3763 : }
3764 :
3765 5930 : public CCodeExpression destroy_local (LocalVariable local) {
3766 5930 : return destroy_value (get_local_cvalue (local));
3767 : }
3768 :
3769 317 : public CCodeExpression destroy_parameter (Parameter param) {
3770 317 : return destroy_value (get_parameter_cvalue (param));
3771 : }
3772 :
3773 1807 : public CCodeExpression destroy_field (Field field, TargetValue? instance) {
3774 1807 : return destroy_value (get_field_cvalue (field, instance));
3775 : }
3776 :
3777 25513 : public virtual CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
3778 12748 : var type = value.value_type;
3779 12748 : if (value.actual_value_type != null) {
3780 3256 : type = value.actual_value_type;
3781 : }
3782 12748 : var cvar = get_cvalue_ (value);
3783 :
3784 12748 : if (type is DelegateType) {
3785 166 : if (context.profile != Profile.GOBJECT) {
3786 : // Required for NULL
3787 0 : cfile.add_include ("stddef.h");
3788 : }
3789 :
3790 166 : var delegate_target = get_delegate_target_cvalue (value);
3791 166 : var delegate_target_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
3792 :
3793 166 : var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
3794 166 : ccall.add_argument (delegate_target);
3795 :
3796 166 : var destroy_call = new CCodeCommaExpression ();
3797 166 : destroy_call.append_expression (ccall);
3798 166 : destroy_call.append_expression (new CCodeConstant ("NULL"));
3799 :
3800 166 : var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
3801 :
3802 166 : var ccomma = new CCodeCommaExpression ();
3803 166 : ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), destroy_call));
3804 166 : ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
3805 166 : ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
3806 166 : ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
3807 :
3808 166 : return ccomma;
3809 : }
3810 :
3811 12582 : bool is_gcollection = (type.type_symbol == glist_type || type.type_symbol == gslist_type || type.type_symbol == gnode_type || type.type_symbol == gqueue_type);
3812 : CCodeFunctionCall ccall;
3813 12582 : var cexpr = get_destroy_func_expression (type);
3814 12582 : if (is_gcollection && cexpr is CCodeFunctionCall) {
3815 4 : ccall = (CCodeFunctionCall) cexpr;
3816 : } else {
3817 12578 : ccall = new CCodeFunctionCall (cexpr);
3818 : }
3819 :
3820 12582 : if (type is ValueType && !type.nullable) {
3821 : // normal value type, no null check
3822 277 : unowned Struct? st = type.type_symbol as Struct;
3823 277 : if (st != null && st.is_simple_type ()) {
3824 : // used for va_list
3825 42 : ccall.add_argument (cvar);
3826 : } else {
3827 235 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3828 : }
3829 :
3830 277 : if (gvalue_type != null && type.type_symbol == gvalue_type) {
3831 : // g_value_unset must not be called for already unset values
3832 70 : var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
3833 70 : cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3834 :
3835 70 : var ccomma = new CCodeCommaExpression ();
3836 70 : ccomma.append_expression (ccall);
3837 70 : ccomma.append_expression (new CCodeConstant ("NULL"));
3838 :
3839 70 : return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
3840 207 : } else if ((type.type_symbol == gmutex_type ||
3841 206 : type.type_symbol == grecmutex_type ||
3842 205 : type.type_symbol == grwlock_type ||
3843 205 : type.type_symbol == gcond_type)) {
3844 : // g_mutex_clear must not be called for uninitialized mutex
3845 : // also, g_mutex_clear does not clear the struct
3846 2 : requires_clear_mutex = true;
3847 2 : ccall.call = new CCodeIdentifier ("_vala_clear_" + get_ccode_name (type.type_symbol));
3848 2 : return ccall;
3849 : } else {
3850 205 : return ccall;
3851 : }
3852 : }
3853 :
3854 12305 : if (!is_gcollection && ccall.call is CCodeIdentifier && !(type is ArrayType) && !(type is GenericType) && !is_macro_definition) {
3855 : // generate and use NULL-aware free macro to simplify code
3856 :
3857 9573 : var freeid = (CCodeIdentifier) ccall.call;
3858 9573 : string free0_func = "_%s0".printf (freeid.name);
3859 :
3860 10897 : if (add_wrapper (free0_func)) {
3861 1324 : var macro = destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true);
3862 1324 : cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("%s(var)".printf (free0_func), macro));
3863 : }
3864 :
3865 : // FIXME this breaks in our macro, so this should not happen
3866 9577 : while (cvar is CCodeCastExpression) {
3867 8 : cvar = ((CCodeCastExpression) cvar).inner;
3868 : }
3869 9573 : if (cvar is CCodeFunctionCall) {
3870 1 : cvar = ((CCodeFunctionCall) cvar).get_arguments ()[0];
3871 : }
3872 :
3873 9573 : ccall = new CCodeFunctionCall (new CCodeIdentifier (free0_func));
3874 9573 : ccall.add_argument (cvar);
3875 9573 : return ccall;
3876 : }
3877 :
3878 2732 : if (context.profile != Profile.GOBJECT) {
3879 : // Required for NULL
3880 62 : cfile.add_include ("stddef.h");
3881 : }
3882 :
3883 : /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
3884 :
3885 : /* can be simplified to
3886 : * foo = (unref (foo), NULL)
3887 : * if foo is of static type non-null
3888 : */
3889 :
3890 2732 : var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
3891 2788 : if (type is GenericType) {
3892 56 : var parent = ((GenericType) type).type_parameter.parent_symbol;
3893 56 : var cl = parent as Class;
3894 56 : if ((!(parent is Method) && !(parent is ObjectTypeSymbol)) || (cl != null && cl.is_compact)) {
3895 0 : return new CCodeConstant ("NULL");
3896 : }
3897 :
3898 : // unref functions are optional for type parameters
3899 56 : var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
3900 56 : cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
3901 : }
3902 :
3903 : // glib collections already have the free_func argument, so make sure the instance parameter gets first
3904 2732 : ccall.insert_argument (0, cvar);
3905 :
3906 : /* set freed references to NULL to prevent further use */
3907 2732 : var ccomma = new CCodeCommaExpression ();
3908 :
3909 3305 : if (context.profile == Profile.GOBJECT
3910 2670 : && type.type_symbol != null && !is_reference_counting (type.type_symbol)
3911 573 : && type.type_symbol.is_subtype_of (gstringbuilder_type)) {
3912 20 : ccall.add_argument (new CCodeConstant ("TRUE"));
3913 2712 : } else if (context.profile == Profile.GOBJECT
3914 2650 : && type.type_symbol == gthreadpool_type) {
3915 1 : ccall.add_argument (new CCodeConstant ("FALSE"));
3916 1 : ccall.add_argument (new CCodeConstant ("TRUE"));
3917 3981 : } else if (type is ArrayType) {
3918 1270 : var array_type = (ArrayType) type;
3919 2181 : if (requires_destroy (array_type.element_type)) {
3920 915 : CCodeExpression csizeexpr = null;
3921 915 : if (((GLibValue) value).array_length_cvalues != null) {
3922 883 : csizeexpr = get_array_length_cvalue (value);
3923 32 : } else if (get_array_null_terminated (value)) {
3924 28 : requires_array_length = true;
3925 28 : var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
3926 28 : len_call.add_argument (cvar);
3927 56 : csizeexpr = len_call;
3928 : } else {
3929 4 : csizeexpr = get_array_length_cexpr (value);
3930 : }
3931 :
3932 2181 : if (csizeexpr != null) {
3933 911 : unowned Struct? st = array_type.element_type.type_symbol as Struct;
3934 911 : if (st != null && !array_type.element_type.nullable) {
3935 14 : ccall.call = new CCodeIdentifier (append_struct_array_free (st));
3936 14 : ccall.add_argument (csizeexpr);
3937 : } else {
3938 897 : requires_array_free = true;
3939 897 : generate_type_declaration (delegate_target_destroy_type, cfile);
3940 :
3941 897 : ccall.call = new CCodeIdentifier ("_vala_array_free");
3942 897 : ccall.add_argument (csizeexpr);
3943 897 : ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), get_ccode_name (delegate_target_destroy_type)));
3944 : }
3945 : }
3946 : }
3947 : }
3948 :
3949 2732 : ccomma.append_expression (ccall);
3950 2732 : ccomma.append_expression (new CCodeConstant ("NULL"));
3951 :
3952 2732 : var cassign = new CCodeAssignment (cvar, ccomma);
3953 :
3954 : // g_free (NULL) is allowed
3955 2998 : bool uses_gfree = (type.type_symbol != null && !is_reference_counting (type.type_symbol) && get_ccode_free_function (type.type_symbol) == "g_free");
3956 2732 : uses_gfree = uses_gfree || type is ArrayType;
3957 1150 : if (uses_gfree) {
3958 1582 : return cassign;
3959 : }
3960 :
3961 1150 : return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
3962 : }
3963 :
3964 14053 : public override void visit_end_full_expression (Expression expr) {
3965 : /* expr is a full expression, i.e. an initializer, the
3966 : * expression in an expression statement, the controlling
3967 : * expression in if, while, for, or foreach statements
3968 : *
3969 : * we unref temporary variables at the end of a full
3970 : * expression
3971 : */
3972 13518 : if (temp_ref_values.size == 0) {
3973 : /* nothing to do without temporary variables */
3974 : return;
3975 : }
3976 :
3977 535 : var local_decl = expr.parent_node as LocalVariable;
3978 535 : if (!(local_decl != null && is_simple_struct_creation (local_decl, local_decl.initializer))) {
3979 534 : expr.target_value = store_temp_value (expr.target_value, expr);
3980 : }
3981 :
3982 2255 : foreach (var value in temp_ref_values) {
3983 860 : ccode.add_expression (destroy_value (value));
3984 : }
3985 :
3986 535 : temp_ref_values.clear ();
3987 : }
3988 :
3989 45336 : public void emit_temp_var (LocalVariable local, bool on_error = false) {
3990 45336 : generate_type_declaration (local.variable_type, cfile);
3991 :
3992 45336 : var init = (!local.name.has_prefix ("*") && local.init);
3993 90337 : if (is_in_coroutine ()) {
3994 335 : closure_struct.add_field (get_ccode_name (local.variable_type), local.name, 0, get_ccode_declarator_suffix (local.variable_type));
3995 :
3996 : // even though closure struct is zerod, we need to initialize temporary variables
3997 : // as they might be used multiple times when declared in a loop
3998 :
3999 360 : if (init) {
4000 25 : var initializer = default_value_for_type (local.variable_type, false, on_error);
4001 28 : if (initializer == null) {
4002 3 : cfile.add_include ("string.h");
4003 3 : var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4004 3 : memset_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (local.name)));
4005 3 : memset_call.add_argument (new CCodeConstant ("0"));
4006 3 : CCodeExpression? size = null;
4007 3 : requires_memset_init (local, out size);
4008 3 : if (size == null) {
4009 2 : size = new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (local.variable_type)));
4010 : }
4011 3 : memset_call.add_argument (size);
4012 3 : ccode.add_expression (memset_call);
4013 : } else {
4014 22 : ccode.add_assignment (get_variable_cexpression (local.name), initializer);
4015 : }
4016 : }
4017 : } else {
4018 45001 : var cvar = new CCodeVariableDeclarator (local.name, null, get_ccode_declarator_suffix (local.variable_type));
4019 45001 : CCodeExpression? size = null;
4020 45001 : if (init && !requires_memset_init (local, out size)) {
4021 1438 : cvar.initializer = default_value_for_type (local.variable_type, true, on_error);
4022 1438 : cvar.init0 = true;
4023 43564 : } else if (init && size != null && local.initializer == null) {
4024 1 : cfile.add_include ("string.h");
4025 1 : var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4026 1 : memset_call.add_argument (get_variable_cexpression (local.name));
4027 1 : memset_call.add_argument (new CCodeConstant ("0"));
4028 1 : memset_call.add_argument (size);
4029 1 : ccode.add_expression (memset_call);
4030 : }
4031 45001 : ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
4032 : }
4033 : }
4034 :
4035 18082 : public override void visit_expression_statement (ExpressionStatement stmt) {
4036 18082 : if (stmt.expression.error) {
4037 0 : stmt.error = true;
4038 0 : return;
4039 : }
4040 :
4041 : /* free temporary objects and handle errors */
4042 :
4043 22410 : foreach (var value in temp_ref_values) {
4044 2164 : ccode.add_expression (destroy_value (value));
4045 : }
4046 :
4047 18082 : if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
4048 : // simple case, no node breakdown necessary
4049 318 : add_simple_check (stmt.expression);
4050 : }
4051 :
4052 18082 : temp_ref_values.clear ();
4053 : }
4054 :
4055 24270 : protected virtual void append_scope_free (Symbol sym, CodeNode? stop_at = null) {
4056 8090 : var b = (Block) sym;
4057 :
4058 16180 : var local_vars = b.get_local_variables ();
4059 : // free in reverse order
4060 22652 : for (int i = local_vars.size - 1; i >= 0; i--) {
4061 7281 : var local = local_vars[i];
4062 7281 : if (!local.unreachable && local.active && !local.captured && requires_destroy (local.variable_type)) {
4063 1880 : ccode.add_expression (destroy_local (local));
4064 : }
4065 : }
4066 :
4067 8117 : if (b.captured) {
4068 27 : int block_id = get_block_id (b);
4069 :
4070 27 : var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
4071 27 : data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
4072 27 : ccode.add_expression (data_unref);
4073 27 : ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
4074 : }
4075 : }
4076 :
4077 15170 : public void append_local_free (Symbol sym, Statement? jump_stmt = null, CodeNode? stop_at = null) {
4078 8090 : var b = (Block) sym;
4079 :
4080 8090 : append_scope_free (sym, stop_at);
4081 :
4082 8090 : if (jump_stmt is BreakStatement) {
4083 1399 : if (b.parent_node is LoopStatement ||
4084 900 : b.parent_node is ForeachStatement ||
4085 898 : b.parent_node is SwitchStatement) {
4086 808 : return;
4087 : }
4088 6691 : } else if (jump_stmt is ContinueStatement) {
4089 99 : if (b.parent_node is LoopStatement ||
4090 75 : b.parent_node is ForeachStatement) {
4091 41 : return;
4092 : }
4093 : }
4094 :
4095 7241 : if (stop_at != null && b.parent_node == stop_at) {
4096 161 : return;
4097 : }
4098 :
4099 7080 : if (sym.parent_symbol is Block) {
4100 3412 : append_local_free (sym.parent_symbol, jump_stmt, stop_at);
4101 3668 : } else if (sym.parent_symbol is Method) {
4102 3188 : append_param_free ((Method) sym.parent_symbol);
4103 949 : } else if (sym.parent_symbol is PropertyAccessor) {
4104 469 : var acc = (PropertyAccessor) sym.parent_symbol;
4105 469 : if (acc.value_parameter != null && requires_destroy (acc.value_parameter.variable_type)) {
4106 0 : ccode.add_expression (destroy_parameter (acc.value_parameter));
4107 : }
4108 : }
4109 : }
4110 :
4111 3188 : private void append_param_free (Method m) {
4112 9720 : foreach (Parameter param in m.get_parameters ()) {
4113 3266 : if (!param.captured && !param.ellipsis && !param.params_array && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
4114 7 : ccode.add_expression (destroy_parameter (param));
4115 : }
4116 : }
4117 : }
4118 :
4119 819 : public void append_out_param_free (Method? m) {
4120 819 : if (m == null) {
4121 : return;
4122 : }
4123 2388 : foreach (Parameter param in m.get_parameters ()) {
4124 790 : if (param.direction == ParameterDirection.OUT && param.variable_type.is_disposable ()) {
4125 14 : ccode.add_expression (destroy_parameter (param));
4126 : }
4127 : }
4128 : }
4129 :
4130 268 : public bool variable_accessible_in_finally (LocalVariable local) {
4131 268 : if (current_try == null) {
4132 266 : return false;
4133 : }
4134 :
4135 4 : var sym = current_symbol;
4136 :
4137 6 : while (!(sym is Method || sym is PropertyAccessor) && sym.scope.lookup (local.name) == null) {
4138 4 : if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) ||
4139 3 : (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) {
4140 :
4141 2 : return true;
4142 : }
4143 :
4144 4 : sym = sym.parent_symbol;
4145 : }
4146 :
4147 2 : return false;
4148 : }
4149 :
4150 332 : public void return_out_parameter (Parameter param) {
4151 166 : var delegate_type = param.variable_type as DelegateType;
4152 :
4153 166 : var value = get_parameter_cvalue (param);
4154 :
4155 166 : var old_coroutine = is_in_coroutine ();
4156 166 : current_method.coroutine = false;
4157 :
4158 166 : ccode.open_if (get_parameter_cexpression (param));
4159 166 : ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_parameter_cexpression (param)), get_cvalue_ (value));
4160 :
4161 166 : if (get_ccode_delegate_target (param) && delegate_type != null && delegate_type.delegate_symbol.has_target) {
4162 2 : ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cexpression (get_ccode_delegate_target_name (param))), get_delegate_target_cvalue (value));
4163 2 : if (delegate_type.is_disposable ()) {
4164 2 : ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cexpression (get_ccode_delegate_target_destroy_notify_name (param))), get_delegate_target_destroy_notify_cvalue (get_parameter_cvalue (param)));
4165 : }
4166 : }
4167 :
4168 166 : if (param.variable_type.is_disposable ()){
4169 62 : ccode.add_else ();
4170 62 : current_method.coroutine = old_coroutine;
4171 62 : ccode.add_expression (destroy_parameter (param));
4172 62 : current_method.coroutine = false;
4173 : }
4174 166 : ccode.close ();
4175 :
4176 166 : var array_type = param.variable_type as ArrayType;
4177 26 : if (array_type != null && !array_type.fixed_length && get_ccode_array_length (param)) {
4178 44 : for (int dim = 1; dim <= array_type.rank; dim++) {
4179 24 : string length_cname = get_variable_array_length_cname (param, dim);
4180 24 : ccode.open_if (get_cexpression (length_cname));
4181 24 : ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cexpression (length_cname)), get_array_length_cvalue (value, dim));
4182 24 : ccode.close ();
4183 : }
4184 : }
4185 :
4186 166 : current_method.coroutine = old_coroutine;
4187 : }
4188 :
4189 5698 : public override void visit_return_statement (ReturnStatement stmt) {
4190 2849 : Symbol return_expression_symbol = null;
4191 :
4192 3163 : if (stmt.return_expression != null) {
4193 : // avoid unnecessary ref/unref pair
4194 2717 : var local = stmt.return_expression.symbol_reference as LocalVariable;
4195 2982 : if (local != null && !local.active) {
4196 : /* return expression is local variable taking ownership and
4197 : * current method is transferring ownership */
4198 :
4199 265 : return_expression_symbol = local;
4200 : }
4201 : }
4202 :
4203 : // return array length if appropriate
4204 2939 : if (((current_method != null && get_ccode_array_length (current_method)) || (current_property_accessor != null && get_ccode_array_length (current_property_accessor))) && current_return_type is ArrayType) {
4205 90 : var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
4206 :
4207 180 : var array_type = (ArrayType) current_return_type;
4208 284 : for (int dim = 1; dim <= array_type.rank; dim++) {
4209 97 : var len_l = get_cexpression (get_array_length_cname ("result", dim));
4210 97 : var len_r = get_array_length_cvalue (temp_value, dim);
4211 97 : if (!is_in_coroutine ()) {
4212 95 : ccode.open_if (len_l);
4213 95 : len_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, len_l);
4214 95 : ccode.add_assignment (len_l, len_r);
4215 95 : ccode.close ();
4216 : } else {
4217 2 : ccode.add_assignment (len_l, len_r);
4218 : }
4219 : }
4220 :
4221 90 : stmt.return_expression.target_value = temp_value;
4222 2778 : } else if (((current_method != null && get_ccode_delegate_target (current_method)) || (current_property_accessor != null && get_ccode_delegate_target (current_property_accessor))) && current_return_type is DelegateType) {
4223 19 : var delegate_type = (DelegateType) current_return_type;
4224 38 : if (delegate_type.delegate_symbol.has_target) {
4225 19 : var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
4226 :
4227 19 : var target_l = get_cexpression (get_delegate_target_cname ("result"));
4228 19 : if (!is_in_coroutine ()) {
4229 18 : target_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l);
4230 : }
4231 19 : var target_r = get_delegate_target_cvalue (temp_value);
4232 19 : ccode.add_assignment (target_l, target_r);
4233 26 : if (delegate_type.is_disposable ()) {
4234 7 : var target_l_destroy_notify = get_cexpression (get_delegate_target_destroy_notify_cname ("result"));
4235 7 : if (!is_in_coroutine ()) {
4236 6 : target_l_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l_destroy_notify);
4237 : }
4238 7 : var target_r_destroy_notify = get_delegate_target_destroy_notify_cvalue (temp_value);
4239 7 : ccode.add_assignment (target_l_destroy_notify, target_r_destroy_notify);
4240 : }
4241 :
4242 19 : stmt.return_expression.target_value = temp_value;
4243 : }
4244 : }
4245 :
4246 5566 : if (stmt.return_expression != null) {
4247 : // assign method result to `result'
4248 2717 : CCodeExpression result_lhs = get_cexpression ("result");
4249 2717 : if (current_return_type.is_real_non_null_struct_type () && !is_in_coroutine ()) {
4250 43 : result_lhs = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result_lhs);
4251 2674 : } else if (current_return_type is GenericType) {
4252 30 : set_cvalue (stmt.return_expression, convert_to_generic_pointer (get_cvalue (stmt.return_expression), stmt.return_expression.value_type));
4253 : }
4254 2717 : ccode.add_assignment (result_lhs, get_cvalue (stmt.return_expression));
4255 : }
4256 :
4257 2849 : if (current_method != null) {
4258 : // check postconditions
4259 2410 : foreach (Expression postcondition in current_method.get_postconditions ()) {
4260 15 : create_postcondition_statement (postcondition);
4261 : }
4262 : }
4263 :
4264 : // free local variables
4265 2849 : append_local_free (current_symbol);
4266 :
4267 2849 : if (current_method != null && !current_method.coroutine) {
4268 : // assign values to output parameters if they are not NULL
4269 : // otherwise, free the value if necessary
4270 4930 : foreach (var param in current_method.get_parameters ()) {
4271 2466 : if (param.direction != ParameterDirection.OUT) {
4272 2352 : continue;
4273 : }
4274 :
4275 114 : return_out_parameter (param);
4276 : }
4277 : }
4278 :
4279 : // TODO: don't duplicate the code in CCodeMethodModule, we do this right now because it needs to be before return
4280 2851 : if (current_method != null && current_method.has_attribute ("Profile")) {
4281 2 : string prefix = "_vala_prof_%s".printf (get_ccode_real_name (current_method));
4282 :
4283 2 : var level = new CCodeIdentifier (prefix + "_level");
4284 2 : ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
4285 :
4286 2 : var timer = new CCodeIdentifier (prefix + "_timer");
4287 :
4288 2 : var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
4289 2 : stop_call.add_argument (timer);
4290 2 : ccode.add_expression (stop_call);
4291 :
4292 2 : ccode.close ();
4293 : }
4294 :
4295 2849 : if (is_in_constructor ()) {
4296 1 : ccode.add_return (new CCodeIdentifier ("obj"));
4297 2848 : } else if (is_in_destructor ()) {
4298 : // do not call return as member cleanup and chain up to base finalizer
4299 : // still need to be executed
4300 2 : ccode.add_goto ("_return");
4301 2846 : } else if (is_in_coroutine ()) {
4302 2816 : } else if (current_method is CreationMethod) {
4303 5 : ccode.add_return (new CCodeIdentifier ("self"));
4304 2811 : } else if (current_return_type is VoidType || current_return_type.is_real_non_null_struct_type ()) {
4305 : // structs are returned via out parameter
4306 166 : ccode.add_return ();
4307 : } else {
4308 2645 : ccode.add_return (new CCodeIdentifier ("result"));
4309 : }
4310 :
4311 2849 : if (return_expression_symbol != null) {
4312 265 : return_expression_symbol.active = true;
4313 : }
4314 :
4315 : // required for destructors
4316 2849 : current_method_return = true;
4317 : }
4318 :
4319 106 : public string get_symbol_lock_name (string symname) {
4320 106 : return "__lock_%s".printf (symname.replace ("-", "_"));
4321 : }
4322 :
4323 52 : private CCodeExpression get_lock_expression (Statement stmt, Expression resource) {
4324 52 : CCodeExpression l = null;
4325 52 : var member = resource.symbol_reference;
4326 52 : var parent = (TypeSymbol)resource.symbol_reference.parent_symbol;
4327 :
4328 52 : if (member.is_instance_member ()) {
4329 26 : l = get_cvalue (((MemberAccess) resource).inner);
4330 26 : l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (get_ccode_name (member)));
4331 40 : } else if (member.is_class_member ()) {
4332 14 : unowned Class cl = (Class) parent;
4333 14 : var cast = get_this_class_cexpression (cl);
4334 14 : var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function (cl)));
4335 14 : get_class_private_call.add_argument (cast);
4336 14 : l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (get_ccode_name (member)));
4337 : } else {
4338 12 : string lock_name = "%s_%s".printf (get_ccode_lower_case_name (parent), get_ccode_name (member));
4339 12 : l = new CCodeIdentifier (get_symbol_lock_name (lock_name));
4340 : }
4341 52 : return l;
4342 : }
4343 :
4344 52 : public override void visit_lock_statement (LockStatement stmt) {
4345 26 : var l = get_lock_expression (stmt, stmt.resource);
4346 :
4347 26 : var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("lock"))));
4348 26 : fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
4349 :
4350 26 : ccode.add_expression (fc);
4351 : }
4352 :
4353 52 : public override void visit_unlock_statement (UnlockStatement stmt) {
4354 26 : var l = get_lock_expression (stmt, stmt.resource);
4355 :
4356 26 : var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("unlock"))));
4357 26 : fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
4358 :
4359 26 : ccode.add_expression (fc);
4360 : }
4361 :
4362 5 : public override void visit_delete_statement (DeleteStatement stmt) {
4363 5 : unowned DataType type = stmt.expression.value_type;
4364 5 : unowned PointerType? pointer_type = type as PointerType;
4365 5 : if (pointer_type != null && pointer_type.base_type.type_symbol != null && pointer_type.base_type.type_symbol.is_reference_type ()) {
4366 3 : type = pointer_type.base_type;
4367 : }
4368 :
4369 5 : ccode.add_expression (destroy_value (new GLibValue (type, get_cvalue (stmt.expression))));
4370 : }
4371 :
4372 18734 : static bool is_compact_class_destructor_call (Expression expr) {
4373 18734 : unowned Class? cl = expr.value_type.type_symbol as Class;
4374 3222 : if (cl != null && cl.is_compact && expr.parent_node is MemberAccess) {
4375 49 : unowned MethodType? mt = ((MemberAccess) expr.parent_node).value_type as MethodType;
4376 49 : if (mt != null && mt.method_symbol != null && mt.method_symbol.has_attribute ("DestroysInstance")) {
4377 : return true;
4378 : }
4379 : }
4380 : return false;
4381 : }
4382 :
4383 144347 : public override void visit_expression (Expression expr) {
4384 144347 : if (get_cvalue (expr) != null && !expr.lvalue) {
4385 115392 : if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
4386 552 : var type_parameter = ((GenericType) expr.formal_value_type).type_parameter;
4387 552 : var st = type_parameter.parent_symbol.parent_symbol as Struct;
4388 552 : if (type_parameter.parent_symbol != garray_type &&
4389 535 : (st == null || get_ccode_name (st) != "va_list")) {
4390 : // GArray and va_list don't use pointer-based generics
4391 500 : set_cvalue (expr, convert_from_generic_pointer (get_cvalue (expr), expr.value_type));
4392 500 : ((GLibValue) expr.target_value).lvalue = false;
4393 : }
4394 : }
4395 :
4396 : // memory management, implicit casts, and boxing/unboxing
4397 114840 : if (expr.value_type != null) {
4398 : // FIXME: temporary workaround until the refactoring is complete, not all target_value have a value_type
4399 114813 : expr.target_value.value_type = expr.value_type;
4400 114813 : expr.target_value = transform_value (expr.target_value, expr.target_type, expr);
4401 : }
4402 :
4403 114840 : if (expr.target_value == null) {
4404 : return;
4405 : }
4406 :
4407 114840 : if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
4408 1036 : if (((GenericType) expr.formal_target_type).type_parameter.parent_symbol != garray_type) {
4409 : // GArray doesn't use pointer-based generics
4410 1013 : set_cvalue (expr, convert_to_generic_pointer (get_cvalue (expr), expr.target_type));
4411 1013 : ((GLibValue) expr.target_value).lvalue = false;
4412 : }
4413 113804 : } else if (expr.formal_target_type is GenericType && !(expr.value_type is GenericType)) {
4414 15 : set_cvalue (expr, convert_to_generic_pointer (get_cvalue (expr), expr.value_type));
4415 : }
4416 :
4417 : // Allow null to initialize non-null struct inside initializer list
4418 114923 : if (expr is NullLiteral && expr.parent_node is InitializerList
4419 80 : && expr.target_type != null && expr.target_type.is_real_non_null_struct_type ()) {
4420 3 : var clist = new CCodeInitializerList ();
4421 3 : clist.append (new CCodeConstant ("0"));
4422 3 : set_cvalue (expr, new CCodeCastExpression (clist, get_ccode_name (expr.target_type.type_symbol)));
4423 : }
4424 :
4425 114840 : if (!(expr.value_type is ValueType && !expr.value_type.nullable)) {
4426 77335 : ((GLibValue) expr.target_value).non_null = expr.is_non_null ();
4427 : }
4428 29514 : } else if (expr.value_type != null && is_compact_class_destructor_call (expr)) {
4429 : // transfer ownership here and consume given instance
4430 7 : var temp_value = store_temp_value (expr.target_value, expr);
4431 7 : ccode.add_assignment (get_cvalue (expr), new CCodeConstant ("NULL"));
4432 7 : expr.target_value = temp_value;
4433 : }
4434 : }
4435 :
4436 3794 : public override void visit_boolean_literal (BooleanLiteral expr) {
4437 3794 : set_cvalue (expr, get_boolean_cconstant (expr.value));
4438 : }
4439 :
4440 591 : public override void visit_character_literal (CharacterLiteral expr) {
4441 591 : if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
4442 587 : set_cvalue (expr, new CCodeConstant (expr.value));
4443 : } else {
4444 4 : set_cvalue (expr, new CCodeConstant ("%uU".printf (expr.get_char ())));
4445 : }
4446 : }
4447 :
4448 8258 : public override void visit_integer_literal (IntegerLiteral expr) {
4449 8258 : set_cvalue (expr, new CCodeConstant (expr.value + expr.type_suffix));
4450 : }
4451 :
4452 480 : public override void visit_real_literal (RealLiteral expr) {
4453 240 : string c_literal = expr.value;
4454 240 : if (c_literal.has_suffix ("d") || c_literal.has_suffix ("D")) {
4455 : // there is no suffix for double in C
4456 26 : c_literal = c_literal.substring (0, c_literal.length - 1);
4457 : }
4458 240 : if (!("." in c_literal || "e" in c_literal || "E" in c_literal)) {
4459 : // C requires period or exponent part for floating constants
4460 44 : if ("f" in c_literal || "F" in c_literal) {
4461 23 : c_literal = c_literal.substring (0, c_literal.length - 1) + ".f";
4462 : } else {
4463 21 : c_literal += ".";
4464 : }
4465 : }
4466 240 : set_cvalue (expr, new CCodeConstant (c_literal));
4467 : }
4468 :
4469 7390 : public override void visit_string_literal (StringLiteral expr) {
4470 7390 : set_cvalue (expr, new CCodeConstant.string (expr.value.replace ("\n", "\\n")));
4471 :
4472 7392 : if (expr.translate) {
4473 : // translated string constant
4474 2 : var translate = new CCodeFunctionCall (new CCodeIdentifier ("_"));
4475 2 : translate.add_argument (get_cvalue (expr));
4476 2 : set_cvalue (expr, translate);
4477 : }
4478 : }
4479 :
4480 42 : public override void visit_regex_literal (RegexLiteral expr) {
4481 21 : string[] parts = expr.value.split ("/", 3);
4482 21 : string re = parts[2].escape ("");
4483 21 : string flags = "0";
4484 :
4485 21 : if (parts[1].contains ("i")) {
4486 5 : flags += " | G_REGEX_CASELESS";
4487 : }
4488 21 : if (parts[1].contains ("m")) {
4489 0 : flags += " | G_REGEX_MULTILINE";
4490 : }
4491 21 : if (parts[1].contains ("s")) {
4492 1 : flags += " | G_REGEX_DOTALL";
4493 : }
4494 21 : if (parts[1].contains ("x")) {
4495 0 : flags += " | G_REGEX_EXTENDED";
4496 : }
4497 21 : if (parts[1].contains ("o")) {
4498 1 : flags += " | G_REGEX_OPTIMIZE";
4499 : }
4500 :
4501 21 : var cdecl = new CCodeDeclaration ("GRegex*");
4502 :
4503 21 : var cname = "_tmp_regex_%d".printf (next_regex_id);
4504 28 : if (this.next_regex_id == 0) {
4505 7 : var fun = new CCodeFunction ("_thread_safe_regex_init", "GRegex*");
4506 7 : fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
4507 7 : fun.add_parameter (new CCodeParameter ("re", "GRegex**"));
4508 7 : fun.add_parameter (new CCodeParameter ("pattern", "const gchar *"));
4509 7 : fun.add_parameter (new CCodeParameter ("compile_flags", "GRegexCompileFlags"));
4510 :
4511 7 : push_function (fun);
4512 :
4513 7 : var once_enter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
4514 7 : if (context.require_glib_version (2, 68)) {
4515 1 : once_enter_call.add_argument (new CCodeConstant ("(gsize*) re"));
4516 : } else {
4517 6 : once_enter_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
4518 : }
4519 7 : ccode.open_if (once_enter_call);
4520 :
4521 7 : var regex_new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_regex_new"));
4522 7 : regex_new_call.add_argument (new CCodeConstant ("pattern"));
4523 7 : regex_new_call.add_argument (new CCodeConstant ("compile_flags"));
4524 7 : regex_new_call.add_argument (new CCodeConstant ("0"));
4525 7 : regex_new_call.add_argument (new CCodeConstant ("NULL"));
4526 7 : ccode.add_assignment (new CCodeIdentifier ("GRegex* val"), regex_new_call);
4527 :
4528 7 : var once_leave_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
4529 7 : if (context.require_glib_version (2, 68)) {
4530 1 : once_leave_call.add_argument (new CCodeConstant ("(gsize*) re"));
4531 : } else {
4532 6 : once_leave_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
4533 : }
4534 7 : once_leave_call.add_argument (new CCodeConstant ("(gsize) val"));
4535 7 : ccode.add_expression (once_leave_call);
4536 :
4537 7 : ccode.close ();
4538 :
4539 7 : ccode.add_return (new CCodeIdentifier ("*re"));
4540 :
4541 7 : pop_function ();
4542 :
4543 7 : cfile.add_function (fun);
4544 : }
4545 21 : this.next_regex_id++;
4546 :
4547 21 : cdecl.add_declarator (new CCodeVariableDeclarator (cname + " = NULL"));
4548 21 : cdecl.modifiers = CCodeModifiers.STATIC;
4549 :
4550 21 : var regex_const = new CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname, re, flags));
4551 :
4552 21 : cfile.add_constant_declaration (cdecl);
4553 21 : set_cvalue (expr, regex_const);
4554 : }
4555 :
4556 7158 : public override void visit_null_literal (NullLiteral expr) {
4557 3579 : if (context.profile == Profile.GOBJECT) {
4558 3565 : cfile.add_include ("glib.h");
4559 : } else {
4560 14 : cfile.add_include ("stddef.h");
4561 : }
4562 3579 : set_cvalue (expr, new CCodeConstant ("NULL"));
4563 :
4564 3579 : var array_type = expr.target_type as ArrayType;
4565 3579 : var delegate_type = expr.target_type as DelegateType;
4566 3579 : if (array_type != null) {
4567 442 : for (int dim = 1; dim <= array_type.rank; dim++) {
4568 221 : append_array_length (expr, new CCodeConstant ("0"));
4569 : }
4570 3358 : } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
4571 77 : set_delegate_target (expr, new CCodeConstant ("NULL"));
4572 77 : set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
4573 : }
4574 : }
4575 :
4576 67179 : public abstract TargetValue get_local_cvalue (LocalVariable local);
4577 :
4578 18198 : public abstract TargetValue get_parameter_cvalue (Parameter param);
4579 :
4580 11146 : public abstract TargetValue get_field_cvalue (Field field, TargetValue? instance);
4581 :
4582 39733 : public abstract TargetValue load_variable (Variable variable, TargetValue value, Expression? expr = null);
4583 :
4584 801 : public abstract TargetValue load_this_parameter (TypeSymbol sym);
4585 :
4586 40575 : public abstract void store_value (TargetValue lvalue, TargetValue value, SourceReference? source_reference = null);
4587 :
4588 738 : public virtual string get_delegate_target_cname (string delegate_cname) {
4589 0 : assert_not_reached ();
4590 : }
4591 :
4592 704 : public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
4593 0 : assert_not_reached ();
4594 : }
4595 :
4596 1396 : public virtual CCodeExpression get_delegate_target_cvalue (TargetValue value) {
4597 0 : return new CCodeInvalidExpression ();
4598 : }
4599 :
4600 1354 : public virtual CCodeExpression get_delegate_target_destroy_notify_cvalue (TargetValue value) {
4601 0 : return new CCodeInvalidExpression ();
4602 : }
4603 :
4604 443 : public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname) {
4605 0 : assert_not_reached ();
4606 : }
4607 :
4608 555 : public override void visit_base_access (BaseAccess expr) {
4609 555 : unowned Class? cl = expr.value_type.type_symbol as Class;
4610 555 : if (cl != null && !cl.is_compact) {
4611 537 : set_cvalue (expr, generate_instance_cast (get_this_cexpression (), cl));
4612 : } else {
4613 18 : expr.target_value = load_this_parameter (expr.value_type.type_symbol);
4614 : }
4615 : }
4616 :
4617 476 : public override void visit_postfix_expression (PostfixExpression expr) {
4618 244 : MemberAccess ma = find_property_access (expr.inner);
4619 244 : if (ma != null) {
4620 : // property postfix expression
4621 12 : var prop = (Property) ma.symbol_reference;
4622 :
4623 : // increment/decrement property
4624 12 : var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4625 12 : var cexpr = new CCodeBinaryExpression (op, get_cvalue (expr.inner), new CCodeConstant ("1"));
4626 12 : store_property (prop, ma.inner, new GLibValue (expr.value_type, cexpr));
4627 :
4628 : // return previous value
4629 12 : expr.target_value = expr.inner.target_value;
4630 12 : return;
4631 : }
4632 :
4633 : // assign current value to temp variable
4634 232 : var temp_value = store_temp_value (expr.inner.target_value, expr);
4635 :
4636 : // increment/decrement variable
4637 232 : var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4638 232 : var cexpr = new CCodeBinaryExpression (op, get_cvalue_ (temp_value), new CCodeConstant ("1"));
4639 232 : ccode.add_assignment (get_cvalue (expr.inner), cexpr);
4640 :
4641 : // return previous value
4642 232 : expr.target_value = temp_value;
4643 : }
4644 :
4645 492 : private MemberAccess? find_property_access (Expression expr) {
4646 492 : if (!(expr is MemberAccess)) {
4647 468 : return null;
4648 : }
4649 :
4650 491 : var ma = (MemberAccess) expr;
4651 491 : if (ma.symbol_reference is Property) {
4652 492 : return ma;
4653 : }
4654 :
4655 467 : return null;
4656 : }
4657 :
4658 141 : static bool is_limited_generic_type (GenericType type) {
4659 141 : unowned Class? cl = type.type_parameter.parent_symbol as Class;
4660 141 : unowned Struct? st = type.type_parameter.parent_symbol as Struct;
4661 141 : if ((cl != null && cl.is_compact) || st != null) {
4662 : // compact classes and structs only
4663 : // have very limited generics support
4664 19 : return true;
4665 : }
4666 141 : return false;
4667 : }
4668 :
4669 7793 : public static bool requires_copy (DataType type) {
4670 7793 : if (!type.is_disposable ()) {
4671 : return false;
4672 : }
4673 :
4674 3895 : unowned Class? cl = type.type_symbol as Class;
4675 3259 : if (cl != null && is_reference_counting (cl)
4676 1286 : && get_ccode_ref_function (cl) == "") {
4677 : // empty ref_function => no ref necessary
4678 : return false;
4679 : }
4680 :
4681 3893 : if (type is GenericType) {
4682 65 : if (is_limited_generic_type ((GenericType) type)) {
4683 : return false;
4684 : }
4685 : }
4686 :
4687 : return true;
4688 : }
4689 :
4690 31372 : public static bool requires_destroy (DataType type) {
4691 31372 : if (!type.is_disposable ()) {
4692 19053 : return false;
4693 : }
4694 :
4695 12353 : var array_type = type as ArrayType;
4696 1302 : if (array_type != null && array_type.fixed_length) {
4697 17 : return requires_destroy (array_type.element_type);
4698 : }
4699 :
4700 12336 : unowned Class? cl = type.type_symbol as Class;
4701 9923 : if (cl != null && is_reference_counting (cl)
4702 5240 : && get_ccode_unref_function (cl) == "") {
4703 : // empty unref_function => no unref necessary
4704 25 : return false;
4705 : }
4706 :
4707 12311 : if (type is GenericType) {
4708 76 : if (is_limited_generic_type ((GenericType) type)) {
4709 9 : return false;
4710 : }
4711 : }
4712 :
4713 12302 : return true;
4714 : }
4715 :
4716 6061 : public virtual TargetValue? copy_value (TargetValue value, CodeNode node) {
4717 3030 : var type = value.value_type;
4718 3030 : var cexpr = get_cvalue_ (value);
4719 3030 : var result = ((GLibValue) value).copy ();
4720 :
4721 3030 : if (type is DelegateType) {
4722 33 : var delegate_type = (DelegateType) type;
4723 33 : if (get_ccode_delegate_target (node) && delegate_type.delegate_symbol.has_target && !context.deprecated) {
4724 26 : Report.deprecated (node.source_reference, "copying delegates is not supported");
4725 : }
4726 33 : result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
4727 33 : return result;
4728 : }
4729 :
4730 2997 : if (type is ValueType && !type.nullable) {
4731 : // normal value type, no null check
4732 :
4733 : // use temp-var for upcoming address-of operator
4734 44 : var temp_cvalue = create_temp_value (type, false, node);
4735 44 : store_value (temp_cvalue, value, node.source_reference);
4736 88 : cexpr = get_cvalue_ (temp_cvalue);
4737 :
4738 44 : var temp_value = create_temp_value (type, true, node, true);
4739 44 : var ctemp = get_cvalue_ (temp_value);
4740 :
4741 44 : var vt = (ValueType) type;
4742 44 : var st = (Struct) vt.type_symbol;
4743 44 : var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
4744 44 : copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4745 44 : copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4746 :
4747 44 : if (!get_ccode_has_copy_function (st)) {
4748 0 : generate_struct_copy_function (st);
4749 : }
4750 :
4751 53 : if (gvalue_type != null && type.type_symbol == gvalue_type) {
4752 9 : var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
4753 9 : cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4754 :
4755 9 : ccode.open_if (cisvalid);
4756 :
4757 : // GValue requires g_value_init in addition to g_value_copy
4758 9 : var value_type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
4759 9 : value_type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4760 :
4761 9 : var init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
4762 9 : init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4763 9 : init_call.add_argument (value_type_call);
4764 9 : ccode.add_expression (init_call);
4765 9 : ccode.add_expression (copy_call);
4766 :
4767 9 : ccode.add_else ();
4768 :
4769 : // g_value_init/copy must not be called for uninitialized values
4770 9 : store_value (temp_value, temp_cvalue, node.source_reference);
4771 9 : ccode.close ();
4772 : } else {
4773 35 : ccode.add_expression (copy_call);
4774 : }
4775 :
4776 44 : return temp_value;
4777 : }
4778 :
4779 : /* (temp = expr, temp == NULL ? NULL : ref (temp))
4780 : *
4781 : * can be simplified to
4782 : * ref (expr)
4783 : * if static type of expr is non-null
4784 : */
4785 :
4786 2953 : var dupexpr = get_dup_func_expression (type, node.source_reference);
4787 :
4788 2953 : if (dupexpr == null) {
4789 0 : node.error = true;
4790 0 : return null;
4791 : }
4792 :
4793 2953 : if (dupexpr is CCodeIdentifier && !(type is ArrayType) && !(type is GenericType) && !is_ref_function_void (type)) {
4794 : // generate and call NULL-aware ref function to reduce number
4795 : // of temporary variables and simplify code
4796 :
4797 2790 : var dupid = (CCodeIdentifier) dupexpr;
4798 2790 : string dup0_func = "_%s0".printf (dupid.name);
4799 :
4800 : // g_strdup is already NULL-safe
4801 2790 : if (dupid.name == "g_strdup") {
4802 3244 : dup0_func = dupid.name;
4803 1505 : } else if (add_wrapper (dup0_func)) {
4804 337 : var dup0_fun = new CCodeFunction (dup0_func, get_ccode_name (pointer_type));
4805 337 : dup0_fun.add_parameter (new CCodeParameter ("self", get_ccode_name (pointer_type)));
4806 337 : dup0_fun.modifiers = CCodeModifiers.STATIC;
4807 :
4808 337 : push_function (dup0_fun);
4809 :
4810 337 : var dup_call = new CCodeFunctionCall (dupexpr);
4811 337 : dup_call.add_argument (new CCodeIdentifier ("self"));
4812 :
4813 337 : ccode.add_return (new CCodeConditionalExpression (new CCodeIdentifier ("self"), dup_call, new CCodeConstant ("NULL")));
4814 :
4815 337 : pop_function ();
4816 :
4817 337 : cfile.add_function (dup0_fun);
4818 : }
4819 :
4820 2790 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (dup0_func));
4821 2790 : ccall.add_argument (cexpr);
4822 5580 : result.cvalue = ccall;
4823 2790 : result.value_type.value_owned = true;
4824 2790 : return store_temp_value (result, node);
4825 : }
4826 :
4827 163 : var ccall = new CCodeFunctionCall (dupexpr);
4828 :
4829 163 : if (!(type is ArrayType) && get_non_null (value) && !is_ref_function_void (type)) {
4830 : // expression is non-null
4831 0 : ccall.add_argument (cexpr);
4832 :
4833 0 : return store_temp_value (new GLibValue (type, ccall), node);
4834 : } else {
4835 : CCodeExpression ccallarg;
4836 163 : if (node is SliceExpression) {
4837 18 : ccallarg = cexpr;
4838 36 : cexpr = get_cvalue (((SliceExpression) node).container);
4839 : } else {
4840 145 : ccallarg = cexpr;
4841 : }
4842 163 : var cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cexpr, new CCodeConstant ("NULL"));
4843 195 : if (type is GenericType) {
4844 : // dup functions are optional for type parameters
4845 32 : var cdupnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_dup_func_expression (type, node.source_reference), new CCodeConstant ("NULL"));
4846 32 : cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.AND, cnotnull, cdupnotnull);
4847 : }
4848 :
4849 163 : if (type is GenericType) {
4850 : // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
4851 32 : ccall.add_argument (new CCodeCastExpression (ccallarg, get_ccode_name (pointer_type)));
4852 : } else {
4853 131 : ccall.add_argument (ccallarg);
4854 : }
4855 :
4856 292 : if (type is ArrayType) {
4857 129 : var array_type = (ArrayType) type;
4858 129 : ccall.add_argument (get_array_length_cvalue (value));
4859 :
4860 131 : if (array_type.element_type is GenericType) {
4861 2 : var elem_dupexpr = get_dup_func_expression (array_type.element_type, node.source_reference);
4862 2 : if (elem_dupexpr == null) {
4863 0 : elem_dupexpr = new CCodeConstant ("NULL");
4864 : }
4865 2 : ccall.add_argument (elem_dupexpr);
4866 : }
4867 : }
4868 :
4869 : CCodeExpression cifnull;
4870 163 : if (type is GenericType) {
4871 : // the value might be non-null even when the dup function is null,
4872 : // so we may not just use NULL for type parameters
4873 :
4874 : // cast from gconstpointer to gpointer as methods in
4875 : // generic classes may not return gconstpointer
4876 32 : cifnull = new CCodeCastExpression (cexpr, get_ccode_name (pointer_type));
4877 131 : } else if (type.type_symbol != null) {
4878 2 : cifnull = new CCodeConstant ("NULL");
4879 : } else {
4880 129 : cifnull = cexpr;
4881 : }
4882 :
4883 163 : if (is_ref_function_void (type)) {
4884 0 : ccode.open_if (cnotnull);
4885 0 : ccode.add_expression (ccall);
4886 0 : ccode.close ();
4887 : } else {
4888 307 : if (get_non_null (value)) {
4889 38 : result.cvalue = ccall;
4890 : } else {
4891 144 : var ccond = new CCodeConditionalExpression (cnotnull, ccall, cifnull);
4892 288 : result.cvalue = ccond;
4893 : }
4894 163 : result = (GLibValue) store_temp_value (result, node, true);
4895 : }
4896 163 : return result;
4897 : }
4898 : }
4899 :
4900 73771 : public virtual void generate_class_declaration (Class cl, CCodeFile decl_space) {
4901 93 : if (add_symbol_declaration (decl_space, cl, get_ccode_name (cl))) {
4902 : return;
4903 : }
4904 : }
4905 :
4906 4474 : public virtual void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
4907 : }
4908 :
4909 29025 : public virtual bool generate_method_declaration (Method m, CCodeFile decl_space) {
4910 : return false;
4911 : }
4912 :
4913 1374 : public virtual void generate_error_domain_declaration (ErrorDomain edomain, CCodeFile decl_space) {
4914 : }
4915 :
4916 1860 : public void add_generic_type_arguments (Method m, Map<int,CCodeExpression> arg_map, List<DataType> type_args, CodeNode expr, bool is_chainup = false, List<TypeParameter>? type_parameters = null) {
4917 1860 : int type_param_index = 0;
4918 2462 : foreach (var type_arg in type_args) {
4919 315 : if (get_ccode_simple_generics (m)) {
4920 28 : if (requires_copy (type_arg)) {
4921 25 : arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), get_destroy0_func_expression (type_arg, is_chainup));
4922 : } else {
4923 3 : arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
4924 : }
4925 28 : type_param_index++;
4926 28 : continue;
4927 : }
4928 :
4929 287 : if (type_parameters != null) {
4930 1 : var type_param_name = type_parameters.get (type_param_index).name.ascii_down ().replace ("_", "-");
4931 1 : arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s-type\"".printf (type_param_name)));
4932 1 : arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("\"%s-dup-func\"".printf (type_param_name)));
4933 1 : arg_map.set (get_param_pos (0.1 * type_param_index + 0.05), new CCodeConstant ("\"%s-destroy-func\"".printf (type_param_name)));
4934 : }
4935 :
4936 287 : arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), get_type_id_expression (type_arg, is_chainup));
4937 525 : if (requires_copy (type_arg)) {
4938 238 : var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference ?? expr.source_reference, is_chainup);
4939 238 : if (dup_func == null) {
4940 : // type doesn't contain a copy function
4941 0 : expr.error = true;
4942 0 : return;
4943 : }
4944 238 : arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
4945 238 : arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeCastExpression (get_destroy_func_expression (type_arg, is_chainup), "GDestroyNotify"));
4946 : } else {
4947 49 : arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeConstant ("NULL"));
4948 49 : arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeConstant ("NULL"));
4949 : }
4950 287 : type_param_index++;
4951 : }
4952 : }
4953 :
4954 3508 : public override void visit_object_creation_expression (ObjectCreationExpression expr) {
4955 1754 : CCodeExpression instance = null;
4956 1754 : CCodeExpression creation_expr = null;
4957 :
4958 1754 : unowned Struct? st = expr.type_reference.type_symbol as Struct;
4959 1917 : if ((st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list")) || expr.get_object_initializer ().size > 0) {
4960 : // value-type initialization or object creation expression with object initializer
4961 :
4962 163 : var local = expr.parent_node as LocalVariable;
4963 163 : var field = expr.parent_node as Field;
4964 163 : var a = expr.parent_node as Assignment;
4965 163 : if (local != null && is_simple_struct_creation (local, local.initializer)) {
4966 134 : instance = get_cvalue_ (get_local_cvalue (local));
4967 96 : } else if (field != null && is_simple_struct_creation (field, field.initializer)) {
4968 : // field initialization
4969 0 : var thisparam = load_this_parameter ((TypeSymbol) field.parent_symbol);
4970 0 : instance = get_cvalue_ (get_field_cvalue (field, thisparam));
4971 99 : } else if (a != null && a.left.symbol_reference is Variable && is_simple_struct_creation ((Variable) a.left.symbol_reference, a.right)) {
4972 3 : if (requires_destroy (a.left.value_type)) {
4973 : /* unref old value */
4974 2 : ccode.add_expression (destroy_value (a.left.target_value));
4975 : }
4976 :
4977 4 : local = a.left.symbol_reference as LocalVariable;
4978 3 : field = a.left.symbol_reference as Field;
4979 3 : var param = a.left.symbol_reference as Parameter;
4980 3 : if (local != null) {
4981 2 : instance = get_cvalue_ (get_local_cvalue (local));
4982 2 : } else if (field != null) {
4983 0 : var inner = ((MemberAccess) a.left).inner;
4984 0 : instance = get_cvalue_ (get_field_cvalue (field, inner != null ? inner.target_value : null));
4985 2 : } else if (param != null) {
4986 4 : instance = get_cvalue_ (get_parameter_cvalue (param));
4987 : }
4988 184 : } else if (expr.is_chainup) {
4989 2 : instance = get_this_cexpression ();
4990 : } else {
4991 91 : var temp_value = create_temp_value (expr.type_reference, true, expr);
4992 182 : instance = get_cvalue_ (temp_value);
4993 : }
4994 : }
4995 :
4996 1754 : if (expr.symbol_reference == null) {
4997 : // no creation method
4998 54 : if (expr.type_reference.type_symbol is Struct) {
4999 : // memset needs string.h
5000 54 : cfile.add_include ("string.h");
5001 54 : var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
5002 54 : creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
5003 54 : creation_call.add_argument (new CCodeConstant ("0"));
5004 54 : creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.type_reference))));
5005 :
5006 108 : creation_expr = creation_call;
5007 : }
5008 1700 : } else if (expr.type_reference.type_symbol == glist_type ||
5009 1688 : expr.type_reference.type_symbol == gslist_type) {
5010 : // NULL is an empty list
5011 19 : set_cvalue (expr, new CCodeConstant ("NULL"));
5012 3291 : } else if (expr.symbol_reference is Method) {
5013 : // use creation method
5014 1610 : var m = (Method) expr.symbol_reference;
5015 1610 : var params = m.get_parameters ();
5016 : CCodeFunctionCall creation_call;
5017 :
5018 1610 : CCodeFunctionCall async_call = null;
5019 1610 : CCodeFunctionCall finish_call = null;
5020 :
5021 1610 : generate_method_declaration (m, cfile);
5022 :
5023 1610 : if (m is CreationMethod && !m.external && m.external_package) {
5024 0 : unowned CreationMethod cm = (CreationMethod) m;
5025 0 : if (!cm.chain_up) {
5026 0 : Report.error (cm.source_reference, "internal: Creation method implementation in binding must be chained up");
5027 : }
5028 : // internal VAPI creation methods
5029 : // only add them once per source file
5030 0 : if (add_generated_external_symbol (cm)) {
5031 0 : visit_creation_method (cm);
5032 : }
5033 : }
5034 :
5035 1610 : unowned Class? cl = expr.type_reference.type_symbol as Class;
5036 :
5037 1610 : if (!get_ccode_has_new_function (m)) {
5038 : // use construct function directly
5039 14 : creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
5040 14 : creation_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
5041 : } else {
5042 1596 : creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
5043 : }
5044 :
5045 1610 : if ((st != null && !st.is_simple_type ()) && !(get_ccode_instance_pos (m) < 0)) {
5046 53 : if (expr.is_chainup) {
5047 2 : creation_call.add_argument (instance);
5048 : } else {
5049 51 : creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
5050 : }
5051 1557 : } else if (st != null && get_ccode_name (st) == "va_list") {
5052 40 : creation_call.add_argument (instance);
5053 40 : if (get_ccode_name (m) == "va_start") {
5054 40 : unowned Class? parent = current_method.parent_symbol as Class;
5055 73 : if (in_creation_method && parent != null && !parent.is_compact) {
5056 7 : creation_call = new CCodeFunctionCall (new CCodeIdentifier ("va_copy"));
5057 7 : creation_call.add_argument (instance);
5058 7 : creation_call.add_argument (new CCodeIdentifier ("_vala_va_list"));
5059 : } else {
5060 33 : Parameter last_param = null;
5061 : // FIXME: this doesn't take into account exception handling parameters
5062 125 : foreach (var param in current_method.get_parameters ()) {
5063 78 : if (param.ellipsis || param.params_array) {
5064 32 : break;
5065 : }
5066 92 : last_param = param;
5067 : }
5068 33 : int nParams = ccode.get_parameter_count ();
5069 33 : if (nParams == 0 || !ccode.get_parameter (nParams - 1).ellipsis) {
5070 1 : Report.error (expr.source_reference, "`va_list' used in method with fixed args");
5071 32 : } else if (nParams == 1) {
5072 0 : Report.error (expr.source_reference, "`va_list' used in method without parameter");
5073 : } else {
5074 32 : creation_call.add_argument (new CCodeIdentifier (ccode.get_parameter (nParams - 2).name));
5075 : }
5076 : }
5077 : }
5078 : }
5079 :
5080 1610 : generate_type_declaration (expr.type_reference, cfile);
5081 :
5082 1610 : var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
5083 3853 : var out_arg_map = in_arg_map;
5084 :
5085 1610 : if (m != null && m.coroutine) {
5086 : // async call
5087 :
5088 7 : async_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
5089 7 : finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
5090 :
5091 14 : creation_call = finish_call;
5092 :
5093 : // output arguments used separately
5094 7 : out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
5095 : // pass GAsyncResult stored in closure to finish function
5096 7 : out_arg_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
5097 : }
5098 :
5099 1610 : if (cl != null && (!cl.is_compact || get_ccode_simple_generics (m))) {
5100 1285 : add_generic_type_arguments (m, in_arg_map, expr.type_reference.get_type_arguments (), expr);
5101 : }
5102 :
5103 1610 : bool ellipsis = false;
5104 :
5105 1610 : int i = 1;
5106 : int arg_pos;
5107 1610 : Iterator<Parameter> params_it = params.iterator ();
5108 6096 : foreach (Expression arg in expr.get_argument_list ()) {
5109 2243 : CCodeExpression cexpr = get_cvalue (arg);
5110 :
5111 2243 : var carg_map = in_arg_map;
5112 :
5113 2243 : Parameter param = null;
5114 2243 : if (params_it.next ()) {
5115 2204 : param = params_it.get ();
5116 2210 : ellipsis = param.ellipsis || param.params_array;
5117 2170 : if (!ellipsis) {
5118 2164 : if (param.direction == ParameterDirection.OUT) {
5119 0 : carg_map = out_arg_map;
5120 : }
5121 :
5122 2170 : if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
5123 12 : var array_type = (ArrayType) param.variable_type;
5124 12 : for (int dim = 1; dim <= array_type.rank; dim++) {
5125 6 : carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_array_length_cexpression (arg, dim));
5126 : }
5127 2163 : } else if (get_ccode_delegate_target (param) && param.variable_type is DelegateType) {
5128 5 : var deleg_type = (DelegateType) param.variable_type;
5129 5 : var d = deleg_type.delegate_symbol;
5130 10 : if (d.has_target) {
5131 : CCodeExpression delegate_target_destroy_notify;
5132 5 : var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
5133 5 : carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
5134 5 : if (deleg_type.is_disposable ()) {
5135 2 : carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), delegate_target_destroy_notify);
5136 : }
5137 : }
5138 : }
5139 :
5140 2164 : cexpr = handle_struct_argument (param, arg, cexpr);
5141 :
5142 2164 : if (get_ccode_type (param) != null) {
5143 0 : cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
5144 : }
5145 : } else {
5146 40 : cexpr = handle_struct_argument (null, arg, cexpr);
5147 : }
5148 :
5149 2204 : arg_pos = get_param_pos (get_ccode_pos (param), ellipsis);
5150 : } else {
5151 : // default argument position
5152 39 : cexpr = handle_struct_argument (null, arg, cexpr);
5153 39 : arg_pos = get_param_pos (i, ellipsis);
5154 : }
5155 :
5156 2243 : carg_map.set (arg_pos, cexpr);
5157 :
5158 2243 : i++;
5159 : }
5160 1625 : if (params_it.next ()) {
5161 15 : var param = params_it.get ();
5162 :
5163 : /* if there are more parameters than arguments,
5164 : * the additional parameter is an ellipsis parameter
5165 : * otherwise there is a bug in the semantic analyzer
5166 : */
5167 15 : assert (param.params_array || param.ellipsis);
5168 15 : ellipsis = true;
5169 : }
5170 :
5171 1610 : if (expr.tree_can_fail) {
5172 : // method can fail
5173 24 : current_method_inner_error = true;
5174 : // add &inner_error before the ellipsis arguments
5175 24 : out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
5176 : }
5177 :
5178 1610 : if (ellipsis) {
5179 : /* ensure variable argument list ends with NULL
5180 : * except when using printf-style arguments */
5181 55 : if (m == null) {
5182 0 : in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
5183 55 : } else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "") {
5184 54 : in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
5185 : }
5186 : }
5187 :
5188 1610 : if ((st != null && !st.is_simple_type ()) && get_ccode_instance_pos (m) < 0) {
5189 : // instance parameter is at the end in a struct creation method
5190 0 : out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
5191 : }
5192 :
5193 1610 : if (m != null && m.coroutine) {
5194 7 : if (expr.is_yield_expression) {
5195 : // asynchronous call
5196 7 : in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
5197 7 : in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
5198 : }
5199 : }
5200 :
5201 1610 : if (m != null && m.coroutine && m.parent_symbol is Class) {
5202 7 : if (get_ccode_finish_instance (m)) {
5203 0 : var tmp = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_source_object_");
5204 0 : out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), tmp);
5205 : }
5206 : }
5207 :
5208 : // append C arguments in the right order
5209 :
5210 : int last_pos;
5211 : int min_pos;
5212 :
5213 1610 : if (async_call != creation_call) {
5214 : // don't append out arguments for .begin() calls
5215 : last_pos = -1;
5216 4549 : while (true) {
5217 4549 : min_pos = -1;
5218 24476 : foreach (int pos in out_arg_map.get_keys ()) {
5219 15378 : if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
5220 6326 : min_pos = pos;
5221 : }
5222 : }
5223 4549 : if (min_pos == -1) {
5224 : break;
5225 : }
5226 2939 : creation_call.add_argument (out_arg_map.get (min_pos));
5227 : last_pos = min_pos;
5228 : }
5229 : }
5230 :
5231 1610 : if (async_call != null) {
5232 : last_pos = -1;
5233 29 : while (true) {
5234 29 : min_pos = -1;
5235 190 : foreach (int pos in in_arg_map.get_keys ()) {
5236 132 : if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
5237 51 : min_pos = pos;
5238 : }
5239 : }
5240 29 : if (min_pos == -1) {
5241 : break;
5242 : }
5243 22 : async_call.add_argument (in_arg_map.get (min_pos));
5244 : last_pos = min_pos;
5245 : }
5246 : }
5247 :
5248 1610 : if (expr.is_yield_expression) {
5249 : // set state before calling async function to support immediate callbacks
5250 7 : int state = emit_context.next_coroutine_state++;
5251 :
5252 7 : ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
5253 7 : ccode.add_expression (async_call);
5254 7 : ccode.add_return (new CCodeConstant ("FALSE"));
5255 7 : ccode.add_label ("_state_%d".printf (state));
5256 : }
5257 :
5258 1610 : creation_expr = creation_call;
5259 :
5260 : // cast the return value of the creation method back to the intended type if
5261 : // it requested a special C return type
5262 1610 : if (get_ccode_type (m) != null) {
5263 10 : creation_expr = new CCodeCastExpression (creation_expr, get_ccode_name (expr.type_reference));
5264 : }
5265 142 : } else if (expr.symbol_reference is ErrorCode) {
5266 71 : var ecode = (ErrorCode) expr.symbol_reference;
5267 71 : var edomain = (ErrorDomain) ecode.parent_symbol;
5268 : CCodeFunctionCall creation_call;
5269 :
5270 71 : generate_error_domain_declaration (edomain, cfile);
5271 :
5272 71 : if (expr.get_argument_list ().size == 1) {
5273 : // must not be a format argument
5274 64 : creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new_literal"));
5275 : } else {
5276 7 : creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new"));
5277 : }
5278 71 : creation_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (edomain)));
5279 71 : creation_call.add_argument (new CCodeIdentifier (get_ccode_name (ecode)));
5280 :
5281 227 : foreach (Expression arg in expr.get_argument_list ()) {
5282 78 : creation_call.add_argument (get_cvalue (arg));
5283 : }
5284 :
5285 142 : creation_expr = creation_call;
5286 : } else {
5287 0 : assert (false);
5288 : }
5289 :
5290 1754 : var local = expr.parent_node as LocalVariable;
5291 1754 : if (local != null && is_simple_struct_creation (local, local.initializer)) {
5292 : // no temporary variable necessary
5293 67 : ccode.add_expression (creation_expr);
5294 67 : set_cvalue (expr, instance);
5295 1687 : } else if (instance != null) {
5296 96 : if (expr.type_reference.type_symbol is Struct) {
5297 80 : ccode.add_expression (creation_expr);
5298 : } else {
5299 16 : ccode.add_assignment (instance, creation_expr);
5300 : }
5301 :
5302 284 : foreach (MemberInitializer init in expr.get_object_initializer ()) {
5303 199 : if (init.symbol_reference is Field) {
5304 79 : var f = (Field) init.symbol_reference;
5305 79 : var instance_target_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
5306 79 : var typed_inst = transform_value (new GLibValue (expr.type_reference, instance, true), instance_target_type, init);
5307 79 : store_field (f, typed_inst, init.initializer.target_value, false, init.source_reference);
5308 :
5309 79 : var cl = f.parent_symbol as Class;
5310 105 : if (cl != null) {
5311 26 : generate_class_struct_declaration (cl, cfile);
5312 : }
5313 30 : } else if (init.symbol_reference is Property) {
5314 15 : var p = (Property) init.symbol_reference;
5315 15 : if (p.base_property != null) {
5316 2 : p = p.base_property;
5317 14 : } else if (p.base_interface_property != null) {
5318 2 : p = p.base_interface_property;
5319 : }
5320 15 : var instance_target_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) p.parent_symbol);
5321 15 : var typed_inst = transform_value (new GLibValue (expr.type_reference, instance), instance_target_type, init);
5322 15 : var inst_ma = new MemberAccess.simple ("fake");
5323 15 : inst_ma.target_value = typed_inst;
5324 15 : store_property (p, inst_ma, init.initializer.target_value);
5325 : // FIXME Do not ref/copy in the first place
5326 15 : if (!p.set_accessor.value_type.value_owned && requires_destroy (init.initializer.target_value.value_type)) {
5327 7 : ccode.add_expression (destroy_value (init.initializer.target_value));
5328 : }
5329 : } else {
5330 0 : Report.error (init.source_reference, "internal: Unsupported symbol");
5331 : }
5332 : }
5333 :
5334 96 : set_cvalue (expr, instance);
5335 3163 : } else if (creation_expr != null) {
5336 1572 : var temp_value = create_temp_value (expr.value_type, false, expr);
5337 1572 : ccode.add_assignment (get_cvalue_ (temp_value), creation_expr);
5338 1572 : expr.target_value = temp_value;
5339 :
5340 1572 : unowned Class? cl = expr.type_reference.type_symbol as Class;
5341 1572 : if (context.gobject_tracing) {
5342 : // GObject creation tracing enabled
5343 :
5344 0 : if (cl != null && cl.is_subtype_of (gobject_type)) {
5345 : // creating GObject
5346 :
5347 : // instance can be NULL in error cases
5348 0 : ccode.open_if (get_cvalue_ (expr.target_value));
5349 :
5350 0 : var set_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set_data"));
5351 0 : set_data_call.add_argument (new CCodeCastExpression (get_cvalue_ (expr.target_value), "GObject *"));
5352 0 : set_data_call.add_argument (new CCodeConstant ("\"vala-creation-function\""));
5353 :
5354 0 : string func_name = "";
5355 0 : if (current_method != null) {
5356 0 : func_name = current_method.get_full_name ();
5357 0 : } else if (current_property_accessor != null) {
5358 0 : func_name = current_property_accessor.get_full_name ();
5359 : }
5360 :
5361 0 : set_data_call.add_argument (new CCodeConstant ("\"%s\"".printf (func_name)));
5362 :
5363 0 : ccode.add_expression (set_data_call);
5364 :
5365 0 : ccode.close ();
5366 : }
5367 : }
5368 :
5369 : // create a special GDestroyNotify for created GArray and set with g_array_set_clear_func (since glib 2.32)
5370 1582 : if (cl != null && cl == garray_type) {
5371 10 : var type_arg = expr.type_reference.get_type_arguments ().get (0);
5372 17 : if (requires_destroy (type_arg)) {
5373 7 : var clear_func = new CCodeFunctionCall (new CCodeIdentifier ("g_array_set_clear_func"));
5374 7 : clear_func.add_argument (get_cvalue_ (expr.target_value));
5375 : string destroy_func;
5376 7 : if (type_arg.is_non_null_simple_type () || type_arg.is_real_non_null_struct_type ()) {
5377 2 : destroy_func = get_ccode_destroy_function (type_arg.type_symbol);
5378 : } else {
5379 5 : destroy_func = generate_destroy_function_content_of_wrapper (type_arg);
5380 : }
5381 7 : clear_func.add_argument (new CCodeCastExpression (new CCodeIdentifier (destroy_func), "GDestroyNotify"));
5382 7 : ccode.add_expression (clear_func);
5383 : }
5384 : }
5385 : }
5386 :
5387 1754 : ((GLibValue) expr.target_value).lvalue = true;
5388 : }
5389 :
5390 22215 : public CCodeExpression? handle_struct_argument (Parameter? param, Expression arg, CCodeExpression? cexpr) {
5391 : DataType type;
5392 22215 : if (param != null) {
5393 21119 : type = param.variable_type;
5394 : } else {
5395 : // varargs
5396 1096 : type = arg.value_type;
5397 : }
5398 :
5399 22215 : var unary = arg as UnaryExpression;
5400 : // pass non-simple struct instances always by reference
5401 22215 : if (!(arg.value_type is NullType) && type.is_real_struct_type ()) {
5402 : // we already use a reference for arguments of ref, out, and nullable parameters
5403 74 : if (!(unary != null && (unary.operator == UnaryOperator.OUT || unary.operator == UnaryOperator.REF)) && !type.nullable) {
5404 60 : if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
5405 58 : return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5406 : } else {
5407 : // if cexpr is e.g. a function call, we can't take the address of the expression
5408 2 : var temp_value = create_temp_value (type, false, arg);
5409 2 : ccode.add_assignment (get_cvalue_ (temp_value), cexpr);
5410 2 : return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value));
5411 : }
5412 : }
5413 : }
5414 :
5415 44310 : return cexpr;
5416 : }
5417 :
5418 82 : public override void visit_sizeof_expression (SizeofExpression expr) {
5419 41 : generate_type_declaration (expr.type_reference, cfile);
5420 :
5421 41 : var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5422 41 : csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference)));
5423 41 : set_cvalue (expr, csizeof);
5424 : }
5425 :
5426 151 : public override void visit_typeof_expression (TypeofExpression expr) {
5427 151 : cfile.add_include ("glib-object.h");
5428 :
5429 151 : set_cvalue (expr, get_type_id_expression (expr.type_reference));
5430 : }
5431 :
5432 1859 : public override void visit_unary_expression (UnaryExpression expr) {
5433 1859 : if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) {
5434 3320 : var glib_value = (GLibValue) expr.inner.target_value;
5435 :
5436 402 : var ref_value = new GLibValue (glib_value.value_type);
5437 402 : if (expr.target_type != null && glib_value.value_type.is_real_struct_type () && glib_value.value_type.nullable != expr.target_type.nullable) {
5438 : // the only possibility is that value_type is nullable and target_type is non-nullable
5439 4 : ref_value.cvalue = glib_value.cvalue;
5440 : } else {
5441 400 : ref_value.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.cvalue);
5442 : }
5443 :
5444 402 : if (glib_value.array_length_cvalues != null) {
5445 92 : for (int i = 0; i < glib_value.array_length_cvalues.size; i++) {
5446 48 : ref_value.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.array_length_cvalues[i]));
5447 : }
5448 : }
5449 :
5450 402 : if (glib_value.delegate_target_cvalue != null) {
5451 6 : ref_value.delegate_target_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_cvalue);
5452 : }
5453 402 : if (glib_value.delegate_target_destroy_notify_cvalue != null) {
5454 6 : ref_value.delegate_target_destroy_notify_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_destroy_notify_cvalue);
5455 : }
5456 :
5457 402 : expr.target_value = ref_value;
5458 402 : return;
5459 : }
5460 :
5461 1457 : if (expr.operator == UnaryOperator.INCREMENT || expr.operator == UnaryOperator.DECREMENT) {
5462 : // increment/decrement variable
5463 248 : var op = expr.operator == UnaryOperator.INCREMENT ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
5464 248 : var cexpr = new CCodeBinaryExpression (op, get_cvalue_ (expr.inner.target_value), new CCodeConstant ("1"));
5465 248 : ccode.add_assignment (get_cvalue (expr.inner), cexpr);
5466 :
5467 : // assign new value to temp variable
5468 248 : var temp_value = store_temp_value (expr.inner.target_value, expr);
5469 :
5470 248 : MemberAccess ma = find_property_access (expr.inner);
5471 260 : if (ma != null) {
5472 : // property postfix expression
5473 12 : var prop = (Property) ma.symbol_reference;
5474 :
5475 12 : store_property (prop, ma.inner, temp_value);
5476 : }
5477 :
5478 : // return new value
5479 248 : expr.target_value = temp_value;
5480 248 : return;
5481 : }
5482 :
5483 : CCodeUnaryOperator op;
5484 1209 : switch (expr.operator) {
5485 : case UnaryOperator.PLUS:
5486 : op = CCodeUnaryOperator.PLUS;
5487 : break;
5488 : case UnaryOperator.MINUS:
5489 : op = CCodeUnaryOperator.MINUS;
5490 : break;
5491 : case UnaryOperator.LOGICAL_NEGATION:
5492 : op = CCodeUnaryOperator.LOGICAL_NEGATION;
5493 : break;
5494 : case UnaryOperator.BITWISE_COMPLEMENT:
5495 : op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
5496 : break;
5497 : case UnaryOperator.INCREMENT:
5498 : op = CCodeUnaryOperator.PREFIX_INCREMENT;
5499 : break;
5500 : case UnaryOperator.DECREMENT:
5501 : op = CCodeUnaryOperator.PREFIX_DECREMENT;
5502 : break;
5503 : default:
5504 0 : assert_not_reached ();
5505 : }
5506 1209 : set_cvalue (expr, new CCodeUnaryExpression (op, get_cvalue (expr.inner)));
5507 : }
5508 :
5509 241 : public virtual CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
5510 0 : assert_not_reached ();
5511 : }
5512 :
5513 262 : public virtual CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
5514 0 : assert_not_reached ();
5515 : }
5516 :
5517 1725 : public override void visit_cast_expression (CastExpression expr) {
5518 863 : if (expr.is_silent_cast) {
5519 1 : set_cvalue (expr, new CCodeInvalidExpression ());
5520 1 : expr.error = true;
5521 1 : Report.error (expr.source_reference, "Operation not supported for this type");
5522 1 : return;
5523 : }
5524 :
5525 862 : generate_type_declaration (expr.type_reference, cfile);
5526 :
5527 : // recompute array length when casting to other array type
5528 862 : var array_type = expr.type_reference as ArrayType;
5529 862 : if (array_type != null && expr.inner.value_type is ArrayType) {
5530 26 : if (array_type.element_type is GenericType || ((ArrayType) expr.inner.value_type).element_type is GenericType) {
5531 : // element size unknown for generic arrays, retain array length as is
5532 0 : for (int dim = 1; dim <= array_type.rank; dim++) {
5533 0 : append_array_length (expr, get_array_length_cexpression (expr.inner, dim));
5534 : }
5535 : } else {
5536 13 : var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5537 13 : sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5538 :
5539 13 : var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5540 13 : sizeof_from.add_argument (new CCodeConstant (get_ccode_name (((ArrayType) expr.inner.value_type).element_type)));
5541 :
5542 26 : for (int dim = 1; dim <= array_type.rank; dim++) {
5543 13 : append_array_length (expr, new CCodeBinaryExpression (CCodeBinaryOperator.DIV, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_array_length_cexpression (expr.inner, dim), sizeof_from), sizeof_to));
5544 : }
5545 : }
5546 873 : } else if (array_type != null) {
5547 : CCodeExpression array_length_expr;
5548 :
5549 24 : var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5550 24 : sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5551 24 : var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5552 :
5553 24 : var value_type = expr.inner.value_type;
5554 24 : if (value_type is ValueType) {
5555 11 : sizeof_from.add_argument (new CCodeConstant (get_ccode_name (value_type.type_symbol)));
5556 11 : array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5557 13 : } else if (value_type is PointerType && ((PointerType) value_type).base_type is ValueType) {
5558 5 : sizeof_from.add_argument (new CCodeConstant (get_ccode_name (((PointerType) value_type).base_type.type_symbol)));
5559 5 : array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5560 : } else {
5561 : // cast from unsupported non-array to array, set invalid length
5562 : // required by string.data, e.g.
5563 8 : array_length_expr = new CCodeConstant ("-1");
5564 : }
5565 :
5566 48 : for (int dim = 1; dim <= array_type.rank; dim++) {
5567 24 : append_array_length (expr, array_length_expr);
5568 : }
5569 : }
5570 :
5571 862 : var innercexpr = get_cvalue (expr.inner);
5572 862 : if (expr.type_reference is ValueType && !expr.type_reference.nullable &&
5573 146 : expr.inner.value_type is ValueType && expr.inner.value_type.nullable) {
5574 : // handle nested cast expressions
5575 35 : unowned Expression? inner_expr = expr.inner;
5576 39 : while (inner_expr is CastExpression) {
5577 4 : inner_expr = ((CastExpression) inner_expr).inner;
5578 : }
5579 45 : if (inner_expr.value_type.value_owned
5580 10 : && !(inner_expr.symbol_reference is Variable || inner_expr is ElementAccess)) {
5581 : // heap allocated struct leaked, destroy it
5582 10 : var value = new GLibValue (new PointerType (new VoidType ()), innercexpr);
5583 10 : temp_ref_values.insert (0, value);
5584 : }
5585 : // nullable integer or float or boolean or struct or enum cast to non-nullable
5586 35 : innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, innercexpr);
5587 842 : } else if (expr.type_reference is ValueType && expr.type_reference.nullable &&
5588 15 : expr.inner.value_type.is_real_non_null_struct_type ()) {
5589 : // real non-null struct cast to nullable
5590 3 : innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, innercexpr);
5591 824 : } else if (expr.type_reference is ArrayType && !(expr.inner is Literal)
5592 36 : && expr.inner.value_type is ValueType && !expr.inner.value_type.nullable) {
5593 : // integer or float or boolean or struct or enum to array cast
5594 7 : innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, innercexpr);
5595 : }
5596 862 : set_cvalue (expr, new CCodeCastExpression (innercexpr, get_ccode_name (expr.type_reference)));
5597 : //TODO Use get_non_null (expr.inner.target_value)
5598 862 : ((GLibValue) expr.target_value).non_null = expr.is_non_null ();
5599 :
5600 942 : if (expr.type_reference is DelegateType) {
5601 80 : var target = get_delegate_target (expr.inner);
5602 80 : if (target != null) {
5603 48 : set_delegate_target (expr, target);
5604 : } else {
5605 32 : set_delegate_target (expr, new CCodeConstant ("NULL"));
5606 : }
5607 80 : var target_destroy_notify = get_delegate_target_destroy_notify (expr.inner);
5608 80 : if (target_destroy_notify != null) {
5609 78 : set_delegate_target_destroy_notify (expr, target_destroy_notify);
5610 : } else {
5611 2 : set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
5612 : }
5613 : }
5614 : }
5615 :
5616 12 : public override void visit_named_argument (NamedArgument expr) {
5617 12 : set_cvalue (expr, get_cvalue (expr.inner));
5618 : }
5619 :
5620 47 : public override void visit_pointer_indirection (PointerIndirection expr) {
5621 47 : set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cvalue (expr.inner)));
5622 47 : ((GLibValue) expr.target_value).lvalue = get_lvalue (expr.inner.target_value);
5623 : }
5624 :
5625 24 : public override void visit_addressof_expression (AddressofExpression expr) {
5626 24 : set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5627 : }
5628 :
5629 155 : public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
5630 : /* tmp = expr.inner; expr.inner = NULL; expr = tmp; */
5631 155 : expr.target_value = store_temp_value (expr.inner.target_value, expr);
5632 :
5633 161 : if (expr.inner.value_type is StructValueType && !expr.inner.value_type.nullable) {
5634 : // memset needs string.h
5635 6 : cfile.add_include ("string.h");
5636 6 : var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
5637 6 : creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5638 6 : creation_call.add_argument (new CCodeConstant ("0"));
5639 6 : creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.inner.value_type))));
5640 6 : ccode.add_expression (creation_call);
5641 163 : } else if (expr.value_type is DelegateType) {
5642 14 : ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5643 14 : var target = get_delegate_target_cvalue (expr.inner.target_value);
5644 14 : if (target != null) {
5645 13 : ccode.add_assignment (target, new CCodeConstant ("NULL"));
5646 : }
5647 14 : var target_destroy_notify = get_delegate_target_destroy_notify_cvalue (expr.inner.target_value);
5648 14 : if (target_destroy_notify != null) {
5649 12 : ccode.add_assignment (target_destroy_notify, new CCodeConstant ("NULL"));
5650 : }
5651 154 : } else if (expr.inner.value_type is ArrayType) {
5652 19 : var array_type = (ArrayType) expr.inner.value_type;
5653 19 : var glib_value = (GLibValue) expr.inner.target_value;
5654 :
5655 19 : ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5656 19 : if (glib_value.array_length_cvalues != null) {
5657 30 : for (int dim = 1; dim <= array_type.rank; dim++) {
5658 15 : ccode.add_assignment (get_array_length_cvalue (glib_value, dim), new CCodeConstant ("0"));
5659 : }
5660 : }
5661 : } else {
5662 116 : ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5663 : }
5664 : }
5665 :
5666 17906 : public override void visit_binary_expression (BinaryExpression expr) {
5667 8953 : var cleft = get_cvalue (expr.left);
5668 8953 : var cright = get_cvalue (expr.right);
5669 :
5670 8953 : CCodeExpression? left_chain = null;
5671 8979 : if (expr.is_chained) {
5672 26 : var lbe = (BinaryExpression) expr.left;
5673 :
5674 26 : var temp_decl = get_temp_variable (lbe.right.target_type, true, null, false);
5675 26 : emit_temp_var (temp_decl);
5676 26 : var cvar = get_variable_cexpression (temp_decl.name);
5677 26 : var clbe = (CCodeBinaryExpression) get_cvalue (lbe);
5678 26 : if (lbe.is_chained) {
5679 14 : clbe = (CCodeBinaryExpression) clbe.right;
5680 : }
5681 26 : ccode.add_assignment (cvar, get_cvalue (lbe.right));
5682 26 : clbe.right = get_variable_cexpression (temp_decl.name);
5683 26 : left_chain = cleft;
5684 52 : cleft = cvar;
5685 : }
5686 :
5687 : CCodeBinaryOperator op;
5688 8953 : switch (expr.operator) {
5689 : case BinaryOperator.PLUS:
5690 : op = CCodeBinaryOperator.PLUS;
5691 : break;
5692 : case BinaryOperator.MINUS:
5693 246 : op = CCodeBinaryOperator.MINUS;
5694 246 : break;
5695 : case BinaryOperator.MUL:
5696 63 : op = CCodeBinaryOperator.MUL;
5697 63 : break;
5698 : case BinaryOperator.DIV:
5699 12 : op = CCodeBinaryOperator.DIV;
5700 12 : break;
5701 : case BinaryOperator.MOD:
5702 : // FIXME Code duplication with CCodeAssignmentModule.emit_simple_assignment()
5703 13 : if (expr.value_type.equals (double_type)) {
5704 1 : cfile.add_include ("math.h");
5705 1 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
5706 1 : ccall.add_argument (cleft);
5707 1 : ccall.add_argument (cright);
5708 1 : set_cvalue (expr, ccall);
5709 1 : return;
5710 12 : } else if (expr.value_type.equals (float_type)) {
5711 1 : cfile.add_include ("math.h");
5712 1 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
5713 1 : ccall.add_argument (cleft);
5714 1 : ccall.add_argument (cright);
5715 1 : set_cvalue (expr, ccall);
5716 1 : return;
5717 : } else {
5718 : op = CCodeBinaryOperator.MOD;
5719 : }
5720 : break;
5721 : case BinaryOperator.SHIFT_LEFT:
5722 27 : op = CCodeBinaryOperator.SHIFT_LEFT;
5723 27 : break;
5724 : case BinaryOperator.SHIFT_RIGHT:
5725 3 : op = CCodeBinaryOperator.SHIFT_RIGHT;
5726 3 : break;
5727 : case BinaryOperator.LESS_THAN:
5728 371 : op = CCodeBinaryOperator.LESS_THAN;
5729 371 : break;
5730 : case BinaryOperator.GREATER_THAN:
5731 193 : op = CCodeBinaryOperator.GREATER_THAN;
5732 193 : break;
5733 : case BinaryOperator.LESS_THAN_OR_EQUAL:
5734 97 : op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
5735 97 : break;
5736 : case BinaryOperator.GREATER_THAN_OR_EQUAL:
5737 127 : op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
5738 127 : break;
5739 : case BinaryOperator.EQUALITY:
5740 5848 : op = CCodeBinaryOperator.EQUALITY;
5741 5848 : break;
5742 : case BinaryOperator.INEQUALITY:
5743 1231 : op = CCodeBinaryOperator.INEQUALITY;
5744 1231 : break;
5745 : case BinaryOperator.BITWISE_AND:
5746 5 : op = CCodeBinaryOperator.BITWISE_AND;
5747 5 : break;
5748 : case BinaryOperator.BITWISE_OR:
5749 27 : op = CCodeBinaryOperator.BITWISE_OR;
5750 27 : break;
5751 : case BinaryOperator.BITWISE_XOR:
5752 6 : op = CCodeBinaryOperator.BITWISE_XOR;
5753 6 : break;
5754 : case BinaryOperator.AND:
5755 3 : op = CCodeBinaryOperator.AND;
5756 3 : break;
5757 : case BinaryOperator.OR:
5758 2 : op = CCodeBinaryOperator.OR;
5759 2 : break;
5760 : case BinaryOperator.IN:
5761 74 : if (expr.right.value_type is ArrayType) {
5762 32 : unowned ArrayType array_type = (ArrayType) expr.right.value_type;
5763 32 : unowned DataType element_type = array_type.element_type;
5764 32 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_contains_wrapper (array_type)));
5765 32 : CCodeExpression node = ccall;
5766 :
5767 32 : ccall.add_argument (cright);
5768 32 : ccall.add_argument (get_array_length_cexpression (expr.right));
5769 32 : if (element_type is StructValueType) {
5770 2 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft));
5771 33 : } else if (element_type is ValueType && !element_type.nullable
5772 9 : && expr.left.value_type is ValueType && expr.left.value_type.nullable) {
5773 : // null check
5774 3 : var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cleft, new CCodeConstant ("NULL"));
5775 3 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft));
5776 3 : node = new CCodeParenthesizedExpression (new CCodeConditionalExpression (cnull, new CCodeConstant ("FALSE"), ccall));
5777 : } else {
5778 27 : ccall.add_argument (cleft);
5779 : }
5780 32 : set_cvalue (expr, node);
5781 : } else {
5782 10 : set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft));
5783 : }
5784 42 : return;
5785 : default:
5786 0 : assert_not_reached ();
5787 : }
5788 :
5789 15988 : if (expr.operator == BinaryOperator.EQUALITY ||
5790 3061 : expr.operator == BinaryOperator.INEQUALITY) {
5791 7079 : var left_type = expr.left.target_type;
5792 7079 : var right_type = expr.right.target_type;
5793 7079 : make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
5794 :
5795 7098 : if (left_type is StructValueType && right_type is StructValueType) {
5796 19 : var equalfunc = generate_struct_equal_function ((Struct) left_type.type_symbol);
5797 19 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5798 19 : ccall.add_argument (cleft);
5799 19 : ccall.add_argument (cright);
5800 38 : cleft = ccall;
5801 19 : cright = get_boolean_cconstant (true);
5802 7111 : } else if ((left_type is IntegerType || left_type is FloatingType || left_type is BooleanType || left_type is EnumValueType) && left_type.nullable &&
5803 71 : (right_type is IntegerType || right_type is FloatingType || right_type is BooleanType || right_type is EnumValueType) && right_type.nullable) {
5804 51 : var equalfunc = generate_numeric_equal_function ((TypeSymbol) left_type.type_symbol);
5805 51 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5806 51 : ccall.add_argument (cleft);
5807 51 : ccall.add_argument (cright);
5808 102 : cleft = ccall;
5809 51 : cright = get_boolean_cconstant (true);
5810 : }
5811 : }
5812 :
5813 8909 : bool is_string_comparison = false;
5814 8909 : if (!(expr.right.value_type is NullType) && expr.right.value_type.compatible (string_type)) {
5815 2004 : if (!(expr.left.value_type is NullType) && expr.left.value_type.compatible (string_type)) {
5816 : is_string_comparison = true;
5817 62 : } else if (expr.is_chained) {
5818 10 : unowned BinaryExpression lbe = (BinaryExpression) expr.left;
5819 10 : if (!(lbe.right.value_type is NullType) && lbe.right.value_type.compatible (string_type)) {
5820 1952 : is_string_comparison = true;
5821 : }
5822 : }
5823 : }
5824 8909 : bool has_string_literal = (expr.left is StringLiteral || expr.right is StringLiteral);
5825 :
5826 8909 : if (is_string_comparison || (has_string_literal && expr.operator != BinaryOperator.PLUS)) {
5827 1967 : switch (expr.operator) {
5828 : case BinaryOperator.PLUS:
5829 : // string concatenation
5830 390 : if (expr.left.is_constant () && expr.right.is_constant ()) {
5831 : string left, right;
5832 :
5833 5 : if (cleft is CCodeIdentifier) {
5834 2 : left = ((CCodeIdentifier) cleft).name;
5835 4 : } else if (cleft is CCodeConstant) {
5836 8 : left = ((CCodeConstant) cleft).name;
5837 : } else {
5838 0 : Report.error (expr.source_reference, "internal: Unsupported expression");
5839 0 : left = "NULL";
5840 : }
5841 5 : if (cright is CCodeIdentifier) {
5842 4 : right = ((CCodeIdentifier) cright).name;
5843 3 : } else if (cright is CCodeConstant) {
5844 6 : right = ((CCodeConstant) cright).name;
5845 : } else {
5846 0 : Report.error (expr.source_reference, "internal: Unsupported expression");
5847 0 : right = "NULL";
5848 : }
5849 :
5850 5 : set_cvalue (expr, new CCodeConstant ("%s %s".printf (left, right)));
5851 : } else {
5852 190 : var temp_value = create_temp_value (expr.value_type, false, expr);
5853 : CCodeFunctionCall ccall;
5854 :
5855 192 : if (context.profile == Profile.POSIX) {
5856 : // convert to strcat (strcpy (malloc (1 + strlen (a) + strlen (b)), a), b)
5857 2 : ccall = new CCodeFunctionCall (new CCodeIdentifier ("strcat"));
5858 2 : var strcpy = new CCodeFunctionCall (new CCodeIdentifier ("strcpy"));
5859 2 : var malloc = new CCodeFunctionCall (new CCodeIdentifier ("malloc"));
5860 :
5861 2 : var strlen_a = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
5862 2 : strlen_a.add_argument (cleft);
5863 2 : var strlen_b = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
5864 2 : strlen_b.add_argument (cright);
5865 2 : var newlength = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("1"),
5866 : new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, strlen_a, strlen_b));
5867 2 : malloc.add_argument (newlength);
5868 :
5869 2 : strcpy.add_argument (malloc);
5870 2 : strcpy.add_argument (cleft);
5871 :
5872 2 : ccall.add_argument (strcpy);
5873 2 : ccall.add_argument (cright);
5874 : } else {
5875 : // convert to g_strconcat (a, b, NULL)
5876 188 : ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
5877 188 : ccall.add_argument (cleft);
5878 188 : ccall.add_argument (cright);
5879 188 : ccall.add_argument (new CCodeConstant("NULL"));
5880 : }
5881 :
5882 190 : ccode.add_assignment (get_cvalue_ (temp_value), ccall);
5883 190 : expr.target_value = temp_value;
5884 : }
5885 195 : return;
5886 : case BinaryOperator.EQUALITY:
5887 : case BinaryOperator.INEQUALITY:
5888 : case BinaryOperator.LESS_THAN:
5889 : case BinaryOperator.GREATER_THAN:
5890 : case BinaryOperator.LESS_THAN_OR_EQUAL:
5891 : case BinaryOperator.GREATER_THAN_OR_EQUAL:
5892 : CCodeExpression call;
5893 1772 : if (context.profile == Profile.POSIX) {
5894 9 : cfile.add_include ("string.h");
5895 9 : call = new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp")));
5896 : } else {
5897 1763 : call = new CCodeIdentifier ("g_strcmp0");
5898 : }
5899 1772 : set_cvalue (expr, new CCodeBinaryCompareExpression (call, op, cleft, cright, new CCodeConstant ("0")));
5900 1772 : break;
5901 : default:
5902 0 : set_cvalue (expr, new CCodeBinaryExpression (op, cleft, cright));
5903 : break;
5904 : }
5905 : } else {
5906 6942 : set_cvalue (expr, new CCodeBinaryExpression (op, cleft, cright));
5907 : }
5908 :
5909 8714 : if (left_chain != null) {
5910 26 : set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.AND, left_chain, get_cvalue (expr)));
5911 : }
5912 : }
5913 :
5914 726 : public CCodeExpression? create_type_check (CCodeNode ccodenode, DataType type) {
5915 726 : var et = type as ErrorType;
5916 726 : if (et != null && et.error_code != null) {
5917 2 : var matches_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
5918 2 : matches_call.add_argument ((CCodeExpression) ccodenode);
5919 2 : matches_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain)));
5920 2 : matches_call.add_argument (new CCodeIdentifier (get_ccode_name (et.error_code)));
5921 2 : return matches_call;
5922 724 : } else if (et != null && et.error_domain != null) {
5923 3 : var instance_domain = new CCodeMemberAccess.pointer ((CCodeExpression) ccodenode, "domain");
5924 3 : var type_domain = new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain));
5925 3 : return new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, instance_domain, type_domain);
5926 : } else {
5927 : CCodeFunctionCall ccheck;
5928 721 : if (type is GenericType || type.type_symbol == null || type.type_symbol.external_package) {
5929 412 : ccheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
5930 412 : ccheck.add_argument ((CCodeExpression) ccodenode);
5931 412 : ccheck.add_argument (get_type_id_expression (type));
5932 : } else {
5933 309 : ccheck = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_check_function (type.type_symbol)));
5934 309 : ccheck.add_argument ((CCodeExpression) ccodenode);
5935 : }
5936 :
5937 721 : return ccheck;
5938 : }
5939 : }
5940 :
5941 32 : string generate_array_contains_wrapper (ArrayType array_type) {
5942 32 : string array_contains_func = "_vala_%s_array_contains".printf (get_ccode_lower_case_name (array_type.element_type));
5943 :
5944 32 : if (!add_wrapper (array_contains_func)) {
5945 32 : return array_contains_func;
5946 : }
5947 :
5948 16 : generate_type_declaration (ssize_t_type, cfile);
5949 :
5950 16 : var function = new CCodeFunction (array_contains_func, get_ccode_name (bool_type));
5951 16 : function.modifiers = CCodeModifiers.STATIC;
5952 :
5953 16 : function.add_parameter (new CCodeParameter ("stack", "%s *".printf (get_ccode_name (array_type.element_type))));
5954 16 : function.add_parameter (new CCodeParameter ("stack_length", get_ccode_name (ssize_t_type)));
5955 16 : if (array_type.element_type is StructValueType) {
5956 2 : function.add_parameter (new CCodeParameter ("needle", "const %s *".printf (get_ccode_name (array_type.element_type))));
5957 : } else {
5958 14 : function.add_parameter (new CCodeParameter ("needle", "const %s".printf (get_ccode_name (array_type.element_type))));
5959 : }
5960 :
5961 16 : push_function (function);
5962 :
5963 16 : ccode.add_declaration (get_ccode_name (ssize_t_type), new CCodeVariableDeclarator ("i"));
5964 :
5965 16 : var cloop_initializer = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
5966 16 : var cloop_condition = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("stack_length"));
5967 16 : var cloop_iterator = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"));
5968 16 : ccode.open_for (cloop_initializer, cloop_condition, cloop_iterator);
5969 :
5970 16 : var celement = new CCodeElementAccess (new CCodeIdentifier ("stack"), new CCodeIdentifier ("i"));
5971 16 : var cneedle = new CCodeIdentifier ("needle");
5972 : CCodeBinaryExpression cif_condition;
5973 21 : if (array_type.element_type.compatible (string_type)) {
5974 : CCodeFunctionCall ccall;
5975 5 : if (context.profile == Profile.POSIX) {
5976 0 : cfile.add_include ("string.h");
5977 0 : ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
5978 : } else {
5979 5 : ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5980 : }
5981 5 : ccall.add_argument (celement);
5982 5 : ccall.add_argument (cneedle);
5983 5 : cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("0"));
5984 13 : } else if (array_type.element_type is StructValueType) {
5985 2 : var equalfunc = generate_struct_equal_function ((Struct) array_type.element_type.type_symbol);
5986 2 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5987 2 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, celement));
5988 2 : ccall.add_argument (cneedle);
5989 2 : cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, get_boolean_cconstant (true));
5990 : } else {
5991 9 : cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cneedle, celement);
5992 : }
5993 :
5994 16 : ccode.open_if (cif_condition);
5995 16 : ccode.add_return (get_boolean_cconstant (true));
5996 16 : ccode.close ();
5997 :
5998 16 : ccode.close ();
5999 :
6000 16 : ccode.add_return (get_boolean_cconstant (false));
6001 :
6002 16 : pop_function ();
6003 :
6004 16 : cfile.add_function_declaration (function);
6005 16 : cfile.add_function (function);
6006 :
6007 16 : return array_contains_func;
6008 : }
6009 :
6010 9 : string generate_cmp_wrapper (CCodeIdentifier cmpid) {
6011 : // generate and call NULL-aware cmp function to reduce number
6012 : // of temporary variables and simplify code
6013 :
6014 9 : string cmp0_func = "_%s0".printf (cmpid.name);
6015 :
6016 : // g_strcmp0 is already NULL-safe
6017 9 : if (cmpid.name == "g_strcmp0") {
6018 0 : cmp0_func = cmpid.name;
6019 13 : } else if (add_wrapper (cmp0_func)) {
6020 4 : var cmp0_fun = new CCodeFunction (cmp0_func, get_ccode_name (int_type));
6021 4 : cmp0_fun.add_parameter (new CCodeParameter ("s1", "const void *"));
6022 4 : cmp0_fun.add_parameter (new CCodeParameter ("s2", "const void *"));
6023 4 : cmp0_fun.modifiers = CCodeModifiers.STATIC;
6024 :
6025 4 : push_function (cmp0_fun);
6026 :
6027 : // s1 != s2;
6028 4 : var noteq = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
6029 :
6030 : // if (!s1) return -(s1 != s2);
6031 4 : {
6032 4 : var cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("s1"));
6033 4 : ccode.open_if (cexp);
6034 4 : ccode.add_return (new CCodeUnaryExpression (CCodeUnaryOperator.MINUS, noteq));
6035 4 : ccode.close ();
6036 : }
6037 : // if (!s2) return s1 != s2;
6038 4 : {
6039 4 : var cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("s2"));
6040 4 : ccode.open_if (cexp);
6041 4 : ccode.add_return (noteq);
6042 4 : ccode.close ();
6043 : }
6044 : // return strcmp (s1, s2);
6045 4 : var cmp_call = new CCodeFunctionCall (cmpid);
6046 4 : cmp_call.add_argument (new CCodeIdentifier ("s1"));
6047 4 : cmp_call.add_argument (new CCodeIdentifier ("s2"));
6048 4 : ccode.add_return (cmp_call);
6049 :
6050 4 : pop_function ();
6051 :
6052 4 : cfile.add_function (cmp0_fun);
6053 : }
6054 :
6055 : return cmp0_func;
6056 : }
6057 :
6058 992 : public override void visit_type_check (TypeCheck expr) {
6059 496 : generate_type_declaration (expr.type_reference, cfile);
6060 :
6061 496 : var type = expr.expression.value_type;
6062 496 : var pointer_type = type as PointerType;
6063 0 : if (pointer_type != null) {
6064 0 : type = pointer_type.base_type;
6065 : }
6066 496 : unowned Class? cl = type.type_symbol as Class;
6067 496 : unowned Interface? iface = type.type_symbol as Interface;
6068 496 : if ((cl != null && !cl.is_compact) || iface != null || type is GenericType || type is ErrorType) {
6069 495 : set_cvalue (expr, create_type_check (get_cvalue (expr.expression), expr.type_reference));
6070 : } else {
6071 1 : set_cvalue (expr, new CCodeInvalidExpression ());
6072 : }
6073 :
6074 496 : if (get_cvalue (expr) is CCodeInvalidExpression) {
6075 1 : Report.error (expr.source_reference, "type check expressions not supported for compact classes, structs, and enums");
6076 : }
6077 : }
6078 :
6079 706 : public override void visit_lambda_expression (LambdaExpression lambda) {
6080 353 : var delegate_type = (DelegateType) lambda.target_type;
6081 :
6082 353 : lambda.accept_children (this);
6083 :
6084 353 : bool expr_owned = lambda.value_type.value_owned;
6085 :
6086 353 : set_cvalue (lambda, new CCodeIdentifier (get_ccode_name (lambda.method)));
6087 :
6088 : unowned DataType? this_type;
6089 447 : if (lambda.method.closure) {
6090 94 : int block_id = get_block_id (current_closure_block);
6091 94 : var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
6092 169 : if (expr_owned || delegate_type.is_called_once) {
6093 75 : var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
6094 75 : ref_call.add_argument (delegate_target);
6095 150 : delegate_target = ref_call;
6096 75 : set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
6097 : } else {
6098 19 : set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
6099 : }
6100 94 : set_delegate_target (lambda, delegate_target);
6101 442 : } else if ((this_type = get_this_type ()) != null) {
6102 183 : CCodeExpression delegate_target = get_this_cexpression ();
6103 183 : delegate_target = convert_to_generic_pointer (delegate_target, this_type);
6104 210 : if (expr_owned || delegate_type.is_called_once) {
6105 27 : var ref_call = new CCodeFunctionCall (get_dup_func_expression (this_type, lambda.source_reference));
6106 27 : ref_call.add_argument (delegate_target);
6107 54 : delegate_target = ref_call;
6108 27 : set_delegate_target_destroy_notify (lambda, get_destroy_func_expression (this_type));
6109 : } else {
6110 156 : set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
6111 : }
6112 183 : set_delegate_target (lambda, delegate_target);
6113 : } else {
6114 76 : set_delegate_target (lambda, new CCodeConstant ("NULL"));
6115 76 : set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
6116 : }
6117 : }
6118 :
6119 789 : public CCodeExpression convert_from_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
6120 789 : unowned SemanticAnalyzer analyzer = context.analyzer;
6121 789 : var result = cexpr;
6122 789 : if (analyzer.is_reference_type_argument (actual_type) || analyzer.is_nullable_value_type_argument (actual_type)) {
6123 733 : generate_type_declaration (actual_type, cfile);
6124 733 : result = new CCodeCastExpression (cexpr, get_ccode_name (actual_type));
6125 56 : } else if (analyzer.is_signed_integer_type_argument (actual_type)) {
6126 : // FIXME this should not happen
6127 40 : while (cexpr is CCodeCastExpression) {
6128 0 : cexpr = ((CCodeCastExpression) cexpr).inner;
6129 : }
6130 40 : result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), get_ccode_name (actual_type));
6131 16 : } else if (analyzer.is_unsigned_integer_type_argument (actual_type)) {
6132 : // FIXME this should not happen
6133 7 : while (cexpr is CCodeCastExpression) {
6134 0 : cexpr = ((CCodeCastExpression) cexpr).inner;
6135 : }
6136 7 : result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), get_ccode_name (actual_type));
6137 : }
6138 : return result;
6139 : }
6140 :
6141 1265 : public CCodeExpression convert_to_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
6142 1265 : unowned SemanticAnalyzer analyzer = context.analyzer;
6143 1265 : var result = cexpr;
6144 1265 : if (analyzer.is_signed_integer_type_argument (actual_type)) {
6145 : // FIXME this should not happen
6146 202 : while (cexpr is CCodeCastExpression) {
6147 2 : cexpr = ((CCodeCastExpression) cexpr).inner;
6148 : }
6149 200 : result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), get_ccode_name (pointer_type));
6150 1065 : } else if (analyzer.is_unsigned_integer_type_argument (actual_type)) {
6151 : // FIXME this should not happen
6152 9 : while (cexpr is CCodeCastExpression) {
6153 3 : cexpr = ((CCodeCastExpression) cexpr).inner;
6154 : }
6155 6 : result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), get_ccode_name (pointer_type));
6156 : }
6157 : return result;
6158 : }
6159 :
6160 1465 : int next_variant_function_id = 0;
6161 :
6162 116215 : public TargetValue transform_value (TargetValue value, DataType? target_type, CodeNode node) {
6163 116215 : var type = value.value_type;
6164 116215 : var result = ((GLibValue) value).copy ();
6165 :
6166 116259 : if (type.value_owned
6167 11080 : && (target_type == null || target_type is GenericType || !target_type.floating_reference)
6168 11075 : && type.floating_reference) {
6169 : /* floating reference, sink it.
6170 : */
6171 44 : unowned ObjectTypeSymbol? cl = type.type_symbol as ObjectTypeSymbol;
6172 44 : var sink_func = (cl != null) ? get_ccode_ref_sink_function (cl) : "";
6173 :
6174 88 : if (sink_func != "") {
6175 53 : if (type.nullable) {
6176 9 : var is_not_null = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, result.cvalue, new CCodeConstant ("NULL"));
6177 9 : ccode.open_if (is_not_null);
6178 : }
6179 :
6180 44 : var csink = new CCodeFunctionCall (new CCodeIdentifier (sink_func));
6181 44 : csink.add_argument (result.cvalue);
6182 44 : ccode.add_expression (csink);
6183 :
6184 44 : if (type.nullable) {
6185 9 : ccode.close ();
6186 : }
6187 : } else {
6188 0 : Report.error (node.source_reference, "type `%s' does not support floating references", type.type_symbol.name);
6189 : }
6190 : }
6191 :
6192 116215 : bool boxing = (type is ValueType && !type.nullable
6193 37676 : && target_type is ValueType && target_type.nullable);
6194 116215 : bool unboxing = (type is ValueType && type.nullable
6195 392 : && target_type is ValueType && !target_type.nullable);
6196 :
6197 116215 : bool gvalue_boxing = (context.profile == Profile.GOBJECT
6198 115283 : && target_type != null
6199 89483 : && target_type.type_symbol == gvalue_type
6200 198 : && !(type is NullType)
6201 197 : && get_ccode_type_id (type) != "G_TYPE_VALUE");
6202 116215 : bool gvariant_boxing = (context.profile == Profile.GOBJECT
6203 115283 : && target_type != null
6204 89483 : && target_type.type_symbol == gvariant_type
6205 230 : && !(type is NullType)
6206 226 : && type.type_symbol != gvariant_type);
6207 :
6208 116215 : if (type.value_owned
6209 11080 : && (target_type == null || !target_type.value_owned || boxing || unboxing || gvariant_boxing)
6210 5042 : && !gvalue_boxing /* gvalue can assume ownership of value, no need to free it */) {
6211 : // value leaked, destroy it
6212 5041 : if (target_type is PointerType) {
6213 : // manual memory management for pointers
6214 5030 : } else if (requires_destroy (type)) {
6215 5903 : if (!is_lvalue_access_allowed (type)) {
6216 : // cannot assign to a temporary variable
6217 1 : temp_ref_values.insert (0, result.copy ());
6218 : } else {
6219 2951 : var temp_value = create_temp_value (type, false, node);
6220 2951 : temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
6221 2951 : store_value (temp_value, result, node.source_reference);
6222 5902 : result.cvalue = get_cvalue_ (temp_value);
6223 : }
6224 : }
6225 : }
6226 :
6227 116215 : if (target_type == null) {
6228 : // value will be destroyed, no need for implicit casts
6229 26190 : return result;
6230 : }
6231 :
6232 90025 : result.value_type = target_type.copy ();
6233 :
6234 90106 : if (gvalue_boxing) {
6235 : // implicit conversion to GValue
6236 81 : var temp_value = create_temp_value (target_type, true, node, true);
6237 :
6238 81 : if (!target_type.value_owned) {
6239 : // boxed GValue leaked, destroy it
6240 13 : temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
6241 : }
6242 :
6243 116 : if (target_type.nullable) {
6244 35 : var newcall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
6245 35 : newcall.add_argument (new CCodeConstant ("GValue"));
6246 35 : newcall.add_argument (new CCodeConstant ("1"));
6247 35 : var newassignment = new CCodeAssignment (get_cvalue_ (temp_value), newcall);
6248 35 : ccode.add_expression (newassignment);
6249 : }
6250 :
6251 81 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
6252 81 : if (target_type.nullable) {
6253 35 : ccall.add_argument (get_cvalue_ (temp_value));
6254 : } else {
6255 46 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
6256 : }
6257 81 : var type_id = get_ccode_type_id (type);
6258 81 : if (type_id == "") {
6259 0 : Report.error (node.source_reference, "GValue boxing of type `%s' is not supported", type.to_string ());
6260 : }
6261 81 : ccall.add_argument (new CCodeIdentifier (type_id));
6262 81 : ccode.add_expression (ccall);
6263 :
6264 81 : if (requires_destroy (type)) {
6265 1 : ccall = new CCodeFunctionCall (get_value_taker_function (type));
6266 : } else {
6267 80 : ccall = new CCodeFunctionCall (get_value_setter_function (type));
6268 : }
6269 81 : if (target_type.nullable) {
6270 35 : ccall.add_argument (get_cvalue_ (temp_value));
6271 : } else {
6272 46 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
6273 : }
6274 81 : if (type.is_real_non_null_struct_type ()) {
6275 3 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue));
6276 : } else {
6277 78 : ccall.add_argument (result.cvalue);
6278 : }
6279 :
6280 81 : ccode.add_expression (ccall);
6281 :
6282 162 : result = (GLibValue) temp_value;
6283 89978 : } else if (gvariant_boxing) {
6284 : // implicit conversion to GVariant
6285 34 : string variant_func = "_variant_new%d".printf (++next_variant_function_id);
6286 :
6287 34 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
6288 34 : ccall.add_argument (result.cvalue);
6289 :
6290 34 : var cfunc = new CCodeFunction (variant_func, "GVariant*");
6291 34 : cfunc.modifiers = CCodeModifiers.STATIC;
6292 34 : cfunc.add_parameter (new CCodeParameter ("value", get_ccode_name (type)));
6293 :
6294 45 : if (type is ArrayType) {
6295 : // return array length if appropriate
6296 11 : var array_type = (ArrayType) type;
6297 11 : var length_ctype = get_ccode_array_length_type (array_type);
6298 26 : for (int dim = 1; dim <= array_type.rank; dim++) {
6299 15 : ccall.add_argument (get_array_length_cvalue (value, dim));
6300 15 : cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), length_ctype));
6301 : }
6302 : }
6303 :
6304 34 : push_function (cfunc);
6305 :
6306 : // sink floating reference
6307 34 : var sink = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_ref_sink"));
6308 34 : sink.add_argument (serialize_expression (type, new CCodeIdentifier ("value")));
6309 34 : ccode.add_return (sink);
6310 :
6311 34 : pop_function ();
6312 :
6313 34 : cfile.add_function_declaration (cfunc);
6314 34 : cfile.add_function (cfunc);
6315 :
6316 68 : result.cvalue = ccall;
6317 34 : result.value_type.value_owned = true;
6318 :
6319 34 : result = (GLibValue) store_temp_value (result, node);
6320 34 : if (!target_type.value_owned) {
6321 : // value leaked
6322 13 : temp_ref_values.insert (0, ((GLibValue) result).copy ());
6323 : }
6324 89910 : } else if (boxing) {
6325 : // value needs to be boxed
6326 :
6327 420 : result.value_type.nullable = false;
6328 420 : if (!result.lvalue || !result.value_type.equals (value.value_type)) {
6329 328 : result.cvalue = get_implicit_cast_expression (result.cvalue, value.value_type, result.value_type, node);
6330 328 : if (!(result.cvalue is CCodeConstantIdentifier)) {
6331 327 : result = (GLibValue) store_temp_value (result, node);
6332 : }
6333 : }
6334 420 : result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue);
6335 420 : result.lvalue = false;
6336 420 : result.value_type.nullable = true;
6337 178862 : } else if (unboxing) {
6338 : // unbox value
6339 :
6340 118 : result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result.cvalue);
6341 : } else {
6342 : // TODO: rewrite get_implicit_cast_expression to return a GLibValue
6343 89372 : var old_cexpr = result.cvalue;
6344 89372 : result.cvalue = get_implicit_cast_expression (result.cvalue, type, target_type, node);
6345 89372 : result.lvalue = result.lvalue && result.cvalue == old_cexpr;
6346 : }
6347 :
6348 90025 : bool array_needs_copy = false;
6349 92362 : if (type is ArrayType && target_type is ArrayType) {
6350 2337 : var array = (ArrayType) type;
6351 2337 : var target_array = (ArrayType) target_type;
6352 2337 : if (target_array.element_type.value_owned && !array.element_type.value_owned) {
6353 24 : array_needs_copy = requires_copy (target_array.element_type);
6354 : }
6355 : }
6356 :
6357 92840 : if (!gvalue_boxing && !gvariant_boxing && target_type.value_owned && (!type.value_owned || boxing || unboxing || array_needs_copy) && requires_copy (target_type) && !(type is NullType)) {
6358 : // need to copy value
6359 2815 : var copy = (GLibValue) copy_value (result, node);
6360 :
6361 : // need to free old array after copying it
6362 2815 : if (array_needs_copy && requires_destroy (type)) {
6363 1 : result.value_type = type.copy ();
6364 1 : ccode.add_expression (destroy_value (result));
6365 : }
6366 5630 : result = copy;
6367 :
6368 : // implicit array copying is deprecated, but allow it for internal codegen usage
6369 2815 : var prop_acc = node as PropertyAccessor;
6370 2815 : if ((prop_acc != null && !prop_acc.automatic_body)
6371 0 : && result.value_type is ArrayType) {
6372 0 : Report.deprecated (node.source_reference, "implicit copy of array is deprecated, explicitly invoke the copy method instead");
6373 : }
6374 : }
6375 :
6376 90025 : return result;
6377 : }
6378 :
6379 178871 : public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, CodeNode? node) {
6380 89171 : var cexpr = source_cexpr;
6381 :
6382 89171 : if (expression_type.type_symbol != null && expression_type.type_symbol == target_type.type_symbol) {
6383 : // same type, no cast required
6384 80044 : return cexpr;
6385 : }
6386 :
6387 16334 : if (expression_type is NullType) {
6388 : // null literal, no cast required when not converting to generic type pointer
6389 80044 : return cexpr;
6390 : }
6391 :
6392 12850 : generate_type_declaration (target_type, cfile);
6393 :
6394 12850 : unowned Class? cl = target_type.type_symbol as Class;
6395 12850 : unowned Interface? iface = target_type.type_symbol as Interface;
6396 12850 : if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
6397 : // checked cast for strict subtypes of GTypeInstance
6398 608 : return generate_instance_cast (cexpr, target_type.type_symbol);
6399 12242 : } else if (target_type.type_symbol != null && get_ccode_name (expression_type) != get_ccode_name (target_type)) {
6400 8820 : unowned Struct? st = target_type.type_symbol as Struct;
6401 8820 : if (target_type.type_symbol.is_reference_type () || (st != null && st.is_simple_type ())) {
6402 : // don't cast non-simple structs
6403 8519 : return new CCodeCastExpression (cexpr, get_ccode_name (target_type));
6404 : } else {
6405 301 : return cexpr;
6406 : }
6407 : } else {
6408 3422 : return cexpr;
6409 : }
6410 : }
6411 :
6412 1665 : public void store_property (Property prop, Expression? instance, TargetValue value) {
6413 837 : unowned Property base_prop = prop;
6414 837 : if (prop.base_property != null) {
6415 24 : base_prop = prop.base_property;
6416 813 : } else if (prop.base_interface_property != null) {
6417 57 : base_prop = prop.base_interface_property;
6418 : }
6419 837 : if (instance is BaseAccess && (base_prop.is_abstract || base_prop.is_virtual)) {
6420 9 : CCodeExpression? vcast = null;
6421 9 : if (base_prop.parent_symbol is Class) {
6422 7 : unowned Class base_class = (Class) base_prop.parent_symbol;
6423 7 : vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
6424 7 : ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
6425 2 : } else if (base_prop.parent_symbol is Interface) {
6426 2 : unowned Interface base_iface = (Interface) base_prop.parent_symbol;
6427 2 : vcast = get_this_interface_cexpression (base_iface);
6428 : }
6429 18 : if (vcast != null) {
6430 9 : var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
6431 9 : ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
6432 9 : var cexpr = get_cvalue_ (value);
6433 9 : if (prop.property_type.is_real_non_null_struct_type ()) {
6434 : //TODO Make use of get_lvalue (value)
6435 11 : if (!(cexpr is CCodeConstant || cexpr is CCodeIdentifier)) {
6436 3 : var temp_value = store_temp_value (value, instance);
6437 6 : cexpr = get_cvalue_ (temp_value);
6438 : }
6439 8 : cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6440 : }
6441 9 : ccall.add_argument (cexpr);
6442 :
6443 9 : ccode.add_expression (ccall);
6444 : } else {
6445 0 : Report.error (instance.source_reference, "internal: Invalid assignment to `%s'", base_prop.get_full_name ());
6446 : }
6447 9 : return;
6448 : }
6449 :
6450 828 : var set_func = "g_object_set";
6451 :
6452 828 : if (!get_ccode_no_accessor_method (prop) && !(prop is DynamicProperty)) {
6453 821 : generate_property_accessor_declaration (base_prop.set_accessor, cfile);
6454 821 : set_func = get_ccode_name (base_prop.set_accessor);
6455 :
6456 821 : if (!prop.external && prop.external_package) {
6457 : // internal VAPI properties
6458 : // only add them once per source file
6459 2 : if (add_generated_external_symbol (prop)) {
6460 0 : visit_property (prop);
6461 : }
6462 : }
6463 : }
6464 :
6465 828 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
6466 :
6467 1649 : if (prop.binding == MemberBinding.INSTANCE) {
6468 : /* target instance is first argument */
6469 821 : var cinstance = (CCodeExpression) get_ccodenode (instance);
6470 :
6471 824 : if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
6472 : // we need to pass struct instance by reference if it isn't a simple-type
6473 3 : var instance_value = instance.target_value;
6474 3 : if (!get_lvalue (instance_value)) {
6475 0 : instance_value = store_temp_value (instance_value, instance);
6476 : }
6477 3 : cinstance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
6478 : }
6479 :
6480 821 : ccall.add_argument (cinstance);
6481 : }
6482 :
6483 828 : if (get_ccode_no_accessor_method (prop) || prop is DynamicProperty) {
6484 : /* property name is second argument of g_object_set */
6485 7 : ccall.add_argument (get_property_canonical_cconstant (prop));
6486 : }
6487 :
6488 828 : var cexpr = get_cvalue_ (value);
6489 :
6490 828 : if (prop.property_type.is_real_non_null_struct_type ()) {
6491 : //TODO Make use of get_lvalue (value)
6492 26 : if (!(cexpr is CCodeConstant || cexpr is CCodeIdentifier)) {
6493 3 : var temp_value = store_temp_value (value, instance);
6494 6 : cexpr = get_cvalue_ (temp_value);
6495 : }
6496 23 : cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6497 : }
6498 :
6499 828 : var array_type = prop.property_type as ArrayType;
6500 :
6501 828 : ccall.add_argument (cexpr);
6502 :
6503 828 : if (array_type != null && get_ccode_array_length (prop)) {
6504 50 : for (int dim = 1; dim <= array_type.rank; dim++) {
6505 25 : ccall.add_argument (get_array_length_cvalue (value, dim));
6506 : }
6507 817 : } else if (prop.property_type is DelegateType) {
6508 14 : var delegate_type = (DelegateType) prop.property_type;
6509 14 : if (get_ccode_delegate_target (prop) && delegate_type.delegate_symbol.has_target) {
6510 9 : ccall.add_argument (get_delegate_target_cvalue (value));
6511 9 : if (base_prop.set_accessor.value_type.value_owned) {
6512 4 : ccall.add_argument (get_delegate_target_destroy_notify_cvalue (value));
6513 : }
6514 : }
6515 : }
6516 :
6517 828 : if (get_ccode_no_accessor_method (prop) || prop is DynamicProperty) {
6518 7 : ccall.add_argument (new CCodeConstant ("NULL"));
6519 : }
6520 :
6521 828 : ccode.add_expression (ccall);
6522 : }
6523 :
6524 12015 : public bool add_wrapper (string wrapper_name) {
6525 12015 : return wrappers.add (wrapper_name);
6526 : }
6527 :
6528 730 : public bool add_generated_external_symbol (Symbol external_symbol) {
6529 730 : return generated_external_symbols.add (external_symbol);
6530 : }
6531 :
6532 23608 : public static DataType get_callable_creturn_type (Callable c) {
6533 23608 : assert (c is Method || c is Delegate);
6534 23608 : var creturn_type = c.return_type.copy ();
6535 23608 : if (c is CreationMethod) {
6536 5876 : unowned Class? cl = c.parent_symbol as Class;
6537 5876 : unowned Struct? st = c.parent_symbol as Struct;
6538 5876 : if (cl != null) {
6539 : // object creation methods return the new object in C
6540 : // in Vala they have no return type
6541 5738 : creturn_type = new ObjectType (cl);
6542 138 : } else if (st != null && st.is_simple_type ()) {
6543 : // constructors return simple type structs by value
6544 4 : creturn_type = new StructValueType (st);
6545 : }
6546 17732 : } else if (c.return_type.is_real_non_null_struct_type ()) {
6547 : // structs are returned via out parameter
6548 106 : creturn_type = new VoidType ();
6549 : }
6550 : return creturn_type;
6551 : }
6552 :
6553 12110 : public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression, bool on_error = false) {
6554 12110 : unowned Struct? st = type.type_symbol as Struct;
6555 12110 : var array_type = type as ArrayType;
6556 19426 : if (type.type_symbol != null && !type.nullable
6557 7316 : && (on_error ? get_ccode_default_value_on_error (type.type_symbol) : get_ccode_default_value (type.type_symbol)) != "") {
6558 4207 : CCodeExpression val = new CCodeConstant (on_error ? get_ccode_default_value_on_error (type.type_symbol) : get_ccode_default_value (type.type_symbol));
6559 4207 : if (st != null && st.get_fields ().size > 0) {
6560 2 : val = new CCodeCastExpression (val, get_ccode_name (st));
6561 : }
6562 4207 : return val;
6563 7903 : } else if (initializer_expression && !type.nullable &&
6564 2745 : (st != null || (array_type != null && array_type.fixed_length))) {
6565 : // 0-initialize struct with struct initializer { 0 }
6566 : // only allowed as initializer expression in C
6567 682 : var clist = new CCodeInitializerList ();
6568 682 : clist.append (new CCodeConstant ("0"));
6569 682 : return clist;
6570 7221 : } else if ((type.type_symbol != null && type.type_symbol.is_reference_type ())
6571 2181 : || type.nullable
6572 1471 : || type is PointerType || type is DelegateType
6573 1296 : || (array_type != null && !array_type.fixed_length)) {
6574 6318 : return new CCodeConstant ("NULL");
6575 903 : } else if (type is GenericType) {
6576 46 : return new CCodeConstant ("NULL");
6577 857 : } else if (type is ErrorType) {
6578 37 : return new CCodeConstant ("NULL");
6579 820 : } else if (type is CType) {
6580 161 : return new CCodeConstant (((CType) type).cdefault_value);
6581 : }
6582 659 : return null;
6583 : }
6584 :
6585 795 : private void create_property_type_check_statement (Property prop, bool check_return_type, TypeSymbol t, bool non_null, string var_name) {
6586 795 : if (check_return_type) {
6587 406 : create_type_check_statement (prop, prop.property_type, t, non_null, var_name);
6588 : } else {
6589 389 : create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
6590 : }
6591 : }
6592 :
6593 4435 : public virtual void create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
6594 : }
6595 :
6596 73306 : public int get_param_pos (double param_pos, bool ellipsis = false) {
6597 73306 : if (!ellipsis) {
6598 71229 : if (param_pos >= 0) {
6599 64388 : return (int) (param_pos * 1000);
6600 : } else {
6601 6841 : return (int) ((100 + param_pos) * 1000);
6602 : }
6603 : } else {
6604 2077 : if (param_pos >= 0) {
6605 1554 : return (int) ((100 + param_pos) * 1000);
6606 : } else {
6607 523 : return (int) ((200 + param_pos) * 1000);
6608 : }
6609 : }
6610 : }
6611 :
6612 11488 : public CCodeExpression? get_ccodenode (Expression node) {
6613 11488 : if (get_cvalue (node) == null) {
6614 94 : node.emit (this);
6615 : }
6616 11488 : return get_cvalue (node);
6617 : }
6618 :
6619 42685 : public bool is_lvalue_access_allowed (DataType type) {
6620 42685 : var array_type = type as ArrayType;
6621 2597 : if (array_type != null && array_type.inline_allocated) {
6622 132 : return false;
6623 : }
6624 42553 : if (type.type_symbol != null) {
6625 39803 : return type.type_symbol.get_attribute_bool ("CCode", "lvalue_access", true);
6626 : }
6627 2750 : return true;
6628 : }
6629 :
6630 8614 : public bool requires_memset_init (Variable variable, out CCodeExpression? size) {
6631 8614 : unowned ArrayType? array_type = variable.variable_type as ArrayType;
6632 621 : if (array_type != null && array_type.fixed_length) {
6633 62 : var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
6634 62 : sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
6635 62 : size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call);
6636 62 : return !is_constant_ccode (array_type.length);
6637 : }
6638 8552 : size = null;
6639 8552 : return false;
6640 : }
6641 :
6642 56467 : public CCodeDeclaratorSuffix? get_ccode_declarator_suffix (DataType type) {
6643 56467 : var array_type = type as ArrayType;
6644 4698 : if (array_type != null) {
6645 4698 : if (array_type.fixed_length) {
6646 158 : return new CCodeDeclaratorSuffix.with_array (get_ccodenode (array_type.length));
6647 4540 : } else if (array_type.inline_allocated) {
6648 0 : return new CCodeDeclaratorSuffix.with_array ();
6649 : }
6650 : }
6651 4540 : return null;
6652 : }
6653 :
6654 124 : public CCodeConstant get_signal_canonical_constant (Signal sig, string? detail = null) {
6655 124 : return new CCodeConstant ("\"%s%s\"".printf (get_ccode_name (sig), (detail != null ? "::%s".printf (detail) : "")));
6656 : }
6657 :
6658 406 : public CCodeConstant get_property_canonical_cconstant (Property prop) {
6659 406 : return new CCodeConstant ("\"%s\"".printf (get_ccode_name (prop)));
6660 : }
6661 :
6662 0 : public override void visit_class (Class cl) {
6663 : }
6664 :
6665 48 : public void create_postcondition_statement (Expression postcondition) {
6666 24 : var cassert = new CCodeFunctionCall (new CCodeIdentifier ("_vala_warn_if_fail"));
6667 :
6668 24 : postcondition.emit (this);
6669 :
6670 24 : string message = ((string) postcondition.source_reference.begin.pos).substring (0, (int) (postcondition.source_reference.end.pos - postcondition.source_reference.begin.pos));
6671 24 : cassert.add_argument (get_cvalue (postcondition));
6672 24 : cassert.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
6673 24 : requires_assert = true;
6674 :
6675 24 : ccode.add_expression (cassert);
6676 :
6677 24 : foreach (var value in temp_ref_values) {
6678 0 : ccode.add_expression (destroy_value (value));
6679 : }
6680 :
6681 24 : temp_ref_values.clear ();
6682 : }
6683 :
6684 719 : public unowned DataType? get_this_type () {
6685 719 : if (current_method != null && current_method.binding == MemberBinding.INSTANCE) {
6686 332 : return current_method.this_parameter.variable_type;
6687 387 : } else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) {
6688 4 : return current_property_accessor.prop.this_parameter.variable_type;
6689 383 : } else if (current_constructor != null && current_constructor.binding == MemberBinding.INSTANCE) {
6690 1 : return current_constructor.this_parameter.variable_type;
6691 382 : } else if (current_destructor != null && current_destructor.binding == MemberBinding.INSTANCE) {
6692 4 : return current_destructor.this_parameter.variable_type;
6693 : }
6694 719 : return null;
6695 : }
6696 :
6697 2810 : public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
6698 2810 : var result = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_CAST"));
6699 2810 : result.add_argument (expr);
6700 2810 : result.add_argument (new CCodeIdentifier (get_ccode_type_id (type)));
6701 2810 : result.add_argument (new CCodeIdentifier (get_ccode_name (type)));
6702 2810 : return result;
6703 : }
6704 :
6705 0 : void generate_struct_destroy_function (Struct st) {
6706 0 : if (cfile.add_declaration (get_ccode_destroy_function (st))) {
6707 : // only generate function once per source file
6708 : return;
6709 : }
6710 :
6711 0 : var function = new CCodeFunction (get_ccode_destroy_function (st), "void");
6712 0 : function.modifiers = CCodeModifiers.STATIC;
6713 0 : function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (st))));
6714 :
6715 0 : push_context (new EmitContext ());
6716 0 : push_function (function);
6717 :
6718 0 : var this_value = load_this_parameter (st);
6719 0 : foreach (Field f in st.get_fields ()) {
6720 0 : if (f.binding == MemberBinding.INSTANCE) {
6721 0 : if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_destroy (f.variable_type)) {
6722 0 : ccode.add_expression (destroy_field (f, this_value));
6723 : }
6724 : }
6725 : }
6726 :
6727 0 : pop_function ();
6728 0 : pop_context ();
6729 :
6730 0 : cfile.add_function_declaration (function);
6731 0 : cfile.add_function (function);
6732 : }
6733 :
6734 0 : void generate_struct_copy_function (Struct st) {
6735 0 : if (cfile.add_declaration (get_ccode_copy_function (st))) {
6736 : // only generate function once per source file
6737 : return;
6738 : }
6739 :
6740 0 : var function = new CCodeFunction (get_ccode_copy_function (st), "void");
6741 0 : function.modifiers = CCodeModifiers.STATIC;
6742 0 : function.add_parameter (new CCodeParameter ("self", "const %s *".printf (get_ccode_name (st))));
6743 0 : function.add_parameter (new CCodeParameter ("dest", "%s *".printf (get_ccode_name (st))));
6744 :
6745 0 : push_context (new EmitContext ());
6746 0 : push_function (function);
6747 :
6748 0 : var dest_struct = new GLibValue (SemanticAnalyzer.get_data_type_for_symbol (st), new CCodeIdentifier ("(*dest)"), true);
6749 0 : foreach (Field f in st.get_fields ()) {
6750 0 : if (f.binding == MemberBinding.INSTANCE) {
6751 0 : var value = load_field (f, load_this_parameter ((TypeSymbol) st));
6752 0 : if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_copy (f.variable_type)) {
6753 0 : value = copy_value (value, f);
6754 0 : if (value == null) {
6755 : // error case, continue to avoid critical
6756 0 : continue;
6757 : }
6758 : }
6759 0 : store_field (f, dest_struct, value, false);
6760 : }
6761 : }
6762 :
6763 0 : pop_function ();
6764 0 : pop_context ();
6765 :
6766 0 : cfile.add_function_declaration (function);
6767 0 : cfile.add_function (function);
6768 : }
6769 :
6770 906 : public void return_default_value (DataType return_type, bool on_error = false) {
6771 906 : unowned Struct? st = return_type.type_symbol as Struct;
6772 1067 : if (st != null && st.is_simple_type () && !return_type.nullable) {
6773 : // 0-initialize struct with struct initializer { 0 }
6774 : // only allowed as initializer expression in C
6775 161 : var ret_temp_var = get_temp_variable (return_type, true, null, true);
6776 161 : emit_temp_var (ret_temp_var, on_error);
6777 161 : ccode.add_return (new CCodeIdentifier (ret_temp_var.name));
6778 : } else {
6779 745 : ccode.add_return (default_value_for_type (return_type, false, on_error));
6780 : }
6781 : }
6782 :
6783 1 : public virtual void generate_dynamic_method_wrapper (DynamicMethod method) {
6784 : }
6785 :
6786 632 : public virtual CCodeExpression get_param_spec_cexpression (Property prop) {
6787 0 : return new CCodeInvalidExpression ();
6788 : }
6789 :
6790 371 : public virtual CCodeExpression get_param_spec (Property prop) {
6791 0 : return new CCodeInvalidExpression ();
6792 : }
6793 :
6794 87 : public virtual CCodeExpression get_signal_creation (Signal sig, ObjectTypeSymbol type) {
6795 0 : return new CCodeInvalidExpression ();
6796 : }
6797 :
6798 92 : public virtual CCodeExpression get_value_getter_function (DataType type_reference) {
6799 0 : return new CCodeInvalidExpression ();
6800 : }
6801 :
6802 419 : public virtual CCodeExpression get_value_setter_function (DataType type_reference) {
6803 0 : return new CCodeInvalidExpression ();
6804 : }
6805 :
6806 24 : public virtual CCodeExpression get_value_taker_function (DataType type_reference) {
6807 0 : return new CCodeInvalidExpression ();
6808 : }
6809 :
6810 851 : public virtual void register_dbus_info (CCodeBlock block, ObjectTypeSymbol bindable) {
6811 : }
6812 :
6813 6 : public virtual string get_dynamic_signal_cname (DynamicSignal node) {
6814 0 : return "";
6815 : }
6816 :
6817 10237 : public virtual string get_array_length_cname (string array_cname, int dim) {
6818 0 : return "";
6819 : }
6820 :
6821 2058 : public virtual string get_variable_array_length_cname (Variable variable, int dim) {
6822 0 : return "";
6823 : }
6824 :
6825 1438 : public virtual CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
6826 0 : return new CCodeInvalidExpression ();
6827 : }
6828 :
6829 8278 : public virtual CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
6830 0 : return new CCodeInvalidExpression ();
6831 : }
6832 :
6833 5354 : public virtual string get_array_size_cname (string array_cname) {
6834 0 : return "";
6835 : }
6836 :
6837 729 : public virtual void add_simple_check (CodeNode node, bool always_fails = false) {
6838 : }
6839 :
6840 52 : public virtual string generate_ready_function (Method m) {
6841 0 : return "";
6842 : }
6843 :
6844 4106 : public CCodeExpression get_boolean_cconstant (bool b) {
6845 4106 : if (context.profile == Profile.GOBJECT) {
6846 4087 : cfile.add_include ("glib.h");
6847 4087 : return new CCodeConstant (b ? "TRUE" : "FALSE");
6848 : } else {
6849 19 : cfile.add_include ("stdbool.h");
6850 19 : return new CCodeConstant (b ? "true" : "false");
6851 : }
6852 : }
6853 : }
|