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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
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 int current_try_id;
35 public int next_try_id;
36 public CatchClause current_catch;
37 public CCodeFunction ccode;
38 public ArrayList<CCodeFunction> ccode_stack = new ArrayList<CCodeFunction> ();
39 public ArrayList<TargetValue> temp_ref_values = new ArrayList<TargetValue> ();
40 public int next_temp_var_id;
41 public int current_inner_error_id;
42 public bool current_method_inner_error;
43 public bool current_method_return;
44 public int next_coroutine_state = 1;
45 public Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
46 public Map<string,int> closure_variable_count_map = new HashMap<string,int> (str_hash, str_equal);
47 public Map<LocalVariable,int> closure_variable_clash_map = new HashMap<LocalVariable,int> ();
48 public bool is_in_method_precondition;
50 public EmitContext (Symbol? symbol = null) {
51 current_symbol = symbol;
54 public void push_symbol (Symbol symbol) {
55 symbol_stack.add (current_symbol);
56 current_symbol = symbol;
59 public void pop_symbol () {
60 current_symbol = symbol_stack.remove_at (symbol_stack.size - 1);
64 public CodeContext context { get; set; }
66 public Symbol root_symbol;
68 public EmitContext emit_context = new EmitContext ();
70 List<EmitContext> emit_context_stack = new ArrayList<EmitContext> ();
72 public CCodeLineDirective? current_line = null;
74 List<CCodeLineDirective> line_directive_stack = new ArrayList<CCodeLineDirective> ();
76 public Symbol current_symbol { get { return emit_context.current_symbol; } }
78 public TryStatement current_try {
79 get { return emit_context.current_try; }
80 set { emit_context.current_try = value; }
83 public int current_try_id {
84 get { return emit_context.current_try_id; }
85 set { emit_context.current_try_id = value; }
88 public int next_try_id {
89 get { return emit_context.next_try_id; }
90 set { emit_context.next_try_id = value; }
93 public CatchClause current_catch {
94 get { return emit_context.current_catch; }
95 set { emit_context.current_catch = value; }
98 public int current_inner_error_id {
99 get { return emit_context.current_inner_error_id; }
100 set { emit_context.current_inner_error_id = value; }
103 public bool is_in_method_precondition {
104 get { return emit_context.is_in_method_precondition; }
105 set { emit_context.is_in_method_precondition = value; }
108 public TypeSymbol? current_type_symbol {
110 var sym = current_symbol;
111 while (sym != null) {
112 if (sym is TypeSymbol) {
113 return (TypeSymbol) sym;
115 sym = sym.parent_symbol;
121 public Class? current_class {
122 get { return current_type_symbol as Class; }
125 public Method? current_method {
127 var sym = current_symbol;
128 while (sym is Block) {
129 sym = sym.parent_symbol;
131 return sym as Method;
135 public PropertyAccessor? current_property_accessor {
137 var sym = current_symbol;
138 while (sym is Block) {
139 sym = sym.parent_symbol;
141 return sym as PropertyAccessor;
145 public Constructor? current_constructor {
147 var sym = current_symbol;
148 while (sym is Block) {
149 sym = sym.parent_symbol;
151 return sym as Constructor;
155 public Destructor? current_destructor {
157 var sym = current_symbol;
158 while (sym is Block) {
159 sym = sym.parent_symbol;
161 return sym as Destructor;
165 public DataType? current_return_type {
167 var m = current_method;
169 return m.return_type;
172 var acc = current_property_accessor;
175 return acc.value_type;
181 if (is_in_constructor () || is_in_destructor ()) {
189 public bool is_in_coroutine () {
190 return current_method != null && current_method.coroutine;
193 public bool is_in_constructor () {
194 if (current_method != null) {
195 // make sure to not return true in lambda expression inside constructor
198 var sym = current_symbol;
199 while (sym != null) {
200 if (sym is Constructor) {
203 sym = sym.parent_symbol;
208 public bool is_in_destructor () {
209 if (current_method != null) {
210 // make sure to not return true in lambda expression inside constructor
213 var sym = current_symbol;
214 while (sym != null) {
215 if (sym is Destructor) {
218 sym = sym.parent_symbol;
223 public Block? current_closure_block {
225 return next_closure_block (current_symbol);
229 public unowned Block? next_closure_block (Symbol sym) {
231 unowned Method method = sym as Method;
232 if (method != null && !method.closure) {
233 // parent blocks are not captured by this method
237 unowned Block block = sym as Block;
238 if (method == null && block == null) {
243 if (block != null && block.captured) {
244 // closure block found
247 sym = sym.parent_symbol;
252 public CCodeFile header_file;
253 public CCodeFile internal_header_file;
254 public CCodeFile cfile;
256 public EmitContext class_init_context;
257 public EmitContext base_init_context;
258 public EmitContext class_finalize_context;
259 public EmitContext base_finalize_context;
260 public EmitContext instance_init_context;
261 public EmitContext instance_finalize_context;
263 public CCodeStruct param_spec_struct;
264 public CCodeStruct closure_struct;
265 public CCodeEnum prop_enum;
266 public CCodeEnum signal_enum;
268 public CCodeFunction ccode { get { return emit_context.ccode; } }
270 /* temporary variables that own their content */
271 public ArrayList<TargetValue> temp_ref_values { get { return emit_context.temp_ref_values; } }
272 /* cache to check whether a certain marshaller has been created yet */
273 public Set<string> user_marshal_set;
274 /* (constant) hash table with all predefined marshallers */
275 public Set<string> predefined_marshal_set;
276 /* (constant) hash table with all reserved identifiers in the generated code */
277 public static Set<string> reserved_identifiers;
279 public int next_temp_var_id {
280 get { return emit_context.next_temp_var_id; }
281 set { emit_context.next_temp_var_id = value; }
284 public int next_regex_id = 0;
285 public bool in_creation_method { get { return current_method is CreationMethod; } }
287 public bool current_method_inner_error {
288 get { return emit_context.current_method_inner_error; }
289 set { emit_context.current_method_inner_error = value; }
292 public bool current_method_return {
293 get { return emit_context.current_method_return; }
294 set { emit_context.current_method_return = value; }
297 int next_block_id = 0;
298 Map<Block,int> block_map = new HashMap<Block,int> ();
300 /* count of emitted inner_error variables in methods */
301 Map<weak Method,int> method_inner_error_var_count = new HashMap<weak Method,int> ();
303 public DataType void_type = new VoidType ();
304 public DataType bool_type;
305 public DataType char_type;
306 public DataType uchar_type;
307 public DataType? unichar_type;
308 public DataType short_type;
309 public DataType ushort_type;
310 public DataType int_type;
311 public DataType uint_type;
312 public DataType long_type;
313 public DataType ulong_type;
314 public DataType int8_type;
315 public DataType uint8_type;
316 public DataType int16_type;
317 public DataType uint16_type;
318 public DataType int32_type;
319 public DataType uint32_type;
320 public DataType int64_type;
321 public DataType uint64_type;
322 public DataType size_t_type;
323 public DataType ssize_t_type;
324 public DataType string_type;
325 public DataType regex_type;
326 public DataType float_type;
327 public DataType double_type;
328 public DataType pointer_type;
329 public TypeSymbol gtype_type;
330 public TypeSymbol gobject_type;
331 public ErrorType gerror_type;
332 public Class glist_type;
333 public Class gslist_type;
334 public Class gnode_type;
335 public Class gqueue_type;
336 public Class gvaluearray_type;
337 public TypeSymbol gstringbuilder_type;
338 public Class garray_type;
339 public TypeSymbol gbytearray_type;
340 public TypeSymbol genericarray_type;
341 public Class gsequence_type;
342 public Class gsequence_iter_type;
343 public TypeSymbol gthreadpool_type;
344 public DataType gquark_type;
345 public Struct gvalue_type;
346 public Class gvariant_type;
347 public Struct mutex_type;
348 public Struct gmutex_type;
349 public Struct grecmutex_type;
350 public Struct grwlock_type;
351 public Struct gcond_type;
352 public Class gsource_type;
353 public TypeSymbol type_module_type;
354 public TypeSymbol dbus_proxy_type;
355 public Class gtk_widget_type;
356 public DataType delegate_target_type;
357 public DelegateType delegate_target_destroy_type;
358 Delegate destroy_notify;
361 public bool in_plugin = false;
362 public string module_init_param_name;
364 public bool requires_assert;
365 public bool requires_array_free;
366 public bool requires_array_move;
367 public bool requires_array_length;
368 public bool requires_array_n_elements;
369 public bool requires_clear_mutex;
370 public bool requires_memdup2;
371 public bool requires_vala_extern;
373 public Set<string> wrappers;
374 Set<Symbol> generated_external_symbols;
376 public Map<string,string> variable_name_map { get { return emit_context.variable_name_map; } }
378 public static int ccode_attribute_cache_index = CodeNode.get_attribute_cache_index ();
380 protected CCodeBaseModule () {
381 if (Vala.get_build_version () != Vala.BUILD_VERSION) {
382 Report.error (null, "Integrity check failed (libvala %s doesn't match ccodegen %s)".printf (Vala.get_build_version (), Vala.BUILD_VERSION));
385 predefined_marshal_set = new HashSet<string> (str_hash, str_equal);
386 predefined_marshal_set.add ("VOID:VOID");
387 predefined_marshal_set.add ("VOID:BOOLEAN");
388 predefined_marshal_set.add ("VOID:CHAR");
389 predefined_marshal_set.add ("VOID:UCHAR");
390 predefined_marshal_set.add ("VOID:INT");
391 predefined_marshal_set.add ("VOID:UINT");
392 predefined_marshal_set.add ("VOID:LONG");
393 predefined_marshal_set.add ("VOID:ULONG");
394 predefined_marshal_set.add ("VOID:ENUM");
395 predefined_marshal_set.add ("VOID:FLAGS");
396 predefined_marshal_set.add ("VOID:FLOAT");
397 predefined_marshal_set.add ("VOID:DOUBLE");
398 predefined_marshal_set.add ("VOID:STRING");
399 predefined_marshal_set.add ("VOID:POINTER");
400 predefined_marshal_set.add ("VOID:OBJECT");
401 predefined_marshal_set.add ("STRING:OBJECT,POINTER");
402 predefined_marshal_set.add ("VOID:UINT,POINTER");
403 predefined_marshal_set.add ("BOOLEAN:FLAGS");
404 predefined_marshal_set.add ("VOID:BOXED");
405 predefined_marshal_set.add ("VOID:VARIANT");
406 predefined_marshal_set.add ("BOOLEAN:BOXED,BOXED");
408 reserved_identifiers = new HashSet<string> (str_hash, str_equal);
411 reserved_identifiers.add ("_Bool");
412 reserved_identifiers.add ("_Complex");
413 reserved_identifiers.add ("_Imaginary");
414 reserved_identifiers.add ("asm");
415 reserved_identifiers.add ("auto");
416 reserved_identifiers.add ("break");
417 reserved_identifiers.add ("case");
418 reserved_identifiers.add ("char");
419 reserved_identifiers.add ("const");
420 reserved_identifiers.add ("continue");
421 reserved_identifiers.add ("default");
422 reserved_identifiers.add ("do");
423 reserved_identifiers.add ("double");
424 reserved_identifiers.add ("else");
425 reserved_identifiers.add ("enum");
426 reserved_identifiers.add ("extern");
427 reserved_identifiers.add ("float");
428 reserved_identifiers.add ("for");
429 reserved_identifiers.add ("goto");
430 reserved_identifiers.add ("if");
431 reserved_identifiers.add ("inline");
432 reserved_identifiers.add ("int");
433 reserved_identifiers.add ("long");
434 reserved_identifiers.add ("register");
435 reserved_identifiers.add ("restrict");
436 reserved_identifiers.add ("return");
437 reserved_identifiers.add ("short");
438 reserved_identifiers.add ("signed");
439 reserved_identifiers.add ("sizeof");
440 reserved_identifiers.add ("static");
441 reserved_identifiers.add ("struct");
442 reserved_identifiers.add ("switch");
443 reserved_identifiers.add ("typedef");
444 reserved_identifiers.add ("union");
445 reserved_identifiers.add ("unsigned");
446 reserved_identifiers.add ("void");
447 reserved_identifiers.add ("volatile");
448 reserved_identifiers.add ("while");
451 reserved_identifiers.add ("_Alignas");
452 reserved_identifiers.add ("_Alignof");
453 reserved_identifiers.add ("_Atomic");
454 reserved_identifiers.add ("_Generic");
455 reserved_identifiers.add ("_Noreturn");
456 reserved_identifiers.add ("_Static_assert");
457 reserved_identifiers.add ("_Thread_local");
460 reserved_identifiers.add ("cdecl");
462 // reserved for Vala/GObject naming conventions
463 reserved_identifiers.add ("error");
464 reserved_identifiers.add ("result");
465 reserved_identifiers.add ("self");
468 public override void emit (CodeContext context) {
469 this.context = context;
471 ccode_init (context.profile);
473 root_symbol = context.root;
475 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
476 char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
477 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
478 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
479 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
480 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
481 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
482 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
483 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
484 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
485 uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8"));
486 int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16"));
487 uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16"));
488 int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32"));
489 uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32"));
490 int64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int64"));
491 uint64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint64"));
492 size_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("size_t"));
493 ssize_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ssize_t"));
494 float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
495 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
496 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
497 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
498 if (unichar_struct != null) {
499 unichar_type = new IntegerType (unichar_struct);
502 if (context.profile == Profile.GOBJECT) {
503 var glib_ns = root_symbol.scope.lookup ("GLib");
505 gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
506 gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
507 gerror_type = new ErrorType (null, null);
508 glist_type = (Class) glib_ns.scope.lookup ("List");
509 gslist_type = (Class) glib_ns.scope.lookup ("SList");
510 gnode_type = (Class) glib_ns.scope.lookup ("Node");
511 gqueue_type = (Class) glib_ns.scope.lookup ("Queue");
512 gvaluearray_type = (Class) glib_ns.scope.lookup ("ValueArray");
513 gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
514 garray_type = (Class) glib_ns.scope.lookup ("Array");
515 gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
516 genericarray_type = (TypeSymbol) glib_ns.scope.lookup ("GenericArray");
517 gsequence_type = (Class) glib_ns.scope.lookup ("Sequence");
518 gsequence_iter_type = (Class) glib_ns.scope.lookup ("SequenceIter");
519 gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
521 gerror = (Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Error");
522 gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
523 gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
524 gvariant_type = (Class) glib_ns.scope.lookup ("Variant");
525 gsource_type = (Class) glib_ns.scope.lookup ("Source");
527 gmutex_type = (Struct) glib_ns.scope.lookup ("Mutex");
528 grecmutex_type = (Struct) glib_ns.scope.lookup ("RecMutex");
529 grwlock_type = (Struct) glib_ns.scope.lookup ("RWLock");
530 gcond_type = (Struct) glib_ns.scope.lookup ("Cond");
532 mutex_type = grecmutex_type;
534 type_module_type = (TypeSymbol) glib_ns.scope.lookup ("TypeModule");
536 regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
538 if (context.module_init_method != null) {
539 foreach (Parameter parameter in context.module_init_method.get_parameters ()) {
540 if (parameter.variable_type.type_symbol.is_subtype_of (type_module_type)) {
542 module_init_param_name = parameter.name;
549 dbus_proxy_type = (TypeSymbol) glib_ns.scope.lookup ("DBusProxy");
551 pointer_type = new StructValueType ((Struct) glib_ns.scope.lookup ("pointer"));
553 delegate_target_type = pointer_type;
554 destroy_notify = (Delegate) glib_ns.scope.lookup ("DestroyNotify");
555 delegate_target_destroy_type = new DelegateType (destroy_notify);
557 pointer_type = new PointerType (new VoidType ());
559 delegate_target_type = pointer_type;
560 destroy_notify = new Delegate ("ValaDestroyNotify", new VoidType ());
561 destroy_notify.add_parameter (new Parameter ("data", new PointerType (new VoidType ())));
562 destroy_notify.has_target = false;
563 destroy_notify.owner = root_symbol.scope;
564 delegate_target_destroy_type = new DelegateType (destroy_notify);
567 var gtk_ns = root_symbol.scope.lookup ("Gtk");
568 if (gtk_ns != null) {
569 gtk_widget_type = (Class) gtk_ns.scope.lookup ("Widget");
572 header_file = new CCodeFile (CCodeFileType.PUBLIC_HEADER);
573 internal_header_file = new CCodeFile (CCodeFileType.INTERNAL_HEADER);
575 /* we're only interested in non-pkg source files */
576 var source_files = context.get_source_files ();
577 foreach (SourceFile file in source_files) {
578 if (file.file_type == SourceFileType.SOURCE ||
579 (context.header_filename != null && file.file_type == SourceFileType.FAST)) {
584 // generate symbols file for public API
585 if (context.symbols_filename != null) {
586 var stream = FileStream.open (context.symbols_filename, "w");
587 if (stream == null) {
588 Report.error (null, "unable to open `%s' for writing", context.symbols_filename);
593 foreach (string symbol in header_file.get_symbols ()) {
594 stream.puts (symbol);
601 // generate C header file for public API
602 if (context.header_filename != null) {
604 if (context.profile == Profile.GOBJECT) {
605 header_file.add_include ("glib.h");
606 ret = header_file.store (context.header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
608 ret = header_file.store (context.header_filename, null, context.version_header, false, "#ifdef __cplusplus\nextern \"C\" {\n#endif", "#ifdef __cplusplus\n}\n#endif");
611 Report.error (null, "unable to open `%s' for writing", context.header_filename);
615 // generate C header file for internal API
616 if (context.internal_header_filename != null) {
618 if (context.profile == Profile.GOBJECT) {
619 internal_header_file.add_include ("glib.h");
620 ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
622 ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false, "#ifdef __cplusplus\nextern \"C\" {\n#endif", "#ifdef __cplusplus\n}\n#endif");
625 Report.error (null, "unable to open `%s' for writing", context.internal_header_filename);
632 public void push_context (EmitContext emit_context) {
633 if (this.emit_context != null) {
634 emit_context_stack.add (this.emit_context);
637 this.emit_context = emit_context;
639 ccode.current_line = current_line;
643 public void pop_context () {
644 if (emit_context_stack.size > 0) {
645 this.emit_context = emit_context_stack.remove_at (emit_context_stack.size - 1);
647 ccode.current_line = current_line;
650 this.emit_context = null;
654 public void push_line (SourceReference? source_reference) {
655 line_directive_stack.add (current_line);
656 if (source_reference != null) {
657 current_line = new CCodeLineDirective (source_reference.file.get_relative_filename (), source_reference.begin.line);
659 ccode.current_line = current_line;
664 public void pop_line () {
665 current_line = line_directive_stack.remove_at (line_directive_stack.size - 1);
667 ccode.current_line = current_line;
671 public void push_function (CCodeFunction func) {
672 emit_context.ccode_stack.add (ccode);
673 emit_context.ccode = func;
674 ccode.current_line = current_line;
677 public void pop_function () {
678 emit_context.ccode = emit_context.ccode_stack.remove_at (emit_context.ccode_stack.size - 1);
680 ccode.current_line = current_line;
684 public bool add_symbol_declaration (CCodeFile decl_space, Symbol sym, string name) {
685 bool in_generated_header = context.header_filename != null
686 && (decl_space.file_type != CCodeFileType.PUBLIC_HEADER && !sym.is_internal_symbol () && !(sym is Class && ((Class) sym).is_opaque));
687 if (decl_space.add_declaration (name)) {
690 if (sym.source_reference != null) {
691 sym.source_reference.file.used = true;
694 return in_generated_header;
696 // constants with initializer-list are special
697 if (sym is Constant && ((Constant) sym).value is InitializerList) {
700 // sealed classes are special
701 if (!sym.external_package && sym is Class && ((Class) sym).is_sealed) {
704 if (sym.external_package || in_generated_header
705 || (sym.is_extern && get_ccode_header_filenames (sym).length > 0)) {
706 // add feature test macros
707 foreach (unowned string feature_test_macro in get_ccode_feature_test_macros (sym).split (",")) {
708 decl_space.add_feature_test_macro (feature_test_macro);
710 // add appropriate include file
711 foreach (unowned string header_filename in get_ccode_header_filenames (sym).split (",")) {
712 decl_space.add_include (header_filename,
713 !sym.is_extern && (!sym.external_package || (sym.external_package && sym.from_commandline)));
715 // declaration complete
718 // require declaration
723 public virtual void append_vala_array_free () {
726 public virtual void append_vala_array_move () {
729 public virtual void append_vala_array_length () {
732 public virtual void append_params_array (Method m) {
735 public void append_vala_clear_mutex (string typename, string funcprefix) {
737 cfile.add_include ("string.h");
739 var fun = new CCodeFunction ("_vala_clear_" + typename);
740 fun.modifiers = CCodeModifiers.STATIC;
741 fun.add_parameter (new CCodeParameter ("mutex", typename + " *"));
745 ccode.add_declaration (typename, new CCodeVariableDeclarator.zero ("zero_mutex", new CCodeConstant ("{ 0 }")));
747 var cmp = new CCodeFunctionCall (new CCodeIdentifier ("memcmp"));
748 cmp.add_argument (new CCodeIdentifier ("mutex"));
749 cmp.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("zero_mutex")));
750 cmp.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
753 var mutex_clear = new CCodeFunctionCall (new CCodeIdentifier (funcprefix + "_clear"));
754 mutex_clear.add_argument (new CCodeIdentifier ("mutex"));
755 ccode.add_expression (mutex_clear);
757 var mset = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
758 mset.add_argument (new CCodeIdentifier ("mutex"));
759 mset.add_argument (new CCodeConstant ("0"));
760 mset.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
761 ccode.add_expression (mset);
767 cfile.add_function_declaration (fun);
768 cfile.add_function (fun);
771 void append_vala_memdup2 () {
773 cfile.add_include ("glib.h");
775 cfile.add_include ("string.h");
777 var fun = new CCodeFunction ("_vala_memdup2", "gpointer");
778 fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
779 fun.add_parameter (new CCodeParameter ("mem", "gconstpointer"));
780 fun.add_parameter (new CCodeParameter ("byte_size", "gsize"));
784 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("new_mem"));
786 ccode.open_if (new CCodeIdentifier ("mem && byte_size != 0"));
788 var malloc = new CCodeFunctionCall (new CCodeIdentifier ("g_malloc"));
789 malloc.add_argument (new CCodeIdentifier ("byte_size"));
790 ccode.add_assignment (new CCodeIdentifier ("new_mem"), malloc);
791 var mcpy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
792 mcpy.add_argument (new CCodeIdentifier ("new_mem"));
793 mcpy.add_argument (new CCodeIdentifier ("mem"));
794 mcpy.add_argument (new CCodeIdentifier ("byte_size"));
795 ccode.add_expression (mcpy);
799 ccode.add_assignment (new CCodeIdentifier ("new_mem"), new CCodeConstant ("NULL"));
803 ccode.add_return (new CCodeIdentifier ("new_mem"));
807 cfile.add_function_declaration (fun);
808 cfile.add_function (fun);
812 * Define a macro hint for exporting a symbol in a portable way.
814 void append_vala_extern_define (CCodeFile decl_space) {
815 var extern_define = new CCodeIfSection ("!defined(VALA_EXTERN)");
817 CCodeIfSection if_section;
818 if_section = new CCodeIfSection ("defined(_MSC_VER)");
819 extern_define.append (if_section);
820 if_section.append (new CCodeDefine ("VALA_EXTERN", "__declspec(dllexport) extern"));
821 if_section = if_section.append_else ("__GNUC__ >= 4");
822 if_section.append (new CCodeDefine ("VALA_EXTERN", "__attribute__((visibility(\"default\"))) extern"));
823 if_section = if_section.append_else ();
824 if_section.append (new CCodeDefine ("VALA_EXTERN", "extern"));
826 decl_space.add_define (extern_define);
829 public override void visit_source_file (SourceFile source_file) {
830 cfile = new CCodeFile (CCodeFileType.SOURCE, source_file);
832 user_marshal_set = new HashSet<string> (str_hash, str_equal);
836 requires_assert = false;
837 requires_array_free = false;
838 requires_array_move = false;
839 requires_array_length = false;
840 requires_array_n_elements = false;
841 requires_clear_mutex = false;
842 requires_vala_extern = false;
844 wrappers = new HashSet<string> (str_hash, str_equal);
845 generated_external_symbols = new HashSet<Symbol> ();
847 source_file.accept_children (this);
849 if (context.report.get_errors () > 0) {
853 /* For fast-vapi, we only wanted the header declarations
854 * to be emitted, so bail out here without writing the
857 if (source_file.file_type == SourceFileType.FAST) {
861 if (requires_assert) {
862 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);")));
863 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; }")));
864 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; }")));
865 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);")));
867 if (requires_array_free) {
868 append_vala_array_free ();
870 if (requires_array_move) {
871 append_vala_array_move ();
873 if (requires_array_length) {
874 append_vala_array_length ();
876 if (requires_array_n_elements) {
877 cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("VALA_N_ELEMENTS(arr)", new CCodeConstant ("(sizeof (arr) / sizeof ((arr)[0]))")));
879 if (requires_clear_mutex) {
880 append_vala_clear_mutex ("GMutex", "g_mutex");
881 append_vala_clear_mutex ("GRecMutex", "g_rec_mutex");
882 append_vala_clear_mutex ("GRWLock", "g_rw_lock");
883 append_vala_clear_mutex ("GCond", "g_cond");
885 if (requires_memdup2) {
886 append_vala_memdup2 ();
888 if (requires_vala_extern) {
889 if (context.header_filename != null) {
890 if (!header_file.add_declaration ("VALA_EXTERN")) {
891 append_vala_extern_define (header_file);
893 cfile.add_include (source_file.get_cinclude_filename (), true);
894 internal_header_file.add_include (source_file.get_cinclude_filename (), true);
896 if (!cfile.add_declaration ("VALA_EXTERN")) {
897 append_vala_extern_define (cfile);
898 append_vala_extern_define (internal_header_file);
903 var comments = source_file.get_comments();
904 if (comments != null) {
905 foreach (Comment comment in comments) {
906 var ccomment = new CCodeComment (comment.content);
907 cfile.add_comment (ccomment);
911 if (!cfile.store (source_file.get_csource_filename (), source_file.filename, context.version_header, context.debug)) {
912 Report.error (null, "unable to open `%s' for writing", source_file.get_csource_filename ());
918 public virtual bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
919 if (add_symbol_declaration (decl_space, en, get_ccode_name (en))) {
923 var cenum = new CCodeEnum (get_ccode_name (en));
925 if (en.version.deprecated) {
926 if (context.profile == Profile.GOBJECT) {
927 decl_space.add_include ("glib.h");
929 cenum.modifiers |= CCodeModifiers.DEPRECATED;
932 var current_cfile = cfile;
936 foreach (EnumValue ev in en.get_values ()) {
938 if (ev.value == null) {
939 c_ev = new CCodeEnumValue (get_ccode_name (ev));
941 c_ev.value = new CCodeConstant ("1 << %d".printf (flag_shift));
945 ev.value.emit (this);
946 c_ev = new CCodeEnumValue (get_ccode_name (ev), get_cvalue (ev.value));
948 c_ev.modifiers |= (ev.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
949 cenum.add_value (c_ev);
952 cfile = current_cfile;
954 decl_space.add_type_declaration (cenum);
955 decl_space.add_type_declaration (new CCodeNewline ());
957 if (context.profile != Profile.GOBJECT || !get_ccode_has_type_id (en)) {
961 decl_space.add_include ("glib-object.h");
962 decl_space.add_type_declaration (new CCodeNewline ());
964 var fun_name = get_ccode_type_function (en);
966 var macro = "(%s ())".printf (fun_name);
967 decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (en), macro));
969 var regfun = new CCodeFunction (fun_name, "GType");
970 regfun.modifiers = CCodeModifiers.CONST;
972 if (en.is_private_symbol ()) {
973 // avoid C warning as this function is not always used
974 regfun.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.UNUSED;
975 } else if (context.hide_internal && en.is_internal_symbol ()) {
976 regfun.modifiers |= CCodeModifiers.INTERNAL;
978 regfun.modifiers |= CCodeModifiers.EXTERN;
979 requires_vala_extern = true;
982 decl_space.add_function_declaration (regfun);
987 public override void visit_enum (Enum en) {
988 push_line (en.source_reference);
990 if (en.comment != null) {
991 cfile.add_type_member_definition (new CCodeComment (en.comment.content));
994 generate_enum_declaration (en, cfile);
996 if (!en.is_internal_symbol ()) {
997 generate_enum_declaration (en, header_file);
999 if (!en.is_private_symbol ()) {
1000 generate_enum_declaration (en, internal_header_file);
1003 en.accept_children (this);
1008 public void visit_member (Symbol m) {
1009 /* stuff meant for all lockable members */
1010 if (m is Lockable && ((Lockable) m).lock_used) {
1011 CCodeExpression l = new CCodeIdentifier ("self");
1012 var init_context = class_init_context;
1013 var finalize_context = class_finalize_context;
1015 if (m.is_instance_member ()) {
1016 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (get_ccode_name (m)));
1017 init_context = instance_init_context;
1018 finalize_context = instance_finalize_context;
1019 } else if (m.is_class_member ()) {
1020 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function ((Class) m.parent_symbol)));
1021 get_class_private_call.add_argument (new CCodeIdentifier ("klass"));
1022 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (get_ccode_name (m)));
1024 l = new CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf (get_ccode_lower_case_name (m.parent_symbol), get_ccode_name (m))));
1027 push_context (init_context);
1028 var initf = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.default_construction_method)));
1029 initf.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
1030 ccode.add_expression (initf);
1033 if (finalize_context != null) {
1034 push_context (finalize_context);
1035 var fc = new CCodeFunctionCall (new CCodeIdentifier ("g_rec_mutex_clear"));
1036 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
1037 ccode.add_expression (fc);
1043 static void constant_array_ranks_sizes (InitializerList initializer_list, int[] sizes, int rank = 0) {
1044 sizes[rank] = int.max (sizes[rank], initializer_list.size);
1046 foreach (var expr in initializer_list.get_initializers()) {
1047 if (expr is InitializerList && ((InitializerList) expr).target_type is ArrayType) {
1048 constant_array_ranks_sizes ((InitializerList) expr, sizes, rank);
1053 CCodeDeclaratorSuffix? get_constant_declarator_suffix (Constant c) {
1054 unowned ArrayType? array = c.type_reference as ArrayType;
1055 unowned InitializerList? initializer_list = c.value as InitializerList;
1056 if (array == null || initializer_list == null) {
1057 if (c.type_reference.compatible (string_type)) {
1058 return new CCodeDeclaratorSuffix.with_array ();
1063 var lengths = new ArrayList<CCodeExpression> ();
1064 int[] sizes = new int[array.rank];
1065 constant_array_ranks_sizes (initializer_list, sizes);
1066 for (int i = 0; i < array.rank; i++) {
1067 lengths.add (new CCodeConstant ("%d".printf (sizes[i])));
1069 return new CCodeDeclaratorSuffix.with_multi_array (lengths);
1072 public void generate_constant_declaration (Constant c, CCodeFile decl_space, bool definition = false) {
1073 if (c.parent_symbol is Block) {
1078 if (add_symbol_declaration (decl_space, c, get_ccode_name (c))) {
1082 if (!c.external && c.value != null) {
1083 generate_type_declaration (c.type_reference, decl_space);
1085 c.value.emit (this);
1087 var initializer_list = c.value as InitializerList;
1088 if (initializer_list != null) {
1089 var cdecl = new CCodeDeclaration (get_ccode_const_name (c.type_reference));
1090 var cinitializer = get_cvalue (c.value);
1092 // never output value in header
1093 // special case needed as this method combines declaration and definition
1094 cinitializer = null;
1097 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_name (c), cinitializer, get_constant_declarator_suffix (c)));
1098 if (c.is_private_symbol ()) {
1099 cdecl.modifiers = CCodeModifiers.STATIC;
1101 cdecl.modifiers = CCodeModifiers.EXTERN;
1102 requires_vala_extern = true;
1105 decl_space.add_constant_declaration (cdecl);
1107 if (c.value is StringLiteral && ((StringLiteral) c.value).translate) {
1108 // translated string constant
1109 var m = (Method) root_symbol.scope.lookup ("GLib").scope.lookup ("_");
1110 add_symbol_declaration (decl_space, m, get_ccode_name (m));
1113 var cdefine = new CCodeDefine.with_expression (get_ccode_name (c), get_cvalue (c.value));
1114 decl_space.add_define (cdefine);
1119 public override void visit_constant (Constant c) {
1120 push_line (c.source_reference);
1122 if (c.parent_symbol is Block) {
1125 generate_type_declaration (c.type_reference, cfile);
1127 c.value.emit (this);
1130 if (c.type_reference.compatible (string_type)) {
1131 type_name = "const char";
1133 type_name = get_ccode_const_name (c.type_reference);
1136 var cinitializer = get_cvalue (c.value);
1138 ccode.add_declaration (type_name, new CCodeVariableDeclarator (get_ccode_name (c), cinitializer, get_constant_declarator_suffix (c)), CCodeModifiers.STATIC);
1140 generate_constant_declaration (c, cfile, true);
1142 if (!c.is_internal_symbol ()) {
1143 generate_constant_declaration (c, header_file);
1145 if (!c.is_private_symbol ()) {
1146 generate_constant_declaration (c, internal_header_file);
1153 public void append_field (CCodeStruct ccode_struct, Field f, CCodeFile decl_space) {
1154 generate_type_declaration (f.variable_type, decl_space);
1156 CCodeModifiers modifiers = (f.is_volatile ? CCodeModifiers.VOLATILE : 0) | (f.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
1157 ccode_struct.add_field (get_ccode_name (f.variable_type), get_ccode_name (f), modifiers, get_ccode_declarator_suffix (f.variable_type));
1159 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1160 // create fields to store array dimensions
1161 var array_type = (ArrayType) f.variable_type;
1162 if (!array_type.fixed_length) {
1163 var length_ctype = get_ccode_array_length_type (f);
1164 for (int dim = 1; dim <= array_type.rank; dim++) {
1165 string length_cname = get_variable_array_length_cname (f, dim);
1166 ccode_struct.add_field (length_ctype, length_cname);
1168 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1169 ccode_struct.add_field (length_ctype, get_array_size_cname (get_ccode_name (f)));
1172 } else if (get_ccode_delegate_target (f)) {
1173 var delegate_type = (DelegateType) f.variable_type;
1174 if (delegate_type.delegate_symbol.has_target) {
1175 // create field to store delegate target
1176 ccode_struct.add_field (get_ccode_name (delegate_target_type), get_ccode_delegate_target_name (f));
1177 if (delegate_type.is_disposable ()) {
1178 ccode_struct.add_field (get_ccode_name (delegate_target_destroy_type), get_ccode_delegate_target_destroy_notify_name (f));
1184 public void generate_field_declaration (Field f, CCodeFile decl_space) {
1185 if (add_symbol_declaration (decl_space, f, get_ccode_name (f))) {
1189 generate_type_declaration (f.variable_type, decl_space);
1191 var cdecl = new CCodeDeclaration (get_ccode_name (f.variable_type));
1192 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type)));
1193 if (f.is_private_symbol ()) {
1194 cdecl.modifiers = CCodeModifiers.STATIC;
1196 cdecl.modifiers = CCodeModifiers.EXTERN;
1197 requires_vala_extern = true;
1199 if (f.version.deprecated) {
1200 cdecl.modifiers |= CCodeModifiers.DEPRECATED;
1202 if (f.is_volatile) {
1203 cdecl.modifiers |= CCodeModifiers.VOLATILE;
1205 decl_space.add_type_member_declaration (cdecl);
1208 // Declare mutex for static member
1209 var flock = new CCodeDeclaration (get_ccode_name (mutex_type));
1210 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}"));
1211 flock.add_declarator (flock_decl);
1213 if (f.is_private_symbol ()) {
1214 flock.modifiers = CCodeModifiers.STATIC;
1216 flock.modifiers = CCodeModifiers.EXTERN;
1217 requires_vala_extern = true;
1219 decl_space.add_type_member_declaration (flock);
1222 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1223 var array_type = (ArrayType) f.variable_type;
1225 if (!array_type.fixed_length) {
1226 var length_ctype = get_ccode_array_length_type (f);
1228 for (int dim = 1; dim <= array_type.rank; dim++) {
1229 cdecl = new CCodeDeclaration (length_ctype);
1230 cdecl.add_declarator (new CCodeVariableDeclarator (get_variable_array_length_cname (f, dim)));
1231 if (f.is_private_symbol ()) {
1232 cdecl.modifiers = CCodeModifiers.STATIC;
1234 cdecl.modifiers = CCodeModifiers.EXTERN;
1235 requires_vala_extern = true;
1237 decl_space.add_type_member_declaration (cdecl);
1240 } else if (get_ccode_delegate_target (f)) {
1241 var delegate_type = (DelegateType) f.variable_type;
1242 if (delegate_type.delegate_symbol.has_target) {
1243 // create field to store delegate target
1245 cdecl = new CCodeDeclaration (get_ccode_name (delegate_target_type));
1246 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f)));
1247 if (f.is_private_symbol ()) {
1248 cdecl.modifiers = CCodeModifiers.STATIC;
1250 cdecl.modifiers = CCodeModifiers.EXTERN;
1251 requires_vala_extern = true;
1253 decl_space.add_type_member_declaration (cdecl);
1255 if (delegate_type.is_disposable ()) {
1256 cdecl = new CCodeDeclaration (get_ccode_name (delegate_target_destroy_type));
1257 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_destroy_notify_name (f)));
1258 if (f.is_private_symbol ()) {
1259 cdecl.modifiers = CCodeModifiers.STATIC;
1261 cdecl.modifiers = CCodeModifiers.EXTERN;
1262 requires_vala_extern = true;
1264 decl_space.add_type_member_declaration (cdecl);
1270 public override void visit_field (Field f) {
1271 push_line (f.source_reference);
1274 var cl = f.parent_symbol as Class;
1275 bool is_gtypeinstance = (cl != null && !cl.is_compact);
1277 CCodeExpression lhs = null;
1279 if (f.binding == MemberBinding.INSTANCE) {
1280 if (is_gtypeinstance && f.access == SymbolAccessibility.PRIVATE) {
1281 lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), get_ccode_name (f));
1283 lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_ccode_name (f));
1286 if (f.initializer != null) {
1287 push_context (instance_init_context);
1289 f.initializer.emit (this);
1291 var rhs = get_cvalue (f.initializer);
1292 if (!is_simple_struct_creation (f, f.initializer)) {
1293 // otherwise handled in visit_object_creation_expression
1295 ccode.add_assignment (lhs, rhs);
1297 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1298 var array_type = (ArrayType) f.variable_type;
1299 var field_value = get_field_cvalue (f, load_this_parameter ((TypeSymbol) f.parent_symbol));
1301 var glib_value = (GLibValue) f.initializer.target_value;
1302 if (glib_value.array_length_cvalues != null) {
1303 for (int dim = 1; dim <= array_type.rank; dim++) {
1304 var array_len_lhs = get_array_length_cvalue (field_value, dim);
1305 ccode.add_assignment (array_len_lhs, get_array_length_cvalue (glib_value, dim));
1307 } else if (glib_value.array_null_terminated) {
1308 requires_array_length = true;
1309 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1310 len_call.add_argument (get_cvalue_ (glib_value));
1312 ccode.add_assignment (get_array_length_cvalue (field_value, 1), len_call);
1314 for (int dim = 1; dim <= array_type.rank; dim++) {
1315 ccode.add_assignment (get_array_length_cvalue (field_value, dim), new CCodeConstant ("-1"));
1319 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1320 var lhs_array_size = get_array_size_cvalue (field_value);
1321 var rhs_array_len = get_array_length_cvalue (field_value, 1);
1322 ccode.add_assignment (lhs_array_size, rhs_array_len);
1324 } else if (get_ccode_delegate_target (f)) {
1325 var delegate_type = (DelegateType) f.variable_type;
1326 if (delegate_type.delegate_symbol.has_target) {
1327 var field_value = get_field_cvalue (f, load_this_parameter ((TypeSymbol) f.parent_symbol));
1328 var target_cvalue = get_delegate_target_cvalue (f.initializer.target_value);
1329 if (target_cvalue != null) {
1330 ccode.add_assignment (get_delegate_target_cvalue (field_value), target_cvalue);
1332 ccode.add_assignment (get_delegate_target_cvalue (field_value), new CCodeIdentifier ("self"));
1334 if (delegate_type.is_disposable ()) {
1335 var destroy_cvalue = get_delegate_target_destroy_notify_cvalue (f.initializer.target_value);
1336 if (destroy_cvalue != null) {
1337 ccode.add_assignment (get_delegate_target_destroy_notify_cvalue (field_value), destroy_cvalue);
1339 ccode.add_assignment (get_delegate_target_destroy_notify_cvalue (field_value), new CCodeConstant ("NULL"));
1346 foreach (var value in temp_ref_values) {
1347 ccode.add_expression (destroy_value (value));
1350 temp_ref_values.clear ();
1355 if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_destroy (f.variable_type) && instance_finalize_context != null) {
1356 push_context (instance_finalize_context);
1357 ccode.add_expression (destroy_field (f, load_this_parameter ((TypeSymbol) f.parent_symbol)));
1360 } else if (f.binding == MemberBinding.CLASS) {
1361 if (f.access == SymbolAccessibility.PRIVATE) {
1362 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function (cl)));
1363 ccall.add_argument (new CCodeIdentifier ("klass"));
1364 lhs = new CCodeMemberAccess (ccall, get_ccode_name (f), true);
1366 lhs = new CCodeMemberAccess (new CCodeIdentifier ("klass"), get_ccode_name (f), true);
1369 if (f.initializer != null) {
1370 push_context (class_init_context);
1372 f.initializer.emit (this);
1374 var rhs = get_cvalue (f.initializer);
1376 ccode.add_assignment (lhs, rhs);
1378 foreach (var value in temp_ref_values) {
1379 ccode.add_expression (destroy_value (value));
1382 temp_ref_values.clear ();
1387 generate_field_declaration (f, cfile);
1389 if (!f.is_internal_symbol ()) {
1390 generate_field_declaration (f, header_file);
1392 if (!f.is_private_symbol ()) {
1393 generate_field_declaration (f, internal_header_file);
1397 lhs = new CCodeIdentifier (get_ccode_name (f));
1399 var var_decl = new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type));
1400 var_decl.initializer = default_value_for_type (f.variable_type, true);
1402 if (class_init_context != null) {
1403 push_context (class_init_context);
1405 push_context (new EmitContext ());
1408 if (f.initializer != null) {
1409 f.initializer.emit (this);
1411 var init = get_cvalue (f.initializer);
1412 if (is_constant_ccode_expression (init)) {
1413 var_decl.initializer = init;
1417 var var_def = new CCodeDeclaration (get_ccode_name (f.variable_type));
1418 var_def.add_declarator (var_decl);
1419 if (!f.is_private_symbol ()) {
1420 var_def.modifiers = CCodeModifiers.EXTERN;
1421 requires_vala_extern = true;
1423 var_def.modifiers = CCodeModifiers.STATIC;
1425 if (f.version.deprecated) {
1426 var_def.modifiers |= CCodeModifiers.DEPRECATED;
1428 if (f.is_volatile) {
1429 var_def.modifiers |= CCodeModifiers.VOLATILE;
1431 cfile.add_type_member_declaration (var_def);
1433 /* add array length fields where necessary */
1434 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1435 var array_type = (ArrayType) f.variable_type;
1437 if (!array_type.fixed_length) {
1438 var length_ctype = get_ccode_array_length_type (f);
1440 for (int dim = 1; dim <= array_type.rank; dim++) {
1441 var len_def = new CCodeDeclaration (length_ctype);
1442 len_def.add_declarator (new CCodeVariableDeclarator (get_variable_array_length_cname (f, dim), new CCodeConstant ("0")));
1443 if (!f.is_private_symbol ()) {
1444 len_def.modifiers = CCodeModifiers.EXTERN;
1445 requires_vala_extern = true;
1447 len_def.modifiers = CCodeModifiers.STATIC;
1449 cfile.add_type_member_declaration (len_def);
1452 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1453 var cdecl = new CCodeDeclaration (length_ctype);
1454 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_size_cname (get_ccode_name (f)), new CCodeConstant ("0")));
1455 cdecl.modifiers = CCodeModifiers.STATIC;
1456 cfile.add_type_member_declaration (cdecl);
1459 } else if (get_ccode_delegate_target (f)) {
1460 var delegate_type = (DelegateType) f.variable_type;
1461 if (delegate_type.delegate_symbol.has_target) {
1462 // create field to store delegate target
1464 var target_def = new CCodeDeclaration (get_ccode_name (delegate_target_type));
1465 target_def.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f), new CCodeConstant ("NULL")));
1466 if (!f.is_private_symbol ()) {
1467 target_def.modifiers = CCodeModifiers.EXTERN;
1468 requires_vala_extern = true;
1470 target_def.modifiers = CCodeModifiers.STATIC;
1472 cfile.add_type_member_declaration (target_def);
1474 if (delegate_type.is_disposable ()) {
1475 var target_destroy_notify_def = new CCodeDeclaration (get_ccode_name (delegate_target_destroy_type));
1476 target_destroy_notify_def.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_destroy_notify_name (f), new CCodeConstant ("NULL")));
1477 if (!f.is_private_symbol ()) {
1478 target_destroy_notify_def.modifiers = CCodeModifiers.EXTERN;
1479 requires_vala_extern = true;
1481 target_destroy_notify_def.modifiers = CCodeModifiers.STATIC;
1483 cfile.add_type_member_declaration (target_destroy_notify_def);
1489 if (f.initializer != null) {
1490 var rhs = get_cvalue (f.initializer);
1491 if (!is_constant_ccode_expression (rhs)) {
1492 if (is_gtypeinstance) {
1493 if (f.initializer is InitializerList) {
1494 ccode.open_block ();
1496 var temp_decl = get_temp_variable (f.variable_type);
1497 var vardecl = new CCodeVariableDeclarator.zero (temp_decl.name, rhs);
1498 ccode.add_declaration (get_ccode_name (temp_decl.variable_type), vardecl);
1500 var tmp = get_variable_cexpression (temp_decl.name);
1501 ccode.add_assignment (lhs, tmp);
1505 ccode.add_assignment (lhs, rhs);
1508 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1509 var array_type = (ArrayType) f.variable_type;
1510 var field_value = get_field_cvalue (f, null);
1512 var glib_value = (GLibValue) f.initializer.target_value;
1513 if (glib_value.array_length_cvalues != null) {
1514 for (int dim = 1; dim <= array_type.rank; dim++) {
1515 var array_len_lhs = get_array_length_cvalue (field_value, dim);
1516 ccode.add_assignment (array_len_lhs, get_array_length_cvalue (glib_value, dim));
1518 } else if (glib_value.array_null_terminated) {
1519 requires_array_length = true;
1520 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1521 len_call.add_argument (get_cvalue_ (glib_value));
1523 ccode.add_assignment (get_array_length_cvalue (field_value, 1), len_call);
1525 for (int dim = 1; dim <= array_type.rank; dim++) {
1526 ccode.add_assignment (get_array_length_cvalue (field_value, dim), new CCodeConstant ("-1"));
1532 Report.error (f.source_reference, "Non-constant field initializers not supported in this context");
1545 public static bool is_constant_ccode_expression (CCodeExpression cexpr) {
1546 if (cexpr is CCodeConstant || cexpr is CCodeConstantIdentifier) {
1548 } else if (cexpr is CCodeCastExpression) {
1549 var ccast = (CCodeCastExpression) cexpr;
1550 return is_constant_ccode_expression (ccast.inner);
1551 } else if (cexpr is CCodeUnaryExpression) {
1552 var cunary = (CCodeUnaryExpression) cexpr;
1553 switch (cunary.operator) {
1554 case CCodeUnaryOperator.PREFIX_INCREMENT:
1555 case CCodeUnaryOperator.PREFIX_DECREMENT:
1556 case CCodeUnaryOperator.POSTFIX_INCREMENT:
1557 case CCodeUnaryOperator.POSTFIX_DECREMENT:
1562 return is_constant_ccode_expression (cunary.inner);
1563 } else if (cexpr is CCodeBinaryExpression) {
1564 var cbinary = (CCodeBinaryExpression) cexpr;
1565 return is_constant_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1568 var cparenthesized = (cexpr as CCodeParenthesizedExpression);
1569 return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
1572 public static bool is_constant_ccode (CodeNode expr) {
1573 if (expr is Constant) {
1574 // Local constants are not considered constant in C
1575 return !(((Constant) expr).parent_symbol is Block);
1576 } else if (expr is IntegerLiteral) {
1577 return ((IntegerLiteral) expr).is_constant ();
1578 } else if (expr is MemberAccess) {
1579 return is_constant_ccode (((MemberAccess) expr).symbol_reference);
1580 } else if (expr is CastExpression) {
1581 return is_constant_ccode (((CastExpression) expr).inner);
1588 * Returns whether the passed cexpr is a pure expression, i.e. an
1589 * expression without side-effects.
1591 public static bool is_pure_ccode_expression (CCodeExpression cexpr) {
1592 if (cexpr is CCodeConstant || cexpr is CCodeIdentifier) {
1594 } else if (cexpr is CCodeBinaryExpression) {
1595 var cbinary = (CCodeBinaryExpression) cexpr;
1596 return is_pure_ccode_expression (cbinary.left) && is_pure_ccode_expression (cbinary.right);
1597 } else if (cexpr is CCodeUnaryExpression) {
1598 var cunary = (CCodeUnaryExpression) cexpr;
1599 switch (cunary.operator) {
1600 case CCodeUnaryOperator.PREFIX_INCREMENT:
1601 case CCodeUnaryOperator.PREFIX_DECREMENT:
1602 case CCodeUnaryOperator.POSTFIX_INCREMENT:
1603 case CCodeUnaryOperator.POSTFIX_DECREMENT:
1606 return is_pure_ccode_expression (cunary.inner);
1608 } else if (cexpr is CCodeMemberAccess) {
1609 var cma = (CCodeMemberAccess) cexpr;
1610 return is_pure_ccode_expression (cma.inner);
1611 } else if (cexpr is CCodeElementAccess) {
1612 var cea = (CCodeElementAccess) cexpr;
1613 return is_pure_ccode_expression (cea.container) && is_pure_ccode_expression (cea.indices[0]);
1614 } else if (cexpr is CCodeCastExpression) {
1615 var ccast = (CCodeCastExpression) cexpr;
1616 return is_pure_ccode_expression (ccast.inner);
1617 } else if (cexpr is CCodeParenthesizedExpression) {
1618 var cparenthesized = (CCodeParenthesizedExpression) cexpr;
1619 return is_pure_ccode_expression (cparenthesized.inner);
1625 public override void visit_property (Property prop) {
1626 visit_member (prop);
1628 if (prop.get_accessor != null) {
1629 prop.get_accessor.accept (this);
1631 if (prop.set_accessor != null) {
1632 prop.set_accessor.accept (this);
1636 public void generate_type_declaration (DataType type, CCodeFile decl_space) {
1637 if (type is ObjectType) {
1638 var object_type = (ObjectType) type;
1639 if (object_type.type_symbol is Class) {
1640 var cl = (Class) object_type.type_symbol;
1641 generate_class_declaration (cl, decl_space);
1642 if (!cl.is_compact && cl.has_type_parameters ()) {
1643 generate_struct_declaration ((Struct) gtype_type, decl_space);
1645 } else if (object_type.type_symbol is Interface) {
1646 var iface = (Interface) object_type.type_symbol;
1647 generate_interface_declaration (iface, decl_space);
1648 if (iface.has_type_parameters ()) {
1649 generate_struct_declaration ((Struct) gtype_type, decl_space);
1652 } else if (type is DelegateType) {
1653 var deleg_type = (DelegateType) type;
1654 var d = deleg_type.delegate_symbol;
1655 generate_delegate_declaration (d, decl_space);
1657 generate_type_declaration (delegate_target_type, decl_space);
1658 if (deleg_type.is_disposable ()) {
1659 generate_type_declaration (delegate_target_destroy_type, decl_space);
1662 } else if (type.type_symbol is Enum) {
1663 var en = (Enum) type.type_symbol;
1664 generate_enum_declaration (en, decl_space);
1665 } else if (type is ValueType) {
1666 var value_type = (ValueType) type;
1667 generate_struct_declaration ((Struct) value_type.type_symbol, decl_space);
1668 } else if (type is ArrayType) {
1669 var array_type = (ArrayType) type;
1670 generate_type_declaration (array_type.element_type, decl_space);
1671 if (array_type.length_type != null) {
1672 generate_type_declaration (array_type.length_type, decl_space);
1674 } else if (type is ErrorType) {
1675 var error_type = (ErrorType) type;
1676 if (error_type.error_domain != null) {
1677 generate_error_domain_declaration (error_type.error_domain, decl_space);
1679 generate_class_declaration (gerror, decl_space);
1681 } else if (type is PointerType) {
1682 var pointer_type = (PointerType) type;
1683 generate_type_declaration (pointer_type.base_type, decl_space);
1684 } else if (type is MethodType) {
1685 var method = ((MethodType) type).method_symbol;
1686 if (method.has_type_parameters () && !get_ccode_simple_generics (method)) {
1687 generate_struct_declaration ((Struct) gtype_type, decl_space);
1691 foreach (DataType type_arg in type.get_type_arguments ()) {
1692 generate_type_declaration (type_arg, decl_space);
1696 public virtual void generate_class_struct_declaration (Class cl, CCodeFile decl_space) {
1699 public virtual void generate_struct_declaration (Struct st, CCodeFile decl_space) {
1702 public virtual void generate_delegate_declaration (Delegate d, CCodeFile decl_space) {
1705 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) {
1708 public void generate_property_accessor_declaration (PropertyAccessor acc, CCodeFile decl_space) {
1709 if (add_symbol_declaration (decl_space, acc, get_ccode_name (acc))) {
1713 var prop = (Property) acc.prop;
1715 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1718 CCodeParameter cvalueparam;
1719 if (returns_real_struct) {
1720 cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (acc.value_type)));
1721 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1722 cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (acc.value_type)));
1724 cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1726 generate_type_declaration (acc.value_type, decl_space);
1728 CCodeFunction function;
1729 if (acc.readable && !returns_real_struct) {
1730 function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (acc.value_type));
1732 function = new CCodeFunction (get_ccode_name (acc), "void");
1735 if (prop.binding == MemberBinding.INSTANCE) {
1736 var t = (TypeSymbol) prop.parent_symbol;
1737 var this_type = SemanticAnalyzer.get_data_type_for_symbol (t);
1738 generate_type_declaration (this_type, decl_space);
1739 var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1740 if (t is Struct && !((Struct) t).is_simple_type ()) {
1741 cselfparam.type_name += "*";
1744 function.add_parameter (cselfparam);
1747 if (acc.writable || acc.construction || returns_real_struct) {
1748 function.add_parameter (cvalueparam);
1751 if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1752 var array_type = (ArrayType) acc.value_type;
1753 var length_ctype = get_ccode_array_length_type (prop);
1754 for (int dim = 1; dim <= array_type.rank; dim++) {
1755 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? length_ctype + "*" : length_ctype));
1757 } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1758 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? get_ccode_name (delegate_target_type) + "*" : get_ccode_name (delegate_target_type)));
1759 if (!acc.readable && acc.value_type.value_owned) {
1760 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), get_ccode_name (delegate_target_destroy_type)));
1764 if (prop.version.deprecated) {
1765 if (context.profile == Profile.GOBJECT) {
1766 decl_space.add_include ("glib.h");
1768 function.modifiers |= CCodeModifiers.DEPRECATED;
1771 if (!prop.is_abstract
1772 && (prop.is_private_symbol () || (!acc.readable && !acc.writable) || acc.access == SymbolAccessibility.PRIVATE)) {
1773 function.modifiers |= CCodeModifiers.STATIC;
1774 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1775 function.modifiers |= CCodeModifiers.INTERNAL;
1777 function.modifiers |= CCodeModifiers.EXTERN;
1778 requires_vala_extern = true;
1780 decl_space.add_function_declaration (function);
1783 public override void visit_property_accessor (PropertyAccessor acc) {
1784 push_context (new EmitContext (acc));
1785 push_line (acc.source_reference);
1787 var prop = (Property) acc.prop;
1789 if (acc.comment != null) {
1790 cfile.add_type_member_definition (new CCodeComment (acc.comment.content));
1793 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1795 if (acc.result_var != null) {
1796 acc.result_var.accept (this);
1799 var t = (TypeSymbol) prop.parent_symbol;
1801 // do not declare overriding properties and interface implementations
1802 if (prop.is_abstract || prop.is_virtual
1803 || (prop.base_property == null && prop.base_interface_property == null)) {
1804 generate_property_accessor_declaration (acc, cfile);
1806 // do not declare construct-only properties in header files
1807 if (acc.readable || acc.writable) {
1808 if (!prop.is_internal_symbol ()
1809 && (acc.access == SymbolAccessibility.PUBLIC
1810 || acc.access == SymbolAccessibility.PROTECTED)) {
1811 generate_property_accessor_declaration (acc, header_file);
1813 if (!prop.is_private_symbol () && acc.access != SymbolAccessibility.PRIVATE) {
1814 generate_property_accessor_declaration (acc, internal_header_file);
1819 if (acc.source_type == SourceFileType.FAST) {
1825 var this_type = SemanticAnalyzer.get_data_type_for_symbol (t);
1826 var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1827 if (t is Struct && !((Struct) t).is_simple_type ()) {
1828 cselfparam.type_name += "*";
1830 CCodeParameter cvalueparam;
1831 if (returns_real_struct) {
1832 cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (acc.value_type)));
1833 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1834 cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (acc.value_type)));
1836 cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1839 if (prop.is_abstract || prop.is_virtual) {
1840 CCodeFunction function;
1841 if (acc.readable && !returns_real_struct) {
1842 function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (current_return_type));
1844 function = new CCodeFunction (get_ccode_name (acc), "void");
1846 function.add_parameter (cselfparam);
1847 if (acc.writable || acc.construction || returns_real_struct) {
1848 function.add_parameter (cvalueparam);
1851 if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1852 var array_type = (ArrayType) acc.value_type;
1853 var length_ctype = get_ccode_array_length_type (prop);
1854 for (int dim = 1; dim <= array_type.rank; dim++) {
1855 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? length_ctype + "*": length_ctype));
1857 } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1858 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? get_ccode_name (delegate_target_type) + "*" : get_ccode_name (delegate_target_type)));
1859 if (!acc.readable && acc.value_type.value_owned) {
1860 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), get_ccode_name (delegate_target_destroy_type)));
1864 if (!prop.is_abstract
1865 && (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE)) {
1866 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1867 function.modifiers |= CCodeModifiers.STATIC;
1868 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1869 function.modifiers |= CCodeModifiers.INTERNAL;
1872 push_function (function);
1874 if (acc.value_type.is_non_null_simple_type () && default_value_for_type (acc.value_type, false) == null) {
1875 var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (acc.value_type, true));
1876 vardecl.init0 = true;
1877 ccode.add_declaration (get_ccode_name (acc.value_type), vardecl);
1880 if (prop.binding == MemberBinding.INSTANCE) {
1881 if (!acc.readable || returns_real_struct) {
1882 create_property_type_check_statement (prop, false, t, true, "self");
1884 create_property_type_check_statement (prop, true, t, true, "self");
1888 CCodeExpression vcast;
1889 if (prop.parent_symbol is Interface) {
1890 var iface = (Interface) prop.parent_symbol;
1892 vcast = new CCodeIdentifier ("_iface_");
1893 var vcastcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
1894 ((CCodeFunctionCall) vcastcall).add_argument (new CCodeIdentifier ("self"));
1895 ccode.add_declaration ("%s*".printf (get_ccode_type_name (iface)), new CCodeVariableDeclarator ("_iface_"));
1896 ccode.add_assignment (vcast, vcastcall);
1898 var cl = (Class) prop.parent_symbol;
1899 if (!cl.is_compact) {
1900 vcast = new CCodeIdentifier ("_klass_");
1901 var vcastcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
1902 ((CCodeFunctionCall) vcastcall).add_argument (new CCodeIdentifier ("self"));
1903 ccode.add_declaration ("%s*".printf (get_ccode_type_name (cl)), new CCodeVariableDeclarator ("_klass_"));
1904 ccode.add_assignment (vcast, vcastcall);
1906 vcast = new CCodeIdentifier ("self");
1911 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
1912 vcall.add_argument (new CCodeIdentifier ("self"));
1914 // check if vfunc pointer is properly set
1915 ccode.open_if (vcall.call);
1917 if (returns_real_struct) {
1918 vcall.add_argument (new CCodeIdentifier ("result"));
1919 ccode.add_expression (vcall);
1921 if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1922 var array_type = (ArrayType) acc.value_type;
1924 for (int dim = 1; dim <= array_type.rank; dim++) {
1925 var len_expr = new CCodeIdentifier (get_array_length_cname ("result", dim));
1926 vcall.add_argument (len_expr);
1928 } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1929 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("result")));
1932 ccode.add_return (vcall);
1936 if (acc.value_type.is_non_null_simple_type () && default_value_for_type (acc.value_type, false) == null) {
1937 ccode.add_return (new CCodeIdentifier ("result"));
1938 } else if (!(acc.value_type is VoidType)) {
1939 ccode.add_return (default_value_for_type (acc.value_type, false, true));
1942 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
1943 vcall.add_argument (new CCodeIdentifier ("self"));
1944 vcall.add_argument (new CCodeIdentifier ("value"));
1946 // check if vfunc pointer is properly set
1947 ccode.open_if (vcall.call);
1949 if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1950 var array_type = (ArrayType) acc.value_type;
1952 for (int dim = 1; dim <= array_type.rank; dim++) {
1953 var len_expr = new CCodeIdentifier (get_array_length_cname ("value", dim));
1954 vcall.add_argument (len_expr);
1956 } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1957 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("value")));
1958 if (!acc.readable && acc.value_type.value_owned) {
1959 vcall.add_argument (new CCodeIdentifier (get_delegate_target_destroy_notify_cname ("value")));
1963 ccode.add_expression (vcall);
1969 cfile.add_function (function);
1972 if (!prop.is_abstract && acc.body != null) {
1973 bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
1975 string cname = get_ccode_real_name (acc);
1977 CCodeFunction function;
1978 if (acc.writable || acc.construction || returns_real_struct) {
1979 function = new CCodeFunction (cname, "void");
1981 function = new CCodeFunction (cname, get_ccode_name (acc.value_type));
1984 ObjectType base_type = null;
1985 if (prop.binding == MemberBinding.INSTANCE) {
1987 if (prop.base_property != null) {
1988 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
1989 } else if (prop.base_interface_property != null) {
1990 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
1992 function.modifiers |= CCodeModifiers.STATIC;
1993 function.add_parameter (new CCodeParameter ("base", get_ccode_name (base_type)));
1995 function.add_parameter (cselfparam);
1998 if (acc.writable || acc.construction || returns_real_struct) {
1999 function.add_parameter (cvalueparam);
2002 if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
2003 var array_type = (ArrayType) acc.value_type;
2004 var length_ctype = get_ccode_array_length_type (prop);
2005 for (int dim = 1; dim <= array_type.rank; dim++) {
2006 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? length_ctype + "*" : length_ctype));
2008 } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
2009 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? get_ccode_name (delegate_target_type) + "*" : get_ccode_name (delegate_target_type)));
2010 if (!acc.readable && acc.value_type.value_owned) {
2011 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), get_ccode_name (delegate_target_destroy_type)));
2016 if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
2017 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
2018 function.modifiers |= CCodeModifiers.STATIC;
2019 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
2020 function.modifiers |= CCodeModifiers.INTERNAL;
2024 push_function (function);
2026 if (prop.binding == MemberBinding.INSTANCE && !is_virtual) {
2027 if (!acc.readable || returns_real_struct) {
2028 create_property_type_check_statement (prop, false, t, true, "self");
2030 create_property_type_check_statement (prop, true, t, true, "self");
2034 if (acc.readable && !returns_real_struct) {
2035 // do not declare result variable if exit block is known to be unreachable
2036 if (acc.return_block == null || acc.return_block.get_predecessors ().size > 0) {
2037 ccode.add_declaration (get_ccode_name (acc.value_type), new CCodeVariableDeclarator ("result"));
2042 ccode.add_declaration (get_ccode_name (this_type), new CCodeVariableDeclarator ("self"));
2043 ccode.add_assignment (new CCodeIdentifier ("self"), get_cvalue_ (transform_value (new GLibValue (base_type, new CCodeIdentifier ("base"), true), this_type, acc)));
2046 // notify on property changes
2047 if (context.analyzer.is_gobject_property (prop) &&
2049 (acc.writable || acc.construction)) {
2050 var notify_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_notify_by_pspec"));
2051 notify_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
2052 notify_call.add_argument (get_param_spec_cexpression (prop));
2054 var get_accessor = prop.get_accessor;
2055 if (get_accessor != null && get_accessor.automatic_body) {
2056 var property_type = prop.property_type;
2057 var get_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (get_accessor)));
2058 get_call.add_argument (new CCodeIdentifier (is_virtual ? "base" : "self"));
2060 if (property_type is ArrayType && get_ccode_array_length (prop)) {
2061 ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2062 ccode.add_declaration (get_ccode_array_length_type (prop), new CCodeVariableDeclarator ("old_value_length"));
2063 get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value_length")));
2064 ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2065 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("old_value"), new CCodeIdentifier ("value")));
2066 } else if (property_type.compatible (string_type)) {
2067 ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2068 ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2069 CCodeFunctionCall ccall;
2070 if (context.profile == Profile.POSIX) {
2071 cfile.add_include ("string.h");
2072 ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
2074 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
2076 ccall.add_argument (new CCodeIdentifier ("value"));
2077 ccall.add_argument (new CCodeIdentifier ("old_value"));
2078 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("0")));
2079 } else if (property_type is StructValueType) {
2080 ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2081 if (property_type.nullable) {
2082 ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2084 get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value")));
2085 ccode.add_expression (get_call);
2087 var equalfunc = generate_struct_equal_function ((Struct) property_type.type_symbol);
2088 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
2089 ccall.add_argument (new CCodeIdentifier ("value"));
2090 if (property_type.nullable) {
2091 ccall.add_argument (new CCodeIdentifier ("old_value"));
2093 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value")));
2095 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("TRUE")));
2097 ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2098 ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2099 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("old_value"), new CCodeIdentifier ("value")));
2102 acc.body.emit (this);
2103 ccode.add_expression (notify_call);
2106 if (prop.get_accessor.value_type.is_disposable ()) {
2107 var old_value = new GLibValue (prop.get_accessor.value_type, new CCodeIdentifier ("old_value"), true);
2108 if (property_type is ArrayType && get_ccode_array_length (prop)) {
2109 old_value.append_array_length_cvalue (new CCodeIdentifier ("old_value_length"));
2111 ccode.add_expression (destroy_value (old_value));
2114 acc.body.emit (this);
2115 ccode.add_expression (notify_call);
2118 acc.body.emit (this);
2121 if (current_method_inner_error) {
2122 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
2127 cfile.add_function (function);
2134 public override void visit_destructor (Destructor d) {
2135 if (d.binding == MemberBinding.STATIC && !in_plugin) {
2136 Report.error (d.source_reference, "static destructors are only supported for dynamic types");
2142 public int get_block_id (Block b) {
2143 int result = block_map[b];
2145 result = ++next_block_id;
2146 block_map[b] = result;
2151 public bool no_implicit_copy (DataType type) {
2152 // note: implicit copy of array is planned to be forbidden
2153 unowned Class? cl = type.type_symbol as Class;
2154 return (type is DelegateType ||
2155 type is ArrayType ||
2156 (cl != null && !cl.is_immutable && !is_reference_counting (cl) && !get_ccode_is_gboxed (cl)));
2159 void capture_parameter (Parameter param, CCodeStruct data, int block_id) {
2160 generate_type_declaration (param.variable_type, cfile);
2162 var param_type = param.variable_type.copy ();
2163 if (!param.variable_type.value_owned) {
2164 param_type.value_owned = !no_implicit_copy (param.variable_type);
2166 data.add_field (get_ccode_name (param_type), get_ccode_name (param), 0, get_ccode_declarator_suffix (param_type));
2168 // create copy if necessary as captured variables may need to be kept alive
2169 param.captured = false;
2170 var value = load_parameter (param);
2172 var array_type = param.variable_type as ArrayType;
2173 var deleg_type = param.variable_type as DelegateType;
2175 if (array_type != null && get_ccode_array_length (param) && !((ArrayType) array_type).fixed_length) {
2176 var length_ctype = get_ccode_array_length_type (param);
2177 for (int dim = 1; dim <= array_type.rank; dim++) {
2178 data.add_field (length_ctype, get_variable_array_length_cname (param, dim));
2180 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
2181 data.add_field (get_ccode_name (delegate_target_type), get_ccode_delegate_target_name (param));
2182 if (param.variable_type.is_disposable ()) {
2183 data.add_field (get_ccode_name (delegate_target_destroy_type), get_ccode_delegate_target_destroy_notify_name (param));
2184 // reference transfer for delegates
2185 var lvalue = get_parameter_cvalue (param);
2186 ((GLibValue) value).delegate_target_destroy_notify_cvalue = get_delegate_target_destroy_notify_cvalue (lvalue);
2189 param.captured = true;
2191 store_parameter (param, value, true);
2194 public override void visit_block (Block b) {
2195 emit_context.push_symbol (b);
2197 var local_vars = b.get_local_variables ();
2199 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
2200 ccode.open_block ();
2203 if (b.parent_node is TryStatement && b == ((TryStatement) b.parent_node).finally_body) {
2204 // finally-block with nested error handling
2205 if (((TryStatement) b.parent_node).body.tree_can_fail) {
2206 if (is_in_coroutine ()) {
2207 // _inner_error0_ gets added to closure_struct in CCodeMethodModule.visit_method()
2208 if (current_inner_error_id > 0
2209 && (!method_inner_error_var_count.contains (current_method)
2210 || method_inner_error_var_count.get (current_method) < current_inner_error_id)) {
2211 // no initialization necessary, closure struct is zeroed
2212 closure_struct.add_field ("GError*", "_inner_error%d_".printf (current_inner_error_id));
2213 method_inner_error_var_count.set (current_method, current_inner_error_id);
2216 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
2222 var parent_block = next_closure_block (b.parent_symbol);
2224 int block_id = get_block_id (b);
2225 string struct_name = "Block%dData".printf (block_id);
2227 var data = new CCodeStruct ("_" + struct_name);
2228 data.add_field ("int", "_ref_count_");
2229 if (parent_block != null) {
2230 int parent_block_id = get_block_id (parent_block);
2232 data.add_field ("Block%dData *".printf (parent_block_id), "_data%d_".printf (parent_block_id));
2234 unowned DataType? this_type = get_this_type ();
2235 if (this_type != null) {
2236 data.add_field (get_ccode_name (this_type), "self");
2239 if (current_method != null) {
2240 // allow capturing generic type parameters
2241 foreach (var type_param in current_method.get_type_parameters ()) {
2242 data.add_field ("GType", get_ccode_type_id (type_param));
2243 data.add_field ("GBoxedCopyFunc", get_ccode_copy_function (type_param));
2244 data.add_field ("GDestroyNotify", get_ccode_destroy_function (type_param));
2248 foreach (var local in local_vars) {
2249 if (local.captured) {
2250 generate_type_declaration (local.variable_type, cfile);
2252 data.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
2254 if (local.variable_type is ArrayType && !((ArrayType) local.variable_type).fixed_length) {
2255 var array_type = (ArrayType) local.variable_type;
2256 var length_ctype = get_ccode_array_length_type (array_type);
2257 for (int dim = 1; dim <= array_type.rank; dim++) {
2258 data.add_field (length_ctype, get_array_length_cname (get_local_cname (local), dim));
2260 data.add_field (length_ctype, get_array_size_cname (get_local_cname (local)));
2261 } else if (local.variable_type is DelegateType && ((DelegateType) local.variable_type).delegate_symbol.has_target) {
2262 data.add_field (get_ccode_name (delegate_target_type), get_delegate_target_cname (get_local_cname (local)));
2263 if (local.variable_type.is_disposable ()) {
2264 data.add_field (get_ccode_name (delegate_target_destroy_type), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2266 } else if (local.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
2267 Report.error (local.source_reference, "internal: Capturing `va_list' variable `%s' is not allowed", local.get_full_name ());
2273 var data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
2274 data_alloc.add_argument (new CCodeIdentifier (struct_name));
2276 if (is_in_coroutine ()) {
2277 closure_struct.add_field (struct_name + "*", "_data%d_".printf (block_id));
2279 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id)));
2281 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), data_alloc);
2283 // initialize ref_count
2284 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_ref_count_"), new CCodeIdentifier ("1"));
2286 if (parent_block != null) {
2287 int parent_block_id = get_block_id (parent_block);
2289 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (parent_block_id)));
2290 ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id)));
2292 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call);
2294 // skip self assignment in toplevel block of creation methods with chainup as self is not set at the beginning of the method
2295 // the chainup statement takes care of assigning self in the closure struct
2296 bool in_creation_method_with_chainup = (current_method is CreationMethod && current_class != null && current_class.base_class != null);
2298 unowned DataType? this_type = get_this_type ();
2299 if (this_type != null && (!in_creation_method_with_chainup || current_method.body != b)) {
2300 CCodeExpression instance;
2301 if (is_in_destructor ()) {
2302 // never increase reference count for self in finalizers to avoid infinite recursion on following unref
2303 instance = new CCodeIdentifier ("self");
2305 var ref_call = new CCodeFunctionCall (get_dup_func_expression (this_type, b.source_reference));
2306 ref_call.add_argument (get_this_cexpression ());
2307 instance = ref_call;
2310 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), instance);
2313 if (current_method != null) {
2314 // allow capturing generic type parameters
2315 var data_var = get_variable_cexpression ("_data%d_".printf (block_id));
2316 foreach (var type_param in current_method.get_type_parameters ()) {
2317 var type = get_ccode_type_id (type_param);
2318 var dup_func = get_ccode_copy_function (type_param);
2319 var destroy_func = get_ccode_destroy_function (type_param);
2320 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, type), get_variable_cexpression (type));
2321 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, dup_func), get_variable_cexpression (dup_func));
2322 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, destroy_func), get_variable_cexpression (destroy_func));
2327 if (b.parent_symbol is Method) {
2328 var m = (Method) b.parent_symbol;
2330 // parameters are captured with the top-level block of the method
2331 foreach (var param in m.get_parameters ()) {
2332 if (param.captured) {
2333 capture_parameter (param, data, block_id);
2335 if (param.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
2336 Report.error (param.source_reference, "internal: Capturing `va_list' parameter `%s' is not allowed", param.get_full_name ());
2343 // capture async data to allow invoking callback from inside closure
2344 data.add_field (get_ccode_name (pointer_type), "_async_data_");
2346 // async method is suspended while waiting for callback,
2347 // so we never need to care about memory management of async data
2348 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_async_data_"), new CCodeIdentifier ("_data_"));
2350 } else if (b.parent_symbol is PropertyAccessor) {
2351 var acc = (PropertyAccessor) b.parent_symbol;
2353 if (!acc.readable && acc.value_parameter.captured) {
2354 capture_parameter (acc.value_parameter, data, block_id);
2356 } else if (b.parent_symbol is ForeachStatement) {
2357 var stmt = (ForeachStatement) b.parent_symbol;
2358 if (!stmt.use_iterator && stmt.element_variable.captured) {
2359 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)));
2363 var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name));
2364 cfile.add_type_declaration (typedef);
2365 cfile.add_type_definition (data);
2367 // create ref/unref functions
2368 var ref_fun = new CCodeFunction ("block%d_data_ref".printf (block_id), struct_name + "*");
2369 ref_fun.add_parameter (new CCodeParameter ("_data%d_".printf (block_id), struct_name + "*"));
2370 ref_fun.modifiers = CCodeModifiers.STATIC;
2372 push_function (ref_fun);
2374 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_inc"));
2375 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2376 ccode.add_expression (ccall);
2377 ccode.add_return (new CCodeIdentifier ("_data%d_".printf (block_id)));
2381 cfile.add_function_declaration (ref_fun);
2382 cfile.add_function (ref_fun);
2384 var unref_fun = new CCodeFunction ("block%d_data_unref".printf (block_id), "void");
2385 unref_fun.add_parameter (new CCodeParameter ("_userdata_", "void *"));
2386 unref_fun.modifiers = CCodeModifiers.STATIC;
2388 push_function (unref_fun);
2390 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id), new CCodeCastExpression (new CCodeIdentifier ("_userdata_"), struct_name + "*")));
2391 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_dec_and_test"));
2392 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2393 ccode.open_if (ccall);
2395 CCodeExpression outer_block = new CCodeIdentifier ("_data%d_".printf (block_id));
2396 unowned Block parent_closure_block = b;
2398 parent_closure_block = next_closure_block (parent_closure_block.parent_symbol);
2399 if (parent_closure_block == null) {
2402 int parent_block_id = get_block_id (parent_closure_block);
2403 outer_block = new CCodeMemberAccess.pointer (outer_block, "_data%d_".printf (parent_block_id));
2406 var this_type = get_this_type ();
2407 if (this_type != null) {
2408 // assign "self" for type parameters
2409 ccode.add_declaration(get_ccode_name (this_type), new CCodeVariableDeclarator ("self"));
2410 ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeMemberAccess.pointer (outer_block, "self"));
2413 if (current_method != null) {
2414 // assign captured generic type parameters
2415 foreach (var type_param in current_method.get_type_parameters ()) {
2416 var type = get_ccode_type_id (type_param);
2417 var dup_func = get_ccode_copy_function (type_param);
2418 var destroy_func = get_ccode_destroy_function (type_param);
2419 ccode.add_declaration ("GType", new CCodeVariableDeclarator (type));
2420 ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (dup_func));
2421 ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (destroy_func));
2422 ccode.add_assignment (new CCodeIdentifier (type), new CCodeMemberAccess.pointer (outer_block, type));
2423 ccode.add_assignment (new CCodeIdentifier (dup_func), new CCodeMemberAccess.pointer (outer_block, dup_func));
2424 ccode.add_assignment (new CCodeIdentifier (destroy_func), new CCodeMemberAccess.pointer (outer_block, destroy_func));
2428 // free in reverse order
2429 for (int i = local_vars.size - 1; i >= 0; i--) {
2430 var local = local_vars[i];
2431 if (local.captured) {
2432 if (requires_destroy (local.variable_type)) {
2433 bool old_coroutine = false;
2434 if (current_method != null) {
2435 old_coroutine = current_method.coroutine;
2436 current_method.coroutine = false;
2439 ccode.add_expression (destroy_local (local));
2441 if (old_coroutine) {
2442 current_method.coroutine = true;
2448 if (b.parent_symbol is Method) {
2449 var m = (Method) b.parent_symbol;
2451 // parameters are captured with the top-level block of the method
2452 foreach (var param in m.get_parameters ()) {
2453 if (param.captured) {
2454 var param_type = param.variable_type.copy ();
2455 if (!param_type.value_owned) {
2456 param_type.value_owned = !no_implicit_copy (param_type);
2459 if (requires_destroy (param_type)) {
2460 bool old_coroutine = false;
2462 old_coroutine = m.coroutine;
2463 m.coroutine = false;
2466 ccode.add_expression (destroy_parameter (param));
2468 if (old_coroutine) {
2474 } else if (b.parent_symbol is PropertyAccessor) {
2475 var acc = (PropertyAccessor) b.parent_symbol;
2477 if (!acc.readable && acc.value_parameter.captured) {
2478 var param_type = acc.value_parameter.variable_type.copy ();
2479 if (!param_type.value_owned) {
2480 param_type.value_owned = !no_implicit_copy (param_type);
2483 if (requires_destroy (param_type)) {
2484 ccode.add_expression (destroy_parameter (acc.value_parameter));
2489 // free parent block and "self" after captured variables
2490 // because they may require type parameters
2491 if (parent_block != null) {
2492 int parent_block_id = get_block_id (parent_block);
2494 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (parent_block_id)));
2495 unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
2496 ccode.add_expression (unref_call);
2497 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), new CCodeConstant ("NULL"));
2499 this_type = get_this_type ();
2500 if (this_type != null) {
2501 this_type = this_type.copy ();
2502 this_type.value_owned = true;
2503 if (this_type.is_disposable () && !is_in_destructor ()) {
2504 // reference count for self is not increased in finalizers
2505 var this_value = new GLibValue (this_type, new CCodeIdentifier ("self"), true);
2506 ccode.add_expression (destroy_value (this_value));
2511 var data_free = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
2512 data_free.add_argument (new CCodeIdentifier (struct_name));
2513 data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id)));
2514 ccode.add_expression (data_free);
2520 cfile.add_function_declaration (unref_fun);
2521 cfile.add_function (unref_fun);
2524 foreach (Statement stmt in b.get_statements ()) {
2525 push_line (stmt.source_reference);
2530 if (!b.unreachable_exit) {
2531 if (b.parent_symbol is Method) {
2532 unowned Method m = (Method) b.parent_symbol;
2533 // check postconditions
2534 foreach (var postcondition in m.get_postconditions ()) {
2535 create_postcondition_statement (postcondition);
2539 // free in reverse order
2540 for (int i = local_vars.size - 1; i >= 0; i--) {
2541 var local = local_vars[i];
2542 local.active = false;
2543 if (!local.unreachable && !local.captured && requires_destroy (local.variable_type)) {
2544 ccode.add_expression (destroy_local (local));
2548 if (b.parent_symbol is Method) {
2549 var m = (Method) b.parent_symbol;
2550 foreach (Parameter param in m.get_parameters ()) {
2551 if (!param.captured && !param.ellipsis && !param.params_array && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
2552 ccode.add_expression (destroy_parameter (param));
2553 } else if (param.direction == ParameterDirection.OUT && !m.coroutine) {
2554 return_out_parameter (param);
2557 } else if (b.parent_symbol is PropertyAccessor) {
2558 var acc = (PropertyAccessor) b.parent_symbol;
2559 if (acc.value_parameter != null && !acc.value_parameter.captured && requires_destroy (acc.value_parameter.variable_type)) {
2560 ccode.add_expression (destroy_parameter (acc.value_parameter));
2565 int block_id = get_block_id (b);
2567 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
2568 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
2569 ccode.add_expression (data_unref);
2570 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
2574 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
2578 emit_context.pop_symbol ();
2581 public override void visit_declaration_statement (DeclarationStatement stmt) {
2582 stmt.declaration.accept (this);
2585 public CCodeExpression get_cexpression (string name) {
2586 if (is_in_coroutine ()) {
2587 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), name);
2589 return new CCodeIdentifier (name);
2593 public CCodeExpression get_local_cexpression (LocalVariable local) {
2594 return get_cexpression (get_local_cname (local));
2597 public CCodeExpression get_parameter_cexpression (Parameter param) {
2598 return get_cexpression (get_ccode_name (param));
2601 public CCodeExpression get_variable_cexpression (string name) {
2602 return get_cexpression (get_variable_cname (name));
2605 public CCodeExpression get_this_cexpression () {
2606 return get_cexpression ("self");
2609 public CCodeExpression get_this_class_cexpression (Class cl, TargetValue? instance = null) {
2610 CCodeExpression cast;
2611 CCodeFunctionCall call;
2612 if (instance != null) {
2613 // Accessing the member of an instance
2614 if (cl.external_package) {
2615 call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_CLASS"));
2616 call.add_argument (get_cvalue_ (instance));
2617 call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
2618 call.add_argument (new CCodeIdentifier (get_ccode_type_name (cl)));
2620 call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
2621 call.add_argument (get_cvalue_ (instance));
2624 } else if (get_this_type () != null) {
2625 // Accessing the member from within an instance method
2626 if (cl.external_package) {
2627 call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_CLASS"));
2628 call.add_argument (get_this_cexpression ());
2629 call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
2630 call.add_argument (new CCodeIdentifier (get_ccode_type_name (cl)));
2632 call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
2633 call.add_argument (get_this_cexpression ());
2637 // Accessing the member from a static or class constructor
2638 if (current_class == cl) {
2639 cast = new CCodeIdentifier ("klass");
2641 call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (cl)));
2642 call.add_argument (new CCodeIdentifier ("klass"));
2649 public CCodeExpression get_this_interface_cexpression (Interface iface, TargetValue? instance = null) {
2650 unowned Class? cl = current_class;
2651 if (cl != null && cl.implements (iface)) {
2652 return new CCodeIdentifier ("%s_%s_parent_iface".printf (get_ccode_lower_case_name (cl), get_ccode_lower_case_name (iface)));
2655 if (cl != null && !cl.is_a (iface)) {
2656 Report.warning (cl.source_reference, "internal: `%s' is not a `%s'", cl.get_full_name (), iface.get_full_name ());
2659 CCodeExpression cast;
2660 CCodeFunctionCall call;
2661 if (instance != null) {
2662 if (iface.external_package) {
2663 call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_INTERFACE"));
2664 call.add_argument (get_cvalue_ (instance));
2665 call.add_argument (new CCodeIdentifier (get_ccode_type_id (iface)));
2666 call.add_argument (new CCodeIdentifier (get_ccode_type_name (iface)));
2668 call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
2669 call.add_argument (get_cvalue_ (instance));
2672 } else if (get_this_type () != null) {
2673 if (iface.external_package) {
2674 call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_INTERFACE"));
2675 call.add_argument (get_this_cexpression ());
2676 call.add_argument (new CCodeIdentifier (get_ccode_type_id (iface)));
2677 call.add_argument (new CCodeIdentifier (get_ccode_type_name (iface)));
2679 call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
2680 call.add_argument (get_this_cexpression ());
2684 Report.error (null, "internal: missing instance");
2686 assert_not_reached ();
2691 public CCodeExpression get_inner_error_cexpression () {
2692 return get_cexpression ("_inner_error%d_".printf (current_inner_error_id));
2695 public string get_local_cname (LocalVariable local) {
2696 var cname = get_variable_cname (local.name);
2697 if (cname[0].isdigit ()) {
2698 cname = "_%s_".printf (cname);
2700 if (is_in_coroutine ()) {
2701 var clash_index = emit_context.closure_variable_clash_map.get (local);
2702 if (clash_index > 0) {
2703 cname = "_vala%d_%s".printf (clash_index, cname);
2709 public string get_variable_cname (string name) {
2710 if (name[0] == '.') {
2711 if (name == ".result") {
2714 // compiler-internal variable
2715 if (!variable_name_map.contains (name)) {
2716 variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
2719 return variable_name_map.get (name);
2720 } else if (reserved_identifiers.contains (name)) {
2721 return "_%s_".printf (name);
2727 public bool is_simple_struct_creation (Variable variable, Expression expr) {
2728 unowned Struct? st = variable.variable_type.type_symbol as Struct;
2729 var creation = expr as ObjectCreationExpression;
2730 if (creation != null && st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list") && !variable.variable_type.nullable &&
2731 variable.variable_type.type_symbol != gvalue_type && creation.get_object_initializer ().size == 0) {
2738 static bool is_foreach_element_variable (LocalVariable local) {
2739 var block = local.parent_symbol;
2740 if (block != null) {
2741 var stmt = block.parent_symbol as ForeachStatement;
2742 if (stmt != null && !stmt.use_iterator && stmt.element_variable == local) {
2749 public override void visit_local_variable (LocalVariable local) {
2752 generate_type_declaration (local.variable_type, cfile);
2754 // captured element variables of foreach statements (without iterator) require local declaration
2755 var declared = !local.captured || is_foreach_element_variable (local);
2757 if (is_in_coroutine ()) {
2758 var count = emit_context.closure_variable_count_map.get (local.name);
2760 emit_context.closure_variable_clash_map.set (local, count);
2762 emit_context.closure_variable_count_map.set (local.name, count + 1);
2764 closure_struct.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
2766 var cvar = new CCodeVariableDeclarator (get_local_cname (local), null, get_ccode_declarator_suffix (local.variable_type));
2768 // try to initialize uninitialized variables
2769 // initialization not necessary for variables stored in closure
2770 CCodeExpression? size = null;
2771 if (!requires_memset_init (local, out size)) {
2772 cvar.initializer = default_value_for_type (local.variable_type, true);
2774 } else if (size != null && local.initializer == null) {
2775 cfile.add_include ("string.h");
2776 var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
2777 memset_call.add_argument (get_variable_cexpression (local.name));
2778 memset_call.add_argument (new CCodeConstant ("0"));
2779 memset_call.add_argument (size);
2780 ccode.add_expression (memset_call);
2783 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
2787 /* Emit initializer */
2788 if (local.initializer != null) {
2789 local.initializer.emit (this);
2791 visit_end_full_expression (local.initializer);
2795 CCodeExpression rhs = null;
2796 if (local.initializer != null && get_cvalue (local.initializer) != null) {
2797 rhs = get_cvalue (local.initializer);
2800 /* Additional temp variables */
2803 if (local.variable_type is ArrayType) {
2804 // create variables to store array dimensions
2805 var array_type = (ArrayType) local.variable_type;
2807 if (!array_type.fixed_length) {
2808 for (int dim = 1; dim <= array_type.rank; dim++) {
2809 var len_var = new LocalVariable (array_type.length_type.copy (), get_array_length_cname (get_local_cname (local), dim));
2810 len_var.init = local.initializer == null;
2811 emit_temp_var (len_var);
2814 if (array_type.rank == 1) {
2815 var size_var = new LocalVariable (array_type.length_type.copy (), get_array_size_cname (get_local_cname (local)));
2816 size_var.init = local.initializer == null;
2817 emit_temp_var (size_var);
2820 } else if (local.variable_type is DelegateType) {
2821 var deleg_type = (DelegateType) local.variable_type;
2822 if (deleg_type.delegate_symbol.has_target) {
2823 // create variable to store delegate target
2824 var target_var = new LocalVariable (delegate_target_type.copy (), get_delegate_target_cname (get_local_cname (local)));
2825 target_var.init = local.initializer == null;
2826 emit_temp_var (target_var);
2827 if (deleg_type.is_disposable ()) {
2828 var target_destroy_notify_var = new LocalVariable (delegate_target_destroy_type.copy (), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2829 target_destroy_notify_var.init = local.initializer == null;
2830 emit_temp_var (target_destroy_notify_var);
2836 /* Store the initializer */
2839 if (!is_simple_struct_creation (local, local.initializer)) {
2840 store_local (local, local.initializer.target_value, true, local.source_reference);
2844 if (local.initializer != null && local.initializer.tree_can_fail) {
2845 add_simple_check (local.initializer);
2848 local.active = true;
2852 * Create a temporary variable and return lvalue access to it
2854 public TargetValue create_temp_value (DataType type, bool init, CodeNode node_reference, bool? value_owned = null) {
2855 if (type is VoidType) {
2856 Report.error (node_reference.source_reference, "internal: 'void' not supported as variable type");
2859 var local = new LocalVariable (type.copy (), "_tmp%d_".printf (next_temp_var_id++), null, node_reference.source_reference);
2861 if (value_owned != null) {
2862 local.variable_type.value_owned = value_owned;
2865 var array_type = local.variable_type as ArrayType;
2866 var deleg_type = local.variable_type as DelegateType;
2868 emit_temp_var (local);
2869 if (array_type != null) {
2870 for (int dim = 1; dim <= array_type.rank; dim++) {
2871 var len_var = new LocalVariable (array_type.length_type.copy (), get_array_length_cname (local.name, dim), null, node_reference.source_reference);
2872 len_var.init = init;
2873 emit_temp_var (len_var);
2875 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
2876 var target_var = new LocalVariable (delegate_target_type.copy (), get_delegate_target_cname (local.name), null, node_reference.source_reference);
2877 target_var.init = init;
2878 emit_temp_var (target_var);
2879 if (deleg_type.is_disposable ()) {
2880 var target_destroy_notify_var = new LocalVariable (delegate_target_destroy_type.copy (), get_delegate_target_destroy_notify_cname (local.name), null, node_reference.source_reference);
2881 target_destroy_notify_var.init = init;
2882 emit_temp_var (target_destroy_notify_var);
2886 var value = get_local_cvalue (local);
2887 set_array_size_cvalue (value, null);
2892 * Load a temporary variable returning unowned or owned rvalue access to it, depending on the ownership of the value type.
2894 public TargetValue load_temp_value (TargetValue lvalue) {
2895 var value = ((GLibValue) lvalue).copy ();
2896 var deleg_type = value.value_type as DelegateType;
2897 if (deleg_type != null) {
2898 if (!deleg_type.delegate_symbol.has_target) {
2899 value.delegate_target_cvalue = new CCodeConstant ("NULL");
2900 ((GLibValue) value).lvalue = false;
2901 } else if (!deleg_type.is_disposable ()) {
2902 value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
2903 ((GLibValue) value).lvalue = false;
2910 * Store a value in a temporary variable and return unowned or owned rvalue access to it, depending on the ownership of the given type.
2912 public TargetValue store_temp_value (TargetValue initializer, CodeNode node_reference, bool? value_owned = null) {
2913 var lvalue = create_temp_value (initializer.value_type, false, node_reference, value_owned);
2914 store_value (lvalue, initializer, node_reference.source_reference);
2915 return load_temp_value (lvalue);
2918 public override void visit_initializer_list (InitializerList list) {
2919 if (list.target_type.type_symbol is Struct) {
2920 /* initializer is used as struct initializer */
2921 unowned Struct st = (Struct) list.target_type.type_symbol;
2922 while (st.base_struct != null) {
2923 st = st.base_struct;
2926 if (list.parent_node is Constant || list.parent_node is Field || list.parent_node is InitializerList) {
2927 var clist = new CCodeInitializerList ();
2929 var field_it = st.get_fields ().iterator ();
2930 foreach (Expression expr in list.get_initializers ()) {
2932 while (field == null) {
2934 field = field_it.get ();
2935 if (field.binding != MemberBinding.INSTANCE) {
2936 // we only initialize instance fields
2941 var cexpr = get_cvalue (expr);
2943 string ctype = get_ccode_type (field);
2944 if (ctype != null) {
2945 cexpr = new CCodeCastExpression (cexpr, ctype);
2948 clist.append (cexpr);
2950 var array_type = field.variable_type as ArrayType;
2951 if (array_type != null && !array_type.fixed_length && get_ccode_array_length (field) && !get_ccode_array_null_terminated (field)) {
2952 for (int dim = 1; dim <= array_type.rank; dim++) {
2953 clist.append (get_array_length_cvalue (expr.target_value, dim));
2955 if (array_type.rank == 1 && field.is_internal_symbol ()) {
2956 clist.append (get_array_length_cvalue (expr.target_value, 1));
2961 if (list.size <= 0) {
2962 clist.append (new CCodeConstant ("0"));
2965 if (list.parent_node is Constant
2966 || (list.parent_node is Expression && ((Expression) list.parent_node).value_type is ArrayType)) {
2967 set_cvalue (list, clist);
2969 set_cvalue (list, new CCodeCastExpression (clist, get_ccode_name (list.target_type.type_symbol)));
2972 // used as expression
2973 var instance = create_temp_value (list.value_type, true, list);
2975 var field_it = st.get_fields ().iterator ();
2976 foreach (Expression expr in list.get_initializers ()) {
2978 while (field == null) {
2980 field = field_it.get ();
2981 if (field.binding != MemberBinding.INSTANCE) {
2982 // we only initialize instance fields
2987 store_field (field, instance, expr.target_value, expr.source_reference);
2990 list.target_value = instance;
2993 var clist = new CCodeInitializerList ();
2994 foreach (Expression expr in list.get_initializers ()) {
2995 clist.append (get_cvalue (expr));
2997 set_cvalue (list, clist);
3001 public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null, bool init = false) {
3002 var var_type = type.copy ();
3003 var_type.value_owned = value_owned;
3004 var local = new LocalVariable (var_type, "_tmp%d_".printf (next_temp_var_id));
3007 if (node_reference != null) {
3008 local.source_reference = node_reference.source_reference;
3016 bool is_in_generic_type (GenericType type) {
3017 if (current_symbol != null && type.type_parameter.parent_symbol is TypeSymbol
3018 && (current_method == null || current_method.binding == MemberBinding.INSTANCE)) {
3025 void require_generic_accessors (Interface iface) {
3026 if (iface.get_attribute ("GenericAccessors") == null) {
3027 Report.error (iface.source_reference,
3028 "missing generic type for interface `%s', add GenericAccessors attribute to interface declaration",
3029 iface.get_full_name ());
3033 CCodeExpression get_generic_type_expression (string identifier, GenericType type, bool is_chainup = false) {
3034 if (type.type_parameter.parent_symbol is Interface) {
3035 unowned Interface iface = (Interface) type.type_parameter.parent_symbol;
3036 require_generic_accessors (iface);
3038 var cast_self = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
3039 cast_self.add_argument (get_this_cexpression ());
3040 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, "get_%s".printf (identifier)));
3041 function_call.add_argument (get_this_cexpression ());
3042 return function_call;
3045 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
3046 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_this_cexpression (), "priv"), identifier);
3048 return get_variable_cexpression (identifier);
3052 public CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
3053 if (type is GenericType) {
3054 var type_parameter = ((GenericType) type).type_parameter;
3055 string identifier = get_ccode_type_id (type_parameter);
3056 return get_generic_type_expression (identifier, (GenericType) type, is_chainup);
3058 string type_id = get_ccode_type_id (type);
3059 if (type_id == "") {
3060 type_id = "G_TYPE_INVALID";
3062 generate_type_declaration (type, cfile);
3064 return new CCodeIdentifier (type_id);
3068 public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup = false) {
3069 if (type is ErrorType) {
3070 return new CCodeIdentifier ("g_error_copy");
3071 } else if (type is GenericType) {
3072 var type_parameter = ((GenericType) type).type_parameter;
3073 string identifier = get_ccode_copy_function (type_parameter);
3074 return get_generic_type_expression (identifier, (GenericType) type, is_chainup);
3075 } else if (type.type_symbol != null) {
3076 string dup_function;
3077 unowned Class? cl = type.type_symbol as Class;
3078 if (is_reference_counting (type.type_symbol)) {
3079 dup_function = get_ccode_ref_function ((ObjectTypeSymbol) type.type_symbol);
3080 if (type.type_symbol is Interface && dup_function == null) {
3081 Report.error (source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure", type.type_symbol.get_full_name ());
3082 return new CCodeInvalidExpression();
3084 } else if (cl != null && cl.is_immutable) {
3085 // allow duplicates of immutable instances as for example strings
3086 dup_function = get_ccode_dup_function (type.type_symbol);
3087 if (dup_function == null) {
3090 } else if (get_ccode_is_gboxed (type.type_symbol)) {
3091 // allow duplicates of gboxed instances
3092 dup_function = generate_dup_func_wrapper (type);
3093 if (dup_function == null) {
3096 } else if (type is ValueType) {
3097 dup_function = get_ccode_dup_function (type.type_symbol);
3098 if (dup_function == null && type.nullable) {
3099 dup_function = generate_struct_dup_wrapper ((ValueType) type);
3100 } else if (dup_function == null) {
3104 // duplicating non-reference counted objects may cause side-effects (and performance issues)
3105 Report.error (source_reference, "duplicating `%s' instance, use unowned variable or explicitly invoke copy method", type.type_symbol.name);
3106 return new CCodeInvalidExpression();
3109 return new CCodeIdentifier (dup_function);
3110 } else if (type is PointerType) {
3111 var pointer_type = (PointerType) type;
3112 return get_dup_func_expression (pointer_type.base_type, source_reference);
3114 return new CCodeConstant ("NULL");
3118 void make_comparable_cexpression (ref DataType left_type, ref CCodeExpression cleft, ref DataType right_type, ref CCodeExpression cright) {
3119 unowned Struct? left_type_as_struct = left_type.type_symbol as Struct;
3120 unowned Struct? right_type_as_struct = right_type.type_symbol as Struct;
3121 unowned ObjectTypeSymbol? left_type_as_object_type = left_type.type_symbol as ObjectTypeSymbol;
3122 unowned ObjectTypeSymbol? right_type_as_object_type = right_type.type_symbol as ObjectTypeSymbol;
3124 if (left_type_as_object_type != null && (!(left_type_as_object_type is Class) || !((Class) left_type_as_object_type).is_compact)
3125 && right_type_as_object_type != null && (!(right_type_as_object_type is Class) || !((Class) right_type_as_object_type).is_compact)) {
3126 if (left_type_as_object_type != right_type_as_object_type) {
3127 if (left_type_as_object_type.is_subtype_of (right_type_as_object_type)) {
3128 cleft = generate_instance_cast (cleft, right_type_as_object_type);
3129 } else if (right_type_as_object_type.is_subtype_of (left_type_as_object_type)) {
3130 cright = generate_instance_cast (cright, left_type_as_object_type);
3133 } else if (left_type_as_struct != null && right_type_as_struct != null) {
3134 if (left_type is StructValueType) {
3135 // real structs (uses compare/equal function)
3136 if (!left_type.nullable) {
3137 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft);
3139 if (!right_type.nullable) {
3140 cright = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cright);
3143 // integer or floating or boolean type
3144 if (left_type.nullable && right_type.nullable) {
3145 // FIXME also compare contents, not just address
3146 } else if (left_type.nullable) {
3147 // FIXME check left value is not null
3148 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
3149 } else if (right_type.nullable) {
3150 // FIXME check right value is not null
3151 cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
3157 private string generate_struct_equal_function (Struct st) {
3158 if (st.base_struct != null) {
3159 return generate_struct_equal_function (st.base_struct);
3162 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (st));
3164 if (!add_wrapper (equal_func)) {
3165 // wrapper already defined
3169 var function = new CCodeFunction (equal_func, get_ccode_name (bool_type));
3170 function.modifiers = CCodeModifiers.STATIC;
3172 function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (st))));
3173 function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (st))));
3175 push_function (function);
3177 // if (s1 == s2) return TRUE;
3179 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
3180 ccode.open_if (cexp);
3181 ccode.add_return (get_boolean_cconstant (true));
3184 // if (s1 == NULL || s2 == NULL) return FALSE;
3186 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
3187 ccode.open_if (cexp);
3188 ccode.add_return (get_boolean_cconstant (false));
3191 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
3192 ccode.open_if (cexp);
3193 ccode.add_return (get_boolean_cconstant (false));
3197 bool has_instance_fields = false;
3198 foreach (Field f in st.get_fields ()) {
3199 if (f.binding != MemberBinding.INSTANCE) {
3200 // we only compare instance fields
3204 has_instance_fields = true;
3206 CCodeExpression cexp; // if (cexp) return FALSE;
3207 var s1 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s1"), get_ccode_name (f)); // s1->f
3208 var s2 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s2"), get_ccode_name (f)); // s2->f
3210 var variable_type = f.variable_type.copy ();
3211 make_comparable_cexpression (ref variable_type, ref s1, ref variable_type, ref s2);
3213 if (!(f.variable_type is NullType) && f.variable_type.compatible (string_type)) {
3214 CCodeFunctionCall ccall;
3215 if (context.profile == Profile.POSIX) {
3216 cfile.add_include ("string.h");
3217 ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
3219 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
3221 ccall.add_argument (s1);
3222 ccall.add_argument (s2);
3224 } else if (f.variable_type is StructValueType) {
3225 var equalfunc = generate_struct_equal_function (f.variable_type.type_symbol as Struct);
3226 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
3227 ccall.add_argument (s1);
3228 ccall.add_argument (s2);
3229 cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
3231 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, s1, s2);
3234 ccode.open_if (cexp);
3235 ccode.add_return (get_boolean_cconstant (false));
3239 if (!has_instance_fields) {
3240 // either opaque structure or simple type
3241 if (st.is_simple_type ()) {
3242 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
3243 ccode.add_return (cexp);
3245 ccode.add_return (get_boolean_cconstant (false));
3248 ccode.add_return (get_boolean_cconstant (true));
3253 cfile.add_function_declaration (function);
3254 cfile.add_function (function);
3259 private string generate_numeric_equal_function (TypeSymbol sym) {
3260 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (sym));
3262 if (!add_wrapper (equal_func)) {
3263 // wrapper already defined
3267 var function = new CCodeFunction (equal_func, get_ccode_name (bool_type));
3268 function.modifiers = CCodeModifiers.STATIC;
3270 function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (sym))));
3271 function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (sym))));
3273 push_function (function);
3275 // if (s1 == s2) return TRUE;
3277 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
3278 ccode.open_if (cexp);
3279 ccode.add_return (get_boolean_cconstant (true));
3282 // if (s1 == NULL || s2 == NULL) return FALSE;
3284 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
3285 ccode.open_if (cexp);
3286 ccode.add_return (get_boolean_cconstant (false));
3289 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
3290 ccode.open_if (cexp);
3291 ccode.add_return (get_boolean_cconstant (false));
3294 // return (*s1 == *s2);
3296 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
3297 ccode.add_return (cexp);
3302 cfile.add_function_declaration (function);
3303 cfile.add_function (function);
3308 private string generate_struct_dup_wrapper (ValueType value_type) {
3309 string dup_func = "_%sdup".printf (get_ccode_lower_case_prefix (value_type.type_symbol));
3311 if (!add_wrapper (dup_func)) {
3312 // wrapper already defined
3316 var function = new CCodeFunction (dup_func, get_ccode_name (value_type));
3317 function.modifiers = CCodeModifiers.STATIC;
3319 function.add_parameter (new CCodeParameter ("self", get_ccode_name (value_type)));
3321 push_function (function);
3323 if (value_type.type_symbol == gvalue_type) {
3324 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
3325 dup_call.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
3326 dup_call.add_argument (new CCodeIdentifier ("self"));
3328 ccode.add_return (dup_call);
3330 ccode.add_declaration (get_ccode_name (value_type), new CCodeVariableDeclarator ("dup"));
3332 CCodeFunctionCall creation_call;
3333 if (context.profile == Profile.POSIX) {
3334 cfile.add_include ("stdlib.h");
3335 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
3336 creation_call.add_argument (new CCodeConstant ("1"));
3337 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
3338 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (value_type.type_symbol)));
3339 creation_call.add_argument (csizeof);
3341 cfile.add_include ("glib.h");
3342 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
3343 creation_call.add_argument (new CCodeIdentifier (get_ccode_name (value_type.type_symbol)));
3344 creation_call.add_argument (new CCodeConstant ("1"));
3346 ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
3348 var st = value_type.type_symbol as Struct;
3349 if (st != null && st.is_disposable ()) {
3350 if (!get_ccode_has_copy_function (st)) {
3351 generate_struct_copy_function (st);
3354 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
3355 copy_call.add_argument (new CCodeIdentifier ("self"));
3356 copy_call.add_argument (new CCodeIdentifier ("dup"));
3357 ccode.add_expression (copy_call);
3359 cfile.add_include ("string.h");
3361 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
3362 sizeof_call.add_argument (new CCodeConstant (get_ccode_name (value_type.type_symbol)));
3364 var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
3365 copy_call.add_argument (new CCodeIdentifier ("dup"));
3366 copy_call.add_argument (new CCodeIdentifier ("self"));
3367 copy_call.add_argument (sizeof_call);
3368 ccode.add_expression (copy_call);
3371 ccode.add_return (new CCodeIdentifier ("dup"));
3376 cfile.add_function_declaration (function);
3377 cfile.add_function (function);
3382 protected string generate_dup_func_wrapper (DataType type) {
3383 string destroy_func = "_vala_%s_copy".printf (get_ccode_name (type.type_symbol));
3385 if (!add_wrapper (destroy_func)) {
3386 // wrapper already defined
3387 return destroy_func;
3390 var function = new CCodeFunction (destroy_func, get_ccode_name (type));
3391 function.modifiers = CCodeModifiers.STATIC;
3392 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3394 push_function (function);
3396 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
3397 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (type.type_symbol)));
3398 free_call.add_argument (new CCodeIdentifier ("self"));
3400 ccode.add_return (free_call);
3404 cfile.add_function_declaration (function);
3405 cfile.add_function (function);
3407 return destroy_func;
3410 protected string generate_free_function_address_of_wrapper (DataType type) {
3411 string destroy_func = "_vala_%s_free_function_address_of".printf (get_ccode_name (type.type_symbol));
3413 if (!add_wrapper (destroy_func)) {
3414 // wrapper already defined
3415 return destroy_func;
3418 var function = new CCodeFunction (destroy_func, "void");
3419 function.modifiers = CCodeModifiers.STATIC;
3420 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3422 push_function (function);
3424 unowned Class? cl = type.type_symbol as Class;
3425 assert (cl != null);
3427 var free_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (cl)));
3428 free_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("self")));
3430 ccode.add_expression (free_call);
3434 cfile.add_function_declaration (function);
3435 cfile.add_function (function);
3437 return destroy_func;
3440 protected string generate_destroy_function_content_of_wrapper (DataType type) {
3441 // g_array_set_clear_func has a specific GDestroyNotify where the content of an element is given
3442 string destroy_func = "_vala_%s_free_function_content_of".printf (get_ccode_name (type.type_symbol));
3444 if (!add_wrapper (destroy_func)) {
3445 // wrapper already defined
3446 return destroy_func;
3449 var function = new CCodeFunction (destroy_func, "void");
3450 function.modifiers = CCodeModifiers.STATIC;
3451 function.add_parameter (new CCodeParameter ("data", get_ccode_name (pointer_type)));
3452 push_function (function);
3454 ccode.add_declaration (get_ccode_name (type), new CCodeVariableDeclarator ("self"));
3455 var cast = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeCastExpression (new CCodeIdentifier ("data"), get_ccode_name (type) + "*"));
3456 ccode.add_assignment (new CCodeIdentifier ("self"), cast);
3458 var free_call = new CCodeFunctionCall (get_destroy0_func_expression (type));
3459 free_call.add_argument (new CCodeIdentifier ("self"));
3461 ccode.add_expression (free_call);
3465 cfile.add_function_declaration (function);
3466 cfile.add_function (function);
3468 return destroy_func;
3471 protected string generate_free_func_wrapper (DataType type) {
3472 string destroy_func = "_vala_%s_free".printf (get_ccode_name (type.type_symbol));
3474 if (!add_wrapper (destroy_func)) {
3475 // wrapper already defined
3476 return destroy_func;
3479 var function = new CCodeFunction (destroy_func, "void");
3480 function.modifiers = CCodeModifiers.STATIC;
3481 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3483 push_function (function);
3485 if (get_ccode_is_gboxed (type.type_symbol) || (gvalue_type != null && type.type_symbol == gvalue_type)) {
3486 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_free"));
3487 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (type.type_symbol)));
3488 free_call.add_argument (new CCodeIdentifier ("self"));
3490 ccode.add_expression (free_call);
3492 unowned Struct? st = type.type_symbol as Struct;
3493 if (st != null && st.is_disposable ()) {
3494 if (!get_ccode_has_destroy_function (st)) {
3495 generate_struct_destroy_function (st);
3498 var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (st)));
3499 destroy_call.add_argument (new CCodeIdentifier ("self"));
3500 ccode.add_expression (destroy_call);
3503 CCodeFunctionCall free_call;
3504 if (context.profile == Profile.POSIX) {
3505 cfile.add_include ("stdlib.h");
3506 free_call = new CCodeFunctionCall (new CCodeIdentifier ("free"));
3508 cfile.add_include ("glib.h");
3509 free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
3511 free_call.add_argument (new CCodeIdentifier ("self"));
3513 ccode.add_expression (free_call);
3518 cfile.add_function_declaration (function);
3519 cfile.add_function (function);
3521 return destroy_func;
3524 public CCodeExpression? get_destroy0_func_expression (DataType type, bool is_chainup = false) {
3525 var element_destroy_func_expression = get_destroy_func_expression (type, is_chainup);
3527 if (!(type is GenericType) && element_destroy_func_expression is CCodeIdentifier) {
3528 var freeid = (CCodeIdentifier) element_destroy_func_expression;
3529 string free0_func = "_%s0_".printf (freeid.name);
3531 if (add_wrapper (free0_func)) {
3532 var function = new CCodeFunction (free0_func, "void");
3533 function.modifiers = CCodeModifiers.STATIC;
3535 function.add_parameter (new CCodeParameter ("var", get_ccode_name (pointer_type)));
3537 push_function (function);
3539 ccode.add_expression (destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true));
3543 cfile.add_function_declaration (function);
3544 cfile.add_function (function);
3547 element_destroy_func_expression = new CCodeIdentifier (free0_func);
3550 return element_destroy_func_expression;
3553 public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
3554 if (context.profile == Profile.GOBJECT && (type.type_symbol == glist_type || type.type_symbol == gslist_type || type.type_symbol == gnode_type || type.type_symbol == gqueue_type)) {
3555 // create wrapper function to free list elements if necessary
3557 bool elements_require_free = false;
3558 bool generic_elements = false;
3559 CCodeExpression element_destroy_func_expression = null;
3561 foreach (DataType type_arg in type.get_type_arguments ()) {
3562 elements_require_free = requires_destroy (type_arg);
3563 if (elements_require_free) {
3564 element_destroy_func_expression = get_destroy0_func_expression (type_arg);
3565 generic_elements = (type_arg is GenericType);
3569 if (elements_require_free) {
3570 CCodeExpression? cexpr = null;
3571 if (element_destroy_func_expression is CCodeIdentifier || element_destroy_func_expression is CCodeMemberAccess) {
3572 cexpr = new CCodeIdentifier (generate_collection_free_wrapper (type, (generic_elements ? null : element_destroy_func_expression as CCodeIdentifier)));
3573 if (generic_elements) {
3574 // adding second argument early, instance parameter will be inserted by destroy_value()
3575 cexpr = new CCodeFunctionCall (cexpr);
3576 ((CCodeFunctionCall) cexpr).add_argument (element_destroy_func_expression);
3579 Report.error (null, "internal error: No useable element_destroy_function found");
3583 return new CCodeIdentifier (get_ccode_free_function (type.type_symbol));
3585 } else if (type is ErrorType) {
3586 cfile.add_include ("glib.h");
3587 return new CCodeIdentifier ("g_error_free");
3588 } else if (type is GenericType) {
3589 var type_parameter = ((GenericType) type).type_parameter;
3590 string identifier = get_ccode_destroy_function (type_parameter);
3591 return get_generic_type_expression (identifier, (GenericType) type, is_chainup);
3592 } else if (type.type_symbol != null) {
3593 string unref_function;
3594 if (type is ReferenceType) {
3595 if (is_reference_counting (type.type_symbol)) {
3596 unref_function = get_ccode_unref_function ((ObjectTypeSymbol) type.type_symbol);
3597 if (type.type_symbol is Interface && unref_function == null) {
3598 Report.error (type.source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure", type.type_symbol.get_full_name ());
3602 if (get_ccode_is_gboxed (type.type_symbol)) {
3603 unref_function = generate_free_func_wrapper (type);
3605 if (is_free_function_address_of (type)) {
3606 unref_function = generate_free_function_address_of_wrapper (type);
3608 unref_function = get_ccode_free_function (type.type_symbol);
3613 if (type.nullable) {
3614 if (get_ccode_is_gboxed (type.type_symbol)) {
3615 unref_function = generate_free_func_wrapper (type);
3617 unref_function = get_ccode_free_function (type.type_symbol);
3619 if (unref_function == null) {
3620 if (type.type_symbol is Struct && ((Struct) type.type_symbol).is_disposable ()) {
3621 unref_function = generate_free_func_wrapper (type);
3623 if (context.profile == Profile.POSIX) {
3624 cfile.add_include ("stdlib.h");
3625 unref_function = "free";
3627 cfile.add_include ("glib.h");
3628 unref_function = "g_free";
3632 } else if (type is EnumValueType) {
3633 unref_function = null;
3635 unowned Struct? st = type.type_symbol as Struct;
3636 if (st != null && st.is_disposable ()) {
3637 if (!get_ccode_has_destroy_function (st)) {
3638 generate_struct_destroy_function (st);
3640 unref_function = get_ccode_destroy_function (st);
3642 unref_function = null;
3646 if (unref_function == null) {
3647 return new CCodeConstant ("NULL");
3649 return new CCodeIdentifier (unref_function);
3650 } else if (type is ArrayType) {
3651 if (context.profile == Profile.POSIX) {
3652 cfile.add_include ("stdlib.h");
3653 return new CCodeIdentifier ("free");
3655 cfile.add_include ("glib.h");
3656 return new CCodeIdentifier ("g_free");
3658 } else if (type is PointerType) {
3659 if (context.profile == Profile.POSIX) {
3660 cfile.add_include ("stdlib.h");
3661 return new CCodeIdentifier ("free");
3663 cfile.add_include ("glib.h");
3664 return new CCodeIdentifier ("g_free");
3667 return new CCodeConstant ("NULL");
3671 private string generate_collection_free_wrapper (DataType collection_type, CCodeIdentifier? element_destroy_func_expression) {
3672 string destroy_func;
3674 string? destroy_func_wrapper = null;
3675 if (element_destroy_func_expression != null) {
3676 destroy_func_wrapper = "_%s_%s".printf (get_ccode_free_function (collection_type.type_symbol), element_destroy_func_expression.name);
3677 if (!add_wrapper (destroy_func_wrapper)) {
3678 // wrapper already defined
3679 return destroy_func_wrapper;
3683 if (collection_type.type_symbol == gnode_type) {
3684 destroy_func = "_g_node_free_all";
3685 if (!add_wrapper (destroy_func)) {
3686 // wrapper already defined
3687 return destroy_func;
3690 var function = new CCodeFunction (destroy_func, "void");
3691 function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3692 function.add_parameter (new CCodeParameter ("free_func", "GDestroyNotify"));
3694 push_function (function);
3696 CCodeFunctionCall element_free_call;
3697 string destroy_node_func = "%s_node".printf (destroy_func);
3698 var wrapper = new CCodeFunction (destroy_node_func, get_ccode_name (bool_type));
3699 wrapper.modifiers = CCodeModifiers.STATIC;
3700 wrapper.add_parameter (new CCodeParameter ("node", get_ccode_name (collection_type)));
3701 wrapper.add_parameter (new CCodeParameter ("free_func", "GDestroyNotify"));
3702 push_function (wrapper);
3704 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("free_func"));
3705 free_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier("node"), "data"));
3707 var data_isnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeMemberAccess.pointer (new CCodeIdentifier("node"), "data"), new CCodeConstant ("NULL"));
3708 var ccomma_data = new CCodeCommaExpression ();
3709 ccomma_data.append_expression (new CCodeConditionalExpression (data_isnull, new CCodeConstant ("NULL"), free_call));
3710 ccode.add_expression (ccomma_data);
3712 ccode.add_return (new CCodeConstant ("FALSE"));
3715 cfile.add_function_declaration (wrapper);
3716 cfile.add_function (wrapper);
3718 /* Now the code to call g_traverse with the above */
3719 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_node_traverse"));
3720 element_free_call.add_argument (new CCodeIdentifier("self"));
3721 element_free_call.add_argument (new CCodeConstant ("G_POST_ORDER"));
3722 element_free_call.add_argument (new CCodeConstant ("G_TRAVERSE_ALL"));
3723 element_free_call.add_argument (new CCodeConstant ("-1"));
3724 element_free_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (destroy_node_func), "GNodeTraverseFunc"));
3725 element_free_call.add_argument (new CCodeIdentifier ("free_func"));
3727 var free_func_isnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("free_func"), new CCodeConstant ("NULL"));
3728 var ccomma = new CCodeCommaExpression ();
3729 ccomma.append_expression (new CCodeConditionalExpression (free_func_isnull, new CCodeConstant ("NULL"), element_free_call));
3731 ccode.add_expression (ccomma);
3733 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (gnode_type)));
3734 cfreecall.add_argument (new CCodeIdentifier ("self"));
3735 ccode.add_expression (cfreecall);
3737 function.modifiers = CCodeModifiers.STATIC;
3740 cfile.add_function_declaration (function);
3741 cfile.add_function (function);
3742 } else if (collection_type.type_symbol == glist_type) {
3743 destroy_func = "g_list_free_full";
3744 } else if (collection_type.type_symbol == gslist_type) {
3745 destroy_func = "g_slist_free_full";
3746 } else if (collection_type.type_symbol == gqueue_type) {
3747 destroy_func = "g_queue_free_full";
3749 Report.error (null, "internal error: type of collection not supported");
3753 if (element_destroy_func_expression != null) {
3754 var function = new CCodeFunction (destroy_func_wrapper, "void");
3755 function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3757 push_function (function);
3759 var collection_free_call = new CCodeFunctionCall (new CCodeIdentifier (destroy_func));
3760 collection_free_call.add_argument (new CCodeIdentifier ("self"));
3761 collection_free_call.add_argument (new CCodeCastExpression (element_destroy_func_expression, "GDestroyNotify"));
3762 ccode.add_expression (collection_free_call);
3764 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
3767 cfile.add_function_declaration (function);
3768 cfile.add_function (function);
3770 return destroy_func_wrapper;
3773 return destroy_func;
3776 public virtual string? append_struct_array_destroy (Struct st) {
3780 public virtual string? append_struct_array_free (Struct st) {
3784 public CCodeExpression destroy_local (LocalVariable local) {
3785 return destroy_value (get_local_cvalue (local));
3788 public CCodeExpression destroy_parameter (Parameter param) {
3789 return destroy_value (get_parameter_cvalue (param));
3792 public CCodeExpression destroy_field (Field field, TargetValue? instance) {
3793 return destroy_value (get_field_cvalue (field, instance));
3796 public virtual CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
3797 var type = value.value_type;
3798 if (value.actual_value_type != null) {
3799 type = value.actual_value_type;
3801 var cvar = get_cvalue_ (value);
3803 if (type is DelegateType) {
3804 if (context.profile != Profile.GOBJECT) {
3805 // Required for NULL
3806 cfile.add_include ("stddef.h");
3809 var delegate_target = get_delegate_target_cvalue (value);
3810 var delegate_target_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
3812 var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
3813 ccall.add_argument (delegate_target);
3815 var destroy_call = new CCodeCommaExpression ();
3816 destroy_call.append_expression (ccall);
3817 destroy_call.append_expression (new CCodeConstant ("NULL"));
3819 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
3821 var ccomma = new CCodeCommaExpression ();
3822 ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), destroy_call));
3823 ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
3824 ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
3825 ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
3830 bool is_gcollection = (type.type_symbol == glist_type || type.type_symbol == gslist_type || type.type_symbol == gnode_type || type.type_symbol == gqueue_type);
3831 CCodeFunctionCall ccall;
3832 var cexpr = get_destroy_func_expression (type);
3833 if (is_gcollection && cexpr is CCodeFunctionCall) {
3834 ccall = (CCodeFunctionCall) cexpr;
3836 ccall = new CCodeFunctionCall (cexpr);
3839 if (type is ValueType && !type.nullable) {
3840 // normal value type, no null check
3841 unowned Struct? st = type.type_symbol as Struct;
3842 if (st != null && st.is_simple_type ()) {
3844 ccall.add_argument (cvar);
3846 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3849 if (gvalue_type != null && type.type_symbol == gvalue_type) {
3850 // g_value_unset must not be called for already unset values
3851 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
3852 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3854 var ccomma = new CCodeCommaExpression ();
3855 ccomma.append_expression (ccall);
3856 ccomma.append_expression (new CCodeConstant ("NULL"));
3858 return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
3859 } else if ((type.type_symbol == gmutex_type ||
3860 type.type_symbol == grecmutex_type ||
3861 type.type_symbol == grwlock_type ||
3862 type.type_symbol == gcond_type)) {
3863 // g_mutex_clear must not be called for uninitialized mutex
3864 // also, g_mutex_clear does not clear the struct
3865 requires_clear_mutex = true;
3866 ccall.call = new CCodeIdentifier ("_vala_clear_" + get_ccode_name (type.type_symbol));
3873 if (!is_gcollection && ccall.call is CCodeIdentifier && !(type is ArrayType) && !(type is GenericType) && !is_macro_definition) {
3874 // generate and use NULL-aware free macro to simplify code
3876 var freeid = (CCodeIdentifier) ccall.call;
3877 string free0_func = "_%s0".printf (freeid.name);
3879 if (add_wrapper (free0_func)) {
3880 var macro = destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true);
3881 cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("%s(var)".printf (free0_func), macro));
3884 // FIXME this breaks in our macro, so this should not happen
3885 while (cvar is CCodeCastExpression) {
3886 cvar = ((CCodeCastExpression) cvar).inner;
3888 if (cvar is CCodeFunctionCall) {
3889 cvar = ((CCodeFunctionCall) cvar).get_arguments ()[0];
3892 ccall = new CCodeFunctionCall (new CCodeIdentifier (free0_func));
3893 ccall.add_argument (cvar);
3897 if (context.profile != Profile.GOBJECT) {
3898 // Required for NULL
3899 cfile.add_include ("stddef.h");
3902 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
3904 /* can be simplified to
3905 * foo = (unref (foo), NULL)
3906 * if foo is of static type non-null
3909 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
3910 if (type is GenericType) {
3911 var parent = ((GenericType) type).type_parameter.parent_symbol;
3912 var cl = parent as Class;
3913 if ((!(parent is Method) && !(parent is ObjectTypeSymbol)) || (cl != null && cl.is_compact)) {
3914 return new CCodeConstant ("NULL");
3917 // unref functions are optional for type parameters
3918 var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
3919 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
3922 // glib collections already have the free_func argument, so make sure the instance parameter gets first
3923 ccall.insert_argument (0, cvar);
3925 /* set freed references to NULL to prevent further use */
3926 var ccomma = new CCodeCommaExpression ();
3928 if (context.profile == Profile.GOBJECT
3929 && type.type_symbol != null && !is_reference_counting (type.type_symbol)
3930 && type.type_symbol.is_subtype_of (gstringbuilder_type)) {
3931 ccall.add_argument (new CCodeConstant ("TRUE"));
3932 } else if (context.profile == Profile.GOBJECT
3933 && type.type_symbol == gthreadpool_type) {
3934 ccall.add_argument (new CCodeConstant ("FALSE"));
3935 ccall.add_argument (new CCodeConstant ("TRUE"));
3936 } else if (type is ArrayType) {
3937 var array_type = (ArrayType) type;
3938 if (requires_destroy (array_type.element_type)) {
3939 CCodeExpression csizeexpr = null;
3940 if (((GLibValue) value).array_length_cvalues != null) {
3941 csizeexpr = get_array_length_cvalue (value);
3942 } else if (get_array_null_terminated (value)) {
3943 requires_array_length = true;
3944 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
3945 len_call.add_argument (cvar);
3946 csizeexpr = len_call;
3948 csizeexpr = get_array_length_cexpr (value);
3951 if (csizeexpr != null) {
3952 unowned Struct? st = array_type.element_type.type_symbol as Struct;
3953 if (st != null && !array_type.element_type.nullable) {
3954 ccall.call = new CCodeIdentifier (append_struct_array_free (st));
3955 ccall.add_argument (csizeexpr);
3957 requires_array_free = true;
3958 generate_type_declaration (delegate_target_destroy_type, cfile);
3960 ccall.call = new CCodeIdentifier ("_vala_array_free");
3961 ccall.add_argument (csizeexpr);
3962 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), get_ccode_name (delegate_target_destroy_type)));
3968 ccomma.append_expression (ccall);
3969 ccomma.append_expression (new CCodeConstant ("NULL"));
3971 var cassign = new CCodeAssignment (cvar, ccomma);
3973 // g_free (NULL) is allowed
3974 bool uses_gfree = (type.type_symbol != null && !is_reference_counting (type.type_symbol) && get_ccode_free_function (type.type_symbol) == "g_free");
3975 uses_gfree = uses_gfree || type is ArrayType;
3980 return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
3983 public override void visit_end_full_expression (Expression expr) {
3984 /* expr is a full expression, i.e. an initializer, the
3985 * expression in an expression statement, the controlling
3986 * expression in if, while, for, or foreach statements
3988 * we unref temporary variables at the end of a full
3991 if (temp_ref_values.size == 0) {
3992 /* nothing to do without temporary variables */
3996 var local_decl = expr.parent_node as LocalVariable;
3997 if (!(local_decl != null && is_simple_struct_creation (local_decl, local_decl.initializer))) {
3998 expr.target_value = store_temp_value (expr.target_value, expr);
4001 foreach (var value in temp_ref_values) {
4002 ccode.add_expression (destroy_value (value));
4005 temp_ref_values.clear ();
4008 public void emit_temp_var (LocalVariable local, bool on_error = false) {
4009 generate_type_declaration (local.variable_type, cfile);
4011 var init = (!local.name.has_prefix ("*") && local.init);
4012 if (is_in_coroutine ()) {
4013 closure_struct.add_field (get_ccode_name (local.variable_type), local.name, 0, get_ccode_declarator_suffix (local.variable_type));
4015 // even though closure struct is zerod, we need to initialize temporary variables
4016 // as they might be used multiple times when declared in a loop
4019 var initializer = default_value_for_type (local.variable_type, false, on_error);
4020 if (initializer == null) {
4021 cfile.add_include ("string.h");
4022 var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4023 memset_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (local.name)));
4024 memset_call.add_argument (new CCodeConstant ("0"));
4025 CCodeExpression? size = null;
4026 requires_memset_init (local, out size);
4028 size = new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (local.variable_type)));
4030 memset_call.add_argument (size);
4031 ccode.add_expression (memset_call);
4033 ccode.add_assignment (get_variable_cexpression (local.name), initializer);
4037 var cvar = new CCodeVariableDeclarator (local.name, null, get_ccode_declarator_suffix (local.variable_type));
4038 CCodeExpression? size = null;
4039 if (init && !requires_memset_init (local, out size)) {
4040 cvar.initializer = default_value_for_type (local.variable_type, true, on_error);
4042 } else if (init && size != null && local.initializer == null) {
4043 cfile.add_include ("string.h");
4044 var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4045 memset_call.add_argument (get_variable_cexpression (local.name));
4046 memset_call.add_argument (new CCodeConstant ("0"));
4047 memset_call.add_argument (size);
4048 ccode.add_expression (memset_call);
4050 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
4054 public override void visit_expression_statement (ExpressionStatement stmt) {
4055 if (stmt.expression.error) {
4060 /* free temporary objects and handle errors */
4062 foreach (var value in temp_ref_values) {
4063 ccode.add_expression (destroy_value (value));
4066 if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
4067 // simple case, no node breakdown necessary
4068 add_simple_check (stmt.expression);
4071 temp_ref_values.clear ();
4074 protected virtual void append_scope_free (Symbol sym, CodeNode? stop_at = null) {
4075 var b = (Block) sym;
4077 var local_vars = b.get_local_variables ();
4078 // free in reverse order
4079 for (int i = local_vars.size - 1; i >= 0; i--) {
4080 var local = local_vars[i];
4081 if (!local.unreachable && local.active && !local.captured && requires_destroy (local.variable_type)) {
4082 ccode.add_expression (destroy_local (local));
4087 int block_id = get_block_id (b);
4089 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
4090 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
4091 ccode.add_expression (data_unref);
4092 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
4096 public void append_local_free (Symbol sym, Statement? jump_stmt = null, CodeNode? stop_at = null) {
4097 var b = (Block) sym;
4099 append_scope_free (sym, stop_at);
4101 if (jump_stmt is BreakStatement) {
4102 if (b.parent_node is LoopStatement ||
4103 b.parent_node is ForeachStatement ||
4104 b.parent_node is SwitchStatement) {
4107 } else if (jump_stmt is ContinueStatement) {
4108 if (b.parent_node is LoopStatement ||
4109 b.parent_node is ForeachStatement) {
4114 if (stop_at != null && b.parent_node == stop_at) {
4118 if (sym.parent_symbol is Block) {
4119 append_local_free (sym.parent_symbol, jump_stmt, stop_at);
4120 } else if (sym.parent_symbol is Method) {
4121 append_param_free ((Method) sym.parent_symbol);
4122 } else if (sym.parent_symbol is PropertyAccessor) {
4123 var acc = (PropertyAccessor) sym.parent_symbol;
4124 if (acc.value_parameter != null && requires_destroy (acc.value_parameter.variable_type)) {
4125 ccode.add_expression (destroy_parameter (acc.value_parameter));
4130 private void append_param_free (Method m) {
4131 foreach (Parameter param in m.get_parameters ()) {
4132 if (!param.captured && !param.ellipsis && !param.params_array && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
4133 ccode.add_expression (destroy_parameter (param));
4138 public void append_out_param_free (Method? m) {
4142 foreach (Parameter param in m.get_parameters ()) {
4143 if (param.direction == ParameterDirection.OUT && param.variable_type.is_disposable ()) {
4144 ccode.add_expression (destroy_parameter (param));
4149 public bool variable_accessible_in_finally (LocalVariable local) {
4150 if (current_try == null) {
4154 var sym = current_symbol;
4156 while (!(sym is Method || sym is PropertyAccessor) && sym.scope.lookup (local.name) == null) {
4157 if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) ||
4158 (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) {
4163 sym = sym.parent_symbol;
4169 public void return_out_parameter (Parameter param) {
4170 var delegate_type = param.variable_type as DelegateType;
4172 var value = get_parameter_cvalue (param);
4174 var old_coroutine = is_in_coroutine ();
4175 current_method.coroutine = false;
4177 ccode.open_if (get_parameter_cexpression (param));
4178 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_parameter_cexpression (param)), get_cvalue_ (value));
4180 if (get_ccode_delegate_target (param) && delegate_type != null && delegate_type.delegate_symbol.has_target) {
4181 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cexpression (get_ccode_delegate_target_name (param))), get_delegate_target_cvalue (value));
4182 if (delegate_type.is_disposable ()) {
4183 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cexpression (get_ccode_delegate_target_destroy_notify_name (param))), get_delegate_target_destroy_notify_cvalue (get_parameter_cvalue (param)));
4187 if (param.variable_type.is_disposable ()){
4189 current_method.coroutine = old_coroutine;
4190 ccode.add_expression (destroy_parameter (param));
4191 current_method.coroutine = false;
4195 var array_type = param.variable_type as ArrayType;
4196 if (array_type != null && !array_type.fixed_length && get_ccode_array_length (param)) {
4197 for (int dim = 1; dim <= array_type.rank; dim++) {
4198 string length_cname = get_variable_array_length_cname (param, dim);
4199 ccode.open_if (get_cexpression (length_cname));
4200 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cexpression (length_cname)), get_array_length_cvalue (value, dim));
4205 current_method.coroutine = old_coroutine;
4208 public override void visit_return_statement (ReturnStatement stmt) {
4209 Symbol return_expression_symbol = null;
4211 if (stmt.return_expression != null) {
4212 // avoid unnecessary ref/unref pair
4213 var local = stmt.return_expression.symbol_reference as LocalVariable;
4214 if (local != null && !local.active) {
4215 /* return expression is local variable taking ownership and
4216 * current method is transferring ownership */
4218 return_expression_symbol = local;
4222 // return array length if appropriate
4223 if (((current_method != null && get_ccode_array_length (current_method)) || (current_property_accessor != null && get_ccode_array_length (current_property_accessor))) && current_return_type is ArrayType) {
4224 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
4226 var array_type = (ArrayType) current_return_type;
4227 for (int dim = 1; dim <= array_type.rank; dim++) {
4228 var len_l = get_cexpression (get_array_length_cname ("result", dim));
4229 var len_r = get_array_length_cvalue (temp_value, dim);
4230 if (!is_in_coroutine ()) {
4231 ccode.open_if (len_l);
4232 len_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, len_l);
4233 ccode.add_assignment (len_l, len_r);
4236 ccode.add_assignment (len_l, len_r);
4240 stmt.return_expression.target_value = temp_value;
4241 } else if (((current_method != null && get_ccode_delegate_target (current_method)) || (current_property_accessor != null && get_ccode_delegate_target (current_property_accessor))) && current_return_type is DelegateType) {
4242 var delegate_type = (DelegateType) current_return_type;
4243 if (delegate_type.delegate_symbol.has_target) {
4244 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
4246 var target_l = get_cexpression (get_delegate_target_cname ("result"));
4247 if (!is_in_coroutine ()) {
4248 target_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l);
4250 var target_r = get_delegate_target_cvalue (temp_value);
4251 ccode.add_assignment (target_l, target_r);
4252 if (delegate_type.is_disposable ()) {
4253 var target_l_destroy_notify = get_cexpression (get_delegate_target_destroy_notify_cname ("result"));
4254 if (!is_in_coroutine ()) {
4255 target_l_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l_destroy_notify);
4257 var target_r_destroy_notify = get_delegate_target_destroy_notify_cvalue (temp_value);
4258 ccode.add_assignment (target_l_destroy_notify, target_r_destroy_notify);
4261 stmt.return_expression.target_value = temp_value;
4265 if (stmt.return_expression != null) {
4266 // assign method result to `result'
4267 CCodeExpression result_lhs = get_cexpression ("result");
4268 if (current_return_type.is_real_non_null_struct_type () && !is_in_coroutine ()) {
4269 result_lhs = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result_lhs);
4271 ccode.add_assignment (result_lhs, get_cvalue (stmt.return_expression));
4274 if (current_method != null) {
4275 // check postconditions
4276 foreach (Expression postcondition in current_method.get_postconditions ()) {
4277 create_postcondition_statement (postcondition);
4281 // free local variables
4282 append_local_free (current_symbol);
4284 if (current_method != null && !current_method.coroutine) {
4285 // assign values to output parameters if they are not NULL
4286 // otherwise, free the value if necessary
4287 foreach (var param in current_method.get_parameters ()) {
4288 if (param.direction != ParameterDirection.OUT) {
4292 return_out_parameter (param);
4296 // TODO: don't duplicate the code in CCodeMethodModule, we do this right now because it needs to be before return
4297 if (current_method != null && current_method.get_attribute ("Profile") != null) {
4298 string prefix = "_vala_prof_%s".printf (get_ccode_real_name (current_method));
4300 var level = new CCodeIdentifier (prefix + "_level");
4301 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
4303 var timer = new CCodeIdentifier (prefix + "_timer");
4305 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
4306 stop_call.add_argument (timer);
4307 ccode.add_expression (stop_call);
4312 if (is_in_constructor ()) {
4313 ccode.add_return (new CCodeIdentifier ("obj"));
4314 } else if (is_in_destructor ()) {
4315 // do not call return as member cleanup and chain up to base finalizer
4316 // still need to be executed
4317 ccode.add_goto ("_return");
4318 } else if (is_in_coroutine ()) {
4319 } else if (current_method is CreationMethod) {
4320 ccode.add_return (new CCodeIdentifier ("self"));
4321 } else if (current_return_type is VoidType || current_return_type.is_real_non_null_struct_type ()) {
4322 // structs are returned via out parameter
4323 ccode.add_return ();
4325 ccode.add_return (new CCodeIdentifier ("result"));
4328 if (return_expression_symbol != null) {
4329 return_expression_symbol.active = true;
4332 // required for destructors
4333 current_method_return = true;
4336 public string get_symbol_lock_name (string symname) {
4337 return "__lock_%s".printf (symname.replace ("-", "_"));
4340 private CCodeExpression get_lock_expression (Statement stmt, Expression resource) {
4341 CCodeExpression l = null;
4342 var member = resource.symbol_reference;
4343 var parent = (TypeSymbol)resource.symbol_reference.parent_symbol;
4345 if (member.is_instance_member ()) {
4346 l = get_cvalue (((MemberAccess) resource).inner);
4347 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (get_ccode_name (member)));
4348 } else if (member.is_class_member ()) {
4349 unowned Class cl = (Class) parent;
4350 var cast = get_this_class_cexpression (cl);
4351 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function (cl)));
4352 get_class_private_call.add_argument (cast);
4353 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (get_ccode_name (member)));
4355 string lock_name = "%s_%s".printf (get_ccode_lower_case_name (parent), get_ccode_name (member));
4356 l = new CCodeIdentifier (get_symbol_lock_name (lock_name));
4361 public override void visit_lock_statement (LockStatement stmt) {
4362 var l = get_lock_expression (stmt, stmt.resource);
4364 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("lock"))));
4365 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
4367 ccode.add_expression (fc);
4370 public override void visit_unlock_statement (UnlockStatement stmt) {
4371 var l = get_lock_expression (stmt, stmt.resource);
4373 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("unlock"))));
4374 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
4376 ccode.add_expression (fc);
4379 public override void visit_delete_statement (DeleteStatement stmt) {
4380 unowned DataType type = stmt.expression.value_type;
4381 unowned PointerType? pointer_type = type as PointerType;
4382 if (pointer_type != null && pointer_type.base_type.type_symbol != null && pointer_type.base_type.type_symbol.is_reference_type ()) {
4383 type = pointer_type.base_type;
4386 ccode.add_expression (destroy_value (new GLibValue (type, get_cvalue (stmt.expression))));
4389 static bool is_compact_class_destructor_call (Expression expr) {
4390 unowned Class? cl = expr.value_type.type_symbol as Class;
4391 if (cl != null && cl.is_compact && expr.parent_node is MemberAccess) {
4392 unowned MethodType? mt = ((MemberAccess) expr.parent_node).value_type as MethodType;
4393 if (mt != null && mt.method_symbol != null && mt.method_symbol.get_attribute ("DestroysInstance") != null) {
4400 public override void visit_expression (Expression expr) {
4401 if (get_cvalue (expr) != null && !expr.lvalue) {
4402 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
4403 var type_parameter = ((GenericType) expr.formal_value_type).type_parameter;
4404 var st = type_parameter.parent_symbol.parent_symbol as Struct;
4405 if (type_parameter.parent_symbol != garray_type &&
4406 (st == null || get_ccode_name (st) != "va_list")) {
4407 // GArray and va_list don't use pointer-based generics
4408 set_cvalue (expr, convert_from_generic_pointer (get_cvalue (expr), expr.value_type));
4409 ((GLibValue) expr.target_value).lvalue = false;
4413 // memory management, implicit casts, and boxing/unboxing
4414 if (expr.value_type != null) {
4415 // FIXME: temporary workaround until the refactoring is complete, not all target_value have a value_type
4416 expr.target_value.value_type = expr.value_type;
4417 expr.target_value = transform_value (expr.target_value, expr.target_type, expr);
4420 if (expr.target_value == null) {
4424 if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
4425 if (((GenericType) expr.formal_target_type).type_parameter.parent_symbol != garray_type) {
4426 // GArray doesn't use pointer-based generics
4427 set_cvalue (expr, convert_to_generic_pointer (get_cvalue (expr), expr.target_type));
4428 ((GLibValue) expr.target_value).lvalue = false;
4432 // Allow null to initialize non-null struct inside initializer list
4433 if (expr is NullLiteral && expr.parent_node is InitializerList
4434 && expr.target_type != null && expr.target_type.is_real_non_null_struct_type ()) {
4435 var clist = new CCodeInitializerList ();
4436 clist.append (new CCodeConstant ("0"));
4437 set_cvalue (expr, new CCodeCastExpression (clist, get_ccode_name (expr.target_type.type_symbol)));
4440 if (!(expr.value_type is ValueType && !expr.value_type.nullable)) {
4441 ((GLibValue) expr.target_value).non_null = expr.is_non_null ();
4443 } else if (expr.value_type != null && is_compact_class_destructor_call (expr)) {
4444 // transfer ownership here and consume given instance
4445 var temp_value = store_temp_value (expr.target_value, expr);
4446 ccode.add_assignment (get_cvalue (expr), new CCodeConstant ("NULL"));
4447 expr.target_value = temp_value;
4451 public override void visit_boolean_literal (BooleanLiteral expr) {
4452 set_cvalue (expr, get_boolean_cconstant (expr.value));
4455 public override void visit_character_literal (CharacterLiteral expr) {
4456 if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
4457 set_cvalue (expr, new CCodeConstant (expr.value));
4459 set_cvalue (expr, new CCodeConstant ("%uU".printf (expr.get_char ())));
4463 public override void visit_integer_literal (IntegerLiteral expr) {
4464 set_cvalue (expr, new CCodeConstant (expr.value + expr.type_suffix));
4467 public override void visit_real_literal (RealLiteral expr) {
4468 string c_literal = expr.value;
4469 if (c_literal.has_suffix ("d") || c_literal.has_suffix ("D")) {
4470 // there is no suffix for double in C
4471 c_literal = c_literal.substring (0, c_literal.length - 1);
4473 if (!("." in c_literal || "e" in c_literal || "E" in c_literal)) {
4474 // C requires period or exponent part for floating constants
4475 if ("f" in c_literal || "F" in c_literal) {
4476 c_literal = c_literal.substring (0, c_literal.length - 1) + ".f";
4481 set_cvalue (expr, new CCodeConstant (c_literal));
4484 public override void visit_string_literal (StringLiteral expr) {
4485 set_cvalue (expr, new CCodeConstant.string (expr.value.replace ("\n", "\\n")));
4487 if (expr.translate) {
4488 // translated string constant
4489 var translate = new CCodeFunctionCall (new CCodeIdentifier ("_"));
4490 translate.add_argument (get_cvalue (expr));
4491 set_cvalue (expr, translate);
4495 public override void visit_regex_literal (RegexLiteral expr) {
4496 string[] parts = expr.value.split ("/", 3);
4497 string re = parts[2].escape ("");
4500 if (parts[1].contains ("i")) {
4501 flags += " | G_REGEX_CASELESS";
4503 if (parts[1].contains ("m")) {
4504 flags += " | G_REGEX_MULTILINE";
4506 if (parts[1].contains ("s")) {
4507 flags += " | G_REGEX_DOTALL";
4509 if (parts[1].contains ("x")) {
4510 flags += " | G_REGEX_EXTENDED";
4513 var cdecl = new CCodeDeclaration ("GRegex*");
4515 var cname = "_tmp_regex_%d".printf (next_regex_id);
4516 if (this.next_regex_id == 0) {
4517 var fun = new CCodeFunction ("_thread_safe_regex_init", "GRegex*");
4518 fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
4519 fun.add_parameter (new CCodeParameter ("re", "GRegex**"));
4520 fun.add_parameter (new CCodeParameter ("pattern", "const gchar *"));
4521 fun.add_parameter (new CCodeParameter ("compile_flags", "GRegexCompileFlags"));
4523 push_function (fun);
4525 var once_enter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
4526 if (context.require_glib_version (2, 68)) {
4527 once_enter_call.add_argument (new CCodeConstant ("(gsize*) re"));
4529 once_enter_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
4531 ccode.open_if (once_enter_call);
4533 var regex_new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_regex_new"));
4534 regex_new_call.add_argument (new CCodeConstant ("pattern"));
4535 regex_new_call.add_argument (new CCodeConstant ("compile_flags"));
4536 regex_new_call.add_argument (new CCodeConstant ("0"));
4537 regex_new_call.add_argument (new CCodeConstant ("NULL"));
4538 ccode.add_assignment (new CCodeIdentifier ("GRegex* val"), regex_new_call);
4540 var once_leave_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
4541 if (context.require_glib_version (2, 68)) {
4542 once_leave_call.add_argument (new CCodeConstant ("(gsize*) re"));
4544 once_leave_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
4546 once_leave_call.add_argument (new CCodeConstant ("(gsize) val"));
4547 ccode.add_expression (once_leave_call);
4551 ccode.add_return (new CCodeIdentifier ("*re"));
4555 cfile.add_function (fun);
4557 this.next_regex_id++;
4559 cdecl.add_declarator (new CCodeVariableDeclarator (cname + " = NULL"));
4560 cdecl.modifiers = CCodeModifiers.STATIC;
4562 var regex_const = new CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname, re, flags));
4564 cfile.add_constant_declaration (cdecl);
4565 set_cvalue (expr, regex_const);
4568 public override void visit_null_literal (NullLiteral expr) {
4569 if (context.profile == Profile.GOBJECT) {
4570 cfile.add_include ("glib.h");
4572 cfile.add_include ("stddef.h");
4574 set_cvalue (expr, new CCodeConstant ("NULL"));
4576 var array_type = expr.target_type as ArrayType;
4577 var delegate_type = expr.target_type as DelegateType;
4578 if (array_type != null) {
4579 for (int dim = 1; dim <= array_type.rank; dim++) {
4580 append_array_length (expr, new CCodeConstant ("0"));
4582 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
4583 set_delegate_target (expr, new CCodeConstant ("NULL"));
4584 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
4588 public abstract TargetValue get_local_cvalue (LocalVariable local);
4590 public abstract TargetValue get_parameter_cvalue (Parameter param);
4592 public abstract TargetValue get_field_cvalue (Field field, TargetValue? instance);
4594 public abstract TargetValue load_variable (Variable variable, TargetValue value, Expression? expr = null);
4596 public abstract TargetValue load_this_parameter (TypeSymbol sym);
4598 public abstract void store_value (TargetValue lvalue, TargetValue value, SourceReference? source_reference = null);
4600 public virtual string get_delegate_target_cname (string delegate_cname) {
4601 assert_not_reached ();
4604 public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
4605 assert_not_reached ();
4608 public virtual CCodeExpression get_delegate_target_cvalue (TargetValue value) {
4609 return new CCodeInvalidExpression ();
4612 public virtual CCodeExpression get_delegate_target_destroy_notify_cvalue (TargetValue value) {
4613 return new CCodeInvalidExpression ();
4616 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname) {
4617 assert_not_reached ();
4620 public override void visit_base_access (BaseAccess expr) {
4621 unowned Class? cl = expr.value_type.type_symbol as Class;
4622 if (cl != null && !cl.is_compact) {
4623 set_cvalue (expr, generate_instance_cast (get_this_cexpression (), cl));
4625 expr.target_value = load_this_parameter (expr.value_type.type_symbol);
4629 public override void visit_postfix_expression (PostfixExpression expr) {
4630 MemberAccess ma = find_property_access (expr.inner);
4632 // property postfix expression
4633 var prop = (Property) ma.symbol_reference;
4635 // increment/decrement property
4636 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4637 var cexpr = new CCodeBinaryExpression (op, get_cvalue (expr.inner), new CCodeConstant ("1"));
4638 store_property (prop, ma.inner, new GLibValue (expr.value_type, cexpr));
4640 // return previous value
4641 expr.target_value = expr.inner.target_value;
4645 // assign current value to temp variable
4646 var temp_value = store_temp_value (expr.inner.target_value, expr);
4648 // increment/decrement variable
4649 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4650 var cexpr = new CCodeBinaryExpression (op, get_cvalue_ (temp_value), new CCodeConstant ("1"));
4651 ccode.add_assignment (get_cvalue (expr.inner), cexpr);
4653 // return previous value
4654 expr.target_value = temp_value;
4657 private MemberAccess? find_property_access (Expression expr) {
4658 if (!(expr is MemberAccess)) {
4662 var ma = (MemberAccess) expr;
4663 if (ma.symbol_reference is Property) {
4670 static bool is_limited_generic_type (GenericType type) {
4671 unowned Class? cl = type.type_parameter.parent_symbol as Class;
4672 unowned Struct? st = type.type_parameter.parent_symbol as Struct;
4673 if ((cl != null && cl.is_compact) || st != null) {
4674 // compact classes and structs only
4675 // have very limited generics support
4681 public static bool requires_copy (DataType type) {
4682 if (!type.is_disposable ()) {
4686 unowned Class? cl = type.type_symbol as Class;
4687 if (cl != null && is_reference_counting (cl)
4688 && get_ccode_ref_function (cl) == "") {
4689 // empty ref_function => no ref necessary
4693 if (type is GenericType) {
4694 if (is_limited_generic_type ((GenericType) type)) {
4702 public static bool requires_destroy (DataType type) {
4703 if (!type.is_disposable ()) {
4707 var array_type = type as ArrayType;
4708 if (array_type != null && array_type.fixed_length) {
4709 return requires_destroy (array_type.element_type);
4712 unowned Class? cl = type.type_symbol as Class;
4713 if (cl != null && is_reference_counting (cl)
4714 && get_ccode_unref_function (cl) == "") {
4715 // empty unref_function => no unref necessary
4719 if (type is GenericType) {
4720 if (is_limited_generic_type ((GenericType) type)) {
4728 public virtual TargetValue? copy_value (TargetValue value, CodeNode node) {
4729 var type = value.value_type;
4730 var cexpr = get_cvalue_ (value);
4731 var result = ((GLibValue) value).copy ();
4733 if (type is DelegateType) {
4734 var delegate_type = (DelegateType) type;
4735 if (get_ccode_delegate_target (node) && delegate_type.delegate_symbol.has_target && !context.deprecated) {
4736 Report.deprecated (node.source_reference, "copying delegates is not supported");
4738 result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
4742 if (type is ValueType && !type.nullable) {
4743 // normal value type, no null check
4745 // use temp-var for upcoming address-of operator
4746 var temp_cvalue = create_temp_value (type, false, node);
4747 store_value (temp_cvalue, value, node.source_reference);
4748 cexpr = get_cvalue_ (temp_cvalue);
4750 var temp_value = create_temp_value (type, true, node, true);
4751 var ctemp = get_cvalue_ (temp_value);
4753 var vt = (ValueType) type;
4754 var st = (Struct) vt.type_symbol;
4755 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
4756 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4757 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4759 if (!get_ccode_has_copy_function (st)) {
4760 generate_struct_copy_function (st);
4763 if (gvalue_type != null && type.type_symbol == gvalue_type) {
4764 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
4765 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4767 ccode.open_if (cisvalid);
4769 // GValue requires g_value_init in addition to g_value_copy
4770 var value_type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
4771 value_type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4773 var init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
4774 init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4775 init_call.add_argument (value_type_call);
4776 ccode.add_expression (init_call);
4777 ccode.add_expression (copy_call);
4781 // g_value_init/copy must not be called for uninitialized values
4782 store_value (temp_value, temp_cvalue, node.source_reference);
4785 ccode.add_expression (copy_call);
4791 /* (temp = expr, temp == NULL ? NULL : ref (temp))
4793 * can be simplified to
4795 * if static type of expr is non-null
4798 var dupexpr = get_dup_func_expression (type, node.source_reference);
4800 if (dupexpr == null) {
4805 if (dupexpr is CCodeIdentifier && !(type is ArrayType) && !(type is GenericType) && !is_ref_function_void (type)) {
4806 // generate and call NULL-aware ref function to reduce number
4807 // of temporary variables and simplify code
4809 var dupid = (CCodeIdentifier) dupexpr;
4810 string dup0_func = "_%s0".printf (dupid.name);
4812 // g_strdup is already NULL-safe
4813 if (dupid.name == "g_strdup") {
4814 dup0_func = dupid.name;
4815 } else if (add_wrapper (dup0_func)) {
4816 var dup0_fun = new CCodeFunction (dup0_func, get_ccode_name (pointer_type));
4817 dup0_fun.add_parameter (new CCodeParameter ("self", get_ccode_name (pointer_type)));
4818 dup0_fun.modifiers = CCodeModifiers.STATIC;
4820 push_function (dup0_fun);
4822 var dup_call = new CCodeFunctionCall (dupexpr);
4823 dup_call.add_argument (new CCodeIdentifier ("self"));
4825 ccode.add_return (new CCodeConditionalExpression (new CCodeIdentifier ("self"), dup_call, new CCodeConstant ("NULL")));
4829 cfile.add_function (dup0_fun);
4832 var ccall = new CCodeFunctionCall (new CCodeIdentifier (dup0_func));
4833 ccall.add_argument (cexpr);
4834 result.cvalue = ccall;
4835 result.value_type.value_owned = true;
4836 return store_temp_value (result, node);
4839 var ccall = new CCodeFunctionCall (dupexpr);
4841 if (!(type is ArrayType) && get_non_null (value) && !is_ref_function_void (type)) {
4842 // expression is non-null
4843 ccall.add_argument (cexpr);
4845 return store_temp_value (new GLibValue (type, ccall), node);
4847 CCodeExpression ccallarg;
4848 if (node is SliceExpression) {
4850 cexpr = get_cvalue (((SliceExpression) node).container);
4854 var cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cexpr, new CCodeConstant ("NULL"));
4855 if (type is GenericType) {
4856 // dup functions are optional for type parameters
4857 var cdupnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_dup_func_expression (type, node.source_reference), new CCodeConstant ("NULL"));
4858 cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.AND, cnotnull, cdupnotnull);
4861 if (type is GenericType) {
4862 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
4863 ccall.add_argument (new CCodeCastExpression (ccallarg, get_ccode_name (pointer_type)));
4865 ccall.add_argument (ccallarg);
4868 if (type is ArrayType) {
4869 var array_type = (ArrayType) type;
4870 ccall.add_argument (get_array_length_cvalue (value));
4872 if (array_type.element_type is GenericType) {
4873 var elem_dupexpr = get_dup_func_expression (array_type.element_type, node.source_reference);
4874 if (elem_dupexpr == null) {
4875 elem_dupexpr = new CCodeConstant ("NULL");
4877 ccall.add_argument (elem_dupexpr);
4881 CCodeExpression cifnull;
4882 if (type is GenericType) {
4883 // the value might be non-null even when the dup function is null,
4884 // so we may not just use NULL for type parameters
4886 // cast from gconstpointer to gpointer as methods in
4887 // generic classes may not return gconstpointer
4888 cifnull = new CCodeCastExpression (cexpr, get_ccode_name (pointer_type));
4889 } else if (type.type_symbol != null) {
4890 cifnull = new CCodeConstant ("NULL");
4895 if (is_ref_function_void (type)) {
4896 ccode.open_if (cnotnull);
4897 ccode.add_expression (ccall);
4900 if (get_non_null (value)) {
4901 result.cvalue = ccall;
4903 var ccond = new CCodeConditionalExpression (cnotnull, ccall, cifnull);
4904 result.cvalue = ccond;
4906 result = (GLibValue) store_temp_value (result, node, true);
4912 public virtual void generate_class_declaration (Class cl, CCodeFile decl_space) {
4913 if (add_symbol_declaration (decl_space, cl, get_ccode_name (cl))) {
4918 public virtual void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
4921 public virtual bool generate_method_declaration (Method m, CCodeFile decl_space) {
4925 public virtual void generate_error_domain_declaration (ErrorDomain edomain, CCodeFile decl_space) {
4928 public void add_generic_type_arguments (Method m, Map<int,CCodeExpression> arg_map, List<DataType> type_args, CodeNode expr, bool is_chainup = false, List<TypeParameter>? type_parameters = null) {
4929 int type_param_index = 0;
4930 foreach (var type_arg in type_args) {
4931 if (get_ccode_simple_generics (m)) {
4932 if (requires_copy (type_arg)) {
4933 arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), get_destroy0_func_expression (type_arg, is_chainup));
4935 arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
4941 if (type_parameters != null) {
4942 var type_param_name = type_parameters.get (type_param_index).name.ascii_down ().replace ("_", "-");
4943 arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s-type\"".printf (type_param_name)));
4944 arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("\"%s-dup-func\"".printf (type_param_name)));
4945 arg_map.set (get_param_pos (0.1 * type_param_index + 0.05), new CCodeConstant ("\"%s-destroy-func\"".printf (type_param_name)));
4948 arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), get_type_id_expression (type_arg, is_chainup));
4949 if (requires_copy (type_arg)) {
4950 var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference ?? expr.source_reference, is_chainup);
4951 if (dup_func == null) {
4952 // type doesn't contain a copy function
4956 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
4957 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeCastExpression (get_destroy_func_expression (type_arg, is_chainup), "GDestroyNotify"));
4959 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeConstant ("NULL"));
4960 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeConstant ("NULL"));
4966 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
4967 CCodeExpression instance = null;
4968 CCodeExpression creation_expr = null;
4970 unowned Struct? st = expr.type_reference.type_symbol as Struct;
4971 if ((st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list")) || expr.get_object_initializer ().size > 0) {
4972 // value-type initialization or object creation expression with object initializer
4974 var local = expr.parent_node as LocalVariable;
4975 var field = expr.parent_node as Field;
4976 var a = expr.parent_node as Assignment;
4977 if (local != null && is_simple_struct_creation (local, local.initializer)) {
4978 instance = get_cvalue_ (get_local_cvalue (local));
4979 } else if (field != null && is_simple_struct_creation (field, field.initializer)) {
4980 // field initialization
4981 var thisparam = load_this_parameter ((TypeSymbol) field.parent_symbol);
4982 instance = get_cvalue_ (get_field_cvalue (field, thisparam));
4983 } else if (a != null && a.left.symbol_reference is Variable && is_simple_struct_creation ((Variable) a.left.symbol_reference, a.right)) {
4984 if (requires_destroy (a.left.value_type)) {
4985 /* unref old value */
4986 ccode.add_expression (destroy_value (a.left.target_value));
4989 local = a.left.symbol_reference as LocalVariable;
4990 field = a.left.symbol_reference as Field;
4991 var param = a.left.symbol_reference as Parameter;
4992 if (local != null) {
4993 instance = get_cvalue_ (get_local_cvalue (local));
4994 } else if (field != null) {
4995 var inner = ((MemberAccess) a.left).inner;
4996 instance = get_cvalue_ (get_field_cvalue (field, inner != null ? inner.target_value : null));
4997 } else if (param != null) {
4998 instance = get_cvalue_ (get_parameter_cvalue (param));
5000 } else if (expr.is_chainup) {
5001 instance = get_this_cexpression ();
5003 var temp_value = create_temp_value (expr.type_reference, true, expr);
5004 instance = get_cvalue_ (temp_value);
5008 if (expr.symbol_reference == null) {
5009 // no creation method
5010 if (expr.type_reference.type_symbol is Struct) {
5011 // memset needs string.h
5012 cfile.add_include ("string.h");
5013 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
5014 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
5015 creation_call.add_argument (new CCodeConstant ("0"));
5016 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.type_reference))));
5018 creation_expr = creation_call;
5020 } else if (expr.type_reference.type_symbol == glist_type ||
5021 expr.type_reference.type_symbol == gslist_type) {
5022 // NULL is an empty list
5023 set_cvalue (expr, new CCodeConstant ("NULL"));
5024 } else if (expr.symbol_reference is Method) {
5025 // use creation method
5026 var m = (Method) expr.symbol_reference;
5027 var params = m.get_parameters ();
5028 CCodeFunctionCall creation_call;
5030 CCodeFunctionCall async_call = null;
5031 CCodeFunctionCall finish_call = null;
5033 generate_method_declaration (m, cfile);
5035 if (m is CreationMethod && !m.external && m.external_package) {
5036 unowned CreationMethod cm = (CreationMethod) m;
5038 Report.error (cm.source_reference, "internal: Creation method implementation in binding must be chained up");
5040 // internal VAPI creation methods
5041 // only add them once per source file
5042 if (add_generated_external_symbol (cm)) {
5043 visit_creation_method (cm);
5047 unowned Class? cl = expr.type_reference.type_symbol as Class;
5049 if (!get_ccode_has_new_function (m)) {
5050 // use construct function directly
5051 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
5052 creation_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
5054 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
5057 if ((st != null && !st.is_simple_type ()) && !(get_ccode_instance_pos (m) < 0)) {
5058 if (expr.is_chainup) {
5059 creation_call.add_argument (instance);
5061 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
5063 } else if (st != null && get_ccode_name (st) == "va_list") {
5064 creation_call.add_argument (instance);
5065 if (get_ccode_name (m) == "va_start") {
5066 unowned Class? parent = current_method.parent_symbol as Class;
5067 if (in_creation_method && parent != null && !parent.is_compact) {
5068 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("va_copy"));
5069 creation_call.add_argument (instance);
5070 creation_call.add_argument (new CCodeIdentifier ("_vala_va_list"));
5072 Parameter last_param = null;
5073 // FIXME: this doesn't take into account exception handling parameters
5074 foreach (var param in current_method.get_parameters ()) {
5075 if (param.ellipsis || param.params_array) {
5080 int nParams = ccode.get_parameter_count ();
5081 if (nParams == 0 || !ccode.get_parameter (nParams - 1).ellipsis) {
5082 Report.error (expr.source_reference, "`va_list' used in method with fixed args");
5083 } else if (nParams == 1) {
5084 Report.error (expr.source_reference, "`va_list' used in method without parameter");
5086 creation_call.add_argument (new CCodeIdentifier (ccode.get_parameter (nParams - 2).name));
5092 generate_type_declaration (expr.type_reference, cfile);
5094 var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
5095 var out_arg_map = in_arg_map;
5097 if (m != null && m.coroutine) {
5100 async_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
5101 finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
5103 creation_call = finish_call;
5105 // output arguments used separately
5106 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
5107 // pass GAsyncResult stored in closure to finish function
5108 out_arg_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
5111 if (cl != null && (!cl.is_compact || get_ccode_simple_generics (m))) {
5112 add_generic_type_arguments (m, in_arg_map, expr.type_reference.get_type_arguments (), expr);
5115 bool ellipsis = false;
5119 Iterator<Parameter> params_it = params.iterator ();
5120 foreach (Expression arg in expr.get_argument_list ()) {
5121 CCodeExpression cexpr = get_cvalue (arg);
5123 var carg_map = in_arg_map;
5125 Parameter param = null;
5126 if (params_it.next ()) {
5127 param = params_it.get ();
5128 ellipsis = param.ellipsis || param.params_array;
5130 if (param.direction == ParameterDirection.OUT) {
5131 carg_map = out_arg_map;
5134 if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
5135 var array_type = (ArrayType) param.variable_type;
5136 for (int dim = 1; dim <= array_type.rank; dim++) {
5137 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_array_length_cexpression (arg, dim));
5139 } else if (get_ccode_delegate_target (param) && param.variable_type is DelegateType) {
5140 var deleg_type = (DelegateType) param.variable_type;
5141 var d = deleg_type.delegate_symbol;
5143 CCodeExpression delegate_target_destroy_notify;
5144 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
5145 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
5146 if (deleg_type.is_disposable ()) {
5147 carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), delegate_target_destroy_notify);
5152 cexpr = handle_struct_argument (param, arg, cexpr);
5154 if (get_ccode_type (param) != null) {
5155 cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
5158 cexpr = handle_struct_argument (null, arg, cexpr);
5161 arg_pos = get_param_pos (get_ccode_pos (param), ellipsis);
5163 // default argument position
5164 cexpr = handle_struct_argument (null, arg, cexpr);
5165 arg_pos = get_param_pos (i, ellipsis);
5168 carg_map.set (arg_pos, cexpr);
5172 if (params_it.next ()) {
5173 var param = params_it.get ();
5175 /* if there are more parameters than arguments,
5176 * the additional parameter is an ellipsis parameter
5177 * otherwise there is a bug in the semantic analyzer
5179 assert (param.params_array || param.ellipsis);
5183 if (expr.tree_can_fail) {
5185 current_method_inner_error = true;
5186 // add &inner_error before the ellipsis arguments
5187 out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
5191 /* ensure variable argument list ends with NULL
5192 * except when using printf-style arguments */
5194 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
5195 } else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "") {
5196 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
5200 if ((st != null && !st.is_simple_type ()) && get_ccode_instance_pos (m) < 0) {
5201 // instance parameter is at the end in a struct creation method
5202 out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
5205 if (m != null && m.coroutine) {
5206 if (expr.is_yield_expression) {
5207 // asynchronous call
5208 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
5209 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
5213 if (m != null && m.coroutine && m.parent_symbol is Class) {
5214 if (get_ccode_finish_instance (m)) {
5215 var tmp = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_source_object_");
5216 out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), tmp);
5220 // append C arguments in the right order
5225 if (async_call != creation_call) {
5226 // don't append out arguments for .begin() calls
5230 foreach (int pos in out_arg_map.get_keys ()) {
5231 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
5235 if (min_pos == -1) {
5238 creation_call.add_argument (out_arg_map.get (min_pos));
5243 if (async_call != null) {
5247 foreach (int pos in in_arg_map.get_keys ()) {
5248 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
5252 if (min_pos == -1) {
5255 async_call.add_argument (in_arg_map.get (min_pos));
5260 if (expr.is_yield_expression) {
5261 // set state before calling async function to support immediate callbacks
5262 int state = emit_context.next_coroutine_state++;
5264 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
5265 ccode.add_expression (async_call);
5266 ccode.add_return (new CCodeConstant ("FALSE"));
5267 ccode.add_label ("_state_%d".printf (state));
5270 creation_expr = creation_call;
5272 // cast the return value of the creation method back to the intended type if
5273 // it requested a special C return type
5274 if (get_ccode_type (m) != null) {
5275 creation_expr = new CCodeCastExpression (creation_expr, get_ccode_name (expr.type_reference));
5277 } else if (expr.symbol_reference is ErrorCode) {
5278 var ecode = (ErrorCode) expr.symbol_reference;
5279 var edomain = (ErrorDomain) ecode.parent_symbol;
5280 CCodeFunctionCall creation_call;
5282 generate_error_domain_declaration (edomain, cfile);
5284 if (expr.get_argument_list ().size == 1) {
5285 // must not be a format argument
5286 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new_literal"));
5288 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new"));
5290 creation_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (edomain)));
5291 creation_call.add_argument (new CCodeIdentifier (get_ccode_name (ecode)));
5293 foreach (Expression arg in expr.get_argument_list ()) {
5294 creation_call.add_argument (get_cvalue (arg));
5297 creation_expr = creation_call;
5302 var local = expr.parent_node as LocalVariable;
5303 if (local != null && is_simple_struct_creation (local, local.initializer)) {
5304 // no temporary variable necessary
5305 ccode.add_expression (creation_expr);
5306 set_cvalue (expr, instance);
5307 } else if (instance != null) {
5308 if (expr.type_reference.type_symbol is Struct) {
5309 ccode.add_expression (creation_expr);
5311 ccode.add_assignment (instance, creation_expr);
5314 foreach (MemberInitializer init in expr.get_object_initializer ()) {
5315 if (init.symbol_reference is Field) {
5316 var f = (Field) init.symbol_reference;
5317 var instance_target_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
5318 var typed_inst = transform_value (new GLibValue (expr.type_reference, instance, true), instance_target_type, init);
5319 store_field (f, typed_inst, init.initializer.target_value, init.source_reference);
5321 var cl = f.parent_symbol as Class;
5323 generate_class_struct_declaration (cl, cfile);
5325 } else if (init.symbol_reference is Property) {
5326 var p = (Property) init.symbol_reference;
5327 if (p.base_property != null) {
5328 p = p.base_property;
5329 } else if (p.base_interface_property != null) {
5330 p = p.base_interface_property;
5332 var instance_target_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) p.parent_symbol);
5333 var typed_inst = transform_value (new GLibValue (expr.type_reference, instance), instance_target_type, init);
5334 var inst_ma = new MemberAccess.simple ("fake");
5335 inst_ma.target_value = typed_inst;
5336 store_property (p, inst_ma, init.initializer.target_value);
5337 // FIXME Do not ref/copy in the first place
5338 if (!p.set_accessor.value_type.value_owned && requires_destroy (init.initializer.target_value.value_type)) {
5339 ccode.add_expression (destroy_value (init.initializer.target_value));
5342 Report.error (init.source_reference, "internal: Unsupported symbol");
5346 set_cvalue (expr, instance);
5347 } else if (creation_expr != null) {
5348 var temp_value = create_temp_value (expr.value_type, false, expr);
5349 ccode.add_assignment (get_cvalue_ (temp_value), creation_expr);
5350 expr.target_value = temp_value;
5352 unowned Class? cl = expr.type_reference.type_symbol as Class;
5353 if (context.gobject_tracing) {
5354 // GObject creation tracing enabled
5356 if (cl != null && cl.is_subtype_of (gobject_type)) {
5359 // instance can be NULL in error cases
5360 ccode.open_if (get_cvalue_ (expr.target_value));
5362 var set_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set_data"));
5363 set_data_call.add_argument (new CCodeCastExpression (get_cvalue_ (expr.target_value), "GObject *"));
5364 set_data_call.add_argument (new CCodeConstant ("\"vala-creation-function\""));
5366 string func_name = "";
5367 if (current_method != null) {
5368 func_name = current_method.get_full_name ();
5369 } else if (current_property_accessor != null) {
5370 func_name = current_property_accessor.get_full_name ();
5373 set_data_call.add_argument (new CCodeConstant ("\"%s\"".printf (func_name)));
5375 ccode.add_expression (set_data_call);
5381 // create a special GDestroyNotify for created GArray and set with g_array_set_clear_func (since glib 2.32)
5382 if (cl != null && cl == garray_type) {
5383 var type_arg = expr.type_reference.get_type_arguments ().get (0);
5384 if (requires_destroy (type_arg)) {
5385 var clear_func = new CCodeFunctionCall (new CCodeIdentifier ("g_array_set_clear_func"));
5386 clear_func.add_argument (get_cvalue_ (expr.target_value));
5387 string destroy_func;
5388 if (type_arg.is_non_null_simple_type () || type_arg.is_real_non_null_struct_type ()) {
5389 destroy_func = get_ccode_destroy_function (type_arg.type_symbol);
5391 destroy_func = generate_destroy_function_content_of_wrapper (type_arg);
5393 clear_func.add_argument (new CCodeCastExpression (new CCodeIdentifier (destroy_func), "GDestroyNotify"));
5394 ccode.add_expression (clear_func);
5399 ((GLibValue) expr.target_value).lvalue = true;
5402 public CCodeExpression? handle_struct_argument (Parameter? param, Expression arg, CCodeExpression? cexpr) {
5404 if (param != null) {
5405 type = param.variable_type;
5408 type = arg.value_type;
5411 var unary = arg as UnaryExpression;
5412 // pass non-simple struct instances always by reference
5413 if (!(arg.value_type is NullType) && type.is_real_struct_type ()) {
5414 // we already use a reference for arguments of ref, out, and nullable parameters
5415 if (!(unary != null && (unary.operator == UnaryOperator.OUT || unary.operator == UnaryOperator.REF)) && !type.nullable) {
5416 if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
5417 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5419 // if cexpr is e.g. a function call, we can't take the address of the expression
5420 var temp_value = create_temp_value (type, false, arg);
5421 ccode.add_assignment (get_cvalue_ (temp_value), cexpr);
5422 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value));
5430 public override void visit_sizeof_expression (SizeofExpression expr) {
5431 generate_type_declaration (expr.type_reference, cfile);
5433 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5434 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference)));
5435 set_cvalue (expr, csizeof);
5438 public override void visit_typeof_expression (TypeofExpression expr) {
5439 cfile.add_include ("glib-object.h");
5441 set_cvalue (expr, get_type_id_expression (expr.type_reference));
5444 public override void visit_unary_expression (UnaryExpression expr) {
5445 if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) {
5446 var glib_value = (GLibValue) expr.inner.target_value;
5448 var ref_value = new GLibValue (glib_value.value_type);
5449 if (expr.target_type != null && glib_value.value_type.is_real_struct_type () && glib_value.value_type.nullable != expr.target_type.nullable) {
5450 // the only possibility is that value_type is nullable and target_type is non-nullable
5451 ref_value.cvalue = glib_value.cvalue;
5453 ref_value.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.cvalue);
5456 if (glib_value.array_length_cvalues != null) {
5457 for (int i = 0; i < glib_value.array_length_cvalues.size; i++) {
5458 ref_value.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.array_length_cvalues[i]));
5462 if (glib_value.delegate_target_cvalue != null) {
5463 ref_value.delegate_target_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_cvalue);
5465 if (glib_value.delegate_target_destroy_notify_cvalue != null) {
5466 ref_value.delegate_target_destroy_notify_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_destroy_notify_cvalue);
5469 expr.target_value = ref_value;
5473 if (expr.operator == UnaryOperator.INCREMENT || expr.operator == UnaryOperator.DECREMENT) {
5474 // increment/decrement variable
5475 var op = expr.operator == UnaryOperator.INCREMENT ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
5476 var cexpr = new CCodeBinaryExpression (op, get_cvalue_ (expr.inner.target_value), new CCodeConstant ("1"));
5477 ccode.add_assignment (get_cvalue (expr.inner), cexpr);
5479 // assign new value to temp variable
5480 var temp_value = store_temp_value (expr.inner.target_value, expr);
5482 MemberAccess ma = find_property_access (expr.inner);
5484 // property postfix expression
5485 var prop = (Property) ma.symbol_reference;
5487 store_property (prop, ma.inner, temp_value);
5491 expr.target_value = temp_value;
5495 CCodeUnaryOperator op;
5496 switch (expr.operator) {
5497 case UnaryOperator.PLUS:
5498 op = CCodeUnaryOperator.PLUS;
5500 case UnaryOperator.MINUS:
5501 op = CCodeUnaryOperator.MINUS;
5503 case UnaryOperator.LOGICAL_NEGATION:
5504 op = CCodeUnaryOperator.LOGICAL_NEGATION;
5506 case UnaryOperator.BITWISE_COMPLEMENT:
5507 op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
5509 case UnaryOperator.INCREMENT:
5510 op = CCodeUnaryOperator.PREFIX_INCREMENT;
5512 case UnaryOperator.DECREMENT:
5513 op = CCodeUnaryOperator.PREFIX_DECREMENT;
5516 assert_not_reached ();
5518 set_cvalue (expr, new CCodeUnaryExpression (op, get_cvalue (expr.inner)));
5521 public virtual CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
5522 assert_not_reached ();
5525 public virtual CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
5526 assert_not_reached ();
5529 public override void visit_cast_expression (CastExpression expr) {
5530 if (expr.is_silent_cast) {
5531 set_cvalue (expr, new CCodeInvalidExpression ());
5533 Report.error (expr.source_reference, "Operation not supported for this type");
5537 generate_type_declaration (expr.type_reference, cfile);
5539 // recompute array length when casting to other array type
5540 var array_type = expr.type_reference as ArrayType;
5541 if (array_type != null && expr.inner.value_type is ArrayType) {
5542 if (array_type.element_type is GenericType || ((ArrayType) expr.inner.value_type).element_type is GenericType) {
5543 // element size unknown for generic arrays, retain array length as is
5544 for (int dim = 1; dim <= array_type.rank; dim++) {
5545 append_array_length (expr, get_array_length_cexpression (expr.inner, dim));
5548 var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5549 sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5551 var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5552 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (((ArrayType) expr.inner.value_type).element_type)));
5554 for (int dim = 1; dim <= array_type.rank; dim++) {
5555 append_array_length (expr, new CCodeBinaryExpression (CCodeBinaryOperator.DIV, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_array_length_cexpression (expr.inner, dim), sizeof_from), sizeof_to));
5558 } else if (array_type != null) {
5559 CCodeExpression array_length_expr;
5561 var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5562 sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5563 var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5565 var value_type = expr.inner.value_type;
5566 if (value_type is ValueType) {
5567 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (value_type.type_symbol)));
5568 array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5569 } else if (value_type is PointerType && ((PointerType) value_type).base_type is ValueType) {
5570 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (((PointerType) value_type).base_type.type_symbol)));
5571 array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5573 // cast from unsupported non-array to array, set invalid length
5574 // required by string.data, e.g.
5575 array_length_expr = new CCodeConstant ("-1");
5578 for (int dim = 1; dim <= array_type.rank; dim++) {
5579 append_array_length (expr, array_length_expr);
5583 var innercexpr = get_cvalue (expr.inner);
5584 if (expr.type_reference is ValueType && !expr.type_reference.nullable &&
5585 expr.inner.value_type is ValueType && expr.inner.value_type.nullable) {
5586 // handle nested cast expressions
5587 unowned Expression? inner_expr = expr.inner;
5588 while (inner_expr is CastExpression) {
5589 inner_expr = ((CastExpression) inner_expr).inner;
5591 if (inner_expr.value_type.value_owned
5592 && !(inner_expr.symbol_reference is Variable || inner_expr is ElementAccess)) {
5593 // heap allocated struct leaked, destroy it
5594 var value = new GLibValue (new PointerType (new VoidType ()), innercexpr);
5595 temp_ref_values.insert (0, value);
5597 // nullable integer or float or boolean or struct or enum cast to non-nullable
5598 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, innercexpr);
5599 } else if (expr.type_reference is ValueType && expr.type_reference.nullable &&
5600 expr.inner.value_type.is_real_non_null_struct_type ()) {
5601 // real non-null struct cast to nullable
5602 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, innercexpr);
5603 } else if (expr.type_reference is ArrayType && !(expr.inner is Literal)
5604 && expr.inner.value_type is ValueType && !expr.inner.value_type.nullable) {
5605 // integer or float or boolean or struct or enum to array cast
5606 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, innercexpr);
5608 set_cvalue (expr, new CCodeCastExpression (innercexpr, get_ccode_name (expr.type_reference)));
5609 //TODO Use get_non_null (expr.inner.target_value)
5610 ((GLibValue) expr.target_value).non_null = expr.is_non_null ();
5612 if (expr.type_reference is DelegateType) {
5613 var target = get_delegate_target (expr.inner);
5614 if (target != null) {
5615 set_delegate_target (expr, target);
5617 set_delegate_target (expr, new CCodeConstant ("NULL"));
5619 var target_destroy_notify = get_delegate_target_destroy_notify (expr.inner);
5620 if (target_destroy_notify != null) {
5621 set_delegate_target_destroy_notify (expr, target_destroy_notify);
5623 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
5628 public override void visit_named_argument (NamedArgument expr) {
5629 set_cvalue (expr, get_cvalue (expr.inner));
5632 public override void visit_pointer_indirection (PointerIndirection expr) {
5633 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cvalue (expr.inner)));
5634 ((GLibValue) expr.target_value).lvalue = get_lvalue (expr.inner.target_value);
5637 public override void visit_addressof_expression (AddressofExpression expr) {
5638 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5641 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
5642 /* tmp = expr.inner; expr.inner = NULL; expr = tmp; */
5643 expr.target_value = store_temp_value (expr.inner.target_value, expr);
5645 if (expr.inner.value_type is StructValueType && !expr.inner.value_type.nullable) {
5646 // memset needs string.h
5647 cfile.add_include ("string.h");
5648 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
5649 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5650 creation_call.add_argument (new CCodeConstant ("0"));
5651 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.inner.value_type))));
5652 ccode.add_expression (creation_call);
5653 } else if (expr.value_type is DelegateType) {
5654 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5655 var target = get_delegate_target_cvalue (expr.inner.target_value);
5656 if (target != null) {
5657 ccode.add_assignment (target, new CCodeConstant ("NULL"));
5659 var target_destroy_notify = get_delegate_target_destroy_notify_cvalue (expr.inner.target_value);
5660 if (target_destroy_notify != null) {
5661 ccode.add_assignment (target_destroy_notify, new CCodeConstant ("NULL"));
5663 } else if (expr.inner.value_type is ArrayType) {
5664 var array_type = (ArrayType) expr.inner.value_type;
5665 var glib_value = (GLibValue) expr.inner.target_value;
5667 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5668 if (glib_value.array_length_cvalues != null) {
5669 for (int dim = 1; dim <= array_type.rank; dim++) {
5670 ccode.add_assignment (get_array_length_cvalue (glib_value, dim), new CCodeConstant ("0"));
5674 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5678 public override void visit_binary_expression (BinaryExpression expr) {
5679 var cleft = get_cvalue (expr.left);
5680 var cright = get_cvalue (expr.right);
5682 CCodeExpression? left_chain = null;
5683 if (expr.is_chained) {
5684 var lbe = (BinaryExpression) expr.left;
5686 var temp_decl = get_temp_variable (lbe.right.target_type, true, null, false);
5687 emit_temp_var (temp_decl);
5688 var cvar = get_variable_cexpression (temp_decl.name);
5689 var clbe = (CCodeBinaryExpression) get_cvalue (lbe);
5690 if (lbe.is_chained) {
5691 clbe = (CCodeBinaryExpression) clbe.right;
5693 ccode.add_assignment (cvar, get_cvalue (lbe.right));
5694 clbe.right = get_variable_cexpression (temp_decl.name);
5699 CCodeBinaryOperator op;
5700 switch (expr.operator) {
5701 case BinaryOperator.PLUS:
5702 op = CCodeBinaryOperator.PLUS;
5704 case BinaryOperator.MINUS:
5705 op = CCodeBinaryOperator.MINUS;
5707 case BinaryOperator.MUL:
5708 op = CCodeBinaryOperator.MUL;
5710 case BinaryOperator.DIV:
5711 op = CCodeBinaryOperator.DIV;
5713 case BinaryOperator.MOD:
5714 // FIXME Code duplication with CCodeAssignmentModule.emit_simple_assignment()
5715 if (expr.value_type.equals (double_type)) {
5716 cfile.add_include ("math.h");
5717 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
5718 ccall.add_argument (cleft);
5719 ccall.add_argument (cright);
5720 set_cvalue (expr, ccall);
5722 } else if (expr.value_type.equals (float_type)) {
5723 cfile.add_include ("math.h");
5724 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
5725 ccall.add_argument (cleft);
5726 ccall.add_argument (cright);
5727 set_cvalue (expr, ccall);
5730 op = CCodeBinaryOperator.MOD;
5733 case BinaryOperator.SHIFT_LEFT:
5734 op = CCodeBinaryOperator.SHIFT_LEFT;
5736 case BinaryOperator.SHIFT_RIGHT:
5737 op = CCodeBinaryOperator.SHIFT_RIGHT;
5739 case BinaryOperator.LESS_THAN:
5740 op = CCodeBinaryOperator.LESS_THAN;
5742 case BinaryOperator.GREATER_THAN:
5743 op = CCodeBinaryOperator.GREATER_THAN;
5745 case BinaryOperator.LESS_THAN_OR_EQUAL:
5746 op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
5748 case BinaryOperator.GREATER_THAN_OR_EQUAL:
5749 op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
5751 case BinaryOperator.EQUALITY:
5752 op = CCodeBinaryOperator.EQUALITY;
5754 case BinaryOperator.INEQUALITY:
5755 op = CCodeBinaryOperator.INEQUALITY;
5757 case BinaryOperator.BITWISE_AND:
5758 op = CCodeBinaryOperator.BITWISE_AND;
5760 case BinaryOperator.BITWISE_OR:
5761 op = CCodeBinaryOperator.BITWISE_OR;
5763 case BinaryOperator.BITWISE_XOR:
5764 op = CCodeBinaryOperator.BITWISE_XOR;
5766 case BinaryOperator.AND:
5767 op = CCodeBinaryOperator.AND;
5769 case BinaryOperator.OR:
5770 op = CCodeBinaryOperator.OR;
5772 case BinaryOperator.IN:
5773 if (expr.right.value_type is ArrayType) {
5774 unowned ArrayType array_type = (ArrayType) expr.right.value_type;
5775 unowned DataType element_type = array_type.element_type;
5776 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_contains_wrapper (array_type)));
5777 CCodeExpression node = ccall;
5779 ccall.add_argument (cright);
5780 ccall.add_argument (get_array_length_cexpression (expr.right));
5781 if (element_type is StructValueType) {
5782 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft));
5783 } else if (element_type is ValueType && !element_type.nullable
5784 && expr.left.value_type is ValueType && expr.left.value_type.nullable) {
5786 var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cleft, new CCodeConstant ("NULL"));
5787 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft));
5788 node = new CCodeParenthesizedExpression (new CCodeConditionalExpression (cnull, new CCodeConstant ("FALSE"), ccall));
5790 ccall.add_argument (cleft);
5792 set_cvalue (expr, node);
5794 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft));
5798 assert_not_reached ();
5801 if (expr.operator == BinaryOperator.EQUALITY ||
5802 expr.operator == BinaryOperator.INEQUALITY) {
5803 var left_type = expr.left.target_type;
5804 var right_type = expr.right.target_type;
5805 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
5807 if (left_type is StructValueType && right_type is StructValueType) {
5808 var equalfunc = generate_struct_equal_function ((Struct) left_type.type_symbol);
5809 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5810 ccall.add_argument (cleft);
5811 ccall.add_argument (cright);
5813 cright = get_boolean_cconstant (true);
5814 } else if ((left_type is IntegerType || left_type is FloatingType || left_type is BooleanType || left_type is EnumValueType) && left_type.nullable &&
5815 (right_type is IntegerType || right_type is FloatingType || right_type is BooleanType || right_type is EnumValueType) && right_type.nullable) {
5816 var equalfunc = generate_numeric_equal_function ((TypeSymbol) left_type.type_symbol);
5817 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5818 ccall.add_argument (cleft);
5819 ccall.add_argument (cright);
5821 cright = get_boolean_cconstant (true);
5825 bool is_string_comparison = !(expr.left.value_type is NullType) && expr.left.value_type.compatible (string_type)
5826 && !(expr.right.value_type is NullType) && expr.right.value_type.compatible (string_type);
5827 bool has_string_literal = (expr.left is StringLiteral || expr.right is StringLiteral);
5829 if (is_string_comparison || (has_string_literal && expr.operator != BinaryOperator.PLUS)) {
5830 switch (expr.operator) {
5831 case BinaryOperator.PLUS:
5832 // string concatenation
5833 if (expr.left.is_constant () && expr.right.is_constant ()) {
5836 if (cleft is CCodeIdentifier) {
5837 left = ((CCodeIdentifier) cleft).name;
5838 } else if (cleft is CCodeConstant) {
5839 left = ((CCodeConstant) cleft).name;
5841 Report.error (expr.source_reference, "internal: Unsupported expression");
5844 if (cright is CCodeIdentifier) {
5845 right = ((CCodeIdentifier) cright).name;
5846 } else if (cright is CCodeConstant) {
5847 right = ((CCodeConstant) cright).name;
5849 Report.error (expr.source_reference, "internal: Unsupported expression");
5853 set_cvalue (expr, new CCodeConstant ("%s %s".printf (left, right)));
5855 var temp_value = create_temp_value (expr.value_type, false, expr);
5856 CCodeFunctionCall ccall;
5858 if (context.profile == Profile.POSIX) {
5859 // convert to strcat (strcpy (malloc (1 + strlen (a) + strlen (b)), a), b)
5860 ccall = new CCodeFunctionCall (new CCodeIdentifier ("strcat"));
5861 var strcpy = new CCodeFunctionCall (new CCodeIdentifier ("strcpy"));
5862 var malloc = new CCodeFunctionCall (new CCodeIdentifier ("malloc"));
5864 var strlen_a = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
5865 strlen_a.add_argument (cleft);
5866 var strlen_b = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
5867 strlen_b.add_argument (cright);
5868 var newlength = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("1"),
5869 new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, strlen_a, strlen_b));
5870 malloc.add_argument (newlength);
5872 strcpy.add_argument (malloc);
5873 strcpy.add_argument (cleft);
5875 ccall.add_argument (strcpy);
5876 ccall.add_argument (cright);
5878 // convert to g_strconcat (a, b, NULL)
5879 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
5880 ccall.add_argument (cleft);
5881 ccall.add_argument (cright);
5882 ccall.add_argument (new CCodeConstant("NULL"));
5885 ccode.add_assignment (get_cvalue_ (temp_value), ccall);
5886 expr.target_value = temp_value;
5889 case BinaryOperator.EQUALITY:
5890 case BinaryOperator.INEQUALITY:
5891 case BinaryOperator.LESS_THAN:
5892 case BinaryOperator.GREATER_THAN:
5893 case BinaryOperator.LESS_THAN_OR_EQUAL:
5894 case BinaryOperator.GREATER_THAN_OR_EQUAL:
5895 CCodeFunctionCall ccall;
5896 if (context.profile == Profile.POSIX) {
5897 cfile.add_include ("string.h");
5898 ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
5900 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5902 ccall.add_argument (cleft);
5903 ccall.add_argument (cright);
5905 cright = new CCodeConstant ("0");
5912 set_cvalue (expr, new CCodeBinaryExpression (op, cleft, cright));
5913 if (left_chain != null) {
5914 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.AND, left_chain, get_cvalue (expr)));
5918 public CCodeExpression? create_type_check (CCodeNode ccodenode, DataType type) {
5919 var et = type as ErrorType;
5920 if (et != null && et.error_code != null) {
5921 var matches_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
5922 matches_call.add_argument ((CCodeExpression) ccodenode);
5923 matches_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain)));
5924 matches_call.add_argument (new CCodeIdentifier (get_ccode_name (et.error_code)));
5925 return matches_call;
5926 } else if (et != null && et.error_domain != null) {
5927 var instance_domain = new CCodeMemberAccess.pointer ((CCodeExpression) ccodenode, "domain");
5928 var type_domain = new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain));
5929 return new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, instance_domain, type_domain);
5931 CCodeFunctionCall ccheck;
5932 if (type is GenericType || type.type_symbol == null || type.type_symbol.external_package) {
5933 ccheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
5934 ccheck.add_argument ((CCodeExpression) ccodenode);
5935 ccheck.add_argument (get_type_id_expression (type));
5937 ccheck = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_check_function (type.type_symbol)));
5938 ccheck.add_argument ((CCodeExpression) ccodenode);
5945 string generate_array_contains_wrapper (ArrayType array_type) {
5946 string array_contains_func = "_vala_%s_array_contains".printf (get_ccode_lower_case_name (array_type.element_type));
5948 if (!add_wrapper (array_contains_func)) {
5949 return array_contains_func;
5952 generate_type_declaration (ssize_t_type, cfile);
5954 var function = new CCodeFunction (array_contains_func, get_ccode_name (bool_type));
5955 function.modifiers = CCodeModifiers.STATIC;
5957 function.add_parameter (new CCodeParameter ("stack", "%s *".printf (get_ccode_name (array_type.element_type))));
5958 function.add_parameter (new CCodeParameter ("stack_length", get_ccode_name (ssize_t_type)));
5959 if (array_type.element_type is StructValueType) {
5960 function.add_parameter (new CCodeParameter ("needle", "const %s *".printf (get_ccode_name (array_type.element_type))));
5962 function.add_parameter (new CCodeParameter ("needle", "const %s".printf (get_ccode_name (array_type.element_type))));
5965 push_function (function);
5967 ccode.add_declaration (get_ccode_name (ssize_t_type), new CCodeVariableDeclarator ("i"));
5969 var cloop_initializer = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
5970 var cloop_condition = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("stack_length"));
5971 var cloop_iterator = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"));
5972 ccode.open_for (cloop_initializer, cloop_condition, cloop_iterator);
5974 var celement = new CCodeElementAccess (new CCodeIdentifier ("stack"), new CCodeIdentifier ("i"));
5975 var cneedle = new CCodeIdentifier ("needle");
5976 CCodeBinaryExpression cif_condition;
5977 if (array_type.element_type.compatible (string_type)) {
5978 CCodeFunctionCall ccall;
5979 if (context.profile == Profile.POSIX) {
5980 cfile.add_include ("string.h");
5981 ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
5983 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5985 ccall.add_argument (celement);
5986 ccall.add_argument (cneedle);
5987 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("0"));
5988 } else if (array_type.element_type is StructValueType) {
5989 var equalfunc = generate_struct_equal_function ((Struct) array_type.element_type.type_symbol);
5990 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5991 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, celement));
5992 ccall.add_argument (cneedle);
5993 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, get_boolean_cconstant (true));
5995 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cneedle, celement);
5998 ccode.open_if (cif_condition);
5999 ccode.add_return (get_boolean_cconstant (true));
6004 ccode.add_return (get_boolean_cconstant (false));
6008 cfile.add_function_declaration (function);
6009 cfile.add_function (function);
6011 return array_contains_func;
6014 string generate_cmp_wrapper (CCodeIdentifier cmpid) {
6015 // generate and call NULL-aware cmp function to reduce number
6016 // of temporary variables and simplify code
6018 string cmp0_func = "_%s0".printf (cmpid.name);
6020 // g_strcmp0 is already NULL-safe
6021 if (cmpid.name == "g_strcmp0") {
6022 cmp0_func = cmpid.name;
6023 } else if (add_wrapper (cmp0_func)) {
6024 var cmp0_fun = new CCodeFunction (cmp0_func, get_ccode_name (int_type));
6025 cmp0_fun.add_parameter (new CCodeParameter ("s1", "const void *"));
6026 cmp0_fun.add_parameter (new CCodeParameter ("s2", "const void *"));
6027 cmp0_fun.modifiers = CCodeModifiers.STATIC;
6029 push_function (cmp0_fun);
6032 var noteq = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
6034 // if (!s1) return -(s1 != s2);
6036 var cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("s1"));
6037 ccode.open_if (cexp);
6038 ccode.add_return (new CCodeUnaryExpression (CCodeUnaryOperator.MINUS, noteq));
6041 // if (!s2) return s1 != s2;
6043 var cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("s2"));
6044 ccode.open_if (cexp);
6045 ccode.add_return (noteq);
6048 // return strcmp (s1, s2);
6049 var cmp_call = new CCodeFunctionCall (cmpid);
6050 cmp_call.add_argument (new CCodeIdentifier ("s1"));
6051 cmp_call.add_argument (new CCodeIdentifier ("s2"));
6052 ccode.add_return (cmp_call);
6056 cfile.add_function (cmp0_fun);
6062 public override void visit_type_check (TypeCheck expr) {
6063 generate_type_declaration (expr.type_reference, cfile);
6065 var type = expr.expression.value_type;
6066 var pointer_type = type as PointerType;
6067 if (pointer_type != null) {
6068 type = pointer_type.base_type;
6070 unowned Class? cl = type.type_symbol as Class;
6071 unowned Interface? iface = type.type_symbol as Interface;
6072 if ((cl != null && !cl.is_compact) || iface != null || type is GenericType || type is ErrorType) {
6073 set_cvalue (expr, create_type_check (get_cvalue (expr.expression), expr.type_reference));
6075 set_cvalue (expr, new CCodeInvalidExpression ());
6078 if (get_cvalue (expr) is CCodeInvalidExpression) {
6079 Report.error (expr.source_reference, "type check expressions not supported for compact classes, structs, and enums");
6083 public override void visit_lambda_expression (LambdaExpression lambda) {
6084 var delegate_type = (DelegateType) lambda.target_type;
6086 lambda.accept_children (this);
6088 bool expr_owned = lambda.value_type.value_owned;
6090 set_cvalue (lambda, new CCodeIdentifier (get_ccode_name (lambda.method)));
6092 unowned DataType? this_type;
6093 if (lambda.method.closure) {
6094 int block_id = get_block_id (current_closure_block);
6095 var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
6096 if (expr_owned || delegate_type.is_called_once) {
6097 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
6098 ref_call.add_argument (delegate_target);
6099 delegate_target = ref_call;
6100 set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
6102 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
6104 set_delegate_target (lambda, delegate_target);
6105 } else if ((this_type = get_this_type ()) != null) {
6106 CCodeExpression delegate_target = get_this_cexpression ();
6107 delegate_target = convert_to_generic_pointer (delegate_target, this_type);
6108 if (expr_owned || delegate_type.is_called_once) {
6109 var ref_call = new CCodeFunctionCall (get_dup_func_expression (this_type, lambda.source_reference));
6110 ref_call.add_argument (delegate_target);
6111 delegate_target = ref_call;
6112 set_delegate_target_destroy_notify (lambda, get_destroy_func_expression (this_type));
6114 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
6116 set_delegate_target (lambda, delegate_target);
6118 set_delegate_target (lambda, new CCodeConstant ("NULL"));
6119 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
6123 public CCodeExpression convert_from_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
6124 unowned SemanticAnalyzer analyzer = context.analyzer;
6126 if (analyzer.is_reference_type_argument (actual_type) || analyzer.is_nullable_value_type_argument (actual_type)) {
6127 generate_type_declaration (actual_type, cfile);
6128 result = new CCodeCastExpression (cexpr, get_ccode_name (actual_type));
6129 } else if (analyzer.is_signed_integer_type_argument (actual_type)) {
6130 // FIXME this should not happen
6131 while (cexpr is CCodeCastExpression) {
6132 cexpr = ((CCodeCastExpression) cexpr).inner;
6134 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), get_ccode_name (actual_type));
6135 } else if (analyzer.is_unsigned_integer_type_argument (actual_type)) {
6136 // FIXME this should not happen
6137 while (cexpr is CCodeCastExpression) {
6138 cexpr = ((CCodeCastExpression) cexpr).inner;
6140 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), get_ccode_name (actual_type));
6145 public CCodeExpression convert_to_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
6146 unowned SemanticAnalyzer analyzer = context.analyzer;
6148 if (analyzer.is_signed_integer_type_argument (actual_type)) {
6149 // FIXME this should not happen
6150 while (cexpr is CCodeCastExpression) {
6151 cexpr = ((CCodeCastExpression) cexpr).inner;
6153 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), get_ccode_name (pointer_type));
6154 } else if (analyzer.is_unsigned_integer_type_argument (actual_type)) {
6155 // FIXME this should not happen
6156 while (cexpr is CCodeCastExpression) {
6157 cexpr = ((CCodeCastExpression) cexpr).inner;
6159 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), get_ccode_name (pointer_type));
6164 int next_variant_function_id = 0;
6166 public TargetValue transform_value (TargetValue value, DataType? target_type, CodeNode node) {
6167 var type = value.value_type;
6168 var result = ((GLibValue) value).copy ();
6170 if (type.value_owned
6171 && (target_type == null || target_type is GenericType || !target_type.floating_reference)
6172 && type.floating_reference) {
6173 /* floating reference, sink it.
6175 unowned ObjectTypeSymbol? cl = type.type_symbol as ObjectTypeSymbol;
6176 var sink_func = (cl != null) ? get_ccode_ref_sink_function (cl) : "";
6178 if (sink_func != "") {
6179 if (type.nullable) {
6180 var is_not_null = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, result.cvalue, new CCodeConstant ("NULL"));
6181 ccode.open_if (is_not_null);
6184 var csink = new CCodeFunctionCall (new CCodeIdentifier (sink_func));
6185 csink.add_argument (result.cvalue);
6186 ccode.add_expression (csink);
6188 if (type.nullable) {
6192 Report.error (node.source_reference, "type `%s' does not support floating references", type.type_symbol.name);
6196 bool boxing = (type is ValueType && !type.nullable
6197 && target_type is ValueType && target_type.nullable);
6198 bool unboxing = (type is ValueType && type.nullable
6199 && target_type is ValueType && !target_type.nullable);
6201 bool gvalue_boxing = (context.profile == Profile.GOBJECT
6202 && target_type != null
6203 && target_type.type_symbol == gvalue_type
6204 && !(type is NullType)
6205 && get_ccode_type_id (type) != "G_TYPE_VALUE");
6206 bool gvariant_boxing = (context.profile == Profile.GOBJECT
6207 && target_type != null
6208 && target_type.type_symbol == gvariant_type
6209 && !(type is NullType)
6210 && type.type_symbol != gvariant_type);
6212 if (type.value_owned
6213 && (target_type == null || !target_type.value_owned || boxing || unboxing || gvariant_boxing)
6214 && !gvalue_boxing /* gvalue can assume ownership of value, no need to free it */) {
6215 // value leaked, destroy it
6216 if (target_type is PointerType) {
6217 // manual memory management for pointers
6218 } else if (requires_destroy (type)) {
6219 if (!is_lvalue_access_allowed (type)) {
6220 // cannot assign to a temporary variable
6221 temp_ref_values.insert (0, result.copy ());
6223 var temp_value = create_temp_value (type, false, node);
6224 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
6225 store_value (temp_value, result, node.source_reference);
6226 result.cvalue = get_cvalue_ (temp_value);
6231 if (target_type == null) {
6232 // value will be destroyed, no need for implicit casts
6236 result.value_type = target_type.copy ();
6238 if (gvalue_boxing) {
6239 // implicit conversion to GValue
6240 var temp_value = create_temp_value (target_type, true, node, true);
6242 if (!target_type.value_owned) {
6243 // boxed GValue leaked, destroy it
6244 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
6247 if (target_type.nullable) {
6248 var newcall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
6249 newcall.add_argument (new CCodeConstant ("GValue"));
6250 newcall.add_argument (new CCodeConstant ("1"));
6251 var newassignment = new CCodeAssignment (get_cvalue_ (temp_value), newcall);
6252 ccode.add_expression (newassignment);
6255 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
6256 if (target_type.nullable) {
6257 ccall.add_argument (get_cvalue_ (temp_value));
6259 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
6261 var type_id = get_ccode_type_id (type);
6262 if (type_id == "") {
6263 Report.error (node.source_reference, "GValue boxing of type `%s' is not supported", type.to_string ());
6265 ccall.add_argument (new CCodeIdentifier (type_id));
6266 ccode.add_expression (ccall);
6268 if (requires_destroy (type)) {
6269 ccall = new CCodeFunctionCall (get_value_taker_function (type));
6271 ccall = new CCodeFunctionCall (get_value_setter_function (type));
6273 if (target_type.nullable) {
6274 ccall.add_argument (get_cvalue_ (temp_value));
6276 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
6278 if (type.is_real_non_null_struct_type ()) {
6279 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue));
6281 ccall.add_argument (result.cvalue);
6284 ccode.add_expression (ccall);
6286 result = (GLibValue) temp_value;
6287 } else if (gvariant_boxing) {
6288 // implicit conversion to GVariant
6289 string variant_func = "_variant_new%d".printf (++next_variant_function_id);
6291 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
6292 ccall.add_argument (result.cvalue);
6294 var cfunc = new CCodeFunction (variant_func, "GVariant*");
6295 cfunc.modifiers = CCodeModifiers.STATIC;
6296 cfunc.add_parameter (new CCodeParameter ("value", get_ccode_name (type)));
6298 if (type is ArrayType) {
6299 // return array length if appropriate
6300 var array_type = (ArrayType) type;
6301 var length_ctype = get_ccode_array_length_type (array_type);
6302 for (int dim = 1; dim <= array_type.rank; dim++) {
6303 ccall.add_argument (get_array_length_cvalue (value, dim));
6304 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), length_ctype));
6308 push_function (cfunc);
6310 // sink floating reference
6311 var sink = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_ref_sink"));
6312 sink.add_argument (serialize_expression (type, new CCodeIdentifier ("value")));
6313 ccode.add_return (sink);
6317 cfile.add_function_declaration (cfunc);
6318 cfile.add_function (cfunc);
6320 result.cvalue = ccall;
6321 result.value_type.value_owned = true;
6323 result = (GLibValue) store_temp_value (result, node);
6324 if (!target_type.value_owned) {
6326 temp_ref_values.insert (0, ((GLibValue) result).copy ());
6328 } else if (boxing) {
6329 // value needs to be boxed
6331 result.value_type.nullable = false;
6332 if (!result.lvalue || !result.value_type.equals (value.value_type)) {
6333 result.cvalue = get_implicit_cast_expression (result.cvalue, value.value_type, result.value_type, node);
6334 if (!(result.cvalue is CCodeConstantIdentifier)) {
6335 result = (GLibValue) store_temp_value (result, node);
6338 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue);
6339 result.lvalue = false;
6340 result.value_type.nullable = true;
6341 } else if (unboxing) {
6344 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result.cvalue);
6346 // TODO: rewrite get_implicit_cast_expression to return a GLibValue
6347 var old_cexpr = result.cvalue;
6348 result.cvalue = get_implicit_cast_expression (result.cvalue, type, target_type, node);
6349 result.lvalue = result.lvalue && result.cvalue == old_cexpr;
6352 bool array_needs_copy = false;
6353 if (type is ArrayType && target_type is ArrayType) {
6354 var array = (ArrayType) type;
6355 var target_array = (ArrayType) target_type;
6356 if (target_array.element_type.value_owned && !array.element_type.value_owned) {
6357 array_needs_copy = requires_copy (target_array.element_type);
6361 if (!gvalue_boxing && !gvariant_boxing && target_type.value_owned && (!type.value_owned || boxing || unboxing || array_needs_copy) && requires_copy (target_type) && !(type is NullType)) {
6362 // need to copy value
6363 var copy = (GLibValue) copy_value (result, node);
6364 if (target_type.type_symbol is Interface && copy == null) {
6365 Report.error (node.source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure", target_type.type_symbol.get_full_name ());
6368 // need to free old array after copying it
6369 if (array_needs_copy && requires_destroy (type)) {
6370 result.value_type = type.copy ();
6371 ccode.add_expression (destroy_value (result));
6375 // implicit array copying is deprecated, but allow it for internal codegen usage
6376 var prop_acc = node as PropertyAccessor;
6377 if ((prop_acc != null && !prop_acc.automatic_body)
6378 && result.value_type is ArrayType) {
6379 Report.deprecated (node.source_reference, "implicit copy of array is deprecated, explicitly invoke the copy method instead");
6386 public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, CodeNode? node) {
6387 var cexpr = source_cexpr;
6389 if (expression_type.type_symbol != null && expression_type.type_symbol == target_type.type_symbol) {
6390 // same type, no cast required
6394 if (expression_type is NullType) {
6395 // null literal, no cast required when not converting to generic type pointer
6399 generate_type_declaration (target_type, cfile);
6401 unowned Class? cl = target_type.type_symbol as Class;
6402 unowned Interface? iface = target_type.type_symbol as Interface;
6403 if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
6404 // checked cast for strict subtypes of GTypeInstance
6405 return generate_instance_cast (cexpr, target_type.type_symbol);
6406 } else if (target_type.type_symbol != null && get_ccode_name (expression_type) != get_ccode_name (target_type)) {
6407 unowned Struct? st = target_type.type_symbol as Struct;
6408 if (target_type.type_symbol.is_reference_type () || (st != null && st.is_simple_type ())) {
6409 // don't cast non-simple structs
6410 return new CCodeCastExpression (cexpr, get_ccode_name (target_type));
6419 public void store_property (Property prop, Expression? instance, TargetValue value) {
6420 unowned Property base_prop = prop;
6421 if (prop.base_property != null) {
6422 base_prop = prop.base_property;
6423 } else if (prop.base_interface_property != null) {
6424 base_prop = prop.base_interface_property;
6426 if (instance is BaseAccess && (base_prop.is_abstract || base_prop.is_virtual)) {
6427 CCodeExpression? vcast = null;
6428 if (base_prop.parent_symbol is Class) {
6429 unowned Class base_class = (Class) base_prop.parent_symbol;
6430 vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
6431 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
6432 } else if (base_prop.parent_symbol is Interface) {
6433 unowned Interface base_iface = (Interface) base_prop.parent_symbol;
6434 vcast = get_this_interface_cexpression (base_iface);
6436 if (vcast != null) {
6437 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
6438 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
6439 var cexpr = get_cvalue_ (value);
6440 if (prop.property_type.is_real_non_null_struct_type ()) {
6441 //TODO Make use of get_lvalue (value)
6442 if (!(cexpr is CCodeConstant || cexpr is CCodeIdentifier)) {
6443 var temp_value = store_temp_value (value, instance);
6444 cexpr = get_cvalue_ (temp_value);
6446 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6448 ccall.add_argument (cexpr);
6450 ccode.add_expression (ccall);
6452 Report.error (instance.source_reference, "internal: Invalid assignment to `%s'", base_prop.get_full_name ());
6457 var set_func = "g_object_set";
6459 if (!get_ccode_no_accessor_method (prop) && !(prop is DynamicProperty)) {
6460 generate_property_accessor_declaration (base_prop.set_accessor, cfile);
6461 set_func = get_ccode_name (base_prop.set_accessor);
6463 if (!prop.external && prop.external_package) {
6464 // internal VAPI properties
6465 // only add them once per source file
6466 if (add_generated_external_symbol (prop)) {
6467 visit_property (prop);
6472 var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
6474 if (prop.binding == MemberBinding.INSTANCE) {
6475 /* target instance is first argument */
6476 var cinstance = (CCodeExpression) get_ccodenode (instance);
6478 if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
6479 // we need to pass struct instance by reference if it isn't a simple-type
6480 var instance_value = instance.target_value;
6481 if (!get_lvalue (instance_value)) {
6482 instance_value = store_temp_value (instance_value, instance);
6484 cinstance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
6487 ccall.add_argument (cinstance);
6490 if (get_ccode_no_accessor_method (prop) || prop is DynamicProperty) {
6491 /* property name is second argument of g_object_set */
6492 ccall.add_argument (get_property_canonical_cconstant (prop));
6495 var cexpr = get_cvalue_ (value);
6497 if (prop.property_type.is_real_non_null_struct_type ()) {
6498 //TODO Make use of get_lvalue (value)
6499 if (!(cexpr is CCodeConstant || cexpr is CCodeIdentifier)) {
6500 var temp_value = store_temp_value (value, instance);
6501 cexpr = get_cvalue_ (temp_value);
6503 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6506 var array_type = prop.property_type as ArrayType;
6508 ccall.add_argument (cexpr);
6510 if (array_type != null && get_ccode_array_length (prop)) {
6511 for (int dim = 1; dim <= array_type.rank; dim++) {
6512 ccall.add_argument (get_array_length_cvalue (value, dim));
6514 } else if (prop.property_type is DelegateType) {
6515 var delegate_type = (DelegateType) prop.property_type;
6516 if (get_ccode_delegate_target (prop) && delegate_type.delegate_symbol.has_target) {
6517 ccall.add_argument (get_delegate_target_cvalue (value));
6518 if (base_prop.set_accessor.value_type.value_owned) {
6519 ccall.add_argument (get_delegate_target_destroy_notify_cvalue (value));
6524 if (get_ccode_no_accessor_method (prop) || prop is DynamicProperty) {
6525 ccall.add_argument (new CCodeConstant ("NULL"));
6528 ccode.add_expression (ccall);
6531 public bool add_wrapper (string wrapper_name) {
6532 return wrappers.add (wrapper_name);
6535 public bool add_generated_external_symbol (Symbol external_symbol) {
6536 return generated_external_symbols.add (external_symbol);
6539 public static DataType get_callable_creturn_type (Callable c) {
6540 assert (c is Method || c is Delegate);
6541 var creturn_type = c.return_type.copy ();
6542 if (c is CreationMethod) {
6543 unowned Class? cl = c.parent_symbol as Class;
6544 unowned Struct? st = c.parent_symbol as Struct;
6546 // object creation methods return the new object in C
6547 // in Vala they have no return type
6548 creturn_type = new ObjectType (cl);
6549 } else if (st != null && st.is_simple_type ()) {
6550 // constructors return simple type structs by value
6551 creturn_type = new StructValueType (st);
6553 } else if (c.return_type.is_real_non_null_struct_type ()) {
6554 // structs are returned via out parameter
6555 creturn_type = new VoidType ();
6557 return creturn_type;
6560 public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression, bool on_error = false) {
6561 unowned Struct? st = type.type_symbol as Struct;
6562 var array_type = type as ArrayType;
6563 if (type.type_symbol != null && !type.nullable
6564 && (on_error ? get_ccode_default_value_on_error (type.type_symbol) : get_ccode_default_value (type.type_symbol)) != "") {
6565 CCodeExpression val = new CCodeConstant (on_error ? get_ccode_default_value_on_error (type.type_symbol) : get_ccode_default_value (type.type_symbol));
6566 if (st != null && st.get_fields ().size > 0) {
6567 val = new CCodeCastExpression (val, get_ccode_name (st));
6570 } else if (initializer_expression && !type.nullable &&
6571 (st != null || (array_type != null && array_type.fixed_length))) {
6572 // 0-initialize struct with struct initializer { 0 }
6573 // only allowed as initializer expression in C
6574 var clist = new CCodeInitializerList ();
6575 clist.append (new CCodeConstant ("0"));
6577 } else if ((type.type_symbol != null && type.type_symbol.is_reference_type ())
6579 || type is PointerType || type is DelegateType
6580 || (array_type != null && !array_type.fixed_length)) {
6581 return new CCodeConstant ("NULL");
6582 } else if (type is GenericType) {
6583 return new CCodeConstant ("NULL");
6584 } else if (type is ErrorType) {
6585 return new CCodeConstant ("NULL");
6586 } else if (type is CType) {
6587 return new CCodeConstant (((CType) type).cdefault_value);
6592 private void create_property_type_check_statement (Property prop, bool check_return_type, TypeSymbol t, bool non_null, string var_name) {
6593 if (check_return_type) {
6594 create_type_check_statement (prop, prop.property_type, t, non_null, var_name);
6596 create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
6600 public virtual void create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
6603 public int get_param_pos (double param_pos, bool ellipsis = false) {
6605 if (param_pos >= 0) {
6606 return (int) (param_pos * 1000);
6608 return (int) ((100 + param_pos) * 1000);
6611 if (param_pos >= 0) {
6612 return (int) ((100 + param_pos) * 1000);
6614 return (int) ((200 + param_pos) * 1000);
6619 public CCodeExpression? get_ccodenode (Expression node) {
6620 if (get_cvalue (node) == null) {
6623 return get_cvalue (node);
6626 public bool is_lvalue_access_allowed (DataType type) {
6627 var array_type = type as ArrayType;
6628 if (array_type != null && array_type.inline_allocated) {
6631 if (type.type_symbol != null) {
6632 return type.type_symbol.get_attribute_bool ("CCode", "lvalue_access", true);
6637 public bool requires_memset_init (Variable variable, out CCodeExpression? size) {
6638 unowned ArrayType? array_type = variable.variable_type as ArrayType;
6639 if (array_type != null && array_type.fixed_length) {
6640 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
6641 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
6642 size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call);
6643 return !is_constant_ccode (array_type.length);
6649 public CCodeDeclaratorSuffix? get_ccode_declarator_suffix (DataType type) {
6650 var array_type = type as ArrayType;
6651 if (array_type != null) {
6652 if (array_type.fixed_length) {
6653 return new CCodeDeclaratorSuffix.with_array (get_ccodenode (array_type.length));
6654 } else if (array_type.inline_allocated) {
6655 return new CCodeDeclaratorSuffix.with_array ();
6661 public CCodeConstant get_signal_canonical_constant (Signal sig, string? detail = null) {
6662 return new CCodeConstant ("\"%s%s\"".printf (get_ccode_name (sig), (detail != null ? "::%s".printf (detail) : "")));
6665 public CCodeConstant get_property_canonical_cconstant (Property prop) {
6666 return new CCodeConstant ("\"%s\"".printf (get_ccode_name (prop)));
6669 public override void visit_class (Class cl) {
6672 public void create_postcondition_statement (Expression postcondition) {
6673 var cassert = new CCodeFunctionCall (new CCodeIdentifier ("_vala_warn_if_fail"));
6675 postcondition.emit (this);
6677 string message = ((string) postcondition.source_reference.begin.pos).substring (0, (int) (postcondition.source_reference.end.pos - postcondition.source_reference.begin.pos));
6678 cassert.add_argument (get_cvalue (postcondition));
6679 cassert.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
6680 requires_assert = true;
6682 ccode.add_expression (cassert);
6684 foreach (var value in temp_ref_values) {
6685 ccode.add_expression (destroy_value (value));
6688 temp_ref_values.clear ();
6691 public unowned DataType? get_this_type () {
6692 if (current_method != null && current_method.binding == MemberBinding.INSTANCE) {
6693 return current_method.this_parameter.variable_type;
6694 } else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) {
6695 return current_property_accessor.prop.this_parameter.variable_type;
6696 } else if (current_constructor != null && current_constructor.binding == MemberBinding.INSTANCE) {
6697 return current_constructor.this_parameter.variable_type;
6698 } else if (current_destructor != null && current_destructor.binding == MemberBinding.INSTANCE) {
6699 return current_destructor.this_parameter.variable_type;
6704 public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
6705 var result = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_CAST"));
6706 result.add_argument (expr);
6707 result.add_argument (new CCodeIdentifier (get_ccode_type_id (type)));
6708 result.add_argument (new CCodeIdentifier (get_ccode_name (type)));
6712 void generate_struct_destroy_function (Struct st) {
6713 if (cfile.add_declaration (get_ccode_destroy_function (st))) {
6714 // only generate function once per source file
6718 var function = new CCodeFunction (get_ccode_destroy_function (st), "void");
6719 function.modifiers = CCodeModifiers.STATIC;
6720 function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (st))));
6722 push_context (new EmitContext ());
6723 push_function (function);
6725 var this_value = load_this_parameter (st);
6726 foreach (Field f in st.get_fields ()) {
6727 if (f.binding == MemberBinding.INSTANCE) {
6728 if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_destroy (f.variable_type)) {
6729 ccode.add_expression (destroy_field (f, this_value));
6737 cfile.add_function_declaration (function);
6738 cfile.add_function (function);
6741 void generate_struct_copy_function (Struct st) {
6742 if (cfile.add_declaration (get_ccode_copy_function (st))) {
6743 // only generate function once per source file
6747 var function = new CCodeFunction (get_ccode_copy_function (st), "void");
6748 function.modifiers = CCodeModifiers.STATIC;
6749 function.add_parameter (new CCodeParameter ("self", "const %s *".printf (get_ccode_name (st))));
6750 function.add_parameter (new CCodeParameter ("dest", "%s *".printf (get_ccode_name (st))));
6752 push_context (new EmitContext ());
6753 push_function (function);
6755 var dest_struct = new GLibValue (SemanticAnalyzer.get_data_type_for_symbol (st), new CCodeIdentifier ("(*dest)"), true);
6756 foreach (Field f in st.get_fields ()) {
6757 if (f.binding == MemberBinding.INSTANCE) {
6758 var value = load_field (f, load_this_parameter ((TypeSymbol) st));
6759 if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_copy (f.variable_type)) {
6760 value = copy_value (value, f);
6761 if (value == null) {
6762 // error case, continue to avoid critical
6766 store_field (f, dest_struct, value);
6773 cfile.add_function_declaration (function);
6774 cfile.add_function (function);
6777 public void return_default_value (DataType return_type, bool on_error = false) {
6778 unowned Struct? st = return_type.type_symbol as Struct;
6779 if (st != null && st.is_simple_type () && !return_type.nullable) {
6780 // 0-initialize struct with struct initializer { 0 }
6781 // only allowed as initializer expression in C
6782 var ret_temp_var = get_temp_variable (return_type, true, null, true);
6783 emit_temp_var (ret_temp_var, on_error);
6784 ccode.add_return (new CCodeIdentifier (ret_temp_var.name));
6786 ccode.add_return (default_value_for_type (return_type, false, on_error));
6790 public virtual void generate_dynamic_method_wrapper (DynamicMethod method) {
6793 public virtual CCodeExpression get_param_spec_cexpression (Property prop) {
6794 return new CCodeInvalidExpression ();
6797 public virtual CCodeExpression get_param_spec (Property prop) {
6798 return new CCodeInvalidExpression ();
6801 public virtual CCodeExpression get_signal_creation (Signal sig, ObjectTypeSymbol type) {
6802 return new CCodeInvalidExpression ();
6805 public virtual CCodeExpression get_value_getter_function (DataType type_reference) {
6806 return new CCodeInvalidExpression ();
6809 public virtual CCodeExpression get_value_setter_function (DataType type_reference) {
6810 return new CCodeInvalidExpression ();
6813 public virtual CCodeExpression get_value_taker_function (DataType type_reference) {
6814 return new CCodeInvalidExpression ();
6817 public virtual void register_dbus_info (CCodeBlock block, ObjectTypeSymbol bindable) {
6820 public virtual string get_dynamic_signal_cname (DynamicSignal node) {
6824 public virtual string get_array_length_cname (string array_cname, int dim) {
6828 public virtual string get_variable_array_length_cname (Variable variable, int dim) {
6832 public virtual CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
6833 return new CCodeInvalidExpression ();
6836 public virtual CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
6837 return new CCodeInvalidExpression ();
6840 public virtual string get_array_size_cname (string array_cname) {
6844 public virtual void add_simple_check (CodeNode node, bool always_fails = false) {
6847 public virtual string generate_ready_function (Method m) {
6851 public CCodeExpression get_boolean_cconstant (bool b) {
6852 if (context.profile == Profile.GOBJECT) {
6853 return new CCodeConstant (b ? "TRUE" : "FALSE");
6855 cfile.add_include ("stdbool.h");
6856 return new CCodeConstant (b ? "true" : "false");