codegen: Add CCodeFunction.add_assignment convenience function
[vala-lang.git] / codegen / valaccodebasemodule.vala
blobf188209852dace15eff75cb7d45217535d5baacd
1 /* valaccodebasemodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 /**
27 * Code visitor generating C Code.
29 public abstract class Vala.CCodeBaseModule : CodeGenerator {
30 public class EmitContext {
31 public Symbol? current_symbol;
32 public ArrayList<Symbol> symbol_stack = new ArrayList<Symbol> ();
33 public TryStatement current_try;
34 public CatchClause current_catch;
35 public CCodeFunction ccode;
36 public ArrayList<CCodeFunction> ccode_stack = new ArrayList<CCodeFunction> ();
37 public ArrayList<LocalVariable> temp_ref_vars = new ArrayList<LocalVariable> ();
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);
43 public EmitContext (Symbol? symbol = null) {
44 current_symbol = symbol;
47 public void push_symbol (Symbol symbol) {
48 symbol_stack.add (current_symbol);
49 current_symbol = symbol;
52 public void pop_symbol () {
53 current_symbol = symbol_stack[symbol_stack.size - 1];
54 symbol_stack.remove_at (symbol_stack.size - 1);
58 public CodeContext context { get; set; }
60 public Symbol root_symbol;
62 public EmitContext emit_context = new EmitContext ();
64 List<EmitContext> emit_context_stack = new ArrayList<EmitContext> ();
66 public Symbol current_symbol { get { return emit_context.current_symbol; } }
68 public TryStatement current_try {
69 get { return emit_context.current_try; }
70 set { emit_context.current_try = value; }
73 public CatchClause current_catch {
74 get { return emit_context.current_catch; }
75 set { emit_context.current_catch = value; }
78 public TypeSymbol? current_type_symbol {
79 get {
80 var sym = current_symbol;
81 while (sym != null) {
82 if (sym is TypeSymbol) {
83 return (TypeSymbol) sym;
85 sym = sym.parent_symbol;
87 return null;
91 public Class? current_class {
92 get { return current_type_symbol as Class; }
95 public Method? current_method {
96 get {
97 var sym = current_symbol;
98 while (sym is Block) {
99 sym = sym.parent_symbol;
101 return sym as Method;
105 public PropertyAccessor? current_property_accessor {
106 get {
107 var sym = current_symbol;
108 while (sym is Block) {
109 sym = sym.parent_symbol;
111 return sym as PropertyAccessor;
115 public DataType? current_return_type {
116 get {
117 var m = current_method;
118 if (m != null) {
119 return m.return_type;
122 var acc = current_property_accessor;
123 if (acc != null) {
124 if (acc.readable) {
125 return acc.value_type;
126 } else {
127 return void_type;
131 if (is_in_constructor () || is_in_destructor ()) {
132 return void_type;
135 return null;
139 public bool is_in_constructor () {
140 if (current_method != null) {
141 // make sure to not return true in lambda expression inside constructor
142 return false;
144 var sym = current_symbol;
145 while (sym != null) {
146 if (sym is Constructor) {
147 return true;
149 sym = sym.parent_symbol;
151 return false;
154 public bool is_in_destructor () {
155 if (current_method != null) {
156 // make sure to not return true in lambda expression inside constructor
157 return false;
159 var sym = current_symbol;
160 while (sym != null) {
161 if (sym is Destructor) {
162 return true;
164 sym = sym.parent_symbol;
166 return false;
169 public Block? current_closure_block {
170 get {
171 return next_closure_block (current_symbol);
175 public unowned Block? next_closure_block (Symbol sym) {
176 unowned Block block = null;
177 while (true) {
178 block = sym as Block;
179 if (!(sym is Block || sym is Method)) {
180 // no closure block
181 break;
183 if (block != null && block.captured) {
184 // closure block found
185 break;
187 sym = sym.parent_symbol;
189 return block;
192 public CCodeFile header_file;
193 public CCodeFile internal_header_file;
194 public CCodeFile cfile;
196 public EmitContext class_init_context;
197 public EmitContext base_init_context;
198 public EmitContext class_finalize_context;
199 public EmitContext base_finalize_context;
200 public EmitContext instance_init_context;
201 public EmitContext instance_finalize_context;
203 public CCodeStruct param_spec_struct;
204 public CCodeStruct closure_struct;
205 public CCodeEnum prop_enum;
207 public CCodeFunction ccode { get { return emit_context.ccode; } }
209 /* temporary variables that own their content */
210 public ArrayList<LocalVariable> temp_ref_vars { get { return emit_context.temp_ref_vars; } }
211 /* cache to check whether a certain marshaller has been created yet */
212 public Set<string> user_marshal_set;
213 /* (constant) hash table with all predefined marshallers */
214 public Set<string> predefined_marshal_set;
215 /* (constant) hash table with all reserved identifiers in the generated code */
216 Set<string> reserved_identifiers;
218 public int next_temp_var_id {
219 get { return emit_context.next_temp_var_id; }
220 set { emit_context.next_temp_var_id = value; }
223 public int next_regex_id = 0;
224 public bool in_creation_method { get { return current_method is CreationMethod; } }
225 public bool in_constructor = false;
226 public bool in_static_or_class_context = false;
228 public bool current_method_inner_error {
229 get { return emit_context.current_method_inner_error; }
230 set { emit_context.current_method_inner_error = value; }
233 public bool current_method_return {
234 get { return emit_context.current_method_return; }
235 set { emit_context.current_method_return = value; }
238 public int next_coroutine_state = 1;
239 int next_block_id = 0;
240 Map<Block,int> block_map = new HashMap<Block,int> ();
242 public DataType void_type = new VoidType ();
243 public DataType bool_type;
244 public DataType char_type;
245 public DataType uchar_type;
246 public DataType? unichar_type;
247 public DataType short_type;
248 public DataType ushort_type;
249 public DataType int_type;
250 public DataType uint_type;
251 public DataType long_type;
252 public DataType ulong_type;
253 public DataType int8_type;
254 public DataType uint8_type;
255 public DataType int16_type;
256 public DataType uint16_type;
257 public DataType int32_type;
258 public DataType uint32_type;
259 public DataType int64_type;
260 public DataType uint64_type;
261 public DataType string_type;
262 public DataType regex_type;
263 public DataType float_type;
264 public DataType double_type;
265 public TypeSymbol gtype_type;
266 public TypeSymbol gobject_type;
267 public ErrorType gerror_type;
268 public Class glist_type;
269 public Class gslist_type;
270 public Class gnode_type;
271 public Class gvaluearray_type;
272 public TypeSymbol gstringbuilder_type;
273 public TypeSymbol garray_type;
274 public TypeSymbol gbytearray_type;
275 public TypeSymbol gptrarray_type;
276 public TypeSymbol gthreadpool_type;
277 public DataType gdestroynotify_type;
278 public DataType gquark_type;
279 public Struct gvalue_type;
280 public Class gvariant_type;
281 public Struct mutex_type;
282 public TypeSymbol type_module_type;
283 public TypeSymbol dbus_proxy_type;
284 public TypeSymbol dbus_object_type;
286 public bool in_plugin = false;
287 public string module_init_param_name;
289 public bool gvaluecollector_h_needed;
290 public bool requires_array_free;
291 public bool requires_array_move;
292 public bool requires_array_length;
294 public Set<string> wrappers;
295 Set<Symbol> generated_external_symbols;
297 public Map<string,string> variable_name_map { get { return emit_context.variable_name_map; } }
299 public CCodeBaseModule () {
300 predefined_marshal_set = new HashSet<string> (str_hash, str_equal);
301 predefined_marshal_set.add ("VOID:VOID");
302 predefined_marshal_set.add ("VOID:BOOLEAN");
303 predefined_marshal_set.add ("VOID:CHAR");
304 predefined_marshal_set.add ("VOID:UCHAR");
305 predefined_marshal_set.add ("VOID:INT");
306 predefined_marshal_set.add ("VOID:UINT");
307 predefined_marshal_set.add ("VOID:LONG");
308 predefined_marshal_set.add ("VOID:ULONG");
309 predefined_marshal_set.add ("VOID:ENUM");
310 predefined_marshal_set.add ("VOID:FLAGS");
311 predefined_marshal_set.add ("VOID:FLOAT");
312 predefined_marshal_set.add ("VOID:DOUBLE");
313 predefined_marshal_set.add ("VOID:STRING");
314 predefined_marshal_set.add ("VOID:POINTER");
315 predefined_marshal_set.add ("VOID:OBJECT");
316 predefined_marshal_set.add ("STRING:OBJECT,POINTER");
317 predefined_marshal_set.add ("VOID:UINT,POINTER");
318 predefined_marshal_set.add ("BOOLEAN:FLAGS");
320 reserved_identifiers = new HashSet<string> (str_hash, str_equal);
322 // C99 keywords
323 reserved_identifiers.add ("_Bool");
324 reserved_identifiers.add ("_Complex");
325 reserved_identifiers.add ("_Imaginary");
326 reserved_identifiers.add ("asm");
327 reserved_identifiers.add ("auto");
328 reserved_identifiers.add ("break");
329 reserved_identifiers.add ("case");
330 reserved_identifiers.add ("char");
331 reserved_identifiers.add ("const");
332 reserved_identifiers.add ("continue");
333 reserved_identifiers.add ("default");
334 reserved_identifiers.add ("do");
335 reserved_identifiers.add ("double");
336 reserved_identifiers.add ("else");
337 reserved_identifiers.add ("enum");
338 reserved_identifiers.add ("extern");
339 reserved_identifiers.add ("float");
340 reserved_identifiers.add ("for");
341 reserved_identifiers.add ("goto");
342 reserved_identifiers.add ("if");
343 reserved_identifiers.add ("inline");
344 reserved_identifiers.add ("int");
345 reserved_identifiers.add ("long");
346 reserved_identifiers.add ("register");
347 reserved_identifiers.add ("restrict");
348 reserved_identifiers.add ("return");
349 reserved_identifiers.add ("short");
350 reserved_identifiers.add ("signed");
351 reserved_identifiers.add ("sizeof");
352 reserved_identifiers.add ("static");
353 reserved_identifiers.add ("struct");
354 reserved_identifiers.add ("switch");
355 reserved_identifiers.add ("typedef");
356 reserved_identifiers.add ("union");
357 reserved_identifiers.add ("unsigned");
358 reserved_identifiers.add ("void");
359 reserved_identifiers.add ("volatile");
360 reserved_identifiers.add ("while");
362 // MSVC keywords
363 reserved_identifiers.add ("cdecl");
365 // reserved for Vala/GObject naming conventions
366 reserved_identifiers.add ("error");
367 reserved_identifiers.add ("result");
368 reserved_identifiers.add ("self");
371 public override void emit (CodeContext context) {
372 this.context = context;
374 root_symbol = context.root;
376 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
377 char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
378 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
379 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
380 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
381 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
382 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
383 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
384 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
385 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
386 uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8"));
387 int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16"));
388 uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16"));
389 int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32"));
390 uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32"));
391 int64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int64"));
392 uint64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint64"));
393 float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
394 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
395 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
396 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
397 if (unichar_struct != null) {
398 unichar_type = new IntegerType (unichar_struct);
401 if (context.profile == Profile.GOBJECT) {
402 var glib_ns = root_symbol.scope.lookup ("GLib");
404 gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
405 gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
406 gerror_type = new ErrorType (null, null);
407 glist_type = (Class) glib_ns.scope.lookup ("List");
408 gslist_type = (Class) glib_ns.scope.lookup ("SList");
409 gnode_type = (Class) glib_ns.scope.lookup ("Node");
410 gvaluearray_type = (Class) glib_ns.scope.lookup ("ValueArray");
411 gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
412 garray_type = (TypeSymbol) glib_ns.scope.lookup ("Array");
413 gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
414 gptrarray_type = (TypeSymbol) glib_ns.scope.lookup ("PtrArray");
415 gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
416 gdestroynotify_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("DestroyNotify"));
418 gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
419 gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
420 gvariant_type = (Class) glib_ns.scope.lookup ("Variant");
421 mutex_type = (Struct) glib_ns.scope.lookup ("StaticRecMutex");
423 type_module_type = (TypeSymbol) glib_ns.scope.lookup ("TypeModule");
425 regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
427 if (context.module_init_method != null) {
428 foreach (Parameter parameter in context.module_init_method.get_parameters ()) {
429 if (parameter.variable_type.data_type == type_module_type) {
430 in_plugin = true;
431 module_init_param_name = parameter.name;
432 break;
435 if (!in_plugin) {
436 Report.error (context.module_init_method.source_reference, "[ModuleInit] requires a parameter of type `GLib.TypeModule'");
440 dbus_proxy_type = (TypeSymbol) glib_ns.scope.lookup ("DBusProxy");
442 var dbus_ns = root_symbol.scope.lookup ("DBus");
443 if (dbus_ns != null) {
444 dbus_object_type = (TypeSymbol) dbus_ns.scope.lookup ("Object");
448 header_file = new CCodeFile ();
449 header_file.is_header = true;
450 internal_header_file = new CCodeFile ();
451 internal_header_file.is_header = true;
453 /* we're only interested in non-pkg source files */
454 var source_files = context.get_source_files ();
455 foreach (SourceFile file in source_files) {
456 if (file.file_type == SourceFileType.SOURCE ||
457 (context.header_filename != null && file.file_type == SourceFileType.FAST)) {
458 file.accept (this);
462 // generate symbols file for public API
463 if (context.symbols_filename != null) {
464 var stream = FileStream.open (context.symbols_filename, "w");
465 if (stream == null) {
466 Report.error (null, "unable to open `%s' for writing".printf (context.symbols_filename));
467 return;
470 foreach (string symbol in header_file.get_symbols ()) {
471 stream.puts (symbol);
472 stream.putc ('\n');
475 stream = null;
478 // generate C header file for public API
479 if (context.header_filename != null) {
480 bool ret;
481 if (context.profile == Profile.GOBJECT) {
482 ret = header_file.store (context.header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
483 } else {
484 ret = header_file.store (context.header_filename, null, context.version_header, false);
486 if (!ret) {
487 Report.error (null, "unable to open `%s' for writing".printf (context.header_filename));
491 // generate C header file for internal API
492 if (context.internal_header_filename != null) {
493 bool ret;
494 if (context.profile == Profile.GOBJECT) {
495 ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
496 } else {
497 ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false);
499 if (!ret) {
500 Report.error (null, "unable to open `%s' for writing".printf (context.internal_header_filename));
505 public void push_context (EmitContext emit_context) {
506 if (this.emit_context != null) {
507 emit_context_stack.add (this.emit_context);
510 this.emit_context = emit_context;
513 public void pop_context () {
514 if (emit_context_stack.size > 0) {
515 this.emit_context = emit_context_stack[emit_context_stack.size - 1];
516 emit_context_stack.remove_at (emit_context_stack.size - 1);
517 } else {
518 this.emit_context = null;
522 public void push_function (CCodeFunction func) {
523 emit_context.ccode_stack.add (ccode);
524 emit_context.ccode = func;
527 public void pop_function () {
528 emit_context.ccode = emit_context.ccode_stack[emit_context.ccode_stack.size - 1];
529 emit_context.ccode_stack.remove_at (emit_context.ccode_stack.size - 1);
532 public bool add_symbol_declaration (CCodeFile decl_space, Symbol sym, string name) {
533 if (decl_space.add_declaration (name)) {
534 return true;
536 if (sym.source_reference != null) {
537 sym.source_reference.file.used = true;
539 if (sym.external_package || (!decl_space.is_header && CodeContext.get ().use_header && !sym.is_internal_symbol ())) {
540 // add appropriate include file
541 foreach (string header_filename in sym.get_cheader_filenames ()) {
542 decl_space.add_include (header_filename, !sym.external_package);
544 // declaration complete
545 return true;
546 } else {
547 // require declaration
548 return false;
552 public CCodeIdentifier get_value_setter_function (DataType type_reference) {
553 var array_type = type_reference as ArrayType;
554 if (type_reference.data_type != null) {
555 return new CCodeIdentifier (type_reference.data_type.get_set_value_function ());
556 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
557 // G_TYPE_STRV
558 return new CCodeIdentifier ("g_value_set_boxed");
559 } else {
560 return new CCodeIdentifier ("g_value_set_pointer");
564 public CCodeIdentifier get_value_taker_function (DataType type_reference) {
565 var array_type = type_reference as ArrayType;
566 if (type_reference.data_type != null) {
567 return new CCodeIdentifier (type_reference.data_type.get_take_value_function ());
568 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
569 // G_TYPE_STRV
570 return new CCodeIdentifier ("g_value_take_boxed");
571 } else {
572 return new CCodeIdentifier ("g_value_set_pointer");
576 CCodeIdentifier get_value_getter_function (DataType type_reference) {
577 var array_type = type_reference as ArrayType;
578 if (type_reference.data_type != null) {
579 return new CCodeIdentifier (type_reference.data_type.get_get_value_function ());
580 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
581 // G_TYPE_STRV
582 return new CCodeIdentifier ("g_value_get_boxed");
583 } else {
584 return new CCodeIdentifier ("g_value_get_pointer");
588 public virtual void append_vala_array_free () {
591 public virtual void append_vala_array_move () {
594 public virtual void append_vala_array_length () {
597 public override void visit_source_file (SourceFile source_file) {
598 cfile = new CCodeFile ();
600 user_marshal_set = new HashSet<string> (str_hash, str_equal);
602 next_regex_id = 0;
604 gvaluecollector_h_needed = false;
605 requires_array_free = false;
606 requires_array_move = false;
607 requires_array_length = false;
609 wrappers = new HashSet<string> (str_hash, str_equal);
610 generated_external_symbols = new HashSet<Symbol> ();
612 if (context.profile == Profile.GOBJECT) {
613 header_file.add_include ("glib.h");
614 internal_header_file.add_include ("glib.h");
615 cfile.add_include ("glib.h");
616 cfile.add_include ("glib-object.h");
619 source_file.accept_children (this);
621 if (context.report.get_errors () > 0) {
622 return;
625 /* For fast-vapi, we only wanted the header declarations
626 * to be emitted, so bail out here without writing the
627 * C code output.
629 if (source_file.file_type == SourceFileType.FAST) {
630 return;
633 if (requires_array_free) {
634 append_vala_array_free ();
636 if (requires_array_move) {
637 append_vala_array_move ();
639 if (requires_array_length) {
640 append_vala_array_length ();
643 if (gvaluecollector_h_needed) {
644 cfile.add_include ("gobject/gvaluecollector.h");
647 var comments = source_file.get_comments();
648 if (comments != null) {
649 foreach (Comment comment in comments) {
650 var ccomment = new CCodeComment (comment.content);
651 cfile.add_comment (ccomment);
655 if (!cfile.store (source_file.get_csource_filename (), source_file.filename, context.version_header, context.debug)) {
656 Report.error (null, "unable to open `%s' for writing".printf (source_file.get_csource_filename ()));
659 cfile = null;
662 public virtual bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
663 if (add_symbol_declaration (decl_space, en, en.get_cname ())) {
664 return false;
667 var cenum = new CCodeEnum (en.get_cname ());
669 cenum.deprecated = en.deprecated;
671 int flag_shift = 0;
672 foreach (EnumValue ev in en.get_values ()) {
673 CCodeEnumValue c_ev;
674 if (ev.value == null) {
675 c_ev = new CCodeEnumValue (ev.get_cname ());
676 if (en.is_flags) {
677 c_ev.value = new CCodeConstant ("1 << %d".printf (flag_shift));
678 flag_shift += 1;
680 } else {
681 ev.value.emit (this);
682 c_ev = new CCodeEnumValue (ev.get_cname (), get_cvalue (ev.value));
684 c_ev.deprecated = ev.deprecated;
685 cenum.add_value (c_ev);
688 decl_space.add_type_definition (cenum);
689 decl_space.add_type_definition (new CCodeNewline ());
691 if (!en.has_type_id) {
692 return true;
695 decl_space.add_type_declaration (new CCodeNewline ());
697 var macro = "(%s_get_type ())".printf (en.get_lower_case_cname (null));
698 decl_space.add_type_declaration (new CCodeMacroReplacement (en.get_type_id (), macro));
700 var fun_name = "%s_get_type".printf (en.get_lower_case_cname (null));
701 var regfun = new CCodeFunction (fun_name, "GType");
702 regfun.attributes = "G_GNUC_CONST";
704 if (en.access == SymbolAccessibility.PRIVATE) {
705 regfun.modifiers = CCodeModifiers.STATIC;
706 // avoid C warning as this function is not always used
707 regfun.attributes = "G_GNUC_UNUSED";
710 decl_space.add_function_declaration (regfun);
712 return true;
715 public override void visit_enum (Enum en) {
716 en.accept_children (this);
718 if (en.comment != null) {
719 cfile.add_type_member_definition (new CCodeComment (en.comment.content));
722 generate_enum_declaration (en, cfile);
724 if (!en.is_internal_symbol ()) {
725 generate_enum_declaration (en, header_file);
727 if (!en.is_private_symbol ()) {
728 generate_enum_declaration (en, internal_header_file);
732 public void visit_member (Symbol m) {
733 /* stuff meant for all lockable members */
734 if (m is Lockable && ((Lockable) m).get_lock_used ()) {
735 CCodeExpression l = new CCodeIdentifier ("self");
736 var init_context = class_init_context;
737 var finalize_context = class_finalize_context;
739 if (m.is_instance_member ()) {
740 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (m.name));
741 init_context = instance_init_context;
742 finalize_context = instance_finalize_context;
743 } else if (m.is_class_member ()) {
744 TypeSymbol parent = (TypeSymbol)m.parent_symbol;
746 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent.get_upper_case_cname ())));
747 get_class_private_call.add_argument (new CCodeIdentifier ("klass"));
748 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (m.name));
749 } else {
750 l = new CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf(m.parent_symbol.get_lower_case_cname (), m.name)));
753 push_context (init_context);
754 var initf = new CCodeFunctionCall (new CCodeIdentifier (mutex_type.default_construction_method.get_cname ()));
755 initf.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
756 ccode.add_expression (initf);
757 pop_context ();
759 if (finalize_context != null) {
760 push_context (finalize_context);
761 var fc = new CCodeFunctionCall (new CCodeIdentifier ("g_static_rec_mutex_free"));
762 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
763 ccode.add_expression (fc);
764 pop_context ();
769 public void generate_constant_declaration (Constant c, CCodeFile decl_space, bool definition = false) {
770 if (c.parent_symbol is Block) {
771 // local constant
772 return;
775 if (add_symbol_declaration (decl_space, c, c.get_cname ())) {
776 return;
779 if (!c.external) {
780 generate_type_declaration (c.type_reference, decl_space);
782 c.value.emit (this);
784 var initializer_list = c.value as InitializerList;
785 if (initializer_list != null) {
786 var cdecl = new CCodeDeclaration (c.type_reference.get_const_cname ());
787 var arr = "";
788 if (c.type_reference is ArrayType) {
789 arr = "[%d]".printf (initializer_list.size);
792 var cinitializer = get_cvalue (c.value);
793 if (!definition) {
794 // never output value in header
795 // special case needed as this method combines declaration and definition
796 cinitializer = null;
799 cdecl.add_declarator (new CCodeVariableDeclarator ("%s%s".printf (c.get_cname (), arr), cinitializer));
800 if (c.is_private_symbol ()) {
801 cdecl.modifiers = CCodeModifiers.STATIC;
802 } else {
803 cdecl.modifiers = CCodeModifiers.EXTERN;
806 decl_space.add_constant_declaration (cdecl);
807 } else {
808 var cdefine = new CCodeMacroReplacement.with_expression (c.get_cname (), get_cvalue (c.value));
809 decl_space.add_type_member_declaration (cdefine);
814 public override void visit_constant (Constant c) {
815 if (c.parent_symbol is Block) {
816 // local constant
818 generate_type_declaration (c.type_reference, cfile);
820 c.value.emit (this);
822 string type_name = c.type_reference.get_const_cname ();
823 string arr = "";
824 if (c.type_reference is ArrayType) {
825 arr = "[]";
828 if (c.type_reference.compatible (string_type)) {
829 type_name = "const char";
830 arr = "[]";
833 var cinitializer = get_cvalue (c.value);
835 ccode.add_declaration (type_name, new CCodeVariableDeclarator ("%s%s".printf (c.get_cname (), arr), cinitializer), CCodeModifiers.STATIC);
837 return;
840 generate_constant_declaration (c, cfile, true);
842 if (!c.is_internal_symbol ()) {
843 generate_constant_declaration (c, header_file);
845 if (!c.is_private_symbol ()) {
846 generate_constant_declaration (c, internal_header_file);
850 public void generate_field_declaration (Field f, CCodeFile decl_space) {
851 if (add_symbol_declaration (decl_space, f, f.get_cname ())) {
852 return;
855 generate_type_declaration (f.variable_type, decl_space);
857 string field_ctype = f.variable_type.get_cname ();
858 if (f.is_volatile) {
859 field_ctype = "volatile " + field_ctype;
862 var cdecl = new CCodeDeclaration (field_ctype);
863 cdecl.add_declarator (new CCodeVariableDeclarator (f.get_cname (), null, f.variable_type.get_cdeclarator_suffix ()));
864 if (f.is_private_symbol ()) {
865 cdecl.modifiers = CCodeModifiers.STATIC;
866 } else {
867 cdecl.modifiers = CCodeModifiers.EXTERN;
869 if (f.deprecated) {
870 cdecl.modifiers |= CCodeModifiers.DEPRECATED;
872 decl_space.add_type_member_declaration (cdecl);
874 if (f.get_lock_used ()) {
875 // Declare mutex for static member
876 var flock = new CCodeDeclaration (mutex_type.get_cname ());
877 var flock_decl = new CCodeVariableDeclarator (get_symbol_lock_name (f.get_cname ()), new CCodeConstant ("{0}"));
878 flock.add_declarator (flock_decl);
880 if (f.is_private_symbol ()) {
881 flock.modifiers = CCodeModifiers.STATIC;
882 } else {
883 flock.modifiers = CCodeModifiers.EXTERN;
885 decl_space.add_type_member_declaration (flock);
888 if (f.variable_type is ArrayType && !f.no_array_length) {
889 var array_type = (ArrayType) f.variable_type;
891 if (!array_type.fixed_length) {
892 for (int dim = 1; dim <= array_type.rank; dim++) {
893 var len_type = int_type.copy ();
895 cdecl = new CCodeDeclaration (len_type.get_cname ());
896 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_length_cname (f.get_cname (), dim)));
897 if (f.is_private_symbol ()) {
898 cdecl.modifiers = CCodeModifiers.STATIC;
899 } else {
900 cdecl.modifiers = CCodeModifiers.EXTERN;
902 decl_space.add_type_member_declaration (cdecl);
905 } else if (f.variable_type is DelegateType) {
906 var delegate_type = (DelegateType) f.variable_type;
907 if (delegate_type.delegate_symbol.has_target) {
908 // create field to store delegate target
910 cdecl = new CCodeDeclaration ("gpointer");
911 cdecl.add_declarator (new CCodeVariableDeclarator (get_delegate_target_cname (f.get_cname ())));
912 if (f.is_private_symbol ()) {
913 cdecl.modifiers = CCodeModifiers.STATIC;
914 } else {
915 cdecl.modifiers = CCodeModifiers.EXTERN;
917 decl_space.add_type_member_declaration (cdecl);
919 if (delegate_type.value_owned) {
920 cdecl = new CCodeDeclaration ("GDestroyNotify");
921 cdecl.add_declarator (new CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f.get_cname ())));
922 if (f.is_private_symbol ()) {
923 cdecl.modifiers = CCodeModifiers.STATIC;
924 } else {
925 cdecl.modifiers = CCodeModifiers.EXTERN;
927 decl_space.add_type_member_declaration (cdecl);
933 public override void visit_field (Field f) {
934 visit_member (f);
936 check_type (f.variable_type);
938 var cl = f.parent_symbol as Class;
939 bool is_gtypeinstance = (cl != null && !cl.is_compact);
941 CCodeExpression lhs = null;
943 string field_ctype = f.variable_type.get_cname ();
944 if (f.is_volatile) {
945 field_ctype = "volatile " + field_ctype;
948 if (f.binding == MemberBinding.INSTANCE) {
949 if (is_gtypeinstance && f.access == SymbolAccessibility.PRIVATE) {
950 lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ());
951 } else {
952 lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
955 if (f.initializer != null) {
956 push_context (instance_init_context);
958 f.initializer.emit (this);
960 var rhs = get_cvalue (f.initializer);
962 ccode.add_assignment (lhs, rhs);
964 if (f.variable_type is ArrayType && !f.no_array_length &&
965 f.initializer is ArrayCreationExpression) {
966 var array_type = (ArrayType) f.variable_type;
967 var this_access = new MemberAccess.simple ("this");
968 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
969 set_cvalue (this_access, new CCodeIdentifier ("self"));
970 var ma = new MemberAccess (this_access, f.name);
971 ma.symbol_reference = f;
972 ma.value_type = f.variable_type.copy ();
973 visit_member_access (ma);
975 List<Expression> sizes = ((ArrayCreationExpression) f.initializer).get_sizes ();
976 for (int dim = 1; dim <= array_type.rank; dim++) {
977 var array_len_lhs = get_array_length_cexpression (ma, dim);
978 var size = sizes[dim - 1];
979 ccode.add_assignment (array_len_lhs, get_cvalue (size));
982 if (array_type.rank == 1 && f.is_internal_symbol ()) {
983 var lhs_array_size = get_array_size_cvalue (ma.target_value);
984 var rhs_array_len = get_array_length_cexpression (ma, 1);
985 ccode.add_assignment (lhs_array_size, rhs_array_len);
989 foreach (LocalVariable local in temp_ref_vars) {
990 ccode.add_expression (get_unref_expression_ (local));
993 temp_ref_vars.clear ();
995 pop_context ();
998 if (requires_destroy (f.variable_type) && instance_finalize_context != null) {
999 push_context (instance_finalize_context);
1001 var this_access = new MemberAccess.simple ("this");
1002 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
1004 var field_st = f.parent_symbol as Struct;
1005 if (field_st != null && !field_st.is_simple_type ()) {
1006 set_cvalue (this_access, new CCodeIdentifier ("(*self)"));
1007 } else {
1008 set_cvalue (this_access, new CCodeIdentifier ("self"));
1011 var ma = new MemberAccess (this_access, f.name);
1012 ma.symbol_reference = f;
1013 ma.value_type = f.variable_type.copy ();
1014 visit_member_access (ma);
1015 ccode.add_expression (get_unref_expression (lhs, f.variable_type, ma));
1017 pop_context ();
1019 } else if (f.binding == MemberBinding.CLASS) {
1020 if (!is_gtypeinstance) {
1021 Report.error (f.source_reference, "class fields are not supported in compact classes");
1022 f.error = true;
1023 return;
1026 if (f.access == SymbolAccessibility.PRIVATE) {
1027 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (cl.get_upper_case_cname ())));
1028 ccall.add_argument (new CCodeIdentifier ("klass"));
1029 lhs = new CCodeMemberAccess (ccall, f.get_cname (), true);
1030 } else {
1031 lhs = new CCodeMemberAccess (new CCodeIdentifier ("klass"), f.get_cname (), true);
1034 if (f.initializer != null) {
1035 push_context (class_init_context);
1037 f.initializer.emit (this);
1039 var rhs = get_cvalue (f.initializer);
1041 ccode.add_assignment (lhs, rhs);
1043 foreach (LocalVariable local in temp_ref_vars) {
1044 ccode.add_expression (get_unref_expression_ (local));
1047 temp_ref_vars.clear ();
1049 pop_context ();
1051 } else {
1052 generate_field_declaration (f, cfile);
1054 if (!f.is_internal_symbol ()) {
1055 generate_field_declaration (f, header_file);
1057 if (!f.is_private_symbol ()) {
1058 generate_field_declaration (f, internal_header_file);
1061 lhs = new CCodeIdentifier (f.get_cname ());
1063 var var_decl = new CCodeVariableDeclarator (f.get_cname (), null, f.variable_type.get_cdeclarator_suffix ());
1064 var_decl.initializer = default_value_for_type (f.variable_type, true);
1066 if (class_init_context != null) {
1067 push_context (class_init_context);
1068 } else {
1069 push_context (new EmitContext ());
1072 if (f.initializer != null) {
1073 f.initializer.emit (this);
1075 var init = get_cvalue (f.initializer);
1076 if (is_constant_ccode_expression (init)) {
1077 var_decl.initializer = init;
1081 var var_def = new CCodeDeclaration (field_ctype);
1082 var_def.add_declarator (var_decl);
1083 if (!f.is_private_symbol ()) {
1084 var_def.modifiers = CCodeModifiers.EXTERN;
1085 } else {
1086 var_def.modifiers = CCodeModifiers.STATIC;
1088 cfile.add_type_member_declaration (var_def);
1090 /* add array length fields where necessary */
1091 if (f.variable_type is ArrayType && !f.no_array_length) {
1092 var array_type = (ArrayType) f.variable_type;
1094 if (!array_type.fixed_length) {
1095 for (int dim = 1; dim <= array_type.rank; dim++) {
1096 var len_type = int_type.copy ();
1098 var len_def = new CCodeDeclaration (len_type.get_cname ());
1099 len_def.add_declarator (new CCodeVariableDeclarator (get_array_length_cname (f.get_cname (), dim), new CCodeConstant ("0")));
1100 if (!f.is_private_symbol ()) {
1101 len_def.modifiers = CCodeModifiers.EXTERN;
1102 } else {
1103 len_def.modifiers = CCodeModifiers.STATIC;
1105 cfile.add_type_member_declaration (len_def);
1108 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1109 var len_type = int_type.copy ();
1111 var cdecl = new CCodeDeclaration (len_type.get_cname ());
1112 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_size_cname (f.get_cname ()), new CCodeConstant ("0")));
1113 cdecl.modifiers = CCodeModifiers.STATIC;
1114 cfile.add_type_member_declaration (cdecl);
1117 } else if (f.variable_type is DelegateType) {
1118 var delegate_type = (DelegateType) f.variable_type;
1119 if (delegate_type.delegate_symbol.has_target) {
1120 // create field to store delegate target
1122 var target_def = new CCodeDeclaration ("gpointer");
1123 target_def.add_declarator (new CCodeVariableDeclarator (get_delegate_target_cname (f.get_cname ()), new CCodeConstant ("NULL")));
1124 if (!f.is_private_symbol ()) {
1125 target_def.modifiers = CCodeModifiers.EXTERN;
1126 } else {
1127 target_def.modifiers = CCodeModifiers.STATIC;
1129 cfile.add_type_member_declaration (target_def);
1131 if (delegate_type.value_owned) {
1132 var target_destroy_notify_def = new CCodeDeclaration ("GDestroyNotify");
1133 target_destroy_notify_def.add_declarator (new CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f.get_cname ()), new CCodeConstant ("NULL")));
1134 if (!f.is_private_symbol ()) {
1135 target_destroy_notify_def.modifiers = CCodeModifiers.EXTERN;
1136 } else {
1137 target_destroy_notify_def.modifiers = CCodeModifiers.STATIC;
1139 cfile.add_type_member_declaration (target_destroy_notify_def);
1145 if (f.initializer != null) {
1146 var rhs = get_cvalue (f.initializer);
1147 if (!is_constant_ccode_expression (rhs)) {
1148 if (f.parent_symbol is Class) {
1149 if (f.initializer is InitializerList) {
1150 ccode.open_block ();
1152 var temp_decl = get_temp_variable (f.variable_type);
1153 var vardecl = new CCodeVariableDeclarator.zero (temp_decl.name, rhs);
1154 ccode.add_declaration (temp_decl.variable_type.get_cname (), vardecl);
1156 var tmp = get_variable_cexpression (get_variable_cname (temp_decl.name));
1157 ccode.add_assignment (lhs, tmp);
1159 ccode.close ();
1160 } else {
1161 ccode.add_assignment (lhs, rhs);
1164 if (f.variable_type is ArrayType && !f.no_array_length &&
1165 f.initializer is ArrayCreationExpression) {
1166 var array_type = (ArrayType) f.variable_type;
1167 var ma = new MemberAccess.simple (f.name);
1168 ma.symbol_reference = f;
1169 ma.value_type = f.variable_type.copy ();
1170 visit_member_access (ma);
1172 List<Expression> sizes = ((ArrayCreationExpression) f.initializer).get_sizes ();
1173 for (int dim = 1; dim <= array_type.rank; dim++) {
1174 var array_len_lhs = get_array_length_cexpression (ma, dim);
1175 var size = sizes[dim - 1];
1176 ccode.add_assignment (array_len_lhs, get_cvalue (size));
1179 } else {
1180 f.error = true;
1181 Report.error (f.source_reference, "Non-constant field initializers not supported in this context");
1182 return;
1187 pop_context ();
1191 public bool is_constant_ccode_expression (CCodeExpression cexpr) {
1192 if (cexpr is CCodeConstant) {
1193 return true;
1194 } else if (cexpr is CCodeCastExpression) {
1195 var ccast = (CCodeCastExpression) cexpr;
1196 return is_constant_ccode_expression (ccast.inner);
1197 } else if (cexpr is CCodeBinaryExpression) {
1198 var cbinary = (CCodeBinaryExpression) cexpr;
1199 return is_constant_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1202 var cparenthesized = (cexpr as CCodeParenthesizedExpression);
1203 return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
1207 * Returns whether the passed cexpr is a pure expression, i.e. an
1208 * expression without side-effects.
1210 public bool is_pure_ccode_expression (CCodeExpression cexpr) {
1211 if (cexpr is CCodeConstant || cexpr is CCodeIdentifier) {
1212 return true;
1213 } else if (cexpr is CCodeBinaryExpression) {
1214 var cbinary = (CCodeBinaryExpression) cexpr;
1215 return is_pure_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1216 } else if (cexpr is CCodeUnaryExpression) {
1217 var cunary = (CCodeUnaryExpression) cexpr;
1218 switch (cunary.operator) {
1219 case CCodeUnaryOperator.PREFIX_INCREMENT:
1220 case CCodeUnaryOperator.PREFIX_DECREMENT:
1221 case CCodeUnaryOperator.POSTFIX_INCREMENT:
1222 case CCodeUnaryOperator.POSTFIX_DECREMENT:
1223 return false;
1224 default:
1225 return is_pure_ccode_expression (cunary.inner);
1227 } else if (cexpr is CCodeMemberAccess) {
1228 var cma = (CCodeMemberAccess) cexpr;
1229 return is_pure_ccode_expression (cma.inner);
1230 } else if (cexpr is CCodeElementAccess) {
1231 var cea = (CCodeElementAccess) cexpr;
1232 return is_pure_ccode_expression (cea.container) && is_pure_ccode_expression (cea.index);
1233 } else if (cexpr is CCodeCastExpression) {
1234 var ccast = (CCodeCastExpression) cexpr;
1235 return is_pure_ccode_expression (ccast.inner);
1236 } else if (cexpr is CCodeParenthesizedExpression) {
1237 var cparenthesized = (CCodeParenthesizedExpression) cexpr;
1238 return is_pure_ccode_expression (cparenthesized.inner);
1241 return false;
1244 public override void visit_formal_parameter (Parameter p) {
1245 if (!p.ellipsis) {
1246 check_type (p.variable_type);
1250 public override void visit_property (Property prop) {
1251 visit_member (prop);
1253 check_type (prop.property_type);
1255 if (prop.get_accessor != null) {
1256 prop.get_accessor.accept (this);
1258 if (prop.set_accessor != null) {
1259 prop.set_accessor.accept (this);
1263 public void generate_type_declaration (DataType type, CCodeFile decl_space) {
1264 if (type is ObjectType) {
1265 var object_type = (ObjectType) type;
1266 if (object_type.type_symbol is Class) {
1267 generate_class_declaration ((Class) object_type.type_symbol, decl_space);
1268 } else if (object_type.type_symbol is Interface) {
1269 generate_interface_declaration ((Interface) object_type.type_symbol, decl_space);
1271 } else if (type is DelegateType) {
1272 var deleg_type = (DelegateType) type;
1273 var d = deleg_type.delegate_symbol;
1274 generate_delegate_declaration (d, decl_space);
1275 } else if (type.data_type is Enum) {
1276 var en = (Enum) type.data_type;
1277 generate_enum_declaration (en, decl_space);
1278 } else if (type is ValueType) {
1279 var value_type = (ValueType) type;
1280 generate_struct_declaration ((Struct) value_type.type_symbol, decl_space);
1281 } else if (type is ArrayType) {
1282 var array_type = (ArrayType) type;
1283 generate_type_declaration (array_type.element_type, decl_space);
1284 } else if (type is ErrorType) {
1285 var error_type = (ErrorType) type;
1286 if (error_type.error_domain != null) {
1287 generate_error_domain_declaration (error_type.error_domain, decl_space);
1289 } else if (type is PointerType) {
1290 var pointer_type = (PointerType) type;
1291 generate_type_declaration (pointer_type.base_type, decl_space);
1294 foreach (DataType type_arg in type.get_type_arguments ()) {
1295 generate_type_declaration (type_arg, decl_space);
1299 public virtual void generate_class_struct_declaration (Class cl, CCodeFile decl_space) {
1302 public virtual void generate_struct_declaration (Struct st, CCodeFile decl_space) {
1305 public virtual void generate_delegate_declaration (Delegate d, CCodeFile decl_space) {
1308 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) {
1311 public void generate_property_accessor_declaration (PropertyAccessor acc, CCodeFile decl_space) {
1312 if (add_symbol_declaration (decl_space, acc, acc.get_cname ())) {
1313 return;
1316 var prop = (Property) acc.prop;
1318 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1321 CCodeParameter cvalueparam;
1322 if (returns_real_struct) {
1323 cvalueparam = new CCodeParameter ("result", acc.value_type.get_cname () + "*");
1324 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1325 cvalueparam = new CCodeParameter ("value", acc.value_type.get_cname () + "*");
1326 } else {
1327 cvalueparam = new CCodeParameter ("value", acc.value_type.get_cname ());
1329 generate_type_declaration (acc.value_type, decl_space);
1331 CCodeFunction function;
1332 if (acc.readable && !returns_real_struct) {
1333 function = new CCodeFunction (acc.get_cname (), acc.value_type.get_cname ());
1334 } else {
1335 function = new CCodeFunction (acc.get_cname (), "void");
1338 if (prop.binding == MemberBinding.INSTANCE) {
1339 var t = (TypeSymbol) prop.parent_symbol;
1340 var this_type = get_data_type_for_symbol (t);
1341 generate_type_declaration (this_type, decl_space);
1342 var cselfparam = new CCodeParameter ("self", this_type.get_cname ());
1343 if (t is Struct) {
1344 cselfparam.type_name += "*";
1347 function.add_parameter (cselfparam);
1350 if (acc.writable || acc.construction || returns_real_struct) {
1351 function.add_parameter (cvalueparam);
1354 if (acc.value_type is ArrayType) {
1355 var array_type = (ArrayType) acc.value_type;
1357 var length_ctype = "int";
1358 if (acc.readable) {
1359 length_ctype = "int*";
1362 for (int dim = 1; dim <= array_type.rank; dim++) {
1363 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), length_ctype));
1365 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1366 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1369 if (prop.is_private_symbol () || (!acc.readable && !acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1370 function.modifiers |= CCodeModifiers.STATIC;
1372 decl_space.add_function_declaration (function);
1375 public override void visit_property_accessor (PropertyAccessor acc) {
1376 push_context (new EmitContext (acc));
1378 var prop = (Property) acc.prop;
1380 if (acc.comment != null) {
1381 cfile.add_type_member_definition (new CCodeComment (acc.comment.content));
1384 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1386 if (acc.result_var != null) {
1387 acc.result_var.accept (this);
1390 var t = (TypeSymbol) prop.parent_symbol;
1392 if (acc.construction && !t.is_subtype_of (gobject_type)) {
1393 Report.error (acc.source_reference, "construct properties require GLib.Object");
1394 acc.error = true;
1395 return;
1396 } else if (acc.construction && !is_gobject_property (prop)) {
1397 Report.error (acc.source_reference, "construct properties not supported for specified property type");
1398 acc.error = true;
1399 return;
1402 // do not declare overriding properties and interface implementations
1403 if (prop.is_abstract || prop.is_virtual
1404 || (prop.base_property == null && prop.base_interface_property == null)) {
1405 generate_property_accessor_declaration (acc, cfile);
1407 // do not declare construct-only properties in header files
1408 if (acc.readable || acc.writable) {
1409 if (!prop.is_internal_symbol ()
1410 && (acc.access == SymbolAccessibility.PUBLIC
1411 || acc.access == SymbolAccessibility.PROTECTED)) {
1412 generate_property_accessor_declaration (acc, header_file);
1414 if (!prop.is_private_symbol () && acc.access != SymbolAccessibility.PRIVATE) {
1415 generate_property_accessor_declaration (acc, internal_header_file);
1420 if (acc.source_type == SourceFileType.FAST) {
1421 return;
1424 var this_type = get_data_type_for_symbol (t);
1425 var cselfparam = new CCodeParameter ("self", this_type.get_cname ());
1426 if (t is Struct) {
1427 cselfparam.type_name += "*";
1429 CCodeParameter cvalueparam;
1430 if (returns_real_struct) {
1431 cvalueparam = new CCodeParameter ("result", acc.value_type.get_cname () + "*");
1432 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1433 cvalueparam = new CCodeParameter ("value", acc.value_type.get_cname () + "*");
1434 } else {
1435 cvalueparam = new CCodeParameter ("value", acc.value_type.get_cname ());
1438 if (prop.is_abstract || prop.is_virtual) {
1439 CCodeFunction function;
1440 if (acc.readable && !returns_real_struct) {
1441 function = new CCodeFunction (acc.get_cname (), current_return_type.get_cname ());
1442 } else {
1443 function = new CCodeFunction (acc.get_cname (), "void");
1445 function.add_parameter (cselfparam);
1446 if (acc.writable || acc.construction || returns_real_struct) {
1447 function.add_parameter (cvalueparam);
1450 if (acc.value_type is ArrayType) {
1451 var array_type = (ArrayType) acc.value_type;
1453 var length_ctype = "int";
1454 if (acc.readable) {
1455 length_ctype = "int*";
1458 for (int dim = 1; dim <= array_type.rank; dim++) {
1459 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), length_ctype));
1461 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1462 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1465 if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1466 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1467 function.modifiers |= CCodeModifiers.STATIC;
1470 push_function (function);
1472 CCodeFunctionCall vcast = null;
1473 if (prop.parent_symbol is Interface) {
1474 var iface = (Interface) prop.parent_symbol;
1476 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
1477 } else {
1478 var cl = (Class) prop.parent_symbol;
1480 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
1482 vcast.add_argument (new CCodeIdentifier ("self"));
1484 if (acc.readable) {
1485 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
1486 vcall.add_argument (new CCodeIdentifier ("self"));
1487 if (returns_real_struct) {
1488 vcall.add_argument (new CCodeIdentifier ("result"));
1489 ccode.add_expression (vcall);
1490 } else {
1491 if (acc.value_type is ArrayType) {
1492 var array_type = (ArrayType) acc.value_type;
1494 for (int dim = 1; dim <= array_type.rank; dim++) {
1495 var len_expr = new CCodeIdentifier (get_array_length_cname ("result", dim));
1496 vcall.add_argument (len_expr);
1498 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1499 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("result")));
1502 ccode.add_return (vcall);
1504 } else {
1505 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
1506 vcall.add_argument (new CCodeIdentifier ("self"));
1507 vcall.add_argument (new CCodeIdentifier ("value"));
1509 if (acc.value_type is ArrayType) {
1510 var array_type = (ArrayType) acc.value_type;
1512 for (int dim = 1; dim <= array_type.rank; dim++) {
1513 var len_expr = new CCodeIdentifier (get_array_length_cname ("value", dim));
1514 vcall.add_argument (len_expr);
1516 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1517 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("value")));
1520 ccode.add_expression (vcall);
1523 pop_function ();
1525 cfile.add_function (function);
1528 if (!prop.is_abstract) {
1529 bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
1531 string cname;
1532 if (is_virtual) {
1533 if (acc.readable) {
1534 cname = "%s_real_get_%s".printf (t.get_lower_case_cname (null), prop.name);
1535 } else {
1536 cname = "%s_real_set_%s".printf (t.get_lower_case_cname (null), prop.name);
1538 } else {
1539 cname = acc.get_cname ();
1542 CCodeFunction function;
1543 if (acc.writable || acc.construction || returns_real_struct) {
1544 function = new CCodeFunction (cname, "void");
1545 } else {
1546 function = new CCodeFunction (cname, acc.value_type.get_cname ());
1549 ObjectType base_type = null;
1550 if (prop.binding == MemberBinding.INSTANCE) {
1551 if (is_virtual) {
1552 if (prop.base_property != null) {
1553 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
1554 } else if (prop.base_interface_property != null) {
1555 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
1557 function.modifiers |= CCodeModifiers.STATIC;
1558 function.add_parameter (new CCodeParameter ("base", base_type.get_cname ()));
1559 } else {
1560 function.add_parameter (cselfparam);
1563 if (acc.writable || acc.construction || returns_real_struct) {
1564 function.add_parameter (cvalueparam);
1567 if (acc.value_type is ArrayType) {
1568 var array_type = (ArrayType) acc.value_type;
1570 var length_ctype = "int";
1571 if (acc.readable) {
1572 length_ctype = "int*";
1575 for (int dim = 1; dim <= array_type.rank; dim++) {
1576 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), length_ctype));
1578 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1579 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1582 if (!is_virtual) {
1583 if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1584 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1585 function.modifiers |= CCodeModifiers.STATIC;
1589 push_function (function);
1591 if (prop.binding == MemberBinding.INSTANCE && !is_virtual) {
1592 if (!acc.readable || returns_real_struct) {
1593 create_property_type_check_statement (prop, false, t, true, "self");
1594 } else {
1595 create_property_type_check_statement (prop, true, t, true, "self");
1599 if (acc.readable && !returns_real_struct) {
1600 // do not declare result variable if exit block is known to be unreachable
1601 if (acc.return_block == null || acc.return_block.get_predecessors ().size > 0) {
1602 ccode.add_declaration (acc.value_type.get_cname (), new CCodeVariableDeclarator ("result"));
1606 if (is_virtual) {
1607 ccode.add_declaration (this_type.get_cname (), new CCodeVariableDeclarator ("self"));
1608 ccode.add_assignment (new CCodeIdentifier ("self"), transform_expression (new CCodeIdentifier ("base"), base_type, this_type));
1611 acc.body.emit (this);
1613 if (current_method_inner_error) {
1614 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
1617 // notify on property changes
1618 if (is_gobject_property (prop) &&
1619 prop.notify &&
1620 (acc.writable || acc.construction)) {
1621 var notify_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_notify"));
1622 notify_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
1623 notify_call.add_argument (prop.get_canonical_cconstant ());
1624 ccode.add_expression (notify_call);
1627 cfile.add_function (function);
1630 pop_context ();
1633 public override void visit_destructor (Destructor d) {
1634 if (d.binding == MemberBinding.STATIC && !in_plugin) {
1635 Report.error (d.source_reference, "static destructors are only supported for dynamic types");
1636 d.error = true;
1637 return;
1641 public int get_block_id (Block b) {
1642 int result = block_map[b];
1643 if (result == 0) {
1644 result = ++next_block_id;
1645 block_map[b] = result;
1647 return result;
1650 void capture_parameter (Parameter param, CCodeStruct data, int block_id, CCodeBlock free_block) {
1651 generate_type_declaration (param.variable_type, cfile);
1653 var param_type = param.variable_type.copy ();
1654 param_type.value_owned = true;
1655 data.add_field (param_type.get_cname (), get_variable_cname (param.name));
1657 bool is_unowned_delegate = param.variable_type is DelegateType && !param.variable_type.value_owned;
1659 // create copy if necessary as captured variables may need to be kept alive
1660 CCodeExpression cparam = get_variable_cexpression (param.name);
1661 if (param.variable_type.is_real_non_null_struct_type ()) {
1662 cparam = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cparam);
1664 if (requires_copy (param_type) && !param.variable_type.value_owned && !is_unowned_delegate) {
1665 var ma = new MemberAccess.simple (param.name);
1666 ma.symbol_reference = param;
1667 ma.value_type = param.variable_type.copy ();
1668 // directly access parameters in ref expressions
1669 param.captured = false;
1670 visit_member_access (ma);
1671 cparam = get_ref_cexpression (param.variable_type, cparam, ma, param);
1672 param.captured = true;
1675 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_variable_cname (param.name)), cparam);
1677 if (param.variable_type is ArrayType) {
1678 var array_type = (ArrayType) param.variable_type;
1679 for (int dim = 1; dim <= array_type.rank; dim++) {
1680 data.add_field ("gint", get_parameter_array_length_cname (param, dim));
1681 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_array_length_cname (get_variable_cname (param.name), dim)), new CCodeIdentifier (get_array_length_cname (get_variable_cname (param.name), dim)));
1683 } else if (param.variable_type is DelegateType) {
1684 CCodeExpression target_expr;
1685 CCodeExpression delegate_target_destroy_notify;
1686 if (current_method != null && current_method.coroutine) {
1687 target_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_delegate_target_cname (get_variable_cname (param.name)));
1688 delegate_target_destroy_notify = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
1689 } else {
1690 target_expr = new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param.name)));
1691 delegate_target_destroy_notify = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
1694 data.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (param.name)));
1695 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_delegate_target_cname (get_variable_cname (param.name))), target_expr);
1696 if (param.variable_type.value_owned) {
1697 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
1698 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_delegate_target_destroy_notify_cname (get_variable_cname (param.name))), delegate_target_destroy_notify);
1702 if (requires_destroy (param_type) && !is_unowned_delegate) {
1703 bool old_coroutine = false;
1704 if (current_method != null) {
1705 old_coroutine = current_method.coroutine;
1706 current_method.coroutine = false;
1709 free_block.add_statement (new CCodeExpressionStatement (get_unref_expression_ (param)));
1711 if (old_coroutine) {
1712 current_method.coroutine = true;
1717 public override void visit_block (Block b) {
1718 emit_context.push_symbol (b);
1720 var local_vars = b.get_local_variables ();
1722 if (b.parent_node is Block || b.parent_node is SwitchStatement) {
1723 ccode.open_block ();
1726 if (b.captured) {
1727 var parent_block = next_closure_block (b.parent_symbol);
1729 int block_id = get_block_id (b);
1730 string struct_name = "Block%dData".printf (block_id);
1732 var free_block = new CCodeBlock ();
1734 var data = new CCodeStruct ("_" + struct_name);
1735 data.add_field ("int", "_ref_count_");
1736 if (parent_block != null) {
1737 int parent_block_id = get_block_id (parent_block);
1739 data.add_field ("Block%dData *".printf (parent_block_id), "_data%d_".printf (parent_block_id));
1741 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (parent_block_id)));
1742 unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
1743 free_block.add_statement (new CCodeExpressionStatement (unref_call));
1744 } else {
1745 if (in_constructor || (current_method != null && current_method.binding == MemberBinding.INSTANCE) ||
1746 (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) {
1747 data.add_field ("%s *".printf (current_class.get_cname ()), "self");
1749 var ma = new MemberAccess.simple ("this");
1750 ma.symbol_reference = current_class;
1751 free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self"), new ObjectType (current_class), ma)));
1754 if (current_method != null) {
1755 // allow capturing generic type parameters
1756 foreach (var type_param in current_method.get_type_parameters ()) {
1757 string func_name;
1759 func_name = "%s_type".printf (type_param.name.down ());
1760 data.add_field ("GType", func_name);
1762 func_name = "%s_dup_func".printf (type_param.name.down ());
1763 data.add_field ("GBoxedCopyFunc", func_name);
1765 func_name = "%s_destroy_func".printf (type_param.name.down ());
1766 data.add_field ("GDestroyNotify", func_name);
1770 foreach (var local in local_vars) {
1771 if (local.captured) {
1772 generate_type_declaration (local.variable_type, cfile);
1774 data.add_field (local.variable_type.get_cname (), get_variable_cname (local.name) + local.variable_type.get_cdeclarator_suffix ());
1776 if (local.variable_type is ArrayType) {
1777 var array_type = (ArrayType) local.variable_type;
1778 for (int dim = 1; dim <= array_type.rank; dim++) {
1779 data.add_field ("gint", get_array_length_cname (get_variable_cname (local.name), dim));
1781 data.add_field ("gint", get_array_size_cname (get_variable_cname (local.name)));
1782 } else if (local.variable_type is DelegateType) {
1783 data.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (local.name)));
1784 if (local.variable_type.value_owned) {
1785 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
1790 // free in reverse order
1791 for (int i = local_vars.size - 1; i >= 0; i--) {
1792 var local = local_vars[i];
1793 if (local.captured) {
1794 if (requires_destroy (local.variable_type)) {
1795 bool old_coroutine = false;
1796 if (current_method != null) {
1797 old_coroutine = current_method.coroutine;
1798 current_method.coroutine = false;
1801 free_block.add_statement (new CCodeExpressionStatement (get_unref_expression_ (local)));
1803 if (old_coroutine) {
1804 current_method.coroutine = true;
1810 var data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
1811 data_alloc.add_argument (new CCodeIdentifier (struct_name));
1813 if (current_method != null && current_method.coroutine) {
1814 closure_struct.add_field (struct_name + "*", "_data%d_".printf (block_id));
1815 } else {
1816 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id)));
1818 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), data_alloc);
1820 // initialize ref_count
1821 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_ref_count_"), new CCodeIdentifier ("1"));
1823 if (parent_block != null) {
1824 int parent_block_id = get_block_id (parent_block);
1826 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (parent_block_id)));
1827 ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id)));
1829 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call);
1830 } else {
1831 if (in_constructor || (current_method != null && current_method.binding == MemberBinding.INSTANCE &&
1832 (!(current_method is CreationMethod) || current_method.body != b)) ||
1833 (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) {
1834 var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), b.source_reference));
1835 ref_call.add_argument (get_result_cexpression ("self"));
1837 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), ref_call);
1840 if (current_method != null) {
1841 // allow capturing generic type parameters
1842 foreach (var type_param in current_method.get_type_parameters ()) {
1843 string func_name;
1845 func_name = "%s_type".printf (type_param.name.down ());
1846 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name), new CCodeIdentifier (func_name));
1848 func_name = "%s_dup_func".printf (type_param.name.down ());
1849 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name), new CCodeIdentifier (func_name));
1851 func_name = "%s_destroy_func".printf (type_param.name.down ());
1852 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name), new CCodeIdentifier (func_name));
1857 if (b.parent_symbol is Method) {
1858 var m = (Method) b.parent_symbol;
1860 // parameters are captured with the top-level block of the method
1861 foreach (var param in m.get_parameters ()) {
1862 if (param.captured) {
1863 capture_parameter (param, data, block_id, free_block);
1867 if (m.coroutine) {
1868 // capture async data to allow invoking callback from inside closure
1869 data.add_field ("gpointer", "_async_data_");
1871 // async method is suspended while waiting for callback,
1872 // so we never need to care about memory management of async data
1873 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_async_data_"), new CCodeIdentifier ("data"));
1875 } else if (b.parent_symbol is PropertyAccessor) {
1876 var acc = (PropertyAccessor) b.parent_symbol;
1878 if (!acc.readable && acc.value_parameter.captured) {
1879 capture_parameter (acc.value_parameter, data, block_id, free_block);
1883 var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name));
1884 cfile.add_type_declaration (typedef);
1885 cfile.add_type_definition (data);
1887 var data_free = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
1888 data_free.add_argument (new CCodeIdentifier (struct_name));
1889 data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id)));
1890 free_block.add_statement (new CCodeExpressionStatement (data_free));
1892 // create ref/unref functions
1893 var ref_fun = new CCodeFunction ("block%d_data_ref".printf (block_id), struct_name + "*");
1894 ref_fun.add_parameter (new CCodeParameter ("_data%d_".printf (block_id), struct_name + "*"));
1895 ref_fun.modifiers = CCodeModifiers.STATIC;
1896 cfile.add_function_declaration (ref_fun);
1897 ref_fun.block = new CCodeBlock ();
1899 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_inc"));
1900 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
1901 ref_fun.block.add_statement (new CCodeExpressionStatement (ccall));
1902 ref_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_data%d_".printf (block_id))));
1903 cfile.add_function (ref_fun);
1905 var unref_fun = new CCodeFunction ("block%d_data_unref".printf (block_id), "void");
1906 unref_fun.add_parameter (new CCodeParameter ("_data%d_".printf (block_id), struct_name + "*"));
1907 unref_fun.modifiers = CCodeModifiers.STATIC;
1908 cfile.add_function_declaration (unref_fun);
1909 unref_fun.block = new CCodeBlock ();
1911 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_dec_and_test"));
1912 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
1913 unref_fun.block.add_statement (new CCodeIfStatement (ccall, free_block));
1915 cfile.add_function (unref_fun);
1918 foreach (Statement stmt in b.get_statements ()) {
1919 stmt.emit (this);
1922 // free in reverse order
1923 for (int i = local_vars.size - 1; i >= 0; i--) {
1924 var local = local_vars[i];
1925 local.active = false;
1926 if (!local.unreachable && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
1927 ccode.add_expression (get_unref_expression_ (local));
1931 if (b.parent_symbol is Method) {
1932 var m = (Method) b.parent_symbol;
1933 foreach (Parameter param in m.get_parameters ()) {
1934 if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
1935 ccode.add_expression (get_unref_expression_ (param));
1936 } else if (param.direction == ParameterDirection.OUT && !m.coroutine) {
1937 return_out_parameter (param);
1942 if (b.captured) {
1943 int block_id = get_block_id (b);
1945 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
1946 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
1947 ccode.add_expression (data_unref);
1950 if (b.parent_node is Block || b.parent_node is SwitchStatement) {
1951 ccode.close ();
1954 emit_context.pop_symbol ();
1957 public override void visit_declaration_statement (DeclarationStatement stmt) {
1958 stmt.declaration.accept (this);
1961 public CCodeExpression get_variable_cexpression (string name) {
1962 if (current_method != null && current_method.coroutine) {
1963 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_variable_cname (name));
1964 } else {
1965 return new CCodeIdentifier (get_variable_cname (name));
1969 public string get_variable_cname (string name) {
1970 if (name[0] == '.') {
1971 if (name == ".result") {
1972 return "result";
1974 // compiler-internal variable
1975 if (!variable_name_map.contains (name)) {
1976 variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
1977 next_temp_var_id++;
1979 return variable_name_map.get (name);
1980 } else if (reserved_identifiers.contains (name)) {
1981 return "_%s_".printf (name);
1982 } else {
1983 return name;
1987 public CCodeExpression get_result_cexpression (string cname = "result") {
1988 if (current_method != null && current_method.coroutine) {
1989 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), cname);
1990 } else {
1991 return new CCodeIdentifier (cname);
1995 bool has_simple_struct_initializer (LocalVariable local) {
1996 var st = local.variable_type.data_type as Struct;
1997 var initializer = local.initializer as ObjectCreationExpression;
1998 if (st != null && (!st.is_simple_type () || st.get_cname () == "va_list") && !local.variable_type.nullable &&
1999 initializer != null && initializer.get_object_initializer ().size == 0) {
2000 return true;
2001 } else {
2002 return false;
2006 public override void visit_local_variable (LocalVariable local) {
2007 check_type (local.variable_type);
2009 if (local.initializer != null) {
2010 local.initializer.emit (this);
2012 visit_end_full_expression (local.initializer);
2015 generate_type_declaration (local.variable_type, cfile);
2017 if (!local.captured) {
2018 if (local.variable_type is ArrayType) {
2019 // create variables to store array dimensions
2020 var array_type = (ArrayType) local.variable_type;
2022 if (!array_type.fixed_length) {
2023 for (int dim = 1; dim <= array_type.rank; dim++) {
2024 var len_var = new LocalVariable (int_type.copy (), get_array_length_cname (get_variable_cname (local.name), dim));
2025 emit_temp_var (len_var);
2028 if (array_type.rank == 1) {
2029 var size_var = new LocalVariable (int_type.copy (), get_array_size_cname (get_variable_cname (local.name)));
2030 emit_temp_var (size_var);
2033 } else if (local.variable_type is DelegateType) {
2034 var deleg_type = (DelegateType) local.variable_type;
2035 var d = deleg_type.delegate_symbol;
2036 if (d.has_target) {
2037 // create variable to store delegate target
2038 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (get_variable_cname (local.name)));
2039 emit_temp_var (target_var);
2040 if (deleg_type.value_owned) {
2041 var target_destroy_notify_var = new LocalVariable (gdestroynotify_type, get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
2042 emit_temp_var (target_destroy_notify_var);
2048 CCodeExpression rhs = null;
2049 if (local.initializer != null && get_cvalue (local.initializer) != null) {
2050 var target_value = get_variable_cvalue (local);
2052 rhs = get_cvalue (local.initializer);
2054 if (local.variable_type is ArrayType) {
2055 var array_type = (ArrayType) local.variable_type;
2057 if (array_type.fixed_length) {
2058 rhs = null;
2059 } else {
2060 var temp_var = get_temp_variable (local.variable_type, true, local, false);
2061 emit_temp_var (temp_var);
2062 ccode.add_assignment (get_variable_cexpression (temp_var.name), rhs);
2064 for (int dim = 1; dim <= array_type.rank; dim++) {
2065 var lhs_array_len = get_array_length_cvalue (target_value, dim);
2066 var rhs_array_len = get_array_length_cexpression (local.initializer, dim);
2067 ccode.add_assignment (lhs_array_len, rhs_array_len);
2069 if (array_type.rank == 1 && !local.captured) {
2070 var lhs_array_size = get_array_size_cvalue (target_value);
2071 var rhs_array_len = get_array_length_cvalue (target_value, 1);
2072 ccode.add_assignment (lhs_array_size, rhs_array_len);
2075 rhs = get_variable_cexpression (temp_var.name);
2077 } else if (local.variable_type is DelegateType) {
2078 var deleg_type = (DelegateType) local.variable_type;
2079 var d = deleg_type.delegate_symbol;
2080 if (d.has_target) {
2081 var temp_var = get_temp_variable (local.variable_type, true, local, false);
2082 emit_temp_var (temp_var);
2083 ccode.add_assignment (get_variable_cexpression (temp_var.name), rhs);
2085 var lhs_delegate_target = get_delegate_target_cvalue (target_value);
2086 var lhs_delegate_target_destroy_notify = get_delegate_target_destroy_notify_cvalue (target_value);
2088 CCodeExpression rhs_delegate_target_destroy_notify;
2089 var rhs_delegate_target = get_delegate_target_cexpression (local.initializer, out rhs_delegate_target_destroy_notify);
2090 ccode.add_assignment (lhs_delegate_target, rhs_delegate_target);
2092 if (deleg_type.value_owned) {
2093 ccode.add_assignment (lhs_delegate_target_destroy_notify, rhs_delegate_target_destroy_notify);
2096 rhs = get_variable_cexpression (temp_var.name);
2099 } else if (local.variable_type.is_reference_type_or_type_parameter ()) {
2100 rhs = new CCodeConstant ("NULL");
2102 if (local.variable_type is ArrayType) {
2103 // initialize array length variables
2104 var array_type = (ArrayType) local.variable_type;
2106 if (array_type.fixed_length) {
2107 rhs = null;
2108 } else {
2109 for (int dim = 1; dim <= array_type.rank; dim++) {
2110 ccode.add_assignment (get_variable_cexpression (get_array_length_cname (get_variable_cname (local.name), dim)), new CCodeConstant ("0"));
2116 if (local.captured) {
2117 if (local.initializer != null) {
2118 if (has_simple_struct_initializer (local)) {
2119 ccode.add_expression (rhs);
2120 } else {
2121 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id ((Block) local.parent_symbol))), get_variable_cname (local.name)), rhs);
2124 } else if (current_method != null && current_method.coroutine) {
2125 closure_struct.add_field (local.variable_type.get_cname (), get_variable_cname (local.name) + local.variable_type.get_cdeclarator_suffix ());
2127 if (local.initializer != null) {
2128 if (has_simple_struct_initializer (local)) {
2129 ccode.add_expression (rhs);
2130 } else {
2131 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_variable_cname (local.name)), rhs);
2134 } else {
2135 CCodeExpression post_rhs = null;
2136 if (has_simple_struct_initializer (local)) {
2137 post_rhs = rhs;
2138 rhs = null;
2141 var cvar = new CCodeVariableDeclarator (get_variable_cname (local.name), rhs, local.variable_type.get_cdeclarator_suffix ());
2142 if (rhs != null) {
2143 cvar.line = rhs.line;
2146 // try to initialize uninitialized variables
2147 // initialization not necessary for variables stored in closure
2148 if (cvar.initializer == null) {
2149 cvar.initializer = default_value_for_type (local.variable_type, true);
2150 cvar.init0 = true;
2153 ccode.add_declaration (local.variable_type.get_cname (), cvar);
2155 if (cvar.initializer != null && !cvar.init0) {
2156 cvar.initializer = null;
2157 ccode.add_assignment (get_variable_cexpression (local.name), rhs);
2160 if (post_rhs != null) {
2161 ccode.add_expression (post_rhs);
2165 if (local.initializer != null && local.variable_type is ArrayType) {
2166 var array_type = (ArrayType) local.variable_type;
2168 if (array_type.fixed_length) {
2169 cfile.add_include ("string.h");
2171 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
2172 // simple assignments do not work in C
2173 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
2174 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
2175 var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
2177 var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
2178 ccopy.add_argument (get_variable_cexpression (local.name));
2179 ccopy.add_argument (get_cvalue (local.initializer));
2180 ccopy.add_argument (size);
2181 ccode.add_expression (ccopy);
2185 if (local.initializer != null && local.initializer.tree_can_fail) {
2186 add_simple_check (local.initializer);
2189 local.active = true;
2192 public override void visit_initializer_list (InitializerList list) {
2193 if (list.target_type.data_type is Struct) {
2194 /* initializer is used as struct initializer */
2195 var st = (Struct) list.target_type.data_type;
2197 if (list.parent_node is Constant || list.parent_node is Field || list.parent_node is InitializerList) {
2198 var clist = new CCodeInitializerList ();
2200 var field_it = st.get_fields ().iterator ();
2201 foreach (Expression expr in list.get_initializers ()) {
2202 Field field = null;
2203 while (field == null) {
2204 field_it.next ();
2205 field = field_it.get ();
2206 if (field.binding != MemberBinding.INSTANCE) {
2207 // we only initialize instance fields
2208 field = null;
2212 var cexpr = get_cvalue (expr);
2214 string ctype = field.get_ctype ();
2215 if (ctype != null) {
2216 cexpr = new CCodeCastExpression (cexpr, ctype);
2219 clist.append (cexpr);
2222 set_cvalue (list, clist);
2223 } else {
2224 // used as expression
2225 var temp_decl = get_temp_variable (list.target_type, false, list);
2226 emit_temp_var (temp_decl);
2228 var instance = get_variable_cexpression (get_variable_cname (temp_decl.name));
2230 var ccomma = new CCodeCommaExpression ();
2232 var field_it = st.get_fields ().iterator ();
2233 foreach (Expression expr in list.get_initializers ()) {
2234 Field field = null;
2235 while (field == null) {
2236 field_it.next ();
2237 field = field_it.get ();
2238 if (field.binding != MemberBinding.INSTANCE) {
2239 // we only initialize instance fields
2240 field = null;
2244 var cexpr = get_cvalue (expr);
2246 string ctype = field.get_ctype ();
2247 if (ctype != null) {
2248 cexpr = new CCodeCastExpression (cexpr, ctype);
2251 var lhs = new CCodeMemberAccess (instance, field.get_cname ());;
2252 ccomma.append_expression (new CCodeAssignment (lhs, cexpr));
2255 ccomma.append_expression (instance);
2256 set_cvalue (list, ccomma);
2258 } else {
2259 var clist = new CCodeInitializerList ();
2260 foreach (Expression expr in list.get_initializers ()) {
2261 clist.append (get_cvalue (expr));
2263 set_cvalue (list, clist);
2267 public override LocalVariable create_local (DataType type) {
2268 var result = get_temp_variable (type, type.value_owned);
2269 emit_temp_var (result);
2270 return result;
2273 public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null, bool init = true) {
2274 var var_type = type.copy ();
2275 var_type.value_owned = value_owned;
2276 var local = new LocalVariable (var_type, "_tmp%d_".printf (next_temp_var_id));
2277 local.no_init = !init;
2279 if (node_reference != null) {
2280 local.source_reference = node_reference.source_reference;
2283 next_temp_var_id++;
2285 return local;
2288 bool is_in_generic_type (DataType type) {
2289 if (current_symbol != null && type.type_parameter.parent_symbol is TypeSymbol
2290 && (current_method == null || current_method.binding == MemberBinding.INSTANCE)) {
2291 return true;
2292 } else {
2293 return false;
2297 public CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
2298 if (type is GenericType) {
2299 string var_name = "%s_type".printf (type.type_parameter.name.down ());
2300 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
2301 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), var_name);
2302 } else {
2303 return new CCodeIdentifier (var_name);
2305 } else {
2306 string type_id = type.get_type_id ();
2307 if (type_id == null) {
2308 type_id = "G_TYPE_INVALID";
2309 } else {
2310 generate_type_declaration (type, cfile);
2312 return new CCodeIdentifier (type_id);
2316 public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup = false) {
2317 if (type is ErrorType) {
2318 return new CCodeIdentifier ("g_error_copy");
2319 } else if (type.data_type != null) {
2320 string dup_function;
2321 var cl = type.data_type as Class;
2322 if (type.data_type.is_reference_counting ()) {
2323 dup_function = type.data_type.get_ref_function ();
2324 if (type.data_type is Interface && dup_function == null) {
2325 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 ()));
2326 return null;
2328 } else if (cl != null && cl.is_immutable) {
2329 // allow duplicates of immutable instances as for example strings
2330 dup_function = type.data_type.get_dup_function ();
2331 if (dup_function == null) {
2332 dup_function = "";
2334 } else if (cl != null && cl.is_gboxed) {
2335 // allow duplicates of gboxed instances
2336 dup_function = generate_dup_func_wrapper (type);
2337 if (dup_function == null) {
2338 dup_function = "";
2340 } else if (type is ValueType) {
2341 dup_function = type.data_type.get_dup_function ();
2342 if (dup_function == null && type.nullable) {
2343 dup_function = generate_struct_dup_wrapper ((ValueType) type);
2344 } else if (dup_function == null) {
2345 dup_function = "";
2347 } else {
2348 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2349 Report.error (source_reference, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type.data_type.name));
2350 return null;
2353 return new CCodeIdentifier (dup_function);
2354 } else if (type.type_parameter != null) {
2355 string func_name = "%s_dup_func".printf (type.type_parameter.name.down ());
2356 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
2357 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
2358 } else {
2359 return new CCodeIdentifier (func_name);
2361 } else if (type is PointerType) {
2362 var pointer_type = (PointerType) type;
2363 return get_dup_func_expression (pointer_type.base_type, source_reference);
2364 } else {
2365 return new CCodeConstant ("NULL");
2369 void make_comparable_cexpression (ref DataType left_type, ref CCodeExpression cleft, ref DataType right_type, ref CCodeExpression cright) {
2370 var left_type_as_struct = left_type.data_type as Struct;
2371 var right_type_as_struct = right_type.data_type as Struct;
2373 // GValue support
2374 var valuecast = try_cast_value_to_type (cleft, left_type, right_type);
2375 if (valuecast != null) {
2376 cleft = valuecast;
2377 left_type = right_type;
2378 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2379 return;
2382 valuecast = try_cast_value_to_type (cright, right_type, left_type);
2383 if (valuecast != null) {
2384 cright = valuecast;
2385 right_type = left_type;
2386 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2387 return;
2390 if (left_type.data_type is Class && !((Class) left_type.data_type).is_compact &&
2391 right_type.data_type is Class && !((Class) right_type.data_type).is_compact) {
2392 var left_cl = (Class) left_type.data_type;
2393 var right_cl = (Class) right_type.data_type;
2395 if (left_cl != right_cl) {
2396 if (left_cl.is_subtype_of (right_cl)) {
2397 cleft = generate_instance_cast (cleft, right_cl);
2398 } else if (right_cl.is_subtype_of (left_cl)) {
2399 cright = generate_instance_cast (cright, left_cl);
2402 } else if (left_type_as_struct != null && right_type_as_struct != null) {
2403 if (left_type is StructValueType) {
2404 // real structs (uses compare/equal function)
2405 if (!left_type.nullable) {
2406 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft);
2408 if (!right_type.nullable) {
2409 cright = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cright);
2411 } else {
2412 // integer or floating or boolean type
2413 if (left_type.nullable && right_type.nullable) {
2414 // FIXME also compare contents, not just address
2415 } else if (left_type.nullable) {
2416 // FIXME check left value is not null
2417 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
2418 } else if (right_type.nullable) {
2419 // FIXME check right value is not null
2420 cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
2426 private string generate_struct_equal_function (Struct st) {
2427 string equal_func = "_%sequal".printf (st.get_lower_case_cprefix ());
2429 if (!add_wrapper (equal_func)) {
2430 // wrapper already defined
2431 return equal_func;
2434 var function = new CCodeFunction (equal_func, "gboolean");
2435 function.modifiers = CCodeModifiers.STATIC;
2437 function.add_parameter (new CCodeParameter ("s1", "const " + st.get_cname () + "*"));
2438 function.add_parameter (new CCodeParameter ("s2", "const " + st.get_cname () + "*"));
2440 push_function (function);
2442 // if (s1 == s2) return TRUE;
2444 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2445 ccode.open_if (cexp);
2446 ccode.add_return (new CCodeConstant ("TRUE"));
2447 ccode.close ();
2449 // if (s1 == NULL || s2 == NULL) return FALSE;
2451 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2452 ccode.open_if (cexp);
2453 ccode.add_return (new CCodeConstant ("FALSE"));
2454 ccode.close ();
2456 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2457 ccode.open_if (cexp);
2458 ccode.add_return (new CCodeConstant ("FALSE"));
2459 ccode.close ();
2462 foreach (Field f in st.get_fields ()) {
2463 if (f.binding != MemberBinding.INSTANCE) {
2464 // we only compare instance fields
2465 continue;
2468 CCodeExpression cexp; // if (cexp) return FALSE;
2469 var s1 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s1"), f.name); // s1->f
2470 var s2 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s2"), f.name); // s2->f
2472 var variable_type = f.variable_type.copy ();
2473 make_comparable_cexpression (ref variable_type, ref s1, ref variable_type, ref s2);
2475 if (!(f.variable_type is NullType) && f.variable_type.compatible (string_type)) {
2476 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
2477 ccall.add_argument (s1);
2478 ccall.add_argument (s2);
2479 cexp = ccall;
2480 } else if (f.variable_type is StructValueType) {
2481 var equalfunc = generate_struct_equal_function (f.variable_type.data_type as Struct);
2482 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
2483 ccall.add_argument (s1);
2484 ccall.add_argument (s2);
2485 cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
2486 } else {
2487 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, s1, s2);
2490 ccode.open_if (cexp);
2491 ccode.add_return (new CCodeConstant ("FALSE"));
2492 ccode.close ();
2495 if (st.get_fields().size == 0) {
2496 // either opaque structure or simple type
2497 if (st.is_simple_type ()) {
2498 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2499 ccode.add_return (cexp);
2500 } else {
2501 ccode.add_return (new CCodeConstant ("FALSE"));
2503 } else {
2504 ccode.add_return (new CCodeConstant ("TRUE"));
2507 pop_function ();
2509 cfile.add_function_declaration (function);
2510 cfile.add_function (function);
2512 return equal_func;
2515 private string generate_numeric_equal_function (Struct st) {
2516 string equal_func = "_%sequal".printf (st.get_lower_case_cprefix ());
2518 if (!add_wrapper (equal_func)) {
2519 // wrapper already defined
2520 return equal_func;
2523 var function = new CCodeFunction (equal_func, "gboolean");
2524 function.modifiers = CCodeModifiers.STATIC;
2526 function.add_parameter (new CCodeParameter ("s1", "const " + st.get_cname () + "*"));
2527 function.add_parameter (new CCodeParameter ("s2", "const " + st.get_cname () + "*"));
2529 push_function (function);
2531 // if (s1 == s2) return TRUE;
2533 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2534 ccode.open_if (cexp);
2535 ccode.add_return (new CCodeConstant ("TRUE"));
2536 ccode.close ();
2538 // if (s1 == NULL || s2 == NULL) return FALSE;
2540 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2541 ccode.open_if (cexp);
2542 ccode.add_return (new CCodeConstant ("FALSE"));
2543 ccode.close ();
2545 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2546 ccode.open_if (cexp);
2547 ccode.add_return (new CCodeConstant ("FALSE"));
2548 ccode.close ();
2550 // return (*s1 == *s2);
2552 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2553 ccode.add_return (cexp);
2556 pop_function ();
2558 cfile.add_function_declaration (function);
2559 cfile.add_function (function);
2561 return equal_func;
2564 private string generate_struct_dup_wrapper (ValueType value_type) {
2565 string dup_func = "_%sdup".printf (value_type.type_symbol.get_lower_case_cprefix ());
2567 if (!add_wrapper (dup_func)) {
2568 // wrapper already defined
2569 return dup_func;
2572 var function = new CCodeFunction (dup_func, value_type.get_cname ());
2573 function.modifiers = CCodeModifiers.STATIC;
2575 function.add_parameter (new CCodeParameter ("self", value_type.get_cname ()));
2577 push_function (function);
2579 if (value_type.type_symbol == gvalue_type) {
2580 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
2581 dup_call.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
2582 dup_call.add_argument (new CCodeIdentifier ("self"));
2584 ccode.add_return (dup_call);
2585 } else {
2586 ccode.add_declaration (value_type.get_cname (), new CCodeVariableDeclarator ("dup"));
2588 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
2589 creation_call.add_argument (new CCodeConstant (value_type.data_type.get_cname ()));
2590 creation_call.add_argument (new CCodeConstant ("1"));
2591 ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
2593 var st = value_type.data_type as Struct;
2594 if (st != null && st.is_disposable ()) {
2595 if (!st.has_copy_function) {
2596 generate_struct_copy_function (st);
2599 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (st.get_copy_function ()));
2600 copy_call.add_argument (new CCodeIdentifier ("self"));
2601 copy_call.add_argument (new CCodeIdentifier ("dup"));
2602 ccode.add_expression (copy_call);
2603 } else {
2604 cfile.add_include ("string.h");
2606 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
2607 sizeof_call.add_argument (new CCodeConstant (value_type.data_type.get_cname ()));
2609 var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
2610 copy_call.add_argument (new CCodeIdentifier ("dup"));
2611 copy_call.add_argument (new CCodeIdentifier ("self"));
2612 copy_call.add_argument (sizeof_call);
2613 ccode.add_expression (copy_call);
2616 ccode.add_return (new CCodeIdentifier ("dup"));
2619 pop_function ();
2621 cfile.add_function_declaration (function);
2622 cfile.add_function (function);
2624 return dup_func;
2627 protected string generate_dup_func_wrapper (DataType type) {
2628 string destroy_func = "_vala_%s_copy".printf (type.data_type.get_cname ());
2630 if (!add_wrapper (destroy_func)) {
2631 // wrapper already defined
2632 return destroy_func;
2635 var function = new CCodeFunction (destroy_func, type.get_cname ());
2636 function.modifiers = CCodeModifiers.STATIC;
2637 function.add_parameter (new CCodeParameter ("self", type.get_cname ()));
2639 push_function (function);
2641 var cl = type.data_type as Class;
2642 assert (cl != null && cl.is_gboxed);
2644 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
2645 free_call.add_argument (new CCodeIdentifier (cl.get_type_id ()));
2646 free_call.add_argument (new CCodeIdentifier ("self"));
2648 ccode.add_return (free_call);
2650 pop_function ();
2652 cfile.add_function_declaration (function);
2653 cfile.add_function (function);
2655 return destroy_func;
2658 protected string generate_free_func_wrapper (DataType type) {
2659 string destroy_func = "_vala_%s_free".printf (type.data_type.get_cname ());
2661 if (!add_wrapper (destroy_func)) {
2662 // wrapper already defined
2663 return destroy_func;
2666 var function = new CCodeFunction (destroy_func, "void");
2667 function.modifiers = CCodeModifiers.STATIC;
2668 function.add_parameter (new CCodeParameter ("self", type.get_cname ()));
2670 push_function (function);
2672 var cl = type.data_type as Class;
2673 if (cl != null && cl.is_gboxed) {
2674 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_free"));
2675 free_call.add_argument (new CCodeIdentifier (cl.get_type_id ()));
2676 free_call.add_argument (new CCodeIdentifier ("self"));
2678 ccode.add_expression (free_call);
2679 } else if (cl != null) {
2680 assert (cl.free_function_address_of);
2682 var free_call = new CCodeFunctionCall (new CCodeIdentifier (type.data_type.get_free_function ()));
2683 free_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("self")));
2685 ccode.add_expression (free_call);
2686 } else {
2687 var st = type.data_type as Struct;
2688 if (st != null && st.is_disposable ()) {
2689 if (!st.has_destroy_function) {
2690 generate_struct_destroy_function (st);
2693 var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (st.get_destroy_function ()));
2694 destroy_call.add_argument (new CCodeIdentifier ("self"));
2695 ccode.add_expression (destroy_call);
2698 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
2699 free_call.add_argument (new CCodeIdentifier ("self"));
2701 ccode.add_expression (free_call);
2704 pop_function ();
2706 cfile.add_function_declaration (function);
2707 cfile.add_function (function);
2709 return destroy_func;
2712 public CCodeExpression? get_destroy0_func_expression (DataType type, bool is_chainup = false) {
2713 var element_destroy_func_expression = get_destroy_func_expression (type, is_chainup);
2715 if (element_destroy_func_expression is CCodeIdentifier) {
2716 var freeid = (CCodeIdentifier) element_destroy_func_expression;
2717 string free0_func = "_%s0_".printf (freeid.name);
2719 if (add_wrapper (free0_func)) {
2720 var function = new CCodeFunction (free0_func, "void");
2721 function.modifiers = CCodeModifiers.STATIC;
2723 function.add_parameter (new CCodeParameter ("var", "gpointer"));
2725 push_function (function);
2727 ccode.add_expression (get_unref_expression (new CCodeIdentifier ("var"), type, null, true));
2729 pop_function ();
2731 cfile.add_function_declaration (function);
2732 cfile.add_function (function);
2735 element_destroy_func_expression = new CCodeIdentifier (free0_func);
2738 return element_destroy_func_expression;
2741 public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
2742 if (context.profile == Profile.GOBJECT && (type.data_type == glist_type || type.data_type == gslist_type || type.data_type == gnode_type)) {
2743 // create wrapper function to free list elements if necessary
2745 bool elements_require_free = false;
2746 CCodeExpression element_destroy_func_expression = null;
2748 foreach (DataType type_arg in type.get_type_arguments ()) {
2749 elements_require_free = requires_destroy (type_arg);
2750 if (elements_require_free) {
2751 element_destroy_func_expression = get_destroy0_func_expression (type_arg);
2755 if (elements_require_free && element_destroy_func_expression is CCodeIdentifier) {
2756 return new CCodeIdentifier (generate_collection_free_wrapper (type, (CCodeIdentifier) element_destroy_func_expression));
2757 } else {
2758 return new CCodeIdentifier (type.data_type.get_free_function ());
2760 } else if (type is ErrorType) {
2761 return new CCodeIdentifier ("g_error_free");
2762 } else if (type.data_type != null) {
2763 string unref_function;
2764 if (type is ReferenceType) {
2765 if (type.data_type.is_reference_counting ()) {
2766 unref_function = type.data_type.get_unref_function ();
2767 if (type.data_type is Interface && unref_function == null) {
2768 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 ()));
2769 return null;
2771 } else {
2772 var cl = type.data_type as Class;
2773 if (cl != null && (cl.free_function_address_of || cl.is_gboxed)) {
2774 unref_function = generate_free_func_wrapper (type);
2775 } else {
2776 unref_function = type.data_type.get_free_function ();
2779 } else {
2780 if (type.nullable) {
2781 unref_function = type.data_type.get_free_function ();
2782 if (unref_function == null) {
2783 if (type.data_type is Struct && ((Struct) type.data_type).is_disposable ()) {
2784 unref_function = generate_free_func_wrapper (type);
2785 } else {
2786 unref_function = "g_free";
2789 } else {
2790 var st = (Struct) type.data_type;
2791 if (!st.has_destroy_function) {
2792 generate_struct_destroy_function (st);
2794 unref_function = st.get_destroy_function ();
2797 if (unref_function == null) {
2798 return new CCodeConstant ("NULL");
2800 return new CCodeIdentifier (unref_function);
2801 } else if (type.type_parameter != null && current_type_symbol is Class) {
2802 string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ());
2803 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
2804 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
2805 } else {
2806 return new CCodeIdentifier (func_name);
2808 } else if (type is ArrayType) {
2809 if (context.profile == Profile.POSIX) {
2810 return new CCodeIdentifier ("free");
2811 } else {
2812 return new CCodeIdentifier ("g_free");
2814 } else if (type is PointerType) {
2815 if (context.profile == Profile.POSIX) {
2816 return new CCodeIdentifier ("free");
2817 } else {
2818 return new CCodeIdentifier ("g_free");
2820 } else {
2821 return new CCodeConstant ("NULL");
2825 private string generate_collection_free_wrapper (DataType collection_type, CCodeIdentifier element_destroy_func_expression) {
2826 string destroy_func = "_%s_%s".printf (collection_type.data_type.get_free_function (), element_destroy_func_expression.name);
2828 if (!add_wrapper (destroy_func)) {
2829 // wrapper already defined
2830 return destroy_func;
2833 var function = new CCodeFunction (destroy_func, "void");
2834 function.modifiers = CCodeModifiers.STATIC;
2836 function.add_parameter (new CCodeParameter ("self", collection_type.get_cname ()));
2838 push_function (function);
2840 CCodeFunctionCall element_free_call;
2841 if (collection_type.data_type == gnode_type) {
2842 /* A wrapper which converts GNodeTraverseFunc into GDestroyNotify */
2843 string destroy_node_func = "%s_node".printf (destroy_func);
2844 var wrapper = new CCodeFunction (destroy_node_func, "gboolean");
2845 wrapper.modifiers = CCodeModifiers.STATIC;
2846 wrapper.add_parameter (new CCodeParameter ("node", collection_type.get_cname ()));
2847 wrapper.add_parameter (new CCodeParameter ("unused", "gpointer"));
2848 var wrapper_block = new CCodeBlock ();
2849 var free_call = new CCodeFunctionCall (element_destroy_func_expression);
2850 free_call.add_argument (new CCodeMemberAccess.pointer(new CCodeIdentifier("node"), "data"));
2851 wrapper_block.add_statement (new CCodeExpressionStatement (free_call));
2852 wrapper_block.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
2853 cfile.add_function_declaration (function);
2854 wrapper.block = wrapper_block;
2855 cfile.add_function (wrapper);
2857 /* Now the code to call g_traverse with the above */
2858 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_node_traverse"));
2859 element_free_call.add_argument (new CCodeIdentifier("self"));
2860 element_free_call.add_argument (new CCodeConstant ("G_POST_ORDER"));
2861 element_free_call.add_argument (new CCodeConstant ("G_TRAVERSE_ALL"));
2862 element_free_call.add_argument (new CCodeConstant ("-1"));
2863 element_free_call.add_argument (new CCodeIdentifier (destroy_node_func));
2864 element_free_call.add_argument (new CCodeConstant ("NULL"));
2865 } else {
2866 if (collection_type.data_type == glist_type) {
2867 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
2868 } else {
2869 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_slist_foreach"));
2872 element_free_call.add_argument (new CCodeIdentifier ("self"));
2873 element_free_call.add_argument (new CCodeCastExpression (element_destroy_func_expression, "GFunc"));
2874 element_free_call.add_argument (new CCodeConstant ("NULL"));
2877 ccode.add_expression (element_free_call);
2879 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier (collection_type.data_type.get_free_function ()));
2880 cfreecall.add_argument (new CCodeIdentifier ("self"));
2881 ccode.add_expression (cfreecall);
2883 pop_function ();
2885 cfile.add_function_declaration (function);
2886 cfile.add_function (function);
2888 return destroy_func;
2891 public virtual string? append_struct_array_free (Struct st) {
2892 return null;
2895 public CCodeExpression get_unref_expression_ (Variable variable, CCodeExpression? inner = null) {
2896 return destroy_value (get_variable_cvalue (variable, inner));
2899 public CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression? expr, bool is_macro_definition = false) {
2900 if (expr != null && (expr.symbol_reference is LocalVariable || expr.symbol_reference is Parameter)) {
2901 return get_unref_expression_ ((Variable) expr.symbol_reference);
2903 var value = new GLibValue (type, cvar);
2904 if (expr != null && expr.target_value != null) {
2905 value.array_length_cvalues = ((GLibValue) expr.target_value).array_length_cvalues;
2906 value.delegate_target_cvalue = get_delegate_target_cvalue (expr.target_value);
2907 value.delegate_target_destroy_notify_cvalue = get_delegate_target_destroy_notify_cvalue (expr.target_value);
2909 return destroy_value (value, is_macro_definition);
2912 public virtual CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
2913 var type = value.value_type;
2914 var cvar = get_cvalue_ (value);
2916 if (type is DelegateType) {
2917 var delegate_target = get_delegate_target_cvalue (value);
2918 var delegate_target_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
2920 var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
2921 ccall.add_argument (delegate_target);
2923 var destroy_call = new CCodeCommaExpression ();
2924 destroy_call.append_expression (ccall);
2925 destroy_call.append_expression (new CCodeConstant ("NULL"));
2927 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
2929 var ccomma = new CCodeCommaExpression ();
2930 ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), destroy_call));
2931 ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
2932 ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
2933 ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
2935 return ccomma;
2938 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
2940 if (type is ValueType && !type.nullable) {
2941 // normal value type, no null check
2942 var st = type.data_type as Struct;
2943 if (st != null && st.is_simple_type ()) {
2944 // used for va_list
2945 ccall.add_argument (cvar);
2946 } else {
2947 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
2950 if (gvalue_type != null && type.data_type == gvalue_type) {
2951 // g_value_unset must not be called for already unset values
2952 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
2953 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
2955 var ccomma = new CCodeCommaExpression ();
2956 ccomma.append_expression (ccall);
2957 ccomma.append_expression (new CCodeConstant ("NULL"));
2959 return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
2960 } else {
2961 return ccall;
2965 if (ccall.call is CCodeIdentifier && !(type is ArrayType) && !is_macro_definition) {
2966 // generate and use NULL-aware free macro to simplify code
2968 var freeid = (CCodeIdentifier) ccall.call;
2969 string free0_func = "_%s0".printf (freeid.name);
2971 if (add_wrapper (free0_func)) {
2972 var macro = destroy_value (new GLibValue (type, new CCodeIdentifier ("var")), true);
2973 cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("%s(var)".printf (free0_func), macro));
2976 ccall = new CCodeFunctionCall (new CCodeIdentifier (free0_func));
2977 ccall.add_argument (cvar);
2978 return ccall;
2981 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
2983 /* can be simplified to
2984 * foo = (unref (foo), NULL)
2985 * if foo is of static type non-null
2988 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
2989 if (type.type_parameter != null) {
2990 if (!(current_type_symbol is Class) || current_class.is_compact) {
2991 return new CCodeConstant ("NULL");
2994 // unref functions are optional for type parameters
2995 var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
2996 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
2999 ccall.add_argument (cvar);
3001 /* set freed references to NULL to prevent further use */
3002 var ccomma = new CCodeCommaExpression ();
3004 if (context.profile == Profile.GOBJECT) {
3005 if (type.data_type != null && !type.data_type.is_reference_counting () &&
3006 (type.data_type == gstringbuilder_type
3007 || type.data_type == garray_type
3008 || type.data_type == gbytearray_type
3009 || type.data_type == gptrarray_type)) {
3010 ccall.add_argument (new CCodeConstant ("TRUE"));
3011 } else if (type.data_type == gthreadpool_type) {
3012 ccall.add_argument (new CCodeConstant ("FALSE"));
3013 ccall.add_argument (new CCodeConstant ("TRUE"));
3014 } else if (type is ArrayType) {
3015 var array_type = (ArrayType) type;
3016 if (requires_destroy (array_type.element_type)) {
3017 CCodeExpression csizeexpr = null;
3018 bool first = true;
3019 for (int dim = 1; dim <= array_type.rank; dim++) {
3020 if (first) {
3021 csizeexpr = get_array_length_cvalue (value, dim);
3022 first = false;
3023 } else {
3024 csizeexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeexpr, get_array_length_cvalue (value, dim));
3028 var st = array_type.element_type.data_type as Struct;
3029 if (st != null && !array_type.element_type.nullable) {
3030 ccall.call = new CCodeIdentifier (append_struct_array_free (st));
3031 ccall.add_argument (csizeexpr);
3032 } else {
3033 requires_array_free = true;
3034 ccall.call = new CCodeIdentifier ("_vala_array_free");
3035 ccall.add_argument (csizeexpr);
3036 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
3042 ccomma.append_expression (ccall);
3043 ccomma.append_expression (new CCodeConstant ("NULL"));
3045 var cassign = new CCodeAssignment (cvar, ccomma);
3047 // g_free (NULL) is allowed
3048 bool uses_gfree = (type.data_type != null && !type.data_type.is_reference_counting () && type.data_type.get_free_function () == "g_free");
3049 uses_gfree = uses_gfree || type is ArrayType;
3050 if (uses_gfree) {
3051 return cassign;
3054 return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
3057 public override void visit_end_full_expression (Expression expr) {
3058 /* expr is a full expression, i.e. an initializer, the
3059 * expression in an expression statement, the controlling
3060 * expression in if, while, for, or foreach statements
3062 * we unref temporary variables at the end of a full
3063 * expression
3065 if (((List<LocalVariable>) temp_ref_vars).size == 0) {
3066 /* nothing to do without temporary variables */
3067 return;
3070 var expr_list = new CCodeCommaExpression ();
3072 LocalVariable full_expr_var = null;
3074 var local_decl = expr.parent_node as LocalVariable;
3075 if (local_decl != null && has_simple_struct_initializer (local_decl)) {
3076 expr_list.append_expression (get_cvalue (expr));
3077 } else {
3078 var expr_type = expr.value_type;
3079 if (expr.target_type != null) {
3080 expr_type = expr.target_type;
3083 full_expr_var = get_temp_variable (expr_type, true, expr, false);
3084 emit_temp_var (full_expr_var);
3086 expr_list.append_expression (new CCodeAssignment (get_variable_cexpression (full_expr_var.name), get_cvalue (expr)));
3089 foreach (LocalVariable local in temp_ref_vars) {
3090 expr_list.append_expression (get_unref_expression_ (local));
3093 if (full_expr_var != null) {
3094 expr_list.append_expression (get_variable_cexpression (full_expr_var.name));
3097 set_cvalue (expr, expr_list);
3099 temp_ref_vars.clear ();
3102 public void emit_temp_var (LocalVariable local) {
3103 var vardecl = new CCodeVariableDeclarator (local.name, null, local.variable_type.get_cdeclarator_suffix ());
3105 var st = local.variable_type.data_type as Struct;
3106 var array_type = local.variable_type as ArrayType;
3108 if (local.name.has_prefix ("*")) {
3109 // do not dereference unintialized variable
3110 // initialization is not needed for these special
3111 // pointer temp variables
3112 // used to avoid side-effects in assignments
3113 } else if (local.no_init) {
3114 // no initialization necessary for this temp var
3115 } else if (!local.variable_type.nullable &&
3116 (st != null && !st.is_simple_type ()) ||
3117 (array_type != null && array_type.fixed_length)) {
3118 // 0-initialize struct with struct initializer { 0 }
3119 // necessary as they will be passed by reference
3120 var clist = new CCodeInitializerList ();
3121 clist.append (new CCodeConstant ("0"));
3123 vardecl.initializer = clist;
3124 vardecl.init0 = true;
3125 } else if (local.variable_type.is_reference_type_or_type_parameter () ||
3126 local.variable_type.nullable ||
3127 local.variable_type is DelegateType) {
3128 vardecl.initializer = new CCodeConstant ("NULL");
3129 vardecl.init0 = true;
3132 if (current_method != null && current_method.coroutine) {
3133 closure_struct.add_field (local.variable_type.get_cname (), local.name);
3135 // even though closure struct is zerod, we need to initialize temporary variables
3136 // as they might be used multiple times when declared in a loop
3138 if (vardecl.initializer is CCodeInitializerList) {
3139 // C does not support initializer lists in assignments, use memset instead
3140 cfile.add_include ("string.h");
3141 var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
3142 memset_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (local.name)));
3143 memset_call.add_argument (new CCodeConstant ("0"));
3144 memset_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (local.variable_type.get_cname ())));
3145 ccode.add_expression (memset_call);
3146 } else if (vardecl.initializer != null) {
3147 ccode.add_assignment (get_variable_cexpression (local.name), vardecl.initializer);
3149 } else {
3150 ccode.add_declaration (local.variable_type.get_cname (), vardecl);
3154 public override void visit_expression_statement (ExpressionStatement stmt) {
3155 if (stmt.expression.error) {
3156 stmt.error = true;
3157 return;
3160 /* free temporary objects and handle errors */
3162 foreach (LocalVariable local in temp_ref_vars) {
3163 ccode.add_expression (get_unref_expression_ (local));
3166 if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
3167 // simple case, no node breakdown necessary
3168 add_simple_check (stmt.expression);
3171 temp_ref_vars.clear ();
3174 public virtual void append_local_free (Symbol sym, bool stop_at_loop = false, CodeNode? stop_at = null) {
3175 var b = (Block) sym;
3177 var local_vars = b.get_local_variables ();
3178 // free in reverse order
3179 for (int i = local_vars.size - 1; i >= 0; i--) {
3180 var local = local_vars[i];
3181 if (!local.unreachable && local.active && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
3182 ccode.add_expression (get_unref_expression_ (local));
3186 if (b.captured) {
3187 int block_id = get_block_id (b);
3189 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
3190 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
3191 ccode.add_expression (data_unref);
3194 if (stop_at_loop) {
3195 if (b.parent_node is Loop ||
3196 b.parent_node is ForeachStatement ||
3197 b.parent_node is SwitchStatement) {
3198 return;
3202 if (b.parent_node == stop_at) {
3203 return;
3206 if (sym.parent_symbol is Block) {
3207 append_local_free (sym.parent_symbol, stop_at_loop, stop_at);
3208 } else if (sym.parent_symbol is Method) {
3209 append_param_free ((Method) sym.parent_symbol);
3213 private void append_param_free (Method m) {
3214 foreach (Parameter param in m.get_parameters ()) {
3215 if (!param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
3216 ccode.add_expression (get_unref_expression_ (param));
3221 public bool variable_accessible_in_finally (LocalVariable local) {
3222 if (current_try == null) {
3223 return false;
3226 var sym = current_symbol;
3228 while (!(sym is Method || sym is PropertyAccessor) && sym.scope.lookup (local.name) == null) {
3229 if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) ||
3230 (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) {
3232 return true;
3235 sym = sym.parent_symbol;
3238 return false;
3241 void return_out_parameter (Parameter param) {
3242 var delegate_type = param.variable_type as DelegateType;
3244 ccode.open_if (get_variable_cexpression (param.name));
3245 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (param.name)), get_variable_cexpression ("_" + param.name));
3247 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
3248 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_delegate_target_cname (param.name))), new CCodeIdentifier (get_delegate_target_cname (get_variable_cname ("_" + param.name))));
3249 if (delegate_type.value_owned) {
3250 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_delegate_target_destroy_notify_cname (param.name))), new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname ("_" + param.name))));
3254 if (param.variable_type.is_disposable ()){
3255 ccode.add_else ();
3256 ccode.add_expression (get_unref_expression_ (param));
3258 ccode.close ();
3260 var array_type = param.variable_type as ArrayType;
3261 if (array_type != null && !array_type.fixed_length && !param.no_array_length) {
3262 for (int dim = 1; dim <= array_type.rank; dim++) {
3263 ccode.open_if (get_variable_cexpression (get_parameter_array_length_cname (param, dim)));
3264 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_parameter_array_length_cname (param, dim))), new CCodeIdentifier (get_array_length_cname (get_variable_cname ("_" + param.name), dim)));
3265 ccode.close ();
3270 public override void visit_return_statement (ReturnStatement stmt) {
3271 Symbol return_expression_symbol = null;
3273 if (stmt.return_expression != null) {
3274 // avoid unnecessary ref/unref pair
3275 var local = stmt.return_expression.symbol_reference as LocalVariable;
3276 if (current_return_type.value_owned
3277 && local != null && local.variable_type.value_owned
3278 && !local.captured
3279 && !variable_accessible_in_finally (local)) {
3280 /* return expression is local variable taking ownership and
3281 * current method is transferring ownership */
3283 return_expression_symbol = local;
3287 // return array length if appropriate
3288 if (((current_method != null && !current_method.no_array_length) || current_property_accessor != null) && current_return_type is ArrayType) {
3289 var return_expr_decl = get_temp_variable (stmt.return_expression.value_type, true, stmt, false);
3291 ccode.add_assignment (get_variable_cexpression (return_expr_decl.name), get_cvalue (stmt.return_expression));
3293 var array_type = (ArrayType) current_return_type;
3295 for (int dim = 1; dim <= array_type.rank; dim++) {
3296 var len_l = get_result_cexpression (get_array_length_cname ("result", dim));
3297 if (current_method == null || !current_method.coroutine) {
3298 len_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, len_l);
3300 var len_r = get_array_length_cexpression (stmt.return_expression, dim);
3301 ccode.add_assignment (len_l, len_r);
3304 set_cvalue (stmt.return_expression, get_variable_cexpression (return_expr_decl.name));
3306 emit_temp_var (return_expr_decl);
3307 } else if ((current_method != null || current_property_accessor != null) && current_return_type is DelegateType) {
3308 var delegate_type = (DelegateType) current_return_type;
3309 if (delegate_type.delegate_symbol.has_target) {
3310 var return_expr_decl = get_temp_variable (stmt.return_expression.value_type, true, stmt, false);
3312 ccode.add_assignment (get_variable_cexpression (return_expr_decl.name), get_cvalue (stmt.return_expression));
3314 var target_l = get_result_cexpression (get_delegate_target_cname ("result"));
3315 if (current_method == null || !current_method.coroutine) {
3316 target_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l);
3318 CCodeExpression target_r_destroy_notify;
3319 var target_r = get_delegate_target_cexpression (stmt.return_expression, out target_r_destroy_notify);
3320 ccode.add_assignment (target_l, target_r);
3321 if (delegate_type.value_owned) {
3322 var target_l_destroy_notify = get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3323 if (current_method == null || !current_method.coroutine) {
3324 target_l_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l_destroy_notify);
3326 ccode.add_assignment (target_l_destroy_notify, target_r_destroy_notify);
3329 set_cvalue (stmt.return_expression, get_variable_cexpression (return_expr_decl.name));
3331 emit_temp_var (return_expr_decl);
3335 if (stmt.return_expression != null) {
3336 // assign method result to `result'
3337 CCodeExpression result_lhs = get_result_cexpression ();
3338 if (current_return_type.is_real_non_null_struct_type () && (current_method == null || !current_method.coroutine)) {
3339 result_lhs = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result_lhs);
3341 ccode.add_assignment (result_lhs, get_cvalue (stmt.return_expression));
3344 // free local variables
3345 append_local_free (current_symbol);
3347 if (current_method != null) {
3348 // check postconditions
3349 foreach (Expression postcondition in current_method.get_postconditions ()) {
3350 create_postcondition_statement (postcondition);
3354 if (current_method != null && !current_method.coroutine) {
3355 // assign values to output parameters if they are not NULL
3356 // otherwise, free the value if necessary
3357 foreach (var param in current_method.get_parameters ()) {
3358 if (param.direction != ParameterDirection.OUT) {
3359 continue;
3362 return_out_parameter (param);
3366 if (is_in_constructor ()) {
3367 ccode.add_return (new CCodeIdentifier ("obj"));
3368 } else if (is_in_destructor ()) {
3369 // do not call return as member cleanup and chain up to base finalizer
3370 // stil need to be executed
3371 ccode.add_goto ("_return");
3372 } else if (current_method is CreationMethod) {
3373 ccode.add_return (new CCodeIdentifier ("self"));
3374 } else if (current_method != null && current_method.coroutine) {
3375 } else if (current_return_type is VoidType || current_return_type.is_real_non_null_struct_type ()) {
3376 // structs are returned via out parameter
3377 ccode.add_return ();
3378 } else {
3379 ccode.add_return (new CCodeIdentifier ("result"));
3382 if (return_expression_symbol != null) {
3383 return_expression_symbol.active = true;
3386 // required for destructors
3387 current_method_return = true;
3390 public string get_symbol_lock_name (string symname) {
3391 return "__lock_%s".printf (symname);
3394 private CCodeExpression get_lock_expression (Statement stmt, Expression resource) {
3395 CCodeExpression l = null;
3396 var inner_node = ((MemberAccess)resource).inner;
3397 var member = resource.symbol_reference;
3398 var parent = (TypeSymbol)resource.symbol_reference.parent_symbol;
3400 if (member.is_instance_member ()) {
3401 if (inner_node == null) {
3402 l = new CCodeIdentifier ("self");
3403 } else if (resource.symbol_reference.parent_symbol != current_type_symbol) {
3404 l = generate_instance_cast (get_cvalue (inner_node), parent);
3405 } else {
3406 l = get_cvalue (inner_node);
3409 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (resource.symbol_reference.name));
3410 } else if (member.is_class_member ()) {
3411 CCodeExpression klass;
3413 if (current_method != null && current_method.binding == MemberBinding.INSTANCE ||
3414 current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE ||
3415 (in_constructor && !in_static_or_class_context)) {
3416 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3417 k.add_argument (new CCodeIdentifier ("self"));
3418 klass = k;
3419 } else {
3420 klass = new CCodeIdentifier ("klass");
3423 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent.get_upper_case_cname ())));
3424 get_class_private_call.add_argument (klass);
3425 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (resource.symbol_reference.name));
3426 } else {
3427 string lock_name = "%s_%s".printf(parent.get_lower_case_cname (), resource.symbol_reference.name);
3428 l = new CCodeIdentifier (get_symbol_lock_name (lock_name));
3430 return l;
3433 public override void visit_lock_statement (LockStatement stmt) {
3434 var l = get_lock_expression (stmt, stmt.resource);
3436 var fc = new CCodeFunctionCall (new CCodeIdentifier (((Method) mutex_type.scope.lookup ("lock")).get_cname ()));
3437 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3439 ccode.add_expression (fc);
3442 public override void visit_unlock_statement (UnlockStatement stmt) {
3443 var l = get_lock_expression (stmt, stmt.resource);
3445 var fc = new CCodeFunctionCall (new CCodeIdentifier (((Method) mutex_type.scope.lookup ("unlock")).get_cname ()));
3446 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3448 ccode.add_expression (fc);
3451 public override void visit_delete_statement (DeleteStatement stmt) {
3452 var pointer_type = (PointerType) stmt.expression.value_type;
3453 DataType type = pointer_type;
3454 if (pointer_type.base_type.data_type != null && pointer_type.base_type.data_type.is_reference_type ()) {
3455 type = pointer_type.base_type;
3458 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
3459 ccall.add_argument (get_cvalue (stmt.expression));
3460 ccode.add_expression (ccall);
3463 public override void visit_expression (Expression expr) {
3464 if (get_cvalue (expr) != null && !expr.lvalue) {
3465 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
3466 var st = expr.formal_value_type.type_parameter.parent_symbol.parent_symbol as Struct;
3467 if (expr.formal_value_type.type_parameter.parent_symbol != garray_type &&
3468 (st == null || st.get_cname () != "va_list")) {
3469 // GArray and va_list don't use pointer-based generics
3470 set_cvalue (expr, convert_from_generic_pointer (get_cvalue (expr), expr.value_type));
3474 // memory management, implicit casts, and boxing/unboxing
3475 set_cvalue (expr, transform_expression (get_cvalue (expr), expr.value_type, expr.target_type, expr));
3477 if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
3478 if (expr.formal_target_type.type_parameter.parent_symbol != garray_type) {
3479 // GArray doesn't use pointer-based generics
3480 set_cvalue (expr, convert_to_generic_pointer (get_cvalue (expr), expr.target_type));
3486 public override void visit_boolean_literal (BooleanLiteral expr) {
3487 if (context.profile == Profile.GOBJECT) {
3488 set_cvalue (expr, new CCodeConstant (expr.value ? "TRUE" : "FALSE"));
3489 } else {
3490 cfile.add_include ("stdbool.h");
3491 set_cvalue (expr, new CCodeConstant (expr.value ? "true" : "false"));
3495 public override void visit_character_literal (CharacterLiteral expr) {
3496 if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
3497 set_cvalue (expr, new CCodeConstant (expr.value));
3498 } else {
3499 set_cvalue (expr, new CCodeConstant ("%uU".printf (expr.get_char ())));
3503 public override void visit_integer_literal (IntegerLiteral expr) {
3504 set_cvalue (expr, new CCodeConstant (expr.value + expr.type_suffix));
3507 public override void visit_real_literal (RealLiteral expr) {
3508 string c_literal = expr.value;
3509 if (c_literal.has_suffix ("d") || c_literal.has_suffix ("D")) {
3510 // there is no suffix for double in C
3511 c_literal = c_literal.substring (0, c_literal.length - 1);
3513 if (!("." in c_literal || "e" in c_literal || "E" in c_literal)) {
3514 // C requires period or exponent part for floating constants
3515 if ("f" in c_literal || "F" in c_literal) {
3516 c_literal = c_literal.substring (0, c_literal.length - 1) + ".f";
3517 } else {
3518 c_literal += ".";
3521 set_cvalue (expr, new CCodeConstant (c_literal));
3524 public override void visit_string_literal (StringLiteral expr) {
3525 set_cvalue (expr, new CCodeConstant.string (expr.value.replace ("\n", "\\n")));
3528 public override void visit_regex_literal (RegexLiteral expr) {
3529 string[] parts = expr.value.split ("/", 3);
3530 string re = parts[2].escape ("");
3531 string flags = "0";
3533 if (parts[1].contains ("i")) {
3534 flags += " | G_REGEX_CASELESS";
3536 if (parts[1].contains ("m")) {
3537 flags += " | G_REGEX_MULTILINE";
3539 if (parts[1].contains ("s")) {
3540 flags += " | G_REGEX_DOTALL";
3542 if (parts[1].contains ("x")) {
3543 flags += " | G_REGEX_EXTENDED";
3546 var regex_var = get_temp_variable (regex_type, true, expr, false);
3547 emit_temp_var (regex_var);
3549 var cdecl = new CCodeDeclaration ("GRegex*");
3551 var cname = regex_var.name + "regex_" + next_regex_id.to_string ();
3552 if (this.next_regex_id == 0) {
3553 var fun = new CCodeFunction ("_thread_safe_regex_init", "GRegex*");
3554 fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
3555 fun.add_parameter (new CCodeParameter ("re", "GRegex**"));
3556 fun.add_parameter (new CCodeParameter ("pattern", "const gchar *"));
3557 fun.add_parameter (new CCodeParameter ("match_options", "GRegexMatchFlags"));
3559 push_function (fun);
3561 var once_enter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
3562 once_enter_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
3563 ccode.open_if (once_enter_call);
3565 var regex_new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_regex_new"));
3566 regex_new_call.add_argument (new CCodeConstant ("pattern"));
3567 regex_new_call.add_argument (new CCodeConstant ("match_options"));
3568 regex_new_call.add_argument (new CCodeConstant ("0"));
3569 regex_new_call.add_argument (new CCodeConstant ("NULL"));
3570 ccode.add_assignment (new CCodeIdentifier ("GRegex* val"), regex_new_call);
3572 var once_leave_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
3573 once_leave_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
3574 once_leave_call.add_argument (new CCodeConstant ("(gsize) val"));
3575 ccode.add_expression (once_leave_call);
3577 ccode.close ();
3579 ccode.add_return (new CCodeIdentifier ("*re"));
3581 pop_function ();
3583 cfile.add_function (fun);
3585 this.next_regex_id++;
3587 cdecl.add_declarator (new CCodeVariableDeclarator (cname + " = NULL"));
3588 cdecl.modifiers = CCodeModifiers.STATIC;
3590 var regex_const = new CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname, re, flags));
3592 cfile.add_constant_declaration (cdecl);
3593 set_cvalue (expr, regex_const);
3596 public override void visit_null_literal (NullLiteral expr) {
3597 if (context.profile != Profile.GOBJECT) {
3598 cfile.add_include ("stddef.h");
3600 set_cvalue (expr, new CCodeConstant ("NULL"));
3602 var array_type = expr.target_type as ArrayType;
3603 var delegate_type = expr.target_type as DelegateType;
3604 if (array_type != null) {
3605 for (int dim = 1; dim <= array_type.rank; dim++) {
3606 append_array_size (expr, new CCodeConstant ("0"));
3608 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
3609 set_delegate_target (expr, new CCodeConstant ("NULL"));
3610 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
3614 public virtual TargetValue get_variable_cvalue (Variable variable, CCodeExpression? inner = null) {
3615 assert_not_reached ();
3618 public virtual string get_delegate_target_cname (string delegate_cname) {
3619 assert_not_reached ();
3622 public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
3623 assert_not_reached ();
3626 public virtual CCodeExpression get_delegate_target_cvalue (TargetValue value) {
3627 return new CCodeInvalidExpression ();
3630 public virtual CCodeExpression get_delegate_target_destroy_notify_cvalue (TargetValue value) {
3631 return new CCodeInvalidExpression ();
3634 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname) {
3635 assert_not_reached ();
3638 public override void visit_base_access (BaseAccess expr) {
3639 CCodeExpression this_access;
3640 if (current_method != null && current_method.coroutine) {
3641 // use closure
3642 this_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "self");
3643 } else {
3644 this_access = new CCodeIdentifier ("self");
3647 set_cvalue (expr, generate_instance_cast (this_access, expr.value_type.data_type));
3650 public override void visit_postfix_expression (PostfixExpression expr) {
3651 MemberAccess ma = find_property_access (expr.inner);
3652 if (ma != null) {
3653 // property postfix expression
3654 var prop = (Property) ma.symbol_reference;
3656 // assign current value to temp variable
3657 var temp_decl = get_temp_variable (prop.property_type, true, expr, false);
3658 emit_temp_var (temp_decl);
3659 ccode.add_assignment (get_variable_cexpression (temp_decl.name), get_cvalue (expr.inner));
3661 // increment/decrement property
3662 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
3663 var cexpr = new CCodeBinaryExpression (op, get_variable_cexpression (temp_decl.name), new CCodeConstant ("1"));
3664 store_property (prop, ma.inner, new GLibValue (expr.value_type, cexpr));
3666 // return previous value
3667 set_cvalue (expr, get_variable_cexpression (temp_decl.name));
3668 return;
3671 if (expr.parent_node is ExpressionStatement) {
3672 var op = expr.increment ? CCodeUnaryOperator.POSTFIX_INCREMENT : CCodeUnaryOperator.POSTFIX_DECREMENT;
3674 ccode.add_expression (new CCodeUnaryExpression (op, get_cvalue (expr.inner)));
3675 } else {
3676 // assign current value to temp variable
3677 var temp_decl = get_temp_variable (expr.inner.value_type, true, expr, false);
3678 emit_temp_var (temp_decl);
3679 ccode.add_assignment (get_variable_cexpression (temp_decl.name), get_cvalue (expr.inner));
3681 // increment/decrement variable
3682 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
3683 var cexpr = new CCodeBinaryExpression (op, get_variable_cexpression (temp_decl.name), new CCodeConstant ("1"));
3684 ccode.add_assignment (get_cvalue (expr.inner), cexpr);
3686 // return previous value
3687 set_cvalue (expr, get_variable_cexpression (temp_decl.name));
3691 private MemberAccess? find_property_access (Expression expr) {
3692 if (!(expr is MemberAccess)) {
3693 return null;
3696 var ma = (MemberAccess) expr;
3697 if (ma.symbol_reference is Property) {
3698 return ma;
3701 return null;
3704 bool is_limited_generic_type (DataType type) {
3705 var cl = type.type_parameter.parent_symbol as Class;
3706 var st = type.type_parameter.parent_symbol as Struct;
3707 if ((cl != null && cl.is_compact) || st != null) {
3708 // compact classes and structs only
3709 // have very limited generics support
3710 return true;
3712 return false;
3715 public bool requires_copy (DataType type) {
3716 if (!type.is_disposable ()) {
3717 return false;
3720 var cl = type.data_type as Class;
3721 if (cl != null && cl.is_reference_counting ()
3722 && cl.get_ref_function () == "") {
3723 // empty ref_function => no ref necessary
3724 return false;
3727 if (type.type_parameter != null) {
3728 if (is_limited_generic_type (type)) {
3729 return false;
3733 return true;
3736 public bool requires_destroy (DataType type) {
3737 if (!type.is_disposable ()) {
3738 return false;
3741 var array_type = type as ArrayType;
3742 if (array_type != null && array_type.fixed_length) {
3743 return requires_destroy (array_type.element_type);
3746 var cl = type.data_type as Class;
3747 if (cl != null && cl.is_reference_counting ()
3748 && cl.get_unref_function () == "") {
3749 // empty unref_function => no unref necessary
3750 return false;
3753 if (type.type_parameter != null) {
3754 if (is_limited_generic_type (type)) {
3755 return false;
3759 return true;
3762 bool is_ref_function_void (DataType type) {
3763 var cl = type.data_type as Class;
3764 if (cl != null && cl.ref_function_void) {
3765 return true;
3766 } else {
3767 return false;
3771 public virtual CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
3772 if (expression_type is DelegateType) {
3773 return cexpr;
3776 if (expression_type is ValueType && !expression_type.nullable) {
3777 // normal value type, no null check
3778 // (copy (&expr, &temp), temp)
3780 var decl = get_temp_variable (expression_type, false, node);
3781 emit_temp_var (decl);
3783 var ctemp = get_variable_cexpression (decl.name);
3785 var vt = (ValueType) expression_type;
3786 var st = (Struct) vt.type_symbol;
3787 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (st.get_copy_function ()));
3788 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
3789 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
3791 if (!st.has_copy_function) {
3792 generate_struct_copy_function (st);
3795 var ccomma = new CCodeCommaExpression ();
3797 if (st.get_copy_function () == "g_value_copy") {
3798 // GValue requires g_value_init in addition to g_value_copy
3800 var value_type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
3801 value_type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
3803 var init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
3804 init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
3805 init_call.add_argument (value_type_call);
3807 ccomma.append_expression (init_call);
3810 ccomma.append_expression (copy_call);
3811 ccomma.append_expression (ctemp);
3813 if (gvalue_type != null && expression_type.data_type == gvalue_type) {
3814 // g_value_init/copy must not be called for uninitialized values
3815 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
3816 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
3818 return new CCodeConditionalExpression (cisvalid, ccomma, cexpr);
3819 } else {
3820 return ccomma;
3824 /* (temp = expr, temp == NULL ? NULL : ref (temp))
3826 * can be simplified to
3827 * ref (expr)
3828 * if static type of expr is non-null
3831 var dupexpr = get_dup_func_expression (expression_type, node.source_reference);
3833 if (dupexpr == null) {
3834 node.error = true;
3835 return null;
3838 if (dupexpr is CCodeIdentifier && !(expression_type is ArrayType) && !(expression_type is GenericType) && !is_ref_function_void (expression_type)) {
3839 // generate and call NULL-aware ref function to reduce number
3840 // of temporary variables and simplify code
3842 var dupid = (CCodeIdentifier) dupexpr;
3843 string dup0_func = "_%s0".printf (dupid.name);
3845 // g_strdup is already NULL-safe
3846 if (dupid.name == "g_strdup") {
3847 dup0_func = dupid.name;
3848 } else if (add_wrapper (dup0_func)) {
3849 string pointer_cname = "gpointer";
3850 if (context.profile == Profile.POSIX) {
3851 pointer_cname = "void*";
3853 var dup0_fun = new CCodeFunction (dup0_func, pointer_cname);
3854 dup0_fun.add_parameter (new CCodeParameter ("self", pointer_cname));
3855 dup0_fun.modifiers = CCodeModifiers.STATIC;
3857 push_function (dup0_fun);
3859 var dup_call = new CCodeFunctionCall (dupexpr);
3860 dup_call.add_argument (new CCodeIdentifier ("self"));
3862 ccode.add_return (new CCodeConditionalExpression (new CCodeIdentifier ("self"), dup_call, new CCodeConstant ("NULL")));
3864 pop_function ();
3866 cfile.add_function (dup0_fun);
3869 var ccall = new CCodeFunctionCall (new CCodeIdentifier (dup0_func));
3870 ccall.add_argument (cexpr);
3871 return ccall;
3874 var ccall = new CCodeFunctionCall (dupexpr);
3876 if (!(expression_type is ArrayType) && expr != null && expr.is_non_null ()
3877 && !is_ref_function_void (expression_type)) {
3878 // expression is non-null
3879 ccall.add_argument (get_cvalue (expr));
3881 return ccall;
3882 } else {
3883 var decl = get_temp_variable (expression_type, false, node, false);
3884 emit_temp_var (decl);
3886 var ctemp = get_variable_cexpression (decl.name);
3888 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL"));
3889 if (expression_type.type_parameter != null) {
3890 // dup functions are optional for type parameters
3891 var cdupisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_dup_func_expression (expression_type, node.source_reference), new CCodeConstant ("NULL"));
3892 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cdupisnull);
3895 if (expression_type.type_parameter != null) {
3896 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
3897 ccall.add_argument (new CCodeCastExpression (ctemp, "gpointer"));
3898 } else {
3899 ccall.add_argument (ctemp);
3902 if (expression_type is ArrayType) {
3903 var array_type = (ArrayType) expression_type;
3904 bool first = true;
3905 CCodeExpression csizeexpr = null;
3906 for (int dim = 1; dim <= array_type.rank; dim++) {
3907 if (first) {
3908 csizeexpr = get_array_length_cexpression (expr, dim);
3909 first = false;
3910 } else {
3911 csizeexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeexpr, get_array_length_cexpression (expr, dim));
3915 ccall.add_argument (csizeexpr);
3917 if (array_type.element_type is GenericType) {
3918 var elem_dupexpr = get_dup_func_expression (array_type.element_type, node.source_reference);
3919 if (elem_dupexpr == null) {
3920 elem_dupexpr = new CCodeConstant ("NULL");
3922 ccall.add_argument (elem_dupexpr);
3926 var ccomma = new CCodeCommaExpression ();
3927 ccomma.append_expression (new CCodeAssignment (ctemp, cexpr));
3929 CCodeExpression cifnull;
3930 if (expression_type.data_type != null) {
3931 cifnull = new CCodeConstant ("NULL");
3932 } else {
3933 // the value might be non-null even when the dup function is null,
3934 // so we may not just use NULL for type parameters
3936 // cast from gconstpointer to gpointer as methods in
3937 // generic classes may not return gconstpointer
3938 cifnull = new CCodeCastExpression (ctemp, "gpointer");
3940 ccomma.append_expression (new CCodeConditionalExpression (cisnull, cifnull, ccall));
3942 // repeat temp variable at the end of the comma expression
3943 // if the ref function returns void
3944 if (is_ref_function_void (expression_type)) {
3945 ccomma.append_expression (ctemp);
3948 return ccomma;
3952 bool is_reference_type_argument (DataType type_arg) {
3953 if (type_arg is ErrorType || (type_arg.data_type != null && type_arg.data_type.is_reference_type ())) {
3954 return true;
3955 } else {
3956 return false;
3960 bool is_nullable_value_type_argument (DataType type_arg) {
3961 if (type_arg is ValueType && type_arg.nullable) {
3962 return true;
3963 } else {
3964 return false;
3968 bool is_signed_integer_type_argument (DataType type_arg) {
3969 var st = type_arg.data_type as Struct;
3970 if (type_arg.nullable) {
3971 return false;
3972 } else if (st == bool_type.data_type) {
3973 return true;
3974 } else if (st == char_type.data_type) {
3975 return true;
3976 } else if (unichar_type != null && st == unichar_type.data_type) {
3977 return true;
3978 } else if (st == short_type.data_type) {
3979 return true;
3980 } else if (st == int_type.data_type) {
3981 return true;
3982 } else if (st == long_type.data_type) {
3983 return true;
3984 } else if (st == int8_type.data_type) {
3985 return true;
3986 } else if (st == int16_type.data_type) {
3987 return true;
3988 } else if (st == int32_type.data_type) {
3989 return true;
3990 } else if (st == gtype_type) {
3991 return true;
3992 } else if (type_arg is EnumValueType) {
3993 return true;
3994 } else {
3995 return false;
3999 bool is_unsigned_integer_type_argument (DataType type_arg) {
4000 var st = type_arg.data_type as Struct;
4001 if (type_arg.nullable) {
4002 return false;
4003 } else if (st == uchar_type.data_type) {
4004 return true;
4005 } else if (st == ushort_type.data_type) {
4006 return true;
4007 } else if (st == uint_type.data_type) {
4008 return true;
4009 } else if (st == ulong_type.data_type) {
4010 return true;
4011 } else if (st == uint8_type.data_type) {
4012 return true;
4013 } else if (st == uint16_type.data_type) {
4014 return true;
4015 } else if (st == uint32_type.data_type) {
4016 return true;
4017 } else {
4018 return false;
4022 public void check_type (DataType type) {
4023 var array_type = type as ArrayType;
4024 if (array_type != null) {
4025 check_type (array_type.element_type);
4026 if (array_type.element_type is ArrayType) {
4027 Report.error (type.source_reference, "Stacked arrays are not supported");
4028 } else if (array_type.element_type is DelegateType) {
4029 var delegate_type = (DelegateType) array_type.element_type;
4030 if (delegate_type.delegate_symbol.has_target) {
4031 Report.error (type.source_reference, "Delegates with target are not supported as array element type");
4035 foreach (var type_arg in type.get_type_arguments ()) {
4036 check_type (type_arg);
4037 check_type_argument (type_arg);
4041 void check_type_argument (DataType type_arg) {
4042 if (type_arg is GenericType
4043 || type_arg is PointerType
4044 || is_reference_type_argument (type_arg)
4045 || is_nullable_value_type_argument (type_arg)
4046 || is_signed_integer_type_argument (type_arg)
4047 || is_unsigned_integer_type_argument (type_arg)) {
4048 // no error
4049 } else if (type_arg is DelegateType) {
4050 var delegate_type = (DelegateType) type_arg;
4051 if (delegate_type.delegate_symbol.has_target) {
4052 Report.error (type_arg.source_reference, "Delegates with target are not supported as generic type arguments");
4054 } else {
4055 Report.error (type_arg.source_reference, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg.to_string ()));
4059 public virtual void generate_class_declaration (Class cl, CCodeFile decl_space) {
4060 if (add_symbol_declaration (decl_space, cl, cl.get_cname ())) {
4061 return;
4065 public virtual void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
4068 public virtual void generate_method_declaration (Method m, CCodeFile decl_space) {
4071 public virtual void generate_error_domain_declaration (ErrorDomain edomain, CCodeFile decl_space) {
4074 public void add_generic_type_arguments (Map<int,CCodeExpression> arg_map, List<DataType> type_args, CodeNode expr, bool is_chainup = false) {
4075 int type_param_index = 0;
4076 foreach (var type_arg in type_args) {
4077 arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), get_type_id_expression (type_arg, is_chainup));
4078 if (requires_copy (type_arg)) {
4079 var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference, is_chainup);
4080 if (dup_func == null) {
4081 // type doesn't contain a copy function
4082 expr.error = true;
4083 return;
4085 arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
4086 arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), get_destroy_func_expression (type_arg, is_chainup));
4087 } else {
4088 arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeConstant ("NULL"));
4089 arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
4091 type_param_index++;
4095 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
4096 CCodeExpression instance = null;
4097 CCodeExpression creation_expr = null;
4099 check_type (expr.type_reference);
4101 var st = expr.type_reference.data_type as Struct;
4102 if ((st != null && (!st.is_simple_type () || st.get_cname () == "va_list")) || expr.get_object_initializer ().size > 0) {
4103 // value-type initialization or object creation expression with object initializer
4105 var local = expr.parent_node as LocalVariable;
4106 if (local != null && has_simple_struct_initializer (local)) {
4107 if (local.captured) {
4108 var block = (Block) local.parent_symbol;
4109 instance = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_cname (local.name));
4110 } else {
4111 instance = get_variable_cexpression (get_variable_cname (local.name));
4113 } else {
4114 var temp_decl = get_temp_variable (expr.type_reference, false, expr);
4115 emit_temp_var (temp_decl);
4117 instance = get_variable_cexpression (get_variable_cname (temp_decl.name));
4121 if (expr.symbol_reference == null) {
4122 // no creation method
4123 if (expr.type_reference.data_type is Struct) {
4124 // memset needs string.h
4125 cfile.add_include ("string.h");
4126 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4127 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4128 creation_call.add_argument (new CCodeConstant ("0"));
4129 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (expr.type_reference.get_cname ())));
4131 creation_expr = creation_call;
4133 } else if (expr.type_reference.data_type == glist_type ||
4134 expr.type_reference.data_type == gslist_type) {
4135 // NULL is an empty list
4136 set_cvalue (expr, new CCodeConstant ("NULL"));
4137 } else if (expr.symbol_reference is Method) {
4138 // use creation method
4139 var m = (Method) expr.symbol_reference;
4140 var params = m.get_parameters ();
4141 CCodeFunctionCall creation_call;
4143 generate_method_declaration (m, cfile);
4145 var cl = expr.type_reference.data_type as Class;
4147 if (!m.has_new_function) {
4148 // use construct function directly
4149 creation_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
4150 creation_call.add_argument (new CCodeIdentifier (cl.get_type_id ()));
4151 } else {
4152 creation_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
4155 if ((st != null && !st.is_simple_type ()) && !(m.cinstance_parameter_position < 0)) {
4156 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4157 } else if (st != null && st.get_cname () == "va_list") {
4158 creation_call.add_argument (instance);
4159 if (m.get_cname () == "va_start") {
4160 Parameter last_param = null;
4161 foreach (var param in current_method.get_parameters ()) {
4162 if (param.ellipsis) {
4163 break;
4165 last_param = param;
4167 creation_call.add_argument (new CCodeIdentifier (get_variable_cname (last_param.name)));
4171 generate_type_declaration (expr.type_reference, cfile);
4173 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
4175 if (cl != null && !cl.is_compact) {
4176 add_generic_type_arguments (carg_map, expr.type_reference.get_type_arguments (), expr);
4177 } else if (cl != null && m.simple_generics) {
4178 int type_param_index = 0;
4179 foreach (var type_arg in expr.type_reference.get_type_arguments ()) {
4180 if (requires_copy (type_arg)) {
4181 carg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), get_destroy0_func_expression (type_arg));
4182 } else {
4183 carg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
4185 type_param_index++;
4189 bool ellipsis = false;
4191 int i = 1;
4192 int arg_pos;
4193 Iterator<Parameter> params_it = params.iterator ();
4194 foreach (Expression arg in expr.get_argument_list ()) {
4195 CCodeExpression cexpr = get_cvalue (arg);
4196 Parameter param = null;
4197 if (params_it.next ()) {
4198 param = params_it.get ();
4199 ellipsis = param.ellipsis;
4200 if (!ellipsis) {
4201 if (!param.no_array_length && param.variable_type is ArrayType) {
4202 var array_type = (ArrayType) param.variable_type;
4203 for (int dim = 1; dim <= array_type.rank; dim++) {
4204 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), get_array_length_cexpression (arg, dim));
4206 } else if (param.variable_type is DelegateType) {
4207 var deleg_type = (DelegateType) param.variable_type;
4208 var d = deleg_type.delegate_symbol;
4209 if (d.has_target) {
4210 CCodeExpression delegate_target_destroy_notify;
4211 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
4212 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), delegate_target);
4213 if (deleg_type.value_owned) {
4214 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), delegate_target_destroy_notify);
4219 cexpr = handle_struct_argument (param, arg, cexpr);
4221 if (param.ctype != null) {
4222 cexpr = new CCodeCastExpression (cexpr, param.ctype);
4224 } else {
4225 cexpr = handle_struct_argument (null, arg, cexpr);
4228 arg_pos = get_param_pos (param.cparameter_position, ellipsis);
4229 } else {
4230 // default argument position
4231 cexpr = handle_struct_argument (null, arg, cexpr);
4232 arg_pos = get_param_pos (i, ellipsis);
4235 carg_map.set (arg_pos, cexpr);
4237 i++;
4239 while (params_it.next ()) {
4240 var param = params_it.get ();
4242 if (param.ellipsis) {
4243 ellipsis = true;
4244 break;
4247 if (param.initializer == null) {
4248 Report.error (expr.source_reference, "no default expression for argument %d".printf (i));
4249 return;
4252 /* evaluate default expression here as the code
4253 * generator might not have visited the formal
4254 * parameter yet */
4255 param.initializer.emit (this);
4257 carg_map.set (get_param_pos (param.cparameter_position), get_cvalue (param.initializer));
4258 i++;
4261 // append C arguments in the right order
4262 int last_pos = -1;
4263 int min_pos;
4264 while (true) {
4265 min_pos = -1;
4266 foreach (int pos in carg_map.get_keys ()) {
4267 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
4268 min_pos = pos;
4271 if (min_pos == -1) {
4272 break;
4274 creation_call.add_argument (carg_map.get (min_pos));
4275 last_pos = min_pos;
4278 if ((st != null && !st.is_simple_type ()) && m.cinstance_parameter_position < 0) {
4279 // instance parameter is at the end in a struct creation method
4280 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4283 if (expr.tree_can_fail) {
4284 // method can fail
4285 current_method_inner_error = true;
4286 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
4289 if (ellipsis) {
4290 /* ensure variable argument list ends with NULL
4291 * except when using printf-style arguments */
4292 if (!m.printf_format && !m.scanf_format && m.sentinel != "") {
4293 creation_call.add_argument (new CCodeConstant (m.sentinel));
4297 creation_expr = creation_call;
4299 // cast the return value of the creation method back to the intended type if
4300 // it requested a special C return type
4301 if (get_custom_creturn_type (m) != null) {
4302 creation_expr = new CCodeCastExpression (creation_expr, expr.type_reference.get_cname ());
4304 } else if (expr.symbol_reference is ErrorCode) {
4305 var ecode = (ErrorCode) expr.symbol_reference;
4306 var edomain = (ErrorDomain) ecode.parent_symbol;
4307 CCodeFunctionCall creation_call;
4309 generate_error_domain_declaration (edomain, cfile);
4311 if (expr.get_argument_list ().size == 1) {
4312 // must not be a format argument
4313 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new_literal"));
4314 } else {
4315 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new"));
4317 creation_call.add_argument (new CCodeIdentifier (edomain.get_upper_case_cname ()));
4318 creation_call.add_argument (new CCodeIdentifier (ecode.get_cname ()));
4320 foreach (Expression arg in expr.get_argument_list ()) {
4321 creation_call.add_argument (get_cvalue (arg));
4324 creation_expr = creation_call;
4325 } else {
4326 assert (false);
4329 var local = expr.parent_node as LocalVariable;
4330 if (local != null && has_simple_struct_initializer (local)) {
4331 // no temporary variable necessary
4332 set_cvalue (expr, creation_expr);
4333 return;
4334 } else if (instance != null) {
4335 if (expr.type_reference.data_type is Struct) {
4336 ccode.add_expression (creation_expr);
4337 } else {
4338 ccode.add_assignment (instance, creation_expr);
4341 foreach (MemberInitializer init in expr.get_object_initializer ()) {
4342 if (init.symbol_reference is Field) {
4343 var f = (Field) init.symbol_reference;
4344 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
4345 var typed_inst = transform_expression (instance, expr.type_reference, instance_target_type);
4346 CCodeExpression lhs;
4347 if (expr.type_reference.data_type is Struct) {
4348 lhs = new CCodeMemberAccess (typed_inst, f.get_cname ());
4349 } else {
4350 lhs = new CCodeMemberAccess.pointer (typed_inst, f.get_cname ());
4352 ccode.add_assignment (lhs, get_cvalue (init.initializer));
4354 if (f.variable_type is ArrayType && !f.no_array_length) {
4355 var array_type = (ArrayType) f.variable_type;
4356 for (int dim = 1; dim <= array_type.rank; dim++) {
4357 if (expr.type_reference.data_type is Struct) {
4358 lhs = new CCodeMemberAccess (typed_inst, get_array_length_cname (f.get_cname (), dim));
4359 } else {
4360 lhs = new CCodeMemberAccess.pointer (typed_inst, get_array_length_cname (f.get_cname (), dim));
4362 var rhs_array_len = get_array_length_cexpression (init.initializer, dim);
4363 ccode.add_assignment (lhs, rhs_array_len);
4365 } else if (f.variable_type is DelegateType && (f.variable_type as DelegateType).delegate_symbol.has_target && !f.no_delegate_target) {
4366 if (expr.type_reference.data_type is Struct) {
4367 lhs = new CCodeMemberAccess (typed_inst, get_delegate_target_cname (f.get_cname ()));
4368 } else {
4369 lhs = new CCodeMemberAccess.pointer (typed_inst, get_delegate_target_cname (f.get_cname ()));
4371 CCodeExpression rhs_delegate_target_destroy_notify;
4372 var rhs_delegate_target = get_delegate_target_cexpression (init.initializer, out rhs_delegate_target_destroy_notify);
4373 ccode.add_assignment (lhs, rhs_delegate_target);
4376 var cl = f.parent_symbol as Class;
4377 if (cl != null) {
4378 generate_class_struct_declaration (cl, cfile);
4380 } else if (init.symbol_reference is Property) {
4381 var inst_ma = new MemberAccess.simple ("new");
4382 inst_ma.value_type = expr.type_reference;
4383 set_cvalue (inst_ma, instance);
4384 store_property ((Property) init.symbol_reference, inst_ma, init.initializer.target_value);
4388 creation_expr = instance;
4391 if (creation_expr != null) {
4392 var temp_var = get_temp_variable (expr.value_type);
4393 var temp_ref = get_variable_cexpression (temp_var.name);
4395 emit_temp_var (temp_var);
4397 ccode.add_assignment (temp_ref, creation_expr);
4398 set_cvalue (expr, temp_ref);
4402 public CCodeExpression? handle_struct_argument (Parameter? param, Expression arg, CCodeExpression? cexpr) {
4403 DataType type;
4404 if (param != null) {
4405 type = param.variable_type;
4406 } else {
4407 // varargs
4408 type = arg.value_type;
4411 // pass non-simple struct instances always by reference
4412 if (!(arg.value_type is NullType) && type.is_real_struct_type ()) {
4413 // we already use a reference for arguments of ref, out, and nullable parameters
4414 if ((param == null || param.direction == ParameterDirection.IN) && !type.nullable) {
4415 var unary = cexpr as CCodeUnaryExpression;
4416 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
4417 // *expr => expr
4418 return unary.inner;
4419 } else if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
4420 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
4421 } else {
4422 // if cexpr is e.g. a function call, we can't take the address of the expression
4423 // (tmp = expr, &tmp)
4424 var ccomma = new CCodeCommaExpression ();
4426 var temp_var = get_temp_variable (type, true, null, false);
4427 emit_temp_var (temp_var);
4428 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), cexpr));
4429 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name)));
4431 return ccomma;
4436 return cexpr;
4439 public override void visit_sizeof_expression (SizeofExpression expr) {
4440 generate_type_declaration (expr.type_reference, cfile);
4442 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
4443 csizeof.add_argument (new CCodeIdentifier (expr.type_reference.get_cname ()));
4444 set_cvalue (expr, csizeof);
4447 public override void visit_typeof_expression (TypeofExpression expr) {
4448 set_cvalue (expr, get_type_id_expression (expr.type_reference));
4451 public override void visit_unary_expression (UnaryExpression expr) {
4452 if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) {
4453 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
4455 var array_type = expr.value_type as ArrayType;
4456 if (array_type != null) {
4457 for (int dim = 1; dim <= array_type.rank; dim++) {
4458 append_array_size (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cexpression (expr.inner, dim)));
4462 var delegate_type = expr.value_type as DelegateType;
4463 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
4464 CCodeExpression target_destroy_notify;
4465 set_delegate_target (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_cexpression (expr.inner, out target_destroy_notify)));
4466 if (target_destroy_notify != null) {
4467 set_delegate_target_destroy_notify (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_destroy_notify));
4471 return;
4474 CCodeUnaryOperator op;
4475 if (expr.operator == UnaryOperator.PLUS) {
4476 op = CCodeUnaryOperator.PLUS;
4477 } else if (expr.operator == UnaryOperator.MINUS) {
4478 op = CCodeUnaryOperator.MINUS;
4479 } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
4480 op = CCodeUnaryOperator.LOGICAL_NEGATION;
4481 } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
4482 op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
4483 } else if (expr.operator == UnaryOperator.INCREMENT) {
4484 op = CCodeUnaryOperator.PREFIX_INCREMENT;
4485 } else if (expr.operator == UnaryOperator.DECREMENT) {
4486 op = CCodeUnaryOperator.PREFIX_DECREMENT;
4487 } else {
4488 assert_not_reached ();
4490 set_cvalue (expr, new CCodeUnaryExpression (op, get_cvalue (expr.inner)));
4493 public CCodeExpression? try_cast_value_to_type (CCodeExpression ccodeexpr, DataType from, DataType to, Expression? expr = null) {
4494 if (from == null || gvalue_type == null || from.data_type != gvalue_type || to.get_type_id () == null) {
4495 return null;
4498 // explicit conversion from GValue
4499 var ccall = new CCodeFunctionCall (get_value_getter_function (to));
4500 CCodeExpression gvalue;
4501 if (from.nullable) {
4502 gvalue = ccodeexpr;
4503 } else {
4504 gvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ccodeexpr);
4506 ccall.add_argument (gvalue);
4508 CCodeExpression rv = ccall;
4510 if (expr != null && to is ArrayType) {
4511 // null-terminated string array
4512 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
4513 len_call.add_argument (rv);
4514 append_array_size (expr, len_call);
4515 } else if (to is StructValueType) {
4516 var temp_decl = get_temp_variable (to, true, null, true);
4517 emit_temp_var (temp_decl);
4518 var ctemp = get_variable_cexpression (temp_decl.name);
4520 rv = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeCastExpression (rv, (new PointerType(to)).get_cname ()));
4521 var holds = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_HOLDS"));
4522 holds.add_argument (gvalue);
4523 holds.add_argument (new CCodeIdentifier (to.get_type_id ()));
4524 var cond = new CCodeBinaryExpression (CCodeBinaryOperator.AND, holds, ccall);
4525 var warn = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
4526 warn.add_argument (new CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
4527 var fail = new CCodeCommaExpression ();
4528 fail.append_expression (warn);
4529 fail.append_expression (ctemp);
4530 rv = new CCodeConditionalExpression (cond, rv, fail);
4533 return rv;
4536 int next_variant_function_id = 0;
4538 public CCodeExpression? try_cast_variant_to_type (CCodeExpression ccodeexpr, DataType from, DataType to, Expression? expr = null) {
4539 if (from == null || gvariant_type == null || from.data_type != gvariant_type) {
4540 return null;
4543 string variant_func = "_variant_get%d".printf (++next_variant_function_id);
4545 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
4546 ccall.add_argument (ccodeexpr);
4548 var cfunc = new CCodeFunction (variant_func);
4549 cfunc.modifiers = CCodeModifiers.STATIC;
4550 cfunc.add_parameter (new CCodeParameter ("value", "GVariant*"));
4552 if (!to.is_real_non_null_struct_type ()) {
4553 cfunc.return_type = to.get_cname ();
4556 if (to.is_real_non_null_struct_type ()) {
4557 // structs are returned via out parameter
4558 cfunc.add_parameter (new CCodeParameter ("result", to.get_cname () + "*"));
4559 } else if (to is ArrayType) {
4560 // return array length if appropriate
4561 var array_type = (ArrayType) to;
4563 for (int dim = 1; dim <= array_type.rank; dim++) {
4564 var temp_decl = get_temp_variable (int_type, false, expr);
4565 emit_temp_var (temp_decl);
4567 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_decl.name)));
4568 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("result", dim), "int*"));
4569 append_array_size (expr, get_variable_cexpression (temp_decl.name));
4573 push_function (cfunc);
4575 var result = deserialize_expression (to, new CCodeIdentifier ("value"), new CCodeIdentifier ("*result"));
4576 ccode.add_return (result);
4578 pop_function ();
4580 cfile.add_function_declaration (cfunc);
4581 cfile.add_function (cfunc);
4583 return ccall;
4586 public virtual CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
4587 return null;
4590 public virtual CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
4591 return null;
4594 public override void visit_cast_expression (CastExpression expr) {
4595 var valuecast = try_cast_value_to_type (get_cvalue (expr.inner), expr.inner.value_type, expr.type_reference, expr);
4596 if (valuecast != null) {
4597 set_cvalue (expr, valuecast);
4598 return;
4601 var variantcast = try_cast_variant_to_type (get_cvalue (expr.inner), expr.inner.value_type, expr.type_reference, expr);
4602 if (variantcast != null) {
4603 set_cvalue (expr, variantcast);
4604 return;
4607 generate_type_declaration (expr.type_reference, cfile);
4609 var cl = expr.type_reference.data_type as Class;
4610 var iface = expr.type_reference.data_type as Interface;
4611 if (context.profile == Profile.GOBJECT && (iface != null || (cl != null && !cl.is_compact))) {
4612 // checked cast for strict subtypes of GTypeInstance
4613 if (expr.is_silent_cast) {
4614 var ccomma = new CCodeCommaExpression ();
4615 var temp_decl = get_temp_variable (expr.inner.value_type, true, expr, false);
4617 emit_temp_var (temp_decl);
4619 var ctemp = get_variable_cexpression (temp_decl.name);
4620 var cinit = new CCodeAssignment (ctemp, get_cvalue (expr.inner));
4621 var ccheck = create_type_check (ctemp, expr.type_reference);
4622 var ccast = new CCodeCastExpression (ctemp, expr.type_reference.get_cname ());
4623 var cnull = new CCodeConstant ("NULL");
4625 ccomma.append_expression (cinit);
4626 ccomma.append_expression (new CCodeConditionalExpression (ccheck, ccast, cnull));
4628 set_cvalue (expr, ccomma);
4629 } else {
4630 set_cvalue (expr, generate_instance_cast (get_cvalue (expr.inner), expr.type_reference.data_type));
4632 } else {
4633 if (expr.is_silent_cast) {
4634 expr.error = true;
4635 Report.error (expr.source_reference, "Operation not supported for this type");
4636 return;
4639 // retain array length
4640 var array_type = expr.type_reference as ArrayType;
4641 if (array_type != null && expr.inner.value_type is ArrayType) {
4642 for (int dim = 1; dim <= array_type.rank; dim++) {
4643 append_array_size (expr, get_array_length_cexpression (expr.inner, dim));
4645 } else if (array_type != null) {
4646 // cast from non-array to array, set invalid length
4647 // required by string.data, e.g.
4648 for (int dim = 1; dim <= array_type.rank; dim++) {
4649 append_array_size (expr, new CCodeConstant ("-1"));
4653 var innercexpr = get_cvalue (expr.inner);
4654 if (expr.type_reference.data_type is Struct && !expr.type_reference.nullable &&
4655 expr.inner.value_type.data_type is Struct && expr.inner.value_type.nullable) {
4656 // nullable integer or float or boolean or struct cast to non-nullable
4657 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, innercexpr);
4659 set_cvalue (expr, new CCodeCastExpression (innercexpr, expr.type_reference.get_cname ()));
4661 if (expr.type_reference is DelegateType) {
4662 if (get_delegate_target (expr.inner) != null) {
4663 set_delegate_target (expr, get_delegate_target (expr.inner));
4664 } else {
4665 set_delegate_target (expr, new CCodeConstant ("NULL"));
4667 if (get_delegate_target_destroy_notify (expr.inner) != null) {
4668 set_delegate_target_destroy_notify (expr, get_delegate_target_destroy_notify (expr.inner));
4669 } else {
4670 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
4676 public override void visit_named_argument (NamedArgument expr) {
4677 set_cvalue (expr, get_cvalue (expr.inner));
4680 public override void visit_pointer_indirection (PointerIndirection expr) {
4681 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cvalue (expr.inner)));
4684 public override void visit_addressof_expression (AddressofExpression expr) {
4685 if (get_cvalue (expr.inner) is CCodeCommaExpression) {
4686 var ccomma = get_cvalue (expr.inner) as CCodeCommaExpression;
4687 var inner = ccomma.get_inner ();
4688 var last = inner.get (inner.size - 1);
4689 ccomma.set_expression (inner.size - 1, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, (CCodeExpression) last));
4690 set_cvalue (expr, ccomma);
4691 } else {
4692 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
4696 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
4697 /* (tmp = var, var = null, tmp) */
4698 var temp_decl = get_temp_variable (expr.value_type, true, expr, false);
4699 emit_temp_var (temp_decl);
4700 var cvar = get_variable_cexpression (temp_decl.name);
4702 ccode.add_assignment (cvar, get_cvalue (expr.inner));
4703 if (!(expr.value_type is DelegateType)) {
4704 ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
4707 set_cvalue (expr, cvar);
4709 var array_type = expr.value_type as ArrayType;
4710 if (array_type != null) {
4711 for (int dim = 1; dim <= array_type.rank; dim++) {
4712 append_array_size (expr, get_array_length_cexpression (expr.inner, dim));
4716 var delegate_type = expr.value_type as DelegateType;
4717 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
4718 var temp_target_decl = get_temp_variable (new PointerType (new VoidType ()), true, expr, false);
4719 emit_temp_var (temp_target_decl);
4720 var target_cvar = get_variable_cexpression (temp_target_decl.name);
4721 CCodeExpression target_destroy_notify;
4722 var target = get_delegate_target_cexpression (expr.inner, out target_destroy_notify);
4723 ccode.add_assignment (target_cvar, target);
4724 set_delegate_target (expr, target_cvar);
4725 if (target_destroy_notify != null) {
4726 var temp_target_destroy_notify_decl = get_temp_variable (gdestroynotify_type, true, expr, false);
4727 emit_temp_var (temp_target_destroy_notify_decl);
4728 var target_destroy_notify_cvar = get_variable_cexpression (temp_target_destroy_notify_decl.name);
4729 ccode.add_assignment (target_destroy_notify_cvar, target_destroy_notify);
4730 ccode.add_assignment (target_destroy_notify, new CCodeConstant ("NULL"));
4731 set_delegate_target_destroy_notify (expr, target_destroy_notify_cvar);
4736 public override void visit_binary_expression (BinaryExpression expr) {
4737 var cleft = get_cvalue (expr.left);
4738 var cright = get_cvalue (expr.right);
4740 CCodeExpression? left_chain = null;
4741 if (expr.chained) {
4742 var lbe = (BinaryExpression) expr.left;
4744 var temp_decl = get_temp_variable (lbe.right.value_type, true, null, false);
4745 emit_temp_var (temp_decl);
4746 var cvar = get_variable_cexpression (temp_decl.name);
4747 var ccomma = new CCodeCommaExpression ();
4748 var clbe = (CCodeBinaryExpression) get_cvalue (lbe);
4749 if (lbe.chained) {
4750 clbe = (CCodeBinaryExpression) clbe.right;
4752 ccomma.append_expression (new CCodeAssignment (cvar, get_cvalue (lbe.right)));
4753 clbe.right = get_variable_cexpression (temp_decl.name);
4754 ccomma.append_expression (cleft);
4755 cleft = cvar;
4756 left_chain = ccomma;
4759 CCodeBinaryOperator op;
4760 if (expr.operator == BinaryOperator.PLUS) {
4761 op = CCodeBinaryOperator.PLUS;
4762 } else if (expr.operator == BinaryOperator.MINUS) {
4763 op = CCodeBinaryOperator.MINUS;
4764 } else if (expr.operator == BinaryOperator.MUL) {
4765 op = CCodeBinaryOperator.MUL;
4766 } else if (expr.operator == BinaryOperator.DIV) {
4767 op = CCodeBinaryOperator.DIV;
4768 } else if (expr.operator == BinaryOperator.MOD) {
4769 if (expr.value_type.equals (double_type)) {
4770 cfile.add_include ("math.h");
4771 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
4772 ccall.add_argument (cleft);
4773 ccall.add_argument (cright);
4774 set_cvalue (expr, ccall);
4775 return;
4776 } else if (expr.value_type.equals (float_type)) {
4777 cfile.add_include ("math.h");
4778 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
4779 ccall.add_argument (cleft);
4780 ccall.add_argument (cright);
4781 set_cvalue (expr, ccall);
4782 return;
4783 } else {
4784 op = CCodeBinaryOperator.MOD;
4786 } else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
4787 op = CCodeBinaryOperator.SHIFT_LEFT;
4788 } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
4789 op = CCodeBinaryOperator.SHIFT_RIGHT;
4790 } else if (expr.operator == BinaryOperator.LESS_THAN) {
4791 op = CCodeBinaryOperator.LESS_THAN;
4792 } else if (expr.operator == BinaryOperator.GREATER_THAN) {
4793 op = CCodeBinaryOperator.GREATER_THAN;
4794 } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
4795 op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
4796 } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
4797 op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
4798 } else if (expr.operator == BinaryOperator.EQUALITY) {
4799 op = CCodeBinaryOperator.EQUALITY;
4800 } else if (expr.operator == BinaryOperator.INEQUALITY) {
4801 op = CCodeBinaryOperator.INEQUALITY;
4802 } else if (expr.operator == BinaryOperator.BITWISE_AND) {
4803 op = CCodeBinaryOperator.BITWISE_AND;
4804 } else if (expr.operator == BinaryOperator.BITWISE_OR) {
4805 op = CCodeBinaryOperator.BITWISE_OR;
4806 } else if (expr.operator == BinaryOperator.BITWISE_XOR) {
4807 op = CCodeBinaryOperator.BITWISE_XOR;
4808 } else if (expr.operator == BinaryOperator.AND) {
4809 op = CCodeBinaryOperator.AND;
4810 } else if (expr.operator == BinaryOperator.OR) {
4811 op = CCodeBinaryOperator.OR;
4812 } else if (expr.operator == BinaryOperator.IN) {
4813 if (expr.right.value_type is ArrayType) {
4814 var array_type = (ArrayType) expr.right.value_type;
4815 var node = new CCodeFunctionCall (new CCodeIdentifier (generate_array_contains_wrapper (array_type)));
4816 node.add_argument (cright);
4817 node.add_argument (get_array_length_cexpression (expr.right));
4818 if (array_type.element_type is StructValueType) {
4819 node.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft));
4820 } else {
4821 node.add_argument (cleft);
4823 set_cvalue (expr, node);
4824 } else {
4825 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft));
4827 return;
4828 } else {
4829 assert_not_reached ();
4832 if (expr.operator == BinaryOperator.EQUALITY ||
4833 expr.operator == BinaryOperator.INEQUALITY) {
4834 var left_type = expr.left.target_type;
4835 var right_type = expr.right.target_type;
4836 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
4838 if (left_type is StructValueType && right_type is StructValueType) {
4839 var equalfunc = generate_struct_equal_function ((Struct) left_type.data_type as Struct);
4840 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
4841 ccall.add_argument (cleft);
4842 ccall.add_argument (cright);
4843 cleft = ccall;
4844 cright = new CCodeConstant ("TRUE");
4845 } else if ((left_type is IntegerType || left_type is FloatingType || left_type is BooleanType) && left_type.nullable &&
4846 (right_type is IntegerType || right_type is FloatingType || right_type is BooleanType) && right_type.nullable) {
4847 var equalfunc = generate_numeric_equal_function ((Struct) left_type.data_type as Struct);
4848 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
4849 ccall.add_argument (cleft);
4850 ccall.add_argument (cright);
4851 cleft = ccall;
4852 cright = new CCodeConstant ("TRUE");
4856 if (!(expr.left.value_type is NullType)
4857 && expr.left.value_type.compatible (string_type)
4858 && !(expr.right.value_type is NullType)
4859 && expr.right.value_type.compatible (string_type)) {
4860 if (expr.operator == BinaryOperator.PLUS) {
4861 // string concatenation
4862 if (expr.left.is_constant () && expr.right.is_constant ()) {
4863 string left, right;
4865 if (cleft is CCodeIdentifier) {
4866 left = ((CCodeIdentifier) cleft).name;
4867 } else if (cleft is CCodeConstant) {
4868 left = ((CCodeConstant) cleft).name;
4869 } else {
4870 assert_not_reached ();
4872 if (cright is CCodeIdentifier) {
4873 right = ((CCodeIdentifier) cright).name;
4874 } else if (cright is CCodeConstant) {
4875 right = ((CCodeConstant) cright).name;
4876 } else {
4877 assert_not_reached ();
4880 set_cvalue (expr, new CCodeConstant ("%s %s".printf (left, right)));
4881 return;
4882 } else {
4883 if (context.profile == Profile.POSIX) {
4884 // convert to strcat(strcpy(malloc(1+strlen(a)+strlen(b)),a),b)
4885 var strcat = new CCodeFunctionCall (new CCodeIdentifier ("strcat"));
4886 var strcpy = new CCodeFunctionCall (new CCodeIdentifier ("strcpy"));
4887 var malloc = new CCodeFunctionCall (new CCodeIdentifier ("malloc"));
4889 var strlen_a = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
4890 strlen_a.add_argument(cleft);
4891 var strlen_b = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
4892 strlen_b.add_argument(cright);
4893 var newlength = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier("1"),
4894 new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, strlen_a, strlen_b));
4895 malloc.add_argument(newlength);
4897 strcpy.add_argument(malloc);
4898 strcpy.add_argument(cleft);
4900 strcat.add_argument(strcpy);
4901 strcat.add_argument(cright);
4902 set_cvalue (expr, strcat);
4903 } else {
4904 // convert to g_strconcat (a, b, NULL)
4905 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
4906 ccall.add_argument (cleft);
4907 ccall.add_argument (cright);
4908 ccall.add_argument (new CCodeConstant("NULL"));
4909 set_cvalue (expr, ccall);
4911 return;
4913 } else if (expr.operator == BinaryOperator.EQUALITY
4914 || expr.operator == BinaryOperator.INEQUALITY
4915 || expr.operator == BinaryOperator.LESS_THAN
4916 || expr.operator == BinaryOperator.GREATER_THAN
4917 || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL
4918 || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
4919 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
4920 ccall.add_argument (cleft);
4921 ccall.add_argument (cright);
4922 cleft = ccall;
4923 cright = new CCodeConstant ("0");
4927 set_cvalue (expr, new CCodeBinaryExpression (op, cleft, cright));
4928 if (left_chain != null) {
4929 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.AND, left_chain, get_cvalue (expr)));
4933 public string? get_type_check_function (TypeSymbol type) {
4934 var cl = type as Class;
4935 if (cl != null && cl.type_check_function != null) {
4936 return cl.type_check_function;
4937 } else if ((cl != null && cl.is_compact) || type is Struct || type is Enum || type is Delegate) {
4938 return null;
4939 } else {
4940 return type.get_upper_case_cname ("IS_");
4944 CCodeExpression? create_type_check (CCodeNode ccodenode, DataType type) {
4945 var et = type as ErrorType;
4946 if (et != null && et.error_code != null) {
4947 var matches_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
4948 matches_call.add_argument ((CCodeExpression) ccodenode);
4949 matches_call.add_argument (new CCodeIdentifier (et.error_domain.get_upper_case_cname ()));
4950 matches_call.add_argument (new CCodeIdentifier (et.error_code.get_cname ()));
4951 return matches_call;
4952 } else if (et != null && et.error_domain != null) {
4953 var instance_domain = new CCodeMemberAccess.pointer ((CCodeExpression) ccodenode, "domain");
4954 var type_domain = new CCodeIdentifier (et.error_domain.get_upper_case_cname ());
4955 return new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, instance_domain, type_domain);
4956 } else {
4957 string type_check_func = get_type_check_function (type.data_type);
4958 if (type_check_func == null) {
4959 return new CCodeInvalidExpression ();
4961 var ccheck = new CCodeFunctionCall (new CCodeIdentifier (type_check_func));
4962 ccheck.add_argument ((CCodeExpression) ccodenode);
4963 return ccheck;
4967 string generate_array_contains_wrapper (ArrayType array_type) {
4968 string array_contains_func = "_vala_%s_array_contains".printf (array_type.element_type.get_lower_case_cname ());
4970 if (!add_wrapper (array_contains_func)) {
4971 return array_contains_func;
4974 var function = new CCodeFunction (array_contains_func, "gboolean");
4975 function.modifiers = CCodeModifiers.STATIC;
4977 function.add_parameter (new CCodeParameter ("stack", array_type.get_cname ()));
4978 function.add_parameter (new CCodeParameter ("stack_length", "int"));
4979 if (array_type.element_type is StructValueType) {
4980 function.add_parameter (new CCodeParameter ("needle", array_type.element_type.get_cname () + "*"));
4981 } else {
4982 function.add_parameter (new CCodeParameter ("needle", array_type.element_type.get_cname ()));
4985 push_function (function);
4987 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
4989 var cloop_initializer = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
4990 var cloop_condition = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("stack_length"));
4991 var cloop_iterator = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"));
4992 ccode.open_for (cloop_initializer, cloop_condition, cloop_iterator);
4994 var celement = new CCodeElementAccess (new CCodeIdentifier ("stack"), new CCodeIdentifier ("i"));
4995 var cneedle = new CCodeIdentifier ("needle");
4996 CCodeBinaryExpression cif_condition;
4997 if (array_type.element_type.compatible (string_type)) {
4998 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
4999 ccall.add_argument (celement);
5000 ccall.add_argument (cneedle);
5001 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("0"));
5002 } else if (array_type.element_type is StructValueType) {
5003 var equalfunc = generate_struct_equal_function ((Struct) array_type.element_type.data_type as Struct);
5004 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5005 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, celement));
5006 ccall.add_argument (cneedle);
5007 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("TRUE"));
5008 } else {
5009 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cneedle, celement);
5012 ccode.open_if (cif_condition);
5013 ccode.add_return (new CCodeConstant ("TRUE"));
5014 ccode.close ();
5016 ccode.close ();
5018 ccode.add_return (new CCodeConstant ("FALSE"));
5020 pop_function ();
5022 cfile.add_function_declaration (function);
5023 cfile.add_function (function);
5025 return array_contains_func;
5028 public override void visit_type_check (TypeCheck expr) {
5029 generate_type_declaration (expr.type_reference, cfile);
5031 set_cvalue (expr, create_type_check (get_cvalue (expr.expression), expr.type_reference));
5032 if (get_cvalue (expr) is CCodeInvalidExpression) {
5033 Report.error (expr.source_reference, "type check expressions not supported for compact classes, structs, and enums");
5037 public override void visit_lambda_expression (LambdaExpression lambda) {
5038 // use instance position from delegate
5039 var dt = (DelegateType) lambda.target_type;
5040 lambda.method.cinstance_parameter_position = dt.delegate_symbol.cinstance_parameter_position;
5042 lambda.accept_children (this);
5044 bool expr_owned = lambda.value_type.value_owned;
5046 set_cvalue (lambda, new CCodeIdentifier (lambda.method.get_cname ()));
5048 var delegate_type = (DelegateType) lambda.target_type;
5049 if (lambda.method.closure) {
5050 int block_id = get_block_id (current_closure_block);
5051 var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
5052 if (expr_owned || delegate_type.is_called_once) {
5053 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
5054 ref_call.add_argument (delegate_target);
5055 delegate_target = ref_call;
5056 set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
5057 } else {
5058 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5060 set_delegate_target (lambda, delegate_target);
5061 } else if (get_this_type () != null || in_constructor) {
5062 CCodeExpression delegate_target = get_result_cexpression ("self");
5063 if (expr_owned || delegate_type.is_called_once) {
5064 if (get_this_type () != null) {
5065 var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_this_type (), lambda.source_reference));
5066 ref_call.add_argument (delegate_target);
5067 delegate_target = ref_call;
5068 set_delegate_target_destroy_notify (lambda, get_destroy_func_expression (get_this_type ()));
5069 } else {
5070 // in constructor
5071 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
5072 ref_call.add_argument (delegate_target);
5073 delegate_target = ref_call;
5074 set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("g_object_unref"));
5076 } else {
5077 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5079 set_delegate_target (lambda, delegate_target);
5080 } else {
5081 set_delegate_target (lambda, new CCodeConstant ("NULL"));
5082 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
5086 public CCodeExpression convert_from_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
5087 var result = cexpr;
5088 if (is_reference_type_argument (actual_type) || is_nullable_value_type_argument (actual_type)) {
5089 result = new CCodeCastExpression (cexpr, actual_type.get_cname ());
5090 } else if (is_signed_integer_type_argument (actual_type)) {
5091 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
5092 cconv.add_argument (cexpr);
5093 result = cconv;
5094 } else if (is_unsigned_integer_type_argument (actual_type)) {
5095 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
5096 cconv.add_argument (cexpr);
5097 result = cconv;
5099 return result;
5102 public CCodeExpression convert_to_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
5103 var result = cexpr;
5104 if (is_signed_integer_type_argument (actual_type)) {
5105 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GINT_TO_POINTER"));
5106 cconv.add_argument (cexpr);
5107 result = cconv;
5108 } else if (is_unsigned_integer_type_argument (actual_type)) {
5109 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GUINT_TO_POINTER"));
5110 cconv.add_argument (cexpr);
5111 result = cconv;
5113 return result;
5116 // manage memory and implicit casts
5117 public CCodeExpression transform_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
5118 var cexpr = source_cexpr;
5119 if (expression_type == null) {
5120 return cexpr;
5124 if (expression_type.value_owned
5125 && expression_type.floating_reference) {
5126 /* floating reference, sink it.
5128 var cl = expression_type.data_type as ObjectTypeSymbol;
5129 var sink_func = (cl != null) ? cl.get_ref_sink_function () : null;
5131 if (sink_func != null) {
5132 var csink = new CCodeFunctionCall (new CCodeIdentifier (sink_func));
5133 csink.add_argument (cexpr);
5135 cexpr = csink;
5136 } else {
5137 Report.error (null, "type `%s' does not support floating references".printf (expression_type.data_type.name));
5141 bool boxing = (expression_type is ValueType && !expression_type.nullable
5142 && target_type is ValueType && target_type.nullable);
5143 bool unboxing = (expression_type is ValueType && expression_type.nullable
5144 && target_type is ValueType && !target_type.nullable);
5146 bool gvalue_boxing = (context.profile == Profile.GOBJECT
5147 && target_type != null
5148 && target_type.data_type == gvalue_type
5149 && !(expression_type is NullType)
5150 && expression_type.get_type_id () != "G_TYPE_VALUE");
5151 bool gvariant_boxing = (context.profile == Profile.GOBJECT
5152 && target_type != null
5153 && target_type.data_type == gvariant_type
5154 && !(expression_type is NullType)
5155 && expression_type.data_type != gvariant_type);
5157 if (expression_type.value_owned
5158 && (target_type == null || !target_type.value_owned || boxing || unboxing)
5159 && !gvalue_boxing /* gvalue can assume ownership of value, no need to free it */) {
5160 // value leaked, destroy it
5161 var pointer_type = target_type as PointerType;
5162 if (pointer_type != null && !(pointer_type.base_type is VoidType)) {
5163 // manual memory management for non-void pointers
5164 // treat void* special to not leak memory with void* method parameters
5165 } else if (requires_destroy (expression_type)) {
5166 var decl = get_temp_variable (expression_type, true, expression_type, false);
5167 emit_temp_var (decl);
5168 temp_ref_vars.insert (0, decl);
5169 ccode.add_assignment (get_variable_cexpression (decl.name), cexpr);
5170 cexpr = get_variable_cexpression (decl.name);
5172 if (expression_type is ArrayType && expr != null) {
5173 var array_type = (ArrayType) expression_type;
5174 for (int dim = 1; dim <= array_type.rank; dim++) {
5175 var len_decl = new LocalVariable (int_type.copy (), get_array_length_cname (decl.name, dim));
5176 emit_temp_var (len_decl);
5177 ccode.add_assignment (get_variable_cexpression (len_decl.name), get_array_length_cexpression (expr, dim));
5179 } else if (expression_type is DelegateType && expr != null) {
5180 var target_decl = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (decl.name));
5181 emit_temp_var (target_decl);
5182 var target_destroy_notify_decl = new LocalVariable (gdestroynotify_type, get_delegate_target_destroy_notify_cname (decl.name));
5183 emit_temp_var (target_destroy_notify_decl);
5184 CCodeExpression target_destroy_notify;
5185 ccode.add_assignment (get_variable_cexpression (target_decl.name), get_delegate_target_cexpression (expr, out target_destroy_notify));
5186 ccode.add_assignment (get_variable_cexpression (target_destroy_notify_decl.name), target_destroy_notify);
5192 if (target_type == null) {
5193 // value will be destroyed, no need for implicit casts
5194 return cexpr;
5197 if (gvalue_boxing) {
5198 // implicit conversion to GValue
5199 var decl = get_temp_variable (target_type, true, target_type);
5200 emit_temp_var (decl);
5202 if (!target_type.value_owned) {
5203 // boxed GValue leaked, destroy it
5204 temp_ref_vars.insert (0, decl);
5207 if (target_type.nullable) {
5208 var newcall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
5209 newcall.add_argument (new CCodeConstant ("GValue"));
5210 newcall.add_argument (new CCodeConstant ("1"));
5211 var newassignment = new CCodeAssignment (get_variable_cexpression (decl.name), newcall);
5212 ccode.add_expression (newassignment);
5215 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
5216 if (target_type.nullable) {
5217 ccall.add_argument (get_variable_cexpression (decl.name));
5218 } else {
5219 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (decl.name)));
5221 ccall.add_argument (new CCodeIdentifier (expression_type.get_type_id ()));
5222 ccode.add_expression (ccall);
5224 if (requires_destroy (expression_type)) {
5225 ccall = new CCodeFunctionCall (get_value_taker_function (expression_type));
5226 } else {
5227 ccall = new CCodeFunctionCall (get_value_setter_function (expression_type));
5229 if (target_type.nullable) {
5230 ccall.add_argument (get_variable_cexpression (decl.name));
5231 } else {
5232 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (decl.name)));
5234 if (expression_type.is_real_non_null_struct_type ()) {
5235 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
5236 } else {
5237 ccall.add_argument (cexpr);
5240 ccode.add_expression (ccall);
5242 cexpr = get_variable_cexpression (decl.name);
5244 return cexpr;
5245 } else if (gvariant_boxing) {
5246 // implicit conversion to GVariant
5247 string variant_func = "_variant_new%d".printf (++next_variant_function_id);
5249 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
5250 ccall.add_argument (cexpr);
5252 var cfunc = new CCodeFunction (variant_func, "GVariant*");
5253 cfunc.modifiers = CCodeModifiers.STATIC;
5254 cfunc.add_parameter (new CCodeParameter ("value", expression_type.get_cname ()));
5256 if (expression_type is ArrayType) {
5257 // return array length if appropriate
5258 var array_type = (ArrayType) expression_type;
5260 for (int dim = 1; dim <= array_type.rank; dim++) {
5261 ccall.add_argument (get_array_length_cexpression (expr, dim));
5262 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), "gint"));
5266 push_function (cfunc);
5268 var result = serialize_expression (expression_type, new CCodeIdentifier ("value"));
5270 // sink floating reference
5271 var sink = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_ref_sink"));
5272 sink.add_argument (result);
5273 ccode.add_return (sink);
5275 pop_function ();
5277 cfile.add_function_declaration (cfunc);
5278 cfile.add_function (cfunc);
5280 return ccall;
5281 } else if (boxing) {
5282 // value needs to be boxed
5284 var unary = cexpr as CCodeUnaryExpression;
5285 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
5286 // *expr => expr
5287 cexpr = unary.inner;
5288 } else if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
5289 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5290 } else {
5291 var decl = get_temp_variable (expression_type, expression_type.value_owned, expression_type, false);
5292 emit_temp_var (decl);
5294 var ccomma = new CCodeCommaExpression ();
5295 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (decl.name), cexpr));
5296 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (decl.name)));
5297 cexpr = ccomma;
5299 } else if (unboxing) {
5300 // unbox value
5302 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cexpr);
5303 } else {
5304 cexpr = get_implicit_cast_expression (cexpr, expression_type, target_type, expr);
5307 if (target_type.value_owned && (!expression_type.value_owned || boxing || unboxing)) {
5308 // need to copy value
5309 if (requires_copy (target_type) && !(expression_type is NullType)) {
5310 CodeNode node = expr;
5311 if (node == null) {
5312 node = expression_type;
5315 var decl = get_temp_variable (target_type, true, node, false);
5316 emit_temp_var (decl);
5317 ccode.add_assignment (get_variable_cexpression (decl.name), get_ref_cexpression (target_type, cexpr, expr, node));
5318 cexpr = get_variable_cexpression (decl.name);
5322 return cexpr;
5325 public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
5326 var cexpr = source_cexpr;
5328 if (expression_type.data_type != null && expression_type.data_type == target_type.data_type) {
5329 // same type, no cast required
5330 return cexpr;
5333 if (expression_type is NullType) {
5334 // null literal, no cast required when not converting to generic type pointer
5335 return cexpr;
5338 generate_type_declaration (target_type, cfile);
5340 var cl = target_type.data_type as Class;
5341 var iface = target_type.data_type as Interface;
5342 if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
5343 // checked cast for strict subtypes of GTypeInstance
5344 return generate_instance_cast (cexpr, target_type.data_type);
5345 } else if (target_type.data_type != null && expression_type.get_cname () != target_type.get_cname ()) {
5346 var st = target_type.data_type as Struct;
5347 if (target_type.data_type.is_reference_type () || (st != null && st.is_simple_type ())) {
5348 // don't cast non-simple structs
5349 return new CCodeCastExpression (cexpr, target_type.get_cname ());
5350 } else {
5351 return cexpr;
5353 } else {
5354 return cexpr;
5358 public void store_property (Property prop, Expression? instance, TargetValue value) {
5359 if (instance is BaseAccess) {
5360 if (prop.base_property != null) {
5361 var base_class = (Class) prop.base_property.parent_symbol;
5362 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
5363 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
5365 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
5366 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
5367 ccall.add_argument (get_cvalue_ (value));
5369 ccode.add_expression (ccall);
5370 } else if (prop.base_interface_property != null) {
5371 var base_iface = (Interface) prop.base_interface_property.parent_symbol;
5372 string parent_iface_var = "%s_%s_parent_iface".printf (current_class.get_lower_case_cname (null), base_iface.get_lower_case_cname (null));
5374 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "set_%s".printf (prop.name)));
5375 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
5376 ccall.add_argument (get_cvalue_ (value));
5378 ccode.add_expression (ccall);
5380 return;
5383 var set_func = "g_object_set";
5385 var base_property = prop;
5386 if (!prop.no_accessor_method) {
5387 if (prop.base_property != null) {
5388 base_property = prop.base_property;
5389 } else if (prop.base_interface_property != null) {
5390 base_property = prop.base_interface_property;
5393 if (prop is DynamicProperty) {
5394 set_func = get_dynamic_property_setter_cname ((DynamicProperty) prop);
5395 } else {
5396 generate_property_accessor_declaration (base_property.set_accessor, cfile);
5397 set_func = base_property.set_accessor.get_cname ();
5399 if (!prop.external && prop.external_package) {
5400 // internal VAPI properties
5401 // only add them once per source file
5402 if (add_generated_external_symbol (prop)) {
5403 visit_property (prop);
5409 var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
5411 if (prop.binding == MemberBinding.INSTANCE) {
5412 /* target instance is first argument */
5413 var cinstance = (CCodeExpression) get_ccodenode (instance);
5415 if (prop.parent_symbol is Struct) {
5416 // we need to pass struct instance by reference
5417 var unary = cinstance as CCodeUnaryExpression;
5418 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
5419 // *expr => expr
5420 cinstance = unary.inner;
5421 } else if (cinstance is CCodeIdentifier || cinstance is CCodeMemberAccess) {
5422 cinstance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cinstance);
5423 } else {
5424 // if instance is e.g. a function call, we can't take the address of the expression
5425 // (tmp = expr, &tmp)
5427 var temp_var = get_temp_variable (instance.target_type, true, null, false);
5428 emit_temp_var (temp_var);
5429 ccode.add_assignment (get_variable_cexpression (temp_var.name), cinstance);
5431 cinstance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name));
5435 ccall.add_argument (cinstance);
5438 if (prop.no_accessor_method) {
5439 /* property name is second argument of g_object_set */
5440 ccall.add_argument (prop.get_canonical_cconstant ());
5443 var cexpr = get_cvalue_ (value);
5445 if (prop.property_type.is_real_non_null_struct_type ()) {
5446 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5449 var array_type = prop.property_type as ArrayType;
5451 if (array_type != null && !prop.no_array_length) {
5452 var temp_var = get_temp_variable (prop.property_type, true, null, false);
5453 emit_temp_var (temp_var);
5454 ccode.add_assignment (get_variable_cexpression (temp_var.name), cexpr);
5455 ccall.add_argument (get_variable_cexpression (temp_var.name));
5456 } else {
5457 ccall.add_argument (cexpr);
5460 if (array_type != null && !prop.no_array_length) {
5461 for (int dim = 1; dim <= array_type.rank; dim++) {
5462 ccall.add_argument (get_array_length_cvalue (value, dim));
5464 } else if (prop.property_type is DelegateType) {
5465 var delegate_type = (DelegateType) prop.property_type;
5466 if (delegate_type.delegate_symbol.has_target) {
5467 ccall.add_argument (get_delegate_target_cvalue (value));
5471 if (prop.no_accessor_method) {
5472 ccall.add_argument (new CCodeConstant ("NULL"));
5475 ccode.add_expression (ccall);
5478 /* indicates whether a given Expression eligable for an ADDRESS_OF operator
5479 * from a vala to C point of view all expressions denoting locals, fields and
5480 * parameters are eligable to an ADDRESS_OF operator */
5481 public bool is_address_of_possible (Expression e) {
5482 if (gvalue_type != null && e.target_type.data_type == gvalue_type && e.value_type.data_type != gvalue_type) {
5483 // implicit conversion to GValue is not addressable
5484 return false;
5487 var ma = e as MemberAccess;
5489 if (ma == null) {
5490 return false;
5493 return (ma.symbol_reference is Variable);
5496 /* retrieve the correct address_of expression for a give expression, creates temporary variables
5497 * where necessary, ce is the corresponding ccode expression for e */
5498 public CCodeExpression get_address_of_expression (Expression e, CCodeExpression ce) {
5499 // is address of trivially possible?
5500 if (is_address_of_possible (e)) {
5501 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ce);
5504 var ccomma = new CCodeCommaExpression ();
5505 DataType address_of_type;
5506 if (gvalue_type != null && e.target_type != null && e.target_type.data_type == gvalue_type) {
5507 // implicit conversion to GValue
5508 address_of_type = e.target_type;
5509 } else {
5510 address_of_type = e.value_type;
5512 var temp_decl = get_temp_variable (address_of_type, true, null, false);
5513 var ctemp = get_variable_cexpression (temp_decl.name);
5514 emit_temp_var (temp_decl);
5515 ccomma.append_expression (new CCodeAssignment (ctemp, ce));
5516 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
5517 return ccomma;
5520 public bool add_wrapper (string wrapper_name) {
5521 return wrappers.add (wrapper_name);
5524 public bool add_generated_external_symbol (Symbol external_symbol) {
5525 return generated_external_symbols.add (external_symbol);
5528 public static DataType get_data_type_for_symbol (TypeSymbol sym) {
5529 DataType type = null;
5531 if (sym is Class) {
5532 type = new ObjectType ((Class) sym);
5533 } else if (sym is Interface) {
5534 type = new ObjectType ((Interface) sym);
5535 } else if (sym is Struct) {
5536 var st = (Struct) sym;
5537 if (st.is_boolean_type ()) {
5538 type = new BooleanType (st);
5539 } else if (st.is_integer_type ()) {
5540 type = new IntegerType (st);
5541 } else if (st.is_floating_type ()) {
5542 type = new FloatingType (st);
5543 } else {
5544 type = new StructValueType (st);
5546 } else if (sym is Enum) {
5547 type = new EnumValueType ((Enum) sym);
5548 } else if (sym is ErrorDomain) {
5549 type = new ErrorType ((ErrorDomain) sym, null);
5550 } else if (sym is ErrorCode) {
5551 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
5552 } else {
5553 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
5554 return new InvalidType ();
5557 return type;
5560 public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) {
5561 var st = type.data_type as Struct;
5562 var array_type = type as ArrayType;
5563 if (initializer_expression && !type.nullable &&
5564 ((st != null && !st.is_simple_type ()) ||
5565 (array_type != null && array_type.fixed_length))) {
5566 // 0-initialize struct with struct initializer { 0 }
5567 // only allowed as initializer expression in C
5568 var clist = new CCodeInitializerList ();
5569 clist.append (new CCodeConstant ("0"));
5570 return clist;
5571 } else if ((type.data_type != null && type.data_type.is_reference_type ())
5572 || type.nullable
5573 || type is PointerType || type is DelegateType
5574 || (array_type != null && !array_type.fixed_length)) {
5575 return new CCodeConstant ("NULL");
5576 } else if (type.data_type != null && type.data_type.get_default_value () != null) {
5577 return new CCodeConstant (type.data_type.get_default_value ());
5578 } else if (type.type_parameter != null) {
5579 return new CCodeConstant ("NULL");
5580 } else if (type is ErrorType) {
5581 return new CCodeConstant ("NULL");
5583 return null;
5586 private void create_property_type_check_statement (Property prop, bool check_return_type, TypeSymbol t, bool non_null, string var_name) {
5587 if (check_return_type) {
5588 create_type_check_statement (prop, prop.property_type, t, non_null, var_name);
5589 } else {
5590 create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
5594 public void create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
5595 var ccheck = new CCodeFunctionCall ();
5597 if (!context.assert) {
5598 return;
5599 } else if (context.checking && ((t is Class && !((Class) t).is_compact) || t is Interface)) {
5600 var ctype_check = new CCodeFunctionCall (new CCodeIdentifier (get_type_check_function (t)));
5601 ctype_check.add_argument (new CCodeIdentifier (var_name));
5603 CCodeExpression cexpr = ctype_check;
5604 if (!non_null) {
5605 var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
5607 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cnull, ctype_check);
5609 ccheck.add_argument (cexpr);
5610 } else if (!non_null) {
5611 return;
5612 } else if (t == glist_type || t == gslist_type) {
5613 // NULL is empty list
5614 return;
5615 } else {
5616 var cnonnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
5617 ccheck.add_argument (cnonnull);
5620 var cm = method_node as CreationMethod;
5621 if (cm != null && cm.parent_symbol is ObjectTypeSymbol) {
5622 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
5623 ccheck.add_argument (new CCodeConstant ("NULL"));
5624 } else if (ret_type is VoidType) {
5625 /* void function */
5626 ccheck.call = new CCodeIdentifier ("g_return_if_fail");
5627 } else {
5628 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
5630 var cdefault = default_value_for_type (ret_type, false);
5631 if (cdefault != null) {
5632 ccheck.add_argument (cdefault);
5633 } else {
5634 return;
5638 ccode.add_expression (ccheck);
5641 public int get_param_pos (double param_pos, bool ellipsis = false) {
5642 if (!ellipsis) {
5643 if (param_pos >= 0) {
5644 return (int) (param_pos * 1000);
5645 } else {
5646 return (int) ((100 + param_pos) * 1000);
5648 } else {
5649 if (param_pos >= 0) {
5650 return (int) ((100 + param_pos) * 1000);
5651 } else {
5652 return (int) ((200 + param_pos) * 1000);
5657 public CCodeExpression? get_ccodenode (Expression node) {
5658 if (get_cvalue (node) == null) {
5659 node.emit (this);
5661 return get_cvalue (node);
5664 public override void visit_class (Class cl) {
5667 public void create_postcondition_statement (Expression postcondition) {
5668 var cassert = new CCodeFunctionCall (new CCodeIdentifier ("g_warn_if_fail"));
5670 postcondition.emit (this);
5672 cassert.add_argument (get_cvalue (postcondition));
5674 ccode.add_expression (cassert);
5677 public virtual bool is_gobject_property (Property prop) {
5678 return false;
5681 public DataType? get_this_type () {
5682 if (current_method != null && current_method.binding == MemberBinding.INSTANCE) {
5683 return current_method.this_parameter.variable_type;
5684 } else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) {
5685 return current_property_accessor.prop.this_parameter.variable_type;
5687 return null;
5690 public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
5691 var result = new CCodeFunctionCall (new CCodeIdentifier (type.get_upper_case_cname (null)));
5692 result.add_argument (expr);
5693 return result;
5696 void generate_struct_destroy_function (Struct st) {
5697 if (cfile.add_declaration (st.get_destroy_function ())) {
5698 // only generate function once per source file
5699 return;
5702 var function = new CCodeFunction (st.get_destroy_function (), "void");
5703 function.modifiers = CCodeModifiers.STATIC;
5704 function.add_parameter (new CCodeParameter ("self", st.get_cname () + "*"));
5706 push_function (function);
5708 foreach (Field f in st.get_fields ()) {
5709 if (f.binding == MemberBinding.INSTANCE) {
5710 if (requires_destroy (f.variable_type)) {
5711 var lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
5713 var this_access = new MemberAccess.simple ("this");
5714 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
5715 set_cvalue (this_access, new CCodeIdentifier ("(*self)"));
5717 var ma = new MemberAccess (this_access, f.name);
5718 ma.symbol_reference = f;
5719 ma.value_type = f.variable_type.copy ();
5720 visit_member_access (ma);
5721 ccode.add_expression (get_unref_expression (lhs, f.variable_type, ma));
5726 pop_function ();
5728 cfile.add_function_declaration (function);
5729 cfile.add_function (function);
5732 void generate_struct_copy_function (Struct st) {
5733 if (cfile.add_declaration (st.get_copy_function ())) {
5734 // only generate function once per source file
5735 return;
5738 var function = new CCodeFunction (st.get_copy_function (), "void");
5739 function.modifiers = CCodeModifiers.STATIC;
5740 function.add_parameter (new CCodeParameter ("self", "const " + st.get_cname () + "*"));
5741 function.add_parameter (new CCodeParameter ("dest", st.get_cname () + "*"));
5743 push_context (new EmitContext ());
5744 push_function (function);
5746 foreach (Field f in st.get_fields ()) {
5747 if (f.binding == MemberBinding.INSTANCE) {
5748 CCodeExpression copy = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.name);
5749 if (requires_copy (f.variable_type)) {
5750 var this_access = new MemberAccess.simple ("this");
5751 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
5752 set_cvalue (this_access, new CCodeIdentifier ("(*self)"));
5753 var ma = new MemberAccess (this_access, f.name);
5754 ma.symbol_reference = f;
5755 ma.value_type = f.variable_type.copy ();
5756 visit_member_access (ma);
5757 copy = get_ref_cexpression (f.variable_type, copy, ma, f);
5759 var dest = new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest"), f.name);
5761 var array_type = f.variable_type as ArrayType;
5762 if (array_type != null && array_type.fixed_length) {
5763 // fixed-length (stack-allocated) arrays
5764 cfile.add_include ("string.h");
5766 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5767 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
5768 var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
5770 var array_copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
5771 array_copy_call.add_argument (dest);
5772 array_copy_call.add_argument (copy);
5773 array_copy_call.add_argument (size);
5774 ccode.add_expression (array_copy_call);
5775 } else {
5776 ccode.add_assignment (dest, copy);
5778 if (array_type != null && !f.no_array_length) {
5779 for (int dim = 1; dim <= array_type.rank; dim++) {
5780 var len_src = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_array_length_cname (f.name, dim));
5781 var len_dest = new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest"), get_array_length_cname (f.name, dim));
5782 ccode.add_assignment (len_dest, len_src);
5789 pop_function ();
5790 pop_context ();
5792 cfile.add_function_declaration (function);
5793 cfile.add_function (function);
5796 public void return_default_value (DataType return_type) {
5797 ccode.add_return (default_value_for_type (return_type, false));
5800 public virtual string? get_custom_creturn_type (Method m) {
5801 return null;
5804 public virtual void generate_dynamic_method_wrapper (DynamicMethod method) {
5807 public virtual bool method_has_wrapper (Method method) {
5808 return false;
5811 public virtual CCodeFunctionCall get_param_spec (Property prop) {
5812 return new CCodeFunctionCall (new CCodeIdentifier (""));
5815 public virtual CCodeFunctionCall get_signal_creation (Signal sig, TypeSymbol type) {
5816 return new CCodeFunctionCall (new CCodeIdentifier (""));
5819 public virtual void register_dbus_info (CCodeBlock block, ObjectTypeSymbol bindable) {
5822 public virtual string get_dynamic_property_getter_cname (DynamicProperty node) {
5823 Report.error (node.source_reference, "dynamic properties are not supported for %s".printf (node.dynamic_type.to_string ()));
5824 return "";
5827 public virtual string get_dynamic_property_setter_cname (DynamicProperty node) {
5828 Report.error (node.source_reference, "dynamic properties are not supported for %s".printf (node.dynamic_type.to_string ()));
5829 return "";
5832 public virtual string get_dynamic_signal_cname (DynamicSignal node) {
5833 return "";
5836 public virtual string get_dynamic_signal_connect_wrapper_name (DynamicSignal node) {
5837 return "";
5840 public virtual string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal node) {
5841 return "";
5844 public virtual string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node) {
5845 return "";
5848 public virtual void generate_marshaller (List<Parameter> params, DataType return_type, bool dbus = false) {
5851 public virtual string get_marshaller_function (List<Parameter> params, DataType return_type, string? prefix = null, bool dbus = false) {
5852 return "";
5855 public virtual string get_array_length_cname (string array_cname, int dim) {
5856 return "";
5859 public virtual string get_parameter_array_length_cname (Parameter param, int dim) {
5860 return "";
5863 public virtual CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
5864 return new CCodeConstant ("");
5867 public virtual CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
5868 return new CCodeInvalidExpression ();
5871 public virtual string get_array_size_cname (string array_cname) {
5872 return "";
5875 public virtual void add_simple_check (CodeNode node, bool always_fails = false) {
5878 public virtual string generate_ready_function (Method m) {
5879 return "";
5882 public CCodeExpression? get_cvalue (Expression expr) {
5883 if (expr.target_value == null) {
5884 return null;
5886 var glib_value = (GLibValue) expr.target_value;
5887 return glib_value.cvalue;
5890 public CCodeExpression? get_cvalue_ (TargetValue value) {
5891 var glib_value = (GLibValue) value;
5892 return glib_value.cvalue;
5895 public void set_cvalue (Expression expr, CCodeExpression? cvalue) {
5896 var glib_value = (GLibValue) expr.target_value;
5897 if (glib_value == null) {
5898 glib_value = new GLibValue (expr.value_type);
5899 expr.target_value = glib_value;
5901 glib_value.cvalue = cvalue;
5904 public CCodeExpression? get_array_size_cvalue (TargetValue value) {
5905 var glib_value = (GLibValue) value;
5906 return glib_value.array_size_cvalue;
5909 public void set_array_size_cvalue (TargetValue value, CCodeExpression? cvalue) {
5910 var glib_value = (GLibValue) value;
5911 glib_value.array_size_cvalue = cvalue;
5914 public CCodeExpression? get_delegate_target (Expression expr) {
5915 if (expr.target_value == null) {
5916 return null;
5918 var glib_value = (GLibValue) expr.target_value;
5919 return glib_value.delegate_target_cvalue;
5922 public void set_delegate_target (Expression expr, CCodeExpression? delegate_target) {
5923 var glib_value = (GLibValue) expr.target_value;
5924 if (glib_value == null) {
5925 glib_value = new GLibValue (expr.value_type);
5926 expr.target_value = glib_value;
5928 glib_value.delegate_target_cvalue = delegate_target;
5931 public CCodeExpression? get_delegate_target_destroy_notify (Expression expr) {
5932 if (expr.target_value == null) {
5933 return null;
5935 var glib_value = (GLibValue) expr.target_value;
5936 return glib_value.delegate_target_destroy_notify_cvalue;
5939 public void set_delegate_target_destroy_notify (Expression expr, CCodeExpression? destroy_notify) {
5940 var glib_value = (GLibValue) expr.target_value;
5941 if (glib_value == null) {
5942 glib_value = new GLibValue (expr.value_type);
5943 expr.target_value = glib_value;
5945 glib_value.delegate_target_destroy_notify_cvalue = destroy_notify;
5948 public void append_array_size (Expression expr, CCodeExpression size) {
5949 var glib_value = (GLibValue) expr.target_value;
5950 if (glib_value == null) {
5951 glib_value = new GLibValue (expr.value_type);
5952 expr.target_value = glib_value;
5954 glib_value.append_array_length_cvalue (size);
5957 public List<CCodeExpression>? get_array_sizes (Expression expr) {
5958 var glib_value = (GLibValue) expr.target_value;
5959 if (glib_value == null) {
5960 glib_value = new GLibValue (expr.value_type);
5961 expr.target_value = glib_value;
5963 return glib_value.array_length_cvalues;
5967 public class Vala.GLibValue : TargetValue {
5968 public CCodeExpression cvalue;
5970 public List<CCodeExpression> array_length_cvalues;
5971 public CCodeExpression? array_size_cvalue;
5973 public CCodeExpression? delegate_target_cvalue;
5974 public CCodeExpression? delegate_target_destroy_notify_cvalue;
5976 public GLibValue (DataType? value_type = null, CCodeExpression? cvalue = null) {
5977 base (value_type);
5978 this.cvalue = cvalue;
5981 public void append_array_length_cvalue (CCodeExpression length_cvalue) {
5982 if (array_length_cvalues == null) {
5983 array_length_cvalues = new ArrayList<CCodeExpression> ();
5985 array_length_cvalues.add (length_cvalue);