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