codegen: Fix floating reference regression with Variants
[vala-gnome.git] / codegen / valaccodebasemodule.vala
blob2da65098a262fb4be52f469fef42f4bb9236588c
1 /* valaccodebasemodule.vala
3 * Copyright (C) 2006-2012 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 /**
27 * Code visitor generating C Code.
29 public abstract class Vala.CCodeBaseModule : CodeGenerator {
30 public class EmitContext {
31 public Symbol? current_symbol;
32 public ArrayList<Symbol> symbol_stack = new ArrayList<Symbol> ();
33 public TryStatement current_try;
34 public CatchClause current_catch;
35 public CCodeFunction ccode;
36 public ArrayList<CCodeFunction> ccode_stack = new ArrayList<CCodeFunction> ();
37 public ArrayList<TargetValue> temp_ref_values = new ArrayList<TargetValue> ();
38 public int next_temp_var_id;
39 public bool current_method_inner_error;
40 public bool current_method_return;
41 public int next_coroutine_state = 1;
42 public Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
43 public Map<string,int> closure_variable_count_map = new HashMap<string,int> (str_hash, str_equal);
44 public Map<LocalVariable,int> closure_variable_clash_map = new HashMap<LocalVariable,int> ();
46 public EmitContext (Symbol? symbol = null) {
47 current_symbol = symbol;
50 public void push_symbol (Symbol symbol) {
51 symbol_stack.add (current_symbol);
52 current_symbol = symbol;
55 public void pop_symbol () {
56 current_symbol = symbol_stack.remove_at (symbol_stack.size - 1);
60 public CodeContext context { get; set; }
62 public Symbol root_symbol;
64 public EmitContext emit_context = new EmitContext ();
66 List<EmitContext> emit_context_stack = new ArrayList<EmitContext> ();
68 public CCodeLineDirective? current_line = null;
70 List<CCodeLineDirective> line_directive_stack = new ArrayList<CCodeLineDirective> ();
72 public Symbol current_symbol { get { return emit_context.current_symbol; } }
74 public TryStatement current_try {
75 get { return emit_context.current_try; }
76 set { emit_context.current_try = value; }
79 public CatchClause current_catch {
80 get { return emit_context.current_catch; }
81 set { emit_context.current_catch = value; }
84 public TypeSymbol? current_type_symbol {
85 get {
86 var sym = current_symbol;
87 while (sym != null) {
88 if (sym is TypeSymbol) {
89 return (TypeSymbol) sym;
91 sym = sym.parent_symbol;
93 return null;
97 public Class? current_class {
98 get { return current_type_symbol as Class; }
101 public Method? current_method {
102 get {
103 var sym = current_symbol;
104 while (sym is Block) {
105 sym = sym.parent_symbol;
107 return sym as Method;
111 public PropertyAccessor? current_property_accessor {
112 get {
113 var sym = current_symbol;
114 while (sym is Block) {
115 sym = sym.parent_symbol;
117 return sym as PropertyAccessor;
121 public Constructor? current_constructor {
122 get {
123 var sym = current_symbol;
124 while (sym is Block) {
125 sym = sym.parent_symbol;
127 return sym as Constructor;
131 public Destructor? current_destructor {
132 get {
133 var sym = current_symbol;
134 while (sym is Block) {
135 sym = sym.parent_symbol;
137 return sym as Destructor;
141 public DataType? current_return_type {
142 get {
143 var m = current_method;
144 if (m != null) {
145 return m.return_type;
148 var acc = current_property_accessor;
149 if (acc != null) {
150 if (acc.readable) {
151 return acc.value_type;
152 } else {
153 return void_type;
157 if (is_in_constructor () || is_in_destructor ()) {
158 return void_type;
161 return null;
165 public bool is_in_coroutine () {
166 return current_method != null && current_method.coroutine;
169 public bool is_in_constructor () {
170 if (current_method != null) {
171 // make sure to not return true in lambda expression inside constructor
172 return false;
174 var sym = current_symbol;
175 while (sym != null) {
176 if (sym is Constructor) {
177 return true;
179 sym = sym.parent_symbol;
181 return false;
184 public bool is_in_destructor () {
185 if (current_method != null) {
186 // make sure to not return true in lambda expression inside constructor
187 return false;
189 var sym = current_symbol;
190 while (sym != null) {
191 if (sym is Destructor) {
192 return true;
194 sym = sym.parent_symbol;
196 return false;
199 public Block? current_closure_block {
200 get {
201 return next_closure_block (current_symbol);
205 public unowned Block? next_closure_block (Symbol sym) {
206 while (true) {
207 unowned Method method = sym as Method;
208 if (method != null && !method.closure) {
209 // parent blocks are not captured by this method
210 break;
213 unowned Block block = sym as Block;
214 if (method == null && block == null) {
215 // no closure block
216 break;
219 if (block != null && block.captured) {
220 // closure block found
221 return block;
223 sym = sym.parent_symbol;
225 return null;
228 public CCodeFile header_file;
229 public CCodeFile internal_header_file;
230 public CCodeFile cfile;
232 public EmitContext class_init_context;
233 public EmitContext base_init_context;
234 public EmitContext class_finalize_context;
235 public EmitContext base_finalize_context;
236 public EmitContext instance_init_context;
237 public EmitContext instance_finalize_context;
239 public CCodeStruct param_spec_struct;
240 public CCodeStruct closure_struct;
241 public CCodeEnum prop_enum;
242 public CCodeEnum signal_enum;
244 public CCodeFunction ccode { get { return emit_context.ccode; } }
246 /* temporary variables that own their content */
247 public ArrayList<TargetValue> temp_ref_values { get { return emit_context.temp_ref_values; } }
248 /* cache to check whether a certain marshaller has been created yet */
249 public Set<string> user_marshal_set;
250 /* (constant) hash table with all predefined marshallers */
251 public Set<string> predefined_marshal_set;
252 /* (constant) hash table with all reserved identifiers in the generated code */
253 Set<string> reserved_identifiers;
255 public int next_temp_var_id {
256 get { return emit_context.next_temp_var_id; }
257 set { emit_context.next_temp_var_id = value; }
260 public int next_regex_id = 0;
261 public bool in_creation_method { get { return current_method is CreationMethod; } }
263 public bool current_method_inner_error {
264 get { return emit_context.current_method_inner_error; }
265 set { emit_context.current_method_inner_error = value; }
268 public bool current_method_return {
269 get { return emit_context.current_method_return; }
270 set { emit_context.current_method_return = value; }
273 int next_block_id = 0;
274 Map<Block,int> block_map = new HashMap<Block,int> ();
276 public DataType void_type = new VoidType ();
277 public DataType bool_type;
278 public DataType char_type;
279 public DataType uchar_type;
280 public DataType? unichar_type;
281 public DataType short_type;
282 public DataType ushort_type;
283 public DataType int_type;
284 public DataType uint_type;
285 public DataType long_type;
286 public DataType ulong_type;
287 public DataType int8_type;
288 public DataType uint8_type;
289 public DataType int16_type;
290 public DataType uint16_type;
291 public DataType int32_type;
292 public DataType uint32_type;
293 public DataType int64_type;
294 public DataType uint64_type;
295 public DataType string_type;
296 public DataType regex_type;
297 public DataType float_type;
298 public DataType double_type;
299 public TypeSymbol gtype_type;
300 public TypeSymbol gobject_type;
301 public ErrorType gerror_type;
302 public Class glist_type;
303 public Class gslist_type;
304 public Class gnode_type;
305 public Class gqueue_type;
306 public Class gvaluearray_type;
307 public TypeSymbol gstringbuilder_type;
308 public TypeSymbol garray_type;
309 public TypeSymbol gbytearray_type;
310 public TypeSymbol gptrarray_type;
311 public TypeSymbol gthreadpool_type;
312 public DataType gdestroynotify_type;
313 public DataType gquark_type;
314 public Struct gvalue_type;
315 public Class gvariant_type;
316 public Struct mutex_type;
317 public Struct gmutex_type;
318 public Struct grecmutex_type;
319 public Struct grwlock_type;
320 public Struct gcond_type;
321 public Class gsource_type;
322 public TypeSymbol type_module_type;
323 public TypeSymbol dbus_proxy_type;
324 public Class gtk_widget_type;
326 public bool in_plugin = false;
327 public string module_init_param_name;
329 public bool gvaluecollector_h_needed;
330 public bool requires_assert;
331 public bool requires_array_free;
332 public bool requires_array_move;
333 public bool requires_array_length;
334 public bool requires_clear_mutex;
336 public Set<string> wrappers;
337 Set<Symbol> generated_external_symbols;
339 public Map<string,string> variable_name_map { get { return emit_context.variable_name_map; } }
341 public static int ccode_attribute_cache_index = CodeNode.get_attribute_cache_index ();
343 public CCodeBaseModule () {
344 predefined_marshal_set = new HashSet<string> (str_hash, str_equal);
345 predefined_marshal_set.add ("VOID:VOID");
346 predefined_marshal_set.add ("VOID:BOOLEAN");
347 predefined_marshal_set.add ("VOID:CHAR");
348 predefined_marshal_set.add ("VOID:UCHAR");
349 predefined_marshal_set.add ("VOID:INT");
350 predefined_marshal_set.add ("VOID:UINT");
351 predefined_marshal_set.add ("VOID:LONG");
352 predefined_marshal_set.add ("VOID:ULONG");
353 predefined_marshal_set.add ("VOID:ENUM");
354 predefined_marshal_set.add ("VOID:FLAGS");
355 predefined_marshal_set.add ("VOID:FLOAT");
356 predefined_marshal_set.add ("VOID:DOUBLE");
357 predefined_marshal_set.add ("VOID:STRING");
358 predefined_marshal_set.add ("VOID:POINTER");
359 predefined_marshal_set.add ("VOID:OBJECT");
360 predefined_marshal_set.add ("STRING:OBJECT,POINTER");
361 predefined_marshal_set.add ("VOID:UINT,POINTER");
362 predefined_marshal_set.add ("BOOLEAN:FLAGS");
363 predefined_marshal_set.add ("VOID:BOXED");
364 predefined_marshal_set.add ("VOID:VARIANT");
365 predefined_marshal_set.add ("BOOLEAN:BOXED,BOXED");
367 reserved_identifiers = new HashSet<string> (str_hash, str_equal);
369 // C99 keywords
370 reserved_identifiers.add ("_Bool");
371 reserved_identifiers.add ("_Complex");
372 reserved_identifiers.add ("_Imaginary");
373 reserved_identifiers.add ("asm");
374 reserved_identifiers.add ("auto");
375 reserved_identifiers.add ("break");
376 reserved_identifiers.add ("case");
377 reserved_identifiers.add ("char");
378 reserved_identifiers.add ("const");
379 reserved_identifiers.add ("continue");
380 reserved_identifiers.add ("default");
381 reserved_identifiers.add ("do");
382 reserved_identifiers.add ("double");
383 reserved_identifiers.add ("else");
384 reserved_identifiers.add ("enum");
385 reserved_identifiers.add ("extern");
386 reserved_identifiers.add ("float");
387 reserved_identifiers.add ("for");
388 reserved_identifiers.add ("goto");
389 reserved_identifiers.add ("if");
390 reserved_identifiers.add ("inline");
391 reserved_identifiers.add ("int");
392 reserved_identifiers.add ("long");
393 reserved_identifiers.add ("register");
394 reserved_identifiers.add ("restrict");
395 reserved_identifiers.add ("return");
396 reserved_identifiers.add ("short");
397 reserved_identifiers.add ("signed");
398 reserved_identifiers.add ("sizeof");
399 reserved_identifiers.add ("static");
400 reserved_identifiers.add ("struct");
401 reserved_identifiers.add ("switch");
402 reserved_identifiers.add ("typedef");
403 reserved_identifiers.add ("union");
404 reserved_identifiers.add ("unsigned");
405 reserved_identifiers.add ("void");
406 reserved_identifiers.add ("volatile");
407 reserved_identifiers.add ("while");
409 // C11 keywords
410 reserved_identifiers.add ("_Alignas");
411 reserved_identifiers.add ("_Alignof");
412 reserved_identifiers.add ("_Atomic");
413 reserved_identifiers.add ("_Generic");
414 reserved_identifiers.add ("_Noreturn");
415 reserved_identifiers.add ("_Static_assert");
416 reserved_identifiers.add ("_Thread_local");
418 // MSVC keywords
419 reserved_identifiers.add ("cdecl");
421 // reserved for Vala/GObject naming conventions
422 reserved_identifiers.add ("error");
423 reserved_identifiers.add ("result");
424 reserved_identifiers.add ("self");
427 public override void emit (CodeContext context) {
428 this.context = context;
430 root_symbol = context.root;
432 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
433 char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
434 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
435 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
436 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
437 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
438 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
439 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
440 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
441 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
442 uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8"));
443 int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16"));
444 uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16"));
445 int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32"));
446 uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32"));
447 int64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int64"));
448 uint64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint64"));
449 float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
450 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
451 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
452 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
453 if (unichar_struct != null) {
454 unichar_type = new IntegerType (unichar_struct);
457 if (context.profile == Profile.GOBJECT) {
458 var glib_ns = root_symbol.scope.lookup ("GLib");
460 gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
461 gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
462 gerror_type = new ErrorType (null, null);
463 glist_type = (Class) glib_ns.scope.lookup ("List");
464 gslist_type = (Class) glib_ns.scope.lookup ("SList");
465 gnode_type = (Class) glib_ns.scope.lookup ("Node");
466 gqueue_type = (Class) glib_ns.scope.lookup ("Queue");
467 gvaluearray_type = (Class) glib_ns.scope.lookup ("ValueArray");
468 gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
469 garray_type = (TypeSymbol) glib_ns.scope.lookup ("Array");
470 gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
471 gptrarray_type = (TypeSymbol) glib_ns.scope.lookup ("PtrArray");
472 gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
473 gdestroynotify_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("DestroyNotify"));
475 gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
476 gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
477 gvariant_type = (Class) glib_ns.scope.lookup ("Variant");
478 gsource_type = (Class) glib_ns.scope.lookup ("Source");
480 gmutex_type = (Struct) glib_ns.scope.lookup ("Mutex");
481 grecmutex_type = (Struct) glib_ns.scope.lookup ("RecMutex");
482 grwlock_type = (Struct) glib_ns.scope.lookup ("RWLock");
483 gcond_type = (Struct) glib_ns.scope.lookup ("Cond");
485 mutex_type = grecmutex_type;
487 type_module_type = (TypeSymbol) glib_ns.scope.lookup ("TypeModule");
489 regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
491 if (context.module_init_method != null) {
492 foreach (Parameter parameter in context.module_init_method.get_parameters ()) {
493 if (parameter.variable_type.data_type.is_subtype_of (type_module_type)) {
494 in_plugin = true;
495 module_init_param_name = parameter.name;
496 break;
502 dbus_proxy_type = (TypeSymbol) glib_ns.scope.lookup ("DBusProxy");
505 var gtk_ns = root_symbol.scope.lookup ("Gtk");
506 if (gtk_ns != null) {
507 gtk_widget_type = (Class) gtk_ns.scope.lookup ("Widget");
510 header_file = new CCodeFile ();
511 header_file.is_header = true;
512 internal_header_file = new CCodeFile ();
513 internal_header_file.is_header = true;
515 /* we're only interested in non-pkg source files */
516 var source_files = context.get_source_files ();
517 foreach (SourceFile file in source_files) {
518 if (file.file_type == SourceFileType.SOURCE ||
519 (context.header_filename != null && file.file_type == SourceFileType.FAST)) {
520 file.accept (this);
524 // generate symbols file for public API
525 if (context.symbols_filename != null) {
526 var stream = FileStream.open (context.symbols_filename, "w");
527 if (stream == null) {
528 Report.error (null, "unable to open `%s' for writing".printf (context.symbols_filename));
529 this.context = null;
530 return;
533 foreach (string symbol in header_file.get_symbols ()) {
534 stream.puts (symbol);
535 stream.putc ('\n');
538 stream = null;
541 // generate C header file for public API
542 if (context.header_filename != null) {
543 bool ret;
544 if (context.profile == Profile.GOBJECT) {
545 ret = header_file.store (context.header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
546 } else {
547 ret = header_file.store (context.header_filename, null, context.version_header, false);
549 if (!ret) {
550 Report.error (null, "unable to open `%s' for writing".printf (context.header_filename));
554 // generate C header file for internal API
555 if (context.internal_header_filename != null) {
556 bool ret;
557 if (context.profile == Profile.GOBJECT) {
558 ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
559 } else {
560 ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false);
562 if (!ret) {
563 Report.error (null, "unable to open `%s' for writing".printf (context.internal_header_filename));
567 this.context = null;
570 public void push_context (EmitContext emit_context) {
571 if (this.emit_context != null) {
572 emit_context_stack.add (this.emit_context);
575 this.emit_context = emit_context;
576 if (ccode != null) {
577 ccode.current_line = current_line;
581 public void pop_context () {
582 if (emit_context_stack.size > 0) {
583 this.emit_context = emit_context_stack.remove_at (emit_context_stack.size - 1);
584 if (ccode != null) {
585 ccode.current_line = current_line;
587 } else {
588 this.emit_context = null;
592 public void push_line (SourceReference? source_reference) {
593 line_directive_stack.add (current_line);
594 if (source_reference != null) {
595 current_line = new CCodeLineDirective (source_reference.file.get_relative_filename (), source_reference.begin.line);
596 if (ccode != null) {
597 ccode.current_line = current_line;
602 public void pop_line () {
603 current_line = line_directive_stack.remove_at (line_directive_stack.size - 1);
604 if (ccode != null) {
605 ccode.current_line = current_line;
609 public void push_function (CCodeFunction func) {
610 emit_context.ccode_stack.add (ccode);
611 emit_context.ccode = func;
612 ccode.current_line = current_line;
615 public void pop_function () {
616 emit_context.ccode = emit_context.ccode_stack.remove_at (emit_context.ccode_stack.size - 1);
617 if (ccode != null) {
618 ccode.current_line = current_line;
622 public bool add_symbol_declaration (CCodeFile decl_space, Symbol sym, string name) {
623 if (decl_space.add_declaration (name)) {
624 return true;
626 if (sym.source_reference != null) {
627 sym.source_reference.file.used = true;
629 if (sym.anonymous) {
630 return !decl_space.is_header && CodeContext.get ().use_header;
632 if (sym.external_package || (!decl_space.is_header && CodeContext.get ().use_header && !sym.is_internal_symbol ())) {
633 // add feature test macros
634 foreach (unowned string feature_test_macro in get_ccode_feature_test_macros (sym).split (",")) {
635 decl_space.add_feature_test_macro (feature_test_macro);
637 // add appropriate include file
638 foreach (unowned string header_filename in get_ccode_header_filenames (sym).split (",")) {
639 decl_space.add_include (header_filename, !sym.external_package ||
640 (sym.external_package &&
641 sym.from_commandline));
643 // declaration complete
644 return true;
645 } else {
646 // require declaration
647 return false;
651 public CCodeIdentifier get_value_setter_function (DataType type_reference) {
652 var array_type = type_reference as ArrayType;
653 if (type_reference.data_type != null) {
654 return new CCodeIdentifier (get_ccode_set_value_function (type_reference.data_type));
655 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
656 // G_TYPE_STRV
657 return new CCodeIdentifier ("g_value_set_boxed");
658 } else {
659 return new CCodeIdentifier ("g_value_set_pointer");
663 public CCodeIdentifier get_value_taker_function (DataType type_reference) {
664 var array_type = type_reference as ArrayType;
665 if (type_reference.data_type != null) {
666 return new CCodeIdentifier (get_ccode_take_value_function (type_reference.data_type));
667 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
668 // G_TYPE_STRV
669 return new CCodeIdentifier ("g_value_take_boxed");
670 } else {
671 return new CCodeIdentifier ("g_value_set_pointer");
675 CCodeIdentifier get_value_getter_function (DataType type_reference) {
676 var array_type = type_reference as ArrayType;
677 if (type_reference.data_type != null) {
678 return new CCodeIdentifier (get_ccode_get_value_function (type_reference.data_type));
679 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
680 // G_TYPE_STRV
681 return new CCodeIdentifier ("g_value_get_boxed");
682 } else {
683 return new CCodeIdentifier ("g_value_get_pointer");
687 public virtual void append_vala_array_free () {
690 public virtual void append_vala_array_move () {
693 public virtual void append_vala_array_length () {
696 public void append_vala_clear_mutex (string typename, string funcprefix) {
697 // memset
698 cfile.add_include ("string.h");
700 var fun = new CCodeFunction ("_vala_clear_" + typename);
701 fun.modifiers = CCodeModifiers.STATIC;
702 fun.add_parameter (new CCodeParameter ("mutex", typename + " *"));
704 push_function (fun);
706 ccode.add_declaration (typename, new CCodeVariableDeclarator.zero ("zero_mutex", new CCodeConstant ("{ 0 }")));
708 var cmp = new CCodeFunctionCall (new CCodeIdentifier ("memcmp"));
709 cmp.add_argument (new CCodeIdentifier ("mutex"));
710 cmp.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("zero_mutex")));
711 cmp.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
712 ccode.open_if (cmp);
714 var mutex_clear = new CCodeFunctionCall (new CCodeIdentifier (funcprefix + "_clear"));
715 mutex_clear.add_argument (new CCodeIdentifier ("mutex"));
716 ccode.add_expression (mutex_clear);
718 var mset = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
719 mset.add_argument (new CCodeIdentifier ("mutex"));
720 mset.add_argument (new CCodeConstant ("0"));
721 mset.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
722 ccode.add_expression (mset);
724 ccode.close ();
726 pop_function ();
728 cfile.add_function_declaration (fun);
729 cfile.add_function (fun);
732 public override void visit_source_file (SourceFile source_file) {
733 cfile = new CCodeFile ();
735 user_marshal_set = new HashSet<string> (str_hash, str_equal);
737 next_regex_id = 0;
739 gvaluecollector_h_needed = false;
740 requires_assert = false;
741 requires_array_free = false;
742 requires_array_move = false;
743 requires_array_length = false;
744 requires_clear_mutex = false;
746 wrappers = new HashSet<string> (str_hash, str_equal);
747 generated_external_symbols = new HashSet<Symbol> ();
749 if (context.profile == Profile.GOBJECT) {
750 header_file.add_include ("glib.h");
751 internal_header_file.add_include ("glib.h");
752 cfile.add_include ("glib.h");
753 cfile.add_include ("glib-object.h");
756 source_file.accept_children (this);
758 if (context.report.get_errors () > 0) {
759 return;
762 /* For fast-vapi, we only wanted the header declarations
763 * to be emitted, so bail out here without writing the
764 * C code output.
766 if (source_file.file_type == SourceFileType.FAST) {
767 return;
770 if (requires_assert) {
771 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);")));
772 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; }")));
773 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; }")));
774 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);")));
776 if (requires_array_free) {
777 append_vala_array_free ();
779 if (requires_array_move) {
780 append_vala_array_move ();
782 if (requires_array_length) {
783 append_vala_array_length ();
785 if (requires_clear_mutex) {
786 append_vala_clear_mutex ("GMutex", "g_mutex");
787 append_vala_clear_mutex ("GRecMutex", "g_rec_mutex");
788 append_vala_clear_mutex ("GRWLock", "g_rw_lock");
789 append_vala_clear_mutex ("GCond", "g_cond");
792 if (gvaluecollector_h_needed) {
793 cfile.add_include ("gobject/gvaluecollector.h");
796 var comments = source_file.get_comments();
797 if (comments != null) {
798 foreach (Comment comment in comments) {
799 var ccomment = new CCodeComment (comment.content);
800 cfile.add_comment (ccomment);
804 if (!cfile.store (source_file.get_csource_filename (), source_file.filename, context.version_header, context.debug)) {
805 Report.error (null, "unable to open `%s' for writing".printf (source_file.get_csource_filename ()));
808 cfile = null;
811 public virtual bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
812 if (add_symbol_declaration (decl_space, en, get_ccode_name (en))) {
813 return false;
816 var cenum = new CCodeEnum (get_ccode_name (en));
818 cenum.modifiers |= (en.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
820 int flag_shift = 0;
821 foreach (EnumValue ev in en.get_values ()) {
822 CCodeEnumValue c_ev;
823 if (ev.value == null) {
824 c_ev = new CCodeEnumValue (get_ccode_name (ev));
825 if (en.is_flags) {
826 c_ev.value = new CCodeConstant ("1 << %d".printf (flag_shift));
827 flag_shift += 1;
829 } else {
830 ev.value.emit (this);
831 c_ev = new CCodeEnumValue (get_ccode_name (ev), get_cvalue (ev.value));
833 c_ev.modifiers |= (ev.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
834 cenum.add_value (c_ev);
837 decl_space.add_type_definition (cenum);
838 decl_space.add_type_definition (new CCodeNewline ());
840 if (!get_ccode_has_type_id (en)) {
841 return true;
844 decl_space.add_include ("glib-object.h");
845 decl_space.add_type_declaration (new CCodeNewline ());
847 var macro = "(%s_get_type ())".printf (get_ccode_lower_case_name (en, null));
848 decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (en), macro));
850 var fun_name = "%s_get_type".printf (get_ccode_lower_case_name (en, null));
851 var regfun = new CCodeFunction (fun_name, "GType");
852 regfun.modifiers = CCodeModifiers.CONST;
854 if (en.is_private_symbol ()) {
855 // avoid C warning as this function is not always used
856 regfun.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.UNUSED;
857 } else if (context.hide_internal && en.is_internal_symbol ()) {
858 regfun.modifiers |= CCodeModifiers.INTERNAL;
861 decl_space.add_function_declaration (regfun);
863 return true;
866 public override void visit_enum (Enum en) {
867 push_line (en.source_reference);
869 en.accept_children (this);
871 if (en.comment != null) {
872 cfile.add_type_member_definition (new CCodeComment (en.comment.content));
875 generate_enum_declaration (en, cfile);
877 if (!en.is_internal_symbol ()) {
878 generate_enum_declaration (en, header_file);
880 if (!en.is_private_symbol ()) {
881 generate_enum_declaration (en, internal_header_file);
884 pop_line ();
887 public void visit_member (Symbol m) {
888 /* stuff meant for all lockable members */
889 if (m is Lockable && ((Lockable) m).lock_used) {
890 CCodeExpression l = new CCodeIdentifier ("self");
891 var init_context = class_init_context;
892 var finalize_context = class_finalize_context;
894 if (m.is_instance_member ()) {
895 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (get_ccode_name (m)));
896 init_context = instance_init_context;
897 finalize_context = instance_finalize_context;
898 } else if (m.is_class_member ()) {
899 TypeSymbol parent = (TypeSymbol)m.parent_symbol;
901 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(get_ccode_upper_case_name (parent))));
902 get_class_private_call.add_argument (new CCodeIdentifier ("klass"));
903 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (get_ccode_name (m)));
904 } else {
905 l = new CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf (get_ccode_lower_case_name (m.parent_symbol), get_ccode_name (m))));
908 push_context (init_context);
909 var initf = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.default_construction_method)));
910 initf.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
911 ccode.add_expression (initf);
912 pop_context ();
914 if (finalize_context != null) {
915 push_context (finalize_context);
916 var fc = new CCodeFunctionCall (new CCodeIdentifier ("g_rec_mutex_clear"));
917 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
918 ccode.add_expression (fc);
919 pop_context ();
924 private void constant_array_ranks_sizes (InitializerList initializer_list, int[] sizes, int rank = 0) {
925 sizes[rank] = int.max (sizes[rank], initializer_list.size);
926 rank++;
927 foreach (var expr in initializer_list.get_initializers()) {
928 if (expr is InitializerList && ((InitializerList) expr).target_type is ArrayType) {
929 constant_array_ranks_sizes ((InitializerList) expr, sizes, rank);
934 public void generate_constant_declaration (Constant c, CCodeFile decl_space, bool definition = false) {
935 if (c.parent_symbol is Block) {
936 // local constant
937 return;
940 if (add_symbol_declaration (decl_space, c, get_ccode_name (c))) {
941 return;
944 if (!c.external) {
945 generate_type_declaration (c.type_reference, decl_space);
947 c.value.emit (this);
949 var initializer_list = c.value as InitializerList;
950 if (initializer_list != null) {
951 var cdecl = new CCodeDeclaration (get_ccode_const_name (c.type_reference));
952 var arr = "";
953 if (c.type_reference is ArrayType) {
954 var array = (ArrayType) c.type_reference;
955 int[] sizes = new int[array.rank];
956 constant_array_ranks_sizes (initializer_list, sizes);
957 for (int i = 0; i < array.rank; i++) {
958 arr += "[%d]".printf (sizes[i]);
962 var cinitializer = get_cvalue (c.value);
963 if (!definition) {
964 // never output value in header
965 // special case needed as this method combines declaration and definition
966 cinitializer = null;
969 cdecl.add_declarator (new CCodeVariableDeclarator ("%s%s".printf (get_ccode_name (c), arr), cinitializer));
970 if (c.is_private_symbol ()) {
971 cdecl.modifiers = CCodeModifiers.STATIC;
972 } else {
973 cdecl.modifiers = CCodeModifiers.EXTERN;
976 decl_space.add_constant_declaration (cdecl);
977 } else {
978 var cdefine = new CCodeMacroReplacement.with_expression (get_ccode_name (c), get_cvalue (c.value));
979 decl_space.add_type_member_declaration (cdefine);
984 public override void visit_constant (Constant c) {
985 push_line (c.source_reference);
987 if (c.parent_symbol is Block) {
988 // local constant
990 generate_type_declaration (c.type_reference, cfile);
992 c.value.emit (this);
994 string type_name = get_ccode_const_name (c.type_reference);
995 string arr = "";
996 if (c.type_reference is ArrayType) {
997 var array = (ArrayType) c.type_reference;
998 var initializer_list = c.value as InitializerList;
999 if (initializer_list != null) {
1000 int[] sizes = new int[array.rank];
1001 constant_array_ranks_sizes (initializer_list, sizes);
1002 for (int i = 0; i < array.rank; i++) {
1003 arr += "[%d]".printf (sizes[i]);
1008 if (c.type_reference.compatible (string_type)) {
1009 type_name = "const char";
1010 arr = "[]";
1013 var cinitializer = get_cvalue (c.value);
1015 ccode.add_declaration (type_name, new CCodeVariableDeclarator ("%s%s".printf (get_ccode_name (c), arr), cinitializer), CCodeModifiers.STATIC);
1016 } else {
1017 generate_constant_declaration (c, cfile, true);
1019 if (!c.is_internal_symbol ()) {
1020 generate_constant_declaration (c, header_file);
1022 if (!c.is_private_symbol ()) {
1023 generate_constant_declaration (c, internal_header_file);
1027 pop_line ();
1030 public void generate_field_declaration (Field f, CCodeFile decl_space) {
1031 if (add_symbol_declaration (decl_space, f, get_ccode_name (f))) {
1032 return;
1035 generate_type_declaration (f.variable_type, decl_space);
1037 var cdecl = new CCodeDeclaration (get_ccode_name (f.variable_type));
1038 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type)));
1039 if (f.is_private_symbol ()) {
1040 cdecl.modifiers = CCodeModifiers.STATIC;
1041 } else {
1042 cdecl.modifiers = CCodeModifiers.EXTERN;
1044 if (f.version.deprecated) {
1045 cdecl.modifiers |= CCodeModifiers.DEPRECATED;
1047 if (f.is_volatile) {
1048 cdecl.modifiers |= CCodeModifiers.VOLATILE;
1050 decl_space.add_type_member_declaration (cdecl);
1052 if (f.lock_used) {
1053 // Declare mutex for static member
1054 var flock = new CCodeDeclaration (get_ccode_name (mutex_type));
1055 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}"));
1056 flock.add_declarator (flock_decl);
1058 if (f.is_private_symbol ()) {
1059 flock.modifiers = CCodeModifiers.STATIC;
1060 } else if (context.hide_internal && f.is_internal_symbol ()) {
1061 flock.modifiers = CCodeModifiers.INTERNAL;
1062 } else {
1063 flock.modifiers = CCodeModifiers.EXTERN;
1065 decl_space.add_type_member_declaration (flock);
1068 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1069 var array_type = (ArrayType) f.variable_type;
1071 if (!array_type.fixed_length) {
1072 for (int dim = 1; dim <= array_type.rank; dim++) {
1073 var len_type = int_type.copy ();
1075 cdecl = new CCodeDeclaration (get_ccode_name (len_type));
1076 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_length_cname (get_ccode_name (f), dim)));
1077 if (f.is_private_symbol ()) {
1078 cdecl.modifiers = CCodeModifiers.STATIC;
1079 } else if (context.hide_internal && f.is_internal_symbol ()) {
1080 cdecl.modifiers = CCodeModifiers.INTERNAL;
1081 } else {
1082 cdecl.modifiers = CCodeModifiers.EXTERN;
1084 decl_space.add_type_member_declaration (cdecl);
1087 } else if (f.variable_type is DelegateType && get_ccode_delegate_target (f)) {
1088 var delegate_type = (DelegateType) f.variable_type;
1089 if (delegate_type.delegate_symbol.has_target) {
1090 // create field to store delegate target
1092 cdecl = new CCodeDeclaration ("gpointer");
1093 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f)));
1094 if (f.is_private_symbol ()) {
1095 cdecl.modifiers = CCodeModifiers.STATIC;
1096 } else if (context.hide_internal && f.is_internal_symbol ()) {
1097 cdecl.modifiers = CCodeModifiers.INTERNAL;
1098 } else {
1099 cdecl.modifiers = CCodeModifiers.EXTERN;
1101 decl_space.add_type_member_declaration (cdecl);
1103 if (delegate_type.is_disposable ()) {
1104 cdecl = new CCodeDeclaration ("GDestroyNotify");
1105 cdecl.add_declarator (new CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (get_ccode_name (f))));
1106 if (f.is_private_symbol ()) {
1107 cdecl.modifiers = CCodeModifiers.STATIC;
1108 } else if (context.hide_internal && f.is_internal_symbol ()) {
1109 cdecl.modifiers = CCodeModifiers.INTERNAL;
1110 } else {
1111 cdecl.modifiers = CCodeModifiers.EXTERN;
1113 decl_space.add_type_member_declaration (cdecl);
1119 public override void visit_field (Field f) {
1120 push_line (f.source_reference);
1121 visit_member (f);
1123 check_type (f.variable_type);
1125 var cl = f.parent_symbol as Class;
1126 bool is_gtypeinstance = (cl != null && !cl.is_compact);
1128 CCodeExpression lhs = null;
1130 if (f.binding == MemberBinding.INSTANCE) {
1131 if (is_gtypeinstance && f.access == SymbolAccessibility.PRIVATE) {
1132 lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), get_ccode_name (f));
1133 } else {
1134 lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_ccode_name (f));
1137 if (f.initializer != null) {
1138 push_context (instance_init_context);
1140 f.initializer.emit (this);
1142 var rhs = get_cvalue (f.initializer);
1143 if (!is_simple_struct_creation (f, f.initializer)) {
1144 // otherwise handled in visit_object_creation_expression
1146 ccode.add_assignment (lhs, rhs);
1148 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1149 var array_type = (ArrayType) f.variable_type;
1150 var field_value = get_field_cvalue (f, load_this_parameter ((TypeSymbol) f.parent_symbol));
1152 var glib_value = (GLibValue) f.initializer.target_value;
1153 if (glib_value.array_length_cvalues != null) {
1154 for (int dim = 1; dim <= array_type.rank; dim++) {
1155 var array_len_lhs = get_array_length_cvalue (field_value, dim);
1156 ccode.add_assignment (array_len_lhs, get_array_length_cvalue (glib_value, dim));
1158 } else if (glib_value.array_null_terminated) {
1159 requires_array_length = true;
1160 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1161 len_call.add_argument (get_cvalue_ (glib_value));
1163 ccode.add_assignment (get_array_length_cvalue (field_value, 1), len_call);
1164 } else {
1165 for (int dim = 1; dim <= array_type.rank; dim++) {
1166 ccode.add_assignment (get_array_length_cvalue (field_value, dim), new CCodeConstant ("-1"));
1170 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1171 var lhs_array_size = get_array_size_cvalue (field_value);
1172 var rhs_array_len = get_array_length_cvalue (field_value, 1);
1173 ccode.add_assignment (lhs_array_size, rhs_array_len);
1175 } else if (f.variable_type is DelegateType && get_ccode_delegate_target (f)) {
1176 var delegate_type = (DelegateType) f.variable_type;
1177 if (delegate_type.delegate_symbol.has_target) {
1178 var field_value = get_field_cvalue (f, load_this_parameter ((TypeSymbol) f.parent_symbol));
1180 ccode.add_assignment (get_delegate_target_cvalue (field_value), new CCodeIdentifier ("self"));
1181 if (delegate_type.is_disposable ()) {
1182 ccode.add_assignment (get_delegate_target_destroy_notify_cvalue (field_value), new CCodeIdentifier ("NULL"));
1188 foreach (var value in temp_ref_values) {
1189 ccode.add_expression (destroy_value (value));
1192 temp_ref_values.clear ();
1194 pop_context ();
1197 if (get_ccode_delegate_target (f) && requires_destroy (f.variable_type) && instance_finalize_context != null) {
1198 push_context (instance_finalize_context);
1199 ccode.add_expression (destroy_field (f, load_this_parameter ((TypeSymbol) f.parent_symbol)));
1200 pop_context ();
1202 } else if (f.binding == MemberBinding.CLASS) {
1203 if (!is_gtypeinstance) {
1204 Report.error (f.source_reference, "class fields are not supported in compact classes");
1205 f.error = true;
1206 return;
1209 if (f.access == SymbolAccessibility.PRIVATE) {
1210 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (get_ccode_upper_case_name (cl))));
1211 ccall.add_argument (new CCodeIdentifier ("klass"));
1212 lhs = new CCodeMemberAccess (ccall, get_ccode_name (f), true);
1213 } else {
1214 lhs = new CCodeMemberAccess (new CCodeIdentifier ("klass"), get_ccode_name (f), true);
1217 if (f.initializer != null) {
1218 push_context (class_init_context);
1220 f.initializer.emit (this);
1222 var rhs = get_cvalue (f.initializer);
1224 ccode.add_assignment (lhs, rhs);
1226 foreach (var value in temp_ref_values) {
1227 ccode.add_expression (destroy_value (value));
1230 temp_ref_values.clear ();
1232 pop_context ();
1234 } else {
1235 generate_field_declaration (f, cfile);
1237 if (!f.is_internal_symbol ()) {
1238 generate_field_declaration (f, header_file);
1240 if (!f.is_private_symbol ()) {
1241 generate_field_declaration (f, internal_header_file);
1244 if (!f.external) {
1245 lhs = new CCodeIdentifier (get_ccode_name (f));
1247 var var_decl = new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type));
1248 var_decl.initializer = default_value_for_type (f.variable_type, true);
1250 if (class_init_context != null) {
1251 push_context (class_init_context);
1252 } else {
1253 push_context (new EmitContext ());
1256 if (f.initializer != null) {
1257 f.initializer.emit (this);
1259 var init = get_cvalue (f.initializer);
1260 if (is_constant_ccode_expression (init)) {
1261 var_decl.initializer = init;
1265 var var_def = new CCodeDeclaration (get_ccode_name (f.variable_type));
1266 var_def.add_declarator (var_decl);
1267 if (!f.is_private_symbol ()) {
1268 var_def.modifiers = CCodeModifiers.EXTERN;
1269 } else {
1270 var_def.modifiers = CCodeModifiers.STATIC;
1272 if (f.version.deprecated) {
1273 var_def.modifiers |= CCodeModifiers.DEPRECATED;
1275 if (f.is_volatile) {
1276 var_def.modifiers |= CCodeModifiers.VOLATILE;
1278 cfile.add_type_member_declaration (var_def);
1280 /* add array length fields where necessary */
1281 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1282 var array_type = (ArrayType) f.variable_type;
1284 if (!array_type.fixed_length) {
1285 for (int dim = 1; dim <= array_type.rank; dim++) {
1286 var len_type = int_type.copy ();
1288 var len_def = new CCodeDeclaration (get_ccode_name (len_type));
1289 len_def.add_declarator (new CCodeVariableDeclarator (get_array_length_cname (get_ccode_name (f), dim), new CCodeConstant ("0")));
1290 if (!f.is_private_symbol ()) {
1291 len_def.modifiers = CCodeModifiers.EXTERN;
1292 } else {
1293 len_def.modifiers = CCodeModifiers.STATIC;
1295 cfile.add_type_member_declaration (len_def);
1298 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1299 var len_type = int_type.copy ();
1301 var cdecl = new CCodeDeclaration (get_ccode_name (len_type));
1302 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_size_cname (get_ccode_name (f)), new CCodeConstant ("0")));
1303 cdecl.modifiers = CCodeModifiers.STATIC;
1304 cfile.add_type_member_declaration (cdecl);
1307 } else if (f.variable_type is DelegateType && get_ccode_delegate_target (f)) {
1308 var delegate_type = (DelegateType) f.variable_type;
1309 if (delegate_type.delegate_symbol.has_target) {
1310 // create field to store delegate target
1312 var target_def = new CCodeDeclaration ("gpointer");
1313 target_def.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f), new CCodeConstant ("NULL")));
1314 if (!f.is_private_symbol ()) {
1315 target_def.modifiers = CCodeModifiers.EXTERN;
1316 } else {
1317 target_def.modifiers = CCodeModifiers.STATIC;
1319 cfile.add_type_member_declaration (target_def);
1321 if (delegate_type.is_disposable ()) {
1322 var target_destroy_notify_def = new CCodeDeclaration ("GDestroyNotify");
1323 target_destroy_notify_def.add_declarator (new CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (get_ccode_name (f)), new CCodeConstant ("NULL")));
1324 if (!f.is_private_symbol ()) {
1325 target_destroy_notify_def.modifiers = CCodeModifiers.EXTERN;
1326 } else {
1327 target_destroy_notify_def.modifiers = CCodeModifiers.STATIC;
1329 cfile.add_type_member_declaration (target_destroy_notify_def);
1335 if (f.initializer != null) {
1336 var rhs = get_cvalue (f.initializer);
1337 if (!is_constant_ccode_expression (rhs)) {
1338 if (is_gtypeinstance) {
1339 if (f.initializer is InitializerList) {
1340 ccode.open_block ();
1342 var temp_decl = get_temp_variable (f.variable_type);
1343 var vardecl = new CCodeVariableDeclarator.zero (temp_decl.name, rhs);
1344 ccode.add_declaration (get_ccode_name (temp_decl.variable_type), vardecl);
1346 var tmp = get_variable_cexpression (get_variable_cname (temp_decl.name));
1347 ccode.add_assignment (lhs, tmp);
1349 ccode.close ();
1350 } else {
1351 ccode.add_assignment (lhs, rhs);
1354 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1355 var array_type = (ArrayType) f.variable_type;
1356 var field_value = get_field_cvalue (f, null);
1358 var glib_value = (GLibValue) f.initializer.target_value;
1359 if (glib_value.array_length_cvalues != null) {
1360 for (int dim = 1; dim <= array_type.rank; dim++) {
1361 var array_len_lhs = get_array_length_cvalue (field_value, dim);
1362 ccode.add_assignment (array_len_lhs, get_array_length_cvalue (glib_value, dim));
1364 } else if (glib_value.array_null_terminated) {
1365 requires_array_length = true;
1366 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1367 len_call.add_argument (get_cvalue_ (glib_value));
1369 ccode.add_assignment (get_array_length_cvalue (field_value, 1), len_call);
1370 } else {
1371 for (int dim = 1; dim <= array_type.rank; dim++) {
1372 ccode.add_assignment (get_array_length_cvalue (field_value, dim), new CCodeConstant ("-1"));
1376 } else {
1377 f.error = true;
1378 Report.error (f.source_reference, "Non-constant field initializers not supported in this context");
1379 return;
1384 pop_context ();
1388 pop_line ();
1391 public bool is_constant_ccode_expression (CCodeExpression cexpr) {
1392 if (cexpr is CCodeConstant) {
1393 return true;
1394 } else if (cexpr is CCodeCastExpression) {
1395 var ccast = (CCodeCastExpression) cexpr;
1396 return is_constant_ccode_expression (ccast.inner);
1397 } else if (cexpr is CCodeUnaryExpression) {
1398 var cunary = (CCodeUnaryExpression) cexpr;
1399 switch (cunary.operator) {
1400 case CCodeUnaryOperator.PREFIX_INCREMENT:
1401 case CCodeUnaryOperator.PREFIX_DECREMENT:
1402 case CCodeUnaryOperator.POSTFIX_INCREMENT:
1403 case CCodeUnaryOperator.POSTFIX_DECREMENT:
1404 return false;
1406 return is_constant_ccode_expression (cunary.inner);
1407 } else if (cexpr is CCodeBinaryExpression) {
1408 var cbinary = (CCodeBinaryExpression) cexpr;
1409 return is_constant_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1412 var cparenthesized = (cexpr as CCodeParenthesizedExpression);
1413 return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
1417 * Returns whether the passed cexpr is a pure expression, i.e. an
1418 * expression without side-effects.
1420 public bool is_pure_ccode_expression (CCodeExpression cexpr) {
1421 if (cexpr is CCodeConstant || cexpr is CCodeIdentifier) {
1422 return true;
1423 } else if (cexpr is CCodeBinaryExpression) {
1424 var cbinary = (CCodeBinaryExpression) cexpr;
1425 return is_pure_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1426 } else if (cexpr is CCodeUnaryExpression) {
1427 var cunary = (CCodeUnaryExpression) cexpr;
1428 switch (cunary.operator) {
1429 case CCodeUnaryOperator.PREFIX_INCREMENT:
1430 case CCodeUnaryOperator.PREFIX_DECREMENT:
1431 case CCodeUnaryOperator.POSTFIX_INCREMENT:
1432 case CCodeUnaryOperator.POSTFIX_DECREMENT:
1433 return false;
1434 default:
1435 return is_pure_ccode_expression (cunary.inner);
1437 } else if (cexpr is CCodeMemberAccess) {
1438 var cma = (CCodeMemberAccess) cexpr;
1439 return is_pure_ccode_expression (cma.inner);
1440 } else if (cexpr is CCodeElementAccess) {
1441 var cea = (CCodeElementAccess) cexpr;
1442 return is_pure_ccode_expression (cea.container) && is_pure_ccode_expression (cea.index);
1443 } else if (cexpr is CCodeCastExpression) {
1444 var ccast = (CCodeCastExpression) cexpr;
1445 return is_pure_ccode_expression (ccast.inner);
1446 } else if (cexpr is CCodeParenthesizedExpression) {
1447 var cparenthesized = (CCodeParenthesizedExpression) cexpr;
1448 return is_pure_ccode_expression (cparenthesized.inner);
1451 return false;
1454 public override void visit_formal_parameter (Parameter p) {
1455 if (!p.ellipsis) {
1456 check_type (p.variable_type);
1460 public override void visit_property (Property prop) {
1461 visit_member (prop);
1463 check_type (prop.property_type);
1465 if (prop.get_accessor != null) {
1466 prop.get_accessor.accept (this);
1468 if (prop.set_accessor != null) {
1469 prop.set_accessor.accept (this);
1473 public void generate_type_declaration (DataType type, CCodeFile decl_space) {
1474 if (type is ObjectType) {
1475 var object_type = (ObjectType) type;
1476 if (object_type.type_symbol is Class) {
1477 generate_class_declaration ((Class) object_type.type_symbol, decl_space);
1478 } else if (object_type.type_symbol is Interface) {
1479 generate_interface_declaration ((Interface) object_type.type_symbol, decl_space);
1481 } else if (type is DelegateType) {
1482 var deleg_type = (DelegateType) type;
1483 var d = deleg_type.delegate_symbol;
1484 generate_delegate_declaration (d, decl_space);
1485 } else if (type.data_type is Enum) {
1486 var en = (Enum) type.data_type;
1487 generate_enum_declaration (en, decl_space);
1488 } else if (type is ValueType) {
1489 var value_type = (ValueType) type;
1490 generate_struct_declaration ((Struct) value_type.type_symbol, decl_space);
1491 } else if (type is ArrayType) {
1492 var array_type = (ArrayType) type;
1493 generate_type_declaration (array_type.element_type, decl_space);
1494 } else if (type is ErrorType) {
1495 var error_type = (ErrorType) type;
1496 if (error_type.error_domain != null) {
1497 generate_error_domain_declaration (error_type.error_domain, decl_space);
1499 } else if (type is PointerType) {
1500 var pointer_type = (PointerType) type;
1501 generate_type_declaration (pointer_type.base_type, decl_space);
1504 foreach (DataType type_arg in type.get_type_arguments ()) {
1505 generate_type_declaration (type_arg, decl_space);
1509 public virtual void generate_class_struct_declaration (Class cl, CCodeFile decl_space) {
1512 public virtual void generate_struct_declaration (Struct st, CCodeFile decl_space) {
1515 public virtual void generate_delegate_declaration (Delegate d, CCodeFile decl_space) {
1518 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) {
1521 public void generate_property_accessor_declaration (PropertyAccessor acc, CCodeFile decl_space) {
1522 if (add_symbol_declaration (decl_space, acc, get_ccode_name (acc))) {
1523 return;
1526 var prop = (Property) acc.prop;
1528 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1531 CCodeParameter cvalueparam;
1532 if (returns_real_struct) {
1533 cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (acc.value_type)));
1534 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1535 cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (acc.value_type)));
1536 } else {
1537 cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1539 generate_type_declaration (acc.value_type, decl_space);
1541 CCodeFunction function;
1542 if (acc.readable && !returns_real_struct) {
1543 function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (acc.value_type));
1544 } else {
1545 function = new CCodeFunction (get_ccode_name (acc), "void");
1548 if (prop.binding == MemberBinding.INSTANCE) {
1549 var t = (TypeSymbol) prop.parent_symbol;
1550 var this_type = get_data_type_for_symbol (t);
1551 generate_type_declaration (this_type, decl_space);
1552 var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1553 if (t is Struct && !((Struct) t).is_simple_type ()) {
1554 cselfparam.type_name += "*";
1557 function.add_parameter (cselfparam);
1560 if (acc.writable || acc.construction || returns_real_struct) {
1561 function.add_parameter (cvalueparam);
1564 if (acc.value_type is ArrayType) {
1565 var array_type = (ArrayType) acc.value_type;
1566 for (int dim = 1; dim <= array_type.rank; dim++) {
1567 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? "int*" : "int"));
1569 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1570 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1571 if (!acc.readable && acc.value_type.value_owned) {
1572 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1576 if (prop.version.deprecated) {
1577 function.modifiers |= CCodeModifiers.DEPRECATED;
1580 if (!prop.is_abstract
1581 && (prop.is_private_symbol () || (!acc.readable && !acc.writable) || acc.access == SymbolAccessibility.PRIVATE)) {
1582 function.modifiers |= CCodeModifiers.STATIC;
1583 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1584 function.modifiers |= CCodeModifiers.INTERNAL;
1586 decl_space.add_function_declaration (function);
1589 public override void visit_property_accessor (PropertyAccessor acc) {
1590 push_context (new EmitContext (acc));
1591 push_line (acc.source_reference);
1593 var prop = (Property) acc.prop;
1595 if (acc.comment != null) {
1596 cfile.add_type_member_definition (new CCodeComment (acc.comment.content));
1599 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1601 if (acc.result_var != null) {
1602 acc.result_var.accept (this);
1605 var t = (TypeSymbol) prop.parent_symbol;
1607 if (acc.construction && !t.is_subtype_of (gobject_type)) {
1608 Report.error (acc.source_reference, "construct properties require GLib.Object");
1609 acc.error = true;
1610 return;
1611 } else if (acc.construction && !is_gobject_property (prop)) {
1612 Report.error (acc.source_reference, "construct properties not supported for specified property type");
1613 acc.error = true;
1614 return;
1617 // do not declare overriding properties and interface implementations
1618 if (prop.is_abstract || prop.is_virtual
1619 || (prop.base_property == null && prop.base_interface_property == null)) {
1620 generate_property_accessor_declaration (acc, cfile);
1622 // do not declare construct-only properties in header files
1623 if (acc.readable || acc.writable) {
1624 if (!prop.is_internal_symbol ()
1625 && (acc.access == SymbolAccessibility.PUBLIC
1626 || acc.access == SymbolAccessibility.PROTECTED)) {
1627 generate_property_accessor_declaration (acc, header_file);
1629 if (!prop.is_private_symbol () && acc.access != SymbolAccessibility.PRIVATE) {
1630 generate_property_accessor_declaration (acc, internal_header_file);
1635 if (acc.source_type == SourceFileType.FAST) {
1636 pop_line ();
1637 return;
1640 var this_type = get_data_type_for_symbol (t);
1641 var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1642 if (t is Struct && !((Struct) t).is_simple_type ()) {
1643 cselfparam.type_name += "*";
1645 CCodeParameter cvalueparam;
1646 if (returns_real_struct) {
1647 cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (acc.value_type)));
1648 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1649 cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (acc.value_type)));
1650 } else {
1651 cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1654 if (prop.is_abstract || prop.is_virtual) {
1655 CCodeFunction function;
1656 if (acc.readable && !returns_real_struct) {
1657 function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (current_return_type));
1658 } else {
1659 function = new CCodeFunction (get_ccode_name (acc), "void");
1661 function.add_parameter (cselfparam);
1662 if (acc.writable || acc.construction || returns_real_struct) {
1663 function.add_parameter (cvalueparam);
1666 if (acc.value_type is ArrayType) {
1667 var array_type = (ArrayType) acc.value_type;
1668 for (int dim = 1; dim <= array_type.rank; dim++) {
1669 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? "int*" : "int"));
1671 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1672 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1673 if (!acc.readable && acc.value_type.value_owned) {
1674 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1678 if (!prop.is_abstract
1679 && (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE)) {
1680 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1681 function.modifiers |= CCodeModifiers.STATIC;
1682 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1683 function.modifiers |= CCodeModifiers.INTERNAL;
1686 push_function (function);
1688 if (prop.binding == MemberBinding.INSTANCE) {
1689 if (!acc.readable || returns_real_struct) {
1690 create_property_type_check_statement (prop, false, t, true, "self");
1691 } else {
1692 create_property_type_check_statement (prop, true, t, true, "self");
1696 CCodeExpression vcast;
1697 if (prop.parent_symbol is Interface) {
1698 var iface = (Interface) prop.parent_symbol;
1700 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface, null))));
1701 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("self"));
1702 } else {
1703 var cl = (Class) prop.parent_symbol;
1704 if (!cl.is_compact) {
1705 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (cl, null))));
1706 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("self"));
1707 } else {
1708 vcast = new CCodeIdentifier ("self");
1712 if (acc.readable) {
1713 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
1714 vcall.add_argument (new CCodeIdentifier ("self"));
1715 if (returns_real_struct) {
1716 vcall.add_argument (new CCodeIdentifier ("result"));
1717 ccode.add_expression (vcall);
1718 } else {
1719 if (acc.value_type is ArrayType) {
1720 var array_type = (ArrayType) acc.value_type;
1722 for (int dim = 1; dim <= array_type.rank; dim++) {
1723 var len_expr = new CCodeIdentifier (get_array_length_cname ("result", dim));
1724 vcall.add_argument (len_expr);
1726 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1727 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("result")));
1730 ccode.add_return (vcall);
1732 } else {
1733 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
1734 vcall.add_argument (new CCodeIdentifier ("self"));
1735 vcall.add_argument (new CCodeIdentifier ("value"));
1737 if (acc.value_type is ArrayType) {
1738 var array_type = (ArrayType) acc.value_type;
1740 for (int dim = 1; dim <= array_type.rank; dim++) {
1741 var len_expr = new CCodeIdentifier (get_array_length_cname ("value", dim));
1742 vcall.add_argument (len_expr);
1744 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1745 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("value")));
1746 if (!acc.readable && acc.value_type.value_owned) {
1747 vcall.add_argument (new CCodeIdentifier (get_delegate_target_destroy_notify_cname ("value")));
1751 ccode.add_expression (vcall);
1754 pop_function ();
1756 cfile.add_function (function);
1759 if (!prop.is_abstract && acc.body != null) {
1760 bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
1762 string cname = get_ccode_real_name (acc);
1764 CCodeFunction function;
1765 if (acc.writable || acc.construction || returns_real_struct) {
1766 function = new CCodeFunction (cname, "void");
1767 } else {
1768 function = new CCodeFunction (cname, get_ccode_name (acc.value_type));
1771 ObjectType base_type = null;
1772 if (prop.binding == MemberBinding.INSTANCE) {
1773 if (is_virtual) {
1774 if (prop.base_property != null) {
1775 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
1776 } else if (prop.base_interface_property != null) {
1777 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
1779 function.modifiers |= CCodeModifiers.STATIC;
1780 function.add_parameter (new CCodeParameter ("base", get_ccode_name (base_type)));
1781 } else {
1782 function.add_parameter (cselfparam);
1785 if (acc.writable || acc.construction || returns_real_struct) {
1786 function.add_parameter (cvalueparam);
1789 if (acc.value_type is ArrayType) {
1790 var array_type = (ArrayType) acc.value_type;
1791 for (int dim = 1; dim <= array_type.rank; dim++) {
1792 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? "int*" : "int"));
1794 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1795 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1796 if (!acc.readable && acc.value_type.value_owned) {
1797 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1801 if (!is_virtual) {
1802 if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1803 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1804 function.modifiers |= CCodeModifiers.STATIC;
1805 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1806 function.modifiers |= CCodeModifiers.INTERNAL;
1810 push_function (function);
1812 if (prop.binding == MemberBinding.INSTANCE && !is_virtual) {
1813 if (!acc.readable || returns_real_struct) {
1814 create_property_type_check_statement (prop, false, t, true, "self");
1815 } else {
1816 create_property_type_check_statement (prop, true, t, true, "self");
1820 if (acc.readable && !returns_real_struct) {
1821 // do not declare result variable if exit block is known to be unreachable
1822 if (acc.return_block == null || acc.return_block.get_predecessors ().size > 0) {
1823 ccode.add_declaration (get_ccode_name (acc.value_type), new CCodeVariableDeclarator ("result"));
1827 if (is_virtual) {
1828 ccode.add_declaration (get_ccode_name (this_type), new CCodeVariableDeclarator ("self"));
1829 ccode.add_assignment (new CCodeIdentifier ("self"), get_cvalue_ (transform_value (new GLibValue (base_type, new CCodeIdentifier ("base"), true), this_type, acc)));
1832 // notify on property changes
1833 if (is_gobject_property (prop) &&
1834 prop.notify &&
1835 (acc.writable || acc.construction)) {
1836 var notify_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_notify_by_pspec"));
1837 notify_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
1838 notify_call.add_argument (get_param_spec_cexpression (prop));
1840 var get_accessor = prop.get_accessor;
1841 if (get_accessor != null && get_accessor.automatic_body) {
1842 var property_type = prop.property_type;
1843 var get_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (get_accessor)));
1844 get_call.add_argument (new CCodeIdentifier (is_virtual ? "base" : "self"));
1846 if (property_type is ArrayType) {
1847 ccode.add_declaration ("int", new CCodeVariableDeclarator ("old_value_length"));
1848 get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value_length")));
1849 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_call, new CCodeIdentifier ("value")));
1850 } else if (property_type.compatible (string_type)) {
1851 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
1852 ccall.add_argument (new CCodeIdentifier ("value"));
1853 ccall.add_argument (get_call);
1854 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("0")));
1855 } else if (property_type is StructValueType) {
1856 ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
1857 get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value")));
1859 var get_expr = new CCodeCommaExpression ();
1860 get_expr.append_expression (get_call);
1861 get_expr.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value")));
1863 var equalfunc = generate_struct_equal_function ((Struct) property_type.data_type);
1864 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
1865 ccall.add_argument (new CCodeIdentifier ("value"));
1866 ccall.add_argument (get_expr);
1867 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("TRUE")));
1868 } else {
1869 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_call, new CCodeIdentifier ("value")));
1872 acc.body.emit (this);
1873 ccode.add_expression (notify_call);
1874 ccode.close ();
1875 } else {
1876 acc.body.emit (this);
1877 ccode.add_expression (notify_call);
1879 } else {
1880 acc.body.emit (this);
1883 if (current_method_inner_error) {
1884 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
1887 cfile.add_function (function);
1890 pop_line ();
1891 pop_context ();
1894 public override void visit_destructor (Destructor d) {
1895 if (d.binding == MemberBinding.STATIC && !in_plugin) {
1896 Report.error (d.source_reference, "static destructors are only supported for dynamic types");
1897 d.error = true;
1898 return;
1902 public int get_block_id (Block b) {
1903 int result = block_map[b];
1904 if (result == 0) {
1905 result = ++next_block_id;
1906 block_map[b] = result;
1908 return result;
1911 public bool no_implicit_copy (DataType type) {
1912 // note: implicit copy of array is planned to be forbidden
1913 var cl = type.data_type as Class;
1914 return (type is DelegateType ||
1915 type.is_array () ||
1916 (cl != null && !cl.is_immutable && !is_reference_counting (cl) && !get_ccode_is_gboxed (cl)));
1919 void capture_parameter (Parameter param, CCodeStruct data, int block_id) {
1920 generate_type_declaration (param.variable_type, cfile);
1922 var param_type = param.variable_type.copy ();
1923 if (!param.variable_type.value_owned) {
1924 param_type.value_owned = !no_implicit_copy (param.variable_type);
1926 data.add_field (get_ccode_name (param_type), get_variable_cname (param.name));
1928 // create copy if necessary as captured variables may need to be kept alive
1929 param.captured = false;
1930 var value = load_parameter (param);
1932 var array_type = param.variable_type as ArrayType;
1933 var deleg_type = param.variable_type as DelegateType;
1935 if (array_type != null && get_ccode_array_length (param)) {
1936 for (int dim = 1; dim <= array_type.rank; dim++) {
1937 data.add_field ("gint", get_parameter_array_length_cname (param, dim));
1939 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
1940 data.add_field ("gpointer", get_ccode_delegate_target_name (param));
1941 if (param.variable_type.is_disposable ()) {
1942 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
1943 // reference transfer for delegates
1944 var lvalue = get_parameter_cvalue (param);
1945 ((GLibValue) value).delegate_target_destroy_notify_cvalue = get_delegate_target_destroy_notify_cvalue (lvalue);
1948 param.captured = true;
1950 store_parameter (param, value, true);
1953 public override void visit_block (Block b) {
1954 emit_context.push_symbol (b);
1956 var local_vars = b.get_local_variables ();
1958 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
1959 ccode.open_block ();
1962 if (b.captured) {
1963 var parent_block = next_closure_block (b.parent_symbol);
1965 int block_id = get_block_id (b);
1966 string struct_name = "Block%dData".printf (block_id);
1968 var data = new CCodeStruct ("_" + struct_name);
1969 data.add_field ("int", "_ref_count_");
1970 if (parent_block != null) {
1971 int parent_block_id = get_block_id (parent_block);
1973 data.add_field ("Block%dData *".printf (parent_block_id), "_data%d_".printf (parent_block_id));
1974 } else {
1975 if (get_this_type () != null) {
1976 data.add_field (get_ccode_name (get_data_type_for_symbol (current_type_symbol)), "self");
1979 if (current_method != null) {
1980 // allow capturing generic type parameters
1981 foreach (var type_param in current_method.get_type_parameters ()) {
1982 string func_name;
1984 func_name = "%s_type".printf (type_param.name.down ());
1985 data.add_field ("GType", func_name);
1987 func_name = "%s_dup_func".printf (type_param.name.down ());
1988 data.add_field ("GBoxedCopyFunc", func_name);
1990 func_name = "%s_destroy_func".printf (type_param.name.down ());
1991 data.add_field ("GDestroyNotify", func_name);
1995 foreach (var local in local_vars) {
1996 if (local.captured) {
1997 generate_type_declaration (local.variable_type, cfile);
1999 data.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
2001 if (local.variable_type is ArrayType && !((ArrayType) local.variable_type).fixed_length) {
2002 var array_type = (ArrayType) local.variable_type;
2003 for (int dim = 1; dim <= array_type.rank; dim++) {
2004 data.add_field ("gint", get_array_length_cname (get_local_cname (local), dim));
2006 data.add_field ("gint", get_array_size_cname (get_local_cname (local)));
2007 } else if (local.variable_type is DelegateType && ((DelegateType) local.variable_type).delegate_symbol.has_target) {
2008 data.add_field ("gpointer", get_delegate_target_cname (get_local_cname (local)));
2009 if (local.variable_type.is_disposable ()) {
2010 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2016 var data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
2017 data_alloc.add_argument (new CCodeIdentifier (struct_name));
2019 if (is_in_coroutine ()) {
2020 closure_struct.add_field (struct_name + "*", "_data%d_".printf (block_id));
2021 } else {
2022 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id)));
2024 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), data_alloc);
2026 // initialize ref_count
2027 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_ref_count_"), new CCodeIdentifier ("1"));
2029 if (parent_block != null) {
2030 int parent_block_id = get_block_id (parent_block);
2032 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (parent_block_id)));
2033 ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id)));
2035 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call);
2036 } else {
2037 // skip self assignment in toplevel block of creation methods with chainup as self is not set at the beginning of the method
2038 // the chainup statement takes care of assigning self in the closure struct
2039 bool in_creation_method_with_chainup = (current_method is CreationMethod && current_class != null && current_class.base_class != null);
2041 if (get_this_type () != null && (!in_creation_method_with_chainup || current_method.body != b)) {
2042 var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_data_type_for_symbol (current_type_symbol), b.source_reference));
2043 ref_call.add_argument (get_result_cexpression ("self"));
2045 // never increase reference count for self in finalizers to avoid infinite recursion on following unref
2046 var instance = (is_in_destructor () ? (CCodeExpression) new CCodeIdentifier ("self") : (CCodeExpression) ref_call);
2048 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), instance);
2051 if (current_method != null) {
2052 // allow capturing generic type parameters
2053 var suffices = new string[] {"type", "dup_func", "destroy_func"};
2054 foreach (var type_param in current_method.get_type_parameters ()) {
2055 foreach (string suffix in suffices) {
2056 string func_name = "%s_%s".printf (type_param.name.down (), suffix);
2057 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name), get_variable_cexpression (func_name));
2063 if (b.parent_symbol is Method) {
2064 var m = (Method) b.parent_symbol;
2066 // parameters are captured with the top-level block of the method
2067 foreach (var param in m.get_parameters ()) {
2068 if (param.captured) {
2069 capture_parameter (param, data, block_id);
2073 if (m.coroutine) {
2074 // capture async data to allow invoking callback from inside closure
2075 data.add_field ("gpointer", "_async_data_");
2077 // async method is suspended while waiting for callback,
2078 // so we never need to care about memory management of async data
2079 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_async_data_"), new CCodeIdentifier ("_data_"));
2081 } else if (b.parent_symbol is PropertyAccessor) {
2082 var acc = (PropertyAccessor) b.parent_symbol;
2084 if (!acc.readable && acc.value_parameter.captured) {
2085 capture_parameter (acc.value_parameter, data, block_id);
2087 } else if (b.parent_symbol is ForeachStatement) {
2088 var stmt = (ForeachStatement) b.parent_symbol;
2089 if (!stmt.use_iterator && stmt.element_variable.captured) {
2090 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)));
2094 var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name));
2095 cfile.add_type_declaration (typedef);
2096 cfile.add_type_definition (data);
2098 // create ref/unref functions
2099 var ref_fun = new CCodeFunction ("block%d_data_ref".printf (block_id), struct_name + "*");
2100 ref_fun.add_parameter (new CCodeParameter ("_data%d_".printf (block_id), struct_name + "*"));
2101 ref_fun.modifiers = CCodeModifiers.STATIC;
2103 push_function (ref_fun);
2105 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_inc"));
2106 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2107 ccode.add_expression (ccall);
2108 ccode.add_return (new CCodeIdentifier ("_data%d_".printf (block_id)));
2110 pop_function ();
2112 cfile.add_function_declaration (ref_fun);
2113 cfile.add_function (ref_fun);
2115 var unref_fun = new CCodeFunction ("block%d_data_unref".printf (block_id), "void");
2116 unref_fun.add_parameter (new CCodeParameter ("_userdata_", "void *"));
2117 unref_fun.modifiers = CCodeModifiers.STATIC;
2119 push_function (unref_fun);
2121 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id), new CCodeCastExpression (new CCodeIdentifier ("_userdata_"), struct_name + "*")));
2122 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_dec_and_test"));
2123 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2124 ccode.open_if (ccall);
2126 CCodeExpression outer_block = new CCodeIdentifier ("_data%d_".printf (block_id));
2127 unowned Block parent_closure_block = b;
2128 while (true) {
2129 parent_closure_block = next_closure_block (parent_closure_block.parent_symbol);
2130 if (parent_closure_block == null) {
2131 break;
2133 int parent_block_id = get_block_id (parent_closure_block);
2134 outer_block = new CCodeMemberAccess.pointer (outer_block, "_data%d_".printf (parent_block_id));
2137 if (get_this_type () != null) {
2138 // assign "self" for type parameters
2139 ccode.add_declaration(get_ccode_name (get_data_type_for_symbol (current_type_symbol)), new CCodeVariableDeclarator ("self"));
2140 ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeMemberAccess.pointer (outer_block, "self"));
2143 if (current_method != null) {
2144 // assign captured generic type parameters
2145 foreach (var type_param in current_method.get_type_parameters ()) {
2146 string func_name;
2148 func_name = "%s_type".printf (type_param.name.down ());
2149 ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name));
2150 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2152 func_name = "%s_dup_func".printf (type_param.name.down ());
2153 ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name));
2154 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2156 func_name = "%s_destroy_func".printf (type_param.name.down ());
2157 ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name));
2158 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2162 // free in reverse order
2163 for (int i = local_vars.size - 1; i >= 0; i--) {
2164 var local = local_vars[i];
2165 if (local.captured) {
2166 if (requires_destroy (local.variable_type)) {
2167 bool old_coroutine = false;
2168 if (current_method != null) {
2169 old_coroutine = current_method.coroutine;
2170 current_method.coroutine = false;
2173 ccode.add_expression (destroy_local (local));
2175 if (old_coroutine) {
2176 current_method.coroutine = true;
2182 if (b.parent_symbol is Method) {
2183 var m = (Method) b.parent_symbol;
2185 // parameters are captured with the top-level block of the method
2186 foreach (var param in m.get_parameters ()) {
2187 if (param.captured) {
2188 var param_type = param.variable_type.copy ();
2189 if (!param_type.value_owned) {
2190 param_type.value_owned = !no_implicit_copy (param_type);
2193 if (requires_destroy (param_type)) {
2194 bool old_coroutine = false;
2195 if (m != null) {
2196 old_coroutine = m.coroutine;
2197 m.coroutine = false;
2200 ccode.add_expression (destroy_parameter (param));
2202 if (old_coroutine) {
2203 m.coroutine = true;
2208 } else if (b.parent_symbol is PropertyAccessor) {
2209 var acc = (PropertyAccessor) b.parent_symbol;
2211 if (!acc.readable && acc.value_parameter.captured) {
2212 var param_type = acc.value_parameter.variable_type.copy ();
2213 if (!param_type.value_owned) {
2214 param_type.value_owned = !no_implicit_copy (param_type);
2217 if (requires_destroy (param_type)) {
2218 ccode.add_expression (destroy_parameter (acc.value_parameter));
2223 // free parent block and "self" after captured variables
2224 // because they may require type parameters
2225 if (parent_block != null) {
2226 int parent_block_id = get_block_id (parent_block);
2228 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (parent_block_id)));
2229 unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
2230 ccode.add_expression (unref_call);
2231 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), new CCodeConstant ("NULL"));
2232 } else {
2233 var this_type = get_this_type ();
2234 if (this_type != null) {
2235 this_type = this_type.copy ();
2236 this_type.value_owned = true;
2237 if (this_type.is_disposable () && !is_in_destructor ()) {
2238 // reference count for self is not increased in finalizers
2239 var this_value = new GLibValue (get_data_type_for_symbol (current_type_symbol), new CCodeIdentifier ("self"), true);
2240 ccode.add_expression (destroy_value (this_value));
2245 var data_free = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
2246 data_free.add_argument (new CCodeIdentifier (struct_name));
2247 data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id)));
2248 ccode.add_expression (data_free);
2250 ccode.close ();
2252 pop_function ();
2254 cfile.add_function_declaration (unref_fun);
2255 cfile.add_function (unref_fun);
2258 foreach (Statement stmt in b.get_statements ()) {
2259 push_line (stmt.source_reference);
2260 stmt.emit (this);
2261 pop_line ();
2264 // free in reverse order
2265 for (int i = local_vars.size - 1; i >= 0; i--) {
2266 var local = local_vars[i];
2267 local.active = false;
2268 if (!local.unreachable && !local.captured && requires_destroy (local.variable_type)) {
2269 ccode.add_expression (destroy_local (local));
2273 if (b.parent_symbol is Method) {
2274 var m = (Method) b.parent_symbol;
2275 foreach (Parameter param in m.get_parameters ()) {
2276 if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
2277 ccode.add_expression (destroy_parameter (param));
2278 } else if (param.direction == ParameterDirection.OUT && !m.coroutine) {
2279 return_out_parameter (param);
2282 // check postconditions
2283 foreach (var postcondition in m.get_postconditions ()) {
2284 create_postcondition_statement (postcondition);
2286 } else if (b.parent_symbol is PropertyAccessor) {
2287 var acc = (PropertyAccessor) b.parent_symbol;
2288 if (acc.value_parameter != null && !acc.value_parameter.captured && requires_destroy (acc.value_parameter.variable_type)) {
2289 ccode.add_expression (destroy_parameter (acc.value_parameter));
2293 if (b.captured) {
2294 int block_id = get_block_id (b);
2296 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
2297 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
2298 ccode.add_expression (data_unref);
2299 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
2302 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
2303 ccode.close ();
2306 emit_context.pop_symbol ();
2309 public override void visit_declaration_statement (DeclarationStatement stmt) {
2310 stmt.declaration.accept (this);
2313 public CCodeExpression get_local_cexpression (LocalVariable local) {
2314 if (is_in_coroutine ()) {
2315 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_local_cname (local));
2316 } else {
2317 return new CCodeIdentifier (get_local_cname (local));
2321 public CCodeExpression get_variable_cexpression (string name) {
2322 if (is_in_coroutine ()) {
2323 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_variable_cname (name));
2324 } else {
2325 return new CCodeIdentifier (get_variable_cname (name));
2329 public CCodeExpression get_this_cexpression () {
2330 if (is_in_coroutine ()) {
2331 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
2332 } else {
2333 return new CCodeIdentifier ("self");
2337 public string get_local_cname (LocalVariable local) {
2338 var cname = get_variable_cname (local.name);
2339 if (cname[0].isdigit ()) {
2340 cname = "_%s_".printf (cname);
2342 if (is_in_coroutine ()) {
2343 var clash_index = emit_context.closure_variable_clash_map.get (local);
2344 if (clash_index > 0) {
2345 cname = "_vala%d_%s".printf (clash_index, cname);
2348 return cname;
2351 public string get_variable_cname (string name) {
2352 if (name[0] == '.') {
2353 if (name == ".result") {
2354 return "result";
2356 // compiler-internal variable
2357 if (!variable_name_map.contains (name)) {
2358 variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
2359 next_temp_var_id++;
2361 return variable_name_map.get (name);
2362 } else if (reserved_identifiers.contains (name)) {
2363 return "_%s_".printf (name);
2364 } else {
2365 return name;
2369 public CCodeExpression get_result_cexpression (string cname = "result") {
2370 if (is_in_coroutine ()) {
2371 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), cname);
2372 } else {
2373 return new CCodeIdentifier (cname);
2377 public bool is_simple_struct_creation (Variable variable, Expression expr) {
2378 var st = variable.variable_type.data_type as Struct;
2379 var creation = expr as ObjectCreationExpression;
2380 if (creation != null && st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list") && !variable.variable_type.nullable &&
2381 variable.variable_type.data_type != gvalue_type && creation.get_object_initializer ().size == 0) {
2382 return true;
2383 } else {
2384 return false;
2388 bool is_foreach_element_variable (LocalVariable local) {
2389 var block = local.parent_symbol;
2390 if (block != null) {
2391 var stmt = block.parent_symbol as ForeachStatement;
2392 if (stmt != null && !stmt.use_iterator && stmt.element_variable == local) {
2393 return true;
2396 return false;
2399 public override void visit_local_variable (LocalVariable local) {
2400 check_type (local.variable_type);
2402 /* Declaration */
2404 generate_type_declaration (local.variable_type, cfile);
2406 // captured element variables of foreach statements (without iterator) require local declaration
2407 var declared = !local.captured || is_foreach_element_variable (local);
2408 if (declared) {
2409 if (is_in_coroutine ()) {
2410 var count = emit_context.closure_variable_count_map.get (local.name);
2411 if (count > 0) {
2412 emit_context.closure_variable_clash_map.set (local, count);
2414 emit_context.closure_variable_count_map.set (local.name, count + 1);
2416 closure_struct.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
2417 } else {
2418 var cvar = new CCodeVariableDeclarator (get_local_cname (local), null, get_ccode_declarator_suffix (local.variable_type));
2420 // try to initialize uninitialized variables
2421 // initialization not necessary for variables stored in closure
2422 cvar.initializer = default_value_for_type (local.variable_type, true);
2423 cvar.init0 = true;
2425 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
2429 /* Emit initializer */
2430 if (local.initializer != null) {
2431 local.initializer.emit (this);
2433 visit_end_full_expression (local.initializer);
2437 CCodeExpression rhs = null;
2438 if (local.initializer != null && get_cvalue (local.initializer) != null) {
2439 rhs = get_cvalue (local.initializer);
2442 /* Additional temp variables */
2444 if (declared) {
2445 if (local.variable_type is ArrayType) {
2446 // create variables to store array dimensions
2447 var array_type = (ArrayType) local.variable_type;
2449 if (!array_type.fixed_length) {
2450 for (int dim = 1; dim <= array_type.rank; dim++) {
2451 var len_var = new LocalVariable (int_type.copy (), get_array_length_cname (get_local_cname (local), dim));
2452 len_var.init = local.initializer == null;
2453 emit_temp_var (len_var);
2456 if (array_type.rank == 1) {
2457 var size_var = new LocalVariable (int_type.copy (), get_array_size_cname (get_local_cname (local)));
2458 size_var.init = local.initializer == null;
2459 emit_temp_var (size_var);
2462 } else if (local.variable_type is DelegateType) {
2463 var deleg_type = (DelegateType) local.variable_type;
2464 if (deleg_type.delegate_symbol.has_target) {
2465 // create variable to store delegate target
2466 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (get_local_cname (local)));
2467 target_var.init = local.initializer == null;
2468 emit_temp_var (target_var);
2469 if (deleg_type.is_disposable ()) {
2470 var target_destroy_notify_var = new LocalVariable (gdestroynotify_type, get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2471 target_destroy_notify_var.init = local.initializer == null;
2472 emit_temp_var (target_destroy_notify_var);
2478 /* Store the initializer */
2480 if (rhs != null) {
2481 if (!is_simple_struct_creation (local, local.initializer)) {
2482 store_local (local, local.initializer.target_value, true, local.source_reference);
2486 if (local.initializer != null && local.initializer.tree_can_fail) {
2487 add_simple_check (local.initializer);
2490 local.active = true;
2494 * Create a temporary variable and return lvalue access to it
2496 public TargetValue create_temp_value (DataType type, bool init, CodeNode node_reference, bool? value_owned = null) {
2497 var local = new LocalVariable (type.copy (), "_tmp%d_".printf (next_temp_var_id++), null, node_reference.source_reference);
2498 local.init = init;
2499 if (value_owned != null) {
2500 local.variable_type.value_owned = value_owned;
2503 var array_type = local.variable_type as ArrayType;
2504 var deleg_type = local.variable_type as DelegateType;
2506 emit_temp_var (local);
2507 if (array_type != null) {
2508 for (int dim = 1; dim <= array_type.rank; dim++) {
2509 var len_var = new LocalVariable (int_type.copy (), get_array_length_cname (local.name, dim), null, node_reference.source_reference);
2510 len_var.init = init;
2511 emit_temp_var (len_var);
2513 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
2514 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (local.name), null, node_reference.source_reference);
2515 target_var.init = init;
2516 emit_temp_var (target_var);
2517 if (deleg_type.is_disposable ()) {
2518 var target_destroy_notify_var = new LocalVariable (gdestroynotify_type.copy (), get_delegate_target_destroy_notify_cname (local.name), null, node_reference.source_reference);
2519 target_destroy_notify_var.init = init;
2520 emit_temp_var (target_destroy_notify_var);
2524 var value = get_local_cvalue (local);
2525 set_array_size_cvalue (value, null);
2526 return value;
2530 * Load a temporary variable returning unowned or owned rvalue access to it, depending on the ownership of the value type.
2532 public TargetValue load_temp_value (TargetValue lvalue) {
2533 var value = ((GLibValue) lvalue).copy ();
2534 var deleg_type = value.value_type as DelegateType;
2535 if (deleg_type != null) {
2536 if (!deleg_type.delegate_symbol.has_target) {
2537 value.delegate_target_cvalue = new CCodeConstant ("NULL");
2538 ((GLibValue) value).lvalue = false;
2539 } else if (!deleg_type.is_disposable ()) {
2540 value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
2541 ((GLibValue) value).lvalue = false;
2544 return value;
2548 * Store a value in a temporary variable and return unowned or owned rvalue access to it, depending on the ownership of the given type.
2550 public TargetValue store_temp_value (TargetValue initializer, CodeNode node_reference, bool? value_owned = null) {
2551 var lvalue = create_temp_value (initializer.value_type, false, node_reference, value_owned);
2552 store_value (lvalue, initializer, node_reference.source_reference);
2553 return load_temp_value (lvalue);
2556 public override void visit_initializer_list (InitializerList list) {
2557 if (list.target_type.data_type is Struct) {
2558 /* initializer is used as struct initializer */
2559 var st = (Struct) list.target_type.data_type;
2560 while (st.base_struct != null) {
2561 st = st.base_struct;
2564 if (list.parent_node is Constant || list.parent_node is Field || list.parent_node is InitializerList) {
2565 var clist = new CCodeInitializerList ();
2567 var field_it = st.get_fields ().iterator ();
2568 foreach (Expression expr in list.get_initializers ()) {
2569 Field field = null;
2570 while (field == null) {
2571 field_it.next ();
2572 field = field_it.get ();
2573 if (field.binding != MemberBinding.INSTANCE) {
2574 // we only initialize instance fields
2575 field = null;
2579 var cexpr = get_cvalue (expr);
2581 string ctype = get_ccode_type (field);
2582 if (ctype != null) {
2583 cexpr = new CCodeCastExpression (cexpr, ctype);
2586 clist.append (cexpr);
2588 var array_type = field.variable_type as ArrayType;
2589 if (array_type != null && !array_type.fixed_length && get_ccode_array_length (field) && !get_ccode_array_null_terminated (field)) {
2590 for (int dim = 1; dim <= array_type.rank; dim++) {
2591 clist.append (get_array_length_cvalue (expr.target_value, dim));
2596 set_cvalue (list, clist);
2597 } else {
2598 // used as expression
2599 var instance = create_temp_value (list.value_type, true, list);
2601 var field_it = st.get_fields ().iterator ();
2602 foreach (Expression expr in list.get_initializers ()) {
2603 Field field = null;
2604 while (field == null) {
2605 field_it.next ();
2606 field = field_it.get ();
2607 if (field.binding != MemberBinding.INSTANCE) {
2608 // we only initialize instance fields
2609 field = null;
2613 store_field (field, instance, expr.target_value, expr.source_reference);
2616 list.target_value = instance;
2618 } else {
2619 var clist = new CCodeInitializerList ();
2620 foreach (Expression expr in list.get_initializers ()) {
2621 clist.append (get_cvalue (expr));
2623 set_cvalue (list, clist);
2627 public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null, bool init = false) {
2628 var var_type = type.copy ();
2629 var_type.value_owned = value_owned;
2630 var local = new LocalVariable (var_type, "_tmp%d_".printf (next_temp_var_id));
2631 local.init = init;
2633 if (node_reference != null) {
2634 local.source_reference = node_reference.source_reference;
2637 next_temp_var_id++;
2639 return local;
2642 bool is_in_generic_type (GenericType type) {
2643 if (current_symbol != null && type.type_parameter.parent_symbol is TypeSymbol
2644 && (current_method == null || current_method.binding == MemberBinding.INSTANCE)) {
2645 return true;
2646 } else {
2647 return false;
2651 void require_generic_accessors (Interface iface) {
2652 if (iface.get_attribute ("GenericAccessors") == null) {
2653 Report.error (iface.source_reference,
2654 "missing generic type for interface `%s', add GenericAccessors attribute to interface declaration"
2655 .printf (iface.get_full_name ()));
2659 public CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
2660 if (type is GenericType) {
2661 var type_parameter = ((GenericType) type).type_parameter;
2662 string var_name = "%s_type".printf (type_parameter.name.down ());
2664 if (type_parameter.parent_symbol is Interface) {
2665 var iface = (Interface) type_parameter.parent_symbol;
2666 require_generic_accessors (iface);
2668 string method_name = "get_%s_type".printf (type_parameter.name.down ());
2669 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
2670 cast_self.add_argument (new CCodeIdentifier ("self"));
2671 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
2672 function_call.add_argument (new CCodeIdentifier ("self"));
2673 return function_call;
2676 if (is_in_generic_type ((GenericType) type) && !is_chainup && !in_creation_method) {
2677 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), var_name);
2678 } else {
2679 return get_variable_cexpression (var_name);
2681 } else {
2682 string type_id = get_ccode_type_id (type);
2683 if (type_id == "") {
2684 type_id = "G_TYPE_INVALID";
2685 } else {
2686 generate_type_declaration (type, cfile);
2688 return new CCodeIdentifier (type_id);
2692 public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup = false) {
2693 if (type is ErrorType) {
2694 return new CCodeIdentifier ("g_error_copy");
2695 } else if (type.data_type != null) {
2696 string dup_function;
2697 var cl = type.data_type as Class;
2698 if (is_reference_counting (type.data_type)) {
2699 dup_function = get_ccode_ref_function ((ObjectTypeSymbol) type.data_type);
2700 if (type.data_type is Interface && dup_function == null) {
2701 Report.error (source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure".printf (type.data_type.get_full_name ()));
2702 return new CCodeInvalidExpression();
2704 } else if (cl != null && cl.is_immutable) {
2705 // allow duplicates of immutable instances as for example strings
2706 dup_function = get_ccode_dup_function (type.data_type);
2707 if (dup_function == null) {
2708 dup_function = "";
2710 } else if (cl != null && get_ccode_is_gboxed (cl)) {
2711 // allow duplicates of gboxed instances
2712 dup_function = generate_dup_func_wrapper (type);
2713 if (dup_function == null) {
2714 dup_function = "";
2716 } else if (type is ValueType) {
2717 dup_function = get_ccode_dup_function (type.data_type);
2718 if (dup_function == null && type.nullable) {
2719 dup_function = generate_struct_dup_wrapper ((ValueType) type);
2720 } else if (dup_function == null) {
2721 dup_function = "";
2723 } else {
2724 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2725 Report.error (source_reference, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type.data_type.name));
2726 return new CCodeInvalidExpression();
2729 return new CCodeIdentifier (dup_function);
2730 } else if (type is GenericType) {
2731 var type_parameter = ((GenericType) type).type_parameter;
2732 string func_name = "%s_dup_func".printf (type_parameter.name.down ());
2734 if (type_parameter.parent_symbol is Interface) {
2735 var iface = (Interface) type_parameter.parent_symbol;
2736 require_generic_accessors (iface);
2738 string method_name = "get_%s_dup_func".printf (type_parameter.name.down ());
2739 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
2740 cast_self.add_argument (new CCodeIdentifier ("self"));
2741 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
2742 function_call.add_argument (new CCodeIdentifier ("self"));
2743 return function_call;
2746 if (is_in_generic_type ((GenericType) type) && !is_chainup && !in_creation_method) {
2747 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
2748 } else {
2749 return get_variable_cexpression (func_name);
2751 } else if (type is PointerType) {
2752 var pointer_type = (PointerType) type;
2753 return get_dup_func_expression (pointer_type.base_type, source_reference);
2754 } else {
2755 return new CCodeConstant ("NULL");
2759 void make_comparable_cexpression (ref DataType left_type, ref CCodeExpression cleft, ref DataType right_type, ref CCodeExpression cright) {
2760 var left_type_as_struct = left_type.data_type as Struct;
2761 var right_type_as_struct = right_type.data_type as Struct;
2763 // GValue support
2764 var valuecast = try_cast_value_to_type (cleft, left_type, right_type);
2765 if (valuecast != null) {
2766 cleft = valuecast;
2767 left_type = right_type;
2768 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2769 return;
2772 valuecast = try_cast_value_to_type (cright, right_type, left_type);
2773 if (valuecast != null) {
2774 cright = valuecast;
2775 right_type = left_type;
2776 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2777 return;
2780 if (left_type.data_type is Class && !((Class) left_type.data_type).is_compact &&
2781 right_type.data_type is Class && !((Class) right_type.data_type).is_compact) {
2782 var left_cl = (Class) left_type.data_type;
2783 var right_cl = (Class) right_type.data_type;
2785 if (left_cl != right_cl) {
2786 if (left_cl.is_subtype_of (right_cl)) {
2787 cleft = generate_instance_cast (cleft, right_cl);
2788 } else if (right_cl.is_subtype_of (left_cl)) {
2789 cright = generate_instance_cast (cright, left_cl);
2792 } else if (left_type_as_struct != null && right_type_as_struct != null) {
2793 if (left_type is StructValueType) {
2794 // real structs (uses compare/equal function)
2795 if (!left_type.nullable) {
2796 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft);
2798 if (!right_type.nullable) {
2799 cright = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cright);
2801 } else {
2802 // integer or floating or boolean type
2803 if (left_type.nullable && right_type.nullable) {
2804 // FIXME also compare contents, not just address
2805 } else if (left_type.nullable) {
2806 // FIXME check left value is not null
2807 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
2808 } else if (right_type.nullable) {
2809 // FIXME check right value is not null
2810 cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
2816 private string generate_struct_equal_function (Struct st) {
2817 if (st.base_struct != null) {
2818 return generate_struct_equal_function (st.base_struct);
2821 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (st));
2823 if (!add_wrapper (equal_func)) {
2824 // wrapper already defined
2825 return equal_func;
2828 var function = new CCodeFunction (equal_func, "gboolean");
2829 function.modifiers = CCodeModifiers.STATIC;
2831 function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (st))));
2832 function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (st))));
2834 push_function (function);
2836 // if (s1 == s2) return TRUE;
2838 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2839 ccode.open_if (cexp);
2840 ccode.add_return (new CCodeConstant ("TRUE"));
2841 ccode.close ();
2843 // if (s1 == NULL || s2 == NULL) return FALSE;
2845 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2846 ccode.open_if (cexp);
2847 ccode.add_return (new CCodeConstant ("FALSE"));
2848 ccode.close ();
2850 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2851 ccode.open_if (cexp);
2852 ccode.add_return (new CCodeConstant ("FALSE"));
2853 ccode.close ();
2856 bool has_instance_fields = false;
2857 foreach (Field f in st.get_fields ()) {
2858 if (f.binding != MemberBinding.INSTANCE) {
2859 // we only compare instance fields
2860 continue;
2863 has_instance_fields = true;
2865 CCodeExpression cexp; // if (cexp) return FALSE;
2866 var s1 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s1"), get_ccode_name (f)); // s1->f
2867 var s2 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s2"), get_ccode_name (f)); // s2->f
2869 var variable_type = f.variable_type.copy ();
2870 make_comparable_cexpression (ref variable_type, ref s1, ref variable_type, ref s2);
2872 if (!(f.variable_type is NullType) && f.variable_type.compatible (string_type)) {
2873 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
2874 ccall.add_argument (s1);
2875 ccall.add_argument (s2);
2876 cexp = ccall;
2877 } else if (f.variable_type is StructValueType) {
2878 var equalfunc = generate_struct_equal_function (f.variable_type.data_type as Struct);
2879 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
2880 ccall.add_argument (s1);
2881 ccall.add_argument (s2);
2882 cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
2883 } else {
2884 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, s1, s2);
2887 ccode.open_if (cexp);
2888 ccode.add_return (new CCodeConstant ("FALSE"));
2889 ccode.close ();
2892 if (!has_instance_fields) {
2893 // either opaque structure or simple type
2894 if (st.is_simple_type ()) {
2895 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2896 ccode.add_return (cexp);
2897 } else {
2898 ccode.add_return (new CCodeConstant ("FALSE"));
2900 } else {
2901 ccode.add_return (new CCodeConstant ("TRUE"));
2904 pop_function ();
2906 cfile.add_function_declaration (function);
2907 cfile.add_function (function);
2909 return equal_func;
2912 private string generate_numeric_equal_function (TypeSymbol sym) {
2913 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (sym));
2915 if (!add_wrapper (equal_func)) {
2916 // wrapper already defined
2917 return equal_func;
2920 var function = new CCodeFunction (equal_func, "gboolean");
2921 function.modifiers = CCodeModifiers.STATIC;
2923 function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (sym))));
2924 function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (sym))));
2926 push_function (function);
2928 // if (s1 == s2) return TRUE;
2930 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2931 ccode.open_if (cexp);
2932 ccode.add_return (new CCodeConstant ("TRUE"));
2933 ccode.close ();
2935 // if (s1 == NULL || s2 == NULL) return FALSE;
2937 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2938 ccode.open_if (cexp);
2939 ccode.add_return (new CCodeConstant ("FALSE"));
2940 ccode.close ();
2942 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2943 ccode.open_if (cexp);
2944 ccode.add_return (new CCodeConstant ("FALSE"));
2945 ccode.close ();
2947 // return (*s1 == *s2);
2949 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2950 ccode.add_return (cexp);
2953 pop_function ();
2955 cfile.add_function_declaration (function);
2956 cfile.add_function (function);
2958 return equal_func;
2961 private string generate_struct_dup_wrapper (ValueType value_type) {
2962 string dup_func = "_%sdup".printf (get_ccode_lower_case_prefix (value_type.type_symbol));
2964 if (!add_wrapper (dup_func)) {
2965 // wrapper already defined
2966 return dup_func;
2969 var function = new CCodeFunction (dup_func, get_ccode_name (value_type));
2970 function.modifiers = CCodeModifiers.STATIC;
2972 function.add_parameter (new CCodeParameter ("self", get_ccode_name (value_type)));
2974 push_function (function);
2976 if (value_type.type_symbol == gvalue_type) {
2977 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
2978 dup_call.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
2979 dup_call.add_argument (new CCodeIdentifier ("self"));
2981 ccode.add_return (dup_call);
2982 } else {
2983 ccode.add_declaration (get_ccode_name (value_type), new CCodeVariableDeclarator ("dup"));
2985 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
2986 creation_call.add_argument (new CCodeConstant (get_ccode_name (value_type.data_type)));
2987 creation_call.add_argument (new CCodeConstant ("1"));
2988 ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
2990 var st = value_type.data_type as Struct;
2991 if (st != null && st.is_disposable ()) {
2992 if (!get_ccode_has_copy_function (st)) {
2993 generate_struct_copy_function (st);
2996 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
2997 copy_call.add_argument (new CCodeIdentifier ("self"));
2998 copy_call.add_argument (new CCodeIdentifier ("dup"));
2999 ccode.add_expression (copy_call);
3000 } else {
3001 cfile.add_include ("string.h");
3003 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
3004 sizeof_call.add_argument (new CCodeConstant (get_ccode_name (value_type.data_type)));
3006 var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
3007 copy_call.add_argument (new CCodeIdentifier ("dup"));
3008 copy_call.add_argument (new CCodeIdentifier ("self"));
3009 copy_call.add_argument (sizeof_call);
3010 ccode.add_expression (copy_call);
3013 ccode.add_return (new CCodeIdentifier ("dup"));
3016 pop_function ();
3018 cfile.add_function_declaration (function);
3019 cfile.add_function (function);
3021 return dup_func;
3024 protected string generate_dup_func_wrapper (DataType type) {
3025 string destroy_func = "_vala_%s_copy".printf (get_ccode_name (type.data_type));
3027 if (!add_wrapper (destroy_func)) {
3028 // wrapper already defined
3029 return destroy_func;
3032 var function = new CCodeFunction (destroy_func, get_ccode_name (type));
3033 function.modifiers = CCodeModifiers.STATIC;
3034 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3036 push_function (function);
3038 var cl = type.data_type as Class;
3039 assert (cl != null && get_ccode_is_gboxed (cl));
3041 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
3042 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
3043 free_call.add_argument (new CCodeIdentifier ("self"));
3045 ccode.add_return (free_call);
3047 pop_function ();
3049 cfile.add_function_declaration (function);
3050 cfile.add_function (function);
3052 return destroy_func;
3055 protected string generate_free_function_address_of_wrapper (DataType type) {
3056 string destroy_func = "_vala_%s_free_function_address_of".printf (get_ccode_name (type.data_type));
3058 if (!add_wrapper (destroy_func)) {
3059 // wrapper already defined
3060 return destroy_func;
3063 var function = new CCodeFunction (destroy_func, "void");
3064 function.modifiers = CCodeModifiers.STATIC;
3065 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3067 push_function (function);
3069 var cl = type.data_type as Class;
3070 var free_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (cl)));
3071 free_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("self")));
3073 ccode.add_expression (free_call);
3075 pop_function ();
3077 cfile.add_function_declaration (function);
3078 cfile.add_function (function);
3080 return destroy_func;
3083 protected string generate_free_func_wrapper (DataType type) {
3084 string destroy_func = "_vala_%s_free".printf (get_ccode_name (type.data_type));
3086 if (!add_wrapper (destroy_func)) {
3087 // wrapper already defined
3088 return destroy_func;
3091 var function = new CCodeFunction (destroy_func, "void");
3092 function.modifiers = CCodeModifiers.STATIC;
3093 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3095 push_function (function);
3097 var cl = type.data_type as Class;
3098 if (cl != null && get_ccode_is_gboxed (cl)) {
3099 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_free"));
3100 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
3101 free_call.add_argument (new CCodeIdentifier ("self"));
3103 ccode.add_expression (free_call);
3104 } else {
3105 var st = type.data_type as Struct;
3106 if (st != null && st.is_disposable ()) {
3107 if (!get_ccode_has_destroy_function (st)) {
3108 generate_struct_destroy_function (st);
3111 var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (st)));
3112 destroy_call.add_argument (new CCodeIdentifier ("self"));
3113 ccode.add_expression (destroy_call);
3116 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
3117 free_call.add_argument (new CCodeIdentifier ("self"));
3119 ccode.add_expression (free_call);
3122 pop_function ();
3124 cfile.add_function_declaration (function);
3125 cfile.add_function (function);
3127 return destroy_func;
3130 public CCodeExpression? get_destroy0_func_expression (DataType type, bool is_chainup = false) {
3131 var element_destroy_func_expression = get_destroy_func_expression (type, is_chainup);
3133 if (!(type is GenericType) && element_destroy_func_expression is CCodeIdentifier) {
3134 var freeid = (CCodeIdentifier) element_destroy_func_expression;
3135 string free0_func = "_%s0_".printf (freeid.name);
3137 if (add_wrapper (free0_func)) {
3138 var function = new CCodeFunction (free0_func, "void");
3139 function.modifiers = CCodeModifiers.STATIC;
3141 function.add_parameter (new CCodeParameter ("var", "gpointer"));
3143 push_function (function);
3145 ccode.add_expression (destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true));
3147 pop_function ();
3149 cfile.add_function_declaration (function);
3150 cfile.add_function (function);
3153 element_destroy_func_expression = new CCodeIdentifier (free0_func);
3156 return element_destroy_func_expression;
3159 public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
3160 if (context.profile == Profile.GOBJECT && (type.data_type == glist_type || type.data_type == gslist_type || type.data_type == gnode_type || type.data_type == gqueue_type)) {
3161 // create wrapper function to free list elements if necessary
3163 bool elements_require_free = false;
3164 bool generic_elements = false;
3165 CCodeExpression element_destroy_func_expression = null;
3167 foreach (DataType type_arg in type.get_type_arguments ()) {
3168 elements_require_free = requires_destroy (type_arg);
3169 if (elements_require_free) {
3170 element_destroy_func_expression = get_destroy0_func_expression (type_arg);
3171 generic_elements = (type_arg is GenericType);
3175 if (elements_require_free) {
3176 CCodeExpression? cexpr = null;
3177 if (element_destroy_func_expression is CCodeIdentifier || element_destroy_func_expression is CCodeMemberAccess) {
3178 cexpr = new CCodeIdentifier (generate_collection_free_wrapper (type, (generic_elements ? null : element_destroy_func_expression as CCodeIdentifier)));
3179 if (generic_elements) {
3180 // adding second argument early, instance parameter will be inserted by destroy_value()
3181 cexpr = new CCodeFunctionCall (cexpr);
3182 ((CCodeFunctionCall) cexpr).add_argument (element_destroy_func_expression);
3184 } else {
3185 Report.error (null, "internal error: No useable element_destroy_function found");
3187 return cexpr;
3188 } else {
3189 return new CCodeIdentifier (get_ccode_free_function (type.data_type));
3191 } else if (type is ErrorType) {
3192 return new CCodeIdentifier ("g_error_free");
3193 } else if (type.data_type != null) {
3194 string unref_function;
3195 if (type is ReferenceType) {
3196 if (is_reference_counting (type.data_type)) {
3197 unref_function = get_ccode_unref_function ((ObjectTypeSymbol) type.data_type);
3198 if (type.data_type is Interface && unref_function == null) {
3199 Report.error (type.source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure".printf (type.data_type.get_full_name ()));
3200 return null;
3202 } else {
3203 var cl = type.data_type as Class;
3204 if (cl != null && get_ccode_is_gboxed (cl)) {
3205 unref_function = generate_free_func_wrapper (type);
3206 } else {
3207 if (is_free_function_address_of (type)) {
3208 unref_function = generate_free_function_address_of_wrapper (type);
3209 } else {
3210 unref_function = get_ccode_free_function (type.data_type);
3214 } else {
3215 if (type.nullable) {
3216 unref_function = get_ccode_free_function (type.data_type);
3217 if (unref_function == null) {
3218 if (type.data_type is Struct && ((Struct) type.data_type).is_disposable ()) {
3219 unref_function = generate_free_func_wrapper (type);
3220 } else {
3221 unref_function = "g_free";
3224 } else if (type is EnumValueType) {
3225 unref_function = null;
3226 } else {
3227 var st = (Struct) type.data_type;
3228 if (st.is_disposable ()) {
3229 if (!get_ccode_has_destroy_function (st)) {
3230 generate_struct_destroy_function (st);
3232 unref_function = get_ccode_destroy_function (st);
3233 } else {
3234 unref_function = null;
3238 if (unref_function == null) {
3239 return new CCodeConstant ("NULL");
3241 return new CCodeIdentifier (unref_function);
3242 } else if (type is GenericType) {
3243 var type_parameter = ((GenericType) type).type_parameter;
3244 string func_name = "%s_destroy_func".printf (type_parameter.name.down ());
3246 if (type_parameter.parent_symbol is Interface) {
3247 var iface = (Interface) type_parameter.parent_symbol;
3248 require_generic_accessors (iface);
3250 string method_name = "get_%s_destroy_func".printf (type_parameter.name.down ());
3251 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
3252 cast_self.add_argument (new CCodeIdentifier ("self"));
3253 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
3254 function_call.add_argument (new CCodeIdentifier ("self"));
3255 return function_call;
3258 if (is_in_generic_type ((GenericType) type) && !is_chainup && !in_creation_method) {
3259 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
3260 } else {
3261 return get_variable_cexpression (func_name);
3263 } else if (type is ArrayType) {
3264 if (context.profile == Profile.POSIX) {
3265 return new CCodeIdentifier ("free");
3266 } else {
3267 return new CCodeIdentifier ("g_free");
3269 } else if (type is PointerType) {
3270 if (context.profile == Profile.POSIX) {
3271 return new CCodeIdentifier ("free");
3272 } else {
3273 return new CCodeIdentifier ("g_free");
3275 } else {
3276 return new CCodeConstant ("NULL");
3280 private string generate_collection_free_wrapper (DataType collection_type, CCodeIdentifier? element_destroy_func_expression) {
3281 string destroy_func;
3283 string? destroy_func_wrapper = null;
3284 if (element_destroy_func_expression != null) {
3285 destroy_func_wrapper = "_%s_%s".printf (get_ccode_free_function (collection_type.data_type), element_destroy_func_expression.name);
3286 if (!add_wrapper (destroy_func_wrapper)) {
3287 // wrapper already defined
3288 return destroy_func_wrapper;
3292 if (collection_type.data_type == gnode_type) {
3293 destroy_func = "_g_node_free_all";
3294 if (!add_wrapper (destroy_func)) {
3295 // wrapper already defined
3296 return destroy_func;
3299 var function = new CCodeFunction (destroy_func, "void");
3300 function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3301 function.add_parameter (new CCodeParameter ("free_func", "GDestroyNotify"));
3303 push_function (function);
3305 CCodeFunctionCall element_free_call;
3306 string destroy_node_func = "%s_node".printf (destroy_func);
3307 var wrapper = new CCodeFunction (destroy_node_func, "gboolean");
3308 wrapper.modifiers = CCodeModifiers.STATIC;
3309 wrapper.add_parameter (new CCodeParameter ("node", get_ccode_name (collection_type)));
3310 wrapper.add_parameter (new CCodeParameter ("free_func", "GDestroyNotify"));
3311 push_function (wrapper);
3313 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("free_func"));
3314 free_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier("node"), "data"));
3316 var data_isnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeMemberAccess.pointer (new CCodeIdentifier("node"), "data"), new CCodeConstant ("NULL"));
3317 var ccomma_data = new CCodeCommaExpression ();
3318 ccomma_data.append_expression (new CCodeConditionalExpression (data_isnull, new CCodeConstant ("NULL"), free_call));
3319 ccode.add_expression (ccomma_data);
3321 ccode.add_return (new CCodeConstant ("FALSE"));
3323 pop_function ();
3324 cfile.add_function_declaration (wrapper);
3325 cfile.add_function (wrapper);
3327 /* Now the code to call g_traverse with the above */
3328 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_node_traverse"));
3329 element_free_call.add_argument (new CCodeIdentifier("self"));
3330 element_free_call.add_argument (new CCodeConstant ("G_POST_ORDER"));
3331 element_free_call.add_argument (new CCodeConstant ("G_TRAVERSE_ALL"));
3332 element_free_call.add_argument (new CCodeConstant ("-1"));
3333 element_free_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (destroy_node_func), "GNodeTraverseFunc"));
3334 element_free_call.add_argument (new CCodeIdentifier ("free_func"));
3336 var free_func_isnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("free_func"), new CCodeConstant ("NULL"));
3337 var ccomma = new CCodeCommaExpression ();
3338 ccomma.append_expression (new CCodeConditionalExpression (free_func_isnull, new CCodeConstant ("NULL"), element_free_call));
3340 ccode.add_expression (ccomma);
3342 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (gnode_type)));
3343 cfreecall.add_argument (new CCodeIdentifier ("self"));
3344 ccode.add_expression (cfreecall);
3346 function.modifiers = CCodeModifiers.STATIC;
3347 pop_function ();
3349 cfile.add_function_declaration (function);
3350 cfile.add_function (function);
3351 } else if (collection_type.data_type == glist_type) {
3352 destroy_func = "g_list_free_full";
3353 } else if (collection_type.data_type == gslist_type) {
3354 destroy_func = "g_slist_free_full";
3355 } else if (collection_type.data_type == gqueue_type) {
3356 destroy_func = "g_queue_free_full";
3357 } else {
3358 Report.error (null, "internal error: type of collection not supported");
3359 return "";
3362 if (element_destroy_func_expression != null) {
3363 var function = new CCodeFunction (destroy_func_wrapper, "void");
3364 function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3366 push_function (function);
3368 var collection_free_call = new CCodeFunctionCall (new CCodeIdentifier (destroy_func));
3369 collection_free_call.add_argument (new CCodeIdentifier ("self"));
3370 collection_free_call.add_argument (new CCodeCastExpression (element_destroy_func_expression, "GDestroyNotify"));
3371 ccode.add_expression (collection_free_call);
3373 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
3374 pop_function ();
3376 cfile.add_function_declaration (function);
3377 cfile.add_function (function);
3379 return destroy_func_wrapper;
3382 return destroy_func;
3385 public virtual string? append_struct_array_free (Struct st) {
3386 return null;
3389 public CCodeExpression destroy_local (LocalVariable local) {
3390 return destroy_value (get_local_cvalue (local));
3393 public CCodeExpression destroy_parameter (Parameter param) {
3394 return destroy_value (get_parameter_cvalue (param));
3397 public CCodeExpression destroy_field (Field field, TargetValue? instance) {
3398 return destroy_value (get_field_cvalue (field, instance));
3401 public virtual CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
3402 var type = value.value_type;
3403 if (value.actual_value_type != null) {
3404 type = value.actual_value_type;
3406 var cvar = get_cvalue_ (value);
3408 if (type is DelegateType) {
3409 var delegate_target = get_delegate_target_cvalue (value);
3410 var delegate_target_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
3412 var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
3413 ccall.add_argument (delegate_target);
3415 var destroy_call = new CCodeCommaExpression ();
3416 destroy_call.append_expression (ccall);
3417 destroy_call.append_expression (new CCodeConstant ("NULL"));
3419 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
3421 var ccomma = new CCodeCommaExpression ();
3422 ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), destroy_call));
3423 ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
3424 ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
3425 ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
3427 return ccomma;
3430 bool is_gcollection = (type.data_type == glist_type || type.data_type == gslist_type || type.data_type == gnode_type || type.data_type == gqueue_type);
3431 CCodeFunctionCall ccall;
3432 var cexpr = get_destroy_func_expression (type);
3433 if (is_gcollection && cexpr is CCodeFunctionCall) {
3434 ccall = (CCodeFunctionCall) cexpr;
3435 } else {
3436 ccall = new CCodeFunctionCall (cexpr);
3439 if (type is ValueType && !type.nullable) {
3440 // normal value type, no null check
3441 var st = type.data_type as Struct;
3442 if (st != null && st.is_simple_type ()) {
3443 // used for va_list
3444 ccall.add_argument (cvar);
3445 } else {
3446 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3449 if (gvalue_type != null && type.data_type == gvalue_type) {
3450 // g_value_unset must not be called for already unset values
3451 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
3452 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3454 var ccomma = new CCodeCommaExpression ();
3455 ccomma.append_expression (ccall);
3456 ccomma.append_expression (new CCodeConstant ("NULL"));
3458 return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
3459 } else if ((type.data_type == gmutex_type ||
3460 type.data_type == grecmutex_type ||
3461 type.data_type == grwlock_type ||
3462 type.data_type == gcond_type)) {
3463 // g_mutex_clear must not be called for uninitialized mutex
3464 // also, g_mutex_clear does not clear the struct
3465 requires_clear_mutex = true;
3466 ccall.call = new CCodeIdentifier ("_vala_clear_" + get_ccode_name (type.data_type));
3467 return ccall;
3468 } else {
3469 return ccall;
3473 if (!is_gcollection && ccall.call is CCodeIdentifier && !(type is ArrayType) && !is_macro_definition) {
3474 // generate and use NULL-aware free macro to simplify code
3476 var freeid = (CCodeIdentifier) ccall.call;
3477 string free0_func = "_%s0".printf (freeid.name);
3479 if (add_wrapper (free0_func)) {
3480 var macro = destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true);
3481 cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("%s(var)".printf (free0_func), macro));
3484 ccall = new CCodeFunctionCall (new CCodeIdentifier (free0_func));
3485 ccall.add_argument (cvar);
3486 return ccall;
3489 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
3491 /* can be simplified to
3492 * foo = (unref (foo), NULL)
3493 * if foo is of static type non-null
3496 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
3497 if (type is GenericType) {
3498 var parent = ((GenericType) type).type_parameter.parent_symbol;
3499 var cl = parent as Class;
3500 if ((!(parent is Method) && !(parent is ObjectTypeSymbol)) || (cl != null && cl.is_compact)) {
3501 return new CCodeConstant ("NULL");
3504 // unref functions are optional for type parameters
3505 var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
3506 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
3509 // glib collections already have the free_func argument, so make sure the instance parameter gets first
3510 ccall.insert_argument (0, cvar);
3512 /* set freed references to NULL to prevent further use */
3513 var ccomma = new CCodeCommaExpression ();
3515 if (context.profile == Profile.GOBJECT) {
3516 if (type.data_type != null && !is_reference_counting (type.data_type) &&
3517 (type.data_type.is_subtype_of (gstringbuilder_type)
3518 || type.data_type.is_subtype_of (garray_type)
3519 || type.data_type.is_subtype_of (gbytearray_type)
3520 || type.data_type.is_subtype_of (gptrarray_type))) {
3521 ccall.add_argument (new CCodeConstant ("TRUE"));
3522 } else if (type.data_type == gthreadpool_type) {
3523 ccall.add_argument (new CCodeConstant ("FALSE"));
3524 ccall.add_argument (new CCodeConstant ("TRUE"));
3525 } else if (type is ArrayType) {
3526 var array_type = (ArrayType) type;
3527 if (requires_destroy (array_type.element_type)) {
3528 CCodeExpression csizeexpr = null;
3529 if (((GLibValue) value).array_length_cvalues != null) {
3530 csizeexpr = get_array_length_cvalue (value);
3531 } else if (get_array_null_terminated (value)) {
3532 requires_array_length = true;
3533 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
3534 len_call.add_argument (cvar);
3535 csizeexpr = len_call;
3536 } else {
3537 csizeexpr = get_array_length_cexpr (value);
3540 if (csizeexpr != null) {
3541 var st = array_type.element_type.data_type as Struct;
3542 if (st != null && !array_type.element_type.nullable) {
3543 ccall.call = new CCodeIdentifier (append_struct_array_free (st));
3544 ccall.add_argument (csizeexpr);
3545 } else {
3546 requires_array_free = true;
3547 ccall.call = new CCodeIdentifier ("_vala_array_free");
3548 ccall.add_argument (csizeexpr);
3549 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
3556 ccomma.append_expression (ccall);
3557 ccomma.append_expression (new CCodeConstant ("NULL"));
3559 var cassign = new CCodeAssignment (cvar, ccomma);
3561 // g_free (NULL) is allowed
3562 bool uses_gfree = (type.data_type != null && !is_reference_counting (type.data_type) && get_ccode_free_function (type.data_type) == "g_free");
3563 uses_gfree = uses_gfree || type is ArrayType;
3564 if (uses_gfree) {
3565 return cassign;
3568 return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
3571 public override void visit_end_full_expression (Expression expr) {
3572 /* expr is a full expression, i.e. an initializer, the
3573 * expression in an expression statement, the controlling
3574 * expression in if, while, for, or foreach statements
3576 * we unref temporary variables at the end of a full
3577 * expression
3579 if (temp_ref_values.size == 0) {
3580 /* nothing to do without temporary variables */
3581 return;
3584 var local_decl = expr.parent_node as LocalVariable;
3585 if (!(local_decl != null && is_simple_struct_creation (local_decl, local_decl.initializer))) {
3586 expr.target_value = store_temp_value (expr.target_value, expr);
3589 foreach (var value in temp_ref_values) {
3590 ccode.add_expression (destroy_value (value));
3593 temp_ref_values.clear ();
3596 public void emit_temp_var (LocalVariable local, bool on_error = false) {
3597 var init = (!local.name.has_prefix ("*") && local.init);
3598 if (is_in_coroutine ()) {
3599 closure_struct.add_field (get_ccode_name (local.variable_type), local.name);
3601 // even though closure struct is zerod, we need to initialize temporary variables
3602 // as they might be used multiple times when declared in a loop
3604 if (init) {
3605 var initializer = default_value_for_type (local.variable_type, false, on_error);
3606 if (initializer == null) {
3607 cfile.add_include ("string.h");
3608 var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
3609 memset_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (local.name)));
3610 memset_call.add_argument (new CCodeConstant ("0"));
3611 memset_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (local.variable_type))));
3612 ccode.add_expression (memset_call);
3613 } else {
3614 ccode.add_assignment (get_variable_cexpression (local.name), initializer);
3617 } else {
3618 var cvar = new CCodeVariableDeclarator (local.name, null, get_ccode_declarator_suffix (local.variable_type));
3619 if (init) {
3620 cvar.initializer = default_value_for_type (local.variable_type, true, on_error);
3621 cvar.init0 = true;
3623 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
3627 public override void visit_expression_statement (ExpressionStatement stmt) {
3628 if (stmt.expression.error) {
3629 stmt.error = true;
3630 return;
3633 /* free temporary objects and handle errors */
3635 foreach (var value in temp_ref_values) {
3636 ccode.add_expression (destroy_value (value));
3639 if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
3640 // simple case, no node breakdown necessary
3641 add_simple_check (stmt.expression);
3644 temp_ref_values.clear ();
3647 protected virtual void append_scope_free (Symbol sym, CodeNode? stop_at = null) {
3648 var b = (Block) sym;
3650 var local_vars = b.get_local_variables ();
3651 // free in reverse order
3652 for (int i = local_vars.size - 1; i >= 0; i--) {
3653 var local = local_vars[i];
3654 if (!local.unreachable && local.active && !local.captured && requires_destroy (local.variable_type)) {
3655 ccode.add_expression (destroy_local (local));
3659 if (b.captured) {
3660 int block_id = get_block_id (b);
3662 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
3663 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
3664 ccode.add_expression (data_unref);
3665 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
3669 public void append_local_free (Symbol sym, bool stop_at_loop = false, CodeNode? stop_at = null) {
3670 var b = (Block) sym;
3672 append_scope_free (sym, stop_at);
3674 if (stop_at_loop) {
3675 if (b.parent_node is Loop ||
3676 b.parent_node is ForeachStatement ||
3677 b.parent_node is SwitchStatement) {
3678 return;
3682 if (stop_at != null && b.parent_node == stop_at) {
3683 return;
3686 if (sym.parent_symbol is Block) {
3687 append_local_free (sym.parent_symbol, stop_at_loop, stop_at);
3688 } else if (sym.parent_symbol is Method) {
3689 append_param_free ((Method) sym.parent_symbol);
3690 } else if (sym.parent_symbol is PropertyAccessor) {
3691 var acc = (PropertyAccessor) sym.parent_symbol;
3692 if (acc.value_parameter != null && requires_destroy (acc.value_parameter.variable_type)) {
3693 ccode.add_expression (destroy_parameter (acc.value_parameter));
3698 private void append_param_free (Method m) {
3699 foreach (Parameter param in m.get_parameters ()) {
3700 if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
3701 ccode.add_expression (destroy_parameter (param));
3706 public bool variable_accessible_in_finally (LocalVariable local) {
3707 if (current_try == null) {
3708 return false;
3711 var sym = current_symbol;
3713 while (!(sym is Method || sym is PropertyAccessor) && sym.scope.lookup (local.name) == null) {
3714 if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) ||
3715 (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) {
3717 return true;
3720 sym = sym.parent_symbol;
3723 return false;
3726 public void return_out_parameter (Parameter param) {
3727 var delegate_type = param.variable_type as DelegateType;
3729 var value = get_parameter_cvalue (param);
3731 var old_coroutine = is_in_coroutine ();
3732 current_method.coroutine = false;
3734 ccode.open_if (get_variable_cexpression (param.name));
3735 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (param.name)), get_cvalue_ (value));
3737 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
3738 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_ccode_delegate_target_name (param))), get_delegate_target_cvalue (value));
3739 if (delegate_type.is_disposable ()) {
3740 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_delegate_target_destroy_notify_cname (param.name))), get_delegate_target_destroy_notify_cvalue (get_parameter_cvalue (param)));
3744 if (param.variable_type.is_disposable ()){
3745 ccode.add_else ();
3746 current_method.coroutine = old_coroutine;
3747 ccode.add_expression (destroy_parameter (param));
3748 current_method.coroutine = false;
3750 ccode.close ();
3752 var array_type = param.variable_type as ArrayType;
3753 if (array_type != null && !array_type.fixed_length && get_ccode_array_length (param)) {
3754 for (int dim = 1; dim <= array_type.rank; dim++) {
3755 ccode.open_if (get_variable_cexpression (get_parameter_array_length_cname (param, dim)));
3756 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_parameter_array_length_cname (param, dim))), get_array_length_cvalue (value, dim));
3757 ccode.close ();
3761 current_method.coroutine = old_coroutine;
3764 public override void visit_return_statement (ReturnStatement stmt) {
3765 Symbol return_expression_symbol = null;
3767 if (stmt.return_expression != null) {
3768 // avoid unnecessary ref/unref pair
3769 var local = stmt.return_expression.symbol_reference as LocalVariable;
3770 if (local != null && !local.active) {
3771 /* return expression is local variable taking ownership and
3772 * current method is transferring ownership */
3774 return_expression_symbol = local;
3778 // return array length if appropriate
3779 if (((current_method != null && get_ccode_array_length (current_method)) || current_property_accessor != null) && current_return_type is ArrayType) {
3780 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
3782 var array_type = (ArrayType) current_return_type;
3783 for (int dim = 1; dim <= array_type.rank; dim++) {
3784 var len_l = get_result_cexpression (get_array_length_cname ("result", dim));
3785 var len_r = get_array_length_cvalue (temp_value, dim);
3786 if (!is_in_coroutine ()) {
3787 ccode.open_if (len_l);
3788 len_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, len_l);
3789 ccode.add_assignment (len_l, len_r);
3790 ccode.close ();
3791 } else {
3792 ccode.add_assignment (len_l, len_r);
3796 stmt.return_expression.target_value = temp_value;
3797 } else if ((current_method != null || current_property_accessor != null) && current_return_type is DelegateType) {
3798 var delegate_type = (DelegateType) current_return_type;
3799 if (delegate_type.delegate_symbol.has_target) {
3800 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
3802 var target_l = get_result_cexpression (get_delegate_target_cname ("result"));
3803 if (!is_in_coroutine ()) {
3804 target_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l);
3806 var target_r = get_delegate_target_cvalue (temp_value);
3807 ccode.add_assignment (target_l, target_r);
3808 if (delegate_type.is_disposable ()) {
3809 var target_l_destroy_notify = get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3810 if (!is_in_coroutine ()) {
3811 target_l_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l_destroy_notify);
3813 var target_r_destroy_notify = get_delegate_target_destroy_notify_cvalue (temp_value);
3814 ccode.add_assignment (target_l_destroy_notify, target_r_destroy_notify);
3817 stmt.return_expression.target_value = temp_value;
3821 if (stmt.return_expression != null) {
3822 // assign method result to `result'
3823 CCodeExpression result_lhs = get_result_cexpression ();
3824 if (current_return_type.is_real_non_null_struct_type () && !is_in_coroutine ()) {
3825 result_lhs = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result_lhs);
3827 ccode.add_assignment (result_lhs, get_cvalue (stmt.return_expression));
3830 // free local variables
3831 append_local_free (current_symbol);
3833 if (current_method != null) {
3834 // check postconditions
3835 foreach (Expression postcondition in current_method.get_postconditions ()) {
3836 create_postcondition_statement (postcondition);
3840 if (current_method != null && !current_method.coroutine) {
3841 // assign values to output parameters if they are not NULL
3842 // otherwise, free the value if necessary
3843 foreach (var param in current_method.get_parameters ()) {
3844 if (param.direction != ParameterDirection.OUT) {
3845 continue;
3848 return_out_parameter (param);
3852 // TODO: don't duplicate the code in CCodeMethodModule, we do this right now because it needs to be before return
3853 if (current_method != null && current_method.get_attribute ("Profile") != null) {
3854 string prefix = "_vala_prof_%s".printf (get_ccode_real_name (current_method));
3856 var level = new CCodeIdentifier (prefix + "_level");
3857 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
3859 var timer = new CCodeIdentifier (prefix + "_timer");
3861 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
3862 stop_call.add_argument (timer);
3863 ccode.add_expression (stop_call);
3865 ccode.close ();
3868 if (is_in_constructor ()) {
3869 ccode.add_return (new CCodeIdentifier ("obj"));
3870 } else if (is_in_destructor ()) {
3871 // do not call return as member cleanup and chain up to base finalizer
3872 // stil need to be executed
3873 ccode.add_goto ("_return");
3874 } else if (is_in_coroutine ()) {
3875 } else if (current_method is CreationMethod) {
3876 ccode.add_return (new CCodeIdentifier ("self"));
3877 } else if (current_return_type is VoidType || current_return_type.is_real_non_null_struct_type ()) {
3878 // structs are returned via out parameter
3879 ccode.add_return ();
3880 } else {
3881 ccode.add_return (new CCodeIdentifier ("result"));
3884 if (return_expression_symbol != null) {
3885 return_expression_symbol.active = true;
3888 // required for destructors
3889 current_method_return = true;
3892 public string get_symbol_lock_name (string symname) {
3893 return "__lock_%s".printf (symname);
3896 private CCodeExpression get_lock_expression (Statement stmt, Expression resource) {
3897 CCodeExpression l = null;
3898 var inner_node = ((MemberAccess)resource).inner;
3899 var member = resource.symbol_reference;
3900 var parent = (TypeSymbol)resource.symbol_reference.parent_symbol;
3902 if (member.is_instance_member ()) {
3903 if (inner_node == null) {
3904 l = new CCodeIdentifier ("self");
3905 } else if (parent != current_type_symbol) {
3906 l = generate_instance_cast (get_cvalue (inner_node), parent);
3907 } else {
3908 l = get_cvalue (inner_node);
3911 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (get_ccode_name (member)));
3912 } else if (member.is_class_member ()) {
3913 CCodeExpression klass;
3915 if (get_this_type () != null) {
3916 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3917 k.add_argument (new CCodeIdentifier ("self"));
3918 klass = k;
3919 } else {
3920 klass = new CCodeIdentifier ("klass");
3923 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(get_ccode_upper_case_name (parent))));
3924 get_class_private_call.add_argument (klass);
3925 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (get_ccode_name (member)));
3926 } else {
3927 string lock_name = "%s_%s".printf (get_ccode_lower_case_name (parent), get_ccode_name (member));
3928 l = new CCodeIdentifier (get_symbol_lock_name (lock_name));
3930 return l;
3933 public override void visit_lock_statement (LockStatement stmt) {
3934 var l = get_lock_expression (stmt, stmt.resource);
3936 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("lock"))));
3937 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3939 ccode.add_expression (fc);
3942 public override void visit_unlock_statement (UnlockStatement stmt) {
3943 var l = get_lock_expression (stmt, stmt.resource);
3945 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("unlock"))));
3946 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3948 ccode.add_expression (fc);
3951 public override void visit_delete_statement (DeleteStatement stmt) {
3952 var pointer_type = (PointerType) stmt.expression.value_type;
3953 DataType type = pointer_type;
3954 if (pointer_type.base_type.data_type != null && pointer_type.base_type.data_type.is_reference_type ()) {
3955 type = pointer_type.base_type;
3958 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
3959 ccall.add_argument (get_cvalue (stmt.expression));
3960 ccode.add_expression (ccall);
3963 public override void visit_expression (Expression expr) {
3964 if (get_cvalue (expr) != null && !expr.lvalue) {
3965 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
3966 var type_parameter = ((GenericType) expr.formal_value_type).type_parameter;
3967 var st = type_parameter.parent_symbol.parent_symbol as Struct;
3968 if (type_parameter.parent_symbol != garray_type &&
3969 (st == null || get_ccode_name (st) != "va_list")) {
3970 // GArray and va_list don't use pointer-based generics
3971 set_cvalue (expr, convert_from_generic_pointer (get_cvalue (expr), expr.value_type));
3972 ((GLibValue) expr.target_value).lvalue = false;
3976 // memory management, implicit casts, and boxing/unboxing
3977 if (expr.value_type != null) {
3978 // FIXME: temporary workaround until the refactoring is complete, not all target_value have a value_type
3979 expr.target_value.value_type = expr.value_type;
3980 expr.target_value = transform_value (expr.target_value, expr.target_type, expr);
3983 if (expr.target_value == null) {
3984 return;
3987 if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
3988 if (((GenericType) expr.formal_target_type).type_parameter.parent_symbol != garray_type) {
3989 // GArray doesn't use pointer-based generics
3990 set_cvalue (expr, convert_to_generic_pointer (get_cvalue (expr), expr.target_type));
3991 ((GLibValue) expr.target_value).lvalue = false;
3995 if (!(expr.value_type is ValueType && !expr.value_type.nullable)) {
3996 ((GLibValue) expr.target_value).non_null = expr.is_non_null ();
4001 public override void visit_boolean_literal (BooleanLiteral expr) {
4002 if (context.profile == Profile.GOBJECT) {
4003 set_cvalue (expr, new CCodeConstant (expr.value ? "TRUE" : "FALSE"));
4004 } else {
4005 cfile.add_include ("stdbool.h");
4006 set_cvalue (expr, new CCodeConstant (expr.value ? "true" : "false"));
4010 public override void visit_character_literal (CharacterLiteral expr) {
4011 if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
4012 set_cvalue (expr, new CCodeConstant (expr.value));
4013 } else {
4014 set_cvalue (expr, new CCodeConstant ("%uU".printf (expr.get_char ())));
4018 public override void visit_integer_literal (IntegerLiteral expr) {
4019 set_cvalue (expr, new CCodeConstant (expr.value + expr.type_suffix));
4022 public override void visit_real_literal (RealLiteral expr) {
4023 string c_literal = expr.value;
4024 if (c_literal.has_suffix ("d") || c_literal.has_suffix ("D")) {
4025 // there is no suffix for double in C
4026 c_literal = c_literal.substring (0, c_literal.length - 1);
4028 if (!("." in c_literal || "e" in c_literal || "E" in c_literal)) {
4029 // C requires period or exponent part for floating constants
4030 if ("f" in c_literal || "F" in c_literal) {
4031 c_literal = c_literal.substring (0, c_literal.length - 1) + ".f";
4032 } else {
4033 c_literal += ".";
4036 set_cvalue (expr, new CCodeConstant (c_literal));
4039 public override void visit_string_literal (StringLiteral expr) {
4040 set_cvalue (expr, new CCodeConstant.string (expr.value.replace ("\n", "\\n")));
4042 if (expr.translate) {
4043 // translated string constant
4045 var m = (Method) root_symbol.scope.lookup ("GLib").scope.lookup ("_");
4046 add_symbol_declaration (cfile, m, get_ccode_name (m));
4048 var translate = new CCodeFunctionCall (new CCodeIdentifier ("_"));
4049 translate.add_argument (get_cvalue (expr));
4050 set_cvalue (expr, translate);
4054 public override void visit_regex_literal (RegexLiteral expr) {
4055 string[] parts = expr.value.split ("/", 3);
4056 string re = parts[2].escape ("");
4057 string flags = "0";
4059 if (parts[1].contains ("i")) {
4060 flags += " | G_REGEX_CASELESS";
4062 if (parts[1].contains ("m")) {
4063 flags += " | G_REGEX_MULTILINE";
4065 if (parts[1].contains ("s")) {
4066 flags += " | G_REGEX_DOTALL";
4068 if (parts[1].contains ("x")) {
4069 flags += " | G_REGEX_EXTENDED";
4072 var cdecl = new CCodeDeclaration ("GRegex*");
4074 var cname = "_tmp_regex_%d".printf (next_regex_id);
4075 if (this.next_regex_id == 0) {
4076 var fun = new CCodeFunction ("_thread_safe_regex_init", "GRegex*");
4077 fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
4078 fun.add_parameter (new CCodeParameter ("re", "GRegex**"));
4079 fun.add_parameter (new CCodeParameter ("pattern", "const gchar *"));
4080 fun.add_parameter (new CCodeParameter ("match_options", "GRegexMatchFlags"));
4082 push_function (fun);
4084 var once_enter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
4085 once_enter_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
4086 ccode.open_if (once_enter_call);
4088 var regex_new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_regex_new"));
4089 regex_new_call.add_argument (new CCodeConstant ("pattern"));
4090 regex_new_call.add_argument (new CCodeConstant ("match_options"));
4091 regex_new_call.add_argument (new CCodeConstant ("0"));
4092 regex_new_call.add_argument (new CCodeConstant ("NULL"));
4093 ccode.add_assignment (new CCodeIdentifier ("GRegex* val"), regex_new_call);
4095 var once_leave_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
4096 once_leave_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
4097 once_leave_call.add_argument (new CCodeConstant ("(gsize) val"));
4098 ccode.add_expression (once_leave_call);
4100 ccode.close ();
4102 ccode.add_return (new CCodeIdentifier ("*re"));
4104 pop_function ();
4106 cfile.add_function (fun);
4108 this.next_regex_id++;
4110 cdecl.add_declarator (new CCodeVariableDeclarator (cname + " = NULL"));
4111 cdecl.modifiers = CCodeModifiers.STATIC;
4113 var regex_const = new CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname, re, flags));
4115 cfile.add_constant_declaration (cdecl);
4116 set_cvalue (expr, regex_const);
4119 public override void visit_null_literal (NullLiteral expr) {
4120 if (context.profile != Profile.GOBJECT) {
4121 cfile.add_include ("stddef.h");
4123 set_cvalue (expr, new CCodeConstant ("NULL"));
4125 var array_type = expr.target_type as ArrayType;
4126 var delegate_type = expr.target_type as DelegateType;
4127 if (array_type != null) {
4128 for (int dim = 1; dim <= array_type.rank; dim++) {
4129 append_array_length (expr, new CCodeConstant ("0"));
4131 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
4132 set_delegate_target (expr, new CCodeConstant ("NULL"));
4133 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
4137 public abstract TargetValue get_local_cvalue (LocalVariable local);
4139 public abstract TargetValue get_parameter_cvalue (Parameter param);
4141 public abstract TargetValue get_field_cvalue (Field field, TargetValue? instance);
4143 public abstract TargetValue load_variable (Variable variable, TargetValue value);
4145 public abstract TargetValue load_this_parameter (TypeSymbol sym);
4147 public abstract void store_value (TargetValue lvalue, TargetValue value, SourceReference? source_reference = null);
4149 public virtual string get_delegate_target_cname (string delegate_cname) {
4150 assert_not_reached ();
4153 public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
4154 assert_not_reached ();
4157 public virtual CCodeExpression get_delegate_target_cvalue (TargetValue value) {
4158 return new CCodeInvalidExpression ();
4161 public virtual CCodeExpression get_delegate_target_destroy_notify_cvalue (TargetValue value) {
4162 return new CCodeInvalidExpression ();
4165 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname) {
4166 assert_not_reached ();
4169 public override void visit_base_access (BaseAccess expr) {
4170 CCodeExpression this_access;
4171 if (is_in_coroutine ()) {
4172 // use closure
4173 this_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
4174 } else {
4175 this_access = new CCodeIdentifier ("self");
4178 set_cvalue (expr, generate_instance_cast (this_access, expr.value_type.data_type));
4181 public override void visit_postfix_expression (PostfixExpression expr) {
4182 MemberAccess ma = find_property_access (expr.inner);
4183 if (ma != null) {
4184 // property postfix expression
4185 var prop = (Property) ma.symbol_reference;
4187 // increment/decrement property
4188 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4189 var cexpr = new CCodeBinaryExpression (op, get_cvalue (expr.inner), new CCodeConstant ("1"));
4190 store_property (prop, ma.inner, new GLibValue (expr.value_type, cexpr));
4192 // return previous value
4193 expr.target_value = expr.inner.target_value;
4194 return;
4197 // assign current value to temp variable
4198 var temp_value = store_temp_value (expr.inner.target_value, expr);
4200 // increment/decrement variable
4201 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4202 var cexpr = new CCodeBinaryExpression (op, get_cvalue_ (temp_value), new CCodeConstant ("1"));
4203 ccode.add_assignment (get_cvalue (expr.inner), cexpr);
4205 // return previous value
4206 expr.target_value = temp_value;
4209 private MemberAccess? find_property_access (Expression expr) {
4210 if (!(expr is MemberAccess)) {
4211 return null;
4214 var ma = (MemberAccess) expr;
4215 if (ma.symbol_reference is Property) {
4216 return ma;
4219 return null;
4222 bool is_limited_generic_type (GenericType type) {
4223 var cl = type.type_parameter.parent_symbol as Class;
4224 var st = type.type_parameter.parent_symbol as Struct;
4225 if ((cl != null && cl.is_compact) || st != null) {
4226 // compact classes and structs only
4227 // have very limited generics support
4228 return true;
4230 return false;
4233 public bool requires_copy (DataType type) {
4234 if (!type.is_disposable ()) {
4235 return false;
4238 var cl = type.data_type as Class;
4239 if (cl != null && is_reference_counting (cl)
4240 && get_ccode_ref_function (cl) == "") {
4241 // empty ref_function => no ref necessary
4242 return false;
4245 if (type is GenericType) {
4246 if (is_limited_generic_type ((GenericType) type)) {
4247 return false;
4251 return true;
4254 public bool requires_destroy (DataType type) {
4255 if (!type.is_disposable ()) {
4256 return false;
4259 var array_type = type as ArrayType;
4260 if (array_type != null && array_type.fixed_length) {
4261 return requires_destroy (array_type.element_type);
4264 var cl = type.data_type as Class;
4265 if (cl != null && is_reference_counting (cl)
4266 && get_ccode_unref_function (cl) == "") {
4267 // empty unref_function => no unref necessary
4268 return false;
4271 if (type is GenericType) {
4272 if (is_limited_generic_type ((GenericType) type)) {
4273 return false;
4277 return true;
4280 bool is_ref_function_void (DataType type) {
4281 var cl = type.data_type as Class;
4282 if (cl != null) {
4283 return get_ccode_ref_function_void (cl);
4284 } else {
4285 return false;
4289 bool is_free_function_address_of (DataType type) {
4290 var cl = type.data_type as Class;
4291 if (cl != null) {
4292 return get_ccode_free_function_address_of (cl);
4293 } else {
4294 return false;
4298 public virtual TargetValue? copy_value (TargetValue value, CodeNode node) {
4299 var type = value.value_type;
4300 var cexpr = get_cvalue_ (value);
4301 var result = ((GLibValue) value).copy ();
4303 if (type is DelegateType) {
4304 var delegate_type = (DelegateType) type;
4305 if (delegate_type.delegate_symbol.has_target && !context.deprecated) {
4306 Report.deprecated (node.source_reference, "copying delegates is not supported");
4308 result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
4309 return result;
4312 if (type is ValueType && !type.nullable) {
4313 // normal value type, no null check
4315 var temp_value = create_temp_value (type, true, node, true);
4316 var ctemp = get_cvalue_ (temp_value);
4318 var vt = (ValueType) type;
4319 var st = (Struct) vt.type_symbol;
4320 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
4321 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4322 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4324 if (!get_ccode_has_copy_function (st)) {
4325 generate_struct_copy_function (st);
4328 if (gvalue_type != null && type.data_type == gvalue_type) {
4329 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
4330 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4332 ccode.open_if (cisvalid);
4334 // GValue requires g_value_init in addition to g_value_copy
4335 var value_type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
4336 value_type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4338 var init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
4339 init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4340 init_call.add_argument (value_type_call);
4341 ccode.add_expression (init_call);
4342 ccode.add_expression (copy_call);
4344 ccode.add_else ();
4346 // g_value_init/copy must not be called for uninitialized values
4347 store_value (temp_value, value, node.source_reference);
4348 ccode.close ();
4349 } else {
4350 ccode.add_expression (copy_call);
4353 return temp_value;
4356 /* (temp = expr, temp == NULL ? NULL : ref (temp))
4358 * can be simplified to
4359 * ref (expr)
4360 * if static type of expr is non-null
4363 var dupexpr = get_dup_func_expression (type, node.source_reference);
4365 if (dupexpr == null) {
4366 node.error = true;
4367 return null;
4370 if (dupexpr is CCodeIdentifier && !(type is ArrayType) && !(type is GenericType) && !is_ref_function_void (type)) {
4371 // generate and call NULL-aware ref function to reduce number
4372 // of temporary variables and simplify code
4374 var dupid = (CCodeIdentifier) dupexpr;
4375 string dup0_func = "_%s0".printf (dupid.name);
4377 // g_strdup is already NULL-safe
4378 if (dupid.name == "g_strdup") {
4379 dup0_func = dupid.name;
4380 } else if (add_wrapper (dup0_func)) {
4381 string pointer_cname = "gpointer";
4382 if (context.profile == Profile.POSIX) {
4383 pointer_cname = "void *";
4385 var dup0_fun = new CCodeFunction (dup0_func, pointer_cname);
4386 dup0_fun.add_parameter (new CCodeParameter ("self", pointer_cname));
4387 dup0_fun.modifiers = CCodeModifiers.STATIC;
4389 push_function (dup0_fun);
4391 var dup_call = new CCodeFunctionCall (dupexpr);
4392 dup_call.add_argument (new CCodeIdentifier ("self"));
4394 ccode.add_return (new CCodeConditionalExpression (new CCodeIdentifier ("self"), dup_call, new CCodeConstant ("NULL")));
4396 pop_function ();
4398 cfile.add_function (dup0_fun);
4401 var ccall = new CCodeFunctionCall (new CCodeIdentifier (dup0_func));
4402 ccall.add_argument (cexpr);
4403 result.cvalue = ccall;
4404 result.value_type.value_owned = true;
4405 return store_temp_value (result, node);
4408 var ccall = new CCodeFunctionCall (dupexpr);
4410 if (!(type is ArrayType) && get_non_null (value) && !is_ref_function_void (type)) {
4411 // expression is non-null
4412 ccall.add_argument (cexpr);
4414 return store_temp_value (new GLibValue (type, ccall), node);
4415 } else {
4416 var cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cexpr, new CCodeConstant ("NULL"));
4417 if (type is GenericType) {
4418 // dup functions are optional for type parameters
4419 var cdupnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_dup_func_expression (type, node.source_reference), new CCodeConstant ("NULL"));
4420 cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.AND, cnotnull, cdupnotnull);
4423 if (type is GenericType) {
4424 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
4425 ccall.add_argument (new CCodeCastExpression (cexpr, "gpointer"));
4426 } else {
4427 ccall.add_argument (cexpr);
4430 if (type is ArrayType) {
4431 var array_type = (ArrayType) type;
4432 ccall.add_argument (get_array_length_cvalue (value));
4434 if (array_type.element_type is GenericType) {
4435 var elem_dupexpr = get_dup_func_expression (array_type.element_type, node.source_reference);
4436 if (elem_dupexpr == null) {
4437 elem_dupexpr = new CCodeConstant ("NULL");
4439 ccall.add_argument (elem_dupexpr);
4443 CCodeExpression cifnull;
4444 if (type.data_type != null) {
4445 cifnull = new CCodeConstant ("NULL");
4446 } else {
4447 // the value might be non-null even when the dup function is null,
4448 // so we may not just use NULL for type parameters
4450 // cast from gconstpointer to gpointer as methods in
4451 // generic classes may not return gconstpointer
4452 cifnull = new CCodeCastExpression (cexpr, "gpointer");
4455 if (is_ref_function_void (type)) {
4456 ccode.open_if (cnotnull);
4457 ccode.add_expression (ccall);
4458 ccode.close ();
4459 } else {
4460 var ccond = new CCodeConditionalExpression (cnotnull, ccall, cifnull);
4461 result.cvalue = ccond;
4462 result = (GLibValue) store_temp_value (result, node, true);
4464 return result;
4468 bool is_reference_type_argument (DataType type_arg) {
4469 if (type_arg is ErrorType || (type_arg.data_type != null && type_arg.data_type.is_reference_type ())) {
4470 return true;
4471 } else {
4472 return false;
4476 bool is_nullable_value_type_argument (DataType type_arg) {
4477 if (type_arg is ValueType && type_arg.nullable) {
4478 return true;
4479 } else {
4480 return false;
4484 bool is_signed_integer_type_argument (DataType type_arg) {
4485 var st = type_arg.data_type as Struct;
4486 if (type_arg is EnumValueType) {
4487 return true;
4488 } else if (type_arg.nullable) {
4489 return false;
4490 } else if (st == null) {
4491 return false;
4492 } else if (st.is_subtype_of (bool_type.data_type)) {
4493 return true;
4494 } else if (st.is_subtype_of (char_type.data_type)) {
4495 return true;
4496 } else if (unichar_type != null && st.is_subtype_of (unichar_type.data_type)) {
4497 return true;
4498 } else if (st.is_subtype_of (short_type.data_type)) {
4499 return true;
4500 } else if (st.is_subtype_of (int_type.data_type)) {
4501 return true;
4502 } else if (st.is_subtype_of (long_type.data_type)) {
4503 return true;
4504 } else if (st.is_subtype_of (int8_type.data_type)) {
4505 return true;
4506 } else if (st.is_subtype_of (int16_type.data_type)) {
4507 return true;
4508 } else if (st.is_subtype_of (int32_type.data_type)) {
4509 return true;
4510 } else if (st.is_subtype_of (gtype_type)) {
4511 return true;
4512 } else {
4513 return false;
4517 bool is_unsigned_integer_type_argument (DataType type_arg) {
4518 var st = type_arg.data_type as Struct;
4519 if (st == null) {
4520 return false;
4521 } else if (type_arg.nullable) {
4522 return false;
4523 } else if (st.is_subtype_of (uchar_type.data_type)) {
4524 return true;
4525 } else if (st.is_subtype_of (ushort_type.data_type)) {
4526 return true;
4527 } else if (st.is_subtype_of (uint_type.data_type)) {
4528 return true;
4529 } else if (st.is_subtype_of (ulong_type.data_type)) {
4530 return true;
4531 } else if (st.is_subtype_of (uint8_type.data_type)) {
4532 return true;
4533 } else if (st.is_subtype_of (uint16_type.data_type)) {
4534 return true;
4535 } else if (st.is_subtype_of (uint32_type.data_type)) {
4536 return true;
4537 } else {
4538 return false;
4542 public void check_type (DataType type) {
4543 var array_type = type as ArrayType;
4544 if (array_type != null) {
4545 check_type (array_type.element_type);
4546 if (array_type.element_type is ArrayType) {
4547 Report.error (type.source_reference, "Stacked arrays are not supported");
4548 } else if (array_type.element_type is DelegateType) {
4549 var delegate_type = (DelegateType) array_type.element_type;
4550 if (delegate_type.delegate_symbol.has_target) {
4551 Report.error (type.source_reference, "Delegates with target are not supported as array element type");
4555 foreach (var type_arg in type.get_type_arguments ()) {
4556 check_type (type_arg);
4557 check_type_argument (type_arg);
4561 public void check_type_arguments (MemberAccess access) {
4562 foreach (var type_arg in access.get_type_arguments ()) {
4563 check_type (type_arg);
4564 check_type_argument (type_arg);
4568 void check_type_argument (DataType type_arg) {
4569 if (type_arg is GenericType
4570 || type_arg is PointerType
4571 || is_reference_type_argument (type_arg)
4572 || is_nullable_value_type_argument (type_arg)
4573 || is_signed_integer_type_argument (type_arg)
4574 || is_unsigned_integer_type_argument (type_arg)) {
4575 // no error
4576 } else if (type_arg is DelegateType) {
4577 var delegate_type = (DelegateType) type_arg;
4578 if (delegate_type.delegate_symbol.has_target) {
4579 Report.error (type_arg.source_reference, "Delegates with target are not supported as generic type arguments");
4581 } else {
4582 Report.error (type_arg.source_reference, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg.to_string ()));
4586 public virtual void generate_class_declaration (Class cl, CCodeFile decl_space) {
4587 if (add_symbol_declaration (decl_space, cl, get_ccode_name (cl))) {
4588 return;
4592 public virtual void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
4595 public virtual void generate_method_declaration (Method m, CCodeFile decl_space) {
4598 public virtual void generate_error_domain_declaration (ErrorDomain edomain, CCodeFile decl_space) {
4601 public void add_generic_type_arguments (Map<int,CCodeExpression> arg_map, List<DataType> type_args, CodeNode expr, bool is_chainup = false, List<TypeParameter>? type_parameters = null) {
4602 int type_param_index = 0;
4603 foreach (var type_arg in type_args) {
4604 if (type_parameters != null) {
4605 var type_param_name = type_parameters.get (type_param_index).name.down ();
4606 arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s_type\"".printf (type_param_name)));
4607 arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("\"%s_dup_func\"".printf (type_param_name)));
4608 arg_map.set (get_param_pos (0.1 * type_param_index + 0.05), new CCodeConstant ("\"%s_destroy_func\"".printf (type_param_name)));
4611 arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), get_type_id_expression (type_arg, is_chainup));
4612 if (requires_copy (type_arg)) {
4613 var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference, is_chainup);
4614 if (dup_func == null) {
4615 // type doesn't contain a copy function
4616 expr.error = true;
4617 return;
4619 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
4620 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeCastExpression (get_destroy_func_expression (type_arg, is_chainup), "GDestroyNotify"));
4621 } else {
4622 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeConstant ("NULL"));
4623 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeConstant ("NULL"));
4625 type_param_index++;
4629 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
4630 CCodeExpression instance = null;
4631 CCodeExpression creation_expr = null;
4633 check_type (expr.type_reference);
4635 var st = expr.type_reference.data_type as Struct;
4636 if ((st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list")) || expr.get_object_initializer ().size > 0) {
4637 // value-type initialization or object creation expression with object initializer
4639 var local = expr.parent_node as LocalVariable;
4640 var field = expr.parent_node as Field;
4641 var a = expr.parent_node as Assignment;
4642 if (local != null && is_simple_struct_creation (local, local.initializer)) {
4643 instance = get_cvalue_ (get_local_cvalue (local));
4644 } else if (field != null && is_simple_struct_creation (field, field.initializer)) {
4645 // field initialization
4646 var thisparam = load_this_parameter ((TypeSymbol) field.parent_symbol);
4647 instance = get_cvalue_ (get_field_cvalue (field, thisparam));
4648 } else if (a != null && a.left.symbol_reference is Variable && is_simple_struct_creation ((Variable) a.left.symbol_reference, a.right)) {
4649 if (requires_destroy (a.left.value_type)) {
4650 /* unref old value */
4651 ccode.add_expression (destroy_value (a.left.target_value));
4654 local = a.left.symbol_reference as LocalVariable;
4655 field = a.left.symbol_reference as Field;
4656 var param = a.left.symbol_reference as Parameter;
4657 if (local != null) {
4658 instance = get_cvalue_ (get_local_cvalue (local));
4659 } else if (field != null) {
4660 var inner = ((MemberAccess) a.left).inner;
4661 instance = get_cvalue_ (get_field_cvalue (field, inner != null ? inner.target_value : null));
4662 } else if (param != null) {
4663 instance = get_cvalue_ (get_parameter_cvalue (param));
4665 } else {
4666 var temp_value = create_temp_value (expr.type_reference, true, expr);
4667 instance = get_cvalue_ (temp_value);
4671 if (expr.symbol_reference == null) {
4672 // no creation method
4673 if (expr.type_reference.data_type is Struct) {
4674 // memset needs string.h
4675 cfile.add_include ("string.h");
4676 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4677 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4678 creation_call.add_argument (new CCodeConstant ("0"));
4679 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.type_reference))));
4681 creation_expr = creation_call;
4683 } else if (expr.type_reference.data_type == glist_type ||
4684 expr.type_reference.data_type == gslist_type) {
4685 // NULL is an empty list
4686 set_cvalue (expr, new CCodeConstant ("NULL"));
4687 } else if (expr.symbol_reference is Method) {
4688 // use creation method
4689 var m = (Method) expr.symbol_reference;
4690 var params = m.get_parameters ();
4691 CCodeFunctionCall creation_call;
4693 CCodeFunctionCall async_call = null;
4694 CCodeFunctionCall finish_call = null;
4696 generate_method_declaration (m, cfile);
4698 var cl = expr.type_reference.data_type as Class;
4700 if (!get_ccode_has_new_function (m)) {
4701 // use construct function directly
4702 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
4703 creation_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
4704 } else {
4705 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
4708 if ((st != null && !st.is_simple_type ()) && !(get_ccode_instance_pos (m) < 0)) {
4709 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4710 } else if (st != null && get_ccode_name (st) == "va_list") {
4711 creation_call.add_argument (instance);
4712 if (get_ccode_name (m) == "va_start") {
4713 if (in_creation_method) {
4714 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("va_copy"));
4715 creation_call.add_argument (instance);
4716 creation_call.add_argument (new CCodeIdentifier ("_vala_va_list"));
4717 } else {
4718 Parameter last_param = null;
4719 // FIXME: this doesn't take into account exception handling parameters
4720 foreach (var param in current_method.get_parameters ()) {
4721 if (param.ellipsis) {
4722 break;
4724 last_param = param;
4726 int nParams = ccode.get_parameter_count ();
4727 if (nParams == 0 || !ccode.get_parameter (nParams - 1).ellipsis) {
4728 Report.error (expr.source_reference, "`va_list' used in method with fixed args");
4729 } else if (nParams == 1) {
4730 Report.error (expr.source_reference, "`va_list' used in method without parameter");
4731 } else {
4732 creation_call.add_argument (new CCodeIdentifier (ccode.get_parameter (nParams - 2).name));
4738 generate_type_declaration (expr.type_reference, cfile);
4740 var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
4741 var out_arg_map = in_arg_map;
4743 if (m != null && m.coroutine) {
4744 // async call
4746 async_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
4747 finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
4749 creation_call = finish_call;
4751 // output arguments used separately
4752 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
4753 // pass GAsyncResult stored in closure to finish function
4754 out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
4757 if (cl != null && !cl.is_compact) {
4758 add_generic_type_arguments (in_arg_map, expr.type_reference.get_type_arguments (), expr);
4759 } else if (cl != null && get_ccode_simple_generics (m)) {
4760 int type_param_index = 0;
4761 foreach (var type_arg in expr.type_reference.get_type_arguments ()) {
4762 if (requires_copy (type_arg)) {
4763 in_arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), get_destroy0_func_expression (type_arg));
4764 } else {
4765 in_arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
4767 type_param_index++;
4771 bool ellipsis = false;
4773 int i = 1;
4774 int arg_pos;
4775 Iterator<Parameter> params_it = params.iterator ();
4776 foreach (Expression arg in expr.get_argument_list ()) {
4777 CCodeExpression cexpr = get_cvalue (arg);
4779 var carg_map = in_arg_map;
4781 Parameter param = null;
4782 if (params_it.next ()) {
4783 param = params_it.get ();
4784 ellipsis = param.ellipsis;
4785 if (!ellipsis) {
4786 if (param.direction == ParameterDirection.OUT) {
4787 carg_map = out_arg_map;
4790 // g_array_new: element size
4791 if (cl == garray_type && param.name == "element_size") {
4792 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
4793 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference.get_type_arguments ().get (0))));
4794 cexpr = csizeof;
4797 if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
4798 var array_type = (ArrayType) param.variable_type;
4799 for (int dim = 1; dim <= array_type.rank; dim++) {
4800 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_array_length_cexpression (arg, dim));
4802 } else if (param.variable_type is DelegateType) {
4803 var deleg_type = (DelegateType) param.variable_type;
4804 var d = deleg_type.delegate_symbol;
4805 if (d.has_target) {
4806 CCodeExpression delegate_target_destroy_notify;
4807 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
4808 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
4809 if (deleg_type.is_disposable ()) {
4810 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param) + 0.01), delegate_target_destroy_notify);
4815 cexpr = handle_struct_argument (param, arg, cexpr);
4817 if (get_ccode_type (param) != null) {
4818 cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
4820 } else {
4821 cexpr = handle_struct_argument (null, arg, cexpr);
4824 arg_pos = get_param_pos (get_ccode_pos (param), ellipsis);
4825 } else {
4826 // default argument position
4827 cexpr = handle_struct_argument (null, arg, cexpr);
4828 arg_pos = get_param_pos (i, ellipsis);
4831 carg_map.set (arg_pos, cexpr);
4833 i++;
4835 if (params_it.next ()) {
4836 var param = params_it.get ();
4838 /* if there are more parameters than arguments,
4839 * the additional parameter is an ellipsis parameter
4840 * otherwise there is a bug in the semantic analyzer
4842 assert (param.params_array || param.ellipsis);
4843 ellipsis = true;
4846 if (expr.tree_can_fail) {
4847 // method can fail
4848 current_method_inner_error = true;
4849 // add &inner_error before the ellipsis arguments
4850 out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
4853 if (ellipsis) {
4854 /* ensure variable argument list ends with NULL
4855 * except when using printf-style arguments */
4856 if (m == null) {
4857 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
4858 } else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "") {
4859 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
4863 if ((st != null && !st.is_simple_type ()) && get_ccode_instance_pos (m) < 0) {
4864 // instance parameter is at the end in a struct creation method
4865 out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4868 if (m != null && m.coroutine) {
4869 if (expr.is_yield_expression) {
4870 // asynchronous call
4871 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
4872 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
4876 if (m != null && m.parent_symbol is Class) {
4877 if (get_ccode_finish_instance (m)) {
4878 var tmp = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_source_object_");
4879 out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), tmp);
4883 // append C arguments in the right order
4885 int last_pos;
4886 int min_pos;
4888 if (async_call != creation_call) {
4889 // don't append out arguments for .begin() calls
4890 last_pos = -1;
4891 while (true) {
4892 min_pos = -1;
4893 foreach (int pos in out_arg_map.get_keys ()) {
4894 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
4895 min_pos = pos;
4898 if (min_pos == -1) {
4899 break;
4901 creation_call.add_argument (out_arg_map.get (min_pos));
4902 last_pos = min_pos;
4906 if (async_call != null) {
4907 last_pos = -1;
4908 while (true) {
4909 min_pos = -1;
4910 foreach (int pos in in_arg_map.get_keys ()) {
4911 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
4912 min_pos = pos;
4915 if (min_pos == -1) {
4916 break;
4918 async_call.add_argument (in_arg_map.get (min_pos));
4919 last_pos = min_pos;
4923 if (expr.is_yield_expression) {
4924 // set state before calling async function to support immediate callbacks
4925 int state = emit_context.next_coroutine_state++;
4927 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
4928 ccode.add_expression (async_call);
4929 ccode.add_return (new CCodeConstant ("FALSE"));
4930 ccode.add_label ("_state_%d".printf (state));
4933 creation_expr = creation_call;
4935 // cast the return value of the creation method back to the intended type if
4936 // it requested a special C return type
4937 if (get_ccode_type (m) != null) {
4938 creation_expr = new CCodeCastExpression (creation_expr, get_ccode_name (expr.type_reference));
4940 } else if (expr.symbol_reference is ErrorCode) {
4941 var ecode = (ErrorCode) expr.symbol_reference;
4942 var edomain = (ErrorDomain) ecode.parent_symbol;
4943 CCodeFunctionCall creation_call;
4945 generate_error_domain_declaration (edomain, cfile);
4947 if (expr.get_argument_list ().size == 1) {
4948 // must not be a format argument
4949 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new_literal"));
4950 } else {
4951 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new"));
4953 creation_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (edomain)));
4954 creation_call.add_argument (new CCodeIdentifier (get_ccode_name (ecode)));
4956 foreach (Expression arg in expr.get_argument_list ()) {
4957 creation_call.add_argument (get_cvalue (arg));
4960 creation_expr = creation_call;
4961 } else {
4962 assert (false);
4965 var local = expr.parent_node as LocalVariable;
4966 if (local != null && is_simple_struct_creation (local, local.initializer)) {
4967 // no temporary variable necessary
4968 ccode.add_expression (creation_expr);
4969 set_cvalue (expr, instance);
4970 } else if (instance != null) {
4971 if (expr.type_reference.data_type is Struct) {
4972 ccode.add_expression (creation_expr);
4973 } else {
4974 ccode.add_assignment (instance, creation_expr);
4977 foreach (MemberInitializer init in expr.get_object_initializer ()) {
4978 if (init.symbol_reference is Field) {
4979 var f = (Field) init.symbol_reference;
4980 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
4981 var typed_inst = transform_value (new GLibValue (expr.type_reference, instance, true), instance_target_type, init);
4982 store_field (f, typed_inst, init.initializer.target_value, init.source_reference);
4984 var cl = f.parent_symbol as Class;
4985 if (cl != null) {
4986 generate_class_struct_declaration (cl, cfile);
4988 } else if (init.symbol_reference is Property) {
4989 var inst_ma = new MemberAccess.simple ("new");
4990 inst_ma.value_type = expr.type_reference;
4991 set_cvalue (inst_ma, instance);
4992 store_property ((Property) init.symbol_reference, inst_ma, init.initializer.target_value);
4993 // FIXME Do not ref/copy in the first place
4994 if (requires_destroy (init.initializer.target_value.value_type)) {
4995 ccode.add_expression (destroy_value (init.initializer.target_value));
5000 set_cvalue (expr, instance);
5001 } else if (creation_expr != null) {
5002 var temp_value = create_temp_value (expr.value_type, false, expr);
5003 ccode.add_assignment (get_cvalue_ (temp_value), creation_expr);
5004 expr.target_value = temp_value;
5006 if (context.gobject_tracing) {
5007 // GObject creation tracing enabled
5009 var cl = expr.type_reference.data_type as Class;
5010 if (cl != null && cl.is_subtype_of (gobject_type)) {
5011 // creating GObject
5013 // instance can be NULL in error cases
5014 ccode.open_if (get_cvalue_ (expr.target_value));
5016 var set_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set_data"));
5017 set_data_call.add_argument (new CCodeCastExpression (get_cvalue_ (expr.target_value), "GObject *"));
5018 set_data_call.add_argument (new CCodeConstant ("\"vala-creation-function\""));
5020 string func_name = "";
5021 if (current_method != null) {
5022 func_name = current_method.get_full_name ();
5023 } else if (current_property_accessor != null) {
5024 func_name = current_property_accessor.get_full_name ();
5027 set_data_call.add_argument (new CCodeConstant ("\"%s\"".printf (func_name)));
5029 ccode.add_expression (set_data_call);
5031 ccode.close ();
5036 ((GLibValue) expr.target_value).lvalue = true;
5039 public CCodeExpression? handle_struct_argument (Parameter? param, Expression arg, CCodeExpression? cexpr) {
5040 DataType type;
5041 if (param != null) {
5042 type = param.variable_type;
5043 } else {
5044 // varargs
5045 type = arg.value_type;
5048 var unary = arg as UnaryExpression;
5049 // pass non-simple struct instances always by reference
5050 if (!(arg.value_type is NullType) && type.is_real_struct_type ()) {
5051 // we already use a reference for arguments of ref, out, and nullable parameters
5052 if (!(unary != null && (unary.operator == UnaryOperator.OUT || unary.operator == UnaryOperator.REF)) && !type.nullable) {
5053 if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
5054 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5055 } else {
5056 // if cexpr is e.g. a function call, we can't take the address of the expression
5057 var temp_value = create_temp_value (type, false, arg);
5058 ccode.add_assignment (get_cvalue_ (temp_value), cexpr);
5059 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value));
5064 return cexpr;
5067 public override void visit_sizeof_expression (SizeofExpression expr) {
5068 generate_type_declaration (expr.type_reference, cfile);
5070 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5071 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference)));
5072 set_cvalue (expr, csizeof);
5075 public override void visit_typeof_expression (TypeofExpression expr) {
5076 set_cvalue (expr, get_type_id_expression (expr.type_reference));
5079 public override void visit_unary_expression (UnaryExpression expr) {
5080 if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) {
5081 var glib_value = (GLibValue) expr.inner.target_value;
5083 var ref_value = new GLibValue (glib_value.value_type);
5084 if (expr.target_type != null && glib_value.value_type.is_real_struct_type () && glib_value.value_type.nullable != expr.target_type.nullable) {
5085 // the only possibility is that value_type is nullable and target_type is non-nullable
5086 ref_value.cvalue = glib_value.cvalue;
5087 } else {
5088 ref_value.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.cvalue);
5091 if (glib_value.array_length_cvalues != null) {
5092 for (int i = 0; i < glib_value.array_length_cvalues.size; i++) {
5093 ref_value.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.array_length_cvalues[i]));
5097 if (glib_value.delegate_target_cvalue != null) {
5098 ref_value.delegate_target_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_cvalue);
5100 if (glib_value.delegate_target_destroy_notify_cvalue != null) {
5101 ref_value.delegate_target_destroy_notify_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_destroy_notify_cvalue);
5104 expr.target_value = ref_value;
5105 return;
5108 CCodeUnaryOperator op;
5109 if (expr.operator == UnaryOperator.PLUS) {
5110 op = CCodeUnaryOperator.PLUS;
5111 } else if (expr.operator == UnaryOperator.MINUS) {
5112 op = CCodeUnaryOperator.MINUS;
5113 } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
5114 op = CCodeUnaryOperator.LOGICAL_NEGATION;
5115 } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
5116 op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
5117 } else if (expr.operator == UnaryOperator.INCREMENT) {
5118 op = CCodeUnaryOperator.PREFIX_INCREMENT;
5119 } else if (expr.operator == UnaryOperator.DECREMENT) {
5120 op = CCodeUnaryOperator.PREFIX_DECREMENT;
5121 } else {
5122 assert_not_reached ();
5124 set_cvalue (expr, new CCodeUnaryExpression (op, get_cvalue (expr.inner)));
5127 public CCodeExpression? try_cast_value_to_type (CCodeExpression ccodeexpr, DataType from, DataType to, Expression? expr = null) {
5128 if (from == null || gvalue_type == null || from.data_type != gvalue_type || to.data_type == gvalue_type || get_ccode_type_id (to) == "") {
5129 return null;
5132 // explicit conversion from GValue
5133 var ccall = new CCodeFunctionCall (get_value_getter_function (to));
5134 CCodeExpression gvalue;
5135 if (from.nullable) {
5136 gvalue = ccodeexpr;
5137 } else {
5138 gvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ccodeexpr);
5140 ccall.add_argument (gvalue);
5142 CCodeExpression rv = ccall;
5144 if (expr != null && to is ArrayType) {
5145 // null-terminated string array
5146 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
5147 len_call.add_argument (rv);
5148 append_array_length (expr, len_call);
5149 } else if (to is StructValueType) {
5150 CodeNode node = expr != null ? (CodeNode) expr : to;
5151 var temp_value = create_temp_value (to, true, node, true);
5152 var ctemp = get_cvalue_ (temp_value);
5154 rv = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeCastExpression (rv, get_ccode_name (new PointerType (to))));
5155 var holds = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_HOLDS"));
5156 holds.add_argument (gvalue);
5157 holds.add_argument (new CCodeIdentifier (get_ccode_type_id (to)));
5158 var cond = new CCodeBinaryExpression (CCodeBinaryOperator.AND, holds, ccall);
5159 var warn = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
5160 warn.add_argument (new CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
5161 var fail = new CCodeCommaExpression ();
5162 fail.append_expression (warn);
5163 fail.append_expression (ctemp);
5164 rv = new CCodeConditionalExpression (cond, rv, fail);
5167 return rv;
5170 int next_variant_function_id = 0;
5172 public TargetValue? try_cast_variant_to_type (TargetValue value, DataType to, CodeNode? node = null) {
5173 if (value.value_type == null || gvariant_type == null || value.value_type.data_type != gvariant_type) {
5174 return null;
5177 string variant_func = "_variant_get%d".printf (++next_variant_function_id);
5179 var variant = value;
5180 if (value.value_type.value_owned) {
5181 // value leaked, destroy it
5182 var temp_value = store_temp_value (value, node);
5183 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5184 variant = temp_value;
5187 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
5188 ccall.add_argument (get_cvalue_ (variant));
5190 var result = create_temp_value (to, false, node);
5192 var cfunc = new CCodeFunction (variant_func);
5193 cfunc.modifiers = CCodeModifiers.STATIC;
5194 cfunc.add_parameter (new CCodeParameter ("value", "GVariant*"));
5196 if (!to.is_real_non_null_struct_type ()) {
5197 cfunc.return_type = get_ccode_name (to);
5200 if (to.is_real_non_null_struct_type ()) {
5201 // structs are returned via out parameter
5202 cfunc.add_parameter (new CCodeParameter ("result", "%s *".printf (get_ccode_name (to))));
5203 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (result)));
5204 } else if (to is ArrayType) {
5205 // return array length if appropriate
5206 // tmp = _variant_get (variant, &tmp_length);
5207 var array_type = (ArrayType) to;
5209 for (int dim = 1; dim <= array_type.rank; dim++) {
5210 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cvalue (result, dim)));
5211 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("result", dim), "int*"));
5215 if (!to.is_real_non_null_struct_type ()) {
5216 ccode.add_assignment (get_cvalue_ (result), ccall);
5217 } else {
5218 ccode.add_expression (ccall);
5221 push_function (cfunc);
5223 CCodeExpression func_result = deserialize_expression (to, new CCodeIdentifier ("value"), new CCodeIdentifier ("*result"));
5224 if (to.is_real_non_null_struct_type ()) {
5225 ccode.add_assignment (new CCodeIdentifier ("*result"), func_result);
5226 } else {
5227 ccode.add_return (func_result);
5230 pop_function ();
5232 cfile.add_function_declaration (cfunc);
5233 cfile.add_function (cfunc);
5235 return load_temp_value (result);
5238 public virtual CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
5239 assert_not_reached ();
5242 public virtual CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
5243 assert_not_reached ();
5246 public override void visit_cast_expression (CastExpression expr) {
5247 generate_type_declaration (expr.type_reference, cfile);
5249 if (!expr.is_non_null_cast) {
5250 var valuecast = try_cast_value_to_type (get_cvalue (expr.inner), expr.inner.value_type, expr.type_reference, expr);
5251 if (valuecast != null) {
5252 set_cvalue (expr, valuecast);
5253 return;
5256 var variantcast = try_cast_variant_to_type (expr.inner.target_value, expr.type_reference, expr);
5257 if (variantcast != null) {
5258 expr.target_value = variantcast;
5259 return;
5263 var cl = expr.type_reference.data_type as Class;
5264 var iface = expr.type_reference.data_type as Interface;
5265 if (context.profile == Profile.GOBJECT && (iface != null || (cl != null && !cl.is_compact))) {
5266 // checked cast for strict subtypes of GTypeInstance
5267 if (expr.is_silent_cast) {
5268 TargetValue to_cast = expr.inner.target_value;
5269 CCodeExpression cexpr;
5270 if (!get_lvalue (to_cast)) {
5271 to_cast = store_temp_value (to_cast, expr);
5273 cexpr = get_cvalue_ (to_cast);
5274 var ccheck = create_type_check (cexpr, expr.type_reference);
5275 var ccast = new CCodeCastExpression (cexpr, get_ccode_name (expr.type_reference));
5276 var cnull = new CCodeConstant ("NULL");
5277 var cast_value = new GLibValue (expr.value_type, new CCodeConditionalExpression (ccheck, ccast, cnull));
5278 if (requires_destroy (expr.inner.value_type)) {
5279 var casted = store_temp_value (cast_value, expr);
5280 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_cvalue_ (casted), new CCodeConstant ("NULL")));
5281 ccode.add_expression (destroy_value (to_cast));
5282 ccode.close ();
5283 expr.target_value = ((GLibValue) casted).copy ();
5284 } else {
5285 expr.target_value = cast_value;
5287 } else {
5288 set_cvalue (expr, generate_instance_cast (get_cvalue (expr.inner), expr.type_reference.data_type));
5290 } else {
5291 if (expr.is_silent_cast) {
5292 set_cvalue (expr, new CCodeInvalidExpression ());
5293 expr.error = true;
5294 Report.error (expr.source_reference, "Operation not supported for this type");
5295 return;
5298 // recompute array length when casting to other array type
5299 var array_type = expr.type_reference as ArrayType;
5300 if (array_type != null && expr.inner.value_type is ArrayType) {
5301 if (array_type.element_type is GenericType || ((ArrayType) expr.inner.value_type).element_type is GenericType) {
5302 // element size unknown for generic arrays, retain array length as is
5303 for (int dim = 1; dim <= array_type.rank; dim++) {
5304 append_array_length (expr, get_array_length_cexpression (expr.inner, dim));
5306 } else {
5307 var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5308 sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5310 var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5311 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (((ArrayType) expr.inner.value_type).element_type)));
5313 for (int dim = 1; dim <= array_type.rank; dim++) {
5314 append_array_length (expr, new CCodeBinaryExpression (CCodeBinaryOperator.DIV, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_array_length_cexpression (expr.inner, dim), sizeof_from), sizeof_to));
5317 } else if (array_type != null) {
5318 CCodeExpression array_length_expr;
5320 var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5321 sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5322 var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5324 var value_type = expr.inner.value_type;
5325 if (value_type is ValueType) {
5326 var data_type = ((ValueType) value_type).data_type;
5327 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (data_type)));
5328 array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5329 } else if (value_type is PointerType && ((PointerType) value_type).base_type is ValueType) {
5330 var data_type = ((ValueType) (((PointerType) value_type).base_type)).data_type;
5331 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (data_type)));
5332 array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5333 } else {
5334 // cast from unsupported non-array to array, set invalid length
5335 // required by string.data, e.g.
5336 array_length_expr = new CCodeConstant ("-1");
5339 for (int dim = 1; dim <= array_type.rank; dim++) {
5340 append_array_length (expr, array_length_expr);
5344 var innercexpr = get_cvalue (expr.inner);
5345 if (expr.type_reference is ValueType && !expr.type_reference.nullable &&
5346 expr.inner.value_type is ValueType && expr.inner.value_type.nullable) {
5347 // nullable integer or float or boolean or struct or enum cast to non-nullable
5348 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, innercexpr);
5349 } else if (expr.type_reference is ArrayType
5350 && expr.inner.value_type is ValueType && !expr.inner.value_type.nullable) {
5351 // integer or float or boolean or struct or enum to array cast
5352 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, innercexpr);
5354 set_cvalue (expr, new CCodeCastExpression (innercexpr, get_ccode_name (expr.type_reference)));
5356 if (expr.type_reference is DelegateType) {
5357 if (get_delegate_target (expr.inner) != null) {
5358 set_delegate_target (expr, get_delegate_target (expr.inner));
5359 } else {
5360 set_delegate_target (expr, new CCodeConstant ("NULL"));
5362 if (get_delegate_target_destroy_notify (expr.inner) != null) {
5363 set_delegate_target_destroy_notify (expr, get_delegate_target_destroy_notify (expr.inner));
5364 } else {
5365 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
5371 public override void visit_named_argument (NamedArgument expr) {
5372 set_cvalue (expr, get_cvalue (expr.inner));
5375 public override void visit_pointer_indirection (PointerIndirection expr) {
5376 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cvalue (expr.inner)));
5377 ((GLibValue) expr.target_value).lvalue = get_lvalue (expr.inner.target_value);
5380 public override void visit_addressof_expression (AddressofExpression expr) {
5381 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5384 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
5385 /* tmp = expr.inner; expr.inner = NULL; expr = tmp; */
5386 expr.target_value = store_temp_value (expr.inner.target_value, expr);
5388 if (expr.inner.value_type is StructValueType && !expr.inner.value_type.nullable) {
5389 // memset needs string.h
5390 cfile.add_include ("string.h");
5391 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
5392 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5393 creation_call.add_argument (new CCodeConstant ("0"));
5394 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.inner.value_type))));
5395 ccode.add_expression (creation_call);
5396 } else if (expr.value_type is DelegateType) {
5397 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5398 var target = get_delegate_target_cvalue (expr.inner.target_value);
5399 if (target != null) {
5400 ccode.add_assignment (target, new CCodeConstant ("NULL"));
5402 var target_destroy_notify = get_delegate_target_destroy_notify_cvalue (expr.inner.target_value);
5403 if (target_destroy_notify != null) {
5404 ccode.add_assignment (target_destroy_notify, new CCodeConstant ("NULL"));
5406 } else if (expr.inner.value_type is ArrayType) {
5407 var array_type = (ArrayType) expr.inner.value_type;
5408 var glib_value = (GLibValue) expr.inner.target_value;
5410 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5411 if (glib_value.array_length_cvalues != null) {
5412 for (int dim = 1; dim <= array_type.rank; dim++) {
5413 ccode.add_assignment (get_array_length_cvalue (glib_value, dim), new CCodeConstant ("0"));
5416 } else {
5417 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5421 public override void visit_binary_expression (BinaryExpression expr) {
5422 var cleft = get_cvalue (expr.left);
5423 var cright = get_cvalue (expr.right);
5425 CCodeExpression? left_chain = null;
5426 if (expr.is_chained) {
5427 var lbe = (BinaryExpression) expr.left;
5429 var temp_decl = get_temp_variable (lbe.right.target_type, true, null, false);
5430 emit_temp_var (temp_decl);
5431 var cvar = get_variable_cexpression (temp_decl.name);
5432 var clbe = (CCodeBinaryExpression) get_cvalue (lbe);
5433 if (lbe.is_chained) {
5434 clbe = (CCodeBinaryExpression) clbe.right;
5436 ccode.add_assignment (cvar, get_cvalue (lbe.right));
5437 clbe.right = get_variable_cexpression (temp_decl.name);
5438 left_chain = cleft;
5439 cleft = cvar;
5442 CCodeBinaryOperator op;
5443 if (expr.operator == BinaryOperator.PLUS) {
5444 op = CCodeBinaryOperator.PLUS;
5445 } else if (expr.operator == BinaryOperator.MINUS) {
5446 op = CCodeBinaryOperator.MINUS;
5447 } else if (expr.operator == BinaryOperator.MUL) {
5448 op = CCodeBinaryOperator.MUL;
5449 } else if (expr.operator == BinaryOperator.DIV) {
5450 op = CCodeBinaryOperator.DIV;
5451 } else if (expr.operator == BinaryOperator.MOD) {
5452 if (expr.value_type.equals (double_type)) {
5453 cfile.add_include ("math.h");
5454 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
5455 ccall.add_argument (cleft);
5456 ccall.add_argument (cright);
5457 set_cvalue (expr, ccall);
5458 return;
5459 } else if (expr.value_type.equals (float_type)) {
5460 cfile.add_include ("math.h");
5461 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
5462 ccall.add_argument (cleft);
5463 ccall.add_argument (cright);
5464 set_cvalue (expr, ccall);
5465 return;
5466 } else {
5467 op = CCodeBinaryOperator.MOD;
5469 } else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
5470 op = CCodeBinaryOperator.SHIFT_LEFT;
5471 } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
5472 op = CCodeBinaryOperator.SHIFT_RIGHT;
5473 } else if (expr.operator == BinaryOperator.LESS_THAN) {
5474 op = CCodeBinaryOperator.LESS_THAN;
5475 } else if (expr.operator == BinaryOperator.GREATER_THAN) {
5476 op = CCodeBinaryOperator.GREATER_THAN;
5477 } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
5478 op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
5479 } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
5480 op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
5481 } else if (expr.operator == BinaryOperator.EQUALITY) {
5482 op = CCodeBinaryOperator.EQUALITY;
5483 } else if (expr.operator == BinaryOperator.INEQUALITY) {
5484 op = CCodeBinaryOperator.INEQUALITY;
5485 } else if (expr.operator == BinaryOperator.BITWISE_AND) {
5486 op = CCodeBinaryOperator.BITWISE_AND;
5487 } else if (expr.operator == BinaryOperator.BITWISE_OR) {
5488 op = CCodeBinaryOperator.BITWISE_OR;
5489 } else if (expr.operator == BinaryOperator.BITWISE_XOR) {
5490 op = CCodeBinaryOperator.BITWISE_XOR;
5491 } else if (expr.operator == BinaryOperator.AND) {
5492 op = CCodeBinaryOperator.AND;
5493 } else if (expr.operator == BinaryOperator.OR) {
5494 op = CCodeBinaryOperator.OR;
5495 } else if (expr.operator == BinaryOperator.IN) {
5496 if (expr.right.value_type is ArrayType) {
5497 var array_type = (ArrayType) expr.right.value_type;
5498 var node = new CCodeFunctionCall (new CCodeIdentifier (generate_array_contains_wrapper (array_type)));
5499 node.add_argument (cright);
5500 node.add_argument (get_array_length_cexpression (expr.right));
5501 if (array_type.element_type is StructValueType) {
5502 node.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft));
5503 } else {
5504 node.add_argument (cleft);
5506 set_cvalue (expr, node);
5507 } else {
5508 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft));
5510 return;
5511 } else {
5512 assert_not_reached ();
5515 if (expr.operator == BinaryOperator.EQUALITY ||
5516 expr.operator == BinaryOperator.INEQUALITY) {
5517 var left_type = expr.left.target_type;
5518 var right_type = expr.right.target_type;
5519 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
5521 if (left_type is StructValueType && right_type is StructValueType) {
5522 var equalfunc = generate_struct_equal_function ((Struct) left_type.data_type);
5523 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5524 ccall.add_argument (cleft);
5525 ccall.add_argument (cright);
5526 cleft = ccall;
5527 cright = new CCodeConstant ("TRUE");
5528 } else if ((left_type is IntegerType || left_type is FloatingType || left_type is BooleanType || left_type is EnumValueType) && left_type.nullable &&
5529 (right_type is IntegerType || right_type is FloatingType || right_type is BooleanType || right_type is EnumValueType) && right_type.nullable) {
5530 var equalfunc = generate_numeric_equal_function ((TypeSymbol) left_type.data_type);
5531 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5532 ccall.add_argument (cleft);
5533 ccall.add_argument (cright);
5534 cleft = ccall;
5535 cright = new CCodeConstant ("TRUE");
5539 if (!(expr.left.value_type is NullType)
5540 && expr.left.value_type.compatible (string_type)
5541 && !(expr.right.value_type is NullType)
5542 && expr.right.value_type.compatible (string_type)) {
5543 if (expr.operator == BinaryOperator.PLUS) {
5544 // string concatenation
5545 if (expr.left.is_constant () && expr.right.is_constant ()) {
5546 string left, right;
5548 if (cleft is CCodeIdentifier) {
5549 left = ((CCodeIdentifier) cleft).name;
5550 } else if (cleft is CCodeConstant) {
5551 left = ((CCodeConstant) cleft).name;
5552 } else {
5553 assert_not_reached ();
5555 if (cright is CCodeIdentifier) {
5556 right = ((CCodeIdentifier) cright).name;
5557 } else if (cright is CCodeConstant) {
5558 right = ((CCodeConstant) cright).name;
5559 } else {
5560 assert_not_reached ();
5563 set_cvalue (expr, new CCodeConstant ("%s %s".printf (left, right)));
5564 return;
5565 } else {
5566 var temp_value = create_temp_value (expr.value_type, false, expr);
5567 CCodeFunctionCall ccall;
5569 if (context.profile == Profile.POSIX) {
5570 // convert to strcat (strcpy (malloc (1 + strlen (a) + strlen (b)), a), b)
5571 ccall = new CCodeFunctionCall (new CCodeIdentifier ("strcat"));
5572 var strcpy = new CCodeFunctionCall (new CCodeIdentifier ("strcpy"));
5573 var malloc = new CCodeFunctionCall (new CCodeIdentifier ("malloc"));
5575 var strlen_a = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
5576 strlen_a.add_argument (cleft);
5577 var strlen_b = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
5578 strlen_b.add_argument (cright);
5579 var newlength = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("1"),
5580 new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, strlen_a, strlen_b));
5581 malloc.add_argument (newlength);
5583 strcpy.add_argument (malloc);
5584 strcpy.add_argument (cleft);
5586 ccall.add_argument (strcpy);
5587 ccall.add_argument (cright);
5588 } else {
5589 // convert to g_strconcat (a, b, NULL)
5590 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
5591 ccall.add_argument (cleft);
5592 ccall.add_argument (cright);
5593 ccall.add_argument (new CCodeConstant("NULL"));
5596 ccode.add_assignment (get_cvalue_ (temp_value), ccall);
5597 expr.target_value = temp_value;
5598 return;
5600 } else if (expr.operator == BinaryOperator.EQUALITY
5601 || expr.operator == BinaryOperator.INEQUALITY
5602 || expr.operator == BinaryOperator.LESS_THAN
5603 || expr.operator == BinaryOperator.GREATER_THAN
5604 || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL
5605 || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
5606 CCodeFunctionCall ccall;
5607 if (context.profile == Profile.POSIX) {
5608 ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
5609 } else {
5610 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5612 ccall.add_argument (cleft);
5613 ccall.add_argument (cright);
5614 cleft = ccall;
5615 cright = new CCodeConstant ("0");
5619 set_cvalue (expr, new CCodeBinaryExpression (op, cleft, cright));
5620 if (left_chain != null) {
5621 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.AND, left_chain, get_cvalue (expr)));
5625 CCodeExpression? create_type_check (CCodeNode ccodenode, DataType type) {
5626 var et = type as ErrorType;
5627 if (et != null && et.error_code != null) {
5628 var matches_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
5629 matches_call.add_argument ((CCodeExpression) ccodenode);
5630 matches_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain)));
5631 matches_call.add_argument (new CCodeIdentifier (get_ccode_name (et.error_code)));
5632 return matches_call;
5633 } else if (et != null && et.error_domain != null) {
5634 var instance_domain = new CCodeMemberAccess.pointer ((CCodeExpression) ccodenode, "domain");
5635 var type_domain = new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain));
5636 return new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, instance_domain, type_domain);
5637 } else {
5638 var type_id = get_type_id_expression (type);
5639 if (type_id == null) {
5640 return new CCodeInvalidExpression ();
5642 var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
5643 ccheck.add_argument ((CCodeExpression) ccodenode);
5644 ccheck.add_argument (type_id);
5645 return ccheck;
5649 string generate_array_contains_wrapper (ArrayType array_type) {
5650 string array_contains_func = "_vala_%s_array_contains".printf (get_ccode_lower_case_name (array_type.element_type));
5652 if (!add_wrapper (array_contains_func)) {
5653 return array_contains_func;
5656 var function = new CCodeFunction (array_contains_func, "gboolean");
5657 function.modifiers = CCodeModifiers.STATIC;
5659 function.add_parameter (new CCodeParameter ("stack", "%s *".printf (get_ccode_name (array_type.element_type))));
5660 function.add_parameter (new CCodeParameter ("stack_length", "int"));
5661 if (array_type.element_type is StructValueType) {
5662 function.add_parameter (new CCodeParameter ("needle", "%s *".printf (get_ccode_name (array_type.element_type))));
5663 } else {
5664 function.add_parameter (new CCodeParameter ("needle", get_ccode_name (array_type.element_type)));
5667 push_function (function);
5669 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
5671 var cloop_initializer = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
5672 var cloop_condition = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("stack_length"));
5673 var cloop_iterator = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"));
5674 ccode.open_for (cloop_initializer, cloop_condition, cloop_iterator);
5676 var celement = new CCodeElementAccess (new CCodeIdentifier ("stack"), new CCodeIdentifier ("i"));
5677 var cneedle = new CCodeIdentifier ("needle");
5678 CCodeBinaryExpression cif_condition;
5679 if (array_type.element_type.compatible (string_type)) {
5680 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5681 ccall.add_argument (celement);
5682 ccall.add_argument (cneedle);
5683 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("0"));
5684 } else if (array_type.element_type is StructValueType) {
5685 var equalfunc = generate_struct_equal_function ((Struct) array_type.element_type.data_type);
5686 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5687 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, celement));
5688 ccall.add_argument (cneedle);
5689 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("TRUE"));
5690 } else {
5691 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cneedle, celement);
5694 ccode.open_if (cif_condition);
5695 ccode.add_return (new CCodeConstant ("TRUE"));
5696 ccode.close ();
5698 ccode.close ();
5700 ccode.add_return (new CCodeConstant ("FALSE"));
5702 pop_function ();
5704 cfile.add_function_declaration (function);
5705 cfile.add_function (function);
5707 return array_contains_func;
5710 string generate_cmp_wrapper (CCodeIdentifier cmpid) {
5711 // generate and call NULL-aware cmp function to reduce number
5712 // of temporary variables and simplify code
5714 string cmp0_func = "_%s0".printf (cmpid.name);
5716 // g_strcmp0 is already NULL-safe
5717 if (cmpid.name == "g_strcmp0") {
5718 cmp0_func = cmpid.name;
5719 } else if (add_wrapper (cmp0_func)) {
5720 var cmp0_fun = new CCodeFunction (cmp0_func, "int");
5721 cmp0_fun.add_parameter (new CCodeParameter ("s1", "const void *"));
5722 cmp0_fun.add_parameter (new CCodeParameter ("s2", "const void *"));
5723 cmp0_fun.modifiers = CCodeModifiers.STATIC;
5725 push_function (cmp0_fun);
5727 // s1 != s2;
5728 var noteq = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
5730 // if (!s1) return -(s1 != s2);
5732 var cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("s1"));
5733 ccode.open_if (cexp);
5734 ccode.add_return (new CCodeUnaryExpression (CCodeUnaryOperator.MINUS, noteq));
5735 ccode.close ();
5737 // if (!s2) return s1 != s2;
5739 var cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("s2"));
5740 ccode.open_if (cexp);
5741 ccode.add_return (noteq);
5742 ccode.close ();
5744 // return strcmp (s1, s2);
5745 var cmp_call = new CCodeFunctionCall (cmpid);
5746 cmp_call.add_argument (new CCodeIdentifier ("s1"));
5747 cmp_call.add_argument (new CCodeIdentifier ("s2"));
5748 ccode.add_return (cmp_call);
5750 pop_function ();
5752 cfile.add_function (cmp0_fun);
5755 return cmp0_func;
5758 public override void visit_type_check (TypeCheck expr) {
5759 generate_type_declaration (expr.type_reference, cfile);
5761 var type = expr.expression.value_type;
5762 var pointer_type = type as PointerType;
5763 if (pointer_type != null) {
5764 type = pointer_type.base_type;
5766 var cl = type.data_type as Class;
5767 var iface = type.data_type as Interface;
5768 if ((cl != null && !cl.is_compact) || iface != null || type is GenericType || type is ErrorType) {
5769 set_cvalue (expr, create_type_check (get_cvalue (expr.expression), expr.type_reference));
5770 } else {
5771 set_cvalue (expr, new CCodeInvalidExpression ());
5774 if (get_cvalue (expr) is CCodeInvalidExpression) {
5775 Report.error (expr.source_reference, "type check expressions not supported for compact classes, structs, and enums");
5779 public override void visit_lambda_expression (LambdaExpression lambda) {
5780 var delegate_type = (DelegateType) lambda.target_type;
5781 var d = delegate_type.delegate_symbol;
5783 lambda.method.set_attribute_bool ("CCode", "array_length", get_ccode_array_length (d));
5784 lambda.method.set_attribute_bool ("CCode", "array_null_terminated", get_ccode_array_null_terminated (d));
5785 lambda.method.set_attribute_string ("CCode", "array_length_type", get_ccode_array_length_type (d));
5787 lambda.accept_children (this);
5789 bool expr_owned = lambda.value_type.value_owned;
5791 set_cvalue (lambda, new CCodeIdentifier (get_ccode_name (lambda.method)));
5793 if (lambda.method.closure) {
5794 int block_id = get_block_id (current_closure_block);
5795 var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
5796 if (expr_owned || delegate_type.is_called_once) {
5797 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
5798 ref_call.add_argument (delegate_target);
5799 delegate_target = ref_call;
5800 set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
5801 } else {
5802 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5804 set_delegate_target (lambda, delegate_target);
5805 } else if (get_this_type () != null) {
5806 CCodeExpression delegate_target = get_result_cexpression ("self");
5807 delegate_target = convert_to_generic_pointer (delegate_target, get_this_type ());
5808 if (expr_owned || delegate_type.is_called_once) {
5809 var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_this_type (), lambda.source_reference));
5810 ref_call.add_argument (delegate_target);
5811 delegate_target = ref_call;
5812 set_delegate_target_destroy_notify (lambda, get_destroy_func_expression (get_this_type ()));
5813 } else {
5814 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5816 set_delegate_target (lambda, delegate_target);
5817 } else {
5818 set_delegate_target (lambda, new CCodeConstant ("NULL"));
5819 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5823 public CCodeExpression convert_from_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
5824 var result = cexpr;
5825 if (is_reference_type_argument (actual_type) || is_nullable_value_type_argument (actual_type)) {
5826 result = new CCodeCastExpression (cexpr, get_ccode_name (actual_type));
5827 } else if (is_signed_integer_type_argument (actual_type)) {
5828 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), get_ccode_name (actual_type));
5829 } else if (is_unsigned_integer_type_argument (actual_type)) {
5830 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), get_ccode_name (actual_type));
5832 return result;
5835 public CCodeExpression convert_to_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
5836 var result = cexpr;
5837 if (is_signed_integer_type_argument (actual_type)) {
5838 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), "gpointer");
5839 } else if (is_unsigned_integer_type_argument (actual_type)) {
5840 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), "gpointer");
5842 return result;
5845 public TargetValue transform_value (TargetValue value, DataType? target_type, CodeNode node) {
5846 var type = value.value_type;
5847 var result = ((GLibValue) value).copy ();
5849 if (type.value_owned
5850 && (target_type == null || target_type is GenericType || !target_type.floating_reference)
5851 && type.floating_reference) {
5852 /* floating reference, sink it.
5854 var cl = type.data_type as ObjectTypeSymbol;
5855 var sink_func = (cl != null) ? get_ccode_ref_sink_function (cl) : "";
5857 if (sink_func != "") {
5858 if (type.nullable) {
5859 var is_not_null = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, result.cvalue, new CCodeIdentifier ("NULL"));
5860 ccode.open_if (is_not_null);
5863 var csink = new CCodeFunctionCall (new CCodeIdentifier (sink_func));
5864 csink.add_argument (result.cvalue);
5865 ccode.add_expression (csink);
5867 if (type.nullable) {
5868 ccode.close ();
5870 } else {
5871 Report.error (node.source_reference, "type `%s' does not support floating references".printf (type.data_type.name));
5875 bool boxing = (type is ValueType && !type.nullable
5876 && target_type is ValueType && target_type.nullable);
5877 bool unboxing = (type is ValueType && type.nullable
5878 && target_type is ValueType && !target_type.nullable);
5880 bool gvalue_boxing = (context.profile == Profile.GOBJECT
5881 && target_type != null
5882 && target_type.data_type == gvalue_type
5883 && !(type is NullType)
5884 && get_ccode_type_id (type) != "G_TYPE_VALUE");
5885 bool gvariant_boxing = (context.profile == Profile.GOBJECT
5886 && target_type != null
5887 && target_type.data_type == gvariant_type
5888 && !(type is NullType)
5889 && type.data_type != gvariant_type);
5891 if (type.value_owned
5892 && (target_type == null || !target_type.value_owned || boxing || unboxing || gvariant_boxing)
5893 && !gvalue_boxing /* gvalue can assume ownership of value, no need to free it */) {
5894 // value leaked, destroy it
5895 if (target_type is PointerType) {
5896 // manual memory management for pointers
5897 } else if (requires_destroy (type)) {
5898 if (!is_lvalue_access_allowed (type)) {
5899 // cannot assign to a temporary variable
5900 temp_ref_values.insert (0, result.copy ());
5901 } else {
5902 var temp_value = create_temp_value (type, false, node);
5903 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5904 store_value (temp_value, result, node.source_reference);
5905 result.cvalue = get_cvalue_ (temp_value);
5910 if (target_type == null) {
5911 // value will be destroyed, no need for implicit casts
5912 return result;
5915 result.value_type = target_type.copy ();
5917 if (gvalue_boxing) {
5918 // implicit conversion to GValue
5919 var temp_value = create_temp_value (target_type, true, node, true);
5921 if (!target_type.value_owned) {
5922 // boxed GValue leaked, destroy it
5923 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5926 if (target_type.nullable) {
5927 var newcall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
5928 newcall.add_argument (new CCodeConstant ("GValue"));
5929 newcall.add_argument (new CCodeConstant ("1"));
5930 var newassignment = new CCodeAssignment (get_cvalue_ (temp_value), newcall);
5931 ccode.add_expression (newassignment);
5934 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
5935 if (target_type.nullable) {
5936 ccall.add_argument (get_cvalue_ (temp_value));
5937 } else {
5938 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
5940 var type_id = get_ccode_type_id (type);
5941 if (type_id == "") {
5942 Report.error (node.source_reference, "GValue boxing of type `%s' is not supported".printf (type.to_string ()));
5944 ccall.add_argument (new CCodeIdentifier (type_id));
5945 ccode.add_expression (ccall);
5947 if (requires_destroy (type)) {
5948 ccall = new CCodeFunctionCall (get_value_taker_function (type));
5949 } else {
5950 ccall = new CCodeFunctionCall (get_value_setter_function (type));
5952 if (target_type.nullable) {
5953 ccall.add_argument (get_cvalue_ (temp_value));
5954 } else {
5955 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
5957 if (type.is_real_non_null_struct_type ()) {
5958 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue));
5959 } else {
5960 ccall.add_argument (result.cvalue);
5963 ccode.add_expression (ccall);
5965 result = (GLibValue) temp_value;
5966 } else if (gvariant_boxing) {
5967 // implicit conversion to GVariant
5968 string variant_func = "_variant_new%d".printf (++next_variant_function_id);
5970 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
5971 ccall.add_argument (result.cvalue);
5973 var cfunc = new CCodeFunction (variant_func, "GVariant*");
5974 cfunc.modifiers = CCodeModifiers.STATIC;
5975 cfunc.add_parameter (new CCodeParameter ("value", get_ccode_name (type)));
5977 if (type is ArrayType) {
5978 // return array length if appropriate
5979 var array_type = (ArrayType) type;
5981 for (int dim = 1; dim <= array_type.rank; dim++) {
5982 ccall.add_argument (get_array_length_cvalue (value, dim));
5983 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), "gint"));
5987 push_function (cfunc);
5989 // sink floating reference
5990 var sink = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_ref_sink"));
5991 sink.add_argument (serialize_expression (type, new CCodeIdentifier ("value")));
5992 ccode.add_return (sink);
5994 pop_function ();
5996 cfile.add_function_declaration (cfunc);
5997 cfile.add_function (cfunc);
5999 result.cvalue = ccall;
6000 result.value_type.value_owned = true;
6002 result = (GLibValue) store_temp_value (result, node);
6003 if (!target_type.value_owned) {
6004 // value leaked
6005 temp_ref_values.insert (0, ((GLibValue) result).copy ());
6007 } else if (boxing) {
6008 // value needs to be boxed
6010 result.value_type.nullable = false;
6011 if (!result.lvalue || !result.value_type.equals (value.value_type)) {
6012 result.cvalue = get_implicit_cast_expression (result.cvalue, value.value_type, result.value_type, node);
6013 result = (GLibValue) store_temp_value (result, node);
6015 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue);
6016 result.lvalue = false;
6017 result.value_type.nullable = true;
6018 } else if (unboxing) {
6019 // unbox value
6021 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result.cvalue);
6022 } else {
6023 // TODO: rewrite get_implicit_cast_expression to return a GLibValue
6024 var old_cexpr = result.cvalue;
6025 result.cvalue = get_implicit_cast_expression (result.cvalue, type, target_type, node);
6026 result.lvalue = result.lvalue && result.cvalue == old_cexpr;
6029 bool array_needs_copy = false;
6030 if (type is ArrayType && target_type is ArrayType) {
6031 var array = (ArrayType) type;
6032 var target_array = (ArrayType) target_type;
6033 if (target_array.element_type.value_owned && !array.element_type.value_owned) {
6034 array_needs_copy = requires_copy (target_array.element_type);
6038 if (!gvalue_boxing && !gvariant_boxing && target_type.value_owned && (!type.value_owned || boxing || unboxing || array_needs_copy) && requires_copy (target_type) && !(type is NullType)) {
6039 // need to copy value
6040 var copy = (GLibValue) copy_value (result, node);
6041 if (target_type.data_type is Interface && copy == null) {
6042 Report.error (node.source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure".printf (target_type.data_type.get_full_name ()));
6043 return result;
6045 result = copy;
6047 // implicit array copying is deprecated, but allow it for internal codegen usage
6048 var prop_acc = node as PropertyAccessor;
6049 if ((prop_acc != null && !prop_acc.automatic_body)
6050 && result.value_type is ArrayType) {
6051 Report.deprecated (node.source_reference, "implicit copy of array is deprecated, explicitly invoke the copy method instead");
6055 return result;
6058 public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, CodeNode? node) {
6059 var cexpr = source_cexpr;
6061 if (expression_type.data_type != null && expression_type.data_type == target_type.data_type) {
6062 // same type, no cast required
6063 return cexpr;
6066 if (expression_type is NullType) {
6067 // null literal, no cast required when not converting to generic type pointer
6068 return cexpr;
6071 generate_type_declaration (target_type, cfile);
6073 var cl = target_type.data_type as Class;
6074 var iface = target_type.data_type as Interface;
6075 if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
6076 // checked cast for strict subtypes of GTypeInstance
6077 return generate_instance_cast (cexpr, target_type.data_type);
6078 } else if (target_type.data_type != null && get_ccode_name (expression_type) != get_ccode_name (target_type)) {
6079 var st = target_type.data_type as Struct;
6080 if (target_type.data_type.is_reference_type () || (st != null && st.is_simple_type ())) {
6081 // don't cast non-simple structs
6082 return new CCodeCastExpression (cexpr, get_ccode_name (target_type));
6083 } else {
6084 return cexpr;
6086 } else {
6087 return cexpr;
6091 public void store_property (Property prop, Expression? instance, TargetValue value) {
6092 if (instance is BaseAccess) {
6093 if (prop.base_property != null) {
6094 var base_class = (Class) prop.base_property.parent_symbol;
6095 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class, null))));
6096 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class, null))));
6098 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
6099 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
6100 var cexpr = get_cvalue_ (value);
6101 if (prop.property_type.is_real_non_null_struct_type ()) {
6102 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6104 ccall.add_argument (cexpr);
6106 ccode.add_expression (ccall);
6107 } else if (prop.base_interface_property != null) {
6108 var base_iface = (Interface) prop.base_interface_property.parent_symbol;
6109 string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface));
6111 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "set_%s".printf (prop.name)));
6112 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
6113 var cexpr = get_cvalue_ (value);
6114 if (prop.property_type.is_real_non_null_struct_type ()) {
6115 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6117 ccall.add_argument (cexpr);
6119 ccode.add_expression (ccall);
6121 return;
6124 var set_func = "g_object_set";
6126 var base_property = prop;
6127 if (!get_ccode_no_accessor_method (prop)) {
6128 if (prop.base_property != null) {
6129 base_property = prop.base_property;
6130 } else if (prop.base_interface_property != null) {
6131 base_property = prop.base_interface_property;
6134 if (prop is DynamicProperty) {
6135 set_func = get_dynamic_property_setter_cname ((DynamicProperty) prop);
6136 } else {
6137 generate_property_accessor_declaration (base_property.set_accessor, cfile);
6138 set_func = get_ccode_name (base_property.set_accessor);
6140 if (!prop.external && prop.external_package) {
6141 // internal VAPI properties
6142 // only add them once per source file
6143 if (add_generated_external_symbol (prop)) {
6144 visit_property (prop);
6150 var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
6152 if (prop.binding == MemberBinding.INSTANCE) {
6153 /* target instance is first argument */
6154 var cinstance = (CCodeExpression) get_ccodenode (instance);
6156 if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
6157 // we need to pass struct instance by reference if it isn't a simple-type
6158 var instance_value = instance.target_value;
6159 if (!get_lvalue (instance_value)) {
6160 instance_value = store_temp_value (instance_value, instance);
6162 cinstance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
6165 ccall.add_argument (cinstance);
6168 if (get_ccode_no_accessor_method (prop)) {
6169 /* property name is second argument of g_object_set */
6170 ccall.add_argument (get_property_canonical_cconstant (prop));
6173 var cexpr = get_cvalue_ (value);
6175 if (prop.property_type.is_real_non_null_struct_type ()) {
6176 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6179 var array_type = prop.property_type as ArrayType;
6181 ccall.add_argument (cexpr);
6183 if (array_type != null && get_ccode_array_length (prop)) {
6184 for (int dim = 1; dim <= array_type.rank; dim++) {
6185 ccall.add_argument (get_array_length_cvalue (value, dim));
6187 } else if (prop.property_type is DelegateType) {
6188 var delegate_type = (DelegateType) prop.property_type;
6189 if (delegate_type.delegate_symbol.has_target) {
6190 ccall.add_argument (get_delegate_target_cvalue (value));
6191 if (base_property.set_accessor.value_type.value_owned) {
6192 ccall.add_argument (get_delegate_target_destroy_notify_cvalue (value));
6197 if (get_ccode_no_accessor_method (prop)) {
6198 ccall.add_argument (new CCodeConstant ("NULL"));
6201 ccode.add_expression (ccall);
6204 public bool add_wrapper (string wrapper_name) {
6205 return wrappers.add (wrapper_name);
6208 public bool add_generated_external_symbol (Symbol external_symbol) {
6209 return generated_external_symbols.add (external_symbol);
6212 public static DataType get_data_type_for_symbol (TypeSymbol sym) {
6213 DataType type = null;
6215 if (sym is Class) {
6216 type = new ObjectType ((Class) sym);
6217 } else if (sym is Interface) {
6218 type = new ObjectType ((Interface) sym);
6219 } else if (sym is Struct) {
6220 var st = (Struct) sym;
6221 if (st.is_boolean_type ()) {
6222 type = new BooleanType (st);
6223 } else if (st.is_integer_type ()) {
6224 type = new IntegerType (st);
6225 } else if (st.is_floating_type ()) {
6226 type = new FloatingType (st);
6227 } else {
6228 type = new StructValueType (st);
6230 } else if (sym is Enum) {
6231 type = new EnumValueType ((Enum) sym);
6232 } else if (sym is ErrorDomain) {
6233 type = new ErrorType ((ErrorDomain) sym, null);
6234 } else if (sym is ErrorCode) {
6235 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
6236 } else {
6237 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
6238 return new InvalidType ();
6241 return type;
6244 public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression, bool on_error = false) {
6245 var st = type.data_type as Struct;
6246 var array_type = type as ArrayType;
6247 if (type.data_type != null && !type.nullable
6248 && (on_error ? get_ccode_default_value_on_error (type.data_type) : get_ccode_default_value (type.data_type)) != "") {
6249 return new CCodeConstant (on_error ? get_ccode_default_value_on_error (type.data_type) : get_ccode_default_value (type.data_type));
6250 } else if (initializer_expression && !type.nullable &&
6251 (st != null || (array_type != null && array_type.fixed_length))) {
6252 // 0-initialize struct with struct initializer { 0 }
6253 // only allowed as initializer expression in C
6254 var clist = new CCodeInitializerList ();
6255 clist.append (new CCodeConstant ("0"));
6256 return clist;
6257 } else if ((type.data_type != null && type.data_type.is_reference_type ())
6258 || type.nullable
6259 || type is PointerType || type is DelegateType
6260 || (array_type != null && !array_type.fixed_length)) {
6261 return new CCodeConstant ("NULL");
6262 } else if (type is GenericType) {
6263 return new CCodeConstant ("NULL");
6264 } else if (type is ErrorType) {
6265 return new CCodeConstant ("NULL");
6267 return null;
6270 private void create_property_type_check_statement (Property prop, bool check_return_type, TypeSymbol t, bool non_null, string var_name) {
6271 if (check_return_type) {
6272 create_type_check_statement (prop, prop.property_type, t, non_null, var_name);
6273 } else {
6274 create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
6278 public virtual void create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
6281 public int get_param_pos (double param_pos, bool ellipsis = false) {
6282 if (!ellipsis) {
6283 if (param_pos >= 0) {
6284 return (int) (param_pos * 1000);
6285 } else {
6286 return (int) ((100 + param_pos) * 1000);
6288 } else {
6289 if (param_pos >= 0) {
6290 return (int) ((100 + param_pos) * 1000);
6291 } else {
6292 return (int) ((200 + param_pos) * 1000);
6297 public CCodeExpression? get_ccodenode (Expression node) {
6298 if (get_cvalue (node) == null) {
6299 node.emit (this);
6301 return get_cvalue (node);
6304 public bool is_lvalue_access_allowed (DataType type) {
6305 var array_type = type as ArrayType;
6306 if (array_type != null && array_type.inline_allocated) {
6307 return false;
6309 if (type.data_type != null) {
6310 return type.data_type.get_attribute_bool ("CCode", "lvalue_access", true);
6312 return true;
6315 public CCodeDeclaratorSuffix? get_ccode_declarator_suffix (DataType type) {
6316 var array_type = type as ArrayType;
6317 if (array_type != null) {
6318 if (array_type.fixed_length) {
6319 return new CCodeDeclaratorSuffix.with_array (get_ccodenode (array_type.length));
6320 } else if (array_type.inline_allocated) {
6321 return new CCodeDeclaratorSuffix.with_array ();
6324 return null;
6327 public CCodeConstant get_signal_canonical_constant (Signal sig, string? detail = null) {
6328 return new CCodeConstant ("\"%s%s\"".printf (get_ccode_name (sig), (detail != null ? "::%s".printf (detail) : "")));
6331 public bool get_signal_has_emitter (Signal sig) {
6332 return sig.get_attribute ("HasEmitter") != null;
6335 public CCodeConstant get_property_canonical_cconstant (Property prop) {
6336 return new CCodeConstant ("\"%s\"".printf (prop.name.replace ("_", "-")));
6339 public override void visit_class (Class cl) {
6342 public void create_postcondition_statement (Expression postcondition) {
6343 var cassert = new CCodeFunctionCall (new CCodeIdentifier ("_vala_warn_if_fail"));
6345 postcondition.emit (this);
6347 string message = ((string) postcondition.source_reference.begin.pos).substring (0, (int) (postcondition.source_reference.end.pos - postcondition.source_reference.begin.pos));
6348 cassert.add_argument (get_cvalue (postcondition));
6349 cassert.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
6350 requires_assert = true;
6352 ccode.add_expression (cassert);
6355 public virtual bool is_gobject_property (Property prop) {
6356 return false;
6359 public DataType? get_this_type () {
6360 if (current_method != null && current_method.binding == MemberBinding.INSTANCE) {
6361 return current_method.this_parameter.variable_type;
6362 } else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) {
6363 return current_property_accessor.prop.this_parameter.variable_type;
6364 } else if (current_constructor != null && current_constructor.binding == MemberBinding.INSTANCE) {
6365 return current_constructor.this_parameter.variable_type;
6366 } else if (current_destructor != null && current_destructor.binding == MemberBinding.INSTANCE) {
6367 return current_destructor.this_parameter.variable_type;
6369 return null;
6372 public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
6373 var result = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_CAST"));
6374 result.add_argument (expr);
6375 result.add_argument (new CCodeIdentifier (get_ccode_type_id (type)));
6376 result.add_argument (new CCodeIdentifier (get_ccode_name (type)));
6377 return result;
6380 void generate_struct_destroy_function (Struct st) {
6381 if (cfile.add_declaration (get_ccode_destroy_function (st))) {
6382 // only generate function once per source file
6383 return;
6386 var function = new CCodeFunction (get_ccode_destroy_function (st), "void");
6387 function.modifiers = CCodeModifiers.STATIC;
6388 function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (st))));
6390 push_context (new EmitContext ());
6391 push_function (function);
6393 var this_value = load_this_parameter (st);
6394 foreach (Field f in st.get_fields ()) {
6395 if (f.binding == MemberBinding.INSTANCE) {
6396 if (get_ccode_delegate_target (f) && requires_destroy (f.variable_type)) {
6397 ccode.add_expression (destroy_field (f, this_value));
6402 pop_function ();
6403 pop_context ();
6405 cfile.add_function_declaration (function);
6406 cfile.add_function (function);
6409 void generate_struct_copy_function (Struct st) {
6410 if (cfile.add_declaration (get_ccode_copy_function (st))) {
6411 // only generate function once per source file
6412 return;
6415 var function = new CCodeFunction (get_ccode_copy_function (st), "void");
6416 function.modifiers = CCodeModifiers.STATIC;
6417 function.add_parameter (new CCodeParameter ("self", "const %s *".printf (get_ccode_name (st))));
6418 function.add_parameter (new CCodeParameter ("dest", "%s *".printf (get_ccode_name (st))));
6420 push_context (new EmitContext ());
6421 push_function (function);
6423 var dest_struct = new GLibValue (get_data_type_for_symbol (st), new CCodeIdentifier ("(*dest)"), true);
6424 foreach (Field f in st.get_fields ()) {
6425 if (f.binding == MemberBinding.INSTANCE) {
6426 var value = load_field (f, load_this_parameter ((TypeSymbol) st));
6427 if (get_ccode_delegate_target (f) && requires_copy (f.variable_type)) {
6428 value = copy_value (value, f);
6429 if (value == null) {
6430 // error case, continue to avoid critical
6431 continue;
6434 store_field (f, dest_struct, value);
6438 pop_function ();
6439 pop_context ();
6441 cfile.add_function_declaration (function);
6442 cfile.add_function (function);
6445 public void return_default_value (DataType return_type, bool on_error = false) {
6446 var st = return_type.data_type as Struct;
6447 if (st != null && st.is_simple_type () && !return_type.nullable) {
6448 // 0-initialize struct with struct initializer { 0 }
6449 // only allowed as initializer expression in C
6450 var ret_temp_var = get_temp_variable (return_type, true, null, true);
6451 emit_temp_var (ret_temp_var, on_error);
6452 ccode.add_return (new CCodeIdentifier (ret_temp_var.name));
6453 } else {
6454 ccode.add_return (default_value_for_type (return_type, false, on_error));
6458 public virtual void generate_dynamic_method_wrapper (DynamicMethod method) {
6461 public virtual bool method_has_wrapper (Method method) {
6462 return false;
6465 public virtual CCodeExpression get_param_spec_cexpression (Property prop) {
6466 return new CCodeFunctionCall (new CCodeIdentifier (""));
6469 public virtual CCodeExpression get_param_spec (Property prop) {
6470 return new CCodeFunctionCall (new CCodeIdentifier (""));
6473 public virtual CCodeExpression get_signal_creation (Signal sig, TypeSymbol type) {
6474 return new CCodeFunctionCall (new CCodeIdentifier (""));
6477 public virtual void register_dbus_info (CCodeBlock block, ObjectTypeSymbol bindable) {
6480 public virtual string get_dynamic_property_getter_cname (DynamicProperty node) {
6481 Report.error (node.source_reference, "dynamic properties are not supported for %s".printf (node.dynamic_type.to_string ()));
6482 return "";
6485 public virtual string get_dynamic_property_setter_cname (DynamicProperty node) {
6486 Report.error (node.source_reference, "dynamic properties are not supported for %s".printf (node.dynamic_type.to_string ()));
6487 return "";
6490 public virtual string get_dynamic_signal_cname (DynamicSignal node) {
6491 return "";
6494 public virtual string get_dynamic_signal_connect_wrapper_name (DynamicSignal node) {
6495 return "";
6498 public virtual string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal node) {
6499 return "";
6502 public virtual string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node) {
6503 return "";
6506 public virtual string get_array_length_cname (string array_cname, int dim) {
6507 return "";
6510 public virtual string get_parameter_array_length_cname (Parameter param, int dim) {
6511 return "";
6514 public virtual CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
6515 return new CCodeConstant ("");
6518 public virtual CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
6519 return new CCodeInvalidExpression ();
6522 public virtual string get_array_size_cname (string array_cname) {
6523 return "";
6526 public virtual void add_simple_check (CodeNode node, bool always_fails = false) {
6529 public virtual string generate_ready_function (Method m) {
6530 return "";
6533 public CCodeExpression? get_cvalue (Expression expr) {
6534 if (expr.target_value == null) {
6535 return null;
6537 var glib_value = (GLibValue) expr.target_value;
6538 return glib_value.cvalue;
6541 public CCodeExpression? get_cvalue_ (TargetValue value) {
6542 var glib_value = (GLibValue) value;
6543 return glib_value.cvalue;
6546 public void set_cvalue (Expression expr, CCodeExpression? cvalue) {
6547 var glib_value = (GLibValue) expr.target_value;
6548 if (glib_value == null) {
6549 glib_value = new GLibValue (expr.value_type);
6550 expr.target_value = glib_value;
6552 glib_value.cvalue = cvalue;
6555 public CCodeExpression? get_array_size_cvalue (TargetValue value) {
6556 var glib_value = (GLibValue) value;
6557 return glib_value.array_size_cvalue;
6560 public void set_array_size_cvalue (TargetValue value, CCodeExpression? cvalue) {
6561 var glib_value = (GLibValue) value;
6562 glib_value.array_size_cvalue = cvalue;
6565 public CCodeExpression? get_delegate_target (Expression expr) {
6566 if (expr.target_value == null) {
6567 return null;
6569 var glib_value = (GLibValue) expr.target_value;
6570 return glib_value.delegate_target_cvalue;
6573 public void set_delegate_target (Expression expr, CCodeExpression? delegate_target) {
6574 var glib_value = (GLibValue) expr.target_value;
6575 if (glib_value == null) {
6576 glib_value = new GLibValue (expr.value_type);
6577 expr.target_value = glib_value;
6579 glib_value.delegate_target_cvalue = delegate_target;
6582 public CCodeExpression? get_delegate_target_destroy_notify (Expression expr) {
6583 if (expr.target_value == null) {
6584 return null;
6586 var glib_value = (GLibValue) expr.target_value;
6587 return glib_value.delegate_target_destroy_notify_cvalue;
6590 public void set_delegate_target_destroy_notify (Expression expr, CCodeExpression? destroy_notify) {
6591 var glib_value = (GLibValue) expr.target_value;
6592 if (glib_value == null) {
6593 glib_value = new GLibValue (expr.value_type);
6594 expr.target_value = glib_value;
6596 glib_value.delegate_target_destroy_notify_cvalue = destroy_notify;
6599 public void append_array_length (Expression expr, CCodeExpression size) {
6600 var glib_value = (GLibValue) expr.target_value;
6601 if (glib_value == null) {
6602 glib_value = new GLibValue (expr.value_type);
6603 expr.target_value = glib_value;
6605 glib_value.append_array_length_cvalue (size);
6608 public List<CCodeExpression>? get_array_lengths (Expression expr) {
6609 var glib_value = (GLibValue) expr.target_value;
6610 if (glib_value == null) {
6611 glib_value = new GLibValue (expr.value_type);
6612 expr.target_value = glib_value;
6614 return glib_value.array_length_cvalues;
6617 public bool get_lvalue (TargetValue value) {
6618 var glib_value = (GLibValue) value;
6619 return glib_value.lvalue;
6622 public bool get_non_null (TargetValue value) {
6623 var glib_value = (GLibValue) value;
6624 return glib_value.non_null;
6627 public string? get_ctype (TargetValue value) {
6628 var glib_value = (GLibValue) value;
6629 return glib_value.ctype;
6632 public bool get_array_null_terminated (TargetValue value) {
6633 var glib_value = (GLibValue) value;
6634 return glib_value.array_null_terminated;
6637 public CCodeExpression get_array_length_cexpr (TargetValue value) {
6638 var glib_value = (GLibValue) value;
6639 return glib_value.array_length_cexpr;
6643 internal class Vala.GLibValue : TargetValue {
6644 public CCodeExpression cvalue;
6645 public bool lvalue;
6646 public bool non_null;
6647 public string? ctype;
6649 public List<CCodeExpression> array_length_cvalues;
6650 public CCodeExpression? array_size_cvalue;
6651 public bool array_null_terminated;
6652 public CCodeExpression? array_length_cexpr;
6654 public CCodeExpression? delegate_target_cvalue;
6655 public CCodeExpression? delegate_target_destroy_notify_cvalue;
6657 public GLibValue (DataType? value_type = null, CCodeExpression? cvalue = null, bool lvalue = false) {
6658 base (value_type);
6659 this.cvalue = cvalue;
6660 this.lvalue = lvalue;
6663 public void append_array_length_cvalue (CCodeExpression length_cvalue) {
6664 if (array_length_cvalues == null) {
6665 array_length_cvalues = new ArrayList<CCodeExpression> ();
6667 array_length_cvalues.add (length_cvalue);
6670 public GLibValue copy () {
6671 var result = new GLibValue (value_type.copy (), cvalue, lvalue);
6672 result.actual_value_type = actual_value_type;
6673 result.non_null = non_null;
6674 result.ctype = ctype;
6676 if (array_length_cvalues != null) {
6677 foreach (var cexpr in array_length_cvalues) {
6678 result.append_array_length_cvalue (cexpr);
6681 result.array_size_cvalue = array_size_cvalue;
6682 result.array_null_terminated = array_null_terminated;
6683 result.array_length_cexpr = array_length_cexpr;
6685 result.delegate_target_cvalue = delegate_target_cvalue;
6686 result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify_cvalue;
6688 return result;