Fix order of commandline arguments passed to C compiler, patch by
[vala-lang.git] / gobject / valaccodebasemodule.vala
blob758187f0d881a6ecbe3c59d8c39a7642f0032399
1 /* valaccodebasemodule.vala
3 * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
24 using Gee;
26 /**
27 * Code visitor generating C Code.
29 public class Vala.CCodeBaseModule : CCodeModule {
30 public CodeContext context { get; set; }
32 public Symbol root_symbol;
33 public Symbol current_symbol;
34 public TypeSymbol current_type_symbol;
35 public Class current_class;
36 public Method current_method;
37 public DataType current_return_type;
38 public TryStatement current_try;
39 public PropertyAccessor current_property_accessor;
41 public CCodeFragment header_begin;
42 public CCodeFragment header_type_declaration;
43 public CCodeFragment header_type_definition;
44 public CCodeFragment header_type_member_declaration;
45 public CCodeFragment header_constant_declaration;
46 public CCodeFragment source_begin;
47 public CCodeFragment source_include_directives;
48 public CCodeFragment source_type_declaration;
49 public CCodeFragment source_type_definition;
50 public CCodeFragment source_type_member_declaration;
51 public CCodeFragment source_constant_declaration;
52 public CCodeFragment source_signal_marshaller_declaration;
53 public CCodeFragment source_type_member_definition;
54 public CCodeFragment class_init_fragment;
55 public CCodeFragment instance_init_fragment;
56 public CCodeFragment instance_finalize_fragment;
57 public CCodeFragment source_signal_marshaller_definition;
58 public CCodeFragment module_init_fragment;
60 public CCodeStruct param_spec_struct;
61 public CCodeStruct instance_struct;
62 public CCodeStruct type_struct;
63 public CCodeStruct instance_priv_struct;
64 public CCodeEnum prop_enum;
65 public CCodeEnum cenum;
66 public CCodeFunction function;
67 public CCodeBlock block;
69 /* all temporary variables */
70 public ArrayList<LocalVariable> temp_vars = new ArrayList<LocalVariable> ();
71 /* temporary variables that own their content */
72 public ArrayList<LocalVariable> temp_ref_vars = new ArrayList<LocalVariable> ();
73 /* cache to check whether a certain marshaller has been created yet */
74 public Gee.Set<string> user_marshal_set;
75 /* (constant) hash table with all predefined marshallers */
76 public Gee.Set<string> predefined_marshal_set;
77 /* (constant) hash table with all C keywords */
78 public Gee.Set<string> c_keywords;
80 public int next_temp_var_id = 0;
81 public bool in_creation_method = false;
82 public bool in_constructor = false;
83 public bool in_static_or_class_ctor = false;
84 public bool current_method_inner_error = false;
85 public int next_coroutine_state = 1;
87 public DataType bool_type;
88 public DataType char_type;
89 public DataType uchar_type;
90 public DataType unichar_type;
91 public DataType short_type;
92 public DataType ushort_type;
93 public DataType int_type;
94 public DataType uint_type;
95 public DataType long_type;
96 public DataType ulong_type;
97 public DataType int8_type;
98 public DataType uint8_type;
99 public DataType int16_type;
100 public DataType uint16_type;
101 public DataType int32_type;
102 public DataType uint32_type;
103 public DataType int64_type;
104 public DataType uint64_type;
105 public DataType string_type;
106 public DataType float_type;
107 public DataType double_type;
108 public TypeSymbol gtype_type;
109 public TypeSymbol gobject_type;
110 public ErrorType gerror_type;
111 public Class glist_type;
112 public Class gslist_type;
113 public TypeSymbol gstringbuilder_type;
114 public TypeSymbol garray_type;
115 public DataType gquark_type;
116 public Struct gvalue_type;
117 public Struct mutex_type;
118 public TypeSymbol type_module_type;
119 public Interface list_type;
120 public Interface map_type;
121 public TypeSymbol dbus_object_type;
123 public Method substring_method;
125 public bool in_plugin = false;
126 public string module_init_param_name;
128 public bool string_h_needed;
129 public bool gvaluecollector_h_needed;
130 public bool gio_h_needed;
131 public bool requires_free_checked;
132 public bool requires_array_free;
133 public bool requires_array_move;
134 public bool requires_strcmp0;
135 public bool dbus_glib_h_needed;
136 public bool dbus_glib_h_needed_in_header;
138 public Set<string> wrappers;
140 Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
142 public CCodeBaseModule (CCodeGenerator codegen, CCodeModule? next) {
143 base (codegen, next);
145 predefined_marshal_set = new HashSet<string> (str_hash, str_equal);
146 predefined_marshal_set.add ("VOID:VOID");
147 predefined_marshal_set.add ("VOID:BOOLEAN");
148 predefined_marshal_set.add ("VOID:CHAR");
149 predefined_marshal_set.add ("VOID:UCHAR");
150 predefined_marshal_set.add ("VOID:INT");
151 predefined_marshal_set.add ("VOID:UINT");
152 predefined_marshal_set.add ("VOID:LONG");
153 predefined_marshal_set.add ("VOID:ULONG");
154 predefined_marshal_set.add ("VOID:ENUM");
155 predefined_marshal_set.add ("VOID:FLAGS");
156 predefined_marshal_set.add ("VOID:FLOAT");
157 predefined_marshal_set.add ("VOID:DOUBLE");
158 predefined_marshal_set.add ("VOID:STRING");
159 predefined_marshal_set.add ("VOID:POINTER");
160 predefined_marshal_set.add ("VOID:OBJECT");
161 predefined_marshal_set.add ("STRING:OBJECT,POINTER");
162 predefined_marshal_set.add ("VOID:UINT,POINTER");
163 predefined_marshal_set.add ("BOOLEAN:FLAGS");
165 c_keywords = new HashSet<string> (str_hash, str_equal);
167 // C99 keywords
168 c_keywords.add ("_Bool");
169 c_keywords.add ("_Complex");
170 c_keywords.add ("_Imaginary");
171 c_keywords.add ("auto");
172 c_keywords.add ("break");
173 c_keywords.add ("case");
174 c_keywords.add ("char");
175 c_keywords.add ("const");
176 c_keywords.add ("continue");
177 c_keywords.add ("default");
178 c_keywords.add ("do");
179 c_keywords.add ("double");
180 c_keywords.add ("else");
181 c_keywords.add ("enum");
182 c_keywords.add ("extern");
183 c_keywords.add ("float");
184 c_keywords.add ("for");
185 c_keywords.add ("goto");
186 c_keywords.add ("if");
187 c_keywords.add ("inline");
188 c_keywords.add ("int");
189 c_keywords.add ("long");
190 c_keywords.add ("register");
191 c_keywords.add ("restrict");
192 c_keywords.add ("return");
193 c_keywords.add ("short");
194 c_keywords.add ("signed");
195 c_keywords.add ("sizeof");
196 c_keywords.add ("static");
197 c_keywords.add ("struct");
198 c_keywords.add ("switch");
199 c_keywords.add ("typedef");
200 c_keywords.add ("union");
201 c_keywords.add ("unsigned");
202 c_keywords.add ("void");
203 c_keywords.add ("volatile");
204 c_keywords.add ("while");
206 // MSVC keywords
207 c_keywords.add ("cdecl");
210 public override CCodeIdentifier get_value_setter_function (DataType type_reference) {
211 if (type_reference.data_type != null) {
212 return new CCodeIdentifier (type_reference.data_type.get_set_value_function ());
213 } else {
214 return new CCodeIdentifier ("g_value_set_pointer");
218 private CCodeIncludeDirective get_internal_include (string filename) {
219 return new CCodeIncludeDirective (filename, context.library == null);
222 public virtual void append_vala_array_free () {
225 public virtual void append_vala_array_move () {
228 private void append_vala_strcmp0 () {
229 var fun = new CCodeFunction ("_vala_strcmp0", "int");
230 fun.modifiers = CCodeModifiers.STATIC;
231 fun.add_parameter (new CCodeFormalParameter ("str1", "const char *"));
232 fun.add_parameter (new CCodeFormalParameter ("str2", "const char *"));
233 source_type_member_declaration.append (fun.copy ());
235 // (str1 != str2)
236 var cineq = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("str1"), new CCodeIdentifier ("str2"));
238 fun.block = new CCodeBlock ();
240 var cblock = new CCodeBlock ();
241 // if (str1 == NULL)
242 var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("str1"), new CCodeConstant ("NULL")), cblock);
243 // return -(str1 != str2);
244 cblock.add_statement (new CCodeReturnStatement (new CCodeUnaryExpression (CCodeUnaryOperator.MINUS, cineq)));
245 fun.block.add_statement (cif);
247 cblock = new CCodeBlock ();
248 // if (str2 == NULL)
249 cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("str2"), new CCodeConstant ("NULL")), cblock);
250 // return (str1 != str2);
251 cblock.add_statement (new CCodeReturnStatement (cineq));
252 fun.block.add_statement (cif);
254 // strcmp (str1, str2)
255 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
256 ccall.add_argument (new CCodeIdentifier ("str1"));
257 ccall.add_argument (new CCodeIdentifier ("str2"));
258 // return strcmp (str1, str2);
259 fun.block.add_statement (new CCodeReturnStatement (ccall));
261 source_type_member_definition.append (fun);
264 public override void visit_source_file (SourceFile source_file) {
265 header_begin = new CCodeFragment ();
266 header_type_declaration = new CCodeFragment ();
267 header_type_definition = new CCodeFragment ();
268 header_type_member_declaration = new CCodeFragment ();
269 header_constant_declaration = new CCodeFragment ();
270 source_begin = new CCodeFragment ();
271 source_include_directives = new CCodeFragment ();
272 source_type_declaration = new CCodeFragment ();
273 source_type_definition = new CCodeFragment ();
274 source_type_member_declaration = new CCodeFragment ();
275 source_constant_declaration = new CCodeFragment ();
276 source_type_member_definition = new CCodeFragment ();
277 source_signal_marshaller_definition = new CCodeFragment ();
278 source_signal_marshaller_declaration = new CCodeFragment ();
280 user_marshal_set = new HashSet<string> (str_hash, str_equal);
282 next_temp_var_id = 0;
284 string_h_needed = false;
285 gvaluecollector_h_needed = false;
286 gio_h_needed = false;
287 dbus_glib_h_needed = false;
288 dbus_glib_h_needed_in_header = false;
289 requires_free_checked = false;
290 requires_array_free = false;
291 requires_array_move = false;
292 requires_strcmp0 = false;
294 wrappers = new HashSet<string> (str_hash, str_equal);
296 header_begin.append (new CCodeIncludeDirective ("glib.h"));
297 header_begin.append (new CCodeIncludeDirective ("glib-object.h"));
298 if (context.basedir != null || context.library != null) {
299 source_include_directives.append (new CCodeIncludeDirective (source_file.get_cinclude_filename ()));
300 } else {
301 source_include_directives.append (new CCodeIncludeDirective (source_file.get_cinclude_filename (), true));
304 Gee.List<string> used_includes = new ArrayList<string> (str_equal);
305 used_includes.add ("glib.h");
306 used_includes.add ("glib-object.h");
307 used_includes.add (source_file.get_cinclude_filename ());
309 foreach (string filename in source_file.get_header_external_includes ()) {
310 if (!used_includes.contains (filename)) {
311 header_begin.append (new CCodeIncludeDirective (filename));
312 used_includes.add (filename);
315 foreach (string filename in source_file.get_header_internal_includes ()) {
316 if (!used_includes.contains (filename)) {
317 header_begin.append (get_internal_include (filename));
318 used_includes.add (filename);
321 foreach (string filename in source_file.get_source_external_includes ()) {
322 if (!used_includes.contains (filename)) {
323 source_include_directives.append (new CCodeIncludeDirective (filename));
324 used_includes.add (filename);
327 foreach (string filename in source_file.get_source_internal_includes ()) {
328 if (!used_includes.contains (filename)) {
329 source_include_directives.append (get_internal_include (filename));
330 used_includes.add (filename);
333 foreach (Symbol symbol in source_file.get_source_symbol_dependencies ()) {
334 if (!symbol.external && symbol.external_package) {
335 symbol.accept (codegen);
338 if (source_file.is_cycle_head) {
339 foreach (SourceFile cycle_file in source_file.cycle.files) {
340 foreach (CodeNode node in cycle_file.get_nodes ()) {
341 if (node is Struct) {
342 var st = (Struct) node;
343 header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (st.get_cname ()), new CCodeVariableDeclarator (st.get_cname ())));
344 } else if (node is Class) {
345 var cl = (Class) node;
346 header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (cl.get_cname ()), new CCodeVariableDeclarator (cl.get_cname ())));
347 header_type_declaration.append (new CCodeTypeDefinition ("struct _%sClass".printf (cl.get_cname ()), new CCodeVariableDeclarator ("%sClass".printf (cl.get_cname ()))));
348 } else if (node is Interface) {
349 var iface = (Interface) node;
350 header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), new CCodeVariableDeclarator (iface.get_cname ())));
351 header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_type_cname ()), new CCodeVariableDeclarator (iface.get_type_cname ())));
357 source_file.accept_children (codegen);
359 if (Report.get_errors () > 0) {
360 return;
363 var header_define = get_define_for_filename (source_file.get_cinclude_filename ());
365 /* generate hardcoded "well-known" macros */
366 if (requires_free_checked) {
367 source_begin.append (new CCodeMacroReplacement ("VALA_FREE_CHECKED(o,f)", "((o) == NULL ? NULL : ((o) = (f (o), NULL)))"));
369 if (requires_array_free) {
370 append_vala_array_free ();
372 if (requires_array_move) {
373 append_vala_array_move ();
375 if (requires_strcmp0) {
376 append_vala_strcmp0 ();
379 if (string_h_needed) {
380 source_include_directives.append (new CCodeIncludeDirective ("string.h"));
383 if (gvaluecollector_h_needed) {
384 source_include_directives.append (new CCodeIncludeDirective ("gobject/gvaluecollector.h"));
387 if (gio_h_needed) {
388 header_begin.append (new CCodeIncludeDirective ("gio/gio.h"));
391 if (dbus_glib_h_needed_in_header) {
392 header_begin.append (new CCodeIncludeDirective ("dbus/dbus.h"));
393 header_begin.append (new CCodeIncludeDirective ("dbus/dbus-glib.h"));
394 } else if (dbus_glib_h_needed) {
395 source_include_directives.append (new CCodeIncludeDirective ("dbus/dbus.h"));
396 source_include_directives.append (new CCodeIncludeDirective ("dbus/dbus-glib.h"));
398 if (dbus_glib_h_needed_in_header || dbus_glib_h_needed) {
399 var dbusvtable = new CCodeStruct ("_DBusObjectVTable");
400 dbusvtable.add_field ("void", "(*register_object) (DBusConnection*, const char*, void*)");
401 source_type_definition.append (dbusvtable);
403 source_type_declaration.append (new CCodeTypeDefinition ("struct _DBusObjectVTable", new CCodeVariableDeclarator ("_DBusObjectVTable")));
405 var cfunc = new CCodeFunction ("_vala_dbus_register_object", "void");
406 cfunc.add_parameter (new CCodeFormalParameter ("connection", "DBusConnection*"));
407 cfunc.add_parameter (new CCodeFormalParameter ("path", "const char*"));
408 cfunc.add_parameter (new CCodeFormalParameter ("object", "void*"));
410 cfunc.modifiers |= CCodeModifiers.STATIC;
411 source_type_member_declaration.append (cfunc.copy ());
413 var block = new CCodeBlock ();
414 cfunc.block = block;
416 var cdecl = new CCodeDeclaration ("const _DBusObjectVTable *");
417 cdecl.add_declarator (new CCodeVariableDeclarator ("vtable"));
418 block.add_statement (cdecl);
420 var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
421 quark.add_argument (new CCodeConstant ("\"DBusObjectVTable\""));
423 var get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
424 get_qdata.add_argument (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE (object)"));
425 get_qdata.add_argument (quark);
427 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("vtable"), get_qdata)));
429 var cregister = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("vtable"), "register_object"));
430 cregister.add_argument (new CCodeIdentifier ("connection"));
431 cregister.add_argument (new CCodeIdentifier ("path"));
432 cregister.add_argument (new CCodeIdentifier ("object"));
433 block.add_statement (new CCodeExpressionStatement (cregister));
435 source_type_member_definition.append (cfunc);
438 CCodeComment comment = null;
439 if (source_file.comment != null) {
440 comment = new CCodeComment (source_file.comment);
443 var writer = new CCodeWriter (source_file.get_cheader_filename ());
444 if (!writer.open ()) {
445 Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
446 return;
448 if (comment != null) {
449 comment.write (writer);
451 writer.write_newline ();
452 var once = new CCodeOnceSection (header_define);
453 once.append (new CCodeNewline ());
454 once.append (header_begin);
455 once.append (new CCodeNewline ());
456 once.append (new CCodeIdentifier ("G_BEGIN_DECLS"));
457 once.append (new CCodeNewline ());
458 once.append (new CCodeNewline ());
459 once.append (header_type_declaration);
460 once.append (new CCodeNewline ());
461 once.append (header_type_definition);
462 once.append (new CCodeNewline ());
463 once.append (header_type_member_declaration);
464 once.append (new CCodeNewline ());
465 once.append (header_constant_declaration);
466 once.append (new CCodeNewline ());
467 once.append (new CCodeIdentifier ("G_END_DECLS"));
468 once.append (new CCodeNewline ());
469 once.append (new CCodeNewline ());
470 once.write (writer);
471 writer.close ();
473 writer = new CCodeWriter (source_file.get_csource_filename ());
474 if (!writer.open ()) {
475 Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
476 return;
478 writer.line_directives = context.debug;
479 if (comment != null) {
480 comment.write (writer);
482 source_begin.write (writer);
483 writer.write_newline ();
484 source_include_directives.write (writer);
485 writer.write_newline ();
486 source_type_declaration.write_combined (writer);
487 writer.write_newline ();
488 source_type_definition.write_combined (writer);
489 writer.write_newline ();
490 source_type_member_declaration.write_declaration (writer);
491 writer.write_newline ();
492 source_type_member_declaration.write (writer);
493 writer.write_newline ();
494 source_constant_declaration.write (writer);
495 writer.write_newline ();
496 source_signal_marshaller_declaration.write_declaration (writer);
497 source_signal_marshaller_declaration.write (writer);
498 writer.write_newline ();
499 source_type_member_definition.write (writer);
500 writer.write_newline ();
501 source_signal_marshaller_definition.write (writer);
502 writer.write_newline ();
503 writer.close ();
505 header_begin = null;
506 header_type_declaration = null;
507 header_type_definition = null;
508 header_type_member_declaration = null;
509 header_constant_declaration = null;
510 source_begin = null;
511 source_include_directives = null;
512 source_type_declaration = null;
513 source_type_definition = null;
514 source_type_member_declaration = null;
515 source_constant_declaration = null;
516 source_type_member_definition = null;
517 source_signal_marshaller_definition = null;
518 source_signal_marshaller_declaration = null;
521 private static string get_define_for_filename (string filename) {
522 var define = new StringBuilder ("__");
524 var i = filename;
525 while (i.len () > 0) {
526 var c = i.get_char ();
527 if (c.isalnum () && c < 0x80) {
528 define.append_unichar (c.toupper ());
529 } else {
530 define.append_c ('_');
533 i = i.next_char ();
536 define.append ("__");
538 return define.str;
541 public override void emit (CodeContext context) {
542 this.context = context;
544 context.find_header_cycles ();
546 root_symbol = context.root;
548 bool_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("bool"));
549 char_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("char"));
550 uchar_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("uchar"));
551 unichar_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("unichar"));
552 short_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("short"));
553 ushort_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("ushort"));
554 int_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("int"));
555 uint_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("uint"));
556 long_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("long"));
557 ulong_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("ulong"));
558 int8_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("int8"));
559 uint8_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("uint8"));
560 int16_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("int16"));
561 uint16_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("uint16"));
562 int32_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("int32"));
563 uint32_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("uint32"));
564 int64_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("int64"));
565 uint64_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("uint64"));
566 float_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("float"));
567 double_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("double"));
568 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
569 substring_method = (Method) string_type.data_type.scope.lookup ("substring");
571 var glib_ns = root_symbol.scope.lookup ("GLib");
573 gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
574 gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
575 gerror_type = new ErrorType (null, null);
576 glist_type = (Class) glib_ns.scope.lookup ("List");
577 gslist_type = (Class) glib_ns.scope.lookup ("SList");
578 gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
579 garray_type = (TypeSymbol) glib_ns.scope.lookup ("Array");
581 gquark_type = new ValueType ((TypeSymbol) glib_ns.scope.lookup ("Quark"));
582 gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
583 mutex_type = (Struct) glib_ns.scope.lookup ("StaticRecMutex");
585 type_module_type = (TypeSymbol) glib_ns.scope.lookup ("TypeModule");
587 if (context.module_init_method != null) {
588 module_init_fragment = new CCodeFragment ();
589 foreach (FormalParameter parameter in context.module_init_method.get_parameters ()) {
590 if (parameter.parameter_type.data_type == type_module_type) {
591 in_plugin = true;
592 module_init_param_name = parameter.name;
593 break;
598 var gee_ns = root_symbol.scope.lookup ("Gee");
599 if (gee_ns != null) {
600 list_type = (Interface) gee_ns.scope.lookup ("List");
601 map_type = (Interface) gee_ns.scope.lookup ("Map");
604 var dbus_ns = root_symbol.scope.lookup ("DBus");
605 if (dbus_ns != null) {
606 dbus_object_type = (TypeSymbol) dbus_ns.scope.lookup ("Object");
609 /* we're only interested in non-pkg source files */
610 var source_files = context.get_source_files ();
611 foreach (SourceFile file in source_files) {
612 if (!file.external_package) {
613 file.accept (codegen);
618 public override void visit_enum (Enum en) {
619 cenum = new CCodeEnum (en.get_cname ());
621 CCodeFragment decl_frag;
622 CCodeFragment def_frag;
623 if (en.access != SymbolAccessibility.PRIVATE) {
624 decl_frag = header_type_declaration;
625 def_frag = header_type_definition;
626 } else {
627 decl_frag = source_type_declaration;
628 def_frag = source_type_definition;
631 if (en.source_reference.comment != null) {
632 def_frag.append (new CCodeComment (en.source_reference.comment));
635 def_frag.append (cenum);
636 def_frag.append (new CCodeNewline ());
638 en.accept_children (codegen);
640 if (!en.has_type_id) {
641 return;
644 decl_frag.append (new CCodeNewline ());
646 var macro = "(%s_get_type ())".printf (en.get_lower_case_cname (null));
647 decl_frag.append (new CCodeMacroReplacement (en.get_type_id (), macro));
649 var clist = new CCodeInitializerList (); /* or during visit time? */
650 CCodeInitializerList clist_ev = null;
651 foreach (EnumValue ev in en.get_values ()) {
652 clist_ev = new CCodeInitializerList ();
653 clist_ev.append (new CCodeConstant (ev.get_cname ()));
654 clist_ev.append (new CCodeIdentifier ("\"%s\"".printf (ev.get_cname ())));
655 clist_ev.append (ev.get_canonical_cconstant ());
656 clist.append (clist_ev);
659 clist_ev = new CCodeInitializerList ();
660 clist_ev.append (new CCodeConstant ("0"));
661 clist_ev.append (new CCodeConstant ("NULL"));
662 clist_ev.append (new CCodeConstant ("NULL"));
663 clist.append (clist_ev);
665 var enum_decl = new CCodeVariableDeclarator.with_initializer ("values[]", clist);
667 CCodeDeclaration cdecl = null;
668 if (en.is_flags) {
669 cdecl = new CCodeDeclaration ("const GFlagsValue");
670 } else {
671 cdecl = new CCodeDeclaration ("const GEnumValue");
674 cdecl.add_declarator (enum_decl);
675 cdecl.modifiers = CCodeModifiers.STATIC;
677 var type_init = new CCodeBlock ();
679 type_init.add_statement (cdecl);
681 var fun_name = "%s_get_type".printf (en.get_lower_case_cname (null));
682 var regfun = new CCodeFunction (fun_name, "GType");
683 var regblock = new CCodeBlock ();
685 cdecl = new CCodeDeclaration ("GType");
686 string type_id_name = "%s_type_id".printf (en.get_lower_case_cname (null));
687 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (type_id_name, new CCodeConstant ("0")));
688 cdecl.modifiers = CCodeModifiers.STATIC;
689 regblock.add_statement (cdecl);
691 CCodeFunctionCall reg_call;
692 if (en.is_flags) {
693 reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_flags_register_static"));
694 } else {
695 reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_enum_register_static"));
698 reg_call.add_argument (new CCodeConstant ("\"%s\"".printf (en.get_cname())));
699 reg_call.add_argument (new CCodeIdentifier ("values"));
701 type_init.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (type_id_name), reg_call)));
703 var cond = new CCodeFunctionCall (new CCodeIdentifier ("G_UNLIKELY"));
704 cond.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (type_id_name), new CCodeConstant ("0")));
705 var cif = new CCodeIfStatement (cond, type_init);
706 regblock.add_statement (cif);
708 regblock.add_statement (new CCodeReturnStatement (new CCodeConstant (type_id_name)));
710 if (en.access != SymbolAccessibility.PRIVATE) {
711 header_type_member_declaration.append (regfun.copy ());
712 } else {
713 source_type_member_declaration.append (regfun.copy ());
715 regfun.block = regblock;
717 source_type_member_definition.append (new CCodeNewline ());
718 source_type_member_definition.append (regfun);
721 public override void visit_enum_value (EnumValue ev) {
722 if (ev.value == null) {
723 cenum.add_value (new CCodeEnumValue (ev.get_cname ()));
724 } else {
725 ev.value.accept (codegen);
726 cenum.add_value (new CCodeEnumValue (ev.get_cname (), (CCodeExpression) ev.value.ccodenode));
730 public override void visit_member (Member m) {
731 /* stuff meant for all lockable members */
732 if (m is Lockable && ((Lockable)m).get_lock_used ()) {
733 CCodeExpression l = new CCodeIdentifier ("self");
734 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (m));
736 instance_priv_struct.add_field (mutex_type.get_cname (), get_symbol_lock_name (m));
738 var initf = new CCodeFunctionCall (
739 new CCodeIdentifier (mutex_type.default_construction_method.get_cname ()));
741 initf.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
743 instance_init_fragment.append (new CCodeExpressionStatement (initf));
745 requires_free_checked = true;
748 var fc = new CCodeFunctionCall (new CCodeIdentifier ("g_static_rec_mutex_free"));
750 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
752 if (instance_finalize_fragment != null) {
753 instance_finalize_fragment.append (new CCodeExpressionStatement (fc));
758 public override void visit_constant (Constant c) {
759 c.accept_children (codegen);
761 if (c.initializer is InitializerList) {
762 var cdecl = new CCodeDeclaration (c.type_reference.get_const_cname ());
763 var arr = "";
764 if (c.type_reference is ArrayType) {
765 arr = "[]";
767 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s%s".printf (c.get_cname (), arr), (CCodeExpression) c.initializer.ccodenode));
768 cdecl.modifiers = CCodeModifiers.STATIC;
770 if (!c.is_internal_symbol ()) {
771 header_constant_declaration.append (cdecl);
772 } else {
773 source_constant_declaration.append (cdecl);
775 } else {
776 var cdefine = new CCodeMacroReplacement.with_expression (c.get_cname (), (CCodeExpression) c.initializer.ccodenode);
777 if (!c.is_internal_symbol ()) {
778 header_type_member_declaration.append (cdefine);
779 } else {
780 source_type_member_declaration.append (cdefine);
785 public override void visit_field (Field f) {
786 check_type (f.field_type);
788 f.accept_children (codegen);
790 var cl = f.parent_symbol as Class;
791 bool is_gtypeinstance = (cl != null && !cl.is_compact);
793 CCodeExpression lhs = null;
794 CCodeStruct st = null;
796 string field_ctype = f.field_type.get_cname ();
797 if (f.is_volatile) {
798 field_ctype = "volatile " + field_ctype;
801 if (f.access != SymbolAccessibility.PRIVATE) {
802 if (f.binding == MemberBinding.INSTANCE) {
803 st = instance_struct;
805 lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
806 } else if (f.binding == MemberBinding.CLASS) {
807 st = type_struct;
808 } else {
809 var cdecl = new CCodeDeclaration (field_ctype);
810 cdecl.add_declarator (new CCodeVariableDeclarator (f.get_cname ()));
811 cdecl.modifiers = CCodeModifiers.EXTERN;
812 header_type_member_declaration.append (cdecl);
814 var var_decl = new CCodeVariableDeclarator (f.get_cname ());
815 var_decl.initializer = default_value_for_type (f.field_type, true);
817 if (f.initializer != null) {
818 var init = (CCodeExpression) f.initializer.ccodenode;
819 if (is_constant_ccode_expression (init)) {
820 var_decl.initializer = init;
824 var var_def = new CCodeDeclaration (field_ctype);
825 var_def.add_declarator (var_decl);
826 var_def.modifiers = CCodeModifiers.EXTERN;
827 source_type_member_declaration.append (var_def);
829 lhs = new CCodeIdentifier (f.get_cname ());
831 } else if (f.access == SymbolAccessibility.PRIVATE) {
832 if (f.binding == MemberBinding.INSTANCE) {
833 if (is_gtypeinstance) {
834 st = instance_priv_struct;
835 lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ());
836 } else {
837 st = instance_struct;
838 lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
840 } else if (f.binding == MemberBinding.CLASS) {
841 st = type_struct;
842 } else {
843 var cdecl = new CCodeDeclaration (field_ctype);
844 var var_decl = new CCodeVariableDeclarator (f.get_cname ());
845 if (f.initializer != null) {
846 var init = (CCodeExpression) f.initializer.ccodenode;
847 if (is_constant_ccode_expression (init)) {
848 var_decl.initializer = init;
851 cdecl.add_declarator (var_decl);
852 cdecl.modifiers = CCodeModifiers.STATIC;
853 source_type_member_declaration.append (cdecl);
855 lhs = new CCodeIdentifier (f.get_cname ());
859 if (f.binding == MemberBinding.INSTANCE) {
860 st.add_field (field_ctype, f.get_cname ());
861 if (f.field_type is ArrayType && !f.no_array_length) {
862 // create fields to store array dimensions
863 var array_type = (ArrayType) f.field_type;
865 for (int dim = 1; dim <= array_type.rank; dim++) {
866 var len_type = int_type.copy ();
868 st.add_field (len_type.get_cname (), head.get_array_length_cname (f.name, dim));
870 } else if (f.field_type is DelegateType) {
871 var delegate_type = (DelegateType) f.field_type;
872 if (delegate_type.delegate_symbol.has_target) {
873 // create field to store delegate target
874 st.add_field ("gpointer", get_delegate_target_cname (f.name));
878 if (f.initializer != null) {
879 var rhs = (CCodeExpression) f.initializer.ccodenode;
881 instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, rhs)));
883 if (f.field_type is ArrayType && !f.no_array_length &&
884 f.initializer is ArrayCreationExpression) {
885 var array_type = (ArrayType) f.field_type;
886 var this_access = new MemberAccess.simple ("this");
887 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
888 this_access.ccodenode = new CCodeIdentifier ("self");
889 var ma = new MemberAccess (this_access, f.name);
890 ma.symbol_reference = f;
892 Gee.List<Expression> sizes = ((ArrayCreationExpression) f.initializer).get_sizes ();
893 for (int dim = 1; dim <= array_type.rank; dim++) {
894 var array_len_lhs = head.get_array_length_cexpression (ma, dim);
895 var size = sizes[dim - 1];
896 instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (array_len_lhs, (CCodeExpression) size.ccodenode)));
901 if (requires_destroy (f.field_type) && instance_finalize_fragment != null) {
902 var this_access = new MemberAccess.simple ("this");
903 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
905 var field_st = f.parent_symbol as Struct;
906 if (field_st != null && !field_st.is_simple_type ()) {
907 this_access.ccodenode = new CCodeIdentifier ("(*self)");
908 } else {
909 this_access.ccodenode = new CCodeIdentifier ("self");
912 var ma = new MemberAccess (this_access, f.name);
913 ma.symbol_reference = f;
914 instance_finalize_fragment.append (new CCodeExpressionStatement (get_unref_expression (lhs, f.field_type, ma)));
916 } else if (f.binding == MemberBinding.CLASS) {
917 st.add_field (field_ctype, f.get_cname ());
918 } else {
919 /* add array length fields where necessary */
920 if (f.field_type is ArrayType && !f.no_array_length) {
921 var array_type = (ArrayType) f.field_type;
923 for (int dim = 1; dim <= array_type.rank; dim++) {
924 var len_type = int_type.copy ();
926 var cdecl = new CCodeDeclaration (len_type.get_cname ());
927 cdecl.add_declarator (new CCodeVariableDeclarator (head.get_array_length_cname (f.get_cname (), dim)));
928 if (f.access != SymbolAccessibility.PRIVATE) {
929 cdecl.modifiers = CCodeModifiers.EXTERN;
930 header_type_member_declaration.append (cdecl);
931 } else {
932 cdecl.modifiers = CCodeModifiers.STATIC;
933 source_type_member_declaration.append (cdecl);
936 } else if (f.field_type is DelegateType) {
937 var delegate_type = (DelegateType) f.field_type;
938 if (delegate_type.delegate_symbol.has_target) {
939 // create field to store delegate target
940 var cdecl = new CCodeDeclaration ("gpointer");
941 cdecl.add_declarator (new CCodeVariableDeclarator (get_delegate_target_cname (f.get_cname ())));
942 if (f.access != SymbolAccessibility.PRIVATE) {
943 cdecl.modifiers = CCodeModifiers.EXTERN;
944 header_type_member_declaration.append (cdecl);
945 } else {
946 cdecl.modifiers = CCodeModifiers.STATIC;
947 source_type_member_declaration.append (cdecl);
952 if (f.initializer != null) {
953 var rhs = (CCodeExpression) f.initializer.ccodenode;
954 if (!is_constant_ccode_expression (rhs)) {
955 if (f.parent_symbol is Class) {
956 class_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, rhs)));
957 } else {
958 f.error = true;
959 Report.error (f.source_reference, "Non-constant field initializers not supported in this context");
960 return;
967 public bool is_constant_ccode_expression (CCodeExpression cexpr) {
968 if (cexpr is CCodeConstant) {
969 return true;
970 } else if (cexpr is CCodeBinaryExpression) {
971 var cbinary = (CCodeBinaryExpression) cexpr;
972 return is_constant_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
975 var cparenthesized = (cexpr as CCodeParenthesizedExpression);
976 return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
980 * Returns whether the passed cexpr is a pure expression, i.e. an
981 * expression without side-effects.
983 public bool is_pure_ccode_expression (CCodeExpression cexpr) {
984 if (cexpr is CCodeConstant || cexpr is CCodeIdentifier) {
985 return true;
986 } else if (cexpr is CCodeBinaryExpression) {
987 var cbinary = (CCodeBinaryExpression) cexpr;
988 return is_pure_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
989 } else if (cexpr is CCodeMemberAccess) {
990 var cma = (CCodeMemberAccess) cexpr;
991 return is_pure_ccode_expression (cma.inner);
994 var cparenthesized = (cexpr as CCodeParenthesizedExpression);
995 return (null != cparenthesized && is_pure_ccode_expression (cparenthesized.inner));
998 public override void visit_formal_parameter (FormalParameter p) {
999 check_type (p.parameter_type);
1001 p.accept_children (codegen);
1003 if (!p.ellipsis) {
1004 string ctypename = p.parameter_type.get_cname ();
1005 string cname = p.name;
1007 // pass non-simple structs always by reference
1008 if (p.parameter_type.data_type is Struct) {
1009 var st = (Struct) p.parameter_type.data_type;
1010 if (!st.is_simple_type () && p.direction == ParameterDirection.IN && !p.parameter_type.nullable) {
1011 ctypename += "*";
1015 if (p.direction != ParameterDirection.IN) {
1016 ctypename += "*";
1019 p.ccodenode = new CCodeFormalParameter (cname, ctypename);
1020 } else {
1021 p.ccodenode = new CCodeFormalParameter.with_ellipsis ();
1025 public override void visit_property (Property prop) {
1026 check_type (prop.property_type);
1028 int old_next_temp_var_id = next_temp_var_id;
1029 next_temp_var_id = 0;
1031 prop.accept_children (codegen);
1033 next_temp_var_id = old_next_temp_var_id;
1035 var cl = prop.parent_symbol as Class;
1036 if (cl != null && cl.is_subtype_of (gobject_type)
1037 && prop.binding == MemberBinding.INSTANCE) {
1038 // GObject property
1039 // FIXME: omit real struct types for now since they
1040 // cannot be expressed as gobject property yet
1041 // don't register private properties
1042 if (!prop.property_type.is_real_struct_type ()
1043 && prop.access != SymbolAccessibility.PRIVATE) {
1044 prop_enum.add_value (new CCodeEnumValue (prop.get_upper_case_cname ()));
1049 public override void visit_property_accessor (PropertyAccessor acc) {
1050 current_property_accessor = acc;
1051 current_method_inner_error = false;
1053 var prop = (Property) acc.prop;
1055 bool returns_real_struct = prop.property_type.is_real_struct_type ();
1057 if (acc.readable && !returns_real_struct) {
1058 current_return_type = prop.property_type;
1059 } else {
1060 current_return_type = new VoidType ();
1063 acc.accept_children (codegen);
1065 var t = (TypeSymbol) prop.parent_symbol;
1067 ReferenceType this_type;
1068 if (t is Class) {
1069 this_type = new ObjectType ((Class) t);
1070 } else {
1071 this_type = new ObjectType ((Interface) t);
1073 var cselfparam = new CCodeFormalParameter ("self", this_type.get_cname ());
1074 var value_type = prop.property_type.copy ();
1075 CCodeFormalParameter cvalueparam;
1076 if (returns_real_struct) {
1077 cvalueparam = new CCodeFormalParameter ("value", value_type.get_cname () + "*");
1078 } else {
1079 cvalueparam = new CCodeFormalParameter ("value", value_type.get_cname ());
1082 if (prop.is_abstract || prop.is_virtual) {
1083 CCodeFunctionDeclarator vdeclarator;
1085 if (acc.readable) {
1086 function = new CCodeFunction (acc.get_cname (), current_return_type.get_cname ());
1088 var vdecl = new CCodeDeclaration (current_return_type.get_cname ());
1089 vdeclarator = new CCodeFunctionDeclarator ("get_%s".printf (prop.name));
1090 vdecl.add_declarator (vdeclarator);
1091 type_struct.add_declaration (vdecl);
1092 } else {
1093 function = new CCodeFunction (acc.get_cname (), "void");
1095 var vdecl = new CCodeDeclaration ("void");
1096 vdeclarator = new CCodeFunctionDeclarator ("set_%s".printf (prop.name));
1097 vdecl.add_declarator (vdeclarator);
1098 type_struct.add_declaration (vdecl);
1100 function.add_parameter (cselfparam);
1101 vdeclarator.add_parameter (cselfparam);
1102 if (acc.writable || acc.construction || returns_real_struct) {
1103 function.add_parameter (cvalueparam);
1104 vdeclarator.add_parameter (cvalueparam);
1107 if (!prop.is_internal_symbol () && (acc.readable || acc.writable) && acc.access != SymbolAccessibility.PRIVATE) {
1108 // accessor function should be public if the property is a public symbol and it's not a construct-only setter
1109 header_type_member_declaration.append (function.copy ());
1110 } else {
1111 function.modifiers |= CCodeModifiers.STATIC;
1112 source_type_member_declaration.append (function.copy ());
1115 var block = new CCodeBlock ();
1116 function.block = block;
1118 CCodeFunctionCall vcast = null;
1119 if (prop.parent_symbol is Interface) {
1120 var iface = (Interface) prop.parent_symbol;
1122 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
1123 } else {
1124 var cl = (Class) prop.parent_symbol;
1126 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
1128 vcast.add_argument (new CCodeIdentifier ("self"));
1130 if (acc.readable) {
1131 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
1132 vcall.add_argument (new CCodeIdentifier ("self"));
1133 if (returns_real_struct) {
1134 vcall.add_argument (new CCodeIdentifier ("value"));
1135 block.add_statement (new CCodeExpressionStatement (vcall));
1136 } else {
1137 block.add_statement (new CCodeReturnStatement (vcall));
1139 } else {
1140 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
1141 vcall.add_argument (new CCodeIdentifier ("self"));
1142 vcall.add_argument (new CCodeIdentifier ("value"));
1143 block.add_statement (new CCodeExpressionStatement (vcall));
1146 source_type_member_definition.append (function);
1149 if (!prop.is_abstract) {
1150 bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
1152 string cname;
1153 if (is_virtual) {
1154 if (acc.readable) {
1155 cname = "%s_real_get_%s".printf (t.get_lower_case_cname (null), prop.name);
1156 } else {
1157 cname = "%s_real_set_%s".printf (t.get_lower_case_cname (null), prop.name);
1159 } else {
1160 cname = acc.get_cname ();
1163 if (acc.writable || acc.construction || returns_real_struct) {
1164 function = new CCodeFunction (cname, "void");
1165 } else {
1166 function = new CCodeFunction (cname, prop.property_type.get_cname ());
1169 ObjectType base_type = null;
1170 if (prop.binding == MemberBinding.INSTANCE) {
1171 if (is_virtual) {
1172 if (prop.base_property != null) {
1173 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
1174 } else if (prop.base_interface_property != null) {
1175 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
1177 function.modifiers |= CCodeModifiers.STATIC;
1178 function.add_parameter (new CCodeFormalParameter ("base", base_type.get_cname ()));
1179 } else {
1180 function.add_parameter (cselfparam);
1183 if (acc.writable || acc.construction || returns_real_struct) {
1184 function.add_parameter (cvalueparam);
1187 if (!is_virtual) {
1188 if (!prop.is_internal_symbol () && (acc.readable || acc.writable) && acc.access != SymbolAccessibility.PRIVATE) {
1189 // accessor function should be public if the property is a public symbol and it's not a construct-only setter
1190 header_type_member_declaration.append (function.copy ());
1191 } else {
1192 function.modifiers |= CCodeModifiers.STATIC;
1193 source_type_member_declaration.append (function.copy ());
1197 function.block = (CCodeBlock) acc.body.ccodenode;
1199 if (is_virtual) {
1200 var cdecl = new CCodeDeclaration (this_type.get_cname ());
1201 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", transform_expression (new CCodeIdentifier ("base"), base_type, this_type)));
1202 function.block.prepend_statement (cdecl);
1205 if (current_method_inner_error) {
1206 var cdecl = new CCodeDeclaration ("GError *");
1207 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
1208 function.block.prepend_statement (cdecl);
1211 if (prop.binding == MemberBinding.INSTANCE && !is_virtual) {
1212 if (returns_real_struct) {
1213 function.block.prepend_statement (create_property_type_check_statement (prop, false, t, true, "self"));
1214 } else {
1215 function.block.prepend_statement (create_property_type_check_statement (prop, acc.readable, t, true, "self"));
1219 // notify on property changes
1220 var typesymbol = (TypeSymbol) prop.parent_symbol;
1221 if (typesymbol.is_subtype_of (gobject_type) &&
1222 prop.notify &&
1223 prop.access != SymbolAccessibility.PRIVATE && // FIXME: use better means to detect gobject properties
1224 prop.binding == MemberBinding.INSTANCE &&
1225 !prop.property_type.is_real_struct_type () &&
1226 (acc.writable || acc.construction)) {
1227 var notify_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_notify"));
1228 notify_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
1229 notify_call.add_argument (prop.get_canonical_cconstant ());
1230 function.block.add_statement (new CCodeExpressionStatement (notify_call));
1233 source_type_member_definition.append (function);
1236 current_property_accessor = null;
1237 current_return_type = null;
1240 public override void visit_destructor (Destructor d) {
1241 current_method_inner_error = false;
1243 d.accept_children (codegen);
1245 CCodeFragment cfrag = new CCodeFragment ();
1247 if (current_method_inner_error) {
1248 var cdecl = new CCodeDeclaration ("GError *");
1249 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
1250 cfrag.append (cdecl);
1253 cfrag.append (d.body.ccodenode);
1255 d.ccodenode = cfrag;
1258 public override void visit_block (Block b) {
1259 var old_symbol = current_symbol;
1260 current_symbol = b;
1262 b.accept_children (codegen);
1264 var local_vars = b.get_local_variables ();
1265 foreach (LocalVariable local in local_vars) {
1266 local.active = false;
1269 var cblock = new CCodeBlock ();
1271 foreach (CodeNode stmt in b.get_statements ()) {
1272 if (stmt.error) {
1273 continue;
1276 var src = stmt.source_reference;
1277 if (src != null && src.comment != null) {
1278 cblock.add_statement (new CCodeComment (src.comment));
1281 if (stmt.ccodenode is CCodeFragment) {
1282 foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
1283 cblock.add_statement (cstmt);
1285 } else {
1286 cblock.add_statement (stmt.ccodenode);
1290 foreach (LocalVariable local in local_vars) {
1291 if (!local.floating && requires_destroy (local.variable_type)) {
1292 var ma = new MemberAccess.simple (local.name);
1293 ma.symbol_reference = local;
1294 cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (local.name)), local.variable_type, ma)));
1298 if (b.parent_symbol is Method) {
1299 var m = (Method) b.parent_symbol;
1300 foreach (FormalParameter param in m.get_parameters ()) {
1301 if (requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
1302 var ma = new MemberAccess.simple (param.name);
1303 ma.symbol_reference = param;
1304 cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (param.name)), param.parameter_type, ma)));
1309 b.ccodenode = cblock;
1311 current_symbol = old_symbol;
1314 public override void visit_empty_statement (EmptyStatement stmt) {
1315 stmt.ccodenode = new CCodeEmptyStatement ();
1318 public override void visit_declaration_statement (DeclarationStatement stmt) {
1319 stmt.declaration.accept (codegen);
1321 stmt.ccodenode = stmt.declaration.ccodenode;
1323 var local = stmt.declaration as LocalVariable;
1324 if (local != null && local.initializer != null) {
1325 create_temp_decl (stmt, local.initializer.temp_vars);
1328 create_temp_decl (stmt, temp_vars);
1329 temp_vars.clear ();
1332 public string get_variable_cname (string name) {
1333 if (name[0] == '.') {
1334 // compiler-internal variable
1335 if (!variable_name_map.contains (name)) {
1336 variable_name_map.set (name, "_tmp%d".printf (next_temp_var_id));
1337 next_temp_var_id++;
1339 return variable_name_map.get (name);
1340 } else if (c_keywords.contains (name)) {
1341 return name + "_";
1342 } else {
1343 return name;
1347 public override void visit_local_variable (LocalVariable local) {
1348 check_type (local.variable_type);
1350 local.accept_children (codegen);
1352 if (local.variable_type is ArrayType) {
1353 // create variables to store array dimensions
1354 var array_type = (ArrayType) local.variable_type;
1356 for (int dim = 1; dim <= array_type.rank; dim++) {
1357 var len_var = new LocalVariable (int_type.copy (), head.get_array_length_cname (get_variable_cname (local.name), dim));
1358 temp_vars.insert (0, len_var);
1360 } else if (local.variable_type is DelegateType) {
1361 var deleg_type = (DelegateType) local.variable_type;
1362 var d = deleg_type.delegate_symbol;
1363 if (d.has_target) {
1364 // create variable to store delegate target
1365 var target_var = new LocalVariable (new PointerType (new VoidType ()), get_delegate_target_cname (get_variable_cname (local.name)));
1366 temp_vars.insert (0, target_var);
1370 CCodeExpression rhs = null;
1371 if (local.initializer != null && local.initializer.ccodenode != null) {
1372 rhs = (CCodeExpression) local.initializer.ccodenode;
1374 if (local.variable_type is ArrayType) {
1375 var array_type = (ArrayType) local.variable_type;
1377 var ccomma = new CCodeCommaExpression ();
1379 var temp_var = get_temp_variable (local.variable_type, true, local);
1380 temp_vars.insert (0, temp_var);
1381 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_var.name), rhs));
1383 for (int dim = 1; dim <= array_type.rank; dim++) {
1384 var lhs_array_len = new CCodeIdentifier (head.get_array_length_cname (get_variable_cname (local.name), dim));
1385 var rhs_array_len = head.get_array_length_cexpression (local.initializer, dim);
1386 ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
1389 ccomma.append_expression (new CCodeIdentifier (temp_var.name));
1391 rhs = ccomma;
1392 } else if (local.variable_type is DelegateType) {
1393 var deleg_type = (DelegateType) local.variable_type;
1394 var d = deleg_type.delegate_symbol;
1395 if (d.has_target) {
1396 var ccomma = new CCodeCommaExpression ();
1398 var temp_var = get_temp_variable (local.variable_type, true, local);
1399 temp_vars.insert (0, temp_var);
1400 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_var.name), rhs));
1402 var lhs_delegate_target = new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (local.name)));
1403 var rhs_delegate_target = get_delegate_target_cexpression (local.initializer);
1404 ccomma.append_expression (new CCodeAssignment (lhs_delegate_target, rhs_delegate_target));
1406 ccomma.append_expression (new CCodeIdentifier (temp_var.name));
1408 rhs = ccomma;
1411 } else if (local.variable_type.is_reference_type_or_type_parameter ()) {
1412 rhs = new CCodeConstant ("NULL");
1414 if (local.variable_type is ArrayType) {
1415 // initialize array length variables
1416 var array_type = (ArrayType) local.variable_type;
1418 var ccomma = new CCodeCommaExpression ();
1420 for (int dim = 1; dim <= array_type.rank; dim++) {
1421 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (head.get_array_length_cname (get_variable_cname (local.name), dim)), new CCodeConstant ("0")));
1424 ccomma.append_expression (rhs);
1426 rhs = ccomma;
1430 var cvar = new CCodeVariableDeclarator.with_initializer (get_variable_cname (local.name), rhs);
1432 var cfrag = new CCodeFragment ();
1433 var cdecl = new CCodeDeclaration (local.variable_type.get_cname ());
1434 cdecl.add_declarator (cvar);
1435 cfrag.append (cdecl);
1437 if (local.initializer != null && local.initializer.tree_can_fail) {
1438 head.add_simple_check (local.initializer, cfrag);
1441 /* try to initialize uninitialized variables */
1442 if (cvar.initializer == null) {
1443 cvar.initializer = default_value_for_type (local.variable_type, true);
1446 local.ccodenode = cfrag;
1448 local.active = true;
1451 public override void visit_initializer_list (InitializerList list) {
1452 list.accept_children (codegen);
1454 if (list.target_type.data_type is Struct) {
1455 /* initializer is used as struct initializer */
1456 var st = (Struct) list.target_type.data_type;
1458 var clist = new CCodeInitializerList ();
1460 var field_it = st.get_fields ().iterator ();
1461 foreach (Expression expr in list.get_initializers ()) {
1462 Field field = null;
1463 while (field == null) {
1464 field_it.next ();
1465 field = field_it.get ();
1466 if (field.binding != MemberBinding.INSTANCE) {
1467 // we only initialize instance fields
1468 field = null;
1472 var cexpr = (CCodeExpression) expr.ccodenode;
1474 string ctype = field.get_ctype ();
1475 if (ctype != null) {
1476 cexpr = new CCodeCastExpression (cexpr, ctype);
1479 clist.append (cexpr);
1482 list.ccodenode = clist;
1483 } else {
1484 var clist = new CCodeInitializerList ();
1485 foreach (Expression expr in list.get_initializers ()) {
1486 clist.append ((CCodeExpression) expr.ccodenode);
1488 list.ccodenode = clist;
1492 public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null) {
1493 var var_type = type.copy ();
1494 var_type.value_owned = value_owned;
1495 var local = new LocalVariable (var_type, "_tmp%d".printf (next_temp_var_id));
1497 if (node_reference != null) {
1498 local.source_reference = node_reference.source_reference;
1501 next_temp_var_id++;
1503 return local;
1506 private CCodeExpression get_type_id_expression (DataType type) {
1507 if (type is GenericType) {
1508 string var_name = "%s_type".printf (type.type_parameter.name.down ());
1509 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), var_name);
1510 } else {
1511 string type_id = type.get_type_id ();
1512 if (type_id == null) {
1513 type_id = "G_TYPE_INVALID";
1515 return new CCodeIdentifier (type_id);
1519 public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference) {
1520 if (type is ErrorType) {
1521 return new CCodeIdentifier ("g_error_copy");
1522 } else if (type.data_type != null) {
1523 string dup_function;
1524 var cl = type.data_type as Class;
1525 if (type.data_type.is_reference_counting ()) {
1526 dup_function = type.data_type.get_ref_function ();
1527 if (type.data_type is Interface && dup_function == null) {
1528 Report.error (source_reference, "missing class prerequisite for interface `%s'".printf (type.data_type.get_full_name ()));
1529 return null;
1531 } else if (cl != null && cl.is_immutable) {
1532 // allow duplicates of immutable instances as for example strings
1533 dup_function = type.data_type.get_dup_function ();
1534 } else if (type is ValueType) {
1535 dup_function = type.data_type.get_dup_function ();
1536 if (dup_function == null && type.nullable) {
1537 dup_function = generate_struct_dup_wrapper ((ValueType) type);
1538 } else if (dup_function == null) {
1539 dup_function = "";
1541 } else {
1542 // duplicating non-reference counted objects may cause side-effects (and performance issues)
1543 Report.error (source_reference, "duplicating %s instance, use weak variable or explicitly invoke copy method".printf (type.data_type.name));
1544 return null;
1547 return new CCodeIdentifier (dup_function);
1548 } else if (type.type_parameter != null && current_type_symbol is Class) {
1549 string func_name = "%s_dup_func".printf (type.type_parameter.name.down ());
1550 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
1551 } else if (type is PointerType) {
1552 var pointer_type = (PointerType) type;
1553 return get_dup_func_expression (pointer_type.base_type, source_reference);
1554 } else {
1555 return new CCodeConstant ("NULL");
1559 private string generate_struct_dup_wrapper (ValueType value_type) {
1560 string dup_func = "_%sdup".printf (value_type.type_symbol.get_lower_case_cprefix ());
1562 if (!add_wrapper (dup_func)) {
1563 // wrapper already defined
1564 return dup_func;
1567 // declaration
1569 var function = new CCodeFunction (dup_func, value_type.get_cname ());
1570 function.modifiers = CCodeModifiers.STATIC;
1572 function.add_parameter (new CCodeFormalParameter ("self", value_type.get_cname ()));
1574 // definition
1576 var block = new CCodeBlock ();
1578 if (value_type.type_symbol == gvalue_type) {
1579 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
1580 dup_call.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
1581 dup_call.add_argument (new CCodeIdentifier ("self"));
1583 block.add_statement (new CCodeReturnStatement (dup_call));
1584 } else {
1585 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
1586 dup_call.add_argument (new CCodeIdentifier ("self"));
1588 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
1589 sizeof_call.add_argument (new CCodeIdentifier (value_type.type_symbol.get_cname ()));
1590 dup_call.add_argument (sizeof_call);
1592 block.add_statement (new CCodeReturnStatement (dup_call));
1595 // append to file
1597 source_type_member_declaration.append (function.copy ());
1599 function.block = block;
1600 source_type_member_definition.append (function);
1602 return dup_func;
1605 public CCodeExpression? get_destroy_func_expression (DataType type) {
1606 if (type.data_type == glist_type || type.data_type == gslist_type) {
1607 // create wrapper function to free list elements if necessary
1609 bool elements_require_free = false;
1610 CCodeExpression element_destroy_func_expression = null;
1612 foreach (DataType type_arg in type.get_type_arguments ()) {
1613 elements_require_free = requires_destroy (type_arg);
1614 if (elements_require_free) {
1615 element_destroy_func_expression = get_destroy_func_expression (type_arg);
1619 if (elements_require_free && element_destroy_func_expression is CCodeIdentifier) {
1620 return new CCodeIdentifier (generate_glist_free_wrapper (type, (CCodeIdentifier) element_destroy_func_expression));
1621 } else {
1622 return new CCodeIdentifier (type.data_type.get_free_function ());
1624 } else if (type is ErrorType) {
1625 return new CCodeIdentifier ("g_error_free");
1626 } else if (type.data_type != null) {
1627 string unref_function;
1628 if (type is ReferenceType) {
1629 if (type.data_type.is_reference_counting ()) {
1630 unref_function = type.data_type.get_unref_function ();
1631 if (type.data_type is Interface && unref_function == null) {
1632 Report.error (type.source_reference, "missing class prerequisite for interface `%s'".printf (type.data_type.get_full_name ()));
1633 return null;
1635 } else {
1636 unref_function = type.data_type.get_free_function ();
1638 } else {
1639 if (type.nullable) {
1640 unref_function = type.data_type.get_free_function ();
1641 if (unref_function == null) {
1642 unref_function = "g_free";
1644 } else {
1645 var st = (Struct) type.data_type;
1646 unref_function = st.get_destroy_function ();
1649 if (unref_function == null) {
1650 return new CCodeConstant ("NULL");
1652 return new CCodeIdentifier (unref_function);
1653 } else if (type.type_parameter != null && current_type_symbol is Class) {
1654 string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ());
1655 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
1656 } else if (type is ArrayType) {
1657 return new CCodeIdentifier ("g_free");
1658 } else if (type is PointerType) {
1659 return new CCodeIdentifier ("g_free");
1660 } else {
1661 return new CCodeConstant ("NULL");
1665 private string generate_glist_free_wrapper (DataType list_type, CCodeIdentifier element_destroy_func_expression) {
1666 string destroy_func = "_%s_%s".printf (list_type.data_type.get_free_function (), element_destroy_func_expression.name);
1668 if (!add_wrapper (destroy_func)) {
1669 // wrapper already defined
1670 return destroy_func;
1673 // declaration
1675 var function = new CCodeFunction (destroy_func, "void");
1676 function.modifiers = CCodeModifiers.STATIC;
1678 function.add_parameter (new CCodeFormalParameter ("self", list_type.get_cname ()));
1680 // definition
1682 var block = new CCodeBlock ();
1684 CCodeFunctionCall element_free_call;
1685 if (list_type.data_type == glist_type) {
1686 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
1687 } else {
1688 element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_slist_foreach"));
1690 element_free_call.add_argument (new CCodeIdentifier ("self"));
1691 element_free_call.add_argument (new CCodeCastExpression (element_destroy_func_expression, "GFunc"));
1692 element_free_call.add_argument (new CCodeConstant ("NULL"));
1693 block.add_statement (new CCodeExpressionStatement (element_free_call));
1695 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier (list_type.data_type.get_free_function ()));
1696 cfreecall.add_argument (new CCodeIdentifier ("self"));
1697 block.add_statement (new CCodeExpressionStatement (cfreecall));
1699 // append to file
1701 source_type_member_declaration.append (function.copy ());
1703 function.block = block;
1704 source_type_member_definition.append (function);
1706 return destroy_func;
1709 public CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr) {
1710 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
1712 if (type is ValueType && !type.nullable) {
1713 // normal value type, no null check
1714 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
1716 if (type.data_type == gvalue_type) {
1717 // g_value_unset must not be called for already unset values
1718 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
1719 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
1721 var ccomma = new CCodeCommaExpression ();
1722 ccomma.append_expression (ccall);
1723 ccomma.append_expression (new CCodeConstant ("NULL"));
1725 return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
1726 } else {
1727 return ccall;
1731 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
1733 /* can be simplified to
1734 * foo = (unref (foo), NULL)
1735 * if foo is of static type non-null
1738 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
1739 if (type.type_parameter != null) {
1740 if (!(current_type_symbol is Class) || current_class.is_compact) {
1741 return new CCodeConstant ("NULL");
1744 // unref functions are optional for type parameters
1745 var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
1746 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
1749 ccall.add_argument (cvar);
1751 /* set freed references to NULL to prevent further use */
1752 var ccomma = new CCodeCommaExpression ();
1754 if (type.data_type == gstringbuilder_type || type.data_type == garray_type) {
1755 ccall.add_argument (new CCodeConstant ("TRUE"));
1756 } else if (type is ArrayType) {
1757 var array_type = (ArrayType) type;
1758 if (array_type.element_type.data_type == null || array_type.element_type.data_type.is_reference_type ()) {
1759 requires_array_free = true;
1761 bool first = true;
1762 CCodeExpression csizeexpr = null;
1763 for (int dim = 1; dim <= array_type.rank; dim++) {
1764 if (first) {
1765 csizeexpr = head.get_array_length_cexpression (expr, dim);
1766 first = false;
1767 } else {
1768 csizeexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeexpr, head.get_array_length_cexpression (expr, dim));
1772 ccall.call = new CCodeIdentifier ("_vala_array_free");
1773 ccall.add_argument (csizeexpr);
1774 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
1778 ccomma.append_expression (ccall);
1779 ccomma.append_expression (new CCodeConstant ("NULL"));
1781 var cassign = new CCodeAssignment (cvar, ccomma);
1783 // g_free (NULL) is allowed
1784 bool uses_gfree = (type.data_type != null && !type.data_type.is_reference_counting () && type.data_type.get_free_function () == "g_free");
1785 uses_gfree = uses_gfree || type is ArrayType;
1786 if (uses_gfree) {
1787 return cassign;
1790 return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
1793 public override void visit_end_full_expression (Expression expr) {
1794 /* expr is a full expression, i.e. an initializer, the
1795 * expression in an expression statement, the controlling
1796 * expression in if, while, for, or foreach statements
1798 * we unref temporary variables at the end of a full
1799 * expression
1802 /* can't automatically deep copy lists yet, so do it
1803 * manually for now
1804 * replace with
1805 * expr.temp_vars = temp_vars;
1806 * when deep list copying works
1808 expr.temp_vars.clear ();
1809 foreach (LocalVariable local in temp_vars) {
1810 expr.temp_vars.add (local);
1812 temp_vars.clear ();
1814 if (((Gee.List<LocalVariable>) temp_ref_vars).size == 0) {
1815 /* nothing to do without temporary variables */
1816 return;
1819 var expr_type = expr.value_type;
1820 if (expr.target_type != null) {
1821 expr_type = expr.target_type;
1824 var full_expr_var = get_temp_variable (expr_type, true, expr);
1825 expr.temp_vars.add (full_expr_var);
1827 var expr_list = new CCodeCommaExpression ();
1828 expr_list.append_expression (new CCodeAssignment (new CCodeIdentifier (full_expr_var.name), (CCodeExpression) expr.ccodenode));
1830 foreach (LocalVariable local in temp_ref_vars) {
1831 var ma = new MemberAccess.simple (local.name);
1832 ma.symbol_reference = local;
1833 expr_list.append_expression (get_unref_expression (new CCodeIdentifier (local.name), local.variable_type, ma));
1836 expr_list.append_expression (new CCodeIdentifier (full_expr_var.name));
1838 expr.ccodenode = expr_list;
1840 temp_ref_vars.clear ();
1843 public void append_temp_decl (CCodeFragment cfrag, Gee.List<LocalVariable> temp_vars) {
1844 foreach (LocalVariable local in temp_vars) {
1845 var cdecl = new CCodeDeclaration (local.variable_type.get_cname ());
1847 var vardecl = new CCodeVariableDeclarator (local.name);
1848 // sets #line
1849 local.ccodenode = vardecl;
1850 cdecl.add_declarator (vardecl);
1852 var st = local.variable_type.data_type as Struct;
1854 if (local.variable_type.is_reference_type_or_type_parameter ()) {
1855 vardecl.initializer = new CCodeConstant ("NULL");
1856 } else if (st != null && !st.is_simple_type ()) {
1857 // 0-initialize struct with struct initializer { 0 }
1858 // necessary as they will be passed by reference
1859 var clist = new CCodeInitializerList ();
1860 clist.append (new CCodeConstant ("0"));
1862 vardecl.initializer = clist;
1865 cfrag.append (cdecl);
1869 public override void visit_expression_statement (ExpressionStatement stmt) {
1870 stmt.accept_children (codegen);
1872 if (stmt.expression.error) {
1873 stmt.error = true;
1874 return;
1877 stmt.ccodenode = new CCodeExpressionStatement ((CCodeExpression) stmt.expression.ccodenode);
1879 var invoc = stmt.expression as MethodCall;
1880 if (invoc != null) {
1881 var m = invoc.call.symbol_reference as Method;
1882 var ma = invoc.call as MemberAccess;
1883 if (m != null && m.coroutine && current_method != null && current_method.coroutine &&
1884 (ma == null || ma.member_name != "begin" || ma.inner.symbol_reference != ma.symbol_reference)) {
1885 var cfrag = new CCodeFragment ();
1887 int state = next_coroutine_state++;
1889 cfrag.append (stmt.ccodenode);
1890 cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "state"), new CCodeConstant (state.to_string ()))));
1891 cfrag.append (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
1892 cfrag.append (new CCodeCaseStatement (new CCodeConstant (state.to_string ())));
1894 stmt.ccodenode = cfrag;
1898 if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
1899 // simple case, no node breakdown necessary
1901 var cfrag = new CCodeFragment ();
1903 cfrag.append (stmt.ccodenode);
1905 head.add_simple_check (stmt.expression, cfrag);
1907 stmt.ccodenode = cfrag;
1910 /* free temporary objects */
1912 if (((Gee.List<LocalVariable>) temp_vars).size == 0) {
1913 /* nothing to do without temporary variables */
1914 return;
1917 var cfrag = new CCodeFragment ();
1918 append_temp_decl (cfrag, temp_vars);
1920 cfrag.append (stmt.ccodenode);
1922 foreach (LocalVariable local in temp_ref_vars) {
1923 var ma = new MemberAccess.simple (local.name);
1924 ma.symbol_reference = local;
1925 cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (local.name), local.variable_type, ma)));
1928 stmt.ccodenode = cfrag;
1930 temp_vars.clear ();
1931 temp_ref_vars.clear ();
1934 public void create_temp_decl (Statement stmt, Gee.List<LocalVariable> temp_vars) {
1935 /* declare temporary variables */
1937 if (temp_vars.size == 0) {
1938 /* nothing to do without temporary variables */
1939 return;
1942 var cfrag = new CCodeFragment ();
1943 append_temp_decl (cfrag, temp_vars);
1945 cfrag.append (stmt.ccodenode);
1947 stmt.ccodenode = cfrag;
1950 public void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop) {
1951 var b = (Block) sym;
1953 var local_vars = b.get_local_variables ();
1954 foreach (LocalVariable local in local_vars) {
1955 if (local.active && !local.floating && requires_destroy (local.variable_type)) {
1956 var ma = new MemberAccess.simple (local.name);
1957 ma.symbol_reference = local;
1958 cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (local.name)), local.variable_type, ma)));
1962 if (stop_at_loop) {
1963 if (b.parent_node is DoStatement || b.parent_node is WhileStatement ||
1964 b.parent_node is ForStatement || b.parent_node is ForeachStatement ||
1965 b.parent_node is SwitchStatement) {
1966 return;
1970 if (sym.parent_symbol is Block) {
1971 append_local_free (sym.parent_symbol, cfrag, stop_at_loop);
1972 } else if (sym.parent_symbol is Method) {
1973 append_param_free ((Method) sym.parent_symbol, cfrag);
1977 private void append_param_free (Method m, CCodeFragment cfrag) {
1978 foreach (FormalParameter param in m.get_parameters ()) {
1979 if (requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
1980 var ma = new MemberAccess.simple (param.name);
1981 ma.symbol_reference = param;
1982 cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (param.name)), param.parameter_type, ma)));
1987 public void create_local_free (CodeNode stmt, bool stop_at_loop = false) {
1988 var cfrag = new CCodeFragment ();
1990 append_local_free (current_symbol, cfrag, stop_at_loop);
1992 cfrag.append (stmt.ccodenode);
1993 stmt.ccodenode = cfrag;
1996 private bool append_local_free_expr (Symbol sym, CCodeCommaExpression ccomma, bool stop_at_loop) {
1997 bool found = false;
1999 var b = (Block) sym;
2001 var local_vars = b.get_local_variables ();
2002 foreach (LocalVariable local in local_vars) {
2003 if (local.active && !local.floating && requires_destroy (local.variable_type)) {
2004 found = true;
2005 var ma = new MemberAccess.simple (local.name);
2006 ma.symbol_reference = local;
2007 ccomma.append_expression (get_unref_expression (new CCodeIdentifier (get_variable_cname (local.name)), local.variable_type, ma));
2011 if (sym.parent_symbol is Block) {
2012 found = append_local_free_expr (sym.parent_symbol, ccomma, stop_at_loop) || found;
2013 } else if (sym.parent_symbol is Method) {
2014 found = append_param_free_expr ((Method) sym.parent_symbol, ccomma) || found;
2017 return found;
2020 private bool append_param_free_expr (Method m, CCodeCommaExpression ccomma) {
2021 bool found = false;
2023 foreach (FormalParameter param in m.get_parameters ()) {
2024 if (requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
2025 found = true;
2026 var ma = new MemberAccess.simple (param.name);
2027 ma.symbol_reference = param;
2028 ccomma.append_expression (get_unref_expression (new CCodeIdentifier (get_variable_cname (param.name)), param.parameter_type, ma));
2032 return found;
2035 private void create_local_free_expr (Expression expr) {
2036 var expr_type = expr.value_type;
2037 if (expr.target_type != null) {
2038 expr_type = expr.target_type;
2041 var return_expr_decl = get_temp_variable (expr_type, true, expr);
2043 var ccomma = new CCodeCommaExpression ();
2044 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (return_expr_decl.name), (CCodeExpression) expr.ccodenode));
2046 if (!append_local_free_expr (current_symbol, ccomma, false)) {
2047 /* no local variables need to be freed */
2048 return;
2051 ccomma.append_expression (new CCodeIdentifier (return_expr_decl.name));
2053 expr.ccodenode = ccomma;
2054 expr.temp_vars.add (return_expr_decl);
2057 public override void visit_return_statement (ReturnStatement stmt) {
2058 // avoid unnecessary ref/unref pair
2059 if (stmt.return_expression != null) {
2060 var local = stmt.return_expression.symbol_reference as LocalVariable;
2061 if (current_return_type.value_owned
2062 && local != null && local.variable_type.value_owned) {
2063 /* return expression is local variable taking ownership and
2064 * current method is transferring ownership */
2066 // don't ref expression
2067 stmt.return_expression.value_type.value_owned = true;
2071 stmt.accept_children (codegen);
2073 if (stmt.return_expression == null) {
2074 stmt.ccodenode = new CCodeReturnStatement ();
2076 create_local_free (stmt);
2077 } else {
2078 Symbol return_expression_symbol = null;
2080 // avoid unnecessary ref/unref pair
2081 var local = stmt.return_expression.symbol_reference as LocalVariable;
2082 if (current_return_type.value_owned
2083 && local != null && local.variable_type.value_owned) {
2084 /* return expression is local variable taking ownership and
2085 * current method is transferring ownership */
2087 // don't unref variable
2088 return_expression_symbol = local;
2089 return_expression_symbol.active = false;
2092 // return array length if appropriate
2093 if (current_method != null && !current_method.no_array_length && current_return_type is ArrayType) {
2094 var return_expr_decl = get_temp_variable (stmt.return_expression.value_type, true, stmt);
2096 var ccomma = new CCodeCommaExpression ();
2097 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (return_expr_decl.name), (CCodeExpression) stmt.return_expression.ccodenode));
2099 var array_type = (ArrayType) current_return_type;
2101 for (int dim = 1; dim <= array_type.rank; dim++) {
2102 var len_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (head.get_array_length_cname ("result", dim)));
2103 var len_r = head.get_array_length_cexpression (stmt.return_expression, dim);
2104 ccomma.append_expression (new CCodeAssignment (len_l, len_r));
2107 ccomma.append_expression (new CCodeIdentifier (return_expr_decl.name));
2109 stmt.return_expression.ccodenode = ccomma;
2110 stmt.return_expression.temp_vars.add (return_expr_decl);
2113 create_local_free_expr (stmt.return_expression);
2115 // Property getters of non simple structs shall return the struct value as out parameter,
2116 // therefore replace any return statement with an assignment statement to the out formal
2117 // paramenter and insert an empty return statement afterwards.
2118 if (current_property_accessor != null &&
2119 current_property_accessor.readable &&
2120 current_property_accessor.prop.property_type.is_real_struct_type()) {
2121 var cfragment = new CCodeFragment ();
2122 cfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("*value"), (CCodeExpression) stmt.return_expression.ccodenode)));
2123 cfragment.append (new CCodeReturnStatement ());
2124 stmt.ccodenode = cfragment;
2125 } else {
2126 stmt.ccodenode = new CCodeReturnStatement ((CCodeExpression) stmt.return_expression.ccodenode);
2129 create_temp_decl (stmt, stmt.return_expression.temp_vars);
2131 if (return_expression_symbol != null) {
2132 return_expression_symbol.active = true;
2137 private string get_symbol_lock_name (Symbol sym) {
2138 return "__lock_%s".printf (sym.name);
2141 public override void visit_lock_statement (LockStatement stmt) {
2142 var cn = new CCodeFragment ();
2143 CCodeExpression l = null;
2144 CCodeFunctionCall fc;
2145 var inner_node = ((MemberAccess)stmt.resource).inner;
2147 if (inner_node == null) {
2148 l = new CCodeIdentifier ("self");
2149 } else if (stmt.resource.symbol_reference.parent_symbol != current_type_symbol) {
2150 l = new InstanceCast ((CCodeExpression) inner_node.ccodenode, (TypeSymbol) stmt.resource.symbol_reference.parent_symbol);
2151 } else {
2152 l = (CCodeExpression) inner_node.ccodenode;
2154 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (stmt.resource.symbol_reference));
2156 fc = new CCodeFunctionCall (new CCodeIdentifier (((Method) mutex_type.scope.lookup ("lock")).get_cname ()));
2157 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
2159 cn.append (new CCodeExpressionStatement (fc));
2161 cn.append (stmt.body.ccodenode);
2163 fc = new CCodeFunctionCall (new CCodeIdentifier (((Method) mutex_type.scope.lookup ("unlock")).get_cname ()));
2164 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
2165 cn.append (new CCodeExpressionStatement (fc));
2167 stmt.ccodenode = cn;
2170 public override void visit_delete_statement (DeleteStatement stmt) {
2171 stmt.accept_children (codegen);
2173 var pointer_type = (PointerType) stmt.expression.value_type;
2174 DataType type = pointer_type;
2175 if (pointer_type.base_type.data_type != null && pointer_type.base_type.data_type.is_reference_type ()) {
2176 type = pointer_type.base_type;
2179 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
2180 ccall.add_argument ((CCodeExpression) stmt.expression.ccodenode);
2181 stmt.ccodenode = new CCodeExpressionStatement (ccall);
2184 public override void visit_expression (Expression expr) {
2185 if (expr.ccodenode != null && !expr.lvalue) {
2186 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
2187 if (expr.formal_value_type.type_parameter.parent_symbol != garray_type) {
2188 // GArray doesn't use pointer-based generics
2189 expr.ccodenode = convert_from_generic_pointer ((CCodeExpression) expr.ccodenode, expr.value_type);
2193 // memory management, implicit casts, and boxing/unboxing
2194 expr.ccodenode = transform_expression ((CCodeExpression) expr.ccodenode, expr.value_type, expr.target_type, expr);
2196 if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
2197 if (expr.formal_target_type.type_parameter.parent_symbol != garray_type) {
2198 // GArray doesn't use pointer-based generics
2199 expr.ccodenode = convert_to_generic_pointer ((CCodeExpression) expr.ccodenode, expr.target_type);
2205 public override void visit_boolean_literal (BooleanLiteral expr) {
2206 expr.ccodenode = new CCodeConstant (expr.value ? "TRUE" : "FALSE");
2209 public override void visit_character_literal (CharacterLiteral expr) {
2210 if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
2211 expr.ccodenode = new CCodeConstant (expr.value);
2212 } else {
2213 expr.ccodenode = new CCodeConstant ("%uU".printf (expr.get_char ()));
2217 public override void visit_integer_literal (IntegerLiteral expr) {
2218 expr.ccodenode = new CCodeConstant (expr.value);
2221 public override void visit_real_literal (RealLiteral expr) {
2222 expr.ccodenode = new CCodeConstant (expr.value);
2225 public override void visit_string_literal (StringLiteral expr) {
2226 expr.ccodenode = new CCodeConstant (expr.value);
2229 public override void visit_null_literal (NullLiteral expr) {
2230 expr.ccodenode = new CCodeConstant ("NULL");
2233 public override void visit_parenthesized_expression (ParenthesizedExpression expr) {
2234 expr.accept_children (codegen);
2236 expr.ccodenode = new CCodeParenthesizedExpression ((CCodeExpression) expr.inner.ccodenode);
2239 public virtual string get_delegate_target_cname (string delegate_cname) {
2240 assert_not_reached ();
2243 public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr) {
2244 assert_not_reached ();
2247 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname) {
2248 assert_not_reached ();
2251 public override void visit_base_access (BaseAccess expr) {
2252 expr.ccodenode = new InstanceCast (new CCodeIdentifier ("self"), expr.value_type.data_type);
2255 public override void visit_postfix_expression (PostfixExpression expr) {
2256 MemberAccess ma = find_property_access (expr.inner);
2257 if (ma != null) {
2258 // property postfix expression
2259 var prop = (Property) ma.symbol_reference;
2261 var ccomma = new CCodeCommaExpression ();
2263 // assign current value to temp variable
2264 var temp_decl = get_temp_variable (prop.property_type, true, expr);
2265 temp_vars.insert (0, temp_decl);
2266 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), (CCodeExpression) expr.inner.ccodenode));
2268 // increment/decrement property
2269 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
2270 var cexpr = new CCodeBinaryExpression (op, new CCodeIdentifier (temp_decl.name), new CCodeConstant ("1"));
2271 var ccall = get_property_set_call (prop, ma, cexpr);
2272 ccomma.append_expression (ccall);
2274 // return previous value
2275 ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
2277 expr.ccodenode = ccomma;
2278 return;
2281 var op = expr.increment ? CCodeUnaryOperator.POSTFIX_INCREMENT : CCodeUnaryOperator.POSTFIX_DECREMENT;
2283 expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
2286 private MemberAccess? find_property_access (Expression expr) {
2287 if (expr is ParenthesizedExpression) {
2288 var pe = (ParenthesizedExpression) expr;
2289 return find_property_access (pe.inner);
2292 if (!(expr is MemberAccess)) {
2293 return null;
2296 var ma = (MemberAccess) expr;
2297 if (ma.symbol_reference is Property) {
2298 return ma;
2301 return null;
2304 public bool requires_copy (DataType type) {
2305 if (!type.is_disposable ()) {
2306 return false;
2309 var cl = type.data_type as Class;
2310 if (cl != null && cl.is_reference_counting ()
2311 && cl.get_ref_function () == "") {
2312 // empty ref_function => no ref necessary
2313 return false;
2316 if (type.type_parameter != null) {
2317 if (!(current_type_symbol is Class) || current_class.is_compact) {
2318 return false;
2322 return true;
2325 public bool requires_destroy (DataType type) {
2326 if (!type.is_disposable ()) {
2327 return false;
2330 var cl = type.data_type as Class;
2331 if (cl != null && cl.is_reference_counting ()
2332 && cl.get_unref_function () == "") {
2333 // empty unref_function => no unref necessary
2334 return false;
2337 if (type.type_parameter != null) {
2338 if (!(current_type_symbol is Class) || current_class.is_compact) {
2339 return false;
2343 return true;
2346 public CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
2347 if (expression_type is ValueType && !expression_type.nullable) {
2348 // normal value type, no null check
2349 // (copy (&expr, &temp), temp)
2351 var decl = get_temp_variable (expression_type, false, node);
2352 temp_vars.insert (0, decl);
2354 var ctemp = new CCodeIdentifier (decl.name);
2356 var vt = (ValueType) expression_type;
2357 var st = (Struct) vt.type_symbol;
2358 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (st.get_copy_function ()));
2359 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
2360 copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
2362 var ccomma = new CCodeCommaExpression ();
2364 if (st.get_copy_function () == "g_value_copy") {
2365 // GValue requires g_value_init in addition to g_value_copy
2367 var value_type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
2368 value_type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
2370 var init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
2371 init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
2372 init_call.add_argument (value_type_call);
2374 ccomma.append_expression (init_call);
2377 ccomma.append_expression (copy_call);
2378 ccomma.append_expression (ctemp);
2380 if (expression_type.data_type == gvalue_type) {
2381 // g_value_init/copy must not be called for uninitialized values
2382 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
2383 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
2385 return new CCodeConditionalExpression (cisvalid, ccomma, cexpr);
2386 } else {
2387 return ccomma;
2391 /* (temp = expr, temp == NULL ? NULL : ref (temp))
2393 * can be simplified to
2394 * ref (expr)
2395 * if static type of expr is non-null
2398 var dupexpr = get_dup_func_expression (expression_type, node.source_reference);
2400 if (dupexpr == null) {
2401 node.error = true;
2402 return null;
2405 var ccall = new CCodeFunctionCall (dupexpr);
2407 if (!(expression_type is ArrayType) && expr != null && expr.is_non_null ()) {
2408 // expression is non-null
2409 ccall.add_argument ((CCodeExpression) expr.ccodenode);
2411 return ccall;
2412 } else {
2413 var decl = get_temp_variable (expression_type, false, node);
2414 temp_vars.insert (0, decl);
2416 var ctemp = new CCodeIdentifier (decl.name);
2418 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL"));
2419 if (expression_type.type_parameter != null) {
2420 if (!(current_type_symbol is Class)) {
2421 return cexpr;
2424 // dup functions are optional for type parameters
2425 var cdupisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_dup_func_expression (expression_type, node.source_reference), new CCodeConstant ("NULL"));
2426 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cdupisnull);
2429 if (expression_type.type_parameter != null) {
2430 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
2431 ccall.add_argument (new CCodeCastExpression (ctemp, "gpointer"));
2432 } else {
2433 ccall.add_argument (ctemp);
2436 if (expression_type is ArrayType) {
2437 var array_type = (ArrayType) expression_type;
2438 bool first = true;
2439 CCodeExpression csizeexpr = null;
2440 for (int dim = 1; dim <= array_type.rank; dim++) {
2441 if (first) {
2442 csizeexpr = head.get_array_length_cexpression (expr, dim);
2443 first = false;
2444 } else {
2445 csizeexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeexpr, head.get_array_length_cexpression (expr, dim));
2449 ccall.add_argument (csizeexpr);
2452 var ccomma = new CCodeCommaExpression ();
2453 ccomma.append_expression (new CCodeAssignment (ctemp, cexpr));
2455 CCodeExpression cifnull;
2456 if (expression_type.data_type != null) {
2457 cifnull = new CCodeConstant ("NULL");
2458 } else {
2459 // the value might be non-null even when the dup function is null,
2460 // so we may not just use NULL for type parameters
2462 // cast from gconstpointer to gpointer as methods in
2463 // generic classes may not return gconstpointer
2464 cifnull = new CCodeCastExpression (ctemp, "gpointer");
2466 ccomma.append_expression (new CCodeConditionalExpression (cisnull, cifnull, ccall));
2468 return ccomma;
2472 bool is_reference_type_argument (DataType type_arg) {
2473 if (type_arg.data_type != null && type_arg.data_type.is_reference_type ()) {
2474 return true;
2475 } else {
2476 return false;
2480 bool is_nullable_value_type_argument (DataType type_arg) {
2481 if (type_arg is ValueType && type_arg.nullable) {
2482 return true;
2483 } else {
2484 return false;
2488 bool is_signed_integer_type_argument (DataType type_arg) {
2489 var st = type_arg.data_type as Struct;
2490 if (type_arg.nullable) {
2491 return false;
2492 } else if (st == bool_type.data_type) {
2493 return true;
2494 } else if (st == char_type.data_type) {
2495 return true;
2496 } else if (st == unichar_type.data_type) {
2497 return true;
2498 } else if (st == short_type.data_type) {
2499 return true;
2500 } else if (st == int_type.data_type) {
2501 return true;
2502 } else if (st == long_type.data_type) {
2503 return true;
2504 } else if (st == int8_type.data_type) {
2505 return true;
2506 } else if (st == int16_type.data_type) {
2507 return true;
2508 } else if (st == int32_type.data_type) {
2509 return true;
2510 } else if (st == gtype_type) {
2511 return true;
2512 } else {
2513 return false;
2517 bool is_unsigned_integer_type_argument (DataType type_arg) {
2518 var st = type_arg.data_type as Struct;
2519 if (type_arg.nullable) {
2520 return false;
2521 } else if (st == uchar_type.data_type) {
2522 return true;
2523 } else if (st == ushort_type.data_type) {
2524 return true;
2525 } else if (st == uint_type.data_type) {
2526 return true;
2527 } else if (st == ulong_type.data_type) {
2528 return true;
2529 } else if (st == uint8_type.data_type) {
2530 return true;
2531 } else if (st == uint16_type.data_type) {
2532 return true;
2533 } else if (st == uint32_type.data_type) {
2534 return true;
2535 } else {
2536 return false;
2540 public void check_type (DataType type) {
2541 var array_type = type as ArrayType;
2542 if (array_type != null) {
2543 check_type (array_type.element_type);
2545 foreach (var type_arg in type.get_type_arguments ()) {
2546 check_type (type_arg);
2547 check_type_argument (type_arg);
2551 void check_type_argument (DataType type_arg) {
2552 if (type_arg is GenericType
2553 || type_arg is PointerType
2554 || is_reference_type_argument (type_arg)
2555 || is_nullable_value_type_argument (type_arg)
2556 || is_signed_integer_type_argument (type_arg)
2557 || is_unsigned_integer_type_argument (type_arg)) {
2558 // no error
2559 } else {
2560 Report.error (type_arg.source_reference, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg.to_string ()));
2564 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
2565 expr.accept_children (codegen);
2567 CCodeExpression instance = null;
2568 CCodeExpression creation_expr = null;
2570 check_type (expr.type_reference);
2572 var st = expr.type_reference.data_type as Struct;
2573 if ((st != null && !st.is_simple_type ()) || expr.get_object_initializer ().size > 0) {
2574 // value-type initialization or object creation expression with object initializer
2575 var temp_decl = get_temp_variable (expr.type_reference, false, expr);
2576 temp_vars.add (temp_decl);
2578 instance = new CCodeIdentifier (get_variable_cname (temp_decl.name));
2581 if (expr.symbol_reference == null) {
2582 CCodeFunctionCall creation_call = null;
2584 // no creation method
2585 if (expr.type_reference.data_type == glist_type ||
2586 expr.type_reference.data_type == gslist_type) {
2587 // NULL is an empty list
2588 expr.ccodenode = new CCodeConstant ("NULL");
2589 } else if (expr.type_reference.data_type is Class && expr.type_reference.data_type.is_subtype_of (gobject_type)) {
2590 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_new"));
2591 creation_call.add_argument (new CCodeConstant (expr.type_reference.data_type.get_type_id ()));
2592 creation_call.add_argument (new CCodeConstant ("NULL"));
2593 } else if (expr.type_reference.data_type is Class) {
2594 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
2595 creation_call.add_argument (new CCodeConstant (expr.type_reference.data_type.get_cname ()));
2596 creation_call.add_argument (new CCodeConstant ("1"));
2597 } else if (expr.type_reference.data_type is Struct) {
2598 // memset needs string.h
2599 string_h_needed = true;
2600 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
2601 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
2602 creation_call.add_argument (new CCodeConstant ("0"));
2603 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (expr.type_reference.get_cname ())));
2606 creation_expr = creation_call;
2607 } else if (expr.symbol_reference is Method) {
2608 // use creation method
2609 var m = (Method) expr.symbol_reference;
2610 var params = m.get_parameters ();
2611 CCodeFunctionCall creation_call;
2613 creation_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
2615 if ((st != null && !st.is_simple_type ()) && !(m.cinstance_parameter_position < 0)) {
2616 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
2619 var cl = expr.type_reference.data_type as Class;
2620 if (cl != null && !cl.is_compact) {
2621 foreach (DataType type_arg in expr.type_reference.get_type_arguments ()) {
2622 creation_call.add_argument (get_type_id_expression (type_arg));
2623 if (requires_copy (type_arg)) {
2624 var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference);
2625 if (dup_func == null) {
2626 // type doesn't contain a copy function
2627 expr.error = true;
2628 return;
2630 creation_call.add_argument (new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
2631 creation_call.add_argument (get_destroy_func_expression (type_arg));
2632 } else {
2633 creation_call.add_argument (new CCodeConstant ("NULL"));
2634 creation_call.add_argument (new CCodeConstant ("NULL"));
2639 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
2641 bool ellipsis = false;
2643 int i = 1;
2644 int arg_pos;
2645 Iterator<FormalParameter> params_it = params.iterator ();
2646 foreach (Expression arg in expr.get_argument_list ()) {
2647 CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
2648 FormalParameter param = null;
2649 if (params_it.next ()) {
2650 param = params_it.get ();
2651 ellipsis = param.ellipsis;
2652 if (!ellipsis) {
2653 if (!param.no_array_length && param.parameter_type is ArrayType) {
2654 var array_type = (ArrayType) param.parameter_type;
2655 for (int dim = 1; dim <= array_type.rank; dim++) {
2656 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), head.get_array_length_cexpression (arg, dim));
2658 } else if (param.parameter_type is DelegateType) {
2659 var deleg_type = (DelegateType) param.parameter_type;
2660 var d = deleg_type.delegate_symbol;
2661 if (d.has_target) {
2662 var delegate_target = get_delegate_target_cexpression (arg);
2663 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), delegate_target);
2667 cexpr = handle_struct_argument (param, arg, cexpr);
2670 arg_pos = get_param_pos (param.cparameter_position, ellipsis);
2671 } else {
2672 // default argument position
2673 arg_pos = get_param_pos (i, ellipsis);
2676 carg_map.set (arg_pos, cexpr);
2678 i++;
2680 while (params_it.next ()) {
2681 var param = params_it.get ();
2683 if (param.ellipsis) {
2684 ellipsis = true;
2685 break;
2688 if (param.default_expression == null) {
2689 Report.error (expr.source_reference, "no default expression for argument %d".printf (i));
2690 return;
2693 /* evaluate default expression here as the code
2694 * generator might not have visited the formal
2695 * parameter yet */
2696 param.default_expression.accept (codegen);
2698 carg_map.set (get_param_pos (param.cparameter_position), (CCodeExpression) param.default_expression.ccodenode);
2699 i++;
2702 // append C arguments in the right order
2703 int last_pos = -1;
2704 int min_pos;
2705 while (true) {
2706 min_pos = -1;
2707 foreach (int pos in carg_map.get_keys ()) {
2708 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
2709 min_pos = pos;
2712 if (min_pos == -1) {
2713 break;
2715 creation_call.add_argument (carg_map.get (min_pos));
2716 last_pos = min_pos;
2719 if ((st != null && !st.is_simple_type ()) && m.cinstance_parameter_position < 0) {
2720 // instance parameter is at the end in a struct creation method
2721 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
2724 if (expr.tree_can_fail) {
2725 // method can fail
2726 current_method_inner_error = true;
2727 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("inner_error")));
2730 if (ellipsis) {
2731 /* ensure variable argument list ends with NULL
2732 * except when using printf-style arguments */
2733 if (!m.printf_format && m.sentinel != "") {
2734 creation_call.add_argument (new CCodeConstant (m.sentinel));
2738 creation_expr = creation_call;
2740 // cast the return value of the creation method back to the intended type if
2741 // it requested a special C return type
2742 if (head.get_custom_creturn_type (m) != null) {
2743 creation_expr = new CCodeCastExpression (creation_expr, expr.type_reference.get_cname ());
2745 } else if (expr.symbol_reference is ErrorCode) {
2746 var ecode = (ErrorCode) expr.symbol_reference;
2747 var edomain = (ErrorDomain) ecode.parent_symbol;
2748 CCodeFunctionCall creation_call;
2750 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new"));
2751 creation_call.add_argument (new CCodeIdentifier (edomain.get_upper_case_cname ()));
2752 creation_call.add_argument (new CCodeIdentifier (ecode.get_cname ()));
2754 foreach (Expression arg in expr.get_argument_list ()) {
2755 creation_call.add_argument ((CCodeExpression) arg.ccodenode);
2758 creation_expr = creation_call;
2759 } else {
2760 assert (false);
2763 if (instance != null) {
2764 var ccomma = new CCodeCommaExpression ();
2766 if (expr.type_reference.data_type is Struct) {
2767 ccomma.append_expression (creation_expr);
2768 } else {
2769 ccomma.append_expression (new CCodeAssignment (instance, creation_expr));
2772 foreach (MemberInitializer init in expr.get_object_initializer ()) {
2773 if (init.symbol_reference is Field) {
2774 var f = (Field) init.symbol_reference;
2775 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
2776 var typed_inst = transform_expression (instance, expr.type_reference, instance_target_type);
2777 CCodeExpression lhs;
2778 if (expr.type_reference.data_type is Struct) {
2779 lhs = new CCodeMemberAccess (typed_inst, f.get_cname ());
2780 } else {
2781 lhs = new CCodeMemberAccess.pointer (typed_inst, f.get_cname ());
2783 ccomma.append_expression (new CCodeAssignment (lhs, (CCodeExpression) init.initializer.ccodenode));
2784 } else if (init.symbol_reference is Property) {
2785 var inst_ma = new MemberAccess.simple ("new");
2786 inst_ma.value_type = expr.type_reference;
2787 inst_ma.ccodenode = instance;
2788 var ma = new MemberAccess (inst_ma, init.name);
2789 ccomma.append_expression (get_property_set_call ((Property) init.symbol_reference, ma, (CCodeExpression) init.initializer.ccodenode));
2793 ccomma.append_expression (instance);
2795 expr.ccodenode = ccomma;
2796 } else if (creation_expr != null) {
2797 expr.ccodenode = creation_expr;
2801 public CCodeExpression? handle_struct_argument (FormalParameter param, Expression arg, CCodeExpression? cexpr) {
2802 // pass non-simple struct instances always by reference
2803 if (!(arg.value_type is NullType) && param.parameter_type.data_type is Struct && !((Struct) param.parameter_type.data_type).is_simple_type ()) {
2804 // we already use a reference for arguments of ref, out, and nullable parameters
2805 if (param.direction == ParameterDirection.IN && !param.parameter_type.nullable) {
2806 var unary = cexpr as CCodeUnaryExpression;
2807 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
2808 // *expr => expr
2809 return unary.inner;
2810 } else if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
2811 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
2812 } else {
2813 // if cexpr is e.g. a function call, we can't take the address of the expression
2814 // (tmp = expr, &tmp)
2815 var ccomma = new CCodeCommaExpression ();
2817 var temp_var = get_temp_variable (arg.value_type);
2818 temp_vars.insert (0, temp_var);
2819 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_var.name), cexpr));
2820 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_var.name)));
2822 return ccomma;
2827 return cexpr;
2830 public override void visit_sizeof_expression (SizeofExpression expr) {
2831 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
2832 csizeof.add_argument (new CCodeIdentifier (expr.type_reference.get_cname ()));
2833 expr.ccodenode = csizeof;
2836 public override void visit_typeof_expression (TypeofExpression expr) {
2837 expr.ccodenode = get_type_id_expression (expr.type_reference);
2840 public override void visit_unary_expression (UnaryExpression expr) {
2841 expr.accept_children (codegen);
2843 CCodeUnaryOperator op;
2844 if (expr.operator == UnaryOperator.PLUS) {
2845 op = CCodeUnaryOperator.PLUS;
2846 } else if (expr.operator == UnaryOperator.MINUS) {
2847 op = CCodeUnaryOperator.MINUS;
2848 } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
2849 op = CCodeUnaryOperator.LOGICAL_NEGATION;
2850 } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
2851 op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
2852 } else if (expr.operator == UnaryOperator.INCREMENT) {
2853 op = CCodeUnaryOperator.PREFIX_INCREMENT;
2854 } else if (expr.operator == UnaryOperator.DECREMENT) {
2855 op = CCodeUnaryOperator.PREFIX_DECREMENT;
2856 } else if (expr.operator == UnaryOperator.REF) {
2857 op = CCodeUnaryOperator.ADDRESS_OF;
2858 } else if (expr.operator == UnaryOperator.OUT) {
2859 op = CCodeUnaryOperator.ADDRESS_OF;
2860 } else {
2861 assert_not_reached ();
2863 expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
2866 public override void visit_cast_expression (CastExpression expr) {
2867 var cl = expr.type_reference.data_type as Class;
2868 var iface = expr.type_reference.data_type as Interface;
2869 if (iface != null || (cl != null && !cl.is_compact)) {
2870 // checked cast for strict subtypes of GTypeInstance
2871 if (expr.is_silent_cast) {
2872 var ccomma = new CCodeCommaExpression ();
2873 var temp_decl = get_temp_variable (expr.inner.value_type, true, expr);
2875 temp_vars.add (temp_decl);
2877 var ctemp = new CCodeIdentifier (temp_decl.name);
2878 var cinit = new CCodeAssignment (ctemp, (CCodeExpression) expr.inner.ccodenode);
2879 var ccheck = create_type_check (ctemp, expr.type_reference);
2880 var ccast = new CCodeCastExpression (ctemp, expr.type_reference.get_cname ());
2881 var cnull = new CCodeConstant ("NULL");
2883 ccomma.append_expression (cinit);
2884 ccomma.append_expression (new CCodeConditionalExpression (ccheck, ccast, cnull));
2886 expr.ccodenode = ccomma;
2887 } else {
2888 expr.ccodenode = new InstanceCast ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.data_type);
2890 } else {
2891 if (expr.is_silent_cast) {
2892 expr.error = true;
2893 Report.error (expr.source_reference, "Operation not supported for this type");
2894 return;
2896 expr.ccodenode = new CCodeCastExpression ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.get_cname ());
2900 public override void visit_pointer_indirection (PointerIndirection expr) {
2901 expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, (CCodeExpression) expr.inner.ccodenode);
2904 public override void visit_addressof_expression (AddressofExpression expr) {
2905 expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, (CCodeExpression) expr.inner.ccodenode);
2908 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
2909 expr.accept_children (codegen);
2911 /* (tmp = var, var = null, tmp) */
2912 var ccomma = new CCodeCommaExpression ();
2913 var temp_decl = get_temp_variable (expr.value_type, true, expr);
2914 temp_vars.insert (0, temp_decl);
2915 var cvar = new CCodeIdentifier (temp_decl.name);
2917 ccomma.append_expression (new CCodeAssignment (cvar, (CCodeExpression) expr.inner.ccodenode));
2918 ccomma.append_expression (new CCodeAssignment ((CCodeExpression) expr.inner.ccodenode, new CCodeConstant ("NULL")));
2919 ccomma.append_expression (cvar);
2920 expr.ccodenode = ccomma;
2923 public override void visit_binary_expression (BinaryExpression expr) {
2924 expr.accept_children (codegen);
2926 var cleft = (CCodeExpression) expr.left.ccodenode;
2927 var cright = (CCodeExpression) expr.right.ccodenode;
2929 CCodeBinaryOperator op;
2930 if (expr.operator == BinaryOperator.PLUS) {
2931 op = CCodeBinaryOperator.PLUS;
2932 } else if (expr.operator == BinaryOperator.MINUS) {
2933 op = CCodeBinaryOperator.MINUS;
2934 } else if (expr.operator == BinaryOperator.MUL) {
2935 op = CCodeBinaryOperator.MUL;
2936 } else if (expr.operator == BinaryOperator.DIV) {
2937 op = CCodeBinaryOperator.DIV;
2938 } else if (expr.operator == BinaryOperator.MOD) {
2939 op = CCodeBinaryOperator.MOD;
2940 } else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
2941 op = CCodeBinaryOperator.SHIFT_LEFT;
2942 } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
2943 op = CCodeBinaryOperator.SHIFT_RIGHT;
2944 } else if (expr.operator == BinaryOperator.LESS_THAN) {
2945 op = CCodeBinaryOperator.LESS_THAN;
2946 } else if (expr.operator == BinaryOperator.GREATER_THAN) {
2947 op = CCodeBinaryOperator.GREATER_THAN;
2948 } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
2949 op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
2950 } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
2951 op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
2952 } else if (expr.operator == BinaryOperator.EQUALITY) {
2953 op = CCodeBinaryOperator.EQUALITY;
2954 } else if (expr.operator == BinaryOperator.INEQUALITY) {
2955 op = CCodeBinaryOperator.INEQUALITY;
2956 } else if (expr.operator == BinaryOperator.BITWISE_AND) {
2957 op = CCodeBinaryOperator.BITWISE_AND;
2958 } else if (expr.operator == BinaryOperator.BITWISE_OR) {
2959 op = CCodeBinaryOperator.BITWISE_OR;
2960 } else if (expr.operator == BinaryOperator.BITWISE_XOR) {
2961 op = CCodeBinaryOperator.BITWISE_XOR;
2962 } else if (expr.operator == BinaryOperator.AND) {
2963 op = CCodeBinaryOperator.AND;
2964 } else if (expr.operator == BinaryOperator.OR) {
2965 op = CCodeBinaryOperator.OR;
2966 } else if (expr.operator == BinaryOperator.IN) {
2967 expr.ccodenode = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft);
2968 return;
2969 } else {
2970 assert_not_reached ();
2973 if (expr.operator == BinaryOperator.EQUALITY ||
2974 expr.operator == BinaryOperator.INEQUALITY) {
2975 var left_type_as_struct = expr.left.value_type.data_type as Struct;
2976 var right_type_as_struct = expr.right.value_type.data_type as Struct;
2978 if (expr.left.value_type.data_type is Class && !((Class) expr.left.value_type.data_type).is_compact &&
2979 expr.right.value_type.data_type is Class && !((Class) expr.right.value_type.data_type).is_compact) {
2980 var left_cl = (Class) expr.left.value_type.data_type;
2981 var right_cl = (Class) expr.right.value_type.data_type;
2983 if (left_cl != right_cl) {
2984 if (left_cl.is_subtype_of (right_cl)) {
2985 cleft = new InstanceCast (cleft, right_cl);
2986 } else if (right_cl.is_subtype_of (left_cl)) {
2987 cright = new InstanceCast (cright, left_cl);
2990 } else if (left_type_as_struct != null && right_type_as_struct != null) {
2991 // FIXME generate and use compare/equal function for real structs
2992 if (expr.left.value_type.nullable && expr.right.value_type.nullable) {
2993 // FIXME also compare contents, not just address
2994 } else if (expr.left.value_type.nullable) {
2995 // FIXME check left value is not null
2996 cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
2997 } else if (expr.right.value_type.nullable) {
2998 // FIXME check right value is not null
2999 cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
3004 if (!(expr.left.value_type is NullType)
3005 && expr.left.value_type.compatible (string_type)
3006 && !(expr.right.value_type is NullType)
3007 && expr.right.value_type.compatible (string_type)) {
3008 if (expr.operator == BinaryOperator.PLUS) {
3009 // string concatenation
3010 if (expr.left.is_constant () && expr.right.is_constant ()) {
3011 string left, right;
3013 if (cleft is CCodeIdentifier) {
3014 left = ((CCodeIdentifier) cleft).name;
3015 } else if (cleft is CCodeConstant) {
3016 left = ((CCodeConstant) cleft).name;
3017 } else {
3018 assert_not_reached ();
3020 if (cright is CCodeIdentifier) {
3021 right = ((CCodeIdentifier) cright).name;
3022 } else if (cright is CCodeConstant) {
3023 right = ((CCodeConstant) cright).name;
3024 } else {
3025 assert_not_reached ();
3028 expr.ccodenode = new CCodeConstant ("%s %s".printf (left, right));
3029 return;
3030 } else {
3031 // convert to g_strconcat (a, b, NULL)
3032 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
3033 ccall.add_argument (cleft);
3034 ccall.add_argument (cright);
3035 ccall.add_argument (new CCodeConstant("NULL"));
3036 expr.ccodenode = ccall;
3037 return;
3039 } else if (expr.operator == BinaryOperator.EQUALITY
3040 || expr.operator == BinaryOperator.INEQUALITY
3041 || expr.operator == BinaryOperator.LESS_THAN
3042 || expr.operator == BinaryOperator.GREATER_THAN
3043 || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL
3044 || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
3045 requires_strcmp0 = true;
3046 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_strcmp0"));
3047 ccall.add_argument (cleft);
3048 ccall.add_argument (cright);
3049 cleft = ccall;
3050 cright = new CCodeConstant ("0");
3054 expr.ccodenode = new CCodeBinaryExpression (op, cleft, cright);
3057 public string get_type_check_function (TypeSymbol type) {
3058 var cl = type as Class;
3059 if (cl != null && cl.type_check_function != null) {
3060 return cl.type_check_function;
3061 } else {
3062 return type.get_upper_case_cname ("IS_");
3066 CCodeExpression create_type_check (CCodeNode ccodenode, DataType type) {
3067 var et = type as ErrorType;
3068 if (et != null && et.error_code != null) {
3069 var matches_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
3070 matches_call.add_argument ((CCodeExpression) ccodenode);
3071 matches_call.add_argument (new CCodeIdentifier (et.error_domain.get_upper_case_cname ()));
3072 matches_call.add_argument (new CCodeIdentifier (et.error_code.get_cname ()));
3073 return matches_call;
3074 } else if (et != null && et.error_domain != null) {
3075 var instance_domain = new CCodeMemberAccess.pointer ((CCodeExpression) ccodenode, "domain");
3076 var type_domain = new CCodeIdentifier (et.error_domain.get_upper_case_cname ());
3077 return new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, instance_domain, type_domain);
3078 } else {
3079 var ccheck = new CCodeFunctionCall (new CCodeIdentifier (get_type_check_function (type.data_type)));
3080 ccheck.add_argument ((CCodeExpression) ccodenode);
3081 return ccheck;
3085 public override void visit_type_check (TypeCheck expr) {
3086 expr.ccodenode = create_type_check (expr.expression.ccodenode, expr.type_reference);
3089 public override void visit_lambda_expression (LambdaExpression l) {
3090 // use instance position from delegate
3091 var dt = (DelegateType) l.target_type;
3092 l.method.cinstance_parameter_position = dt.delegate_symbol.cinstance_parameter_position;
3094 var old_temp_vars = temp_vars;
3095 var old_temp_ref_vars = temp_ref_vars;
3096 temp_vars = new ArrayList<LocalVariable> ();
3097 temp_ref_vars = new ArrayList<LocalVariable> ();
3099 l.accept_children (codegen);
3101 temp_vars = old_temp_vars;
3102 temp_ref_vars = old_temp_ref_vars;
3104 l.ccodenode = new CCodeIdentifier (l.method.get_cname ());
3107 public CCodeExpression convert_from_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
3108 var result = cexpr;
3109 if (is_reference_type_argument (actual_type) || is_nullable_value_type_argument (actual_type)) {
3110 result = new CCodeCastExpression (cexpr, actual_type.get_cname ());
3111 } else if (is_signed_integer_type_argument (actual_type)) {
3112 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
3113 cconv.add_argument (cexpr);
3114 result = cconv;
3115 } else if (is_unsigned_integer_type_argument (actual_type)) {
3116 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
3117 cconv.add_argument (cexpr);
3118 result = cconv;
3120 return result;
3123 public CCodeExpression convert_to_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
3124 var result = cexpr;
3125 if (is_signed_integer_type_argument (actual_type)) {
3126 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GINT_TO_POINTER"));
3127 cconv.add_argument (cexpr);
3128 result = cconv;
3129 } else if (is_unsigned_integer_type_argument (actual_type)) {
3130 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GUINT_TO_POINTER"));
3131 cconv.add_argument (cexpr);
3132 result = cconv;
3134 return result;
3137 // manage memory and implicit casts
3138 public CCodeExpression transform_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
3139 var cexpr = source_cexpr;
3140 if (expression_type == null) {
3141 return cexpr;
3145 if (expression_type.value_owned
3146 && expression_type.floating_reference) {
3147 /* constructor of GInitiallyUnowned subtype
3148 * returns floating reference, sink it
3150 var csink = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref_sink"));
3151 csink.add_argument (cexpr);
3153 cexpr = csink;
3156 bool boxing = (expression_type is ValueType && !expression_type.nullable
3157 && target_type is ValueType && target_type.nullable);
3158 bool unboxing = (expression_type is ValueType && expression_type.nullable
3159 && target_type is ValueType && !target_type.nullable);
3161 if (expression_type.value_owned
3162 && (target_type == null || !target_type.value_owned || boxing || unboxing)) {
3163 // value leaked, destroy it
3164 var pointer_type = target_type as PointerType;
3165 if (pointer_type != null && !(pointer_type.base_type is VoidType)) {
3166 // manual memory management for non-void pointers
3167 // treat void* special to not leak memory with void* method parameters
3168 } else if (requires_destroy (expression_type)) {
3169 var decl = get_temp_variable (expression_type, true, expression_type);
3170 temp_vars.insert (0, decl);
3171 temp_ref_vars.insert (0, decl);
3172 cexpr = new CCodeAssignment (new CCodeIdentifier (get_variable_cname (decl.name)), cexpr);
3174 if (expression_type is ArrayType && expr != null) {
3175 var array_type = (ArrayType) expression_type;
3176 var ccomma = new CCodeCommaExpression ();
3177 ccomma.append_expression (cexpr);
3178 for (int dim = 1; dim <= array_type.rank; dim++) {
3179 var len_decl = new LocalVariable (int_type.copy (), head.get_array_length_cname (decl.name, dim));
3180 temp_vars.insert (0, len_decl);
3181 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (get_variable_cname (len_decl.name)), head.get_array_length_cexpression (expr, dim)));
3183 ccomma.append_expression (new CCodeIdentifier (get_variable_cname (decl.name)));
3184 cexpr = ccomma;
3189 if (target_type == null) {
3190 // value will be destroyed, no need for implicit casts
3191 return cexpr;
3194 if (boxing) {
3195 // value needs to be boxed
3197 var unary = cexpr as CCodeUnaryExpression;
3198 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
3199 // *expr => expr
3200 cexpr = unary.inner;
3201 } else if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
3202 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
3203 } else {
3204 var decl = get_temp_variable (expression_type, expression_type.value_owned, expression_type);
3205 temp_vars.insert (0, decl);
3207 var ccomma = new CCodeCommaExpression ();
3208 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (get_variable_cname (decl.name)), cexpr));
3209 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (get_variable_cname (decl.name))));
3210 cexpr = ccomma;
3212 } else if (unboxing) {
3213 // unbox value
3215 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cexpr);
3216 } else {
3217 cexpr = get_implicit_cast_expression (cexpr, expression_type, target_type, expr);
3220 if (target_type.value_owned && (!expression_type.value_owned || boxing || unboxing)) {
3221 // need to copy value
3222 if (requires_copy (target_type) && !(expression_type is NullType)) {
3223 CodeNode node = expr;
3224 if (node == null) {
3225 node = expression_type;
3227 cexpr = get_ref_cexpression (target_type, cexpr, expr, node);
3231 return cexpr;
3234 public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
3235 var cexpr = source_cexpr;
3237 if (expression_type.data_type != null && expression_type.data_type == target_type.data_type) {
3238 // same type, no cast required
3239 return cexpr;
3242 if (expression_type is NullType) {
3243 // null literal, no cast required when not converting to generic type pointer
3244 return cexpr;
3247 var cl = target_type.data_type as Class;
3248 var iface = target_type.data_type as Interface;
3249 if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
3250 // checked cast for strict subtypes of GTypeInstance
3251 return new InstanceCast (cexpr, target_type.data_type);
3252 } else if (target_type.data_type != null && expression_type.get_cname () != target_type.get_cname ()) {
3253 var st = target_type.data_type as Struct;
3254 if (target_type.data_type.is_reference_type () || (st != null && st.is_simple_type ())) {
3255 // don't cast non-simple structs
3256 return new CCodeCastExpression (cexpr, target_type.get_cname ());
3257 } else {
3258 return cexpr;
3260 } else {
3261 return cexpr;
3265 public CCodeFunctionCall get_property_set_call (Property prop, MemberAccess ma, CCodeExpression cexpr) {
3266 if (ma.inner is BaseAccess) {
3267 if (prop.base_property != null) {
3268 var base_class = (Class) prop.base_property.parent_symbol;
3269 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
3270 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
3272 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
3273 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
3274 ccall.add_argument (cexpr);
3275 return ccall;
3276 } else if (prop.base_interface_property != null) {
3277 var base_iface = (Interface) prop.base_interface_property.parent_symbol;
3278 string parent_iface_var = "%s_%s_parent_iface".printf (current_class.get_lower_case_cname (null), base_iface.get_lower_case_cname (null));
3280 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "set_%s".printf (prop.name)));
3281 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
3282 ccall.add_argument (cexpr);
3283 return ccall;
3287 var set_func = "g_object_set";
3289 var base_property = prop;
3290 if (!prop.no_accessor_method) {
3291 if (prop.base_property != null) {
3292 base_property = prop.base_property;
3293 } else if (prop.base_interface_property != null) {
3294 base_property = prop.base_interface_property;
3296 var base_property_type = (TypeSymbol) base_property.parent_symbol;
3297 set_func = "%s_set_%s".printf (base_property_type.get_lower_case_cname (null), base_property.name);
3298 if (prop is DynamicProperty) {
3299 set_func = head.get_dynamic_property_setter_cname ((DynamicProperty) prop);
3303 var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
3305 if (prop.binding == MemberBinding.INSTANCE) {
3306 /* target instance is first argument */
3307 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
3310 if (prop.no_accessor_method) {
3311 /* property name is second argument of g_object_set */
3312 ccall.add_argument (prop.get_canonical_cconstant ());
3315 ccall.add_argument (cexpr);
3317 if (prop.no_accessor_method) {
3318 ccall.add_argument (new CCodeConstant ("NULL"));
3321 return ccall;
3324 /* indicates whether a given Expression eligable for an ADDRESS_OF operator
3325 * from a vala to C point of view all expressions denoting locals, fields and
3326 * parameters are eligable to an ADDRESS_OF operator */
3327 public bool is_address_of_possible (Expression e) {
3328 var ma = e as MemberAccess;
3330 if (ma == null) {
3331 return false;
3333 if (ma.symbol_reference == null) {
3334 return false;
3336 if (ma.symbol_reference is FormalParameter) {
3337 return true;
3339 if (ma.symbol_reference is LocalVariable) {
3340 return true;
3342 if (ma.symbol_reference is Field) {
3343 return true;
3345 return false;
3348 /* retrieve the correct address_of expression for a give expression, creates temporary variables
3349 * where necessary, ce is the corresponding ccode expression for e */
3350 public CCodeExpression get_address_of_expression (Expression e, CCodeExpression ce) {
3351 // is address of trivially possible?
3352 if (is_address_of_possible (e)) {
3353 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ce);
3356 var ccomma = new CCodeCommaExpression ();
3357 var temp_decl = get_temp_variable (e.value_type);
3358 var ctemp = new CCodeIdentifier (temp_decl.name);
3359 temp_vars.add (temp_decl);
3360 ccomma.append_expression (new CCodeAssignment (ctemp, ce));
3361 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
3362 return ccomma;
3365 public bool add_wrapper (string wrapper_name) {
3366 return wrappers.add (wrapper_name);
3369 public static DataType get_data_type_for_symbol (TypeSymbol sym) {
3370 DataType type = null;
3372 if (sym is Class) {
3373 type = new ObjectType ((Class) sym);
3374 } else if (sym is Interface) {
3375 type = new ObjectType ((Interface) sym);
3376 } else if (sym is Struct) {
3377 type = new ValueType ((Struct) sym);
3378 } else if (sym is Enum) {
3379 type = new ValueType ((Enum) sym);
3380 } else if (sym is ErrorDomain) {
3381 type = new ErrorType ((ErrorDomain) sym, null);
3382 } else if (sym is ErrorCode) {
3383 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
3384 } else {
3385 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
3386 return new InvalidType ();
3389 return type;
3392 public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) {
3393 if ((type.data_type != null && type.data_type.is_reference_type ()) || type is PointerType || type is ArrayType) {
3394 return new CCodeConstant ("NULL");
3395 } else if (type.data_type != null && type.data_type.get_default_value () != null) {
3396 return new CCodeConstant (type.data_type.get_default_value ());
3397 } else if (type.data_type is Struct && initializer_expression) {
3398 // 0-initialize struct with struct initializer { 0 }
3399 // only allowed as initializer expression in C
3400 var clist = new CCodeInitializerList ();
3401 clist.append (new CCodeConstant ("0"));
3402 return clist;
3403 } else if (type.type_parameter != null) {
3404 return new CCodeConstant ("NULL");
3405 } else if (type is ErrorType) {
3406 return new CCodeConstant ("NULL");
3408 return null;
3411 private CCodeStatement create_property_type_check_statement (Property prop, bool check_return_type, TypeSymbol t, bool non_null, string var_name) {
3412 if (check_return_type) {
3413 return create_type_check_statement (prop, prop.property_type, t, non_null, var_name);
3414 } else {
3415 return create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
3419 public CCodeStatement? create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
3420 var ccheck = new CCodeFunctionCall ();
3422 if (context.checking && ((t is Class && !((Class) t).is_compact) || t is Interface)) {
3423 var ctype_check = new CCodeFunctionCall (new CCodeIdentifier (get_type_check_function (t)));
3424 ctype_check.add_argument (new CCodeIdentifier (var_name));
3426 CCodeExpression cexpr = ctype_check;
3427 if (!non_null) {
3428 var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
3430 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cnull, ctype_check);
3432 ccheck.add_argument (cexpr);
3433 } else if (!non_null) {
3434 return null;
3435 } else {
3436 var cnonnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
3437 ccheck.add_argument (cnonnull);
3440 if (ret_type is VoidType) {
3441 /* void function */
3442 ccheck.call = new CCodeIdentifier ("g_return_if_fail");
3443 } else {
3444 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
3446 var cdefault = default_value_for_type (ret_type, false);
3447 if (cdefault != null) {
3448 ccheck.add_argument (cdefault);
3449 } else {
3450 return new CCodeExpressionStatement (new CCodeConstant ("0"));
3454 return new CCodeExpressionStatement (ccheck);
3457 public int get_param_pos (double param_pos, bool ellipsis = false) {
3458 if (!ellipsis) {
3459 if (param_pos >= 0) {
3460 return (int) (param_pos * 1000);
3461 } else {
3462 return (int) ((100 + param_pos) * 1000);
3464 } else {
3465 if (param_pos >= 0) {
3466 return (int) ((100 + param_pos) * 1000);
3467 } else {
3468 return (int) ((200 + param_pos) * 1000);
3473 public CCodeNode? get_ccodenode (CodeNode node) {
3474 if (node.ccodenode == null) {
3475 node.accept (codegen);
3477 return node.ccodenode;