vala: Allow read-only properties
[vala-gnome.git] / codegen / valaccodebasemodule.vala
blob71d5d5ae67b6779971fe3bae17a67af1c42af72b
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 == 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 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), get_result_cexpression ("self"));
2045 if (current_method != null) {
2046 // allow capturing generic type parameters
2047 var suffices = new string[] {"type", "dup_func", "destroy_func"};
2048 foreach (var type_param in current_method.get_type_parameters ()) {
2049 foreach (string suffix in suffices) {
2050 string func_name = "%s_%s".printf (type_param.name.down (), suffix);
2051 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name), get_variable_cexpression (func_name));
2057 if (b.parent_symbol is Method) {
2058 var m = (Method) b.parent_symbol;
2060 // parameters are captured with the top-level block of the method
2061 foreach (var param in m.get_parameters ()) {
2062 if (param.captured) {
2063 capture_parameter (param, data, block_id);
2067 if (m.coroutine) {
2068 // capture async data to allow invoking callback from inside closure
2069 data.add_field ("gpointer", "_async_data_");
2071 // async method is suspended while waiting for callback,
2072 // so we never need to care about memory management of async data
2073 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_async_data_"), new CCodeIdentifier ("_data_"));
2075 } else if (b.parent_symbol is PropertyAccessor) {
2076 var acc = (PropertyAccessor) b.parent_symbol;
2078 if (!acc.readable && acc.value_parameter.captured) {
2079 capture_parameter (acc.value_parameter, data, block_id);
2081 } else if (b.parent_symbol is ForeachStatement) {
2082 var stmt = (ForeachStatement) b.parent_symbol;
2083 if (!stmt.use_iterator && stmt.element_variable.captured) {
2084 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)));
2088 var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name));
2089 cfile.add_type_declaration (typedef);
2090 cfile.add_type_definition (data);
2092 // create ref/unref functions
2093 var ref_fun = new CCodeFunction ("block%d_data_ref".printf (block_id), struct_name + "*");
2094 ref_fun.add_parameter (new CCodeParameter ("_data%d_".printf (block_id), struct_name + "*"));
2095 ref_fun.modifiers = CCodeModifiers.STATIC;
2097 push_function (ref_fun);
2099 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_inc"));
2100 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2101 ccode.add_expression (ccall);
2102 ccode.add_return (new CCodeIdentifier ("_data%d_".printf (block_id)));
2104 pop_function ();
2106 cfile.add_function_declaration (ref_fun);
2107 cfile.add_function (ref_fun);
2109 var unref_fun = new CCodeFunction ("block%d_data_unref".printf (block_id), "void");
2110 unref_fun.add_parameter (new CCodeParameter ("_userdata_", "void *"));
2111 unref_fun.modifiers = CCodeModifiers.STATIC;
2113 push_function (unref_fun);
2115 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id), new CCodeCastExpression (new CCodeIdentifier ("_userdata_"), struct_name + "*")));
2116 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_dec_and_test"));
2117 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2118 ccode.open_if (ccall);
2120 CCodeExpression outer_block = new CCodeIdentifier ("_data%d_".printf (block_id));
2121 unowned Block parent_closure_block = b;
2122 while (true) {
2123 parent_closure_block = next_closure_block (parent_closure_block.parent_symbol);
2124 if (parent_closure_block == null) {
2125 break;
2127 int parent_block_id = get_block_id (parent_closure_block);
2128 outer_block = new CCodeMemberAccess.pointer (outer_block, "_data%d_".printf (parent_block_id));
2131 if (get_this_type () != null) {
2132 // assign "self" for type parameters
2133 ccode.add_declaration(get_ccode_name (get_data_type_for_symbol (current_type_symbol)), new CCodeVariableDeclarator ("self"));
2134 ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeMemberAccess.pointer (outer_block, "self"));
2137 if (current_method != null) {
2138 // assign captured generic type parameters
2139 foreach (var type_param in current_method.get_type_parameters ()) {
2140 string func_name;
2142 func_name = "%s_type".printf (type_param.name.down ());
2143 ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name));
2144 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2146 func_name = "%s_dup_func".printf (type_param.name.down ());
2147 ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name));
2148 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2150 func_name = "%s_destroy_func".printf (type_param.name.down ());
2151 ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name));
2152 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2156 // free in reverse order
2157 for (int i = local_vars.size - 1; i >= 0; i--) {
2158 var local = local_vars[i];
2159 if (local.captured) {
2160 if (requires_destroy (local.variable_type)) {
2161 bool old_coroutine = false;
2162 if (current_method != null) {
2163 old_coroutine = current_method.coroutine;
2164 current_method.coroutine = false;
2167 ccode.add_expression (destroy_local (local));
2169 if (old_coroutine) {
2170 current_method.coroutine = true;
2176 if (b.parent_symbol is Method) {
2177 var m = (Method) b.parent_symbol;
2179 // parameters are captured with the top-level block of the method
2180 foreach (var param in m.get_parameters ()) {
2181 if (param.captured) {
2182 var param_type = param.variable_type.copy ();
2183 if (!param_type.value_owned) {
2184 param_type.value_owned = !no_implicit_copy (param_type);
2187 if (requires_destroy (param_type)) {
2188 bool old_coroutine = false;
2189 if (m != null) {
2190 old_coroutine = m.coroutine;
2191 m.coroutine = false;
2194 ccode.add_expression (destroy_parameter (param));
2196 if (old_coroutine) {
2197 m.coroutine = true;
2202 } else if (b.parent_symbol is PropertyAccessor) {
2203 var acc = (PropertyAccessor) b.parent_symbol;
2205 if (!acc.readable && acc.value_parameter.captured) {
2206 var param_type = acc.value_parameter.variable_type.copy ();
2207 if (!param_type.value_owned) {
2208 param_type.value_owned = !no_implicit_copy (param_type);
2211 if (requires_destroy (param_type)) {
2212 ccode.add_expression (destroy_parameter (acc.value_parameter));
2217 // free parent block and "self" after captured variables
2218 // because they may require type parameters
2219 if (parent_block != null) {
2220 int parent_block_id = get_block_id (parent_block);
2222 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (parent_block_id)));
2223 unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
2224 ccode.add_expression (unref_call);
2225 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), new CCodeConstant ("NULL"));
2228 var data_free = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
2229 data_free.add_argument (new CCodeIdentifier (struct_name));
2230 data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id)));
2231 ccode.add_expression (data_free);
2233 ccode.close ();
2235 pop_function ();
2237 cfile.add_function_declaration (unref_fun);
2238 cfile.add_function (unref_fun);
2241 foreach (Statement stmt in b.get_statements ()) {
2242 push_line (stmt.source_reference);
2243 stmt.emit (this);
2244 pop_line ();
2247 // free in reverse order
2248 for (int i = local_vars.size - 1; i >= 0; i--) {
2249 var local = local_vars[i];
2250 local.active = false;
2251 if (!local.unreachable && !local.captured && requires_destroy (local.variable_type)) {
2252 ccode.add_expression (destroy_local (local));
2256 if (b.parent_symbol is Method) {
2257 var m = (Method) b.parent_symbol;
2258 foreach (Parameter param in m.get_parameters ()) {
2259 if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
2260 ccode.add_expression (destroy_parameter (param));
2261 } else if (param.direction == ParameterDirection.OUT && !m.coroutine) {
2262 return_out_parameter (param);
2265 // check postconditions
2266 foreach (var postcondition in m.get_postconditions ()) {
2267 create_postcondition_statement (postcondition);
2269 } else if (b.parent_symbol is PropertyAccessor) {
2270 var acc = (PropertyAccessor) b.parent_symbol;
2271 if (acc.value_parameter != null && !acc.value_parameter.captured && requires_destroy (acc.value_parameter.variable_type)) {
2272 ccode.add_expression (destroy_parameter (acc.value_parameter));
2276 if (b.captured) {
2277 int block_id = get_block_id (b);
2279 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
2280 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
2281 ccode.add_expression (data_unref);
2282 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
2285 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
2286 ccode.close ();
2289 emit_context.pop_symbol ();
2292 public override void visit_declaration_statement (DeclarationStatement stmt) {
2293 stmt.declaration.accept (this);
2296 public CCodeExpression get_local_cexpression (LocalVariable local) {
2297 if (is_in_coroutine ()) {
2298 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_local_cname (local));
2299 } else {
2300 return new CCodeIdentifier (get_local_cname (local));
2304 public CCodeExpression get_variable_cexpression (string name) {
2305 if (is_in_coroutine ()) {
2306 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_variable_cname (name));
2307 } else {
2308 return new CCodeIdentifier (get_variable_cname (name));
2312 public CCodeExpression get_this_cexpression () {
2313 if (is_in_coroutine ()) {
2314 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
2315 } else {
2316 return new CCodeIdentifier ("self");
2320 public string get_local_cname (LocalVariable local) {
2321 var cname = get_variable_cname (local.name);
2322 if (cname[0].isdigit ()) {
2323 cname = "_%s_".printf (cname);
2325 if (is_in_coroutine ()) {
2326 var clash_index = emit_context.closure_variable_clash_map.get (local);
2327 if (clash_index > 0) {
2328 cname = "_vala%d_%s".printf (clash_index, cname);
2331 return cname;
2334 public string get_variable_cname (string name) {
2335 if (name[0] == '.') {
2336 if (name == ".result") {
2337 return "result";
2339 // compiler-internal variable
2340 if (!variable_name_map.contains (name)) {
2341 variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
2342 next_temp_var_id++;
2344 return variable_name_map.get (name);
2345 } else if (reserved_identifiers.contains (name)) {
2346 return "_%s_".printf (name);
2347 } else {
2348 return name;
2352 public CCodeExpression get_result_cexpression (string cname = "result") {
2353 if (is_in_coroutine ()) {
2354 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), cname);
2355 } else {
2356 return new CCodeIdentifier (cname);
2360 public bool is_simple_struct_creation (Variable variable, Expression expr) {
2361 var st = variable.variable_type.data_type as Struct;
2362 var creation = expr as ObjectCreationExpression;
2363 if (creation != null && st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list") && !variable.variable_type.nullable &&
2364 variable.variable_type.data_type != gvalue_type && creation.get_object_initializer ().size == 0) {
2365 return true;
2366 } else {
2367 return false;
2371 bool is_foreach_element_variable (LocalVariable local) {
2372 var block = local.parent_symbol;
2373 if (block != null) {
2374 var stmt = block.parent_symbol as ForeachStatement;
2375 if (stmt != null && !stmt.use_iterator && stmt.element_variable == local) {
2376 return true;
2379 return false;
2382 public override void visit_local_variable (LocalVariable local) {
2383 check_type (local.variable_type);
2385 /* Declaration */
2387 generate_type_declaration (local.variable_type, cfile);
2389 // captured element variables of foreach statements (without iterator) require local declaration
2390 var declared = !local.captured || is_foreach_element_variable (local);
2391 if (declared) {
2392 if (is_in_coroutine ()) {
2393 var count = emit_context.closure_variable_count_map.get (local.name);
2394 if (count > 0) {
2395 emit_context.closure_variable_clash_map.set (local, count);
2397 emit_context.closure_variable_count_map.set (local.name, count + 1);
2399 closure_struct.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
2400 } else {
2401 var cvar = new CCodeVariableDeclarator (get_local_cname (local), null, get_ccode_declarator_suffix (local.variable_type));
2403 // try to initialize uninitialized variables
2404 // initialization not necessary for variables stored in closure
2405 cvar.initializer = default_value_for_type (local.variable_type, true);
2406 cvar.init0 = true;
2408 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
2412 /* Emit initializer */
2413 if (local.initializer != null) {
2414 local.initializer.emit (this);
2416 visit_end_full_expression (local.initializer);
2420 CCodeExpression rhs = null;
2421 if (local.initializer != null && get_cvalue (local.initializer) != null) {
2422 rhs = get_cvalue (local.initializer);
2425 /* Additional temp variables */
2427 if (declared) {
2428 if (local.variable_type is ArrayType) {
2429 // create variables to store array dimensions
2430 var array_type = (ArrayType) local.variable_type;
2432 if (!array_type.fixed_length) {
2433 for (int dim = 1; dim <= array_type.rank; dim++) {
2434 var len_var = new LocalVariable (int_type.copy (), get_array_length_cname (get_local_cname (local), dim));
2435 len_var.init = local.initializer == null;
2436 emit_temp_var (len_var);
2439 if (array_type.rank == 1) {
2440 var size_var = new LocalVariable (int_type.copy (), get_array_size_cname (get_local_cname (local)));
2441 size_var.init = local.initializer == null;
2442 emit_temp_var (size_var);
2445 } else if (local.variable_type is DelegateType) {
2446 var deleg_type = (DelegateType) local.variable_type;
2447 if (deleg_type.delegate_symbol.has_target) {
2448 // create variable to store delegate target
2449 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (get_local_cname (local)));
2450 target_var.init = local.initializer == null;
2451 emit_temp_var (target_var);
2452 if (deleg_type.is_disposable ()) {
2453 var target_destroy_notify_var = new LocalVariable (gdestroynotify_type, get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2454 target_destroy_notify_var.init = local.initializer == null;
2455 emit_temp_var (target_destroy_notify_var);
2461 /* Store the initializer */
2463 if (rhs != null) {
2464 if (!is_simple_struct_creation (local, local.initializer)) {
2465 store_local (local, local.initializer.target_value, true, local.source_reference);
2469 if (local.initializer != null && local.initializer.tree_can_fail) {
2470 add_simple_check (local.initializer);
2473 local.active = true;
2477 * Create a temporary variable and return lvalue access to it
2479 public TargetValue create_temp_value (DataType type, bool init, CodeNode node_reference, bool? value_owned = null) {
2480 var local = new LocalVariable (type.copy (), "_tmp%d_".printf (next_temp_var_id++), null, node_reference.source_reference);
2481 local.init = init;
2482 if (value_owned != null) {
2483 local.variable_type.value_owned = value_owned;
2486 var array_type = local.variable_type as ArrayType;
2487 var deleg_type = local.variable_type as DelegateType;
2489 emit_temp_var (local);
2490 if (array_type != null) {
2491 for (int dim = 1; dim <= array_type.rank; dim++) {
2492 var len_var = new LocalVariable (int_type.copy (), get_array_length_cname (local.name, dim), null, node_reference.source_reference);
2493 len_var.init = init;
2494 emit_temp_var (len_var);
2496 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
2497 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (local.name), null, node_reference.source_reference);
2498 target_var.init = init;
2499 emit_temp_var (target_var);
2500 if (deleg_type.is_disposable ()) {
2501 var target_destroy_notify_var = new LocalVariable (gdestroynotify_type.copy (), get_delegate_target_destroy_notify_cname (local.name), null, node_reference.source_reference);
2502 target_destroy_notify_var.init = init;
2503 emit_temp_var (target_destroy_notify_var);
2507 var value = get_local_cvalue (local);
2508 set_array_size_cvalue (value, null);
2509 return value;
2513 * Load a temporary variable returning unowned or owned rvalue access to it, depending on the ownership of the value type.
2515 public TargetValue load_temp_value (TargetValue lvalue) {
2516 var value = ((GLibValue) lvalue).copy ();
2517 var deleg_type = value.value_type as DelegateType;
2518 if (deleg_type != null) {
2519 if (!deleg_type.delegate_symbol.has_target) {
2520 value.delegate_target_cvalue = new CCodeConstant ("NULL");
2521 ((GLibValue) value).lvalue = false;
2522 } else if (!deleg_type.is_disposable ()) {
2523 value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
2524 ((GLibValue) value).lvalue = false;
2527 return value;
2531 * Store a value in a temporary variable and return unowned or owned rvalue access to it, depending on the ownership of the given type.
2533 public TargetValue store_temp_value (TargetValue initializer, CodeNode node_reference, bool? value_owned = null) {
2534 var lvalue = create_temp_value (initializer.value_type, false, node_reference, value_owned);
2535 store_value (lvalue, initializer, node_reference.source_reference);
2536 return load_temp_value (lvalue);
2539 public override void visit_initializer_list (InitializerList list) {
2540 if (list.target_type.data_type is Struct) {
2541 /* initializer is used as struct initializer */
2542 var st = (Struct) list.target_type.data_type;
2543 while (st.base_struct != null) {
2544 st = st.base_struct;
2547 if (list.parent_node is Constant || list.parent_node is Field || list.parent_node is InitializerList) {
2548 var clist = new CCodeInitializerList ();
2550 var field_it = st.get_fields ().iterator ();
2551 foreach (Expression expr in list.get_initializers ()) {
2552 Field field = null;
2553 while (field == null) {
2554 field_it.next ();
2555 field = field_it.get ();
2556 if (field.binding != MemberBinding.INSTANCE) {
2557 // we only initialize instance fields
2558 field = null;
2562 var cexpr = get_cvalue (expr);
2564 string ctype = get_ccode_type (field);
2565 if (ctype != null) {
2566 cexpr = new CCodeCastExpression (cexpr, ctype);
2569 clist.append (cexpr);
2571 var array_type = field.variable_type as ArrayType;
2572 if (array_type != null && !array_type.fixed_length && get_ccode_array_length (field) && !get_ccode_array_null_terminated (field)) {
2573 for (int dim = 1; dim <= array_type.rank; dim++) {
2574 clist.append (get_array_length_cvalue (expr.target_value, dim));
2579 set_cvalue (list, clist);
2580 } else {
2581 // used as expression
2582 var instance = create_temp_value (list.value_type, true, list);
2584 var field_it = st.get_fields ().iterator ();
2585 foreach (Expression expr in list.get_initializers ()) {
2586 Field field = null;
2587 while (field == null) {
2588 field_it.next ();
2589 field = field_it.get ();
2590 if (field.binding != MemberBinding.INSTANCE) {
2591 // we only initialize instance fields
2592 field = null;
2596 store_field (field, instance, expr.target_value, expr.source_reference);
2599 list.target_value = instance;
2601 } else {
2602 var clist = new CCodeInitializerList ();
2603 foreach (Expression expr in list.get_initializers ()) {
2604 clist.append (get_cvalue (expr));
2606 set_cvalue (list, clist);
2610 public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null, bool init = false) {
2611 var var_type = type.copy ();
2612 var_type.value_owned = value_owned;
2613 var local = new LocalVariable (var_type, "_tmp%d_".printf (next_temp_var_id));
2614 local.init = init;
2616 if (node_reference != null) {
2617 local.source_reference = node_reference.source_reference;
2620 next_temp_var_id++;
2622 return local;
2625 bool is_in_generic_type (GenericType type) {
2626 if (current_symbol != null && type.type_parameter.parent_symbol is TypeSymbol
2627 && (current_method == null || current_method.binding == MemberBinding.INSTANCE)) {
2628 return true;
2629 } else {
2630 return false;
2634 void require_generic_accessors (Interface iface) {
2635 if (iface.get_attribute ("GenericAccessors") == null) {
2636 Report.error (iface.source_reference,
2637 "missing generic type for interface `%s', add GenericAccessors attribute to interface declaration"
2638 .printf (iface.get_full_name ()));
2642 public CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
2643 if (type is GenericType) {
2644 var type_parameter = ((GenericType) type).type_parameter;
2645 string var_name = "%s_type".printf (type_parameter.name.down ());
2647 if (type_parameter.parent_symbol is Interface) {
2648 var iface = (Interface) type_parameter.parent_symbol;
2649 require_generic_accessors (iface);
2651 string method_name = "get_%s_type".printf (type_parameter.name.down ());
2652 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
2653 cast_self.add_argument (new CCodeIdentifier ("self"));
2654 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
2655 function_call.add_argument (new CCodeIdentifier ("self"));
2656 return function_call;
2659 if (is_in_generic_type ((GenericType) type) && !is_chainup && !in_creation_method) {
2660 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), var_name);
2661 } else {
2662 return get_variable_cexpression (var_name);
2664 } else {
2665 string type_id = get_ccode_type_id (type);
2666 if (type_id == "") {
2667 type_id = "G_TYPE_INVALID";
2668 } else {
2669 generate_type_declaration (type, cfile);
2671 return new CCodeIdentifier (type_id);
2675 public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup = false) {
2676 if (type is ErrorType) {
2677 return new CCodeIdentifier ("g_error_copy");
2678 } else if (type.data_type != null) {
2679 string dup_function;
2680 var cl = type.data_type as Class;
2681 if (is_reference_counting (type.data_type)) {
2682 dup_function = get_ccode_ref_function ((ObjectTypeSymbol) type.data_type);
2683 if (type.data_type is Interface && dup_function == null) {
2684 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 ()));
2685 return new CCodeInvalidExpression();
2687 } else if (cl != null && cl.is_immutable) {
2688 // allow duplicates of immutable instances as for example strings
2689 dup_function = get_ccode_dup_function (type.data_type);
2690 if (dup_function == null) {
2691 dup_function = "";
2693 } else if (cl != null && get_ccode_is_gboxed (cl)) {
2694 // allow duplicates of gboxed instances
2695 dup_function = generate_dup_func_wrapper (type);
2696 if (dup_function == null) {
2697 dup_function = "";
2699 } else if (type is ValueType) {
2700 dup_function = get_ccode_dup_function (type.data_type);
2701 if (dup_function == null && type.nullable) {
2702 dup_function = generate_struct_dup_wrapper ((ValueType) type);
2703 } else if (dup_function == null) {
2704 dup_function = "";
2706 } else {
2707 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2708 Report.error (source_reference, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type.data_type.name));
2709 return new CCodeInvalidExpression();
2712 return new CCodeIdentifier (dup_function);
2713 } else if (type is GenericType) {
2714 var type_parameter = ((GenericType) type).type_parameter;
2715 string func_name = "%s_dup_func".printf (type_parameter.name.down ());
2717 if (type_parameter.parent_symbol is Interface) {
2718 var iface = (Interface) type_parameter.parent_symbol;
2719 require_generic_accessors (iface);
2721 string method_name = "get_%s_dup_func".printf (type_parameter.name.down ());
2722 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
2723 cast_self.add_argument (new CCodeIdentifier ("self"));
2724 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
2725 function_call.add_argument (new CCodeIdentifier ("self"));
2726 return function_call;
2729 if (is_in_generic_type ((GenericType) type) && !is_chainup && !in_creation_method) {
2730 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
2731 } else {
2732 return get_variable_cexpression (func_name);
2734 } else if (type is PointerType) {
2735 var pointer_type = (PointerType) type;
2736 return get_dup_func_expression (pointer_type.base_type, source_reference);
2737 } else {
2738 return new CCodeConstant ("NULL");
2742 void make_comparable_cexpression (ref DataType left_type, ref CCodeExpression cleft, ref DataType right_type, ref CCodeExpression cright) {
2743 var left_type_as_struct = left_type.data_type as Struct;
2744 var right_type_as_struct = right_type.data_type as Struct;
2746 // GValue support
2747 var valuecast = try_cast_value_to_type (cleft, left_type, right_type);
2748 if (valuecast != null) {
2749 cleft = valuecast;
2750 left_type = right_type;
2751 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2752 return;
2755 valuecast = try_cast_value_to_type (cright, right_type, left_type);
2756 if (valuecast != null) {
2757 cright = valuecast;
2758 right_type = left_type;
2759 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2760 return;
2763 if (left_type.data_type is Class && !((Class) left_type.data_type).is_compact &&
2764 right_type.data_type is Class && !((Class) right_type.data_type).is_compact) {
2765 var left_cl = (Class) left_type.data_type;
2766 var right_cl = (Class) right_type.data_type;
2768 if (left_cl != right_cl) {
2769 if (left_cl.is_subtype_of (right_cl)) {
2770 cleft = generate_instance_cast (cleft, right_cl);
2771 } else if (right_cl.is_subtype_of (left_cl)) {
2772 cright = generate_instance_cast (cright, left_cl);
2775 } else if (left_type_as_struct != null && right_type_as_struct != null) {
2776 if (left_type is StructValueType) {
2777 // real structs (uses compare/equal function)
2778 if (!left_type.nullable) {
2779 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft);
2781 if (!right_type.nullable) {
2782 cright = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cright);
2784 } else {
2785 // integer or floating or boolean type
2786 if (left_type.nullable && right_type.nullable) {
2787 // FIXME also compare contents, not just address
2788 } else if (left_type.nullable) {
2789 // FIXME check left value is not null
2790 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
2791 } else if (right_type.nullable) {
2792 // FIXME check right value is not null
2793 cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
2799 private string generate_struct_equal_function (Struct st) {
2800 if (st.base_struct != null) {
2801 return generate_struct_equal_function (st.base_struct);
2804 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (st));
2806 if (!add_wrapper (equal_func)) {
2807 // wrapper already defined
2808 return equal_func;
2811 var function = new CCodeFunction (equal_func, "gboolean");
2812 function.modifiers = CCodeModifiers.STATIC;
2814 function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (st))));
2815 function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (st))));
2817 push_function (function);
2819 // if (s1 == s2) return TRUE;
2821 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2822 ccode.open_if (cexp);
2823 ccode.add_return (new CCodeConstant ("TRUE"));
2824 ccode.close ();
2826 // if (s1 == NULL || s2 == NULL) return FALSE;
2828 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2829 ccode.open_if (cexp);
2830 ccode.add_return (new CCodeConstant ("FALSE"));
2831 ccode.close ();
2833 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2834 ccode.open_if (cexp);
2835 ccode.add_return (new CCodeConstant ("FALSE"));
2836 ccode.close ();
2839 bool has_instance_fields = false;
2840 foreach (Field f in st.get_fields ()) {
2841 if (f.binding != MemberBinding.INSTANCE) {
2842 // we only compare instance fields
2843 continue;
2846 has_instance_fields = true;
2848 CCodeExpression cexp; // if (cexp) return FALSE;
2849 var s1 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s1"), get_ccode_name (f)); // s1->f
2850 var s2 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s2"), get_ccode_name (f)); // s2->f
2852 var variable_type = f.variable_type.copy ();
2853 make_comparable_cexpression (ref variable_type, ref s1, ref variable_type, ref s2);
2855 if (!(f.variable_type is NullType) && f.variable_type.compatible (string_type)) {
2856 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
2857 ccall.add_argument (s1);
2858 ccall.add_argument (s2);
2859 cexp = ccall;
2860 } else if (f.variable_type is StructValueType) {
2861 var equalfunc = generate_struct_equal_function (f.variable_type.data_type as Struct);
2862 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
2863 ccall.add_argument (s1);
2864 ccall.add_argument (s2);
2865 cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
2866 } else {
2867 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, s1, s2);
2870 ccode.open_if (cexp);
2871 ccode.add_return (new CCodeConstant ("FALSE"));
2872 ccode.close ();
2875 if (!has_instance_fields) {
2876 // either opaque structure or simple type
2877 if (st.is_simple_type ()) {
2878 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2879 ccode.add_return (cexp);
2880 } else {
2881 ccode.add_return (new CCodeConstant ("FALSE"));
2883 } else {
2884 ccode.add_return (new CCodeConstant ("TRUE"));
2887 pop_function ();
2889 cfile.add_function_declaration (function);
2890 cfile.add_function (function);
2892 return equal_func;
2895 private string generate_numeric_equal_function (TypeSymbol sym) {
2896 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (sym));
2898 if (!add_wrapper (equal_func)) {
2899 // wrapper already defined
2900 return equal_func;
2903 var function = new CCodeFunction (equal_func, "gboolean");
2904 function.modifiers = CCodeModifiers.STATIC;
2906 function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (sym))));
2907 function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (sym))));
2909 push_function (function);
2911 // if (s1 == s2) return TRUE;
2913 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2914 ccode.open_if (cexp);
2915 ccode.add_return (new CCodeConstant ("TRUE"));
2916 ccode.close ();
2918 // if (s1 == NULL || s2 == NULL) return FALSE;
2920 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2921 ccode.open_if (cexp);
2922 ccode.add_return (new CCodeConstant ("FALSE"));
2923 ccode.close ();
2925 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2926 ccode.open_if (cexp);
2927 ccode.add_return (new CCodeConstant ("FALSE"));
2928 ccode.close ();
2930 // return (*s1 == *s2);
2932 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2933 ccode.add_return (cexp);
2936 pop_function ();
2938 cfile.add_function_declaration (function);
2939 cfile.add_function (function);
2941 return equal_func;
2944 private string generate_struct_dup_wrapper (ValueType value_type) {
2945 string dup_func = "_%sdup".printf (get_ccode_lower_case_prefix (value_type.type_symbol));
2947 if (!add_wrapper (dup_func)) {
2948 // wrapper already defined
2949 return dup_func;
2952 var function = new CCodeFunction (dup_func, get_ccode_name (value_type));
2953 function.modifiers = CCodeModifiers.STATIC;
2955 function.add_parameter (new CCodeParameter ("self", get_ccode_name (value_type)));
2957 push_function (function);
2959 if (value_type.type_symbol == gvalue_type) {
2960 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
2961 dup_call.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
2962 dup_call.add_argument (new CCodeIdentifier ("self"));
2964 ccode.add_return (dup_call);
2965 } else {
2966 ccode.add_declaration (get_ccode_name (value_type), new CCodeVariableDeclarator ("dup"));
2968 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
2969 creation_call.add_argument (new CCodeConstant (get_ccode_name (value_type.data_type)));
2970 creation_call.add_argument (new CCodeConstant ("1"));
2971 ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
2973 var st = value_type.data_type as Struct;
2974 if (st != null && st.is_disposable ()) {
2975 if (!get_ccode_has_copy_function (st)) {
2976 generate_struct_copy_function (st);
2979 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
2980 copy_call.add_argument (new CCodeIdentifier ("self"));
2981 copy_call.add_argument (new CCodeIdentifier ("dup"));
2982 ccode.add_expression (copy_call);
2983 } else {
2984 cfile.add_include ("string.h");
2986 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
2987 sizeof_call.add_argument (new CCodeConstant (get_ccode_name (value_type.data_type)));
2989 var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
2990 copy_call.add_argument (new CCodeIdentifier ("dup"));
2991 copy_call.add_argument (new CCodeIdentifier ("self"));
2992 copy_call.add_argument (sizeof_call);
2993 ccode.add_expression (copy_call);
2996 ccode.add_return (new CCodeIdentifier ("dup"));
2999 pop_function ();
3001 cfile.add_function_declaration (function);
3002 cfile.add_function (function);
3004 return dup_func;
3007 protected string generate_dup_func_wrapper (DataType type) {
3008 string destroy_func = "_vala_%s_copy".printf (get_ccode_name (type.data_type));
3010 if (!add_wrapper (destroy_func)) {
3011 // wrapper already defined
3012 return destroy_func;
3015 var function = new CCodeFunction (destroy_func, get_ccode_name (type));
3016 function.modifiers = CCodeModifiers.STATIC;
3017 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3019 push_function (function);
3021 var cl = type.data_type as Class;
3022 assert (cl != null && get_ccode_is_gboxed (cl));
3024 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
3025 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
3026 free_call.add_argument (new CCodeIdentifier ("self"));
3028 ccode.add_return (free_call);
3030 pop_function ();
3032 cfile.add_function_declaration (function);
3033 cfile.add_function (function);
3035 return destroy_func;
3038 protected string generate_free_function_address_of_wrapper (DataType type) {
3039 string destroy_func = "_vala_%s_free_function_address_of".printf (get_ccode_name (type.data_type));
3041 if (!add_wrapper (destroy_func)) {
3042 // wrapper already defined
3043 return destroy_func;
3046 var function = new CCodeFunction (destroy_func, "void");
3047 function.modifiers = CCodeModifiers.STATIC;
3048 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3050 push_function (function);
3052 var cl = type.data_type as Class;
3053 var free_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (cl)));
3054 free_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("self")));
3056 ccode.add_expression (free_call);
3058 pop_function ();
3060 cfile.add_function_declaration (function);
3061 cfile.add_function (function);
3063 return destroy_func;
3066 protected string generate_free_func_wrapper (DataType type) {
3067 string destroy_func = "_vala_%s_free".printf (get_ccode_name (type.data_type));
3069 if (!add_wrapper (destroy_func)) {
3070 // wrapper already defined
3071 return destroy_func;
3074 var function = new CCodeFunction (destroy_func, "void");
3075 function.modifiers = CCodeModifiers.STATIC;
3076 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3078 push_function (function);
3080 var cl = type.data_type as Class;
3081 if (cl != null && get_ccode_is_gboxed (cl)) {
3082 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_free"));
3083 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
3084 free_call.add_argument (new CCodeIdentifier ("self"));
3086 ccode.add_expression (free_call);
3087 } else {
3088 var st = type.data_type as Struct;
3089 if (st != null && st.is_disposable ()) {
3090 if (!get_ccode_has_destroy_function (st)) {
3091 generate_struct_destroy_function (st);
3094 var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (st)));
3095 destroy_call.add_argument (new CCodeIdentifier ("self"));
3096 ccode.add_expression (destroy_call);
3099 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
3100 free_call.add_argument (new CCodeIdentifier ("self"));
3102 ccode.add_expression (free_call);
3105 pop_function ();
3107 cfile.add_function_declaration (function);
3108 cfile.add_function (function);
3110 return destroy_func;
3113 public CCodeExpression? get_destroy0_func_expression (DataType type, bool is_chainup = false) {
3114 var element_destroy_func_expression = get_destroy_func_expression (type, is_chainup);
3116 if (!(type is GenericType) && element_destroy_func_expression is CCodeIdentifier) {
3117 var freeid = (CCodeIdentifier) element_destroy_func_expression;
3118 string free0_func = "_%s0_".printf (freeid.name);
3120 if (add_wrapper (free0_func)) {
3121 var function = new CCodeFunction (free0_func, "void");
3122 function.modifiers = CCodeModifiers.STATIC;
3124 function.add_parameter (new CCodeParameter ("var", "gpointer"));
3126 push_function (function);
3128 ccode.add_expression (destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true));
3130 pop_function ();
3132 cfile.add_function_declaration (function);
3133 cfile.add_function (function);
3136 element_destroy_func_expression = new CCodeIdentifier (free0_func);
3139 return element_destroy_func_expression;
3142 public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
3143 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)) {
3144 // create wrapper function to free list elements if necessary
3146 bool elements_require_free = false;
3147 bool generic_elements = false;
3148 CCodeExpression element_destroy_func_expression = null;
3150 foreach (DataType type_arg in type.get_type_arguments ()) {
3151 elements_require_free = requires_destroy (type_arg);
3152 if (elements_require_free) {
3153 element_destroy_func_expression = get_destroy0_func_expression (type_arg);
3154 generic_elements = (type_arg is GenericType);
3158 if (elements_require_free) {
3159 CCodeExpression? cexpr = null;
3160 if (element_destroy_func_expression is CCodeIdentifier || element_destroy_func_expression is CCodeMemberAccess) {
3161 cexpr = new CCodeIdentifier (generate_collection_free_wrapper (type, (generic_elements ? null : element_destroy_func_expression as CCodeIdentifier)));
3162 if (generic_elements) {
3163 // adding second argument early, instance parameter will be inserted by destroy_value()
3164 cexpr = new CCodeFunctionCall (cexpr);
3165 ((CCodeFunctionCall) cexpr).add_argument (element_destroy_func_expression);
3167 } else {
3168 Report.error (null, "internal error: No useable element_destroy_function found");
3170 return cexpr;
3171 } else {
3172 return new CCodeIdentifier (get_ccode_free_function (type.data_type));
3174 } else if (type is ErrorType) {
3175 return new CCodeIdentifier ("g_error_free");
3176 } else if (type.data_type != null) {
3177 string unref_function;
3178 if (type is ReferenceType) {
3179 if (is_reference_counting (type.data_type)) {
3180 unref_function = get_ccode_unref_function ((ObjectTypeSymbol) type.data_type);
3181 if (type.data_type is Interface && unref_function == null) {
3182 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 ()));
3183 return null;
3185 } else {
3186 var cl = type.data_type as Class;
3187 if (cl != null && get_ccode_is_gboxed (cl)) {
3188 unref_function = generate_free_func_wrapper (type);
3189 } else {
3190 if (is_free_function_address_of (type)) {
3191 unref_function = generate_free_function_address_of_wrapper (type);
3192 } else {
3193 unref_function = get_ccode_free_function (type.data_type);
3197 } else {
3198 if (type.nullable) {
3199 unref_function = get_ccode_free_function (type.data_type);
3200 if (unref_function == null) {
3201 if (type.data_type is Struct && ((Struct) type.data_type).is_disposable ()) {
3202 unref_function = generate_free_func_wrapper (type);
3203 } else {
3204 unref_function = "g_free";
3207 } else if (type is EnumValueType) {
3208 unref_function = null;
3209 } else {
3210 var st = (Struct) type.data_type;
3211 if (st.is_disposable ()) {
3212 if (!get_ccode_has_destroy_function (st)) {
3213 generate_struct_destroy_function (st);
3215 unref_function = get_ccode_destroy_function (st);
3216 } else {
3217 unref_function = null;
3221 if (unref_function == null) {
3222 return new CCodeConstant ("NULL");
3224 return new CCodeIdentifier (unref_function);
3225 } else if (type is GenericType) {
3226 var type_parameter = ((GenericType) type).type_parameter;
3227 string func_name = "%s_destroy_func".printf (type_parameter.name.down ());
3229 if (type_parameter.parent_symbol is Interface) {
3230 var iface = (Interface) type_parameter.parent_symbol;
3231 require_generic_accessors (iface);
3233 string method_name = "get_%s_destroy_func".printf (type_parameter.name.down ());
3234 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
3235 cast_self.add_argument (new CCodeIdentifier ("self"));
3236 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
3237 function_call.add_argument (new CCodeIdentifier ("self"));
3238 return function_call;
3241 if (is_in_generic_type ((GenericType) type) && !is_chainup && !in_creation_method) {
3242 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
3243 } else {
3244 return get_variable_cexpression (func_name);
3246 } else if (type is ArrayType) {
3247 if (context.profile == Profile.POSIX) {
3248 return new CCodeIdentifier ("free");
3249 } else {
3250 return new CCodeIdentifier ("g_free");
3252 } else if (type is PointerType) {
3253 if (context.profile == Profile.POSIX) {
3254 return new CCodeIdentifier ("free");
3255 } else {
3256 return new CCodeIdentifier ("g_free");
3258 } else {
3259 return new CCodeConstant ("NULL");
3263 private string generate_collection_free_wrapper (DataType collection_type, CCodeIdentifier? element_destroy_func_expression) {
3264 string destroy_func;
3266 string? destroy_func_wrapper = null;
3267 if (element_destroy_func_expression != null) {
3268 destroy_func_wrapper = "_%s_%s".printf (get_ccode_free_function (collection_type.data_type), element_destroy_func_expression.name);
3269 if (!add_wrapper (destroy_func_wrapper)) {
3270 // wrapper already defined
3271 return destroy_func_wrapper;
3275 if (collection_type.data_type == gnode_type) {
3276 destroy_func = "_g_node_free_all";
3277 if (!add_wrapper (destroy_func)) {
3278 // wrapper already defined
3279 return destroy_func;
3282 var function = new CCodeFunction (destroy_func, "void");
3283 function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3284 function.add_parameter (new CCodeParameter ("free_func", "GDestroyNotify"));
3286 push_function (function);
3288 CCodeFunctionCall element_free_call;
3289 string destroy_node_func = "%s_node".printf (destroy_func);
3290 var wrapper = new CCodeFunction (destroy_node_func, "gboolean");
3291 wrapper.modifiers = CCodeModifiers.STATIC;
3292 wrapper.add_parameter (new CCodeParameter ("node", get_ccode_name (collection_type)));
3293 wrapper.add_parameter (new CCodeParameter ("free_func", "GDestroyNotify"));
3294 push_function (wrapper);
3296 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("free_func"));
3297 free_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier("node"), "data"));
3299 var data_isnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeMemberAccess.pointer (new CCodeIdentifier("node"), "data"), new CCodeConstant ("NULL"));
3300 var ccomma_data = new CCodeCommaExpression ();
3301 ccomma_data.append_expression (new CCodeConditionalExpression (data_isnull, new CCodeConstant ("NULL"), free_call));
3302 ccode.add_expression (ccomma_data);
3304 ccode.add_return (new CCodeConstant ("FALSE"));
3306 pop_function ();
3307 cfile.add_function_declaration (wrapper);
3308 cfile.add_function (wrapper);
3310 /* Now the code to call g_traverse with the above */
3311 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_node_traverse"));
3312 element_free_call.add_argument (new CCodeIdentifier("self"));
3313 element_free_call.add_argument (new CCodeConstant ("G_POST_ORDER"));
3314 element_free_call.add_argument (new CCodeConstant ("G_TRAVERSE_ALL"));
3315 element_free_call.add_argument (new CCodeConstant ("-1"));
3316 element_free_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (destroy_node_func), "GNodeTraverseFunc"));
3317 element_free_call.add_argument (new CCodeIdentifier ("free_func"));
3319 var free_func_isnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("free_func"), new CCodeConstant ("NULL"));
3320 var ccomma = new CCodeCommaExpression ();
3321 ccomma.append_expression (new CCodeConditionalExpression (free_func_isnull, new CCodeConstant ("NULL"), element_free_call));
3323 ccode.add_expression (ccomma);
3325 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (gnode_type)));
3326 cfreecall.add_argument (new CCodeIdentifier ("self"));
3327 ccode.add_expression (cfreecall);
3329 function.modifiers = CCodeModifiers.STATIC;
3330 pop_function ();
3332 cfile.add_function_declaration (function);
3333 cfile.add_function (function);
3334 } else if (collection_type.data_type == glist_type) {
3335 destroy_func = "g_list_free_full";
3336 } else if (collection_type.data_type == gslist_type) {
3337 destroy_func = "g_slist_free_full";
3338 } else if (collection_type.data_type == gqueue_type) {
3339 destroy_func = "g_queue_free_full";
3340 } else {
3341 Report.error (null, "internal error: type of collection not supported");
3342 return "";
3345 if (element_destroy_func_expression != null) {
3346 var function = new CCodeFunction (destroy_func_wrapper, "void");
3347 function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3349 push_function (function);
3351 var collection_free_call = new CCodeFunctionCall (new CCodeIdentifier (destroy_func));
3352 collection_free_call.add_argument (new CCodeIdentifier ("self"));
3353 collection_free_call.add_argument (new CCodeCastExpression (element_destroy_func_expression, "GDestroyNotify"));
3354 ccode.add_expression (collection_free_call);
3356 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
3357 pop_function ();
3359 cfile.add_function_declaration (function);
3360 cfile.add_function (function);
3362 return destroy_func_wrapper;
3365 return destroy_func;
3368 public virtual string? append_struct_array_free (Struct st) {
3369 return null;
3372 public CCodeExpression destroy_local (LocalVariable local) {
3373 return destroy_value (get_local_cvalue (local));
3376 public CCodeExpression destroy_parameter (Parameter param) {
3377 return destroy_value (get_parameter_cvalue (param));
3380 public CCodeExpression destroy_field (Field field, TargetValue? instance) {
3381 return destroy_value (get_field_cvalue (field, instance));
3384 public virtual CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
3385 var type = value.value_type;
3386 if (value.actual_value_type != null) {
3387 type = value.actual_value_type;
3389 var cvar = get_cvalue_ (value);
3391 if (type is DelegateType) {
3392 var delegate_target = get_delegate_target_cvalue (value);
3393 var delegate_target_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
3395 var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
3396 ccall.add_argument (delegate_target);
3398 var destroy_call = new CCodeCommaExpression ();
3399 destroy_call.append_expression (ccall);
3400 destroy_call.append_expression (new CCodeConstant ("NULL"));
3402 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
3404 var ccomma = new CCodeCommaExpression ();
3405 ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), destroy_call));
3406 ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
3407 ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
3408 ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
3410 return ccomma;
3413 bool is_gcollection = (type.data_type == glist_type || type.data_type == gslist_type || type.data_type == gnode_type || type.data_type == gqueue_type);
3414 CCodeFunctionCall ccall;
3415 var cexpr = get_destroy_func_expression (type);
3416 if (is_gcollection && cexpr is CCodeFunctionCall) {
3417 ccall = (CCodeFunctionCall) cexpr;
3418 } else {
3419 ccall = new CCodeFunctionCall (cexpr);
3422 if (type is ValueType && !type.nullable) {
3423 // normal value type, no null check
3424 var st = type.data_type as Struct;
3425 if (st != null && st.is_simple_type ()) {
3426 // used for va_list
3427 ccall.add_argument (cvar);
3428 } else {
3429 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3432 if (gvalue_type != null && type.data_type == gvalue_type) {
3433 // g_value_unset must not be called for already unset values
3434 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
3435 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3437 var ccomma = new CCodeCommaExpression ();
3438 ccomma.append_expression (ccall);
3439 ccomma.append_expression (new CCodeConstant ("NULL"));
3441 return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
3442 } else if ((type.data_type == gmutex_type ||
3443 type.data_type == grecmutex_type ||
3444 type.data_type == grwlock_type ||
3445 type.data_type == gcond_type)) {
3446 // g_mutex_clear must not be called for uninitialized mutex
3447 // also, g_mutex_clear does not clear the struct
3448 requires_clear_mutex = true;
3449 ccall.call = new CCodeIdentifier ("_vala_clear_" + get_ccode_name (type.data_type));
3450 return ccall;
3451 } else {
3452 return ccall;
3456 if (!is_gcollection && ccall.call is CCodeIdentifier && !(type is ArrayType) && !is_macro_definition) {
3457 // generate and use NULL-aware free macro to simplify code
3459 var freeid = (CCodeIdentifier) ccall.call;
3460 string free0_func = "_%s0".printf (freeid.name);
3462 if (add_wrapper (free0_func)) {
3463 var macro = destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true);
3464 cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("%s(var)".printf (free0_func), macro));
3467 ccall = new CCodeFunctionCall (new CCodeIdentifier (free0_func));
3468 ccall.add_argument (cvar);
3469 return ccall;
3472 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
3474 /* can be simplified to
3475 * foo = (unref (foo), NULL)
3476 * if foo is of static type non-null
3479 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
3480 if (type is GenericType) {
3481 var parent = ((GenericType) type).type_parameter.parent_symbol;
3482 var cl = parent as Class;
3483 if ((!(parent is Method) && !(parent is ObjectTypeSymbol)) || (cl != null && cl.is_compact)) {
3484 return new CCodeConstant ("NULL");
3487 // unref functions are optional for type parameters
3488 var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
3489 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
3492 // glib collections already have the free_func argument, so make sure the instance parameter gets first
3493 ccall.insert_argument (0, cvar);
3495 /* set freed references to NULL to prevent further use */
3496 var ccomma = new CCodeCommaExpression ();
3498 if (context.profile == Profile.GOBJECT) {
3499 if (type.data_type != null && !is_reference_counting (type.data_type) &&
3500 (type.data_type.is_subtype_of (gstringbuilder_type)
3501 || type.data_type.is_subtype_of (garray_type)
3502 || type.data_type.is_subtype_of (gbytearray_type)
3503 || type.data_type.is_subtype_of (gptrarray_type))) {
3504 ccall.add_argument (new CCodeConstant ("TRUE"));
3505 } else if (type.data_type == gthreadpool_type) {
3506 ccall.add_argument (new CCodeConstant ("FALSE"));
3507 ccall.add_argument (new CCodeConstant ("TRUE"));
3508 } else if (type is ArrayType) {
3509 var array_type = (ArrayType) type;
3510 if (requires_destroy (array_type.element_type)) {
3511 CCodeExpression csizeexpr = null;
3512 if (((GLibValue) value).array_length_cvalues != null) {
3513 csizeexpr = get_array_length_cvalue (value);
3514 } else if (get_array_null_terminated (value)) {
3515 requires_array_length = true;
3516 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
3517 len_call.add_argument (cvar);
3518 csizeexpr = len_call;
3519 } else {
3520 csizeexpr = get_array_length_cexpr (value);
3523 if (csizeexpr != null) {
3524 var st = array_type.element_type.data_type as Struct;
3525 if (st != null && !array_type.element_type.nullable) {
3526 ccall.call = new CCodeIdentifier (append_struct_array_free (st));
3527 ccall.add_argument (csizeexpr);
3528 } else {
3529 requires_array_free = true;
3530 ccall.call = new CCodeIdentifier ("_vala_array_free");
3531 ccall.add_argument (csizeexpr);
3532 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
3539 ccomma.append_expression (ccall);
3540 ccomma.append_expression (new CCodeConstant ("NULL"));
3542 var cassign = new CCodeAssignment (cvar, ccomma);
3544 // g_free (NULL) is allowed
3545 bool uses_gfree = (type.data_type != null && !is_reference_counting (type.data_type) && get_ccode_free_function (type.data_type) == "g_free");
3546 uses_gfree = uses_gfree || type is ArrayType;
3547 if (uses_gfree) {
3548 return cassign;
3551 return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
3554 public override void visit_end_full_expression (Expression expr) {
3555 /* expr is a full expression, i.e. an initializer, the
3556 * expression in an expression statement, the controlling
3557 * expression in if, while, for, or foreach statements
3559 * we unref temporary variables at the end of a full
3560 * expression
3562 if (temp_ref_values.size == 0) {
3563 /* nothing to do without temporary variables */
3564 return;
3567 var local_decl = expr.parent_node as LocalVariable;
3568 if (!(local_decl != null && is_simple_struct_creation (local_decl, local_decl.initializer))) {
3569 expr.target_value = store_temp_value (expr.target_value, expr);
3572 foreach (var value in temp_ref_values) {
3573 ccode.add_expression (destroy_value (value));
3576 temp_ref_values.clear ();
3579 public void emit_temp_var (LocalVariable local) {
3580 var init = (!local.name.has_prefix ("*") && local.init);
3581 if (is_in_coroutine ()) {
3582 closure_struct.add_field (get_ccode_name (local.variable_type), local.name);
3584 // even though closure struct is zerod, we need to initialize temporary variables
3585 // as they might be used multiple times when declared in a loop
3587 if (init) {
3588 var initializer = default_value_for_type (local.variable_type, false);
3589 if (initializer == null) {
3590 cfile.add_include ("string.h");
3591 var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
3592 memset_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (local.name)));
3593 memset_call.add_argument (new CCodeConstant ("0"));
3594 memset_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (local.variable_type))));
3595 ccode.add_expression (memset_call);
3596 } else {
3597 ccode.add_assignment (get_variable_cexpression (local.name), initializer);
3600 } else {
3601 var cvar = new CCodeVariableDeclarator (local.name, null, get_ccode_declarator_suffix (local.variable_type));
3602 if (init) {
3603 cvar.initializer = default_value_for_type (local.variable_type, true);
3604 cvar.init0 = true;
3606 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
3610 public override void visit_expression_statement (ExpressionStatement stmt) {
3611 if (stmt.expression.error) {
3612 stmt.error = true;
3613 return;
3616 /* free temporary objects and handle errors */
3618 foreach (var value in temp_ref_values) {
3619 ccode.add_expression (destroy_value (value));
3622 if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
3623 // simple case, no node breakdown necessary
3624 add_simple_check (stmt.expression);
3627 temp_ref_values.clear ();
3630 protected virtual void append_scope_free (Symbol sym, CodeNode? stop_at = null) {
3631 var b = (Block) sym;
3633 var local_vars = b.get_local_variables ();
3634 // free in reverse order
3635 for (int i = local_vars.size - 1; i >= 0; i--) {
3636 var local = local_vars[i];
3637 if (!local.unreachable && local.active && !local.captured && requires_destroy (local.variable_type)) {
3638 ccode.add_expression (destroy_local (local));
3642 if (b.captured) {
3643 int block_id = get_block_id (b);
3645 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
3646 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
3647 ccode.add_expression (data_unref);
3648 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
3652 public void append_local_free (Symbol sym, bool stop_at_loop = false, CodeNode? stop_at = null) {
3653 var b = (Block) sym;
3655 append_scope_free (sym, stop_at);
3657 if (stop_at_loop) {
3658 if (b.parent_node is Loop ||
3659 b.parent_node is ForeachStatement ||
3660 b.parent_node is SwitchStatement) {
3661 return;
3665 if (stop_at != null && b.parent_node == stop_at) {
3666 return;
3669 if (sym.parent_symbol is Block) {
3670 append_local_free (sym.parent_symbol, stop_at_loop, stop_at);
3671 } else if (sym.parent_symbol is Method) {
3672 append_param_free ((Method) sym.parent_symbol);
3673 } else if (sym.parent_symbol is PropertyAccessor) {
3674 var acc = (PropertyAccessor) sym.parent_symbol;
3675 if (acc.value_parameter != null && requires_destroy (acc.value_parameter.variable_type)) {
3676 ccode.add_expression (destroy_parameter (acc.value_parameter));
3681 private void append_param_free (Method m) {
3682 foreach (Parameter param in m.get_parameters ()) {
3683 if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
3684 ccode.add_expression (destroy_parameter (param));
3689 public bool variable_accessible_in_finally (LocalVariable local) {
3690 if (current_try == null) {
3691 return false;
3694 var sym = current_symbol;
3696 while (!(sym is Method || sym is PropertyAccessor) && sym.scope.lookup (local.name) == null) {
3697 if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) ||
3698 (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) {
3700 return true;
3703 sym = sym.parent_symbol;
3706 return false;
3709 public void return_out_parameter (Parameter param) {
3710 var delegate_type = param.variable_type as DelegateType;
3712 var value = get_parameter_cvalue (param);
3714 var old_coroutine = is_in_coroutine ();
3715 current_method.coroutine = false;
3717 ccode.open_if (get_variable_cexpression (param.name));
3718 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (param.name)), get_cvalue_ (value));
3720 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
3721 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_ccode_delegate_target_name (param))), get_delegate_target_cvalue (value));
3722 if (delegate_type.is_disposable ()) {
3723 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)));
3727 if (param.variable_type.is_disposable ()){
3728 ccode.add_else ();
3729 current_method.coroutine = old_coroutine;
3730 ccode.add_expression (destroy_parameter (param));
3731 current_method.coroutine = false;
3733 ccode.close ();
3735 var array_type = param.variable_type as ArrayType;
3736 if (array_type != null && !array_type.fixed_length && get_ccode_array_length (param)) {
3737 for (int dim = 1; dim <= array_type.rank; dim++) {
3738 ccode.open_if (get_variable_cexpression (get_parameter_array_length_cname (param, dim)));
3739 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_parameter_array_length_cname (param, dim))), get_array_length_cvalue (value, dim));
3740 ccode.close ();
3744 current_method.coroutine = old_coroutine;
3747 public override void visit_return_statement (ReturnStatement stmt) {
3748 Symbol return_expression_symbol = null;
3750 if (stmt.return_expression != null) {
3751 // avoid unnecessary ref/unref pair
3752 var local = stmt.return_expression.symbol_reference as LocalVariable;
3753 if (local != null && !local.active) {
3754 /* return expression is local variable taking ownership and
3755 * current method is transferring ownership */
3757 return_expression_symbol = local;
3761 // return array length if appropriate
3762 if (((current_method != null && get_ccode_array_length (current_method)) || current_property_accessor != null) && current_return_type is ArrayType) {
3763 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
3765 var array_type = (ArrayType) current_return_type;
3766 for (int dim = 1; dim <= array_type.rank; dim++) {
3767 var len_l = get_result_cexpression (get_array_length_cname ("result", dim));
3768 var len_r = get_array_length_cvalue (temp_value, dim);
3769 if (!is_in_coroutine ()) {
3770 ccode.open_if (len_l);
3771 len_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, len_l);
3772 ccode.add_assignment (len_l, len_r);
3773 ccode.close ();
3774 } else {
3775 ccode.add_assignment (len_l, len_r);
3779 stmt.return_expression.target_value = temp_value;
3780 } else if ((current_method != null || current_property_accessor != null) && current_return_type is DelegateType) {
3781 var delegate_type = (DelegateType) current_return_type;
3782 if (delegate_type.delegate_symbol.has_target) {
3783 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
3785 var target_l = get_result_cexpression (get_delegate_target_cname ("result"));
3786 if (!is_in_coroutine ()) {
3787 target_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l);
3789 var target_r = get_delegate_target_cvalue (temp_value);
3790 ccode.add_assignment (target_l, target_r);
3791 if (delegate_type.is_disposable ()) {
3792 var target_l_destroy_notify = get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3793 if (!is_in_coroutine ()) {
3794 target_l_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l_destroy_notify);
3796 var target_r_destroy_notify = get_delegate_target_destroy_notify_cvalue (temp_value);
3797 ccode.add_assignment (target_l_destroy_notify, target_r_destroy_notify);
3800 stmt.return_expression.target_value = temp_value;
3804 if (stmt.return_expression != null) {
3805 // assign method result to `result'
3806 CCodeExpression result_lhs = get_result_cexpression ();
3807 if (current_return_type.is_real_non_null_struct_type () && !is_in_coroutine ()) {
3808 result_lhs = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result_lhs);
3810 ccode.add_assignment (result_lhs, get_cvalue (stmt.return_expression));
3813 // free local variables
3814 append_local_free (current_symbol);
3816 if (current_method != null) {
3817 // check postconditions
3818 foreach (Expression postcondition in current_method.get_postconditions ()) {
3819 create_postcondition_statement (postcondition);
3823 if (current_method != null && !current_method.coroutine) {
3824 // assign values to output parameters if they are not NULL
3825 // otherwise, free the value if necessary
3826 foreach (var param in current_method.get_parameters ()) {
3827 if (param.direction != ParameterDirection.OUT) {
3828 continue;
3831 return_out_parameter (param);
3835 // TODO: don't duplicate the code in CCodeMethodModule, we do this right now because it needs to be before return
3836 if (current_method != null && current_method.get_attribute ("Profile") != null) {
3837 string prefix = "_vala_prof_%s".printf (get_ccode_real_name (current_method));
3839 var level = new CCodeIdentifier (prefix + "_level");
3840 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
3842 var timer = new CCodeIdentifier (prefix + "_timer");
3844 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
3845 stop_call.add_argument (timer);
3846 ccode.add_expression (stop_call);
3848 ccode.close ();
3851 if (is_in_constructor ()) {
3852 ccode.add_return (new CCodeIdentifier ("obj"));
3853 } else if (is_in_destructor ()) {
3854 // do not call return as member cleanup and chain up to base finalizer
3855 // stil need to be executed
3856 ccode.add_goto ("_return");
3857 } else if (is_in_coroutine ()) {
3858 } else if (current_method is CreationMethod) {
3859 ccode.add_return (new CCodeIdentifier ("self"));
3860 } else if (current_return_type is VoidType || current_return_type.is_real_non_null_struct_type ()) {
3861 // structs are returned via out parameter
3862 ccode.add_return ();
3863 } else {
3864 ccode.add_return (new CCodeIdentifier ("result"));
3867 if (return_expression_symbol != null) {
3868 return_expression_symbol.active = true;
3871 // required for destructors
3872 current_method_return = true;
3875 public string get_symbol_lock_name (string symname) {
3876 return "__lock_%s".printf (symname);
3879 private CCodeExpression get_lock_expression (Statement stmt, Expression resource) {
3880 CCodeExpression l = null;
3881 var inner_node = ((MemberAccess)resource).inner;
3882 var member = resource.symbol_reference;
3883 var parent = (TypeSymbol)resource.symbol_reference.parent_symbol;
3885 if (member.is_instance_member ()) {
3886 if (inner_node == null) {
3887 l = new CCodeIdentifier ("self");
3888 } else if (parent != current_type_symbol) {
3889 l = generate_instance_cast (get_cvalue (inner_node), parent);
3890 } else {
3891 l = get_cvalue (inner_node);
3894 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (get_ccode_name (member)));
3895 } else if (member.is_class_member ()) {
3896 CCodeExpression klass;
3898 if (get_this_type () != null) {
3899 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3900 k.add_argument (new CCodeIdentifier ("self"));
3901 klass = k;
3902 } else {
3903 klass = new CCodeIdentifier ("klass");
3906 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(get_ccode_upper_case_name (parent))));
3907 get_class_private_call.add_argument (klass);
3908 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (get_ccode_name (member)));
3909 } else {
3910 string lock_name = "%s_%s".printf (get_ccode_lower_case_name (parent), get_ccode_name (member));
3911 l = new CCodeIdentifier (get_symbol_lock_name (lock_name));
3913 return l;
3916 public override void visit_lock_statement (LockStatement stmt) {
3917 var l = get_lock_expression (stmt, stmt.resource);
3919 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("lock"))));
3920 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3922 ccode.add_expression (fc);
3925 public override void visit_unlock_statement (UnlockStatement stmt) {
3926 var l = get_lock_expression (stmt, stmt.resource);
3928 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("unlock"))));
3929 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3931 ccode.add_expression (fc);
3934 public override void visit_delete_statement (DeleteStatement stmt) {
3935 var pointer_type = (PointerType) stmt.expression.value_type;
3936 DataType type = pointer_type;
3937 if (pointer_type.base_type.data_type != null && pointer_type.base_type.data_type.is_reference_type ()) {
3938 type = pointer_type.base_type;
3941 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
3942 ccall.add_argument (get_cvalue (stmt.expression));
3943 ccode.add_expression (ccall);
3946 public override void visit_expression (Expression expr) {
3947 if (get_cvalue (expr) != null && !expr.lvalue) {
3948 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
3949 var type_parameter = ((GenericType) expr.formal_value_type).type_parameter;
3950 var st = type_parameter.parent_symbol.parent_symbol as Struct;
3951 if (type_parameter.parent_symbol != garray_type &&
3952 (st == null || get_ccode_name (st) != "va_list")) {
3953 // GArray and va_list don't use pointer-based generics
3954 set_cvalue (expr, convert_from_generic_pointer (get_cvalue (expr), expr.value_type));
3955 ((GLibValue) expr.target_value).lvalue = false;
3959 // memory management, implicit casts, and boxing/unboxing
3960 if (expr.value_type != null) {
3961 // FIXME: temporary workaround until the refactoring is complete, not all target_value have a value_type
3962 expr.target_value.value_type = expr.value_type;
3963 expr.target_value = transform_value (expr.target_value, expr.target_type, expr);
3966 if (expr.target_value == null) {
3967 return;
3970 if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
3971 if (((GenericType) expr.formal_target_type).type_parameter.parent_symbol != garray_type) {
3972 // GArray doesn't use pointer-based generics
3973 set_cvalue (expr, convert_to_generic_pointer (get_cvalue (expr), expr.target_type));
3974 ((GLibValue) expr.target_value).lvalue = false;
3978 if (!(expr.value_type is ValueType && !expr.value_type.nullable)) {
3979 ((GLibValue) expr.target_value).non_null = expr.is_non_null ();
3984 public override void visit_boolean_literal (BooleanLiteral expr) {
3985 if (context.profile == Profile.GOBJECT) {
3986 set_cvalue (expr, new CCodeConstant (expr.value ? "TRUE" : "FALSE"));
3987 } else {
3988 cfile.add_include ("stdbool.h");
3989 set_cvalue (expr, new CCodeConstant (expr.value ? "true" : "false"));
3993 public override void visit_character_literal (CharacterLiteral expr) {
3994 if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
3995 set_cvalue (expr, new CCodeConstant (expr.value));
3996 } else {
3997 set_cvalue (expr, new CCodeConstant ("%uU".printf (expr.get_char ())));
4001 public override void visit_integer_literal (IntegerLiteral expr) {
4002 set_cvalue (expr, new CCodeConstant (expr.value + expr.type_suffix));
4005 public override void visit_real_literal (RealLiteral expr) {
4006 string c_literal = expr.value;
4007 if (c_literal.has_suffix ("d") || c_literal.has_suffix ("D")) {
4008 // there is no suffix for double in C
4009 c_literal = c_literal.substring (0, c_literal.length - 1);
4011 if (!("." in c_literal || "e" in c_literal || "E" in c_literal)) {
4012 // C requires period or exponent part for floating constants
4013 if ("f" in c_literal || "F" in c_literal) {
4014 c_literal = c_literal.substring (0, c_literal.length - 1) + ".f";
4015 } else {
4016 c_literal += ".";
4019 set_cvalue (expr, new CCodeConstant (c_literal));
4022 public override void visit_string_literal (StringLiteral expr) {
4023 set_cvalue (expr, new CCodeConstant.string (expr.value.replace ("\n", "\\n")));
4025 if (expr.translate) {
4026 // translated string constant
4028 var m = (Method) root_symbol.scope.lookup ("GLib").scope.lookup ("_");
4029 add_symbol_declaration (cfile, m, get_ccode_name (m));
4031 var translate = new CCodeFunctionCall (new CCodeIdentifier ("_"));
4032 translate.add_argument (get_cvalue (expr));
4033 set_cvalue (expr, translate);
4037 public override void visit_regex_literal (RegexLiteral expr) {
4038 string[] parts = expr.value.split ("/", 3);
4039 string re = parts[2].escape ("");
4040 string flags = "0";
4042 if (parts[1].contains ("i")) {
4043 flags += " | G_REGEX_CASELESS";
4045 if (parts[1].contains ("m")) {
4046 flags += " | G_REGEX_MULTILINE";
4048 if (parts[1].contains ("s")) {
4049 flags += " | G_REGEX_DOTALL";
4051 if (parts[1].contains ("x")) {
4052 flags += " | G_REGEX_EXTENDED";
4055 var cdecl = new CCodeDeclaration ("GRegex*");
4057 var cname = "_tmp_regex_%d".printf (next_regex_id);
4058 if (this.next_regex_id == 0) {
4059 var fun = new CCodeFunction ("_thread_safe_regex_init", "GRegex*");
4060 fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
4061 fun.add_parameter (new CCodeParameter ("re", "GRegex**"));
4062 fun.add_parameter (new CCodeParameter ("pattern", "const gchar *"));
4063 fun.add_parameter (new CCodeParameter ("match_options", "GRegexMatchFlags"));
4065 push_function (fun);
4067 var once_enter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
4068 once_enter_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
4069 ccode.open_if (once_enter_call);
4071 var regex_new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_regex_new"));
4072 regex_new_call.add_argument (new CCodeConstant ("pattern"));
4073 regex_new_call.add_argument (new CCodeConstant ("match_options"));
4074 regex_new_call.add_argument (new CCodeConstant ("0"));
4075 regex_new_call.add_argument (new CCodeConstant ("NULL"));
4076 ccode.add_assignment (new CCodeIdentifier ("GRegex* val"), regex_new_call);
4078 var once_leave_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
4079 once_leave_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
4080 once_leave_call.add_argument (new CCodeConstant ("(gsize) val"));
4081 ccode.add_expression (once_leave_call);
4083 ccode.close ();
4085 ccode.add_return (new CCodeIdentifier ("*re"));
4087 pop_function ();
4089 cfile.add_function (fun);
4091 this.next_regex_id++;
4093 cdecl.add_declarator (new CCodeVariableDeclarator (cname + " = NULL"));
4094 cdecl.modifiers = CCodeModifiers.STATIC;
4096 var regex_const = new CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname, re, flags));
4098 cfile.add_constant_declaration (cdecl);
4099 set_cvalue (expr, regex_const);
4102 public override void visit_null_literal (NullLiteral expr) {
4103 if (context.profile != Profile.GOBJECT) {
4104 cfile.add_include ("stddef.h");
4106 set_cvalue (expr, new CCodeConstant ("NULL"));
4108 var array_type = expr.target_type as ArrayType;
4109 var delegate_type = expr.target_type as DelegateType;
4110 if (array_type != null) {
4111 for (int dim = 1; dim <= array_type.rank; dim++) {
4112 append_array_length (expr, new CCodeConstant ("0"));
4114 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
4115 set_delegate_target (expr, new CCodeConstant ("NULL"));
4116 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
4120 public abstract TargetValue get_local_cvalue (LocalVariable local);
4122 public abstract TargetValue get_parameter_cvalue (Parameter param);
4124 public abstract TargetValue get_field_cvalue (Field field, TargetValue? instance);
4126 public abstract TargetValue load_variable (Variable variable, TargetValue value);
4128 public abstract TargetValue load_this_parameter (TypeSymbol sym);
4130 public abstract void store_value (TargetValue lvalue, TargetValue value, SourceReference? source_reference = null);
4132 public virtual string get_delegate_target_cname (string delegate_cname) {
4133 assert_not_reached ();
4136 public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
4137 assert_not_reached ();
4140 public virtual CCodeExpression get_delegate_target_cvalue (TargetValue value) {
4141 return new CCodeInvalidExpression ();
4144 public virtual CCodeExpression get_delegate_target_destroy_notify_cvalue (TargetValue value) {
4145 return new CCodeInvalidExpression ();
4148 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname) {
4149 assert_not_reached ();
4152 public override void visit_base_access (BaseAccess expr) {
4153 CCodeExpression this_access;
4154 if (is_in_coroutine ()) {
4155 // use closure
4156 this_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
4157 } else {
4158 this_access = new CCodeIdentifier ("self");
4161 set_cvalue (expr, generate_instance_cast (this_access, expr.value_type.data_type));
4164 public override void visit_postfix_expression (PostfixExpression expr) {
4165 MemberAccess ma = find_property_access (expr.inner);
4166 if (ma != null) {
4167 // property postfix expression
4168 var prop = (Property) ma.symbol_reference;
4170 // increment/decrement property
4171 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4172 var cexpr = new CCodeBinaryExpression (op, get_cvalue (expr.inner), new CCodeConstant ("1"));
4173 store_property (prop, ma.inner, new GLibValue (expr.value_type, cexpr));
4175 // return previous value
4176 expr.target_value = expr.inner.target_value;
4177 return;
4180 // assign current value to temp variable
4181 var temp_value = store_temp_value (expr.inner.target_value, expr);
4183 // increment/decrement variable
4184 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4185 var cexpr = new CCodeBinaryExpression (op, get_cvalue_ (temp_value), new CCodeConstant ("1"));
4186 ccode.add_assignment (get_cvalue (expr.inner), cexpr);
4188 // return previous value
4189 expr.target_value = temp_value;
4192 private MemberAccess? find_property_access (Expression expr) {
4193 if (!(expr is MemberAccess)) {
4194 return null;
4197 var ma = (MemberAccess) expr;
4198 if (ma.symbol_reference is Property) {
4199 return ma;
4202 return null;
4205 bool is_limited_generic_type (GenericType type) {
4206 var cl = type.type_parameter.parent_symbol as Class;
4207 var st = type.type_parameter.parent_symbol as Struct;
4208 if ((cl != null && cl.is_compact) || st != null) {
4209 // compact classes and structs only
4210 // have very limited generics support
4211 return true;
4213 return false;
4216 public bool requires_copy (DataType type) {
4217 if (!type.is_disposable ()) {
4218 return false;
4221 var cl = type.data_type as Class;
4222 if (cl != null && is_reference_counting (cl)
4223 && get_ccode_ref_function (cl) == "") {
4224 // empty ref_function => no ref necessary
4225 return false;
4228 if (type is GenericType) {
4229 if (is_limited_generic_type ((GenericType) type)) {
4230 return false;
4234 return true;
4237 public bool requires_destroy (DataType type) {
4238 if (!type.is_disposable ()) {
4239 return false;
4242 var array_type = type as ArrayType;
4243 if (array_type != null && array_type.fixed_length) {
4244 return requires_destroy (array_type.element_type);
4247 var cl = type.data_type as Class;
4248 if (cl != null && is_reference_counting (cl)
4249 && get_ccode_unref_function (cl) == "") {
4250 // empty unref_function => no unref necessary
4251 return false;
4254 if (type is GenericType) {
4255 if (is_limited_generic_type ((GenericType) type)) {
4256 return false;
4260 return true;
4263 bool is_ref_function_void (DataType type) {
4264 var cl = type.data_type as Class;
4265 if (cl != null) {
4266 return get_ccode_ref_function_void (cl);
4267 } else {
4268 return false;
4272 bool is_free_function_address_of (DataType type) {
4273 var cl = type.data_type as Class;
4274 if (cl != null) {
4275 return get_ccode_free_function_address_of (cl);
4276 } else {
4277 return false;
4281 public virtual TargetValue? copy_value (TargetValue value, CodeNode node) {
4282 var type = value.value_type;
4283 var cexpr = get_cvalue_ (value);
4284 var result = ((GLibValue) value).copy ();
4286 if (type is DelegateType) {
4287 var delegate_type = (DelegateType) type;
4288 if (delegate_type.delegate_symbol.has_target && !context.deprecated) {
4289 Report.deprecated (node.source_reference, "copying delegates is not supported");
4291 result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
4292 return result;
4295 if (type is ValueType && !type.nullable) {
4296 // normal value type, no null check
4298 var temp_value = create_temp_value (type, true, node, true);
4299 var ctemp = get_cvalue_ (temp_value);
4301 var vt = (ValueType) type;
4302 var st = (Struct) vt.type_symbol;
4303 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
4304 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4305 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4307 if (!get_ccode_has_copy_function (st)) {
4308 generate_struct_copy_function (st);
4311 if (gvalue_type != null && type.data_type == gvalue_type) {
4312 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
4313 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4315 ccode.open_if (cisvalid);
4317 // GValue requires g_value_init in addition to g_value_copy
4318 var value_type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
4319 value_type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4321 var init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
4322 init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4323 init_call.add_argument (value_type_call);
4324 ccode.add_expression (init_call);
4325 ccode.add_expression (copy_call);
4327 ccode.add_else ();
4329 // g_value_init/copy must not be called for uninitialized values
4330 store_value (temp_value, value, node.source_reference);
4331 ccode.close ();
4332 } else {
4333 ccode.add_expression (copy_call);
4336 return temp_value;
4339 /* (temp = expr, temp == NULL ? NULL : ref (temp))
4341 * can be simplified to
4342 * ref (expr)
4343 * if static type of expr is non-null
4346 var dupexpr = get_dup_func_expression (type, node.source_reference);
4348 if (dupexpr == null) {
4349 node.error = true;
4350 return null;
4353 if (dupexpr is CCodeIdentifier && !(type is ArrayType) && !(type is GenericType) && !is_ref_function_void (type)) {
4354 // generate and call NULL-aware ref function to reduce number
4355 // of temporary variables and simplify code
4357 var dupid = (CCodeIdentifier) dupexpr;
4358 string dup0_func = "_%s0".printf (dupid.name);
4360 // g_strdup is already NULL-safe
4361 if (dupid.name == "g_strdup") {
4362 dup0_func = dupid.name;
4363 } else if (add_wrapper (dup0_func)) {
4364 string pointer_cname = "gpointer";
4365 if (context.profile == Profile.POSIX) {
4366 pointer_cname = "void *";
4368 var dup0_fun = new CCodeFunction (dup0_func, pointer_cname);
4369 dup0_fun.add_parameter (new CCodeParameter ("self", pointer_cname));
4370 dup0_fun.modifiers = CCodeModifiers.STATIC;
4372 push_function (dup0_fun);
4374 var dup_call = new CCodeFunctionCall (dupexpr);
4375 dup_call.add_argument (new CCodeIdentifier ("self"));
4377 ccode.add_return (new CCodeConditionalExpression (new CCodeIdentifier ("self"), dup_call, new CCodeConstant ("NULL")));
4379 pop_function ();
4381 cfile.add_function (dup0_fun);
4384 var ccall = new CCodeFunctionCall (new CCodeIdentifier (dup0_func));
4385 ccall.add_argument (cexpr);
4386 result.cvalue = ccall;
4387 result.value_type.value_owned = true;
4388 return store_temp_value (result, node);
4391 var ccall = new CCodeFunctionCall (dupexpr);
4393 if (!(type is ArrayType) && get_non_null (value) && !is_ref_function_void (type)) {
4394 // expression is non-null
4395 ccall.add_argument (cexpr);
4397 return store_temp_value (new GLibValue (type, ccall), node);
4398 } else {
4399 var cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cexpr, new CCodeConstant ("NULL"));
4400 if (type is GenericType) {
4401 // dup functions are optional for type parameters
4402 var cdupnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_dup_func_expression (type, node.source_reference), new CCodeConstant ("NULL"));
4403 cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.AND, cnotnull, cdupnotnull);
4406 if (type is GenericType) {
4407 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
4408 ccall.add_argument (new CCodeCastExpression (cexpr, "gpointer"));
4409 } else {
4410 ccall.add_argument (cexpr);
4413 if (type is ArrayType) {
4414 var array_type = (ArrayType) type;
4415 ccall.add_argument (get_array_length_cvalue (value));
4417 if (array_type.element_type is GenericType) {
4418 var elem_dupexpr = get_dup_func_expression (array_type.element_type, node.source_reference);
4419 if (elem_dupexpr == null) {
4420 elem_dupexpr = new CCodeConstant ("NULL");
4422 ccall.add_argument (elem_dupexpr);
4426 CCodeExpression cifnull;
4427 if (type.data_type != null) {
4428 cifnull = new CCodeConstant ("NULL");
4429 } else {
4430 // the value might be non-null even when the dup function is null,
4431 // so we may not just use NULL for type parameters
4433 // cast from gconstpointer to gpointer as methods in
4434 // generic classes may not return gconstpointer
4435 cifnull = new CCodeCastExpression (cexpr, "gpointer");
4438 if (is_ref_function_void (type)) {
4439 ccode.open_if (cnotnull);
4440 ccode.add_expression (ccall);
4441 ccode.close ();
4442 } else {
4443 var ccond = new CCodeConditionalExpression (cnotnull, ccall, cifnull);
4444 result.cvalue = ccond;
4445 result = (GLibValue) store_temp_value (result, node, true);
4447 return result;
4451 bool is_reference_type_argument (DataType type_arg) {
4452 if (type_arg is ErrorType || (type_arg.data_type != null && type_arg.data_type.is_reference_type ())) {
4453 return true;
4454 } else {
4455 return false;
4459 bool is_nullable_value_type_argument (DataType type_arg) {
4460 if (type_arg is ValueType && type_arg.nullable) {
4461 return true;
4462 } else {
4463 return false;
4467 bool is_signed_integer_type_argument (DataType type_arg) {
4468 var st = type_arg.data_type as Struct;
4469 if (type_arg is EnumValueType) {
4470 return true;
4471 } else if (type_arg.nullable) {
4472 return false;
4473 } else if (st == null) {
4474 return false;
4475 } else if (st.is_subtype_of (bool_type.data_type)) {
4476 return true;
4477 } else if (st.is_subtype_of (char_type.data_type)) {
4478 return true;
4479 } else if (unichar_type != null && st.is_subtype_of (unichar_type.data_type)) {
4480 return true;
4481 } else if (st.is_subtype_of (short_type.data_type)) {
4482 return true;
4483 } else if (st.is_subtype_of (int_type.data_type)) {
4484 return true;
4485 } else if (st.is_subtype_of (long_type.data_type)) {
4486 return true;
4487 } else if (st.is_subtype_of (int8_type.data_type)) {
4488 return true;
4489 } else if (st.is_subtype_of (int16_type.data_type)) {
4490 return true;
4491 } else if (st.is_subtype_of (int32_type.data_type)) {
4492 return true;
4493 } else if (st.is_subtype_of (gtype_type)) {
4494 return true;
4495 } else {
4496 return false;
4500 bool is_unsigned_integer_type_argument (DataType type_arg) {
4501 var st = type_arg.data_type as Struct;
4502 if (st == null) {
4503 return false;
4504 } else if (type_arg.nullable) {
4505 return false;
4506 } else if (st.is_subtype_of (uchar_type.data_type)) {
4507 return true;
4508 } else if (st.is_subtype_of (ushort_type.data_type)) {
4509 return true;
4510 } else if (st.is_subtype_of (uint_type.data_type)) {
4511 return true;
4512 } else if (st.is_subtype_of (ulong_type.data_type)) {
4513 return true;
4514 } else if (st.is_subtype_of (uint8_type.data_type)) {
4515 return true;
4516 } else if (st.is_subtype_of (uint16_type.data_type)) {
4517 return true;
4518 } else if (st.is_subtype_of (uint32_type.data_type)) {
4519 return true;
4520 } else {
4521 return false;
4525 public void check_type (DataType type) {
4526 var array_type = type as ArrayType;
4527 if (array_type != null) {
4528 check_type (array_type.element_type);
4529 if (array_type.element_type is ArrayType) {
4530 Report.error (type.source_reference, "Stacked arrays are not supported");
4531 } else if (array_type.element_type is DelegateType) {
4532 var delegate_type = (DelegateType) array_type.element_type;
4533 if (delegate_type.delegate_symbol.has_target) {
4534 Report.error (type.source_reference, "Delegates with target are not supported as array element type");
4538 foreach (var type_arg in type.get_type_arguments ()) {
4539 check_type (type_arg);
4540 check_type_argument (type_arg);
4544 public void check_type_arguments (MemberAccess access) {
4545 foreach (var type_arg in access.get_type_arguments ()) {
4546 check_type (type_arg);
4547 check_type_argument (type_arg);
4551 void check_type_argument (DataType type_arg) {
4552 if (type_arg is GenericType
4553 || type_arg is PointerType
4554 || is_reference_type_argument (type_arg)
4555 || is_nullable_value_type_argument (type_arg)
4556 || is_signed_integer_type_argument (type_arg)
4557 || is_unsigned_integer_type_argument (type_arg)) {
4558 // no error
4559 } else if (type_arg is DelegateType) {
4560 var delegate_type = (DelegateType) type_arg;
4561 if (delegate_type.delegate_symbol.has_target) {
4562 Report.error (type_arg.source_reference, "Delegates with target are not supported as generic type arguments");
4564 } else {
4565 Report.error (type_arg.source_reference, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg.to_string ()));
4569 public virtual void generate_class_declaration (Class cl, CCodeFile decl_space) {
4570 if (add_symbol_declaration (decl_space, cl, get_ccode_name (cl))) {
4571 return;
4575 public virtual void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
4578 public virtual void generate_method_declaration (Method m, CCodeFile decl_space) {
4581 public virtual void generate_error_domain_declaration (ErrorDomain edomain, CCodeFile decl_space) {
4584 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) {
4585 int type_param_index = 0;
4586 foreach (var type_arg in type_args) {
4587 if (type_parameters != null) {
4588 var type_param_name = type_parameters.get (type_param_index).name.down ();
4589 arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s_type\"".printf (type_param_name)));
4590 arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("\"%s_dup_func\"".printf (type_param_name)));
4591 arg_map.set (get_param_pos (0.1 * type_param_index + 0.05), new CCodeConstant ("\"%s_destroy_func\"".printf (type_param_name)));
4594 arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), get_type_id_expression (type_arg, is_chainup));
4595 if (requires_copy (type_arg)) {
4596 var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference, is_chainup);
4597 if (dup_func == null) {
4598 // type doesn't contain a copy function
4599 expr.error = true;
4600 return;
4602 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
4603 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeCastExpression (get_destroy_func_expression (type_arg, is_chainup), "GDestroyNotify"));
4604 } else {
4605 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeConstant ("NULL"));
4606 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeConstant ("NULL"));
4608 type_param_index++;
4612 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
4613 CCodeExpression instance = null;
4614 CCodeExpression creation_expr = null;
4616 check_type (expr.type_reference);
4618 var st = expr.type_reference.data_type as Struct;
4619 if ((st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list")) || expr.get_object_initializer ().size > 0) {
4620 // value-type initialization or object creation expression with object initializer
4622 var local = expr.parent_node as LocalVariable;
4623 var field = expr.parent_node as Field;
4624 var a = expr.parent_node as Assignment;
4625 if (local != null && is_simple_struct_creation (local, local.initializer)) {
4626 instance = get_cvalue_ (get_local_cvalue (local));
4627 } else if (field != null && is_simple_struct_creation (field, field.initializer)) {
4628 // field initialization
4629 var thisparam = load_this_parameter ((TypeSymbol) field.parent_symbol);
4630 instance = get_cvalue_ (get_field_cvalue (field, thisparam));
4631 } else if (a != null && a.left.symbol_reference is Variable && is_simple_struct_creation ((Variable) a.left.symbol_reference, a.right)) {
4632 if (requires_destroy (a.left.value_type)) {
4633 /* unref old value */
4634 ccode.add_expression (destroy_value (a.left.target_value));
4637 local = a.left.symbol_reference as LocalVariable;
4638 field = a.left.symbol_reference as Field;
4639 var param = a.left.symbol_reference as Parameter;
4640 if (local != null) {
4641 instance = get_cvalue_ (get_local_cvalue (local));
4642 } else if (field != null) {
4643 var inner = ((MemberAccess) a.left).inner;
4644 instance = get_cvalue_ (get_field_cvalue (field, inner != null ? inner.target_value : null));
4645 } else if (param != null) {
4646 instance = get_cvalue_ (get_parameter_cvalue (param));
4648 } else {
4649 var temp_value = create_temp_value (expr.type_reference, true, expr);
4650 instance = get_cvalue_ (temp_value);
4654 if (expr.symbol_reference == null) {
4655 // no creation method
4656 if (expr.type_reference.data_type is Struct) {
4657 // memset needs string.h
4658 cfile.add_include ("string.h");
4659 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4660 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4661 creation_call.add_argument (new CCodeConstant ("0"));
4662 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.type_reference))));
4664 creation_expr = creation_call;
4666 } else if (expr.type_reference.data_type == glist_type ||
4667 expr.type_reference.data_type == gslist_type) {
4668 // NULL is an empty list
4669 set_cvalue (expr, new CCodeConstant ("NULL"));
4670 } else if (expr.symbol_reference is Method) {
4671 // use creation method
4672 var m = (Method) expr.symbol_reference;
4673 var params = m.get_parameters ();
4674 CCodeFunctionCall creation_call;
4676 CCodeFunctionCall async_call = null;
4677 CCodeFunctionCall finish_call = null;
4679 generate_method_declaration (m, cfile);
4681 var cl = expr.type_reference.data_type as Class;
4683 if (!get_ccode_has_new_function (m)) {
4684 // use construct function directly
4685 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
4686 creation_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
4687 } else {
4688 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
4691 if ((st != null && !st.is_simple_type ()) && !(get_ccode_instance_pos (m) < 0)) {
4692 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4693 } else if (st != null && get_ccode_name (st) == "va_list") {
4694 creation_call.add_argument (instance);
4695 if (get_ccode_name (m) == "va_start") {
4696 if (in_creation_method) {
4697 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("va_copy"));
4698 creation_call.add_argument (instance);
4699 creation_call.add_argument (new CCodeIdentifier ("_vala_va_list"));
4700 } else {
4701 Parameter last_param = null;
4702 // FIXME: this doesn't take into account exception handling parameters
4703 foreach (var param in current_method.get_parameters ()) {
4704 if (param.ellipsis) {
4705 break;
4707 last_param = param;
4709 int nParams = ccode.get_parameter_count ();
4710 if (nParams == 0 || !ccode.get_parameter (nParams - 1).ellipsis) {
4711 Report.error (expr.source_reference, "`va_list' used in method with fixed args");
4712 } else if (nParams == 1) {
4713 Report.error (expr.source_reference, "`va_list' used in method without parameter");
4714 } else {
4715 creation_call.add_argument (new CCodeIdentifier (ccode.get_parameter (nParams - 2).name));
4721 generate_type_declaration (expr.type_reference, cfile);
4723 var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
4724 var out_arg_map = in_arg_map;
4726 if (m != null && m.coroutine) {
4727 // async call
4729 async_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
4730 finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
4732 creation_call = finish_call;
4734 // output arguments used separately
4735 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
4736 // pass GAsyncResult stored in closure to finish function
4737 out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
4740 if (cl != null && !cl.is_compact) {
4741 add_generic_type_arguments (in_arg_map, expr.type_reference.get_type_arguments (), expr);
4742 } else if (cl != null && get_ccode_simple_generics (m)) {
4743 int type_param_index = 0;
4744 foreach (var type_arg in expr.type_reference.get_type_arguments ()) {
4745 if (requires_copy (type_arg)) {
4746 in_arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), get_destroy0_func_expression (type_arg));
4747 } else {
4748 in_arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
4750 type_param_index++;
4754 bool ellipsis = false;
4756 int i = 1;
4757 int arg_pos;
4758 Iterator<Parameter> params_it = params.iterator ();
4759 foreach (Expression arg in expr.get_argument_list ()) {
4760 CCodeExpression cexpr = get_cvalue (arg);
4762 var carg_map = in_arg_map;
4764 Parameter param = null;
4765 if (params_it.next ()) {
4766 param = params_it.get ();
4767 ellipsis = param.ellipsis;
4768 if (!ellipsis) {
4769 if (param.direction == ParameterDirection.OUT) {
4770 carg_map = out_arg_map;
4773 // g_array_new: element size
4774 if (cl == garray_type && param.name == "element_size") {
4775 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
4776 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference.get_type_arguments ().get (0))));
4777 cexpr = csizeof;
4780 if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
4781 var array_type = (ArrayType) param.variable_type;
4782 for (int dim = 1; dim <= array_type.rank; dim++) {
4783 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_array_length_cexpression (arg, dim));
4785 } else if (param.variable_type is DelegateType) {
4786 var deleg_type = (DelegateType) param.variable_type;
4787 var d = deleg_type.delegate_symbol;
4788 if (d.has_target) {
4789 CCodeExpression delegate_target_destroy_notify;
4790 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
4791 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
4792 if (deleg_type.is_disposable ()) {
4793 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param) + 0.01), delegate_target_destroy_notify);
4798 cexpr = handle_struct_argument (param, arg, cexpr);
4800 if (get_ccode_type (param) != null) {
4801 cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
4803 } else {
4804 cexpr = handle_struct_argument (null, arg, cexpr);
4807 arg_pos = get_param_pos (get_ccode_pos (param), ellipsis);
4808 } else {
4809 // default argument position
4810 cexpr = handle_struct_argument (null, arg, cexpr);
4811 arg_pos = get_param_pos (i, ellipsis);
4814 carg_map.set (arg_pos, cexpr);
4816 i++;
4818 if (params_it.next ()) {
4819 var param = params_it.get ();
4821 /* if there are more parameters than arguments,
4822 * the additional parameter is an ellipsis parameter
4823 * otherwise there is a bug in the semantic analyzer
4825 assert (param.params_array || param.ellipsis);
4826 ellipsis = true;
4829 if (expr.tree_can_fail) {
4830 // method can fail
4831 current_method_inner_error = true;
4832 // add &inner_error before the ellipsis arguments
4833 out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
4836 if (ellipsis) {
4837 /* ensure variable argument list ends with NULL
4838 * except when using printf-style arguments */
4839 if (m == null) {
4840 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
4841 } else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "") {
4842 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
4846 if ((st != null && !st.is_simple_type ()) && get_ccode_instance_pos (m) < 0) {
4847 // instance parameter is at the end in a struct creation method
4848 out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4851 if (m != null && m.coroutine) {
4852 if (expr.is_yield_expression) {
4853 // asynchronous call
4854 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
4855 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
4859 if (m != null && m.parent_symbol is Class) {
4860 if (get_ccode_finish_instance (m)) {
4861 var tmp = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_source_object_");
4862 out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), tmp);
4866 // append C arguments in the right order
4868 int last_pos;
4869 int min_pos;
4871 if (async_call != creation_call) {
4872 // don't append out arguments for .begin() calls
4873 last_pos = -1;
4874 while (true) {
4875 min_pos = -1;
4876 foreach (int pos in out_arg_map.get_keys ()) {
4877 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
4878 min_pos = pos;
4881 if (min_pos == -1) {
4882 break;
4884 creation_call.add_argument (out_arg_map.get (min_pos));
4885 last_pos = min_pos;
4889 if (async_call != null) {
4890 last_pos = -1;
4891 while (true) {
4892 min_pos = -1;
4893 foreach (int pos in in_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 async_call.add_argument (in_arg_map.get (min_pos));
4902 last_pos = min_pos;
4906 if (expr.is_yield_expression) {
4907 // set state before calling async function to support immediate callbacks
4908 int state = emit_context.next_coroutine_state++;
4910 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
4911 ccode.add_expression (async_call);
4912 ccode.add_return (new CCodeConstant ("FALSE"));
4913 ccode.add_label ("_state_%d".printf (state));
4916 creation_expr = creation_call;
4918 // cast the return value of the creation method back to the intended type if
4919 // it requested a special C return type
4920 if (get_ccode_type (m) != null) {
4921 creation_expr = new CCodeCastExpression (creation_expr, get_ccode_name (expr.type_reference));
4923 } else if (expr.symbol_reference is ErrorCode) {
4924 var ecode = (ErrorCode) expr.symbol_reference;
4925 var edomain = (ErrorDomain) ecode.parent_symbol;
4926 CCodeFunctionCall creation_call;
4928 generate_error_domain_declaration (edomain, cfile);
4930 if (expr.get_argument_list ().size == 1) {
4931 // must not be a format argument
4932 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new_literal"));
4933 } else {
4934 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new"));
4936 creation_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (edomain)));
4937 creation_call.add_argument (new CCodeIdentifier (get_ccode_name (ecode)));
4939 foreach (Expression arg in expr.get_argument_list ()) {
4940 creation_call.add_argument (get_cvalue (arg));
4943 creation_expr = creation_call;
4944 } else {
4945 assert (false);
4948 var local = expr.parent_node as LocalVariable;
4949 if (local != null && is_simple_struct_creation (local, local.initializer)) {
4950 // no temporary variable necessary
4951 ccode.add_expression (creation_expr);
4952 set_cvalue (expr, instance);
4953 } else if (instance != null) {
4954 if (expr.type_reference.data_type is Struct) {
4955 ccode.add_expression (creation_expr);
4956 } else {
4957 ccode.add_assignment (instance, creation_expr);
4960 foreach (MemberInitializer init in expr.get_object_initializer ()) {
4961 if (init.symbol_reference is Field) {
4962 var f = (Field) init.symbol_reference;
4963 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
4964 var typed_inst = transform_value (new GLibValue (expr.type_reference, instance, true), instance_target_type, init);
4965 store_field (f, typed_inst, init.initializer.target_value, init.source_reference);
4967 var cl = f.parent_symbol as Class;
4968 if (cl != null) {
4969 generate_class_struct_declaration (cl, cfile);
4971 } else if (init.symbol_reference is Property) {
4972 var inst_ma = new MemberAccess.simple ("new");
4973 inst_ma.value_type = expr.type_reference;
4974 set_cvalue (inst_ma, instance);
4975 store_property ((Property) init.symbol_reference, inst_ma, init.initializer.target_value);
4976 // FIXME Do not ref/copy in the first place
4977 if (requires_destroy (init.initializer.target_value.value_type)) {
4978 ccode.add_expression (destroy_value (init.initializer.target_value));
4983 set_cvalue (expr, instance);
4984 } else if (creation_expr != null) {
4985 var temp_value = create_temp_value (expr.value_type, false, expr);
4986 ccode.add_assignment (get_cvalue_ (temp_value), creation_expr);
4987 expr.target_value = temp_value;
4989 if (context.gobject_tracing) {
4990 // GObject creation tracing enabled
4992 var cl = expr.type_reference.data_type as Class;
4993 if (cl != null && cl.is_subtype_of (gobject_type)) {
4994 // creating GObject
4996 // instance can be NULL in error cases
4997 ccode.open_if (get_cvalue_ (expr.target_value));
4999 var set_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set_data"));
5000 set_data_call.add_argument (new CCodeCastExpression (get_cvalue_ (expr.target_value), "GObject *"));
5001 set_data_call.add_argument (new CCodeConstant ("\"vala-creation-function\""));
5003 string func_name = "";
5004 if (current_method != null) {
5005 func_name = current_method.get_full_name ();
5006 } else if (current_property_accessor != null) {
5007 func_name = current_property_accessor.get_full_name ();
5010 set_data_call.add_argument (new CCodeConstant ("\"%s\"".printf (func_name)));
5012 ccode.add_expression (set_data_call);
5014 ccode.close ();
5019 ((GLibValue) expr.target_value).lvalue = true;
5022 public CCodeExpression? handle_struct_argument (Parameter? param, Expression arg, CCodeExpression? cexpr) {
5023 DataType type;
5024 if (param != null) {
5025 type = param.variable_type;
5026 } else {
5027 // varargs
5028 type = arg.value_type;
5031 var unary = arg as UnaryExpression;
5032 // pass non-simple struct instances always by reference
5033 if (!(arg.value_type is NullType) && type.is_real_struct_type ()) {
5034 // we already use a reference for arguments of ref, out, and nullable parameters
5035 if (!(unary != null && (unary.operator == UnaryOperator.OUT || unary.operator == UnaryOperator.REF)) && !type.nullable) {
5036 if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
5037 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5038 } else {
5039 // if cexpr is e.g. a function call, we can't take the address of the expression
5040 var temp_value = create_temp_value (type, false, arg);
5041 ccode.add_assignment (get_cvalue_ (temp_value), cexpr);
5042 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value));
5047 return cexpr;
5050 public override void visit_sizeof_expression (SizeofExpression expr) {
5051 generate_type_declaration (expr.type_reference, cfile);
5053 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5054 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference)));
5055 set_cvalue (expr, csizeof);
5058 public override void visit_typeof_expression (TypeofExpression expr) {
5059 set_cvalue (expr, get_type_id_expression (expr.type_reference));
5062 public override void visit_unary_expression (UnaryExpression expr) {
5063 if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) {
5064 var glib_value = (GLibValue) expr.inner.target_value;
5066 var ref_value = new GLibValue (glib_value.value_type);
5067 if (expr.target_type != null && glib_value.value_type.is_real_struct_type () && glib_value.value_type.nullable != expr.target_type.nullable) {
5068 // the only possibility is that value_type is nullable and target_type is non-nullable
5069 ref_value.cvalue = glib_value.cvalue;
5070 } else {
5071 ref_value.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.cvalue);
5074 if (glib_value.array_length_cvalues != null) {
5075 for (int i = 0; i < glib_value.array_length_cvalues.size; i++) {
5076 ref_value.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.array_length_cvalues[i]));
5080 if (glib_value.delegate_target_cvalue != null) {
5081 ref_value.delegate_target_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_cvalue);
5083 if (glib_value.delegate_target_destroy_notify_cvalue != null) {
5084 ref_value.delegate_target_destroy_notify_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_destroy_notify_cvalue);
5087 expr.target_value = ref_value;
5088 return;
5091 CCodeUnaryOperator op;
5092 if (expr.operator == UnaryOperator.PLUS) {
5093 op = CCodeUnaryOperator.PLUS;
5094 } else if (expr.operator == UnaryOperator.MINUS) {
5095 op = CCodeUnaryOperator.MINUS;
5096 } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
5097 op = CCodeUnaryOperator.LOGICAL_NEGATION;
5098 } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
5099 op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
5100 } else if (expr.operator == UnaryOperator.INCREMENT) {
5101 op = CCodeUnaryOperator.PREFIX_INCREMENT;
5102 } else if (expr.operator == UnaryOperator.DECREMENT) {
5103 op = CCodeUnaryOperator.PREFIX_DECREMENT;
5104 } else {
5105 assert_not_reached ();
5107 set_cvalue (expr, new CCodeUnaryExpression (op, get_cvalue (expr.inner)));
5110 public CCodeExpression? try_cast_value_to_type (CCodeExpression ccodeexpr, DataType from, DataType to, Expression? expr = null) {
5111 if (from == null || gvalue_type == null || from.data_type != gvalue_type || to.data_type == gvalue_type || get_ccode_type_id (to) == "") {
5112 return null;
5115 // explicit conversion from GValue
5116 var ccall = new CCodeFunctionCall (get_value_getter_function (to));
5117 CCodeExpression gvalue;
5118 if (from.nullable) {
5119 gvalue = ccodeexpr;
5120 } else {
5121 gvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ccodeexpr);
5123 ccall.add_argument (gvalue);
5125 CCodeExpression rv = ccall;
5127 if (expr != null && to is ArrayType) {
5128 // null-terminated string array
5129 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
5130 len_call.add_argument (rv);
5131 append_array_length (expr, len_call);
5132 } else if (to is StructValueType) {
5133 CodeNode node = expr != null ? (CodeNode) expr : to;
5134 var temp_value = create_temp_value (to, true, node, true);
5135 var ctemp = get_cvalue_ (temp_value);
5137 rv = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeCastExpression (rv, get_ccode_name (new PointerType (to))));
5138 var holds = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_HOLDS"));
5139 holds.add_argument (gvalue);
5140 holds.add_argument (new CCodeIdentifier (get_ccode_type_id (to)));
5141 var cond = new CCodeBinaryExpression (CCodeBinaryOperator.AND, holds, ccall);
5142 var warn = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
5143 warn.add_argument (new CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
5144 var fail = new CCodeCommaExpression ();
5145 fail.append_expression (warn);
5146 fail.append_expression (ctemp);
5147 rv = new CCodeConditionalExpression (cond, rv, fail);
5150 return rv;
5153 int next_variant_function_id = 0;
5155 public TargetValue? try_cast_variant_to_type (TargetValue value, DataType to, CodeNode? node = null) {
5156 if (value.value_type == null || gvariant_type == null || value.value_type.data_type != gvariant_type) {
5157 return null;
5160 string variant_func = "_variant_get%d".printf (++next_variant_function_id);
5162 var variant = value;
5163 if (value.value_type.value_owned) {
5164 // value leaked, destroy it
5165 var temp_value = store_temp_value (value, node);
5166 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5167 variant = temp_value;
5170 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
5171 ccall.add_argument (get_cvalue_ (variant));
5173 var result = create_temp_value (to, false, node);
5175 var cfunc = new CCodeFunction (variant_func);
5176 cfunc.modifiers = CCodeModifiers.STATIC;
5177 cfunc.add_parameter (new CCodeParameter ("value", "GVariant*"));
5179 if (!to.is_real_non_null_struct_type ()) {
5180 cfunc.return_type = get_ccode_name (to);
5183 if (to.is_real_non_null_struct_type ()) {
5184 // structs are returned via out parameter
5185 cfunc.add_parameter (new CCodeParameter ("result", "%s *".printf (get_ccode_name (to))));
5186 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (result)));
5187 } else if (to is ArrayType) {
5188 // return array length if appropriate
5189 // tmp = _variant_get (variant, &tmp_length);
5190 var array_type = (ArrayType) to;
5192 for (int dim = 1; dim <= array_type.rank; dim++) {
5193 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cvalue (result, dim)));
5194 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("result", dim), "int*"));
5198 if (!to.is_real_non_null_struct_type ()) {
5199 ccode.add_assignment (get_cvalue_ (result), ccall);
5200 } else {
5201 ccode.add_expression (ccall);
5204 push_function (cfunc);
5206 CCodeExpression func_result = deserialize_expression (to, new CCodeIdentifier ("value"), new CCodeIdentifier ("*result"));
5207 if (to.is_real_non_null_struct_type ()) {
5208 ccode.add_assignment (new CCodeIdentifier ("*result"), func_result);
5209 } else {
5210 ccode.add_return (func_result);
5213 pop_function ();
5215 cfile.add_function_declaration (cfunc);
5216 cfile.add_function (cfunc);
5218 return load_temp_value (result);
5221 public virtual CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
5222 assert_not_reached ();
5225 public virtual CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
5226 assert_not_reached ();
5229 public override void visit_cast_expression (CastExpression expr) {
5230 generate_type_declaration (expr.type_reference, cfile);
5232 if (!expr.is_non_null_cast) {
5233 var valuecast = try_cast_value_to_type (get_cvalue (expr.inner), expr.inner.value_type, expr.type_reference, expr);
5234 if (valuecast != null) {
5235 set_cvalue (expr, valuecast);
5236 return;
5239 var variantcast = try_cast_variant_to_type (expr.inner.target_value, expr.type_reference, expr);
5240 if (variantcast != null) {
5241 expr.target_value = variantcast;
5242 return;
5246 var cl = expr.type_reference.data_type as Class;
5247 var iface = expr.type_reference.data_type as Interface;
5248 if (context.profile == Profile.GOBJECT && (iface != null || (cl != null && !cl.is_compact))) {
5249 // checked cast for strict subtypes of GTypeInstance
5250 if (expr.is_silent_cast) {
5251 TargetValue to_cast = expr.inner.target_value;
5252 CCodeExpression cexpr;
5253 if (!get_lvalue (to_cast)) {
5254 to_cast = store_temp_value (to_cast, expr);
5256 cexpr = get_cvalue_ (to_cast);
5257 var ccheck = create_type_check (cexpr, expr.type_reference);
5258 var ccast = new CCodeCastExpression (cexpr, get_ccode_name (expr.type_reference));
5259 var cnull = new CCodeConstant ("NULL");
5260 var cast_value = new GLibValue (expr.value_type, new CCodeConditionalExpression (ccheck, ccast, cnull));
5261 if (requires_destroy (expr.inner.value_type)) {
5262 var casted = store_temp_value (cast_value, expr);
5263 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_cvalue_ (casted), new CCodeConstant ("NULL")));
5264 ccode.add_expression (destroy_value (to_cast));
5265 ccode.close ();
5266 expr.target_value = ((GLibValue) casted).copy ();
5267 } else {
5268 expr.target_value = cast_value;
5270 } else {
5271 set_cvalue (expr, generate_instance_cast (get_cvalue (expr.inner), expr.type_reference.data_type));
5273 } else {
5274 if (expr.is_silent_cast) {
5275 set_cvalue (expr, new CCodeInvalidExpression ());
5276 expr.error = true;
5277 Report.error (expr.source_reference, "Operation not supported for this type");
5278 return;
5281 // recompute array length when casting to other array type
5282 var array_type = expr.type_reference as ArrayType;
5283 if (array_type != null && expr.inner.value_type is ArrayType) {
5284 if (array_type.element_type is GenericType || ((ArrayType) expr.inner.value_type).element_type is GenericType) {
5285 // element size unknown for generic arrays, retain array length as is
5286 for (int dim = 1; dim <= array_type.rank; dim++) {
5287 append_array_length (expr, get_array_length_cexpression (expr.inner, dim));
5289 } else {
5290 var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5291 sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5293 var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5294 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (((ArrayType) expr.inner.value_type).element_type)));
5296 for (int dim = 1; dim <= array_type.rank; dim++) {
5297 append_array_length (expr, new CCodeBinaryExpression (CCodeBinaryOperator.DIV, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_array_length_cexpression (expr.inner, dim), sizeof_from), sizeof_to));
5300 } else if (array_type != null) {
5301 CCodeExpression array_length_expr;
5303 var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5304 sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5305 var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5307 var value_type = expr.inner.value_type;
5308 if (value_type is ValueType) {
5309 var data_type = ((ValueType) value_type).data_type;
5310 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (data_type)));
5311 array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5312 } else if (value_type is PointerType && ((PointerType) value_type).base_type is ValueType) {
5313 var data_type = ((ValueType) (((PointerType) value_type).base_type)).data_type;
5314 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (data_type)));
5315 array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5316 } else {
5317 // cast from unsupported non-array to array, set invalid length
5318 // required by string.data, e.g.
5319 array_length_expr = new CCodeConstant ("-1");
5322 for (int dim = 1; dim <= array_type.rank; dim++) {
5323 append_array_length (expr, array_length_expr);
5327 var innercexpr = get_cvalue (expr.inner);
5328 if (expr.type_reference is ValueType && !expr.type_reference.nullable &&
5329 expr.inner.value_type is ValueType && expr.inner.value_type.nullable) {
5330 // nullable integer or float or boolean or struct or enum cast to non-nullable
5331 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, innercexpr);
5332 } else if (expr.type_reference is ArrayType
5333 && expr.inner.value_type is ValueType && !expr.inner.value_type.nullable) {
5334 // integer or float or boolean or struct or enum to array cast
5335 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, innercexpr);
5337 set_cvalue (expr, new CCodeCastExpression (innercexpr, get_ccode_name (expr.type_reference)));
5339 if (expr.type_reference is DelegateType) {
5340 if (get_delegate_target (expr.inner) != null) {
5341 set_delegate_target (expr, get_delegate_target (expr.inner));
5342 } else {
5343 set_delegate_target (expr, new CCodeConstant ("NULL"));
5345 if (get_delegate_target_destroy_notify (expr.inner) != null) {
5346 set_delegate_target_destroy_notify (expr, get_delegate_target_destroy_notify (expr.inner));
5347 } else {
5348 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
5354 public override void visit_named_argument (NamedArgument expr) {
5355 set_cvalue (expr, get_cvalue (expr.inner));
5358 public override void visit_pointer_indirection (PointerIndirection expr) {
5359 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cvalue (expr.inner)));
5360 ((GLibValue) expr.target_value).lvalue = get_lvalue (expr.inner.target_value);
5363 public override void visit_addressof_expression (AddressofExpression expr) {
5364 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5367 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
5368 /* tmp = expr.inner; expr.inner = NULL; expr = tmp; */
5369 expr.target_value = store_temp_value (expr.inner.target_value, expr);
5371 if (expr.inner.value_type is StructValueType && !expr.inner.value_type.nullable) {
5372 // memset needs string.h
5373 cfile.add_include ("string.h");
5374 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
5375 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5376 creation_call.add_argument (new CCodeConstant ("0"));
5377 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.inner.value_type))));
5378 ccode.add_expression (creation_call);
5379 } else if (expr.value_type is DelegateType) {
5380 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5381 var target = get_delegate_target_cvalue (expr.inner.target_value);
5382 if (target != null) {
5383 ccode.add_assignment (target, new CCodeConstant ("NULL"));
5385 var target_destroy_notify = get_delegate_target_destroy_notify_cvalue (expr.inner.target_value);
5386 if (target_destroy_notify != null) {
5387 ccode.add_assignment (target_destroy_notify, new CCodeConstant ("NULL"));
5389 } else if (expr.inner.value_type is ArrayType) {
5390 var array_type = (ArrayType) expr.inner.value_type;
5391 var glib_value = (GLibValue) expr.inner.target_value;
5393 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5394 if (glib_value.array_length_cvalues != null) {
5395 for (int dim = 1; dim <= array_type.rank; dim++) {
5396 ccode.add_assignment (get_array_length_cvalue (glib_value, dim), new CCodeConstant ("0"));
5399 } else {
5400 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5404 public override void visit_binary_expression (BinaryExpression expr) {
5405 var cleft = get_cvalue (expr.left);
5406 var cright = get_cvalue (expr.right);
5408 CCodeExpression? left_chain = null;
5409 if (expr.is_chained) {
5410 var lbe = (BinaryExpression) expr.left;
5412 var temp_decl = get_temp_variable (lbe.right.target_type, true, null, false);
5413 emit_temp_var (temp_decl);
5414 var cvar = get_variable_cexpression (temp_decl.name);
5415 var clbe = (CCodeBinaryExpression) get_cvalue (lbe);
5416 if (lbe.is_chained) {
5417 clbe = (CCodeBinaryExpression) clbe.right;
5419 ccode.add_assignment (cvar, get_cvalue (lbe.right));
5420 clbe.right = get_variable_cexpression (temp_decl.name);
5421 left_chain = cleft;
5422 cleft = cvar;
5425 CCodeBinaryOperator op;
5426 if (expr.operator == BinaryOperator.PLUS) {
5427 op = CCodeBinaryOperator.PLUS;
5428 } else if (expr.operator == BinaryOperator.MINUS) {
5429 op = CCodeBinaryOperator.MINUS;
5430 } else if (expr.operator == BinaryOperator.MUL) {
5431 op = CCodeBinaryOperator.MUL;
5432 } else if (expr.operator == BinaryOperator.DIV) {
5433 op = CCodeBinaryOperator.DIV;
5434 } else if (expr.operator == BinaryOperator.MOD) {
5435 if (expr.value_type.equals (double_type)) {
5436 cfile.add_include ("math.h");
5437 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
5438 ccall.add_argument (cleft);
5439 ccall.add_argument (cright);
5440 set_cvalue (expr, ccall);
5441 return;
5442 } else if (expr.value_type.equals (float_type)) {
5443 cfile.add_include ("math.h");
5444 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
5445 ccall.add_argument (cleft);
5446 ccall.add_argument (cright);
5447 set_cvalue (expr, ccall);
5448 return;
5449 } else {
5450 op = CCodeBinaryOperator.MOD;
5452 } else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
5453 op = CCodeBinaryOperator.SHIFT_LEFT;
5454 } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
5455 op = CCodeBinaryOperator.SHIFT_RIGHT;
5456 } else if (expr.operator == BinaryOperator.LESS_THAN) {
5457 op = CCodeBinaryOperator.LESS_THAN;
5458 } else if (expr.operator == BinaryOperator.GREATER_THAN) {
5459 op = CCodeBinaryOperator.GREATER_THAN;
5460 } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
5461 op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
5462 } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
5463 op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
5464 } else if (expr.operator == BinaryOperator.EQUALITY) {
5465 op = CCodeBinaryOperator.EQUALITY;
5466 } else if (expr.operator == BinaryOperator.INEQUALITY) {
5467 op = CCodeBinaryOperator.INEQUALITY;
5468 } else if (expr.operator == BinaryOperator.BITWISE_AND) {
5469 op = CCodeBinaryOperator.BITWISE_AND;
5470 } else if (expr.operator == BinaryOperator.BITWISE_OR) {
5471 op = CCodeBinaryOperator.BITWISE_OR;
5472 } else if (expr.operator == BinaryOperator.BITWISE_XOR) {
5473 op = CCodeBinaryOperator.BITWISE_XOR;
5474 } else if (expr.operator == BinaryOperator.AND) {
5475 op = CCodeBinaryOperator.AND;
5476 } else if (expr.operator == BinaryOperator.OR) {
5477 op = CCodeBinaryOperator.OR;
5478 } else if (expr.operator == BinaryOperator.IN) {
5479 if (expr.right.value_type is ArrayType) {
5480 var array_type = (ArrayType) expr.right.value_type;
5481 var node = new CCodeFunctionCall (new CCodeIdentifier (generate_array_contains_wrapper (array_type)));
5482 node.add_argument (cright);
5483 node.add_argument (get_array_length_cexpression (expr.right));
5484 if (array_type.element_type is StructValueType) {
5485 node.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft));
5486 } else {
5487 node.add_argument (cleft);
5489 set_cvalue (expr, node);
5490 } else {
5491 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft));
5493 return;
5494 } else {
5495 assert_not_reached ();
5498 if (expr.operator == BinaryOperator.EQUALITY ||
5499 expr.operator == BinaryOperator.INEQUALITY) {
5500 var left_type = expr.left.target_type;
5501 var right_type = expr.right.target_type;
5502 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
5504 if (left_type is StructValueType && right_type is StructValueType) {
5505 var equalfunc = generate_struct_equal_function ((Struct) left_type.data_type);
5506 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5507 ccall.add_argument (cleft);
5508 ccall.add_argument (cright);
5509 cleft = ccall;
5510 cright = new CCodeConstant ("TRUE");
5511 } else if ((left_type is IntegerType || left_type is FloatingType || left_type is BooleanType || left_type is EnumValueType) && left_type.nullable &&
5512 (right_type is IntegerType || right_type is FloatingType || right_type is BooleanType || right_type is EnumValueType) && right_type.nullable) {
5513 var equalfunc = generate_numeric_equal_function ((TypeSymbol) left_type.data_type);
5514 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5515 ccall.add_argument (cleft);
5516 ccall.add_argument (cright);
5517 cleft = ccall;
5518 cright = new CCodeConstant ("TRUE");
5522 if (!(expr.left.value_type is NullType)
5523 && expr.left.value_type.compatible (string_type)
5524 && !(expr.right.value_type is NullType)
5525 && expr.right.value_type.compatible (string_type)) {
5526 if (expr.operator == BinaryOperator.PLUS) {
5527 // string concatenation
5528 if (expr.left.is_constant () && expr.right.is_constant ()) {
5529 string left, right;
5531 if (cleft is CCodeIdentifier) {
5532 left = ((CCodeIdentifier) cleft).name;
5533 } else if (cleft is CCodeConstant) {
5534 left = ((CCodeConstant) cleft).name;
5535 } else {
5536 assert_not_reached ();
5538 if (cright is CCodeIdentifier) {
5539 right = ((CCodeIdentifier) cright).name;
5540 } else if (cright is CCodeConstant) {
5541 right = ((CCodeConstant) cright).name;
5542 } else {
5543 assert_not_reached ();
5546 set_cvalue (expr, new CCodeConstant ("%s %s".printf (left, right)));
5547 return;
5548 } else {
5549 var temp_value = create_temp_value (expr.value_type, false, expr);
5550 CCodeFunctionCall ccall;
5552 if (context.profile == Profile.POSIX) {
5553 // convert to strcat (strcpy (malloc (1 + strlen (a) + strlen (b)), a), b)
5554 ccall = new CCodeFunctionCall (new CCodeIdentifier ("strcat"));
5555 var strcpy = new CCodeFunctionCall (new CCodeIdentifier ("strcpy"));
5556 var malloc = new CCodeFunctionCall (new CCodeIdentifier ("malloc"));
5558 var strlen_a = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
5559 strlen_a.add_argument (cleft);
5560 var strlen_b = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
5561 strlen_b.add_argument (cright);
5562 var newlength = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("1"),
5563 new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, strlen_a, strlen_b));
5564 malloc.add_argument (newlength);
5566 strcpy.add_argument (malloc);
5567 strcpy.add_argument (cleft);
5569 ccall.add_argument (strcpy);
5570 ccall.add_argument (cright);
5571 } else {
5572 // convert to g_strconcat (a, b, NULL)
5573 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
5574 ccall.add_argument (cleft);
5575 ccall.add_argument (cright);
5576 ccall.add_argument (new CCodeConstant("NULL"));
5579 ccode.add_assignment (get_cvalue_ (temp_value), ccall);
5580 expr.target_value = temp_value;
5581 return;
5583 } else if (expr.operator == BinaryOperator.EQUALITY
5584 || expr.operator == BinaryOperator.INEQUALITY
5585 || expr.operator == BinaryOperator.LESS_THAN
5586 || expr.operator == BinaryOperator.GREATER_THAN
5587 || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL
5588 || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
5589 CCodeFunctionCall ccall;
5590 if (context.profile == Profile.POSIX) {
5591 ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
5592 } else {
5593 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5595 ccall.add_argument (cleft);
5596 ccall.add_argument (cright);
5597 cleft = ccall;
5598 cright = new CCodeConstant ("0");
5602 set_cvalue (expr, new CCodeBinaryExpression (op, cleft, cright));
5603 if (left_chain != null) {
5604 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.AND, left_chain, get_cvalue (expr)));
5608 CCodeExpression? create_type_check (CCodeNode ccodenode, DataType type) {
5609 var et = type as ErrorType;
5610 if (et != null && et.error_code != null) {
5611 var matches_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
5612 matches_call.add_argument ((CCodeExpression) ccodenode);
5613 matches_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain)));
5614 matches_call.add_argument (new CCodeIdentifier (get_ccode_name (et.error_code)));
5615 return matches_call;
5616 } else if (et != null && et.error_domain != null) {
5617 var instance_domain = new CCodeMemberAccess.pointer ((CCodeExpression) ccodenode, "domain");
5618 var type_domain = new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain));
5619 return new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, instance_domain, type_domain);
5620 } else {
5621 var type_id = get_type_id_expression (type);
5622 if (type_id == null) {
5623 return new CCodeInvalidExpression ();
5625 var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
5626 ccheck.add_argument ((CCodeExpression) ccodenode);
5627 ccheck.add_argument (type_id);
5628 return ccheck;
5632 string generate_array_contains_wrapper (ArrayType array_type) {
5633 string array_contains_func = "_vala_%s_array_contains".printf (get_ccode_lower_case_name (array_type.element_type));
5635 if (!add_wrapper (array_contains_func)) {
5636 return array_contains_func;
5639 var function = new CCodeFunction (array_contains_func, "gboolean");
5640 function.modifiers = CCodeModifiers.STATIC;
5642 function.add_parameter (new CCodeParameter ("stack", "%s *".printf (get_ccode_name (array_type.element_type))));
5643 function.add_parameter (new CCodeParameter ("stack_length", "int"));
5644 if (array_type.element_type is StructValueType) {
5645 function.add_parameter (new CCodeParameter ("needle", "%s *".printf (get_ccode_name (array_type.element_type))));
5646 } else {
5647 function.add_parameter (new CCodeParameter ("needle", get_ccode_name (array_type.element_type)));
5650 push_function (function);
5652 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
5654 var cloop_initializer = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
5655 var cloop_condition = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("stack_length"));
5656 var cloop_iterator = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"));
5657 ccode.open_for (cloop_initializer, cloop_condition, cloop_iterator);
5659 var celement = new CCodeElementAccess (new CCodeIdentifier ("stack"), new CCodeIdentifier ("i"));
5660 var cneedle = new CCodeIdentifier ("needle");
5661 CCodeBinaryExpression cif_condition;
5662 if (array_type.element_type.compatible (string_type)) {
5663 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5664 ccall.add_argument (celement);
5665 ccall.add_argument (cneedle);
5666 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("0"));
5667 } else if (array_type.element_type is StructValueType) {
5668 var equalfunc = generate_struct_equal_function ((Struct) array_type.element_type.data_type);
5669 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5670 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, celement));
5671 ccall.add_argument (cneedle);
5672 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("TRUE"));
5673 } else {
5674 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cneedle, celement);
5677 ccode.open_if (cif_condition);
5678 ccode.add_return (new CCodeConstant ("TRUE"));
5679 ccode.close ();
5681 ccode.close ();
5683 ccode.add_return (new CCodeConstant ("FALSE"));
5685 pop_function ();
5687 cfile.add_function_declaration (function);
5688 cfile.add_function (function);
5690 return array_contains_func;
5693 string generate_cmp_wrapper (CCodeIdentifier cmpid) {
5694 // generate and call NULL-aware cmp function to reduce number
5695 // of temporary variables and simplify code
5697 string cmp0_func = "_%s0".printf (cmpid.name);
5699 // g_strcmp0 is already NULL-safe
5700 if (cmpid.name == "g_strcmp0") {
5701 cmp0_func = cmpid.name;
5702 } else if (add_wrapper (cmp0_func)) {
5703 var cmp0_fun = new CCodeFunction (cmp0_func, "int");
5704 cmp0_fun.add_parameter (new CCodeParameter ("s1", "const void *"));
5705 cmp0_fun.add_parameter (new CCodeParameter ("s2", "const void *"));
5706 cmp0_fun.modifiers = CCodeModifiers.STATIC;
5708 push_function (cmp0_fun);
5710 // s1 != s2;
5711 var noteq = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
5713 // if (!s1) return -(s1 != s2);
5715 var cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("s1"));
5716 ccode.open_if (cexp);
5717 ccode.add_return (new CCodeUnaryExpression (CCodeUnaryOperator.MINUS, noteq));
5718 ccode.close ();
5720 // if (!s2) return s1 != s2;
5722 var cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("s2"));
5723 ccode.open_if (cexp);
5724 ccode.add_return (noteq);
5725 ccode.close ();
5727 // return strcmp (s1, s2);
5728 var cmp_call = new CCodeFunctionCall (cmpid);
5729 cmp_call.add_argument (new CCodeIdentifier ("s1"));
5730 cmp_call.add_argument (new CCodeIdentifier ("s2"));
5731 ccode.add_return (cmp_call);
5733 pop_function ();
5735 cfile.add_function (cmp0_fun);
5738 return cmp0_func;
5741 public override void visit_type_check (TypeCheck expr) {
5742 generate_type_declaration (expr.type_reference, cfile);
5744 var type = expr.expression.value_type;
5745 var pointer_type = type as PointerType;
5746 if (pointer_type != null) {
5747 type = pointer_type.base_type;
5749 var cl = type.data_type as Class;
5750 var iface = type.data_type as Interface;
5751 if ((cl != null && !cl.is_compact) || iface != null || type is GenericType || type is ErrorType) {
5752 set_cvalue (expr, create_type_check (get_cvalue (expr.expression), expr.type_reference));
5753 } else {
5754 set_cvalue (expr, new CCodeInvalidExpression ());
5757 if (get_cvalue (expr) is CCodeInvalidExpression) {
5758 Report.error (expr.source_reference, "type check expressions not supported for compact classes, structs, and enums");
5762 public override void visit_lambda_expression (LambdaExpression lambda) {
5763 var delegate_type = (DelegateType) lambda.target_type;
5764 var d = delegate_type.delegate_symbol;
5766 lambda.method.set_attribute_bool ("CCode", "array_length", get_ccode_array_length (d));
5767 lambda.method.set_attribute_bool ("CCode", "array_null_terminated", get_ccode_array_null_terminated (d));
5768 lambda.method.set_attribute_string ("CCode", "array_length_type", get_ccode_array_length_type (d));
5770 lambda.accept_children (this);
5772 bool expr_owned = lambda.value_type.value_owned;
5774 set_cvalue (lambda, new CCodeIdentifier (get_ccode_name (lambda.method)));
5776 if (lambda.method.closure) {
5777 int block_id = get_block_id (current_closure_block);
5778 var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
5779 if (expr_owned || delegate_type.is_called_once) {
5780 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
5781 ref_call.add_argument (delegate_target);
5782 delegate_target = ref_call;
5783 set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
5784 } else {
5785 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5787 set_delegate_target (lambda, delegate_target);
5788 } else if (get_this_type () != null) {
5789 CCodeExpression delegate_target = get_result_cexpression ("self");
5790 delegate_target = convert_to_generic_pointer (delegate_target, get_this_type ());
5791 if (expr_owned || delegate_type.is_called_once) {
5792 var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_this_type (), lambda.source_reference));
5793 ref_call.add_argument (delegate_target);
5794 delegate_target = ref_call;
5795 set_delegate_target_destroy_notify (lambda, get_destroy_func_expression (get_this_type ()));
5796 } else {
5797 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5799 set_delegate_target (lambda, delegate_target);
5800 } else {
5801 set_delegate_target (lambda, new CCodeConstant ("NULL"));
5802 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5806 public CCodeExpression convert_from_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
5807 var result = cexpr;
5808 if (is_reference_type_argument (actual_type) || is_nullable_value_type_argument (actual_type)) {
5809 result = new CCodeCastExpression (cexpr, get_ccode_name (actual_type));
5810 } else if (is_signed_integer_type_argument (actual_type)) {
5811 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), get_ccode_name (actual_type));
5812 } else if (is_unsigned_integer_type_argument (actual_type)) {
5813 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), get_ccode_name (actual_type));
5815 return result;
5818 public CCodeExpression convert_to_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
5819 var result = cexpr;
5820 if (is_signed_integer_type_argument (actual_type)) {
5821 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), "gpointer");
5822 } else if (is_unsigned_integer_type_argument (actual_type)) {
5823 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), "gpointer");
5825 return result;
5828 public TargetValue transform_value (TargetValue value, DataType? target_type, CodeNode node) {
5829 var type = value.value_type;
5830 var result = ((GLibValue) value).copy ();
5832 if (type.value_owned
5833 && target_type is ObjectType && !target_type.floating_reference
5834 && type.floating_reference) {
5835 /* floating reference, sink it.
5837 var cl = type.data_type as ObjectTypeSymbol;
5838 var sink_func = (cl != null) ? get_ccode_ref_sink_function (cl) : "";
5840 if (sink_func != "") {
5841 if (type.nullable) {
5842 var is_not_null = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, result.cvalue, new CCodeIdentifier ("NULL"));
5843 ccode.open_if (is_not_null);
5846 var csink = new CCodeFunctionCall (new CCodeIdentifier (sink_func));
5847 csink.add_argument (result.cvalue);
5848 ccode.add_expression (csink);
5850 if (type.nullable) {
5851 ccode.close ();
5853 } else {
5854 Report.error (null, "type `%s' does not support floating references".printf (type.data_type.name));
5858 bool boxing = (type is ValueType && !type.nullable
5859 && target_type is ValueType && target_type.nullable);
5860 bool unboxing = (type is ValueType && type.nullable
5861 && target_type is ValueType && !target_type.nullable);
5863 bool gvalue_boxing = (context.profile == Profile.GOBJECT
5864 && target_type != null
5865 && target_type.data_type == gvalue_type
5866 && !(type is NullType)
5867 && get_ccode_type_id (type) != "G_TYPE_VALUE");
5868 bool gvariant_boxing = (context.profile == Profile.GOBJECT
5869 && target_type != null
5870 && target_type.data_type == gvariant_type
5871 && !(type is NullType)
5872 && type.data_type != gvariant_type);
5874 if (type.value_owned
5875 && (target_type == null || !target_type.value_owned || boxing || unboxing || gvariant_boxing)
5876 && !gvalue_boxing /* gvalue can assume ownership of value, no need to free it */) {
5877 // value leaked, destroy it
5878 if (target_type is PointerType) {
5879 // manual memory management for pointers
5880 } else if (requires_destroy (type)) {
5881 if (!is_lvalue_access_allowed (type)) {
5882 // cannot assign to a temporary variable
5883 temp_ref_values.insert (0, result.copy ());
5884 } else {
5885 var temp_value = create_temp_value (type, false, node);
5886 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5887 store_value (temp_value, result, node.source_reference);
5888 result.cvalue = get_cvalue_ (temp_value);
5893 if (target_type == null) {
5894 // value will be destroyed, no need for implicit casts
5895 return result;
5898 result.value_type = target_type.copy ();
5900 if (gvalue_boxing) {
5901 // implicit conversion to GValue
5902 var temp_value = create_temp_value (target_type, true, node, true);
5904 if (!target_type.value_owned) {
5905 // boxed GValue leaked, destroy it
5906 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5909 if (target_type.nullable) {
5910 var newcall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
5911 newcall.add_argument (new CCodeConstant ("GValue"));
5912 newcall.add_argument (new CCodeConstant ("1"));
5913 var newassignment = new CCodeAssignment (get_cvalue_ (temp_value), newcall);
5914 ccode.add_expression (newassignment);
5917 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
5918 if (target_type.nullable) {
5919 ccall.add_argument (get_cvalue_ (temp_value));
5920 } else {
5921 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
5923 var type_id = get_ccode_type_id (type);
5924 if (type_id == "") {
5925 Report.error (node.source_reference, "GValue boxing of type `%s' is not supported".printf (type.to_string ()));
5927 ccall.add_argument (new CCodeIdentifier (type_id));
5928 ccode.add_expression (ccall);
5930 if (requires_destroy (type)) {
5931 ccall = new CCodeFunctionCall (get_value_taker_function (type));
5932 } else {
5933 ccall = new CCodeFunctionCall (get_value_setter_function (type));
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 if (type.is_real_non_null_struct_type ()) {
5941 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue));
5942 } else {
5943 ccall.add_argument (result.cvalue);
5946 ccode.add_expression (ccall);
5948 result = (GLibValue) temp_value;
5949 } else if (gvariant_boxing) {
5950 // implicit conversion to GVariant
5951 string variant_func = "_variant_new%d".printf (++next_variant_function_id);
5953 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
5954 ccall.add_argument (result.cvalue);
5956 var cfunc = new CCodeFunction (variant_func, "GVariant*");
5957 cfunc.modifiers = CCodeModifiers.STATIC;
5958 cfunc.add_parameter (new CCodeParameter ("value", get_ccode_name (type)));
5960 if (type is ArrayType) {
5961 // return array length if appropriate
5962 var array_type = (ArrayType) type;
5964 for (int dim = 1; dim <= array_type.rank; dim++) {
5965 ccall.add_argument (get_array_length_cvalue (value, dim));
5966 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), "gint"));
5970 push_function (cfunc);
5972 // sink floating reference
5973 var sink = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_ref_sink"));
5974 sink.add_argument (serialize_expression (type, new CCodeIdentifier ("value")));
5975 ccode.add_return (sink);
5977 pop_function ();
5979 cfile.add_function_declaration (cfunc);
5980 cfile.add_function (cfunc);
5982 result.cvalue = ccall;
5983 result.value_type.value_owned = true;
5985 result = (GLibValue) store_temp_value (result, node);
5986 if (!target_type.value_owned) {
5987 // value leaked
5988 temp_ref_values.insert (0, ((GLibValue) result).copy ());
5990 } else if (boxing) {
5991 // value needs to be boxed
5993 result.value_type.nullable = false;
5994 if (!result.lvalue || !result.value_type.equals (value.value_type)) {
5995 result.cvalue = get_implicit_cast_expression (result.cvalue, value.value_type, result.value_type, node);
5996 result = (GLibValue) store_temp_value (result, node);
5998 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue);
5999 result.lvalue = false;
6000 result.value_type.nullable = true;
6001 } else if (unboxing) {
6002 // unbox value
6004 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result.cvalue);
6005 } else {
6006 // TODO: rewrite get_implicit_cast_expression to return a GLibValue
6007 var old_cexpr = result.cvalue;
6008 result.cvalue = get_implicit_cast_expression (result.cvalue, type, target_type, node);
6009 result.lvalue = result.lvalue && result.cvalue == old_cexpr;
6012 bool array_needs_copy = false;
6013 if (type is ArrayType && target_type is ArrayType) {
6014 var array = (ArrayType) type;
6015 var target_array = (ArrayType) target_type;
6016 if (target_array.element_type.value_owned && !array.element_type.value_owned) {
6017 array_needs_copy = requires_copy (target_array.element_type);
6021 if (!gvalue_boxing && !gvariant_boxing && target_type.value_owned && (!type.value_owned || boxing || unboxing || array_needs_copy) && requires_copy (target_type) && !(type is NullType)) {
6022 // need to copy value
6023 var copy = (GLibValue) copy_value (result, node);
6024 if (target_type.data_type is Interface && copy == null) {
6025 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 ()));
6026 return result;
6028 result = copy;
6030 // implicit array copying is deprecated, but allow it for internal codegen usage
6031 var prop_acc = node as PropertyAccessor;
6032 if ((prop_acc != null && !prop_acc.automatic_body)
6033 && result.value_type is ArrayType) {
6034 Report.deprecated (node.source_reference, "implicit copy of array is deprecated, explicitly invoke the copy method instead");
6038 return result;
6041 public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, CodeNode? node) {
6042 var cexpr = source_cexpr;
6044 if (expression_type.data_type != null && expression_type.data_type == target_type.data_type) {
6045 // same type, no cast required
6046 return cexpr;
6049 if (expression_type is NullType) {
6050 // null literal, no cast required when not converting to generic type pointer
6051 return cexpr;
6054 generate_type_declaration (target_type, cfile);
6056 var cl = target_type.data_type as Class;
6057 var iface = target_type.data_type as Interface;
6058 if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
6059 // checked cast for strict subtypes of GTypeInstance
6060 return generate_instance_cast (cexpr, target_type.data_type);
6061 } else if (target_type.data_type != null && get_ccode_name (expression_type) != get_ccode_name (target_type)) {
6062 var st = target_type.data_type as Struct;
6063 if (target_type.data_type.is_reference_type () || (st != null && st.is_simple_type ())) {
6064 // don't cast non-simple structs
6065 return new CCodeCastExpression (cexpr, get_ccode_name (target_type));
6066 } else {
6067 return cexpr;
6069 } else {
6070 return cexpr;
6074 public void store_property (Property prop, Expression? instance, TargetValue value) {
6075 if (instance is BaseAccess) {
6076 if (prop.base_property != null) {
6077 var base_class = (Class) prop.base_property.parent_symbol;
6078 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class, null))));
6079 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class, null))));
6081 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
6082 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
6083 var cexpr = get_cvalue_ (value);
6084 if (prop.property_type.is_real_non_null_struct_type ()) {
6085 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6087 ccall.add_argument (cexpr);
6089 ccode.add_expression (ccall);
6090 } else if (prop.base_interface_property != null) {
6091 var base_iface = (Interface) prop.base_interface_property.parent_symbol;
6092 string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface));
6094 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "set_%s".printf (prop.name)));
6095 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
6096 var cexpr = get_cvalue_ (value);
6097 if (prop.property_type.is_real_non_null_struct_type ()) {
6098 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6100 ccall.add_argument (cexpr);
6102 ccode.add_expression (ccall);
6104 return;
6107 var set_func = "g_object_set";
6109 var base_property = prop;
6110 if (!get_ccode_no_accessor_method (prop)) {
6111 if (prop.base_property != null) {
6112 base_property = prop.base_property;
6113 } else if (prop.base_interface_property != null) {
6114 base_property = prop.base_interface_property;
6117 if (prop is DynamicProperty) {
6118 set_func = get_dynamic_property_setter_cname ((DynamicProperty) prop);
6119 } else {
6120 generate_property_accessor_declaration (base_property.set_accessor, cfile);
6121 set_func = get_ccode_name (base_property.set_accessor);
6123 if (!prop.external && prop.external_package) {
6124 // internal VAPI properties
6125 // only add them once per source file
6126 if (add_generated_external_symbol (prop)) {
6127 visit_property (prop);
6133 var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
6135 if (prop.binding == MemberBinding.INSTANCE) {
6136 /* target instance is first argument */
6137 var cinstance = (CCodeExpression) get_ccodenode (instance);
6139 if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
6140 // we need to pass struct instance by reference if it isn't a simple-type
6141 var instance_value = instance.target_value;
6142 if (!get_lvalue (instance_value)) {
6143 instance_value = store_temp_value (instance_value, instance);
6145 cinstance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
6148 ccall.add_argument (cinstance);
6151 if (get_ccode_no_accessor_method (prop)) {
6152 /* property name is second argument of g_object_set */
6153 ccall.add_argument (get_property_canonical_cconstant (prop));
6156 var cexpr = get_cvalue_ (value);
6158 if (prop.property_type.is_real_non_null_struct_type ()) {
6159 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6162 var array_type = prop.property_type as ArrayType;
6164 ccall.add_argument (cexpr);
6166 if (array_type != null && get_ccode_array_length (prop)) {
6167 for (int dim = 1; dim <= array_type.rank; dim++) {
6168 ccall.add_argument (get_array_length_cvalue (value, dim));
6170 } else if (prop.property_type is DelegateType) {
6171 var delegate_type = (DelegateType) prop.property_type;
6172 if (delegate_type.delegate_symbol.has_target) {
6173 ccall.add_argument (get_delegate_target_cvalue (value));
6174 if (base_property.set_accessor.value_type.value_owned) {
6175 ccall.add_argument (get_delegate_target_destroy_notify_cvalue (value));
6180 if (get_ccode_no_accessor_method (prop)) {
6181 ccall.add_argument (new CCodeConstant ("NULL"));
6184 ccode.add_expression (ccall);
6187 public bool add_wrapper (string wrapper_name) {
6188 return wrappers.add (wrapper_name);
6191 public bool add_generated_external_symbol (Symbol external_symbol) {
6192 return generated_external_symbols.add (external_symbol);
6195 public static DataType get_data_type_for_symbol (TypeSymbol sym) {
6196 DataType type = null;
6198 if (sym is Class) {
6199 type = new ObjectType ((Class) sym);
6200 } else if (sym is Interface) {
6201 type = new ObjectType ((Interface) sym);
6202 } else if (sym is Struct) {
6203 var st = (Struct) sym;
6204 if (st.is_boolean_type ()) {
6205 type = new BooleanType (st);
6206 } else if (st.is_integer_type ()) {
6207 type = new IntegerType (st);
6208 } else if (st.is_floating_type ()) {
6209 type = new FloatingType (st);
6210 } else {
6211 type = new StructValueType (st);
6213 } else if (sym is Enum) {
6214 type = new EnumValueType ((Enum) sym);
6215 } else if (sym is ErrorDomain) {
6216 type = new ErrorType ((ErrorDomain) sym, null);
6217 } else if (sym is ErrorCode) {
6218 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
6219 } else {
6220 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
6221 return new InvalidType ();
6224 return type;
6227 public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) {
6228 var st = type.data_type as Struct;
6229 var array_type = type as ArrayType;
6230 if (type.data_type != null && !type.nullable && get_ccode_default_value (type.data_type) != "") {
6231 return new CCodeConstant (get_ccode_default_value (type.data_type));
6232 } else if (initializer_expression && !type.nullable &&
6233 (st != null || (array_type != null && array_type.fixed_length))) {
6234 // 0-initialize struct with struct initializer { 0 }
6235 // only allowed as initializer expression in C
6236 var clist = new CCodeInitializerList ();
6237 clist.append (new CCodeConstant ("0"));
6238 return clist;
6239 } else if ((type.data_type != null && type.data_type.is_reference_type ())
6240 || type.nullable
6241 || type is PointerType || type is DelegateType
6242 || (array_type != null && !array_type.fixed_length)) {
6243 return new CCodeConstant ("NULL");
6244 } else if (type is GenericType) {
6245 return new CCodeConstant ("NULL");
6246 } else if (type is ErrorType) {
6247 return new CCodeConstant ("NULL");
6249 return null;
6252 private void create_property_type_check_statement (Property prop, bool check_return_type, TypeSymbol t, bool non_null, string var_name) {
6253 if (check_return_type) {
6254 create_type_check_statement (prop, prop.property_type, t, non_null, var_name);
6255 } else {
6256 create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
6260 public virtual void create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
6263 public int get_param_pos (double param_pos, bool ellipsis = false) {
6264 if (!ellipsis) {
6265 if (param_pos >= 0) {
6266 return (int) (param_pos * 1000);
6267 } else {
6268 return (int) ((100 + param_pos) * 1000);
6270 } else {
6271 if (param_pos >= 0) {
6272 return (int) ((100 + param_pos) * 1000);
6273 } else {
6274 return (int) ((200 + param_pos) * 1000);
6279 public CCodeExpression? get_ccodenode (Expression node) {
6280 if (get_cvalue (node) == null) {
6281 node.emit (this);
6283 return get_cvalue (node);
6286 public bool is_lvalue_access_allowed (DataType type) {
6287 var array_type = type as ArrayType;
6288 if (array_type != null && array_type.inline_allocated) {
6289 return false;
6291 if (type.data_type != null) {
6292 return type.data_type.get_attribute_bool ("CCode", "lvalue_access", true);
6294 return true;
6297 public CCodeDeclaratorSuffix? get_ccode_declarator_suffix (DataType type) {
6298 var array_type = type as ArrayType;
6299 if (array_type != null) {
6300 if (array_type.fixed_length) {
6301 return new CCodeDeclaratorSuffix.with_array (get_ccodenode (array_type.length));
6302 } else if (array_type.inline_allocated) {
6303 return new CCodeDeclaratorSuffix.with_array ();
6306 return null;
6309 public CCodeConstant get_signal_canonical_constant (Signal sig, string? detail = null) {
6310 return new CCodeConstant ("\"%s%s\"".printf (get_ccode_name (sig), (detail != null ? "::%s".printf (detail) : "")));
6313 public bool get_signal_has_emitter (Signal sig) {
6314 return sig.get_attribute ("HasEmitter") != null;
6317 public CCodeConstant get_property_canonical_cconstant (Property prop) {
6318 return new CCodeConstant ("\"%s\"".printf (prop.name.replace ("_", "-")));
6321 public override void visit_class (Class cl) {
6324 public void create_postcondition_statement (Expression postcondition) {
6325 var cassert = new CCodeFunctionCall (new CCodeIdentifier ("_vala_warn_if_fail"));
6327 postcondition.emit (this);
6329 string message = ((string) postcondition.source_reference.begin.pos).substring (0, (int) (postcondition.source_reference.end.pos - postcondition.source_reference.begin.pos));
6330 cassert.add_argument (get_cvalue (postcondition));
6331 cassert.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
6332 requires_assert = true;
6334 ccode.add_expression (cassert);
6337 public virtual bool is_gobject_property (Property prop) {
6338 return false;
6341 public DataType? get_this_type () {
6342 if (current_method != null && current_method.binding == MemberBinding.INSTANCE) {
6343 return current_method.this_parameter.variable_type;
6344 } else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) {
6345 return current_property_accessor.prop.this_parameter.variable_type;
6346 } else if (current_constructor != null && current_constructor.binding == MemberBinding.INSTANCE) {
6347 return current_constructor.this_parameter.variable_type;
6348 } else if (current_destructor != null && current_destructor.binding == MemberBinding.INSTANCE) {
6349 return current_destructor.this_parameter.variable_type;
6351 return null;
6354 public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
6355 var result = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_CAST"));
6356 result.add_argument (expr);
6357 result.add_argument (new CCodeIdentifier (get_ccode_type_id (type)));
6358 result.add_argument (new CCodeIdentifier (get_ccode_name (type)));
6359 return result;
6362 void generate_struct_destroy_function (Struct st) {
6363 if (cfile.add_declaration (get_ccode_destroy_function (st))) {
6364 // only generate function once per source file
6365 return;
6368 var function = new CCodeFunction (get_ccode_destroy_function (st), "void");
6369 function.modifiers = CCodeModifiers.STATIC;
6370 function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (st))));
6372 push_context (new EmitContext ());
6373 push_function (function);
6375 var this_value = load_this_parameter (st);
6376 foreach (Field f in st.get_fields ()) {
6377 if (f.binding == MemberBinding.INSTANCE) {
6378 if (get_ccode_delegate_target (f) && requires_destroy (f.variable_type)) {
6379 ccode.add_expression (destroy_field (f, this_value));
6384 pop_function ();
6385 pop_context ();
6387 cfile.add_function_declaration (function);
6388 cfile.add_function (function);
6391 void generate_struct_copy_function (Struct st) {
6392 if (cfile.add_declaration (get_ccode_copy_function (st))) {
6393 // only generate function once per source file
6394 return;
6397 var function = new CCodeFunction (get_ccode_copy_function (st), "void");
6398 function.modifiers = CCodeModifiers.STATIC;
6399 function.add_parameter (new CCodeParameter ("self", "const %s *".printf (get_ccode_name (st))));
6400 function.add_parameter (new CCodeParameter ("dest", "%s *".printf (get_ccode_name (st))));
6402 push_context (new EmitContext ());
6403 push_function (function);
6405 var dest_struct = new GLibValue (get_data_type_for_symbol (st), new CCodeIdentifier ("(*dest)"), true);
6406 foreach (Field f in st.get_fields ()) {
6407 if (f.binding == MemberBinding.INSTANCE) {
6408 var value = load_field (f, load_this_parameter ((TypeSymbol) st));
6409 if (get_ccode_delegate_target (f) && requires_copy (f.variable_type)) {
6410 value = copy_value (value, f);
6411 if (value == null) {
6412 // error case, continue to avoid critical
6413 continue;
6416 store_field (f, dest_struct, value);
6420 pop_function ();
6421 pop_context ();
6423 cfile.add_function_declaration (function);
6424 cfile.add_function (function);
6427 public void return_default_value (DataType return_type) {
6428 var st = return_type.data_type as Struct;
6429 if (st != null && st.is_simple_type () && !return_type.nullable) {
6430 // 0-initialize struct with struct initializer { 0 }
6431 // only allowed as initializer expression in C
6432 var ret_temp_var = get_temp_variable (return_type, true, null, true);
6433 emit_temp_var (ret_temp_var);
6434 ccode.add_return (new CCodeIdentifier (ret_temp_var.name));
6435 } else {
6436 ccode.add_return (default_value_for_type (return_type, false));
6440 public virtual void generate_dynamic_method_wrapper (DynamicMethod method) {
6443 public virtual bool method_has_wrapper (Method method) {
6444 return false;
6447 public virtual CCodeExpression get_param_spec_cexpression (Property prop) {
6448 return new CCodeFunctionCall (new CCodeIdentifier (""));
6451 public virtual CCodeExpression get_param_spec (Property prop) {
6452 return new CCodeFunctionCall (new CCodeIdentifier (""));
6455 public virtual CCodeExpression get_signal_creation (Signal sig, TypeSymbol type) {
6456 return new CCodeFunctionCall (new CCodeIdentifier (""));
6459 public virtual void register_dbus_info (CCodeBlock block, ObjectTypeSymbol bindable) {
6462 public virtual string get_dynamic_property_getter_cname (DynamicProperty node) {
6463 Report.error (node.source_reference, "dynamic properties are not supported for %s".printf (node.dynamic_type.to_string ()));
6464 return "";
6467 public virtual string get_dynamic_property_setter_cname (DynamicProperty node) {
6468 Report.error (node.source_reference, "dynamic properties are not supported for %s".printf (node.dynamic_type.to_string ()));
6469 return "";
6472 public virtual string get_dynamic_signal_cname (DynamicSignal node) {
6473 return "";
6476 public virtual string get_dynamic_signal_connect_wrapper_name (DynamicSignal node) {
6477 return "";
6480 public virtual string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal node) {
6481 return "";
6484 public virtual string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node) {
6485 return "";
6488 public virtual string get_array_length_cname (string array_cname, int dim) {
6489 return "";
6492 public virtual string get_parameter_array_length_cname (Parameter param, int dim) {
6493 return "";
6496 public virtual CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
6497 return new CCodeConstant ("");
6500 public virtual CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
6501 return new CCodeInvalidExpression ();
6504 public virtual string get_array_size_cname (string array_cname) {
6505 return "";
6508 public virtual void add_simple_check (CodeNode node, bool always_fails = false) {
6511 public virtual string generate_ready_function (Method m) {
6512 return "";
6515 public CCodeExpression? get_cvalue (Expression expr) {
6516 if (expr.target_value == null) {
6517 return null;
6519 var glib_value = (GLibValue) expr.target_value;
6520 return glib_value.cvalue;
6523 public CCodeExpression? get_cvalue_ (TargetValue value) {
6524 var glib_value = (GLibValue) value;
6525 return glib_value.cvalue;
6528 public void set_cvalue (Expression expr, CCodeExpression? cvalue) {
6529 var glib_value = (GLibValue) expr.target_value;
6530 if (glib_value == null) {
6531 glib_value = new GLibValue (expr.value_type);
6532 expr.target_value = glib_value;
6534 glib_value.cvalue = cvalue;
6537 public CCodeExpression? get_array_size_cvalue (TargetValue value) {
6538 var glib_value = (GLibValue) value;
6539 return glib_value.array_size_cvalue;
6542 public void set_array_size_cvalue (TargetValue value, CCodeExpression? cvalue) {
6543 var glib_value = (GLibValue) value;
6544 glib_value.array_size_cvalue = cvalue;
6547 public CCodeExpression? get_delegate_target (Expression expr) {
6548 if (expr.target_value == null) {
6549 return null;
6551 var glib_value = (GLibValue) expr.target_value;
6552 return glib_value.delegate_target_cvalue;
6555 public void set_delegate_target (Expression expr, CCodeExpression? delegate_target) {
6556 var glib_value = (GLibValue) expr.target_value;
6557 if (glib_value == null) {
6558 glib_value = new GLibValue (expr.value_type);
6559 expr.target_value = glib_value;
6561 glib_value.delegate_target_cvalue = delegate_target;
6564 public CCodeExpression? get_delegate_target_destroy_notify (Expression expr) {
6565 if (expr.target_value == null) {
6566 return null;
6568 var glib_value = (GLibValue) expr.target_value;
6569 return glib_value.delegate_target_destroy_notify_cvalue;
6572 public void set_delegate_target_destroy_notify (Expression expr, CCodeExpression? destroy_notify) {
6573 var glib_value = (GLibValue) expr.target_value;
6574 if (glib_value == null) {
6575 glib_value = new GLibValue (expr.value_type);
6576 expr.target_value = glib_value;
6578 glib_value.delegate_target_destroy_notify_cvalue = destroy_notify;
6581 public void append_array_length (Expression expr, CCodeExpression size) {
6582 var glib_value = (GLibValue) expr.target_value;
6583 if (glib_value == null) {
6584 glib_value = new GLibValue (expr.value_type);
6585 expr.target_value = glib_value;
6587 glib_value.append_array_length_cvalue (size);
6590 public List<CCodeExpression>? get_array_lengths (Expression expr) {
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 return glib_value.array_length_cvalues;
6599 public bool get_lvalue (TargetValue value) {
6600 var glib_value = (GLibValue) value;
6601 return glib_value.lvalue;
6604 public bool get_non_null (TargetValue value) {
6605 var glib_value = (GLibValue) value;
6606 return glib_value.non_null;
6609 public string? get_ctype (TargetValue value) {
6610 var glib_value = (GLibValue) value;
6611 return glib_value.ctype;
6614 public bool get_array_null_terminated (TargetValue value) {
6615 var glib_value = (GLibValue) value;
6616 return glib_value.array_null_terminated;
6619 public CCodeExpression get_array_length_cexpr (TargetValue value) {
6620 var glib_value = (GLibValue) value;
6621 return glib_value.array_length_cexpr;
6625 internal class Vala.GLibValue : TargetValue {
6626 public CCodeExpression cvalue;
6627 public bool lvalue;
6628 public bool non_null;
6629 public string? ctype;
6631 public List<CCodeExpression> array_length_cvalues;
6632 public CCodeExpression? array_size_cvalue;
6633 public bool array_null_terminated;
6634 public CCodeExpression? array_length_cexpr;
6636 public CCodeExpression? delegate_target_cvalue;
6637 public CCodeExpression? delegate_target_destroy_notify_cvalue;
6639 public GLibValue (DataType? value_type = null, CCodeExpression? cvalue = null, bool lvalue = false) {
6640 base (value_type);
6641 this.cvalue = cvalue;
6642 this.lvalue = lvalue;
6645 public void append_array_length_cvalue (CCodeExpression length_cvalue) {
6646 if (array_length_cvalues == null) {
6647 array_length_cvalues = new ArrayList<CCodeExpression> ();
6649 array_length_cvalues.add (length_cvalue);
6652 public GLibValue copy () {
6653 var result = new GLibValue (value_type.copy (), cvalue, lvalue);
6654 result.actual_value_type = actual_value_type;
6655 result.non_null = non_null;
6656 result.ctype = ctype;
6658 if (array_length_cvalues != null) {
6659 foreach (var cexpr in array_length_cvalues) {
6660 result.append_array_length_cvalue (cexpr);
6663 result.array_size_cvalue = array_size_cvalue;
6664 result.array_null_terminated = array_null_terminated;
6665 result.array_length_cexpr = array_length_cexpr;
6667 result.delegate_target_cvalue = delegate_target_cvalue;
6668 result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify_cvalue;
6670 return result;