Add experimental support for regular expression literals
[vala-lang.git] / codegen / valaccodebasemodule.vala
blobf839654adfb23633f611332ed02843b675720f65
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 internal class Vala.CCodeBaseModule : CCodeModule {
30 public CodeContext context { get; set; }
32 public Symbol root_symbol;
33 public Symbol current_symbol;
34 public TryStatement current_try;
36 public TypeSymbol? current_type_symbol {
37 get {
38 var sym = current_symbol;
39 while (sym != null) {
40 if (sym is TypeSymbol) {
41 return (TypeSymbol) sym;
43 sym = sym.parent_symbol;
45 return null;
49 public Class? current_class {
50 get { return current_type_symbol as Class; }
53 public Method? current_method {
54 get {
55 var sym = current_symbol;
56 while (sym is Block) {
57 sym = sym.parent_symbol;
59 return sym as Method;
63 public PropertyAccessor? current_property_accessor {
64 get {
65 var sym = current_symbol;
66 while (sym is Block) {
67 sym = sym.parent_symbol;
69 return sym as PropertyAccessor;
73 public DataType? current_return_type {
74 get {
75 var m = current_method;
76 if (m != null) {
77 return m.return_type;
80 var acc = current_property_accessor;
81 if (acc != null) {
82 if (acc.readable) {
83 return acc.value_type;
84 } else {
85 return void_type;
89 return null;
93 public Block? current_closure_block {
94 get {
95 return next_closure_block (current_symbol);
99 public unowned Block? next_closure_block (Symbol sym) {
100 unowned Block block = null;
101 while (true) {
102 block = sym as Block;
103 if (!(sym is Block || sym is Method)) {
104 // no closure block
105 break;
107 if (block != null && block.captured) {
108 // closure block found
109 break;
111 sym = sym.parent_symbol;
113 return block;
116 public CCodeDeclarationSpace header_declarations;
117 public CCodeDeclarationSpace internal_header_declarations;
118 public CCodeDeclarationSpace source_declarations;
120 public CCodeFragment source_signal_marshaller_declaration;
121 public CCodeFragment source_type_member_definition;
122 public CCodeFragment class_init_fragment;
123 public CCodeFragment base_init_fragment;
124 public CCodeFragment class_finalize_fragment;
125 public CCodeFragment base_finalize_fragment;
126 public CCodeFragment instance_init_fragment;
127 public CCodeFragment instance_finalize_fragment;
128 public CCodeFragment source_signal_marshaller_definition;
130 public CCodeStruct param_spec_struct;
131 public CCodeStruct closure_struct;
132 public CCodeEnum prop_enum;
133 public CCodeFunction function;
135 // code nodes to be inserted before the current statement
136 // used by async method calls in coroutines
137 public CCodeFragment pre_statement_fragment;
138 // case statements to be inserted for the couroutine state
139 public CCodeSwitchStatement state_switch_statement;
141 /* all temporary variables */
142 public ArrayList<LocalVariable> temp_vars = new ArrayList<LocalVariable> ();
143 /* temporary variables that own their content */
144 public ArrayList<LocalVariable> temp_ref_vars = new ArrayList<LocalVariable> ();
145 /* cache to check whether a certain marshaller has been created yet */
146 public Set<string> user_marshal_set;
147 /* (constant) hash table with all predefined marshallers */
148 public Set<string> predefined_marshal_set;
149 /* (constant) hash table with all reserved identifiers in the generated code */
150 Set<string> reserved_identifiers;
152 public int next_temp_var_id = 0;
153 public int next_regex_id = 0;
154 public bool in_creation_method { get { return current_method is CreationMethod; } }
155 public bool in_constructor = false;
156 public bool in_static_or_class_context = false;
157 public bool current_method_inner_error = false;
158 public int next_coroutine_state = 1;
159 int next_block_id = 0;
160 Map<Block,int> block_map = new HashMap<Block,int> ();
162 public DataType void_type = new VoidType ();
163 public DataType bool_type;
164 public DataType char_type;
165 public DataType uchar_type;
166 public DataType? unichar_type;
167 public DataType short_type;
168 public DataType ushort_type;
169 public DataType int_type;
170 public DataType uint_type;
171 public DataType long_type;
172 public DataType ulong_type;
173 public DataType int8_type;
174 public DataType uint8_type;
175 public DataType int16_type;
176 public DataType uint16_type;
177 public DataType int32_type;
178 public DataType uint32_type;
179 public DataType int64_type;
180 public DataType uint64_type;
181 public DataType string_type;
182 public DataType regex_type;
183 public DataType float_type;
184 public DataType double_type;
185 public TypeSymbol gtype_type;
186 public TypeSymbol gobject_type;
187 public ErrorType gerror_type;
188 public Class glist_type;
189 public Class gslist_type;
190 public Class gvaluearray_type;
191 public TypeSymbol gstringbuilder_type;
192 public TypeSymbol garray_type;
193 public TypeSymbol gbytearray_type;
194 public TypeSymbol gptrarray_type;
195 public TypeSymbol gthreadpool_type;
196 public DataType gquark_type;
197 public DataType genumvalue_type;
198 public Struct gvalue_type;
199 public Struct mutex_type;
200 public TypeSymbol type_module_type;
201 public TypeSymbol dbus_object_type;
203 public bool in_plugin = false;
204 public string module_init_param_name;
206 public bool gvaluecollector_h_needed;
207 public bool requires_array_free;
208 public bool requires_array_move;
209 public bool requires_array_length;
210 public bool requires_strcmp0;
211 public bool dbus_glib_h_needed;
212 public bool dbus_glib_h_needed_in_header;
214 public Set<string> wrappers;
215 Set<Symbol> generated_external_symbols;
217 public Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
219 public CCodeBaseModule (CCodeGenerator codegen, CCodeModule? next) {
220 base (codegen, next);
222 predefined_marshal_set = new HashSet<string> (str_hash, str_equal);
223 predefined_marshal_set.add ("VOID:VOID");
224 predefined_marshal_set.add ("VOID:BOOLEAN");
225 predefined_marshal_set.add ("VOID:CHAR");
226 predefined_marshal_set.add ("VOID:UCHAR");
227 predefined_marshal_set.add ("VOID:INT");
228 predefined_marshal_set.add ("VOID:UINT");
229 predefined_marshal_set.add ("VOID:LONG");
230 predefined_marshal_set.add ("VOID:ULONG");
231 predefined_marshal_set.add ("VOID:ENUM");
232 predefined_marshal_set.add ("VOID:FLAGS");
233 predefined_marshal_set.add ("VOID:FLOAT");
234 predefined_marshal_set.add ("VOID:DOUBLE");
235 predefined_marshal_set.add ("VOID:STRING");
236 predefined_marshal_set.add ("VOID:POINTER");
237 predefined_marshal_set.add ("VOID:OBJECT");
238 predefined_marshal_set.add ("STRING:OBJECT,POINTER");
239 predefined_marshal_set.add ("VOID:UINT,POINTER");
240 predefined_marshal_set.add ("BOOLEAN:FLAGS");
242 reserved_identifiers = new HashSet<string> (str_hash, str_equal);
244 // C99 keywords
245 reserved_identifiers.add ("_Bool");
246 reserved_identifiers.add ("_Complex");
247 reserved_identifiers.add ("_Imaginary");
248 reserved_identifiers.add ("asm");
249 reserved_identifiers.add ("auto");
250 reserved_identifiers.add ("break");
251 reserved_identifiers.add ("case");
252 reserved_identifiers.add ("char");
253 reserved_identifiers.add ("const");
254 reserved_identifiers.add ("continue");
255 reserved_identifiers.add ("default");
256 reserved_identifiers.add ("do");
257 reserved_identifiers.add ("double");
258 reserved_identifiers.add ("else");
259 reserved_identifiers.add ("enum");
260 reserved_identifiers.add ("extern");
261 reserved_identifiers.add ("float");
262 reserved_identifiers.add ("for");
263 reserved_identifiers.add ("goto");
264 reserved_identifiers.add ("if");
265 reserved_identifiers.add ("inline");
266 reserved_identifiers.add ("int");
267 reserved_identifiers.add ("long");
268 reserved_identifiers.add ("register");
269 reserved_identifiers.add ("restrict");
270 reserved_identifiers.add ("return");
271 reserved_identifiers.add ("short");
272 reserved_identifiers.add ("signed");
273 reserved_identifiers.add ("sizeof");
274 reserved_identifiers.add ("static");
275 reserved_identifiers.add ("struct");
276 reserved_identifiers.add ("switch");
277 reserved_identifiers.add ("typedef");
278 reserved_identifiers.add ("union");
279 reserved_identifiers.add ("unsigned");
280 reserved_identifiers.add ("void");
281 reserved_identifiers.add ("volatile");
282 reserved_identifiers.add ("while");
284 // MSVC keywords
285 reserved_identifiers.add ("cdecl");
287 // reserved for Vala/GObject naming conventions
288 reserved_identifiers.add ("error");
289 reserved_identifiers.add ("result");
290 reserved_identifiers.add ("self");
293 public override void emit (CodeContext context) {
294 this.context = context;
296 root_symbol = context.root;
298 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
299 char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
300 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
301 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
302 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
303 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
304 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
305 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
306 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
307 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
308 uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8"));
309 int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16"));
310 uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16"));
311 int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32"));
312 uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32"));
313 int64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int64"));
314 uint64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint64"));
315 float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
316 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
317 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
318 regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
320 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
321 if (unichar_struct != null) {
322 unichar_type = new IntegerType (unichar_struct);
325 if (context.profile == Profile.GOBJECT) {
326 var glib_ns = root_symbol.scope.lookup ("GLib");
328 gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
329 gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
330 gerror_type = new ErrorType (null, null);
331 glist_type = (Class) glib_ns.scope.lookup ("List");
332 gslist_type = (Class) glib_ns.scope.lookup ("SList");
333 gvaluearray_type = (Class) glib_ns.scope.lookup ("ValueArray");
334 gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
335 garray_type = (TypeSymbol) glib_ns.scope.lookup ("Array");
336 gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
337 gptrarray_type = (TypeSymbol) glib_ns.scope.lookup ("PtrArray");
338 gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
340 gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
341 genumvalue_type = new ObjectType ((Class) glib_ns.scope.lookup ("EnumValue"));
342 gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
343 mutex_type = (Struct) glib_ns.scope.lookup ("StaticRecMutex");
345 type_module_type = (TypeSymbol) glib_ns.scope.lookup ("TypeModule");
347 if (context.module_init_method != null) {
348 foreach (FormalParameter parameter in context.module_init_method.get_parameters ()) {
349 if (parameter.parameter_type.data_type == type_module_type) {
350 in_plugin = true;
351 module_init_param_name = parameter.name;
352 break;
357 var dbus_ns = root_symbol.scope.lookup ("DBus");
358 if (dbus_ns != null) {
359 dbus_object_type = (TypeSymbol) dbus_ns.scope.lookup ("Object");
363 header_declarations = new CCodeDeclarationSpace ();
364 header_declarations.is_header = true;
365 internal_header_declarations = new CCodeDeclarationSpace ();
366 internal_header_declarations.is_header = true;
368 /* we're only interested in non-pkg source files */
369 var source_files = context.get_source_files ();
370 foreach (SourceFile file in source_files) {
371 if (!file.external_package) {
372 file.accept (codegen);
376 // generate symbols file for public API
377 if (context.symbols_filename != null) {
378 var stream = FileStream.open (context.symbols_filename, "w");
379 if (stream == null) {
380 Report.error (null, "unable to open `%s' for writing".printf (context.symbols_filename));
381 return;
384 foreach (CCodeNode node in header_declarations.type_member_declaration.get_children ()) {
385 if (node is CCodeFunction) {
386 var func = (CCodeFunction) node;
387 stream.puts (func.name);
388 stream.putc ('\n');
392 stream = null;
395 // generate C header file for public API
396 if (context.header_filename != null) {
397 var writer = new CCodeWriter (context.header_filename);
398 if (!writer.open (context.version_header)) {
399 Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
400 return;
402 writer.write_newline ();
404 var once = new CCodeOnceSection (get_define_for_filename (writer.filename));
405 once.append (new CCodeNewline ());
406 once.append (header_declarations.include_directives);
407 once.append (new CCodeNewline ());
409 if (context.profile == Profile.GOBJECT) {
410 once.append (new CCodeIdentifier ("G_BEGIN_DECLS"));
411 once.append (new CCodeNewline ());
414 once.append (new CCodeNewline ());
415 once.append (header_declarations.type_declaration);
416 once.append (new CCodeNewline ());
417 once.append (header_declarations.type_definition);
418 once.append (new CCodeNewline ());
419 once.append (header_declarations.type_member_declaration);
420 once.append (new CCodeNewline ());
421 once.append (header_declarations.constant_declaration);
422 once.append (new CCodeNewline ());
424 if (context.profile == Profile.GOBJECT) {
425 once.append (new CCodeIdentifier ("G_END_DECLS"));
426 once.append (new CCodeNewline ());
429 once.append (new CCodeNewline ());
430 once.write (writer);
431 writer.close ();
434 // generate C header file for internal API
435 if (context.internal_header_filename != null) {
436 var writer = new CCodeWriter (context.internal_header_filename);
437 if (!writer.open (context.version_header)) {
438 Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
439 return;
441 writer.write_newline ();
443 var once = new CCodeOnceSection (get_define_for_filename (writer.filename));
444 once.append (new CCodeNewline ());
445 once.append (internal_header_declarations.include_directives);
446 once.append (new CCodeNewline ());
448 if (context.profile == Profile.GOBJECT) {
449 once.append (new CCodeIdentifier ("G_BEGIN_DECLS"));
450 once.append (new CCodeNewline ());
453 once.append (new CCodeNewline ());
454 once.append (internal_header_declarations.type_declaration);
455 once.append (new CCodeNewline ());
456 once.append (internal_header_declarations.type_definition);
457 once.append (new CCodeNewline ());
458 once.append (internal_header_declarations.type_member_declaration);
459 once.append (new CCodeNewline ());
460 once.append (internal_header_declarations.constant_declaration);
461 once.append (new CCodeNewline ());
463 if (context.profile == Profile.GOBJECT) {
464 once.append (new CCodeIdentifier ("G_END_DECLS"));
465 once.append (new CCodeNewline ());
468 once.append (new CCodeNewline ());
469 once.write (writer);
470 writer.close ();
474 public override CCodeIdentifier get_value_setter_function (DataType type_reference) {
475 var array_type = type_reference as ArrayType;
476 if (type_reference.data_type != null) {
477 return new CCodeIdentifier (type_reference.data_type.get_set_value_function ());
478 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
479 // G_TYPE_STRV
480 return new CCodeIdentifier ("g_value_set_boxed");
481 } else {
482 return new CCodeIdentifier ("g_value_set_pointer");
486 public override CCodeIdentifier get_value_taker_function (DataType type_reference) {
487 var array_type = type_reference as ArrayType;
488 if (type_reference.data_type != null) {
489 return new CCodeIdentifier (type_reference.data_type.get_take_value_function ());
490 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
491 // G_TYPE_STRV
492 return new CCodeIdentifier ("g_value_take_boxed");
493 } else {
494 return new CCodeIdentifier ("g_value_set_pointer");
498 CCodeIdentifier get_value_getter_function (DataType type_reference) {
499 var array_type = type_reference as ArrayType;
500 if (type_reference.data_type != null) {
501 return new CCodeIdentifier (type_reference.data_type.get_get_value_function ());
502 } else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
503 // G_TYPE_STRV
504 return new CCodeIdentifier ("g_value_get_boxed");
505 } else {
506 return new CCodeIdentifier ("g_value_get_pointer");
510 public virtual void append_vala_array_free () {
513 public virtual void append_vala_array_move () {
516 public virtual void append_vala_array_length () {
519 private void append_vala_strcmp0 () {
520 source_declarations.add_include ("string.h");;
522 var fun = new CCodeFunction ("_vala_strcmp0", "int");
523 fun.modifiers = CCodeModifiers.STATIC;
524 fun.add_parameter (new CCodeFormalParameter ("str1", "const char *"));
525 fun.add_parameter (new CCodeFormalParameter ("str2", "const char *"));
526 source_declarations.add_type_member_declaration (fun.copy ());
528 // (str1 != str2)
529 var cineq = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("str1"), new CCodeIdentifier ("str2"));
531 fun.block = new CCodeBlock ();
533 var cblock = new CCodeBlock ();
534 // if (str1 == NULL)
535 var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("str1"), new CCodeConstant ("NULL")), cblock);
536 // return -(str1 != str2);
537 cblock.add_statement (new CCodeReturnStatement (new CCodeUnaryExpression (CCodeUnaryOperator.MINUS, cineq)));
538 fun.block.add_statement (cif);
540 cblock = new CCodeBlock ();
541 // if (str2 == NULL)
542 cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("str2"), new CCodeConstant ("NULL")), cblock);
543 // return (str1 != str2);
544 cblock.add_statement (new CCodeReturnStatement (cineq));
545 fun.block.add_statement (cif);
547 // strcmp (str1, str2)
548 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
549 ccall.add_argument (new CCodeIdentifier ("str1"));
550 ccall.add_argument (new CCodeIdentifier ("str2"));
551 // return strcmp (str1, str2);
552 fun.block.add_statement (new CCodeReturnStatement (ccall));
554 source_type_member_definition.append (fun);
557 public override void visit_source_file (SourceFile source_file) {
558 source_declarations = new CCodeDeclarationSpace ();
559 source_type_member_definition = new CCodeFragment ();
560 source_signal_marshaller_definition = new CCodeFragment ();
561 source_signal_marshaller_declaration = new CCodeFragment ();
563 user_marshal_set = new HashSet<string> (str_hash, str_equal);
565 next_temp_var_id = 0;
566 variable_name_map.clear ();
568 gvaluecollector_h_needed = false;
569 dbus_glib_h_needed = false;
570 dbus_glib_h_needed_in_header = false;
571 requires_array_free = false;
572 requires_array_move = false;
573 requires_array_length = false;
574 requires_strcmp0 = false;
576 wrappers = new HashSet<string> (str_hash, str_equal);
577 generated_external_symbols = new HashSet<Symbol> ();
579 if (context.profile == Profile.GOBJECT) {
580 header_declarations.add_include ("glib.h");
581 internal_header_declarations.add_include ("glib.h");
582 source_declarations.add_include ("glib.h");
583 source_declarations.add_include ("glib-object.h");
586 source_file.accept_children (codegen);
588 if (context.report.get_errors () > 0) {
589 return;
592 if (requires_array_free) {
593 append_vala_array_free ();
595 if (requires_array_move) {
596 append_vala_array_move ();
598 if (requires_array_length) {
599 append_vala_array_length ();
601 if (requires_strcmp0) {
602 append_vala_strcmp0 ();
605 if (gvaluecollector_h_needed) {
606 source_declarations.add_include ("gobject/gvaluecollector.h");
609 if (dbus_glib_h_needed) {
610 source_declarations.add_include ("dbus/dbus.h");
611 source_declarations.add_include ("dbus/dbus-glib.h");
612 source_declarations.add_include ("dbus/dbus-glib-lowlevel.h");
614 if (dbus_glib_h_needed_in_header || dbus_glib_h_needed) {
615 var dbusvtable = new CCodeStruct ("_DBusObjectVTable");
616 dbusvtable.add_field ("void", "(*register_object) (DBusConnection*, const char*, void*)");
617 source_declarations.add_type_definition (dbusvtable);
619 source_declarations.add_type_declaration (new CCodeTypeDefinition ("struct _DBusObjectVTable", new CCodeVariableDeclarator ("_DBusObjectVTable")));
621 var cfunc = new CCodeFunction ("_vala_dbus_register_object", "void");
622 cfunc.add_parameter (new CCodeFormalParameter ("connection", "DBusConnection*"));
623 cfunc.add_parameter (new CCodeFormalParameter ("path", "const char*"));
624 cfunc.add_parameter (new CCodeFormalParameter ("object", "void*"));
626 cfunc.modifiers |= CCodeModifiers.STATIC;
627 source_declarations.add_type_member_declaration (cfunc.copy ());
629 var block = new CCodeBlock ();
630 cfunc.block = block;
632 var cdecl = new CCodeDeclaration ("const _DBusObjectVTable *");
633 cdecl.add_declarator (new CCodeVariableDeclarator ("vtable"));
634 block.add_statement (cdecl);
636 var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
637 quark.add_argument (new CCodeConstant ("\"DBusObjectVTable\""));
639 var get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
640 get_qdata.add_argument (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE (object)"));
641 get_qdata.add_argument (quark);
643 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("vtable"), get_qdata)));
645 var cregister = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("vtable"), "register_object"));
646 cregister.add_argument (new CCodeIdentifier ("connection"));
647 cregister.add_argument (new CCodeIdentifier ("path"));
648 cregister.add_argument (new CCodeIdentifier ("object"));
650 var ifblock = new CCodeBlock ();
651 ifblock.add_statement (new CCodeExpressionStatement (cregister));
653 var elseblock = new CCodeBlock ();
655 var warn = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
656 warn.add_argument (new CCodeConstant ("\"Object does not implement any D-Bus interface\""));
658 elseblock.add_statement (new CCodeExpressionStatement(warn));
660 block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("vtable"), ifblock, elseblock));
662 source_type_member_definition.append (cfunc);
664 // unregister function
665 cfunc = new CCodeFunction ("_vala_dbus_unregister_object", "void");
666 cfunc.add_parameter (new CCodeFormalParameter ("connection", "gpointer"));
667 cfunc.add_parameter (new CCodeFormalParameter ("object", "GObject*"));
669 cfunc.modifiers |= CCodeModifiers.STATIC;
670 source_declarations.add_type_member_declaration (cfunc.copy ());
672 block = new CCodeBlock ();
673 cfunc.block = block;
675 cdecl = new CCodeDeclaration ("char*");
676 cdecl.add_declarator (new CCodeVariableDeclarator ("path"));
677 block.add_statement (cdecl);
679 var path = new CCodeFunctionCall (new CCodeIdentifier ("g_object_steal_data"));
680 path.add_argument (new CCodeCastExpression (new CCodeIdentifier ("object"), "GObject*"));
681 path.add_argument (new CCodeConstant ("\"dbus_object_path\""));
682 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("path"), path)));
684 var unregister_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_unregister_object_path"));
685 unregister_call.add_argument (new CCodeIdentifier ("connection"));
686 unregister_call.add_argument (new CCodeIdentifier ("path"));
687 block.add_statement (new CCodeExpressionStatement (unregister_call));
689 var path_free = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
690 path_free.add_argument (new CCodeIdentifier ("path"));
691 block.add_statement (new CCodeExpressionStatement (path_free));
693 source_type_member_definition.append (cfunc);
696 var writer = new CCodeWriter (source_file.get_csource_filename (), source_file.filename);
697 if (!writer.open (context.version_header)) {
698 Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
699 return;
701 writer.line_directives = context.debug;
703 var comments = source_file.get_comments();
704 if (comments != null) {
705 foreach (Comment comment in comments) {
706 var ccomment = new CCodeComment (comment.content);
707 ccomment.write (writer);
711 writer.write_newline ();
712 source_declarations.include_directives.write (writer);
713 writer.write_newline ();
714 source_declarations.type_declaration.write_combined (writer);
715 writer.write_newline ();
716 source_declarations.type_definition.write_combined (writer);
717 writer.write_newline ();
718 source_declarations.type_member_declaration.write_declaration (writer);
719 writer.write_newline ();
720 source_declarations.type_member_declaration.write (writer);
721 writer.write_newline ();
722 source_declarations.constant_declaration.write_combined (writer);
723 writer.write_newline ();
724 source_signal_marshaller_declaration.write_declaration (writer);
725 source_signal_marshaller_declaration.write (writer);
726 writer.write_newline ();
727 source_type_member_definition.write (writer);
728 writer.write_newline ();
729 source_signal_marshaller_definition.write (writer);
730 writer.write_newline ();
731 writer.close ();
733 source_declarations = null;
734 source_type_member_definition = null;
735 source_signal_marshaller_definition = null;
736 source_signal_marshaller_declaration = null;
739 private static string get_define_for_filename (string filename) {
740 var define = new StringBuilder ("__");
742 var i = filename;
743 while (i.len () > 0) {
744 var c = i.get_char ();
745 if (c.isalnum () && c < 0x80) {
746 define.append_unichar (c.toupper ());
747 } else {
748 define.append_c ('_');
751 i = i.next_char ();
754 define.append ("__");
756 return define.str;
759 public virtual bool generate_enum_declaration (Enum en, CCodeDeclarationSpace decl_space) {
760 if (decl_space.add_symbol_declaration (en, en.get_cname ())) {
761 return false;
764 var cenum = new CCodeEnum (en.get_cname ());
766 foreach (EnumValue ev in en.get_values ()) {
767 if (ev.value == null) {
768 cenum.add_value (new CCodeEnumValue (ev.get_cname ()));
769 } else {
770 ev.value.accept (codegen);
771 cenum.add_value (new CCodeEnumValue (ev.get_cname (), (CCodeExpression) ev.value.ccodenode));
775 decl_space.add_type_definition (cenum);
776 decl_space.add_type_definition (new CCodeNewline ());
778 if (!en.has_type_id) {
779 return true;
782 decl_space.add_type_declaration (new CCodeNewline ());
784 var macro = "(%s_get_type ())".printf (en.get_lower_case_cname (null));
785 decl_space.add_type_declaration (new CCodeMacroReplacement (en.get_type_id (), macro));
787 var fun_name = "%s_get_type".printf (en.get_lower_case_cname (null));
788 var regfun = new CCodeFunction (fun_name, "GType");
790 if (en.access == SymbolAccessibility.PRIVATE) {
791 regfun.modifiers = CCodeModifiers.STATIC;
792 // avoid C warning as this function is not always used
793 regfun.attributes = "G_GNUC_UNUSED";
796 decl_space.add_type_member_declaration (regfun);
798 return true;
801 public override void visit_enum (Enum en) {
802 en.accept_children (codegen);
804 generate_enum_declaration (en, source_declarations);
806 if (!en.is_internal_symbol ()) {
807 generate_enum_declaration (en, header_declarations);
809 if (!en.is_private_symbol ()) {
810 generate_enum_declaration (en, internal_header_declarations);
814 public override void visit_member (Member m) {
815 /* stuff meant for all lockable members */
816 if (m is Lockable && ((Lockable) m).get_lock_used ()) {
817 CCodeExpression l = new CCodeIdentifier ("self");
818 CCodeFragment init_fragment = class_init_fragment;
819 CCodeFragment finalize_fragment = class_finalize_fragment;
821 if (m.is_instance_member ()) {
822 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (m.name));
823 init_fragment = instance_init_fragment;
824 finalize_fragment = instance_finalize_fragment;
825 } else if (m.is_class_member ()) {
826 TypeSymbol parent = (TypeSymbol)m.parent_symbol;
828 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent.get_upper_case_cname ())));
829 get_class_private_call.add_argument (new CCodeIdentifier ("klass"));
830 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (m.name));
831 } else {
832 l = new CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf(m.parent_symbol.get_lower_case_cname (), m.name)));
835 var initf = new CCodeFunctionCall (new CCodeIdentifier (mutex_type.default_construction_method.get_cname ()));
836 initf.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
837 init_fragment.append (new CCodeExpressionStatement (initf));
839 if (finalize_fragment != null) {
840 var fc = new CCodeFunctionCall (new CCodeIdentifier ("g_static_rec_mutex_free"));
841 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
842 finalize_fragment.append (new CCodeExpressionStatement (fc));
847 public void generate_constant_declaration (Constant c, CCodeDeclarationSpace decl_space, bool definition = false) {
848 if (decl_space.add_symbol_declaration (c, c.get_cname ())) {
849 return;
852 c.accept_children (codegen);
854 if (!c.external) {
855 generate_type_declaration (c.type_reference, decl_space);
857 var initializer_list = c.initializer as InitializerList;
858 if (initializer_list != null) {
859 var cdecl = new CCodeDeclaration (c.type_reference.get_const_cname ());
860 var arr = "";
861 if (c.type_reference is ArrayType) {
862 arr = "[%d]".printf (initializer_list.size);
865 var cinitializer = (CCodeExpression) c.initializer.ccodenode;
866 if (!definition) {
867 // never output value in header
868 // special case needed as this method combines declaration and definition
869 cinitializer = null;
872 cdecl.add_declarator (new CCodeVariableDeclarator ("%s%s".printf (c.get_cname (), arr), cinitializer));
873 if (c.is_private_symbol ()) {
874 cdecl.modifiers = CCodeModifiers.STATIC;
875 } else {
876 cdecl.modifiers = CCodeModifiers.EXTERN;
879 decl_space.add_constant_declaration (cdecl);
880 } else {
881 var cdefine = new CCodeMacroReplacement.with_expression (c.get_cname (), (CCodeExpression) c.initializer.ccodenode);
882 decl_space.add_type_member_declaration (cdefine);
887 public override void visit_constant (Constant c) {
888 generate_constant_declaration (c, source_declarations, true);
890 if (!c.is_internal_symbol ()) {
891 generate_constant_declaration (c, header_declarations);
893 if (!c.is_private_symbol ()) {
894 generate_constant_declaration (c, internal_header_declarations);
898 public void generate_field_declaration (Field f, CCodeDeclarationSpace decl_space) {
899 if (decl_space.add_symbol_declaration (f, f.get_cname ())) {
900 return;
903 generate_type_declaration (f.field_type, decl_space);
905 string field_ctype = f.field_type.get_cname ();
906 if (f.is_volatile) {
907 field_ctype = "volatile " + field_ctype;
910 var cdecl = new CCodeDeclaration (field_ctype);
911 cdecl.add_declarator (new CCodeVariableDeclarator (f.get_cname (), null, f.field_type.get_cdeclarator_suffix ()));
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 (f.get_lock_used ()) {
920 // Declare mutex for static member
921 var flock = new CCodeDeclaration (mutex_type.get_cname ());
922 var flock_decl = new CCodeVariableDeclarator (get_symbol_lock_name (f.get_cname ()), new CCodeConstant ("{0}"));
923 flock.add_declarator (flock_decl);
925 if (f.is_private_symbol ()) {
926 flock.modifiers = CCodeModifiers.STATIC;
927 } else {
928 flock.modifiers = CCodeModifiers.EXTERN;
930 decl_space.add_type_member_declaration (flock);
933 if (f.field_type is ArrayType && !f.no_array_length) {
934 var array_type = (ArrayType) f.field_type;
936 if (!array_type.fixed_length) {
937 for (int dim = 1; dim <= array_type.rank; dim++) {
938 var len_type = int_type.copy ();
940 cdecl = new CCodeDeclaration (len_type.get_cname ());
941 cdecl.add_declarator (new CCodeVariableDeclarator (head.get_array_length_cname (f.get_cname (), dim)));
942 if (f.is_private_symbol ()) {
943 cdecl.modifiers = CCodeModifiers.STATIC;
944 } else {
945 cdecl.modifiers = CCodeModifiers.EXTERN;
947 decl_space.add_type_member_declaration (cdecl);
950 } else if (f.field_type is DelegateType) {
951 var delegate_type = (DelegateType) f.field_type;
952 if (delegate_type.delegate_symbol.has_target) {
953 // create field to store delegate target
955 cdecl = new CCodeDeclaration ("gpointer");
956 cdecl.add_declarator (new CCodeVariableDeclarator (get_delegate_target_cname (f.get_cname ())));
957 if (f.is_private_symbol ()) {
958 cdecl.modifiers = CCodeModifiers.STATIC;
959 } else {
960 cdecl.modifiers = CCodeModifiers.EXTERN;
962 decl_space.add_type_member_declaration (cdecl);
964 if (delegate_type.value_owned) {
965 cdecl = new CCodeDeclaration ("GDestroyNotify");
966 cdecl.add_declarator (new CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f.get_cname ())));
967 if (f.is_private_symbol ()) {
968 cdecl.modifiers = CCodeModifiers.STATIC;
969 } else {
970 cdecl.modifiers = CCodeModifiers.EXTERN;
972 decl_space.add_type_member_declaration (cdecl);
978 public override void visit_field (Field f) {
979 check_type (f.field_type);
981 f.accept_children (codegen);
983 var cl = f.parent_symbol as Class;
984 bool is_gtypeinstance = (cl != null && !cl.is_compact);
986 CCodeExpression lhs = null;
988 string field_ctype = f.field_type.get_cname ();
989 if (f.is_volatile) {
990 field_ctype = "volatile " + field_ctype;
993 if (f.binding == MemberBinding.INSTANCE) {
994 if (is_gtypeinstance && f.access == SymbolAccessibility.PRIVATE) {
995 lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ());
996 } else {
997 lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
1000 if (f.initializer != null) {
1001 var rhs = (CCodeExpression) f.initializer.ccodenode;
1003 instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, rhs)));
1005 if (f.field_type is ArrayType && !f.no_array_length &&
1006 f.initializer is ArrayCreationExpression) {
1007 var array_type = (ArrayType) f.field_type;
1008 var this_access = new MemberAccess.simple ("this");
1009 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
1010 this_access.ccodenode = new CCodeIdentifier ("self");
1011 var ma = new MemberAccess (this_access, f.name);
1012 ma.symbol_reference = f;
1014 List<Expression> sizes = ((ArrayCreationExpression) f.initializer).get_sizes ();
1015 for (int dim = 1; dim <= array_type.rank; dim++) {
1016 var array_len_lhs = head.get_array_length_cexpression (ma, dim);
1017 var size = sizes[dim - 1];
1018 instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (array_len_lhs, (CCodeExpression) size.ccodenode)));
1021 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1022 var lhs_array_size = head.get_array_size_cexpression (ma);
1023 var rhs_array_len = head.get_array_length_cexpression (ma, 1);
1024 instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs_array_size, rhs_array_len)));
1028 append_temp_decl (instance_init_fragment, temp_vars);
1030 foreach (LocalVariable local in temp_ref_vars) {
1031 var ma = new MemberAccess.simple (local.name);
1032 ma.symbol_reference = local;
1033 ma.value_type = local.variable_type.copy ();
1034 instance_init_fragment.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
1037 temp_vars.clear ();
1038 temp_ref_vars.clear ();
1041 if (requires_destroy (f.field_type) && instance_finalize_fragment != null) {
1042 var this_access = new MemberAccess.simple ("this");
1043 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
1045 var field_st = f.parent_symbol as Struct;
1046 if (field_st != null && !field_st.is_simple_type ()) {
1047 this_access.ccodenode = new CCodeIdentifier ("(*self)");
1048 } else {
1049 this_access.ccodenode = new CCodeIdentifier ("self");
1052 var ma = new MemberAccess (this_access, f.name);
1053 ma.symbol_reference = f;
1054 ma.value_type = f.field_type.copy ();
1055 instance_finalize_fragment.append (new CCodeExpressionStatement (get_unref_expression (lhs, f.field_type, ma)));
1057 } else if (f.binding == MemberBinding.CLASS) {
1058 if (!is_gtypeinstance) {
1059 Report.error (f.source_reference, "class fields are not supported in compact classes");
1060 f.error = true;
1061 return;
1064 if (f.access == SymbolAccessibility.PRIVATE) {
1065 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (cl.get_upper_case_cname ())));
1066 ccall.add_argument (new CCodeIdentifier ("klass"));
1067 lhs = new CCodeMemberAccess (ccall, f.get_cname (), true);
1068 } else {
1069 lhs = new CCodeMemberAccess (new CCodeIdentifier ("klass"), f.get_cname (), true);
1072 if (f.initializer != null) {
1073 var rhs = (CCodeExpression) f.initializer.ccodenode;
1075 class_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, rhs)));
1077 append_temp_decl (class_init_fragment, temp_vars);
1079 foreach (LocalVariable local in temp_ref_vars) {
1080 var ma = new MemberAccess.simple (local.name);
1081 ma.symbol_reference = local;
1082 ma.value_type = local.variable_type.copy ();
1083 class_init_fragment.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
1086 temp_vars.clear ();
1087 temp_ref_vars.clear ();
1089 } else {
1090 generate_field_declaration (f, source_declarations);
1092 if (!f.is_internal_symbol ()) {
1093 generate_field_declaration (f, header_declarations);
1095 if (!f.is_private_symbol ()) {
1096 generate_field_declaration (f, internal_header_declarations);
1099 lhs = new CCodeIdentifier (f.get_cname ());
1101 var var_decl = new CCodeVariableDeclarator (f.get_cname (), null, f.field_type.get_cdeclarator_suffix ());
1102 var_decl.initializer = default_value_for_type (f.field_type, true);
1104 if (f.initializer != null) {
1105 var init = (CCodeExpression) f.initializer.ccodenode;
1106 if (is_constant_ccode_expression (init)) {
1107 var_decl.initializer = init;
1111 var var_def = new CCodeDeclaration (field_ctype);
1112 var_def.add_declarator (var_decl);
1113 if (!f.is_private_symbol ()) {
1114 var_def.modifiers = CCodeModifiers.EXTERN;
1115 } else {
1116 var_def.modifiers = CCodeModifiers.STATIC;
1118 source_declarations.add_type_member_declaration (var_def);
1120 /* add array length fields where necessary */
1121 if (f.field_type is ArrayType && !f.no_array_length) {
1122 var array_type = (ArrayType) f.field_type;
1124 if (!array_type.fixed_length) {
1125 for (int dim = 1; dim <= array_type.rank; dim++) {
1126 var len_type = int_type.copy ();
1128 var len_def = new CCodeDeclaration (len_type.get_cname ());
1129 len_def.add_declarator (new CCodeVariableDeclarator (head.get_array_length_cname (f.get_cname (), dim), new CCodeConstant ("0")));
1130 if (!f.is_private_symbol ()) {
1131 len_def.modifiers = CCodeModifiers.EXTERN;
1132 } else {
1133 len_def.modifiers = CCodeModifiers.STATIC;
1135 source_declarations.add_type_member_declaration (len_def);
1138 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1139 var len_type = int_type.copy ();
1141 var cdecl = new CCodeDeclaration (len_type.get_cname ());
1142 cdecl.add_declarator (new CCodeVariableDeclarator (head.get_array_size_cname (f.get_cname ()), new CCodeConstant ("0")));
1143 cdecl.modifiers = CCodeModifiers.STATIC;
1144 source_declarations.add_type_member_declaration (cdecl);
1147 } else if (f.field_type is DelegateType) {
1148 var delegate_type = (DelegateType) f.field_type;
1149 if (delegate_type.delegate_symbol.has_target) {
1150 // create field to store delegate target
1152 var target_def = new CCodeDeclaration ("gpointer");
1153 target_def.add_declarator (new CCodeVariableDeclarator (get_delegate_target_cname (f.get_cname ()), new CCodeConstant ("NULL")));
1154 if (!f.is_private_symbol ()) {
1155 target_def.modifiers = CCodeModifiers.EXTERN;
1156 } else {
1157 target_def.modifiers = CCodeModifiers.STATIC;
1159 source_declarations.add_type_member_declaration (target_def);
1161 if (delegate_type.value_owned) {
1162 var target_destroy_notify_def = new CCodeDeclaration ("GDestroyNotify");
1163 target_destroy_notify_def.add_declarator (new CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f.get_cname ()), new CCodeConstant ("NULL")));
1164 if (!f.is_private_symbol ()) {
1165 target_destroy_notify_def.modifiers = CCodeModifiers.EXTERN;
1166 } else {
1167 target_destroy_notify_def.modifiers = CCodeModifiers.STATIC;
1169 source_declarations.add_type_member_declaration (target_destroy_notify_def);
1175 if (f.initializer != null) {
1176 var rhs = (CCodeExpression) f.initializer.ccodenode;
1177 if (!is_constant_ccode_expression (rhs)) {
1178 if (f.parent_symbol is Class) {
1179 if (f.initializer is InitializerList) {
1180 var block = new CCodeBlock ();
1181 var frag = new CCodeFragment ();
1183 var temp_decl = get_temp_variable (f.field_type);
1184 var cdecl = new CCodeDeclaration (temp_decl.variable_type.get_cname ());
1185 var vardecl = new CCodeVariableDeclarator (temp_decl.name, rhs);
1186 cdecl.add_declarator (vardecl);
1187 vardecl.init0 = true;
1188 frag.append (cdecl);
1190 var tmp = get_variable_cexpression (get_variable_cname (temp_decl.name));
1191 frag.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, tmp)));
1193 block.add_statement (frag);
1194 class_init_fragment.append (block);
1195 } else {
1196 class_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, rhs)));
1199 if (f.field_type is ArrayType && !f.no_array_length &&
1200 f.initializer is ArrayCreationExpression) {
1201 var array_type = (ArrayType) f.field_type;
1202 var ma = new MemberAccess.simple (f.name);
1203 ma.symbol_reference = f;
1205 List<Expression> sizes = ((ArrayCreationExpression) f.initializer).get_sizes ();
1206 for (int dim = 1; dim <= array_type.rank; dim++) {
1207 var array_len_lhs = head.get_array_length_cexpression (ma, dim);
1208 var size = sizes[dim - 1];
1209 class_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (array_len_lhs, (CCodeExpression) size.ccodenode)));
1213 append_temp_decl (class_init_fragment, temp_vars);
1214 temp_vars.clear ();
1215 } else {
1216 f.error = true;
1217 Report.error (f.source_reference, "Non-constant field initializers not supported in this context");
1218 return;
1225 public bool is_constant_ccode_expression (CCodeExpression cexpr) {
1226 if (cexpr is CCodeConstant) {
1227 return true;
1228 } else if (cexpr is CCodeCastExpression) {
1229 var ccast = (CCodeCastExpression) cexpr;
1230 return is_constant_ccode_expression (ccast.inner);
1231 } else if (cexpr is CCodeBinaryExpression) {
1232 var cbinary = (CCodeBinaryExpression) cexpr;
1233 return is_constant_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1236 var cparenthesized = (cexpr as CCodeParenthesizedExpression);
1237 return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
1241 * Returns whether the passed cexpr is a pure expression, i.e. an
1242 * expression without side-effects.
1244 public bool is_pure_ccode_expression (CCodeExpression cexpr) {
1245 if (cexpr is CCodeConstant || cexpr is CCodeIdentifier) {
1246 return true;
1247 } else if (cexpr is CCodeBinaryExpression) {
1248 var cbinary = (CCodeBinaryExpression) cexpr;
1249 return is_pure_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1250 } else if (cexpr is CCodeUnaryExpression) {
1251 var cunary = (CCodeUnaryExpression) cexpr;
1252 switch (cunary.operator) {
1253 case CCodeUnaryOperator.PREFIX_INCREMENT:
1254 case CCodeUnaryOperator.PREFIX_DECREMENT:
1255 case CCodeUnaryOperator.POSTFIX_INCREMENT:
1256 case CCodeUnaryOperator.POSTFIX_DECREMENT:
1257 return false;
1258 default:
1259 return is_pure_ccode_expression (cunary.inner);
1261 } else if (cexpr is CCodeMemberAccess) {
1262 var cma = (CCodeMemberAccess) cexpr;
1263 return is_pure_ccode_expression (cma.inner);
1264 } else if (cexpr is CCodeElementAccess) {
1265 var cea = (CCodeElementAccess) cexpr;
1266 return is_pure_ccode_expression (cea.container) && is_pure_ccode_expression (cea.index);
1267 } else if (cexpr is CCodeCastExpression) {
1268 var ccast = (CCodeCastExpression) cexpr;
1269 return is_pure_ccode_expression (ccast.inner);
1270 } else if (cexpr is CCodeParenthesizedExpression) {
1271 var cparenthesized = (CCodeParenthesizedExpression) cexpr;
1272 return is_pure_ccode_expression (cparenthesized.inner);
1275 return false;
1278 public override void visit_formal_parameter (FormalParameter p) {
1279 if (!p.ellipsis) {
1280 check_type (p.parameter_type);
1284 public override void visit_property (Property prop) {
1285 check_type (prop.property_type);
1287 int old_next_temp_var_id = next_temp_var_id;
1288 var old_temp_vars = temp_vars;
1289 var old_temp_ref_vars = temp_ref_vars;
1290 var old_variable_name_map = variable_name_map;
1291 next_temp_var_id = 0;
1292 temp_vars = new ArrayList<LocalVariable> ();
1293 temp_ref_vars = new ArrayList<LocalVariable> ();
1294 variable_name_map = new HashMap<string,string> (str_hash, str_equal);
1296 prop.accept_children (codegen);
1298 next_temp_var_id = old_next_temp_var_id;
1299 temp_vars = old_temp_vars;
1300 temp_ref_vars = old_temp_ref_vars;
1301 variable_name_map = old_variable_name_map;
1304 public void generate_type_declaration (DataType type, CCodeDeclarationSpace decl_space) {
1305 if (type is ObjectType) {
1306 var object_type = (ObjectType) type;
1307 if (object_type.type_symbol is Class) {
1308 generate_class_declaration ((Class) object_type.type_symbol, decl_space);
1309 } else if (object_type.type_symbol is Interface) {
1310 generate_interface_declaration ((Interface) object_type.type_symbol, decl_space);
1312 } else if (type is DelegateType) {
1313 var deleg_type = (DelegateType) type;
1314 var d = deleg_type.delegate_symbol;
1315 generate_delegate_declaration (d, decl_space);
1316 } else if (type.data_type is Enum) {
1317 var en = (Enum) type.data_type;
1318 generate_enum_declaration (en, decl_space);
1319 } else if (type is ValueType) {
1320 var value_type = (ValueType) type;
1321 generate_struct_declaration ((Struct) value_type.type_symbol, decl_space);
1322 } else if (type is ArrayType) {
1323 var array_type = (ArrayType) type;
1324 generate_type_declaration (array_type.element_type, decl_space);
1325 } else if (type is ErrorType) {
1326 var error_type = (ErrorType) type;
1327 if (error_type.error_domain != null) {
1328 generate_error_domain_declaration (error_type.error_domain, decl_space);
1330 } else if (type is PointerType) {
1331 var pointer_type = (PointerType) type;
1332 generate_type_declaration (pointer_type.base_type, decl_space);
1335 foreach (DataType type_arg in type.get_type_arguments ()) {
1336 generate_type_declaration (type_arg, decl_space);
1340 public virtual void generate_class_struct_declaration (Class cl, CCodeDeclarationSpace decl_space) {
1343 public virtual void generate_struct_declaration (Struct st, CCodeDeclarationSpace decl_space) {
1346 public virtual void generate_delegate_declaration (Delegate d, CCodeDeclarationSpace decl_space) {
1349 public virtual void generate_cparameters (Method m, CCodeDeclarationSpace decl_space, Map<int,CCodeFormalParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
1352 public void generate_property_accessor_declaration (PropertyAccessor acc, CCodeDeclarationSpace decl_space) {
1353 if (decl_space.add_symbol_declaration (acc, acc.get_cname ())) {
1354 return;
1357 var prop = (Property) acc.prop;
1359 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1362 CCodeFormalParameter cvalueparam;
1363 if (returns_real_struct) {
1364 cvalueparam = new CCodeFormalParameter ("result", acc.value_type.get_cname () + "*");
1365 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1366 cvalueparam = new CCodeFormalParameter ("value", acc.value_type.get_cname () + "*");
1367 } else {
1368 cvalueparam = new CCodeFormalParameter ("value", acc.value_type.get_cname ());
1370 generate_type_declaration (acc.value_type, decl_space);
1372 if (acc.readable && !returns_real_struct) {
1373 function = new CCodeFunction (acc.get_cname (), acc.value_type.get_cname ());
1374 } else {
1375 function = new CCodeFunction (acc.get_cname (), "void");
1378 if (prop.binding == MemberBinding.INSTANCE) {
1379 var t = (TypeSymbol) prop.parent_symbol;
1380 var this_type = get_data_type_for_symbol (t);
1381 generate_type_declaration (this_type, decl_space);
1382 var cselfparam = new CCodeFormalParameter ("self", this_type.get_cname ());
1383 if (t is Struct) {
1384 cselfparam.type_name += "*";
1387 function.add_parameter (cselfparam);
1390 if (acc.writable || acc.construction || returns_real_struct) {
1391 function.add_parameter (cvalueparam);
1394 if (acc.value_type is ArrayType) {
1395 var array_type = (ArrayType) acc.value_type;
1397 var length_ctype = "int";
1398 if (acc.readable) {
1399 length_ctype = "int*";
1402 for (int dim = 1; dim <= array_type.rank; dim++) {
1403 function.add_parameter (new CCodeFormalParameter (head.get_array_length_cname (acc.readable ? "result" : "value", dim), length_ctype));
1405 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1406 function.add_parameter (new CCodeFormalParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1409 if (prop.is_private_symbol () || (!acc.readable && !acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1410 function.modifiers |= CCodeModifiers.STATIC;
1412 decl_space.add_type_member_declaration (function);
1415 public override void visit_property_accessor (PropertyAccessor acc) {
1416 var old_symbol = current_symbol;
1417 bool old_method_inner_error = current_method_inner_error;
1418 current_symbol = acc;
1419 current_method_inner_error = false;
1421 var prop = (Property) acc.prop;
1423 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1425 acc.accept_children (codegen);
1427 var t = (TypeSymbol) prop.parent_symbol;
1429 if (acc.construction && !t.is_subtype_of (gobject_type)) {
1430 Report.error (acc.source_reference, "construct properties require GLib.Object");
1431 acc.error = true;
1432 return;
1433 } else if (acc.construction && !is_gobject_property (prop)) {
1434 Report.error (acc.source_reference, "construct properties not supported for specified property type");
1435 acc.error = true;
1436 return;
1439 // do not declare overriding properties and interface implementations
1440 if (prop.is_abstract || prop.is_virtual
1441 || (prop.base_property == null && prop.base_interface_property == null)) {
1442 generate_property_accessor_declaration (acc, source_declarations);
1444 // do not declare construct-only properties in header files
1445 if (acc.readable || acc.writable) {
1446 if (!prop.is_internal_symbol ()
1447 && (acc.access == SymbolAccessibility.PUBLIC
1448 || acc.access == SymbolAccessibility.PROTECTED)) {
1449 generate_property_accessor_declaration (acc, header_declarations);
1451 if (!prop.is_private_symbol () && acc.access != SymbolAccessibility.PRIVATE) {
1452 generate_property_accessor_declaration (acc, internal_header_declarations);
1457 var this_type = get_data_type_for_symbol (t);
1458 var cselfparam = new CCodeFormalParameter ("self", this_type.get_cname ());
1459 if (t is Struct) {
1460 cselfparam.type_name += "*";
1462 CCodeFormalParameter cvalueparam;
1463 if (returns_real_struct) {
1464 cvalueparam = new CCodeFormalParameter ("result", acc.value_type.get_cname () + "*");
1465 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1466 cvalueparam = new CCodeFormalParameter ("value", acc.value_type.get_cname () + "*");
1467 } else {
1468 cvalueparam = new CCodeFormalParameter ("value", acc.value_type.get_cname ());
1471 if (prop.is_abstract || prop.is_virtual) {
1472 if (acc.readable && !returns_real_struct) {
1473 function = new CCodeFunction (acc.get_cname (), current_return_type.get_cname ());
1474 } else {
1475 function = new CCodeFunction (acc.get_cname (), "void");
1477 function.add_parameter (cselfparam);
1478 if (acc.writable || acc.construction || returns_real_struct) {
1479 function.add_parameter (cvalueparam);
1482 if (acc.value_type is ArrayType) {
1483 var array_type = (ArrayType) acc.value_type;
1485 var length_ctype = "int";
1486 if (acc.readable) {
1487 length_ctype = "int*";
1490 for (int dim = 1; dim <= array_type.rank; dim++) {
1491 function.add_parameter (new CCodeFormalParameter (head.get_array_length_cname (acc.readable ? "result" : "value", dim), length_ctype));
1493 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1494 function.add_parameter (new CCodeFormalParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1497 if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1498 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1499 function.modifiers |= CCodeModifiers.STATIC;
1502 var block = new CCodeBlock ();
1503 function.block = block;
1505 CCodeFunctionCall vcast = null;
1506 if (prop.parent_symbol is Interface) {
1507 var iface = (Interface) prop.parent_symbol;
1509 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
1510 } else {
1511 var cl = (Class) prop.parent_symbol;
1513 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
1515 vcast.add_argument (new CCodeIdentifier ("self"));
1517 if (acc.readable) {
1518 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
1519 vcall.add_argument (new CCodeIdentifier ("self"));
1520 if (returns_real_struct) {
1521 vcall.add_argument (new CCodeIdentifier ("result"));
1522 block.add_statement (new CCodeExpressionStatement (vcall));
1523 } else {
1524 if (acc.value_type is ArrayType) {
1525 var array_type = (ArrayType) acc.value_type;
1527 for (int dim = 1; dim <= array_type.rank; dim++) {
1528 var len_expr = new CCodeIdentifier (head.get_array_length_cname ("result", dim));
1529 vcall.add_argument (len_expr);
1533 block.add_statement (new CCodeReturnStatement (vcall));
1535 } else {
1536 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
1537 vcall.add_argument (new CCodeIdentifier ("self"));
1538 vcall.add_argument (new CCodeIdentifier ("value"));
1540 if (acc.value_type is ArrayType) {
1541 var array_type = (ArrayType) acc.value_type;
1543 for (int dim = 1; dim <= array_type.rank; dim++) {
1544 var len_expr = new CCodeIdentifier (head.get_array_length_cname ("value", dim));
1545 vcall.add_argument (len_expr);
1549 block.add_statement (new CCodeExpressionStatement (vcall));
1552 source_type_member_definition.append (function);
1555 if (!prop.is_abstract) {
1556 bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
1558 string cname;
1559 if (is_virtual) {
1560 if (acc.readable) {
1561 cname = "%s_real_get_%s".printf (t.get_lower_case_cname (null), prop.name);
1562 } else {
1563 cname = "%s_real_set_%s".printf (t.get_lower_case_cname (null), prop.name);
1565 } else {
1566 cname = acc.get_cname ();
1569 if (acc.writable || acc.construction || returns_real_struct) {
1570 function = new CCodeFunction (cname, "void");
1571 } else {
1572 function = new CCodeFunction (cname, acc.value_type.get_cname ());
1575 ObjectType base_type = null;
1576 if (prop.binding == MemberBinding.INSTANCE) {
1577 if (is_virtual) {
1578 if (prop.base_property != null) {
1579 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
1580 } else if (prop.base_interface_property != null) {
1581 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
1583 function.modifiers |= CCodeModifiers.STATIC;
1584 function.add_parameter (new CCodeFormalParameter ("base", base_type.get_cname ()));
1585 } else {
1586 function.add_parameter (cselfparam);
1589 if (acc.writable || acc.construction || returns_real_struct) {
1590 function.add_parameter (cvalueparam);
1593 if (acc.value_type is ArrayType) {
1594 var array_type = (ArrayType) acc.value_type;
1596 var length_ctype = "int";
1597 if (acc.readable) {
1598 length_ctype = "int*";
1601 for (int dim = 1; dim <= array_type.rank; dim++) {
1602 function.add_parameter (new CCodeFormalParameter (head.get_array_length_cname (acc.readable ? "result" : "value", dim), length_ctype));
1604 } else if ((acc.value_type is DelegateType) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1605 function.add_parameter (new CCodeFormalParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? "gpointer*" : "gpointer"));
1608 if (!is_virtual) {
1609 if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
1610 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1611 function.modifiers |= CCodeModifiers.STATIC;
1615 function.block = (CCodeBlock) acc.body.ccodenode;
1617 if (is_virtual) {
1618 var cdecl = new CCodeDeclaration (this_type.get_cname ());
1619 cdecl.add_declarator (new CCodeVariableDeclarator ("self", transform_expression (new CCodeIdentifier ("base"), base_type, this_type)));
1620 function.block.prepend_statement (cdecl);
1623 if (acc.readable && !returns_real_struct) {
1624 // do not declare result variable if exit block is known to be unreachable
1625 if (acc.exit_block == null || acc.exit_block.get_predecessors ().size > 0) {
1626 var cdecl = new CCodeDeclaration (acc.value_type.get_cname ());
1627 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
1628 function.block.prepend_statement (cdecl);
1632 if (current_method_inner_error) {
1633 var cdecl = new CCodeDeclaration ("GError *");
1634 cdecl.add_declarator (new CCodeVariableDeclarator ("_inner_error_", new CCodeConstant ("NULL")));
1635 function.block.prepend_statement (cdecl);
1638 if (prop.binding == MemberBinding.INSTANCE && !is_virtual) {
1639 CCodeStatement check_stmt;
1640 if (!acc.readable || returns_real_struct) {
1641 check_stmt = create_property_type_check_statement (prop, false, t, true, "self");
1642 } else {
1643 check_stmt = create_property_type_check_statement (prop, true, t, true, "self");
1645 if (check_stmt != null) {
1646 function.block.prepend_statement (check_stmt);
1650 // notify on property changes
1651 if (is_gobject_property (prop) &&
1652 prop.notify &&
1653 (acc.writable || acc.construction)) {
1654 var notify_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_notify"));
1655 notify_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
1656 notify_call.add_argument (prop.get_canonical_cconstant ());
1657 function.block.add_statement (new CCodeExpressionStatement (notify_call));
1660 source_type_member_definition.append (function);
1663 current_symbol = old_symbol;
1664 current_method_inner_error = old_method_inner_error;
1667 public override void visit_destructor (Destructor d) {
1668 bool old_method_inner_error = current_method_inner_error;
1669 current_method_inner_error = false;
1671 d.accept_children (codegen);
1673 if (d.binding == MemberBinding.STATIC && !in_plugin) {
1674 Report.error (d.source_reference, "static destructors are only supported for dynamic types");
1675 d.error = true;
1676 return;
1679 CCodeFragment cfrag = new CCodeFragment ();
1681 if (current_method_inner_error) {
1682 var cdecl = new CCodeDeclaration ("GError *");
1683 cdecl.add_declarator (new CCodeVariableDeclarator ("_inner_error_", new CCodeConstant ("NULL")));
1684 cfrag.append (cdecl);
1687 cfrag.append (d.body.ccodenode);
1689 d.ccodenode = cfrag;
1691 current_method_inner_error = old_method_inner_error;
1694 public int get_block_id (Block b) {
1695 int result = block_map[b];
1696 if (result == 0) {
1697 result = ++next_block_id;
1698 block_map[b] = result;
1700 return result;
1703 void capture_parameter (FormalParameter param, CCodeStruct data, CCodeBlock cblock, int block_id, CCodeBlock free_block) {
1704 var param_type = param.parameter_type.copy ();
1705 param_type.value_owned = true;
1706 data.add_field (param_type.get_cname (), get_variable_cname (param.name));
1708 bool is_unowned_delegate = param.parameter_type is DelegateType && !param.parameter_type.value_owned;
1710 // create copy if necessary as captured variables may need to be kept alive
1711 CCodeExpression cparam = get_variable_cexpression (param.name);
1712 if (requires_copy (param_type) && !param.parameter_type.value_owned && !is_unowned_delegate) {
1713 var ma = new MemberAccess.simple (param.name);
1714 ma.symbol_reference = param;
1715 ma.value_type = param.parameter_type.copy ();
1716 // directly access parameters in ref expressions
1717 param.captured = false;
1718 cparam = get_ref_cexpression (param.parameter_type, cparam, ma, param);
1719 param.captured = true;
1722 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_variable_cname (param.name)), cparam)));
1724 if (param.parameter_type is ArrayType) {
1725 var array_type = (ArrayType) param.parameter_type;
1726 for (int dim = 1; dim <= array_type.rank; dim++) {
1727 data.add_field ("gint", get_array_length_cname (get_variable_cname (param.name), dim));
1728 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (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)))));
1730 } else if (param.parameter_type is DelegateType) {
1731 data.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (param.name)));
1732 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_delegate_target_cname (get_variable_cname (param.name))), new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param.name))))));
1733 if (param.parameter_type.value_owned) {
1734 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
1735 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_delegate_target_destroy_notify_cname (get_variable_cname (param.name))), new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (param.name))))));
1739 if (requires_destroy (param_type) && !is_unowned_delegate) {
1740 bool old_coroutine = false;
1741 if (current_method != null) {
1742 old_coroutine = current_method.coroutine;
1743 current_method.coroutine = false;
1746 var ma = new MemberAccess.simple (param.name);
1747 ma.symbol_reference = param;
1748 ma.value_type = param_type.copy ();
1749 free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), get_variable_cname (param.name)), param.parameter_type, ma)));
1751 if (old_coroutine) {
1752 current_method.coroutine = true;
1757 public override void visit_block (Block b) {
1758 var old_symbol = current_symbol;
1759 current_symbol = b;
1761 b.accept_children (codegen);
1763 var local_vars = b.get_local_variables ();
1764 foreach (LocalVariable local in local_vars) {
1765 local.active = false;
1768 var cblock = new CCodeBlock ();
1770 if (b.captured) {
1771 var parent_block = next_closure_block (b.parent_symbol);
1773 int block_id = get_block_id (b);
1774 string struct_name = "Block%dData".printf (block_id);
1776 var free_block = new CCodeBlock ();
1778 var data = new CCodeStruct ("_" + struct_name);
1779 data.add_field ("int", "_ref_count_");
1780 if (parent_block != null) {
1781 int parent_block_id = get_block_id (parent_block);
1783 data.add_field ("Block%dData *".printf (parent_block_id), "_data%d_".printf (parent_block_id));
1785 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (parent_block_id)));
1786 unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
1787 free_block.add_statement (new CCodeExpressionStatement (unref_call));
1788 } else if (in_constructor || (current_method != null && current_method.binding == MemberBinding.INSTANCE) ||
1789 (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) {
1790 data.add_field ("%s *".printf (current_class.get_cname ()), "self");
1792 var ma = new MemberAccess.simple ("this");
1793 ma.symbol_reference = current_class;
1794 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)));
1796 foreach (var local in local_vars) {
1797 if (local.captured) {
1798 data.add_field (local.variable_type.get_cname (), get_variable_cname (local.name) + local.variable_type.get_cdeclarator_suffix ());
1800 if (local.variable_type is ArrayType) {
1801 var array_type = (ArrayType) local.variable_type;
1802 for (int dim = 1; dim <= array_type.rank; dim++) {
1803 data.add_field ("gint", get_array_length_cname (get_variable_cname (local.name), dim));
1805 data.add_field ("gint", get_array_size_cname (get_variable_cname (local.name)));
1806 } else if (local.variable_type is DelegateType) {
1807 data.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (local.name)));
1808 if (local.variable_type.value_owned) {
1809 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
1813 if (requires_destroy (local.variable_type)) {
1814 bool old_coroutine = false;
1815 if (current_method != null) {
1816 old_coroutine = current_method.coroutine;
1817 current_method.coroutine = false;
1820 var ma = new MemberAccess.simple (local.name);
1821 ma.symbol_reference = local;
1822 ma.value_type = local.variable_type.copy ();
1823 free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), get_variable_cname (local.name)), local.variable_type, ma)));
1825 if (old_coroutine) {
1826 current_method.coroutine = true;
1832 var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name));
1833 source_declarations.add_type_declaration (typedef);
1834 source_declarations.add_type_definition (data);
1836 var data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
1837 data_alloc.add_argument (new CCodeIdentifier (struct_name));
1839 if (current_method != null && current_method.coroutine) {
1840 closure_struct.add_field (struct_name + "*", "_data%d_".printf (block_id));
1841 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression ("_data%d_".printf (block_id)), data_alloc)));
1842 } else {
1843 var data_decl = new CCodeDeclaration (struct_name + "*");
1844 data_decl.add_declarator (new CCodeVariableDeclarator ("_data%d_".printf (block_id), data_alloc));
1845 cblock.add_statement (data_decl);
1848 // initialize ref_count
1849 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_ref_count_"), new CCodeIdentifier ("1"))));
1851 if (parent_block != null) {
1852 int parent_block_id = get_block_id (parent_block);
1854 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (parent_block_id)));
1855 ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id)));
1857 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call)));
1858 } else if (in_constructor || (current_method != null && current_method.binding == MemberBinding.INSTANCE &&
1859 (!(current_method is CreationMethod) || current_method.body != b)) ||
1860 (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) {
1861 var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), b.source_reference));
1862 ref_call.add_argument (get_result_cexpression ("self"));
1864 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), ref_call)));
1867 if (b.parent_symbol is Method) {
1868 var m = (Method) b.parent_symbol;
1870 // parameters are captured with the top-level block of the method
1871 foreach (var param in m.get_parameters ()) {
1872 if (param.captured) {
1873 capture_parameter (param, data, cblock, block_id, free_block);
1877 if (m.coroutine) {
1878 // capture async data to allow invoking callback from inside closure
1879 data.add_field ("gpointer", "_async_data_");
1881 // async method is suspended while waiting for callback,
1882 // so we never need to care about memory management of async data
1883 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_async_data_"), new CCodeIdentifier ("data"))));
1886 var cfrag = new CCodeFragment ();
1887 append_temp_decl (cfrag, temp_vars);
1888 temp_vars.clear ();
1889 cblock.add_statement (cfrag);
1890 } else if (b.parent_symbol is PropertyAccessor) {
1891 var acc = (PropertyAccessor) b.parent_symbol;
1893 if (!acc.readable && acc.value_parameter.captured) {
1894 capture_parameter (acc.value_parameter, data, cblock, block_id, free_block);
1897 var cfrag = new CCodeFragment ();
1898 append_temp_decl (cfrag, temp_vars);
1899 temp_vars.clear ();
1900 cblock.add_statement (cfrag);
1903 var data_free = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
1904 data_free.add_argument (new CCodeIdentifier (struct_name));
1905 data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id)));
1906 free_block.add_statement (new CCodeExpressionStatement (data_free));
1908 // create ref/unref functions
1909 var ref_fun = new CCodeFunction ("block%d_data_ref".printf (block_id), struct_name + "*");
1910 ref_fun.add_parameter (new CCodeFormalParameter ("_data%d_".printf (block_id), struct_name + "*"));
1911 ref_fun.modifiers = CCodeModifiers.STATIC;
1912 source_declarations.add_type_member_declaration (ref_fun.copy ());
1913 ref_fun.block = new CCodeBlock ();
1914 ref_fun.block.add_statement (new CCodeExpressionStatement (new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_INCREMENT, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_"))));
1915 ref_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_data%d_".printf (block_id))));
1916 source_type_member_definition.append (ref_fun);
1918 var unref_fun = new CCodeFunction ("block%d_data_unref".printf (block_id), "void");
1919 unref_fun.add_parameter (new CCodeFormalParameter ("_data%d_".printf (block_id), struct_name + "*"));
1920 unref_fun.modifiers = CCodeModifiers.STATIC;
1921 source_declarations.add_type_member_declaration (unref_fun.copy ());
1922 unref_fun.block = new CCodeBlock ();
1923 var dec = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")), new CCodeConstant ("0"));
1924 unref_fun.block.add_statement (new CCodeIfStatement (dec, free_block));
1925 source_type_member_definition.append (unref_fun);
1928 foreach (CodeNode stmt in b.get_statements ()) {
1929 if (stmt.error || stmt.unreachable) {
1930 continue;
1933 if (stmt.ccodenode is CCodeFragment) {
1934 foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
1935 cblock.add_statement (cstmt);
1937 } else {
1938 cblock.add_statement (stmt.ccodenode);
1942 foreach (LocalVariable local in local_vars) {
1943 if (!local.floating && !local.captured && requires_destroy (local.variable_type)) {
1944 var ma = new MemberAccess.simple (local.name);
1945 ma.symbol_reference = local;
1946 ma.value_type = local.variable_type.copy ();
1947 cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
1951 if (b.parent_symbol is Method) {
1952 var m = (Method) b.parent_symbol;
1953 foreach (FormalParameter param in m.get_parameters ()) {
1954 if (!param.captured && !param.ellipsis && requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
1955 var ma = new MemberAccess.simple (param.name);
1956 ma.symbol_reference = param;
1957 ma.value_type = param.parameter_type.copy ();
1958 cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param.name), param.parameter_type, ma)));
1963 if (b.captured) {
1964 int block_id = get_block_id (b);
1966 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
1967 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
1968 cblock.add_statement (new CCodeExpressionStatement (data_unref));
1971 b.ccodenode = cblock;
1973 current_symbol = old_symbol;
1976 public override void visit_empty_statement (EmptyStatement stmt) {
1977 stmt.ccodenode = new CCodeEmptyStatement ();
1980 public override void visit_declaration_statement (DeclarationStatement stmt) {
1981 stmt.declaration.accept (codegen);
1983 stmt.ccodenode = stmt.declaration.ccodenode;
1985 var local = stmt.declaration as LocalVariable;
1986 if (local != null && local.initializer != null) {
1987 create_temp_decl (stmt, local.initializer.temp_vars);
1990 create_temp_decl (stmt, temp_vars);
1991 temp_vars.clear ();
1994 public CCodeExpression get_variable_cexpression (string name) {
1995 if (current_method != null && current_method.coroutine) {
1996 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_variable_cname (name));
1997 } else {
1998 return new CCodeIdentifier (get_variable_cname (name));
2002 public string get_variable_cname (string name) {
2003 if (name[0] == '.') {
2004 if (name == ".result") {
2005 return "result";
2007 // compiler-internal variable
2008 if (!variable_name_map.contains (name)) {
2009 variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
2010 next_temp_var_id++;
2012 return variable_name_map.get (name);
2013 } else if (reserved_identifiers.contains (name)) {
2014 return "_%s_".printf (name);
2015 } else {
2016 return name;
2020 public CCodeExpression get_result_cexpression (string cname = "result") {
2021 if (current_method != null && current_method.coroutine) {
2022 return new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), cname);
2023 } else {
2024 return new CCodeIdentifier (cname);
2028 bool has_simple_struct_initializer (LocalVariable local) {
2029 var st = local.variable_type.data_type as Struct;
2030 var initializer = local.initializer as ObjectCreationExpression;
2031 if (st != null && (!st.is_simple_type () || st.get_cname () == "va_list") && !local.variable_type.nullable &&
2032 initializer != null && initializer.get_object_initializer ().size == 0) {
2033 return true;
2034 } else {
2035 return false;
2039 public override void visit_local_variable (LocalVariable local) {
2040 check_type (local.variable_type);
2042 local.accept_children (codegen);
2044 generate_type_declaration (local.variable_type, source_declarations);
2046 if (!local.captured) {
2047 if (local.variable_type is ArrayType) {
2048 // create variables to store array dimensions
2049 var array_type = (ArrayType) local.variable_type;
2051 if (!array_type.fixed_length) {
2052 for (int dim = 1; dim <= array_type.rank; dim++) {
2053 var len_var = new LocalVariable (int_type.copy (), head.get_array_length_cname (get_variable_cname (local.name), dim));
2054 temp_vars.insert (0, len_var);
2057 if (array_type.rank == 1) {
2058 var size_var = new LocalVariable (int_type.copy (), head.get_array_size_cname (get_variable_cname (local.name)));
2059 temp_vars.insert (0, size_var);
2062 } else if (local.variable_type is DelegateType) {
2063 var deleg_type = (DelegateType) local.variable_type;
2064 var d = deleg_type.delegate_symbol;
2065 if (d.has_target) {
2066 // create variable to store delegate target
2067 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (get_variable_cname (local.name)));
2068 temp_vars.insert (0, target_var);
2069 if (deleg_type.value_owned) {
2070 var target_destroy_notify_var = new LocalVariable (new DelegateType ((Delegate) context.root.scope.lookup ("GLib").scope.lookup ("DestroyNotify")), get_delegate_target_destroy_notify_cname (get_variable_cname (local.name)));
2071 temp_vars.insert (0, target_destroy_notify_var);
2077 CCodeExpression rhs = null;
2078 if (local.initializer != null && local.initializer.ccodenode != null) {
2079 var ma = new MemberAccess.simple (local.name);
2080 ma.symbol_reference = local;
2081 ma.value_type = local.variable_type.copy ();
2083 rhs = (CCodeExpression) local.initializer.ccodenode;
2085 if (local.variable_type is ArrayType) {
2086 var array_type = (ArrayType) local.variable_type;
2088 if (array_type.fixed_length) {
2089 rhs = null;
2090 } else {
2091 var ccomma = new CCodeCommaExpression ();
2093 var temp_var = get_temp_variable (local.variable_type, true, local, false);
2094 temp_vars.insert (0, temp_var);
2095 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), rhs));
2097 for (int dim = 1; dim <= array_type.rank; dim++) {
2098 var lhs_array_len = head.get_array_length_cexpression (ma, dim);
2099 var rhs_array_len = head.get_array_length_cexpression (local.initializer, dim);
2100 ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
2102 if (array_type.rank == 1 && !local.captured) {
2103 var lhs_array_size = head.get_array_size_cexpression (ma);
2104 var rhs_array_len = head.get_array_length_cexpression (ma, 1);
2105 ccomma.append_expression (new CCodeAssignment (lhs_array_size, rhs_array_len));
2108 ccomma.append_expression (get_variable_cexpression (temp_var.name));
2110 rhs = ccomma;
2112 } else if (local.variable_type is DelegateType) {
2113 var deleg_type = (DelegateType) local.variable_type;
2114 var d = deleg_type.delegate_symbol;
2115 if (d.has_target) {
2116 var ccomma = new CCodeCommaExpression ();
2118 var temp_var = get_temp_variable (local.variable_type, true, local, false);
2119 temp_vars.insert (0, temp_var);
2120 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), rhs));
2122 CCodeExpression lhs_delegate_target_destroy_notify;
2123 var lhs_delegate_target = get_delegate_target_cexpression (ma, out lhs_delegate_target_destroy_notify);
2124 if (local.captured) {
2125 var block = (Block) local.parent_symbol;
2126 lhs_delegate_target = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_cname (local.name));
2128 CCodeExpression rhs_delegate_target_destroy_notify;
2129 var rhs_delegate_target = get_delegate_target_cexpression (local.initializer, out rhs_delegate_target_destroy_notify);
2130 ccomma.append_expression (new CCodeAssignment (lhs_delegate_target, rhs_delegate_target));
2132 if (deleg_type.value_owned) {
2133 if (local.captured) {
2134 var block = (Block) local.parent_symbol;
2135 lhs_delegate_target = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_destroy_notify_cname (local.name));
2137 ccomma.append_expression (new CCodeAssignment (lhs_delegate_target_destroy_notify, rhs_delegate_target_destroy_notify));
2140 ccomma.append_expression (get_variable_cexpression (temp_var.name));
2142 rhs = ccomma;
2145 } else if (local.variable_type.is_reference_type_or_type_parameter ()) {
2146 rhs = new CCodeConstant ("NULL");
2148 if (local.variable_type is ArrayType) {
2149 // initialize array length variables
2150 var array_type = (ArrayType) local.variable_type;
2152 if (array_type.fixed_length) {
2153 rhs = null;
2154 } else {
2155 var ccomma = new CCodeCommaExpression ();
2157 for (int dim = 1; dim <= array_type.rank; dim++) {
2158 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), dim)), new CCodeConstant ("0")));
2161 ccomma.append_expression (rhs);
2163 rhs = ccomma;
2168 var cfrag = new CCodeFragment ();
2170 if (pre_statement_fragment != null) {
2171 cfrag.append (pre_statement_fragment);
2172 pre_statement_fragment = null;
2175 if (local.captured) {
2176 if (local.initializer != null) {
2177 cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id ((Block) local.parent_symbol))), get_variable_cname (local.name)), rhs)));
2179 } else if (current_method != null && current_method.coroutine) {
2180 closure_struct.add_field (local.variable_type.get_cname (), get_variable_cname (local.name) + local.variable_type.get_cdeclarator_suffix ());
2182 if (local.initializer != null) {
2183 if (has_simple_struct_initializer (local)) {
2184 cfrag.append (new CCodeExpressionStatement (rhs));
2185 } else {
2186 cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_variable_cname (local.name)), rhs)));
2189 } else {
2190 CCodeStatement post_stmt = null;
2191 if (has_simple_struct_initializer (local)) {
2192 post_stmt = new CCodeExpressionStatement (rhs);
2193 rhs = null;
2196 var cvar = new CCodeVariableDeclarator (get_variable_cname (local.name), rhs, local.variable_type.get_cdeclarator_suffix ());
2197 if (rhs != null) {
2198 cvar.line = rhs.line;
2201 var cdecl = new CCodeDeclaration (local.variable_type.get_cname ());
2202 cdecl.add_declarator (cvar);
2203 cfrag.append (cdecl);
2205 // try to initialize uninitialized variables
2206 // initialization not necessary for variables stored in closure
2207 if (cvar.initializer == null) {
2208 cvar.initializer = default_value_for_type (local.variable_type, true);
2209 cvar.init0 = true;
2212 if (post_stmt != null) {
2213 cfrag.append (post_stmt);
2217 if (local.initializer != null && local.variable_type is ArrayType) {
2218 var array_type = (ArrayType) local.variable_type;
2220 if (array_type.fixed_length) {
2221 source_declarations.add_include ("string.h");
2223 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
2224 // simple assignments do not work in C
2225 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
2226 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
2227 var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
2229 var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
2230 ccopy.add_argument (get_variable_cexpression (local.name));
2231 ccopy.add_argument ((CCodeExpression) local.initializer.ccodenode);
2232 ccopy.add_argument (size);
2233 cfrag.append (new CCodeExpressionStatement (ccopy));
2237 if (local.initializer != null && local.initializer.tree_can_fail) {
2238 head.add_simple_check (local.initializer, cfrag);
2241 local.ccodenode = cfrag;
2243 local.active = true;
2246 public override void visit_initializer_list (InitializerList list) {
2247 list.accept_children (codegen);
2249 if (list.target_type.data_type is Struct) {
2250 /* initializer is used as struct initializer */
2251 var st = (Struct) list.target_type.data_type;
2253 if (list.parent_node is Constant || list.parent_node is Field || list.parent_node is InitializerList) {
2254 var clist = new CCodeInitializerList ();
2256 var field_it = st.get_fields ().iterator ();
2257 foreach (Expression expr in list.get_initializers ()) {
2258 Field field = null;
2259 while (field == null) {
2260 field_it.next ();
2261 field = field_it.get ();
2262 if (field.binding != MemberBinding.INSTANCE) {
2263 // we only initialize instance fields
2264 field = null;
2268 var cexpr = (CCodeExpression) expr.ccodenode;
2270 string ctype = field.get_ctype ();
2271 if (ctype != null) {
2272 cexpr = new CCodeCastExpression (cexpr, ctype);
2275 clist.append (cexpr);
2278 list.ccodenode = clist;
2279 } else {
2280 // used as expression
2281 var temp_decl = get_temp_variable (list.target_type, false, list);
2282 temp_vars.add (temp_decl);
2284 var instance = get_variable_cexpression (get_variable_cname (temp_decl.name));
2286 var ccomma = new CCodeCommaExpression ();
2288 var field_it = st.get_fields ().iterator ();
2289 foreach (Expression expr in list.get_initializers ()) {
2290 Field field = null;
2291 while (field == null) {
2292 field_it.next ();
2293 field = field_it.get ();
2294 if (field.binding != MemberBinding.INSTANCE) {
2295 // we only initialize instance fields
2296 field = null;
2300 var cexpr = (CCodeExpression) expr.ccodenode;
2302 string ctype = field.get_ctype ();
2303 if (ctype != null) {
2304 cexpr = new CCodeCastExpression (cexpr, ctype);
2307 var lhs = new CCodeMemberAccess (instance, field.get_cname ());;
2308 ccomma.append_expression (new CCodeAssignment (lhs, cexpr));
2311 ccomma.append_expression (instance);
2312 list.ccodenode = ccomma;
2314 } else {
2315 var clist = new CCodeInitializerList ();
2316 foreach (Expression expr in list.get_initializers ()) {
2317 clist.append ((CCodeExpression) expr.ccodenode);
2319 list.ccodenode = clist;
2323 public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null, bool init = true) {
2324 var var_type = type.copy ();
2325 var_type.value_owned = value_owned;
2326 var local = new LocalVariable (var_type, "_tmp%d_".printf (next_temp_var_id));
2327 local.no_init = !init;
2329 if (node_reference != null) {
2330 local.source_reference = node_reference.source_reference;
2333 next_temp_var_id++;
2335 return local;
2338 bool is_in_generic_type (DataType type) {
2339 if (current_symbol != null && type.type_parameter.parent_symbol is TypeSymbol
2340 && (current_method == null || current_method.binding == MemberBinding.INSTANCE)) {
2341 return true;
2342 } else {
2343 return false;
2347 private CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
2348 if (type is GenericType) {
2349 string var_name = "%s_type".printf (type.type_parameter.name.down ());
2350 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
2351 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), var_name);
2352 } else {
2353 return new CCodeIdentifier (var_name);
2355 } else {
2356 string type_id = type.get_type_id ();
2357 if (type_id == null) {
2358 type_id = "G_TYPE_INVALID";
2359 } else {
2360 generate_type_declaration (type, source_declarations);
2362 return new CCodeIdentifier (type_id);
2366 public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup = false) {
2367 if (type is ErrorType) {
2368 return new CCodeIdentifier ("g_error_copy");
2369 } else if (type.data_type != null) {
2370 string dup_function;
2371 var cl = type.data_type as Class;
2372 if (type.data_type.is_reference_counting ()) {
2373 dup_function = type.data_type.get_ref_function ();
2374 if (type.data_type is Interface && dup_function == null) {
2375 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 ()));
2376 return null;
2378 } else if (cl != null && cl.is_immutable) {
2379 // allow duplicates of immutable instances as for example strings
2380 dup_function = type.data_type.get_dup_function ();
2381 if (dup_function == null) {
2382 dup_function = "";
2384 } else if (type is ValueType) {
2385 dup_function = type.data_type.get_dup_function ();
2386 if (dup_function == null && type.nullable) {
2387 dup_function = generate_struct_dup_wrapper ((ValueType) type);
2388 } else if (dup_function == null) {
2389 dup_function = "";
2391 } else {
2392 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2393 Report.error (source_reference, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type.data_type.name));
2394 return null;
2397 return new CCodeIdentifier (dup_function);
2398 } else if (type.type_parameter != null) {
2399 string func_name = "%s_dup_func".printf (type.type_parameter.name.down ());
2400 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
2401 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
2402 } else {
2403 return new CCodeIdentifier (func_name);
2405 } else if (type is PointerType) {
2406 var pointer_type = (PointerType) type;
2407 return get_dup_func_expression (pointer_type.base_type, source_reference);
2408 } else {
2409 return new CCodeConstant ("NULL");
2413 void make_comparable_cexpression (ref DataType left_type, ref CCodeExpression cleft, ref DataType right_type, ref CCodeExpression cright) {
2414 var left_type_as_struct = left_type.data_type as Struct;
2415 var right_type_as_struct = right_type.data_type as Struct;
2417 // GValue support
2418 var valuecast = try_cast_value_to_type (cleft, left_type, right_type);
2419 if (valuecast != null) {
2420 cleft = valuecast;
2421 left_type = right_type;
2422 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2423 return;
2426 valuecast = try_cast_value_to_type (cright, right_type, left_type);
2427 if (valuecast != null) {
2428 cright = valuecast;
2429 right_type = left_type;
2430 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
2431 return;
2434 if (left_type.data_type is Class && !((Class) left_type.data_type).is_compact &&
2435 right_type.data_type is Class && !((Class) right_type.data_type).is_compact) {
2436 var left_cl = (Class) left_type.data_type;
2437 var right_cl = (Class) right_type.data_type;
2439 if (left_cl != right_cl) {
2440 if (left_cl.is_subtype_of (right_cl)) {
2441 cleft = generate_instance_cast (cleft, right_cl);
2442 } else if (right_cl.is_subtype_of (left_cl)) {
2443 cright = generate_instance_cast (cright, left_cl);
2446 } else if (left_type_as_struct != null && right_type_as_struct != null) {
2447 if (left_type is StructValueType) {
2448 // real structs (uses compare/equal function)
2449 if (!left_type.nullable) {
2450 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft);
2452 if (!right_type.nullable) {
2453 cright = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cright);
2455 } else {
2456 // integer or floating or boolean type
2457 if (left_type.nullable && right_type.nullable) {
2458 // FIXME also compare contents, not just address
2459 } else if (left_type.nullable) {
2460 // FIXME check left value is not null
2461 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
2462 } else if (right_type.nullable) {
2463 // FIXME check right value is not null
2464 cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
2470 private string generate_struct_equal_function (Struct st) {
2471 string equal_func = "_%sequal".printf (st.get_lower_case_cprefix ());
2473 if (!add_wrapper (equal_func)) {
2474 // wrapper already defined
2475 return equal_func;
2477 // declaration
2479 var function = new CCodeFunction (equal_func, "gboolean");
2480 function.modifiers = CCodeModifiers.STATIC;
2482 function.add_parameter (new CCodeFormalParameter ("s1", "const " + st.get_cname () + "*"));
2483 function.add_parameter (new CCodeFormalParameter ("s2", "const " + st.get_cname () + "*"));
2485 // definition
2486 var cblock = new CCodeBlock ();
2488 // if (s1 == s2) return TRUE;
2490 var block = new CCodeBlock ();
2491 block.add_statement (new CCodeReturnStatement (new CCodeConstant ("TRUE")));
2493 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2494 var cif = new CCodeIfStatement (cexp, block);
2495 cblock.add_statement (cif);
2497 // if (s1 == NULL || s2 == NULL) return FALSE;
2499 var block = new CCodeBlock ();
2500 block.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
2502 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2503 var cif = new CCodeIfStatement (cexp, block);
2504 cblock.add_statement (cif);
2506 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2507 cif = new CCodeIfStatement (cexp, block);
2508 cblock.add_statement (cif);
2511 foreach (Field f in st.get_fields ()) {
2512 if (f.binding != MemberBinding.INSTANCE) {
2513 // we only compare instance fields
2514 continue;
2517 CCodeExpression cexp; // if (cexp) return FALSE;
2518 var s1 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s1"), f.name); // s1->f
2519 var s2 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s2"), f.name); // s2->f
2521 var field_type = f.field_type.copy ();
2522 make_comparable_cexpression (ref field_type, ref s1, ref field_type, ref s2);
2524 if (!(f.field_type is NullType) && f.field_type.compatible (string_type)) {
2525 requires_strcmp0 = true;
2526 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_strcmp0"));
2527 ccall.add_argument (s1);
2528 ccall.add_argument (s2);
2529 cexp = ccall;
2530 } else if (f.field_type is StructValueType) {
2531 var equalfunc = generate_struct_equal_function (f.field_type.data_type as Struct);
2532 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
2533 ccall.add_argument (s1);
2534 ccall.add_argument (s2);
2535 cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
2536 } else {
2537 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, s1, s2);
2540 var block = new CCodeBlock ();
2541 block.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
2542 var cif = new CCodeIfStatement (cexp, block);
2543 cblock.add_statement (cif);
2546 cblock.add_statement (new CCodeReturnStatement (new CCodeConstant ("TRUE")));
2548 // append to file
2550 source_declarations.add_type_member_declaration (function.copy ());
2552 function.block = cblock;
2553 source_type_member_definition.append (function);
2555 return equal_func;
2558 private string generate_numeric_equal_function (Struct st) {
2559 string equal_func = "_%sequal".printf (st.get_lower_case_cprefix ());
2561 if (!add_wrapper (equal_func)) {
2562 // wrapper already defined
2563 return equal_func;
2565 // declaration
2567 var function = new CCodeFunction (equal_func, "gboolean");
2568 function.modifiers = CCodeModifiers.STATIC;
2570 function.add_parameter (new CCodeFormalParameter ("s1", "const " + st.get_cname () + "*"));
2571 function.add_parameter (new CCodeFormalParameter ("s2", "const " + st.get_cname () + "*"));
2573 // definition
2574 var cblock = new CCodeBlock ();
2576 // if (s1 == s2) return TRUE;
2578 var block = new CCodeBlock ();
2579 block.add_statement (new CCodeReturnStatement (new CCodeConstant ("TRUE")));
2581 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
2582 var cif = new CCodeIfStatement (cexp, block);
2583 cblock.add_statement (cif);
2585 // if (s1 == NULL || s2 == NULL) return FALSE;
2587 var block = new CCodeBlock ();
2588 block.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
2590 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
2591 var cif = new CCodeIfStatement (cexp, block);
2592 cblock.add_statement (cif);
2594 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
2595 cif = new CCodeIfStatement (cexp, block);
2596 cblock.add_statement (cif);
2598 // return (*s1 == *s2);
2600 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
2601 cblock.add_statement (new CCodeReturnStatement (cexp));
2604 // append to file
2606 source_declarations.add_type_member_declaration (function.copy ());
2608 function.block = cblock;
2609 source_type_member_definition.append (function);
2611 return equal_func;
2614 private string generate_struct_dup_wrapper (ValueType value_type) {
2615 string dup_func = "_%sdup".printf (value_type.type_symbol.get_lower_case_cprefix ());
2617 if (!add_wrapper (dup_func)) {
2618 // wrapper already defined
2619 return dup_func;
2622 // declaration
2624 var function = new CCodeFunction (dup_func, value_type.get_cname ());
2625 function.modifiers = CCodeModifiers.STATIC;
2627 function.add_parameter (new CCodeFormalParameter ("self", value_type.get_cname ()));
2629 // definition
2631 var block = new CCodeBlock ();
2633 if (value_type.type_symbol == gvalue_type) {
2634 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
2635 dup_call.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
2636 dup_call.add_argument (new CCodeIdentifier ("self"));
2638 block.add_statement (new CCodeReturnStatement (dup_call));
2639 } else {
2640 var cdecl = new CCodeDeclaration (value_type.get_cname ());
2641 cdecl.add_declarator (new CCodeVariableDeclarator ("dup"));
2642 block.add_statement (cdecl);
2644 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
2645 creation_call.add_argument (new CCodeConstant (value_type.data_type.get_cname ()));
2646 creation_call.add_argument (new CCodeConstant ("1"));
2647 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("dup"), creation_call)));
2649 var st = value_type.data_type as Struct;
2650 if (st != null && st.is_disposable ()) {
2651 if (!st.has_copy_function) {
2652 generate_struct_copy_function (st);
2655 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (st.get_copy_function ()));
2656 copy_call.add_argument (new CCodeIdentifier ("self"));
2657 copy_call.add_argument (new CCodeIdentifier ("dup"));
2658 block.add_statement (new CCodeExpressionStatement (copy_call));
2659 } else {
2660 source_declarations.add_include ("string.h");
2662 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
2663 sizeof_call.add_argument (new CCodeConstant (value_type.data_type.get_cname ()));
2665 var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
2666 copy_call.add_argument (new CCodeIdentifier ("dup"));
2667 copy_call.add_argument (new CCodeIdentifier ("self"));
2668 copy_call.add_argument (sizeof_call);
2669 block.add_statement (new CCodeExpressionStatement (copy_call));
2672 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("dup")));
2675 // append to file
2677 source_declarations.add_type_member_declaration (function.copy ());
2679 function.block = block;
2680 source_type_member_definition.append (function);
2682 return dup_func;
2685 protected string generate_destroy_func_wrapper (DataType type) {
2686 string destroy_func = "_vala_%s_free".printf (type.data_type.get_cname ());
2688 if (!add_wrapper (destroy_func)) {
2689 // wrapper already defined
2690 return destroy_func;
2693 // declaration
2695 var function = new CCodeFunction (destroy_func, "void");
2696 function.modifiers = CCodeModifiers.STATIC;
2697 function.add_parameter (new CCodeFormalParameter ("self", type.get_cname ()));
2699 // definition
2701 var block = new CCodeBlock ();
2703 var free_call = new CCodeFunctionCall (new CCodeIdentifier (type.data_type.get_free_function ()));
2704 free_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("self")));
2706 block.add_statement (new CCodeExpressionStatement (free_call));
2708 // append to file
2710 source_declarations.add_type_member_declaration (function.copy ());
2712 function.block = block;
2713 source_type_member_definition.append (function);
2715 return destroy_func;
2718 public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
2719 if (context.profile == Profile.GOBJECT && (type.data_type == glist_type || type.data_type == gslist_type)) {
2720 // create wrapper function to free list elements if necessary
2722 bool elements_require_free = false;
2723 CCodeExpression element_destroy_func_expression = null;
2725 foreach (DataType type_arg in type.get_type_arguments ()) {
2726 elements_require_free = requires_destroy (type_arg);
2727 if (elements_require_free) {
2728 element_destroy_func_expression = get_destroy_func_expression (type_arg);
2732 if (elements_require_free && element_destroy_func_expression is CCodeIdentifier) {
2733 return new CCodeIdentifier (generate_glist_free_wrapper (type, (CCodeIdentifier) element_destroy_func_expression));
2734 } else {
2735 return new CCodeIdentifier (type.data_type.get_free_function ());
2737 } else if (type is ErrorType) {
2738 return new CCodeIdentifier ("g_error_free");
2739 } else if (type.data_type != null) {
2740 string unref_function;
2741 if (type is ReferenceType) {
2742 if (type.data_type.is_reference_counting ()) {
2743 unref_function = type.data_type.get_unref_function ();
2744 if (type.data_type is Interface && unref_function == null) {
2745 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 ()));
2746 return null;
2748 } else {
2749 var cl = type.data_type as Class;
2750 if (cl != null && cl.free_function_address_of) {
2751 unref_function = generate_destroy_func_wrapper (type);
2752 } else {
2753 unref_function = type.data_type.get_free_function ();
2756 } else {
2757 if (type.nullable) {
2758 unref_function = type.data_type.get_free_function ();
2759 if (unref_function == null) {
2760 unref_function = "g_free";
2762 } else {
2763 var st = (Struct) type.data_type;
2764 if (!st.has_destroy_function) {
2765 generate_struct_destroy_function (st);
2767 unref_function = st.get_destroy_function ();
2770 if (unref_function == null) {
2771 return new CCodeConstant ("NULL");
2773 return new CCodeIdentifier (unref_function);
2774 } else if (type.type_parameter != null && current_type_symbol is Class) {
2775 string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ());
2776 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
2777 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
2778 } else {
2779 return new CCodeIdentifier (func_name);
2781 } else if (type is ArrayType) {
2782 if (context.profile == Profile.POSIX) {
2783 return new CCodeIdentifier ("free");
2784 } else {
2785 return new CCodeIdentifier ("g_free");
2787 } else if (type is PointerType) {
2788 if (context.profile == Profile.POSIX) {
2789 return new CCodeIdentifier ("free");
2790 } else {
2791 return new CCodeIdentifier ("g_free");
2793 } else {
2794 return new CCodeConstant ("NULL");
2798 private string generate_glist_free_wrapper (DataType list_type, CCodeIdentifier element_destroy_func_expression) {
2799 string destroy_func = "_%s_%s".printf (list_type.data_type.get_free_function (), element_destroy_func_expression.name);
2801 if (!add_wrapper (destroy_func)) {
2802 // wrapper already defined
2803 return destroy_func;
2806 // declaration
2808 var function = new CCodeFunction (destroy_func, "void");
2809 function.modifiers = CCodeModifiers.STATIC;
2811 function.add_parameter (new CCodeFormalParameter ("self", list_type.get_cname ()));
2813 // definition
2815 var block = new CCodeBlock ();
2817 CCodeFunctionCall element_free_call;
2818 if (list_type.data_type == glist_type) {
2819 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
2820 } else {
2821 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_slist_foreach"));
2823 element_free_call.add_argument (new CCodeIdentifier ("self"));
2824 element_free_call.add_argument (new CCodeCastExpression (element_destroy_func_expression, "GFunc"));
2825 element_free_call.add_argument (new CCodeConstant ("NULL"));
2826 block.add_statement (new CCodeExpressionStatement (element_free_call));
2828 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier (list_type.data_type.get_free_function ()));
2829 cfreecall.add_argument (new CCodeIdentifier ("self"));
2830 block.add_statement (new CCodeExpressionStatement (cfreecall));
2832 // append to file
2834 source_declarations.add_type_member_declaration (function.copy ());
2836 function.block = block;
2837 source_type_member_definition.append (function);
2839 return destroy_func;
2842 public virtual string? append_struct_array_free (Struct st) {
2843 return null;
2846 public virtual CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr, bool is_macro_definition = false) {
2847 if (type is DelegateType) {
2848 CCodeExpression delegate_target_destroy_notify;
2849 var delegate_target = get_delegate_target_cexpression (expr, out delegate_target_destroy_notify);
2851 var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
2852 ccall.add_argument (delegate_target);
2854 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
2856 var ccomma = new CCodeCommaExpression ();
2857 ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), ccall));
2858 ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
2859 ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
2860 ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
2862 return ccomma;
2865 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
2867 if (type is ValueType && !type.nullable) {
2868 // normal value type, no null check
2869 var st = type.data_type as Struct;
2870 if (st != null && st.is_simple_type ()) {
2871 // used for va_list
2872 ccall.add_argument (cvar);
2873 } else {
2874 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
2877 if (gvalue_type != null && type.data_type == gvalue_type) {
2878 // g_value_unset must not be called for already unset values
2879 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
2880 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
2882 var ccomma = new CCodeCommaExpression ();
2883 ccomma.append_expression (ccall);
2884 ccomma.append_expression (new CCodeConstant ("NULL"));
2886 return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
2887 } else {
2888 return ccall;
2892 if (ccall.call is CCodeIdentifier && !(type is ArrayType) && !is_macro_definition) {
2893 // generate and use NULL-aware free macro to simplify code
2895 var freeid = (CCodeIdentifier) ccall.call;
2896 string free0_func = "_%s0".printf (freeid.name);
2898 if (add_wrapper (free0_func)) {
2899 var macro = get_unref_expression (new CCodeIdentifier ("var"), type, expr, true);
2900 source_declarations.add_type_declaration (new CCodeMacroReplacement.with_expression ("%s(var)".printf (free0_func), macro));
2903 ccall = new CCodeFunctionCall (new CCodeIdentifier (free0_func));
2904 ccall.add_argument (cvar);
2905 return ccall;
2908 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
2910 /* can be simplified to
2911 * foo = (unref (foo), NULL)
2912 * if foo is of static type non-null
2915 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
2916 if (type.type_parameter != null) {
2917 if (!(current_type_symbol is Class) || current_class.is_compact) {
2918 return new CCodeConstant ("NULL");
2921 // unref functions are optional for type parameters
2922 var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
2923 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
2926 ccall.add_argument (cvar);
2928 /* set freed references to NULL to prevent further use */
2929 var ccomma = new CCodeCommaExpression ();
2931 if (context.profile == Profile.GOBJECT) {
2932 if (type.data_type == gstringbuilder_type
2933 || type.data_type == garray_type
2934 || type.data_type == gbytearray_type
2935 || type.data_type == gptrarray_type) {
2936 ccall.add_argument (new CCodeConstant ("TRUE"));
2937 } else if (type.data_type == gthreadpool_type) {
2938 ccall.add_argument (new CCodeConstant ("FALSE"));
2939 ccall.add_argument (new CCodeConstant ("TRUE"));
2940 } else if (type is ArrayType) {
2941 var array_type = (ArrayType) type;
2942 if (requires_destroy (array_type.element_type)) {
2943 CCodeExpression csizeexpr = null;
2944 bool first = true;
2945 for (int dim = 1; dim <= array_type.rank; dim++) {
2946 if (first) {
2947 csizeexpr = head.get_array_length_cexpression (expr, dim);
2948 first = false;
2949 } else {
2950 csizeexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeexpr, head.get_array_length_cexpression (expr, dim));
2954 var st = array_type.element_type.data_type as Struct;
2955 if (st != null && !array_type.element_type.nullable) {
2956 ccall.call = new CCodeIdentifier (append_struct_array_free (st));
2957 ccall.add_argument (csizeexpr);
2958 } else {
2959 requires_array_free = true;
2960 ccall.call = new CCodeIdentifier ("_vala_array_free");
2961 ccall.add_argument (csizeexpr);
2962 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
2968 ccomma.append_expression (ccall);
2969 ccomma.append_expression (new CCodeConstant ("NULL"));
2971 var cassign = new CCodeAssignment (cvar, ccomma);
2973 // g_free (NULL) is allowed
2974 bool uses_gfree = (type.data_type != null && !type.data_type.is_reference_counting () && type.data_type.get_free_function () == "g_free");
2975 uses_gfree = uses_gfree || type is ArrayType;
2976 if (uses_gfree) {
2977 return cassign;
2980 return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
2983 public override void visit_end_full_expression (Expression expr) {
2984 /* expr is a full expression, i.e. an initializer, the
2985 * expression in an expression statement, the controlling
2986 * expression in if, while, for, or foreach statements
2988 * we unref temporary variables at the end of a full
2989 * expression
2992 /* can't automatically deep copy lists yet, so do it
2993 * manually for now
2994 * replace with
2995 * expr.temp_vars = temp_vars;
2996 * when deep list copying works
2998 expr.temp_vars.clear ();
2999 foreach (LocalVariable local in temp_vars) {
3000 expr.temp_vars.add (local);
3002 temp_vars.clear ();
3004 if (((List<LocalVariable>) temp_ref_vars).size == 0) {
3005 /* nothing to do without temporary variables */
3006 return;
3009 var expr_list = new CCodeCommaExpression ();
3011 LocalVariable full_expr_var = null;
3013 var local_decl = expr.parent_node as LocalVariable;
3014 if (local_decl != null && has_simple_struct_initializer (local_decl)) {
3015 expr_list.append_expression ((CCodeExpression) expr.ccodenode);
3016 } else {
3017 var expr_type = expr.value_type;
3018 if (expr.target_type != null) {
3019 expr_type = expr.target_type;
3022 full_expr_var = get_temp_variable (expr_type, true, expr, false);
3023 expr.temp_vars.add (full_expr_var);
3025 expr_list.append_expression (new CCodeAssignment (get_variable_cexpression (full_expr_var.name), (CCodeExpression) expr.ccodenode));
3028 foreach (LocalVariable local in temp_ref_vars) {
3029 var ma = new MemberAccess.simple (local.name);
3030 ma.symbol_reference = local;
3031 ma.value_type = local.variable_type.copy ();
3032 expr_list.append_expression (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma));
3035 if (full_expr_var != null) {
3036 expr_list.append_expression (get_variable_cexpression (full_expr_var.name));
3039 expr.ccodenode = expr_list;
3041 temp_ref_vars.clear ();
3044 public void append_temp_decl (CCodeFragment cfrag, List<LocalVariable> temp_vars) {
3045 foreach (LocalVariable local in temp_vars) {
3046 var cdecl = new CCodeDeclaration (local.variable_type.get_cname ());
3048 var vardecl = new CCodeVariableDeclarator (local.name, null, local.variable_type.get_cdeclarator_suffix ());
3049 // sets #line
3050 local.ccodenode = vardecl;
3051 cdecl.add_declarator (vardecl);
3053 var st = local.variable_type.data_type as Struct;
3054 var array_type = local.variable_type as ArrayType;
3056 if (local.name.has_prefix ("*")) {
3057 // do not dereference unintialized variable
3058 // initialization is not needed for these special
3059 // pointer temp variables
3060 // used to avoid side-effects in assignments
3061 } else if (local.no_init) {
3062 // no initialization necessary for this temp var
3063 } else if (!local.variable_type.nullable &&
3064 (st != null && !st.is_simple_type ()) ||
3065 (array_type != null && array_type.fixed_length)) {
3066 // 0-initialize struct with struct initializer { 0 }
3067 // necessary as they will be passed by reference
3068 var clist = new CCodeInitializerList ();
3069 clist.append (new CCodeConstant ("0"));
3071 vardecl.initializer = clist;
3072 vardecl.init0 = true;
3073 } else if (local.variable_type.is_reference_type_or_type_parameter () ||
3074 local.variable_type.nullable ||
3075 local.variable_type is DelegateType) {
3076 vardecl.initializer = new CCodeConstant ("NULL");
3077 vardecl.init0 = true;
3080 if (current_method != null && current_method.coroutine) {
3081 closure_struct.add_field (local.variable_type.get_cname (), local.name);
3083 // even though closure struct is zerod, we need to initialize temporary variables
3084 // as they might be used multiple times when declared in a loop
3086 if (vardecl.initializer is CCodeInitializerList) {
3087 // C does not support initializer lists in assignments, use memset instead
3088 source_declarations.add_include ("string.h");
3089 var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
3090 memset_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (local.name)));
3091 memset_call.add_argument (new CCodeConstant ("0"));
3092 memset_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (local.variable_type.get_cname ())));
3093 cfrag.append (new CCodeExpressionStatement (memset_call));
3094 } else if (vardecl.initializer != null) {
3095 cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (local.name), vardecl.initializer)));
3097 } else {
3098 cfrag.append (cdecl);
3103 public override void visit_expression_statement (ExpressionStatement stmt) {
3104 stmt.accept_children (codegen);
3106 if (stmt.expression.error) {
3107 stmt.error = true;
3108 return;
3111 stmt.ccodenode = new CCodeExpressionStatement ((CCodeExpression) stmt.expression.ccodenode);
3113 /* free temporary objects and handle errors */
3115 if (((List<LocalVariable>) temp_vars).size == 0
3116 && pre_statement_fragment == null
3117 && (!stmt.tree_can_fail || !stmt.expression.tree_can_fail)) {
3118 /* nothing to do without temporary variables and errors */
3119 return;
3122 var cfrag = new CCodeFragment ();
3123 append_temp_decl (cfrag, temp_vars);
3125 if (pre_statement_fragment != null) {
3126 cfrag.append (pre_statement_fragment);
3127 pre_statement_fragment = null;
3130 cfrag.append (stmt.ccodenode);
3132 foreach (LocalVariable local in temp_ref_vars) {
3133 var ma = new MemberAccess.simple (local.name);
3134 ma.symbol_reference = local;
3135 ma.value_type = local.variable_type.copy ();
3136 cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
3139 if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
3140 // simple case, no node breakdown necessary
3141 head.add_simple_check (stmt.expression, cfrag);
3144 stmt.ccodenode = cfrag;
3146 temp_vars.clear ();
3147 temp_ref_vars.clear ();
3150 public void create_temp_decl (Statement stmt, List<LocalVariable> temp_vars) {
3151 /* declare temporary variables */
3153 if (temp_vars.size == 0) {
3154 /* nothing to do without temporary variables */
3155 return;
3158 var cfrag = new CCodeFragment ();
3159 append_temp_decl (cfrag, temp_vars);
3161 cfrag.append (stmt.ccodenode);
3163 stmt.ccodenode = cfrag;
3166 public virtual void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop = false) {
3167 var b = (Block) sym;
3169 var local_vars = b.get_local_variables ();
3170 foreach (LocalVariable local in local_vars) {
3171 if (local.active && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
3172 var ma = new MemberAccess.simple (local.name);
3173 ma.symbol_reference = local;
3174 ma.value_type = local.variable_type.copy ();
3175 cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
3179 if (b.captured) {
3180 int block_id = get_block_id (b);
3182 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
3183 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
3184 cfrag.append (new CCodeExpressionStatement (data_unref));
3187 if (stop_at_loop) {
3188 if (b.parent_node is Loop ||
3189 b.parent_node is ForeachStatement ||
3190 b.parent_node is SwitchStatement) {
3191 return;
3195 if (sym.parent_symbol is Block) {
3196 append_local_free (sym.parent_symbol, cfrag, stop_at_loop);
3197 } else if (sym.parent_symbol is Method) {
3198 append_param_free ((Method) sym.parent_symbol, cfrag);
3202 public void append_error_free (Symbol sym, CCodeFragment cfrag, TryStatement current_try) {
3203 var b = (Block) sym;
3205 var local_vars = b.get_local_variables ();
3206 foreach (LocalVariable local in local_vars) {
3207 if (local.active && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
3208 var ma = new MemberAccess.simple (local.name);
3209 ma.symbol_reference = local;
3210 cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
3214 if (b.captured) {
3215 int block_id = get_block_id (b);
3217 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
3218 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
3219 cfrag.append (new CCodeExpressionStatement (data_unref));
3222 if (sym == current_try.body) {
3223 return;
3226 if (sym.parent_symbol is Block) {
3227 append_error_free (sym.parent_symbol, cfrag, current_try);
3228 } else if (sym.parent_symbol is Method) {
3229 append_param_free ((Method) sym.parent_symbol, cfrag);
3233 private void append_param_free (Method m, CCodeFragment cfrag) {
3234 foreach (FormalParameter param in m.get_parameters ()) {
3235 if (!param.ellipsis && requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
3236 var ma = new MemberAccess.simple (param.name);
3237 ma.symbol_reference = param;
3238 ma.value_type = param.parameter_type.copy ();
3239 cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param.name), param.parameter_type, ma)));
3244 public void create_local_free (CodeNode stmt, bool stop_at_loop = false) {
3245 var cfrag = new CCodeFragment ();
3247 append_local_free (current_symbol, cfrag, stop_at_loop);
3249 cfrag.append (stmt.ccodenode);
3250 stmt.ccodenode = cfrag;
3253 public virtual bool variable_accessible_in_finally (LocalVariable local) {
3254 if (current_try == null) {
3255 return false;
3258 var sym = current_symbol;
3260 while (!(sym is Method) && sym.scope.lookup (local.name) == null) {
3261 if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) ||
3262 (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) {
3264 return true;
3267 sym = sym.parent_symbol;
3270 return false;
3273 public override void visit_return_statement (ReturnStatement stmt) {
3274 // avoid unnecessary ref/unref pair
3275 if (stmt.return_expression != null) {
3276 var local = stmt.return_expression.symbol_reference as LocalVariable;
3277 if (current_return_type.value_owned
3278 && local != null && local.variable_type.value_owned
3279 && !local.captured
3280 && !variable_accessible_in_finally (local)) {
3281 /* return expression is local variable taking ownership and
3282 * current method is transferring ownership */
3284 // don't ref expression
3285 stmt.return_expression.value_type.value_owned = true;
3289 stmt.accept_children (codegen);
3291 Symbol return_expression_symbol = null;
3293 if (stmt.return_expression != null) {
3294 // avoid unnecessary ref/unref pair
3295 var local = stmt.return_expression.symbol_reference as LocalVariable;
3296 if (current_return_type.value_owned
3297 && local != null && local.variable_type.value_owned
3298 && !local.captured
3299 && !variable_accessible_in_finally (local)) {
3300 /* return expression is local variable taking ownership and
3301 * current method is transferring ownership */
3303 // don't unref variable
3304 return_expression_symbol = local;
3305 return_expression_symbol.active = false;
3309 // return array length if appropriate
3310 if (((current_method != null && !current_method.no_array_length) || current_property_accessor != null) && current_return_type is ArrayType) {
3311 var return_expr_decl = get_temp_variable (stmt.return_expression.value_type, true, stmt, false);
3313 var ccomma = new CCodeCommaExpression ();
3314 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (return_expr_decl.name), (CCodeExpression) stmt.return_expression.ccodenode));
3316 var array_type = (ArrayType) current_return_type;
3318 for (int dim = 1; dim <= array_type.rank; dim++) {
3319 var len_l = get_result_cexpression (head.get_array_length_cname ("result", dim));
3320 if (current_method == null || !current_method.coroutine) {
3321 len_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, len_l);
3323 var len_r = head.get_array_length_cexpression (stmt.return_expression, dim);
3324 ccomma.append_expression (new CCodeAssignment (len_l, len_r));
3327 ccomma.append_expression (get_variable_cexpression (return_expr_decl.name));
3329 stmt.return_expression.ccodenode = ccomma;
3330 stmt.return_expression.temp_vars.add (return_expr_decl);
3331 } else if ((current_method != null || current_property_accessor != null) && current_return_type is DelegateType) {
3332 var delegate_type = (DelegateType) current_return_type;
3333 if (delegate_type.delegate_symbol.has_target) {
3334 var return_expr_decl = get_temp_variable (stmt.return_expression.value_type, true, stmt, false);
3336 var ccomma = new CCodeCommaExpression ();
3337 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (return_expr_decl.name), (CCodeExpression) stmt.return_expression.ccodenode));
3339 var target_l = get_result_cexpression (get_delegate_target_cname ("result"));
3340 if (current_method == null || !current_method.coroutine) {
3341 target_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l);
3343 CCodeExpression target_r_destroy_notify;
3344 var target_r = get_delegate_target_cexpression (stmt.return_expression, out target_r_destroy_notify);
3345 ccomma.append_expression (new CCodeAssignment (target_l, target_r));
3346 if (delegate_type.value_owned) {
3347 var target_l_destroy_notify = get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3348 if (current_method == null || !current_method.coroutine) {
3349 target_l_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l_destroy_notify);
3351 ccomma.append_expression (new CCodeAssignment (target_l_destroy_notify, target_r_destroy_notify));
3354 ccomma.append_expression (get_variable_cexpression (return_expr_decl.name));
3356 stmt.return_expression.ccodenode = ccomma;
3357 stmt.return_expression.temp_vars.add (return_expr_decl);
3361 var cfrag = new CCodeFragment ();
3363 if (stmt.return_expression != null) {
3364 // assign method result to `result'
3365 CCodeExpression result_lhs = get_result_cexpression ();
3366 if (current_return_type.is_real_non_null_struct_type () && (current_method == null || !current_method.coroutine)) {
3367 result_lhs = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result_lhs);
3369 cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (result_lhs, (CCodeExpression) stmt.return_expression.ccodenode)));
3372 // free local variables
3373 append_local_free (current_symbol, cfrag);
3375 if (current_method != null) {
3376 // check postconditions
3377 foreach (Expression postcondition in current_method.get_postconditions ()) {
3378 cfrag.append (create_postcondition_statement (postcondition));
3382 CCodeReturnStatement creturn = null;
3383 if (current_method is CreationMethod) {
3384 creturn = new CCodeReturnStatement (new CCodeIdentifier ("self"));
3385 cfrag.append (creturn);
3386 } else if (current_method != null && current_method.coroutine) {
3387 } else if (current_return_type is VoidType || current_return_type.is_real_non_null_struct_type ()) {
3388 // structs are returned via out parameter
3389 creturn = new CCodeReturnStatement ();
3390 cfrag.append (creturn);
3391 } else {
3392 creturn = new CCodeReturnStatement (new CCodeIdentifier ("result"));
3393 cfrag.append (creturn);
3396 stmt.ccodenode = cfrag;
3397 if (creturn != null) {
3398 creturn.line = stmt.ccodenode.line;
3401 if (stmt.return_expression != null) {
3402 create_temp_decl (stmt, stmt.return_expression.temp_vars);
3405 if (return_expression_symbol != null) {
3406 return_expression_symbol.active = true;
3410 public string get_symbol_lock_name (string symname) {
3411 return "__lock_%s".printf (symname);
3414 private CCodeExpression get_lock_expression (Statement stmt, Expression resource) {
3415 CCodeExpression l = null;
3416 var inner_node = ((MemberAccess)resource).inner;
3417 var member = (Member)resource.symbol_reference;
3418 var parent = (TypeSymbol)resource.symbol_reference.parent_symbol;
3420 if (member.is_instance_member ()) {
3421 if (inner_node == null) {
3422 l = new CCodeIdentifier ("self");
3423 } else if (resource.symbol_reference.parent_symbol != current_type_symbol) {
3424 l = generate_instance_cast ((CCodeExpression) inner_node.ccodenode, parent);
3425 } else {
3426 l = (CCodeExpression) inner_node.ccodenode;
3429 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (resource.symbol_reference.name));
3430 } else if (member.is_class_member ()) {
3431 CCodeExpression klass;
3433 if (current_method != null && current_method.binding == MemberBinding.INSTANCE ||
3434 current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE ||
3435 (in_constructor && !in_static_or_class_context)) {
3436 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3437 k.add_argument (new CCodeIdentifier ("self"));
3438 klass = k;
3439 } else {
3440 klass = new CCodeIdentifier ("klass");
3443 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent.get_upper_case_cname ())));
3444 get_class_private_call.add_argument (klass);
3445 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (resource.symbol_reference.name));
3446 } else {
3447 string lock_name = "%s_%s".printf(parent.get_lower_case_cname (), resource.symbol_reference.name);
3448 l = new CCodeIdentifier (get_symbol_lock_name (lock_name));
3450 return l;
3453 public override void visit_lock_statement (LockStatement stmt) {
3454 var l = get_lock_expression (stmt, stmt.resource);
3456 var fc = new CCodeFunctionCall (new CCodeIdentifier (((Method) mutex_type.scope.lookup ("lock")).get_cname ()));
3457 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3459 var cn = new CCodeFragment ();
3460 cn.append (new CCodeExpressionStatement (fc));
3461 stmt.ccodenode = cn;
3464 public override void visit_unlock_statement (UnlockStatement stmt) {
3465 var l = get_lock_expression (stmt, stmt.resource);
3467 var fc = new CCodeFunctionCall (new CCodeIdentifier (((Method) mutex_type.scope.lookup ("unlock")).get_cname ()));
3468 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
3470 var cn = new CCodeFragment ();
3471 cn.append (new CCodeExpressionStatement (fc));
3472 stmt.ccodenode = cn;
3475 public override void visit_delete_statement (DeleteStatement stmt) {
3476 stmt.accept_children (codegen);
3478 var pointer_type = (PointerType) stmt.expression.value_type;
3479 DataType type = pointer_type;
3480 if (pointer_type.base_type.data_type != null && pointer_type.base_type.data_type.is_reference_type ()) {
3481 type = pointer_type.base_type;
3484 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
3485 ccall.add_argument ((CCodeExpression) stmt.expression.ccodenode);
3486 stmt.ccodenode = new CCodeExpressionStatement (ccall);
3489 public override void visit_expression (Expression expr) {
3490 if (expr.ccodenode != null && !expr.lvalue) {
3491 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
3492 var st = expr.formal_value_type.type_parameter.parent_symbol.parent_symbol as Struct;
3493 if (expr.formal_value_type.type_parameter.parent_symbol != garray_type &&
3494 (st == null || st.get_cname () != "va_list")) {
3495 // GArray and va_list don't use pointer-based generics
3496 expr.ccodenode = convert_from_generic_pointer ((CCodeExpression) expr.ccodenode, expr.value_type);
3500 // memory management, implicit casts, and boxing/unboxing
3501 expr.ccodenode = transform_expression ((CCodeExpression) expr.ccodenode, expr.value_type, expr.target_type, expr);
3503 if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
3504 if (expr.formal_target_type.type_parameter.parent_symbol != garray_type) {
3505 // GArray doesn't use pointer-based generics
3506 expr.ccodenode = convert_to_generic_pointer ((CCodeExpression) expr.ccodenode, expr.target_type);
3512 public override void visit_boolean_literal (BooleanLiteral expr) {
3513 if (context.profile == Profile.GOBJECT) {
3514 expr.ccodenode = new CCodeConstant (expr.value ? "TRUE" : "FALSE");
3515 } else {
3516 source_declarations.add_include ("stdbool.h");
3517 expr.ccodenode = new CCodeConstant (expr.value ? "true" : "false");
3521 public override void visit_character_literal (CharacterLiteral expr) {
3522 if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
3523 expr.ccodenode = new CCodeConstant (expr.value);
3524 } else {
3525 expr.ccodenode = new CCodeConstant ("%uU".printf (expr.get_char ()));
3529 public override void visit_integer_literal (IntegerLiteral expr) {
3530 expr.ccodenode = new CCodeConstant (expr.value + expr.type_suffix);
3533 public override void visit_real_literal (RealLiteral expr) {
3534 string c_literal = expr.value;
3535 if (c_literal.has_suffix ("d") || c_literal.has_suffix ("D")) {
3536 // there is no suffix for double in C
3537 c_literal = c_literal.substring (0, c_literal.length - 1);
3539 if (!("." in c_literal || "e" in c_literal || "E" in c_literal)) {
3540 // C requires period or exponent part for floating constants
3541 if ("f" in c_literal || "F" in c_literal) {
3542 c_literal = c_literal.substring (0, c_literal.length - 1) + ".f";
3543 } else {
3544 c_literal += ".";
3547 expr.ccodenode = new CCodeConstant (c_literal);
3550 public override void visit_string_literal (StringLiteral expr) {
3551 expr.ccodenode = new CCodeConstant.string (expr.value);
3554 public override void visit_regex_literal (RegexLiteral expr) {
3555 string[] parts = expr.value.split ("/", 3);
3556 string re = parts[2].escape ("");
3557 string flags = "0";
3559 if (parts[1].contains ("i")) {
3560 flags += " | G_REGEX_CASELESS";
3562 if (parts[1].contains ("m")) {
3563 flags += " | G_REGEX_MULTILINE";
3565 if (parts[1].contains ("s")) {
3566 flags += " | G_REGEX_DOTALL";
3568 if (parts[1].contains ("x")) {
3569 flags += " | G_REGEX_EXTENDED";
3572 var regex_var = get_temp_variable (regex_type, true, expr, false);
3573 expr.temp_vars.add (regex_var);
3575 var cdecl = new CCodeDeclaration ("GRegex*");
3577 var cname = regex_var.name + "regex_" + next_regex_id.to_string ();
3578 this.next_regex_id++;
3580 cdecl.add_declarator (new CCodeVariableDeclarator (cname + " = NULL"));
3581 cdecl.modifiers = CCodeModifiers.STATIC;
3583 var regex_const = new CCodeConstant ("(%s == NULL) ? (%s = g_regex_new (\"".printf (cname, cname)
3584 + re + "\", " + flags + ", 0, NULL)) : %s".printf (cname));
3586 source_declarations.add_constant_declaration (cdecl);
3587 expr.ccodenode = regex_const;
3590 public override void visit_null_literal (NullLiteral expr) {
3591 if (context.profile != Profile.GOBJECT) {
3592 source_declarations.add_include ("stddef.h");
3594 expr.ccodenode = new CCodeConstant ("NULL");
3597 public virtual string get_delegate_target_cname (string delegate_cname) {
3598 assert_not_reached ();
3601 public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
3602 assert_not_reached ();
3605 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname) {
3606 assert_not_reached ();
3609 public override void visit_base_access (BaseAccess expr) {
3610 CCodeExpression this_access;
3611 if (current_method != null && current_method.coroutine) {
3612 // use closure
3613 this_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "self");
3614 } else {
3615 this_access = new CCodeIdentifier ("self");
3618 expr.ccodenode = generate_instance_cast (this_access, expr.value_type.data_type);
3621 public override void visit_postfix_expression (PostfixExpression expr) {
3622 MemberAccess ma = find_property_access (expr.inner);
3623 if (ma != null) {
3624 // property postfix expression
3625 var prop = (Property) ma.symbol_reference;
3627 var ccomma = new CCodeCommaExpression ();
3629 // assign current value to temp variable
3630 var temp_decl = get_temp_variable (prop.property_type, true, expr, false);
3631 temp_vars.insert (0, temp_decl);
3632 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_decl.name), (CCodeExpression) expr.inner.ccodenode));
3634 // increment/decrement property
3635 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
3636 var cexpr = new CCodeBinaryExpression (op, get_variable_cexpression (temp_decl.name), new CCodeConstant ("1"));
3637 var ccall = get_property_set_call (prop, ma, cexpr);
3638 ccomma.append_expression (ccall);
3640 // return previous value
3641 ccomma.append_expression (get_variable_cexpression (temp_decl.name));
3643 expr.ccodenode = ccomma;
3644 return;
3647 var op = expr.increment ? CCodeUnaryOperator.POSTFIX_INCREMENT : CCodeUnaryOperator.POSTFIX_DECREMENT;
3649 expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
3652 private MemberAccess? find_property_access (Expression expr) {
3653 if (!(expr is MemberAccess)) {
3654 return null;
3657 var ma = (MemberAccess) expr;
3658 if (ma.symbol_reference is Property) {
3659 return ma;
3662 return null;
3665 bool is_limited_generic_type (DataType type) {
3666 var cl = type.type_parameter.parent_symbol as Class;
3667 var st = type.type_parameter.parent_symbol as Struct;
3668 if ((cl != null && cl.is_compact) || st != null) {
3669 // compact classes and structs only
3670 // have very limited generics support
3671 return true;
3673 return false;
3676 public bool requires_copy (DataType type) {
3677 if (!type.is_disposable ()) {
3678 return false;
3681 var cl = type.data_type as Class;
3682 if (cl != null && cl.is_reference_counting ()
3683 && cl.get_ref_function () == "") {
3684 // empty ref_function => no ref necessary
3685 return false;
3688 if (type.type_parameter != null) {
3689 if (is_limited_generic_type (type)) {
3690 return false;
3694 return true;
3697 public bool requires_destroy (DataType type) {
3698 if (!type.is_disposable ()) {
3699 return false;
3702 var array_type = type as ArrayType;
3703 if (array_type != null && array_type.fixed_length) {
3704 return requires_destroy (array_type.element_type);
3707 var cl = type.data_type as Class;
3708 if (cl != null && cl.is_reference_counting ()
3709 && cl.get_unref_function () == "") {
3710 // empty unref_function => no unref necessary
3711 return false;
3714 if (type.type_parameter != null) {
3715 if (is_limited_generic_type (type)) {
3716 return false;
3720 return true;
3723 bool is_ref_function_void (DataType type) {
3724 var cl = type.data_type as Class;
3725 if (cl != null && cl.ref_function_void) {
3726 return true;
3727 } else {
3728 return false;
3732 public virtual CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
3733 if (expression_type is DelegateType) {
3734 return cexpr;
3737 if (expression_type is ValueType && !expression_type.nullable) {
3738 // normal value type, no null check
3739 // (copy (&expr, &temp), temp)
3741 var decl = get_temp_variable (expression_type, false, node);
3742 temp_vars.insert (0, decl);
3744 var ctemp = get_variable_cexpression (decl.name);
3746 var vt = (ValueType) expression_type;
3747 var st = (Struct) vt.type_symbol;
3748 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (st.get_copy_function ()));
3749 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
3750 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
3752 if (!st.has_copy_function) {
3753 generate_struct_copy_function (st);
3756 var ccomma = new CCodeCommaExpression ();
3758 if (st.get_copy_function () == "g_value_copy") {
3759 // GValue requires g_value_init in addition to g_value_copy
3761 var value_type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
3762 value_type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
3764 var init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
3765 init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
3766 init_call.add_argument (value_type_call);
3768 ccomma.append_expression (init_call);
3771 ccomma.append_expression (copy_call);
3772 ccomma.append_expression (ctemp);
3774 if (gvalue_type != null && expression_type.data_type == gvalue_type) {
3775 // g_value_init/copy must not be called for uninitialized values
3776 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
3777 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
3779 return new CCodeConditionalExpression (cisvalid, ccomma, cexpr);
3780 } else {
3781 return ccomma;
3785 /* (temp = expr, temp == NULL ? NULL : ref (temp))
3787 * can be simplified to
3788 * ref (expr)
3789 * if static type of expr is non-null
3792 var dupexpr = get_dup_func_expression (expression_type, node.source_reference);
3794 if (dupexpr == null) {
3795 node.error = true;
3796 return null;
3799 if (dupexpr is CCodeIdentifier && !(expression_type is ArrayType) && !(expression_type is GenericType) && !is_ref_function_void (expression_type)) {
3800 // generate and call NULL-aware ref function to reduce number
3801 // of temporary variables and simplify code
3803 var dupid = (CCodeIdentifier) dupexpr;
3804 string dup0_func = "_%s0".printf (dupid.name);
3806 // g_strdup is already NULL-safe
3807 if (dupid.name == "g_strdup") {
3808 dup0_func = dupid.name;
3809 } else if (add_wrapper (dup0_func)) {
3810 string pointer_cname = "gpointer";
3811 if (context.profile == Profile.POSIX) {
3812 pointer_cname = "void*";
3814 var dup0_fun = new CCodeFunction (dup0_func, pointer_cname);
3815 dup0_fun.add_parameter (new CCodeFormalParameter ("self", pointer_cname));
3816 dup0_fun.modifiers = CCodeModifiers.STATIC;
3817 dup0_fun.block = new CCodeBlock ();
3819 var dup_call = new CCodeFunctionCall (dupexpr);
3820 dup_call.add_argument (new CCodeIdentifier ("self"));
3822 dup0_fun.block.add_statement (new CCodeReturnStatement (new CCodeConditionalExpression (new CCodeIdentifier ("self"), dup_call, new CCodeConstant ("NULL"))));
3824 source_type_member_definition.append (dup0_fun);
3827 var ccall = new CCodeFunctionCall (new CCodeIdentifier (dup0_func));
3828 ccall.add_argument (cexpr);
3829 return ccall;
3832 var ccall = new CCodeFunctionCall (dupexpr);
3834 if (!(expression_type is ArrayType) && expr != null && expr.is_non_null ()
3835 && !is_ref_function_void (expression_type)) {
3836 // expression is non-null
3837 ccall.add_argument ((CCodeExpression) expr.ccodenode);
3839 return ccall;
3840 } else {
3841 var decl = get_temp_variable (expression_type, false, node, false);
3842 temp_vars.insert (0, decl);
3844 var ctemp = get_variable_cexpression (decl.name);
3846 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL"));
3847 if (expression_type.type_parameter != null) {
3848 // dup functions are optional for type parameters
3849 var cdupisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_dup_func_expression (expression_type, node.source_reference), new CCodeConstant ("NULL"));
3850 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cdupisnull);
3853 if (expression_type.type_parameter != null) {
3854 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
3855 ccall.add_argument (new CCodeCastExpression (ctemp, "gpointer"));
3856 } else {
3857 ccall.add_argument (ctemp);
3860 if (expression_type is ArrayType) {
3861 var array_type = (ArrayType) expression_type;
3862 bool first = true;
3863 CCodeExpression csizeexpr = null;
3864 for (int dim = 1; dim <= array_type.rank; dim++) {
3865 if (first) {
3866 csizeexpr = head.get_array_length_cexpression (expr, dim);
3867 first = false;
3868 } else {
3869 csizeexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeexpr, head.get_array_length_cexpression (expr, dim));
3873 ccall.add_argument (csizeexpr);
3875 if (array_type.element_type is GenericType) {
3876 var elem_dupexpr = get_dup_func_expression (array_type.element_type, node.source_reference);
3877 if (elem_dupexpr == null) {
3878 elem_dupexpr = new CCodeConstant ("NULL");
3880 ccall.add_argument (elem_dupexpr);
3884 var ccomma = new CCodeCommaExpression ();
3885 ccomma.append_expression (new CCodeAssignment (ctemp, cexpr));
3887 CCodeExpression cifnull;
3888 if (expression_type.data_type != null) {
3889 cifnull = new CCodeConstant ("NULL");
3890 } else {
3891 // the value might be non-null even when the dup function is null,
3892 // so we may not just use NULL for type parameters
3894 // cast from gconstpointer to gpointer as methods in
3895 // generic classes may not return gconstpointer
3896 cifnull = new CCodeCastExpression (ctemp, "gpointer");
3898 ccomma.append_expression (new CCodeConditionalExpression (cisnull, cifnull, ccall));
3900 // repeat temp variable at the end of the comma expression
3901 // if the ref function returns void
3902 if (is_ref_function_void (expression_type)) {
3903 ccomma.append_expression (ctemp);
3906 return ccomma;
3910 bool is_reference_type_argument (DataType type_arg) {
3911 if (type_arg.data_type != null && type_arg.data_type.is_reference_type ()) {
3912 return true;
3913 } else {
3914 return false;
3918 bool is_nullable_value_type_argument (DataType type_arg) {
3919 if (type_arg is ValueType && type_arg.nullable) {
3920 return true;
3921 } else {
3922 return false;
3926 bool is_signed_integer_type_argument (DataType type_arg) {
3927 var st = type_arg.data_type as Struct;
3928 if (type_arg.nullable) {
3929 return false;
3930 } else if (st == bool_type.data_type) {
3931 return true;
3932 } else if (st == char_type.data_type) {
3933 return true;
3934 } else if (unichar_type != null && st == unichar_type.data_type) {
3935 return true;
3936 } else if (st == short_type.data_type) {
3937 return true;
3938 } else if (st == int_type.data_type) {
3939 return true;
3940 } else if (st == long_type.data_type) {
3941 return true;
3942 } else if (st == int8_type.data_type) {
3943 return true;
3944 } else if (st == int16_type.data_type) {
3945 return true;
3946 } else if (st == int32_type.data_type) {
3947 return true;
3948 } else if (st == gtype_type) {
3949 return true;
3950 } else if (type_arg is EnumValueType) {
3951 return true;
3952 } else {
3953 return false;
3957 bool is_unsigned_integer_type_argument (DataType type_arg) {
3958 var st = type_arg.data_type as Struct;
3959 if (type_arg.nullable) {
3960 return false;
3961 } else if (st == uchar_type.data_type) {
3962 return true;
3963 } else if (st == ushort_type.data_type) {
3964 return true;
3965 } else if (st == uint_type.data_type) {
3966 return true;
3967 } else if (st == ulong_type.data_type) {
3968 return true;
3969 } else if (st == uint8_type.data_type) {
3970 return true;
3971 } else if (st == uint16_type.data_type) {
3972 return true;
3973 } else if (st == uint32_type.data_type) {
3974 return true;
3975 } else {
3976 return false;
3980 public void check_type (DataType type) {
3981 var array_type = type as ArrayType;
3982 if (array_type != null) {
3983 check_type (array_type.element_type);
3985 foreach (var type_arg in type.get_type_arguments ()) {
3986 check_type (type_arg);
3987 check_type_argument (type_arg);
3991 void check_type_argument (DataType type_arg) {
3992 if (type_arg is GenericType
3993 || type_arg is PointerType
3994 || is_reference_type_argument (type_arg)
3995 || is_nullable_value_type_argument (type_arg)
3996 || is_signed_integer_type_argument (type_arg)
3997 || is_unsigned_integer_type_argument (type_arg)) {
3998 // no error
3999 } else if (type_arg is DelegateType) {
4000 var delegate_type = (DelegateType) type_arg;
4001 if (delegate_type.delegate_symbol.has_target) {
4002 Report.error (type_arg.source_reference, "Delegates with target are not supported as generic type arguments");
4004 } else {
4005 Report.error (type_arg.source_reference, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg.to_string ()));
4009 public virtual void generate_class_declaration (Class cl, CCodeDeclarationSpace decl_space) {
4010 if (decl_space.add_symbol_declaration (cl, cl.get_cname ())) {
4011 return;
4015 public virtual void generate_interface_declaration (Interface iface, CCodeDeclarationSpace decl_space) {
4018 public virtual void generate_method_declaration (Method m, CCodeDeclarationSpace decl_space) {
4021 public virtual void generate_error_domain_declaration (ErrorDomain edomain, CCodeDeclarationSpace decl_space) {
4024 public void add_generic_type_arguments (Map<int,CCodeExpression> arg_map, List<DataType> type_args, CodeNode expr, bool is_chainup = false) {
4025 int type_param_index = 0;
4026 foreach (var type_arg in type_args) {
4027 arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), get_type_id_expression (type_arg, is_chainup));
4028 if (requires_copy (type_arg)) {
4029 var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference, is_chainup);
4030 if (dup_func == null) {
4031 // type doesn't contain a copy function
4032 expr.error = true;
4033 return;
4035 arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
4036 arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), get_destroy_func_expression (type_arg, is_chainup));
4037 } else {
4038 arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeConstant ("NULL"));
4039 arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
4041 type_param_index++;
4045 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
4046 expr.accept_children (codegen);
4048 CCodeExpression instance = null;
4049 CCodeExpression creation_expr = null;
4051 check_type (expr.type_reference);
4053 var st = expr.type_reference.data_type as Struct;
4054 if ((st != null && (!st.is_simple_type () || st.get_cname () == "va_list")) || expr.get_object_initializer ().size > 0) {
4055 // value-type initialization or object creation expression with object initializer
4057 var local = expr.parent_node as LocalVariable;
4058 if (local != null && has_simple_struct_initializer (local)) {
4059 instance = get_variable_cexpression (get_variable_cname (local.name));
4060 } else {
4061 var temp_decl = get_temp_variable (expr.type_reference, false, expr);
4062 temp_vars.add (temp_decl);
4064 instance = get_variable_cexpression (get_variable_cname (temp_decl.name));
4068 if (expr.symbol_reference == null) {
4069 // no creation method
4070 if (expr.type_reference.data_type is Struct) {
4071 // memset needs string.h
4072 source_declarations.add_include ("string.h");
4073 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4074 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4075 creation_call.add_argument (new CCodeConstant ("0"));
4076 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (expr.type_reference.get_cname ())));
4078 creation_expr = creation_call;
4080 } else if (expr.type_reference.data_type == glist_type ||
4081 expr.type_reference.data_type == gslist_type) {
4082 // NULL is an empty list
4083 expr.ccodenode = new CCodeConstant ("NULL");
4084 } else if (expr.symbol_reference is Method) {
4085 // use creation method
4086 var m = (Method) expr.symbol_reference;
4087 var params = m.get_parameters ();
4088 CCodeFunctionCall creation_call;
4090 generate_method_declaration (m, source_declarations);
4092 var cl = expr.type_reference.data_type as Class;
4094 if (!m.has_new_function) {
4095 // use construct function directly
4096 creation_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
4097 creation_call.add_argument (new CCodeIdentifier (cl.get_type_id ()));
4098 } else {
4099 creation_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
4102 if ((st != null && !st.is_simple_type ()) && !(m.cinstance_parameter_position < 0)) {
4103 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4104 } else if (st != null && st.get_cname () == "va_list") {
4105 creation_call.add_argument (instance);
4106 if (m.get_cname () == "va_start") {
4107 FormalParameter last_param = null;
4108 foreach (var param in current_method.get_parameters ()) {
4109 if (param.ellipsis) {
4110 break;
4112 last_param = param;
4114 creation_call.add_argument (new CCodeIdentifier (get_variable_cname (last_param.name)));
4118 generate_type_declaration (expr.type_reference, source_declarations);
4120 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
4122 if (cl != null && !cl.is_compact) {
4123 add_generic_type_arguments (carg_map, expr.type_reference.get_type_arguments (), expr);
4126 bool ellipsis = false;
4128 int i = 1;
4129 int arg_pos;
4130 Iterator<FormalParameter> params_it = params.iterator ();
4131 foreach (Expression arg in expr.get_argument_list ()) {
4132 CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
4133 FormalParameter param = null;
4134 if (params_it.next ()) {
4135 param = params_it.get ();
4136 ellipsis = param.ellipsis;
4137 if (!ellipsis) {
4138 if (!param.no_array_length && param.parameter_type is ArrayType) {
4139 var array_type = (ArrayType) param.parameter_type;
4140 for (int dim = 1; dim <= array_type.rank; dim++) {
4141 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), head.get_array_length_cexpression (arg, dim));
4143 } else if (param.parameter_type is DelegateType) {
4144 var deleg_type = (DelegateType) param.parameter_type;
4145 var d = deleg_type.delegate_symbol;
4146 if (d.has_target) {
4147 CCodeExpression delegate_target_destroy_notify;
4148 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
4149 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), delegate_target);
4150 if (deleg_type.value_owned) {
4151 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), delegate_target_destroy_notify);
4156 cexpr = handle_struct_argument (param, arg, cexpr);
4158 if (param.ctype != null) {
4159 cexpr = new CCodeCastExpression (cexpr, param.ctype);
4163 arg_pos = get_param_pos (param.cparameter_position, ellipsis);
4164 } else {
4165 // default argument position
4166 arg_pos = get_param_pos (i, ellipsis);
4169 carg_map.set (arg_pos, cexpr);
4171 i++;
4173 while (params_it.next ()) {
4174 var param = params_it.get ();
4176 if (param.ellipsis) {
4177 ellipsis = true;
4178 break;
4181 if (param.default_expression == null) {
4182 Report.error (expr.source_reference, "no default expression for argument %d".printf (i));
4183 return;
4186 /* evaluate default expression here as the code
4187 * generator might not have visited the formal
4188 * parameter yet */
4189 param.default_expression.accept (codegen);
4191 carg_map.set (get_param_pos (param.cparameter_position), (CCodeExpression) param.default_expression.ccodenode);
4192 i++;
4195 // append C arguments in the right order
4196 int last_pos = -1;
4197 int min_pos;
4198 while (true) {
4199 min_pos = -1;
4200 foreach (int pos in carg_map.get_keys ()) {
4201 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
4202 min_pos = pos;
4205 if (min_pos == -1) {
4206 break;
4208 creation_call.add_argument (carg_map.get (min_pos));
4209 last_pos = min_pos;
4212 if ((st != null && !st.is_simple_type ()) && m.cinstance_parameter_position < 0) {
4213 // instance parameter is at the end in a struct creation method
4214 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
4217 if (expr.tree_can_fail) {
4218 // method can fail
4219 current_method_inner_error = true;
4220 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
4223 if (ellipsis) {
4224 /* ensure variable argument list ends with NULL
4225 * except when using printf-style arguments */
4226 if (!m.printf_format && !m.scanf_format && m.sentinel != "") {
4227 creation_call.add_argument (new CCodeConstant (m.sentinel));
4231 creation_expr = creation_call;
4233 // cast the return value of the creation method back to the intended type if
4234 // it requested a special C return type
4235 if (head.get_custom_creturn_type (m) != null) {
4236 creation_expr = new CCodeCastExpression (creation_expr, expr.type_reference.get_cname ());
4238 } else if (expr.symbol_reference is ErrorCode) {
4239 var ecode = (ErrorCode) expr.symbol_reference;
4240 var edomain = (ErrorDomain) ecode.parent_symbol;
4241 CCodeFunctionCall creation_call;
4243 generate_error_domain_declaration (edomain, source_declarations);
4245 if (expr.get_argument_list ().size == 1) {
4246 // must not be a format argument
4247 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new_literal"));
4248 } else {
4249 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new"));
4251 creation_call.add_argument (new CCodeIdentifier (edomain.get_upper_case_cname ()));
4252 creation_call.add_argument (new CCodeIdentifier (ecode.get_cname ()));
4254 foreach (Expression arg in expr.get_argument_list ()) {
4255 creation_call.add_argument ((CCodeExpression) arg.ccodenode);
4258 creation_expr = creation_call;
4259 } else {
4260 assert (false);
4263 var local = expr.parent_node as LocalVariable;
4264 if (local != null && has_simple_struct_initializer (local)) {
4265 // no comma expression necessary
4266 expr.ccodenode = creation_expr;
4267 } else if (instance != null) {
4268 var ccomma = new CCodeCommaExpression ();
4270 if (expr.type_reference.data_type is Struct) {
4271 ccomma.append_expression (creation_expr);
4272 } else {
4273 ccomma.append_expression (new CCodeAssignment (instance, creation_expr));
4276 foreach (MemberInitializer init in expr.get_object_initializer ()) {
4277 if (init.symbol_reference is Field) {
4278 var f = (Field) init.symbol_reference;
4279 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
4280 var typed_inst = transform_expression (instance, expr.type_reference, instance_target_type);
4281 CCodeExpression lhs;
4282 if (expr.type_reference.data_type is Struct) {
4283 lhs = new CCodeMemberAccess (typed_inst, f.get_cname ());
4284 } else {
4285 lhs = new CCodeMemberAccess.pointer (typed_inst, f.get_cname ());
4287 ccomma.append_expression (new CCodeAssignment (lhs, (CCodeExpression) init.initializer.ccodenode));
4289 if (f.field_type is ArrayType && !f.no_array_length) {
4290 var array_type = (ArrayType) f.field_type;
4291 for (int dim = 1; dim <= array_type.rank; dim++) {
4292 if (expr.type_reference.data_type is Struct) {
4293 lhs = new CCodeMemberAccess (typed_inst, head.get_array_length_cname (f.get_cname (), dim));
4294 } else {
4295 lhs = new CCodeMemberAccess.pointer (typed_inst, head.get_array_length_cname (f.get_cname (), dim));
4297 var rhs_array_len = head.get_array_length_cexpression (init.initializer, dim);
4298 ccomma.append_expression (new CCodeAssignment (lhs, rhs_array_len));
4300 } else if (f.field_type is DelegateType && !f.no_delegate_target) {
4301 if (expr.type_reference.data_type is Struct) {
4302 lhs = new CCodeMemberAccess (typed_inst, get_delegate_target_cname (f.get_cname ()));
4303 } else {
4304 lhs = new CCodeMemberAccess.pointer (typed_inst, get_delegate_target_cname (f.get_cname ()));
4306 CCodeExpression rhs_delegate_target_destroy_notify;
4307 var rhs_delegate_target = get_delegate_target_cexpression (init.initializer, out rhs_delegate_target_destroy_notify);
4308 ccomma.append_expression (new CCodeAssignment (lhs, rhs_delegate_target));
4311 var cl = f.parent_symbol as Class;
4312 if (cl != null) {
4313 generate_class_struct_declaration (cl, source_declarations);
4315 } else if (init.symbol_reference is Property) {
4316 var inst_ma = new MemberAccess.simple ("new");
4317 inst_ma.value_type = expr.type_reference;
4318 inst_ma.ccodenode = instance;
4319 var ma = new MemberAccess (inst_ma, init.name);
4320 ccomma.append_expression (get_property_set_call ((Property) init.symbol_reference, ma, (CCodeExpression) init.initializer.ccodenode));
4324 ccomma.append_expression (instance);
4326 expr.ccodenode = ccomma;
4327 } else if (creation_expr != null) {
4328 expr.ccodenode = creation_expr;
4332 public CCodeExpression? handle_struct_argument (FormalParameter param, Expression arg, CCodeExpression? cexpr) {
4333 // pass non-simple struct instances always by reference
4334 if (!(arg.value_type is NullType) && param.parameter_type.data_type is Struct && !((Struct) param.parameter_type.data_type).is_simple_type ()) {
4335 // we already use a reference for arguments of ref, out, and nullable parameters
4336 if (param.direction == ParameterDirection.IN && !param.parameter_type.nullable) {
4337 var unary = cexpr as CCodeUnaryExpression;
4338 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
4339 // *expr => expr
4340 return unary.inner;
4341 } else if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
4342 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
4343 } else {
4344 // if cexpr is e.g. a function call, we can't take the address of the expression
4345 // (tmp = expr, &tmp)
4346 var ccomma = new CCodeCommaExpression ();
4348 var temp_var = get_temp_variable (param.parameter_type, true, null, false);
4349 temp_vars.insert (0, temp_var);
4350 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), cexpr));
4351 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name)));
4353 return ccomma;
4358 return cexpr;
4361 public override void visit_sizeof_expression (SizeofExpression expr) {
4362 generate_type_declaration (expr.type_reference, source_declarations);
4364 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
4365 csizeof.add_argument (new CCodeIdentifier (expr.type_reference.get_cname ()));
4366 expr.ccodenode = csizeof;
4369 public override void visit_typeof_expression (TypeofExpression expr) {
4370 expr.ccodenode = get_type_id_expression (expr.type_reference);
4373 public override void visit_unary_expression (UnaryExpression expr) {
4374 expr.accept_children (codegen);
4376 CCodeUnaryOperator op;
4377 if (expr.operator == UnaryOperator.PLUS) {
4378 op = CCodeUnaryOperator.PLUS;
4379 } else if (expr.operator == UnaryOperator.MINUS) {
4380 op = CCodeUnaryOperator.MINUS;
4381 } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
4382 op = CCodeUnaryOperator.LOGICAL_NEGATION;
4383 } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
4384 op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
4385 } else if (expr.operator == UnaryOperator.INCREMENT) {
4386 op = CCodeUnaryOperator.PREFIX_INCREMENT;
4387 } else if (expr.operator == UnaryOperator.DECREMENT) {
4388 op = CCodeUnaryOperator.PREFIX_DECREMENT;
4389 } else if (expr.operator == UnaryOperator.REF) {
4390 op = CCodeUnaryOperator.ADDRESS_OF;
4391 } else if (expr.operator == UnaryOperator.OUT) {
4392 op = CCodeUnaryOperator.ADDRESS_OF;
4393 } else {
4394 assert_not_reached ();
4396 expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
4399 public CCodeExpression? try_cast_value_to_type (CCodeExpression ccodeexpr, DataType from, DataType to, Expression? expr = null) {
4400 if (from == null || gvalue_type == null || from.data_type != gvalue_type || to.get_type_id () == null) {
4401 return null;
4404 // explicit conversion from GValue
4405 var ccall = new CCodeFunctionCall (get_value_getter_function (to));
4406 CCodeExpression gvalue;
4407 if (from.nullable) {
4408 gvalue = ccodeexpr;
4409 } else {
4410 gvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ccodeexpr);
4412 ccall.add_argument (gvalue);
4414 CCodeExpression rv = ccall;
4416 if (expr != null && to is ArrayType) {
4417 // null-terminated string array
4418 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
4419 len_call.add_argument (rv);
4420 expr.append_array_size (len_call);
4421 } else if (to is StructValueType) {
4422 var temp_decl = get_temp_variable (to, true, null, true);
4423 temp_vars.add (temp_decl);
4424 var ctemp = get_variable_cexpression (temp_decl.name);
4426 rv = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeCastExpression (rv, (new PointerType(to)).get_cname ()));
4427 var holds = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_HOLDS"));
4428 holds.add_argument (gvalue);
4429 holds.add_argument (new CCodeIdentifier (to.get_type_id ()));
4430 var cond = new CCodeBinaryExpression (CCodeBinaryOperator.AND, holds, ccall);
4431 var warn = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
4432 warn.add_argument (new CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
4433 var fail = new CCodeCommaExpression ();
4434 fail.append_expression (warn);
4435 fail.append_expression (ctemp);
4436 rv = new CCodeConditionalExpression (cond, rv, fail);
4439 return rv;
4442 public override void visit_cast_expression (CastExpression expr) {
4443 var valuecast = try_cast_value_to_type ((CCodeExpression) expr.inner.ccodenode, expr.inner.value_type, expr.type_reference, expr);
4444 if (valuecast != null) {
4445 expr.ccodenode = valuecast;
4446 return;
4449 generate_type_declaration (expr.type_reference, source_declarations);
4451 var cl = expr.type_reference.data_type as Class;
4452 var iface = expr.type_reference.data_type as Interface;
4453 if (context.profile == Profile.GOBJECT && (iface != null || (cl != null && !cl.is_compact))) {
4454 // checked cast for strict subtypes of GTypeInstance
4455 if (expr.is_silent_cast) {
4456 var ccomma = new CCodeCommaExpression ();
4457 var temp_decl = get_temp_variable (expr.inner.value_type, true, expr, false);
4459 temp_vars.add (temp_decl);
4461 var ctemp = get_variable_cexpression (temp_decl.name);
4462 var cinit = new CCodeAssignment (ctemp, (CCodeExpression) expr.inner.ccodenode);
4463 var ccheck = create_type_check (ctemp, expr.type_reference);
4464 var ccast = new CCodeCastExpression (ctemp, expr.type_reference.get_cname ());
4465 var cnull = new CCodeConstant ("NULL");
4467 ccomma.append_expression (cinit);
4468 ccomma.append_expression (new CCodeConditionalExpression (ccheck, ccast, cnull));
4470 expr.ccodenode = ccomma;
4471 } else {
4472 expr.ccodenode = generate_instance_cast ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.data_type);
4474 } else {
4475 if (expr.is_silent_cast) {
4476 expr.error = true;
4477 Report.error (expr.source_reference, "Operation not supported for this type");
4478 return;
4481 // retain array length
4482 var array_type = expr.type_reference as ArrayType;
4483 if (array_type != null && expr.inner.value_type is ArrayType) {
4484 for (int dim = 1; dim <= array_type.rank; dim++) {
4485 expr.append_array_size (get_array_length_cexpression (expr.inner, dim));
4489 var innercexpr = (CCodeExpression) expr.inner.ccodenode;
4490 if (expr.type_reference.data_type is Struct && !expr.type_reference.nullable &&
4491 expr.inner.value_type.data_type is Struct && expr.inner.value_type.nullable) {
4492 // nullable integer or float or boolean or struct cast to non-nullable
4493 innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, innercexpr);
4495 expr.ccodenode = new CCodeCastExpression (innercexpr, expr.type_reference.get_cname ());
4499 public override void visit_named_argument (NamedArgument expr) {
4500 expr.accept_children (codegen);
4502 expr.ccodenode = expr.inner.ccodenode;
4505 public override void visit_pointer_indirection (PointerIndirection expr) {
4506 expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, (CCodeExpression) expr.inner.ccodenode);
4509 public override void visit_addressof_expression (AddressofExpression expr) {
4510 if (expr.inner.ccodenode is CCodeCommaExpression) {
4511 var ccomma = expr.inner.ccodenode as CCodeCommaExpression;
4512 var inner = ccomma.get_inner ();
4513 var last = inner.get (inner.size - 1);
4514 ccomma.set_expression (inner.size - 1, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, (CCodeExpression) last));
4515 expr.ccodenode = ccomma;
4516 } else {
4517 expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, (CCodeExpression) expr.inner.ccodenode);
4521 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
4522 expr.accept_children (codegen);
4524 /* (tmp = var, var = null, tmp) */
4525 var ccomma = new CCodeCommaExpression ();
4526 var temp_decl = get_temp_variable (expr.value_type, true, expr, false);
4527 temp_vars.insert (0, temp_decl);
4528 var cvar = get_variable_cexpression (temp_decl.name);
4530 ccomma.append_expression (new CCodeAssignment (cvar, (CCodeExpression) expr.inner.ccodenode));
4531 ccomma.append_expression (new CCodeAssignment ((CCodeExpression) expr.inner.ccodenode, new CCodeConstant ("NULL")));
4532 ccomma.append_expression (cvar);
4533 expr.ccodenode = ccomma;
4536 public override void visit_binary_expression (BinaryExpression expr) {
4537 expr.accept_children (codegen);
4539 var cleft = (CCodeExpression) expr.left.ccodenode;
4540 var cright = (CCodeExpression) expr.right.ccodenode;
4542 CCodeExpression? left_chain = null;
4543 if (expr.chained) {
4544 var lbe = (BinaryExpression) expr.left;
4546 var temp_decl = get_temp_variable (lbe.right.value_type, true, null, false);
4547 temp_vars.insert (0, temp_decl);
4548 var cvar = get_variable_cexpression (temp_decl.name);
4549 var ccomma = new CCodeCommaExpression ();
4550 var clbe = (CCodeBinaryExpression) lbe.ccodenode;
4551 if (lbe.chained) {
4552 clbe = (CCodeBinaryExpression) clbe.right;
4554 ccomma.append_expression (new CCodeAssignment (cvar, (CCodeExpression)lbe.right.ccodenode));
4555 clbe.right = get_variable_cexpression (temp_decl.name);
4556 ccomma.append_expression (cleft);
4557 cleft = cvar;
4558 left_chain = ccomma;
4561 CCodeBinaryOperator op;
4562 if (expr.operator == BinaryOperator.PLUS) {
4563 op = CCodeBinaryOperator.PLUS;
4564 } else if (expr.operator == BinaryOperator.MINUS) {
4565 op = CCodeBinaryOperator.MINUS;
4566 } else if (expr.operator == BinaryOperator.MUL) {
4567 op = CCodeBinaryOperator.MUL;
4568 } else if (expr.operator == BinaryOperator.DIV) {
4569 op = CCodeBinaryOperator.DIV;
4570 } else if (expr.operator == BinaryOperator.MOD) {
4571 if (expr.value_type.equals (double_type)) {
4572 source_declarations.add_include ("math.h");
4573 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
4574 ccall.add_argument (cleft);
4575 ccall.add_argument (cright);
4576 expr.ccodenode = ccall;
4577 return;
4578 } else if (expr.value_type.equals (float_type)) {
4579 source_declarations.add_include ("math.h");
4580 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
4581 ccall.add_argument (cleft);
4582 ccall.add_argument (cright);
4583 expr.ccodenode = ccall;
4584 return;
4585 } else {
4586 op = CCodeBinaryOperator.MOD;
4588 } else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
4589 op = CCodeBinaryOperator.SHIFT_LEFT;
4590 } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
4591 op = CCodeBinaryOperator.SHIFT_RIGHT;
4592 } else if (expr.operator == BinaryOperator.LESS_THAN) {
4593 op = CCodeBinaryOperator.LESS_THAN;
4594 } else if (expr.operator == BinaryOperator.GREATER_THAN) {
4595 op = CCodeBinaryOperator.GREATER_THAN;
4596 } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
4597 op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
4598 } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
4599 op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
4600 } else if (expr.operator == BinaryOperator.EQUALITY) {
4601 op = CCodeBinaryOperator.EQUALITY;
4602 } else if (expr.operator == BinaryOperator.INEQUALITY) {
4603 op = CCodeBinaryOperator.INEQUALITY;
4604 } else if (expr.operator == BinaryOperator.BITWISE_AND) {
4605 op = CCodeBinaryOperator.BITWISE_AND;
4606 } else if (expr.operator == BinaryOperator.BITWISE_OR) {
4607 op = CCodeBinaryOperator.BITWISE_OR;
4608 } else if (expr.operator == BinaryOperator.BITWISE_XOR) {
4609 op = CCodeBinaryOperator.BITWISE_XOR;
4610 } else if (expr.operator == BinaryOperator.AND) {
4611 op = CCodeBinaryOperator.AND;
4612 } else if (expr.operator == BinaryOperator.OR) {
4613 op = CCodeBinaryOperator.OR;
4614 } else if (expr.operator == BinaryOperator.IN) {
4615 if (expr.right.value_type is ArrayType) {
4616 var array_type = (ArrayType) expr.right.value_type;
4617 var node = new CCodeFunctionCall (new CCodeIdentifier (generate_array_contains_wrapper (array_type)));
4618 node.add_argument (cright);
4619 node.add_argument (get_array_length_cexpression (expr.right));
4620 if (array_type.element_type is StructValueType) {
4621 node.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft));
4622 } else {
4623 node.add_argument (cleft);
4625 expr.ccodenode = node;
4626 } else {
4627 expr.ccodenode = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft);
4629 return;
4630 } else {
4631 assert_not_reached ();
4634 if (expr.operator == BinaryOperator.EQUALITY ||
4635 expr.operator == BinaryOperator.INEQUALITY) {
4636 var left_type = expr.left.target_type;
4637 var right_type = expr.right.target_type;
4638 make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
4640 if (left_type is StructValueType && right_type is StructValueType) {
4641 var equalfunc = generate_struct_equal_function ((Struct) left_type.data_type as Struct);
4642 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
4643 ccall.add_argument (cleft);
4644 ccall.add_argument (cright);
4645 cleft = ccall;
4646 cright = new CCodeConstant ("TRUE");
4647 } else if ((left_type is IntegerType || left_type is FloatingType || left_type is BooleanType) && left_type.nullable &&
4648 (right_type is IntegerType || right_type is FloatingType || right_type is BooleanType) && right_type.nullable) {
4649 var equalfunc = generate_numeric_equal_function ((Struct) left_type.data_type as Struct);
4650 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
4651 ccall.add_argument (cleft);
4652 ccall.add_argument (cright);
4653 cleft = ccall;
4654 cright = new CCodeConstant ("TRUE");
4658 if (!(expr.left.value_type is NullType)
4659 && expr.left.value_type.compatible (string_type)
4660 && !(expr.right.value_type is NullType)
4661 && expr.right.value_type.compatible (string_type)) {
4662 if (expr.operator == BinaryOperator.PLUS) {
4663 // string concatenation
4664 if (expr.left.is_constant () && expr.right.is_constant ()) {
4665 string left, right;
4667 if (cleft is CCodeIdentifier) {
4668 left = ((CCodeIdentifier) cleft).name;
4669 } else if (cleft is CCodeConstant) {
4670 left = ((CCodeConstant) cleft).name;
4671 } else {
4672 assert_not_reached ();
4674 if (cright is CCodeIdentifier) {
4675 right = ((CCodeIdentifier) cright).name;
4676 } else if (cright is CCodeConstant) {
4677 right = ((CCodeConstant) cright).name;
4678 } else {
4679 assert_not_reached ();
4682 expr.ccodenode = new CCodeConstant ("%s %s".printf (left, right));
4683 return;
4684 } else {
4685 if (context.profile == Profile.POSIX) {
4686 // convert to strcat(strcpy(malloc(1+strlen(a)+strlen(b)),a),b)
4687 var strcat = new CCodeFunctionCall (new CCodeIdentifier ("strcat"));
4688 var strcpy = new CCodeFunctionCall (new CCodeIdentifier ("strcpy"));
4689 var malloc = new CCodeFunctionCall (new CCodeIdentifier ("malloc"));
4691 var strlen_a = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
4692 strlen_a.add_argument(cleft);
4693 var strlen_b = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
4694 strlen_b.add_argument(cright);
4695 var newlength = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier("1"),
4696 new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, strlen_a, strlen_b));
4697 malloc.add_argument(newlength);
4699 strcpy.add_argument(malloc);
4700 strcpy.add_argument(cleft);
4702 strcat.add_argument(strcpy);
4703 strcat.add_argument(cright);
4704 expr.ccodenode = strcat;
4705 } else {
4706 // convert to g_strconcat (a, b, NULL)
4707 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
4708 ccall.add_argument (cleft);
4709 ccall.add_argument (cright);
4710 ccall.add_argument (new CCodeConstant("NULL"));
4711 expr.ccodenode = ccall;
4713 return;
4715 } else if (expr.operator == BinaryOperator.EQUALITY
4716 || expr.operator == BinaryOperator.INEQUALITY
4717 || expr.operator == BinaryOperator.LESS_THAN
4718 || expr.operator == BinaryOperator.GREATER_THAN
4719 || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL
4720 || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
4721 requires_strcmp0 = true;
4722 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_strcmp0"));
4723 ccall.add_argument (cleft);
4724 ccall.add_argument (cright);
4725 cleft = ccall;
4726 cright = new CCodeConstant ("0");
4730 expr.ccodenode = new CCodeBinaryExpression (op, cleft, cright);
4731 if (left_chain != null) {
4732 expr.ccodenode = new CCodeBinaryExpression (CCodeBinaryOperator.AND, left_chain, (CCodeExpression) expr.ccodenode);
4736 public string? get_type_check_function (TypeSymbol type) {
4737 var cl = type as Class;
4738 if (cl != null && cl.type_check_function != null) {
4739 return cl.type_check_function;
4740 } else if ((cl != null && cl.is_compact) || type is Struct || type is Enum || type is Delegate) {
4741 return null;
4742 } else {
4743 return type.get_upper_case_cname ("IS_");
4747 CCodeExpression? create_type_check (CCodeNode ccodenode, DataType type) {
4748 var et = type as ErrorType;
4749 if (et != null && et.error_code != null) {
4750 var matches_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
4751 matches_call.add_argument ((CCodeExpression) ccodenode);
4752 matches_call.add_argument (new CCodeIdentifier (et.error_domain.get_upper_case_cname ()));
4753 matches_call.add_argument (new CCodeIdentifier (et.error_code.get_cname ()));
4754 return matches_call;
4755 } else if (et != null && et.error_domain != null) {
4756 var instance_domain = new CCodeMemberAccess.pointer ((CCodeExpression) ccodenode, "domain");
4757 var type_domain = new CCodeIdentifier (et.error_domain.get_upper_case_cname ());
4758 return new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, instance_domain, type_domain);
4759 } else {
4760 string type_check_func = get_type_check_function (type.data_type);
4761 if (type_check_func == null) {
4762 return new CCodeInvalidExpression ();
4764 var ccheck = new CCodeFunctionCall (new CCodeIdentifier (type_check_func));
4765 ccheck.add_argument ((CCodeExpression) ccodenode);
4766 return ccheck;
4770 string generate_array_contains_wrapper (ArrayType array_type) {
4771 string array_contains_func = "_vala_%s_array_contains".printf (array_type.element_type.get_lower_case_cname ());
4773 if (!add_wrapper (array_contains_func)) {
4774 return array_contains_func;
4777 var function = new CCodeFunction (array_contains_func, "gboolean");
4778 function.modifiers = CCodeModifiers.STATIC;
4780 function.add_parameter (new CCodeFormalParameter ("stack", array_type.get_cname ()));
4781 function.add_parameter (new CCodeFormalParameter ("stack_length", "int"));
4782 if (array_type.element_type is StructValueType) {
4783 function.add_parameter (new CCodeFormalParameter ("needle", array_type.element_type.get_cname () + "*"));
4784 } else {
4785 function.add_parameter (new CCodeFormalParameter ("needle", array_type.element_type.get_cname ()));
4787 var block = new CCodeBlock ();
4789 var idx_decl = new CCodeDeclaration ("int");
4790 idx_decl.add_declarator (new CCodeVariableDeclarator ("i"));
4791 block.add_statement (idx_decl);
4793 var celement = new CCodeElementAccess (new CCodeIdentifier ("stack"), new CCodeIdentifier ("i"));
4794 var cneedle = new CCodeIdentifier ("needle");
4795 CCodeBinaryExpression cif_condition;
4796 if (array_type.element_type.compatible (string_type)) {
4797 requires_strcmp0 = true;
4798 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_strcmp0"));
4799 ccall.add_argument (celement);
4800 ccall.add_argument (cneedle);
4801 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("0"));
4802 } else if (array_type.element_type is StructValueType) {
4803 var equalfunc = generate_struct_equal_function ((Struct) array_type.element_type.data_type as Struct);
4804 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
4805 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, celement));
4806 ccall.add_argument (cneedle);
4807 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("TRUE"));
4808 } else {
4809 cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cneedle, celement);
4811 var cif_found = new CCodeBlock ();
4812 cif_found.add_statement (new CCodeReturnStatement (new CCodeConstant ("TRUE")));
4813 var cloop_body = new CCodeBlock ();
4814 cloop_body.add_statement (new CCodeIfStatement (cif_condition, cif_found));
4816 var cloop_condition = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("stack_length"));
4817 var cloop = new CCodeForStatement (cloop_condition, cloop_body);
4818 cloop.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
4819 cloop.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
4821 block.add_statement (cloop);
4822 block.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
4823 source_declarations.add_type_member_declaration (function.copy ());
4824 function.block = block;
4825 source_type_member_definition.append (function);
4827 return array_contains_func;
4830 public override void visit_type_check (TypeCheck expr) {
4831 generate_type_declaration (expr.type_reference, source_declarations);
4833 expr.ccodenode = create_type_check (expr.expression.ccodenode, expr.type_reference);
4834 if (expr.ccodenode is CCodeInvalidExpression) {
4835 Report.error (expr.source_reference, "type check expressions not supported for compact classes, structs, and enums");
4839 public override void visit_lambda_expression (LambdaExpression l) {
4840 // use instance position from delegate
4841 var dt = (DelegateType) l.target_type;
4842 l.method.cinstance_parameter_position = dt.delegate_symbol.cinstance_parameter_position;
4844 var old_temp_vars = temp_vars;
4845 var old_temp_ref_vars = temp_ref_vars;
4846 temp_vars = new ArrayList<LocalVariable> ();
4847 temp_ref_vars = new ArrayList<LocalVariable> ();
4849 l.accept_children (codegen);
4851 temp_vars = old_temp_vars;
4852 temp_ref_vars = old_temp_ref_vars;
4854 l.ccodenode = new CCodeIdentifier (l.method.get_cname ());
4857 public CCodeExpression convert_from_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
4858 var result = cexpr;
4859 if (is_reference_type_argument (actual_type) || is_nullable_value_type_argument (actual_type)) {
4860 result = new CCodeCastExpression (cexpr, actual_type.get_cname ());
4861 } else if (is_signed_integer_type_argument (actual_type)) {
4862 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
4863 cconv.add_argument (cexpr);
4864 result = cconv;
4865 } else if (is_unsigned_integer_type_argument (actual_type)) {
4866 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
4867 cconv.add_argument (cexpr);
4868 result = cconv;
4870 return result;
4873 public CCodeExpression convert_to_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
4874 var result = cexpr;
4875 if (is_signed_integer_type_argument (actual_type)) {
4876 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GINT_TO_POINTER"));
4877 cconv.add_argument (cexpr);
4878 result = cconv;
4879 } else if (is_unsigned_integer_type_argument (actual_type)) {
4880 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GUINT_TO_POINTER"));
4881 cconv.add_argument (cexpr);
4882 result = cconv;
4884 return result;
4887 // manage memory and implicit casts
4888 public CCodeExpression transform_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
4889 var cexpr = source_cexpr;
4890 if (expression_type == null) {
4891 return cexpr;
4895 if (expression_type.value_owned
4896 && expression_type.floating_reference) {
4897 /* floating reference, sink it.
4899 var cl = expression_type.data_type as ObjectTypeSymbol;
4900 var sink_func = (cl != null) ? cl.get_ref_sink_function () : null;
4902 if (sink_func != null) {
4903 var csink = new CCodeFunctionCall (new CCodeIdentifier (sink_func));
4904 csink.add_argument (cexpr);
4906 cexpr = csink;
4907 } else {
4908 Report.error (null, "type `%s' does not support floating references".printf (expression_type.data_type.name));
4912 bool boxing = (expression_type is ValueType && !expression_type.nullable
4913 && target_type is ValueType && target_type.nullable);
4914 bool unboxing = (expression_type is ValueType && expression_type.nullable
4915 && target_type is ValueType && !target_type.nullable);
4917 bool gvalue_boxing = (context.profile == Profile.GOBJECT
4918 && target_type != null
4919 && target_type.data_type == gvalue_type
4920 && !(expression_type is NullType)
4921 && expression_type.get_type_id () != "G_TYPE_VALUE");
4923 if (expression_type.value_owned
4924 && (target_type == null || !target_type.value_owned || boxing || unboxing)) {
4925 // value leaked, destroy it
4926 var pointer_type = target_type as PointerType;
4927 if (pointer_type != null && !(pointer_type.base_type is VoidType)) {
4928 // manual memory management for non-void pointers
4929 // treat void* special to not leak memory with void* method parameters
4930 } else if (requires_destroy (expression_type)) {
4931 var decl = get_temp_variable (expression_type, true, expression_type, false);
4932 temp_vars.insert (0, decl);
4933 temp_ref_vars.insert (0, decl);
4934 cexpr = new CCodeAssignment (get_variable_cexpression (decl.name), cexpr);
4936 if (expression_type is ArrayType && expr != null) {
4937 var array_type = (ArrayType) expression_type;
4938 var ccomma = new CCodeCommaExpression ();
4939 ccomma.append_expression (cexpr);
4940 for (int dim = 1; dim <= array_type.rank; dim++) {
4941 var len_decl = new LocalVariable (int_type.copy (), head.get_array_length_cname (decl.name, dim));
4942 temp_vars.insert (0, len_decl);
4943 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (len_decl.name), head.get_array_length_cexpression (expr, dim)));
4945 ccomma.append_expression (get_variable_cexpression (decl.name));
4946 cexpr = ccomma;
4947 } else if (expression_type is DelegateType && expr != null) {
4948 var ccomma = new CCodeCommaExpression ();
4949 ccomma.append_expression (cexpr);
4951 var target_decl = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (decl.name));
4952 temp_vars.insert (0, target_decl);
4953 var target_destroy_notify_decl = new LocalVariable (new DelegateType ((Delegate) context.root.scope.lookup ("GLib").scope.lookup ("DestroyNotify")), get_delegate_target_destroy_notify_cname (decl.name));
4954 temp_vars.insert (0, target_destroy_notify_decl);
4955 CCodeExpression target_destroy_notify;
4956 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (target_decl.name), get_delegate_target_cexpression (expr, out target_destroy_notify)));
4957 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (target_destroy_notify_decl.name), target_destroy_notify));
4959 ccomma.append_expression (get_variable_cexpression (decl.name));
4960 cexpr = ccomma;
4965 if (target_type == null) {
4966 // value will be destroyed, no need for implicit casts
4967 return cexpr;
4970 if (gvalue_boxing) {
4971 // implicit conversion to GValue
4972 var decl = get_temp_variable (target_type, true, target_type);
4973 temp_vars.insert (0, decl);
4975 var ccomma = new CCodeCommaExpression ();
4977 if (target_type.nullable) {
4978 var newcall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
4979 newcall.add_argument (new CCodeConstant ("GValue"));
4980 newcall.add_argument (new CCodeConstant ("1"));
4981 var newassignment = new CCodeAssignment (get_variable_cexpression (decl.name), newcall);
4982 ccomma.append_expression (newassignment);
4985 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
4986 if (target_type.nullable) {
4987 ccall.add_argument (get_variable_cexpression (decl.name));
4988 } else {
4989 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (decl.name)));
4991 ccall.add_argument (new CCodeIdentifier (expression_type.get_type_id ()));
4992 ccomma.append_expression (ccall);
4994 if (expression_type.value_owned) {
4995 ccall = new CCodeFunctionCall (get_value_taker_function (expression_type));
4996 } else {
4997 ccall = new CCodeFunctionCall (get_value_setter_function (expression_type));
4999 if (target_type.nullable) {
5000 ccall.add_argument (get_variable_cexpression (decl.name));
5001 } else {
5002 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (decl.name)));
5004 if (expression_type.is_real_non_null_struct_type ()) {
5005 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
5006 } else {
5007 ccall.add_argument (cexpr);
5010 ccomma.append_expression (ccall);
5012 ccomma.append_expression (get_variable_cexpression (decl.name));
5013 cexpr = ccomma;
5015 return cexpr;
5016 } else if (boxing) {
5017 // value needs to be boxed
5019 var unary = cexpr as CCodeUnaryExpression;
5020 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
5021 // *expr => expr
5022 cexpr = unary.inner;
5023 } else if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
5024 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5025 } else {
5026 var decl = get_temp_variable (expression_type, expression_type.value_owned, expression_type, false);
5027 temp_vars.insert (0, decl);
5029 var ccomma = new CCodeCommaExpression ();
5030 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (decl.name), cexpr));
5031 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (decl.name)));
5032 cexpr = ccomma;
5034 } else if (unboxing) {
5035 // unbox value
5037 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cexpr);
5038 } else {
5039 cexpr = get_implicit_cast_expression (cexpr, expression_type, target_type, expr);
5042 if (target_type.value_owned && (!expression_type.value_owned || boxing || unboxing)) {
5043 // need to copy value
5044 if (requires_copy (target_type) && !(expression_type is NullType)) {
5045 CodeNode node = expr;
5046 if (node == null) {
5047 node = expression_type;
5049 cexpr = get_ref_cexpression (target_type, cexpr, expr, node);
5053 return cexpr;
5056 public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
5057 var cexpr = source_cexpr;
5059 if (expression_type.data_type != null && expression_type.data_type == target_type.data_type) {
5060 // same type, no cast required
5061 return cexpr;
5064 if (expression_type is NullType) {
5065 // null literal, no cast required when not converting to generic type pointer
5066 return cexpr;
5069 generate_type_declaration (target_type, source_declarations);
5071 var cl = target_type.data_type as Class;
5072 var iface = target_type.data_type as Interface;
5073 if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
5074 // checked cast for strict subtypes of GTypeInstance
5075 return generate_instance_cast (cexpr, target_type.data_type);
5076 } else if (target_type.data_type != null && expression_type.get_cname () != target_type.get_cname ()) {
5077 var st = target_type.data_type as Struct;
5078 if (target_type.data_type.is_reference_type () || (st != null && st.is_simple_type ())) {
5079 // don't cast non-simple structs
5080 return new CCodeCastExpression (cexpr, target_type.get_cname ());
5081 } else {
5082 return cexpr;
5084 } else {
5085 return cexpr;
5089 public CCodeExpression get_property_set_call (Property prop, MemberAccess ma, CCodeExpression cexpr, Expression? rhs = null) {
5090 if (ma.inner is BaseAccess) {
5091 if (prop.base_property != null) {
5092 var base_class = (Class) prop.base_property.parent_symbol;
5093 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
5094 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
5096 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
5097 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
5098 ccall.add_argument (cexpr);
5099 return ccall;
5100 } else if (prop.base_interface_property != null) {
5101 var base_iface = (Interface) prop.base_interface_property.parent_symbol;
5102 string parent_iface_var = "%s_%s_parent_iface".printf (current_class.get_lower_case_cname (null), base_iface.get_lower_case_cname (null));
5104 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "set_%s".printf (prop.name)));
5105 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
5106 ccall.add_argument (cexpr);
5107 return ccall;
5111 var set_func = "g_object_set";
5113 var base_property = prop;
5114 if (!prop.no_accessor_method) {
5115 if (prop.base_property != null) {
5116 base_property = prop.base_property;
5117 } else if (prop.base_interface_property != null) {
5118 base_property = prop.base_interface_property;
5121 if (prop is DynamicProperty) {
5122 set_func = head.get_dynamic_property_setter_cname ((DynamicProperty) prop);
5123 } else {
5124 generate_property_accessor_declaration (base_property.set_accessor, source_declarations);
5125 set_func = base_property.set_accessor.get_cname ();
5129 var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
5131 if (prop.binding == MemberBinding.INSTANCE) {
5132 /* target instance is first argument */
5133 var instance = (CCodeExpression) get_ccodenode (ma.inner);
5135 if (prop.parent_symbol is Struct) {
5136 // we need to pass struct instance by reference
5137 var unary = instance as CCodeUnaryExpression;
5138 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
5139 // *expr => expr
5140 instance = unary.inner;
5141 } else if (instance is CCodeIdentifier || instance is CCodeMemberAccess) {
5142 instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance);
5143 } else {
5144 // if instance is e.g. a function call, we can't take the address of the expression
5145 // (tmp = expr, &tmp)
5146 var ccomma = new CCodeCommaExpression ();
5148 var temp_var = get_temp_variable (ma.inner.target_type, true, null, false);
5149 temp_vars.insert (0, temp_var);
5150 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), instance));
5151 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name)));
5153 instance = ccomma;
5157 ccall.add_argument (instance);
5160 if (prop.no_accessor_method) {
5161 /* property name is second argument of g_object_set */
5162 ccall.add_argument (prop.get_canonical_cconstant ());
5165 var array_type = prop.property_type as ArrayType;
5167 CCodeExpression rv;
5168 if (array_type != null && !prop.no_array_length) {
5169 var temp_var = get_temp_variable (prop.property_type, true, null, false);
5170 temp_vars.insert (0, temp_var);
5171 var ccomma = new CCodeCommaExpression ();
5172 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), cexpr));
5173 ccall.add_argument (get_variable_cexpression (temp_var.name));
5174 ccomma.append_expression (ccall);
5175 rv = ccomma;
5176 } else {
5177 ccall.add_argument (cexpr);
5178 rv = ccall;
5181 if (array_type != null && !prop.no_array_length && rhs != null) {
5182 for (int dim = 1; dim <= array_type.rank; dim++) {
5183 ccall.add_argument (head.get_array_length_cexpression (rhs, dim));
5185 } else if (prop.property_type is DelegateType && rhs != null) {
5186 var delegate_type = (DelegateType) prop.property_type;
5187 if (delegate_type.delegate_symbol.has_target) {
5188 CCodeExpression delegate_target_destroy_notify;
5189 ccall.add_argument (get_delegate_target_cexpression (rhs, out delegate_target_destroy_notify));
5193 if (prop.no_accessor_method) {
5194 ccall.add_argument (new CCodeConstant ("NULL"));
5197 return rv;
5200 /* indicates whether a given Expression eligable for an ADDRESS_OF operator
5201 * from a vala to C point of view all expressions denoting locals, fields and
5202 * parameters are eligable to an ADDRESS_OF operator */
5203 public bool is_address_of_possible (Expression e) {
5204 var ma = e as MemberAccess;
5206 if (ma == null) {
5207 return false;
5209 if (ma.symbol_reference == null) {
5210 return false;
5212 if (ma.symbol_reference is FormalParameter) {
5213 return true;
5215 if (ma.symbol_reference is LocalVariable) {
5216 return true;
5218 if (ma.symbol_reference is Field) {
5219 return true;
5221 return false;
5224 /* retrieve the correct address_of expression for a give expression, creates temporary variables
5225 * where necessary, ce is the corresponding ccode expression for e */
5226 public CCodeExpression get_address_of_expression (Expression e, CCodeExpression ce) {
5227 // is address of trivially possible?
5228 if (is_address_of_possible (e)) {
5229 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ce);
5232 var ccomma = new CCodeCommaExpression ();
5233 var temp_decl = get_temp_variable (e.value_type, true, null, false);
5234 var ctemp = get_variable_cexpression (temp_decl.name);
5235 temp_vars.add (temp_decl);
5236 ccomma.append_expression (new CCodeAssignment (ctemp, ce));
5237 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
5238 return ccomma;
5241 public bool add_wrapper (string wrapper_name) {
5242 return wrappers.add (wrapper_name);
5245 public bool add_generated_external_symbol (Symbol external_symbol) {
5246 return generated_external_symbols.add (external_symbol);
5249 public static DataType get_data_type_for_symbol (TypeSymbol sym) {
5250 DataType type = null;
5252 if (sym is Class) {
5253 type = new ObjectType ((Class) sym);
5254 } else if (sym is Interface) {
5255 type = new ObjectType ((Interface) sym);
5256 } else if (sym is Struct) {
5257 var st = (Struct) sym;
5258 if (st.is_boolean_type ()) {
5259 type = new BooleanType (st);
5260 } else if (st.is_integer_type ()) {
5261 type = new IntegerType (st);
5262 } else if (st.is_floating_type ()) {
5263 type = new FloatingType (st);
5264 } else {
5265 type = new StructValueType (st);
5267 } else if (sym is Enum) {
5268 type = new EnumValueType ((Enum) sym);
5269 } else if (sym is ErrorDomain) {
5270 type = new ErrorType ((ErrorDomain) sym, null);
5271 } else if (sym is ErrorCode) {
5272 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
5273 } else {
5274 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
5275 return new InvalidType ();
5278 return type;
5281 public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) {
5282 var st = type.data_type as Struct;
5283 var array_type = type as ArrayType;
5284 if (initializer_expression && !type.nullable &&
5285 ((st != null && !st.is_simple_type ()) ||
5286 (array_type != null && array_type.fixed_length))) {
5287 // 0-initialize struct with struct initializer { 0 }
5288 // only allowed as initializer expression in C
5289 var clist = new CCodeInitializerList ();
5290 clist.append (new CCodeConstant ("0"));
5291 return clist;
5292 } else if ((type.data_type != null && type.data_type.is_reference_type ())
5293 || type.nullable
5294 || type is PointerType || type is DelegateType
5295 || (array_type != null && !array_type.fixed_length)) {
5296 return new CCodeConstant ("NULL");
5297 } else if (type.data_type != null && type.data_type.get_default_value () != null) {
5298 return new CCodeConstant (type.data_type.get_default_value ());
5299 } else if (type.type_parameter != null) {
5300 return new CCodeConstant ("NULL");
5301 } else if (type is ErrorType) {
5302 return new CCodeConstant ("NULL");
5304 return null;
5307 private CCodeStatement? create_property_type_check_statement (Property prop, bool check_return_type, TypeSymbol t, bool non_null, string var_name) {
5308 if (check_return_type) {
5309 return create_type_check_statement (prop, prop.property_type, t, non_null, var_name);
5310 } else {
5311 return create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
5315 public CCodeStatement? create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
5316 var ccheck = new CCodeFunctionCall ();
5318 if (!context.assert) {
5319 return null;
5320 } else if (context.checking && ((t is Class && !((Class) t).is_compact) || t is Interface)) {
5321 var ctype_check = new CCodeFunctionCall (new CCodeIdentifier (get_type_check_function (t)));
5322 ctype_check.add_argument (new CCodeIdentifier (var_name));
5324 CCodeExpression cexpr = ctype_check;
5325 if (!non_null) {
5326 var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
5328 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cnull, ctype_check);
5330 ccheck.add_argument (cexpr);
5331 } else if (!non_null) {
5332 return null;
5333 } else if (t == glist_type || t == gslist_type) {
5334 // NULL is empty list
5335 return null;
5336 } else {
5337 var cnonnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
5338 ccheck.add_argument (cnonnull);
5341 var cm = method_node as CreationMethod;
5342 if (cm != null && cm.parent_symbol is ObjectTypeSymbol) {
5343 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
5344 ccheck.add_argument (new CCodeConstant ("NULL"));
5345 } else if (ret_type is VoidType) {
5346 /* void function */
5347 ccheck.call = new CCodeIdentifier ("g_return_if_fail");
5348 } else {
5349 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
5351 var cdefault = default_value_for_type (ret_type, false);
5352 if (cdefault != null) {
5353 ccheck.add_argument (cdefault);
5354 } else {
5355 return null;
5359 return new CCodeExpressionStatement (ccheck);
5362 public int get_param_pos (double param_pos, bool ellipsis = false) {
5363 if (!ellipsis) {
5364 if (param_pos >= 0) {
5365 return (int) (param_pos * 1000);
5366 } else {
5367 return (int) ((100 + param_pos) * 1000);
5369 } else {
5370 if (param_pos >= 0) {
5371 return (int) ((100 + param_pos) * 1000);
5372 } else {
5373 return (int) ((200 + param_pos) * 1000);
5378 public CCodeNode? get_ccodenode (CodeNode node) {
5379 if (node.ccodenode == null) {
5380 node.accept (codegen);
5382 return node.ccodenode;
5385 public override void visit_class (Class cl) {
5388 public CCodeStatement create_postcondition_statement (Expression postcondition) {
5389 var cassert = new CCodeFunctionCall (new CCodeIdentifier ("g_warn_if_fail"));
5391 cassert.add_argument ((CCodeExpression) postcondition.ccodenode);
5393 return new CCodeExpressionStatement (cassert);
5396 public virtual bool is_gobject_property (Property prop) {
5397 return false;
5400 public DataType? get_this_type () {
5401 if (current_method != null && current_method.binding == MemberBinding.INSTANCE) {
5402 return current_method.this_parameter.parameter_type;
5403 } else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) {
5404 return current_property_accessor.prop.this_parameter.parameter_type;
5406 return null;
5409 public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
5410 var result = new CCodeFunctionCall (new CCodeIdentifier (type.get_upper_case_cname (null)));
5411 result.add_argument (expr);
5412 return result;
5415 void generate_struct_destroy_function (Struct st) {
5416 if (source_declarations.add_declaration (st.get_destroy_function ())) {
5417 // only generate function once per source file
5418 return;
5421 var function = new CCodeFunction (st.get_destroy_function (), "void");
5422 function.modifiers = CCodeModifiers.STATIC;
5423 function.add_parameter (new CCodeFormalParameter ("self", st.get_cname () + "*"));
5425 var cblock = new CCodeBlock ();
5426 foreach (Field f in st.get_fields ()) {
5427 if (f.binding == MemberBinding.INSTANCE) {
5428 if (requires_destroy (f.field_type)) {
5429 var lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
5431 var this_access = new MemberAccess.simple ("this");
5432 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
5433 this_access.ccodenode = new CCodeIdentifier ("(*self)");
5435 var ma = new MemberAccess (this_access, f.name);
5436 ma.symbol_reference = f;
5437 cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (lhs, f.field_type, ma)));
5442 source_declarations.add_type_member_declaration (function.copy ());
5443 function.block = cblock;
5444 source_type_member_definition.append (function);
5447 void generate_struct_copy_function (Struct st) {
5448 if (source_declarations.add_declaration (st.get_copy_function ())) {
5449 // only generate function once per source file
5450 return;
5453 var function = new CCodeFunction (st.get_copy_function (), "void");
5454 function.modifiers = CCodeModifiers.STATIC;
5455 function.add_parameter (new CCodeFormalParameter ("self", "const " + st.get_cname () + "*"));
5456 function.add_parameter (new CCodeFormalParameter ("dest", st.get_cname () + "*"));
5458 int old_next_temp_var_id = next_temp_var_id;
5459 var old_temp_vars = temp_vars;
5460 var old_temp_ref_vars = temp_ref_vars;
5461 var old_variable_name_map = variable_name_map;
5462 next_temp_var_id = 0;
5463 temp_vars = new ArrayList<LocalVariable> ();
5464 temp_ref_vars = new ArrayList<LocalVariable> ();
5465 variable_name_map = new HashMap<string,string> (str_hash, str_equal);
5467 var cblock = new CCodeBlock ();
5468 var cfrag = new CCodeFragment ();
5469 cblock.add_statement (cfrag);
5471 foreach (Field f in st.get_fields ()) {
5472 if (f.binding == MemberBinding.INSTANCE) {
5473 CCodeExpression copy = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.name);
5474 if (requires_copy (f.field_type)) {
5475 var this_access = new MemberAccess.simple ("this");
5476 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
5477 this_access.ccodenode = new CCodeIdentifier ("(*self)");
5478 var ma = new MemberAccess (this_access, f.name);
5479 ma.symbol_reference = f;
5480 copy = get_ref_cexpression (f.field_type, copy, ma, f);
5482 var dest = new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest"), f.name);
5484 var array_type = f.field_type as ArrayType;
5485 if (array_type != null && array_type.fixed_length) {
5486 // fixed-length (stack-allocated) arrays
5487 source_declarations.add_include ("string.h");
5489 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5490 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
5491 var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
5493 var array_copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
5494 array_copy_call.add_argument (dest);
5495 array_copy_call.add_argument (copy);
5496 array_copy_call.add_argument (size);
5497 cblock.add_statement (new CCodeExpressionStatement (array_copy_call));
5498 } else {
5499 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dest, copy)));
5501 if (array_type != null && !f.no_array_length) {
5502 for (int dim = 1; dim <= array_type.rank; dim++) {
5503 var len_src = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_array_length_cname (f.name, dim));
5504 var len_dest = new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest"), get_array_length_cname (f.name, dim));
5505 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (len_dest, len_src)));
5512 append_temp_decl (cfrag, temp_vars);
5513 temp_vars.clear ();
5515 next_temp_var_id = old_next_temp_var_id;
5516 temp_vars = old_temp_vars;
5517 temp_ref_vars = old_temp_ref_vars;
5518 variable_name_map = old_variable_name_map;
5520 source_declarations.add_type_member_declaration (function.copy ());
5521 function.block = cblock;
5522 source_type_member_definition.append (function);
5526 // vim:sw=8 noet