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
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <rasa@gmx.ch>
27 * Code visitor generating C Code.
29 public class Vala
.CodeGenerator
: CodeVisitor
{
31 * Specifies whether automatic memory management is active.
33 public bool memory_management
{ get; set; }
35 private CodeContext context
;
38 Symbol current_symbol
;
39 Symbol current_type_symbol
;
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
;
62 CCodeFunction function
;
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
;
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
;
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
);
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);
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
) {
242 module_init_param_name
= parameter
.name
;
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
) {
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
) {
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
) {
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
);
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"));
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 ());
354 if (c
.type_reference
.data_type is Array
) {
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
);
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
;
377 lhs
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.get_cname ());
379 } else if (f
.access
== MemberAccessibility
.PRIVATE
) {
381 st
= instance_priv_struct
;
382 lhs
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), f
.get_cname ());
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
);
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
);
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
;
451 current_return_type
= prop
.type_reference
;
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
) {
470 function
= new
CCodeFunction ("%s_get_%s".printf (t
.get_lower_case_cname (null), prop
.name
), prop
.type_reference
.get_cname ());
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
;
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")));
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);
533 function
= new
CCodeFunction ("%s_get_%s".printf (prefix
, prop
.name
), prop
.type_reference
.get_cname ());
535 function
= new
CCodeFunction ("%s_set_%s".printf (prefix
, prop
.name
), "void");
538 function
.modifiers
|= CCodeModifiers
.STATIC
;
540 function
.add_parameter (cselfparam
);
541 if (acc
.writable
|| acc
.construction
) {
542 function
.add_parameter (cvalueparam
);
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
);
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 ()) {
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
));
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
);
754 private string! get_variable_cname (string! name
) {
755 if (c_keywords
.lookup (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
));
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
) {
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
;
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 ();
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
);
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
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 ();
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") {
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
;
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"));
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
) {
928 temp_ref_vars
= null;
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
940 /* can't automatically deep copy lists yet, so do it
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
);
952 if (temp_ref_vars
== null) {
953 /* nothing to do without temporary variables */
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
) {
995 temp_ref_vars
= null;
999 if (temp_vars
== null) {
1000 /* nothing to do without temporary variables */
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
;
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 */
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
);
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 ();
1069 CCodeBinaryExpression cor
= null;
1070 foreach (SwitchLabel label
in section
.get_labels ()) {
1071 var ccmp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, (CCodeExpression
) label
.expression
.ccodenode
);
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
);
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
;
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
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 */
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
));
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
));
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
) {
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
) {
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
) {
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
);
1338 private void create_local_free_expr (Expression expr
) {
1339 if (!memory_management
) {
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 */
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
);
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
) {
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
);
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) {
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
);
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
));
1494 ce
.append_expression (name_cnode
);
1496 expr
.ccodenode
= ce
;
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
);
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
;
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
));
1567 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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
));
1576 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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
;
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
);
1613 typed_inst
= pub_inst
;
1615 CCodeExpression inst
;
1616 if (field
.access
== MemberAccessibility
.PRIVATE
) {
1617 inst
= new CCodeMemberAccess
.pointer (typed_inst
, "priv");
1621 if (((DataType
) field
.symbol
.parent_symbol
.node
).is_reference_type ()) {
1622 length_expr
= new CCodeMemberAccess
.pointer (inst
, length_cname
);
1624 length_expr
= new
CCodeMemberAccess (inst
, length_cname
);
1627 length_expr
= new
CCodeIdentifier (length_cname
);
1631 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, length_expr
);
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");
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 ();
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
);
1662 Report
.error (expr
.source_reference
, "Arrays with more then one dimension are not supported yet");
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
);
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
;
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
)) {
1716 var ma
= (MemberAccess
) expr
;
1717 if (ma
.symbol_reference
.node is Property
) {
1724 private CCodeExpression
get_ref_expression (Expression
! expr
) {
1725 /* (temp = expr, temp == NULL ? NULL : ref (temp))
1727 * can be simplified to
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 ();
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
);
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
));
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");
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
;
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
));
1855 ccall
.add_argument (new
CCodeConstant ("NULL"));
1860 bool ellipsis
= false;
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
;
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
);
1884 ccall
.add_argument (cexpr
);
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
) {
1899 if (param
.default_expression
== null) {
1900 Report
.error (expr
.source_reference
, "no default expression for argument %d".printf (i
));
1904 /* evaluate default expression here as the code
1905 * generator might not have visited the formal
1907 param
.default_expression
.accept (this
);
1909 ccall
.add_argument ((CCodeExpression
) param
.default_expression
.ccodenode
);
1912 params_it
= params_it
.next
;
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
) {
1963 expr
.ccodenode
= new
InstanceCast ((CCodeExpression
) expr
.inner
.ccodenode
, expr
.type_reference
.data_type
);
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 ());