gtk+-4.0: Update to 3.93.0+6aeae2c8
[vala-gnome.git] / codegen / valaccodebasemodule.vala
blob7c8edb482a3fc34621454dfb23e156b449560871
1 /* valaccodebasemodule.vala
3 * Copyright (C) 2006-2012 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 /**
27 * Code visitor generating C Code.
29 public abstract class Vala.CCodeBaseModule : CodeGenerator {
30 public class EmitContext {
31 public Symbol? current_symbol;
32 public ArrayList<Symbol> symbol_stack = new ArrayList<Symbol> ();
33 public TryStatement current_try;
34 public CatchClause current_catch;
35 public CCodeFunction ccode;
36 public ArrayList<CCodeFunction> ccode_stack = new ArrayList<CCodeFunction> ();
37 public ArrayList<TargetValue> temp_ref_values = new ArrayList<TargetValue> ();
38 public int next_temp_var_id;
39 public bool current_method_inner_error;
40 public bool current_method_return;
41 public int next_coroutine_state = 1;
42 public Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
43 public Map<string,int> closure_variable_count_map = new HashMap<string,int> (str_hash, str_equal);
44 public Map<LocalVariable,int> closure_variable_clash_map = new HashMap<LocalVariable,int> ();
46 public EmitContext (Symbol? symbol = null) {
47 current_symbol = symbol;
50 public void push_symbol (Symbol symbol) {
51 symbol_stack.add (current_symbol);
52 current_symbol = symbol;
55 public void pop_symbol () {
56 current_symbol = symbol_stack.remove_at (symbol_stack.size - 1);
60 public CodeContext context { get; set; }
62 public Symbol root_symbol;
64 public EmitContext emit_context = new EmitContext ();
66 List<EmitContext> emit_context_stack = new ArrayList<EmitContext> ();
68 public CCodeLineDirective? current_line = null;
70 List<CCodeLineDirective> line_directive_stack = new ArrayList<CCodeLineDirective> ();
72 public Symbol current_symbol { get { return emit_context.current_symbol; } }
74 public TryStatement current_try {
75 get { return emit_context.current_try; }
76 set { emit_context.current_try = value; }
79 public CatchClause current_catch {
80 get { return emit_context.current_catch; }
81 set { emit_context.current_catch = value; }
84 public TypeSymbol? current_type_symbol {
85 get {
86 var sym = current_symbol;
87 while (sym != null) {
88 if (sym is TypeSymbol) {
89 return (TypeSymbol) sym;
91 sym = sym.parent_symbol;
93 return null;
97 public Class? current_class {
98 get { return current_type_symbol as Class; }
101 public Method? current_method {
102 get {
103 var sym = current_symbol;
104 while (sym is Block) {
105 sym = sym.parent_symbol;
107 return sym as Method;
111 public PropertyAccessor? current_property_accessor {
112 get {
113 var sym = current_symbol;
114 while (sym is Block) {
115 sym = sym.parent_symbol;
117 return sym as PropertyAccessor;
121 public Constructor? current_constructor {
122 get {
123 var sym = current_symbol;
124 while (sym is Block) {
125 sym = sym.parent_symbol;
127 return sym as Constructor;
131 public Destructor? current_destructor {
132 get {
133 var sym = current_symbol;
134 while (sym is Block) {
135 sym = sym.parent_symbol;
137 return sym as Destructor;
141 public DataType? current_return_type {
142 get {
143 var m = current_method;
144 if (m != null) {
145 return m.return_type;
148 var acc = current_property_accessor;
149 if (acc != null) {
150 if (acc.readable) {
151 return acc.value_type;
152 } else {
153 return void_type;
157 if (is_in_constructor () || is_in_destructor ()) {
158 return void_type;
161 return null;
165 public bool is_in_coroutine () {
166 return current_method != null && current_method.coroutine;
169 public bool is_in_constructor () {
170 if (current_method != null) {
171 // make sure to not return true in lambda expression inside constructor
172 return false;
174 var sym = current_symbol;
175 while (sym != null) {
176 if (sym is Constructor) {
177 return true;
179 sym = sym.parent_symbol;
181 return false;
184 public bool is_in_destructor () {
185 if (current_method != null) {
186 // make sure to not return true in lambda expression inside constructor
187 return false;
189 var sym = current_symbol;
190 while (sym != null) {
191 if (sym is Destructor) {
192 return true;
194 sym = sym.parent_symbol;
196 return false;
199 public Block? current_closure_block {
200 get {
201 return next_closure_block (current_symbol);
205 public unowned Block? next_closure_block (Symbol sym) {
206 while (true) {
207 unowned Method method = sym as Method;
208 if (method != null && !method.closure) {
209 // parent blocks are not captured by this method
210 break;
213 unowned Block block = sym as Block;
214 if (method == null && block == null) {
215 // no closure block
216 break;
219 if (block != null && block.captured) {
220 // closure block found
221 return block;
223 sym = sym.parent_symbol;
225 return null;
228 public CCodeFile header_file;
229 public CCodeFile internal_header_file;
230 public CCodeFile cfile;
232 public EmitContext class_init_context;
233 public EmitContext base_init_context;
234 public EmitContext class_finalize_context;
235 public EmitContext base_finalize_context;
236 public EmitContext instance_init_context;
237 public EmitContext instance_finalize_context;
239 public CCodeStruct param_spec_struct;
240 public CCodeStruct closure_struct;
241 public CCodeEnum prop_enum;
242 public CCodeEnum signal_enum;
244 public CCodeFunction ccode { get { return emit_context.ccode; } }
246 /* temporary variables that own their content */
247 public ArrayList<TargetValue> temp_ref_values { get { return emit_context.temp_ref_values; } }
248 /* cache to check whether a certain marshaller has been created yet */
249 public Set<string> user_marshal_set;
250 /* (constant) hash table with all predefined marshallers */
251 public Set<string> predefined_marshal_set;
252 /* (constant) hash table with all reserved identifiers in the generated code */
253 Set<string> reserved_identifiers;
255 public int next_temp_var_id {
256 get { return emit_context.next_temp_var_id; }
257 set { emit_context.next_temp_var_id = value; }
260 public int next_regex_id = 0;
261 public bool in_creation_method { get { return current_method is CreationMethod; } }
263 public bool current_method_inner_error {
264 get { return emit_context.current_method_inner_error; }
265 set { emit_context.current_method_inner_error = value; }
268 public bool current_method_return {
269 get { return emit_context.current_method_return; }
270 set { emit_context.current_method_return = value; }
273 int next_block_id = 0;
274 Map<Block,int> block_map = new HashMap<Block,int> ();
276 public DataType void_type = new VoidType ();
277 public DataType bool_type;
278 public DataType char_type;
279 public DataType uchar_type;
280 public DataType? unichar_type;
281 public DataType short_type;
282 public DataType ushort_type;
283 public DataType int_type;
284 public DataType uint_type;
285 public DataType long_type;
286 public DataType ulong_type;
287 public DataType int8_type;
288 public DataType uint8_type;
289 public DataType int16_type;
290 public DataType uint16_type;
291 public DataType int32_type;
292 public DataType uint32_type;
293 public DataType int64_type;
294 public DataType uint64_type;
295 public DataType string_type;
296 public DataType regex_type;
297 public DataType float_type;
298 public DataType double_type;
299 public TypeSymbol gtype_type;
300 public TypeSymbol gobject_type;
301 public ErrorType gerror_type;
302 public Class glist_type;
303 public Class gslist_type;
304 public Class gnode_type;
305 public Class gqueue_type;
306 public Class gvaluearray_type;
307 public TypeSymbol gstringbuilder_type;
308 public TypeSymbol garray_type;
309 public TypeSymbol gbytearray_type;
310 public TypeSymbol gptrarray_type;
311 public TypeSymbol gthreadpool_type;
312 public DataType gdestroynotify_type;
313 public DataType gquark_type;
314 public Struct gvalue_type;
315 public Class gvariant_type;
316 public Struct mutex_type;
317 public Struct gmutex_type;
318 public Struct grecmutex_type;
319 public Struct grwlock_type;
320 public Struct gcond_type;
321 public Class gsource_type;
322 public TypeSymbol type_module_type;
323 public TypeSymbol dbus_proxy_type;
324 public Class gtk_widget_type;
326 public bool in_plugin = false;
327 public string module_init_param_name;
329 public bool gvaluecollector_h_needed;
330 public bool requires_assert;
331 public bool requires_array_free;
332 public bool requires_array_move;
333 public bool requires_array_length;
334 public bool requires_clear_mutex;
336 public Set<string> wrappers;
337 Set<Symbol> generated_external_symbols;
339 public Map<string,string> variable_name_map { get { return emit_context.variable_name_map; } }
341 public static int ccode_attribute_cache_index = CodeNode.get_attribute_cache_index ();
343 public CCodeBaseModule () {
344 predefined_marshal_set = new HashSet<string> (str_hash, str_equal);
345 predefined_marshal_set.add ("VOID:VOID");
346 predefined_marshal_set.add ("VOID:BOOLEAN");
347 predefined_marshal_set.add ("VOID:CHAR");
348 predefined_marshal_set.add ("VOID:UCHAR");
349 predefined_marshal_set.add ("VOID:INT");
350 predefined_marshal_set.add ("VOID:UINT");
351 predefined_marshal_set.add ("VOID:LONG");
352 predefined_marshal_set.add ("VOID:ULONG");
353 predefined_marshal_set.add ("VOID:ENUM");
354 predefined_marshal_set.add ("VOID:FLAGS");
355 predefined_marshal_set.add ("VOID:FLOAT");
356 predefined_marshal_set.add ("VOID:DOUBLE");
357 predefined_marshal_set.add ("VOID:STRING");
358 predefined_marshal_set.add ("VOID:POINTER");
359 predefined_marshal_set.add ("VOID:OBJECT");
360 predefined_marshal_set.add ("STRING:OBJECT,POINTER");
361 predefined_marshal_set.add ("VOID:UINT,POINTER");
362 predefined_marshal_set.add ("BOOLEAN:FLAGS");
363 predefined_marshal_set.add ("VOID:BOXED");
364 predefined_marshal_set.add ("VOID:VARIANT");
365 predefined_marshal_set.add ("BOOLEAN:BOXED,BOXED");
367 reserved_identifiers = new HashSet<string> (str_hash, str_equal);
369 // C99 keywords
370 reserved_identifiers.add ("_Bool");
371 reserved_identifiers.add ("_Complex");
372 reserved_identifiers.add ("_Imaginary");
373 reserved_identifiers.add ("asm");
374 reserved_identifiers.add ("auto");
375 reserved_identifiers.add ("break");
376 reserved_identifiers.add ("case");
377 reserved_identifiers.add ("char");
378 reserved_identifiers.add ("const");
379 reserved_identifiers.add ("continue");
380 reserved_identifiers.add ("default");
381 reserved_identifiers.add ("do");
382 reserved_identifiers.add ("double");
383 reserved_identifiers.add ("else");
384 reserved_identifiers.add ("enum");
385 reserved_identifiers.add ("extern");
386 reserved_identifiers.add ("float");
387 reserved_identifiers.add ("for");
388 reserved_identifiers.add ("goto");
389 reserved_identifiers.add ("if");
390 reserved_identifiers.add ("inline");
391 reserved_identifiers.add ("int");
392 reserved_identifiers.add ("long");
393 reserved_identifiers.add ("register");
394 reserved_identifiers.add ("restrict");
395 reserved_identifiers.add ("return");
396 reserved_identifiers.add ("short");
397 reserved_identifiers.add ("signed");
398 reserved_identifiers.add ("sizeof");
399 reserved_identifiers.add ("static");
400 reserved_identifiers.add ("struct");
401 reserved_identifiers.add ("switch");
402 reserved_identifiers.add ("typedef");
403 reserved_identifiers.add ("union");
404 reserved_identifiers.add ("unsigned");
405 reserved_identifiers.add ("void");
406 reserved_identifiers.add ("volatile");
407 reserved_identifiers.add ("while");
409 // C11 keywords
410 reserved_identifiers.add ("_Alignas");
411 reserved_identifiers.add ("_Alignof");
412 reserved_identifiers.add ("_Atomic");
413 reserved_identifiers.add ("_Generic");
414 reserved_identifiers.add ("_Noreturn");
415 reserved_identifiers.add ("_Static_assert");
416 reserved_identifiers.add ("_Thread_local");
418 // MSVC keywords
419 reserved_identifiers.add ("cdecl");
421 // reserved for Vala/GObject naming conventions
422 reserved_identifiers.add ("error");
423 reserved_identifiers.add ("result");
424 reserved_identifiers.add ("self");
427 public override void emit (CodeContext context) {
428 this.context = context;
430 root_symbol = context.root;
432 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
433 char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
434 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
435 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
436 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
437 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
438 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
439 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
440 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
441 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
442 uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8"));
443 int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16"));
444 uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16"));
445 int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32"));
446 uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32"));
447 int64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int64"));
448 uint64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint64"));
449 float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
450 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
451 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
452 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
453 if (unichar_struct != null) {
454 unichar_type = new IntegerType (unichar_struct);
457 var glib_ns = root_symbol.scope.lookup ("GLib");
459 gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
460 gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
461 gerror_type = new ErrorType (null, null);
462 glist_type = (Class) glib_ns.scope.lookup ("List");
463 gslist_type = (Class) glib_ns.scope.lookup ("SList");
464 gnode_type = (Class) glib_ns.scope.lookup ("Node");
465 gqueue_type = (Class) glib_ns.scope.lookup ("Queue");
466 gvaluearray_type = (Class) glib_ns.scope.lookup ("ValueArray");
467 gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
468 garray_type = (TypeSymbol) glib_ns.scope.lookup ("Array");
469 gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
470 gptrarray_type = (TypeSymbol) glib_ns.scope.lookup ("PtrArray");
471 gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
472 gdestroynotify_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("DestroyNotify"));
474 gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
475 gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
476 gvariant_type = (Class) glib_ns.scope.lookup ("Variant");
477 gsource_type = (Class) glib_ns.scope.lookup ("Source");
479 gmutex_type = (Struct) glib_ns.scope.lookup ("Mutex");
480 grecmutex_type = (Struct) glib_ns.scope.lookup ("RecMutex");
481 grwlock_type = (Struct) glib_ns.scope.lookup ("RWLock");
482 gcond_type = (Struct) glib_ns.scope.lookup ("Cond");
484 mutex_type = grecmutex_type;
486 type_module_type = (TypeSymbol) glib_ns.scope.lookup ("TypeModule");
488 regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
490 if (context.module_init_method != null) {
491 foreach (Parameter parameter in context.module_init_method.get_parameters ()) {
492 if (parameter.variable_type.data_type == type_module_type) {
493 in_plugin = true;
494 module_init_param_name = parameter.name;
495 break;
498 if (!in_plugin) {
499 Report.error (context.module_init_method.source_reference, "[ModuleInit] requires a parameter of type `GLib.TypeModule'");
503 dbus_proxy_type = (TypeSymbol) glib_ns.scope.lookup ("DBusProxy");
505 var gtk_ns = root_symbol.scope.lookup ("Gtk");
506 if (gtk_ns != null) {
507 gtk_widget_type = (Class) gtk_ns.scope.lookup ("Widget");
510 header_file = new CCodeFile ();
511 header_file.is_header = true;
512 internal_header_file = new CCodeFile ();
513 internal_header_file.is_header = true;
515 /* we're only interested in non-pkg source files */
516 var source_files = context.get_source_files ();
517 foreach (SourceFile file in source_files) {
518 if (file.file_type == SourceFileType.SOURCE ||
519 (context.header_filename != null && file.file_type == SourceFileType.FAST)) {
520 file.accept (this);
524 // generate symbols file for public API
525 if (context.symbols_filename != null) {
526 var stream = FileStream.open (context.symbols_filename, "w");
527 if (stream == null) {
528 Report.error (null, "unable to open `%s' for writing".printf (context.symbols_filename));
529 this.context = null;
530 return;
533 foreach (string symbol in header_file.get_symbols ()) {
534 stream.puts (symbol);
535 stream.putc ('\n');
538 stream = null;
541 // generate C header file for public API
542 if (context.header_filename != null) {
543 bool ret = header_file.store (context.header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
544 if (!ret) {
545 Report.error (null, "unable to open `%s' for writing".printf (context.header_filename));
549 // generate C header file for internal API
550 if (context.internal_header_filename != null) {
551 bool ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
552 if (!ret) {
553 Report.error (null, "unable to open `%s' for writing".printf (context.internal_header_filename));
557 this.context = null;
560 public void push_context (EmitContext emit_context) {
561 if (this.emit_context != null) {
562 emit_context_stack.add (this.emit_context);
565 this.emit_context = emit_context;
566 if (ccode != null) {
567 ccode.current_line = current_line;
571 public void pop_context () {
572 if (emit_context_stack.size > 0) {
573 this.emit_context = emit_context_stack.remove_at (emit_context_stack.size - 1);
574 if (ccode != null) {
575 ccode.current_line = current_line;
577 } else {
578 this.emit_context = null;
582 public void push_line (SourceReference? source_reference) {
583 line_directive_stack.add (current_line);
584 if (source_reference != null) {
585 current_line = new CCodeLineDirective (source_reference.file.filename, source_reference.begin.line);
586 if (ccode != null) {
587 ccode.current_line = current_line;
592 public void pop_line () {
593 current_line = line_directive_stack.remove_at (line_directive_stack.size - 1);
594 if (ccode != null) {
595 ccode.current_line = current_line;
599 public void push_function (CCodeFunction func) {
600 emit_context.ccode_stack.add (ccode);
601 emit_context.ccode = func;
602 ccode.current_line = current_line;
605 public void pop_function () {
606 emit_context.ccode = emit_context.ccode_stack.remove_at (emit_context.ccode_stack.size - 1);
607 if (ccode != null) {
608 ccode.current_line = current_line;
612 public bool add_symbol_declaration (CCodeFile decl_space, Symbol sym, string name) {
613 if (decl_space.add_declaration (name)) {
614 return true;
616 if (sym.source_reference != null) {
617 sym.source_reference.file.used = true;
619 if (sym.external_package || (!decl_space.is_header && CodeContext.get ().use_header && !sym.is_internal_symbol ())) {
620 // add appropriate include file
621 foreach (unowned string header_filename in get_ccode_header_filenames (sym).split (",")) {
622 decl_space.add_include (header_filename, !sym.external_package ||
623 (sym.external_package &&
624 sym.from_commandline));
626 // declaration complete
627 return true;
628 } else {
629 // require declaration
630 return false;
634 public CCodeIdentifier get_value_setter_function (DataType type_reference) {
635 var array_type = type_reference as ArrayType;
636 if (type_reference.data_type != null) {
637 return new CCodeIdentifier (get_ccode_set_value_function (type_reference.data_type));
638 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
639 // G_TYPE_STRV
640 return new CCodeIdentifier ("g_value_set_boxed");
641 } else {
642 return new CCodeIdentifier ("g_value_set_pointer");
646 public CCodeIdentifier get_value_taker_function (DataType type_reference) {
647 var array_type = type_reference as ArrayType;
648 if (type_reference.data_type != null) {
649 return new CCodeIdentifier (get_ccode_take_value_function (type_reference.data_type));
650 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
651 // G_TYPE_STRV
652 return new CCodeIdentifier ("g_value_take_boxed");
653 } else {
654 return new CCodeIdentifier ("g_value_set_pointer");
658 CCodeIdentifier get_value_getter_function (DataType type_reference) {
659 var array_type = type_reference as ArrayType;
660 if (type_reference.data_type != null) {
661 return new CCodeIdentifier (get_ccode_get_value_function (type_reference.data_type));
662 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
663 // G_TYPE_STRV
664 return new CCodeIdentifier ("g_value_get_boxed");
665 } else {
666 return new CCodeIdentifier ("g_value_get_pointer");
670 public virtual void append_vala_array_free () {
673 public virtual void append_vala_array_move () {
676 public virtual void append_vala_array_length () {
679 public void append_vala_clear_mutex (string typename, string funcprefix) {
680 // memset
681 cfile.add_include ("string.h");
683 var fun = new CCodeFunction ("_vala_clear_" + typename);
684 fun.modifiers = CCodeModifiers.STATIC;
685 fun.add_parameter (new CCodeParameter ("mutex", typename + " *"));
687 push_function (fun);
689 ccode.add_declaration (typename, new CCodeVariableDeclarator.zero ("zero_mutex", new CCodeConstant ("{ 0 }")));
691 var cmp = new CCodeFunctionCall (new CCodeIdentifier ("memcmp"));
692 cmp.add_argument (new CCodeIdentifier ("mutex"));
693 cmp.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("zero_mutex")));
694 cmp.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
695 ccode.open_if (cmp);
697 var mutex_clear = new CCodeFunctionCall (new CCodeIdentifier (funcprefix + "_clear"));
698 mutex_clear.add_argument (new CCodeIdentifier ("mutex"));
699 ccode.add_expression (mutex_clear);
701 var mset = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
702 mset.add_argument (new CCodeIdentifier ("mutex"));
703 mset.add_argument (new CCodeConstant ("0"));
704 mset.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
705 ccode.add_expression (mset);
707 ccode.close ();
709 pop_function ();
711 cfile.add_function_declaration (fun);
712 cfile.add_function (fun);
715 public override void visit_source_file (SourceFile source_file) {
716 cfile = new CCodeFile ();
718 user_marshal_set = new HashSet<string> (str_hash, str_equal);
720 next_regex_id = 0;
722 gvaluecollector_h_needed = false;
723 requires_assert = false;
724 requires_array_free = false;
725 requires_array_move = false;
726 requires_array_length = false;
727 requires_clear_mutex = false;
729 wrappers = new HashSet<string> (str_hash, str_equal);
730 generated_external_symbols = new HashSet<Symbol> ();
732 header_file.add_include ("glib.h");
733 internal_header_file.add_include ("glib.h");
734 cfile.add_include ("glib.h");
735 cfile.add_include ("glib-object.h");
737 source_file.accept_children (this);
739 if (context.report.get_errors () > 0) {
740 return;
743 /* For fast-vapi, we only wanted the header declarations
744 * to be emitted, so bail out here without writing the
745 * C code output.
747 if (source_file.file_type == SourceFileType.FAST) {
748 return;
751 if (requires_assert) {
752 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);")));
753 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; }")));
754 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; }")));
755 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);")));
757 if (requires_array_free) {
758 append_vala_array_free ();
760 if (requires_array_move) {
761 append_vala_array_move ();
763 if (requires_array_length) {
764 append_vala_array_length ();
766 if (requires_clear_mutex) {
767 append_vala_clear_mutex ("GMutex", "g_mutex");
768 append_vala_clear_mutex ("GRecMutex", "g_rec_mutex");
769 append_vala_clear_mutex ("GRWLock", "g_rw_lock");
770 append_vala_clear_mutex ("GCond", "g_cond");
773 if (gvaluecollector_h_needed) {
774 cfile.add_include ("gobject/gvaluecollector.h");
777 var comments = source_file.get_comments();
778 if (comments != null) {
779 foreach (Comment comment in comments) {
780 var ccomment = new CCodeComment (comment.content);
781 cfile.add_comment (ccomment);
785 if (!cfile.store (source_file.get_csource_filename (), source_file.filename, context.version_header, context.debug)) {
786 Report.error (null, "unable to open `%s' for writing".printf (source_file.get_csource_filename ()));
789 cfile = null;
792 public virtual bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
793 if (add_symbol_declaration (decl_space, en, get_ccode_name (en))) {
794 return false;
797 var cenum = new CCodeEnum (get_ccode_name (en));
799 cenum.modifiers |= (en.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
801 int flag_shift = 0;
802 foreach (EnumValue ev in en.get_values ()) {
803 CCodeEnumValue c_ev;
804 if (ev.value == null) {
805 c_ev = new CCodeEnumValue (get_ccode_name (ev));
806 if (en.is_flags) {
807 c_ev.value = new CCodeConstant ("1 << %d".printf (flag_shift));
808 flag_shift += 1;
810 } else {
811 ev.value.emit (this);
812 c_ev = new CCodeEnumValue (get_ccode_name (ev), get_cvalue (ev.value));
814 c_ev.modifiers |= (ev.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
815 cenum.add_value (c_ev);
818 decl_space.add_type_definition (cenum);
819 decl_space.add_type_definition (new CCodeNewline ());
821 if (!get_ccode_has_type_id (en)) {
822 return true;
825 decl_space.add_include ("glib-object.h");
826 decl_space.add_type_declaration (new CCodeNewline ());
828 var macro = "(%s_get_type ())".printf (get_ccode_lower_case_name (en, null));
829 decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (en), macro));
831 var fun_name = "%s_get_type".printf (get_ccode_lower_case_name (en, null));
832 var regfun = new CCodeFunction (fun_name, "GType");
833 regfun.modifiers = CCodeModifiers.CONST;
835 if (en.is_private_symbol ()) {
836 // avoid C warning as this function is not always used
837 regfun.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.UNUSED;
838 } else if (context.hide_internal && en.is_internal_symbol ()) {
839 regfun.modifiers |= CCodeModifiers.INTERNAL;
842 decl_space.add_function_declaration (regfun);
844 return true;
847 public override void visit_enum (Enum en) {
848 push_line (en.source_reference);
850 en.accept_children (this);
852 if (en.comment != null) {
853 cfile.add_type_member_definition (new CCodeComment (en.comment.content));
856 generate_enum_declaration (en, cfile);
858 if (!en.is_internal_symbol ()) {
859 generate_enum_declaration (en, header_file);
861 if (!en.is_private_symbol ()) {
862 generate_enum_declaration (en, internal_header_file);
865 pop_line ();
868 public void visit_member (Symbol m) {
869 /* stuff meant for all lockable members */
870 if (m is Lockable && ((Lockable) m).get_lock_used ()) {
871 CCodeExpression l = new CCodeIdentifier ("self");
872 var init_context = class_init_context;
873 var finalize_context = class_finalize_context;
875 if (m.is_instance_member ()) {
876 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (m.name));
877 init_context = instance_init_context;
878 finalize_context = instance_finalize_context;
879 } else if (m.is_class_member ()) {
880 TypeSymbol parent = (TypeSymbol)m.parent_symbol;
882 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(get_ccode_upper_case_name (parent))));
883 get_class_private_call.add_argument (new CCodeIdentifier ("klass"));
884 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (m.name));
885 } else {
886 l = new CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf(get_ccode_lower_case_name (m.parent_symbol), m.name)));
889 push_context (init_context);
890 var initf = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.default_construction_method)));
891 initf.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
892 ccode.add_expression (initf);
893 pop_context ();
895 if (finalize_context != null) {
896 push_context (finalize_context);
897 var fc = new CCodeFunctionCall (new CCodeIdentifier ("g_rec_mutex_clear"));
898 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
899 ccode.add_expression (fc);
900 pop_context ();
905 public void generate_constant_declaration (Constant c, CCodeFile decl_space, bool definition = false) {
906 if (c.parent_symbol is Block) {
907 // local constant
908 return;
911 if (add_symbol_declaration (decl_space, c, get_ccode_name (c))) {
912 return;
915 if (!c.external) {
916 generate_type_declaration (c.type_reference, decl_space);
918 c.value.emit (this);
920 var initializer_list = c.value as InitializerList;
921 if (initializer_list != null) {
922 var cdecl = new CCodeDeclaration (get_ccode_const_name (c.type_reference));
923 var arr = "";
924 if (c.type_reference is ArrayType) {
925 arr = "[%d]".printf (initializer_list.size);
928 var cinitializer = get_cvalue (c.value);
929 if (!definition) {
930 // never output value in header
931 // special case needed as this method combines declaration and definition
932 cinitializer = null;
935 cdecl.add_declarator (new CCodeVariableDeclarator ("%s%s".printf (get_ccode_name (c), arr), cinitializer));
936 if (c.is_private_symbol ()) {
937 cdecl.modifiers = CCodeModifiers.STATIC;
938 } else {
939 cdecl.modifiers = CCodeModifiers.EXTERN;
942 decl_space.add_constant_declaration (cdecl);
943 } else {
944 var cdefine = new CCodeMacroReplacement.with_expression (get_ccode_name (c), get_cvalue (c.value));
945 decl_space.add_type_member_declaration (cdefine);
950 public override void visit_constant (Constant c) {
951 push_line (c.source_reference);
953 if (c.parent_symbol is Block) {
954 // local constant
956 generate_type_declaration (c.type_reference, cfile);
958 c.value.emit (this);
960 string type_name = get_ccode_const_name (c.type_reference);
961 string arr = "";
962 if (c.type_reference is ArrayType) {
963 arr = "[]";
966 if (c.type_reference.compatible (string_type)) {
967 type_name = "const char";
968 arr = "[]";
971 var cinitializer = get_cvalue (c.value);
973 ccode.add_declaration (type_name, new CCodeVariableDeclarator ("%s%s".printf (get_ccode_name (c), arr), cinitializer), CCodeModifiers.STATIC);
974 } else {
975 generate_constant_declaration (c, cfile, true);
977 if (!c.is_internal_symbol ()) {
978 generate_constant_declaration (c, header_file);
980 if (!c.is_private_symbol ()) {
981 generate_constant_declaration (c, internal_header_file);
985 pop_line ();
988 public void generate_field_declaration (Field f, CCodeFile decl_space) {
989 if (add_symbol_declaration (decl_space, f, get_ccode_name (f))) {
990 return;
993 generate_type_declaration (f.variable_type, decl_space);
995 var cdecl = new CCodeDeclaration (get_ccode_name (f.variable_type));
996 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type)));
997 if (f.is_private_symbol ()) {
998 cdecl.modifiers = CCodeModifiers.STATIC;
999 } else {
1000 cdecl.modifiers = CCodeModifiers.EXTERN;
1002 if (f.version.deprecated) {
1003 cdecl.modifiers |= CCodeModifiers.DEPRECATED;
1005 if (f.is_volatile) {
1006 cdecl.modifiers |= CCodeModifiers.VOLATILE;
1008 decl_space.add_type_member_declaration (cdecl);
1010 if (f.get_lock_used ()) {
1011 // Declare mutex for static member
1012 var flock = new CCodeDeclaration (get_ccode_name (mutex_type));
1013 var flock_decl = new CCodeVariableDeclarator (get_symbol_lock_name (get_ccode_name (f)), new CCodeConstant ("{0}"));
1014 flock.add_declarator (flock_decl);
1016 if (f.is_private_symbol ()) {
1017 flock.modifiers = CCodeModifiers.STATIC;
1018 } else if (context.hide_internal && f.is_internal_symbol ()) {
1019 flock.modifiers = CCodeModifiers.INTERNAL;
1020 } else {
1021 flock.modifiers = CCodeModifiers.EXTERN;
1023 decl_space.add_type_member_declaration (flock);
1026 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1027 var array_type = (ArrayType) f.variable_type;
1029 if (!array_type.fixed_length) {
1030 for (int dim = 1; dim <= array_type.rank; dim++) {
1031 var len_type = int_type.copy ();
1033 cdecl = new CCodeDeclaration (get_ccode_name (len_type));
1034 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_length_cname (get_ccode_name (f), dim)));
1035 if (f.is_private_symbol ()) {
1036 cdecl.modifiers = CCodeModifiers.STATIC;
1037 } else if (context.hide_internal && f.is_internal_symbol ()) {
1038 cdecl.modifiers = CCodeModifiers.INTERNAL;
1039 } else {
1040 cdecl.modifiers = CCodeModifiers.EXTERN;
1042 decl_space.add_type_member_declaration (cdecl);
1045 } else if (f.variable_type is DelegateType) {
1046 var delegate_type = (DelegateType) f.variable_type;
1047 if (delegate_type.delegate_symbol.has_target) {
1048 // create field to store delegate target
1050 cdecl = new CCodeDeclaration ("gpointer");
1051 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f)));
1052 if (f.is_private_symbol ()) {
1053 cdecl.modifiers = CCodeModifiers.STATIC;
1054 } else if (context.hide_internal && f.is_internal_symbol ()) {
1055 cdecl.modifiers = CCodeModifiers.INTERNAL;
1056 } else {
1057 cdecl.modifiers = CCodeModifiers.EXTERN;
1059 decl_space.add_type_member_declaration (cdecl);
1061 if (delegate_type.value_owned && !delegate_type.is_called_once) {
1062 cdecl = new CCodeDeclaration ("GDestroyNotify");
1063 cdecl.add_declarator (new CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (get_ccode_name (f))));
1064 if (f.is_private_symbol ()) {
1065 cdecl.modifiers = CCodeModifiers.STATIC;
1066 } else if (context.hide_internal && f.is_internal_symbol ()) {
1067 cdecl.modifiers = CCodeModifiers.INTERNAL;
1068 } else {
1069 cdecl.modifiers = CCodeModifiers.EXTERN;
1071 decl_space.add_type_member_declaration (cdecl);
1077 public override void visit_field (Field f) {
1078 push_line (f.source_reference);
1079 visit_member (f);
1081 check_type (f.variable_type);
1083 var cl = f.parent_symbol as Class;
1084 bool is_gtypeinstance = (cl != null && !cl.is_compact);
1086 CCodeExpression lhs = null;
1088 if (f.binding == MemberBinding.INSTANCE) {
1089 if (is_gtypeinstance && f.access == SymbolAccessibility.PRIVATE) {
1090 lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), get_ccode_name (f));
1091 } else {
1092 lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_ccode_name (f));
1095 if (f.initializer != null) {
1096 push_context (instance_init_context);
1098 f.initializer.emit (this);
1100 var rhs = get_cvalue (f.initializer);
1101 if (!is_simple_struct_creation (f, f.initializer)) {
1102 // otherwise handled in visit_object_creation_expression
1104 ccode.add_assignment (lhs, rhs);
1106 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1107 var array_type = (ArrayType) f.variable_type;
1108 var field_value = get_field_cvalue (f, load_this_parameter ((TypeSymbol) f.parent_symbol));
1110 var glib_value = (GLibValue) f.initializer.target_value;
1111 if (glib_value.array_length_cvalues != null) {
1112 for (int dim = 1; dim <= array_type.rank; dim++) {
1113 var array_len_lhs = get_array_length_cvalue (field_value, dim);
1114 ccode.add_assignment (array_len_lhs, get_array_length_cvalue (glib_value, dim));
1116 } else if (glib_value.array_null_terminated) {
1117 requires_array_length = true;
1118 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1119 len_call.add_argument (get_cvalue_ (glib_value));
1121 ccode.add_assignment (get_array_length_cvalue (field_value, 1), len_call);
1122 } else {
1123 for (int dim = 1; dim <= array_type.rank; dim++) {
1124 ccode.add_assignment (get_array_length_cvalue (field_value, dim), new CCodeConstant ("-1"));
1128 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1129 var lhs_array_size = get_array_size_cvalue (field_value);
1130 var rhs_array_len = get_array_length_cvalue (field_value, 1);
1131 ccode.add_assignment (lhs_array_size, rhs_array_len);
1133 } else if (f.variable_type is DelegateType) {
1134 var delegate_type = (DelegateType) f.variable_type;
1135 if (delegate_type.delegate_symbol.has_target) {
1136 var field_value = get_field_cvalue (f, load_this_parameter ((TypeSymbol) f.parent_symbol));
1138 ccode.add_assignment (get_delegate_target_cvalue (field_value), new CCodeIdentifier ("self"));
1139 if (delegate_type.is_disposable ()) {
1140 ccode.add_assignment (get_delegate_target_destroy_notify_cvalue (field_value), new CCodeIdentifier ("NULL"));
1146 foreach (var value in temp_ref_values) {
1147 ccode.add_expression (destroy_value (value));
1150 temp_ref_values.clear ();
1152 pop_context ();
1155 if (requires_destroy (f.variable_type) && instance_finalize_context != null) {
1156 push_context (instance_finalize_context);
1157 ccode.add_expression (destroy_field (f, load_this_parameter ((TypeSymbol) f.parent_symbol)));
1158 pop_context ();
1160 } else if (f.binding == MemberBinding.CLASS) {
1161 if (!is_gtypeinstance) {
1162 Report.error (f.source_reference, "class fields are not supported in compact classes");
1163 f.error = true;
1164 return;
1167 if (f.access == SymbolAccessibility.PRIVATE) {
1168 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (get_ccode_upper_case_name (cl))));
1169 ccall.add_argument (new CCodeIdentifier ("klass"));
1170 lhs = new CCodeMemberAccess (ccall, get_ccode_name (f), true);
1171 } else {
1172 lhs = new CCodeMemberAccess (new CCodeIdentifier ("klass"), get_ccode_name (f), true);
1175 if (f.initializer != null) {
1176 push_context (class_init_context);
1178 f.initializer.emit (this);
1180 var rhs = get_cvalue (f.initializer);
1182 ccode.add_assignment (lhs, rhs);
1184 foreach (var value in temp_ref_values) {
1185 ccode.add_expression (destroy_value (value));
1188 temp_ref_values.clear ();
1190 pop_context ();
1192 } else {
1193 generate_field_declaration (f, cfile);
1195 if (!f.is_internal_symbol ()) {
1196 generate_field_declaration (f, header_file);
1198 if (!f.is_private_symbol ()) {
1199 generate_field_declaration (f, internal_header_file);
1202 if (!f.external) {
1203 lhs = new CCodeIdentifier (get_ccode_name (f));
1205 var var_decl = new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type));
1206 var_decl.initializer = default_value_for_type (f.variable_type, true);
1208 if (class_init_context != null) {
1209 push_context (class_init_context);
1210 } else {
1211 push_context (new EmitContext ());
1214 if (f.initializer != null) {
1215 f.initializer.emit (this);
1217 var init = get_cvalue (f.initializer);
1218 if (is_constant_ccode_expression (init)) {
1219 var_decl.initializer = init;
1223 var var_def = new CCodeDeclaration (get_ccode_name (f.variable_type));
1224 var_def.add_declarator (var_decl);
1225 if (!f.is_private_symbol ()) {
1226 var_def.modifiers = CCodeModifiers.EXTERN;
1227 } else {
1228 var_def.modifiers = CCodeModifiers.STATIC;
1230 if (f.version.deprecated) {
1231 var_def.modifiers |= CCodeModifiers.DEPRECATED;
1233 if (f.is_volatile) {
1234 var_def.modifiers |= CCodeModifiers.VOLATILE;
1236 cfile.add_type_member_declaration (var_def);
1238 /* add array length fields where necessary */
1239 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1240 var array_type = (ArrayType) f.variable_type;
1242 if (!array_type.fixed_length) {
1243 for (int dim = 1; dim <= array_type.rank; dim++) {
1244 var len_type = int_type.copy ();
1246 var len_def = new CCodeDeclaration (get_ccode_name (len_type));
1247 len_def.add_declarator (new CCodeVariableDeclarator (get_array_length_cname (get_ccode_name (f), dim), new CCodeConstant ("0")));
1248 if (!f.is_private_symbol ()) {
1249 len_def.modifiers = CCodeModifiers.EXTERN;
1250 } else {
1251 len_def.modifiers = CCodeModifiers.STATIC;
1253 cfile.add_type_member_declaration (len_def);
1256 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1257 var len_type = int_type.copy ();
1259 var cdecl = new CCodeDeclaration (get_ccode_name (len_type));
1260 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_size_cname (get_ccode_name (f)), new CCodeConstant ("0")));
1261 cdecl.modifiers = CCodeModifiers.STATIC;
1262 cfile.add_type_member_declaration (cdecl);
1265 } else if (f.variable_type is DelegateType) {
1266 var delegate_type = (DelegateType) f.variable_type;
1267 if (delegate_type.delegate_symbol.has_target) {
1268 // create field to store delegate target
1270 var target_def = new CCodeDeclaration ("gpointer");
1271 target_def.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f), new CCodeConstant ("NULL")));
1272 if (!f.is_private_symbol ()) {
1273 target_def.modifiers = CCodeModifiers.EXTERN;
1274 } else {
1275 target_def.modifiers = CCodeModifiers.STATIC;
1277 cfile.add_type_member_declaration (target_def);
1279 if (delegate_type.is_disposable ()) {
1280 var target_destroy_notify_def = new CCodeDeclaration ("GDestroyNotify");
1281 target_destroy_notify_def.add_declarator (new CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (get_ccode_name (f)), new CCodeConstant ("NULL")));
1282 if (!f.is_private_symbol ()) {
1283 target_destroy_notify_def.modifiers = CCodeModifiers.EXTERN;
1284 } else {
1285 target_destroy_notify_def.modifiers = CCodeModifiers.STATIC;
1287 cfile.add_type_member_declaration (target_destroy_notify_def);
1293 if (f.initializer != null) {
1294 var rhs = get_cvalue (f.initializer);
1295 if (!is_constant_ccode_expression (rhs)) {
1296 if (is_gtypeinstance) {
1297 if (f.initializer is InitializerList) {
1298 ccode.open_block ();
1300 var temp_decl = get_temp_variable (f.variable_type);
1301 var vardecl = new CCodeVariableDeclarator.zero (temp_decl.name, rhs);
1302 ccode.add_declaration (get_ccode_name (temp_decl.variable_type), vardecl);
1304 var tmp = get_variable_cexpression (get_variable_cname (temp_decl.name));
1305 ccode.add_assignment (lhs, tmp);
1307 ccode.close ();
1308 } else {
1309 ccode.add_assignment (lhs, rhs);
1312 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1313 var array_type = (ArrayType) f.variable_type;
1314 var field_value = get_field_cvalue (f, null);
1316 var glib_value = (GLibValue) f.initializer.target_value;
1317 if (glib_value.array_length_cvalues != null) {
1318 for (int dim = 1; dim <= array_type.rank; dim++) {
1319 var array_len_lhs = get_array_length_cvalue (field_value, dim);
1320 ccode.add_assignment (array_len_lhs, get_array_length_cvalue (glib_value, dim));
1322 } else if (glib_value.array_null_terminated) {
1323 requires_array_length = true;
1324 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1325 len_call.add_argument (get_cvalue_ (glib_value));
1327 ccode.add_assignment (get_array_length_cvalue (field_value, 1), len_call);
1328 } else {
1329 for (int dim = 1; dim <= array_type.rank; dim++) {
1330 ccode.add_assignment (get_array_length_cvalue (field_value, dim), new CCodeConstant ("-1"));
1334 } else {
1335 f.error = true;
1336 Report.error (f.source_reference, "Non-constant field initializers not supported in this context");
1337 return;
1342 pop_context ();
1346 pop_line ();
1349 public bool is_constant_ccode_expression (CCodeExpression cexpr) {
1350 if (cexpr is CCodeConstant) {
1351 return true;
1352 } else if (cexpr is CCodeCastExpression) {
1353 var ccast = (CCodeCastExpression) cexpr;
1354 return is_constant_ccode_expression (ccast.inner);
1355 } else if (cexpr is CCodeUnaryExpression) {
1356 var cunary = (CCodeUnaryExpression) cexpr;
1357 switch (cunary.operator) {
1358 case CCodeUnaryOperator.PREFIX_INCREMENT:
1359 case CCodeUnaryOperator.PREFIX_DECREMENT:
1360 case CCodeUnaryOperator.POSTFIX_INCREMENT:
1361 case CCodeUnaryOperator.POSTFIX_DECREMENT:
1362 return false;
1364 return is_constant_ccode_expression (cunary.inner);
1365 } else if (cexpr is CCodeBinaryExpression) {
1366 var cbinary = (CCodeBinaryExpression) cexpr;
1367 return is_constant_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1370 var cparenthesized = (cexpr as CCodeParenthesizedExpression);
1371 return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
1375 * Returns whether the passed cexpr is a pure expression, i.e. an
1376 * expression without side-effects.
1378 public bool is_pure_ccode_expression (CCodeExpression cexpr) {
1379 if (cexpr is CCodeConstant || cexpr is CCodeIdentifier) {
1380 return true;
1381 } else if (cexpr is CCodeBinaryExpression) {
1382 var cbinary = (CCodeBinaryExpression) cexpr;
1383 return is_pure_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1384 } else if (cexpr is CCodeUnaryExpression) {
1385 var cunary = (CCodeUnaryExpression) cexpr;
1386 switch (cunary.operator) {
1387 case CCodeUnaryOperator.PREFIX_INCREMENT:
1388 case CCodeUnaryOperator.PREFIX_DECREMENT:
1389 case CCodeUnaryOperator.POSTFIX_INCREMENT:
1390 case CCodeUnaryOperator.POSTFIX_DECREMENT:
1391 return false;
1392 default:
1393 return is_pure_ccode_expression (cunary.inner);
1395 } else if (cexpr is CCodeMemberAccess) {
1396 var cma = (CCodeMemberAccess) cexpr;
1397 return is_pure_ccode_expression (cma.inner);
1398 } else if (cexpr is CCodeElementAccess) {
1399 var cea = (CCodeElementAccess) cexpr;
1400 return is_pure_ccode_expression (cea.container) && is_pure_ccode_expression (cea.index);
1401 } else if (cexpr is CCodeCastExpression) {
1402 var ccast = (CCodeCastExpression) cexpr;
1403 return is_pure_ccode_expression (ccast.inner);
1404 } else if (cexpr is CCodeParenthesizedExpression) {
1405 var cparenthesized = (CCodeParenthesizedExpression) cexpr;
1406 return is_pure_ccode_expression (cparenthesized.inner);
1409 return false;
1412 public override void visit_formal_parameter (Parameter p) {
1413 if (!p.ellipsis) {
1414 check_type (p.variable_type);
1418 public override void visit_property (Property prop) {
1419 visit_member (prop);
1421 check_type (prop.property_type);
1423 if (prop.get_accessor != null) {
1424 prop.get_accessor.accept (this);
1426 if (prop.set_accessor != null) {
1427 prop.set_accessor.accept (this);
1431 public void generate_type_declaration (DataType type, CCodeFile decl_space) {
1432 if (type is ObjectType) {
1433 var object_type = (ObjectType) type;
1434 if (object_type.type_symbol is Class) {
1435 generate_class_declaration ((Class) object_type.type_symbol, decl_space);
1436 } else if (object_type.type_symbol is Interface) {
1437 generate_interface_declaration ((Interface) object_type.type_symbol, decl_space);
1439 } else if (type is DelegateType) {
1440 var deleg_type = (DelegateType) type;
1441 var d = deleg_type.delegate_symbol;
1442 generate_delegate_declaration (d, decl_space);
1443 } else if (type.data_type is Enum) {
1444 var en = (Enum) type.data_type;
1445 generate_enum_declaration (en, decl_space);
1446 } else if (type is ValueType) {
1447 var value_type = (ValueType) type;
1448 generate_struct_declaration ((Struct) value_type.type_symbol, decl_space);
1449 } else if (type is ArrayType) {
1450 var array_type = (ArrayType) type;
1451 generate_type_declaration (array_type.element_type, decl_space);
1452 } else if (type is ErrorType) {
1453 var error_type = (ErrorType) type;
1454 if (error_type.error_domain != null) {
1455 generate_error_domain_declaration (error_type.error_domain, decl_space);
1457 } else if (type is PointerType) {
1458 var pointer_type = (PointerType) type;
1459 generate_type_declaration (pointer_type.base_type, decl_space);
1462 foreach (DataType type_arg in type.get_type_arguments ()) {
1463 generate_type_declaration (type_arg, decl_space);
1467 public virtual void generate_class_struct_declaration (Class cl, CCodeFile decl_space) {
1470 public virtual void generate_struct_declaration (Struct st, CCodeFile decl_space) {
1473 public virtual void generate_delegate_declaration (Delegate d, CCodeFile decl_space) {
1476 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) {
1479 public void generate_property_accessor_declaration (PropertyAccessor acc, CCodeFile decl_space) {
1480 if (add_symbol_declaration (decl_space, acc, get_ccode_name (acc))) {
1481 return;
1484 var prop = (Property) acc.prop;
1486 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1489 CCodeParameter cvalueparam;
1490 if (returns_real_struct) {
1491 cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (acc.value_type)));
1492 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1493 cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (acc.value_type)));
1494 } else {
1495 cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1497 generate_type_declaration (acc.value_type, decl_space);
1499 CCodeFunction function;
1500 if (acc.readable && !returns_real_struct) {
1501 function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (acc.value_type));
1502 } else {
1503 function = new CCodeFunction (get_ccode_name (acc), "void");
1506 if (prop.binding == MemberBinding.INSTANCE) {
1507 var t = (TypeSymbol) prop.parent_symbol;
1508 var this_type = get_data_type_for_symbol (t);
1509 generate_type_declaration (this_type, decl_space);
1510 var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1511 if (t is Struct && !((Struct) t).is_simple_type ()) {
1512 cselfparam.type_name += "*";
1515 function.add_parameter (cselfparam);
1518 if (acc.writable || acc.construction || returns_real_struct) {
1519 function.add_parameter (cvalueparam);
1522 if (acc.value_type is ArrayType) {
1523 var array_type = (ArrayType) acc.value_type;
1524 for (int dim = 1; dim <= array_type.rank; dim++) {
1525 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? "int*" : "int"));
1527 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1528 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1529 if (!acc.readable && acc.value_type.value_owned) {
1530 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1534 if (prop.version.deprecated) {
1535 function.modifiers |= CCodeModifiers.DEPRECATED;
1538 if (!prop.is_abstract
1539 && (prop.is_private_symbol () || (!acc.readable && !acc.writable) || acc.access == SymbolAccessibility.PRIVATE)) {
1540 function.modifiers |= CCodeModifiers.STATIC;
1541 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1542 function.modifiers |= CCodeModifiers.INTERNAL;
1544 decl_space.add_function_declaration (function);
1547 public override void visit_property_accessor (PropertyAccessor acc) {
1548 push_context (new EmitContext (acc));
1549 push_line (acc.source_reference);
1551 var prop = (Property) acc.prop;
1553 if (acc.comment != null) {
1554 cfile.add_type_member_definition (new CCodeComment (acc.comment.content));
1557 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1559 if (acc.result_var != null) {
1560 acc.result_var.accept (this);
1563 var t = (TypeSymbol) prop.parent_symbol;
1565 if (acc.construction && !t.is_subtype_of (gobject_type)) {
1566 Report.error (acc.source_reference, "construct properties require GLib.Object");
1567 acc.error = true;
1568 return;
1569 } else if (acc.construction && !is_gobject_property (prop)) {
1570 Report.error (acc.source_reference, "construct properties not supported for specified property type");
1571 acc.error = true;
1572 return;
1575 // do not declare overriding properties and interface implementations
1576 if (prop.is_abstract || prop.is_virtual
1577 || (prop.base_property == null && prop.base_interface_property == null)) {
1578 generate_property_accessor_declaration (acc, cfile);
1580 // do not declare construct-only properties in header files
1581 if (acc.readable || acc.writable) {
1582 if (!prop.is_internal_symbol ()
1583 && (acc.access == SymbolAccessibility.PUBLIC
1584 || acc.access == SymbolAccessibility.PROTECTED)) {
1585 generate_property_accessor_declaration (acc, header_file);
1587 if (!prop.is_private_symbol () && acc.access != SymbolAccessibility.PRIVATE) {
1588 generate_property_accessor_declaration (acc, internal_header_file);
1593 if (acc.source_type == SourceFileType.FAST) {
1594 pop_line ();
1595 return;
1598 var this_type = get_data_type_for_symbol (t);
1599 var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1600 if (t is Struct && !((Struct) t).is_simple_type ()) {
1601 cselfparam.type_name += "*";
1603 CCodeParameter cvalueparam;
1604 if (returns_real_struct) {
1605 cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (acc.value_type)));
1606 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1607 cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (acc.value_type)));
1608 } else {
1609 cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1612 if (prop.is_abstract || prop.is_virtual) {
1613 CCodeFunction function;
1614 if (acc.readable && !returns_real_struct) {
1615 function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (current_return_type));
1616 } else {
1617 function = new CCodeFunction (get_ccode_name (acc), "void");
1619 function.add_parameter (cselfparam);
1620 if (acc.writable || acc.construction || returns_real_struct) {
1621 function.add_parameter (cvalueparam);
1624 if (acc.value_type is ArrayType) {
1625 var array_type = (ArrayType) acc.value_type;
1626 for (int dim = 1; dim <= array_type.rank; dim++) {
1627 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? "int*" : "int"));
1629 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1630 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1631 if (!acc.readable && acc.value_type.value_owned) {
1632 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1636 if (!prop.is_abstract
1637 && (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE)) {
1638 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1639 function.modifiers |= CCodeModifiers.STATIC;
1640 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1641 function.modifiers |= CCodeModifiers.INTERNAL;
1644 push_function (function);
1646 if (prop.binding == MemberBinding.INSTANCE) {
1647 if (!acc.readable || returns_real_struct) {
1648 create_property_type_check_statement (prop, false, t, true, "self");
1649 } else {
1650 create_property_type_check_statement (prop, true, t, true, "self");
1654 CCodeFunctionCall vcast = null;
1655 if (prop.parent_symbol is Interface) {
1656 var iface = (Interface) prop.parent_symbol;
1658 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface, null))));
1659 } else {
1660 var cl = (Class) prop.parent_symbol;
1662 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (cl, null))));
1664 vcast.add_argument (new CCodeIdentifier ("self"));
1666 if (acc.readable) {
1667 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
1668 vcall.add_argument (new CCodeIdentifier ("self"));
1669 if (returns_real_struct) {
1670 vcall.add_argument (new CCodeIdentifier ("result"));
1671 ccode.add_expression (vcall);
1672 } else {
1673 if (acc.value_type is ArrayType) {
1674 var array_type = (ArrayType) acc.value_type;
1676 for (int dim = 1; dim <= array_type.rank; dim++) {
1677 var len_expr = new CCodeIdentifier (get_array_length_cname ("result", dim));
1678 vcall.add_argument (len_expr);
1680 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1681 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("result")));
1684 ccode.add_return (vcall);
1686 } else {
1687 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
1688 vcall.add_argument (new CCodeIdentifier ("self"));
1689 vcall.add_argument (new CCodeIdentifier ("value"));
1691 if (acc.value_type is ArrayType) {
1692 var array_type = (ArrayType) acc.value_type;
1694 for (int dim = 1; dim <= array_type.rank; dim++) {
1695 var len_expr = new CCodeIdentifier (get_array_length_cname ("value", dim));
1696 vcall.add_argument (len_expr);
1698 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1699 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("value")));
1700 if (!acc.readable && acc.value_type.value_owned) {
1701 vcall.add_argument (new CCodeIdentifier (get_delegate_target_destroy_notify_cname ("value")));
1705 ccode.add_expression (vcall);
1708 pop_function ();
1710 cfile.add_function (function);
1713 if (!prop.is_abstract && acc.body != null) {
1714 bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
1716 string cname = get_ccode_real_name (acc);
1718 CCodeFunction function;
1719 if (acc.writable || acc.construction || returns_real_struct) {
1720 function = new CCodeFunction (cname, "void");
1721 } else {
1722 function = new CCodeFunction (cname, get_ccode_name (acc.value_type));
1725 ObjectType base_type = null;
1726 if (prop.binding == MemberBinding.INSTANCE) {
1727 if (is_virtual) {
1728 if (prop.base_property != null) {
1729 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
1730 } else if (prop.base_interface_property != null) {
1731 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
1733 function.modifiers |= CCodeModifiers.STATIC;
1734 function.add_parameter (new CCodeParameter ("base", get_ccode_name (base_type)));
1735 } else {
1736 function.add_parameter (cselfparam);
1739 if (acc.writable || acc.construction || returns_real_struct) {
1740 function.add_parameter (cvalueparam);
1743 if (acc.value_type is ArrayType) {
1744 var array_type = (ArrayType) acc.value_type;
1745 for (int dim = 1; dim <= array_type.rank; dim++) {
1746 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? "int*" : "int"));
1748 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1749 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1750 if (!acc.readable && acc.value_type.value_owned) {
1751 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1755 if (!is_virtual) {
1756 if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1757 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1758 function.modifiers |= CCodeModifiers.STATIC;
1759 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1760 function.modifiers |= CCodeModifiers.INTERNAL;
1764 push_function (function);
1766 if (prop.binding == MemberBinding.INSTANCE && !is_virtual) {
1767 if (!acc.readable || returns_real_struct) {
1768 create_property_type_check_statement (prop, false, t, true, "self");
1769 } else {
1770 create_property_type_check_statement (prop, true, t, true, "self");
1774 if (acc.readable && !returns_real_struct) {
1775 // do not declare result variable if exit block is known to be unreachable
1776 if (acc.return_block == null || acc.return_block.get_predecessors ().size > 0) {
1777 ccode.add_declaration (get_ccode_name (acc.value_type), new CCodeVariableDeclarator ("result"));
1781 if (is_virtual) {
1782 ccode.add_declaration (get_ccode_name (this_type), new CCodeVariableDeclarator ("self"));
1783 ccode.add_assignment (new CCodeIdentifier ("self"), get_cvalue_ (transform_value (new GLibValue (base_type, new CCodeIdentifier ("base"), true), this_type, acc)));
1786 // notify on property changes
1787 if (is_gobject_property (prop) &&
1788 prop.notify &&
1789 (acc.writable || acc.construction)) {
1790 var notify_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_notify_by_pspec"));
1791 notify_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
1792 notify_call.add_argument (get_param_spec_cexpression (prop));
1794 var get_accessor = prop.get_accessor;
1795 if (get_accessor != null && get_accessor.automatic_body) {
1796 var property_type = prop.property_type;
1797 var get_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (get_accessor)));
1798 get_call.add_argument (new CCodeIdentifier (is_virtual ? "base" : "self"));
1800 if (property_type is ArrayType) {
1801 ccode.add_declaration ("int", new CCodeVariableDeclarator ("old_value_length"));
1802 get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value_length")));
1803 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_call, new CCodeIdentifier ("value")));
1804 } else if (property_type.compatible (string_type)) {
1805 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
1806 ccall.add_argument (new CCodeIdentifier ("value"));
1807 ccall.add_argument (get_call);
1808 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("0")));
1809 } else if (property_type is StructValueType) {
1810 ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
1811 get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value")));
1813 var get_expr = new CCodeCommaExpression ();
1814 get_expr.append_expression (get_call);
1815 get_expr.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value")));
1817 var equalfunc = generate_struct_equal_function ((Struct) property_type.data_type);
1818 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
1819 ccall.add_argument (new CCodeIdentifier ("value"));
1820 ccall.add_argument (get_expr);
1821 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("TRUE")));
1822 } else {
1823 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_call, new CCodeIdentifier ("value")));
1826 acc.body.emit (this);
1827 ccode.add_expression (notify_call);
1828 ccode.close ();
1829 } else {
1830 acc.body.emit (this);
1831 ccode.add_expression (notify_call);
1833 } else {
1834 acc.body.emit (this);
1837 if (current_method_inner_error) {
1838 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
1841 cfile.add_function (function);
1844 pop_line ();
1845 pop_context ();
1848 public override void visit_destructor (Destructor d) {
1849 if (d.binding == MemberBinding.STATIC && !in_plugin) {
1850 Report.error (d.source_reference, "static destructors are only supported for dynamic types");
1851 d.error = true;
1852 return;
1856 public int get_block_id (Block b) {
1857 int result = block_map[b];
1858 if (result == 0) {
1859 result = ++next_block_id;
1860 block_map[b] = result;
1862 return result;
1865 public bool no_implicit_copy (DataType type) {
1866 // note: implicit copy of array is planned to be forbidden
1867 var cl = type.data_type as Class;
1868 return (type is DelegateType ||
1869 type.is_array () ||
1870 (cl != null && !cl.is_immutable && !is_reference_counting (cl) && !get_ccode_is_gboxed (cl)));
1873 void capture_parameter (Parameter param, CCodeStruct data, int block_id) {
1874 generate_type_declaration (param.variable_type, cfile);
1876 var param_type = param.variable_type.copy ();
1877 if (!param.variable_type.value_owned) {
1878 param_type.value_owned = !no_implicit_copy (param.variable_type);
1880 data.add_field (get_ccode_name (param_type), get_variable_cname (param.name));
1882 // create copy if necessary as captured variables may need to be kept alive
1883 param.captured = false;
1884 var value = load_parameter (param);
1886 var array_type = param.variable_type as ArrayType;
1887 var deleg_type = param.variable_type as DelegateType;
1889 if (array_type != null && get_ccode_array_length (param)) {
1890 for (int dim = 1; dim <= array_type.rank; dim++) {
1891 data.add_field ("gint", get_parameter_array_length_cname (param, dim));
1893 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
1894 data.add_field ("gpointer", get_ccode_delegate_target_name (param));
1895 if (param.variable_type.is_disposable ()) {
1896 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
1897 // reference transfer for delegates
1898 var lvalue = get_parameter_cvalue (param);
1899 ((GLibValue) value).delegate_target_destroy_notify_cvalue = get_delegate_target_destroy_notify_cvalue (lvalue);
1902 param.captured = true;
1904 store_parameter (param, value, true);
1907 public override void visit_block (Block b) {
1908 emit_context.push_symbol (b);
1910 var local_vars = b.get_local_variables ();
1912 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
1913 ccode.open_block ();
1916 if (b.captured) {
1917 var parent_block = next_closure_block (b.parent_symbol);
1919 int block_id = get_block_id (b);
1920 string struct_name = "Block%dData".printf (block_id);
1922 var data = new CCodeStruct ("_" + struct_name);
1923 data.add_field ("int", "_ref_count_");
1924 if (parent_block != null) {
1925 int parent_block_id = get_block_id (parent_block);
1927 data.add_field ("Block%dData *".printf (parent_block_id), "_data%d_".printf (parent_block_id));
1928 } else {
1929 if (get_this_type () != null) {
1930 data.add_field (get_ccode_name (get_data_type_for_symbol (current_type_symbol)), "self");
1933 if (current_method != null) {
1934 // allow capturing generic type parameters
1935 foreach (var type_param in current_method.get_type_parameters ()) {
1936 string func_name;
1938 func_name = "%s_type".printf (type_param.name.down ());
1939 data.add_field ("GType", func_name);
1941 func_name = "%s_dup_func".printf (type_param.name.down ());
1942 data.add_field ("GBoxedCopyFunc", func_name);
1944 func_name = "%s_destroy_func".printf (type_param.name.down ());
1945 data.add_field ("GDestroyNotify", func_name);
1949 foreach (var local in local_vars) {
1950 if (local.captured) {
1951 generate_type_declaration (local.variable_type, cfile);
1953 data.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
1955 if (local.variable_type is ArrayType) {
1956 var array_type = (ArrayType) local.variable_type;
1957 for (int dim = 1; dim <= array_type.rank; dim++) {
1958 data.add_field ("gint", get_array_length_cname (get_local_cname (local), dim));
1960 data.add_field ("gint", get_array_size_cname (get_local_cname (local)));
1961 } else if (local.variable_type is DelegateType) {
1962 data.add_field ("gpointer", get_delegate_target_cname (get_local_cname (local)));
1963 if (local.variable_type.value_owned) {
1964 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_local_cname (local)));
1970 var data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
1971 data_alloc.add_argument (new CCodeIdentifier (struct_name));
1973 if (is_in_coroutine ()) {
1974 closure_struct.add_field (struct_name + "*", "_data%d_".printf (block_id));
1975 } else {
1976 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id)));
1978 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), data_alloc);
1980 // initialize ref_count
1981 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_ref_count_"), new CCodeIdentifier ("1"));
1983 if (parent_block != null) {
1984 int parent_block_id = get_block_id (parent_block);
1986 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (parent_block_id)));
1987 ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id)));
1989 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call);
1990 } else {
1991 // skip self assignment in toplevel block of creation methods with chainup as self is not set at the beginning of the method
1992 // the chainup statement takes care of assigning self in the closure struct
1993 bool in_creation_method_with_chainup = (current_method is CreationMethod && current_class != null && current_class.base_class != null);
1995 if (get_this_type () != null && (!in_creation_method_with_chainup || current_method.body != b)) {
1996 var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_data_type_for_symbol (current_type_symbol), b.source_reference));
1997 ref_call.add_argument (get_result_cexpression ("self"));
1999 // never increase reference count for self in finalizers to avoid infinite recursion on following unref
2000 var instance = (is_in_destructor () ? (CCodeExpression) new CCodeIdentifier ("self") : (CCodeExpression) ref_call);
2002 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), instance);
2005 if (current_method != null) {
2006 // allow capturing generic type parameters
2007 var suffices = new string[] {"type", "dup_func", "destroy_func"};
2008 foreach (var type_param in current_method.get_type_parameters ()) {
2009 foreach (string suffix in suffices) {
2010 string func_name = "%s_%s".printf (type_param.name.down (), suffix);
2011 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name), get_variable_cexpression (func_name));
2017 if (b.parent_symbol is Method) {
2018 var m = (Method) b.parent_symbol;
2020 // parameters are captured with the top-level block of the method
2021 foreach (var param in m.get_parameters ()) {
2022 if (param.captured) {
2023 capture_parameter (param, data, block_id);
2027 if (m.coroutine) {
2028 // capture async data to allow invoking callback from inside closure
2029 data.add_field ("gpointer", "_async_data_");
2031 // async method is suspended while waiting for callback,
2032 // so we never need to care about memory management of async data
2033 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_async_data_"), new CCodeIdentifier ("_data_"));
2035 } else if (b.parent_symbol is PropertyAccessor) {
2036 var acc = (PropertyAccessor) b.parent_symbol;
2038 if (!acc.readable && acc.value_parameter.captured) {
2039 capture_parameter (acc.value_parameter, data, block_id);
2041 } else if (b.parent_symbol is ForeachStatement) {
2042 var stmt = (ForeachStatement) b.parent_symbol;
2043 if (!stmt.use_iterator && stmt.element_variable.captured) {
2044 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)));
2048 var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name));
2049 cfile.add_type_declaration (typedef);
2050 cfile.add_type_definition (data);
2052 // create ref/unref functions
2053 var ref_fun = new CCodeFunction ("block%d_data_ref".printf (block_id), struct_name + "*");
2054 ref_fun.add_parameter (new CCodeParameter ("_data%d_".printf (block_id), struct_name + "*"));
2055 ref_fun.modifiers = CCodeModifiers.STATIC;
2057 push_function (ref_fun);
2059 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_inc"));
2060 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2061 ccode.add_expression (ccall);
2062 ccode.add_return (new CCodeIdentifier ("_data%d_".printf (block_id)));
2064 pop_function ();
2066 cfile.add_function_declaration (ref_fun);
2067 cfile.add_function (ref_fun);
2069 var unref_fun = new CCodeFunction ("block%d_data_unref".printf (block_id), "void");
2070 unref_fun.add_parameter (new CCodeParameter ("_userdata_", "void *"));
2071 unref_fun.modifiers = CCodeModifiers.STATIC;
2073 push_function (unref_fun);
2075 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id), new CCodeCastExpression (new CCodeIdentifier ("_userdata_"), struct_name + "*")));
2076 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_dec_and_test"));
2077 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2078 ccode.open_if (ccall);
2080 CCodeExpression outer_block = new CCodeIdentifier ("_data%d_".printf (block_id));
2081 unowned Block parent_closure_block = b;
2082 while (true) {
2083 parent_closure_block = next_closure_block (parent_closure_block.parent_symbol);
2084 if (parent_closure_block == null) {
2085 break;
2087 int parent_block_id = get_block_id (parent_closure_block);
2088 outer_block = new CCodeMemberAccess.pointer (outer_block, "_data%d_".printf (parent_block_id));
2091 if (get_this_type () != null) {
2092 // assign "self" for type parameters
2093 ccode.add_declaration(get_ccode_name (get_data_type_for_symbol (current_type_symbol)), new CCodeVariableDeclarator ("self"));
2094 ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeMemberAccess.pointer (outer_block, "self"));
2097 if (current_method != null) {
2098 // assign captured generic type parameters
2099 foreach (var type_param in current_method.get_type_parameters ()) {
2100 string func_name;
2102 func_name = "%s_type".printf (type_param.name.down ());
2103 ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name));
2104 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2106 func_name = "%s_dup_func".printf (type_param.name.down ());
2107 ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name));
2108 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2110 func_name = "%s_destroy_func".printf (type_param.name.down ());
2111 ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name));
2112 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2116 // free in reverse order
2117 for (int i = local_vars.size - 1; i >= 0; i--) {
2118 var local = local_vars[i];
2119 if (local.captured) {
2120 if (requires_destroy (local.variable_type)) {
2121 bool old_coroutine = false;
2122 if (current_method != null) {
2123 old_coroutine = current_method.coroutine;
2124 current_method.coroutine = false;
2127 ccode.add_expression (destroy_local (local));
2129 if (old_coroutine) {
2130 current_method.coroutine = true;
2136 if (b.parent_symbol is Method) {
2137 var m = (Method) b.parent_symbol;
2139 // parameters are captured with the top-level block of the method
2140 foreach (var param in m.get_parameters ()) {
2141 if (param.captured) {
2142 var param_type = param.variable_type.copy ();
2143 if (!param_type.value_owned) {
2144 param_type.value_owned = !no_implicit_copy (param_type);
2147 if (requires_destroy (param_type)) {
2148 bool old_coroutine = false;
2149 if (m != null) {
2150 old_coroutine = m.coroutine;
2151 m.coroutine = false;
2154 ccode.add_expression (destroy_parameter (param));
2156 if (old_coroutine) {
2157 m.coroutine = true;
2162 } else if (b.parent_symbol is PropertyAccessor) {
2163 var acc = (PropertyAccessor) b.parent_symbol;
2165 if (!acc.readable && acc.value_parameter.captured) {
2166 var param_type = acc.value_parameter.variable_type.copy ();
2167 if (!param_type.value_owned) {
2168 param_type.value_owned = !no_implicit_copy (param_type);
2171 if (requires_destroy (param_type)) {
2172 ccode.add_expression (destroy_parameter (acc.value_parameter));
2177 // free parent block and "self" after captured variables
2178 // because they may require type parameters
2179 if (parent_block != null) {
2180 int parent_block_id = get_block_id (parent_block);
2182 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (parent_block_id)));
2183 unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
2184 ccode.add_expression (unref_call);
2185 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), new CCodeConstant ("NULL"));
2186 } else {
2187 var this_type = get_this_type ();
2188 if (this_type != null) {
2189 this_type = this_type.copy ();
2190 this_type.value_owned = true;
2191 if (this_type.is_disposable () && !is_in_destructor ()) {
2192 // reference count for self is not increased in finalizers
2193 var this_value = new GLibValue (get_data_type_for_symbol (current_type_symbol), new CCodeIdentifier ("self"), true);
2194 ccode.add_expression (destroy_value (this_value));
2199 var data_free = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
2200 data_free.add_argument (new CCodeIdentifier (struct_name));
2201 data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id)));
2202 ccode.add_expression (data_free);
2204 ccode.close ();
2206 pop_function ();
2208 cfile.add_function_declaration (unref_fun);
2209 cfile.add_function (unref_fun);
2212 foreach (Statement stmt in b.get_statements ()) {
2213 push_line (stmt.source_reference);
2214 stmt.emit (this);
2215 pop_line ();
2218 // free in reverse order
2219 for (int i = local_vars.size - 1; i >= 0; i--) {
2220 var local = local_vars[i];
2221 local.active = false;
2222 if (!local.unreachable && !local.captured && requires_destroy (local.variable_type)) {
2223 ccode.add_expression (destroy_local (local));
2227 if (b.parent_symbol is Method) {
2228 var m = (Method) b.parent_symbol;
2229 foreach (Parameter param in m.get_parameters ()) {
2230 if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
2231 ccode.add_expression (destroy_parameter (param));
2232 } else if (param.direction == ParameterDirection.OUT && !m.coroutine) {
2233 return_out_parameter (param);
2236 // check postconditions
2237 foreach (var postcondition in m.get_postconditions ()) {
2238 create_postcondition_statement (postcondition);
2240 } else if (b.parent_symbol is PropertyAccessor) {
2241 var acc = (PropertyAccessor) b.parent_symbol;
2242 if (acc.value_parameter != null && !acc.value_parameter.captured && requires_destroy (acc.value_parameter.variable_type)) {
2243 ccode.add_expression (destroy_parameter (acc.value_parameter));
2247 if (b.captured) {
2248 int block_id = get_block_id (b);
2250 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
2251 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
2252 ccode.add_expression (data_unref);
2253 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
2256 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
2257 ccode.close ();
2260 emit_context.pop_symbol ();
2263 public override void visit_declaration_statement (DeclarationStatement stmt) {
2264 stmt.declaration.accept (this);
2267 public CCodeExpression get_local_cexpression (LocalVariable local) {
2268 if (is_in_coroutine ()) {
2269 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_local_cname (local));
2270 } else {
2271 return new CCodeIdentifier (get_local_cname (local));
2275 public CCodeExpression get_variable_cexpression (string name) {
2276 if (is_in_coroutine ()) {
2277 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_variable_cname (name));
2278 } else {
2279 return new CCodeIdentifier (get_variable_cname (name));
2283 public CCodeExpression get_this_cexpression () {
2284 if (is_in_coroutine ()) {
2285 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
2286 } else {
2287 return new CCodeIdentifier ("self");
2291 public string get_local_cname (LocalVariable local) {
2292 var cname = get_variable_cname (local.name);
2293 if (cname[0].isdigit ()) {
2294 cname = "_%s_".printf (cname);
2296 if (is_in_coroutine ()) {
2297 var clash_index = emit_context.closure_variable_clash_map.get (local);
2298 if (clash_index > 0) {
2299 cname = "_vala%d_%s".printf (clash_index, cname);
2302 return cname;
2305 public string get_variable_cname (string name) {
2306 if (name[0] == '.') {
2307 if (name == ".result") {
2308 return "result";
2310 // compiler-internal variable
2311 if (!variable_name_map.contains (name)) {
2312 variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
2313 next_temp_var_id++;
2315 return variable_name_map.get (name);
2316 } else if (reserved_identifiers.contains (name)) {
2317 return "_%s_".printf (name);
2318 } else {
2319 return name;
2323 public CCodeExpression get_result_cexpression (string cname = "result") {
2324 if (is_in_coroutine ()) {
2325 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), cname);
2326 } else {
2327 return new CCodeIdentifier (cname);
2331 public bool is_simple_struct_creation (Variable variable, Expression expr) {
2332 var st = variable.variable_type.data_type as Struct;
2333 var creation = expr as ObjectCreationExpression;
2334 if (creation != null && st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list") && !variable.variable_type.nullable &&
2335 variable.variable_type.data_type != gvalue_type && creation.get_object_initializer ().size == 0) {
2336 return true;
2337 } else {
2338 return false;
2342 bool is_foreach_element_variable (LocalVariable local) {
2343 var block = local.parent_symbol;
2344 if (block != null) {
2345 var stmt = block.parent_symbol as ForeachStatement;
2346 if (stmt != null && !stmt.use_iterator && stmt.element_variable == local) {
2347 return true;
2350 return false;
2353 public override void visit_local_variable (LocalVariable local) {
2354 check_type (local.variable_type);
2356 /* Declaration */
2358 generate_type_declaration (local.variable_type, cfile);
2360 // captured element variables of foreach statements (without iterator) require local declaration
2361 var declared = !local.captured || is_foreach_element_variable (local);
2362 if (declared) {
2363 if (is_in_coroutine ()) {
2364 var count = emit_context.closure_variable_count_map.get (local.name);
2365 if (count > 0) {
2366 emit_context.closure_variable_clash_map.set (local, count);
2368 emit_context.closure_variable_count_map.set (local.name, count + 1);
2370 closure_struct.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
2371 } else {
2372 var cvar = new CCodeVariableDeclarator (get_local_cname (local), null, get_ccode_declarator_suffix (local.variable_type));
2374 // try to initialize uninitialized variables
2375 // initialization not necessary for variables stored in closure
2376 cvar.initializer = default_value_for_type (local.variable_type, true);
2377 cvar.init0 = true;
2379 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
2383 /* Emit initializer */
2384 if (local.initializer != null) {
2385 local.initializer.emit (this);
2387 visit_end_full_expression (local.initializer);
2391 CCodeExpression rhs = null;
2392 if (local.initializer != null && get_cvalue (local.initializer) != null) {
2393 rhs = get_cvalue (local.initializer);
2396 /* Additional temp variables */
2398 if (declared) {
2399 if (local.variable_type is ArrayType) {
2400 // create variables to store array dimensions
2401 var array_type = (ArrayType) local.variable_type;
2403 if (!array_type.fixed_length) {
2404 for (int dim = 1; dim <= array_type.rank; dim++) {
2405 var len_var = new LocalVariable (int_type.copy (), get_array_length_cname (get_local_cname (local), dim));
2406 len_var.init = local.initializer == null;
2407 emit_temp_var (len_var);
2410 if (array_type.rank == 1) {
2411 var size_var = new LocalVariable (int_type.copy (), get_array_size_cname (get_local_cname (local)));
2412 size_var.init = local.initializer == null;
2413 emit_temp_var (size_var);
2416 } else if (local.variable_type is DelegateType) {
2417 var deleg_type = (DelegateType) local.variable_type;
2418 var d = deleg_type.delegate_symbol;
2419 if (d.has_target) {
2420 // create variable to store delegate target
2421 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (get_local_cname (local)));
2422 target_var.init = local.initializer == null;
2423 emit_temp_var (target_var);
2424 if (deleg_type.value_owned) {
2425 var target_destroy_notify_var = new LocalVariable (gdestroynotify_type, get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2426 target_destroy_notify_var.init = local.initializer == null;
2427 emit_temp_var (target_destroy_notify_var);
2433 /* Store the initializer */
2435 if (rhs != null) {
2436 if (!is_simple_struct_creation (local, local.initializer)) {
2437 store_local (local, local.initializer.target_value, true);
2441 if (local.initializer != null && local.initializer.tree_can_fail) {
2442 add_simple_check (local.initializer);
2445 local.active = true;
2449 * Create a temporary variable and return lvalue access to it
2451 public TargetValue create_temp_value (DataType type, bool init, CodeNode node_reference, bool? value_owned = null) {
2452 var local = new LocalVariable (type.copy (), "_tmp%d_".printf (next_temp_var_id++), null, node_reference.source_reference);
2453 local.init = init;
2454 if (value_owned != null) {
2455 local.variable_type.value_owned = value_owned;
2458 var array_type = local.variable_type as ArrayType;
2459 var deleg_type = local.variable_type as DelegateType;
2461 emit_temp_var (local);
2462 if (array_type != null) {
2463 for (int dim = 1; dim <= array_type.rank; dim++) {
2464 var len_var = new LocalVariable (int_type.copy (), get_array_length_cname (local.name, dim), null, node_reference.source_reference);
2465 len_var.init = init;
2466 emit_temp_var (len_var);
2468 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
2469 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (local.name), null, node_reference.source_reference);
2470 target_var.init = init;
2471 emit_temp_var (target_var);
2472 if (deleg_type.value_owned) {
2473 var target_destroy_notify_var = new LocalVariable (gdestroynotify_type.copy (), get_delegate_target_destroy_notify_cname (local.name), null, node_reference.source_reference);
2474 target_destroy_notify_var.init = init;
2475 emit_temp_var (target_destroy_notify_var);
2479 var value = get_local_cvalue (local);
2480 set_array_size_cvalue (value, null);
2481 return value;
2485 * Load a temporary variable returning unowned or owned rvalue access to it, depending on the ownership of the value type.
2487 public TargetValue load_temp_value (TargetValue lvalue) {
2488 var value = ((GLibValue) lvalue).copy ();
2489 var deleg_type = value.value_type as DelegateType;
2490 if (deleg_type != null) {
2491 if (!deleg_type.delegate_symbol.has_target) {
2492 value.delegate_target_cvalue = new CCodeConstant ("NULL");
2493 ((GLibValue) value).lvalue = false;
2494 } else if (!deleg_type.is_disposable ()) {
2495 value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
2496 ((GLibValue) value).lvalue = false;
2499 return value;
2503 * Store a value in a temporary variable and return unowned or owned rvalue access to it, depending on the ownership of the given type.
2505 public TargetValue store_temp_value (TargetValue initializer, CodeNode node_reference, bool? value_owned = null) {
2506 var lvalue = create_temp_value (initializer.value_type, false, node_reference, value_owned);
2507 store_value (lvalue, initializer, node_reference.source_reference);
2508 return load_temp_value (lvalue);
2511 public override void visit_initializer_list (InitializerList list) {
2512 if (list.target_type.data_type is Struct) {
2513 /* initializer is used as struct initializer */
2514 var st = (Struct) list.target_type.data_type;
2515 while (st.base_struct != null) {
2516 st = st.base_struct;
2519 if (list.parent_node is Constant || list.parent_node is Field || list.parent_node is InitializerList) {
2520 var clist = new CCodeInitializerList ();
2522 var field_it = st.get_fields ().iterator ();
2523 foreach (Expression expr in list.get_initializers ()) {
2524 Field field = null;
2525 while (field == null) {
2526 field_it.next ();
2527 field = field_it.get ();
2528 if (field.binding != MemberBinding.INSTANCE) {
2529 // we only initialize instance fields
2530 field = null;
2534 var cexpr = get_cvalue (expr);
2536 string ctype = get_ccode_type (field);
2537 if (ctype != null) {
2538 cexpr = new CCodeCastExpression (cexpr, ctype);
2541 clist.append (cexpr);
2543 var array_type = field.variable_type as ArrayType;
2544 if (array_type != null && get_ccode_array_length (field) && !get_ccode_array_null_terminated (field)) {
2545 for (int dim = 1; dim <= array_type.rank; dim++) {
2546 clist.append (get_array_length_cvalue (expr.target_value, dim));
2551 set_cvalue (list, clist);
2552 } else {
2553 // used as expression
2554 var instance = create_temp_value (list.value_type, true, list);
2556 var field_it = st.get_fields ().iterator ();
2557 foreach (Expression expr in list.get_initializers ()) {
2558 Field field = null;
2559 while (field == null) {
2560 field_it.next ();
2561 field = field_it.get ();
2562 if (field.binding != MemberBinding.INSTANCE) {
2563 // we only initialize instance fields
2564 field = null;
2568 store_field (field, instance, expr.target_value);
2571 list.target_value = instance;
2573 } else {
2574 var clist = new CCodeInitializerList ();
2575 foreach (Expression expr in list.get_initializers ()) {
2576 clist.append (get_cvalue (expr));
2578 set_cvalue (list, clist);
2582 public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null, bool init = false) {
2583 var var_type = type.copy ();
2584 var_type.value_owned = value_owned;
2585 var local = new LocalVariable (var_type, "_tmp%d_".printf (next_temp_var_id));
2586 local.init = init;
2588 if (node_reference != null) {
2589 local.source_reference = node_reference.source_reference;
2592 next_temp_var_id++;
2594 return local;
2597 bool is_in_generic_type (GenericType type) {
2598 if (current_symbol != null && type.type_parameter.parent_symbol is TypeSymbol
2599 && (current_method == null || current_method.binding == MemberBinding.INSTANCE)) {
2600 return true;
2601 } else {
2602 return false;
2606 void require_generic_accessors (Interface iface) {
2607 if (iface.get_attribute ("GenericAccessors") == null) {
2608 Report.error (iface.source_reference,
2609 "missing generic type for interface `%s', add GenericAccessors attribute to interface declaration"
2610 .printf (iface.get_full_name ()));
2614 public CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
2615 if (type is GenericType) {
2616 var type_parameter = ((GenericType) type).type_parameter;
2617 string var_name = "%s_type".printf (type_parameter.name.down ());
2619 if (type_parameter.parent_symbol is Interface) {
2620 var iface = (Interface) type_parameter.parent_symbol;
2621 require_generic_accessors (iface);
2623 string method_name = "get_%s_type".printf (type_parameter.name.down ());
2624 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
2625 cast_self.add_argument (new CCodeIdentifier ("self"));
2626 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
2627 function_call.add_argument (new CCodeIdentifier ("self"));
2628 return function_call;
2631 if (is_in_generic_type ((GenericType) type) && !is_chainup && !in_creation_method) {
2632 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), var_name);
2633 } else {
2634 return get_variable_cexpression (var_name);
2636 } else {
2637 string type_id = get_ccode_type_id (type);
2638 if (type_id == "") {
2639 type_id = "G_TYPE_INVALID";
2640 } else {
2641 generate_type_declaration (type, cfile);
2643 return new CCodeIdentifier (type_id);
2647 public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup = false) {
2648 if (type is ErrorType) {
2649 return new CCodeIdentifier ("g_error_copy");
2650 } else if (type.data_type != null) {
2651 string dup_function;
2652 var cl = type.data_type as Class;
2653 if (is_reference_counting (type.data_type)) {
2654 dup_function = get_ccode_ref_function ((ObjectTypeSymbol) type.data_type);
2655 if (type.data_type is Interface && dup_function == null) {
2656 Report.error (source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure".printf (type.data_type.get_full_name ()));
2657 return new CCodeInvalidExpression();
2659 } else if (cl != null && cl.is_immutable) {
2660 // allow duplicates of immutable instances as for example strings
2661 dup_function = get_ccode_dup_function (type.data_type);
2662 if (dup_function == null) {
2663 dup_function = "";
2665 } else if (cl != null && get_ccode_is_gboxed (cl)) {
2666 // allow duplicates of gboxed instances
2667 dup_function = generate_dup_func_wrapper (type);
2668 if (dup_function == null) {
2669 dup_function = "";
2671 } else if (type is ValueType) {
2672 dup_function = get_ccode_dup_function (type.data_type);
2673 if (dup_function == null && type.nullable) {
2674 dup_function = generate_struct_dup_wrapper ((ValueType) type);
2675 } else if (dup_function == null) {
2676 dup_function = "";
2678 } else {
2679 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2680 Report.error (source_reference, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type.data_type.name));
2681 return new CCodeInvalidExpression();
2684 return new CCodeIdentifier (dup_function);
2685 } else if (type is GenericType) {
2686 var type_parameter = ((GenericType) type).type_parameter;
2687 string func_name = "%s_dup_func".printf (type_parameter.name.down ());
2689 if (type_parameter.parent_symbol is Interface) {
2690 var iface = (Interface) type_parameter.parent_symbol;
2691 require_generic_accessors (iface);
2693 string method_name = "get_%s_dup_func".printf (type_parameter.name.down ());
2694 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
2695 cast_self.add_argument (new CCodeIdentifier ("self"));
2696 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
2697 function_call.add_argument (new CCodeIdentifier ("self"));
2698 return function_call;
2701 if (is_in_generic_type ((GenericType) type) && !is_chainup && !in_creation_method) {
2702 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
2703 } else {
2704 return get_variable_cexpression (func_name);
2706 } else if (type is PointerType) {
2707 var pointer_type = (PointerType) type;
2708 return get_dup_func_expression (pointer_type.base_type, source_reference);
2709 } else {
2710 return new CCodeConstant ("NULL");
2714 void make_comparable_cexpression (ref DataType left_type, ref CCodeExpression cleft, ref DataType right_type, ref CCodeExpression cright) {
2715 var left_type_as_struct = left_type.data_type as Struct;
2716 var right_type_as_struct = right_type.data_type as Struct;
2718 // GValue support
2719 var valuecast = try_cast_value_to_type (cleft, left_type, right_type);
2720 if (valuecast != null) {
2721 cleft = valuecast;
2722 left_type = right_type;
2723 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2724 return;
2727 valuecast = try_cast_value_to_type (cright, right_type, left_type);
2728 if (valuecast != null) {
2729 cright = valuecast;
2730 right_type = left_type;
2731 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2732 return;
2735 if (left_type.data_type is Class && !((Class) left_type.data_type).is_compact &&
2736 right_type.data_type is Class && !((Class) right_type.data_type).is_compact) {
2737 var left_cl = (Class) left_type.data_type;
2738 var right_cl = (Class) right_type.data_type;
2740 if (left_cl != right_cl) {
2741 if (left_cl.is_subtype_of (right_cl)) {
2742 cleft = generate_instance_cast (cleft, right_cl);
2743 } else if (right_cl.is_subtype_of (left_cl)) {
2744 cright = generate_instance_cast (cright, left_cl);
2747 } else if (left_type_as_struct != null && right_type_as_struct != null) {
2748 if (left_type is StructValueType) {
2749 // real structs (uses compare/equal function)
2750 if (!left_type.nullable) {
2751 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft);
2753 if (!right_type.nullable) {
2754 cright = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cright);
2756 } else {
2757 // integer or floating or boolean type
2758 if (left_type.nullable && right_type.nullable) {
2759 // FIXME also compare contents, not just address
2760 } else if (left_type.nullable) {
2761 // FIXME check left value is not null
2762 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
2763 } else if (right_type.nullable) {
2764 // FIXME check right value is not null
2765 cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
2771 private string generate_struct_equal_function (Struct st) {
2772 if (st.base_struct != null) {
2773 return generate_struct_equal_function (st.base_struct);
2776 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (st));
2778 if (!add_wrapper (equal_func)) {
2779 // wrapper already defined
2780 return equal_func;
2783 var function = new CCodeFunction (equal_func, "gboolean");
2784 function.modifiers = CCodeModifiers.STATIC;
2786 function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (st))));
2787 function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (st))));
2789 push_function (function);
2791 // if (s1 == s2) return TRUE;
2793 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2794 ccode.open_if (cexp);
2795 ccode.add_return (new CCodeConstant ("TRUE"));
2796 ccode.close ();
2798 // if (s1 == NULL || s2 == NULL) return FALSE;
2800 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2801 ccode.open_if (cexp);
2802 ccode.add_return (new CCodeConstant ("FALSE"));
2803 ccode.close ();
2805 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2806 ccode.open_if (cexp);
2807 ccode.add_return (new CCodeConstant ("FALSE"));
2808 ccode.close ();
2811 bool has_instance_fields = false;
2812 foreach (Field f in st.get_fields ()) {
2813 if (f.binding != MemberBinding.INSTANCE) {
2814 // we only compare instance fields
2815 continue;
2818 has_instance_fields = true;
2820 CCodeExpression cexp; // if (cexp) return FALSE;
2821 var s1 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s1"), get_ccode_name (f)); // s1->f
2822 var s2 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s2"), get_ccode_name (f)); // s2->f
2824 var variable_type = f.variable_type.copy ();
2825 make_comparable_cexpression (ref variable_type, ref s1, ref variable_type, ref s2);
2827 if (!(f.variable_type is NullType) && f.variable_type.compatible (string_type)) {
2828 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
2829 ccall.add_argument (s1);
2830 ccall.add_argument (s2);
2831 cexp = ccall;
2832 } else if (f.variable_type is StructValueType) {
2833 var equalfunc = generate_struct_equal_function (f.variable_type.data_type as Struct);
2834 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
2835 ccall.add_argument (s1);
2836 ccall.add_argument (s2);
2837 cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
2838 } else {
2839 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, s1, s2);
2842 ccode.open_if (cexp);
2843 ccode.add_return (new CCodeConstant ("FALSE"));
2844 ccode.close ();
2847 if (!has_instance_fields) {
2848 // either opaque structure or simple type
2849 if (st.is_simple_type ()) {
2850 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2851 ccode.add_return (cexp);
2852 } else {
2853 ccode.add_return (new CCodeConstant ("FALSE"));
2855 } else {
2856 ccode.add_return (new CCodeConstant ("TRUE"));
2859 pop_function ();
2861 cfile.add_function_declaration (function);
2862 cfile.add_function (function);
2864 return equal_func;
2867 private string generate_numeric_equal_function (TypeSymbol sym) {
2868 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (sym));
2870 if (!add_wrapper (equal_func)) {
2871 // wrapper already defined
2872 return equal_func;
2875 var function = new CCodeFunction (equal_func, "gboolean");
2876 function.modifiers = CCodeModifiers.STATIC;
2878 function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (sym))));
2879 function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (sym))));
2881 push_function (function);
2883 // if (s1 == s2) return TRUE;
2885 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2886 ccode.open_if (cexp);
2887 ccode.add_return (new CCodeConstant ("TRUE"));
2888 ccode.close ();
2890 // if (s1 == NULL || s2 == NULL) return FALSE;
2892 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2893 ccode.open_if (cexp);
2894 ccode.add_return (new CCodeConstant ("FALSE"));
2895 ccode.close ();
2897 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2898 ccode.open_if (cexp);
2899 ccode.add_return (new CCodeConstant ("FALSE"));
2900 ccode.close ();
2902 // return (*s1 == *s2);
2904 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2905 ccode.add_return (cexp);
2908 pop_function ();
2910 cfile.add_function_declaration (function);
2911 cfile.add_function (function);
2913 return equal_func;
2916 private string generate_struct_dup_wrapper (ValueType value_type) {
2917 string dup_func = "_%sdup".printf (get_ccode_lower_case_prefix (value_type.type_symbol));
2919 if (!add_wrapper (dup_func)) {
2920 // wrapper already defined
2921 return dup_func;
2924 var function = new CCodeFunction (dup_func, get_ccode_name (value_type));
2925 function.modifiers = CCodeModifiers.STATIC;
2927 function.add_parameter (new CCodeParameter ("self", get_ccode_name (value_type)));
2929 push_function (function);
2931 if (value_type.type_symbol == gvalue_type) {
2932 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
2933 dup_call.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
2934 dup_call.add_argument (new CCodeIdentifier ("self"));
2936 ccode.add_return (dup_call);
2937 } else {
2938 ccode.add_declaration (get_ccode_name (value_type), new CCodeVariableDeclarator ("dup"));
2940 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
2941 creation_call.add_argument (new CCodeConstant (get_ccode_name (value_type.data_type)));
2942 creation_call.add_argument (new CCodeConstant ("1"));
2943 ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
2945 var st = value_type.data_type as Struct;
2946 if (st != null && st.is_disposable ()) {
2947 if (!get_ccode_has_copy_function (st)) {
2948 generate_struct_copy_function (st);
2951 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
2952 copy_call.add_argument (new CCodeIdentifier ("self"));
2953 copy_call.add_argument (new CCodeIdentifier ("dup"));
2954 ccode.add_expression (copy_call);
2955 } else {
2956 cfile.add_include ("string.h");
2958 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
2959 sizeof_call.add_argument (new CCodeConstant (get_ccode_name (value_type.data_type)));
2961 var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
2962 copy_call.add_argument (new CCodeIdentifier ("dup"));
2963 copy_call.add_argument (new CCodeIdentifier ("self"));
2964 copy_call.add_argument (sizeof_call);
2965 ccode.add_expression (copy_call);
2968 ccode.add_return (new CCodeIdentifier ("dup"));
2971 pop_function ();
2973 cfile.add_function_declaration (function);
2974 cfile.add_function (function);
2976 return dup_func;
2979 protected string generate_dup_func_wrapper (DataType type) {
2980 string destroy_func = "_vala_%s_copy".printf (get_ccode_name (type.data_type));
2982 if (!add_wrapper (destroy_func)) {
2983 // wrapper already defined
2984 return destroy_func;
2987 var function = new CCodeFunction (destroy_func, get_ccode_name (type));
2988 function.modifiers = CCodeModifiers.STATIC;
2989 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
2991 push_function (function);
2993 var cl = type.data_type as Class;
2994 assert (cl != null && get_ccode_is_gboxed (cl));
2996 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
2997 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
2998 free_call.add_argument (new CCodeIdentifier ("self"));
3000 ccode.add_return (free_call);
3002 pop_function ();
3004 cfile.add_function_declaration (function);
3005 cfile.add_function (function);
3007 return destroy_func;
3010 protected string generate_free_function_address_of_wrapper (DataType type) {
3011 string destroy_func = "_vala_%s_free_function_address_of".printf (get_ccode_name (type.data_type));
3013 if (!add_wrapper (destroy_func)) {
3014 // wrapper already defined
3015 return destroy_func;
3018 var function = new CCodeFunction (destroy_func, "void");
3019 function.modifiers = CCodeModifiers.STATIC;
3020 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3022 push_function (function);
3024 var cl = type.data_type as Class;
3025 var free_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (cl)));
3026 free_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("self")));
3028 ccode.add_expression (free_call);
3030 pop_function ();
3032 cfile.add_function_declaration (function);
3033 cfile.add_function (function);
3035 return destroy_func;
3038 protected string generate_free_func_wrapper (DataType type) {
3039 string destroy_func = "_vala_%s_free".printf (get_ccode_name (type.data_type));
3041 if (!add_wrapper (destroy_func)) {
3042 // wrapper already defined
3043 return destroy_func;
3046 var function = new CCodeFunction (destroy_func, "void");
3047 function.modifiers = CCodeModifiers.STATIC;
3048 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3050 push_function (function);
3052 var cl = type.data_type as Class;
3053 if (cl != null && get_ccode_is_gboxed (cl)) {
3054 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_free"));
3055 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
3056 free_call.add_argument (new CCodeIdentifier ("self"));
3058 ccode.add_expression (free_call);
3059 } else {
3060 var st = type.data_type as Struct;
3061 if (st != null && st.is_disposable ()) {
3062 if (!get_ccode_has_destroy_function (st)) {
3063 generate_struct_destroy_function (st);
3066 var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (st)));
3067 destroy_call.add_argument (new CCodeIdentifier ("self"));
3068 ccode.add_expression (destroy_call);
3071 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
3072 free_call.add_argument (new CCodeIdentifier ("self"));
3074 ccode.add_expression (free_call);
3077 pop_function ();
3079 cfile.add_function_declaration (function);
3080 cfile.add_function (function);
3082 return destroy_func;
3085 public CCodeExpression? get_destroy0_func_expression (DataType type, bool is_chainup = false) {
3086 var element_destroy_func_expression = get_destroy_func_expression (type, is_chainup);
3088 if (!(type is GenericType) && element_destroy_func_expression is CCodeIdentifier) {
3089 var freeid = (CCodeIdentifier) element_destroy_func_expression;
3090 string free0_func = "_%s0_".printf (freeid.name);
3092 if (add_wrapper (free0_func)) {
3093 var function = new CCodeFunction (free0_func, "void");
3094 function.modifiers = CCodeModifiers.STATIC;
3096 function.add_parameter (new CCodeParameter ("var", "gpointer"));
3098 push_function (function);
3100 ccode.add_expression (destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true));
3102 pop_function ();
3104 cfile.add_function_declaration (function);
3105 cfile.add_function (function);
3108 element_destroy_func_expression = new CCodeIdentifier (free0_func);
3111 return element_destroy_func_expression;
3114 public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
3115 if (type.data_type == glist_type || type.data_type == gslist_type || type.data_type == gnode_type || type.data_type == gqueue_type) {
3116 // create wrapper function to free list elements if necessary
3118 bool elements_require_free = false;
3119 CCodeExpression element_destroy_func_expression = null;
3121 foreach (DataType type_arg in type.get_type_arguments ()) {
3122 elements_require_free = requires_destroy (type_arg);
3123 if (elements_require_free) {
3124 element_destroy_func_expression = get_destroy0_func_expression (type_arg);
3128 if (elements_require_free && element_destroy_func_expression is CCodeIdentifier) {
3129 return new CCodeIdentifier (generate_collection_free_wrapper (type, (CCodeIdentifier) element_destroy_func_expression));
3130 } else {
3131 return new CCodeIdentifier (get_ccode_free_function (type.data_type));
3133 } else if (type is ErrorType) {
3134 return new CCodeIdentifier ("g_error_free");
3135 } else if (type.data_type != null) {
3136 string unref_function;
3137 if (type is ReferenceType) {
3138 if (is_reference_counting (type.data_type)) {
3139 unref_function = get_ccode_unref_function ((ObjectTypeSymbol) type.data_type);
3140 if (type.data_type is Interface && unref_function == null) {
3141 Report.error (type.source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure".printf (type.data_type.get_full_name ()));
3142 return null;
3144 } else {
3145 var cl = type.data_type as Class;
3146 if (cl != null && get_ccode_is_gboxed (cl)) {
3147 unref_function = generate_free_func_wrapper (type);
3148 } else {
3149 if (is_free_function_address_of (type)) {
3150 unref_function = generate_free_function_address_of_wrapper (type);
3151 } else {
3152 unref_function = get_ccode_free_function (type.data_type);
3156 } else {
3157 if (type.nullable) {
3158 unref_function = get_ccode_free_function (type.data_type);
3159 if (unref_function == null) {
3160 if (type.data_type is Struct && ((Struct) type.data_type).is_disposable ()) {
3161 unref_function = generate_free_func_wrapper (type);
3162 } else {
3163 unref_function = "g_free";
3166 } else if (type is EnumValueType) {
3167 unref_function = null;
3168 } else {
3169 var st = (Struct) type.data_type;
3170 if (st.is_disposable ()) {
3171 if (!get_ccode_has_destroy_function (st)) {
3172 generate_struct_destroy_function (st);
3174 unref_function = get_ccode_destroy_function (st);
3175 } else {
3176 unref_function = null;
3180 if (unref_function == null) {
3181 return new CCodeConstant ("NULL");
3183 return new CCodeIdentifier (unref_function);
3184 } else if (type is GenericType) {
3185 var type_parameter = ((GenericType) type).type_parameter;
3186 string func_name = "%s_destroy_func".printf (type_parameter.name.down ());
3188 if (type_parameter.parent_symbol is Interface) {
3189 var iface = (Interface) type_parameter.parent_symbol;
3190 require_generic_accessors (iface);
3192 string method_name = "get_%s_destroy_func".printf (type_parameter.name.down ());
3193 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
3194 cast_self.add_argument (new CCodeIdentifier ("self"));
3195 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
3196 function_call.add_argument (new CCodeIdentifier ("self"));
3197 return function_call;
3200 if (is_in_generic_type ((GenericType) type) && !is_chainup && !in_creation_method) {
3201 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
3202 } else {
3203 return get_variable_cexpression (func_name);
3205 } else if (type is ArrayType) {
3206 return new CCodeIdentifier ("g_free");
3207 } else if (type is PointerType) {
3208 return new CCodeIdentifier ("g_free");
3209 } else {
3210 return new CCodeConstant ("NULL");
3214 private string generate_collection_free_wrapper (DataType collection_type, CCodeIdentifier element_destroy_func_expression) {
3215 string destroy_func = "_%s_%s".printf (get_ccode_free_function (collection_type.data_type), element_destroy_func_expression.name);
3217 if (!add_wrapper (destroy_func)) {
3218 // wrapper already defined
3219 return destroy_func;
3222 var function = new CCodeFunction (destroy_func, "void");
3223 function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3225 push_function (function);
3227 if (collection_type.data_type == gnode_type) {
3228 CCodeFunctionCall element_free_call;
3229 /* A wrapper which converts GNodeTraverseFunc into GDestroyNotify */
3230 string destroy_node_func = "%s_node".printf (destroy_func);
3231 var wrapper = new CCodeFunction (destroy_node_func, "gboolean");
3232 wrapper.modifiers = CCodeModifiers.STATIC;
3233 wrapper.add_parameter (new CCodeParameter ("node", get_ccode_name (collection_type)));
3234 wrapper.add_parameter (new CCodeParameter ("unused", "gpointer"));
3235 push_function (wrapper);
3237 var free_call = new CCodeFunctionCall (element_destroy_func_expression);
3238 free_call.add_argument (new CCodeMemberAccess.pointer(new CCodeIdentifier("node"), "data"));
3239 ccode.add_expression (free_call);
3240 ccode.add_return (new CCodeConstant ("FALSE"));
3242 pop_function ();
3243 cfile.add_function_declaration (wrapper);
3244 cfile.add_function (wrapper);
3246 /* Now the code to call g_traverse with the above */
3247 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_node_traverse"));
3248 element_free_call.add_argument (new CCodeIdentifier("self"));
3249 element_free_call.add_argument (new CCodeConstant ("G_POST_ORDER"));
3250 element_free_call.add_argument (new CCodeConstant ("G_TRAVERSE_ALL"));
3251 element_free_call.add_argument (new CCodeConstant ("-1"));
3252 element_free_call.add_argument (new CCodeIdentifier (destroy_node_func));
3253 element_free_call.add_argument (new CCodeConstant ("NULL"));
3254 ccode.add_expression (element_free_call);
3256 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (gnode_type)));
3257 cfreecall.add_argument (new CCodeIdentifier ("self"));
3258 ccode.add_expression (cfreecall);
3260 function.modifiers = CCodeModifiers.STATIC;
3261 } else {
3262 CCodeFunctionCall collection_free_call;
3263 if (collection_type.data_type == glist_type) {
3264 collection_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_list_free_full"));
3265 } else if (collection_type.data_type == gslist_type) {
3266 collection_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_slist_free_full"));
3267 } else {
3268 collection_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_queue_free_full"));
3271 collection_free_call.add_argument (new CCodeIdentifier ("self"));
3272 collection_free_call.add_argument (new CCodeCastExpression (element_destroy_func_expression, "GDestroyNotify"));
3273 ccode.add_expression (collection_free_call);
3275 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
3278 pop_function ();
3280 cfile.add_function_declaration (function);
3281 cfile.add_function (function);
3283 return destroy_func;
3286 public virtual string? append_struct_array_free (Struct st) {
3287 return null;
3290 public CCodeExpression destroy_local (LocalVariable local) {
3291 return destroy_value (get_local_cvalue (local));
3294 public CCodeExpression destroy_parameter (Parameter param) {
3295 return destroy_value (get_parameter_cvalue (param));
3298 public CCodeExpression destroy_field (Field field, TargetValue? instance) {
3299 return destroy_value (get_field_cvalue (field, instance));
3302 public virtual CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
3303 var type = value.value_type;
3304 if (value.actual_value_type != null) {
3305 type = value.actual_value_type;
3307 var cvar = get_cvalue_ (value);
3309 if (type is DelegateType) {
3310 var delegate_target = get_delegate_target_cvalue (value);
3311 var delegate_target_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
3313 var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
3314 ccall.add_argument (delegate_target);
3316 var destroy_call = new CCodeCommaExpression ();
3317 destroy_call.append_expression (ccall);
3318 destroy_call.append_expression (new CCodeConstant ("NULL"));
3320 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
3322 var ccomma = new CCodeCommaExpression ();
3323 ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), destroy_call));
3324 ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
3325 ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
3326 ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
3328 return ccomma;
3331 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
3333 if (type is ValueType && !type.nullable) {
3334 // normal value type, no null check
3335 var st = type.data_type as Struct;
3336 if (st != null && st.is_simple_type ()) {
3337 // used for va_list
3338 ccall.add_argument (cvar);
3339 } else {
3340 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3343 if (gvalue_type != null && type.data_type == gvalue_type) {
3344 // g_value_unset must not be called for already unset values
3345 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
3346 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3348 var ccomma = new CCodeCommaExpression ();
3349 ccomma.append_expression (ccall);
3350 ccomma.append_expression (new CCodeConstant ("NULL"));
3352 return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
3353 } else if ((type.data_type == gmutex_type ||
3354 type.data_type == grecmutex_type ||
3355 type.data_type == grwlock_type ||
3356 type.data_type == gcond_type)) {
3357 // g_mutex_clear must not be called for uninitialized mutex
3358 // also, g_mutex_clear does not clear the struct
3359 requires_clear_mutex = true;
3360 ccall.call = new CCodeIdentifier ("_vala_clear_" + get_ccode_name (type.data_type));
3361 return ccall;
3362 } else {
3363 return ccall;
3367 if (ccall.call is CCodeIdentifier && !(type is ArrayType) && !is_macro_definition) {
3368 // generate and use NULL-aware free macro to simplify code
3370 var freeid = (CCodeIdentifier) ccall.call;
3371 string free0_func = "_%s0".printf (freeid.name);
3373 if (add_wrapper (free0_func)) {
3374 var macro = destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true);
3375 cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("%s(var)".printf (free0_func), macro));
3378 ccall = new CCodeFunctionCall (new CCodeIdentifier (free0_func));
3379 ccall.add_argument (cvar);
3380 return ccall;
3383 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
3385 /* can be simplified to
3386 * foo = (unref (foo), NULL)
3387 * if foo is of static type non-null
3390 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
3391 if (type is GenericType) {
3392 var parent = ((GenericType) type).type_parameter.parent_symbol;
3393 var cl = parent as Class;
3394 if ((!(parent is Method) && !(parent is ObjectTypeSymbol)) || (cl != null && cl.is_compact)) {
3395 return new CCodeConstant ("NULL");
3398 // unref functions are optional for type parameters
3399 var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
3400 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
3403 ccall.add_argument (cvar);
3405 /* set freed references to NULL to prevent further use */
3406 var ccomma = new CCodeCommaExpression ();
3408 if (type.data_type != null && !is_reference_counting (type.data_type) &&
3409 (type.data_type.is_subtype_of (gstringbuilder_type)
3410 || type.data_type.is_subtype_of (garray_type)
3411 || type.data_type.is_subtype_of (gbytearray_type)
3412 || type.data_type.is_subtype_of (gptrarray_type))) {
3413 ccall.add_argument (new CCodeConstant ("TRUE"));
3414 } else if (type.data_type == gthreadpool_type) {
3415 ccall.add_argument (new CCodeConstant ("FALSE"));
3416 ccall.add_argument (new CCodeConstant ("TRUE"));
3417 } else if (type is ArrayType) {
3418 var array_type = (ArrayType) type;
3419 if (requires_destroy (array_type.element_type)) {
3420 CCodeExpression csizeexpr = null;
3421 if (((GLibValue) value).array_length_cvalues != null) {
3422 csizeexpr = get_array_length_cvalue (value);
3423 } else if (get_array_null_terminated (value)) {
3424 requires_array_length = true;
3425 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
3426 len_call.add_argument (cvar);
3427 csizeexpr = len_call;
3428 } else {
3429 csizeexpr = get_array_length_cexpr (value);
3432 if (csizeexpr != null) {
3433 var st = array_type.element_type.data_type as Struct;
3434 if (st != null && !array_type.element_type.nullable) {
3435 ccall.call = new CCodeIdentifier (append_struct_array_free (st));
3436 ccall.add_argument (csizeexpr);
3437 } else {
3438 requires_array_free = true;
3439 ccall.call = new CCodeIdentifier ("_vala_array_free");
3440 ccall.add_argument (csizeexpr);
3441 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
3447 ccomma.append_expression (ccall);
3448 ccomma.append_expression (new CCodeConstant ("NULL"));
3450 var cassign = new CCodeAssignment (cvar, ccomma);
3452 // g_free (NULL) is allowed
3453 bool uses_gfree = (type.data_type != null && !is_reference_counting (type.data_type) && get_ccode_free_function (type.data_type) == "g_free");
3454 uses_gfree = uses_gfree || type is ArrayType;
3455 if (uses_gfree) {
3456 return cassign;
3459 return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
3462 public override void visit_end_full_expression (Expression expr) {
3463 /* expr is a full expression, i.e. an initializer, the
3464 * expression in an expression statement, the controlling
3465 * expression in if, while, for, or foreach statements
3467 * we unref temporary variables at the end of a full
3468 * expression
3470 if (temp_ref_values.size == 0) {
3471 /* nothing to do without temporary variables */
3472 return;
3475 var local_decl = expr.parent_node as LocalVariable;
3476 if (!(local_decl != null && is_simple_struct_creation (local_decl, local_decl.initializer))) {
3477 expr.target_value = store_temp_value (expr.target_value, expr);
3480 foreach (var value in temp_ref_values) {
3481 ccode.add_expression (destroy_value (value));
3484 temp_ref_values.clear ();
3487 public void emit_temp_var (LocalVariable local) {
3488 var init = (!local.name.has_prefix ("*") && local.init);
3489 if (is_in_coroutine ()) {
3490 closure_struct.add_field (get_ccode_name (local.variable_type), local.name);
3492 // even though closure struct is zerod, we need to initialize temporary variables
3493 // as they might be used multiple times when declared in a loop
3495 if (init) {
3496 var initializer = default_value_for_type (local.variable_type, false);
3497 if (initializer == null) {
3498 cfile.add_include ("string.h");
3499 var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
3500 memset_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (local.name)));
3501 memset_call.add_argument (new CCodeConstant ("0"));
3502 memset_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (local.variable_type))));
3503 ccode.add_expression (memset_call);
3504 } else {
3505 ccode.add_assignment (get_variable_cexpression (local.name), initializer);
3508 } else {
3509 var cvar = new CCodeVariableDeclarator (local.name, null, get_ccode_declarator_suffix (local.variable_type));
3510 if (init) {
3511 cvar.initializer = default_value_for_type (local.variable_type, true);
3512 cvar.init0 = true;
3514 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
3518 public override void visit_expression_statement (ExpressionStatement stmt) {
3519 if (stmt.expression.error) {
3520 stmt.error = true;
3521 return;
3524 /* free temporary objects and handle errors */
3526 foreach (var value in temp_ref_values) {
3527 ccode.add_expression (destroy_value (value));
3530 if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
3531 // simple case, no node breakdown necessary
3532 add_simple_check (stmt.expression);
3535 temp_ref_values.clear ();
3538 protected virtual void append_scope_free (Symbol sym, CodeNode? stop_at = null) {
3539 var b = (Block) sym;
3541 var local_vars = b.get_local_variables ();
3542 // free in reverse order
3543 for (int i = local_vars.size - 1; i >= 0; i--) {
3544 var local = local_vars[i];
3545 if (!local.unreachable && local.active && !local.captured && requires_destroy (local.variable_type)) {
3546 ccode.add_expression (destroy_local (local));
3550 if (b.captured) {
3551 int block_id = get_block_id (b);
3553 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
3554 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
3555 ccode.add_expression (data_unref);
3556 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
3560 public void append_local_free (Symbol sym, bool stop_at_loop = false, CodeNode? stop_at = null) {
3561 var b = (Block) sym;
3563 append_scope_free (sym, stop_at);
3565 if (stop_at_loop) {
3566 if (b.parent_node is Loop ||
3567 b.parent_node is ForeachStatement ||
3568 b.parent_node is SwitchStatement) {
3569 return;
3573 if (stop_at != null && b.parent_node == stop_at) {
3574 return;
3577 if (sym.parent_symbol is Block) {
3578 append_local_free (sym.parent_symbol, stop_at_loop, stop_at);
3579 } else if (sym.parent_symbol is Method) {
3580 append_param_free ((Method) sym.parent_symbol);
3581 } else if (sym.parent_symbol is PropertyAccessor) {
3582 var acc = (PropertyAccessor) sym.parent_symbol;
3583 if (acc.value_parameter != null && requires_destroy (acc.value_parameter.variable_type)) {
3584 ccode.add_expression (destroy_parameter (acc.value_parameter));
3589 private void append_param_free (Method m) {
3590 foreach (Parameter param in m.get_parameters ()) {
3591 if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
3592 ccode.add_expression (destroy_parameter (param));
3597 public bool variable_accessible_in_finally (LocalVariable local) {
3598 if (current_try == null) {
3599 return false;
3602 var sym = current_symbol;
3604 while (!(sym is Method || sym is PropertyAccessor) && sym.scope.lookup (local.name) == null) {
3605 if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) ||
3606 (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) {
3608 return true;
3611 sym = sym.parent_symbol;
3614 return false;
3617 public void return_out_parameter (Parameter param) {
3618 var delegate_type = param.variable_type as DelegateType;
3620 var value = get_parameter_cvalue (param);
3622 var old_coroutine = is_in_coroutine ();
3623 current_method.coroutine = false;
3625 ccode.open_if (get_variable_cexpression (param.name));
3626 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (param.name)), get_cvalue_ (value));
3628 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
3629 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_ccode_delegate_target_name (param))), get_delegate_target_cvalue (value));
3630 if (delegate_type.is_disposable ()) {
3631 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_delegate_target_destroy_notify_cname (param.name))), get_delegate_target_destroy_notify_cvalue (get_parameter_cvalue (param)));
3635 if (param.variable_type.is_disposable ()){
3636 ccode.add_else ();
3637 current_method.coroutine = old_coroutine;
3638 ccode.add_expression (destroy_parameter (param));
3639 current_method.coroutine = false;
3641 ccode.close ();
3643 var array_type = param.variable_type as ArrayType;
3644 if (array_type != null && !array_type.fixed_length && get_ccode_array_length (param)) {
3645 for (int dim = 1; dim <= array_type.rank; dim++) {
3646 ccode.open_if (get_variable_cexpression (get_parameter_array_length_cname (param, dim)));
3647 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_parameter_array_length_cname (param, dim))), get_array_length_cvalue (value, dim));
3648 ccode.close ();
3652 current_method.coroutine = old_coroutine;
3655 public override void visit_return_statement (ReturnStatement stmt) {
3656 Symbol return_expression_symbol = null;
3658 if (stmt.return_expression != null) {
3659 // avoid unnecessary ref/unref pair
3660 var local = stmt.return_expression.symbol_reference as LocalVariable;
3661 if (local != null && !local.active) {
3662 /* return expression is local variable taking ownership and
3663 * current method is transferring ownership */
3665 return_expression_symbol = local;
3669 // return array length if appropriate
3670 if (((current_method != null && get_ccode_array_length (current_method)) || current_property_accessor != null) && current_return_type is ArrayType) {
3671 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
3673 var array_type = (ArrayType) current_return_type;
3674 for (int dim = 1; dim <= array_type.rank; dim++) {
3675 var len_l = get_result_cexpression (get_array_length_cname ("result", dim));
3676 var len_r = get_array_length_cvalue (temp_value, dim);
3677 if (!is_in_coroutine ()) {
3678 ccode.open_if (len_l);
3679 len_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, len_l);
3680 ccode.add_assignment (len_l, len_r);
3681 ccode.close ();
3682 } else {
3683 ccode.add_assignment (len_l, len_r);
3687 stmt.return_expression.target_value = temp_value;
3688 } else if ((current_method != null || current_property_accessor != null) && current_return_type is DelegateType) {
3689 var delegate_type = (DelegateType) current_return_type;
3690 if (delegate_type.delegate_symbol.has_target) {
3691 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
3693 var target_l = get_result_cexpression (get_delegate_target_cname ("result"));
3694 if (!is_in_coroutine ()) {
3695 target_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l);
3697 var target_r = get_delegate_target_cvalue (temp_value);
3698 ccode.add_assignment (target_l, target_r);
3699 if (delegate_type.is_disposable ()) {
3700 var target_l_destroy_notify = get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3701 if (!is_in_coroutine ()) {
3702 target_l_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l_destroy_notify);
3704 var target_r_destroy_notify = get_delegate_target_destroy_notify_cvalue (temp_value);
3705 ccode.add_assignment (target_l_destroy_notify, target_r_destroy_notify);
3708 stmt.return_expression.target_value = temp_value;
3712 if (stmt.return_expression != null) {
3713 // assign method result to `result'
3714 CCodeExpression result_lhs = get_result_cexpression ();
3715 if (current_return_type.is_real_non_null_struct_type () && !is_in_coroutine ()) {
3716 result_lhs = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result_lhs);
3718 ccode.add_assignment (result_lhs, get_cvalue (stmt.return_expression));
3721 // free local variables
3722 append_local_free (current_symbol);
3724 if (current_method != null) {
3725 // check postconditions
3726 foreach (Expression postcondition in current_method.get_postconditions ()) {
3727 create_postcondition_statement (postcondition);
3731 if (current_method != null && !current_method.coroutine) {
3732 // assign values to output parameters if they are not NULL
3733 // otherwise, free the value if necessary
3734 foreach (var param in current_method.get_parameters ()) {
3735 if (param.direction != ParameterDirection.OUT) {
3736 continue;
3739 return_out_parameter (param);
3743 // TODO: don't duplicate the code in CCodeMethodModule, we do this right now because it needs to be before return
3744 if (current_method != null && current_method.get_attribute ("Profile") != null) {
3745 string prefix = "_vala_prof_%s".printf (get_ccode_real_name (current_method));
3747 var level = new CCodeIdentifier (prefix + "_level");
3748 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
3750 var timer = new CCodeIdentifier (prefix + "_timer");
3752 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
3753 stop_call.add_argument (timer);
3754 ccode.add_expression (stop_call);
3756 ccode.close ();
3759 if (is_in_constructor ()) {
3760 ccode.add_return (new CCodeIdentifier ("obj"));
3761 } else if (is_in_destructor ()) {
3762 // do not call return as member cleanup and chain up to base finalizer
3763 // stil need to be executed
3764 ccode.add_goto ("_return");
3765 } else if (is_in_coroutine ()) {
3766 } else if (current_method is CreationMethod) {
3767 ccode.add_return (new CCodeIdentifier ("self"));
3768 } else if (current_return_type is VoidType || current_return_type.is_real_non_null_struct_type ()) {
3769 // structs are returned via out parameter
3770 ccode.add_return ();
3771 } else {
3772 ccode.add_return (new CCodeIdentifier ("result"));
3775 if (return_expression_symbol != null) {
3776 return_expression_symbol.active = true;
3779 // required for destructors
3780 current_method_return = true;
3783 public string get_symbol_lock_name (string symname) {
3784 return "__lock_%s".printf (symname);
3787 private CCodeExpression get_lock_expression (Statement stmt, Expression resource) {
3788 CCodeExpression l = null;
3789 var inner_node = ((MemberAccess)resource).inner;
3790 var member = resource.symbol_reference;
3791 var parent = (TypeSymbol)resource.symbol_reference.parent_symbol;
3793 if (member.is_instance_member ()) {
3794 if (inner_node == null) {
3795 l = new CCodeIdentifier ("self");
3796 } else if (resource.symbol_reference.parent_symbol != current_type_symbol) {
3797 l = generate_instance_cast (get_cvalue (inner_node), parent);
3798 } else {
3799 l = get_cvalue (inner_node);
3802 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (resource.symbol_reference.name));
3803 } else if (member.is_class_member ()) {
3804 CCodeExpression klass;
3806 if (get_this_type () != null) {
3807 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3808 k.add_argument (new CCodeIdentifier ("self"));
3809 klass = k;
3810 } else {
3811 klass = new CCodeIdentifier ("klass");
3814 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(get_ccode_upper_case_name (parent))));
3815 get_class_private_call.add_argument (klass);
3816 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (resource.symbol_reference.name));
3817 } else {
3818 string lock_name = "%s_%s".printf(get_ccode_lower_case_name (parent), resource.symbol_reference.name);
3819 l = new CCodeIdentifier (get_symbol_lock_name (lock_name));
3821 return l;
3824 public override void visit_lock_statement (LockStatement stmt) {
3825 var l = get_lock_expression (stmt, stmt.resource);
3827 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("lock"))));
3828 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3830 ccode.add_expression (fc);
3833 public override void visit_unlock_statement (UnlockStatement stmt) {
3834 var l = get_lock_expression (stmt, stmt.resource);
3836 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("unlock"))));
3837 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3839 ccode.add_expression (fc);
3842 public override void visit_delete_statement (DeleteStatement stmt) {
3843 var pointer_type = (PointerType) stmt.expression.value_type;
3844 DataType type = pointer_type;
3845 if (pointer_type.base_type.data_type != null && pointer_type.base_type.data_type.is_reference_type ()) {
3846 type = pointer_type.base_type;
3849 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
3850 ccall.add_argument (get_cvalue (stmt.expression));
3851 ccode.add_expression (ccall);
3854 public override void visit_expression (Expression expr) {
3855 if (get_cvalue (expr) != null && !expr.lvalue) {
3856 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
3857 var type_parameter = ((GenericType) expr.formal_value_type).type_parameter;
3858 var st = type_parameter.parent_symbol.parent_symbol as Struct;
3859 if (type_parameter.parent_symbol != garray_type &&
3860 (st == null || get_ccode_name (st) != "va_list")) {
3861 // GArray and va_list don't use pointer-based generics
3862 set_cvalue (expr, convert_from_generic_pointer (get_cvalue (expr), expr.value_type));
3863 ((GLibValue) expr.target_value).lvalue = false;
3867 // memory management, implicit casts, and boxing/unboxing
3868 if (expr.value_type != null) {
3869 // FIXME: temporary workaround until the refactoring is complete, not all target_value have a value_type
3870 expr.target_value.value_type = expr.value_type;
3871 expr.target_value = transform_value (expr.target_value, expr.target_type, expr);
3874 if (expr.target_value == null) {
3875 return;
3878 if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
3879 if (((GenericType) expr.formal_target_type).type_parameter.parent_symbol != garray_type) {
3880 // GArray doesn't use pointer-based generics
3881 set_cvalue (expr, convert_to_generic_pointer (get_cvalue (expr), expr.target_type));
3882 ((GLibValue) expr.target_value).lvalue = false;
3886 if (!(expr.value_type is ValueType && !expr.value_type.nullable)) {
3887 ((GLibValue) expr.target_value).non_null = expr.is_non_null ();
3892 public override void visit_boolean_literal (BooleanLiteral expr) {
3893 set_cvalue (expr, new CCodeConstant (expr.value ? "TRUE" : "FALSE"));
3896 public override void visit_character_literal (CharacterLiteral expr) {
3897 if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
3898 set_cvalue (expr, new CCodeConstant (expr.value));
3899 } else {
3900 set_cvalue (expr, new CCodeConstant ("%uU".printf (expr.get_char ())));
3904 public override void visit_integer_literal (IntegerLiteral expr) {
3905 set_cvalue (expr, new CCodeConstant (expr.value + expr.type_suffix));
3908 public override void visit_real_literal (RealLiteral expr) {
3909 string c_literal = expr.value;
3910 if (c_literal.has_suffix ("d") || c_literal.has_suffix ("D")) {
3911 // there is no suffix for double in C
3912 c_literal = c_literal.substring (0, c_literal.length - 1);
3914 if (!("." in c_literal || "e" in c_literal || "E" in c_literal)) {
3915 // C requires period or exponent part for floating constants
3916 if ("f" in c_literal || "F" in c_literal) {
3917 c_literal = c_literal.substring (0, c_literal.length - 1) + ".f";
3918 } else {
3919 c_literal += ".";
3922 set_cvalue (expr, new CCodeConstant (c_literal));
3925 public override void visit_string_literal (StringLiteral expr) {
3926 set_cvalue (expr, new CCodeConstant.string (expr.value.replace ("\n", "\\n")));
3928 if (expr.translate) {
3929 // translated string constant
3931 var m = (Method) root_symbol.scope.lookup ("GLib").scope.lookup ("_");
3932 add_symbol_declaration (cfile, m, get_ccode_name (m));
3934 var translate = new CCodeFunctionCall (new CCodeIdentifier ("_"));
3935 translate.add_argument (get_cvalue (expr));
3936 set_cvalue (expr, translate);
3940 public override void visit_regex_literal (RegexLiteral expr) {
3941 string[] parts = expr.value.split ("/", 3);
3942 string re = parts[2].escape ("");
3943 string flags = "0";
3945 if (parts[1].contains ("i")) {
3946 flags += " | G_REGEX_CASELESS";
3948 if (parts[1].contains ("m")) {
3949 flags += " | G_REGEX_MULTILINE";
3951 if (parts[1].contains ("s")) {
3952 flags += " | G_REGEX_DOTALL";
3954 if (parts[1].contains ("x")) {
3955 flags += " | G_REGEX_EXTENDED";
3958 var cdecl = new CCodeDeclaration ("GRegex*");
3960 var cname = "_tmp_regex_%d".printf (next_regex_id);
3961 if (this.next_regex_id == 0) {
3962 var fun = new CCodeFunction ("_thread_safe_regex_init", "GRegex*");
3963 fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
3964 fun.add_parameter (new CCodeParameter ("re", "GRegex**"));
3965 fun.add_parameter (new CCodeParameter ("pattern", "const gchar *"));
3966 fun.add_parameter (new CCodeParameter ("match_options", "GRegexMatchFlags"));
3968 push_function (fun);
3970 var once_enter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
3971 once_enter_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
3972 ccode.open_if (once_enter_call);
3974 var regex_new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_regex_new"));
3975 regex_new_call.add_argument (new CCodeConstant ("pattern"));
3976 regex_new_call.add_argument (new CCodeConstant ("match_options"));
3977 regex_new_call.add_argument (new CCodeConstant ("0"));
3978 regex_new_call.add_argument (new CCodeConstant ("NULL"));
3979 ccode.add_assignment (new CCodeIdentifier ("GRegex* val"), regex_new_call);
3981 var once_leave_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
3982 once_leave_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
3983 once_leave_call.add_argument (new CCodeConstant ("(gsize) val"));
3984 ccode.add_expression (once_leave_call);
3986 ccode.close ();
3988 ccode.add_return (new CCodeIdentifier ("*re"));
3990 pop_function ();
3992 cfile.add_function (fun);
3994 this.next_regex_id++;
3996 cdecl.add_declarator (new CCodeVariableDeclarator (cname + " = NULL"));
3997 cdecl.modifiers = CCodeModifiers.STATIC;
3999 var regex_const = new CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname, re, flags));
4001 cfile.add_constant_declaration (cdecl);
4002 set_cvalue (expr, regex_const);
4005 public override void visit_null_literal (NullLiteral expr) {
4006 set_cvalue (expr, new CCodeConstant ("NULL"));
4008 var array_type = expr.target_type as ArrayType;
4009 var delegate_type = expr.target_type as DelegateType;
4010 if (array_type != null) {
4011 for (int dim = 1; dim <= array_type.rank; dim++) {
4012 append_array_length (expr, new CCodeConstant ("0"));
4014 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
4015 set_delegate_target (expr, new CCodeConstant ("NULL"));
4016 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
4020 public abstract TargetValue get_local_cvalue (LocalVariable local);
4022 public abstract TargetValue get_parameter_cvalue (Parameter param);
4024 public abstract TargetValue get_field_cvalue (Field field, TargetValue? instance);
4026 public abstract TargetValue load_variable (Variable variable, TargetValue value);
4028 public abstract TargetValue load_this_parameter (TypeSymbol sym);
4030 public abstract void store_value (TargetValue lvalue, TargetValue value, SourceReference? source_reference = null);
4032 public virtual string get_delegate_target_cname (string delegate_cname) {
4033 assert_not_reached ();
4036 public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
4037 assert_not_reached ();
4040 public virtual CCodeExpression get_delegate_target_cvalue (TargetValue value) {
4041 return new CCodeInvalidExpression ();
4044 public virtual CCodeExpression get_delegate_target_destroy_notify_cvalue (TargetValue value) {
4045 return new CCodeInvalidExpression ();
4048 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname) {
4049 assert_not_reached ();
4052 public override void visit_base_access (BaseAccess expr) {
4053 CCodeExpression this_access;
4054 if (is_in_coroutine ()) {
4055 // use closure
4056 this_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
4057 } else {
4058 this_access = new CCodeIdentifier ("self");
4061 set_cvalue (expr, generate_instance_cast (this_access, expr.value_type.data_type));
4064 public override void visit_postfix_expression (PostfixExpression expr) {
4065 MemberAccess ma = find_property_access (expr.inner);
4066 if (ma != null) {
4067 // property postfix expression
4068 var prop = (Property) ma.symbol_reference;
4070 // increment/decrement property
4071 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4072 var cexpr = new CCodeBinaryExpression (op, get_cvalue (expr.inner), new CCodeConstant ("1"));
4073 store_property (prop, ma.inner, new GLibValue (expr.value_type, cexpr));
4075 // return previous value
4076 expr.target_value = expr.inner.target_value;
4077 return;
4080 // assign current value to temp variable
4081 var temp_value = store_temp_value (expr.inner.target_value, expr);
4083 // increment/decrement variable
4084 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4085 var cexpr = new CCodeBinaryExpression (op, get_cvalue_ (temp_value), new CCodeConstant ("1"));
4086 ccode.add_assignment (get_cvalue (expr.inner), cexpr);
4088 // return previous value
4089 expr.target_value = temp_value;
4092 private MemberAccess? find_property_access (Expression expr) {
4093 if (!(expr is MemberAccess)) {
4094 return null;
4097 var ma = (MemberAccess) expr;
4098 if (ma.symbol_reference is Property) {
4099 return ma;
4102 return null;
4105 bool is_limited_generic_type (GenericType type) {
4106 var cl = type.type_parameter.parent_symbol as Class;
4107 var st = type.type_parameter.parent_symbol as Struct;
4108 if ((cl != null && cl.is_compact) || st != null) {
4109 // compact classes and structs only
4110 // have very limited generics support
4111 return true;
4113 return false;
4116 public bool requires_copy (DataType type) {
4117 if (!type.is_disposable ()) {
4118 return false;
4121 var cl = type.data_type as Class;
4122 if (cl != null && is_reference_counting (cl)
4123 && get_ccode_ref_function (cl) == "") {
4124 // empty ref_function => no ref necessary
4125 return false;
4128 if (type is GenericType) {
4129 if (is_limited_generic_type ((GenericType) type)) {
4130 return false;
4134 return true;
4137 public bool requires_destroy (DataType type) {
4138 if (!type.is_disposable ()) {
4139 return false;
4142 var array_type = type as ArrayType;
4143 if (array_type != null && array_type.fixed_length) {
4144 return requires_destroy (array_type.element_type);
4147 var cl = type.data_type as Class;
4148 if (cl != null && is_reference_counting (cl)
4149 && get_ccode_unref_function (cl) == "") {
4150 // empty unref_function => no unref necessary
4151 return false;
4154 if (type is GenericType) {
4155 if (is_limited_generic_type ((GenericType) type)) {
4156 return false;
4160 return true;
4163 bool is_ref_function_void (DataType type) {
4164 var cl = type.data_type as Class;
4165 if (cl != null) {
4166 return get_ccode_ref_function_void (cl);
4167 } else {
4168 return false;
4172 bool is_free_function_address_of (DataType type) {
4173 var cl = type.data_type as Class;
4174 if (cl != null) {
4175 return get_ccode_free_function_address_of (cl);
4176 } else {
4177 return false;
4181 public virtual TargetValue? copy_value (TargetValue value, CodeNode node) {
4182 var type = value.value_type;
4183 var cexpr = get_cvalue_ (value);
4184 var result = ((GLibValue) value).copy ();
4186 if (type is DelegateType) {
4187 var delegate_type = (DelegateType) type;
4188 if (delegate_type.delegate_symbol.has_target && !context.deprecated) {
4189 Report.deprecated (node.source_reference, "copying delegates is not supported");
4191 result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
4192 return result;
4195 if (type is ValueType && !type.nullable) {
4196 // normal value type, no null check
4198 var temp_value = create_temp_value (type, true, node, true);
4199 var ctemp = get_cvalue_ (temp_value);
4201 var vt = (ValueType) type;
4202 var st = (Struct) vt.type_symbol;
4203 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
4204 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4205 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4207 if (!get_ccode_has_copy_function (st)) {
4208 generate_struct_copy_function (st);
4211 if (gvalue_type != null && type.data_type == gvalue_type) {
4212 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
4213 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4215 ccode.open_if (cisvalid);
4217 // GValue requires g_value_init in addition to g_value_copy
4218 var value_type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
4219 value_type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4221 var init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
4222 init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4223 init_call.add_argument (value_type_call);
4224 ccode.add_expression (init_call);
4225 ccode.add_expression (copy_call);
4227 ccode.add_else ();
4229 // g_value_init/copy must not be called for uninitialized values
4230 store_value (temp_value, value, node.source_reference);
4231 ccode.close ();
4232 } else {
4233 ccode.add_expression (copy_call);
4236 return temp_value;
4239 /* (temp = expr, temp == NULL ? NULL : ref (temp))
4241 * can be simplified to
4242 * ref (expr)
4243 * if static type of expr is non-null
4246 var dupexpr = get_dup_func_expression (type, node.source_reference);
4248 if (dupexpr == null) {
4249 node.error = true;
4250 return null;
4253 if (dupexpr is CCodeIdentifier && !(type is ArrayType) && !(type is GenericType) && !is_ref_function_void (type)) {
4254 // generate and call NULL-aware ref function to reduce number
4255 // of temporary variables and simplify code
4257 var dupid = (CCodeIdentifier) dupexpr;
4258 string dup0_func = "_%s0".printf (dupid.name);
4260 // g_strdup is already NULL-safe
4261 if (dupid.name == "g_strdup") {
4262 dup0_func = dupid.name;
4263 } else if (add_wrapper (dup0_func)) {
4264 string pointer_cname = "gpointer";
4265 var dup0_fun = new CCodeFunction (dup0_func, pointer_cname);
4266 dup0_fun.add_parameter (new CCodeParameter ("self", pointer_cname));
4267 dup0_fun.modifiers = CCodeModifiers.STATIC;
4269 push_function (dup0_fun);
4271 var dup_call = new CCodeFunctionCall (dupexpr);
4272 dup_call.add_argument (new CCodeIdentifier ("self"));
4274 ccode.add_return (new CCodeConditionalExpression (new CCodeIdentifier ("self"), dup_call, new CCodeConstant ("NULL")));
4276 pop_function ();
4278 cfile.add_function (dup0_fun);
4281 var ccall = new CCodeFunctionCall (new CCodeIdentifier (dup0_func));
4282 ccall.add_argument (cexpr);
4283 result.cvalue = ccall;
4284 result.value_type.value_owned = true;
4285 return store_temp_value (result, node);
4288 var ccall = new CCodeFunctionCall (dupexpr);
4290 if (!(type is ArrayType) && get_non_null (value) && !is_ref_function_void (type)) {
4291 // expression is non-null
4292 ccall.add_argument (cexpr);
4294 return store_temp_value (new GLibValue (type, ccall), node);
4295 } else {
4296 var cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cexpr, new CCodeConstant ("NULL"));
4297 if (type is GenericType) {
4298 // dup functions are optional for type parameters
4299 var cdupnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_dup_func_expression (type, node.source_reference), new CCodeConstant ("NULL"));
4300 cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.AND, cnotnull, cdupnotnull);
4303 if (type is GenericType) {
4304 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
4305 ccall.add_argument (new CCodeCastExpression (cexpr, "gpointer"));
4306 } else {
4307 ccall.add_argument (cexpr);
4310 if (type is ArrayType) {
4311 var array_type = (ArrayType) type;
4312 ccall.add_argument (get_array_length_cvalue (value));
4314 if (array_type.element_type is GenericType) {
4315 var elem_dupexpr = get_dup_func_expression (array_type.element_type, node.source_reference);
4316 if (elem_dupexpr == null) {
4317 elem_dupexpr = new CCodeConstant ("NULL");
4319 ccall.add_argument (elem_dupexpr);
4323 CCodeExpression cifnull;
4324 if (type.data_type != null) {
4325 cifnull = new CCodeConstant ("NULL");
4326 } else {
4327 // the value might be non-null even when the dup function is null,
4328 // so we may not just use NULL for type parameters
4330 // cast from gconstpointer to gpointer as methods in
4331 // generic classes may not return gconstpointer
4332 cifnull = new CCodeCastExpression (cexpr, "gpointer");
4335 if (is_ref_function_void (type)) {
4336 ccode.open_if (cnotnull);
4337 ccode.add_expression (ccall);
4338 ccode.close ();
4339 } else {
4340 var ccond = new CCodeConditionalExpression (cnotnull, ccall, cifnull);
4341 result.cvalue = ccond;
4342 result = (GLibValue) store_temp_value (result, node, true);
4344 return result;
4348 bool is_reference_type_argument (DataType type_arg) {
4349 if (type_arg is ErrorType || (type_arg.data_type != null && type_arg.data_type.is_reference_type ())) {
4350 return true;
4351 } else {
4352 return false;
4356 bool is_nullable_value_type_argument (DataType type_arg) {
4357 if (type_arg is ValueType && type_arg.nullable) {
4358 return true;
4359 } else {
4360 return false;
4364 bool is_signed_integer_type_argument (DataType type_arg) {
4365 var st = type_arg.data_type as Struct;
4366 if (type_arg is EnumValueType) {
4367 return true;
4368 } else if (type_arg.nullable) {
4369 return false;
4370 } else if (st == null) {
4371 return false;
4372 } else if (st.is_subtype_of (bool_type.data_type)) {
4373 return true;
4374 } else if (st.is_subtype_of (char_type.data_type)) {
4375 return true;
4376 } else if (unichar_type != null && st.is_subtype_of (unichar_type.data_type)) {
4377 return true;
4378 } else if (st.is_subtype_of (short_type.data_type)) {
4379 return true;
4380 } else if (st.is_subtype_of (int_type.data_type)) {
4381 return true;
4382 } else if (st.is_subtype_of (long_type.data_type)) {
4383 return true;
4384 } else if (st.is_subtype_of (int8_type.data_type)) {
4385 return true;
4386 } else if (st.is_subtype_of (int16_type.data_type)) {
4387 return true;
4388 } else if (st.is_subtype_of (int32_type.data_type)) {
4389 return true;
4390 } else if (st.is_subtype_of (gtype_type)) {
4391 return true;
4392 } else {
4393 return false;
4397 bool is_unsigned_integer_type_argument (DataType type_arg) {
4398 var st = type_arg.data_type as Struct;
4399 if (st == null) {
4400 return false;
4401 } else if (type_arg.nullable) {
4402 return false;
4403 } else if (st.is_subtype_of (uchar_type.data_type)) {
4404 return true;
4405 } else if (st.is_subtype_of (ushort_type.data_type)) {
4406 return true;
4407 } else if (st.is_subtype_of (uint_type.data_type)) {
4408 return true;
4409 } else if (st.is_subtype_of (ulong_type.data_type)) {
4410 return true;
4411 } else if (st.is_subtype_of (uint8_type.data_type)) {
4412 return true;
4413 } else if (st.is_subtype_of (uint16_type.data_type)) {
4414 return true;
4415 } else if (st.is_subtype_of (uint32_type.data_type)) {
4416 return true;
4417 } else {
4418 return false;
4422 public void check_type (DataType type) {
4423 var array_type = type as ArrayType;
4424 if (array_type != null) {
4425 check_type (array_type.element_type);
4426 if (array_type.element_type is ArrayType) {
4427 Report.error (type.source_reference, "Stacked arrays are not supported");
4428 } else if (array_type.element_type is DelegateType) {
4429 var delegate_type = (DelegateType) array_type.element_type;
4430 if (delegate_type.delegate_symbol.has_target) {
4431 Report.error (type.source_reference, "Delegates with target are not supported as array element type");
4435 foreach (var type_arg in type.get_type_arguments ()) {
4436 check_type (type_arg);
4437 check_type_argument (type_arg);
4441 public void check_type_arguments (MemberAccess access) {
4442 foreach (var type_arg in access.get_type_arguments ()) {
4443 check_type (type_arg);
4444 check_type_argument (type_arg);
4448 void check_type_argument (DataType type_arg) {
4449 if (type_arg is GenericType
4450 || type_arg is PointerType
4451 || is_reference_type_argument (type_arg)
4452 || is_nullable_value_type_argument (type_arg)
4453 || is_signed_integer_type_argument (type_arg)
4454 || is_unsigned_integer_type_argument (type_arg)) {
4455 // no error
4456 } else if (type_arg is DelegateType) {
4457 var delegate_type = (DelegateType) type_arg;
4458 if (delegate_type.delegate_symbol.has_target) {
4459 Report.error (type_arg.source_reference, "Delegates with target are not supported as generic type arguments");
4461 } else {
4462 Report.error (type_arg.source_reference, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg.to_string ()));
4466 public virtual void generate_class_declaration (Class cl, CCodeFile decl_space) {
4467 if (add_symbol_declaration (decl_space, cl, get_ccode_name (cl))) {
4468 return;
4472 public virtual void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
4475 public virtual void generate_method_declaration (Method m, CCodeFile decl_space) {
4478 public virtual void generate_error_domain_declaration (ErrorDomain edomain, CCodeFile decl_space) {
4481 public void add_generic_type_arguments (Map<int,CCodeExpression> arg_map, List<DataType> type_args, CodeNode expr, bool is_chainup = false, List<TypeParameter>? type_parameters = null) {
4482 int type_param_index = 0;
4483 foreach (var type_arg in type_args) {
4484 if (type_parameters != null) {
4485 var type_param_name = type_parameters.get (type_param_index).name.down ();
4486 arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s_type\"".printf (type_param_name)));
4487 arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("\"%s_dup_func\"".printf (type_param_name)));
4488 arg_map.set (get_param_pos (0.1 * type_param_index + 0.05), new CCodeConstant ("\"%s_destroy_func\"".printf (type_param_name)));
4491 arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), get_type_id_expression (type_arg, is_chainup));
4492 if (requires_copy (type_arg)) {
4493 var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference, is_chainup);
4494 if (dup_func == null) {
4495 // type doesn't contain a copy function
4496 expr.error = true;
4497 return;
4499 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
4500 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeCastExpression (get_destroy_func_expression (type_arg, is_chainup), "GDestroyNotify"));
4501 } else {
4502 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeConstant ("NULL"));
4503 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeConstant ("NULL"));
4505 type_param_index++;
4509 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
4510 CCodeExpression instance = null;
4511 CCodeExpression creation_expr = null;
4513 check_type (expr.type_reference);
4515 var st = expr.type_reference.data_type as Struct;
4516 if ((st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list")) || expr.get_object_initializer ().size > 0) {
4517 // value-type initialization or object creation expression with object initializer
4519 var local = expr.parent_node as LocalVariable;
4520 var field = expr.parent_node as Field;
4521 var a = expr.parent_node as Assignment;
4522 if (local != null && is_simple_struct_creation (local, local.initializer)) {
4523 instance = get_cvalue_ (get_local_cvalue (local));
4524 } else if (field != null && is_simple_struct_creation (field, field.initializer)) {
4525 // field initialization
4526 var thisparam = load_this_parameter ((TypeSymbol) field.parent_symbol);
4527 instance = get_cvalue_ (get_field_cvalue (field, thisparam));
4528 } else if (a != null && a.left.symbol_reference is Variable && is_simple_struct_creation ((Variable) a.left.symbol_reference, a.right)) {
4529 if (requires_destroy (a.left.value_type)) {
4530 /* unref old value */
4531 ccode.add_expression (destroy_value (a.left.target_value));
4534 local = a.left.symbol_reference as LocalVariable;
4535 field = a.left.symbol_reference as Field;
4536 var param = a.left.symbol_reference as Parameter;
4537 if (local != null) {
4538 instance = get_cvalue_ (get_local_cvalue (local));
4539 } else if (field != null) {
4540 var inner = ((MemberAccess) a.left).inner;
4541 instance = get_cvalue_ (get_field_cvalue (field, inner != null ? inner.target_value : null));
4542 } else if (param != null) {
4543 instance = get_cvalue_ (get_parameter_cvalue (param));
4545 } else {
4546 var temp_value = create_temp_value (expr.type_reference, true, expr);
4547 instance = get_cvalue_ (temp_value);
4551 if (expr.symbol_reference == null) {
4552 // no creation method
4553 if (expr.type_reference.data_type is Struct) {
4554 // memset needs string.h
4555 cfile.add_include ("string.h");
4556 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4557 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4558 creation_call.add_argument (new CCodeConstant ("0"));
4559 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.type_reference))));
4561 creation_expr = creation_call;
4563 } else if (expr.type_reference.data_type == glist_type ||
4564 expr.type_reference.data_type == gslist_type) {
4565 // NULL is an empty list
4566 set_cvalue (expr, new CCodeConstant ("NULL"));
4567 } else if (expr.symbol_reference is Method) {
4568 // use creation method
4569 var m = (Method) expr.symbol_reference;
4570 var params = m.get_parameters ();
4571 CCodeFunctionCall creation_call;
4573 CCodeFunctionCall async_call = null;
4574 CCodeFunctionCall finish_call = null;
4576 generate_method_declaration (m, cfile);
4578 var cl = expr.type_reference.data_type as Class;
4580 if (!get_ccode_has_new_function (m)) {
4581 // use construct function directly
4582 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
4583 creation_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
4584 } else {
4585 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
4588 if ((st != null && !st.is_simple_type ()) && !(get_ccode_instance_pos (m) < 0)) {
4589 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4590 } else if (st != null && get_ccode_name (st) == "va_list") {
4591 creation_call.add_argument (instance);
4592 if (get_ccode_name (m) == "va_start") {
4593 if (in_creation_method) {
4594 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("va_copy"));
4595 creation_call.add_argument (instance);
4596 creation_call.add_argument (new CCodeIdentifier ("_vala_va_list"));
4597 } else {
4598 Parameter last_param = null;
4599 // FIXME: this doesn't take into account exception handling parameters
4600 foreach (var param in current_method.get_parameters ()) {
4601 if (param.ellipsis) {
4602 break;
4604 last_param = param;
4606 int nParams = ccode.get_parameter_count ();
4607 if (nParams == 0 || !ccode.get_parameter (nParams - 1).ellipsis) {
4608 Report.error (expr.source_reference, "`va_list' used in method with fixed args");
4609 } else if (nParams == 1) {
4610 Report.error (expr.source_reference, "`va_list' used in method without parameter");
4611 } else {
4612 creation_call.add_argument (new CCodeIdentifier (ccode.get_parameter (nParams - 2).name));
4618 generate_type_declaration (expr.type_reference, cfile);
4620 var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
4621 var out_arg_map = in_arg_map;
4623 if (m != null && m.coroutine) {
4624 // async call
4626 async_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
4627 finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
4629 creation_call = finish_call;
4631 // output arguments used separately
4632 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
4633 // pass GAsyncResult stored in closure to finish function
4634 out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
4637 if (cl != null && !cl.is_compact) {
4638 add_generic_type_arguments (in_arg_map, expr.type_reference.get_type_arguments (), expr);
4639 } else if (cl != null && get_ccode_simple_generics (m)) {
4640 int type_param_index = 0;
4641 foreach (var type_arg in expr.type_reference.get_type_arguments ()) {
4642 if (requires_copy (type_arg)) {
4643 in_arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), get_destroy0_func_expression (type_arg));
4644 } else {
4645 in_arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
4647 type_param_index++;
4651 bool ellipsis = false;
4653 int i = 1;
4654 int arg_pos;
4655 Iterator<Parameter> params_it = params.iterator ();
4656 foreach (Expression arg in expr.get_argument_list ()) {
4657 CCodeExpression cexpr = get_cvalue (arg);
4659 var carg_map = in_arg_map;
4661 Parameter param = null;
4662 if (params_it.next ()) {
4663 param = params_it.get ();
4664 ellipsis = param.ellipsis;
4665 if (!ellipsis) {
4666 if (param.direction == ParameterDirection.OUT) {
4667 carg_map = out_arg_map;
4670 // g_array_new: element size
4671 if (cl == garray_type && param.name == "element_size") {
4672 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
4673 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference.get_type_arguments ().get (0))));
4674 cexpr = csizeof;
4677 if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
4678 var array_type = (ArrayType) param.variable_type;
4679 for (int dim = 1; dim <= array_type.rank; dim++) {
4680 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_array_length_cexpression (arg, dim));
4682 } else if (param.variable_type is DelegateType) {
4683 var deleg_type = (DelegateType) param.variable_type;
4684 var d = deleg_type.delegate_symbol;
4685 if (d.has_target) {
4686 CCodeExpression delegate_target_destroy_notify;
4687 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
4688 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
4689 if (deleg_type.is_disposable ()) {
4690 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param) + 0.01), delegate_target_destroy_notify);
4695 cexpr = handle_struct_argument (param, arg, cexpr);
4697 if (get_ccode_type (param) != null) {
4698 cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
4700 } else {
4701 cexpr = handle_struct_argument (null, arg, cexpr);
4704 arg_pos = get_param_pos (get_ccode_pos (param), ellipsis);
4705 } else {
4706 // default argument position
4707 cexpr = handle_struct_argument (null, arg, cexpr);
4708 arg_pos = get_param_pos (i, ellipsis);
4711 carg_map.set (arg_pos, cexpr);
4713 i++;
4715 if (params_it.next ()) {
4716 var param = params_it.get ();
4718 /* if there are more parameters than arguments,
4719 * the additional parameter is an ellipsis parameter
4720 * otherwise there is a bug in the semantic analyzer
4722 assert (param.params_array || param.ellipsis);
4723 ellipsis = true;
4726 if (expr.tree_can_fail) {
4727 // method can fail
4728 current_method_inner_error = true;
4729 // add &inner_error before the ellipsis arguments
4730 out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
4733 if (ellipsis) {
4734 /* ensure variable argument list ends with NULL
4735 * except when using printf-style arguments */
4736 if (m == null) {
4737 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
4738 } else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "") {
4739 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
4743 if ((st != null && !st.is_simple_type ()) && get_ccode_instance_pos (m) < 0) {
4744 // instance parameter is at the end in a struct creation method
4745 out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4748 if (m != null && m.coroutine) {
4749 if (expr.is_yield_expression) {
4750 // asynchronous call
4751 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
4752 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
4756 if (m != null && m.parent_symbol is Class) {
4757 if (get_ccode_finish_instance (m)) {
4758 var tmp = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_source_object_");
4759 out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), tmp);
4763 // append C arguments in the right order
4765 int last_pos;
4766 int min_pos;
4768 if (async_call != creation_call) {
4769 // don't append out arguments for .begin() calls
4770 last_pos = -1;
4771 while (true) {
4772 min_pos = -1;
4773 foreach (int pos in out_arg_map.get_keys ()) {
4774 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
4775 min_pos = pos;
4778 if (min_pos == -1) {
4779 break;
4781 creation_call.add_argument (out_arg_map.get (min_pos));
4782 last_pos = min_pos;
4786 if (async_call != null) {
4787 last_pos = -1;
4788 while (true) {
4789 min_pos = -1;
4790 foreach (int pos in in_arg_map.get_keys ()) {
4791 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
4792 min_pos = pos;
4795 if (min_pos == -1) {
4796 break;
4798 async_call.add_argument (in_arg_map.get (min_pos));
4799 last_pos = min_pos;
4803 if (expr.is_yield_expression) {
4804 // set state before calling async function to support immediate callbacks
4805 int state = emit_context.next_coroutine_state++;
4807 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
4808 ccode.add_expression (async_call);
4809 ccode.add_return (new CCodeConstant ("FALSE"));
4810 ccode.add_label ("_state_%d".printf (state));
4813 creation_expr = creation_call;
4815 // cast the return value of the creation method back to the intended type if
4816 // it requested a special C return type
4817 if (get_ccode_type (m) != null) {
4818 creation_expr = new CCodeCastExpression (creation_expr, get_ccode_name (expr.type_reference));
4820 } else if (expr.symbol_reference is ErrorCode) {
4821 var ecode = (ErrorCode) expr.symbol_reference;
4822 var edomain = (ErrorDomain) ecode.parent_symbol;
4823 CCodeFunctionCall creation_call;
4825 generate_error_domain_declaration (edomain, cfile);
4827 if (expr.get_argument_list ().size == 1) {
4828 // must not be a format argument
4829 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new_literal"));
4830 } else {
4831 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new"));
4833 creation_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (edomain)));
4834 creation_call.add_argument (new CCodeIdentifier (get_ccode_name (ecode)));
4836 foreach (Expression arg in expr.get_argument_list ()) {
4837 creation_call.add_argument (get_cvalue (arg));
4840 creation_expr = creation_call;
4841 } else {
4842 assert (false);
4845 var local = expr.parent_node as LocalVariable;
4846 if (local != null && is_simple_struct_creation (local, local.initializer)) {
4847 // no temporary variable necessary
4848 ccode.add_expression (creation_expr);
4849 set_cvalue (expr, instance);
4850 } else if (instance != null) {
4851 if (expr.type_reference.data_type is Struct) {
4852 ccode.add_expression (creation_expr);
4853 } else {
4854 ccode.add_assignment (instance, creation_expr);
4857 foreach (MemberInitializer init in expr.get_object_initializer ()) {
4858 if (init.symbol_reference is Field) {
4859 var f = (Field) init.symbol_reference;
4860 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
4861 var typed_inst = transform_value (new GLibValue (expr.type_reference, instance, true), instance_target_type, init);
4862 store_field (f, typed_inst, init.initializer.target_value);
4864 var cl = f.parent_symbol as Class;
4865 if (cl != null) {
4866 generate_class_struct_declaration (cl, cfile);
4868 } else if (init.symbol_reference is Property) {
4869 var inst_ma = new MemberAccess.simple ("new");
4870 inst_ma.value_type = expr.type_reference;
4871 set_cvalue (inst_ma, instance);
4872 store_property ((Property) init.symbol_reference, inst_ma, init.initializer.target_value);
4873 // FIXME Do not ref/copy in the first place
4874 if (requires_destroy (init.initializer.target_value.value_type)) {
4875 ccode.add_expression (destroy_value (init.initializer.target_value));
4880 set_cvalue (expr, instance);
4881 } else if (creation_expr != null) {
4882 var temp_value = create_temp_value (expr.value_type, false, expr);
4883 ccode.add_assignment (get_cvalue_ (temp_value), creation_expr);
4884 expr.target_value = temp_value;
4886 if (context.gobject_tracing) {
4887 // GObject creation tracing enabled
4889 var cl = expr.type_reference.data_type as Class;
4890 if (cl != null && cl.is_subtype_of (gobject_type)) {
4891 // creating GObject
4893 // instance can be NULL in error cases
4894 ccode.open_if (get_cvalue_ (expr.target_value));
4896 var set_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set_data"));
4897 set_data_call.add_argument (new CCodeCastExpression (get_cvalue_ (expr.target_value), "GObject *"));
4898 set_data_call.add_argument (new CCodeConstant ("\"vala-creation-function\""));
4900 string func_name = "";
4901 if (current_method != null) {
4902 func_name = current_method.get_full_name ();
4903 } else if (current_property_accessor != null) {
4904 func_name = current_property_accessor.get_full_name ();
4907 set_data_call.add_argument (new CCodeConstant ("\"%s\"".printf (func_name)));
4909 ccode.add_expression (set_data_call);
4911 ccode.close ();
4916 ((GLibValue) expr.target_value).lvalue = true;
4919 public CCodeExpression? handle_struct_argument (Parameter? param, Expression arg, CCodeExpression? cexpr) {
4920 DataType type;
4921 if (param != null) {
4922 type = param.variable_type;
4923 } else {
4924 // varargs
4925 type = arg.value_type;
4928 var unary = arg as UnaryExpression;
4929 // pass non-simple struct instances always by reference
4930 if (!(arg.value_type is NullType) && type.is_real_struct_type ()) {
4931 // we already use a reference for arguments of ref, out, and nullable parameters
4932 if (!(unary != null && (unary.operator == UnaryOperator.OUT || unary.operator == UnaryOperator.REF)) && !type.nullable) {
4933 if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
4934 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
4935 } else {
4936 // if cexpr is e.g. a function call, we can't take the address of the expression
4937 var temp_value = create_temp_value (type, false, arg);
4938 ccode.add_assignment (get_cvalue_ (temp_value), cexpr);
4939 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value));
4944 return cexpr;
4947 public override void visit_sizeof_expression (SizeofExpression expr) {
4948 generate_type_declaration (expr.type_reference, cfile);
4950 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
4951 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference)));
4952 set_cvalue (expr, csizeof);
4955 public override void visit_typeof_expression (TypeofExpression expr) {
4956 set_cvalue (expr, get_type_id_expression (expr.type_reference));
4959 public override void visit_unary_expression (UnaryExpression expr) {
4960 if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) {
4961 var glib_value = (GLibValue) expr.inner.target_value;
4963 var ref_value = new GLibValue (glib_value.value_type);
4964 if (expr.target_type != null && glib_value.value_type.is_real_struct_type () && glib_value.value_type.nullable != expr.target_type.nullable) {
4965 // the only possibility is that value_type is nullable and target_type is non-nullable
4966 ref_value.cvalue = glib_value.cvalue;
4967 } else {
4968 ref_value.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.cvalue);
4971 if (glib_value.array_length_cvalues != null) {
4972 for (int i = 0; i < glib_value.array_length_cvalues.size; i++) {
4973 ref_value.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.array_length_cvalues[i]));
4977 if (glib_value.delegate_target_cvalue != null) {
4978 ref_value.delegate_target_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_cvalue);
4980 if (glib_value.delegate_target_destroy_notify_cvalue != null) {
4981 ref_value.delegate_target_destroy_notify_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_destroy_notify_cvalue);
4984 expr.target_value = ref_value;
4985 return;
4988 CCodeUnaryOperator op;
4989 if (expr.operator == UnaryOperator.PLUS) {
4990 op = CCodeUnaryOperator.PLUS;
4991 } else if (expr.operator == UnaryOperator.MINUS) {
4992 op = CCodeUnaryOperator.MINUS;
4993 } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
4994 op = CCodeUnaryOperator.LOGICAL_NEGATION;
4995 } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
4996 op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
4997 } else if (expr.operator == UnaryOperator.INCREMENT) {
4998 op = CCodeUnaryOperator.PREFIX_INCREMENT;
4999 } else if (expr.operator == UnaryOperator.DECREMENT) {
5000 op = CCodeUnaryOperator.PREFIX_DECREMENT;
5001 } else {
5002 assert_not_reached ();
5004 set_cvalue (expr, new CCodeUnaryExpression (op, get_cvalue (expr.inner)));
5007 public CCodeExpression? try_cast_value_to_type (CCodeExpression ccodeexpr, DataType from, DataType to, Expression? expr = null) {
5008 if (from == null || gvalue_type == null || from.data_type != gvalue_type || to.data_type == gvalue_type || get_ccode_type_id (to) == "") {
5009 return null;
5012 // explicit conversion from GValue
5013 var ccall = new CCodeFunctionCall (get_value_getter_function (to));
5014 CCodeExpression gvalue;
5015 if (from.nullable) {
5016 gvalue = ccodeexpr;
5017 } else {
5018 gvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ccodeexpr);
5020 ccall.add_argument (gvalue);
5022 CCodeExpression rv = ccall;
5024 if (expr != null && to is ArrayType) {
5025 // null-terminated string array
5026 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
5027 len_call.add_argument (rv);
5028 append_array_length (expr, len_call);
5029 } else if (to is StructValueType) {
5030 CodeNode node = expr != null ? (CodeNode) expr : to;
5031 var temp_value = create_temp_value (to, true, node, true);
5032 var ctemp = get_cvalue_ (temp_value);
5034 rv = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeCastExpression (rv, get_ccode_name (new PointerType (to))));
5035 var holds = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_HOLDS"));
5036 holds.add_argument (gvalue);
5037 holds.add_argument (new CCodeIdentifier (get_ccode_type_id (to)));
5038 var cond = new CCodeBinaryExpression (CCodeBinaryOperator.AND, holds, ccall);
5039 var warn = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
5040 warn.add_argument (new CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
5041 var fail = new CCodeCommaExpression ();
5042 fail.append_expression (warn);
5043 fail.append_expression (ctemp);
5044 rv = new CCodeConditionalExpression (cond, rv, fail);
5047 return rv;
5050 int next_variant_function_id = 0;
5052 public TargetValue? try_cast_variant_to_type (TargetValue value, DataType to, CodeNode? node = null) {
5053 if (value.value_type == null || gvariant_type == null || value.value_type.data_type != gvariant_type) {
5054 return null;
5057 string variant_func = "_variant_get%d".printf (++next_variant_function_id);
5059 var variant = value;
5060 if (value.value_type.value_owned) {
5061 // value leaked, destroy it
5062 var temp_value = store_temp_value (value, node);
5063 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5064 variant = temp_value;
5067 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
5068 ccall.add_argument (get_cvalue_ (variant));
5070 var result = create_temp_value (to, false, node);
5072 var cfunc = new CCodeFunction (variant_func);
5073 cfunc.modifiers = CCodeModifiers.STATIC;
5074 cfunc.add_parameter (new CCodeParameter ("value", "GVariant*"));
5076 if (!to.is_real_non_null_struct_type ()) {
5077 cfunc.return_type = get_ccode_name (to);
5080 if (to.is_real_non_null_struct_type ()) {
5081 // structs are returned via out parameter
5082 cfunc.add_parameter (new CCodeParameter ("result", "%s *".printf (get_ccode_name (to))));
5083 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (result)));
5084 } else if (to is ArrayType) {
5085 // return array length if appropriate
5086 // tmp = _variant_get (variant, &tmp_length);
5087 var array_type = (ArrayType) to;
5089 for (int dim = 1; dim <= array_type.rank; dim++) {
5090 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cvalue (result, dim)));
5091 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("result", dim), "int*"));
5095 if (!to.is_real_non_null_struct_type ()) {
5096 ccode.add_assignment (get_cvalue_ (result), ccall);
5097 } else {
5098 ccode.add_expression (ccall);
5101 push_function (cfunc);
5103 CCodeExpression func_result = deserialize_expression (to, new CCodeIdentifier ("value"), new CCodeIdentifier ("*result"));
5104 if (to.is_real_non_null_struct_type ()) {
5105 ccode.add_assignment (new CCodeIdentifier ("*result"), func_result);
5106 } else {
5107 ccode.add_return (func_result);
5110 pop_function ();
5112 cfile.add_function_declaration (cfunc);
5113 cfile.add_function (cfunc);
5115 return load_temp_value (result);
5118 public virtual CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
5119 assert_not_reached ();
5122 public virtual CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
5123 assert_not_reached ();
5126 public override void visit_cast_expression (CastExpression expr) {
5127 generate_type_declaration (expr.type_reference, cfile);
5129 if (!expr.is_non_null_cast) {
5130 var valuecast = try_cast_value_to_type (get_cvalue (expr.inner), expr.inner.value_type, expr.type_reference, expr);
5131 if (valuecast != null) {
5132 set_cvalue (expr, valuecast);
5133 return;
5136 var variantcast = try_cast_variant_to_type (expr.inner.target_value, expr.type_reference, expr);
5137 if (variantcast != null) {
5138 expr.target_value = variantcast;
5139 return;
5143 var cl = expr.type_reference.data_type as Class;
5144 var iface = expr.type_reference.data_type as Interface;
5145 if (iface != null || (cl != null && !cl.is_compact)) {
5146 // checked cast for strict subtypes of GTypeInstance
5147 if (expr.is_silent_cast) {
5148 TargetValue to_cast = expr.inner.target_value;
5149 CCodeExpression cexpr;
5150 if (!get_lvalue (to_cast)) {
5151 to_cast = store_temp_value (to_cast, expr);
5153 cexpr = get_cvalue_ (to_cast);
5154 var ccheck = create_type_check (cexpr, expr.type_reference);
5155 var ccast = new CCodeCastExpression (cexpr, get_ccode_name (expr.type_reference));
5156 var cnull = new CCodeConstant ("NULL");
5157 var cast_value = new GLibValue (expr.value_type, new CCodeConditionalExpression (ccheck, ccast, cnull));
5158 if (requires_destroy (expr.inner.value_type)) {
5159 var casted = store_temp_value (cast_value, expr);
5160 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_cvalue_ (casted), new CCodeConstant ("NULL")));
5161 ccode.add_expression (destroy_value (to_cast));
5162 ccode.close ();
5163 expr.target_value = ((GLibValue) casted).copy ();
5164 } else {
5165 expr.target_value = cast_value;
5167 } else {
5168 set_cvalue (expr, generate_instance_cast (get_cvalue (expr.inner), expr.type_reference.data_type));
5170 } else {
5171 if (expr.is_silent_cast) {
5172 set_cvalue (expr, new CCodeInvalidExpression ());
5173 expr.error = true;
5174 Report.error (expr.source_reference, "Operation not supported for this type");
5175 return;
5178 // recompute array length when casting to other array type
5179 var array_type = expr.type_reference as ArrayType;
5180 if (array_type != null && expr.inner.value_type is ArrayType) {
5181 if (array_type.element_type is GenericType || ((ArrayType) expr.inner.value_type).element_type is GenericType) {
5182 // element size unknown for generic arrays, retain array length as is
5183 for (int dim = 1; dim <= array_type.rank; dim++) {
5184 append_array_length (expr, get_array_length_cexpression (expr.inner, dim));
5186 } else {
5187 var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5188 sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5190 var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5191 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (((ArrayType) expr.inner.value_type).element_type)));
5193 for (int dim = 1; dim <= array_type.rank; dim++) {
5194 append_array_length (expr, new CCodeBinaryExpression (CCodeBinaryOperator.DIV, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_array_length_cexpression (expr.inner, dim), sizeof_from), sizeof_to));
5197 } else if (array_type != null) {
5198 CCodeExpression array_length_expr;
5200 var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5201 sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5202 var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5204 var value_type = expr.inner.value_type;
5205 if (value_type is ValueType) {
5206 var data_type = ((ValueType) value_type).data_type;
5207 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (data_type)));
5208 array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5209 } else if (value_type is PointerType && ((PointerType) value_type).base_type is ValueType) {
5210 var data_type = ((ValueType) (((PointerType) value_type).base_type)).data_type;
5211 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (data_type)));
5212 array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5213 } else {
5214 // cast from unsupported non-array to array, set invalid length
5215 // required by string.data, e.g.
5216 array_length_expr = new CCodeConstant ("-1");
5219 for (int dim = 1; dim <= array_type.rank; dim++) {
5220 append_array_length (expr, array_length_expr);
5224 var innercexpr = get_cvalue (expr.inner);
5225 if (expr.type_reference is ValueType && !expr.type_reference.nullable &&
5226 expr.inner.value_type is ValueType && expr.inner.value_type.nullable) {
5227 // nullable integer or float or boolean or struct or enum cast to non-nullable
5228 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, innercexpr);
5229 } else if (expr.type_reference is ArrayType
5230 && expr.inner.value_type is ValueType && !expr.inner.value_type.nullable) {
5231 // integer or float or boolean or struct or enum to array cast
5232 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, innercexpr);
5234 set_cvalue (expr, new CCodeCastExpression (innercexpr, get_ccode_name (expr.type_reference)));
5236 if (expr.type_reference is DelegateType) {
5237 if (get_delegate_target (expr.inner) != null) {
5238 set_delegate_target (expr, get_delegate_target (expr.inner));
5239 } else {
5240 set_delegate_target (expr, new CCodeConstant ("NULL"));
5242 if (get_delegate_target_destroy_notify (expr.inner) != null) {
5243 set_delegate_target_destroy_notify (expr, get_delegate_target_destroy_notify (expr.inner));
5244 } else {
5245 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
5251 public override void visit_named_argument (NamedArgument expr) {
5252 set_cvalue (expr, get_cvalue (expr.inner));
5255 public override void visit_pointer_indirection (PointerIndirection expr) {
5256 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cvalue (expr.inner)));
5257 ((GLibValue) expr.target_value).lvalue = get_lvalue (expr.inner.target_value);
5260 public override void visit_addressof_expression (AddressofExpression expr) {
5261 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5264 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
5265 /* tmp = expr.inner; expr.inner = NULL; expr = tmp; */
5266 expr.target_value = store_temp_value (expr.inner.target_value, expr);
5268 if (expr.inner.value_type is StructValueType && !expr.inner.value_type.nullable) {
5269 // memset needs string.h
5270 cfile.add_include ("string.h");
5271 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
5272 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5273 creation_call.add_argument (new CCodeConstant ("0"));
5274 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.inner.value_type))));
5275 ccode.add_expression (creation_call);
5276 } else if (expr.value_type is DelegateType) {
5277 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5278 var target = get_delegate_target_cvalue (expr.inner.target_value);
5279 if (target != null) {
5280 ccode.add_assignment (target, new CCodeConstant ("NULL"));
5282 var target_destroy_notify = get_delegate_target_destroy_notify_cvalue (expr.inner.target_value);
5283 if (target_destroy_notify != null) {
5284 ccode.add_assignment (target_destroy_notify, new CCodeConstant ("NULL"));
5286 } else if (expr.inner.value_type is ArrayType) {
5287 var array_type = (ArrayType) expr.inner.value_type;
5288 var glib_value = (GLibValue) expr.inner.target_value;
5290 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5291 if (glib_value.array_length_cvalues != null) {
5292 for (int dim = 1; dim <= array_type.rank; dim++) {
5293 ccode.add_assignment (get_array_length_cvalue (glib_value, dim), new CCodeConstant ("0"));
5296 } else {
5297 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5301 public override void visit_binary_expression (BinaryExpression expr) {
5302 var cleft = get_cvalue (expr.left);
5303 var cright = get_cvalue (expr.right);
5305 CCodeExpression? left_chain = null;
5306 if (expr.is_chained) {
5307 var lbe = (BinaryExpression) expr.left;
5309 var temp_decl = get_temp_variable (lbe.right.target_type, true, null, false);
5310 emit_temp_var (temp_decl);
5311 var cvar = get_variable_cexpression (temp_decl.name);
5312 var clbe = (CCodeBinaryExpression) get_cvalue (lbe);
5313 if (lbe.is_chained) {
5314 clbe = (CCodeBinaryExpression) clbe.right;
5316 ccode.add_assignment (cvar, get_cvalue (lbe.right));
5317 clbe.right = get_variable_cexpression (temp_decl.name);
5318 left_chain = cleft;
5319 cleft = cvar;
5322 CCodeBinaryOperator op;
5323 if (expr.operator == BinaryOperator.PLUS) {
5324 op = CCodeBinaryOperator.PLUS;
5325 } else if (expr.operator == BinaryOperator.MINUS) {
5326 op = CCodeBinaryOperator.MINUS;
5327 } else if (expr.operator == BinaryOperator.MUL) {
5328 op = CCodeBinaryOperator.MUL;
5329 } else if (expr.operator == BinaryOperator.DIV) {
5330 op = CCodeBinaryOperator.DIV;
5331 } else if (expr.operator == BinaryOperator.MOD) {
5332 if (expr.value_type.equals (double_type)) {
5333 cfile.add_include ("math.h");
5334 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
5335 ccall.add_argument (cleft);
5336 ccall.add_argument (cright);
5337 set_cvalue (expr, ccall);
5338 return;
5339 } else if (expr.value_type.equals (float_type)) {
5340 cfile.add_include ("math.h");
5341 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
5342 ccall.add_argument (cleft);
5343 ccall.add_argument (cright);
5344 set_cvalue (expr, ccall);
5345 return;
5346 } else {
5347 op = CCodeBinaryOperator.MOD;
5349 } else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
5350 op = CCodeBinaryOperator.SHIFT_LEFT;
5351 } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
5352 op = CCodeBinaryOperator.SHIFT_RIGHT;
5353 } else if (expr.operator == BinaryOperator.LESS_THAN) {
5354 op = CCodeBinaryOperator.LESS_THAN;
5355 } else if (expr.operator == BinaryOperator.GREATER_THAN) {
5356 op = CCodeBinaryOperator.GREATER_THAN;
5357 } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
5358 op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
5359 } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
5360 op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
5361 } else if (expr.operator == BinaryOperator.EQUALITY) {
5362 op = CCodeBinaryOperator.EQUALITY;
5363 } else if (expr.operator == BinaryOperator.INEQUALITY) {
5364 op = CCodeBinaryOperator.INEQUALITY;
5365 } else if (expr.operator == BinaryOperator.BITWISE_AND) {
5366 op = CCodeBinaryOperator.BITWISE_AND;
5367 } else if (expr.operator == BinaryOperator.BITWISE_OR) {
5368 op = CCodeBinaryOperator.BITWISE_OR;
5369 } else if (expr.operator == BinaryOperator.BITWISE_XOR) {
5370 op = CCodeBinaryOperator.BITWISE_XOR;
5371 } else if (expr.operator == BinaryOperator.AND) {
5372 op = CCodeBinaryOperator.AND;
5373 } else if (expr.operator == BinaryOperator.OR) {
5374 op = CCodeBinaryOperator.OR;
5375 } else if (expr.operator == BinaryOperator.IN) {
5376 if (expr.right.value_type is ArrayType) {
5377 var array_type = (ArrayType) expr.right.value_type;
5378 var node = new CCodeFunctionCall (new CCodeIdentifier (generate_array_contains_wrapper (array_type)));
5379 node.add_argument (cright);
5380 node.add_argument (get_array_length_cexpression (expr.right));
5381 if (array_type.element_type is StructValueType) {
5382 node.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft));
5383 } else {
5384 node.add_argument (cleft);
5386 set_cvalue (expr, node);
5387 } else {
5388 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft));
5390 return;
5391 } else {
5392 assert_not_reached ();
5395 if (expr.operator == BinaryOperator.EQUALITY ||
5396 expr.operator == BinaryOperator.INEQUALITY) {
5397 var left_type = expr.left.target_type;
5398 var right_type = expr.right.target_type;
5399 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
5401 if (left_type is StructValueType && right_type is StructValueType) {
5402 var equalfunc = generate_struct_equal_function ((Struct) left_type.data_type);
5403 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5404 ccall.add_argument (cleft);
5405 ccall.add_argument (cright);
5406 cleft = ccall;
5407 cright = new CCodeConstant ("TRUE");
5408 } else if ((left_type is IntegerType || left_type is FloatingType || left_type is BooleanType || left_type is EnumValueType) && left_type.nullable &&
5409 (right_type is IntegerType || right_type is FloatingType || right_type is BooleanType || right_type is EnumValueType) && right_type.nullable) {
5410 var equalfunc = generate_numeric_equal_function ((TypeSymbol) left_type.data_type);
5411 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5412 ccall.add_argument (cleft);
5413 ccall.add_argument (cright);
5414 cleft = ccall;
5415 cright = new CCodeConstant ("TRUE");
5419 if (!(expr.left.value_type is NullType)
5420 && expr.left.value_type.compatible (string_type)
5421 && !(expr.right.value_type is NullType)
5422 && expr.right.value_type.compatible (string_type)) {
5423 if (expr.operator == BinaryOperator.PLUS) {
5424 // string concatenation
5425 if (expr.left.is_constant () && expr.right.is_constant ()) {
5426 string left, right;
5428 if (cleft is CCodeIdentifier) {
5429 left = ((CCodeIdentifier) cleft).name;
5430 } else if (cleft is CCodeConstant) {
5431 left = ((CCodeConstant) cleft).name;
5432 } else {
5433 assert_not_reached ();
5435 if (cright is CCodeIdentifier) {
5436 right = ((CCodeIdentifier) cright).name;
5437 } else if (cright is CCodeConstant) {
5438 right = ((CCodeConstant) cright).name;
5439 } else {
5440 assert_not_reached ();
5443 set_cvalue (expr, new CCodeConstant ("%s %s".printf (left, right)));
5444 return;
5445 } else {
5446 // convert to g_strconcat (a, b, NULL)
5447 var temp_value = create_temp_value (expr.value_type, false, expr);
5449 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
5450 ccall.add_argument (cleft);
5451 ccall.add_argument (cright);
5452 ccall.add_argument (new CCodeConstant("NULL"));
5454 ccode.add_assignment (get_cvalue_ (temp_value), ccall);
5455 expr.target_value = temp_value;
5456 return;
5458 } else if (expr.operator == BinaryOperator.EQUALITY
5459 || expr.operator == BinaryOperator.INEQUALITY
5460 || expr.operator == BinaryOperator.LESS_THAN
5461 || expr.operator == BinaryOperator.GREATER_THAN
5462 || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL
5463 || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
5464 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5465 ccall.add_argument (cleft);
5466 ccall.add_argument (cright);
5467 cleft = ccall;
5468 cright = new CCodeConstant ("0");
5472 set_cvalue (expr, new CCodeBinaryExpression (op, cleft, cright));
5473 if (left_chain != null) {
5474 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.AND, left_chain, get_cvalue (expr)));
5478 CCodeExpression? create_type_check (CCodeNode ccodenode, DataType type) {
5479 var et = type as ErrorType;
5480 if (et != null && et.error_code != null) {
5481 var matches_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
5482 matches_call.add_argument ((CCodeExpression) ccodenode);
5483 matches_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain)));
5484 matches_call.add_argument (new CCodeIdentifier (get_ccode_name (et.error_code)));
5485 return matches_call;
5486 } else if (et != null && et.error_domain != null) {
5487 var instance_domain = new CCodeMemberAccess.pointer ((CCodeExpression) ccodenode, "domain");
5488 var type_domain = new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain));
5489 return new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, instance_domain, type_domain);
5490 } else {
5491 var type_id = get_type_id_expression (type);
5492 if (type_id == null) {
5493 return new CCodeInvalidExpression ();
5495 var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
5496 ccheck.add_argument ((CCodeExpression) ccodenode);
5497 ccheck.add_argument (type_id);
5498 return ccheck;
5502 string generate_array_contains_wrapper (ArrayType array_type) {
5503 string array_contains_func = "_vala_%s_array_contains".printf (get_ccode_lower_case_name (array_type.element_type));
5505 if (!add_wrapper (array_contains_func)) {
5506 return array_contains_func;
5509 var function = new CCodeFunction (array_contains_func, "gboolean");
5510 function.modifiers = CCodeModifiers.STATIC;
5512 function.add_parameter (new CCodeParameter ("stack", "%s *".printf (get_ccode_name (array_type.element_type))));
5513 function.add_parameter (new CCodeParameter ("stack_length", "int"));
5514 if (array_type.element_type is StructValueType) {
5515 function.add_parameter (new CCodeParameter ("needle", "%s *".printf (get_ccode_name (array_type.element_type))));
5516 } else {
5517 function.add_parameter (new CCodeParameter ("needle", get_ccode_name (array_type.element_type)));
5520 push_function (function);
5522 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
5524 var cloop_initializer = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
5525 var cloop_condition = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("stack_length"));
5526 var cloop_iterator = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"));
5527 ccode.open_for (cloop_initializer, cloop_condition, cloop_iterator);
5529 var celement = new CCodeElementAccess (new CCodeIdentifier ("stack"), new CCodeIdentifier ("i"));
5530 var cneedle = new CCodeIdentifier ("needle");
5531 CCodeBinaryExpression cif_condition;
5532 if (array_type.element_type.compatible (string_type)) {
5533 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5534 ccall.add_argument (celement);
5535 ccall.add_argument (cneedle);
5536 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("0"));
5537 } else if (array_type.element_type is StructValueType) {
5538 var equalfunc = generate_struct_equal_function ((Struct) array_type.element_type.data_type);
5539 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5540 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, celement));
5541 ccall.add_argument (cneedle);
5542 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("TRUE"));
5543 } else {
5544 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cneedle, celement);
5547 ccode.open_if (cif_condition);
5548 ccode.add_return (new CCodeConstant ("TRUE"));
5549 ccode.close ();
5551 ccode.close ();
5553 ccode.add_return (new CCodeConstant ("FALSE"));
5555 pop_function ();
5557 cfile.add_function_declaration (function);
5558 cfile.add_function (function);
5560 return array_contains_func;
5563 public override void visit_type_check (TypeCheck expr) {
5564 generate_type_declaration (expr.type_reference, cfile);
5566 var type = expr.expression.value_type;
5567 var pointer_type = type as PointerType;
5568 if (pointer_type != null) {
5569 type = pointer_type.base_type;
5571 var cl = type.data_type as Class;
5572 var iface = type.data_type as Interface;
5573 if ((cl != null && !cl.is_compact) || iface != null || type is GenericType || type is ErrorType) {
5574 set_cvalue (expr, create_type_check (get_cvalue (expr.expression), expr.type_reference));
5575 } else {
5576 set_cvalue (expr, new CCodeInvalidExpression ());
5579 if (get_cvalue (expr) is CCodeInvalidExpression) {
5580 Report.error (expr.source_reference, "type check expressions not supported for compact classes, structs, and enums");
5584 public override void visit_lambda_expression (LambdaExpression lambda) {
5585 var delegate_type = (DelegateType) lambda.target_type;
5586 var d = delegate_type.delegate_symbol;
5588 lambda.method.set_attribute_bool ("CCode", "array_length", get_ccode_array_length (d));
5589 lambda.method.set_attribute_bool ("CCode", "array_null_terminated", get_ccode_array_null_terminated (d));
5590 lambda.method.set_attribute_string ("CCode", "array_length_type", get_ccode_array_length_type (d));
5592 lambda.accept_children (this);
5594 bool expr_owned = lambda.value_type.value_owned;
5596 set_cvalue (lambda, new CCodeIdentifier (get_ccode_name (lambda.method)));
5598 if (lambda.method.closure) {
5599 int block_id = get_block_id (current_closure_block);
5600 var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
5601 if (expr_owned || delegate_type.is_called_once) {
5602 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
5603 ref_call.add_argument (delegate_target);
5604 delegate_target = ref_call;
5605 set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
5606 } else {
5607 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5609 set_delegate_target (lambda, delegate_target);
5610 } else if (get_this_type () != null) {
5611 CCodeExpression delegate_target = get_result_cexpression ("self");
5612 delegate_target = convert_to_generic_pointer (delegate_target, get_this_type ());
5613 if (expr_owned || delegate_type.is_called_once) {
5614 if (get_this_type () != null) {
5615 var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_this_type (), lambda.source_reference));
5616 ref_call.add_argument (delegate_target);
5617 delegate_target = ref_call;
5618 set_delegate_target_destroy_notify (lambda, get_destroy_func_expression (get_this_type ()));
5619 } else {
5620 // in constructor
5621 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
5622 ref_call.add_argument (delegate_target);
5623 delegate_target = ref_call;
5624 set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("g_object_unref"));
5626 } else {
5627 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5629 set_delegate_target (lambda, delegate_target);
5630 } else {
5631 set_delegate_target (lambda, new CCodeConstant ("NULL"));
5632 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5636 public CCodeExpression convert_from_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
5637 var result = cexpr;
5638 if (is_reference_type_argument (actual_type) || is_nullable_value_type_argument (actual_type)) {
5639 result = new CCodeCastExpression (cexpr, get_ccode_name (actual_type));
5640 } else if (is_signed_integer_type_argument (actual_type)) {
5641 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), get_ccode_name (actual_type));
5642 } else if (is_unsigned_integer_type_argument (actual_type)) {
5643 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), get_ccode_name (actual_type));
5645 return result;
5648 public CCodeExpression convert_to_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
5649 var result = cexpr;
5650 if (is_signed_integer_type_argument (actual_type)) {
5651 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), "gpointer");
5652 } else if (is_unsigned_integer_type_argument (actual_type)) {
5653 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), "gpointer");
5655 return result;
5658 public TargetValue transform_value (TargetValue value, DataType? target_type, CodeNode node) {
5659 var type = value.value_type;
5660 var result = ((GLibValue) value).copy ();
5662 if (type.value_owned
5663 && type.floating_reference) {
5664 /* floating reference, sink it.
5666 var cl = type.data_type as ObjectTypeSymbol;
5667 var sink_func = (cl != null) ? get_ccode_ref_sink_function (cl) : "";
5669 if (sink_func != "") {
5670 if (type.nullable) {
5671 var is_not_null = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, result.cvalue, new CCodeIdentifier ("NULL"));
5672 ccode.open_if (is_not_null);
5675 var csink = new CCodeFunctionCall (new CCodeIdentifier (sink_func));
5676 csink.add_argument (result.cvalue);
5677 ccode.add_expression (csink);
5679 if (type.nullable) {
5680 ccode.close ();
5682 } else {
5683 Report.error (null, "type `%s' does not support floating references".printf (type.data_type.name));
5687 bool boxing = (type is ValueType && !type.nullable
5688 && target_type is ValueType && target_type.nullable);
5689 bool unboxing = (type is ValueType && type.nullable
5690 && target_type is ValueType && !target_type.nullable);
5692 bool gvalue_boxing = (target_type != null
5693 && target_type.data_type == gvalue_type
5694 && !(type is NullType)
5695 && get_ccode_type_id (type) != "G_TYPE_VALUE");
5696 bool gvariant_boxing = (target_type != null
5697 && target_type.data_type == gvariant_type
5698 && !(type is NullType)
5699 && type.data_type != gvariant_type);
5701 if (type.value_owned
5702 && (target_type == null || !target_type.value_owned || boxing || unboxing || gvariant_boxing)
5703 && !gvalue_boxing /* gvalue can assume ownership of value, no need to free it */) {
5704 // value leaked, destroy it
5705 if (target_type is PointerType) {
5706 // manual memory management for pointers
5707 } else if (requires_destroy (type)) {
5708 if (!is_lvalue_access_allowed (type)) {
5709 // cannot assign to a temporary variable
5710 temp_ref_values.insert (0, result.copy ());
5711 } else {
5712 var temp_value = create_temp_value (type, false, node);
5713 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5714 store_value (temp_value, result, node.source_reference);
5715 result.cvalue = get_cvalue_ (temp_value);
5720 if (target_type == null) {
5721 // value will be destroyed, no need for implicit casts
5722 return result;
5725 result.value_type = target_type.copy ();
5727 if (gvalue_boxing) {
5728 // implicit conversion to GValue
5729 var temp_value = create_temp_value (target_type, true, node, true);
5731 if (!target_type.value_owned) {
5732 // boxed GValue leaked, destroy it
5733 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5736 if (target_type.nullable) {
5737 var newcall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
5738 newcall.add_argument (new CCodeConstant ("GValue"));
5739 newcall.add_argument (new CCodeConstant ("1"));
5740 var newassignment = new CCodeAssignment (get_cvalue_ (temp_value), newcall);
5741 ccode.add_expression (newassignment);
5744 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
5745 if (target_type.nullable) {
5746 ccall.add_argument (get_cvalue_ (temp_value));
5747 } else {
5748 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
5750 var type_id = get_ccode_type_id (type);
5751 if (type_id == "") {
5752 Report.error (node.source_reference, "GValue boxing of type `%s' is not supported".printf (type.to_string ()));
5754 ccall.add_argument (new CCodeIdentifier (type_id));
5755 ccode.add_expression (ccall);
5757 if (requires_destroy (type)) {
5758 ccall = new CCodeFunctionCall (get_value_taker_function (type));
5759 } else {
5760 ccall = new CCodeFunctionCall (get_value_setter_function (type));
5762 if (target_type.nullable) {
5763 ccall.add_argument (get_cvalue_ (temp_value));
5764 } else {
5765 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
5767 if (type.is_real_non_null_struct_type ()) {
5768 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue));
5769 } else {
5770 ccall.add_argument (result.cvalue);
5773 ccode.add_expression (ccall);
5775 result = (GLibValue) temp_value;
5776 } else if (gvariant_boxing) {
5777 // implicit conversion to GVariant
5778 string variant_func = "_variant_new%d".printf (++next_variant_function_id);
5780 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
5781 ccall.add_argument (result.cvalue);
5783 var cfunc = new CCodeFunction (variant_func, "GVariant*");
5784 cfunc.modifiers = CCodeModifiers.STATIC;
5785 cfunc.add_parameter (new CCodeParameter ("value", get_ccode_name (type)));
5787 if (type is ArrayType) {
5788 // return array length if appropriate
5789 var array_type = (ArrayType) type;
5791 for (int dim = 1; dim <= array_type.rank; dim++) {
5792 ccall.add_argument (get_array_length_cvalue (value, dim));
5793 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), "gint"));
5797 push_function (cfunc);
5799 // sink floating reference
5800 var sink = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_ref_sink"));
5801 sink.add_argument (serialize_expression (type, new CCodeIdentifier ("value")));
5802 ccode.add_return (sink);
5804 pop_function ();
5806 cfile.add_function_declaration (cfunc);
5807 cfile.add_function (cfunc);
5809 result.cvalue = ccall;
5810 result.value_type.value_owned = true;
5812 result = (GLibValue) store_temp_value (result, node);
5813 if (!target_type.value_owned) {
5814 // value leaked
5815 temp_ref_values.insert (0, ((GLibValue) result).copy ());
5817 } else if (boxing) {
5818 // value needs to be boxed
5820 result.value_type.nullable = false;
5821 if (!result.lvalue || !result.value_type.equals (value.value_type)) {
5822 result.cvalue = get_implicit_cast_expression (result.cvalue, value.value_type, result.value_type, node);
5823 result = (GLibValue) store_temp_value (result, node);
5825 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue);
5826 result.lvalue = false;
5827 result.value_type.nullable = true;
5828 } else if (unboxing) {
5829 // unbox value
5831 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result.cvalue);
5832 } else {
5833 // TODO: rewrite get_implicit_cast_expression to return a GLibValue
5834 var old_cexpr = result.cvalue;
5835 result.cvalue = get_implicit_cast_expression (result.cvalue, type, target_type, node);
5836 result.lvalue = result.lvalue && result.cvalue == old_cexpr;
5839 bool array_needs_copy = false;
5840 if (type is ArrayType && target_type is ArrayType) {
5841 var array = (ArrayType) type;
5842 var target_array = (ArrayType) target_type;
5843 if (target_array.element_type.value_owned && !array.element_type.value_owned) {
5844 array_needs_copy = requires_copy (target_array.element_type);
5848 if (!gvalue_boxing && !gvariant_boxing && target_type.value_owned && (!type.value_owned || boxing || unboxing || array_needs_copy) && requires_copy (target_type) && !(type is NullType)) {
5849 // need to copy value
5850 var copy = (GLibValue) copy_value (result, node);
5851 if (target_type.data_type is Interface && copy == null) {
5852 Report.error (node.source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure".printf (target_type.data_type.get_full_name ()));
5853 return result;
5855 result = copy;
5858 return result;
5861 public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, CodeNode? node) {
5862 var cexpr = source_cexpr;
5864 if (expression_type.data_type != null && expression_type.data_type == target_type.data_type) {
5865 // same type, no cast required
5866 return cexpr;
5869 if (expression_type is NullType) {
5870 // null literal, no cast required when not converting to generic type pointer
5871 return cexpr;
5874 generate_type_declaration (target_type, cfile);
5876 var cl = target_type.data_type as Class;
5877 var iface = target_type.data_type as Interface;
5878 if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
5879 // checked cast for strict subtypes of GTypeInstance
5880 return generate_instance_cast (cexpr, target_type.data_type);
5881 } else if (target_type.data_type != null && get_ccode_name (expression_type) != get_ccode_name (target_type)) {
5882 var st = target_type.data_type as Struct;
5883 if (target_type.data_type.is_reference_type () || (st != null && st.is_simple_type ())) {
5884 // don't cast non-simple structs
5885 return new CCodeCastExpression (cexpr, get_ccode_name (target_type));
5886 } else {
5887 return cexpr;
5889 } else {
5890 return cexpr;
5894 public void store_property (Property prop, Expression? instance, TargetValue value) {
5895 if (instance is BaseAccess) {
5896 if (prop.base_property != null) {
5897 var base_class = (Class) prop.base_property.parent_symbol;
5898 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class, null))));
5899 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class, null))));
5901 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
5902 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
5903 var cexpr = get_cvalue_ (value);
5904 if (prop.property_type.is_real_non_null_struct_type ()) {
5905 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5907 ccall.add_argument (cexpr);
5909 ccode.add_expression (ccall);
5910 } else if (prop.base_interface_property != null) {
5911 var base_iface = (Interface) prop.base_interface_property.parent_symbol;
5912 string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface));
5914 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "set_%s".printf (prop.name)));
5915 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
5916 var cexpr = get_cvalue_ (value);
5917 if (prop.property_type.is_real_non_null_struct_type ()) {
5918 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5920 ccall.add_argument (cexpr);
5922 ccode.add_expression (ccall);
5924 return;
5927 var set_func = "g_object_set";
5929 var base_property = prop;
5930 if (!get_ccode_no_accessor_method (prop)) {
5931 if (prop.base_property != null) {
5932 base_property = prop.base_property;
5933 } else if (prop.base_interface_property != null) {
5934 base_property = prop.base_interface_property;
5937 if (prop is DynamicProperty) {
5938 set_func = get_dynamic_property_setter_cname ((DynamicProperty) prop);
5939 } else {
5940 generate_property_accessor_declaration (base_property.set_accessor, cfile);
5941 set_func = get_ccode_name (base_property.set_accessor);
5943 if (!prop.external && prop.external_package) {
5944 // internal VAPI properties
5945 // only add them once per source file
5946 if (add_generated_external_symbol (prop)) {
5947 visit_property (prop);
5953 var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
5955 if (prop.binding == MemberBinding.INSTANCE) {
5956 /* target instance is first argument */
5957 var cinstance = (CCodeExpression) get_ccodenode (instance);
5959 if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
5960 // we need to pass struct instance by reference if it isn't a simple-type
5961 var instance_value = instance.target_value;
5962 if (!get_lvalue (instance_value)) {
5963 instance_value = store_temp_value (instance_value, instance);
5965 cinstance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
5968 ccall.add_argument (cinstance);
5971 if (get_ccode_no_accessor_method (prop)) {
5972 /* property name is second argument of g_object_set */
5973 ccall.add_argument (get_property_canonical_cconstant (prop));
5976 var cexpr = get_cvalue_ (value);
5978 if (prop.property_type.is_real_non_null_struct_type ()) {
5979 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5982 var array_type = prop.property_type as ArrayType;
5984 ccall.add_argument (cexpr);
5986 if (array_type != null && get_ccode_array_length (prop)) {
5987 for (int dim = 1; dim <= array_type.rank; dim++) {
5988 ccall.add_argument (get_array_length_cvalue (value, dim));
5990 } else if (prop.property_type is DelegateType) {
5991 var delegate_type = (DelegateType) prop.property_type;
5992 if (delegate_type.delegate_symbol.has_target) {
5993 ccall.add_argument (get_delegate_target_cvalue (value));
5994 if (base_property.set_accessor.value_type.value_owned) {
5995 ccall.add_argument (get_delegate_target_destroy_notify_cvalue (value));
6000 if (get_ccode_no_accessor_method (prop)) {
6001 ccall.add_argument (new CCodeConstant ("NULL"));
6004 ccode.add_expression (ccall);
6007 public bool add_wrapper (string wrapper_name) {
6008 return wrappers.add (wrapper_name);
6011 public bool add_generated_external_symbol (Symbol external_symbol) {
6012 return generated_external_symbols.add (external_symbol);
6015 public static DataType get_data_type_for_symbol (TypeSymbol sym) {
6016 DataType type = null;
6018 if (sym is Class) {
6019 type = new ObjectType ((Class) sym);
6020 } else if (sym is Interface) {
6021 type = new ObjectType ((Interface) sym);
6022 } else if (sym is Struct) {
6023 var st = (Struct) sym;
6024 if (st.is_boolean_type ()) {
6025 type = new BooleanType (st);
6026 } else if (st.is_integer_type ()) {
6027 type = new IntegerType (st);
6028 } else if (st.is_floating_type ()) {
6029 type = new FloatingType (st);
6030 } else {
6031 type = new StructValueType (st);
6033 } else if (sym is Enum) {
6034 type = new EnumValueType ((Enum) sym);
6035 } else if (sym is ErrorDomain) {
6036 type = new ErrorType ((ErrorDomain) sym, null);
6037 } else if (sym is ErrorCode) {
6038 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
6039 } else {
6040 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
6041 return new InvalidType ();
6044 return type;
6047 public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) {
6048 var st = type.data_type as Struct;
6049 var array_type = type as ArrayType;
6050 if (type.data_type != null && !type.nullable && get_ccode_default_value (type.data_type) != "") {
6051 return new CCodeConstant (get_ccode_default_value (type.data_type));
6052 } else if (initializer_expression && !type.nullable &&
6053 (st != null || (array_type != null && array_type.fixed_length))) {
6054 // 0-initialize struct with struct initializer { 0 }
6055 // only allowed as initializer expression in C
6056 var clist = new CCodeInitializerList ();
6057 clist.append (new CCodeConstant ("0"));
6058 return clist;
6059 } else if ((type.data_type != null && type.data_type.is_reference_type ())
6060 || type.nullable
6061 || type is PointerType || type is DelegateType
6062 || (array_type != null && !array_type.fixed_length)) {
6063 return new CCodeConstant ("NULL");
6064 } else if (type is GenericType) {
6065 return new CCodeConstant ("NULL");
6066 } else if (type is ErrorType) {
6067 return new CCodeConstant ("NULL");
6069 return null;
6072 private void create_property_type_check_statement (Property prop, bool check_return_type, TypeSymbol t, bool non_null, string var_name) {
6073 if (check_return_type) {
6074 create_type_check_statement (prop, prop.property_type, t, non_null, var_name);
6075 } else {
6076 create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
6080 public virtual void create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
6083 public int get_param_pos (double param_pos, bool ellipsis = false) {
6084 if (!ellipsis) {
6085 if (param_pos >= 0) {
6086 return (int) (param_pos * 1000);
6087 } else {
6088 return (int) ((100 + param_pos) * 1000);
6090 } else {
6091 if (param_pos >= 0) {
6092 return (int) ((100 + param_pos) * 1000);
6093 } else {
6094 return (int) ((200 + param_pos) * 1000);
6099 public CCodeExpression? get_ccodenode (Expression node) {
6100 if (get_cvalue (node) == null) {
6101 node.emit (this);
6103 return get_cvalue (node);
6106 public bool is_lvalue_access_allowed (DataType type) {
6107 var array_type = type as ArrayType;
6108 if (array_type != null && array_type.inline_allocated) {
6109 return false;
6111 if (type.data_type != null) {
6112 return type.data_type.get_attribute_bool ("CCode", "lvalue_access", true);
6114 return true;
6117 public CCodeDeclaratorSuffix? get_ccode_declarator_suffix (DataType type) {
6118 var array_type = type as ArrayType;
6119 if (array_type != null) {
6120 if (array_type.fixed_length) {
6121 return new CCodeDeclaratorSuffix.with_array (get_ccodenode (array_type.length));
6122 } else if (array_type.inline_allocated) {
6123 return new CCodeDeclaratorSuffix.with_array ();
6126 return null;
6129 public CCodeConstant get_signal_canonical_constant (Signal sig, string? detail = null) {
6130 return new CCodeConstant ("\"%s%s\"".printf (get_ccode_name (sig), (detail != null ? "::%s".printf (detail) : "")));
6133 public static CCodeConstant get_enum_value_canonical_cconstant (EnumValue ev) {
6134 return new CCodeConstant ("\"%s\"".printf (ev.name.down ().replace ("_", "-")));
6137 public bool get_signal_has_emitter (Signal sig) {
6138 return sig.get_attribute ("HasEmitter") != null;
6141 public CCodeConstant get_property_canonical_cconstant (Property prop) {
6142 return new CCodeConstant ("\"%s\"".printf (prop.name.replace ("_", "-")));
6145 public override void visit_class (Class cl) {
6148 public void create_postcondition_statement (Expression postcondition) {
6149 var cassert = new CCodeFunctionCall (new CCodeIdentifier ("_vala_warn_if_fail"));
6151 postcondition.emit (this);
6153 string message = ((string) postcondition.source_reference.begin.pos).substring (0, (int) (postcondition.source_reference.end.pos - postcondition.source_reference.begin.pos));
6154 cassert.add_argument (get_cvalue (postcondition));
6155 cassert.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
6156 requires_assert = true;
6158 ccode.add_expression (cassert);
6161 public virtual bool is_gobject_property (Property prop) {
6162 return false;
6165 public DataType? get_this_type () {
6166 if (current_method != null && current_method.binding == MemberBinding.INSTANCE) {
6167 return current_method.this_parameter.variable_type;
6168 } else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) {
6169 return current_property_accessor.prop.this_parameter.variable_type;
6170 } else if (current_constructor != null && current_constructor.binding == MemberBinding.INSTANCE) {
6171 return current_constructor.this_parameter.variable_type;
6172 } else if (current_destructor != null && current_destructor.binding == MemberBinding.INSTANCE) {
6173 return current_destructor.this_parameter.variable_type;
6175 return null;
6178 public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
6179 var result = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_CAST"));
6180 result.add_argument (expr);
6181 result.add_argument (new CCodeIdentifier (get_ccode_type_id (type)));
6182 result.add_argument (new CCodeIdentifier (get_ccode_name (type)));
6183 return result;
6186 void generate_struct_destroy_function (Struct st) {
6187 if (cfile.add_declaration (get_ccode_destroy_function (st))) {
6188 // only generate function once per source file
6189 return;
6192 var function = new CCodeFunction (get_ccode_destroy_function (st), "void");
6193 function.modifiers = CCodeModifiers.STATIC;
6194 function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (st))));
6196 push_context (new EmitContext ());
6197 push_function (function);
6199 var this_value = load_this_parameter (st);
6200 foreach (Field f in st.get_fields ()) {
6201 if (f.binding == MemberBinding.INSTANCE) {
6202 if (requires_destroy (f.variable_type)) {
6203 ccode.add_expression (destroy_field (f, this_value));
6208 pop_function ();
6209 pop_context ();
6211 cfile.add_function_declaration (function);
6212 cfile.add_function (function);
6215 void generate_struct_copy_function (Struct st) {
6216 if (cfile.add_declaration (get_ccode_copy_function (st))) {
6217 // only generate function once per source file
6218 return;
6221 var function = new CCodeFunction (get_ccode_copy_function (st), "void");
6222 function.modifiers = CCodeModifiers.STATIC;
6223 function.add_parameter (new CCodeParameter ("self", "const %s *".printf (get_ccode_name (st))));
6224 function.add_parameter (new CCodeParameter ("dest", "%s *".printf (get_ccode_name (st))));
6226 push_context (new EmitContext ());
6227 push_function (function);
6229 var dest_struct = new GLibValue (get_data_type_for_symbol (st), new CCodeIdentifier ("(*dest)"), true);
6230 foreach (Field f in st.get_fields ()) {
6231 if (f.binding == MemberBinding.INSTANCE) {
6232 var value = load_field (f, load_this_parameter ((TypeSymbol) st));
6233 if (requires_copy (f.variable_type)) {
6234 value = copy_value (value, f);
6235 if (value == null) {
6236 // error case, continue to avoid critical
6237 continue;
6240 store_field (f, dest_struct, value);
6244 pop_function ();
6245 pop_context ();
6247 cfile.add_function_declaration (function);
6248 cfile.add_function (function);
6251 public void return_default_value (DataType return_type) {
6252 var st = return_type.data_type as Struct;
6253 if (st != null && st.is_simple_type () && !return_type.nullable) {
6254 // 0-initialize struct with struct initializer { 0 }
6255 // only allowed as initializer expression in C
6256 var ret_temp_var = get_temp_variable (return_type, true, null, true);
6257 emit_temp_var (ret_temp_var);
6258 ccode.add_return (new CCodeIdentifier (ret_temp_var.name));
6259 } else {
6260 ccode.add_return (default_value_for_type (return_type, false));
6264 public virtual void generate_dynamic_method_wrapper (DynamicMethod method) {
6267 public virtual bool method_has_wrapper (Method method) {
6268 return false;
6271 public virtual CCodeExpression get_param_spec_cexpression (Property prop) {
6272 return new CCodeFunctionCall (new CCodeIdentifier (""));
6275 public virtual CCodeExpression get_param_spec (Property prop) {
6276 return new CCodeFunctionCall (new CCodeIdentifier (""));
6279 public virtual CCodeExpression get_signal_creation (Signal sig, TypeSymbol type) {
6280 return new CCodeFunctionCall (new CCodeIdentifier (""));
6283 public virtual void register_dbus_info (CCodeBlock block, ObjectTypeSymbol bindable) {
6286 public virtual string get_dynamic_property_getter_cname (DynamicProperty node) {
6287 Report.error (node.source_reference, "dynamic properties are not supported for %s".printf (node.dynamic_type.to_string ()));
6288 return "";
6291 public virtual string get_dynamic_property_setter_cname (DynamicProperty node) {
6292 Report.error (node.source_reference, "dynamic properties are not supported for %s".printf (node.dynamic_type.to_string ()));
6293 return "";
6296 public virtual string get_dynamic_signal_cname (DynamicSignal node) {
6297 return "";
6300 public virtual string get_dynamic_signal_connect_wrapper_name (DynamicSignal node) {
6301 return "";
6304 public virtual string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal node) {
6305 return "";
6308 public virtual string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node) {
6309 return "";
6312 public virtual string get_array_length_cname (string array_cname, int dim) {
6313 return "";
6316 public virtual string get_parameter_array_length_cname (Parameter param, int dim) {
6317 return "";
6320 public virtual CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
6321 return new CCodeConstant ("");
6324 public virtual CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
6325 return new CCodeInvalidExpression ();
6328 public virtual string get_array_size_cname (string array_cname) {
6329 return "";
6332 public virtual void add_simple_check (CodeNode node, bool always_fails = false) {
6335 public virtual string generate_ready_function (Method m) {
6336 return "";
6339 public CCodeExpression? get_cvalue (Expression expr) {
6340 if (expr.target_value == null) {
6341 return null;
6343 var glib_value = (GLibValue) expr.target_value;
6344 return glib_value.cvalue;
6347 public CCodeExpression? get_cvalue_ (TargetValue value) {
6348 var glib_value = (GLibValue) value;
6349 return glib_value.cvalue;
6352 public void set_cvalue (Expression expr, CCodeExpression? cvalue) {
6353 var glib_value = (GLibValue) expr.target_value;
6354 if (glib_value == null) {
6355 glib_value = new GLibValue (expr.value_type);
6356 expr.target_value = glib_value;
6358 glib_value.cvalue = cvalue;
6361 public CCodeExpression? get_array_size_cvalue (TargetValue value) {
6362 var glib_value = (GLibValue) value;
6363 return glib_value.array_size_cvalue;
6366 public void set_array_size_cvalue (TargetValue value, CCodeExpression? cvalue) {
6367 var glib_value = (GLibValue) value;
6368 glib_value.array_size_cvalue = cvalue;
6371 public CCodeExpression? get_delegate_target (Expression expr) {
6372 if (expr.target_value == null) {
6373 return null;
6375 var glib_value = (GLibValue) expr.target_value;
6376 return glib_value.delegate_target_cvalue;
6379 public void set_delegate_target (Expression expr, CCodeExpression? delegate_target) {
6380 var glib_value = (GLibValue) expr.target_value;
6381 if (glib_value == null) {
6382 glib_value = new GLibValue (expr.value_type);
6383 expr.target_value = glib_value;
6385 glib_value.delegate_target_cvalue = delegate_target;
6388 public CCodeExpression? get_delegate_target_destroy_notify (Expression expr) {
6389 if (expr.target_value == null) {
6390 return null;
6392 var glib_value = (GLibValue) expr.target_value;
6393 return glib_value.delegate_target_destroy_notify_cvalue;
6396 public void set_delegate_target_destroy_notify (Expression expr, CCodeExpression? destroy_notify) {
6397 var glib_value = (GLibValue) expr.target_value;
6398 if (glib_value == null) {
6399 glib_value = new GLibValue (expr.value_type);
6400 expr.target_value = glib_value;
6402 glib_value.delegate_target_destroy_notify_cvalue = destroy_notify;
6405 public void append_array_length (Expression expr, CCodeExpression size) {
6406 var glib_value = (GLibValue) expr.target_value;
6407 if (glib_value == null) {
6408 glib_value = new GLibValue (expr.value_type);
6409 expr.target_value = glib_value;
6411 glib_value.append_array_length_cvalue (size);
6414 public List<CCodeExpression>? get_array_lengths (Expression expr) {
6415 var glib_value = (GLibValue) expr.target_value;
6416 if (glib_value == null) {
6417 glib_value = new GLibValue (expr.value_type);
6418 expr.target_value = glib_value;
6420 return glib_value.array_length_cvalues;
6423 public bool get_lvalue (TargetValue value) {
6424 var glib_value = (GLibValue) value;
6425 return glib_value.lvalue;
6428 public bool get_non_null (TargetValue value) {
6429 var glib_value = (GLibValue) value;
6430 return glib_value.non_null;
6433 public string? get_ctype (TargetValue value) {
6434 var glib_value = (GLibValue) value;
6435 return glib_value.ctype;
6438 public bool get_array_null_terminated (TargetValue value) {
6439 var glib_value = (GLibValue) value;
6440 return glib_value.array_null_terminated;
6443 public CCodeExpression get_array_length_cexpr (TargetValue value) {
6444 var glib_value = (GLibValue) value;
6445 return glib_value.array_length_cexpr;
6449 internal class Vala.GLibValue : TargetValue {
6450 public CCodeExpression cvalue;
6451 public bool lvalue;
6452 public bool non_null;
6453 public string? ctype;
6455 public List<CCodeExpression> array_length_cvalues;
6456 public CCodeExpression? array_size_cvalue;
6457 public bool array_null_terminated;
6458 public CCodeExpression? array_length_cexpr;
6460 public CCodeExpression? delegate_target_cvalue;
6461 public CCodeExpression? delegate_target_destroy_notify_cvalue;
6463 public GLibValue (DataType? value_type = null, CCodeExpression? cvalue = null, bool lvalue = false) {
6464 base (value_type);
6465 this.cvalue = cvalue;
6466 this.lvalue = lvalue;
6469 public void append_array_length_cvalue (CCodeExpression length_cvalue) {
6470 if (array_length_cvalues == null) {
6471 array_length_cvalues = new ArrayList<CCodeExpression> ();
6473 array_length_cvalues.add (length_cvalue);
6476 public GLibValue copy () {
6477 var result = new GLibValue (value_type.copy (), cvalue, lvalue);
6478 result.actual_value_type = actual_value_type;
6479 result.non_null = non_null;
6480 result.ctype = ctype;
6482 if (array_length_cvalues != null) {
6483 foreach (var cexpr in array_length_cvalues) {
6484 result.append_array_length_cvalue (cexpr);
6487 result.array_size_cvalue = array_size_cvalue;
6488 result.array_null_terminated = array_null_terminated;
6489 result.array_length_cexpr = array_length_cexpr;
6491 result.delegate_target_cvalue = delegate_target_cvalue;
6492 result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify_cvalue;
6494 return result;