1 /* valaccodebasemodule.vala
3 * Copyright (C) 2006-2012 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
27 * Code visitor generating C Code.
29 public abstract class Vala.CCodeBaseModule : CodeGenerator {
30 public class EmitContext {
31 public Symbol? current_symbol;
32 public ArrayList<Symbol> symbol_stack = new ArrayList<Symbol> ();
33 public TryStatement current_try;
34 public 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 Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
42 public Map<string,int> closure_variable_count_map = new HashMap<string,int> (str_hash, str_equal);
43 public Map<LocalVariable,int> closure_variable_clash_map = new HashMap<LocalVariable,int> ();
45 public EmitContext (Symbol? symbol = null) {
46 current_symbol = symbol;
49 public void push_symbol (Symbol symbol) {
50 symbol_stack.add (current_symbol);
51 current_symbol = symbol;
54 public void pop_symbol () {
55 current_symbol = symbol_stack[symbol_stack.size - 1];
56 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 {
86 var sym = current_symbol;
88 if (sym is TypeSymbol) {
89 return (TypeSymbol) sym;
91 sym = sym.parent_symbol;
97 public Class? current_class {
98 get { return current_type_symbol as Class; }
101 public Method? current_method {
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 {
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 {
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 {
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 {
143 var m = current_method;
145 return m.return_type;
148 var acc = current_property_accessor;
151 return acc.value_type;
157 if (is_in_constructor () || is_in_destructor ()) {
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
174 var sym = current_symbol;
175 while (sym != null) {
176 if (sym is Constructor) {
179 sym = sym.parent_symbol;
184 public bool is_in_destructor () {
185 if (current_method != null) {
186 // make sure to not return true in lambda expression inside constructor
189 var sym = current_symbol;
190 while (sym != null) {
191 if (sym is Destructor) {
194 sym = sym.parent_symbol;
199 public Block? current_closure_block {
201 return next_closure_block (current_symbol);
205 public unowned Block? next_closure_block (Symbol sym) {
207 unowned Method method = sym as Method;
208 if (method != null && !method.closure) {
209 // parent blocks are not captured by this method
213 unowned Block block = sym as Block;
214 if (method == null && block == null) {
219 if (block != null && block.captured) {
220 // closure block found
223 sym = sym.parent_symbol;
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;
243 public CCodeFunction ccode { get { return emit_context.ccode; } }
245 /* temporary variables that own their content */
246 public ArrayList<TargetValue> temp_ref_values { get { return emit_context.temp_ref_values; } }
247 /* cache to check whether a certain marshaller has been created yet */
248 public Set<string> user_marshal_set;
249 /* (constant) hash table with all predefined marshallers */
250 public Set<string> predefined_marshal_set;
251 /* (constant) hash table with all reserved identifiers in the generated code */
252 Set<string> reserved_identifiers;
254 public int next_temp_var_id {
255 get { return emit_context.next_temp_var_id; }
256 set { emit_context.next_temp_var_id = value; }
259 public int next_regex_id = 0;
260 public bool in_creation_method { get { return current_method is CreationMethod; } }
262 public bool current_method_inner_error {
263 get { return emit_context.current_method_inner_error; }
264 set { emit_context.current_method_inner_error = value; }
267 public bool current_method_return {
268 get { return emit_context.current_method_return; }
269 set { emit_context.current_method_return = value; }
272 public int next_coroutine_state = 1;
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;
325 public bool in_plugin = false;
326 public string module_init_param_name;
328 public bool gvaluecollector_h_needed;
329 public bool requires_assert;
330 public bool requires_array_free;
331 public bool requires_array_move;
332 public bool requires_array_length;
333 public bool requires_clear_mutex;
335 public Set<string> wrappers;
336 Set<Symbol> generated_external_symbols;
338 public Map<string,string> variable_name_map { get { return emit_context.variable_name_map; } }
340 public static int ccode_attribute_cache_index = CodeNode.get_attribute_cache_index ();
342 public CCodeBaseModule () {
343 predefined_marshal_set = new HashSet<string> (str_hash, str_equal);
344 predefined_marshal_set.add ("VOID:VOID");
345 predefined_marshal_set.add ("VOID:BOOLEAN");
346 predefined_marshal_set.add ("VOID:CHAR");
347 predefined_marshal_set.add ("VOID:UCHAR");
348 predefined_marshal_set.add ("VOID:INT");
349 predefined_marshal_set.add ("VOID:UINT");
350 predefined_marshal_set.add ("VOID:LONG");
351 predefined_marshal_set.add ("VOID:ULONG");
352 predefined_marshal_set.add ("VOID:ENUM");
353 predefined_marshal_set.add ("VOID:FLAGS");
354 predefined_marshal_set.add ("VOID:FLOAT");
355 predefined_marshal_set.add ("VOID:DOUBLE");
356 predefined_marshal_set.add ("VOID:STRING");
357 predefined_marshal_set.add ("VOID:POINTER");
358 predefined_marshal_set.add ("VOID:OBJECT");
359 predefined_marshal_set.add ("STRING:OBJECT,POINTER");
360 predefined_marshal_set.add ("VOID:UINT,POINTER");
361 predefined_marshal_set.add ("BOOLEAN:FLAGS");
363 reserved_identifiers = new HashSet<string> (str_hash, str_equal);
366 reserved_identifiers.add ("_Bool");
367 reserved_identifiers.add ("_Complex");
368 reserved_identifiers.add ("_Imaginary");
369 reserved_identifiers.add ("asm");
370 reserved_identifiers.add ("auto");
371 reserved_identifiers.add ("break");
372 reserved_identifiers.add ("case");
373 reserved_identifiers.add ("char");
374 reserved_identifiers.add ("const");
375 reserved_identifiers.add ("continue");
376 reserved_identifiers.add ("default");
377 reserved_identifiers.add ("do");
378 reserved_identifiers.add ("double");
379 reserved_identifiers.add ("else");
380 reserved_identifiers.add ("enum");
381 reserved_identifiers.add ("extern");
382 reserved_identifiers.add ("float");
383 reserved_identifiers.add ("for");
384 reserved_identifiers.add ("goto");
385 reserved_identifiers.add ("if");
386 reserved_identifiers.add ("inline");
387 reserved_identifiers.add ("int");
388 reserved_identifiers.add ("long");
389 reserved_identifiers.add ("register");
390 reserved_identifiers.add ("restrict");
391 reserved_identifiers.add ("return");
392 reserved_identifiers.add ("short");
393 reserved_identifiers.add ("signed");
394 reserved_identifiers.add ("sizeof");
395 reserved_identifiers.add ("static");
396 reserved_identifiers.add ("struct");
397 reserved_identifiers.add ("switch");
398 reserved_identifiers.add ("typedef");
399 reserved_identifiers.add ("union");
400 reserved_identifiers.add ("unsigned");
401 reserved_identifiers.add ("void");
402 reserved_identifiers.add ("volatile");
403 reserved_identifiers.add ("while");
406 reserved_identifiers.add ("cdecl");
408 // reserved for Vala/GObject naming conventions
409 reserved_identifiers.add ("error");
410 reserved_identifiers.add ("result");
411 reserved_identifiers.add ("self");
414 public override void emit (CodeContext context) {
415 this.context = context;
417 root_symbol = context.root;
419 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
420 char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
421 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
422 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
423 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
424 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
425 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
426 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
427 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
428 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
429 uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8"));
430 int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16"));
431 uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16"));
432 int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32"));
433 uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32"));
434 int64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int64"));
435 uint64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint64"));
436 float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
437 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
438 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
439 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
440 if (unichar_struct != null) {
441 unichar_type = new IntegerType (unichar_struct);
444 var glib_ns = root_symbol.scope.lookup ("GLib");
446 gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
447 gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
448 gerror_type = new ErrorType (null, null);
449 glist_type = (Class) glib_ns.scope.lookup ("List");
450 gslist_type = (Class) glib_ns.scope.lookup ("SList");
451 gnode_type = (Class) glib_ns.scope.lookup ("Node");
452 gqueue_type = (Class) glib_ns.scope.lookup ("Queue");
453 gvaluearray_type = (Class) glib_ns.scope.lookup ("ValueArray");
454 gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
455 garray_type = (TypeSymbol) glib_ns.scope.lookup ("Array");
456 gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
457 gptrarray_type = (TypeSymbol) glib_ns.scope.lookup ("PtrArray");
458 gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
459 gdestroynotify_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("DestroyNotify"));
461 gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
462 gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
463 gvariant_type = (Class) glib_ns.scope.lookup ("Variant");
464 gsource_type = (Class) glib_ns.scope.lookup ("Source");
466 if (context.require_glib_version (2, 32)) {
467 gmutex_type = (Struct) glib_ns.scope.lookup ("Mutex");
468 grecmutex_type = (Struct) glib_ns.scope.lookup ("RecMutex");
469 grwlock_type = (Struct) glib_ns.scope.lookup ("RWLock");
470 gcond_type = (Struct) glib_ns.scope.lookup ("Cond");
472 mutex_type = grecmutex_type;
474 mutex_type = (Struct) glib_ns.scope.lookup ("StaticRecMutex");
477 type_module_type = (TypeSymbol) glib_ns.scope.lookup ("TypeModule");
479 regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
481 if (context.module_init_method != null) {
482 foreach (Parameter parameter in context.module_init_method.get_parameters ()) {
483 if (parameter.variable_type.data_type == type_module_type) {
485 module_init_param_name = parameter.name;
490 Report.error (context.module_init_method.source_reference, "[ModuleInit] requires a parameter of type `GLib.TypeModule'");
494 dbus_proxy_type = (TypeSymbol) glib_ns.scope.lookup ("DBusProxy");
496 header_file = new CCodeFile ();
497 header_file.is_header = true;
498 internal_header_file = new CCodeFile ();
499 internal_header_file.is_header = true;
501 /* we're only interested in non-pkg source files */
502 var source_files = context.get_source_files ();
503 foreach (SourceFile file in source_files) {
504 if (file.file_type == SourceFileType.SOURCE ||
505 (context.header_filename != null && file.file_type == SourceFileType.FAST)) {
510 // generate symbols file for public API
511 if (context.symbols_filename != null) {
512 var stream = FileStream.open (context.symbols_filename, "w");
513 if (stream == null) {
514 Report.error (null, "unable to open `%s' for writing".printf (context.symbols_filename));
518 foreach (string symbol in header_file.get_symbols ()) {
519 stream.puts (symbol);
526 // generate C header file for public API
527 if (context.header_filename != null) {
528 bool ret = header_file.store (context.header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
530 Report.error (null, "unable to open `%s' for writing".printf (context.header_filename));
534 // generate C header file for internal API
535 if (context.internal_header_filename != null) {
536 bool ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
538 Report.error (null, "unable to open `%s' for writing".printf (context.internal_header_filename));
543 public void push_context (EmitContext emit_context) {
544 if (this.emit_context != null) {
545 emit_context_stack.add (this.emit_context);
548 this.emit_context = emit_context;
550 ccode.current_line = current_line;
554 public void pop_context () {
555 if (emit_context_stack.size > 0) {
556 this.emit_context = emit_context_stack[emit_context_stack.size - 1];
557 emit_context_stack.remove_at (emit_context_stack.size - 1);
559 ccode.current_line = current_line;
562 this.emit_context = null;
566 public void push_line (SourceReference? source_reference) {
567 line_directive_stack.add (current_line);
568 if (source_reference != null) {
569 current_line = new CCodeLineDirective (source_reference.file.filename, source_reference.begin.line);
571 ccode.current_line = current_line;
576 public void pop_line () {
577 current_line = line_directive_stack[line_directive_stack.size - 1];
578 line_directive_stack.remove_at (line_directive_stack.size - 1);
580 ccode.current_line = current_line;
584 public void push_function (CCodeFunction func) {
585 emit_context.ccode_stack.add (ccode);
586 emit_context.ccode = func;
587 ccode.current_line = current_line;
590 public void pop_function () {
591 emit_context.ccode = emit_context.ccode_stack[emit_context.ccode_stack.size - 1];
592 emit_context.ccode_stack.remove_at (emit_context.ccode_stack.size - 1);
594 ccode.current_line = current_line;
598 public bool add_symbol_declaration (CCodeFile decl_space, Symbol sym, string name) {
599 if (decl_space.add_declaration (name)) {
602 if (sym.source_reference != null) {
603 sym.source_reference.file.used = true;
605 if (sym.external_package || (!decl_space.is_header && CodeContext.get ().use_header && !sym.is_internal_symbol ())) {
606 // add appropriate include file
607 foreach (string header_filename in get_ccode_header_filenames (sym).split (",")) {
608 decl_space.add_include (header_filename, !sym.external_package ||
609 (sym.external_package &&
610 sym.from_commandline));
612 // declaration complete
615 // require declaration
620 public CCodeIdentifier get_value_setter_function (DataType type_reference) {
621 var array_type = type_reference as ArrayType;
622 if (type_reference.data_type != null) {
623 return new CCodeIdentifier (get_ccode_set_value_function (type_reference.data_type));
624 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
626 return new CCodeIdentifier ("g_value_set_boxed");
628 return new CCodeIdentifier ("g_value_set_pointer");
632 public CCodeIdentifier get_value_taker_function (DataType type_reference) {
633 var array_type = type_reference as ArrayType;
634 if (type_reference.data_type != null) {
635 return new CCodeIdentifier (get_ccode_take_value_function (type_reference.data_type));
636 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
638 return new CCodeIdentifier ("g_value_take_boxed");
640 return new CCodeIdentifier ("g_value_set_pointer");
644 CCodeIdentifier get_value_getter_function (DataType type_reference) {
645 var array_type = type_reference as ArrayType;
646 if (type_reference.data_type != null) {
647 return new CCodeIdentifier (get_ccode_get_value_function (type_reference.data_type));
648 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
650 return new CCodeIdentifier ("g_value_get_boxed");
652 return new CCodeIdentifier ("g_value_get_pointer");
656 public virtual void append_vala_array_free () {
659 public virtual void append_vala_array_move () {
662 public virtual void append_vala_array_length () {
665 public void append_vala_clear_mutex (string typename, string funcprefix) {
667 cfile.add_include ("string.h");
669 var fun = new CCodeFunction ("_vala_clear_" + typename);
670 fun.modifiers = CCodeModifiers.STATIC;
671 fun.add_parameter (new CCodeParameter ("mutex", typename + " *"));
675 ccode.add_declaration (typename, new CCodeVariableDeclarator.zero ("zero_mutex", new CCodeConstant ("{ 0 }")));
677 var cmp = new CCodeFunctionCall (new CCodeIdentifier ("memcmp"));
678 cmp.add_argument (new CCodeIdentifier ("mutex"));
679 cmp.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("zero_mutex")));
680 cmp.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
683 var mutex_clear = new CCodeFunctionCall (new CCodeIdentifier (funcprefix + "_clear"));
684 mutex_clear.add_argument (new CCodeIdentifier ("mutex"));
685 ccode.add_expression (mutex_clear);
687 var mset = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
688 mset.add_argument (new CCodeIdentifier ("mutex"));
689 mset.add_argument (new CCodeConstant ("0"));
690 mset.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
691 ccode.add_expression (mset);
697 cfile.add_function_declaration (fun);
698 cfile.add_function (fun);
701 public override void visit_source_file (SourceFile source_file) {
702 cfile = new CCodeFile ();
704 user_marshal_set = new HashSet<string> (str_hash, str_equal);
708 gvaluecollector_h_needed = false;
709 requires_assert = false;
710 requires_array_free = false;
711 requires_array_move = false;
712 requires_array_length = false;
713 requires_clear_mutex = false;
715 wrappers = new HashSet<string> (str_hash, str_equal);
716 generated_external_symbols = new HashSet<Symbol> ();
718 header_file.add_include ("glib.h");
719 internal_header_file.add_include ("glib.h");
720 cfile.add_include ("glib.h");
721 cfile.add_include ("glib-object.h");
723 source_file.accept_children (this);
725 if (context.report.get_errors () > 0) {
729 /* For fast-vapi, we only wanted the header declarations
730 * to be emitted, so bail out here without writing the
733 if (source_file.file_type == SourceFileType.FAST) {
737 if (requires_assert) {
738 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);")));
740 if (requires_array_free) {
741 append_vala_array_free ();
743 if (requires_array_move) {
744 append_vala_array_move ();
746 if (requires_array_length) {
747 append_vala_array_length ();
749 if (requires_clear_mutex) {
750 append_vala_clear_mutex ("GMutex", "g_mutex");
751 append_vala_clear_mutex ("GRecMutex", "g_rec_mutex");
752 append_vala_clear_mutex ("GRWLock", "g_rw_lock");
753 append_vala_clear_mutex ("GCond", "g_cond");
756 if (gvaluecollector_h_needed) {
757 cfile.add_include ("gobject/gvaluecollector.h");
760 var comments = source_file.get_comments();
761 if (comments != null) {
762 foreach (Comment comment in comments) {
763 var ccomment = new CCodeComment (comment.content);
764 cfile.add_comment (ccomment);
768 if (!cfile.store (source_file.get_csource_filename (), source_file.filename, context.version_header, context.debug)) {
769 Report.error (null, "unable to open `%s' for writing".printf (source_file.get_csource_filename ()));
775 public virtual bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
776 if (add_symbol_declaration (decl_space, en, get_ccode_name (en))) {
780 var cenum = new CCodeEnum (get_ccode_name (en));
782 cenum.deprecated = en.deprecated;
785 foreach (EnumValue ev in en.get_values ()) {
787 if (ev.value == null) {
788 c_ev = new CCodeEnumValue (get_ccode_name (ev));
790 c_ev.value = new CCodeConstant ("1 << %d".printf (flag_shift));
794 ev.value.emit (this);
795 c_ev = new CCodeEnumValue (get_ccode_name (ev), get_cvalue (ev.value));
797 c_ev.deprecated = ev.deprecated;
798 cenum.add_value (c_ev);
801 decl_space.add_type_definition (cenum);
802 decl_space.add_type_definition (new CCodeNewline ());
804 if (!get_ccode_has_type_id (en)) {
808 decl_space.add_type_declaration (new CCodeNewline ());
810 var macro = "(%s_get_type ())".printf (get_ccode_lower_case_name (en, null));
811 decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (en), macro));
813 var fun_name = "%s_get_type".printf (get_ccode_lower_case_name (en, null));
814 var regfun = new CCodeFunction (fun_name, "GType");
815 regfun.attributes = "G_GNUC_CONST";
817 if (en.access == SymbolAccessibility.PRIVATE) {
818 regfun.modifiers = CCodeModifiers.STATIC;
819 // avoid C warning as this function is not always used
820 regfun.attributes = "G_GNUC_UNUSED";
823 decl_space.add_function_declaration (regfun);
828 public override void visit_enum (Enum en) {
829 push_line (en.source_reference);
831 en.accept_children (this);
833 if (en.comment != null) {
834 cfile.add_type_member_definition (new CCodeComment (en.comment.content));
837 generate_enum_declaration (en, cfile);
839 if (!en.is_internal_symbol ()) {
840 generate_enum_declaration (en, header_file);
842 if (!en.is_private_symbol ()) {
843 generate_enum_declaration (en, internal_header_file);
849 public void visit_member (Symbol m) {
850 /* stuff meant for all lockable members */
851 if (m is Lockable && ((Lockable) m).get_lock_used ()) {
852 CCodeExpression l = new CCodeIdentifier ("self");
853 var init_context = class_init_context;
854 var finalize_context = class_finalize_context;
856 if (m.is_instance_member ()) {
857 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (m.name));
858 init_context = instance_init_context;
859 finalize_context = instance_finalize_context;
860 } else if (m.is_class_member ()) {
861 TypeSymbol parent = (TypeSymbol)m.parent_symbol;
863 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(get_ccode_upper_case_name (parent))));
864 get_class_private_call.add_argument (new CCodeIdentifier ("klass"));
865 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (m.name));
867 l = new CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf(get_ccode_lower_case_name (m.parent_symbol), m.name)));
870 push_context (init_context);
871 var initf = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.default_construction_method)));
872 initf.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
873 ccode.add_expression (initf);
876 if (finalize_context != null) {
878 if (context.require_glib_version (2, 32)) {
879 mutex_clear = "g_rec_mutex_clear";
881 mutex_clear = "g_static_rec_mutex_free";
884 push_context (finalize_context);
885 var fc = new CCodeFunctionCall (new CCodeIdentifier (mutex_clear));
886 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
887 ccode.add_expression (fc);
893 public void generate_constant_declaration (Constant c, CCodeFile decl_space, bool definition = false) {
894 if (c.parent_symbol is Block) {
899 if (add_symbol_declaration (decl_space, c, get_ccode_name (c))) {
904 generate_type_declaration (c.type_reference, decl_space);
908 var initializer_list = c.value as InitializerList;
909 if (initializer_list != null) {
910 var cdecl = new CCodeDeclaration (get_ccode_const_name (c.type_reference));
912 if (c.type_reference is ArrayType) {
913 arr = "[%d]".printf (initializer_list.size);
916 var cinitializer = get_cvalue (c.value);
918 // never output value in header
919 // special case needed as this method combines declaration and definition
923 cdecl.add_declarator (new CCodeVariableDeclarator ("%s%s".printf (get_ccode_name (c), arr), cinitializer));
924 if (c.is_private_symbol ()) {
925 cdecl.modifiers = CCodeModifiers.STATIC;
927 cdecl.modifiers = CCodeModifiers.EXTERN;
930 decl_space.add_constant_declaration (cdecl);
932 var cdefine = new CCodeMacroReplacement.with_expression (get_ccode_name (c), get_cvalue (c.value));
933 decl_space.add_type_member_declaration (cdefine);
938 public override void visit_constant (Constant c) {
939 push_line (c.source_reference);
941 if (c.parent_symbol is Block) {
944 generate_type_declaration (c.type_reference, cfile);
948 string type_name = get_ccode_const_name (c.type_reference);
950 if (c.type_reference is ArrayType) {
954 if (c.type_reference.compatible (string_type)) {
955 type_name = "const char";
959 var cinitializer = get_cvalue (c.value);
961 ccode.add_declaration (type_name, new CCodeVariableDeclarator ("%s%s".printf (get_ccode_name (c), arr), cinitializer), CCodeModifiers.STATIC);
963 generate_constant_declaration (c, cfile, true);
965 if (!c.is_internal_symbol ()) {
966 generate_constant_declaration (c, header_file);
968 if (!c.is_private_symbol ()) {
969 generate_constant_declaration (c, internal_header_file);
976 public void generate_field_declaration (Field f, CCodeFile decl_space) {
977 if (add_symbol_declaration (decl_space, f, get_ccode_name (f))) {
981 generate_type_declaration (f.variable_type, decl_space);
983 string field_ctype = get_ccode_name (f.variable_type);
985 field_ctype = "volatile " + field_ctype;
988 var cdecl = new CCodeDeclaration (field_ctype);
989 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type)));
990 if (f.is_private_symbol ()) {
991 cdecl.modifiers = CCodeModifiers.STATIC;
993 cdecl.modifiers = CCodeModifiers.EXTERN;
996 cdecl.modifiers |= CCodeModifiers.DEPRECATED;
998 decl_space.add_type_member_declaration (cdecl);
1000 if (f.get_lock_used ()) {
1001 // Declare mutex for static member
1002 var flock = new CCodeDeclaration (get_ccode_name (mutex_type));
1003 var flock_decl = new CCodeVariableDeclarator (get_symbol_lock_name (get_ccode_name (f)), new CCodeConstant ("{0}"));
1004 flock.add_declarator (flock_decl);
1006 if (f.is_private_symbol ()) {
1007 flock.modifiers = CCodeModifiers.STATIC;
1009 flock.modifiers = CCodeModifiers.EXTERN;
1011 decl_space.add_type_member_declaration (flock);
1014 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1015 var array_type = (ArrayType) f.variable_type;
1017 if (!array_type.fixed_length) {
1018 for (int dim = 1; dim <= array_type.rank; dim++) {
1019 var len_type = int_type.copy ();
1021 cdecl = new CCodeDeclaration (get_ccode_name (len_type));
1022 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_length_cname (get_ccode_name (f), dim)));
1023 if (f.is_private_symbol ()) {
1024 cdecl.modifiers = CCodeModifiers.STATIC;
1026 cdecl.modifiers = CCodeModifiers.EXTERN;
1028 decl_space.add_type_member_declaration (cdecl);
1031 } else if (f.variable_type is DelegateType) {
1032 var delegate_type = (DelegateType) f.variable_type;
1033 if (delegate_type.delegate_symbol.has_target) {
1034 // create field to store delegate target
1036 cdecl = new CCodeDeclaration ("gpointer");
1037 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f)));
1038 if (f.is_private_symbol ()) {
1039 cdecl.modifiers = CCodeModifiers.STATIC;
1041 cdecl.modifiers = CCodeModifiers.EXTERN;
1043 decl_space.add_type_member_declaration (cdecl);
1045 if (delegate_type.value_owned) {
1046 cdecl = new CCodeDeclaration ("GDestroyNotify");
1047 cdecl.add_declarator (new CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (get_ccode_name (f))));
1048 if (f.is_private_symbol ()) {
1049 cdecl.modifiers = CCodeModifiers.STATIC;
1051 cdecl.modifiers = CCodeModifiers.EXTERN;
1053 decl_space.add_type_member_declaration (cdecl);
1059 public override void visit_field (Field f) {
1060 push_line (f.source_reference);
1063 check_type (f.variable_type);
1065 var cl = f.parent_symbol as Class;
1066 bool is_gtypeinstance = (cl != null && !cl.is_compact);
1068 CCodeExpression lhs = null;
1070 string field_ctype = get_ccode_name (f.variable_type);
1071 if (f.is_volatile) {
1072 field_ctype = "volatile " + field_ctype;
1075 if (f.binding == MemberBinding.INSTANCE) {
1076 if (is_gtypeinstance && f.access == SymbolAccessibility.PRIVATE) {
1077 lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), get_ccode_name (f));
1079 lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_ccode_name (f));
1082 if (f.initializer != null) {
1083 push_context (instance_init_context);
1085 f.initializer.emit (this);
1087 var rhs = get_cvalue (f.initializer);
1089 ccode.add_assignment (lhs, rhs);
1091 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1092 var array_type = (ArrayType) f.variable_type;
1093 var field_value = get_field_cvalue (f, load_this_parameter ((TypeSymbol) f.parent_symbol));
1095 var glib_value = (GLibValue) f.initializer.target_value;
1096 if (glib_value.array_length_cvalues != null) {
1097 for (int dim = 1; dim <= array_type.rank; dim++) {
1098 var array_len_lhs = get_array_length_cvalue (field_value, dim);
1099 ccode.add_assignment (array_len_lhs, get_array_length_cvalue (glib_value, dim));
1101 } else if (glib_value.array_null_terminated) {
1102 requires_array_length = true;
1103 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1104 len_call.add_argument (get_cvalue_ (glib_value));
1106 ccode.add_assignment (get_array_length_cvalue (field_value, 1), len_call);
1108 for (int dim = 1; dim <= array_type.rank; dim++) {
1109 ccode.add_assignment (get_array_length_cvalue (field_value, dim), new CCodeConstant ("-1"));
1113 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1114 var lhs_array_size = get_array_size_cvalue (field_value);
1115 var rhs_array_len = get_array_length_cvalue (field_value, 1);
1116 ccode.add_assignment (lhs_array_size, rhs_array_len);
1120 foreach (var value in temp_ref_values) {
1121 ccode.add_expression (destroy_value (value));
1124 temp_ref_values.clear ();
1129 if (requires_destroy (f.variable_type) && instance_finalize_context != null) {
1130 push_context (instance_finalize_context);
1131 ccode.add_expression (destroy_field (f, load_this_parameter ((TypeSymbol) f.parent_symbol)));
1134 } else if (f.binding == MemberBinding.CLASS) {
1135 if (!is_gtypeinstance) {
1136 Report.error (f.source_reference, "class fields are not supported in compact classes");
1141 if (f.access == SymbolAccessibility.PRIVATE) {
1142 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (get_ccode_upper_case_name (cl))));
1143 ccall.add_argument (new CCodeIdentifier ("klass"));
1144 lhs = new CCodeMemberAccess (ccall, get_ccode_name (f), true);
1146 lhs = new CCodeMemberAccess (new CCodeIdentifier ("klass"), get_ccode_name (f), true);
1149 if (f.initializer != null) {
1150 push_context (class_init_context);
1152 f.initializer.emit (this);
1154 var rhs = get_cvalue (f.initializer);
1156 ccode.add_assignment (lhs, rhs);
1158 foreach (var value in temp_ref_values) {
1159 ccode.add_expression (destroy_value (value));
1162 temp_ref_values.clear ();
1167 generate_field_declaration (f, cfile);
1169 if (!f.is_internal_symbol ()) {
1170 generate_field_declaration (f, header_file);
1172 if (!f.is_private_symbol ()) {
1173 generate_field_declaration (f, internal_header_file);
1177 lhs = new CCodeIdentifier (get_ccode_name (f));
1179 var var_decl = new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type));
1180 var_decl.initializer = default_value_for_type (f.variable_type, true);
1182 if (class_init_context != null) {
1183 push_context (class_init_context);
1185 push_context (new EmitContext ());
1188 if (f.initializer != null) {
1189 f.initializer.emit (this);
1191 var init = get_cvalue (f.initializer);
1192 if (is_constant_ccode_expression (init)) {
1193 var_decl.initializer = init;
1197 var var_def = new CCodeDeclaration (field_ctype);
1198 var_def.add_declarator (var_decl);
1199 if (!f.is_private_symbol ()) {
1200 var_def.modifiers = CCodeModifiers.EXTERN;
1202 var_def.modifiers = CCodeModifiers.STATIC;
1204 cfile.add_type_member_declaration (var_def);
1206 /* add array length fields where necessary */
1207 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1208 var array_type = (ArrayType) f.variable_type;
1210 if (!array_type.fixed_length) {
1211 for (int dim = 1; dim <= array_type.rank; dim++) {
1212 var len_type = int_type.copy ();
1214 var len_def = new CCodeDeclaration (get_ccode_name (len_type));
1215 len_def.add_declarator (new CCodeVariableDeclarator (get_array_length_cname (get_ccode_name (f), dim), new CCodeConstant ("0")));
1216 if (!f.is_private_symbol ()) {
1217 len_def.modifiers = CCodeModifiers.EXTERN;
1219 len_def.modifiers = CCodeModifiers.STATIC;
1221 cfile.add_type_member_declaration (len_def);
1224 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1225 var len_type = int_type.copy ();
1227 var cdecl = new CCodeDeclaration (get_ccode_name (len_type));
1228 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_size_cname (get_ccode_name (f)), new CCodeConstant ("0")));
1229 cdecl.modifiers = CCodeModifiers.STATIC;
1230 cfile.add_type_member_declaration (cdecl);
1233 } else if (f.variable_type is DelegateType) {
1234 var delegate_type = (DelegateType) f.variable_type;
1235 if (delegate_type.delegate_symbol.has_target) {
1236 // create field to store delegate target
1238 var target_def = new CCodeDeclaration ("gpointer");
1239 target_def.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f), new CCodeConstant ("NULL")));
1240 if (!f.is_private_symbol ()) {
1241 target_def.modifiers = CCodeModifiers.EXTERN;
1243 target_def.modifiers = CCodeModifiers.STATIC;
1245 cfile.add_type_member_declaration (target_def);
1247 if (delegate_type.value_owned) {
1248 var target_destroy_notify_def = new CCodeDeclaration ("GDestroyNotify");
1249 target_destroy_notify_def.add_declarator (new CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (get_ccode_name (f)), new CCodeConstant ("NULL")));
1250 if (!f.is_private_symbol ()) {
1251 target_destroy_notify_def.modifiers = CCodeModifiers.EXTERN;
1253 target_destroy_notify_def.modifiers = CCodeModifiers.STATIC;
1255 cfile.add_type_member_declaration (target_destroy_notify_def);
1261 if (f.initializer != null) {
1262 var rhs = get_cvalue (f.initializer);
1263 if (!is_constant_ccode_expression (rhs)) {
1264 if (is_gtypeinstance) {
1265 if (f.initializer is InitializerList) {
1266 ccode.open_block ();
1268 var temp_decl = get_temp_variable (f.variable_type);
1269 var vardecl = new CCodeVariableDeclarator.zero (temp_decl.name, rhs);
1270 ccode.add_declaration (get_ccode_name (temp_decl.variable_type), vardecl);
1272 var tmp = get_variable_cexpression (get_variable_cname (temp_decl.name));
1273 ccode.add_assignment (lhs, tmp);
1277 ccode.add_assignment (lhs, rhs);
1280 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1281 var array_type = (ArrayType) f.variable_type;
1282 var field_value = get_field_cvalue (f, null);
1284 var glib_value = (GLibValue) f.initializer.target_value;
1285 if (glib_value.array_length_cvalues != null) {
1286 for (int dim = 1; dim <= array_type.rank; dim++) {
1287 var array_len_lhs = get_array_length_cvalue (field_value, dim);
1288 ccode.add_assignment (array_len_lhs, get_array_length_cvalue (glib_value, dim));
1290 } else if (glib_value.array_null_terminated) {
1291 requires_array_length = true;
1292 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1293 len_call.add_argument (get_cvalue_ (glib_value));
1295 ccode.add_assignment (get_array_length_cvalue (field_value, 1), len_call);
1297 for (int dim = 1; dim <= array_type.rank; dim++) {
1298 ccode.add_assignment (get_array_length_cvalue (field_value, dim), new CCodeConstant ("-1"));
1304 Report.error (f.source_reference, "Non-constant field initializers not supported in this context");
1317 public bool is_constant_ccode_expression (CCodeExpression cexpr) {
1318 if (cexpr is CCodeConstant) {
1320 } else if (cexpr is CCodeCastExpression) {
1321 var ccast = (CCodeCastExpression) cexpr;
1322 return is_constant_ccode_expression (ccast.inner);
1323 } else if (cexpr is CCodeBinaryExpression) {
1324 var cbinary = (CCodeBinaryExpression) cexpr;
1325 return is_constant_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1328 var cparenthesized = (cexpr as CCodeParenthesizedExpression);
1329 return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
1333 * Returns whether the passed cexpr is a pure expression, i.e. an
1334 * expression without side-effects.
1336 public bool is_pure_ccode_expression (CCodeExpression cexpr) {
1337 if (cexpr is CCodeConstant || cexpr is CCodeIdentifier) {
1339 } else if (cexpr is CCodeBinaryExpression) {
1340 var cbinary = (CCodeBinaryExpression) cexpr;
1341 return is_pure_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1342 } else if (cexpr is CCodeUnaryExpression) {
1343 var cunary = (CCodeUnaryExpression) cexpr;
1344 switch (cunary.operator) {
1345 case CCodeUnaryOperator.PREFIX_INCREMENT:
1346 case CCodeUnaryOperator.PREFIX_DECREMENT:
1347 case CCodeUnaryOperator.POSTFIX_INCREMENT:
1348 case CCodeUnaryOperator.POSTFIX_DECREMENT:
1351 return is_pure_ccode_expression (cunary.inner);
1353 } else if (cexpr is CCodeMemberAccess) {
1354 var cma = (CCodeMemberAccess) cexpr;
1355 return is_pure_ccode_expression (cma.inner);
1356 } else if (cexpr is CCodeElementAccess) {
1357 var cea = (CCodeElementAccess) cexpr;
1358 return is_pure_ccode_expression (cea.container) && is_pure_ccode_expression (cea.index);
1359 } else if (cexpr is CCodeCastExpression) {
1360 var ccast = (CCodeCastExpression) cexpr;
1361 return is_pure_ccode_expression (ccast.inner);
1362 } else if (cexpr is CCodeParenthesizedExpression) {
1363 var cparenthesized = (CCodeParenthesizedExpression) cexpr;
1364 return is_pure_ccode_expression (cparenthesized.inner);
1370 public override void visit_formal_parameter (Parameter p) {
1372 check_type (p.variable_type);
1376 public override void visit_property (Property prop) {
1377 visit_member (prop);
1379 check_type (prop.property_type);
1381 if (prop.get_accessor != null) {
1382 prop.get_accessor.accept (this);
1384 if (prop.set_accessor != null) {
1385 prop.set_accessor.accept (this);
1389 public void generate_type_declaration (DataType type, CCodeFile decl_space) {
1390 if (type is ObjectType) {
1391 var object_type = (ObjectType) type;
1392 if (object_type.type_symbol is Class) {
1393 generate_class_declaration ((Class) object_type.type_symbol, decl_space);
1394 } else if (object_type.type_symbol is Interface) {
1395 generate_interface_declaration ((Interface) object_type.type_symbol, decl_space);
1397 } else if (type is DelegateType) {
1398 var deleg_type = (DelegateType) type;
1399 var d = deleg_type.delegate_symbol;
1400 generate_delegate_declaration (d, decl_space);
1401 } else if (type.data_type is Enum) {
1402 var en = (Enum) type.data_type;
1403 generate_enum_declaration (en, decl_space);
1404 } else if (type is ValueType) {
1405 var value_type = (ValueType) type;
1406 generate_struct_declaration ((Struct) value_type.type_symbol, decl_space);
1407 } else if (type is ArrayType) {
1408 var array_type = (ArrayType) type;
1409 generate_type_declaration (array_type.element_type, decl_space);
1410 } else if (type is ErrorType) {
1411 var error_type = (ErrorType) type;
1412 if (error_type.error_domain != null) {
1413 generate_error_domain_declaration (error_type.error_domain, decl_space);
1415 } else if (type is PointerType) {
1416 var pointer_type = (PointerType) type;
1417 generate_type_declaration (pointer_type.base_type, decl_space);
1420 foreach (DataType type_arg in type.get_type_arguments ()) {
1421 generate_type_declaration (type_arg, decl_space);
1425 public virtual void generate_class_struct_declaration (Class cl, CCodeFile decl_space) {
1428 public virtual void generate_struct_declaration (Struct st, CCodeFile decl_space) {
1431 public virtual void generate_delegate_declaration (Delegate d, CCodeFile decl_space) {
1434 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) {
1437 public void generate_property_accessor_declaration (PropertyAccessor acc, CCodeFile decl_space) {
1438 if (add_symbol_declaration (decl_space, acc, get_ccode_name (acc))) {
1442 var prop = (Property) acc.prop;
1444 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1447 CCodeParameter cvalueparam;
1448 if (returns_real_struct) {
1449 cvalueparam = new CCodeParameter ("result", get_ccode_name (acc.value_type) + "*");
1450 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1451 cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type) + "*");
1453 cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1455 generate_type_declaration (acc.value_type, decl_space);
1457 CCodeFunction function;
1458 if (acc.readable && !returns_real_struct) {
1459 function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (acc.value_type));
1461 function = new CCodeFunction (get_ccode_name (acc), "void");
1464 if (prop.binding == MemberBinding.INSTANCE) {
1465 var t = (TypeSymbol) prop.parent_symbol;
1466 var this_type = get_data_type_for_symbol (t);
1467 generate_type_declaration (this_type, decl_space);
1468 var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1469 if (t is Struct && !((Struct) t).is_simple_type ()) {
1470 cselfparam.type_name += "*";
1473 function.add_parameter (cselfparam);
1476 if (acc.writable || acc.construction || returns_real_struct) {
1477 function.add_parameter (cvalueparam);
1480 if (acc.value_type is ArrayType) {
1481 var array_type = (ArrayType) acc.value_type;
1483 var length_ctype = "int";
1485 length_ctype = "int*";
1488 for (int dim = 1; dim <= array_type.rank; dim++) {
1489 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), length_ctype));
1491 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1492 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1493 if (!acc.readable && acc.value_type.value_owned) {
1494 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1498 if (prop.is_private_symbol () || (!acc.readable && !acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1499 function.modifiers |= CCodeModifiers.STATIC;
1501 decl_space.add_function_declaration (function);
1504 public override void visit_property_accessor (PropertyAccessor acc) {
1505 push_context (new EmitContext (acc));
1506 push_line (acc.source_reference);
1508 var prop = (Property) acc.prop;
1510 if (acc.comment != null) {
1511 cfile.add_type_member_definition (new CCodeComment (acc.comment.content));
1514 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1516 if (acc.result_var != null) {
1517 acc.result_var.accept (this);
1520 var t = (TypeSymbol) prop.parent_symbol;
1522 if (acc.construction && !t.is_subtype_of (gobject_type)) {
1523 Report.error (acc.source_reference, "construct properties require GLib.Object");
1526 } else if (acc.construction && !is_gobject_property (prop)) {
1527 Report.error (acc.source_reference, "construct properties not supported for specified property type");
1532 // do not declare overriding properties and interface implementations
1533 if (prop.is_abstract || prop.is_virtual
1534 || (prop.base_property == null && prop.base_interface_property == null)) {
1535 generate_property_accessor_declaration (acc, cfile);
1537 // do not declare construct-only properties in header files
1538 if (acc.readable || acc.writable) {
1539 if (!prop.is_internal_symbol ()
1540 && (acc.access == SymbolAccessibility.PUBLIC
1541 || acc.access == SymbolAccessibility.PROTECTED)) {
1542 generate_property_accessor_declaration (acc, header_file);
1544 if (!prop.is_private_symbol () && acc.access != SymbolAccessibility.PRIVATE) {
1545 generate_property_accessor_declaration (acc, internal_header_file);
1550 if (acc.source_type == SourceFileType.FAST) {
1555 var this_type = get_data_type_for_symbol (t);
1556 var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1557 if (t is Struct && !((Struct) t).is_simple_type ()) {
1558 cselfparam.type_name += "*";
1560 CCodeParameter cvalueparam;
1561 if (returns_real_struct) {
1562 cvalueparam = new CCodeParameter ("result", get_ccode_name (acc.value_type) + "*");
1563 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1564 cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type) + "*");
1566 cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1569 if (prop.is_abstract || prop.is_virtual) {
1570 CCodeFunction function;
1571 if (acc.readable && !returns_real_struct) {
1572 function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (current_return_type));
1574 function = new CCodeFunction (get_ccode_name (acc), "void");
1576 function.add_parameter (cselfparam);
1577 if (acc.writable || acc.construction || returns_real_struct) {
1578 function.add_parameter (cvalueparam);
1581 if (acc.value_type is ArrayType) {
1582 var array_type = (ArrayType) acc.value_type;
1584 var length_ctype = "int";
1586 length_ctype = "int*";
1589 for (int dim = 1; dim <= array_type.rank; dim++) {
1590 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), length_ctype));
1592 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1593 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1594 if (!acc.readable && acc.value_type.value_owned) {
1595 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1599 if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1600 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1601 function.modifiers |= CCodeModifiers.STATIC;
1604 push_function (function);
1606 if (prop.binding == MemberBinding.INSTANCE) {
1607 if (!acc.readable || returns_real_struct) {
1608 create_property_type_check_statement (prop, false, t, true, "self");
1610 create_property_type_check_statement (prop, true, t, true, "self");
1614 CCodeFunctionCall vcast = null;
1615 if (prop.parent_symbol is Interface) {
1616 var iface = (Interface) prop.parent_symbol;
1618 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface, null))));
1620 var cl = (Class) prop.parent_symbol;
1622 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (cl, null))));
1624 vcast.add_argument (new CCodeIdentifier ("self"));
1627 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
1628 vcall.add_argument (new CCodeIdentifier ("self"));
1629 if (returns_real_struct) {
1630 vcall.add_argument (new CCodeIdentifier ("result"));
1631 ccode.add_expression (vcall);
1633 if (acc.value_type is ArrayType) {
1634 var array_type = (ArrayType) acc.value_type;
1636 for (int dim = 1; dim <= array_type.rank; dim++) {
1637 var len_expr = new CCodeIdentifier (get_array_length_cname ("result", dim));
1638 vcall.add_argument (len_expr);
1640 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1641 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("result")));
1644 ccode.add_return (vcall);
1647 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
1648 vcall.add_argument (new CCodeIdentifier ("self"));
1649 vcall.add_argument (new CCodeIdentifier ("value"));
1651 if (acc.value_type is ArrayType) {
1652 var array_type = (ArrayType) acc.value_type;
1654 for (int dim = 1; dim <= array_type.rank; dim++) {
1655 var len_expr = new CCodeIdentifier (get_array_length_cname ("value", dim));
1656 vcall.add_argument (len_expr);
1658 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1659 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("value")));
1660 if (!acc.readable && acc.value_type.value_owned) {
1661 vcall.add_argument (new CCodeIdentifier (get_delegate_target_destroy_notify_cname ("value")));
1665 ccode.add_expression (vcall);
1670 cfile.add_function (function);
1673 if (!prop.is_abstract) {
1674 bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
1676 string cname = get_ccode_real_name (acc);
1678 CCodeFunction function;
1679 if (acc.writable || acc.construction || returns_real_struct) {
1680 function = new CCodeFunction (cname, "void");
1682 function = new CCodeFunction (cname, get_ccode_name (acc.value_type));
1685 ObjectType base_type = null;
1686 if (prop.binding == MemberBinding.INSTANCE) {
1688 if (prop.base_property != null) {
1689 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
1690 } else if (prop.base_interface_property != null) {
1691 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
1693 function.modifiers |= CCodeModifiers.STATIC;
1694 function.add_parameter (new CCodeParameter ("base", get_ccode_name (base_type)));
1696 function.add_parameter (cselfparam);
1699 if (acc.writable || acc.construction || returns_real_struct) {
1700 function.add_parameter (cvalueparam);
1703 if (acc.value_type is ArrayType) {
1704 var array_type = (ArrayType) acc.value_type;
1706 var length_ctype = "int";
1708 length_ctype = "int*";
1711 for (int dim = 1; dim <= array_type.rank; dim++) {
1712 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), length_ctype));
1714 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1715 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1716 if (!acc.readable && acc.value_type.value_owned) {
1717 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1722 if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1723 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1724 function.modifiers |= CCodeModifiers.STATIC;
1728 push_function (function);
1730 if (prop.binding == MemberBinding.INSTANCE && !is_virtual) {
1731 if (!acc.readable || returns_real_struct) {
1732 create_property_type_check_statement (prop, false, t, true, "self");
1734 create_property_type_check_statement (prop, true, t, true, "self");
1738 if (acc.readable && !returns_real_struct) {
1739 // do not declare result variable if exit block is known to be unreachable
1740 if (acc.return_block == null || acc.return_block.get_predecessors ().size > 0) {
1741 ccode.add_declaration (get_ccode_name (acc.value_type), new CCodeVariableDeclarator ("result"));
1746 ccode.add_declaration (get_ccode_name (this_type), new CCodeVariableDeclarator ("self"));
1747 ccode.add_assignment (new CCodeIdentifier ("self"), get_cvalue_ (transform_value (new GLibValue (base_type, new CCodeIdentifier ("base"), true), this_type, acc)));
1750 acc.body.emit (this);
1752 if (current_method_inner_error) {
1753 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
1756 // notify on property changes
1757 if (is_gobject_property (prop) &&
1758 get_ccode_notify (prop) &&
1759 (acc.writable || acc.construction)) {
1760 var notify_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_notify"));
1761 notify_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
1762 notify_call.add_argument (get_property_canonical_cconstant (prop));
1763 ccode.add_expression (notify_call);
1766 cfile.add_function (function);
1773 public override void visit_destructor (Destructor d) {
1774 if (d.binding == MemberBinding.STATIC && !in_plugin) {
1775 Report.error (d.source_reference, "static destructors are only supported for dynamic types");
1781 public int get_block_id (Block b) {
1782 int result = block_map[b];
1784 result = ++next_block_id;
1785 block_map[b] = result;
1790 public bool no_implicit_copy (DataType type) {
1791 // note: implicit copy of array is planned to be forbidden
1792 var cl = type.data_type as Class;
1793 return (type is DelegateType ||
1795 (cl != null && !cl.is_immutable && !is_reference_counting (cl) && !get_ccode_is_gboxed (cl)));
1798 void capture_parameter (Parameter param, CCodeStruct data, int block_id) {
1799 generate_type_declaration (param.variable_type, cfile);
1801 var param_type = param.variable_type.copy ();
1802 if (!param.variable_type.value_owned) {
1803 param_type.value_owned = !no_implicit_copy (param.variable_type);
1805 data.add_field (get_ccode_name (param_type), get_variable_cname (param.name));
1807 // create copy if necessary as captured variables may need to be kept alive
1808 param.captured = false;
1809 var value = load_parameter (param);
1811 var array_type = param.variable_type as ArrayType;
1812 var deleg_type = param.variable_type as DelegateType;
1814 if (array_type != null && get_ccode_array_length (param)) {
1815 for (int dim = 1; dim <= array_type.rank; dim++) {
1816 data.add_field ("gint", get_parameter_array_length_cname (param, dim));
1818 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
1819 data.add_field ("gpointer", get_ccode_delegate_target_name (param));
1820 if (param.variable_type.value_owned) {
1821 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
1822 // reference transfer for delegates
1823 var lvalue = get_parameter_cvalue (param);
1824 ((GLibValue) value).delegate_target_destroy_notify_cvalue = get_delegate_target_destroy_notify_cvalue (lvalue);
1827 param.captured = true;
1829 store_parameter (param, value, true);
1832 public override void visit_block (Block b) {
1833 emit_context.push_symbol (b);
1835 var local_vars = b.get_local_variables ();
1837 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
1838 ccode.open_block ();
1842 var parent_block = next_closure_block (b.parent_symbol);
1844 int block_id = get_block_id (b);
1845 string struct_name = "Block%dData".printf (block_id);
1847 var data = new CCodeStruct ("_" + struct_name);
1848 data.add_field ("int", "_ref_count_");
1849 if (parent_block != null) {
1850 int parent_block_id = get_block_id (parent_block);
1852 data.add_field ("Block%dData *".printf (parent_block_id), "_data%d_".printf (parent_block_id));
1854 if (get_this_type () != null) {
1855 data.add_field ("%s *".printf (get_ccode_name (current_type_symbol)), "self");
1858 if (current_method != null) {
1859 // allow capturing generic type parameters
1860 foreach (var type_param in current_method.get_type_parameters ()) {
1863 func_name = "%s_type".printf (type_param.name.down ());
1864 data.add_field ("GType", func_name);
1866 func_name = "%s_dup_func".printf (type_param.name.down ());
1867 data.add_field ("GBoxedCopyFunc", func_name);
1869 func_name = "%s_destroy_func".printf (type_param.name.down ());
1870 data.add_field ("GDestroyNotify", func_name);
1874 foreach (var local in local_vars) {
1875 if (local.captured) {
1876 generate_type_declaration (local.variable_type, cfile);
1878 data.add_field (get_ccode_name (local.variable_type), get_local_cname (local) + get_ccode_declarator_suffix (local.variable_type));
1880 if (local.variable_type is ArrayType) {
1881 var array_type = (ArrayType) local.variable_type;
1882 for (int dim = 1; dim <= array_type.rank; dim++) {
1883 data.add_field ("gint", get_array_length_cname (get_local_cname (local), dim));
1885 data.add_field ("gint", get_array_size_cname (get_local_cname (local)));
1886 } else if (local.variable_type is DelegateType) {
1887 data.add_field ("gpointer", get_delegate_target_cname (get_local_cname (local)));
1888 if (local.variable_type.value_owned) {
1889 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_local_cname (local)));
1895 var data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
1896 data_alloc.add_argument (new CCodeIdentifier (struct_name));
1898 if (is_in_coroutine ()) {
1899 closure_struct.add_field (struct_name + "*", "_data%d_".printf (block_id));
1901 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id)));
1903 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), data_alloc);
1905 // initialize ref_count
1906 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_ref_count_"), new CCodeIdentifier ("1"));
1908 if (parent_block != null) {
1909 int parent_block_id = get_block_id (parent_block);
1911 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (parent_block_id)));
1912 ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id)));
1914 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call);
1916 // skip self assignment in toplevel block of creation methods with chainup as self is not set at the beginning of the method
1917 // the chainup statement takes care of assigning self in the closure struct
1918 bool in_creation_method_with_chainup = (current_method is CreationMethod && current_class != null && current_class.base_class != null);
1920 if (get_this_type () != null && (!in_creation_method_with_chainup || current_method.body != b)) {
1921 var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_data_type_for_symbol (current_type_symbol), b.source_reference));
1922 ref_call.add_argument (get_result_cexpression ("self"));
1924 // never increase reference count for self in finalizers to avoid infinite recursion on following unref
1925 var instance = (is_in_destructor () ? (CCodeExpression) new CCodeIdentifier ("self") : (CCodeExpression) ref_call);
1927 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), instance);
1930 if (current_method != null) {
1931 // allow capturing generic type parameters
1932 var suffices = new string[] {"type", "dup_func", "destroy_func"};
1933 foreach (var type_param in current_method.get_type_parameters ()) {
1934 foreach (string suffix in suffices) {
1935 string func_name = "%s_%s".printf (type_param.name.down (), suffix);
1936 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name), get_variable_cexpression (func_name));
1942 if (b.parent_symbol is Method) {
1943 var m = (Method) b.parent_symbol;
1945 // parameters are captured with the top-level block of the method
1946 foreach (var param in m.get_parameters ()) {
1947 if (param.captured) {
1948 capture_parameter (param, data, block_id);
1953 // capture async data to allow invoking callback from inside closure
1954 data.add_field ("gpointer", "_async_data_");
1956 // async method is suspended while waiting for callback,
1957 // so we never need to care about memory management of async data
1958 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_async_data_"), new CCodeIdentifier ("_data_"));
1960 } else if (b.parent_symbol is PropertyAccessor) {
1961 var acc = (PropertyAccessor) b.parent_symbol;
1963 if (!acc.readable && acc.value_parameter.captured) {
1964 capture_parameter (acc.value_parameter, data, block_id);
1966 } else if (b.parent_symbol is ForeachStatement) {
1967 var stmt = (ForeachStatement) b.parent_symbol;
1968 if (!stmt.use_iterator && stmt.element_variable.captured) {
1969 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)));
1973 var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name));
1974 cfile.add_type_declaration (typedef);
1975 cfile.add_type_definition (data);
1977 // create ref/unref functions
1978 var ref_fun = new CCodeFunction ("block%d_data_ref".printf (block_id), struct_name + "*");
1979 ref_fun.add_parameter (new CCodeParameter ("_data%d_".printf (block_id), struct_name + "*"));
1980 ref_fun.modifiers = CCodeModifiers.STATIC;
1982 push_function (ref_fun);
1984 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_inc"));
1985 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
1986 ccode.add_expression (ccall);
1987 ccode.add_return (new CCodeIdentifier ("_data%d_".printf (block_id)));
1991 cfile.add_function_declaration (ref_fun);
1992 cfile.add_function (ref_fun);
1994 var unref_fun = new CCodeFunction ("block%d_data_unref".printf (block_id), "void");
1995 unref_fun.add_parameter (new CCodeParameter ("_userdata_", "void *"));
1996 unref_fun.modifiers = CCodeModifiers.STATIC;
1998 push_function (unref_fun);
2000 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id), new CCodeCastExpression (new CCodeIdentifier ("_userdata_"), struct_name + "*")));
2001 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_dec_and_test"));
2002 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2003 ccode.open_if (ccall);
2005 CCodeExpression outer_block = new CCodeIdentifier ("_data%d_".printf (block_id));
2006 unowned Block parent_closure_block = b;
2008 parent_closure_block = next_closure_block (parent_closure_block.parent_symbol);
2009 if (parent_closure_block == null) {
2012 int parent_block_id = get_block_id (parent_closure_block);
2013 outer_block = new CCodeMemberAccess.pointer (outer_block, "_data%d_".printf (parent_block_id));
2016 if (get_this_type () != null) {
2017 // assign "self" for type parameters
2018 ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator ("self"));
2019 ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeMemberAccess.pointer (outer_block, "self"));
2022 if (current_method != null) {
2023 // assign captured generic type parameters
2024 foreach (var type_param in current_method.get_type_parameters ()) {
2027 func_name = "%s_type".printf (type_param.name.down ());
2028 ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name));
2029 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2031 func_name = "%s_dup_func".printf (type_param.name.down ());
2032 ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name));
2033 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2035 func_name = "%s_destroy_func".printf (type_param.name.down ());
2036 ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name));
2037 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (outer_block, func_name));
2041 // free in reverse order
2042 for (int i = local_vars.size - 1; i >= 0; i--) {
2043 var local = local_vars[i];
2044 if (local.captured) {
2045 if (requires_destroy (local.variable_type)) {
2046 bool old_coroutine = false;
2047 if (current_method != null) {
2048 old_coroutine = current_method.coroutine;
2049 current_method.coroutine = false;
2052 ccode.add_expression (destroy_local (local));
2054 if (old_coroutine) {
2055 current_method.coroutine = true;
2061 if (b.parent_symbol is Method) {
2062 var m = (Method) b.parent_symbol;
2064 // parameters are captured with the top-level block of the method
2065 foreach (var param in m.get_parameters ()) {
2066 if (param.captured) {
2067 var param_type = param.variable_type.copy ();
2068 if (!param_type.value_owned) {
2069 param_type.value_owned = !no_implicit_copy (param_type);
2072 if (requires_destroy (param_type)) {
2073 bool old_coroutine = false;
2075 old_coroutine = m.coroutine;
2076 m.coroutine = false;
2079 ccode.add_expression (destroy_parameter (param));
2081 if (old_coroutine) {
2087 } else if (b.parent_symbol is PropertyAccessor) {
2088 var acc = (PropertyAccessor) b.parent_symbol;
2090 if (!acc.readable && acc.value_parameter.captured) {
2091 var param_type = acc.value_parameter.variable_type.copy ();
2092 if (!param_type.value_owned) {
2093 param_type.value_owned = !no_implicit_copy (param_type);
2096 if (requires_destroy (param_type)) {
2097 ccode.add_expression (destroy_parameter (acc.value_parameter));
2102 // free parent block and "self" after captured variables
2103 // because they may require type parameters
2104 if (parent_block != null) {
2105 int parent_block_id = get_block_id (parent_block);
2107 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (parent_block_id)));
2108 unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
2109 ccode.add_expression (unref_call);
2110 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), new CCodeConstant ("NULL"));
2112 if (get_this_type () != null) {
2113 // reference count for self is not increased in finalizers
2114 if (!is_in_destructor ()) {
2115 var this_value = new GLibValue (get_data_type_for_symbol (current_type_symbol), new CCodeIdentifier ("self"), true);
2116 ccode.add_expression (destroy_value (this_value));
2121 var data_free = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
2122 data_free.add_argument (new CCodeIdentifier (struct_name));
2123 data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id)));
2124 ccode.add_expression (data_free);
2130 cfile.add_function_declaration (unref_fun);
2131 cfile.add_function (unref_fun);
2134 foreach (Statement stmt in b.get_statements ()) {
2135 push_line (stmt.source_reference);
2140 // free in reverse order
2141 for (int i = local_vars.size - 1; i >= 0; i--) {
2142 var local = local_vars[i];
2143 local.active = false;
2144 if (!local.unreachable && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
2145 ccode.add_expression (destroy_local (local));
2149 if (b.parent_symbol is Method) {
2150 var m = (Method) b.parent_symbol;
2151 foreach (Parameter param in m.get_parameters ()) {
2152 if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
2153 ccode.add_expression (destroy_parameter (param));
2154 } else if (param.direction == ParameterDirection.OUT && !m.coroutine) {
2155 return_out_parameter (param);
2158 } else if (b.parent_symbol is PropertyAccessor) {
2159 var acc = (PropertyAccessor) b.parent_symbol;
2160 if (acc.value_parameter != null && !acc.value_parameter.captured && requires_destroy (acc.value_parameter.variable_type)) {
2161 ccode.add_expression (destroy_parameter (acc.value_parameter));
2166 int block_id = get_block_id (b);
2168 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
2169 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
2170 ccode.add_expression (data_unref);
2171 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
2174 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
2178 emit_context.pop_symbol ();
2181 public override void visit_declaration_statement (DeclarationStatement stmt) {
2182 stmt.declaration.accept (this);
2185 public CCodeExpression get_local_cexpression (LocalVariable local) {
2186 if (is_in_coroutine ()) {
2187 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_local_cname (local));
2189 return new CCodeIdentifier (get_local_cname (local));
2193 public CCodeExpression get_variable_cexpression (string name) {
2194 if (is_in_coroutine ()) {
2195 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_variable_cname (name));
2197 return new CCodeIdentifier (get_variable_cname (name));
2201 public CCodeExpression get_this_cexpression () {
2202 if (is_in_coroutine ()) {
2203 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
2205 return new CCodeIdentifier ("self");
2209 public string get_local_cname (LocalVariable local) {
2210 var cname = get_variable_cname (local.name);
2211 if (is_in_coroutine ()) {
2212 var clash_index = emit_context.closure_variable_clash_map.get (local);
2213 if (clash_index > 0) {
2214 cname = "_vala%d_%s".printf (clash_index, cname);
2220 public string get_variable_cname (string name) {
2221 if (name[0] == '.') {
2222 if (name == ".result") {
2225 // compiler-internal variable
2226 if (!variable_name_map.contains (name)) {
2227 variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
2230 return variable_name_map.get (name);
2231 } else if (reserved_identifiers.contains (name)) {
2232 return "_%s_".printf (name);
2238 public CCodeExpression get_result_cexpression (string cname = "result") {
2239 if (is_in_coroutine ()) {
2240 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), cname);
2242 return new CCodeIdentifier (cname);
2246 public bool is_simple_struct_creation (Variable variable, Expression expr) {
2247 var st = variable.variable_type.data_type as Struct;
2248 var creation = expr as ObjectCreationExpression;
2249 if (creation != null && st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list") && !variable.variable_type.nullable &&
2250 variable.variable_type.data_type != gvalue_type && creation.get_object_initializer ().size == 0) {
2257 bool is_foreach_element_variable (LocalVariable local) {
2258 var block = local.parent_symbol;
2259 if (block != null) {
2260 var stmt = block.parent_symbol as ForeachStatement;
2261 if (stmt != null && !stmt.use_iterator && stmt.element_variable == local) {
2268 public override void visit_local_variable (LocalVariable local) {
2269 check_type (local.variable_type);
2271 if (local.initializer != null) {
2272 local.initializer.emit (this);
2274 visit_end_full_expression (local.initializer);
2277 generate_type_declaration (local.variable_type, cfile);
2279 CCodeExpression rhs = null;
2280 if (local.initializer != null && get_cvalue (local.initializer) != null) {
2281 rhs = get_cvalue (local.initializer);
2284 // captured element variables of foreach statements (without iterator) require local declaration
2285 if (!local.captured || is_foreach_element_variable (local)) {
2286 if (is_in_coroutine ()) {
2287 var count = emit_context.closure_variable_count_map.get (local.name);
2289 emit_context.closure_variable_clash_map.set (local, count);
2291 emit_context.closure_variable_count_map.set (local.name, count + 1);
2293 closure_struct.add_field (get_ccode_name (local.variable_type), get_local_cname (local) + get_ccode_declarator_suffix (local.variable_type));
2295 var cvar = new CCodeVariableDeclarator (get_local_cname (local), null, get_ccode_declarator_suffix (local.variable_type));
2297 // try to initialize uninitialized variables
2298 // initialization not necessary for variables stored in closure
2299 if (rhs == null || is_simple_struct_creation (local, local.initializer)) {
2300 cvar.initializer = default_value_for_type (local.variable_type, true);
2304 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
2307 if (local.variable_type is ArrayType) {
2308 // create variables to store array dimensions
2309 var array_type = (ArrayType) local.variable_type;
2311 if (!array_type.fixed_length) {
2312 for (int dim = 1; dim <= array_type.rank; dim++) {
2313 var len_var = new LocalVariable (int_type.copy (), get_array_length_cname (get_local_cname (local), dim));
2314 len_var.no_init = local.initializer != null;
2315 emit_temp_var (len_var);
2318 if (array_type.rank == 1) {
2319 var size_var = new LocalVariable (int_type.copy (), get_array_size_cname (get_local_cname (local)));
2320 size_var.no_init = local.initializer != null;
2321 emit_temp_var (size_var);
2324 } else if (local.variable_type is DelegateType) {
2325 var deleg_type = (DelegateType) local.variable_type;
2326 var d = deleg_type.delegate_symbol;
2328 // create variable to store delegate target
2329 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (get_local_cname (local)));
2330 target_var.no_init = local.initializer != null;
2331 emit_temp_var (target_var);
2332 if (deleg_type.value_owned) {
2333 var target_destroy_notify_var = new LocalVariable (gdestroynotify_type, get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2334 target_destroy_notify_var.no_init = local.initializer != null;
2335 emit_temp_var (target_destroy_notify_var);
2342 if (!is_simple_struct_creation (local, local.initializer)) {
2343 store_local (local, local.initializer.target_value, true);
2347 if (local.initializer != null && local.initializer.tree_can_fail) {
2348 add_simple_check (local.initializer);
2351 local.active = true;
2355 * Create a temporary variable and return lvalue access to it
2357 public TargetValue create_temp_value (DataType type, bool init, CodeNode node_reference, bool? value_owned = null) {
2358 var local = new LocalVariable (type.copy (), "_tmp%d_".printf (next_temp_var_id++), null, node_reference.source_reference);
2359 local.no_init = !init;
2360 if (value_owned != null) {
2361 local.variable_type.value_owned = value_owned;
2364 var array_type = local.variable_type as ArrayType;
2365 var deleg_type = local.variable_type as DelegateType;
2367 emit_temp_var (local);
2368 if (array_type != null) {
2369 for (int dim = 1; dim <= array_type.rank; dim++) {
2370 var len_var = new LocalVariable (int_type.copy (), get_array_length_cname (local.name, dim), null, node_reference.source_reference);
2371 len_var.no_init = !init;
2372 emit_temp_var (len_var);
2374 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
2375 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (local.name), null, node_reference.source_reference);
2376 target_var.no_init = !init;
2377 emit_temp_var (target_var);
2378 if (deleg_type.value_owned) {
2379 var target_destroy_notify_var = new LocalVariable (gdestroynotify_type.copy (), get_delegate_target_destroy_notify_cname (local.name), null, node_reference.source_reference);
2380 target_destroy_notify_var.no_init = !init;
2381 emit_temp_var (target_destroy_notify_var);
2385 var value = get_local_cvalue (local);
2386 set_array_size_cvalue (value, null);
2391 * Load a temporary variable returning unowned or owned rvalue access to it, depending on the ownership of the value type.
2393 public TargetValue load_temp_value (TargetValue lvalue) {
2394 var value = ((GLibValue) lvalue).copy ();
2395 var deleg_type = value.value_type as DelegateType;
2396 if (deleg_type != null) {
2397 if (!deleg_type.delegate_symbol.has_target) {
2398 value.delegate_target_cvalue = new CCodeConstant ("NULL");
2399 ((GLibValue) value).lvalue = false;
2400 } else if (!deleg_type.value_owned) {
2401 value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
2402 ((GLibValue) value).lvalue = false;
2409 * Store a value in a temporary variable and return unowned or owned rvalue access to it, depending on the ownership of the given type.
2411 public TargetValue store_temp_value (TargetValue initializer, CodeNode node_reference, bool? value_owned = null) {
2412 var lvalue = create_temp_value (initializer.value_type, false, node_reference, value_owned);
2413 store_value (lvalue, initializer);
2414 return load_temp_value (lvalue);
2417 public override void visit_initializer_list (InitializerList list) {
2418 if (list.target_type.data_type is Struct) {
2419 /* initializer is used as struct initializer */
2420 var st = (Struct) list.target_type.data_type;
2421 while (st.base_struct != null) {
2422 st = st.base_struct;
2425 if (list.parent_node is Constant || list.parent_node is Field || list.parent_node is InitializerList) {
2426 var clist = new CCodeInitializerList ();
2428 var field_it = st.get_fields ().iterator ();
2429 foreach (Expression expr in list.get_initializers ()) {
2431 while (field == null) {
2433 field = field_it.get ();
2434 if (field.binding != MemberBinding.INSTANCE) {
2435 // we only initialize instance fields
2440 var cexpr = get_cvalue (expr);
2442 string ctype = get_ccode_type (field);
2443 if (ctype != null) {
2444 cexpr = new CCodeCastExpression (cexpr, ctype);
2447 clist.append (cexpr);
2449 var array_type = field.variable_type as ArrayType;
2450 if (array_type != null && get_ccode_array_length (field) && !get_ccode_array_null_terminated (field)) {
2451 for (int dim = 1; dim <= array_type.rank; dim++) {
2452 clist.append (get_array_length_cvalue (expr.target_value, dim));
2457 set_cvalue (list, clist);
2459 // used as expression
2460 var instance = create_temp_value (list.value_type, true, list);
2462 var field_it = st.get_fields ().iterator ();
2463 foreach (Expression expr in list.get_initializers ()) {
2465 while (field == null) {
2467 field = field_it.get ();
2468 if (field.binding != MemberBinding.INSTANCE) {
2469 // we only initialize instance fields
2474 store_field (field, instance, expr.target_value);
2477 list.target_value = instance;
2480 var clist = new CCodeInitializerList ();
2481 foreach (Expression expr in list.get_initializers ()) {
2482 clist.append (get_cvalue (expr));
2484 set_cvalue (list, clist);
2488 public override LocalVariable create_local (DataType type) {
2489 var result = get_temp_variable (type, type.value_owned);
2490 emit_temp_var (result);
2494 public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null, bool init = true) {
2495 var var_type = type.copy ();
2496 var_type.value_owned = value_owned;
2497 var local = new LocalVariable (var_type, "_tmp%d_".printf (next_temp_var_id));
2498 local.no_init = !init;
2500 if (node_reference != null) {
2501 local.source_reference = node_reference.source_reference;
2509 bool is_in_generic_type (DataType type) {
2510 if (current_symbol != null && type.type_parameter.parent_symbol is TypeSymbol
2511 && (current_method == null || current_method.binding == MemberBinding.INSTANCE)) {
2518 void require_generic_accessors (Interface iface) {
2519 if (iface.get_attribute ("GenericAccessors") == null) {
2520 Report.error (iface.source_reference,
2521 "missing generic type for interface `%s', add GenericAccessors attribute to interface declaration"
2522 .printf (iface.get_full_name ()));
2526 public CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
2527 if (type is GenericType) {
2528 string var_name = "%s_type".printf (type.type_parameter.name.down ());
2530 if (type.type_parameter.parent_symbol is Interface) {
2531 var iface = (Interface) type.type_parameter.parent_symbol;
2532 require_generic_accessors (iface);
2534 string method_name = "get_%s_type".printf (type.type_parameter.name.down ());
2535 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
2536 cast_self.add_argument (new CCodeIdentifier ("self"));
2537 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
2538 function_call.add_argument (new CCodeIdentifier ("self"));
2539 return function_call;
2542 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
2543 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), var_name);
2545 return get_variable_cexpression (var_name);
2548 string type_id = get_ccode_type_id (type);
2549 if (type_id == "") {
2550 type_id = "G_TYPE_INVALID";
2552 generate_type_declaration (type, cfile);
2554 return new CCodeIdentifier (type_id);
2558 public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup = false) {
2559 if (type is ErrorType) {
2560 return new CCodeIdentifier ("g_error_copy");
2561 } else if (type.data_type != null) {
2562 string dup_function;
2563 var cl = type.data_type as Class;
2564 if (is_reference_counting (type.data_type)) {
2565 dup_function = get_ccode_ref_function ((ObjectTypeSymbol) type.data_type);
2566 if (type.data_type is Interface && dup_function == null) {
2567 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 ()));
2570 } else if (cl != null && cl.is_immutable) {
2571 // allow duplicates of immutable instances as for example strings
2572 dup_function = get_ccode_dup_function (type.data_type);
2573 if (dup_function == null) {
2576 } else if (cl != null && get_ccode_is_gboxed (cl)) {
2577 // allow duplicates of gboxed instances
2578 dup_function = generate_dup_func_wrapper (type);
2579 if (dup_function == null) {
2582 } else if (type is ValueType) {
2583 dup_function = get_ccode_dup_function (type.data_type);
2584 if (dup_function == null && type.nullable) {
2585 dup_function = generate_struct_dup_wrapper ((ValueType) type);
2586 } else if (dup_function == null) {
2590 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2591 Report.error (source_reference, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type.data_type.name));
2595 return new CCodeIdentifier (dup_function);
2596 } else if (type.type_parameter != null) {
2597 string func_name = "%s_dup_func".printf (type.type_parameter.name.down ());
2599 if (type.type_parameter.parent_symbol is Interface) {
2600 var iface = (Interface) type.type_parameter.parent_symbol;
2601 require_generic_accessors (iface);
2603 string method_name = "get_%s_dup_func".printf (type.type_parameter.name.down ());
2604 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
2605 cast_self.add_argument (new CCodeIdentifier ("self"));
2606 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
2607 function_call.add_argument (new CCodeIdentifier ("self"));
2608 return function_call;
2611 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
2612 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
2614 return get_variable_cexpression (func_name);
2616 } else if (type is PointerType) {
2617 var pointer_type = (PointerType) type;
2618 return get_dup_func_expression (pointer_type.base_type, source_reference);
2620 return new CCodeConstant ("NULL");
2624 void make_comparable_cexpression (ref DataType left_type, ref CCodeExpression cleft, ref DataType right_type, ref CCodeExpression cright) {
2625 var left_type_as_struct = left_type.data_type as Struct;
2626 var right_type_as_struct = right_type.data_type as Struct;
2629 var valuecast = try_cast_value_to_type (cleft, left_type, right_type);
2630 if (valuecast != null) {
2632 left_type = right_type;
2633 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2637 valuecast = try_cast_value_to_type (cright, right_type, left_type);
2638 if (valuecast != null) {
2640 right_type = left_type;
2641 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2645 if (left_type.data_type is Class && !((Class) left_type.data_type).is_compact &&
2646 right_type.data_type is Class && !((Class) right_type.data_type).is_compact) {
2647 var left_cl = (Class) left_type.data_type;
2648 var right_cl = (Class) right_type.data_type;
2650 if (left_cl != right_cl) {
2651 if (left_cl.is_subtype_of (right_cl)) {
2652 cleft = generate_instance_cast (cleft, right_cl);
2653 } else if (right_cl.is_subtype_of (left_cl)) {
2654 cright = generate_instance_cast (cright, left_cl);
2657 } else if (left_type_as_struct != null && right_type_as_struct != null) {
2658 if (left_type is StructValueType) {
2659 // real structs (uses compare/equal function)
2660 if (!left_type.nullable) {
2661 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft);
2663 if (!right_type.nullable) {
2664 cright = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cright);
2667 // integer or floating or boolean type
2668 if (left_type.nullable && right_type.nullable) {
2669 // FIXME also compare contents, not just address
2670 } else if (left_type.nullable) {
2671 // FIXME check left value is not null
2672 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
2673 } else if (right_type.nullable) {
2674 // FIXME check right value is not null
2675 cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
2681 private string generate_struct_equal_function (Struct st) {
2682 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (st));
2684 if (!add_wrapper (equal_func)) {
2685 // wrapper already defined
2689 var function = new CCodeFunction (equal_func, "gboolean");
2690 function.modifiers = CCodeModifiers.STATIC;
2692 function.add_parameter (new CCodeParameter ("s1", "const " + get_ccode_name (st) + "*"));
2693 function.add_parameter (new CCodeParameter ("s2", "const " + get_ccode_name (st) + "*"));
2695 push_function (function);
2697 // if (s1 == s2) return TRUE;
2699 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2700 ccode.open_if (cexp);
2701 ccode.add_return (new CCodeConstant ("TRUE"));
2704 // if (s1 == NULL || s2 == NULL) return FALSE;
2706 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2707 ccode.open_if (cexp);
2708 ccode.add_return (new CCodeConstant ("FALSE"));
2711 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2712 ccode.open_if (cexp);
2713 ccode.add_return (new CCodeConstant ("FALSE"));
2717 bool has_instance_fields = false;
2718 foreach (Field f in st.get_fields ()) {
2719 if (f.binding != MemberBinding.INSTANCE) {
2720 // we only compare instance fields
2724 has_instance_fields = true;
2726 CCodeExpression cexp; // if (cexp) return FALSE;
2727 var s1 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s1"), f.name); // s1->f
2728 var s2 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s2"), f.name); // s2->f
2730 var variable_type = f.variable_type.copy ();
2731 make_comparable_cexpression (ref variable_type, ref s1, ref variable_type, ref s2);
2733 if (!(f.variable_type is NullType) && f.variable_type.compatible (string_type)) {
2734 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
2735 ccall.add_argument (s1);
2736 ccall.add_argument (s2);
2738 } else if (f.variable_type is StructValueType) {
2739 var equalfunc = generate_struct_equal_function (f.variable_type.data_type as Struct);
2740 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
2741 ccall.add_argument (s1);
2742 ccall.add_argument (s2);
2743 cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
2745 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, s1, s2);
2748 ccode.open_if (cexp);
2749 ccode.add_return (new CCodeConstant ("FALSE"));
2753 if (!has_instance_fields) {
2754 // either opaque structure or simple type
2755 if (st.is_simple_type ()) {
2756 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2757 ccode.add_return (cexp);
2759 ccode.add_return (new CCodeConstant ("FALSE"));
2762 ccode.add_return (new CCodeConstant ("TRUE"));
2767 cfile.add_function_declaration (function);
2768 cfile.add_function (function);
2773 private string generate_numeric_equal_function (TypeSymbol sym) {
2774 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (sym));
2776 if (!add_wrapper (equal_func)) {
2777 // wrapper already defined
2781 var function = new CCodeFunction (equal_func, "gboolean");
2782 function.modifiers = CCodeModifiers.STATIC;
2784 function.add_parameter (new CCodeParameter ("s1", "const " + get_ccode_name (sym) + "*"));
2785 function.add_parameter (new CCodeParameter ("s2", "const " + get_ccode_name (sym) + "*"));
2787 push_function (function);
2789 // if (s1 == s2) return TRUE;
2791 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2792 ccode.open_if (cexp);
2793 ccode.add_return (new CCodeConstant ("TRUE"));
2796 // if (s1 == NULL || s2 == NULL) return FALSE;
2798 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2799 ccode.open_if (cexp);
2800 ccode.add_return (new CCodeConstant ("FALSE"));
2803 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2804 ccode.open_if (cexp);
2805 ccode.add_return (new CCodeConstant ("FALSE"));
2808 // return (*s1 == *s2);
2810 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2811 ccode.add_return (cexp);
2816 cfile.add_function_declaration (function);
2817 cfile.add_function (function);
2822 private string generate_struct_dup_wrapper (ValueType value_type) {
2823 string dup_func = "_%sdup".printf (get_ccode_lower_case_prefix (value_type.type_symbol));
2825 if (!add_wrapper (dup_func)) {
2826 // wrapper already defined
2830 var function = new CCodeFunction (dup_func, get_ccode_name (value_type));
2831 function.modifiers = CCodeModifiers.STATIC;
2833 function.add_parameter (new CCodeParameter ("self", get_ccode_name (value_type)));
2835 push_function (function);
2837 if (value_type.type_symbol == gvalue_type) {
2838 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
2839 dup_call.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
2840 dup_call.add_argument (new CCodeIdentifier ("self"));
2842 ccode.add_return (dup_call);
2844 ccode.add_declaration (get_ccode_name (value_type), new CCodeVariableDeclarator ("dup"));
2846 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
2847 creation_call.add_argument (new CCodeConstant (get_ccode_name (value_type.data_type)));
2848 creation_call.add_argument (new CCodeConstant ("1"));
2849 ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
2851 var st = value_type.data_type as Struct;
2852 if (st != null && st.is_disposable ()) {
2853 if (!get_ccode_has_copy_function (st)) {
2854 generate_struct_copy_function (st);
2857 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
2858 copy_call.add_argument (new CCodeIdentifier ("self"));
2859 copy_call.add_argument (new CCodeIdentifier ("dup"));
2860 ccode.add_expression (copy_call);
2862 cfile.add_include ("string.h");
2864 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
2865 sizeof_call.add_argument (new CCodeConstant (get_ccode_name (value_type.data_type)));
2867 var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
2868 copy_call.add_argument (new CCodeIdentifier ("dup"));
2869 copy_call.add_argument (new CCodeIdentifier ("self"));
2870 copy_call.add_argument (sizeof_call);
2871 ccode.add_expression (copy_call);
2874 ccode.add_return (new CCodeIdentifier ("dup"));
2879 cfile.add_function_declaration (function);
2880 cfile.add_function (function);
2885 protected string generate_dup_func_wrapper (DataType type) {
2886 string destroy_func = "_vala_%s_copy".printf (get_ccode_name (type.data_type));
2888 if (!add_wrapper (destroy_func)) {
2889 // wrapper already defined
2890 return destroy_func;
2893 var function = new CCodeFunction (destroy_func, get_ccode_name (type));
2894 function.modifiers = CCodeModifiers.STATIC;
2895 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
2897 push_function (function);
2899 var cl = type.data_type as Class;
2900 assert (cl != null && get_ccode_is_gboxed (cl));
2902 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
2903 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
2904 free_call.add_argument (new CCodeIdentifier ("self"));
2906 ccode.add_return (free_call);
2910 cfile.add_function_declaration (function);
2911 cfile.add_function (function);
2913 return destroy_func;
2916 protected string generate_free_function_address_of_wrapper (DataType type) {
2917 string destroy_func = "_vala_%s_free_function_address_of".printf (get_ccode_name (type.data_type));
2919 if (!add_wrapper (destroy_func)) {
2920 // wrapper already defined
2921 return destroy_func;
2924 var function = new CCodeFunction (destroy_func, "void");
2925 function.modifiers = CCodeModifiers.STATIC;
2926 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
2928 push_function (function);
2930 var cl = type.data_type as Class;
2931 var free_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (cl)));
2932 free_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("self")));
2934 ccode.add_expression (free_call);
2938 cfile.add_function_declaration (function);
2939 cfile.add_function (function);
2941 return destroy_func;
2944 protected string generate_free_func_wrapper (DataType type) {
2945 string destroy_func = "_vala_%s_free".printf (get_ccode_name (type.data_type));
2947 if (!add_wrapper (destroy_func)) {
2948 // wrapper already defined
2949 return destroy_func;
2952 var function = new CCodeFunction (destroy_func, "void");
2953 function.modifiers = CCodeModifiers.STATIC;
2954 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
2956 push_function (function);
2958 var cl = type.data_type as Class;
2959 if (cl != null && get_ccode_is_gboxed (cl)) {
2960 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_free"));
2961 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
2962 free_call.add_argument (new CCodeIdentifier ("self"));
2964 ccode.add_expression (free_call);
2966 var st = type.data_type as Struct;
2967 if (st != null && st.is_disposable ()) {
2968 if (!get_ccode_has_destroy_function (st)) {
2969 generate_struct_destroy_function (st);
2972 var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (st)));
2973 destroy_call.add_argument (new CCodeIdentifier ("self"));
2974 ccode.add_expression (destroy_call);
2977 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
2978 free_call.add_argument (new CCodeIdentifier ("self"));
2980 ccode.add_expression (free_call);
2985 cfile.add_function_declaration (function);
2986 cfile.add_function (function);
2988 return destroy_func;
2991 public CCodeExpression? get_destroy0_func_expression (DataType type, bool is_chainup = false) {
2992 var element_destroy_func_expression = get_destroy_func_expression (type, is_chainup);
2994 if (element_destroy_func_expression is CCodeIdentifier) {
2995 var freeid = (CCodeIdentifier) element_destroy_func_expression;
2996 string free0_func = "_%s0_".printf (freeid.name);
2998 if (add_wrapper (free0_func)) {
2999 var function = new CCodeFunction (free0_func, "void");
3000 function.modifiers = CCodeModifiers.STATIC;
3002 function.add_parameter (new CCodeParameter ("var", "gpointer"));
3004 push_function (function);
3006 ccode.add_expression (destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true));
3010 cfile.add_function_declaration (function);
3011 cfile.add_function (function);
3014 element_destroy_func_expression = new CCodeIdentifier (free0_func);
3017 return element_destroy_func_expression;
3020 public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
3021 if (type.data_type == glist_type || type.data_type == gslist_type || type.data_type == gnode_type || type.data_type == gqueue_type) {
3022 // create wrapper function to free list elements if necessary
3024 bool elements_require_free = false;
3025 CCodeExpression element_destroy_func_expression = null;
3027 foreach (DataType type_arg in type.get_type_arguments ()) {
3028 elements_require_free = requires_destroy (type_arg);
3029 if (elements_require_free) {
3030 element_destroy_func_expression = get_destroy0_func_expression (type_arg);
3034 if (elements_require_free && element_destroy_func_expression is CCodeIdentifier) {
3035 return new CCodeIdentifier (generate_collection_free_wrapper (type, (CCodeIdentifier) element_destroy_func_expression));
3037 return new CCodeIdentifier (get_ccode_free_function (type.data_type));
3039 } else if (type is ErrorType) {
3040 return new CCodeIdentifier ("g_error_free");
3041 } else if (type.data_type != null) {
3042 string unref_function;
3043 if (type is ReferenceType) {
3044 if (is_reference_counting (type.data_type)) {
3045 unref_function = get_ccode_unref_function ((ObjectTypeSymbol) type.data_type);
3046 if (type.data_type is Interface && unref_function == null) {
3047 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 ()));
3051 var cl = type.data_type as Class;
3052 if (cl != null && get_ccode_is_gboxed (cl)) {
3053 unref_function = generate_free_func_wrapper (type);
3055 if (is_free_function_address_of (type)) {
3056 unref_function = generate_free_function_address_of_wrapper (type);
3058 unref_function = get_ccode_free_function (type.data_type);
3063 if (type.nullable) {
3064 unref_function = get_ccode_free_function (type.data_type);
3065 if (unref_function == null) {
3066 if (type.data_type is Struct && ((Struct) type.data_type).is_disposable ()) {
3067 unref_function = generate_free_func_wrapper (type);
3069 unref_function = "g_free";
3073 var st = (Struct) type.data_type;
3074 if (!get_ccode_has_destroy_function (st)) {
3075 generate_struct_destroy_function (st);
3077 unref_function = get_ccode_destroy_function (st);
3080 if (unref_function == null) {
3081 return new CCodeConstant ("NULL");
3083 return new CCodeIdentifier (unref_function);
3084 } else if (type.type_parameter != null) {
3085 string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ());
3087 if (type.type_parameter.parent_symbol is Interface) {
3088 var iface = (Interface) type.type_parameter.parent_symbol;
3089 require_generic_accessors (iface);
3091 string method_name = "get_%s_destroy_func".printf (type.type_parameter.name.down ());
3092 var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
3093 cast_self.add_argument (new CCodeIdentifier ("self"));
3094 var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
3095 function_call.add_argument (new CCodeIdentifier ("self"));
3096 return function_call;
3099 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
3100 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
3102 return get_variable_cexpression (func_name);
3104 } else if (type is ArrayType) {
3105 return new CCodeIdentifier ("g_free");
3106 } else if (type is PointerType) {
3107 return new CCodeIdentifier ("g_free");
3109 return new CCodeConstant ("NULL");
3113 private string generate_collection_free_wrapper (DataType collection_type, CCodeIdentifier element_destroy_func_expression) {
3114 string destroy_func = "_%s_%s".printf (get_ccode_free_function (collection_type.data_type), element_destroy_func_expression.name);
3116 if (!add_wrapper (destroy_func)) {
3117 // wrapper already defined
3118 return destroy_func;
3121 var function = new CCodeFunction (destroy_func, "void");
3122 function.modifiers = CCodeModifiers.STATIC;
3124 function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3126 push_function (function);
3128 CCodeFunctionCall element_free_call;
3129 if (collection_type.data_type == gnode_type) {
3130 /* A wrapper which converts GNodeTraverseFunc into GDestroyNotify */
3131 string destroy_node_func = "%s_node".printf (destroy_func);
3132 var wrapper = new CCodeFunction (destroy_node_func, "gboolean");
3133 wrapper.modifiers = CCodeModifiers.STATIC;
3134 wrapper.add_parameter (new CCodeParameter ("node", get_ccode_name (collection_type)));
3135 wrapper.add_parameter (new CCodeParameter ("unused", "gpointer"));
3136 push_function (wrapper);
3138 var free_call = new CCodeFunctionCall (element_destroy_func_expression);
3139 free_call.add_argument (new CCodeMemberAccess.pointer(new CCodeIdentifier("node"), "data"));
3140 ccode.add_expression (free_call);
3141 ccode.add_return (new CCodeConstant ("FALSE"));
3144 cfile.add_function_declaration (function);
3145 cfile.add_function (wrapper);
3147 /* Now the code to call g_traverse with the above */
3148 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_node_traverse"));
3149 element_free_call.add_argument (new CCodeIdentifier("self"));
3150 element_free_call.add_argument (new CCodeConstant ("G_POST_ORDER"));
3151 element_free_call.add_argument (new CCodeConstant ("G_TRAVERSE_ALL"));
3152 element_free_call.add_argument (new CCodeConstant ("-1"));
3153 element_free_call.add_argument (new CCodeIdentifier (destroy_node_func));
3154 element_free_call.add_argument (new CCodeConstant ("NULL"));
3156 if (collection_type.data_type == glist_type) {
3157 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
3158 } else if (collection_type.data_type == gslist_type) {
3159 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_slist_foreach"));
3161 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_queue_foreach"));
3164 element_free_call.add_argument (new CCodeIdentifier ("self"));
3165 element_free_call.add_argument (new CCodeCastExpression (element_destroy_func_expression, "GFunc"));
3166 element_free_call.add_argument (new CCodeConstant ("NULL"));
3169 ccode.add_expression (element_free_call);
3171 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (collection_type.data_type)));
3172 cfreecall.add_argument (new CCodeIdentifier ("self"));
3173 ccode.add_expression (cfreecall);
3177 cfile.add_function_declaration (function);
3178 cfile.add_function (function);
3180 return destroy_func;
3183 public virtual string? append_struct_array_free (Struct st) {
3187 public CCodeExpression destroy_local (LocalVariable local) {
3188 return destroy_value (get_local_cvalue (local));
3191 public CCodeExpression destroy_parameter (Parameter param) {
3192 return destroy_value (get_parameter_cvalue (param));
3195 public CCodeExpression destroy_field (Field field, TargetValue? instance) {
3196 return destroy_value (get_field_cvalue (field, instance));
3199 // logic in this method is temporarily duplicated in destroy_variable
3200 // apply changes to both methods
3201 public virtual CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
3202 var type = value.value_type;
3203 if (value.actual_value_type != null) {
3204 type = value.actual_value_type;
3206 var cvar = get_cvalue_ (value);
3208 if (type is DelegateType) {
3209 var delegate_target = get_delegate_target_cvalue (value);
3210 var delegate_target_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
3212 var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
3213 ccall.add_argument (delegate_target);
3215 var destroy_call = new CCodeCommaExpression ();
3216 destroy_call.append_expression (ccall);
3217 destroy_call.append_expression (new CCodeConstant ("NULL"));
3219 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
3221 var ccomma = new CCodeCommaExpression ();
3222 ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), destroy_call));
3223 ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
3224 ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
3225 ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
3230 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
3232 if (type is ValueType && !type.nullable) {
3233 // normal value type, no null check
3234 var st = type.data_type as Struct;
3235 if (st != null && st.is_simple_type ()) {
3237 ccall.add_argument (cvar);
3239 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3242 if (gvalue_type != null && type.data_type == gvalue_type) {
3243 // g_value_unset must not be called for already unset values
3244 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
3245 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3247 var ccomma = new CCodeCommaExpression ();
3248 ccomma.append_expression (ccall);
3249 ccomma.append_expression (new CCodeConstant ("NULL"));
3251 return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
3252 } else if (context.require_glib_version (2, 32) &&
3253 (type.data_type == gmutex_type ||
3254 type.data_type == grecmutex_type ||
3255 type.data_type == grwlock_type ||
3256 type.data_type == gcond_type)) {
3257 // g_mutex_clear must not be called for uninitialized mutex
3258 // also, g_mutex_clear does not clear the struct
3259 requires_clear_mutex = true;
3260 ccall.call = new CCodeIdentifier ("_vala_clear_" + get_ccode_name (type.data_type));
3267 if (ccall.call is CCodeIdentifier && !(type is ArrayType) && !is_macro_definition) {
3268 // generate and use NULL-aware free macro to simplify code
3270 var freeid = (CCodeIdentifier) ccall.call;
3271 string free0_func = "_%s0".printf (freeid.name);
3273 if (add_wrapper (free0_func)) {
3274 var macro = destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true);
3275 cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("%s(var)".printf (free0_func), macro));
3278 ccall = new CCodeFunctionCall (new CCodeIdentifier (free0_func));
3279 ccall.add_argument (cvar);
3283 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
3285 /* can be simplified to
3286 * foo = (unref (foo), NULL)
3287 * if foo is of static type non-null
3290 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
3291 if (type.type_parameter != null) {
3292 var parent = type.type_parameter.parent_symbol;
3293 var cl = parent as Class;
3294 if ((!(parent is Method) && !(parent is ObjectTypeSymbol)) || (cl != null && cl.is_compact)) {
3295 return new CCodeConstant ("NULL");
3298 // unref functions are optional for type parameters
3299 var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
3300 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
3303 ccall.add_argument (cvar);
3305 /* set freed references to NULL to prevent further use */
3306 var ccomma = new CCodeCommaExpression ();
3308 if (type.data_type != null && !is_reference_counting (type.data_type) &&
3309 (type.data_type.is_subtype_of (gstringbuilder_type)
3310 || type.data_type.is_subtype_of (garray_type)
3311 || type.data_type.is_subtype_of (gbytearray_type)
3312 || type.data_type.is_subtype_of (gptrarray_type))) {
3313 ccall.add_argument (new CCodeConstant ("TRUE"));
3314 } else if (type.data_type == gthreadpool_type) {
3315 ccall.add_argument (new CCodeConstant ("FALSE"));
3316 ccall.add_argument (new CCodeConstant ("TRUE"));
3317 } else if (type is ArrayType) {
3318 var array_type = (ArrayType) type;
3319 if (requires_destroy (array_type.element_type)) {
3320 CCodeExpression csizeexpr = null;
3321 if (((GLibValue) value).array_length_cvalues != null) {
3322 csizeexpr = get_array_length_cvalue (value);
3323 } else if (get_array_null_terminated (value)) {
3324 requires_array_length = true;
3325 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
3326 len_call.add_argument (cvar);
3327 csizeexpr = len_call;
3329 csizeexpr = get_array_length_cexpr (value);
3332 if (csizeexpr != null) {
3333 var st = array_type.element_type.data_type as Struct;
3334 if (st != null && !array_type.element_type.nullable) {
3335 ccall.call = new CCodeIdentifier (append_struct_array_free (st));
3336 ccall.add_argument (csizeexpr);
3338 requires_array_free = true;
3339 ccall.call = new CCodeIdentifier ("_vala_array_free");
3340 ccall.add_argument (csizeexpr);
3341 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
3347 ccomma.append_expression (ccall);
3348 ccomma.append_expression (new CCodeConstant ("NULL"));
3350 var cassign = new CCodeAssignment (cvar, ccomma);
3352 // g_free (NULL) is allowed
3353 bool uses_gfree = (type.data_type != null && !is_reference_counting (type.data_type) && get_ccode_free_function (type.data_type) == "g_free");
3354 uses_gfree = uses_gfree || type is ArrayType;
3359 return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
3362 public override void visit_end_full_expression (Expression expr) {
3363 /* expr is a full expression, i.e. an initializer, the
3364 * expression in an expression statement, the controlling
3365 * expression in if, while, for, or foreach statements
3367 * we unref temporary variables at the end of a full
3370 if (temp_ref_values.size == 0) {
3371 /* nothing to do without temporary variables */
3375 var local_decl = expr.parent_node as LocalVariable;
3376 if (!(local_decl != null && is_simple_struct_creation (local_decl, local_decl.initializer))) {
3377 expr.target_value = store_temp_value (expr.target_value, expr);
3380 foreach (var value in temp_ref_values) {
3381 ccode.add_expression (destroy_value (value));
3384 temp_ref_values.clear ();
3387 public void emit_temp_var (LocalVariable local) {
3388 var init = !(local.name.has_prefix ("*") || local.no_init);
3389 if (is_in_coroutine ()) {
3390 closure_struct.add_field (get_ccode_name (local.variable_type), local.name);
3392 // even though closure struct is zerod, we need to initialize temporary variables
3393 // as they might be used multiple times when declared in a loop
3396 var initializer = default_value_for_type (local.variable_type, false);
3397 if (initializer == null) {
3398 cfile.add_include ("string.h");
3399 var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
3400 memset_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (local.name)));
3401 memset_call.add_argument (new CCodeConstant ("0"));
3402 memset_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (local.variable_type))));
3403 ccode.add_expression (memset_call);
3405 ccode.add_assignment (get_variable_cexpression (local.name), initializer);
3409 var cvar = new CCodeVariableDeclarator (local.name, null, get_ccode_declarator_suffix (local.variable_type));
3411 cvar.initializer = default_value_for_type (local.variable_type, true);
3414 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
3418 public override void visit_expression_statement (ExpressionStatement stmt) {
3419 if (stmt.expression.error) {
3424 /* free temporary objects and handle errors */
3426 foreach (var value in temp_ref_values) {
3427 ccode.add_expression (destroy_value (value));
3430 if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
3431 // simple case, no node breakdown necessary
3432 add_simple_check (stmt.expression);
3435 temp_ref_values.clear ();
3438 protected virtual void append_scope_free (Symbol sym, CodeNode? stop_at = null) {
3439 var b = (Block) sym;
3441 var local_vars = b.get_local_variables ();
3442 // free in reverse order
3443 for (int i = local_vars.size - 1; i >= 0; i--) {
3444 var local = local_vars[i];
3445 if (!local.unreachable && local.active && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
3446 ccode.add_expression (destroy_local (local));
3451 int block_id = get_block_id (b);
3453 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
3454 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
3455 ccode.add_expression (data_unref);
3456 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
3460 public void append_local_free (Symbol sym, bool stop_at_loop = false, CodeNode? stop_at = null) {
3461 var b = (Block) sym;
3463 append_scope_free (sym, stop_at);
3466 if (b.parent_node is Loop ||
3467 b.parent_node is ForeachStatement ||
3468 b.parent_node is SwitchStatement) {
3473 if (stop_at != null && b.parent_node == stop_at) {
3477 if (sym.parent_symbol is Block) {
3478 append_local_free (sym.parent_symbol, stop_at_loop, stop_at);
3479 } else if (sym.parent_symbol is Method) {
3480 append_param_free ((Method) sym.parent_symbol);
3481 } else if (sym.parent_symbol is PropertyAccessor) {
3482 var acc = (PropertyAccessor) sym.parent_symbol;
3483 if (acc.value_parameter != null && requires_destroy (acc.value_parameter.variable_type)) {
3484 ccode.add_expression (destroy_parameter (acc.value_parameter));
3489 private void append_param_free (Method m) {
3490 foreach (Parameter param in m.get_parameters ()) {
3491 if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
3492 ccode.add_expression (destroy_parameter (param));
3497 public bool variable_accessible_in_finally (LocalVariable local) {
3498 if (current_try == null) {
3502 var sym = current_symbol;
3504 while (!(sym is Method || sym is PropertyAccessor) && sym.scope.lookup (local.name) == null) {
3505 if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) ||
3506 (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) {
3511 sym = sym.parent_symbol;
3517 public void return_out_parameter (Parameter param) {
3518 var delegate_type = param.variable_type as DelegateType;
3520 var value = get_parameter_cvalue (param);
3522 var old_coroutine = is_in_coroutine ();
3523 current_method.coroutine = false;
3525 ccode.open_if (get_variable_cexpression (param.name));
3526 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (param.name)), get_cvalue_ (value));
3528 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
3529 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_ccode_delegate_target_name (param))), get_delegate_target_cvalue (value));
3530 if (delegate_type.value_owned) {
3531 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)));
3535 if (param.variable_type.is_disposable ()){
3537 current_method.coroutine = old_coroutine;
3538 ccode.add_expression (destroy_parameter (param));
3539 current_method.coroutine = false;
3543 var array_type = param.variable_type as ArrayType;
3544 if (array_type != null && !array_type.fixed_length && get_ccode_array_length (param)) {
3545 for (int dim = 1; dim <= array_type.rank; dim++) {
3546 ccode.open_if (get_variable_cexpression (get_parameter_array_length_cname (param, dim)));
3547 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_parameter_array_length_cname (param, dim))), get_array_length_cvalue (value, dim));
3552 current_method.coroutine = old_coroutine;
3555 public override void visit_return_statement (ReturnStatement stmt) {
3556 Symbol return_expression_symbol = null;
3558 if (stmt.return_expression != null) {
3559 // avoid unnecessary ref/unref pair
3560 var local = stmt.return_expression.symbol_reference as LocalVariable;
3561 if (local != null && !local.active) {
3562 /* return expression is local variable taking ownership and
3563 * current method is transferring ownership */
3565 return_expression_symbol = local;
3569 // return array length if appropriate
3570 if (((current_method != null && get_ccode_array_length (current_method)) || current_property_accessor != null) && current_return_type is ArrayType) {
3571 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
3573 var array_type = (ArrayType) current_return_type;
3574 for (int dim = 1; dim <= array_type.rank; dim++) {
3575 var len_l = get_result_cexpression (get_array_length_cname ("result", dim));
3576 var len_r = get_array_length_cvalue (temp_value, dim);
3577 if (!is_in_coroutine ()) {
3578 ccode.open_if (len_l);
3579 len_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, len_l);
3580 ccode.add_assignment (len_l, len_r);
3583 ccode.add_assignment (len_l, len_r);
3587 stmt.return_expression.target_value = temp_value;
3588 } else if ((current_method != null || current_property_accessor != null) && current_return_type is DelegateType) {
3589 var delegate_type = (DelegateType) current_return_type;
3590 if (delegate_type.delegate_symbol.has_target) {
3591 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
3593 var target_l = get_result_cexpression (get_delegate_target_cname ("result"));
3594 if (!is_in_coroutine ()) {
3595 target_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l);
3597 var target_r = get_delegate_target_cvalue (temp_value);
3598 ccode.add_assignment (target_l, target_r);
3599 if (delegate_type.value_owned) {
3600 var target_l_destroy_notify = get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3601 if (!is_in_coroutine ()) {
3602 target_l_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l_destroy_notify);
3604 var target_r_destroy_notify = get_delegate_target_destroy_notify_cvalue (temp_value);
3605 ccode.add_assignment (target_l_destroy_notify, target_r_destroy_notify);
3608 stmt.return_expression.target_value = temp_value;
3612 if (stmt.return_expression != null) {
3613 // assign method result to `result'
3614 CCodeExpression result_lhs = get_result_cexpression ();
3615 if (current_return_type.is_real_non_null_struct_type () && !is_in_coroutine ()) {
3616 result_lhs = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result_lhs);
3618 ccode.add_assignment (result_lhs, get_cvalue (stmt.return_expression));
3621 // free local variables
3622 append_local_free (current_symbol);
3624 if (current_method != null) {
3625 // check postconditions
3626 foreach (Expression postcondition in current_method.get_postconditions ()) {
3627 create_postcondition_statement (postcondition);
3631 if (current_method != null && !current_method.coroutine) {
3632 // assign values to output parameters if they are not NULL
3633 // otherwise, free the value if necessary
3634 foreach (var param in current_method.get_parameters ()) {
3635 if (param.direction != ParameterDirection.OUT) {
3639 return_out_parameter (param);
3643 if (current_method != null && current_method.get_attribute ("Profile") != null) {
3644 string prefix = "_vala_prof_%s".printf (get_ccode_real_name (current_method));
3646 var timer = new CCodeIdentifier (prefix + "_timer");
3648 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
3649 stop_call.add_argument (timer);
3650 ccode.add_expression (stop_call);
3653 if (is_in_constructor ()) {
3654 ccode.add_return (new CCodeIdentifier ("obj"));
3655 } else if (is_in_destructor ()) {
3656 // do not call return as member cleanup and chain up to base finalizer
3657 // stil need to be executed
3658 ccode.add_goto ("_return");
3659 } else if (is_in_coroutine ()) {
3660 } else if (current_method is CreationMethod) {
3661 ccode.add_return (new CCodeIdentifier ("self"));
3662 } else if (current_return_type is VoidType || current_return_type.is_real_non_null_struct_type ()) {
3663 // structs are returned via out parameter
3664 ccode.add_return ();
3666 ccode.add_return (new CCodeIdentifier ("result"));
3669 if (return_expression_symbol != null) {
3670 return_expression_symbol.active = true;
3673 // required for destructors
3674 current_method_return = true;
3677 public string get_symbol_lock_name (string symname) {
3678 return "__lock_%s".printf (symname);
3681 private CCodeExpression get_lock_expression (Statement stmt, Expression resource) {
3682 CCodeExpression l = null;
3683 var inner_node = ((MemberAccess)resource).inner;
3684 var member = resource.symbol_reference;
3685 var parent = (TypeSymbol)resource.symbol_reference.parent_symbol;
3687 if (member.is_instance_member ()) {
3688 if (inner_node == null) {
3689 l = new CCodeIdentifier ("self");
3690 } else if (resource.symbol_reference.parent_symbol != current_type_symbol) {
3691 l = generate_instance_cast (get_cvalue (inner_node), parent);
3693 l = get_cvalue (inner_node);
3696 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (resource.symbol_reference.name));
3697 } else if (member.is_class_member ()) {
3698 CCodeExpression klass;
3700 if (get_this_type () != null) {
3701 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3702 k.add_argument (new CCodeIdentifier ("self"));
3705 klass = new CCodeIdentifier ("klass");
3708 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(get_ccode_upper_case_name (parent))));
3709 get_class_private_call.add_argument (klass);
3710 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (resource.symbol_reference.name));
3712 string lock_name = "%s_%s".printf(get_ccode_lower_case_name (parent), resource.symbol_reference.name);
3713 l = new CCodeIdentifier (get_symbol_lock_name (lock_name));
3718 public override void visit_lock_statement (LockStatement stmt) {
3719 var l = get_lock_expression (stmt, stmt.resource);
3721 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("lock"))));
3722 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3724 ccode.add_expression (fc);
3727 public override void visit_unlock_statement (UnlockStatement stmt) {
3728 var l = get_lock_expression (stmt, stmt.resource);
3730 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("unlock"))));
3731 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3733 ccode.add_expression (fc);
3736 public override void visit_delete_statement (DeleteStatement stmt) {
3737 var pointer_type = (PointerType) stmt.expression.value_type;
3738 DataType type = pointer_type;
3739 if (pointer_type.base_type.data_type != null && pointer_type.base_type.data_type.is_reference_type ()) {
3740 type = pointer_type.base_type;
3743 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
3744 ccall.add_argument (get_cvalue (stmt.expression));
3745 ccode.add_expression (ccall);
3748 public override void visit_expression (Expression expr) {
3749 if (get_cvalue (expr) != null && !expr.lvalue) {
3750 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
3751 var st = expr.formal_value_type.type_parameter.parent_symbol.parent_symbol as Struct;
3752 if (expr.formal_value_type.type_parameter.parent_symbol != garray_type &&
3753 (st == null || get_ccode_name (st) != "va_list")) {
3754 // GArray and va_list don't use pointer-based generics
3755 set_cvalue (expr, convert_from_generic_pointer (get_cvalue (expr), expr.value_type));
3759 // memory management, implicit casts, and boxing/unboxing
3760 if (expr.value_type != null) {
3761 // FIXME: temporary workaround until the refactoring is complete, not all target_value have a value_type
3762 expr.target_value.value_type = expr.value_type;
3763 expr.target_value = transform_value (expr.target_value, expr.target_type, expr);
3766 if (expr.target_value == null) {
3770 if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
3771 if (expr.formal_target_type.type_parameter.parent_symbol != garray_type) {
3772 // GArray doesn't use pointer-based generics
3773 set_cvalue (expr, convert_to_generic_pointer (get_cvalue (expr), expr.target_type));
3777 if (!(expr.value_type is ValueType && !expr.value_type.nullable)) {
3778 ((GLibValue) expr.target_value).non_null = expr.is_non_null ();
3783 public override void visit_boolean_literal (BooleanLiteral expr) {
3784 set_cvalue (expr, new CCodeConstant (expr.value ? "TRUE" : "FALSE"));
3787 public override void visit_character_literal (CharacterLiteral expr) {
3788 if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
3789 set_cvalue (expr, new CCodeConstant (expr.value));
3791 set_cvalue (expr, new CCodeConstant ("%uU".printf (expr.get_char ())));
3795 public override void visit_integer_literal (IntegerLiteral expr) {
3796 set_cvalue (expr, new CCodeConstant (expr.value + expr.type_suffix));
3799 public override void visit_real_literal (RealLiteral expr) {
3800 string c_literal = expr.value;
3801 if (c_literal.has_suffix ("d") || c_literal.has_suffix ("D")) {
3802 // there is no suffix for double in C
3803 c_literal = c_literal.substring (0, c_literal.length - 1);
3805 if (!("." in c_literal || "e" in c_literal || "E" in c_literal)) {
3806 // C requires period or exponent part for floating constants
3807 if ("f" in c_literal || "F" in c_literal) {
3808 c_literal = c_literal.substring (0, c_literal.length - 1) + ".f";
3813 set_cvalue (expr, new CCodeConstant (c_literal));
3816 public override void visit_string_literal (StringLiteral expr) {
3817 set_cvalue (expr, new CCodeConstant.string (expr.value.replace ("\n", "\\n")));
3819 if (expr.translate) {
3820 // translated string constant
3822 var m = (Method) root_symbol.scope.lookup ("GLib").scope.lookup ("_");
3823 add_symbol_declaration (cfile, m, get_ccode_name (m));
3825 var translate = new CCodeFunctionCall (new CCodeIdentifier ("_"));
3826 translate.add_argument (get_cvalue (expr));
3827 set_cvalue (expr, translate);
3831 public override void visit_regex_literal (RegexLiteral expr) {
3832 string[] parts = expr.value.split ("/", 3);
3833 string re = parts[2].escape ("");
3836 if (parts[1].contains ("i")) {
3837 flags += " | G_REGEX_CASELESS";
3839 if (parts[1].contains ("m")) {
3840 flags += " | G_REGEX_MULTILINE";
3842 if (parts[1].contains ("s")) {
3843 flags += " | G_REGEX_DOTALL";
3845 if (parts[1].contains ("x")) {
3846 flags += " | G_REGEX_EXTENDED";
3849 var cdecl = new CCodeDeclaration ("GRegex*");
3851 var cname = "_tmp_regex_%d".printf (next_regex_id);
3852 if (this.next_regex_id == 0) {
3853 var fun = new CCodeFunction ("_thread_safe_regex_init", "GRegex*");
3854 fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
3855 fun.add_parameter (new CCodeParameter ("re", "GRegex**"));
3856 fun.add_parameter (new CCodeParameter ("pattern", "const gchar *"));
3857 fun.add_parameter (new CCodeParameter ("match_options", "GRegexMatchFlags"));
3859 push_function (fun);
3861 var once_enter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
3862 once_enter_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
3863 ccode.open_if (once_enter_call);
3865 var regex_new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_regex_new"));
3866 regex_new_call.add_argument (new CCodeConstant ("pattern"));
3867 regex_new_call.add_argument (new CCodeConstant ("match_options"));
3868 regex_new_call.add_argument (new CCodeConstant ("0"));
3869 regex_new_call.add_argument (new CCodeConstant ("NULL"));
3870 ccode.add_assignment (new CCodeIdentifier ("GRegex* val"), regex_new_call);
3872 var once_leave_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
3873 once_leave_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
3874 once_leave_call.add_argument (new CCodeConstant ("(gsize) val"));
3875 ccode.add_expression (once_leave_call);
3879 ccode.add_return (new CCodeIdentifier ("*re"));
3883 cfile.add_function (fun);
3885 this.next_regex_id++;
3887 cdecl.add_declarator (new CCodeVariableDeclarator (cname + " = NULL"));
3888 cdecl.modifiers = CCodeModifiers.STATIC;
3890 var regex_const = new CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname, re, flags));
3892 cfile.add_constant_declaration (cdecl);
3893 set_cvalue (expr, regex_const);
3896 public override void visit_null_literal (NullLiteral expr) {
3897 set_cvalue (expr, new CCodeConstant ("NULL"));
3899 var array_type = expr.target_type as ArrayType;
3900 var delegate_type = expr.target_type as DelegateType;
3901 if (array_type != null) {
3902 for (int dim = 1; dim <= array_type.rank; dim++) {
3903 append_array_length (expr, new CCodeConstant ("0"));
3905 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
3906 set_delegate_target (expr, new CCodeConstant ("NULL"));
3907 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
3911 public abstract TargetValue get_local_cvalue (LocalVariable local);
3913 public abstract TargetValue get_parameter_cvalue (Parameter param);
3915 public abstract TargetValue get_field_cvalue (Field field, TargetValue? instance);
3917 public abstract TargetValue load_variable (Variable variable, TargetValue value);
3919 public abstract TargetValue load_this_parameter (TypeSymbol sym);
3921 public abstract void store_value (TargetValue lvalue, TargetValue value);
3923 public virtual string get_delegate_target_cname (string delegate_cname) {
3924 assert_not_reached ();
3927 public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
3928 assert_not_reached ();
3931 public virtual CCodeExpression get_delegate_target_cvalue (TargetValue value) {
3932 return new CCodeInvalidExpression ();
3935 public virtual CCodeExpression get_delegate_target_destroy_notify_cvalue (TargetValue value) {
3936 return new CCodeInvalidExpression ();
3939 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname) {
3940 assert_not_reached ();
3943 public override void visit_base_access (BaseAccess expr) {
3944 CCodeExpression this_access;
3945 if (is_in_coroutine ()) {
3947 this_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
3949 this_access = new CCodeIdentifier ("self");
3952 set_cvalue (expr, generate_instance_cast (this_access, expr.value_type.data_type));
3955 public override void visit_postfix_expression (PostfixExpression expr) {
3956 MemberAccess ma = find_property_access (expr.inner);
3958 // property postfix expression
3959 var prop = (Property) ma.symbol_reference;
3961 // increment/decrement property
3962 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
3963 var cexpr = new CCodeBinaryExpression (op, get_cvalue (expr.inner), new CCodeConstant ("1"));
3964 store_property (prop, ma.inner, new GLibValue (expr.value_type, cexpr));
3966 // return previous value
3967 expr.target_value = expr.inner.target_value;
3971 // assign current value to temp variable
3972 var temp_value = store_temp_value (expr.inner.target_value, expr);
3974 // increment/decrement variable
3975 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
3976 var cexpr = new CCodeBinaryExpression (op, get_cvalue_ (temp_value), new CCodeConstant ("1"));
3977 ccode.add_assignment (get_cvalue (expr.inner), cexpr);
3979 // return previous value
3980 expr.target_value = temp_value;
3983 private MemberAccess? find_property_access (Expression expr) {
3984 if (!(expr is MemberAccess)) {
3988 var ma = (MemberAccess) expr;
3989 if (ma.symbol_reference is Property) {
3996 bool is_limited_generic_type (DataType type) {
3997 var cl = type.type_parameter.parent_symbol as Class;
3998 var st = type.type_parameter.parent_symbol as Struct;
3999 if ((cl != null && cl.is_compact) || st != null) {
4000 // compact classes and structs only
4001 // have very limited generics support
4007 public bool requires_copy (DataType type) {
4008 if (!type.is_disposable ()) {
4012 var cl = type.data_type as Class;
4013 if (cl != null && is_reference_counting (cl)
4014 && get_ccode_ref_function (cl) == "") {
4015 // empty ref_function => no ref necessary
4019 if (type.type_parameter != null) {
4020 if (is_limited_generic_type (type)) {
4028 public bool requires_destroy (DataType type) {
4029 if (!type.is_disposable ()) {
4033 var array_type = type as ArrayType;
4034 if (array_type != null && array_type.fixed_length) {
4035 return requires_destroy (array_type.element_type);
4038 var cl = type.data_type as Class;
4039 if (cl != null && is_reference_counting (cl)
4040 && get_ccode_unref_function (cl) == "") {
4041 // empty unref_function => no unref necessary
4045 if (type.type_parameter != null) {
4046 if (is_limited_generic_type (type)) {
4054 bool is_ref_function_void (DataType type) {
4055 var cl = type.data_type as Class;
4057 return get_ccode_ref_function_void (cl);
4063 bool is_free_function_address_of (DataType type) {
4064 var cl = type.data_type as Class;
4066 return get_ccode_free_function_address_of (cl);
4072 public virtual TargetValue? copy_value (TargetValue value, CodeNode node) {
4073 var type = value.value_type;
4074 var cexpr = get_cvalue_ (value);
4075 var result = ((GLibValue) value).copy ();
4077 if (type is DelegateType) {
4078 var delegate_type = (DelegateType) type;
4079 if (delegate_type.delegate_symbol.has_target && !context.deprecated) {
4080 Report.deprecated (node.source_reference, "copying delegates is discouraged");
4082 result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
4086 if (type is ValueType && !type.nullable) {
4087 // normal value type, no null check
4089 var temp_value = create_temp_value (type, true, node, true);
4090 var ctemp = get_cvalue_ (temp_value);
4092 var vt = (ValueType) type;
4093 var st = (Struct) vt.type_symbol;
4094 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
4095 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4096 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4098 if (!get_ccode_has_copy_function (st)) {
4099 generate_struct_copy_function (st);
4102 if (gvalue_type != null && type.data_type == gvalue_type) {
4103 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
4104 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4106 ccode.open_if (cisvalid);
4108 // GValue requires g_value_init in addition to g_value_copy
4109 var value_type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
4110 value_type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4112 var init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
4113 init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4114 init_call.add_argument (value_type_call);
4115 ccode.add_expression (init_call);
4116 ccode.add_expression (copy_call);
4120 // g_value_init/copy must not be called for uninitialized values
4121 store_value (temp_value, value);
4124 ccode.add_expression (copy_call);
4130 /* (temp = expr, temp == NULL ? NULL : ref (temp))
4132 * can be simplified to
4134 * if static type of expr is non-null
4137 var dupexpr = get_dup_func_expression (type, node.source_reference);
4139 if (dupexpr == null) {
4144 if (dupexpr is CCodeIdentifier && !(type is ArrayType) && !(type is GenericType) && !is_ref_function_void (type)) {
4145 // generate and call NULL-aware ref function to reduce number
4146 // of temporary variables and simplify code
4148 var dupid = (CCodeIdentifier) dupexpr;
4149 string dup0_func = "_%s0".printf (dupid.name);
4151 // g_strdup is already NULL-safe
4152 if (dupid.name == "g_strdup") {
4153 dup0_func = dupid.name;
4154 } else if (add_wrapper (dup0_func)) {
4155 string pointer_cname = "gpointer";
4156 var dup0_fun = new CCodeFunction (dup0_func, pointer_cname);
4157 dup0_fun.add_parameter (new CCodeParameter ("self", pointer_cname));
4158 dup0_fun.modifiers = CCodeModifiers.STATIC;
4160 push_function (dup0_fun);
4162 var dup_call = new CCodeFunctionCall (dupexpr);
4163 dup_call.add_argument (new CCodeIdentifier ("self"));
4165 ccode.add_return (new CCodeConditionalExpression (new CCodeIdentifier ("self"), dup_call, new CCodeConstant ("NULL")));
4169 cfile.add_function (dup0_fun);
4172 var ccall = new CCodeFunctionCall (new CCodeIdentifier (dup0_func));
4173 ccall.add_argument (cexpr);
4174 result.cvalue = ccall;
4175 result.value_type.value_owned = true;
4176 return store_temp_value (result, node);
4179 var ccall = new CCodeFunctionCall (dupexpr);
4181 if (!(type is ArrayType) && get_non_null (value) && !is_ref_function_void (type)) {
4182 // expression is non-null
4183 ccall.add_argument (cexpr);
4185 return store_temp_value (new GLibValue (type, ccall), node);
4187 var cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cexpr, new CCodeConstant ("NULL"));
4188 if (type.type_parameter != null) {
4189 // dup functions are optional for type parameters
4190 var cdupnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_dup_func_expression (type, node.source_reference), new CCodeConstant ("NULL"));
4191 cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.AND, cnotnull, cdupnotnull);
4194 if (type.type_parameter != null) {
4195 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
4196 ccall.add_argument (new CCodeCastExpression (cexpr, "gpointer"));
4198 ccall.add_argument (cexpr);
4201 if (type is ArrayType) {
4202 var array_type = (ArrayType) type;
4203 ccall.add_argument (get_array_length_cvalue (value));
4205 if (array_type.element_type is GenericType) {
4206 var elem_dupexpr = get_dup_func_expression (array_type.element_type, node.source_reference);
4207 if (elem_dupexpr == null) {
4208 elem_dupexpr = new CCodeConstant ("NULL");
4210 ccall.add_argument (elem_dupexpr);
4214 CCodeExpression cifnull;
4215 if (type.data_type != null) {
4216 cifnull = new CCodeConstant ("NULL");
4218 // the value might be non-null even when the dup function is null,
4219 // so we may not just use NULL for type parameters
4221 // cast from gconstpointer to gpointer as methods in
4222 // generic classes may not return gconstpointer
4223 cifnull = new CCodeCastExpression (cexpr, "gpointer");
4226 if (is_ref_function_void (type)) {
4227 ccode.open_if (cnotnull);
4228 ccode.add_expression (ccall);
4231 var ccond = new CCodeConditionalExpression (cnotnull, ccall, cifnull);
4232 result.cvalue = ccond;
4233 result = (GLibValue) store_temp_value (result, node, true);
4239 bool is_reference_type_argument (DataType type_arg) {
4240 if (type_arg is ErrorType || (type_arg.data_type != null && type_arg.data_type.is_reference_type ())) {
4247 bool is_nullable_value_type_argument (DataType type_arg) {
4248 if (type_arg is ValueType && type_arg.nullable) {
4255 bool is_signed_integer_type_argument (DataType type_arg) {
4256 var st = type_arg.data_type as Struct;
4257 if (type_arg is EnumValueType) {
4259 } else if (type_arg.nullable) {
4261 } else if (st == null) {
4263 } else if (st.is_subtype_of (bool_type.data_type)) {
4265 } else if (st.is_subtype_of (char_type.data_type)) {
4267 } else if (unichar_type != null && st.is_subtype_of (unichar_type.data_type)) {
4269 } else if (st.is_subtype_of (short_type.data_type)) {
4271 } else if (st.is_subtype_of (int_type.data_type)) {
4273 } else if (st.is_subtype_of (long_type.data_type)) {
4275 } else if (st.is_subtype_of (int8_type.data_type)) {
4277 } else if (st.is_subtype_of (int16_type.data_type)) {
4279 } else if (st.is_subtype_of (int32_type.data_type)) {
4281 } else if (st.is_subtype_of (gtype_type)) {
4288 bool is_unsigned_integer_type_argument (DataType type_arg) {
4289 var st = type_arg.data_type as Struct;
4292 } else if (type_arg.nullable) {
4294 } else if (st.is_subtype_of (uchar_type.data_type)) {
4296 } else if (st.is_subtype_of (ushort_type.data_type)) {
4298 } else if (st.is_subtype_of (uint_type.data_type)) {
4300 } else if (st.is_subtype_of (ulong_type.data_type)) {
4302 } else if (st.is_subtype_of (uint8_type.data_type)) {
4304 } else if (st.is_subtype_of (uint16_type.data_type)) {
4306 } else if (st.is_subtype_of (uint32_type.data_type)) {
4313 public void check_type (DataType type) {
4314 var array_type = type as ArrayType;
4315 if (array_type != null) {
4316 check_type (array_type.element_type);
4317 if (array_type.element_type is ArrayType) {
4318 Report.error (type.source_reference, "Stacked arrays are not supported");
4319 } else if (array_type.element_type is DelegateType) {
4320 var delegate_type = (DelegateType) array_type.element_type;
4321 if (delegate_type.delegate_symbol.has_target) {
4322 Report.error (type.source_reference, "Delegates with target are not supported as array element type");
4326 foreach (var type_arg in type.get_type_arguments ()) {
4327 check_type (type_arg);
4328 check_type_argument (type_arg);
4332 void check_type_argument (DataType type_arg) {
4333 if (type_arg is GenericType
4334 || type_arg is PointerType
4335 || is_reference_type_argument (type_arg)
4336 || is_nullable_value_type_argument (type_arg)
4337 || is_signed_integer_type_argument (type_arg)
4338 || is_unsigned_integer_type_argument (type_arg)) {
4340 } else if (type_arg is DelegateType) {
4341 var delegate_type = (DelegateType) type_arg;
4342 if (delegate_type.delegate_symbol.has_target) {
4343 Report.error (type_arg.source_reference, "Delegates with target are not supported as generic type arguments");
4346 Report.error (type_arg.source_reference, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg.to_string ()));
4350 public virtual void generate_class_declaration (Class cl, CCodeFile decl_space) {
4351 if (add_symbol_declaration (decl_space, cl, get_ccode_name (cl))) {
4356 public virtual void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
4359 public virtual void generate_method_declaration (Method m, CCodeFile decl_space) {
4362 public virtual void generate_error_domain_declaration (ErrorDomain edomain, CCodeFile decl_space) {
4365 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) {
4366 int type_param_index = 0;
4367 foreach (var type_arg in type_args) {
4368 if (type_parameters != null) {
4369 var type_param_name = type_parameters.get (type_param_index).name.down ();
4370 arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s_type\"".printf (type_param_name)));
4371 arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("\"%s_dup_func\"".printf (type_param_name)));
4372 arg_map.set (get_param_pos (0.1 * type_param_index + 0.05), new CCodeConstant ("\"%s_destroy_func\"".printf (type_param_name)));
4375 arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), get_type_id_expression (type_arg, is_chainup));
4376 if (requires_copy (type_arg)) {
4377 var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference, is_chainup);
4378 if (dup_func == null) {
4379 // type doesn't contain a copy function
4383 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
4384 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), get_destroy_func_expression (type_arg, is_chainup));
4386 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeConstant ("NULL"));
4387 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeConstant ("NULL"));
4393 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
4394 CCodeExpression instance = null;
4395 CCodeExpression creation_expr = null;
4397 check_type (expr.type_reference);
4399 var st = expr.type_reference.data_type as Struct;
4400 if ((st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list")) || expr.get_object_initializer ().size > 0) {
4401 // value-type initialization or object creation expression with object initializer
4403 var local = expr.parent_node as LocalVariable;
4404 var a = expr.parent_node as Assignment;
4405 if (local != null && is_simple_struct_creation (local, local.initializer)) {
4406 instance = get_cvalue_ (get_local_cvalue (local));
4407 } else if (a != null && a.left.symbol_reference is Variable && is_simple_struct_creation ((Variable) a.left.symbol_reference, a.right)) {
4408 if (requires_destroy (a.left.value_type)) {
4409 /* unref old value */
4410 ccode.add_expression (destroy_value (a.left.target_value));
4413 local = a.left.symbol_reference as LocalVariable;
4414 var field = a.left.symbol_reference as Field;
4415 var param = a.left.symbol_reference as Parameter;
4416 if (local != null) {
4417 instance = get_cvalue_ (get_local_cvalue (local));
4418 } else if (field != null) {
4419 var inner = ((MemberAccess) a.left).inner;
4420 instance = get_cvalue_ (get_field_cvalue (field, inner != null ? inner.target_value : null));
4421 } else if (param != null) {
4422 instance = get_cvalue_ (get_parameter_cvalue (param));
4425 var temp_value = create_temp_value (expr.type_reference, true, expr);
4426 instance = get_cvalue_ (temp_value);
4430 if (expr.symbol_reference == null) {
4431 // no creation method
4432 if (expr.type_reference.data_type is Struct) {
4433 // memset needs string.h
4434 cfile.add_include ("string.h");
4435 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4436 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4437 creation_call.add_argument (new CCodeConstant ("0"));
4438 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.type_reference))));
4440 creation_expr = creation_call;
4442 } else if (expr.type_reference.data_type == glist_type ||
4443 expr.type_reference.data_type == gslist_type) {
4444 // NULL is an empty list
4445 set_cvalue (expr, new CCodeConstant ("NULL"));
4446 } else if (expr.symbol_reference is Method) {
4447 // use creation method
4448 var m = (Method) expr.symbol_reference;
4449 var params = m.get_parameters ();
4450 CCodeFunctionCall creation_call;
4452 CCodeFunctionCall async_call = null;
4453 CCodeFunctionCall finish_call = null;
4455 generate_method_declaration (m, cfile);
4457 var cl = expr.type_reference.data_type as Class;
4459 if (!get_ccode_has_new_function (m)) {
4460 // use construct function directly
4461 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
4462 creation_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
4464 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
4467 if ((st != null && !st.is_simple_type ()) && !(get_ccode_instance_pos (m) < 0)) {
4468 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4469 } else if (st != null && get_ccode_name (st) == "va_list") {
4470 creation_call.add_argument (instance);
4471 if (get_ccode_name (m) == "va_start") {
4472 if (in_creation_method) {
4473 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("va_copy"));
4474 creation_call.add_argument (instance);
4475 creation_call.add_argument (new CCodeIdentifier ("_vala_va_list"));
4477 Parameter last_param = null;
4478 // FIXME: this doesn't take into account exception handling parameters
4479 foreach (var param in current_method.get_parameters ()) {
4480 if (param.ellipsis) {
4485 int nParams = ccode.get_parameter_count ();
4486 if (nParams == 0 || !ccode.get_parameter (nParams - 1).ellipsis) {
4487 Report.error (expr.source_reference, "`va_list' used in method with fixed args");
4488 } else if (nParams == 1) {
4489 Report.error (expr.source_reference, "`va_list' used in method without parameter");
4491 creation_call.add_argument (new CCodeIdentifier (ccode.get_parameter (nParams - 2).name));
4497 generate_type_declaration (expr.type_reference, cfile);
4499 var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
4500 var out_arg_map = in_arg_map;
4502 if (m != null && m.coroutine) {
4505 async_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
4506 finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
4508 creation_call = finish_call;
4510 // output arguments used separately
4511 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
4512 // pass GAsyncResult stored in closure to finish function
4513 out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
4516 if (cl != null && !cl.is_compact) {
4517 add_generic_type_arguments (in_arg_map, expr.type_reference.get_type_arguments (), expr);
4518 } else if (cl != null && get_ccode_simple_generics (m)) {
4519 int type_param_index = 0;
4520 foreach (var type_arg in expr.type_reference.get_type_arguments ()) {
4521 if (requires_copy (type_arg)) {
4522 in_arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), get_destroy0_func_expression (type_arg));
4524 in_arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
4530 bool ellipsis = false;
4534 Iterator<Parameter> params_it = params.iterator ();
4535 foreach (Expression arg in expr.get_argument_list ()) {
4536 CCodeExpression cexpr = get_cvalue (arg);
4538 var carg_map = in_arg_map;
4540 Parameter param = null;
4541 if (params_it.next ()) {
4542 param = params_it.get ();
4543 ellipsis = param.ellipsis;
4545 if (param.direction == ParameterDirection.OUT) {
4546 carg_map = out_arg_map;
4549 // g_array_new: element size
4550 if (cl == garray_type && param.name == "element_size") {
4551 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
4552 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference.get_type_arguments ().get (0))));
4556 if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
4557 var array_type = (ArrayType) param.variable_type;
4558 for (int dim = 1; dim <= array_type.rank; dim++) {
4559 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_array_length_cexpression (arg, dim));
4561 } else if (param.variable_type is DelegateType) {
4562 var deleg_type = (DelegateType) param.variable_type;
4563 var d = deleg_type.delegate_symbol;
4565 CCodeExpression delegate_target_destroy_notify;
4566 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
4567 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
4568 if (deleg_type.value_owned) {
4569 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param) + 0.01), delegate_target_destroy_notify);
4574 cexpr = handle_struct_argument (param, arg, cexpr);
4576 if (get_ccode_type (param) != null) {
4577 cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
4580 cexpr = handle_struct_argument (null, arg, cexpr);
4583 arg_pos = get_param_pos (get_ccode_pos (param), ellipsis);
4585 // default argument position
4586 cexpr = handle_struct_argument (null, arg, cexpr);
4587 arg_pos = get_param_pos (i, ellipsis);
4590 carg_map.set (arg_pos, cexpr);
4594 if (params_it.next ()) {
4595 var param = params_it.get ();
4597 /* if there are more parameters than arguments,
4598 * the additional parameter is an ellipsis parameter
4599 * otherwise there is a bug in the semantic analyzer
4601 assert (param.params_array || param.ellipsis);
4605 if (expr.tree_can_fail) {
4607 current_method_inner_error = true;
4608 // add &inner_error before the ellipsis arguments
4609 out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
4613 /* ensure variable argument list ends with NULL
4614 * except when using printf-style arguments */
4616 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
4617 } else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "") {
4618 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
4622 if ((st != null && !st.is_simple_type ()) && get_ccode_instance_pos (m) < 0) {
4623 // instance parameter is at the end in a struct creation method
4624 out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4627 if (m != null && m.coroutine) {
4628 if (expr.is_yield_expression) {
4629 // asynchronous call
4630 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
4631 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
4635 // append C arguments in the right order
4640 if (async_call != creation_call) {
4641 // don't append out arguments for .begin() calls
4645 foreach (int pos in out_arg_map.get_keys ()) {
4646 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
4650 if (min_pos == -1) {
4653 creation_call.add_argument (out_arg_map.get (min_pos));
4658 if (async_call != null) {
4662 foreach (int pos in in_arg_map.get_keys ()) {
4663 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
4667 if (min_pos == -1) {
4670 async_call.add_argument (in_arg_map.get (min_pos));
4675 if (expr.is_yield_expression) {
4676 // set state before calling async function to support immediate callbacks
4677 int state = next_coroutine_state++;
4679 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
4680 ccode.add_expression (async_call);
4681 ccode.add_return (new CCodeConstant ("FALSE"));
4682 ccode.add_label ("_state_%d".printf (state));
4685 creation_expr = creation_call;
4687 // cast the return value of the creation method back to the intended type if
4688 // it requested a special C return type
4689 if (get_ccode_type (m) != null) {
4690 creation_expr = new CCodeCastExpression (creation_expr, get_ccode_name (expr.type_reference));
4692 } else if (expr.symbol_reference is ErrorCode) {
4693 var ecode = (ErrorCode) expr.symbol_reference;
4694 var edomain = (ErrorDomain) ecode.parent_symbol;
4695 CCodeFunctionCall creation_call;
4697 generate_error_domain_declaration (edomain, cfile);
4699 if (expr.get_argument_list ().size == 1) {
4700 // must not be a format argument
4701 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new_literal"));
4703 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new"));
4705 creation_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (edomain)));
4706 creation_call.add_argument (new CCodeIdentifier (get_ccode_name (ecode)));
4708 foreach (Expression arg in expr.get_argument_list ()) {
4709 creation_call.add_argument (get_cvalue (arg));
4712 creation_expr = creation_call;
4717 var local = expr.parent_node as LocalVariable;
4718 if (local != null && is_simple_struct_creation (local, local.initializer)) {
4719 // no temporary variable necessary
4720 ccode.add_expression (creation_expr);
4721 set_cvalue (expr, instance);
4722 } else if (instance != null) {
4723 if (expr.type_reference.data_type is Struct) {
4724 ccode.add_expression (creation_expr);
4726 ccode.add_assignment (instance, creation_expr);
4729 foreach (MemberInitializer init in expr.get_object_initializer ()) {
4730 if (init.symbol_reference is Field) {
4731 var f = (Field) init.symbol_reference;
4732 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
4733 var typed_inst = transform_value (new GLibValue (expr.type_reference, instance, true), instance_target_type, init);
4734 store_field (f, typed_inst, init.initializer.target_value);
4736 var cl = f.parent_symbol as Class;
4738 generate_class_struct_declaration (cl, cfile);
4740 } else if (init.symbol_reference is Property) {
4741 var inst_ma = new MemberAccess.simple ("new");
4742 inst_ma.value_type = expr.type_reference;
4743 set_cvalue (inst_ma, instance);
4744 store_property ((Property) init.symbol_reference, inst_ma, init.initializer.target_value);
4748 set_cvalue (expr, instance);
4749 } else if (creation_expr != null) {
4750 var temp_value = create_temp_value (expr.value_type, false, expr);
4751 ccode.add_assignment (get_cvalue_ (temp_value), creation_expr);
4752 expr.target_value = temp_value;
4754 if (context.gobject_tracing) {
4755 // GObject creation tracing enabled
4757 var cl = expr.type_reference.data_type as Class;
4758 if (cl != null && cl.is_subtype_of (gobject_type)) {
4761 // instance can be NULL in error cases
4762 ccode.open_if (get_cvalue_ (expr.target_value));
4764 var set_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set_data"));
4765 set_data_call.add_argument (new CCodeCastExpression (get_cvalue_ (expr.target_value), "GObject *"));
4766 set_data_call.add_argument (new CCodeConstant ("\"vala-creation-function\""));
4768 string func_name = "";
4769 if (current_method != null) {
4770 func_name = current_method.get_full_name ();
4771 } else if (current_property_accessor != null) {
4772 func_name = current_property_accessor.get_full_name ();
4775 set_data_call.add_argument (new CCodeConstant ("\"%s\"".printf (func_name)));
4777 ccode.add_expression (set_data_call);
4784 ((GLibValue) expr.target_value).lvalue = true;
4787 public CCodeExpression? handle_struct_argument (Parameter? param, Expression arg, CCodeExpression? cexpr) {
4789 if (param != null) {
4790 type = param.variable_type;
4793 type = arg.value_type;
4796 var unary = arg as UnaryExpression;
4797 // pass non-simple struct instances always by reference
4798 if (!(arg.value_type is NullType) && type.is_real_struct_type ()) {
4799 // we already use a reference for arguments of ref, out, and nullable parameters
4800 if (!(unary != null && (unary.operator == UnaryOperator.OUT || unary.operator == UnaryOperator.REF)) && !type.nullable) {
4801 if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
4802 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
4804 // if cexpr is e.g. a function call, we can't take the address of the expression
4805 var temp_value = create_temp_value (type, false, arg);
4806 ccode.add_assignment (get_cvalue_ (temp_value), cexpr);
4807 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value));
4815 public override void visit_sizeof_expression (SizeofExpression expr) {
4816 generate_type_declaration (expr.type_reference, cfile);
4818 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
4819 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference)));
4820 set_cvalue (expr, csizeof);
4823 public override void visit_typeof_expression (TypeofExpression expr) {
4824 set_cvalue (expr, get_type_id_expression (expr.type_reference));
4827 public override void visit_unary_expression (UnaryExpression expr) {
4828 if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) {
4829 var glib_value = (GLibValue) expr.inner.target_value;
4831 var ref_value = new GLibValue (glib_value.value_type);
4832 ref_value.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.cvalue);
4834 if (glib_value.array_length_cvalues != null) {
4835 for (int i = 0; i < glib_value.array_length_cvalues.size; i++) {
4836 ref_value.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.array_length_cvalues[i]));
4840 if (glib_value.delegate_target_cvalue != null) {
4841 ref_value.delegate_target_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_cvalue);
4843 if (glib_value.delegate_target_destroy_notify_cvalue != null) {
4844 ref_value.delegate_target_destroy_notify_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_destroy_notify_cvalue);
4847 expr.target_value = ref_value;
4851 CCodeUnaryOperator op;
4852 if (expr.operator == UnaryOperator.PLUS) {
4853 op = CCodeUnaryOperator.PLUS;
4854 } else if (expr.operator == UnaryOperator.MINUS) {
4855 op = CCodeUnaryOperator.MINUS;
4856 } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
4857 op = CCodeUnaryOperator.LOGICAL_NEGATION;
4858 } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
4859 op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
4860 } else if (expr.operator == UnaryOperator.INCREMENT) {
4861 op = CCodeUnaryOperator.PREFIX_INCREMENT;
4862 } else if (expr.operator == UnaryOperator.DECREMENT) {
4863 op = CCodeUnaryOperator.PREFIX_DECREMENT;
4865 assert_not_reached ();
4867 set_cvalue (expr, new CCodeUnaryExpression (op, get_cvalue (expr.inner)));
4870 public CCodeExpression? try_cast_value_to_type (CCodeExpression ccodeexpr, DataType from, DataType to, Expression? expr = null) {
4871 if (from == null || gvalue_type == null || from.data_type != gvalue_type || to.data_type == gvalue_type || get_ccode_type_id (to) == "") {
4875 // explicit conversion from GValue
4876 var ccall = new CCodeFunctionCall (get_value_getter_function (to));
4877 CCodeExpression gvalue;
4878 if (from.nullable) {
4881 gvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ccodeexpr);
4883 ccall.add_argument (gvalue);
4885 CCodeExpression rv = ccall;
4887 if (expr != null && to is ArrayType) {
4888 // null-terminated string array
4889 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
4890 len_call.add_argument (rv);
4891 append_array_length (expr, len_call);
4892 } else if (to is StructValueType) {
4893 CodeNode node = expr != null ? (CodeNode) expr : to;
4894 var temp_value = create_temp_value (to, true, node, true);
4895 var ctemp = get_cvalue_ (temp_value);
4897 rv = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeCastExpression (rv, get_ccode_name (new PointerType (to))));
4898 var holds = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_HOLDS"));
4899 holds.add_argument (gvalue);
4900 holds.add_argument (new CCodeIdentifier (get_ccode_type_id (to)));
4901 var cond = new CCodeBinaryExpression (CCodeBinaryOperator.AND, holds, ccall);
4902 var warn = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
4903 warn.add_argument (new CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
4904 var fail = new CCodeCommaExpression ();
4905 fail.append_expression (warn);
4906 fail.append_expression (ctemp);
4907 rv = new CCodeConditionalExpression (cond, rv, fail);
4913 int next_variant_function_id = 0;
4915 public TargetValue? try_cast_variant_to_type (TargetValue value, DataType to, CodeNode? node = null) {
4916 if (value.value_type == null || gvariant_type == null || value.value_type.data_type != gvariant_type) {
4920 string variant_func = "_variant_get%d".printf (++next_variant_function_id);
4922 var variant = value;
4923 if (value.value_type.value_owned) {
4924 // value leaked, destroy it
4925 var temp_value = store_temp_value (value, node);
4926 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
4927 variant = temp_value;
4930 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
4931 ccall.add_argument (get_cvalue_ (variant));
4933 var result = create_temp_value (to, false, node);
4935 var cfunc = new CCodeFunction (variant_func);
4936 cfunc.modifiers = CCodeModifiers.STATIC;
4937 cfunc.add_parameter (new CCodeParameter ("value", "GVariant*"));
4939 if (!to.is_real_non_null_struct_type ()) {
4940 cfunc.return_type = get_ccode_name (to);
4943 if (to.is_real_non_null_struct_type ()) {
4944 // structs are returned via out parameter
4945 cfunc.add_parameter (new CCodeParameter ("result", get_ccode_name (to) + "*"));
4946 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (result)));
4947 } else if (to is ArrayType) {
4948 // return array length if appropriate
4949 // tmp = _variant_get (variant, &tmp_length);
4950 var array_type = (ArrayType) to;
4952 for (int dim = 1; dim <= array_type.rank; dim++) {
4953 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cvalue (result, dim)));
4954 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("result", dim), "int*"));
4958 if (!to.is_real_non_null_struct_type ()) {
4959 ccode.add_assignment (get_cvalue_ (result), ccall);
4961 ccode.add_expression (ccall);
4964 push_function (cfunc);
4966 CCodeExpression func_result = deserialize_expression (to, new CCodeIdentifier ("value"), new CCodeIdentifier ("*result"));
4967 if (to.is_real_non_null_struct_type ()) {
4968 ccode.add_assignment (new CCodeIdentifier ("*result"), func_result);
4970 ccode.add_return (func_result);
4975 cfile.add_function_declaration (cfunc);
4976 cfile.add_function (cfunc);
4978 return load_temp_value (result);
4981 public virtual CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
4982 assert_not_reached ();
4985 public virtual CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
4986 assert_not_reached ();
4989 public override void visit_cast_expression (CastExpression expr) {
4990 var valuecast = try_cast_value_to_type (get_cvalue (expr.inner), expr.inner.value_type, expr.type_reference, expr);
4991 if (valuecast != null) {
4992 set_cvalue (expr, valuecast);
4996 var variantcast = try_cast_variant_to_type (expr.inner.target_value, expr.type_reference, expr);
4997 if (variantcast != null) {
4998 expr.target_value = variantcast;
5002 generate_type_declaration (expr.type_reference, cfile);
5004 var cl = expr.type_reference.data_type as Class;
5005 var iface = expr.type_reference.data_type as Interface;
5006 if (iface != null || (cl != null && !cl.is_compact)) {
5007 // checked cast for strict subtypes of GTypeInstance
5008 if (expr.is_silent_cast) {
5009 var cexpr = get_cvalue (expr.inner);
5010 var ccheck = create_type_check (cexpr, expr.type_reference);
5011 var ccast = new CCodeCastExpression (cexpr, get_ccode_name (expr.type_reference));
5012 var cnull = new CCodeConstant ("NULL");
5014 set_cvalue (expr, new CCodeConditionalExpression (ccheck, ccast, cnull));
5016 set_cvalue (expr, generate_instance_cast (get_cvalue (expr.inner), expr.type_reference.data_type));
5019 if (expr.is_silent_cast) {
5021 Report.error (expr.source_reference, "Operation not supported for this type");
5025 // recompute array length when casting to other array type
5026 var array_type = expr.type_reference as ArrayType;
5027 if (array_type != null && expr.inner.value_type is ArrayType) {
5028 if (array_type.element_type is GenericType || ((ArrayType) expr.inner.value_type).element_type is GenericType) {
5029 // element size unknown for generic arrays, retain array length as is
5030 for (int dim = 1; dim <= array_type.rank; dim++) {
5031 append_array_length (expr, get_array_length_cexpression (expr.inner, dim));
5034 var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5035 sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5037 var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5038 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (((ArrayType) expr.inner.value_type).element_type)));
5040 for (int dim = 1; dim <= array_type.rank; dim++) {
5041 append_array_length (expr, new CCodeBinaryExpression (CCodeBinaryOperator.DIV, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_array_length_cexpression (expr.inner, dim), sizeof_from), sizeof_to));
5044 } else if (array_type != null) {
5045 // cast from non-array to array, set invalid length
5046 // required by string.data, e.g.
5047 for (int dim = 1; dim <= array_type.rank; dim++) {
5048 append_array_length (expr, new CCodeConstant ("-1"));
5052 var innercexpr = get_cvalue (expr.inner);
5053 if (expr.type_reference.data_type is Struct && !expr.type_reference.nullable &&
5054 expr.inner.value_type.data_type is Struct && expr.inner.value_type.nullable) {
5055 // nullable integer or float or boolean or struct cast to non-nullable
5056 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, innercexpr);
5058 set_cvalue (expr, new CCodeCastExpression (innercexpr, get_ccode_name (expr.type_reference)));
5060 if (expr.type_reference is DelegateType) {
5061 if (get_delegate_target (expr.inner) != null) {
5062 set_delegate_target (expr, get_delegate_target (expr.inner));
5064 set_delegate_target (expr, new CCodeConstant ("NULL"));
5066 if (get_delegate_target_destroy_notify (expr.inner) != null) {
5067 set_delegate_target_destroy_notify (expr, get_delegate_target_destroy_notify (expr.inner));
5069 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
5075 public override void visit_named_argument (NamedArgument expr) {
5076 set_cvalue (expr, get_cvalue (expr.inner));
5079 public override void visit_pointer_indirection (PointerIndirection expr) {
5080 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cvalue (expr.inner)));
5083 public override void visit_addressof_expression (AddressofExpression expr) {
5084 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5087 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
5088 /* tmp = expr.inner; expr.inner = NULL; expr = tmp; */
5089 expr.target_value = store_temp_value (expr.inner.target_value, expr);
5091 if (expr.inner.value_type is StructValueType && !expr.inner.value_type.nullable) {
5092 // memset needs string.h
5093 cfile.add_include ("string.h");
5094 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
5095 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5096 creation_call.add_argument (new CCodeConstant ("0"));
5097 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.inner.value_type))));
5098 ccode.add_expression (creation_call);
5099 } else if (expr.value_type is DelegateType) {
5100 var target_destroy_notify = get_delegate_target_destroy_notify_cvalue (expr.inner.target_value);
5101 if (target_destroy_notify != null) {
5102 ccode.add_assignment (target_destroy_notify, new CCodeConstant ("NULL"));
5105 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5109 public override void visit_binary_expression (BinaryExpression expr) {
5110 var cleft = get_cvalue (expr.left);
5111 var cright = get_cvalue (expr.right);
5113 CCodeExpression? left_chain = null;
5115 var lbe = (BinaryExpression) expr.left;
5117 var temp_decl = get_temp_variable (lbe.right.target_type, true, null, false);
5118 emit_temp_var (temp_decl);
5119 var cvar = get_variable_cexpression (temp_decl.name);
5120 var clbe = (CCodeBinaryExpression) get_cvalue (lbe);
5122 clbe = (CCodeBinaryExpression) clbe.right;
5124 ccode.add_assignment (cvar, get_cvalue (lbe.right));
5125 clbe.right = get_variable_cexpression (temp_decl.name);
5130 CCodeBinaryOperator op;
5131 if (expr.operator == BinaryOperator.PLUS) {
5132 op = CCodeBinaryOperator.PLUS;
5133 } else if (expr.operator == BinaryOperator.MINUS) {
5134 op = CCodeBinaryOperator.MINUS;
5135 } else if (expr.operator == BinaryOperator.MUL) {
5136 op = CCodeBinaryOperator.MUL;
5137 } else if (expr.operator == BinaryOperator.DIV) {
5138 op = CCodeBinaryOperator.DIV;
5139 } else if (expr.operator == BinaryOperator.MOD) {
5140 if (expr.value_type.equals (double_type)) {
5141 cfile.add_include ("math.h");
5142 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
5143 ccall.add_argument (cleft);
5144 ccall.add_argument (cright);
5145 set_cvalue (expr, ccall);
5147 } else if (expr.value_type.equals (float_type)) {
5148 cfile.add_include ("math.h");
5149 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
5150 ccall.add_argument (cleft);
5151 ccall.add_argument (cright);
5152 set_cvalue (expr, ccall);
5155 op = CCodeBinaryOperator.MOD;
5157 } else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
5158 op = CCodeBinaryOperator.SHIFT_LEFT;
5159 } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
5160 op = CCodeBinaryOperator.SHIFT_RIGHT;
5161 } else if (expr.operator == BinaryOperator.LESS_THAN) {
5162 op = CCodeBinaryOperator.LESS_THAN;
5163 } else if (expr.operator == BinaryOperator.GREATER_THAN) {
5164 op = CCodeBinaryOperator.GREATER_THAN;
5165 } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
5166 op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
5167 } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
5168 op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
5169 } else if (expr.operator == BinaryOperator.EQUALITY) {
5170 op = CCodeBinaryOperator.EQUALITY;
5171 } else if (expr.operator == BinaryOperator.INEQUALITY) {
5172 op = CCodeBinaryOperator.INEQUALITY;
5173 } else if (expr.operator == BinaryOperator.BITWISE_AND) {
5174 op = CCodeBinaryOperator.BITWISE_AND;
5175 } else if (expr.operator == BinaryOperator.BITWISE_OR) {
5176 op = CCodeBinaryOperator.BITWISE_OR;
5177 } else if (expr.operator == BinaryOperator.BITWISE_XOR) {
5178 op = CCodeBinaryOperator.BITWISE_XOR;
5179 } else if (expr.operator == BinaryOperator.AND) {
5180 op = CCodeBinaryOperator.AND;
5181 } else if (expr.operator == BinaryOperator.OR) {
5182 op = CCodeBinaryOperator.OR;
5183 } else if (expr.operator == BinaryOperator.IN) {
5184 if (expr.right.value_type is ArrayType) {
5185 var array_type = (ArrayType) expr.right.value_type;
5186 var node = new CCodeFunctionCall (new CCodeIdentifier (generate_array_contains_wrapper (array_type)));
5187 node.add_argument (cright);
5188 node.add_argument (get_array_length_cexpression (expr.right));
5189 if (array_type.element_type is StructValueType) {
5190 node.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft));
5192 node.add_argument (cleft);
5194 set_cvalue (expr, node);
5196 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft));
5200 assert_not_reached ();
5203 if (expr.operator == BinaryOperator.EQUALITY ||
5204 expr.operator == BinaryOperator.INEQUALITY) {
5205 var left_type = expr.left.target_type;
5206 var right_type = expr.right.target_type;
5207 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
5209 if (left_type is StructValueType && right_type is StructValueType) {
5210 var equalfunc = generate_struct_equal_function ((Struct) left_type.data_type as Struct);
5211 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5212 ccall.add_argument (cleft);
5213 ccall.add_argument (cright);
5215 cright = new CCodeConstant ("TRUE");
5216 } else if ((left_type is IntegerType || left_type is FloatingType || left_type is BooleanType || left_type is EnumValueType) && left_type.nullable &&
5217 (right_type is IntegerType || right_type is FloatingType || right_type is BooleanType || right_type is EnumValueType) && right_type.nullable) {
5218 var equalfunc = generate_numeric_equal_function ((TypeSymbol) left_type.data_type);
5219 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5220 ccall.add_argument (cleft);
5221 ccall.add_argument (cright);
5223 cright = new CCodeConstant ("TRUE");
5227 if (!(expr.left.value_type is NullType)
5228 && expr.left.value_type.compatible (string_type)
5229 && !(expr.right.value_type is NullType)
5230 && expr.right.value_type.compatible (string_type)) {
5231 if (expr.operator == BinaryOperator.PLUS) {
5232 // string concatenation
5233 if (expr.left.is_constant () && expr.right.is_constant ()) {
5236 if (cleft is CCodeIdentifier) {
5237 left = ((CCodeIdentifier) cleft).name;
5238 } else if (cleft is CCodeConstant) {
5239 left = ((CCodeConstant) cleft).name;
5241 assert_not_reached ();
5243 if (cright is CCodeIdentifier) {
5244 right = ((CCodeIdentifier) cright).name;
5245 } else if (cright is CCodeConstant) {
5246 right = ((CCodeConstant) cright).name;
5248 assert_not_reached ();
5251 set_cvalue (expr, new CCodeConstant ("%s %s".printf (left, right)));
5254 // convert to g_strconcat (a, b, NULL)
5255 var temp_value = create_temp_value (expr.value_type, false, expr);
5257 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
5258 ccall.add_argument (cleft);
5259 ccall.add_argument (cright);
5260 ccall.add_argument (new CCodeConstant("NULL"));
5262 ccode.add_assignment (get_cvalue_ (temp_value), ccall);
5263 expr.target_value = temp_value;
5266 } else if (expr.operator == BinaryOperator.EQUALITY
5267 || expr.operator == BinaryOperator.INEQUALITY
5268 || expr.operator == BinaryOperator.LESS_THAN
5269 || expr.operator == BinaryOperator.GREATER_THAN
5270 || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL
5271 || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
5272 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5273 ccall.add_argument (cleft);
5274 ccall.add_argument (cright);
5276 cright = new CCodeConstant ("0");
5280 set_cvalue (expr, new CCodeBinaryExpression (op, cleft, cright));
5281 if (left_chain != null) {
5282 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.AND, left_chain, get_cvalue (expr)));
5286 CCodeExpression? create_type_check (CCodeNode ccodenode, DataType type) {
5287 var et = type as ErrorType;
5288 if (et != null && et.error_code != null) {
5289 var matches_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
5290 matches_call.add_argument ((CCodeExpression) ccodenode);
5291 matches_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain)));
5292 matches_call.add_argument (new CCodeIdentifier (get_ccode_name (et.error_code)));
5293 return matches_call;
5294 } else if (et != null && et.error_domain != null) {
5295 var instance_domain = new CCodeMemberAccess.pointer ((CCodeExpression) ccodenode, "domain");
5296 var type_domain = new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain));
5297 return new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, instance_domain, type_domain);
5299 string type_id = get_ccode_type_id (type.data_type);
5300 if (type_id == "") {
5301 return new CCodeInvalidExpression ();
5303 var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
5304 ccheck.add_argument ((CCodeExpression) ccodenode);
5305 ccheck.add_argument (new CCodeIdentifier (type_id));
5310 string generate_array_contains_wrapper (ArrayType array_type) {
5311 string array_contains_func = "_vala_%s_array_contains".printf (get_ccode_lower_case_name (array_type.element_type));
5313 if (!add_wrapper (array_contains_func)) {
5314 return array_contains_func;
5317 var function = new CCodeFunction (array_contains_func, "gboolean");
5318 function.modifiers = CCodeModifiers.STATIC;
5320 function.add_parameter (new CCodeParameter ("stack", "%s*".printf (get_ccode_name (array_type.element_type))));
5321 function.add_parameter (new CCodeParameter ("stack_length", "int"));
5322 if (array_type.element_type is StructValueType) {
5323 function.add_parameter (new CCodeParameter ("needle", get_ccode_name (array_type.element_type) + "*"));
5325 function.add_parameter (new CCodeParameter ("needle", get_ccode_name (array_type.element_type)));
5328 push_function (function);
5330 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
5332 var cloop_initializer = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
5333 var cloop_condition = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("stack_length"));
5334 var cloop_iterator = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"));
5335 ccode.open_for (cloop_initializer, cloop_condition, cloop_iterator);
5337 var celement = new CCodeElementAccess (new CCodeIdentifier ("stack"), new CCodeIdentifier ("i"));
5338 var cneedle = new CCodeIdentifier ("needle");
5339 CCodeBinaryExpression cif_condition;
5340 if (array_type.element_type.compatible (string_type)) {
5341 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5342 ccall.add_argument (celement);
5343 ccall.add_argument (cneedle);
5344 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("0"));
5345 } else if (array_type.element_type is StructValueType) {
5346 var equalfunc = generate_struct_equal_function ((Struct) array_type.element_type.data_type as Struct);
5347 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5348 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, celement));
5349 ccall.add_argument (cneedle);
5350 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("TRUE"));
5352 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cneedle, celement);
5355 ccode.open_if (cif_condition);
5356 ccode.add_return (new CCodeConstant ("TRUE"));
5361 ccode.add_return (new CCodeConstant ("FALSE"));
5365 cfile.add_function_declaration (function);
5366 cfile.add_function (function);
5368 return array_contains_func;
5371 public override void visit_type_check (TypeCheck expr) {
5372 generate_type_declaration (expr.type_reference, cfile);
5374 set_cvalue (expr, create_type_check (get_cvalue (expr.expression), expr.type_reference));
5375 if (get_cvalue (expr) is CCodeInvalidExpression) {
5376 Report.error (expr.source_reference, "type check expressions not supported for compact classes, structs, and enums");
5380 public override void visit_lambda_expression (LambdaExpression lambda) {
5381 var delegate_type = (DelegateType) lambda.target_type;
5382 var d = delegate_type.delegate_symbol;
5384 lambda.method.set_attribute_bool ("CCode", "array_length", d.get_attribute_bool ("CCode", "array_length"));
5385 lambda.method.set_attribute_bool ("CCode", "array_null_terminated", d.get_attribute_bool ("CCode", "array_null_terminated"));
5386 lambda.method.set_attribute_string ("CCode", "array_length_type", d.get_attribute_string ("CCode", "array_length_type"));
5388 lambda.accept_children (this);
5390 bool expr_owned = lambda.value_type.value_owned;
5392 set_cvalue (lambda, new CCodeIdentifier (get_ccode_name (lambda.method)));
5394 if (lambda.method.closure) {
5395 int block_id = get_block_id (current_closure_block);
5396 var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
5397 if (expr_owned || delegate_type.is_called_once) {
5398 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
5399 ref_call.add_argument (delegate_target);
5400 delegate_target = ref_call;
5401 set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
5403 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5405 set_delegate_target (lambda, delegate_target);
5406 } else if (get_this_type () != null) {
5407 CCodeExpression delegate_target = get_result_cexpression ("self");
5408 if (expr_owned || delegate_type.is_called_once) {
5409 if (get_this_type () != null) {
5410 var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_this_type (), lambda.source_reference));
5411 ref_call.add_argument (delegate_target);
5412 delegate_target = ref_call;
5413 set_delegate_target_destroy_notify (lambda, get_destroy_func_expression (get_this_type ()));
5416 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
5417 ref_call.add_argument (delegate_target);
5418 delegate_target = ref_call;
5419 set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("g_object_unref"));
5422 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5424 set_delegate_target (lambda, delegate_target);
5426 set_delegate_target (lambda, new CCodeConstant ("NULL"));
5427 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5431 public CCodeExpression convert_from_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
5433 if (is_reference_type_argument (actual_type) || is_nullable_value_type_argument (actual_type)) {
5434 result = new CCodeCastExpression (cexpr, get_ccode_name (actual_type));
5435 } else if (is_signed_integer_type_argument (actual_type)) {
5436 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), get_ccode_name (actual_type));
5437 } else if (is_unsigned_integer_type_argument (actual_type)) {
5438 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), get_ccode_name (actual_type));
5443 public CCodeExpression convert_to_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
5445 if (is_signed_integer_type_argument (actual_type)) {
5446 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), "gpointer");
5447 } else if (is_unsigned_integer_type_argument (actual_type)) {
5448 result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), "gpointer");
5453 public TargetValue transform_value (TargetValue value, DataType? target_type, CodeNode node) {
5454 var type = value.value_type;
5455 var result = ((GLibValue) value).copy ();
5456 var requires_temp_value = false;
5458 if (type.value_owned
5459 && type.floating_reference) {
5460 /* floating reference, sink it.
5462 var cl = type.data_type as ObjectTypeSymbol;
5463 var sink_func = (cl != null) ? get_ccode_ref_sink_function (cl) : "";
5465 if (sink_func != "") {
5466 if (type.nullable) {
5467 var is_not_null = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, result.cvalue, new CCodeIdentifier ("NULL"));
5468 ccode.open_if (is_not_null);
5471 var csink = new CCodeFunctionCall (new CCodeIdentifier (sink_func));
5472 csink.add_argument (result.cvalue);
5473 ccode.add_expression (csink);
5475 if (type.nullable) {
5479 Report.error (null, "type `%s' does not support floating references".printf (type.data_type.name));
5483 bool boxing = (type is ValueType && !type.nullable
5484 && target_type is ValueType && target_type.nullable);
5485 bool unboxing = (type is ValueType && type.nullable
5486 && target_type is ValueType && !target_type.nullable);
5488 bool gvalue_boxing = (target_type != null
5489 && target_type.data_type == gvalue_type
5490 && !(type is NullType)
5491 && get_ccode_type_id (type) != "G_TYPE_VALUE");
5492 bool gvariant_boxing = (target_type != null
5493 && target_type.data_type == gvariant_type
5494 && !(type is NullType)
5495 && type.data_type != gvariant_type);
5497 if (type.value_owned
5498 && (target_type == null || !target_type.value_owned || boxing || unboxing || gvariant_boxing)
5499 && !gvalue_boxing /* gvalue can assume ownership of value, no need to free it */) {
5500 // value leaked, destroy it
5501 if (target_type is PointerType) {
5502 // manual memory management for pointers
5503 } else if (requires_destroy (type)) {
5504 if (!is_lvalue_access_allowed (type)) {
5505 // cannot assign to a temporary variable
5506 temp_ref_values.insert (0, result.copy ());
5508 var temp_value = create_temp_value (type, false, node);
5509 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5510 store_value (temp_value, result);
5511 result.cvalue = get_cvalue_ (temp_value);
5512 requires_temp_value = false;
5517 if (target_type == null) {
5518 // value will be destroyed, no need for implicit casts
5522 result.value_type = target_type.copy ();
5524 if (gvalue_boxing) {
5525 // implicit conversion to GValue
5526 var temp_value = create_temp_value (target_type, true, node, true);
5528 if (!target_type.value_owned) {
5529 // boxed GValue leaked, destroy it
5530 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
5533 if (target_type.nullable) {
5534 var newcall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
5535 newcall.add_argument (new CCodeConstant ("GValue"));
5536 newcall.add_argument (new CCodeConstant ("1"));
5537 var newassignment = new CCodeAssignment (get_cvalue_ (temp_value), newcall);
5538 ccode.add_expression (newassignment);
5541 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
5542 if (target_type.nullable) {
5543 ccall.add_argument (get_cvalue_ (temp_value));
5545 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
5547 var type_id = get_ccode_type_id (type);
5548 if (type_id == "") {
5549 Report.error (node.source_reference, "GValue boxing of type `%s' is not supported".printf (type.to_string ()));
5551 ccall.add_argument (new CCodeIdentifier (type_id));
5552 ccode.add_expression (ccall);
5554 if (requires_destroy (type)) {
5555 ccall = new CCodeFunctionCall (get_value_taker_function (type));
5557 ccall = new CCodeFunctionCall (get_value_setter_function (type));
5559 if (target_type.nullable) {
5560 ccall.add_argument (get_cvalue_ (temp_value));
5562 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
5564 if (type.is_real_non_null_struct_type ()) {
5565 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue));
5567 ccall.add_argument (result.cvalue);
5570 ccode.add_expression (ccall);
5572 result = (GLibValue) temp_value;
5573 requires_temp_value = false;
5574 } else if (gvariant_boxing) {
5575 // implicit conversion to GVariant
5576 string variant_func = "_variant_new%d".printf (++next_variant_function_id);
5578 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
5579 ccall.add_argument (result.cvalue);
5581 var cfunc = new CCodeFunction (variant_func, "GVariant*");
5582 cfunc.modifiers = CCodeModifiers.STATIC;
5583 cfunc.add_parameter (new CCodeParameter ("value", get_ccode_name (type)));
5585 if (type is ArrayType) {
5586 // return array length if appropriate
5587 var array_type = (ArrayType) type;
5589 for (int dim = 1; dim <= array_type.rank; dim++) {
5590 ccall.add_argument (get_array_length_cvalue (value, dim));
5591 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), "gint"));
5595 push_function (cfunc);
5597 // sink floating reference
5598 var sink = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_ref_sink"));
5599 sink.add_argument (serialize_expression (type, new CCodeIdentifier ("value")));
5600 ccode.add_return (sink);
5604 cfile.add_function_declaration (cfunc);
5605 cfile.add_function (cfunc);
5607 result.cvalue = ccall;
5608 requires_temp_value = true;
5609 } else if (boxing) {
5610 // value needs to be boxed
5612 result.value_type.nullable = false;
5613 if (!result.lvalue || !result.value_type.equals (value.value_type)) {
5614 result.cvalue = get_implicit_cast_expression (result.cvalue, value.value_type, result.value_type, node);
5615 result = (GLibValue) store_temp_value (result, node);
5616 requires_temp_value = false;
5618 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue);
5619 result.lvalue = false;
5620 result.value_type.nullable = true;
5621 } else if (unboxing) {
5624 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result.cvalue);
5626 result.cvalue = get_implicit_cast_expression (result.cvalue, type, target_type, node);
5629 if (requires_temp_value && !(target_type is ArrayType && ((ArrayType) target_type).inline_allocated)) {
5630 result = (GLibValue) store_temp_value (result, node);
5633 if (!gvalue_boxing && !gvariant_boxing && target_type.value_owned && (!type.value_owned || boxing || unboxing) && requires_copy (target_type) && !(type is NullType)) {
5634 // need to copy value
5635 var copy = (GLibValue) copy_value (result, node);
5636 if (target_type.data_type is Interface && copy == null) {
5637 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 ()));
5646 public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, CodeNode? node) {
5647 var cexpr = source_cexpr;
5649 if (expression_type.data_type != null && expression_type.data_type == target_type.data_type) {
5650 // same type, no cast required
5654 if (expression_type is NullType) {
5655 // null literal, no cast required when not converting to generic type pointer
5659 generate_type_declaration (target_type, cfile);
5661 var cl = target_type.data_type as Class;
5662 var iface = target_type.data_type as Interface;
5663 if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
5664 // checked cast for strict subtypes of GTypeInstance
5665 return generate_instance_cast (cexpr, target_type.data_type);
5666 } else if (target_type.data_type != null && get_ccode_name (expression_type) != get_ccode_name (target_type)) {
5667 var st = target_type.data_type as Struct;
5668 if (target_type.data_type.is_reference_type () || (st != null && st.is_simple_type ())) {
5669 // don't cast non-simple structs
5670 return new CCodeCastExpression (cexpr, get_ccode_name (target_type));
5679 public void store_property (Property prop, Expression? instance, TargetValue value) {
5680 if (instance is BaseAccess) {
5681 if (prop.base_property != null) {
5682 var base_class = (Class) prop.base_property.parent_symbol;
5683 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class, null))));
5684 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class, null))));
5686 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
5687 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
5688 ccall.add_argument (get_cvalue_ (value));
5690 ccode.add_expression (ccall);
5691 } else if (prop.base_interface_property != null) {
5692 var base_iface = (Interface) prop.base_interface_property.parent_symbol;
5693 string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface));
5695 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "set_%s".printf (prop.name)));
5696 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
5697 ccall.add_argument (get_cvalue_ (value));
5699 ccode.add_expression (ccall);
5704 var set_func = "g_object_set";
5706 var base_property = prop;
5707 if (!get_ccode_no_accessor_method (prop)) {
5708 if (prop.base_property != null) {
5709 base_property = prop.base_property;
5710 } else if (prop.base_interface_property != null) {
5711 base_property = prop.base_interface_property;
5714 if (prop is DynamicProperty) {
5715 set_func = get_dynamic_property_setter_cname ((DynamicProperty) prop);
5717 generate_property_accessor_declaration (base_property.set_accessor, cfile);
5718 set_func = get_ccode_name (base_property.set_accessor);
5720 if (!prop.external && prop.external_package) {
5721 // internal VAPI properties
5722 // only add them once per source file
5723 if (add_generated_external_symbol (prop)) {
5724 visit_property (prop);
5730 var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
5732 if (prop.binding == MemberBinding.INSTANCE) {
5733 /* target instance is first argument */
5734 var cinstance = (CCodeExpression) get_ccodenode (instance);
5736 if (prop.parent_symbol is Struct) {
5737 // we need to pass struct instance by reference
5738 var instance_value = instance.target_value;
5739 if (!get_lvalue (instance_value)) {
5740 instance_value = store_temp_value (instance_value, instance);
5742 cinstance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
5745 ccall.add_argument (cinstance);
5748 if (get_ccode_no_accessor_method (prop)) {
5749 /* property name is second argument of g_object_set */
5750 ccall.add_argument (get_property_canonical_cconstant (prop));
5753 var cexpr = get_cvalue_ (value);
5755 if (prop.property_type.is_real_non_null_struct_type ()) {
5756 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5759 var array_type = prop.property_type as ArrayType;
5761 ccall.add_argument (cexpr);
5763 if (array_type != null && get_ccode_array_length (prop)) {
5764 for (int dim = 1; dim <= array_type.rank; dim++) {
5765 ccall.add_argument (get_array_length_cvalue (value, dim));
5767 } else if (prop.property_type is DelegateType) {
5768 var delegate_type = (DelegateType) prop.property_type;
5769 if (delegate_type.delegate_symbol.has_target) {
5770 ccall.add_argument (get_delegate_target_cvalue (value));
5771 if (base_property.set_accessor.value_type.value_owned) {
5772 ccall.add_argument (get_delegate_target_destroy_notify_cvalue (value));
5777 if (get_ccode_no_accessor_method (prop)) {
5778 ccall.add_argument (new CCodeConstant ("NULL"));
5781 ccode.add_expression (ccall);
5784 public bool add_wrapper (string wrapper_name) {
5785 return wrappers.add (wrapper_name);
5788 public bool add_generated_external_symbol (Symbol external_symbol) {
5789 return generated_external_symbols.add (external_symbol);
5792 public static DataType get_data_type_for_symbol (TypeSymbol sym) {
5793 DataType type = null;
5796 type = new ObjectType ((Class) sym);
5797 } else if (sym is Interface) {
5798 type = new ObjectType ((Interface) sym);
5799 } else if (sym is Struct) {
5800 var st = (Struct) sym;
5801 if (st.is_boolean_type ()) {
5802 type = new BooleanType (st);
5803 } else if (st.is_integer_type ()) {
5804 type = new IntegerType (st);
5805 } else if (st.is_floating_type ()) {
5806 type = new FloatingType (st);
5808 type = new StructValueType (st);
5810 } else if (sym is Enum) {
5811 type = new EnumValueType ((Enum) sym);
5812 } else if (sym is ErrorDomain) {
5813 type = new ErrorType ((ErrorDomain) sym, null);
5814 } else if (sym is ErrorCode) {
5815 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
5817 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
5818 return new InvalidType ();
5824 public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) {
5825 var st = type.data_type as Struct;
5826 var array_type = type as ArrayType;
5827 if (type.data_type != null && !type.nullable && get_ccode_default_value (type.data_type) != "") {
5828 return new CCodeConstant (get_ccode_default_value (type.data_type));
5829 } else if (initializer_expression && !type.nullable &&
5830 (st != null || (array_type != null && array_type.fixed_length))) {
5831 // 0-initialize struct with struct initializer { 0 }
5832 // only allowed as initializer expression in C
5833 var clist = new CCodeInitializerList ();
5834 clist.append (new CCodeConstant ("0"));
5836 } else if ((type.data_type != null && type.data_type.is_reference_type ())
5838 || type is PointerType || type is DelegateType
5839 || (array_type != null && !array_type.fixed_length)) {
5840 return new CCodeConstant ("NULL");
5841 } else if (type.type_parameter != null) {
5842 return new CCodeConstant ("NULL");
5843 } else if (type is ErrorType) {
5844 return new CCodeConstant ("NULL");
5849 private void create_property_type_check_statement (Property prop, bool check_return_type, TypeSymbol t, bool non_null, string var_name) {
5850 if (check_return_type) {
5851 create_type_check_statement (prop, prop.property_type, t, non_null, var_name);
5853 create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
5857 public virtual void create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
5860 public int get_param_pos (double param_pos, bool ellipsis = false) {
5862 if (param_pos >= 0) {
5863 return (int) (param_pos * 1000);
5865 return (int) ((100 + param_pos) * 1000);
5868 if (param_pos >= 0) {
5869 return (int) ((100 + param_pos) * 1000);
5871 return (int) ((200 + param_pos) * 1000);
5876 public CCodeExpression? get_ccodenode (Expression node) {
5877 if (get_cvalue (node) == null) {
5880 return get_cvalue (node);
5883 public bool is_lvalue_access_allowed (DataType type) {
5884 var array_type = type as ArrayType;
5885 if (array_type != null && array_type.inline_allocated) {
5888 if (type.data_type != null) {
5889 return type.data_type.get_attribute_bool ("CCode", "lvalue_access", true);
5894 public static CCodeAttribute get_ccode_attribute (CodeNode node) {
5895 var attr = node.get_attribute_cache (ccode_attribute_cache_index);
5897 attr = new CCodeAttribute (node);
5898 node.set_attribute_cache (ccode_attribute_cache_index, attr);
5900 return (CCodeAttribute) attr;
5903 public static string get_ccode_name (CodeNode node) {
5904 return get_ccode_attribute(node).name;
5907 public static string get_ccode_const_name (CodeNode node) {
5908 return get_ccode_attribute(node).const_name;
5911 public static string get_ccode_type_name (Interface iface) {
5912 return get_ccode_attribute(iface).type_name;
5915 public static string get_ccode_lower_case_name (CodeNode node, string? infix = null) {
5916 var sym = node as Symbol;
5918 if (infix == null) {
5921 if (sym is Delegate) {
5922 return "%s%s%s".printf (get_ccode_lower_case_prefix (sym.parent_symbol), infix, Symbol.camel_case_to_lower_case (sym.name));
5923 } else if (sym is ErrorCode) {
5924 return get_ccode_name (sym).down ();
5926 return "%s%s%s".printf (get_ccode_lower_case_prefix (sym.parent_symbol), infix, get_ccode_lower_case_suffix (sym));
5928 } else if (node is ErrorType) {
5929 var type = (ErrorType) node;
5930 if (type.error_domain == null) {
5931 if (infix == null) {
5934 return "g_%s_error".printf (infix);
5936 } else if (type.error_code == null) {
5937 return get_ccode_lower_case_name (type.error_domain, infix);
5939 return get_ccode_lower_case_name (type.error_code, infix);
5942 var type = (DataType) node;
5943 return get_ccode_lower_case_name (type.data_type, infix);
5947 public static string get_ccode_upper_case_name (Symbol sym, string? infix = null) {
5948 if (sym is Property) {
5949 return "%s_%s".printf (get_ccode_lower_case_name (sym.parent_symbol), Symbol.camel_case_to_lower_case (sym.name)).up ();
5951 return get_ccode_lower_case_name (sym, infix).up ();
5955 public static string get_ccode_header_filenames (Symbol sym) {
5956 return get_ccode_attribute(sym).header_filenames;
5959 public static string get_ccode_prefix (Symbol sym) {
5960 return get_ccode_attribute(sym).prefix;
5963 public static string get_ccode_lower_case_prefix (Symbol sym) {
5964 return get_ccode_attribute(sym).lower_case_prefix;
5967 public static string get_ccode_lower_case_suffix (Symbol sym) {
5968 return get_ccode_attribute(sym).lower_case_suffix;
5971 public static string get_ccode_ref_function (TypeSymbol sym) {
5972 return get_ccode_attribute(sym).ref_function;
5975 public static bool is_reference_counting (TypeSymbol sym) {
5977 return get_ccode_ref_function (sym) != null;
5978 } else if (sym is Interface) {
5985 public static bool get_ccode_ref_function_void (Class cl) {
5986 return get_ccode_attribute(cl).ref_function_void;
5989 public static bool get_ccode_free_function_address_of (Class cl) {
5990 return get_ccode_attribute(cl).free_function_address_of;
5993 public static string get_ccode_unref_function (ObjectTypeSymbol sym) {
5994 return get_ccode_attribute(sym).unref_function;
5997 public static string get_ccode_ref_sink_function (ObjectTypeSymbol sym) {
5998 return get_ccode_attribute(sym).ref_sink_function;
6001 public static string get_ccode_copy_function (TypeSymbol sym) {
6002 return get_ccode_attribute(sym).copy_function;
6005 public static string get_ccode_destroy_function (TypeSymbol sym) {
6006 return get_ccode_attribute(sym).destroy_function;
6009 public static string? get_ccode_dup_function (TypeSymbol sym) {
6010 if (sym is Struct) {
6011 if (sym.external_package) {
6014 return get_ccode_lower_case_prefix (sym) + "dup";
6017 return get_ccode_copy_function (sym);
6020 public static string get_ccode_free_function (TypeSymbol sym) {
6021 return get_ccode_attribute(sym).free_function;
6024 public static bool get_ccode_is_gboxed (TypeSymbol sym) {
6025 return get_ccode_free_function (sym) == "g_boxed_free";
6028 public static string get_ccode_type_id (CodeNode node) {
6029 return get_ccode_attribute(node).type_id;
6032 public static string get_ccode_marshaller_type_name (CodeNode node) {
6033 return get_ccode_attribute(node).marshaller_type_name;
6036 public static string get_ccode_get_value_function (CodeNode sym) {
6037 return get_ccode_attribute(sym).get_value_function;
6040 public static string get_ccode_set_value_function (CodeNode sym) {
6041 return get_ccode_attribute(sym).set_value_function;
6044 public static string get_ccode_take_value_function (CodeNode sym) {
6045 return get_ccode_attribute(sym).take_value_function;
6048 public static string get_ccode_param_spec_function (CodeNode sym) {
6049 return get_ccode_attribute(sym).param_spec_function;
6052 public static string get_ccode_type_check_function (TypeSymbol sym) {
6053 var cl = sym as Class;
6054 var a = sym.get_attribute_string ("CCode", "type_check_function");
6055 if (cl != null && a != null) {
6057 } else if ((cl != null && cl.is_compact) || sym is Struct || sym is Enum || sym is Delegate) {
6060 return get_ccode_upper_case_name (sym, "IS_");
6064 public static string get_ccode_default_value (TypeSymbol sym) {
6065 return get_ccode_attribute(sym).default_value;
6068 public static bool get_ccode_has_copy_function (Struct st) {
6069 return st.get_attribute_bool ("CCode", "has_copy_function", true);
6072 public static bool get_ccode_has_destroy_function (Struct st) {
6073 return st.get_attribute_bool ("CCode", "has_destroy_function", true);
6076 public static double get_ccode_instance_pos (CodeNode node) {
6077 if (node is Delegate) {
6078 return node.get_attribute_double ("CCode", "instance_pos", -2);
6080 return node.get_attribute_double ("CCode", "instance_pos", 0);
6084 public static bool get_ccode_array_length (CodeNode node) {
6085 return get_ccode_attribute(node).array_length;
6088 public static string? get_ccode_array_length_type (CodeNode node) {
6089 return get_ccode_attribute(node).array_length_type;
6092 public static bool get_ccode_array_null_terminated (CodeNode node) {
6093 return get_ccode_attribute(node).array_null_terminated;
6096 public static string? get_ccode_array_length_name (CodeNode node) {
6097 return get_ccode_attribute(node).array_length_name;
6100 public static string? get_ccode_array_length_expr (CodeNode node) {
6101 return get_ccode_attribute(node).array_length_expr;
6104 public static double get_ccode_array_length_pos (CodeNode node) {
6105 var a = node.get_attribute ("CCode");
6106 if (a != null && a.has_argument ("array_length_pos")) {
6107 return a.get_double ("array_length_pos");
6109 if (node is Parameter) {
6110 var param = (Parameter) node;
6111 return get_ccode_pos (param) + 0.1;
6117 public static double get_ccode_delegate_target_pos (CodeNode node) {
6118 var a = node.get_attribute ("CCode");
6119 if (a != null && a.has_argument ("delegate_target_pos")) {
6120 return a.get_double ("delegate_target_pos");
6122 if (node is Parameter) {
6123 var param = (Parameter) node;
6124 return get_ccode_pos (param) + 0.1;
6130 public static double get_ccode_destroy_notify_pos (CodeNode node) {
6131 var a = node.get_attribute ("CCode");
6132 if (a != null && a.has_argument ("destroy_notify_pos")) {
6133 return a.get_double ("destroy_notify_pos");
6135 if (node is Parameter) {
6136 var param = (Parameter) node;
6137 return get_ccode_pos (param) + 0.1;
6143 public static bool get_ccode_delegate_target (CodeNode node) {
6144 return get_ccode_attribute(node).delegate_target;
6147 public static string get_ccode_delegate_target_name (Variable variable) {
6148 return get_ccode_attribute(variable).delegate_target_name;
6151 public static double get_ccode_pos (Parameter param) {
6152 return get_ccode_attribute(param).pos;
6155 public static string? get_ccode_type (CodeNode node) {
6156 return node.get_attribute_string ("CCode", "type");
6159 public static bool get_ccode_simple_generics (Method m) {
6160 return m.get_attribute_bool ("CCode", "simple_generics");
6163 public static string get_ccode_real_name (Symbol sym) {
6164 return get_ccode_attribute(sym).real_name;
6167 public static string get_ccode_vfunc_name (Method m) {
6168 return get_ccode_attribute(m).vfunc_name;
6171 public static string get_ccode_finish_name (Method m) {
6172 return get_ccode_attribute(m).finish_name;
6175 public static string get_ccode_finish_vfunc_name (Method m) {
6176 return get_ccode_attribute(m).finish_vfunc_name;
6179 public static string get_ccode_finish_real_name (Method m) {
6180 return get_ccode_attribute(m).finish_real_name;
6183 public static bool get_ccode_no_accessor_method (Property p) {
6184 return p.get_attribute ("NoAccessorMethod") != null;
6187 public static bool get_ccode_has_type_id (TypeSymbol sym) {
6188 return sym.get_attribute_bool ("CCode", "has_type_id", true);
6191 public static bool get_ccode_has_new_function (Method m) {
6192 return m.get_attribute_bool ("CCode", "has_new_function", true);
6195 public static bool get_ccode_has_generic_type_parameter (Method m) {
6196 var a = m.get_attribute ("CCode");
6197 return a != null && a.has_argument ("generic_type_pos");
6200 public static double get_ccode_generic_type_pos (Method m) {
6201 return m.get_attribute_double ("CCode", "generic_type_pos");
6204 public static string get_ccode_sentinel (Method m) {
6205 return get_ccode_attribute(m).sentinel;
6208 public static bool get_ccode_notify (Property prop) {
6209 return prop.get_attribute_bool ("CCode", "notify", true);
6212 public static string get_ccode_nick (Property prop) {
6213 var nick = prop.get_attribute_string ("Description", "nick");
6215 nick = prop.name.replace ("_", "-");
6220 public static string get_ccode_blurb (Property prop) {
6221 var blurb = prop.get_attribute_string ("Description", "blurb");
6222 if (blurb == null) {
6223 blurb = prop.name.replace ("_", "-");
6228 public static string get_ccode_declarator_suffix (DataType type) {
6229 var array_type = type as ArrayType;
6230 if (array_type != null) {
6231 if (array_type.fixed_length) {
6232 return "[%d]".printf (array_type.length);
6233 } else if (array_type.inline_allocated) {
6240 public CCodeConstant get_signal_canonical_constant (Signal sig, string? detail = null) {
6241 var str = new StringBuilder ("\"");
6243 string i = get_ccode_name (sig);
6245 while (i.length > 0) {
6246 unichar c = i.get_char ();
6250 str.append_unichar (c);
6256 if (detail != null) {
6258 str.append (detail);
6263 return new CCodeConstant (str.str);
6266 public static CCodeConstant get_enum_value_canonical_cconstant (EnumValue ev) {
6267 var str = new StringBuilder ("\"");
6271 while (i.length > 0) {
6272 unichar c = i.get_char ();
6276 str.append_unichar (c.tolower ());
6284 return new CCodeConstant (str.str);
6287 public bool get_signal_has_emitter (Signal sig) {
6288 return sig.get_attribute ("HasEmitter") != null;
6291 public CCodeConstant get_property_canonical_cconstant (Property prop) {
6292 return new CCodeConstant ("\"%s\"".printf (prop.name.replace ("_", "-")));
6295 public override void visit_class (Class cl) {
6298 public void create_postcondition_statement (Expression postcondition) {
6299 var cassert = new CCodeFunctionCall (new CCodeIdentifier ("g_warn_if_fail"));
6301 postcondition.emit (this);
6303 cassert.add_argument (get_cvalue (postcondition));
6305 ccode.add_expression (cassert);
6308 public virtual bool is_gobject_property (Property prop) {
6312 public DataType? get_this_type () {
6313 if (current_method != null && current_method.binding == MemberBinding.INSTANCE) {
6314 return current_method.this_parameter.variable_type;
6315 } else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) {
6316 return current_property_accessor.prop.this_parameter.variable_type;
6317 } else if (current_constructor != null && current_constructor.binding == MemberBinding.INSTANCE) {
6318 return current_constructor.this_parameter.variable_type;
6319 } else if (current_destructor != null && current_destructor.binding == MemberBinding.INSTANCE) {
6320 return current_destructor.this_parameter.variable_type;
6325 public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
6326 var result = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_CAST"));
6327 result.add_argument (expr);
6328 result.add_argument (new CCodeIdentifier (get_ccode_type_id (type)));
6329 result.add_argument (new CCodeIdentifier (get_ccode_name (type)));
6333 void generate_struct_destroy_function (Struct st) {
6334 if (cfile.add_declaration (get_ccode_destroy_function (st))) {
6335 // only generate function once per source file
6339 var function = new CCodeFunction (get_ccode_destroy_function (st), "void");
6340 function.modifiers = CCodeModifiers.STATIC;
6341 function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
6343 push_context (new EmitContext ());
6344 push_function (function);
6346 var this_value = load_this_parameter (st);
6347 foreach (Field f in st.get_fields ()) {
6348 if (f.binding == MemberBinding.INSTANCE) {
6349 if (requires_destroy (f.variable_type)) {
6350 ccode.add_expression (destroy_field (f, this_value));
6358 cfile.add_function_declaration (function);
6359 cfile.add_function (function);
6362 void generate_struct_copy_function (Struct st) {
6363 if (cfile.add_declaration (get_ccode_copy_function (st))) {
6364 // only generate function once per source file
6368 var function = new CCodeFunction (get_ccode_copy_function (st), "void");
6369 function.modifiers = CCodeModifiers.STATIC;
6370 function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
6371 function.add_parameter (new CCodeParameter ("dest", get_ccode_name (st) + "*"));
6373 push_context (new EmitContext ());
6374 push_function (function);
6376 var dest_struct = new GLibValue (get_data_type_for_symbol (st), new CCodeIdentifier ("(*dest)"), true);
6377 foreach (Field f in st.get_fields ()) {
6378 if (f.binding == MemberBinding.INSTANCE) {
6379 var value = load_field (f, load_this_parameter ((TypeSymbol) st));
6380 if (requires_copy (f.variable_type)) {
6381 value = copy_value (value, f);
6382 if (value == null) {
6383 // error case, continue to avoid critical
6387 store_field (f, dest_struct, value);
6394 cfile.add_function_declaration (function);
6395 cfile.add_function (function);
6398 public void return_default_value (DataType return_type) {
6399 ccode.add_return (default_value_for_type (return_type, false));
6402 public virtual void generate_dynamic_method_wrapper (DynamicMethod method) {
6405 public virtual bool method_has_wrapper (Method method) {
6409 public virtual CCodeFunctionCall get_param_spec (Property prop) {
6410 return new CCodeFunctionCall (new CCodeIdentifier (""));
6413 public virtual CCodeFunctionCall get_signal_creation (Signal sig, TypeSymbol type) {
6414 return new CCodeFunctionCall (new CCodeIdentifier (""));
6417 public virtual void register_dbus_info (CCodeBlock block, ObjectTypeSymbol bindable) {
6420 public virtual string get_dynamic_property_getter_cname (DynamicProperty node) {
6421 Report.error (node.source_reference, "dynamic properties are not supported for %s".printf (node.dynamic_type.to_string ()));
6425 public virtual string get_dynamic_property_setter_cname (DynamicProperty node) {
6426 Report.error (node.source_reference, "dynamic properties are not supported for %s".printf (node.dynamic_type.to_string ()));
6430 public virtual string get_dynamic_signal_cname (DynamicSignal node) {
6434 public virtual string get_dynamic_signal_connect_wrapper_name (DynamicSignal node) {
6438 public virtual string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal node) {
6442 public virtual string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node) {
6446 public virtual string get_array_length_cname (string array_cname, int dim) {
6450 public virtual string get_parameter_array_length_cname (Parameter param, int dim) {
6454 public virtual CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
6455 return new CCodeConstant ("");
6458 public virtual CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
6459 return new CCodeInvalidExpression ();
6462 public virtual string get_array_size_cname (string array_cname) {
6466 public virtual void add_simple_check (CodeNode node, bool always_fails = false) {
6469 public virtual string generate_ready_function (Method m) {
6473 public CCodeExpression? get_cvalue (Expression expr) {
6474 if (expr.target_value == null) {
6477 var glib_value = (GLibValue) expr.target_value;
6478 return glib_value.cvalue;
6481 public CCodeExpression? get_cvalue_ (TargetValue value) {
6482 var glib_value = (GLibValue) value;
6483 return glib_value.cvalue;
6486 public void set_cvalue (Expression expr, CCodeExpression? cvalue) {
6487 var glib_value = (GLibValue) expr.target_value;
6488 if (glib_value == null) {
6489 glib_value = new GLibValue (expr.value_type);
6490 expr.target_value = glib_value;
6492 glib_value.cvalue = cvalue;
6495 public CCodeExpression? get_array_size_cvalue (TargetValue value) {
6496 var glib_value = (GLibValue) value;
6497 return glib_value.array_size_cvalue;
6500 public void set_array_size_cvalue (TargetValue value, CCodeExpression? cvalue) {
6501 var glib_value = (GLibValue) value;
6502 glib_value.array_size_cvalue = cvalue;
6505 public CCodeExpression? get_delegate_target (Expression expr) {
6506 if (expr.target_value == null) {
6509 var glib_value = (GLibValue) expr.target_value;
6510 return glib_value.delegate_target_cvalue;
6513 public void set_delegate_target (Expression expr, CCodeExpression? delegate_target) {
6514 var glib_value = (GLibValue) expr.target_value;
6515 if (glib_value == null) {
6516 glib_value = new GLibValue (expr.value_type);
6517 expr.target_value = glib_value;
6519 glib_value.delegate_target_cvalue = delegate_target;
6522 public CCodeExpression? get_delegate_target_destroy_notify (Expression expr) {
6523 if (expr.target_value == null) {
6526 var glib_value = (GLibValue) expr.target_value;
6527 return glib_value.delegate_target_destroy_notify_cvalue;
6530 public void set_delegate_target_destroy_notify (Expression expr, CCodeExpression? destroy_notify) {
6531 var glib_value = (GLibValue) expr.target_value;
6532 if (glib_value == null) {
6533 glib_value = new GLibValue (expr.value_type);
6534 expr.target_value = glib_value;
6536 glib_value.delegate_target_destroy_notify_cvalue = destroy_notify;
6539 public void append_array_length (Expression expr, CCodeExpression size) {
6540 var glib_value = (GLibValue) expr.target_value;
6541 if (glib_value == null) {
6542 glib_value = new GLibValue (expr.value_type);
6543 expr.target_value = glib_value;
6545 glib_value.append_array_length_cvalue (size);
6548 public List<CCodeExpression>? get_array_lengths (Expression expr) {
6549 var glib_value = (GLibValue) expr.target_value;
6550 if (glib_value == null) {
6551 glib_value = new GLibValue (expr.value_type);
6552 expr.target_value = glib_value;
6554 return glib_value.array_length_cvalues;
6557 public bool get_lvalue (TargetValue value) {
6558 var glib_value = (GLibValue) value;
6559 return glib_value.lvalue;
6562 public bool get_non_null (TargetValue value) {
6563 var glib_value = (GLibValue) value;
6564 return glib_value.non_null;
6567 public string? get_ctype (TargetValue value) {
6568 var glib_value = (GLibValue) value;
6569 return glib_value.ctype;
6572 public bool get_array_null_terminated (TargetValue value) {
6573 var glib_value = (GLibValue) value;
6574 return glib_value.array_null_terminated;
6577 public CCodeExpression get_array_length_cexpr (TargetValue value) {
6578 var glib_value = (GLibValue) value;
6579 return glib_value.array_length_cexpr;
6583 public class Vala.GLibValue : TargetValue {
6584 public CCodeExpression cvalue;
6586 public bool non_null;
6587 public string? ctype;
6589 public List<CCodeExpression> array_length_cvalues;
6590 public CCodeExpression? array_size_cvalue;
6591 public bool array_null_terminated;
6592 public CCodeExpression? array_length_cexpr;
6594 public CCodeExpression? delegate_target_cvalue;
6595 public CCodeExpression? delegate_target_destroy_notify_cvalue;
6597 public GLibValue (DataType? value_type = null, CCodeExpression? cvalue = null, bool lvalue = false) {
6599 this.cvalue = cvalue;
6600 this.lvalue = lvalue;
6603 public void append_array_length_cvalue (CCodeExpression length_cvalue) {
6604 if (array_length_cvalues == null) {
6605 array_length_cvalues = new ArrayList<CCodeExpression> ();
6607 array_length_cvalues.add (length_cvalue);
6610 public GLibValue copy () {
6611 var result = new GLibValue (value_type.copy (), cvalue, lvalue);
6612 result.actual_value_type = actual_value_type;
6613 result.non_null = non_null;
6614 result.ctype = ctype;
6616 if (array_length_cvalues != null) {
6617 foreach (var cexpr in array_length_cvalues) {
6618 result.append_array_length_cvalue (cexpr);
6621 result.array_size_cvalue = array_size_cvalue;
6622 result.array_null_terminated = array_null_terminated;
6623 result.array_length_cexpr = array_length_cexpr;
6625 result.delegate_target_cvalue = delegate_target_cvalue;
6626 result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify_cvalue;