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