remove obsolete ref modifier and callback keyword
[vala-lang.git] / gobject / valacodegenerator.vala
blob0e26fcbf85309d175fcc9dd49b063bc6a58c6142
1 /* valacodegenerator.vala
3 * Copyright (C) 2006-2007 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 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 <rasa@gmx.ch>
24 using GLib;
26 /**
27 * Code visitor generating C Code.
29 public class Vala.CodeGenerator : CodeVisitor {
30 /**
31 * Specifies whether automatic memory management is active.
33 public bool memory_management { get; set; }
35 private CodeContext context;
37 Symbol root_symbol;
38 Symbol current_symbol;
39 Symbol current_type_symbol;
40 Class current_class;
41 TypeReference current_return_type;
43 CCodeFragment header_begin;
44 CCodeFragment header_type_declaration;
45 CCodeFragment header_type_definition;
46 CCodeFragment header_type_member_declaration;
47 CCodeFragment source_begin;
48 CCodeFragment source_include_directives;
49 CCodeFragment source_type_member_declaration;
50 CCodeFragment source_signal_marshaller_declaration;
51 CCodeFragment source_type_member_definition;
52 CCodeFragment instance_init_fragment;
53 CCodeFragment instance_dispose_fragment;
54 CCodeFragment source_signal_marshaller_definition;
55 CCodeFragment module_init_fragment;
57 CCodeStruct instance_struct;
58 CCodeStruct type_struct;
59 CCodeStruct instance_priv_struct;
60 CCodeEnum prop_enum;
61 CCodeEnum cenum;
62 CCodeFunction function;
63 CCodeBlock block;
65 /* all temporary variables */
66 List<VariableDeclarator> temp_vars;
67 /* temporary variables that own their content */
68 List<VariableDeclarator> temp_ref_vars;
69 /* cache to check whether a certain marshaller has been created yet */
70 HashTable<string,bool> user_marshal_list;
71 /* (constant) hash table with all predefined marshallers */
72 HashTable<string,bool> predefined_marshal_list;
73 /* (constant) hash table with all C keywords */
74 HashTable<string,bool> c_keywords;
76 private int next_temp_var_id = 0;
77 private bool in_creation_method = false;
79 TypeReference bool_type;
80 TypeReference char_type;
81 TypeReference unichar_type;
82 TypeReference short_type;
83 TypeReference ushort_type;
84 TypeReference int_type;
85 TypeReference uint_type;
86 TypeReference long_type;
87 TypeReference ulong_type;
88 TypeReference int64_type;
89 TypeReference uint64_type;
90 TypeReference string_type;
91 TypeReference float_type;
92 TypeReference double_type;
93 DataType list_type;
94 DataType slist_type;
95 TypeReference mutex_type;
96 DataType type_module_type;
98 private bool in_plugin = false;
99 private string module_init_param_name;
101 private bool string_h_needed;
103 public CodeGenerator (bool manage_memory = true) {
104 memory_management = manage_memory;
107 construct {
108 predefined_marshal_list = new HashTable (str_hash, str_equal);
109 predefined_marshal_list.insert ("VOID:VOID", true);
110 predefined_marshal_list.insert ("VOID:BOOLEAN", true);
111 predefined_marshal_list.insert ("VOID:CHAR", true);
112 predefined_marshal_list.insert ("VOID:UCHAR", true);
113 predefined_marshal_list.insert ("VOID:INT", true);
114 predefined_marshal_list.insert ("VOID:UINT", true);
115 predefined_marshal_list.insert ("VOID:LONG", true);
116 predefined_marshal_list.insert ("VOID:ULONG", true);
117 predefined_marshal_list.insert ("VOID:ENUM", true);
118 predefined_marshal_list.insert ("VOID:FLAGS", true);
119 predefined_marshal_list.insert ("VOID:FLOAT", true);
120 predefined_marshal_list.insert ("VOID:DOUBLE", true);
121 predefined_marshal_list.insert ("VOID:STRING", true);
122 predefined_marshal_list.insert ("VOID:POINTER", true);
123 predefined_marshal_list.insert ("VOID:OBJECT", true);
124 predefined_marshal_list.insert ("STRING:OBJECT,POINTER", true);
125 predefined_marshal_list.insert ("VOID:UINT,POINTER", true);
126 predefined_marshal_list.insert ("BOOLEAN:FLAGS", true);
128 c_keywords = new HashTable (str_hash, str_equal);
130 // C99 keywords
131 c_keywords.insert ("_Bool", true);
132 c_keywords.insert ("_Complex", true);
133 c_keywords.insert ("_Imaginary", true);
134 c_keywords.insert ("auto", true);
135 c_keywords.insert ("break", true);
136 c_keywords.insert ("case", true);
137 c_keywords.insert ("char", true);
138 c_keywords.insert ("const", true);
139 c_keywords.insert ("continue", true);
140 c_keywords.insert ("default", true);
141 c_keywords.insert ("do", true);
142 c_keywords.insert ("double", true);
143 c_keywords.insert ("else", true);
144 c_keywords.insert ("enum", true);
145 c_keywords.insert ("extern", true);
146 c_keywords.insert ("float", true);
147 c_keywords.insert ("for", true);
148 c_keywords.insert ("goto", true);
149 c_keywords.insert ("if", true);
150 c_keywords.insert ("inline", true);
151 c_keywords.insert ("int", true);
152 c_keywords.insert ("long", true);
153 c_keywords.insert ("register", true);
154 c_keywords.insert ("restrict", true);
155 c_keywords.insert ("return", true);
156 c_keywords.insert ("short", true);
157 c_keywords.insert ("signed", true);
158 c_keywords.insert ("sizeof", true);
159 c_keywords.insert ("static", true);
160 c_keywords.insert ("struct", true);
161 c_keywords.insert ("switch", true);
162 c_keywords.insert ("typedef", true);
163 c_keywords.insert ("union", true);
164 c_keywords.insert ("unsigned", true);
165 c_keywords.insert ("void", true);
166 c_keywords.insert ("volatile", true);
167 c_keywords.insert ("while", true);
169 // MSVC keywords
170 c_keywords.insert ("cdecl", true);
174 * Generate and emit C code for the specified code context.
176 * @param context a code context
178 public void emit (CodeContext! context) {
179 this.context = context;
181 context.find_header_cycles ();
183 root_symbol = context.get_root ();
185 bool_type = new TypeReference ();
186 bool_type.data_type = (DataType) root_symbol.lookup ("bool").node;
188 char_type = new TypeReference ();
189 char_type.data_type = (DataType) root_symbol.lookup ("char").node;
191 unichar_type = new TypeReference ();
192 unichar_type.data_type = (DataType) root_symbol.lookup ("unichar").node;
194 short_type = new TypeReference ();
195 short_type.data_type = (DataType) root_symbol.lookup ("short").node;
197 ushort_type = new TypeReference ();
198 ushort_type.data_type = (DataType) root_symbol.lookup ("ushort").node;
200 int_type = new TypeReference ();
201 int_type.data_type = (DataType) root_symbol.lookup ("int").node;
203 uint_type = new TypeReference ();
204 uint_type.data_type = (DataType) root_symbol.lookup ("uint").node;
206 long_type = new TypeReference ();
207 long_type.data_type = (DataType) root_symbol.lookup ("long").node;
209 ulong_type = new TypeReference ();
210 ulong_type.data_type = (DataType) root_symbol.lookup ("ulong").node;
212 int64_type = new TypeReference ();
213 int64_type.data_type = (DataType) root_symbol.lookup ("int64").node;
215 uint64_type = new TypeReference ();
216 uint64_type.data_type = (DataType) root_symbol.lookup ("uint64").node;
218 float_type = new TypeReference ();
219 float_type.data_type = (DataType) root_symbol.lookup ("float").node;
221 double_type = new TypeReference ();
222 double_type.data_type = (DataType) root_symbol.lookup ("double").node;
224 string_type = new TypeReference ();
225 string_type.data_type = (DataType) root_symbol.lookup ("string").node;
227 var glib_ns = root_symbol.lookup ("GLib");
229 list_type = (DataType) glib_ns.lookup ("List").node;
230 slist_type = (DataType) glib_ns.lookup ("SList").node;
232 mutex_type = new TypeReference ();
233 mutex_type.data_type = (DataType) glib_ns.lookup ("Mutex").node;
235 type_module_type = (DataType) glib_ns.lookup ("TypeModule").node;
237 if (context.module_init_method != null) {
238 module_init_fragment = new CCodeFragment ();
239 foreach (FormalParameter parameter in context.module_init_method.get_parameters ()) {
240 if (parameter.type_reference.data_type == type_module_type) {
241 in_plugin = true;
242 module_init_param_name = parameter.name;
243 break;
248 /* we're only interested in non-pkg source files */
249 var source_files = context.get_source_files ();
250 foreach (SourceFile file in source_files) {
251 if (!file.pkg) {
252 file.accept (this);
257 public override void visit_namespace (Namespace! ns) {
258 ns.accept_children (this);
261 public override void visit_enum (Enum! en) {
262 cenum = new CCodeEnum (en.get_cname ());
264 if (en.source_reference.comment != null) {
265 header_type_definition.append (new CCodeComment (en.source_reference.comment));
267 header_type_definition.append (cenum);
269 en.accept_children (this);
272 public override void visit_enum_value (EnumValue! ev) {
273 string val;
274 if (ev.value is LiteralExpression) {
275 var lit = ((LiteralExpression) ev.value).literal;
276 if (lit is IntegerLiteral) {
277 val = ((IntegerLiteral) lit).value;
280 cenum.add_value (ev.get_cname (), val);
283 public override void visit_flags (Flags! fl) {
284 cenum = new CCodeEnum (fl.get_cname ());
286 if (fl.source_reference.comment != null) {
287 header_type_definition.append (new CCodeComment (fl.source_reference.comment));
289 header_type_definition.append (cenum);
291 fl.accept_children (this);
294 public override void visit_flags_value (FlagsValue! fv) {
295 string val;
296 if (fv.value is LiteralExpression) {
297 var lit = ((LiteralExpression) fv.value).literal;
298 if (lit is IntegerLiteral) {
299 val = ((IntegerLiteral) lit).value;
302 cenum.add_value (fv.get_cname (), val);
305 public override void visit_callback (Callback! cb) {
306 cb.accept_children (this);
308 var cfundecl = new CCodeFunctionDeclarator (cb.get_cname ());
309 foreach (FormalParameter param in cb.get_parameters ()) {
310 cfundecl.add_parameter ((CCodeFormalParameter) param.ccodenode);
313 var ctypedef = new CCodeTypeDefinition (cb.return_type.get_cname (), cfundecl);
315 if (cb.access != MemberAccessibility.PRIVATE) {
316 header_type_declaration.append (ctypedef);
317 } else {
318 source_type_member_declaration.append (ctypedef);
322 public override void visit_member (Member! m) {
323 /* stuff meant for all lockable members */
324 if (m is Lockable && ((Lockable)m).get_lock_used ()) {
325 instance_priv_struct.add_field (mutex_type.get_cname (), get_symbol_lock_name (m.symbol));
327 instance_init_fragment.append (
328 new CCodeExpressionStatement (
329 new CCodeAssignment (
330 new CCodeMemberAccess.pointer (
331 new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"),
332 get_symbol_lock_name (m.symbol)),
333 new CCodeFunctionCall (new CCodeIdentifier (((Struct)mutex_type.data_type).default_construction_method.get_cname ())))));
335 var fc = new CCodeFunctionCall (new CCodeIdentifier ("VALA_FREE_CHECKED"));
336 fc.add_argument (
337 new CCodeMemberAccess.pointer (
338 new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"),
339 get_symbol_lock_name (m.symbol)));
340 fc.add_argument (new CCodeIdentifier (mutex_type.data_type.get_free_function ()));
341 if (instance_dispose_fragment != null) {
342 instance_dispose_fragment.append (new CCodeExpressionStatement (fc));
347 public override void visit_constant (Constant! c) {
348 c.accept_children (this);
350 if (c.symbol.parent_symbol.node is DataType) {
351 var t = (DataType) c.symbol.parent_symbol.node;
352 var cdecl = new CCodeDeclaration (c.type_reference.get_const_cname ());
353 var arr = "";
354 if (c.type_reference.data_type is Array) {
355 arr = "[]";
357 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s%s".printf (c.get_cname (), arr), (CCodeExpression) c.initializer.ccodenode));
358 cdecl.modifiers = CCodeModifiers.STATIC;
360 if (c.access != MemberAccessibility.PRIVATE) {
361 header_type_member_declaration.append (cdecl);
362 } else {
363 source_type_member_declaration.append (cdecl);
368 public override void visit_field (Field! f) {
369 f.accept_children (this);
371 CCodeExpression lhs = null;
372 CCodeStruct st = null;
374 if (f.access != MemberAccessibility.PRIVATE) {
375 st = instance_struct;
376 if (f.instance) {
377 lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
379 } else if (f.access == MemberAccessibility.PRIVATE) {
380 if (f.instance) {
381 st = instance_priv_struct;
382 lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ());
383 } else {
384 if (f.symbol.parent_symbol.node is DataType) {
385 var t = (DataType) f.symbol.parent_symbol.node;
386 var cdecl = new CCodeDeclaration (f.type_reference.get_cname ());
387 var var_decl = new CCodeVariableDeclarator (f.get_cname ());
388 if (f.initializer != null) {
389 var_decl.initializer = (CCodeExpression) f.initializer.ccodenode;
391 cdecl.add_declarator (var_decl);
392 cdecl.modifiers = CCodeModifiers.STATIC;
393 source_type_member_declaration.append (cdecl);
398 if (f.instance) {
399 st.add_field (f.type_reference.get_cname (), f.get_cname ());
400 if (f.type_reference.data_type is Array && !f.no_array_length) {
401 // create fields to store array dimensions
402 var arr = (Array) f.type_reference.data_type;
404 for (int dim = 1; dim <= arr.rank; dim++) {
405 var len_type = new TypeReference ();
406 len_type.data_type = int_type.data_type;
408 st.add_field (len_type.get_cname (), get_array_length_cname (f.name, dim));
412 if (f.initializer != null) {
413 instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, (CCodeExpression) f.initializer.ccodenode)));
415 if (f.type_reference.data_type is Array && !f.no_array_length &&
416 f.initializer is ArrayCreationExpression) {
417 var ma = new MemberAccess.simple (f.name);
418 ma.symbol_reference = f.symbol;
420 var array_len_lhs = get_array_length_cexpression (ma, 1);
421 var sizes = ((ArrayCreationExpression) f.initializer).get_sizes ();
422 var size = (Expression) sizes.data;
423 instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (array_len_lhs, (CCodeExpression) size.ccodenode)));
427 if (f.type_reference.takes_ownership && instance_dispose_fragment != null) {
428 instance_dispose_fragment.append (new CCodeExpressionStatement (get_unref_expression (lhs, f.type_reference)));
433 public override void visit_formal_parameter (FormalParameter! p) {
434 p.accept_children (this);
436 if (!p.ellipsis) {
437 p.ccodenode = new CCodeFormalParameter (p.name, p.type_reference.get_cname (false, !p.type_reference.takes_ownership));
441 public override void visit_property (Property! prop) {
442 prop.accept_children (this);
444 prop_enum.add_value (prop.get_upper_case_cname (), null);
447 public override void visit_property_accessor (PropertyAccessor! acc) {
448 var prop = (Property) acc.symbol.parent_symbol.node;
450 if (acc.readable) {
451 current_return_type = prop.type_reference;
452 } else {
453 // void
454 current_return_type = new TypeReference ();
457 acc.accept_children (this);
459 current_return_type = null;
461 var t = (DataType) prop.symbol.parent_symbol.node;
463 var this_type = new TypeReference ();
464 this_type.data_type = t;
465 var cselfparam = new CCodeFormalParameter ("self", this_type.get_cname ());
466 var cvalueparam = new CCodeFormalParameter ("value", prop.type_reference.get_cname (false, true));
468 if (prop.is_abstract || prop.is_virtual) {
469 if (acc.readable) {
470 function = new CCodeFunction ("%s_get_%s".printf (t.get_lower_case_cname (null), prop.name), prop.type_reference.get_cname ());
471 } else {
472 function = new CCodeFunction ("%s_set_%s".printf (t.get_lower_case_cname (null), prop.name), "void");
474 function.add_parameter (cselfparam);
475 if (acc.writable || acc.construction) {
476 function.add_parameter (cvalueparam);
479 header_type_member_declaration.append (function.copy ());
481 var block = new CCodeBlock ();
482 function.block = block;
484 if (acc.readable) {
485 // declare temporary variable to save the property value
486 var decl = new CCodeDeclaration (prop.type_reference.get_cname ());
487 decl.add_declarator (new CCodeVariableDeclarator ("value"));
488 block.add_statement (decl);
490 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
492 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
493 ccast.add_argument (new CCodeIdentifier ("self"));
494 ccall.add_argument (ccast);
496 // property name is second argument of g_object_get
497 ccall.add_argument (prop.get_canonical_cconstant ());
499 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
501 ccall.add_argument (new CCodeConstant ("NULL"));
503 block.add_statement (new CCodeExpressionStatement (ccall));
504 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value")));
505 } else {
506 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
508 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
509 ccast.add_argument (new CCodeIdentifier ("self"));
510 ccall.add_argument (ccast);
512 // property name is second argument of g_object_set
513 ccall.add_argument (prop.get_canonical_cconstant ());
515 ccall.add_argument (new CCodeIdentifier ("value"));
517 ccall.add_argument (new CCodeConstant ("NULL"));
519 block.add_statement (new CCodeExpressionStatement (ccall));
522 source_type_member_definition.append (function);
525 if (!prop.is_abstract) {
526 bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
528 string prefix = t.get_lower_case_cname (null);
529 if (is_virtual) {
530 prefix += "_real";
532 if (acc.readable) {
533 function = new CCodeFunction ("%s_get_%s".printf (prefix, prop.name), prop.type_reference.get_cname ());
534 } else {
535 function = new CCodeFunction ("%s_set_%s".printf (prefix, prop.name), "void");
537 if (is_virtual) {
538 function.modifiers |= CCodeModifiers.STATIC;
540 function.add_parameter (cselfparam);
541 if (acc.writable || acc.construction) {
542 function.add_parameter (cvalueparam);
545 if (!is_virtual) {
546 header_type_member_declaration.append (function.copy ());
549 if (acc.body != null) {
550 function.block = (CCodeBlock) acc.body.ccodenode;
552 function.block.prepend_statement (create_property_type_check_statement (prop, acc.readable, t, true, "self"));
555 source_type_member_definition.append (function);
559 public override void visit_constructor (Constructor! c) {
560 c.accept_children (this);
562 var cl = (Class) c.symbol.parent_symbol.node;
564 function = new CCodeFunction ("%s_constructor".printf (cl.get_lower_case_cname (null)), "GObject *");
565 function.modifiers = CCodeModifiers.STATIC;
567 function.add_parameter (new CCodeFormalParameter ("type", "GType"));
568 function.add_parameter (new CCodeFormalParameter ("n_construct_properties", "guint"));
569 function.add_parameter (new CCodeFormalParameter ("construct_properties", "GObjectConstructParam *"));
571 source_type_member_declaration.append (function.copy ());
574 var cblock = new CCodeBlock ();
575 var cdecl = new CCodeDeclaration ("GObject *");
576 cdecl.add_declarator (new CCodeVariableDeclarator ("obj"));
577 cblock.add_statement (cdecl);
579 cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ()));
580 cdecl.add_declarator (new CCodeVariableDeclarator ("klass"));
581 cblock.add_statement (cdecl);
583 cdecl = new CCodeDeclaration ("GObjectClass *");
584 cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class"));
585 cblock.add_statement (cdecl);
588 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek"));
589 ccall.add_argument (new CCodeIdentifier (cl.get_upper_case_cname ("TYPE_")));
590 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null))));
591 ccast.add_argument (ccall);
592 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("klass"), ccast)));
594 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
595 ccall.add_argument (new CCodeIdentifier ("klass"));
596 ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
597 ccast.add_argument (ccall);
598 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast)));
601 ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
602 ccall.add_argument (new CCodeIdentifier ("type"));
603 ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
604 ccall.add_argument (new CCodeIdentifier ("construct_properties"));
605 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("obj"), ccall)));
608 ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
609 ccall.add_argument (new CCodeIdentifier ("obj"));
611 cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
612 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
614 cblock.add_statement (cdecl);
617 cblock.add_statement (c.body.ccodenode);
619 cblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("obj")));
621 function.block = cblock;
623 if (c.source_reference.comment != null) {
624 source_type_member_definition.append (new CCodeComment (c.source_reference.comment));
626 source_type_member_definition.append (function);
629 public override void visit_destructor (Destructor! d) {
630 d.accept_children (this);
633 public override void visit_begin_block (Block! b) {
634 current_symbol = b.symbol;
637 private void add_object_creation (CCodeBlock! b) {
638 var cl = (Class) current_type_symbol.node;
640 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
641 ccall.add_argument (new CCodeConstant (cl.get_type_id ()));
642 ccall.add_argument (new CCodeConstant ("__params_it - __params"));
643 ccall.add_argument (new CCodeConstant ("__params"));
645 var cdecl = new CCodeVariableDeclarator ("self");
646 cdecl.initializer = ccall;
648 var cdeclaration = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
649 cdeclaration.add_declarator (cdecl);
651 b.add_statement (cdeclaration);
654 public override void visit_end_block (Block! b) {
655 var local_vars = b.get_local_variables ();
656 foreach (VariableDeclarator decl in local_vars) {
657 decl.symbol.active = false;
660 var cblock = new CCodeBlock ();
662 foreach (Statement stmt in b.get_statements ()) {
663 var src = stmt.source_reference;
664 if (src != null && src.comment != null) {
665 cblock.add_statement (new CCodeComment (src.comment));
668 if (stmt.ccodenode is CCodeFragment) {
669 foreach (CCodeStatement cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
670 cblock.add_statement (cstmt);
672 } else {
673 cblock.add_statement ((CCodeStatement) stmt.ccodenode);
677 if (memory_management) {
678 foreach (VariableDeclarator decl in local_vars) {
679 if (decl.type_reference.takes_ownership) {
680 cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (decl.name)), decl.type_reference)));
685 b.ccodenode = cblock;
687 current_symbol = current_symbol.parent_symbol;
690 public override void visit_empty_statement (EmptyStatement! stmt) {
691 stmt.ccodenode = new CCodeEmptyStatement ();
694 private bool struct_has_instance_fields (Struct! st) {
695 foreach (Field f in st.get_fields ()) {
696 if (f.instance) {
697 return true;
701 return false;
704 public override void visit_declaration_statement (DeclarationStatement! stmt) {
705 /* split declaration statement as var declarators
706 * might have different types */
708 var cfrag = new CCodeFragment ();
710 foreach (VariableDeclarator decl in stmt.declaration.get_variable_declarators ()) {
711 var cdecl = new CCodeDeclaration (decl.type_reference.get_cname (false, !decl.type_reference.takes_ownership));
713 cdecl.add_declarator ((CCodeVariableDeclarator) decl.ccodenode);
715 cfrag.append (cdecl);
717 /* try to initialize uninitialized variables */
718 if (decl.initializer == null && decl.type_reference.data_type is Struct) {
719 if (decl.type_reference.data_type.is_reference_type ()) {
720 ((CCodeVariableDeclarator) decl.ccodenode).initializer = new CCodeConstant ("NULL");
721 } else if (decl.type_reference.data_type.get_default_value () != null) {
722 ((CCodeVariableDeclarator) decl.ccodenode).initializer = new CCodeConstant (decl.type_reference.data_type.get_default_value ());
723 } else if (decl.type_reference.data_type is Struct &&
724 struct_has_instance_fields ((Struct) decl.type_reference.data_type)) {
725 var st = (Struct) decl.type_reference.data_type;
727 /* memset needs string.h */
728 string_h_needed = true;
730 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
731 czero.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (get_variable_cname (decl.name))));
732 czero.add_argument (new CCodeConstant ("0"));
733 czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (decl.type_reference.get_cname ())));
735 cfrag.append (new CCodeExpressionStatement (czero));
736 } else {
737 Report.warning (decl.source_reference, "unable to initialize a variable of type `%s'".printf (decl.type_reference.data_type.symbol.get_full_name ()));
742 stmt.ccodenode = cfrag;
744 foreach (VariableDeclarator decl in stmt.declaration.get_variable_declarators ()) {
745 if (decl.initializer != null) {
746 create_temp_decl (stmt, decl.initializer.temp_vars);
750 create_temp_decl (stmt, temp_vars);
751 temp_vars = null;
754 private string! get_variable_cname (string! name) {
755 if (c_keywords.lookup (name)) {
756 return name + "_";
757 } else {
758 return name;
762 public override void visit_variable_declarator (VariableDeclarator! decl) {
763 if (decl.type_reference.data_type is Array) {
764 // create variables to store array dimensions
765 var arr = (Array) decl.type_reference.data_type;
767 for (int dim = 1; dim <= arr.rank; dim++) {
768 var len_decl = new VariableDeclarator (get_array_length_cname (decl.name, dim));
769 len_decl.type_reference = new TypeReference ();
770 len_decl.type_reference.data_type = int_type.data_type;
772 temp_vars.prepend (len_decl);
776 CCodeExpression rhs = null;
777 if (decl.initializer != null) {
778 rhs = (CCodeExpression) decl.initializer.ccodenode;
780 if (decl.type_reference.data_type != null
781 && decl.initializer.static_type.data_type != null
782 && decl.type_reference.data_type.is_reference_type ()
783 && decl.initializer.static_type.data_type != decl.type_reference.data_type) {
784 // FIXME: use C cast if debugging disabled
785 rhs = new InstanceCast (rhs, decl.type_reference.data_type);
788 if (decl.type_reference.data_type is Array) {
789 var ccomma = new CCodeCommaExpression ();
791 var temp_decl = get_temp_variable_declarator (decl.type_reference);
792 temp_vars.prepend (temp_decl);
793 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), rhs));
795 var lhs_array_len = new CCodeIdentifier (get_array_length_cname (decl.name, 1));
796 var rhs_array_len = get_array_length_cexpression (decl.initializer, 1);
797 ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
799 ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
801 rhs = ccomma;
803 } else if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) {
804 rhs = new CCodeConstant ("NULL");
807 decl.ccodenode = new CCodeVariableDeclarator.with_initializer (get_variable_cname (decl.name), rhs);
809 decl.symbol.active = true;
812 public override void visit_end_initializer_list (InitializerList! list) {
813 if (list.expected_type != null && list.expected_type.data_type is Array) {
814 /* TODO */
815 } else {
816 var clist = new CCodeInitializerList ();
817 foreach (Expression expr in list.get_initializers ()) {
818 clist.append ((CCodeExpression) expr.ccodenode);
820 list.ccodenode = clist;
824 private VariableDeclarator get_temp_variable_declarator (TypeReference! type, bool takes_ownership = true) {
825 var decl = new VariableDeclarator ("__temp%d".printf (next_temp_var_id));
826 decl.type_reference = type.copy ();
827 decl.type_reference.is_ref = false;
828 decl.type_reference.is_out = false;
829 decl.type_reference.takes_ownership = takes_ownership;
831 next_temp_var_id++;
833 return decl;
836 private CCodeExpression get_destroy_func_expression (TypeReference! type) {
837 if (type.data_type != null) {
838 string unref_function;
839 if (type.data_type.is_reference_counting ()) {
840 unref_function = type.data_type.get_unref_function ();
841 } else {
842 unref_function = type.data_type.get_free_function ();
844 return new CCodeIdentifier (unref_function);
845 } else if (type.type_parameter != null && current_class != null) {
846 string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ());
847 return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
848 } else {
849 return new CCodeConstant ("NULL");
853 private CCodeExpression get_unref_expression (CCodeExpression! cvar, TypeReference! type) {
854 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
856 /* can be simplified to
857 * foo = (unref (foo), NULL)
858 * if foo is of static type non-null
861 if (type.is_null) {
862 return new CCodeConstant ("NULL");
865 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
866 if (type.data_type == null) {
867 if (current_class == null) {
868 return new CCodeConstant ("NULL");
871 // unref functions are optional for type parameters
872 var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
873 cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
876 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
877 ccall.add_argument (cvar);
879 /* set freed references to NULL to prevent further use */
880 var ccomma = new CCodeCommaExpression ();
882 // TODO cleanup
883 if (type.data_type != null && !type.data_type.is_reference_counting ()) {
884 string unref_function = type.data_type.get_free_function ();
885 if (unref_function == "g_list_free") {
886 bool is_ref = false;
887 bool is_class = false;
888 bool is_interface = false;
890 foreach (TypeReference type_arg in type.get_type_arguments ()) {
891 is_ref |= type_arg.takes_ownership;
892 is_class |= type_arg.data_type is Class;
893 is_interface |= type_arg.data_type is Interface;
896 if (is_ref) {
897 var cunrefcall = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
898 cunrefcall.add_argument (cvar);
899 if (is_class || is_interface) {
900 cunrefcall.add_argument (new CCodeIdentifier ("(GFunc) g_object_unref"));
901 } else {
902 cunrefcall.add_argument (new CCodeIdentifier ("(GFunc) g_free"));
904 cunrefcall.add_argument (new CCodeConstant ("NULL"));
905 ccomma.append_expression (cunrefcall);
907 } else if (unref_function == "g_string_free") {
908 ccall.add_argument (new CCodeConstant ("TRUE"));
912 ccomma.append_expression (ccall);
913 ccomma.append_expression (new CCodeConstant ("NULL"));
915 var cassign = new CCodeAssignment (cvar, ccomma);
917 // g_free (NULL) is allowed
918 if (type.non_null || (type.data_type != null && !type.data_type.is_reference_counting () && type.data_type.get_free_function () == "g_free")) {
919 return new CCodeParenthesizedExpression (cassign);
922 return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), new CCodeParenthesizedExpression (cassign));
925 public override void visit_end_full_expression (Expression! expr) {
926 if (!memory_management) {
927 temp_vars = null;
928 temp_ref_vars = null;
929 return;
932 /* expr is a full expression, i.e. an initializer, the
933 * expression in an expression statement, the controlling
934 * expression in if, while, for, or foreach statements
936 * we unref temporary variables at the end of a full
937 * expression
940 /* can't automatically deep copy lists yet, so do it
941 * manually for now
942 * replace with
943 * expr.temp_vars = temp_vars;
944 * when deep list copying works
946 expr.temp_vars = null;
947 foreach (VariableDeclarator decl1 in temp_vars) {
948 expr.temp_vars.append (decl1);
950 temp_vars = null;
952 if (temp_ref_vars == null) {
953 /* nothing to do without temporary variables */
954 return;
957 var full_expr_decl = get_temp_variable_declarator (expr.static_type);
958 expr.temp_vars.append (full_expr_decl);
960 var expr_list = new CCodeCommaExpression ();
961 expr_list.append_expression (new CCodeAssignment (new CCodeIdentifier (full_expr_decl.name), (CCodeExpression) expr.ccodenode));
963 foreach (VariableDeclarator decl in temp_ref_vars) {
964 expr_list.append_expression (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference));
967 expr_list.append_expression (new CCodeIdentifier (full_expr_decl.name));
969 expr.ccodenode = expr_list;
971 temp_ref_vars = null;
974 private void append_temp_decl (CCodeFragment! cfrag, List<VariableDeclarator> temp_vars) {
975 foreach (VariableDeclarator decl in temp_vars) {
976 var cdecl = new CCodeDeclaration (decl.type_reference.get_cname (true, !decl.type_reference.takes_ownership));
978 var vardecl = new CCodeVariableDeclarator (decl.name);
979 cdecl.add_declarator (vardecl);
981 if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) {
982 vardecl.initializer = new CCodeConstant ("NULL");
985 cfrag.append (cdecl);
989 public override void visit_expression_statement (ExpressionStatement! stmt) {
990 stmt.ccodenode = new CCodeExpressionStatement ((CCodeExpression) stmt.expression.ccodenode);
992 /* free temporary objects */
993 if (!memory_management) {
994 temp_vars = null;
995 temp_ref_vars = null;
996 return;
999 if (temp_vars == null) {
1000 /* nothing to do without temporary variables */
1001 return;
1004 var cfrag = new CCodeFragment ();
1005 append_temp_decl (cfrag, temp_vars);
1007 cfrag.append (stmt.ccodenode);
1009 foreach (VariableDeclarator decl in temp_ref_vars) {
1010 cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference)));
1013 stmt.ccodenode = cfrag;
1015 temp_vars = null;
1016 temp_ref_vars = null;
1019 private void create_temp_decl (Statement! stmt, List<VariableDeclarator> temp_vars) {
1020 /* declare temporary variables */
1022 if (temp_vars == null) {
1023 /* nothing to do without temporary variables */
1024 return;
1027 var cfrag = new CCodeFragment ();
1028 append_temp_decl (cfrag, temp_vars);
1030 cfrag.append (stmt.ccodenode);
1032 stmt.ccodenode = cfrag;
1035 public override void visit_if_statement (IfStatement! stmt) {
1036 if (stmt.false_statement != null) {
1037 stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode);
1038 } else {
1039 stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode);
1042 create_temp_decl (stmt, stmt.condition.temp_vars);
1045 public override void visit_switch_statement (SwitchStatement! stmt) {
1046 // we need a temporary variable to save the property value
1047 var temp_decl = get_temp_variable_declarator (stmt.expression.static_type);
1048 stmt.expression.temp_vars.prepend (temp_decl);
1050 var ctemp = new CCodeIdentifier (temp_decl.name);
1052 var cinit = new CCodeAssignment (ctemp, (CCodeExpression) stmt.expression.ccodenode);
1054 var cswitchblock = new CCodeFragment ();
1055 cswitchblock.append (new CCodeExpressionStatement (cinit));
1056 stmt.ccodenode = cswitchblock;
1058 create_temp_decl (stmt, stmt.expression.temp_vars);
1060 List<weak Statement> default_statements = null;
1062 // generate nested if statements
1063 CCodeStatement ctopstmt = null;
1064 CCodeIfStatement coldif = null;
1065 foreach (SwitchSection section in stmt.get_sections ()) {
1066 if (section.has_default_label ()) {
1067 default_statements = section.get_statements ();
1068 } else {
1069 CCodeBinaryExpression cor = null;
1070 foreach (SwitchLabel label in section.get_labels ()) {
1071 var ccmp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, (CCodeExpression) label.expression.ccodenode);
1072 if (cor == null) {
1073 cor = ccmp;
1074 } else {
1075 cor = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cor, ccmp);
1079 var cblock = new CCodeBlock ();
1080 foreach (Statement body_stmt in section.get_statements ()) {
1081 if (body_stmt.ccodenode is CCodeFragment) {
1082 foreach (CCodeStatement cstmt in ((CCodeFragment) body_stmt.ccodenode).get_children ()) {
1083 cblock.add_statement (cstmt);
1085 } else {
1086 cblock.add_statement ((CCodeStatement) body_stmt.ccodenode);
1090 var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
1092 var cif = new CCodeIfStatement (cor, cdo);
1093 if (coldif != null) {
1094 coldif.false_statement = cif;
1095 } else {
1096 ctopstmt = cif;
1098 coldif = cif;
1102 if (default_statements != null) {
1103 var cblock = new CCodeBlock ();
1104 foreach (Statement body_stmt in default_statements) {
1105 cblock.add_statement ((CCodeStatement) body_stmt.ccodenode);
1108 var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
1110 if (coldif == null) {
1111 // there is only one section and that section
1112 // contains a default label
1113 ctopstmt = cdo;
1114 } else {
1115 coldif.false_statement = cdo;
1119 cswitchblock.append (ctopstmt);
1122 public override void visit_while_statement (WhileStatement! stmt) {
1123 stmt.ccodenode = new CCodeWhileStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
1125 create_temp_decl (stmt, stmt.condition.temp_vars);
1128 public override void visit_do_statement (DoStatement! stmt) {
1129 stmt.ccodenode = new CCodeDoStatement ((CCodeStatement) stmt.body.ccodenode, (CCodeExpression) stmt.condition.ccodenode);
1131 create_temp_decl (stmt, stmt.condition.temp_vars);
1134 public override void visit_for_statement (ForStatement! stmt) {
1135 var cfor = new CCodeForStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
1136 stmt.ccodenode = cfor;
1138 foreach (Expression init_expr in stmt.get_initializer ()) {
1139 cfor.add_initializer ((CCodeExpression) init_expr.ccodenode);
1140 create_temp_decl (stmt, init_expr.temp_vars);
1143 foreach (Expression it_expr in stmt.get_iterator ()) {
1144 cfor.add_iterator ((CCodeExpression) it_expr.ccodenode);
1145 create_temp_decl (stmt, it_expr.temp_vars);
1148 create_temp_decl (stmt, stmt.condition.temp_vars);
1151 public override void visit_end_foreach_statement (ForeachStatement! stmt) {
1152 var cblock = new CCodeBlock ();
1153 CCodeForStatement cfor;
1154 VariableDeclarator collection_backup = get_temp_variable_declarator (stmt.collection.static_type);
1156 stmt.collection.temp_vars.prepend (collection_backup);
1157 var cfrag = new CCodeFragment ();
1158 append_temp_decl (cfrag, stmt.collection.temp_vars);
1159 cblock.add_statement (cfrag);
1160 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode)));
1162 stmt.ccodenode = cblock;
1164 if (stmt.collection.static_type.data_type is Array) {
1165 var arr = (Array) stmt.collection.static_type.data_type;
1167 var array_len = get_array_length_cexpression (stmt.collection, 1);
1169 /* the array has no length parameter i.e. is NULL-terminated array */
1170 if (array_len is CCodeConstant) {
1171 var it_name = "%s_it".printf (stmt.variable_name);
1173 var citdecl = new CCodeDeclaration (stmt.collection.static_type.get_cname ());
1174 citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
1175 cblock.add_statement (citdecl);
1177 var cbody = new CCodeBlock ();
1179 var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
1180 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeIdentifier ("*%s".printf (it_name))));
1181 cbody.add_statement (cdecl);
1183 cbody.add_statement (stmt.body.ccodenode);
1185 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("*%s".printf (it_name)), new CCodeConstant ("NULL"));
1187 var cfor = new CCodeForStatement (ccond, cbody);
1189 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name)));
1191 cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
1192 cblock.add_statement (cfor);
1193 /* the array has a length parameter */
1194 } else {
1195 var it_name = (stmt.variable_name + "_it");
1197 var citdecl = new CCodeDeclaration ("int");
1198 citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
1199 cblock.add_statement (citdecl);
1201 var cbody = new CCodeBlock ();
1203 var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
1204 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name))));
1205 cbody.add_statement (cdecl);
1207 cbody.add_statement (stmt.body.ccodenode);
1209 var ccond_ind1 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, array_len, new CCodeConstant ("-1"));
1210 var ccond_ind2 = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (it_name), array_len);
1211 var ccond_ind = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_ind1, ccond_ind2);
1213 /* only check for null if the containers elements are of reference-type */
1214 CCodeBinaryExpression ccond;
1215 if (arr.element_type.is_reference_type ()) {
1216 var ccond_term1 = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, array_len, new CCodeConstant ("-1"));
1217 var ccond_term2 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name)), new CCodeConstant ("NULL"));
1218 var ccond_term = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_term1, ccond_term2);
1220 ccond = new CCodeBinaryExpression (CCodeBinaryOperator.OR, new CCodeParenthesizedExpression (ccond_ind), new CCodeParenthesizedExpression (ccond_term));
1221 } else {
1222 /* assert when trying to iterate over value-type arrays of unknown length */
1223 var cassert = new CCodeFunctionCall (new CCodeIdentifier ("g_assert"));
1224 cassert.add_argument (ccond_ind1);
1225 cblock.add_statement (new CCodeExpressionStatement (cassert));
1227 ccond = ccond_ind2;
1230 var cfor = new CCodeForStatement (ccond, cbody);
1231 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeConstant ("0")));
1232 cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
1233 cblock.add_statement (cfor);
1235 } else if (stmt.collection.static_type.data_type == list_type ||
1236 stmt.collection.static_type.data_type == slist_type) {
1237 var it_name = "%s_it".printf (stmt.variable_name);
1239 var citdecl = new CCodeDeclaration (stmt.collection.static_type.get_cname ());
1240 citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
1241 cblock.add_statement (citdecl);
1243 var cbody = new CCodeBlock ();
1245 CCodeExpression element_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "data");
1247 /* cast pointer to actual type if appropriate */
1248 if (stmt.type_reference.data_type is Struct) {
1249 var st = (Struct) stmt.type_reference.data_type;
1250 if (st == uint_type.data_type) {
1251 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
1252 cconv.add_argument (element_expr);
1253 element_expr = cconv;
1254 } else if (st == bool_type.data_type || st.is_integer_type ()) {
1255 var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
1256 cconv.add_argument (element_expr);
1257 element_expr = cconv;
1261 var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
1262 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
1263 cbody.add_statement (cdecl);
1265 cbody.add_statement (stmt.body.ccodenode);
1267 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (it_name), new CCodeConstant ("NULL"));
1269 var cfor = new CCodeForStatement (ccond, cbody);
1271 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name)));
1273 cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "next")));
1274 cblock.add_statement (cfor);
1277 if (memory_management && stmt.collection.static_type.transfers_ownership) {
1278 cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (collection_backup.name), stmt.collection.static_type)));
1282 public override void visit_break_statement (BreakStatement! stmt) {
1283 stmt.ccodenode = new CCodeBreakStatement ();
1286 public override void visit_continue_statement (ContinueStatement! stmt) {
1287 stmt.ccodenode = new CCodeContinueStatement ();
1290 private void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop) {
1291 var b = (Block) sym.node;
1293 var local_vars = b.get_local_variables ();
1294 foreach (VariableDeclarator decl in local_vars) {
1295 if (decl.symbol.active && decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) {
1296 cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (decl.name)), decl.type_reference)));
1300 if (sym.parent_symbol.node is Block) {
1301 append_local_free (sym.parent_symbol, cfrag, stop_at_loop);
1305 private void create_local_free (Statement stmt) {
1306 if (!memory_management) {
1307 return;
1310 var cfrag = new CCodeFragment ();
1312 append_local_free (current_symbol, cfrag, false);
1314 cfrag.append (stmt.ccodenode);
1315 stmt.ccodenode = cfrag;
1318 private bool append_local_free_expr (Symbol sym, CCodeCommaExpression ccomma, bool stop_at_loop) {
1319 var found = false;
1321 var b = (Block) sym.node;
1323 var local_vars = b.get_local_variables ();
1324 foreach (VariableDeclarator decl in local_vars) {
1325 if (decl.symbol.active && decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) {
1326 found = true;
1327 ccomma.append_expression (get_unref_expression (new CCodeIdentifier (get_variable_cname (decl.name)), decl.type_reference));
1331 if (sym.parent_symbol.node is Block) {
1332 found = found || append_local_free_expr (sym.parent_symbol, ccomma, stop_at_loop);
1335 return found;
1338 private void create_local_free_expr (Expression expr) {
1339 if (!memory_management) {
1340 return;
1343 var return_expr_decl = get_temp_variable_declarator (expr.static_type);
1345 var ccomma = new CCodeCommaExpression ();
1346 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (return_expr_decl.name), (CCodeExpression) expr.ccodenode));
1348 if (!append_local_free_expr (current_symbol, ccomma, false)) {
1349 /* no local variables need to be freed */
1350 return;
1353 ccomma.append_expression (new CCodeIdentifier (return_expr_decl.name));
1355 expr.ccodenode = ccomma;
1356 expr.temp_vars.append (return_expr_decl);
1359 public override void visit_begin_return_statement (ReturnStatement! stmt) {
1360 if (stmt.return_expression != null) {
1361 // avoid unnecessary ref/unref pair
1362 if (stmt.return_expression.ref_missing &&
1363 stmt.return_expression.symbol_reference != null &&
1364 stmt.return_expression.symbol_reference.node is VariableDeclarator) {
1365 var decl = (VariableDeclarator) stmt.return_expression.symbol_reference.node;
1366 if (decl.type_reference.takes_ownership) {
1367 /* return expression is local variable taking ownership and
1368 * current method is transferring ownership */
1370 stmt.return_expression.ref_sink = true;
1372 // don't ref expression
1373 stmt.return_expression.ref_missing = false;
1379 public override void visit_end_return_statement (ReturnStatement! stmt) {
1380 if (stmt.return_expression == null) {
1381 stmt.ccodenode = new CCodeReturnStatement ();
1383 create_local_free (stmt);
1384 } else {
1385 Symbol return_expression_symbol = null;
1387 // avoid unnecessary ref/unref pair
1388 if (stmt.return_expression.ref_sink &&
1389 stmt.return_expression.symbol_reference != null &&
1390 stmt.return_expression.symbol_reference.node is VariableDeclarator) {
1391 var decl = (VariableDeclarator) stmt.return_expression.symbol_reference.node;
1392 if (decl.type_reference.takes_ownership) {
1393 /* return expression is local variable taking ownership and
1394 * current method is transferring ownership */
1396 // don't unref expression
1397 return_expression_symbol = decl.symbol;
1398 return_expression_symbol.active = false;
1402 create_local_free_expr (stmt.return_expression);
1404 if (stmt.return_expression.static_type != null &&
1405 stmt.return_expression.static_type.data_type != current_return_type.data_type) {
1406 /* cast required */
1407 if (current_return_type.data_type is Class || current_return_type.data_type is Interface) {
1408 stmt.return_expression.ccodenode = new InstanceCast ((CCodeExpression) stmt.return_expression.ccodenode, current_return_type.data_type);
1412 stmt.ccodenode = new CCodeReturnStatement ((CCodeExpression) stmt.return_expression.ccodenode);
1414 create_temp_decl (stmt, stmt.return_expression.temp_vars);
1416 if (return_expression_symbol != null) {
1417 return_expression_symbol.active = true;
1422 private string get_symbol_lock_name (Symbol! sym) {
1423 return "__lock_%s".printf (sym.name);
1427 * Visit operation called for lock statements.
1429 * @param stmt a lock statement
1431 public override void visit_lock_statement (LockStatement! stmt) {
1432 var cn = new CCodeFragment ();
1433 CCodeExpression l = null;
1434 CCodeFunctionCall fc;
1435 var inner_node = ((MemberAccess)stmt.resource).inner;
1437 if (inner_node == null) {
1438 l = new CCodeIdentifier ("self");
1439 } else if (stmt.resource.symbol_reference.parent_symbol.node != current_class) {
1440 l = new CCodeFunctionCall (new CCodeIdentifier (((DataType) stmt.resource.symbol_reference.parent_symbol.node).get_upper_case_cname ()));
1441 ((CCodeFunctionCall) l).add_argument ((CCodeExpression)inner_node.ccodenode);
1442 } else {
1443 l = (CCodeExpression)inner_node.ccodenode;
1445 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (stmt.resource.symbol_reference));
1447 fc = new CCodeFunctionCall (new CCodeIdentifier (((Method)mutex_type.data_type.symbol.lookup ("lock").node).get_cname ()));
1448 fc.add_argument (l);
1449 cn.append (new CCodeExpressionStatement (fc));
1451 cn.append (stmt.body.ccodenode);
1453 fc = new CCodeFunctionCall (new CCodeIdentifier (((Method)mutex_type.data_type.symbol.lookup ("unlock").node).get_cname ()));
1454 fc.add_argument (l);
1455 cn.append (new CCodeExpressionStatement (fc));
1457 stmt.ccodenode = cn;
1461 * Visit operations called for array creation expresions.
1463 * @param expr an array creation expression
1465 public override void visit_end_array_creation_expression (ArrayCreationExpression! expr) {
1466 /* FIXME: rank > 1 not supported yet */
1467 if (expr.rank > 1) {
1468 expr.error = true;
1469 Report.error (expr.source_reference, "Creating arrays with rank greater than 1 is not supported yet");
1472 var sizes = expr.get_sizes ();
1473 var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
1474 gnew.add_argument (new CCodeIdentifier (expr.element_type.get_cname ()));
1475 /* FIXME: had to add Expression cast due to possible compiler bug */
1476 gnew.add_argument ((CCodeExpression) ((Expression) sizes.first ().data).ccodenode);
1478 if (expr.initializer_list != null) {
1479 var ce = new CCodeCommaExpression ();
1480 var temp_var = get_temp_variable_declarator (expr.static_type);
1481 var name_cnode = new CCodeIdentifier (temp_var.name);
1482 int i = 0;
1484 temp_vars.prepend (temp_var);
1486 /* FIXME: had to add Expression cast due to possible compiler bug */
1487 ce.append_expression (new CCodeAssignment (name_cnode, gnew));
1489 foreach (Expression e in expr.initializer_list.get_initializers ()) {
1490 ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode));
1491 i++;
1494 ce.append_expression (name_cnode);
1496 expr.ccodenode = ce;
1497 } else {
1498 expr.ccodenode = gnew;
1502 public override void visit_boolean_literal (BooleanLiteral! expr) {
1503 expr.ccodenode = new CCodeConstant (expr.value ? "TRUE" : "FALSE");
1506 public override void visit_character_literal (CharacterLiteral! expr) {
1507 if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
1508 expr.ccodenode = new CCodeConstant (expr.value);
1509 } else {
1510 expr.ccodenode = new CCodeConstant ("%uU".printf (expr.get_char ()));
1514 public override void visit_integer_literal (IntegerLiteral! expr) {
1515 expr.ccodenode = new CCodeConstant (expr.value);
1518 public override void visit_real_literal (RealLiteral! expr) {
1519 expr.ccodenode = new CCodeConstant (expr.value);
1522 public override void visit_string_literal (StringLiteral! expr) {
1523 expr.ccodenode = new CCodeConstant (expr.value);
1526 public override void visit_null_literal (NullLiteral! expr) {
1527 expr.ccodenode = new CCodeConstant ("NULL");
1530 public override void visit_literal_expression (LiteralExpression! expr) {
1531 expr.ccodenode = expr.literal.ccodenode;
1533 visit_expression (expr);
1536 public override void visit_parenthesized_expression (ParenthesizedExpression! expr) {
1537 expr.ccodenode = new CCodeParenthesizedExpression ((CCodeExpression) expr.inner.ccodenode);
1539 visit_expression (expr);
1542 private CCodeExpression! get_array_length_cexpression (Expression! array_expr, int dim) {
1543 bool is_out = false;
1545 if (array_expr is UnaryExpression) {
1546 var unary_expr = (UnaryExpression) array_expr;
1547 if (unary_expr.operator == UnaryOperator.OUT) {
1548 array_expr = unary_expr.inner;
1549 is_out = true;
1553 if (array_expr is ArrayCreationExpression) {
1554 List<weak Expression> size = ((ArrayCreationExpression) array_expr).get_sizes ();
1555 var length_expr = size.nth_data (dim - 1);
1556 return (CCodeExpression) length_expr.ccodenode;
1557 } else if (array_expr is InvocationExpression) {
1558 var invocation_expr = (InvocationExpression) array_expr;
1559 List<weak CCodeExpression> size = invocation_expr.get_array_sizes ();
1560 return size.nth_data (dim - 1);
1561 } else if (array_expr.symbol_reference != null) {
1562 if (array_expr.symbol_reference.node is FormalParameter) {
1563 var param = (FormalParameter) array_expr.symbol_reference.node;
1564 if (!param.no_array_length) {
1565 var length_expr = new CCodeIdentifier (get_array_length_cname (param.name, dim));
1566 if (is_out) {
1567 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
1568 } else {
1569 return length_expr;
1572 } else if (array_expr.symbol_reference.node is VariableDeclarator) {
1573 var decl = (VariableDeclarator) array_expr.symbol_reference.node;
1574 var length_expr = new CCodeIdentifier (get_array_length_cname (decl.name, dim));
1575 if (is_out) {
1576 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
1577 } else {
1578 return length_expr;
1580 } else if (array_expr.symbol_reference.node is Field) {
1581 var field = (Field) array_expr.symbol_reference.node;
1582 if (!field.no_array_length) {
1583 var length_cname = get_array_length_cname (field.name, dim);
1585 var ma = (MemberAccess) array_expr;
1587 CCodeExpression pub_inst = null;
1588 DataType base_type = null;
1589 CCodeExpression length_expr = null;
1591 if (ma.inner == null) {
1592 pub_inst = new CCodeIdentifier ("self");
1594 if (current_type_symbol != null) {
1595 /* base type is available if this is a type method */
1596 base_type = (DataType) current_type_symbol.node;
1598 } else {
1599 pub_inst = (CCodeExpression) ma.inner.ccodenode;
1601 if (ma.inner.static_type != null) {
1602 base_type = ma.inner.static_type.data_type;
1606 if (field.instance) {
1607 CCodeExpression typed_inst;
1608 if (field.symbol.parent_symbol.node != base_type) {
1609 // FIXME: use C cast if debugging disabled
1610 typed_inst = new CCodeFunctionCall (new CCodeIdentifier (((DataType) field.symbol.parent_symbol.node).get_upper_case_cname (null)));
1611 ((CCodeFunctionCall) typed_inst).add_argument (pub_inst);
1612 } else {
1613 typed_inst = pub_inst;
1615 CCodeExpression inst;
1616 if (field.access == MemberAccessibility.PRIVATE) {
1617 inst = new CCodeMemberAccess.pointer (typed_inst, "priv");
1618 } else {
1619 inst = typed_inst;
1621 if (((DataType) field.symbol.parent_symbol.node).is_reference_type ()) {
1622 length_expr = new CCodeMemberAccess.pointer (inst, length_cname);
1623 } else {
1624 length_expr = new CCodeMemberAccess (inst, length_cname);
1626 } else {
1627 length_expr = new CCodeIdentifier (length_cname);
1630 if (is_out) {
1631 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
1632 } else {
1633 return length_expr;
1639 if (!is_out) {
1640 /* allow arrays with unknown length even for value types
1641 * as else it may be impossible to bind some libraries
1642 * users of affected libraries should explicitly set
1643 * the array length as early as possible
1644 * by setting the virtual length field of the array
1646 return new CCodeConstant ("-1");
1647 } else {
1648 return new CCodeConstant ("NULL");
1652 public override void visit_element_access (ElementAccess! expr)
1654 List<weak Expression> indices = expr.get_indices ();
1655 int rank = indices.length ();
1657 if (rank == 1) {
1658 /* FIXME: had to add Expression cast due to possible compiler bug */
1659 expr.ccodenode = new CCodeElementAccess ((CCodeExpression)expr.container.ccodenode, (CCodeExpression)((Expression)indices.first ().data).ccodenode);
1660 } else {
1661 expr.error = true;
1662 Report.error (expr.source_reference, "Arrays with more then one dimension are not supported yet");
1663 return;
1666 visit_expression (expr);
1669 public override void visit_base_access (BaseAccess! expr) {
1670 expr.ccodenode = new InstanceCast (new CCodeIdentifier ("self"), expr.static_type.data_type);
1673 public override void visit_postfix_expression (PostfixExpression! expr) {
1674 MemberAccess ma = find_property_access (expr.inner);
1675 if (ma != null) {
1676 // property postfix expression
1677 var prop = (Property) ma.symbol_reference.node;
1679 var ccomma = new CCodeCommaExpression ();
1681 // assign current value to temp variable
1682 var temp_decl = get_temp_variable_declarator (prop.type_reference);
1683 temp_vars.prepend (temp_decl);
1684 ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), (CCodeExpression) expr.inner.ccodenode));
1686 // increment/decrement property
1687 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
1688 var cexpr = new CCodeBinaryExpression (op, new CCodeIdentifier (temp_decl.name), new CCodeConstant ("1"));
1689 var ccall = get_property_set_call (prop, ma, cexpr);
1690 ccomma.append_expression (ccall);
1692 // return previous value
1693 ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
1695 expr.ccodenode = ccomma;
1696 return;
1699 var op = expr.increment ? CCodeUnaryOperator.POSTFIX_INCREMENT : CCodeUnaryOperator.POSTFIX_DECREMENT;
1701 expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
1703 visit_expression (expr);
1706 private MemberAccess find_property_access (Expression! expr) {
1707 if (expr is ParenthesizedExpression) {
1708 var pe = (ParenthesizedExpression) expr;
1709 return find_property_access (pe.inner);
1712 if (!(expr is MemberAccess)) {
1713 return null;
1716 var ma = (MemberAccess) expr;
1717 if (ma.symbol_reference.node is Property) {
1718 return ma;
1721 return null;
1724 private CCodeExpression get_ref_expression (Expression! expr) {
1725 /* (temp = expr, temp == NULL ? NULL : ref (temp))
1727 * can be simplified to
1728 * ref (expr)
1729 * if static type of expr is non-null
1732 if (expr.static_type.data_type == null &&
1733 expr.static_type.type_parameter != null) {
1734 Report.warning (expr.source_reference, "Missing generics support for memory management");
1735 return (CCodeExpression) expr.ccodenode;
1738 string ref_function;
1739 if (expr.static_type.data_type.is_reference_counting ()) {
1740 ref_function = expr.static_type.data_type.get_ref_function ();
1741 } else {
1742 if (expr.static_type.data_type != string_type.data_type) {
1743 // duplicating non-reference counted structs may cause side-effects (and performance issues)
1744 Report.warning (expr.source_reference, "duplicating %s instance, use weak variable or explicitly invoke copy method".printf (expr.static_type.data_type.name));
1746 ref_function = expr.static_type.data_type.get_dup_function ();
1749 var ccall = new CCodeFunctionCall (new CCodeIdentifier (ref_function));
1751 if (expr.static_type.non_null) {
1752 ccall.add_argument ((CCodeExpression) expr.ccodenode);
1754 return ccall;
1755 } else {
1756 var decl = get_temp_variable_declarator (expr.static_type, false);
1757 temp_vars.prepend (decl);
1759 var ctemp = new CCodeIdentifier (decl.name);
1761 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL"));
1763 ccall.add_argument (ctemp);
1765 var ccomma = new CCodeCommaExpression ();
1766 ccomma.append_expression (new CCodeAssignment (ctemp, (CCodeExpression) expr.ccodenode));
1768 if (ref_function == "g_list_copy") {
1769 bool is_ref = false;
1770 bool is_class = false;
1771 bool is_interface = false;
1773 foreach (TypeReference type_arg in expr.static_type.get_type_arguments ()) {
1774 is_ref |= type_arg.takes_ownership;
1775 is_class |= type_arg.data_type is Class;
1776 is_interface |= type_arg.data_type is Interface;
1779 if (is_ref && (is_class || is_interface)) {
1780 var crefcall = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
1782 crefcall.add_argument (ctemp);
1783 crefcall.add_argument (new CCodeIdentifier ("(GFunc) g_object_ref"));
1784 crefcall.add_argument (new CCodeConstant ("NULL"));
1786 ccomma.append_expression (crefcall);
1790 ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), ccall));
1792 return ccomma;
1796 private void visit_expression (Expression! expr) {
1797 if (expr.static_type != null &&
1798 expr.static_type.transfers_ownership &&
1799 expr.static_type.floating_reference) {
1800 /* constructor of GInitiallyUnowned subtype
1801 * returns floating reference, sink it
1803 var csink = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref_sink"));
1804 csink.add_argument ((CCodeExpression) expr.ccodenode);
1806 expr.ccodenode = csink;
1809 if (expr.ref_leaked) {
1810 var decl = get_temp_variable_declarator (expr.static_type);
1811 temp_vars.prepend (decl);
1812 temp_ref_vars.prepend (decl);
1813 expr.ccodenode = new CCodeParenthesizedExpression (new CCodeAssignment (new CCodeIdentifier (get_variable_cname (decl.name)), (CCodeExpression) expr.ccodenode));
1814 } else if (expr.ref_missing) {
1815 expr.ccodenode = get_ref_expression (expr);
1819 public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) {
1820 if (expr.symbol_reference == null) {
1821 // no creation method
1822 if (expr.type_reference.data_type is Class) {
1823 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_new"));
1825 ccall.add_argument (new CCodeConstant (expr.type_reference.data_type.get_type_id ()));
1827 ccall.add_argument (new CCodeConstant ("NULL"));
1829 expr.ccodenode = ccall;
1830 } else if (expr.type_reference.data_type == list_type ||
1831 expr.type_reference.data_type == slist_type) {
1832 // NULL is an empty list
1833 expr.ccodenode = new CCodeConstant ("NULL");
1834 } else {
1835 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
1837 ccall.add_argument (new CCodeConstant (expr.type_reference.data_type.get_cname ()));
1839 ccall.add_argument (new CCodeConstant ("1"));
1841 expr.ccodenode = ccall;
1843 } else {
1844 // use creation method
1845 var m = (Method) expr.symbol_reference.node;
1846 var params = m.get_parameters ();
1848 var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
1850 if (expr.type_reference.data_type is Class) {
1851 foreach (TypeReference type_arg in expr.type_reference.get_type_arguments ()) {
1852 if (type_arg.takes_ownership) {
1853 ccall.add_argument (get_destroy_func_expression (type_arg));
1854 } else {
1855 ccall.add_argument (new CCodeConstant ("NULL"));
1860 bool ellipsis = false;
1862 int i = 1;
1863 weak List<weak FormalParameter> params_it = params;
1864 foreach (Expression arg in expr.get_argument_list ()) {
1865 /* explicitly use strong reference as ccall gets
1866 * unrefed at end of inner block
1868 CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
1869 if (params_it != null) {
1870 var param = (FormalParameter) params_it.data;
1871 ellipsis = param.ellipsis;
1872 if (!param.ellipsis
1873 && param.type_reference.data_type != null
1874 && param.type_reference.data_type.is_reference_type ()
1875 && arg.static_type.data_type != null
1876 && param.type_reference.data_type != arg.static_type.data_type) {
1877 // FIXME: use C cast if debugging disabled
1878 var ccall = new CCodeFunctionCall (new CCodeIdentifier (param.type_reference.data_type.get_upper_case_cname (null)));
1879 ccall.add_argument (cexpr);
1880 cexpr = ccall;
1884 ccall.add_argument (cexpr);
1885 i++;
1887 if (params_it != null) {
1888 params_it = params_it.next;
1891 while (params_it != null) {
1892 var param = (FormalParameter) params_it.data;
1894 if (param.ellipsis) {
1895 ellipsis = true;
1896 break;
1899 if (param.default_expression == null) {
1900 Report.error (expr.source_reference, "no default expression for argument %d".printf (i));
1901 return;
1904 /* evaluate default expression here as the code
1905 * generator might not have visited the formal
1906 * parameter yet */
1907 param.default_expression.accept (this);
1909 ccall.add_argument ((CCodeExpression) param.default_expression.ccodenode);
1910 i++;
1912 params_it = params_it.next;
1915 if (ellipsis) {
1916 // ensure variable argument list ends with NULL
1917 ccall.add_argument (new CCodeConstant ("NULL"));
1920 expr.ccodenode = ccall;
1923 visit_expression (expr);
1926 public override void visit_sizeof_expression (SizeofExpression! expr) {
1927 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
1928 csizeof.add_argument (new CCodeIdentifier (expr.type_reference.data_type.get_cname ()));
1929 expr.ccodenode = csizeof;
1932 public override void visit_typeof_expression (TypeofExpression! expr) {
1933 expr.ccodenode = new CCodeIdentifier (expr.type_reference.data_type.get_type_id ());
1936 public override void visit_unary_expression (UnaryExpression! expr) {
1937 CCodeUnaryOperator op;
1938 if (expr.operator == UnaryOperator.PLUS) {
1939 op = CCodeUnaryOperator.PLUS;
1940 } else if (expr.operator == UnaryOperator.MINUS) {
1941 op = CCodeUnaryOperator.MINUS;
1942 } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
1943 op = CCodeUnaryOperator.LOGICAL_NEGATION;
1944 } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
1945 op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
1946 } else if (expr.operator == UnaryOperator.INCREMENT) {
1947 op = CCodeUnaryOperator.PREFIX_INCREMENT;
1948 } else if (expr.operator == UnaryOperator.DECREMENT) {
1949 op = CCodeUnaryOperator.PREFIX_DECREMENT;
1950 } else if (expr.operator == UnaryOperator.REF) {
1951 op = CCodeUnaryOperator.ADDRESS_OF;
1952 } else if (expr.operator == UnaryOperator.OUT) {
1953 op = CCodeUnaryOperator.ADDRESS_OF;
1955 expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
1957 visit_expression (expr);
1960 public override void visit_cast_expression (CastExpression! expr) {
1961 if (expr.type_reference.data_type is Class || expr.type_reference.data_type is Interface) {
1962 // GObject cast
1963 expr.ccodenode = new InstanceCast ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.data_type);
1964 } else {
1965 expr.ccodenode = new CCodeCastExpression ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.get_cname ());
1968 visit_expression (expr);
1971 public override void visit_pointer_indirection (PointerIndirection! expr) {
1972 expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, (CCodeExpression) expr.inner.ccodenode);
1975 public override void visit_addressof_expression (AddressofExpression! expr) {
1976 expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, (CCodeExpression) expr.inner.ccodenode);
1979 public override void visit_reference_transfer_expression (ReferenceTransferExpression! expr) {
1980 /* (tmp = var, var = null, tmp) */
1981 var ccomma = new CCodeCommaExpression ();
1982 var temp_decl = get_temp_variable_declarator (expr.static_type);
1983 temp_vars.prepend (temp_decl);
1984 var cvar = new CCodeIdentifier (temp_decl.name);
1986 ccomma.append_expression (new CCodeAssignment (cvar, (CCodeExpression) expr.inner.ccodenode));
1987 ccomma.append_expression (new CCodeAssignment ((CCodeExpression) expr.inner.ccodenode, new CCodeConstant ("NULL")));
1988 ccomma.append_expression (cvar);
1989 expr.ccodenode = ccomma;
1991 visit_expression (expr);
1994 public override void visit_binary_expression (BinaryExpression! expr) {
1995 CCodeBinaryOperator op;
1996 if (expr.operator == BinaryOperator.PLUS) {
1997 op = CCodeBinaryOperator.PLUS;
1998 } else if (expr.operator == BinaryOperator.MINUS) {
1999 op = CCodeBinaryOperator.MINUS;
2000 } else if (expr.operator == BinaryOperator.MUL) {
2001 op = CCodeBinaryOperator.MUL;
2002 } else if (expr.operator == BinaryOperator.DIV) {
2003 op = CCodeBinaryOperator.DIV;
2004 } else if (expr.operator == BinaryOperator.MOD) {
2005 op = CCodeBinaryOperator.MOD;
2006 } else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
2007 op = CCodeBinaryOperator.SHIFT_LEFT;
2008 } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
2009 op = CCodeBinaryOperator.SHIFT_RIGHT;
2010 } else if (expr.operator == BinaryOperator.LESS_THAN) {
2011 op = CCodeBinaryOperator.LESS_THAN;
2012 } else if (expr.operator == BinaryOperator.GREATER_THAN) {
2013 op = CCodeBinaryOperator.GREATER_THAN;
2014 } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
2015 op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
2016 } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
2017 op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
2018 } else if (expr.operator == BinaryOperator.EQUALITY) {
2019 op = CCodeBinaryOperator.EQUALITY;
2020 } else if (expr.operator == BinaryOperator.INEQUALITY) {
2021 op = CCodeBinaryOperator.INEQUALITY;
2022 } else if (expr.operator == BinaryOperator.BITWISE_AND) {
2023 op = CCodeBinaryOperator.BITWISE_AND;
2024 } else if (expr.operator == BinaryOperator.BITWISE_OR) {
2025 op = CCodeBinaryOperator.BITWISE_OR;
2026 } else if (expr.operator == BinaryOperator.BITWISE_XOR) {
2027 op = CCodeBinaryOperator.BITWISE_XOR;
2028 } else if (expr.operator == BinaryOperator.AND) {
2029 op = CCodeBinaryOperator.AND;
2030 } else if (expr.operator == BinaryOperator.OR) {
2031 op = CCodeBinaryOperator.OR;
2034 var cleft = (CCodeExpression) expr.left.ccodenode;
2035 var cright = (CCodeExpression) expr.right.ccodenode;
2037 if (expr.operator == BinaryOperator.EQUALITY ||
2038 expr.operator == BinaryOperator.INEQUALITY) {
2039 if (expr.left.static_type != null && expr.right.static_type != null &&
2040 expr.left.static_type.data_type is Class && expr.right.static_type.data_type is Class) {
2041 var left_cl = (Class) expr.left.static_type.data_type;
2042 var right_cl = (Class) expr.right.static_type.data_type;
2044 if (left_cl != right_cl) {
2045 if (left_cl.is_subtype_of (right_cl)) {
2046 cleft = new InstanceCast (cleft, right_cl);
2047 } else if (right_cl.is_subtype_of (left_cl)) {
2048 cright = new InstanceCast (cright, left_cl);
2054 expr.ccodenode = new CCodeBinaryExpression (op, cleft, cright);
2056 visit_expression (expr);
2059 public override void visit_type_check (TypeCheck! expr) {
2060 var ccheck = new CCodeFunctionCall (new CCodeIdentifier (expr.type_reference.data_type.get_upper_case_cname ("IS_")));
2061 ccheck.add_argument ((CCodeExpression) expr.expression.ccodenode);
2062 expr.ccodenode = ccheck;
2065 public override void visit_conditional_expression (ConditionalExpression! expr) {
2066 expr.ccodenode = new CCodeConditionalExpression ((CCodeExpression) expr.condition.ccodenode, (CCodeExpression) expr.true_expression.ccodenode, (CCodeExpression) expr.false_expression.ccodenode);
2069 public override void visit_end_lambda_expression (LambdaExpression! l) {
2070 l.ccodenode = new CCodeIdentifier (l.method.get_cname ());