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 public abstract class Vala
.CCodeBaseModule
: CodeGenerator
{
30 public class EmitContext
{
31 public Symbol? current_symbol
;
32 public ArrayList
<Symbol
> symbol_stack
= new ArrayList
<Symbol
> ();
33 public TryStatement current_try
;
34 public CCodeFunction ccode
;
35 public ArrayList
<CCodeFunction
> ccode_stack
= new ArrayList
<CCodeFunction
> ();
36 public ArrayList
<LocalVariable
> temp_ref_vars
= new ArrayList
<LocalVariable
> ();
37 public int next_temp_var_id
;
38 public bool current_method_inner_error
;
39 public bool current_method_return
;
40 public Map
<string,string> variable_name_map
= new HashMap
<string,string> (str_hash
, str_equal
);
42 public EmitContext (Symbol? symbol
= null) {
43 current_symbol
= symbol
;
46 public void push_symbol (Symbol symbol
) {
47 symbol_stack
.add (current_symbol
);
48 current_symbol
= symbol
;
51 public void pop_symbol () {
52 current_symbol
= symbol_stack
[symbol_stack
.size
- 1];
53 symbol_stack
.remove_at (symbol_stack
.size
- 1);
57 public CodeContext context
{ get; set; }
59 public Symbol root_symbol
;
61 public EmitContext emit_context
= new
EmitContext ();
63 List
<EmitContext
> emit_context_stack
= new ArrayList
<EmitContext
> ();
65 public Symbol current_symbol
{ get { return emit_context
.current_symbol
; } }
67 public TryStatement current_try
{
68 get { return emit_context
.current_try
; }
69 set { emit_context
.current_try
= value
; }
72 public TypeSymbol? current_type_symbol
{
74 var sym
= current_symbol
;
76 if (sym is TypeSymbol
) {
77 return (TypeSymbol
) sym
;
79 sym
= sym
.parent_symbol
;
85 public Class? current_class
{
86 get { return current_type_symbol as Class
; }
89 public Method? current_method
{
91 var sym
= current_symbol
;
92 while (sym is Block
) {
93 sym
= sym
.parent_symbol
;
99 public PropertyAccessor? current_property_accessor
{
101 var sym
= current_symbol
;
102 while (sym is Block
) {
103 sym
= sym
.parent_symbol
;
105 return sym as PropertyAccessor
;
109 public DataType? current_return_type
{
111 var m
= current_method
;
113 return m
.return_type
;
116 var acc
= current_property_accessor
;
119 return acc
.value_type
;
125 if (is_in_constructor () || is_in_destructor ()) {
133 public bool is_in_constructor () {
134 var sym
= current_symbol
;
135 while (sym
!= null) {
136 if (sym is Constructor
) {
139 sym
= sym
.parent_symbol
;
144 public bool is_in_destructor () {
145 var sym
= current_symbol
;
146 while (sym
!= null) {
147 if (sym is Destructor
) {
150 sym
= sym
.parent_symbol
;
155 public Block? current_closure_block
{
157 return next_closure_block (current_symbol
);
161 public unowned Block?
next_closure_block (Symbol sym
) {
162 unowned Block block
= null;
164 block
= sym as Block
;
165 if (!(sym is Block
|| sym is Method
)) {
169 if (block
!= null && block
.captured
) {
170 // closure block found
173 sym
= sym
.parent_symbol
;
178 public CCodeFile header_file
;
179 public CCodeFile internal_header_file
;
180 public CCodeFile cfile
;
182 public EmitContext class_init_context
;
183 public EmitContext base_init_context
;
184 public EmitContext class_finalize_context
;
185 public EmitContext base_finalize_context
;
186 public EmitContext instance_init_context
;
187 public EmitContext instance_finalize_context
;
189 public CCodeStruct param_spec_struct
;
190 public CCodeStruct closure_struct
;
191 public CCodeEnum prop_enum
;
193 public CCodeFunction ccode
{ get { return emit_context
.ccode
; } }
195 /* temporary variables that own their content */
196 public ArrayList
<LocalVariable
> temp_ref_vars
{ get { return emit_context
.temp_ref_vars
; } }
197 /* cache to check whether a certain marshaller has been created yet */
198 public Set
<string> user_marshal_set
;
199 /* (constant) hash table with all predefined marshallers */
200 public Set
<string> predefined_marshal_set
;
201 /* (constant) hash table with all reserved identifiers in the generated code */
202 Set
<string> reserved_identifiers
;
204 public int next_temp_var_id
{
205 get { return emit_context
.next_temp_var_id
; }
206 set { emit_context
.next_temp_var_id
= value
; }
209 public int next_regex_id
= 0;
210 public bool in_creation_method
{ get { return current_method is CreationMethod
; } }
211 public bool in_constructor
= false;
212 public bool in_static_or_class_context
= false;
214 public bool current_method_inner_error
{
215 get { return emit_context
.current_method_inner_error
; }
216 set { emit_context
.current_method_inner_error
= value
; }
219 public bool current_method_return
{
220 get { return emit_context
.current_method_return
; }
221 set { emit_context
.current_method_return
= value
; }
224 public int next_coroutine_state
= 1;
225 int next_block_id
= 0;
226 Map
<Block
,int> block_map
= new HashMap
<Block
,int> ();
228 public DataType void_type
= new
VoidType ();
229 public DataType bool_type
;
230 public DataType char_type
;
231 public DataType uchar_type
;
232 public DataType? unichar_type
;
233 public DataType short_type
;
234 public DataType ushort_type
;
235 public DataType int_type
;
236 public DataType uint_type
;
237 public DataType long_type
;
238 public DataType ulong_type
;
239 public DataType int8_type
;
240 public DataType uint8_type
;
241 public DataType int16_type
;
242 public DataType uint16_type
;
243 public DataType int32_type
;
244 public DataType uint32_type
;
245 public DataType int64_type
;
246 public DataType uint64_type
;
247 public DataType string_type
;
248 public DataType regex_type
;
249 public DataType float_type
;
250 public DataType double_type
;
251 public TypeSymbol gtype_type
;
252 public TypeSymbol gobject_type
;
253 public ErrorType gerror_type
;
254 public Class glist_type
;
255 public Class gslist_type
;
256 public Class gnode_type
;
257 public Class gvaluearray_type
;
258 public TypeSymbol gstringbuilder_type
;
259 public TypeSymbol garray_type
;
260 public TypeSymbol gbytearray_type
;
261 public TypeSymbol gptrarray_type
;
262 public TypeSymbol gthreadpool_type
;
263 public DataType gquark_type
;
264 public Struct gvalue_type
;
265 public Class gvariant_type
;
266 public Struct mutex_type
;
267 public TypeSymbol type_module_type
;
268 public TypeSymbol dbus_proxy_type
;
269 public TypeSymbol dbus_object_type
;
271 public bool in_plugin
= false;
272 public string module_init_param_name
;
274 public bool gvaluecollector_h_needed
;
275 public bool requires_array_free
;
276 public bool requires_array_move
;
277 public bool requires_array_length
;
279 public Set
<string> wrappers
;
280 Set
<Symbol
> generated_external_symbols
;
282 public Map
<string,string> variable_name_map
{ get { return emit_context
.variable_name_map
; } }
284 public CCodeBaseModule () {
285 predefined_marshal_set
= new HashSet
<string> (str_hash
, str_equal
);
286 predefined_marshal_set
.add ("VOID:VOID");
287 predefined_marshal_set
.add ("VOID:BOOLEAN");
288 predefined_marshal_set
.add ("VOID:CHAR");
289 predefined_marshal_set
.add ("VOID:UCHAR");
290 predefined_marshal_set
.add ("VOID:INT");
291 predefined_marshal_set
.add ("VOID:UINT");
292 predefined_marshal_set
.add ("VOID:LONG");
293 predefined_marshal_set
.add ("VOID:ULONG");
294 predefined_marshal_set
.add ("VOID:ENUM");
295 predefined_marshal_set
.add ("VOID:FLAGS");
296 predefined_marshal_set
.add ("VOID:FLOAT");
297 predefined_marshal_set
.add ("VOID:DOUBLE");
298 predefined_marshal_set
.add ("VOID:STRING");
299 predefined_marshal_set
.add ("VOID:POINTER");
300 predefined_marshal_set
.add ("VOID:OBJECT");
301 predefined_marshal_set
.add ("STRING:OBJECT,POINTER");
302 predefined_marshal_set
.add ("VOID:UINT,POINTER");
303 predefined_marshal_set
.add ("BOOLEAN:FLAGS");
305 reserved_identifiers
= new HashSet
<string> (str_hash
, str_equal
);
308 reserved_identifiers
.add ("_Bool");
309 reserved_identifiers
.add ("_Complex");
310 reserved_identifiers
.add ("_Imaginary");
311 reserved_identifiers
.add ("asm");
312 reserved_identifiers
.add ("auto");
313 reserved_identifiers
.add ("break");
314 reserved_identifiers
.add ("case");
315 reserved_identifiers
.add ("char");
316 reserved_identifiers
.add ("const");
317 reserved_identifiers
.add ("continue");
318 reserved_identifiers
.add ("default");
319 reserved_identifiers
.add ("do");
320 reserved_identifiers
.add ("double");
321 reserved_identifiers
.add ("else");
322 reserved_identifiers
.add ("enum");
323 reserved_identifiers
.add ("extern");
324 reserved_identifiers
.add ("float");
325 reserved_identifiers
.add ("for");
326 reserved_identifiers
.add ("goto");
327 reserved_identifiers
.add ("if");
328 reserved_identifiers
.add ("inline");
329 reserved_identifiers
.add ("int");
330 reserved_identifiers
.add ("long");
331 reserved_identifiers
.add ("register");
332 reserved_identifiers
.add ("restrict");
333 reserved_identifiers
.add ("return");
334 reserved_identifiers
.add ("short");
335 reserved_identifiers
.add ("signed");
336 reserved_identifiers
.add ("sizeof");
337 reserved_identifiers
.add ("static");
338 reserved_identifiers
.add ("struct");
339 reserved_identifiers
.add ("switch");
340 reserved_identifiers
.add ("typedef");
341 reserved_identifiers
.add ("union");
342 reserved_identifiers
.add ("unsigned");
343 reserved_identifiers
.add ("void");
344 reserved_identifiers
.add ("volatile");
345 reserved_identifiers
.add ("while");
348 reserved_identifiers
.add ("cdecl");
350 // reserved for Vala/GObject naming conventions
351 reserved_identifiers
.add ("error");
352 reserved_identifiers
.add ("result");
353 reserved_identifiers
.add ("self");
356 public override void emit (CodeContext context
) {
357 this
.context
= context
;
359 root_symbol
= context
.root
;
361 bool_type
= new
BooleanType ((Struct
) root_symbol
.scope
.lookup ("bool"));
362 char_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("char"));
363 uchar_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uchar"));
364 short_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("short"));
365 ushort_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ushort"));
366 int_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int"));
367 uint_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint"));
368 long_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("long"));
369 ulong_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ulong"));
370 int8_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int8"));
371 uint8_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint8"));
372 int16_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int16"));
373 uint16_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint16"));
374 int32_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int32"));
375 uint32_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint32"));
376 int64_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int64"));
377 uint64_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint64"));
378 float_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("float"));
379 double_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("double"));
380 string_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("string"));
381 var unichar_struct
= (Struct
) root_symbol
.scope
.lookup ("unichar");
382 if (unichar_struct
!= null) {
383 unichar_type
= new
IntegerType (unichar_struct
);
386 if (context
.profile
== Profile
.GOBJECT
) {
387 var glib_ns
= root_symbol
.scope
.lookup ("GLib");
389 gtype_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Type");
390 gobject_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Object");
391 gerror_type
= new
ErrorType (null, null);
392 glist_type
= (Class
) glib_ns
.scope
.lookup ("List");
393 gslist_type
= (Class
) glib_ns
.scope
.lookup ("SList");
394 gnode_type
= (Class
) glib_ns
.scope
.lookup ("Node");
395 gvaluearray_type
= (Class
) glib_ns
.scope
.lookup ("ValueArray");
396 gstringbuilder_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("StringBuilder");
397 garray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Array");
398 gbytearray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("ByteArray");
399 gptrarray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("PtrArray");
400 gthreadpool_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("ThreadPool");
402 gquark_type
= new
IntegerType ((Struct
) glib_ns
.scope
.lookup ("Quark"));
403 gvalue_type
= (Struct
) glib_ns
.scope
.lookup ("Value");
404 gvariant_type
= (Class
) glib_ns
.scope
.lookup ("Variant");
405 mutex_type
= (Struct
) glib_ns
.scope
.lookup ("StaticRecMutex");
407 type_module_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("TypeModule");
409 regex_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("GLib").scope
.lookup ("Regex"));
411 if (context
.module_init_method
!= null) {
412 foreach (Parameter parameter
in context
.module_init_method
.get_parameters ()) {
413 if (parameter
.variable_type
.data_type
== type_module_type
) {
415 module_init_param_name
= parameter
.name
;
420 Report
.error (context
.module_init_method
.source_reference
, "[ModuleInit] requires a parameter of type `GLib.TypeModule'");
424 dbus_proxy_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("DBusProxy");
426 var dbus_ns
= root_symbol
.scope
.lookup ("DBus");
427 if (dbus_ns
!= null) {
428 dbus_object_type
= (TypeSymbol
) dbus_ns
.scope
.lookup ("Object");
432 header_file
= new
CCodeFile ();
433 header_file
.is_header
= true;
434 internal_header_file
= new
CCodeFile ();
435 internal_header_file
.is_header
= true;
437 /* we're only interested in non-pkg source files */
438 var source_files
= context
.get_source_files ();
439 foreach (SourceFile file
in source_files
) {
440 if (file
.file_type
== SourceFileType
.SOURCE
||
441 (context
.header_filename
!= null && file
.file_type
== SourceFileType
.FAST
)) {
446 // generate symbols file for public API
447 if (context
.symbols_filename
!= null) {
448 var stream
= FileStream
.open (context
.symbols_filename
, "w");
449 if (stream
== null) {
450 Report
.error (null, "unable to open `%s' for writing".printf (context
.symbols_filename
));
454 foreach (string symbol
in header_file
.get_symbols ()) {
455 stream
.puts (symbol
);
462 // generate C header file for public API
463 if (context
.header_filename
!= null) {
465 if (context
.profile
== Profile
.GOBJECT
) {
466 ret
= header_file
.store (context
.header_filename
, null, context
.version_header
, false, "G_BEGIN_DECLS", "G_END_DECLS");
468 ret
= header_file
.store (context
.header_filename
, null, context
.version_header
, false);
471 Report
.error (null, "unable to open `%s' for writing".printf (context
.header_filename
));
475 // generate C header file for internal API
476 if (context
.internal_header_filename
!= null) {
478 if (context
.profile
== Profile
.GOBJECT
) {
479 ret
= internal_header_file
.store (context
.internal_header_filename
, null, context
.version_header
, false, "G_BEGIN_DECLS", "G_END_DECLS");
481 ret
= internal_header_file
.store (context
.internal_header_filename
, null, context
.version_header
, false);
484 Report
.error (null, "unable to open `%s' for writing".printf (context
.internal_header_filename
));
489 public void push_context (EmitContext emit_context
) {
490 if (this
.emit_context
!= null) {
491 emit_context_stack
.add (this
.emit_context
);
494 this
.emit_context
= emit_context
;
497 public void pop_context () {
498 if (emit_context_stack
.size
> 0) {
499 this
.emit_context
= emit_context_stack
[emit_context_stack
.size
- 1];
500 emit_context_stack
.remove_at (emit_context_stack
.size
- 1);
502 this
.emit_context
= null;
506 public void push_function (CCodeFunction func
) {
507 emit_context
.ccode_stack
.add (ccode
);
508 emit_context
.ccode
= func
;
511 public void pop_function () {
512 emit_context
.ccode
= emit_context
.ccode_stack
[emit_context
.ccode_stack
.size
- 1];
513 emit_context
.ccode_stack
.remove_at (emit_context
.ccode_stack
.size
- 1);
516 public bool add_symbol_declaration (CCodeFile decl_space
, Symbol sym
, string name
) {
517 if (decl_space
.add_declaration (name
)) {
520 if (sym
.source_reference
!= null) {
521 sym
.source_reference
.file
.used
= true;
523 if (sym
.external_package
|| (!decl_space
.is_header
&& CodeContext
.get ().use_header
&& !sym
.is_internal_symbol ())) {
524 // add appropriate include file
525 foreach (string header_filename
in sym
.get_cheader_filenames ()) {
526 decl_space
.add_include (header_filename
, !sym
.external_package
);
528 // declaration complete
531 // require declaration
536 public CCodeIdentifier
get_value_setter_function (DataType type_reference
) {
537 var array_type
= type_reference as ArrayType
;
538 if (type_reference
.data_type
!= null) {
539 return new
CCodeIdentifier (type_reference
.data_type
.get_set_value_function ());
540 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
542 return new
CCodeIdentifier ("g_value_set_boxed");
544 return new
CCodeIdentifier ("g_value_set_pointer");
548 public CCodeIdentifier
get_value_taker_function (DataType type_reference
) {
549 var array_type
= type_reference as ArrayType
;
550 if (type_reference
.data_type
!= null) {
551 return new
CCodeIdentifier (type_reference
.data_type
.get_take_value_function ());
552 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
554 return new
CCodeIdentifier ("g_value_take_boxed");
556 return new
CCodeIdentifier ("g_value_set_pointer");
560 CCodeIdentifier
get_value_getter_function (DataType type_reference
) {
561 var array_type
= type_reference as ArrayType
;
562 if (type_reference
.data_type
!= null) {
563 return new
CCodeIdentifier (type_reference
.data_type
.get_get_value_function ());
564 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
566 return new
CCodeIdentifier ("g_value_get_boxed");
568 return new
CCodeIdentifier ("g_value_get_pointer");
572 public virtual void append_vala_array_free () {
575 public virtual void append_vala_array_move () {
578 public virtual void append_vala_array_length () {
581 public override void visit_source_file (SourceFile source_file
) {
582 cfile
= new
CCodeFile ();
584 user_marshal_set
= new HashSet
<string> (str_hash
, str_equal
);
588 gvaluecollector_h_needed
= false;
589 requires_array_free
= false;
590 requires_array_move
= false;
591 requires_array_length
= false;
593 wrappers
= new HashSet
<string> (str_hash
, str_equal
);
594 generated_external_symbols
= new HashSet
<Symbol
> ();
596 if (context
.profile
== Profile
.GOBJECT
) {
597 header_file
.add_include ("glib.h");
598 internal_header_file
.add_include ("glib.h");
599 cfile
.add_include ("glib.h");
600 cfile
.add_include ("glib-object.h");
603 source_file
.accept_children (this
);
605 if (context
.report
.get_errors () > 0) {
609 /* For fast-vapi, we only wanted the header declarations
610 * to be emitted, so bail out here without writing the
613 if (source_file
.file_type
== SourceFileType
.FAST
) {
617 if (requires_array_free
) {
618 append_vala_array_free ();
620 if (requires_array_move
) {
621 append_vala_array_move ();
623 if (requires_array_length
) {
624 append_vala_array_length ();
627 if (gvaluecollector_h_needed
) {
628 cfile
.add_include ("gobject/gvaluecollector.h");
631 var comments
= source_file
.get_comments();
632 if (comments
!= null) {
633 foreach (Comment comment
in comments
) {
634 var ccomment
= new
CCodeComment (comment
.content
);
635 cfile
.add_comment (ccomment
);
639 if (!cfile
.store (source_file
.get_csource_filename (), source_file
.filename
, context
.version_header
, context
.debug
)) {
640 Report
.error (null, "unable to open `%s' for writing".printf (source_file
.get_csource_filename ()));
646 public virtual bool generate_enum_declaration (Enum en
, CCodeFile decl_space
) {
647 if (add_symbol_declaration (decl_space
, en
, en
.get_cname ())) {
651 var cenum
= new
CCodeEnum (en
.get_cname ());
653 cenum
.deprecated
= en
.deprecated
;
656 foreach (EnumValue ev
in en
.get_values ()) {
658 if (ev
.value
== null) {
659 c_ev
= new
CCodeEnumValue (ev
.get_cname ());
661 c_ev
.value
= new
CCodeConstant ("1 << %d".printf (flag_shift
));
665 ev
.value
.emit (this
);
666 c_ev
= new
CCodeEnumValue (ev
.get_cname (), get_cvalue (ev
.value
));
668 c_ev
.deprecated
= ev
.deprecated
;
669 cenum
.add_value (c_ev
);
672 decl_space
.add_type_definition (cenum
);
673 decl_space
.add_type_definition (new
CCodeNewline ());
675 if (!en
.has_type_id
) {
679 decl_space
.add_type_declaration (new
CCodeNewline ());
681 var macro
= "(%s_get_type ())".printf (en
.get_lower_case_cname (null));
682 decl_space
.add_type_declaration (new
CCodeMacroReplacement (en
.get_type_id (), macro
));
684 var fun_name
= "%s_get_type".printf (en
.get_lower_case_cname (null));
685 var regfun
= new
CCodeFunction (fun_name
, "GType");
686 regfun
.attributes
= "G_GNUC_CONST";
688 if (en
.access
== SymbolAccessibility
.PRIVATE
) {
689 regfun
.modifiers
= CCodeModifiers
.STATIC
;
690 // avoid C warning as this function is not always used
691 regfun
.attributes
= "G_GNUC_UNUSED";
694 decl_space
.add_function_declaration (regfun
);
699 public override void visit_enum (Enum en
) {
700 en
.accept_children (this
);
702 if (en
.comment
!= null) {
703 cfile
.add_type_member_definition (new
CCodeComment (en
.comment
.content
));
706 generate_enum_declaration (en
, cfile
);
708 if (!en
.is_internal_symbol ()) {
709 generate_enum_declaration (en
, header_file
);
711 if (!en
.is_private_symbol ()) {
712 generate_enum_declaration (en
, internal_header_file
);
716 public void visit_member (Symbol m
) {
717 /* stuff meant for all lockable members */
718 if (m is Lockable
&& ((Lockable
) m
).get_lock_used ()) {
719 CCodeExpression l
= new
CCodeIdentifier ("self");
720 var init_context
= class_init_context
;
721 var finalize_context
= class_finalize_context
;
723 if (m
.is_instance_member ()) {
724 l
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (l
, "priv"), get_symbol_lock_name (m
.name
));
725 init_context
= instance_init_context
;
726 finalize_context
= instance_finalize_context
;
727 } else if (m
.is_class_member ()) {
728 TypeSymbol parent
= (TypeSymbol
)m
.parent_symbol
;
730 var get_class_private_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent
.get_upper_case_cname ())));
731 get_class_private_call
.add_argument (new
CCodeIdentifier ("klass"));
732 l
= new CCodeMemberAccess
.pointer (get_class_private_call
, get_symbol_lock_name (m
.name
));
734 l
= new
CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf(m
.parent_symbol
.get_lower_case_cname (), m
.name
)));
737 push_context (init_context
);
738 var initf
= new
CCodeFunctionCall (new
CCodeIdentifier (mutex_type
.default_construction_method
.get_cname ()));
739 initf
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
740 ccode
.add_expression (initf
);
743 if (finalize_context
!= null) {
744 push_context (finalize_context
);
745 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_static_rec_mutex_free"));
746 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
747 ccode
.add_expression (fc
);
753 public void generate_constant_declaration (Constant c
, CCodeFile decl_space
, bool definition
= false) {
754 if (c
.parent_symbol is Block
) {
759 if (add_symbol_declaration (decl_space
, c
, c
.get_cname ())) {
764 generate_type_declaration (c
.type_reference
, decl_space
);
768 var initializer_list
= c
.value as InitializerList
;
769 if (initializer_list
!= null) {
770 var cdecl
= new
CCodeDeclaration (c
.type_reference
.get_const_cname ());
772 if (c
.type_reference is ArrayType
) {
773 arr
= "[%d]".printf (initializer_list
.size
);
776 var cinitializer
= get_cvalue (c
.value
);
778 // never output value in header
779 // special case needed as this method combines declaration and definition
783 cdecl
.add_declarator (new
CCodeVariableDeclarator ("%s%s".printf (c
.get_cname (), arr
), cinitializer
));
784 if (c
.is_private_symbol ()) {
785 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
787 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
790 decl_space
.add_constant_declaration (cdecl
);
792 var cdefine
= new CCodeMacroReplacement
.with_expression (c
.get_cname (), get_cvalue (c
.value
));
793 decl_space
.add_type_member_declaration (cdefine
);
798 public override void visit_constant (Constant c
) {
799 if (c
.parent_symbol is Block
) {
802 generate_type_declaration (c
.type_reference
, cfile
);
806 string type_name
= c
.type_reference
.get_const_cname ();
808 if (c
.type_reference is ArrayType
) {
812 if (c
.type_reference
.compatible (string_type
)) {
813 type_name
= "const char";
817 var cinitializer
= get_cvalue (c
.value
);
819 ccode
.add_declaration (type_name
, new
CCodeVariableDeclarator ("%s%s".printf (c
.get_cname (), arr
), cinitializer
), CCodeModifiers
.STATIC
);
824 generate_constant_declaration (c
, cfile
, true);
826 if (!c
.is_internal_symbol ()) {
827 generate_constant_declaration (c
, header_file
);
829 if (!c
.is_private_symbol ()) {
830 generate_constant_declaration (c
, internal_header_file
);
834 public void generate_field_declaration (Field f
, CCodeFile decl_space
) {
835 if (add_symbol_declaration (decl_space
, f
, f
.get_cname ())) {
839 generate_type_declaration (f
.variable_type
, decl_space
);
841 string field_ctype
= f
.variable_type
.get_cname ();
843 field_ctype
= "volatile " + field_ctype
;
846 var cdecl
= new
CCodeDeclaration (field_ctype
);
847 cdecl
.add_declarator (new
CCodeVariableDeclarator (f
.get_cname (), null, f
.variable_type
.get_cdeclarator_suffix ()));
848 if (f
.is_private_symbol ()) {
849 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
851 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
854 cdecl
.modifiers
|= CCodeModifiers
.DEPRECATED
;
856 decl_space
.add_type_member_declaration (cdecl
);
858 if (f
.get_lock_used ()) {
859 // Declare mutex for static member
860 var flock
= new
CCodeDeclaration (mutex_type
.get_cname ());
861 var flock_decl
= new
CCodeVariableDeclarator (get_symbol_lock_name (f
.get_cname ()), new
CCodeConstant ("{0}"));
862 flock
.add_declarator (flock_decl
);
864 if (f
.is_private_symbol ()) {
865 flock
.modifiers
= CCodeModifiers
.STATIC
;
867 flock
.modifiers
= CCodeModifiers
.EXTERN
;
869 decl_space
.add_type_member_declaration (flock
);
872 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
873 var array_type
= (ArrayType
) f
.variable_type
;
875 if (!array_type
.fixed_length
) {
876 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
877 var len_type
= int_type
.copy ();
879 cdecl
= new
CCodeDeclaration (len_type
.get_cname ());
880 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (f
.get_cname (), dim
)));
881 if (f
.is_private_symbol ()) {
882 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
884 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
886 decl_space
.add_type_member_declaration (cdecl
);
889 } else if (f
.variable_type is DelegateType
) {
890 var delegate_type
= (DelegateType
) f
.variable_type
;
891 if (delegate_type
.delegate_symbol
.has_target
) {
892 // create field to store delegate target
894 cdecl
= new
CCodeDeclaration ("gpointer");
895 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_cname (f
.get_cname ())));
896 if (f
.is_private_symbol ()) {
897 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
899 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
901 decl_space
.add_type_member_declaration (cdecl
);
903 if (delegate_type
.value_owned
) {
904 cdecl
= new
CCodeDeclaration ("GDestroyNotify");
905 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f
.get_cname ())));
906 if (f
.is_private_symbol ()) {
907 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
909 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
911 decl_space
.add_type_member_declaration (cdecl
);
917 public override void visit_field (Field f
) {
920 check_type (f
.variable_type
);
922 var cl
= f
.parent_symbol as Class
;
923 bool is_gtypeinstance
= (cl
!= null && !cl
.is_compact
);
925 CCodeExpression lhs
= null;
927 string field_ctype
= f
.variable_type
.get_cname ();
929 field_ctype
= "volatile " + field_ctype
;
932 if (f
.binding
== MemberBinding
.INSTANCE
) {
933 if (is_gtypeinstance
&& f
.access
== SymbolAccessibility
.PRIVATE
) {
934 lhs
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), f
.get_cname ());
936 lhs
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.get_cname ());
939 if (f
.initializer
!= null) {
940 push_context (instance_init_context
);
942 f
.initializer
.emit (this
);
944 var rhs
= get_cvalue (f
.initializer
);
946 ccode
.add_expression (new
CCodeAssignment (lhs
, rhs
));
948 if (f
.variable_type is ArrayType
&& !f
.no_array_length
&&
949 f
.initializer is ArrayCreationExpression
) {
950 var array_type
= (ArrayType
) f
.variable_type
;
951 var this_access
= new MemberAccess
.simple ("this");
952 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
953 set_cvalue (this_access
, new
CCodeIdentifier ("self"));
954 var ma
= new
MemberAccess (this_access
, f
.name
);
955 ma
.symbol_reference
= f
;
956 ma
.value_type
= f
.variable_type
.copy ();
957 visit_member_access (ma
);
959 List
<Expression
> sizes
= ((ArrayCreationExpression
) f
.initializer
).get_sizes ();
960 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
961 var array_len_lhs
= get_array_length_cexpression (ma
, dim
);
962 var size
= sizes
[dim
- 1];
963 ccode
.add_expression (new
CCodeAssignment (array_len_lhs
, get_cvalue (size
)));
966 if (array_type
.rank
== 1 && f
.is_internal_symbol ()) {
967 var lhs_array_size
= get_array_size_cvalue (ma
.target_value
);
968 var rhs_array_len
= get_array_length_cexpression (ma
, 1);
969 ccode
.add_expression (new
CCodeAssignment (lhs_array_size
, rhs_array_len
));
973 foreach (LocalVariable local
in temp_ref_vars
) {
974 var ma
= new MemberAccess
.simple (local
.name
);
975 ma
.symbol_reference
= local
;
976 ma
.value_type
= local
.variable_type
.copy ();
977 visit_member_access (ma
);
978 ccode
.add_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
981 temp_ref_vars
.clear ();
986 if (requires_destroy (f
.variable_type
) && instance_finalize_context
!= null) {
987 push_context (instance_finalize_context
);
989 var this_access
= new MemberAccess
.simple ("this");
990 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
992 var field_st
= f
.parent_symbol as Struct
;
993 if (field_st
!= null && !field_st
.is_simple_type ()) {
994 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
996 set_cvalue (this_access
, new
CCodeIdentifier ("self"));
999 var ma
= new
MemberAccess (this_access
, f
.name
);
1000 ma
.symbol_reference
= f
;
1001 ma
.value_type
= f
.variable_type
.copy ();
1002 visit_member_access (ma
);
1003 ccode
.add_expression (get_unref_expression (lhs
, f
.variable_type
, ma
));
1007 } else if (f
.binding
== MemberBinding
.CLASS
) {
1008 if (!is_gtypeinstance
) {
1009 Report
.error (f
.source_reference
, "class fields are not supported in compact classes");
1014 if (f
.access
== SymbolAccessibility
.PRIVATE
) {
1015 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (cl
.get_upper_case_cname ())));
1016 ccall
.add_argument (new
CCodeIdentifier ("klass"));
1017 lhs
= new
CCodeMemberAccess (ccall
, f
.get_cname (), true);
1019 lhs
= new
CCodeMemberAccess (new
CCodeIdentifier ("klass"), f
.get_cname (), true);
1022 if (f
.initializer
!= null) {
1023 push_context (class_init_context
);
1025 f
.initializer
.emit (this
);
1027 var rhs
= get_cvalue (f
.initializer
);
1029 ccode
.add_expression (new
CCodeAssignment (lhs
, rhs
));
1031 foreach (LocalVariable local
in temp_ref_vars
) {
1032 var ma
= new MemberAccess
.simple (local
.name
);
1033 ma
.symbol_reference
= local
;
1034 ma
.value_type
= local
.variable_type
.copy ();
1035 visit_member_access (ma
);
1036 ccode
.add_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
1039 temp_ref_vars
.clear ();
1044 generate_field_declaration (f
, cfile
);
1046 if (!f
.is_internal_symbol ()) {
1047 generate_field_declaration (f
, header_file
);
1049 if (!f
.is_private_symbol ()) {
1050 generate_field_declaration (f
, internal_header_file
);
1053 lhs
= new
CCodeIdentifier (f
.get_cname ());
1055 var var_decl
= new
CCodeVariableDeclarator (f
.get_cname (), null, f
.variable_type
.get_cdeclarator_suffix ());
1056 var_decl
.initializer
= default_value_for_type (f
.variable_type
, true);
1058 if (class_init_context
!= null) {
1059 push_context (class_init_context
);
1061 push_context (new
EmitContext ());
1064 if (f
.initializer
!= null) {
1065 f
.initializer
.emit (this
);
1067 var init
= get_cvalue (f
.initializer
);
1068 if (is_constant_ccode_expression (init
)) {
1069 var_decl
.initializer
= init
;
1073 var var_def
= new
CCodeDeclaration (field_ctype
);
1074 var_def
.add_declarator (var_decl
);
1075 if (!f
.is_private_symbol ()) {
1076 var_def
.modifiers
= CCodeModifiers
.EXTERN
;
1078 var_def
.modifiers
= CCodeModifiers
.STATIC
;
1080 cfile
.add_type_member_declaration (var_def
);
1082 /* add array length fields where necessary */
1083 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
1084 var array_type
= (ArrayType
) f
.variable_type
;
1086 if (!array_type
.fixed_length
) {
1087 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1088 var len_type
= int_type
.copy ();
1090 var len_def
= new
CCodeDeclaration (len_type
.get_cname ());
1091 len_def
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (f
.get_cname (), dim
), new
CCodeConstant ("0")));
1092 if (!f
.is_private_symbol ()) {
1093 len_def
.modifiers
= CCodeModifiers
.EXTERN
;
1095 len_def
.modifiers
= CCodeModifiers
.STATIC
;
1097 cfile
.add_type_member_declaration (len_def
);
1100 if (array_type
.rank
== 1 && f
.is_internal_symbol ()) {
1101 var len_type
= int_type
.copy ();
1103 var cdecl
= new
CCodeDeclaration (len_type
.get_cname ());
1104 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_size_cname (f
.get_cname ()), new
CCodeConstant ("0")));
1105 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
1106 cfile
.add_type_member_declaration (cdecl
);
1109 } else if (f
.variable_type is DelegateType
) {
1110 var delegate_type
= (DelegateType
) f
.variable_type
;
1111 if (delegate_type
.delegate_symbol
.has_target
) {
1112 // create field to store delegate target
1114 var target_def
= new
CCodeDeclaration ("gpointer");
1115 target_def
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_cname (f
.get_cname ()), new
CCodeConstant ("NULL")));
1116 if (!f
.is_private_symbol ()) {
1117 target_def
.modifiers
= CCodeModifiers
.EXTERN
;
1119 target_def
.modifiers
= CCodeModifiers
.STATIC
;
1121 cfile
.add_type_member_declaration (target_def
);
1123 if (delegate_type
.value_owned
) {
1124 var target_destroy_notify_def
= new
CCodeDeclaration ("GDestroyNotify");
1125 target_destroy_notify_def
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f
.get_cname ()), new
CCodeConstant ("NULL")));
1126 if (!f
.is_private_symbol ()) {
1127 target_destroy_notify_def
.modifiers
= CCodeModifiers
.EXTERN
;
1129 target_destroy_notify_def
.modifiers
= CCodeModifiers
.STATIC
;
1131 cfile
.add_type_member_declaration (target_destroy_notify_def
);
1137 if (f
.initializer
!= null) {
1138 var rhs
= get_cvalue (f
.initializer
);
1139 if (!is_constant_ccode_expression (rhs
)) {
1140 if (f
.parent_symbol is Class
) {
1141 if (f
.initializer is InitializerList
) {
1142 ccode
.open_block ();
1144 var temp_decl
= get_temp_variable (f
.variable_type
);
1145 var vardecl
= new CCodeVariableDeclarator
.zero (temp_decl
.name
, rhs
);
1146 ccode
.add_declaration (temp_decl
.variable_type
.get_cname (), vardecl
);
1148 var tmp
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
1149 ccode
.add_expression (new
CCodeAssignment (lhs
, tmp
));
1153 ccode
.add_expression (new
CCodeAssignment (lhs
, rhs
));
1156 if (f
.variable_type is ArrayType
&& !f
.no_array_length
&&
1157 f
.initializer is ArrayCreationExpression
) {
1158 var array_type
= (ArrayType
) f
.variable_type
;
1159 var ma
= new MemberAccess
.simple (f
.name
);
1160 ma
.symbol_reference
= f
;
1161 ma
.value_type
= f
.variable_type
.copy ();
1162 visit_member_access (ma
);
1164 List
<Expression
> sizes
= ((ArrayCreationExpression
) f
.initializer
).get_sizes ();
1165 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1166 var array_len_lhs
= get_array_length_cexpression (ma
, dim
);
1167 var size
= sizes
[dim
- 1];
1168 ccode
.add_expression (new
CCodeAssignment (array_len_lhs
, get_cvalue (size
)));
1173 Report
.error (f
.source_reference
, "Non-constant field initializers not supported in this context");
1183 public bool is_constant_ccode_expression (CCodeExpression cexpr
) {
1184 if (cexpr is CCodeConstant
) {
1186 } else if (cexpr is CCodeCastExpression
) {
1187 var ccast
= (CCodeCastExpression
) cexpr
;
1188 return is_constant_ccode_expression (ccast
.inner
);
1189 } else if (cexpr is CCodeBinaryExpression
) {
1190 var cbinary
= (CCodeBinaryExpression
) cexpr
;
1191 return is_constant_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
1194 var cparenthesized
= (cexpr as CCodeParenthesizedExpression
);
1195 return (null != cparenthesized
&& is_constant_ccode_expression (cparenthesized
.inner
));
1199 * Returns whether the passed cexpr is a pure expression, i.e. an
1200 * expression without side-effects.
1202 public bool is_pure_ccode_expression (CCodeExpression cexpr
) {
1203 if (cexpr is CCodeConstant
|| cexpr is CCodeIdentifier
) {
1205 } else if (cexpr is CCodeBinaryExpression
) {
1206 var cbinary
= (CCodeBinaryExpression
) cexpr
;
1207 return is_pure_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
1208 } else if (cexpr is CCodeUnaryExpression
) {
1209 var cunary
= (CCodeUnaryExpression
) cexpr
;
1210 switch (cunary
.operator
) {
1211 case CCodeUnaryOperator
.PREFIX_INCREMENT
:
1212 case CCodeUnaryOperator
.PREFIX_DECREMENT
:
1213 case CCodeUnaryOperator
.POSTFIX_INCREMENT
:
1214 case CCodeUnaryOperator
.POSTFIX_DECREMENT
:
1217 return is_pure_ccode_expression (cunary
.inner
);
1219 } else if (cexpr is CCodeMemberAccess
) {
1220 var cma
= (CCodeMemberAccess
) cexpr
;
1221 return is_pure_ccode_expression (cma
.inner
);
1222 } else if (cexpr is CCodeElementAccess
) {
1223 var cea
= (CCodeElementAccess
) cexpr
;
1224 return is_pure_ccode_expression (cea
.container
) && is_pure_ccode_expression (cea
.index
);
1225 } else if (cexpr is CCodeCastExpression
) {
1226 var ccast
= (CCodeCastExpression
) cexpr
;
1227 return is_pure_ccode_expression (ccast
.inner
);
1228 } else if (cexpr is CCodeParenthesizedExpression
) {
1229 var cparenthesized
= (CCodeParenthesizedExpression
) cexpr
;
1230 return is_pure_ccode_expression (cparenthesized
.inner
);
1236 public override void visit_formal_parameter (Parameter p
) {
1238 check_type (p
.variable_type
);
1242 public override void visit_property (Property prop
) {
1243 visit_member (prop
);
1245 check_type (prop
.property_type
);
1247 if (prop
.get_accessor
!= null) {
1248 prop
.get_accessor
.accept (this
);
1250 if (prop
.set_accessor
!= null) {
1251 prop
.set_accessor
.accept (this
);
1255 public void generate_type_declaration (DataType type
, CCodeFile decl_space
) {
1256 if (type is ObjectType
) {
1257 var object_type
= (ObjectType
) type
;
1258 if (object_type
.type_symbol is Class
) {
1259 generate_class_declaration ((Class
) object_type
.type_symbol
, decl_space
);
1260 } else if (object_type
.type_symbol is Interface
) {
1261 generate_interface_declaration ((Interface
) object_type
.type_symbol
, decl_space
);
1263 } else if (type is DelegateType
) {
1264 var deleg_type
= (DelegateType
) type
;
1265 var d
= deleg_type
.delegate_symbol
;
1266 generate_delegate_declaration (d
, decl_space
);
1267 } else if (type
.data_type is Enum
) {
1268 var en
= (Enum
) type
.data_type
;
1269 generate_enum_declaration (en
, decl_space
);
1270 } else if (type is ValueType
) {
1271 var value_type
= (ValueType
) type
;
1272 generate_struct_declaration ((Struct
) value_type
.type_symbol
, decl_space
);
1273 } else if (type is ArrayType
) {
1274 var array_type
= (ArrayType
) type
;
1275 generate_type_declaration (array_type
.element_type
, decl_space
);
1276 } else if (type is ErrorType
) {
1277 var error_type
= (ErrorType
) type
;
1278 if (error_type
.error_domain
!= null) {
1279 generate_error_domain_declaration (error_type
.error_domain
, decl_space
);
1281 } else if (type is PointerType
) {
1282 var pointer_type
= (PointerType
) type
;
1283 generate_type_declaration (pointer_type
.base_type
, decl_space
);
1286 foreach (DataType type_arg
in type
.get_type_arguments ()) {
1287 generate_type_declaration (type_arg
, decl_space
);
1291 public virtual void generate_class_struct_declaration (Class cl
, CCodeFile decl_space
) {
1294 public virtual void generate_struct_declaration (Struct st
, CCodeFile decl_space
) {
1297 public virtual void generate_delegate_declaration (Delegate d
, CCodeFile decl_space
) {
1300 public virtual void generate_cparameters (Method m
, CCodeFile decl_space
, Map
<int,CCodeParameter
> cparam_map
, CCodeFunction func
, CCodeFunctionDeclarator? vdeclarator
= null, Map
<int,CCodeExpression
>? carg_map
= null, CCodeFunctionCall? vcall
= null, int direction
= 3) {
1303 public void generate_property_accessor_declaration (PropertyAccessor acc
, CCodeFile decl_space
) {
1304 if (add_symbol_declaration (decl_space
, acc
, acc
.get_cname ())) {
1308 var prop
= (Property
) acc
.prop
;
1310 bool returns_real_struct
= acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ();
1313 CCodeParameter cvalueparam
;
1314 if (returns_real_struct
) {
1315 cvalueparam
= new
CCodeParameter ("result", acc
.value_type
.get_cname () + "*");
1316 } else if (!acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ()) {
1317 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname () + "*");
1319 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname ());
1321 generate_type_declaration (acc
.value_type
, decl_space
);
1323 CCodeFunction function
;
1324 if (acc
.readable
&& !returns_real_struct
) {
1325 function
= new
CCodeFunction (acc
.get_cname (), acc
.value_type
.get_cname ());
1327 function
= new
CCodeFunction (acc
.get_cname (), "void");
1330 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1331 var t
= (TypeSymbol
) prop
.parent_symbol
;
1332 var this_type
= get_data_type_for_symbol (t
);
1333 generate_type_declaration (this_type
, decl_space
);
1334 var cselfparam
= new
CCodeParameter ("self", this_type
.get_cname ());
1336 cselfparam
.type_name
+= "*";
1339 function
.add_parameter (cselfparam
);
1342 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1343 function
.add_parameter (cvalueparam
);
1346 if (acc
.value_type is ArrayType
) {
1347 var array_type
= (ArrayType
) acc
.value_type
;
1349 var length_ctype
= "int";
1351 length_ctype
= "int*";
1354 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1355 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1357 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1358 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1361 if (prop
.is_private_symbol () || (!acc
.readable
&& !acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1362 function
.modifiers
|= CCodeModifiers
.STATIC
;
1364 decl_space
.add_function_declaration (function
);
1367 public override void visit_property_accessor (PropertyAccessor acc
) {
1368 push_context (new
EmitContext (acc
));
1370 var prop
= (Property
) acc
.prop
;
1372 if (acc
.comment
!= null) {
1373 cfile
.add_type_member_definition (new
CCodeComment (acc
.comment
.content
));
1376 bool returns_real_struct
= acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ();
1378 if (acc
.result_var
!= null) {
1379 acc
.result_var
.accept (this
);
1382 var t
= (TypeSymbol
) prop
.parent_symbol
;
1384 if (acc
.construction
&& !t
.is_subtype_of (gobject_type
)) {
1385 Report
.error (acc
.source_reference
, "construct properties require GLib.Object");
1388 } else if (acc
.construction
&& !is_gobject_property (prop
)) {
1389 Report
.error (acc
.source_reference
, "construct properties not supported for specified property type");
1394 // do not declare overriding properties and interface implementations
1395 if (prop
.is_abstract
|| prop
.is_virtual
1396 || (prop
.base_property
== null && prop
.base_interface_property
== null)) {
1397 generate_property_accessor_declaration (acc
, cfile
);
1399 // do not declare construct-only properties in header files
1400 if (acc
.readable
|| acc
.writable
) {
1401 if (!prop
.is_internal_symbol ()
1402 && (acc
.access
== SymbolAccessibility
.PUBLIC
1403 || acc
.access
== SymbolAccessibility
.PROTECTED
)) {
1404 generate_property_accessor_declaration (acc
, header_file
);
1406 if (!prop
.is_private_symbol () && acc
.access
!= SymbolAccessibility
.PRIVATE
) {
1407 generate_property_accessor_declaration (acc
, internal_header_file
);
1412 if (acc
.source_type
== SourceFileType
.FAST
) {
1416 var this_type
= get_data_type_for_symbol (t
);
1417 var cselfparam
= new
CCodeParameter ("self", this_type
.get_cname ());
1419 cselfparam
.type_name
+= "*";
1421 CCodeParameter cvalueparam
;
1422 if (returns_real_struct
) {
1423 cvalueparam
= new
CCodeParameter ("result", acc
.value_type
.get_cname () + "*");
1424 } else if (!acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ()) {
1425 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname () + "*");
1427 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname ());
1430 if (prop
.is_abstract
|| prop
.is_virtual
) {
1431 CCodeFunction function
;
1432 if (acc
.readable
&& !returns_real_struct
) {
1433 function
= new
CCodeFunction (acc
.get_cname (), current_return_type
.get_cname ());
1435 function
= new
CCodeFunction (acc
.get_cname (), "void");
1437 function
.add_parameter (cselfparam
);
1438 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1439 function
.add_parameter (cvalueparam
);
1442 if (acc
.value_type is ArrayType
) {
1443 var array_type
= (ArrayType
) acc
.value_type
;
1445 var length_ctype
= "int";
1447 length_ctype
= "int*";
1450 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1451 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1453 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1454 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1457 if (prop
.is_private_symbol () || !(acc
.readable
|| acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1458 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1459 function
.modifiers
|= CCodeModifiers
.STATIC
;
1462 push_function (function
);
1464 CCodeFunctionCall vcast
= null;
1465 if (prop
.parent_symbol is Interface
) {
1466 var iface
= (Interface
) prop
.parent_symbol
;
1468 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (iface
.get_upper_case_cname (null))));
1470 var cl
= (Class
) prop
.parent_symbol
;
1472 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (cl
.get_upper_case_cname (null))));
1474 vcast
.add_argument (new
CCodeIdentifier ("self"));
1477 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "get_%s".printf (prop
.name
)));
1478 vcall
.add_argument (new
CCodeIdentifier ("self"));
1479 if (returns_real_struct
) {
1480 vcall
.add_argument (new
CCodeIdentifier ("result"));
1481 ccode
.add_expression (vcall
);
1483 if (acc
.value_type is ArrayType
) {
1484 var array_type
= (ArrayType
) acc
.value_type
;
1486 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1487 var len_expr
= new
CCodeIdentifier (get_array_length_cname ("result", dim
));
1488 vcall
.add_argument (len_expr
);
1490 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1491 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_cname ("result")));
1494 ccode
.add_return (vcall
);
1497 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "set_%s".printf (prop
.name
)));
1498 vcall
.add_argument (new
CCodeIdentifier ("self"));
1499 vcall
.add_argument (new
CCodeIdentifier ("value"));
1501 if (acc
.value_type is ArrayType
) {
1502 var array_type
= (ArrayType
) acc
.value_type
;
1504 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1505 var len_expr
= new
CCodeIdentifier (get_array_length_cname ("value", dim
));
1506 vcall
.add_argument (len_expr
);
1508 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1509 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_cname ("value")));
1512 ccode
.add_expression (vcall
);
1517 cfile
.add_function (function
);
1520 if (!prop
.is_abstract
) {
1521 bool is_virtual
= prop
.base_property
!= null || prop
.base_interface_property
!= null;
1526 cname
= "%s_real_get_%s".printf (t
.get_lower_case_cname (null), prop
.name
);
1528 cname
= "%s_real_set_%s".printf (t
.get_lower_case_cname (null), prop
.name
);
1531 cname
= acc
.get_cname ();
1534 CCodeFunction function
;
1535 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1536 function
= new
CCodeFunction (cname
, "void");
1538 function
= new
CCodeFunction (cname
, acc
.value_type
.get_cname ());
1541 ObjectType base_type
= null;
1542 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1544 if (prop
.base_property
!= null) {
1545 base_type
= new
ObjectType ((ObjectTypeSymbol
) prop
.base_property
.parent_symbol
);
1546 } else if (prop
.base_interface_property
!= null) {
1547 base_type
= new
ObjectType ((ObjectTypeSymbol
) prop
.base_interface_property
.parent_symbol
);
1549 function
.modifiers
|= CCodeModifiers
.STATIC
;
1550 function
.add_parameter (new
CCodeParameter ("base", base_type
.get_cname ()));
1552 function
.add_parameter (cselfparam
);
1555 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1556 function
.add_parameter (cvalueparam
);
1559 if (acc
.value_type is ArrayType
) {
1560 var array_type
= (ArrayType
) acc
.value_type
;
1562 var length_ctype
= "int";
1564 length_ctype
= "int*";
1567 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1568 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1570 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1571 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1575 if (prop
.is_private_symbol () || !(acc
.readable
|| acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1576 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1577 function
.modifiers
|= CCodeModifiers
.STATIC
;
1581 push_function (function
);
1583 if (prop
.binding
== MemberBinding
.INSTANCE
&& !is_virtual
) {
1584 if (!acc
.readable
|| returns_real_struct
) {
1585 create_property_type_check_statement (prop
, false, t
, true, "self");
1587 create_property_type_check_statement (prop
, true, t
, true, "self");
1591 if (acc
.readable
&& !returns_real_struct
) {
1592 // do not declare result variable if exit block is known to be unreachable
1593 if (acc
.return_block
== null || acc
.return_block
.get_predecessors ().size
> 0) {
1594 ccode
.add_declaration (acc
.value_type
.get_cname (), new
CCodeVariableDeclarator ("result"));
1599 ccode
.add_declaration (this_type
.get_cname (), new
CCodeVariableDeclarator ("self"));
1600 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("self"), transform_expression (new
CCodeIdentifier ("base"), base_type
, this_type
)));
1603 acc
.body
.emit (this
);
1605 if (current_method_inner_error
) {
1606 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
1609 // notify on property changes
1610 if (is_gobject_property (prop
) &&
1612 (acc
.writable
|| acc
.construction
)) {
1613 var notify_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_notify"));
1614 notify_call
.add_argument (new
CCodeCastExpression (new
CCodeIdentifier ("self"), "GObject *"));
1615 notify_call
.add_argument (prop
.get_canonical_cconstant ());
1616 ccode
.add_expression (notify_call
);
1619 cfile
.add_function (function
);
1625 public override void visit_destructor (Destructor d
) {
1626 if (d
.binding
== MemberBinding
.STATIC
&& !in_plugin
) {
1627 Report
.error (d
.source_reference
, "static destructors are only supported for dynamic types");
1633 public int get_block_id (Block b
) {
1634 int result
= block_map
[b
];
1636 result
= ++next_block_id
;
1637 block_map
[b
] = result
;
1642 void capture_parameter (Parameter param
, CCodeStruct data
, int block_id
, CCodeBlock free_block
) {
1643 generate_type_declaration (param
.variable_type
, cfile
);
1645 var param_type
= param
.variable_type
.copy ();
1646 param_type
.value_owned
= true;
1647 data
.add_field (param_type
.get_cname (), get_variable_cname (param
.name
));
1649 bool is_unowned_delegate
= param
.variable_type is DelegateType
&& !param
.variable_type
.value_owned
;
1651 // create copy if necessary as captured variables may need to be kept alive
1652 CCodeExpression cparam
= get_variable_cexpression (param
.name
);
1653 if (param
.variable_type
.is_real_non_null_struct_type ()) {
1654 cparam
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cparam
);
1656 if (requires_copy (param_type
) && !param
.variable_type
.value_owned
&& !is_unowned_delegate
) {
1657 var ma
= new MemberAccess
.simple (param
.name
);
1658 ma
.symbol_reference
= param
;
1659 ma
.value_type
= param
.variable_type
.copy ();
1660 visit_member_access (ma
);
1661 // directly access parameters in ref expressions
1662 param
.captured
= false;
1663 cparam
= get_ref_cexpression (param
.variable_type
, cparam
, ma
, param
);
1664 param
.captured
= true;
1667 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_variable_cname (param
.name
)), cparam
));
1669 if (param
.variable_type is ArrayType
) {
1670 var array_type
= (ArrayType
) param
.variable_type
;
1671 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1672 data
.add_field ("gint", get_parameter_array_length_cname (param
, dim
));
1673 ccode
.add_expression (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
))));
1675 } else if (param
.variable_type is DelegateType
) {
1676 data
.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (param
.name
)));
1677 ccode
.add_expression (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
)))));
1678 if (param
.variable_type
.value_owned
) {
1679 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1680 ccode
.add_expression (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
)))));
1684 if (requires_destroy (param_type
) && !is_unowned_delegate
) {
1685 bool old_coroutine
= false;
1686 if (current_method
!= null) {
1687 old_coroutine
= current_method
.coroutine
;
1688 current_method
.coroutine
= false;
1691 var ma
= new MemberAccess
.simple (param
.name
);
1692 ma
.symbol_reference
= param
;
1693 ma
.value_type
= param_type
.copy ();
1694 visit_member_access (ma
);
1695 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
.variable_type
, ma
)));
1697 if (old_coroutine
) {
1698 current_method
.coroutine
= true;
1703 public override void visit_block (Block b
) {
1704 emit_context
.push_symbol (b
);
1706 var local_vars
= b
.get_local_variables ();
1708 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
) {
1709 ccode
.open_block ();
1713 var parent_block
= next_closure_block (b
.parent_symbol
);
1715 int block_id
= get_block_id (b
);
1716 string struct_name
= "Block%dData".printf (block_id
);
1718 var free_block
= new
CCodeBlock ();
1720 var data
= new
CCodeStruct ("_" + struct_name
);
1721 data
.add_field ("int", "_ref_count_");
1722 if (parent_block
!= null) {
1723 int parent_block_id
= get_block_id (parent_block
);
1725 data
.add_field ("Block%dData *".printf (parent_block_id
), "_data%d_".printf (parent_block_id
));
1727 var unref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (parent_block_id
)));
1728 unref_call
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)));
1729 free_block
.add_statement (new
CCodeExpressionStatement (unref_call
));
1731 if (in_constructor
|| (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) ||
1732 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
1733 data
.add_field ("%s *".printf (current_class
.get_cname ()), "self");
1735 var ma
= new MemberAccess
.simple ("this");
1736 ma
.symbol_reference
= current_class
;
1737 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
)));
1740 if (current_method
!= null) {
1741 // allow capturing generic type parameters
1742 foreach (var type_param
in current_method
.get_type_parameters ()) {
1745 func_name
= "%s_type".printf (type_param
.name
.down ());
1746 data
.add_field ("GType", func_name
);
1748 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
1749 data
.add_field ("GBoxedCopyFunc", func_name
);
1751 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
1752 data
.add_field ("GDestroyNotify", func_name
);
1756 foreach (var local
in local_vars
) {
1757 if (local
.captured
) {
1758 generate_type_declaration (local
.variable_type
, cfile
);
1760 data
.add_field (local
.variable_type
.get_cname (), get_variable_cname (local
.name
) + local
.variable_type
.get_cdeclarator_suffix ());
1762 if (local
.variable_type is ArrayType
) {
1763 var array_type
= (ArrayType
) local
.variable_type
;
1764 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1765 data
.add_field ("gint", get_array_length_cname (get_variable_cname (local
.name
), dim
));
1767 data
.add_field ("gint", get_array_size_cname (get_variable_cname (local
.name
)));
1768 } else if (local
.variable_type is DelegateType
) {
1769 data
.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (local
.name
)));
1770 if (local
.variable_type
.value_owned
) {
1771 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (local
.name
)));
1776 // free in reverse order
1777 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1778 var local
= local_vars
[i
];
1779 if (local
.captured
) {
1780 if (requires_destroy (local
.variable_type
)) {
1781 bool old_coroutine
= false;
1782 if (current_method
!= null) {
1783 old_coroutine
= current_method
.coroutine
;
1784 current_method
.coroutine
= false;
1787 var ma
= new MemberAccess
.simple (local
.name
);
1788 ma
.symbol_reference
= local
;
1789 ma
.value_type
= local
.variable_type
.copy ();
1790 visit_member_access (ma
);
1791 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
)));
1793 if (old_coroutine
) {
1794 current_method
.coroutine
= true;
1800 var data_alloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
1801 data_alloc
.add_argument (new
CCodeIdentifier (struct_name
));
1803 if (current_method
!= null && current_method
.coroutine
) {
1804 closure_struct
.add_field (struct_name
+ "*", "_data%d_".printf (block_id
));
1806 ccode
.add_declaration (struct_name
+ "*", new
CCodeVariableDeclarator ("_data%d_".printf (block_id
)));
1808 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression ("_data%d_".printf (block_id
)), data_alloc
));
1810 // initialize ref_count
1811 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_ref_count_"), new
CCodeIdentifier ("1")));
1813 if (parent_block
!= null) {
1814 int parent_block_id
= get_block_id (parent_block
);
1816 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (parent_block_id
)));
1817 ref_call
.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id
)));
1819 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)), ref_call
));
1821 if (in_constructor
|| (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
&&
1822 (!(current_method is CreationMethod
) || current_method
.body
!= b
)) ||
1823 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
1824 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (new
ObjectType (current_class
), b
.source_reference
));
1825 ref_call
.add_argument (get_result_cexpression ("self"));
1827 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "self"), ref_call
));
1830 if (current_method
!= null) {
1831 // allow capturing generic type parameters
1832 foreach (var type_param
in current_method
.get_type_parameters ()) {
1835 func_name
= "%s_type".printf (type_param
.name
.down ());
1836 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
)));
1838 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
1839 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
)));
1841 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
1842 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
)));
1847 if (b
.parent_symbol is Method
) {
1848 var m
= (Method
) b
.parent_symbol
;
1850 // parameters are captured with the top-level block of the method
1851 foreach (var param
in m
.get_parameters ()) {
1852 if (param
.captured
) {
1853 capture_parameter (param
, data
, block_id
, free_block
);
1858 // capture async data to allow invoking callback from inside closure
1859 data
.add_field ("gpointer", "_async_data_");
1861 // async method is suspended while waiting for callback,
1862 // so we never need to care about memory management of async data
1863 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_async_data_"), new
CCodeIdentifier ("data")));
1865 } else if (b
.parent_symbol is PropertyAccessor
) {
1866 var acc
= (PropertyAccessor
) b
.parent_symbol
;
1868 if (!acc
.readable
&& acc
.value_parameter
.captured
) {
1869 capture_parameter (acc
.value_parameter
, data
, block_id
, free_block
);
1873 var typedef
= new
CCodeTypeDefinition ("struct _" + struct_name
, new
CCodeVariableDeclarator (struct_name
));
1874 cfile
.add_type_declaration (typedef
);
1875 cfile
.add_type_definition (data
);
1877 var data_free
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_free"));
1878 data_free
.add_argument (new
CCodeIdentifier (struct_name
));
1879 data_free
.add_argument (new
CCodeIdentifier ("_data%d_".printf (block_id
)));
1880 free_block
.add_statement (new
CCodeExpressionStatement (data_free
));
1882 // create ref/unref functions
1883 var ref_fun
= new
CCodeFunction ("block%d_data_ref".printf (block_id
), struct_name
+ "*");
1884 ref_fun
.add_parameter (new
CCodeParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
1885 ref_fun
.modifiers
= CCodeModifiers
.STATIC
;
1886 cfile
.add_function_declaration (ref_fun
);
1887 ref_fun
.block
= new
CCodeBlock ();
1889 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_atomic_int_inc"));
1890 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_ref_count_")));
1891 ref_fun
.block
.add_statement (new
CCodeExpressionStatement (ccall
));
1892 ref_fun
.block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("_data%d_".printf (block_id
))));
1893 cfile
.add_function (ref_fun
);
1895 var unref_fun
= new
CCodeFunction ("block%d_data_unref".printf (block_id
), "void");
1896 unref_fun
.add_parameter (new
CCodeParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
1897 unref_fun
.modifiers
= CCodeModifiers
.STATIC
;
1898 cfile
.add_function_declaration (unref_fun
);
1899 unref_fun
.block
= new
CCodeBlock ();
1901 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_atomic_int_dec_and_test"));
1902 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_ref_count_")));
1903 unref_fun
.block
.add_statement (new
CCodeIfStatement (ccall
, free_block
));
1905 cfile
.add_function (unref_fun
);
1908 foreach (Statement stmt
in b
.get_statements ()) {
1912 // free in reverse order
1913 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1914 var local
= local_vars
[i
];
1915 local
.active
= false;
1916 if (!local
.unreachable
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
1917 var ma
= new MemberAccess
.simple (local
.name
);
1918 ma
.symbol_reference
= local
;
1919 ma
.value_type
= local
.variable_type
.copy ();
1920 visit_member_access (ma
);
1921 ccode
.add_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
1925 if (b
.parent_symbol is Method
) {
1926 var m
= (Method
) b
.parent_symbol
;
1927 foreach (Parameter param
in m
.get_parameters ()) {
1928 if (!param
.captured
&& !param
.ellipsis
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
1929 var ma
= new MemberAccess
.simple (param
.name
);
1930 ma
.symbol_reference
= param
;
1931 ma
.value_type
= param
.variable_type
.copy ();
1932 visit_member_access (ma
);
1933 ccode
.add_expression (get_unref_expression (get_variable_cexpression (param
.name
), param
.variable_type
, ma
));
1934 } else if (param
.direction
== ParameterDirection
.OUT
&& !m
.coroutine
) {
1935 return_out_parameter (param
);
1941 int block_id
= get_block_id (b
);
1943 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
1944 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
1945 ccode
.add_expression (data_unref
);
1948 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
) {
1952 emit_context
.pop_symbol ();
1955 public override void visit_declaration_statement (DeclarationStatement stmt
) {
1956 stmt
.declaration
.accept (this
);
1959 public CCodeExpression
get_variable_cexpression (string name
) {
1960 if (current_method
!= null && current_method
.coroutine
) {
1961 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_variable_cname (name
));
1963 return new
CCodeIdentifier (get_variable_cname (name
));
1967 public string get_variable_cname (string name
) {
1968 if (name
[0] == '.') {
1969 if (name
== ".result") {
1972 // compiler-internal variable
1973 if (!variable_name_map
.contains (name
)) {
1974 variable_name_map
.set (name
, "_tmp%d_".printf (next_temp_var_id
));
1977 return variable_name_map
.get (name
);
1978 } else if (reserved_identifiers
.contains (name
)) {
1979 return "_%s_".printf (name
);
1985 public CCodeExpression
get_result_cexpression (string cname
= "result") {
1986 if (current_method
!= null && current_method
.coroutine
) {
1987 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), cname
);
1989 return new
CCodeIdentifier (cname
);
1993 bool has_simple_struct_initializer (LocalVariable local
) {
1994 var st
= local
.variable_type
.data_type as Struct
;
1995 var initializer
= local
.initializer as ObjectCreationExpression
;
1996 if (st
!= null && (!st
.is_simple_type () || st
.get_cname () == "va_list") && !local
.variable_type
.nullable
&&
1997 initializer
!= null && initializer
.get_object_initializer ().size
== 0) {
2004 public override void visit_local_variable (LocalVariable local
) {
2005 check_type (local
.variable_type
);
2007 if (local
.initializer
!= null) {
2008 local
.initializer
.emit (this
);
2010 visit_end_full_expression (local
.initializer
);
2013 generate_type_declaration (local
.variable_type
, cfile
);
2015 if (!local
.captured
) {
2016 if (local
.variable_type is ArrayType
) {
2017 // create variables to store array dimensions
2018 var array_type
= (ArrayType
) local
.variable_type
;
2020 if (!array_type
.fixed_length
) {
2021 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2022 var len_var
= new
LocalVariable (int_type
.copy (), get_array_length_cname (get_variable_cname (local
.name
), dim
));
2023 emit_temp_var (len_var
);
2026 if (array_type
.rank
== 1) {
2027 var size_var
= new
LocalVariable (int_type
.copy (), get_array_size_cname (get_variable_cname (local
.name
)));
2028 emit_temp_var (size_var
);
2031 } else if (local
.variable_type is DelegateType
) {
2032 var deleg_type
= (DelegateType
) local
.variable_type
;
2033 var d
= deleg_type
.delegate_symbol
;
2035 // create variable to store delegate target
2036 var target_var
= new
LocalVariable (new
PointerType (new
VoidType ()), get_delegate_target_cname (get_variable_cname (local
.name
)));
2037 emit_temp_var (target_var
);
2038 if (deleg_type
.value_owned
) {
2039 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
)));
2040 emit_temp_var (target_destroy_notify_var
);
2046 CCodeExpression rhs
= null;
2047 if (local
.initializer
!= null && get_cvalue (local
.initializer
) != null) {
2048 var ma
= new MemberAccess
.simple (local
.name
);
2049 ma
.symbol_reference
= local
;
2050 ma
.value_type
= local
.variable_type
.copy ();
2051 visit_member_access (ma
);
2053 rhs
= get_cvalue (local
.initializer
);
2055 if (local
.variable_type is ArrayType
) {
2056 var array_type
= (ArrayType
) local
.variable_type
;
2058 if (array_type
.fixed_length
) {
2061 var temp_var
= get_temp_variable (local
.variable_type
, true, local
, false);
2062 emit_temp_var (temp_var
);
2063 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), rhs
));
2065 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2066 var lhs_array_len
= get_array_length_cexpression (ma
, dim
);
2067 var rhs_array_len
= get_array_length_cexpression (local
.initializer
, dim
);
2068 ccode
.add_expression (new
CCodeAssignment (lhs_array_len
, rhs_array_len
));
2070 if (array_type
.rank
== 1 && !local
.captured
) {
2071 var lhs_array_size
= get_array_size_cvalue (ma
.target_value
);
2072 var rhs_array_len
= get_array_length_cexpression (ma
, 1);
2073 ccode
.add_expression (new
CCodeAssignment (lhs_array_size
, rhs_array_len
));
2076 rhs
= get_variable_cexpression (temp_var
.name
);
2078 } else if (local
.variable_type is DelegateType
) {
2079 var deleg_type
= (DelegateType
) local
.variable_type
;
2080 var d
= deleg_type
.delegate_symbol
;
2082 var temp_var
= get_temp_variable (local
.variable_type
, true, local
, false);
2083 emit_temp_var (temp_var
);
2084 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), rhs
));
2086 CCodeExpression lhs_delegate_target_destroy_notify
;
2087 var lhs_delegate_target
= get_delegate_target_cexpression (ma
, out lhs_delegate_target_destroy_notify
);
2088 if (local
.captured
) {
2089 var block
= (Block
) local
.parent_symbol
;
2090 lhs_delegate_target
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_delegate_target_cname (local
.name
));
2092 CCodeExpression rhs_delegate_target_destroy_notify
;
2093 var rhs_delegate_target
= get_delegate_target_cexpression (local
.initializer
, out rhs_delegate_target_destroy_notify
);
2094 ccode
.add_expression (new
CCodeAssignment (lhs_delegate_target
, rhs_delegate_target
));
2096 if (deleg_type
.value_owned
) {
2097 if (local
.captured
) {
2098 var block
= (Block
) local
.parent_symbol
;
2099 lhs_delegate_target
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_delegate_target_destroy_notify_cname (local
.name
));
2101 ccode
.add_expression (new
CCodeAssignment (lhs_delegate_target_destroy_notify
, rhs_delegate_target_destroy_notify
));
2104 rhs
= get_variable_cexpression (temp_var
.name
);
2107 } else if (local
.variable_type
.is_reference_type_or_type_parameter ()) {
2108 rhs
= new
CCodeConstant ("NULL");
2110 if (local
.variable_type is ArrayType
) {
2111 // initialize array length variables
2112 var array_type
= (ArrayType
) local
.variable_type
;
2114 if (array_type
.fixed_length
) {
2117 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2118 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (get_array_length_cname (get_variable_cname (local
.name
), dim
)), new
CCodeConstant ("0")));
2124 if (local
.captured
) {
2125 if (local
.initializer
!= null) {
2126 if (has_simple_struct_initializer (local
)) {
2127 ccode
.add_expression (rhs
);
2129 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id ((Block
) local
.parent_symbol
))), get_variable_cname (local
.name
)), rhs
));
2132 } else if (current_method
!= null && current_method
.coroutine
) {
2133 closure_struct
.add_field (local
.variable_type
.get_cname (), get_variable_cname (local
.name
) + local
.variable_type
.get_cdeclarator_suffix ());
2135 if (local
.initializer
!= null) {
2136 if (has_simple_struct_initializer (local
)) {
2137 ccode
.add_expression (rhs
);
2139 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_variable_cname (local
.name
)), rhs
));
2143 CCodeExpression post_rhs
= null;
2144 if (has_simple_struct_initializer (local
)) {
2149 var cvar
= new
CCodeVariableDeclarator (get_variable_cname (local
.name
), rhs
, local
.variable_type
.get_cdeclarator_suffix ());
2151 cvar
.line
= rhs
.line
;
2154 // try to initialize uninitialized variables
2155 // initialization not necessary for variables stored in closure
2156 if (cvar
.initializer
== null) {
2157 cvar
.initializer
= default_value_for_type (local
.variable_type
, true);
2161 ccode
.add_declaration (local
.variable_type
.get_cname (), cvar
);
2163 if (cvar
.initializer
!= null && !cvar
.init0
) {
2164 cvar
.initializer
= null;
2165 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (local
.name
), rhs
));
2168 if (post_rhs
!= null) {
2169 ccode
.add_expression (post_rhs
);
2173 if (local
.initializer
!= null && local
.variable_type is ArrayType
) {
2174 var array_type
= (ArrayType
) local
.variable_type
;
2176 if (array_type
.fixed_length
) {
2177 cfile
.add_include ("string.h");
2179 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
2180 // simple assignments do not work in C
2181 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
2182 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
2183 var size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
);
2185 var ccopy
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
2186 ccopy
.add_argument (get_variable_cexpression (local
.name
));
2187 ccopy
.add_argument (get_cvalue (local
.initializer
));
2188 ccopy
.add_argument (size
);
2189 ccode
.add_expression (ccopy
);
2193 if (local
.initializer
!= null && local
.initializer
.tree_can_fail
) {
2194 add_simple_check (local
.initializer
);
2197 local
.active
= true;
2200 public override void visit_initializer_list (InitializerList list
) {
2201 if (list
.target_type
.data_type is Struct
) {
2202 /* initializer is used as struct initializer */
2203 var st
= (Struct
) list
.target_type
.data_type
;
2205 if (list
.parent_node is Constant
|| list
.parent_node is Field
|| list
.parent_node is InitializerList
) {
2206 var clist
= new
CCodeInitializerList ();
2208 var field_it
= st
.get_fields ().iterator ();
2209 foreach (Expression expr
in list
.get_initializers ()) {
2211 while (field
== null) {
2213 field
= field_it
.get ();
2214 if (field
.binding
!= MemberBinding
.INSTANCE
) {
2215 // we only initialize instance fields
2220 var cexpr
= get_cvalue (expr
);
2222 string ctype
= field
.get_ctype ();
2223 if (ctype
!= null) {
2224 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
2227 clist
.append (cexpr
);
2230 set_cvalue (list
, clist
);
2232 // used as expression
2233 var temp_decl
= get_temp_variable (list
.target_type
, false, list
);
2234 emit_temp_var (temp_decl
);
2236 var instance
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
2238 var ccomma
= new
CCodeCommaExpression ();
2240 var field_it
= st
.get_fields ().iterator ();
2241 foreach (Expression expr
in list
.get_initializers ()) {
2243 while (field
== null) {
2245 field
= field_it
.get ();
2246 if (field
.binding
!= MemberBinding
.INSTANCE
) {
2247 // we only initialize instance fields
2252 var cexpr
= get_cvalue (expr
);
2254 string ctype
= field
.get_ctype ();
2255 if (ctype
!= null) {
2256 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
2259 var lhs
= new
CCodeMemberAccess (instance
, field
.get_cname ());;
2260 ccomma
.append_expression (new
CCodeAssignment (lhs
, cexpr
));
2263 ccomma
.append_expression (instance
);
2264 set_cvalue (list
, ccomma
);
2267 var clist
= new
CCodeInitializerList ();
2268 foreach (Expression expr
in list
.get_initializers ()) {
2269 clist
.append (get_cvalue (expr
));
2271 set_cvalue (list
, clist
);
2275 public override LocalVariable
create_local (DataType type
) {
2276 var result
= get_temp_variable (type
, type
.value_owned
);
2277 emit_temp_var (result
);
2281 public LocalVariable
get_temp_variable (DataType type
, bool value_owned
= true, CodeNode? node_reference
= null, bool init
= true) {
2282 var var_type
= type
.copy ();
2283 var_type
.value_owned
= value_owned
;
2284 var local
= new
LocalVariable (var_type
, "_tmp%d_".printf (next_temp_var_id
));
2285 local
.no_init
= !init
;
2287 if (node_reference
!= null) {
2288 local
.source_reference
= node_reference
.source_reference
;
2296 bool is_in_generic_type (DataType type
) {
2297 if (current_symbol
!= null && type
.type_parameter
.parent_symbol is TypeSymbol
2298 && (current_method
== null || current_method
.binding
== MemberBinding
.INSTANCE
)) {
2305 public CCodeExpression
get_type_id_expression (DataType type
, bool is_chainup
= false) {
2306 if (type is GenericType
) {
2307 string var_name
= "%s_type".printf (type
.type_parameter
.name
.down ());
2308 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2309 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), var_name
);
2311 return new
CCodeIdentifier (var_name
);
2314 string type_id
= type
.get_type_id ();
2315 if (type_id
== null) {
2316 type_id
= "G_TYPE_INVALID";
2318 generate_type_declaration (type
, cfile
);
2320 return new
CCodeIdentifier (type_id
);
2324 public virtual CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
, bool is_chainup
= false) {
2325 if (type is ErrorType
) {
2326 return new
CCodeIdentifier ("g_error_copy");
2327 } else if (type
.data_type
!= null) {
2328 string dup_function
;
2329 var cl
= type
.data_type as Class
;
2330 if (type
.data_type
.is_reference_counting ()) {
2331 dup_function
= type
.data_type
.get_ref_function ();
2332 if (type
.data_type is Interface
&& dup_function
== null) {
2333 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 ()));
2336 } else if (cl
!= null && cl
.is_immutable
) {
2337 // allow duplicates of immutable instances as for example strings
2338 dup_function
= type
.data_type
.get_dup_function ();
2339 if (dup_function
== null) {
2342 } else if (cl
!= null && cl
.is_gboxed
) {
2343 // allow duplicates of gboxed instances
2344 dup_function
= generate_dup_func_wrapper (type
);
2345 if (dup_function
== null) {
2348 } else if (type is ValueType
) {
2349 dup_function
= type
.data_type
.get_dup_function ();
2350 if (dup_function
== null && type
.nullable
) {
2351 dup_function
= generate_struct_dup_wrapper ((ValueType
) type
);
2352 } else if (dup_function
== null) {
2356 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2357 Report
.error (source_reference
, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type
.data_type
.name
));
2361 return new
CCodeIdentifier (dup_function
);
2362 } else if (type
.type_parameter
!= null) {
2363 string func_name
= "%s_dup_func".printf (type
.type_parameter
.name
.down ());
2364 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2365 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), func_name
);
2367 return new
CCodeIdentifier (func_name
);
2369 } else if (type is PointerType
) {
2370 var pointer_type
= (PointerType
) type
;
2371 return get_dup_func_expression (pointer_type
.base_type
, source_reference
);
2373 return new
CCodeConstant ("NULL");
2377 void make_comparable_cexpression (ref DataType left_type
, ref CCodeExpression cleft
, ref DataType right_type
, ref CCodeExpression cright
) {
2378 var left_type_as_struct
= left_type
.data_type as Struct
;
2379 var right_type_as_struct
= right_type
.data_type as Struct
;
2382 var valuecast
= try_cast_value_to_type (cleft
, left_type
, right_type
);
2383 if (valuecast
!= null) {
2385 left_type
= right_type
;
2386 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
2390 valuecast
= try_cast_value_to_type (cright
, right_type
, left_type
);
2391 if (valuecast
!= null) {
2393 right_type
= left_type
;
2394 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
2398 if (left_type
.data_type is Class
&& !((Class
) left_type
.data_type
).is_compact
&&
2399 right_type
.data_type is Class
&& !((Class
) right_type
.data_type
).is_compact
) {
2400 var left_cl
= (Class
) left_type
.data_type
;
2401 var right_cl
= (Class
) right_type
.data_type
;
2403 if (left_cl
!= right_cl
) {
2404 if (left_cl
.is_subtype_of (right_cl
)) {
2405 cleft
= generate_instance_cast (cleft
, right_cl
);
2406 } else if (right_cl
.is_subtype_of (left_cl
)) {
2407 cright
= generate_instance_cast (cright
, left_cl
);
2410 } else if (left_type_as_struct
!= null && right_type_as_struct
!= null) {
2411 if (left_type is StructValueType
) {
2412 // real structs (uses compare/equal function)
2413 if (!left_type
.nullable
) {
2414 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cleft
);
2416 if (!right_type
.nullable
) {
2417 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cright
);
2420 // integer or floating or boolean type
2421 if (left_type
.nullable
&& right_type
.nullable
) {
2422 // FIXME also compare contents, not just address
2423 } else if (left_type
.nullable
) {
2424 // FIXME check left value is not null
2425 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cleft
);
2426 } else if (right_type
.nullable
) {
2427 // FIXME check right value is not null
2428 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cright
);
2434 private string generate_struct_equal_function (Struct st
) {
2435 string equal_func
= "_%sequal".printf (st
.get_lower_case_cprefix ());
2437 if (!add_wrapper (equal_func
)) {
2438 // wrapper already defined
2442 var function
= new
CCodeFunction (equal_func
, "gboolean");
2443 function
.modifiers
= CCodeModifiers
.STATIC
;
2445 function
.add_parameter (new
CCodeParameter ("s1", "const " + st
.get_cname () + "*"));
2446 function
.add_parameter (new
CCodeParameter ("s2", "const " + st
.get_cname () + "*"));
2448 push_function (function
);
2450 // if (s1 == s2) return TRUE;
2452 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
2453 ccode
.open_if (cexp
);
2454 ccode
.add_return (new
CCodeConstant ("TRUE"));
2457 // if (s1 == NULL || s2 == NULL) return FALSE;
2459 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeConstant ("NULL"));
2460 ccode
.open_if (cexp
);
2461 ccode
.add_return (new
CCodeConstant ("FALSE"));
2464 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s2"), new
CCodeConstant ("NULL"));
2465 ccode
.open_if (cexp
);
2466 ccode
.add_return (new
CCodeConstant ("FALSE"));
2470 foreach (Field f
in st
.get_fields ()) {
2471 if (f
.binding
!= MemberBinding
.INSTANCE
) {
2472 // we only compare instance fields
2476 CCodeExpression cexp
; // if (cexp) return FALSE;
2477 var s1
= (CCodeExpression
) new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("s1"), f
.name
); // s1->f
2478 var s2
= (CCodeExpression
) new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("s2"), f
.name
); // s2->f
2480 var variable_type
= f
.variable_type
.copy ();
2481 make_comparable_cexpression (ref variable_type
, ref s1
, ref variable_type
, ref s2
);
2483 if (!(f
.variable_type is NullType
) && f
.variable_type
.compatible (string_type
)) {
2484 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
2485 ccall
.add_argument (s1
);
2486 ccall
.add_argument (s2
);
2488 } else if (f
.variable_type is StructValueType
) {
2489 var equalfunc
= generate_struct_equal_function (f
.variable_type
.data_type as Struct
);
2490 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
2491 ccall
.add_argument (s1
);
2492 ccall
.add_argument (s2
);
2493 cexp
= new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, ccall
);
2495 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, s1
, s2
);
2498 ccode
.open_if (cexp
);
2499 ccode
.add_return (new
CCodeConstant ("FALSE"));
2503 if (st
.get_fields().size
== 0) {
2504 // either opaque structure or simple type
2505 if (st
.is_simple_type ()) {
2506 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s1")), new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s2")));
2507 ccode
.add_return (cexp
);
2509 ccode
.add_return (new
CCodeConstant ("FALSE"));
2512 ccode
.add_return (new
CCodeConstant ("TRUE"));
2517 cfile
.add_function_declaration (function
);
2518 cfile
.add_function (function
);
2523 private string generate_numeric_equal_function (Struct st
) {
2524 string equal_func
= "_%sequal".printf (st
.get_lower_case_cprefix ());
2526 if (!add_wrapper (equal_func
)) {
2527 // wrapper already defined
2531 var function
= new
CCodeFunction (equal_func
, "gboolean");
2532 function
.modifiers
= CCodeModifiers
.STATIC
;
2534 function
.add_parameter (new
CCodeParameter ("s1", "const " + st
.get_cname () + "*"));
2535 function
.add_parameter (new
CCodeParameter ("s2", "const " + st
.get_cname () + "*"));
2537 push_function (function
);
2539 // if (s1 == s2) return TRUE;
2541 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
2542 ccode
.open_if (cexp
);
2543 ccode
.add_return (new
CCodeConstant ("TRUE"));
2546 // if (s1 == NULL || s2 == NULL) return FALSE;
2548 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeConstant ("NULL"));
2549 ccode
.open_if (cexp
);
2550 ccode
.add_return (new
CCodeConstant ("FALSE"));
2553 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s2"), new
CCodeConstant ("NULL"));
2554 ccode
.open_if (cexp
);
2555 ccode
.add_return (new
CCodeConstant ("FALSE"));
2558 // return (*s1 == *s2);
2560 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s1")), new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s2")));
2561 ccode
.add_return (cexp
);
2566 cfile
.add_function_declaration (function
);
2567 cfile
.add_function (function
);
2572 private string generate_struct_dup_wrapper (ValueType value_type
) {
2573 string dup_func
= "_%sdup".printf (value_type
.type_symbol
.get_lower_case_cprefix ());
2575 if (!add_wrapper (dup_func
)) {
2576 // wrapper already defined
2580 var function
= new
CCodeFunction (dup_func
, value_type
.get_cname ());
2581 function
.modifiers
= CCodeModifiers
.STATIC
;
2583 function
.add_parameter (new
CCodeParameter ("self", value_type
.get_cname ()));
2585 push_function (function
);
2587 if (value_type
.type_symbol
== gvalue_type
) {
2588 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_copy"));
2589 dup_call
.add_argument (new
CCodeIdentifier ("G_TYPE_VALUE"));
2590 dup_call
.add_argument (new
CCodeIdentifier ("self"));
2592 ccode
.add_return (dup_call
);
2594 ccode
.add_declaration (value_type
.get_cname (), new
CCodeVariableDeclarator ("dup"));
2596 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
2597 creation_call
.add_argument (new
CCodeConstant (value_type
.data_type
.get_cname ()));
2598 creation_call
.add_argument (new
CCodeConstant ("1"));
2599 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("dup"), creation_call
));
2601 var st
= value_type
.data_type as Struct
;
2602 if (st
!= null && st
.is_disposable ()) {
2603 if (!st
.has_copy_function
) {
2604 generate_struct_copy_function (st
);
2607 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_copy_function ()));
2608 copy_call
.add_argument (new
CCodeIdentifier ("self"));
2609 copy_call
.add_argument (new
CCodeIdentifier ("dup"));
2610 ccode
.add_expression (copy_call
);
2612 cfile
.add_include ("string.h");
2614 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
2615 sizeof_call
.add_argument (new
CCodeConstant (value_type
.data_type
.get_cname ()));
2617 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
2618 copy_call
.add_argument (new
CCodeIdentifier ("dup"));
2619 copy_call
.add_argument (new
CCodeIdentifier ("self"));
2620 copy_call
.add_argument (sizeof_call
);
2621 ccode
.add_expression (copy_call
);
2624 ccode
.add_return (new
CCodeIdentifier ("dup"));
2629 cfile
.add_function_declaration (function
);
2630 cfile
.add_function (function
);
2635 protected string generate_dup_func_wrapper (DataType type
) {
2636 string destroy_func
= "_vala_%s_copy".printf (type
.data_type
.get_cname ());
2638 if (!add_wrapper (destroy_func
)) {
2639 // wrapper already defined
2640 return destroy_func
;
2643 var function
= new
CCodeFunction (destroy_func
, type
.get_cname ());
2644 function
.modifiers
= CCodeModifiers
.STATIC
;
2645 function
.add_parameter (new
CCodeParameter ("self", type
.get_cname ()));
2647 push_function (function
);
2649 var cl
= type
.data_type as Class
;
2650 assert (cl
!= null && cl
.is_gboxed
);
2652 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_copy"));
2653 free_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
2654 free_call
.add_argument (new
CCodeIdentifier ("self"));
2656 ccode
.add_return (free_call
);
2660 cfile
.add_function_declaration (function
);
2661 cfile
.add_function (function
);
2663 return destroy_func
;
2666 protected string generate_free_func_wrapper (DataType type
) {
2667 string destroy_func
= "_vala_%s_free".printf (type
.data_type
.get_cname ());
2669 if (!add_wrapper (destroy_func
)) {
2670 // wrapper already defined
2671 return destroy_func
;
2674 var function
= new
CCodeFunction (destroy_func
, "void");
2675 function
.modifiers
= CCodeModifiers
.STATIC
;
2676 function
.add_parameter (new
CCodeParameter ("self", type
.get_cname ()));
2678 push_function (function
);
2680 var cl
= type
.data_type as Class
;
2681 if (cl
!= null && cl
.is_gboxed
) {
2682 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_free"));
2683 free_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
2684 free_call
.add_argument (new
CCodeIdentifier ("self"));
2686 ccode
.add_expression (free_call
);
2687 } else if (cl
!= null) {
2688 assert (cl
.free_function_address_of
);
2690 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier (type
.data_type
.get_free_function ()));
2691 free_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("self")));
2693 ccode
.add_expression (free_call
);
2695 var st
= type
.data_type as Struct
;
2696 if (st
!= null && st
.is_disposable ()) {
2697 if (!st
.has_destroy_function
) {
2698 generate_struct_destroy_function (st
);
2701 var destroy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_destroy_function ()));
2702 destroy_call
.add_argument (new
CCodeIdentifier ("self"));
2703 ccode
.add_expression (destroy_call
);
2706 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
2707 free_call
.add_argument (new
CCodeIdentifier ("self"));
2709 ccode
.add_expression (free_call
);
2714 cfile
.add_function_declaration (function
);
2715 cfile
.add_function (function
);
2717 return destroy_func
;
2720 public CCodeExpression?
get_destroy0_func_expression (DataType type
, bool is_chainup
= false) {
2721 var element_destroy_func_expression
= get_destroy_func_expression (type
, is_chainup
);
2723 if (element_destroy_func_expression is CCodeIdentifier
) {
2724 var freeid
= (CCodeIdentifier
) element_destroy_func_expression
;
2725 string free0_func
= "_%s0_".printf (freeid
.name
);
2727 if (add_wrapper (free0_func
)) {
2728 var function
= new
CCodeFunction (free0_func
, "void");
2729 function
.modifiers
= CCodeModifiers
.STATIC
;
2731 function
.add_parameter (new
CCodeParameter ("var", "gpointer"));
2733 push_function (function
);
2735 ccode
.add_expression (get_unref_expression (new
CCodeIdentifier ("var"), type
, null, true));
2739 cfile
.add_function_declaration (function
);
2740 cfile
.add_function (function
);
2743 element_destroy_func_expression
= new
CCodeIdentifier (free0_func
);
2746 return element_destroy_func_expression
;
2749 public CCodeExpression?
get_destroy_func_expression (DataType type
, bool is_chainup
= false) {
2750 if (context
.profile
== Profile
.GOBJECT
&& (type
.data_type
== glist_type
|| type
.data_type
== gslist_type
|| type
.data_type
== gnode_type
)) {
2751 // create wrapper function to free list elements if necessary
2753 bool elements_require_free
= false;
2754 CCodeExpression element_destroy_func_expression
= null;
2756 foreach (DataType type_arg
in type
.get_type_arguments ()) {
2757 elements_require_free
= requires_destroy (type_arg
);
2758 if (elements_require_free
) {
2759 element_destroy_func_expression
= get_destroy0_func_expression (type_arg
);
2763 if (elements_require_free
&& element_destroy_func_expression is CCodeIdentifier
) {
2764 return new
CCodeIdentifier (generate_collection_free_wrapper (type
, (CCodeIdentifier
) element_destroy_func_expression
));
2766 return new
CCodeIdentifier (type
.data_type
.get_free_function ());
2768 } else if (type is ErrorType
) {
2769 return new
CCodeIdentifier ("g_error_free");
2770 } else if (type
.data_type
!= null) {
2771 string unref_function
;
2772 if (type is ReferenceType
) {
2773 if (type
.data_type
.is_reference_counting ()) {
2774 unref_function
= type
.data_type
.get_unref_function ();
2775 if (type
.data_type is Interface
&& unref_function
== null) {
2776 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 ()));
2780 var cl
= type
.data_type as Class
;
2781 if (cl
!= null && (cl
.free_function_address_of
|| cl
.is_gboxed
)) {
2782 unref_function
= generate_free_func_wrapper (type
);
2784 unref_function
= type
.data_type
.get_free_function ();
2788 if (type
.nullable
) {
2789 unref_function
= type
.data_type
.get_free_function ();
2790 if (unref_function
== null) {
2791 if (type
.data_type is Struct
&& ((Struct
) type
.data_type
).is_disposable ()) {
2792 unref_function
= generate_free_func_wrapper (type
);
2794 unref_function
= "g_free";
2798 var st
= (Struct
) type
.data_type
;
2799 if (!st
.has_destroy_function
) {
2800 generate_struct_destroy_function (st
);
2802 unref_function
= st
.get_destroy_function ();
2805 if (unref_function
== null) {
2806 return new
CCodeConstant ("NULL");
2808 return new
CCodeIdentifier (unref_function
);
2809 } else if (type
.type_parameter
!= null && current_type_symbol is Class
) {
2810 string func_name
= "%s_destroy_func".printf (type
.type_parameter
.name
.down ());
2811 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2812 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), func_name
);
2814 return new
CCodeIdentifier (func_name
);
2816 } else if (type is ArrayType
) {
2817 if (context
.profile
== Profile
.POSIX
) {
2818 return new
CCodeIdentifier ("free");
2820 return new
CCodeIdentifier ("g_free");
2822 } else if (type is PointerType
) {
2823 if (context
.profile
== Profile
.POSIX
) {
2824 return new
CCodeIdentifier ("free");
2826 return new
CCodeIdentifier ("g_free");
2829 return new
CCodeConstant ("NULL");
2833 private string generate_collection_free_wrapper (DataType collection_type
, CCodeIdentifier element_destroy_func_expression
) {
2834 string destroy_func
= "_%s_%s".printf (collection_type
.data_type
.get_free_function (), element_destroy_func_expression
.name
);
2836 if (!add_wrapper (destroy_func
)) {
2837 // wrapper already defined
2838 return destroy_func
;
2841 var function
= new
CCodeFunction (destroy_func
, "void");
2842 function
.modifiers
= CCodeModifiers
.STATIC
;
2844 function
.add_parameter (new
CCodeParameter ("self", collection_type
.get_cname ()));
2846 push_function (function
);
2848 CCodeFunctionCall element_free_call
;
2849 if (collection_type
.data_type
== gnode_type
) {
2850 /* A wrapper which converts GNodeTraverseFunc into GDestroyNotify */
2851 string destroy_node_func
= "%s_node".printf (destroy_func
);
2852 var wrapper
= new
CCodeFunction (destroy_node_func
, "gboolean");
2853 wrapper
.modifiers
= CCodeModifiers
.STATIC
;
2854 wrapper
.add_parameter (new
CCodeParameter ("node", collection_type
.get_cname ()));
2855 wrapper
.add_parameter (new
CCodeParameter ("unused", "gpointer"));
2856 var wrapper_block
= new
CCodeBlock ();
2857 var free_call
= new
CCodeFunctionCall (element_destroy_func_expression
);
2858 free_call
.add_argument (new CCodeMemberAccess
.pointer(new
CCodeIdentifier("node"), "data"));
2859 wrapper_block
.add_statement (new
CCodeExpressionStatement (free_call
));
2860 wrapper_block
.add_statement (new
CCodeReturnStatement (new
CCodeConstant ("FALSE")));
2861 cfile
.add_function_declaration (function
);
2862 wrapper
.block
= wrapper_block
;
2863 cfile
.add_function (wrapper
);
2865 /* Now the code to call g_traverse with the above */
2866 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_node_traverse"));
2867 element_free_call
.add_argument (new
CCodeIdentifier("self"));
2868 element_free_call
.add_argument (new
CCodeConstant ("G_POST_ORDER"));
2869 element_free_call
.add_argument (new
CCodeConstant ("G_TRAVERSE_ALL"));
2870 element_free_call
.add_argument (new
CCodeConstant ("-1"));
2871 element_free_call
.add_argument (new
CCodeIdentifier (destroy_node_func
));
2872 element_free_call
.add_argument (new
CCodeConstant ("NULL"));
2874 if (collection_type
.data_type
== glist_type
) {
2875 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_list_foreach"));
2877 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slist_foreach"));
2880 element_free_call
.add_argument (new
CCodeIdentifier ("self"));
2881 element_free_call
.add_argument (new
CCodeCastExpression (element_destroy_func_expression
, "GFunc"));
2882 element_free_call
.add_argument (new
CCodeConstant ("NULL"));
2885 ccode
.add_expression (element_free_call
);
2887 var cfreecall
= new
CCodeFunctionCall (new
CCodeIdentifier (collection_type
.data_type
.get_free_function ()));
2888 cfreecall
.add_argument (new
CCodeIdentifier ("self"));
2889 ccode
.add_expression (cfreecall
);
2893 cfile
.add_function_declaration (function
);
2894 cfile
.add_function (function
);
2896 return destroy_func
;
2899 public virtual string?
append_struct_array_free (Struct st
) {
2903 public CCodeExpression
get_unref_expression (CCodeExpression cvar
, DataType type
, Expression? expr
, bool is_macro_definition
= false) {
2904 var value
= new
GLibValue (type
, cvar
);
2905 if (expr
!= null && expr
.target_value
!= null) {
2906 value
.array_length_cvalues
= ((GLibValue
) expr
.target_value
).array_length_cvalues
;
2907 value
.delegate_target_cvalue
= get_delegate_target_cvalue (expr
.target_value
);
2908 value
.delegate_target_destroy_notify_cvalue
= get_delegate_target_destroy_notify_cvalue (expr
.target_value
);
2910 return destroy_value (value
, is_macro_definition
);
2913 public virtual CCodeExpression
destroy_value (TargetValue value
, bool is_macro_definition
= false) {
2914 var type
= value
.value_type
;
2915 var cvar
= get_cvalue_ (value
);
2917 if (type is DelegateType
) {
2918 var delegate_target
= get_delegate_target_cvalue (value
);
2919 var delegate_target_destroy_notify
= get_delegate_target_destroy_notify_cvalue (value
);
2921 var ccall
= new
CCodeFunctionCall (delegate_target_destroy_notify
);
2922 ccall
.add_argument (delegate_target
);
2924 var destroy_call
= new
CCodeCommaExpression ();
2925 destroy_call
.append_expression (ccall
);
2926 destroy_call
.append_expression (new
CCodeConstant ("NULL"));
2928 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, delegate_target_destroy_notify
, new
CCodeConstant ("NULL"));
2930 var ccomma
= new
CCodeCommaExpression ();
2931 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), destroy_call
));
2932 ccomma
.append_expression (new
CCodeAssignment (cvar
, new
CCodeConstant ("NULL")));
2933 ccomma
.append_expression (new
CCodeAssignment (delegate_target
, new
CCodeConstant ("NULL")));
2934 ccomma
.append_expression (new
CCodeAssignment (delegate_target_destroy_notify
, new
CCodeConstant ("NULL")));
2939 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
2941 if (type is ValueType
&& !type
.nullable
) {
2942 // normal value type, no null check
2943 var st
= type
.data_type as Struct
;
2944 if (st
!= null && st
.is_simple_type ()) {
2946 ccall
.add_argument (cvar
);
2948 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
2951 if (gvalue_type
!= null && type
.data_type
== gvalue_type
) {
2952 // g_value_unset must not be called for already unset values
2953 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
2954 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
2956 var ccomma
= new
CCodeCommaExpression ();
2957 ccomma
.append_expression (ccall
);
2958 ccomma
.append_expression (new
CCodeConstant ("NULL"));
2960 return new
CCodeConditionalExpression (cisvalid
, ccomma
, new
CCodeConstant ("NULL"));
2966 if (ccall
.call is CCodeIdentifier
&& !(type is ArrayType
) && !is_macro_definition
) {
2967 // generate and use NULL-aware free macro to simplify code
2969 var freeid
= (CCodeIdentifier
) ccall
.call
;
2970 string free0_func
= "_%s0".printf (freeid
.name
);
2972 if (add_wrapper (free0_func
)) {
2973 var macro
= destroy_value (new
GLibValue (type
, new
CCodeIdentifier ("var")), true);
2974 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("%s(var)".printf (free0_func
), macro
));
2977 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (free0_func
));
2978 ccall
.add_argument (cvar
);
2982 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
2984 /* can be simplified to
2985 * foo = (unref (foo), NULL)
2986 * if foo is of static type non-null
2989 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cvar
, new
CCodeConstant ("NULL"));
2990 if (type
.type_parameter
!= null) {
2991 if (!(current_type_symbol is Class
) || current_class
.is_compact
) {
2992 return new
CCodeConstant ("NULL");
2995 // unref functions are optional for type parameters
2996 var cunrefisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_destroy_func_expression (type
), new
CCodeConstant ("NULL"));
2997 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cunrefisnull
);
3000 ccall
.add_argument (cvar
);
3002 /* set freed references to NULL to prevent further use */
3003 var ccomma
= new
CCodeCommaExpression ();
3005 if (context
.profile
== Profile
.GOBJECT
) {
3006 if (type
.data_type
!= null && !type
.data_type
.is_reference_counting () &&
3007 (type
.data_type
== gstringbuilder_type
3008 || type
.data_type
== garray_type
3009 || type
.data_type
== gbytearray_type
3010 || type
.data_type
== gptrarray_type
)) {
3011 ccall
.add_argument (new
CCodeConstant ("TRUE"));
3012 } else if (type
.data_type
== gthreadpool_type
) {
3013 ccall
.add_argument (new
CCodeConstant ("FALSE"));
3014 ccall
.add_argument (new
CCodeConstant ("TRUE"));
3015 } else if (type is ArrayType
) {
3016 var array_type
= (ArrayType
) type
;
3017 if (requires_destroy (array_type
.element_type
)) {
3018 CCodeExpression csizeexpr
= null;
3020 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3022 csizeexpr
= get_array_length_cvalue (value
, dim
);
3025 csizeexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeexpr
, get_array_length_cvalue (value
, dim
));
3029 var st
= array_type
.element_type
.data_type as Struct
;
3030 if (st
!= null && !array_type
.element_type
.nullable
) {
3031 ccall
.call
= new
CCodeIdentifier (append_struct_array_free (st
));
3032 ccall
.add_argument (csizeexpr
);
3034 requires_array_free
= true;
3035 ccall
.call
= new
CCodeIdentifier ("_vala_array_free");
3036 ccall
.add_argument (csizeexpr
);
3037 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
3043 ccomma
.append_expression (ccall
);
3044 ccomma
.append_expression (new
CCodeConstant ("NULL"));
3046 var cassign
= new
CCodeAssignment (cvar
, ccomma
);
3048 // g_free (NULL) is allowed
3049 bool uses_gfree
= (type
.data_type
!= null && !type
.data_type
.is_reference_counting () && type
.data_type
.get_free_function () == "g_free");
3050 uses_gfree
= uses_gfree
|| type is ArrayType
;
3055 return new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), cassign
);
3058 public override void visit_end_full_expression (Expression expr
) {
3059 /* expr is a full expression, i.e. an initializer, the
3060 * expression in an expression statement, the controlling
3061 * expression in if, while, for, or foreach statements
3063 * we unref temporary variables at the end of a full
3066 if (((List
<LocalVariable
>) temp_ref_vars
).size
== 0) {
3067 /* nothing to do without temporary variables */
3071 var expr_list
= new
CCodeCommaExpression ();
3073 LocalVariable full_expr_var
= null;
3075 var local_decl
= expr
.parent_node as LocalVariable
;
3076 if (local_decl
!= null && has_simple_struct_initializer (local_decl
)) {
3077 expr_list
.append_expression (get_cvalue (expr
));
3079 var expr_type
= expr
.value_type
;
3080 if (expr
.target_type
!= null) {
3081 expr_type
= expr
.target_type
;
3084 full_expr_var
= get_temp_variable (expr_type
, true, expr
, false);
3085 emit_temp_var (full_expr_var
);
3087 expr_list
.append_expression (new
CCodeAssignment (get_variable_cexpression (full_expr_var
.name
), get_cvalue (expr
)));
3090 foreach (LocalVariable local
in temp_ref_vars
) {
3091 var ma
= new MemberAccess
.simple (local
.name
);
3092 ma
.symbol_reference
= local
;
3093 ma
.value_type
= local
.variable_type
.copy ();
3094 visit_member_access (ma
);
3095 expr_list
.append_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
3098 if (full_expr_var
!= null) {
3099 expr_list
.append_expression (get_variable_cexpression (full_expr_var
.name
));
3102 set_cvalue (expr
, expr_list
);
3104 temp_ref_vars
.clear ();
3107 public void emit_temp_var (LocalVariable local
) {
3108 var vardecl
= new
CCodeVariableDeclarator (local
.name
, null, local
.variable_type
.get_cdeclarator_suffix ());
3110 var st
= local
.variable_type
.data_type as Struct
;
3111 var array_type
= local
.variable_type as ArrayType
;
3113 if (local
.name
.has_prefix ("*")) {
3114 // do not dereference unintialized variable
3115 // initialization is not needed for these special
3116 // pointer temp variables
3117 // used to avoid side-effects in assignments
3118 } else if (local
.no_init
) {
3119 // no initialization necessary for this temp var
3120 } else if (!local
.variable_type
.nullable
&&
3121 (st
!= null && !st
.is_simple_type ()) ||
3122 (array_type
!= null && array_type
.fixed_length
)) {
3123 // 0-initialize struct with struct initializer { 0 }
3124 // necessary as they will be passed by reference
3125 var clist
= new
CCodeInitializerList ();
3126 clist
.append (new
CCodeConstant ("0"));
3128 vardecl
.initializer
= clist
;
3129 vardecl
.init0
= true;
3130 } else if (local
.variable_type
.is_reference_type_or_type_parameter () ||
3131 local
.variable_type
.nullable
||
3132 local
.variable_type is DelegateType
) {
3133 vardecl
.initializer
= new
CCodeConstant ("NULL");
3134 vardecl
.init0
= true;
3137 if (current_method
!= null && current_method
.coroutine
) {
3138 closure_struct
.add_field (local
.variable_type
.get_cname (), local
.name
);
3140 // even though closure struct is zerod, we need to initialize temporary variables
3141 // as they might be used multiple times when declared in a loop
3143 if (vardecl
.initializer is CCodeInitializerList
) {
3144 // C does not support initializer lists in assignments, use memset instead
3145 cfile
.add_include ("string.h");
3146 var memset_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
3147 memset_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (local
.name
)));
3148 memset_call
.add_argument (new
CCodeConstant ("0"));
3149 memset_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (local
.variable_type
.get_cname ())));
3150 ccode
.add_expression (memset_call
);
3151 } else if (vardecl
.initializer
!= null) {
3152 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (local
.name
), vardecl
.initializer
));
3155 ccode
.add_declaration (local
.variable_type
.get_cname (), vardecl
);
3159 public override void visit_expression_statement (ExpressionStatement stmt
) {
3160 if (stmt
.expression
.error
) {
3165 if (get_cvalue (stmt
.expression
) != null) {
3166 ccode
.add_expression (get_cvalue (stmt
.expression
));
3169 /* free temporary objects and handle errors */
3171 foreach (LocalVariable local
in temp_ref_vars
) {
3172 var ma
= new MemberAccess
.simple (local
.name
);
3173 ma
.symbol_reference
= local
;
3174 ma
.value_type
= local
.variable_type
.copy ();
3175 visit_member_access (ma
);
3176 ccode
.add_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
3179 if (stmt
.tree_can_fail
&& stmt
.expression
.tree_can_fail
) {
3180 // simple case, no node breakdown necessary
3181 add_simple_check (stmt
.expression
);
3184 temp_ref_vars
.clear ();
3187 public virtual void append_local_free (Symbol sym
, bool stop_at_loop
= false) {
3188 var b
= (Block
) sym
;
3190 var local_vars
= b
.get_local_variables ();
3191 // free in reverse order
3192 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
3193 var local
= local_vars
[i
];
3194 if (!local
.unreachable
&& local
.active
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
3195 var ma
= new MemberAccess
.simple (local
.name
);
3196 ma
.symbol_reference
= local
;
3197 ma
.value_type
= local
.variable_type
.copy ();
3198 visit_member_access (ma
);
3199 ccode
.add_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
3204 int block_id
= get_block_id (b
);
3206 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
3207 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
3208 ccode
.add_expression (data_unref
);
3212 if (b
.parent_node is Loop
||
3213 b
.parent_node is ForeachStatement
||
3214 b
.parent_node is SwitchStatement
) {
3219 if (sym
.parent_symbol is Block
) {
3220 append_local_free (sym
.parent_symbol
, stop_at_loop
);
3221 } else if (sym
.parent_symbol is Method
) {
3222 append_param_free ((Method
) sym
.parent_symbol
);
3226 public void append_error_free (Symbol sym
, TryStatement current_try
) {
3227 var b
= (Block
) sym
;
3229 var local_vars
= b
.get_local_variables ();
3230 // free in reverse order
3231 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
3232 var local
= local_vars
[i
];
3233 if (!local
.unreachable
&& local
.active
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
3234 var ma
= new MemberAccess
.simple (local
.name
);
3235 ma
.symbol_reference
= local
;
3236 ma
.value_type
= local
.variable_type
.copy ();
3237 visit_member_access (ma
);
3238 ccode
.add_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
3243 int block_id
= get_block_id (b
);
3245 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
3246 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
3247 ccode
.add_expression (data_unref
);
3250 if (sym
== current_try
.body
) {
3254 if (sym
.parent_symbol is Block
) {
3255 append_error_free (sym
.parent_symbol
, current_try
);
3256 } else if (sym
.parent_symbol is Method
) {
3257 append_param_free ((Method
) sym
.parent_symbol
);
3261 private void append_param_free (Method m
) {
3262 foreach (Parameter param
in m
.get_parameters ()) {
3263 if (!param
.ellipsis
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
3264 var ma
= new MemberAccess
.simple (param
.name
);
3265 ma
.symbol_reference
= param
;
3266 ma
.value_type
= param
.variable_type
.copy ();
3267 visit_member_access (ma
);
3268 ccode
.add_expression (get_unref_expression (get_variable_cexpression (param
.name
), param
.variable_type
, ma
));
3273 public bool variable_accessible_in_finally (LocalVariable local
) {
3274 if (current_try
== null) {
3278 var sym
= current_symbol
;
3280 while (!(sym is Method
|| sym is PropertyAccessor
) && sym
.scope
.lookup (local
.name
) == null) {
3281 if ((sym
.parent_node is TryStatement
&& ((TryStatement
) sym
.parent_node
).finally_body
!= null) ||
3282 (sym
.parent_node is CatchClause
&& ((TryStatement
) sym
.parent_node
.parent_node
).finally_body
!= null)) {
3287 sym
= sym
.parent_symbol
;
3293 void return_out_parameter (Parameter param
) {
3294 var delegate_type
= param
.variable_type as DelegateType
;
3296 ccode
.open_if (get_variable_cexpression (param
.name
));
3297 ccode
.add_expression (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (param
.name
)), get_variable_cexpression ("_" + param
.name
)));
3299 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
3300 ccode
.add_expression (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_delegate_target_cname (param
.name
))), new
CCodeIdentifier (get_delegate_target_cname (get_variable_cname ("_" + param
.name
)))));
3301 if (delegate_type
.value_owned
) {
3302 ccode
.add_expression (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_delegate_target_destroy_notify_cname (param
.name
))), new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname ("_" + param
.name
)))));
3306 if (param
.variable_type
.is_disposable ()){
3308 var ma
= new
MemberAccess (null, param
.name
);
3309 ma
.symbol_reference
= param
;
3310 ma
.value_type
= param
.variable_type
.copy ();
3311 visit_member_access (ma
);
3312 ccode
.add_expression (get_unref_expression (get_variable_cexpression ("_" + param
.name
), param
.variable_type
, ma
));
3316 var array_type
= param
.variable_type as ArrayType
;
3317 if (array_type
!= null && !array_type
.fixed_length
&& !param
.no_array_length
) {
3318 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3319 ccode
.open_if (get_variable_cexpression (get_parameter_array_length_cname (param
, dim
)));
3320 ccode
.add_expression (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_parameter_array_length_cname (param
, dim
))), new
CCodeIdentifier (get_array_length_cname (get_variable_cname ("_" + param
.name
), dim
))));
3326 public override void visit_return_statement (ReturnStatement stmt
) {
3327 Symbol return_expression_symbol
= null;
3329 if (stmt
.return_expression
!= null) {
3330 // avoid unnecessary ref/unref pair
3331 var local
= stmt
.return_expression
.symbol_reference as LocalVariable
;
3332 if (current_return_type
.value_owned
3333 && local
!= null && local
.variable_type
.value_owned
3335 && !variable_accessible_in_finally (local
)) {
3336 /* return expression is local variable taking ownership and
3337 * current method is transferring ownership */
3339 return_expression_symbol
= local
;
3343 // return array length if appropriate
3344 if (((current_method
!= null && !current_method
.no_array_length
) || current_property_accessor
!= null) && current_return_type is ArrayType
) {
3345 var return_expr_decl
= get_temp_variable (stmt
.return_expression
.value_type
, true, stmt
, false);
3347 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (return_expr_decl
.name
), get_cvalue (stmt
.return_expression
)));
3349 var array_type
= (ArrayType
) current_return_type
;
3351 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3352 var len_l
= get_result_cexpression (get_array_length_cname ("result", dim
));
3353 if (current_method
== null || !current_method
.coroutine
) {
3354 len_l
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, len_l
);
3356 var len_r
= get_array_length_cexpression (stmt
.return_expression
, dim
);
3357 ccode
.add_expression (new
CCodeAssignment (len_l
, len_r
));
3360 set_cvalue (stmt
.return_expression
, get_variable_cexpression (return_expr_decl
.name
));
3362 emit_temp_var (return_expr_decl
);
3363 } else if ((current_method
!= null || current_property_accessor
!= null) && current_return_type is DelegateType
) {
3364 var delegate_type
= (DelegateType
) current_return_type
;
3365 if (delegate_type
.delegate_symbol
.has_target
) {
3366 var return_expr_decl
= get_temp_variable (stmt
.return_expression
.value_type
, true, stmt
, false);
3368 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (return_expr_decl
.name
), get_cvalue (stmt
.return_expression
)));
3370 var target_l
= get_result_cexpression (get_delegate_target_cname ("result"));
3371 if (current_method
== null || !current_method
.coroutine
) {
3372 target_l
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_l
);
3374 CCodeExpression target_r_destroy_notify
;
3375 var target_r
= get_delegate_target_cexpression (stmt
.return_expression
, out target_r_destroy_notify
);
3376 ccode
.add_expression (new
CCodeAssignment (target_l
, target_r
));
3377 if (delegate_type
.value_owned
) {
3378 var target_l_destroy_notify
= get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3379 if (current_method
== null || !current_method
.coroutine
) {
3380 target_l_destroy_notify
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_l_destroy_notify
);
3382 ccode
.add_expression (new
CCodeAssignment (target_l_destroy_notify
, target_r_destroy_notify
));
3385 set_cvalue (stmt
.return_expression
, get_variable_cexpression (return_expr_decl
.name
));
3387 emit_temp_var (return_expr_decl
);
3391 if (stmt
.return_expression
!= null) {
3392 // assign method result to `result'
3393 CCodeExpression result_lhs
= get_result_cexpression ();
3394 if (current_return_type
.is_real_non_null_struct_type () && (current_method
== null || !current_method
.coroutine
)) {
3395 result_lhs
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, result_lhs
);
3397 ccode
.add_expression (new
CCodeAssignment (result_lhs
, get_cvalue (stmt
.return_expression
)));
3400 // free local variables
3401 append_local_free (current_symbol
);
3403 if (current_method
!= null) {
3404 // check postconditions
3405 foreach (Expression postcondition
in current_method
.get_postconditions ()) {
3406 create_postcondition_statement (postcondition
);
3410 if (current_method
!= null && !current_method
.coroutine
) {
3411 // assign values to output parameters if they are not NULL
3412 // otherwise, free the value if necessary
3413 foreach (var param
in current_method
.get_parameters ()) {
3414 if (param
.direction
!= ParameterDirection
.OUT
) {
3418 return_out_parameter (param
);
3422 if (is_in_constructor ()) {
3423 ccode
.add_return (new
CCodeIdentifier ("obj"));
3424 } else if (is_in_destructor ()) {
3425 // do not call return as member cleanup and chain up to base finalizer
3426 // stil need to be executed
3427 ccode
.add_goto ("_return");
3428 } else if (current_method is CreationMethod
) {
3429 ccode
.add_return (new
CCodeIdentifier ("self"));
3430 } else if (current_method
!= null && current_method
.coroutine
) {
3431 } else if (current_return_type is VoidType
|| current_return_type
.is_real_non_null_struct_type ()) {
3432 // structs are returned via out parameter
3433 ccode
.add_return ();
3435 ccode
.add_return (new
CCodeIdentifier ("result"));
3438 if (return_expression_symbol
!= null) {
3439 return_expression_symbol
.active
= true;
3442 // required for destructors
3443 current_method_return
= true;
3446 public string get_symbol_lock_name (string symname
) {
3447 return "__lock_%s".printf (symname
);
3450 private CCodeExpression
get_lock_expression (Statement stmt
, Expression resource
) {
3451 CCodeExpression l
= null;
3452 var inner_node
= ((MemberAccess
)resource
).inner
;
3453 var member
= resource
.symbol_reference
;
3454 var parent
= (TypeSymbol
)resource
.symbol_reference
.parent_symbol
;
3456 if (member
.is_instance_member ()) {
3457 if (inner_node
== null) {
3458 l
= new
CCodeIdentifier ("self");
3459 } else if (resource
.symbol_reference
.parent_symbol
!= current_type_symbol
) {
3460 l
= generate_instance_cast (get_cvalue (inner_node
), parent
);
3462 l
= get_cvalue (inner_node
);
3465 l
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (l
, "priv"), get_symbol_lock_name (resource
.symbol_reference
.name
));
3466 } else if (member
.is_class_member ()) {
3467 CCodeExpression klass
;
3469 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
||
3470 current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
||
3471 (in_constructor
&& !in_static_or_class_context
)) {
3472 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3473 k
.add_argument (new
CCodeIdentifier ("self"));
3476 klass
= new
CCodeIdentifier ("klass");
3479 var get_class_private_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent
.get_upper_case_cname ())));
3480 get_class_private_call
.add_argument (klass
);
3481 l
= new CCodeMemberAccess
.pointer (get_class_private_call
, get_symbol_lock_name (resource
.symbol_reference
.name
));
3483 string lock_name
= "%s_%s".printf(parent
.get_lower_case_cname (), resource
.symbol_reference
.name
);
3484 l
= new
CCodeIdentifier (get_symbol_lock_name (lock_name
));
3489 public override void visit_lock_statement (LockStatement stmt
) {
3490 var l
= get_lock_expression (stmt
, stmt
.resource
);
3492 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier (((Method
) mutex_type
.scope
.lookup ("lock")).get_cname ()));
3493 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
3495 ccode
.add_expression (fc
);
3498 public override void visit_unlock_statement (UnlockStatement stmt
) {
3499 var l
= get_lock_expression (stmt
, stmt
.resource
);
3501 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier (((Method
) mutex_type
.scope
.lookup ("unlock")).get_cname ()));
3502 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
3504 ccode
.add_expression (fc
);
3507 public override void visit_delete_statement (DeleteStatement stmt
) {
3508 var pointer_type
= (PointerType
) stmt
.expression
.value_type
;
3509 DataType type
= pointer_type
;
3510 if (pointer_type
.base_type
.data_type
!= null && pointer_type
.base_type
.data_type
.is_reference_type ()) {
3511 type
= pointer_type
.base_type
;
3514 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
3515 ccall
.add_argument (get_cvalue (stmt
.expression
));
3516 ccode
.add_expression (ccall
);
3519 public override void visit_expression (Expression expr
) {
3520 if (get_cvalue (expr
) != null && !expr
.lvalue
) {
3521 if (expr
.formal_value_type is GenericType
&& !(expr
.value_type is GenericType
)) {
3522 var st
= expr
.formal_value_type
.type_parameter
.parent_symbol
.parent_symbol as Struct
;
3523 if (expr
.formal_value_type
.type_parameter
.parent_symbol
!= garray_type
&&
3524 (st
== null || st
.get_cname () != "va_list")) {
3525 // GArray and va_list don't use pointer-based generics
3526 set_cvalue (expr
, convert_from_generic_pointer (get_cvalue (expr
), expr
.value_type
));
3530 // memory management, implicit casts, and boxing/unboxing
3531 set_cvalue (expr
, transform_expression (get_cvalue (expr
), expr
.value_type
, expr
.target_type
, expr
));
3533 if (expr
.formal_target_type is GenericType
&& !(expr
.target_type is GenericType
)) {
3534 if (expr
.formal_target_type
.type_parameter
.parent_symbol
!= garray_type
) {
3535 // GArray doesn't use pointer-based generics
3536 set_cvalue (expr
, convert_to_generic_pointer (get_cvalue (expr
), expr
.target_type
));
3542 public override void visit_boolean_literal (BooleanLiteral expr
) {
3543 if (context
.profile
== Profile
.GOBJECT
) {
3544 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"TRUE" : "FALSE"));
3546 cfile
.add_include ("stdbool.h");
3547 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"true" : "false"));
3551 public override void visit_character_literal (CharacterLiteral expr
) {
3552 if (expr
.get_char () >= 0x20 && expr
.get_char () < 0x80) {
3553 set_cvalue (expr
, new
CCodeConstant (expr
.value
));
3555 set_cvalue (expr
, new
CCodeConstant ("%uU".printf (expr
.get_char ())));
3559 public override void visit_integer_literal (IntegerLiteral expr
) {
3560 set_cvalue (expr
, new
CCodeConstant (expr
.value
+ expr
.type_suffix
));
3563 public override void visit_real_literal (RealLiteral expr
) {
3564 string c_literal
= expr
.value
;
3565 if (c_literal
.has_suffix ("d") || c_literal
.has_suffix ("D")) {
3566 // there is no suffix for double in C
3567 c_literal
= c_literal
.substring (0, c_literal
.length
- 1);
3569 if (!("." in c_literal
|| "e" in c_literal
|| "E" in c_literal
)) {
3570 // C requires period or exponent part for floating constants
3571 if ("f" in c_literal
|| "F" in c_literal
) {
3572 c_literal
= c_literal
.substring (0, c_literal
.length
- 1) + ".f";
3577 set_cvalue (expr
, new
CCodeConstant (c_literal
));
3580 public override void visit_string_literal (StringLiteral expr
) {
3581 set_cvalue (expr
, new CCodeConstant
.string (expr
.value
.replace ("\n", "\\n")));
3584 public override void visit_regex_literal (RegexLiteral expr
) {
3585 string[] parts
= expr
.value
.split ("/", 3);
3586 string re
= parts
[2].escape ("");
3589 if (parts
[1].contains ("i")) {
3590 flags
+= " | G_REGEX_CASELESS";
3592 if (parts
[1].contains ("m")) {
3593 flags
+= " | G_REGEX_MULTILINE";
3595 if (parts
[1].contains ("s")) {
3596 flags
+= " | G_REGEX_DOTALL";
3598 if (parts
[1].contains ("x")) {
3599 flags
+= " | G_REGEX_EXTENDED";
3602 var regex_var
= get_temp_variable (regex_type
, true, expr
, false);
3603 emit_temp_var (regex_var
);
3605 var cdecl
= new
CCodeDeclaration ("GRegex*");
3607 var cname
= regex_var
.name
+ "regex_" + next_regex_id
.to_string ();
3608 if (this
.next_regex_id
== 0) {
3609 var fun
= new
CCodeFunction ("_thread_safe_regex_init", "GRegex*");
3610 fun
.modifiers
= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
3611 fun
.add_parameter (new
CCodeParameter ("re", "GRegex**"));
3612 fun
.add_parameter (new
CCodeParameter ("pattern", "const gchar *"));
3613 fun
.add_parameter (new
CCodeParameter ("match_options", "GRegexMatchFlags"));
3615 push_function (fun
);
3617 var once_enter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_once_init_enter"));
3618 once_enter_call
.add_argument (new
CCodeConstant ("(volatile gsize*) re"));
3619 ccode
.open_if (once_enter_call
);
3621 var regex_new_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_regex_new"));
3622 regex_new_call
.add_argument (new
CCodeConstant ("pattern"));
3623 regex_new_call
.add_argument (new
CCodeConstant ("match_options"));
3624 regex_new_call
.add_argument (new
CCodeConstant ("0"));
3625 regex_new_call
.add_argument (new
CCodeConstant ("NULL"));
3626 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("GRegex* val"), regex_new_call
));
3628 var once_leave_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_once_init_leave"));
3629 once_leave_call
.add_argument (new
CCodeConstant ("(volatile gsize*) re"));
3630 once_leave_call
.add_argument (new
CCodeConstant ("(gsize) val"));
3631 ccode
.add_expression (once_leave_call
);
3635 ccode
.add_return (new
CCodeIdentifier ("*re"));
3639 cfile
.add_function (fun
);
3641 this
.next_regex_id
++;
3643 cdecl
.add_declarator (new
CCodeVariableDeclarator (cname
+ " = NULL"));
3644 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
3646 var regex_const
= new
CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname
, re
, flags
));
3648 cfile
.add_constant_declaration (cdecl
);
3649 set_cvalue (expr
, regex_const
);
3652 public override void visit_null_literal (NullLiteral expr
) {
3653 if (context
.profile
!= Profile
.GOBJECT
) {
3654 cfile
.add_include ("stddef.h");
3656 set_cvalue (expr
, new
CCodeConstant ("NULL"));
3658 var array_type
= expr
.target_type as ArrayType
;
3659 var delegate_type
= expr
.target_type as DelegateType
;
3660 if (array_type
!= null) {
3661 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3662 append_array_size (expr
, new
CCodeConstant ("0"));
3664 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
3665 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
3666 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
3670 public virtual string get_delegate_target_cname (string delegate_cname
) {
3671 assert_not_reached ();
3674 public virtual CCodeExpression
get_delegate_target_cexpression (Expression delegate_expr
, out CCodeExpression delegate_target_destroy_notify
) {
3675 assert_not_reached ();
3678 public virtual CCodeExpression
get_delegate_target_cvalue (TargetValue value
) {
3679 return new
CCodeInvalidExpression ();
3682 public virtual CCodeExpression
get_delegate_target_destroy_notify_cvalue (TargetValue value
) {
3683 return new
CCodeInvalidExpression ();
3686 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname
) {
3687 assert_not_reached ();
3690 public override void visit_base_access (BaseAccess expr
) {
3691 CCodeExpression this_access
;
3692 if (current_method
!= null && current_method
.coroutine
) {
3694 this_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "self");
3696 this_access
= new
CCodeIdentifier ("self");
3699 set_cvalue (expr
, generate_instance_cast (this_access
, expr
.value_type
.data_type
));
3702 public override void visit_postfix_expression (PostfixExpression expr
) {
3703 MemberAccess ma
= find_property_access (expr
.inner
);
3705 // property postfix expression
3706 var prop
= (Property
) ma
.symbol_reference
;
3708 // assign current value to temp variable
3709 var temp_decl
= get_temp_variable (prop
.property_type
, true, expr
, false);
3710 emit_temp_var (temp_decl
);
3711 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_decl
.name
), get_cvalue (expr
.inner
)));
3713 // increment/decrement property
3714 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
3715 var cexpr
= new
CCodeBinaryExpression (op
, get_variable_cexpression (temp_decl
.name
), new
CCodeConstant ("1"));
3716 store_property (prop
, ma
, cexpr
);
3718 // return previous value
3719 set_cvalue (expr
, get_variable_cexpression (temp_decl
.name
));
3723 var op
= expr
.increment ? CCodeUnaryOperator
.POSTFIX_INCREMENT
: CCodeUnaryOperator
.POSTFIX_DECREMENT
;
3725 set_cvalue (expr
, new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
3728 private MemberAccess?
find_property_access (Expression expr
) {
3729 if (!(expr is MemberAccess
)) {
3733 var ma
= (MemberAccess
) expr
;
3734 if (ma
.symbol_reference is Property
) {
3741 bool is_limited_generic_type (DataType type
) {
3742 var cl
= type
.type_parameter
.parent_symbol as Class
;
3743 var st
= type
.type_parameter
.parent_symbol as Struct
;
3744 if ((cl
!= null && cl
.is_compact
) || st
!= null) {
3745 // compact classes and structs only
3746 // have very limited generics support
3752 public bool requires_copy (DataType type
) {
3753 if (!type
.is_disposable ()) {
3757 var cl
= type
.data_type as Class
;
3758 if (cl
!= null && cl
.is_reference_counting ()
3759 && cl
.get_ref_function () == "") {
3760 // empty ref_function => no ref necessary
3764 if (type
.type_parameter
!= null) {
3765 if (is_limited_generic_type (type
)) {
3773 public bool requires_destroy (DataType type
) {
3774 if (!type
.is_disposable ()) {
3778 var array_type
= type as ArrayType
;
3779 if (array_type
!= null && array_type
.fixed_length
) {
3780 return requires_destroy (array_type
.element_type
);
3783 var cl
= type
.data_type as Class
;
3784 if (cl
!= null && cl
.is_reference_counting ()
3785 && cl
.get_unref_function () == "") {
3786 // empty unref_function => no unref necessary
3790 if (type
.type_parameter
!= null) {
3791 if (is_limited_generic_type (type
)) {
3799 bool is_ref_function_void (DataType type
) {
3800 var cl
= type
.data_type as Class
;
3801 if (cl
!= null && cl
.ref_function_void
) {
3808 public virtual CCodeExpression?
get_ref_cexpression (DataType expression_type
, CCodeExpression cexpr
, Expression? expr
, CodeNode node
) {
3809 if (expression_type is DelegateType
) {
3813 if (expression_type is ValueType
&& !expression_type
.nullable
) {
3814 // normal value type, no null check
3815 // (copy (&expr, &temp), temp)
3817 var decl
= get_temp_variable (expression_type
, false, node
);
3818 emit_temp_var (decl
);
3820 var ctemp
= get_variable_cexpression (decl
.name
);
3822 var vt
= (ValueType
) expression_type
;
3823 var st
= (Struct
) vt
.type_symbol
;
3824 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_copy_function ()));
3825 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3826 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
3828 if (!st
.has_copy_function
) {
3829 generate_struct_copy_function (st
);
3832 var ccomma
= new
CCodeCommaExpression ();
3834 if (st
.get_copy_function () == "g_value_copy") {
3835 // GValue requires g_value_init in addition to g_value_copy
3837 var value_type_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VALUE_TYPE"));
3838 value_type_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3840 var init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
3841 init_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
3842 init_call
.add_argument (value_type_call
);
3844 ccomma
.append_expression (init_call
);
3847 ccomma
.append_expression (copy_call
);
3848 ccomma
.append_expression (ctemp
);
3850 if (gvalue_type
!= null && expression_type
.data_type
== gvalue_type
) {
3851 // g_value_init/copy must not be called for uninitialized values
3852 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
3853 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3855 return new
CCodeConditionalExpression (cisvalid
, ccomma
, cexpr
);
3861 /* (temp = expr, temp == NULL ? NULL : ref (temp))
3863 * can be simplified to
3865 * if static type of expr is non-null
3868 var dupexpr
= get_dup_func_expression (expression_type
, node
.source_reference
);
3870 if (dupexpr
== null) {
3875 if (dupexpr is CCodeIdentifier
&& !(expression_type is ArrayType
) && !(expression_type is GenericType
) && !is_ref_function_void (expression_type
)) {
3876 // generate and call NULL-aware ref function to reduce number
3877 // of temporary variables and simplify code
3879 var dupid
= (CCodeIdentifier
) dupexpr
;
3880 string dup0_func
= "_%s0".printf (dupid
.name
);
3882 // g_strdup is already NULL-safe
3883 if (dupid
.name
== "g_strdup") {
3884 dup0_func
= dupid
.name
;
3885 } else if (add_wrapper (dup0_func
)) {
3886 string pointer_cname
= "gpointer";
3887 if (context
.profile
== Profile
.POSIX
) {
3888 pointer_cname
= "void*";
3890 var dup0_fun
= new
CCodeFunction (dup0_func
, pointer_cname
);
3891 dup0_fun
.add_parameter (new
CCodeParameter ("self", pointer_cname
));
3892 dup0_fun
.modifiers
= CCodeModifiers
.STATIC
;
3894 push_function (dup0_fun
);
3896 var dup_call
= new
CCodeFunctionCall (dupexpr
);
3897 dup_call
.add_argument (new
CCodeIdentifier ("self"));
3899 ccode
.add_return (new
CCodeConditionalExpression (new
CCodeIdentifier ("self"), dup_call
, new
CCodeConstant ("NULL")));
3903 cfile
.add_function (dup0_fun
);
3906 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (dup0_func
));
3907 ccall
.add_argument (cexpr
);
3911 var ccall
= new
CCodeFunctionCall (dupexpr
);
3913 if (!(expression_type is ArrayType
) && expr
!= null && expr
.is_non_null ()
3914 && !is_ref_function_void (expression_type
)) {
3915 // expression is non-null
3916 ccall
.add_argument (get_cvalue (expr
));
3920 var decl
= get_temp_variable (expression_type
, false, node
, false);
3921 emit_temp_var (decl
);
3923 var ctemp
= get_variable_cexpression (decl
.name
);
3925 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, new
CCodeConstant ("NULL"));
3926 if (expression_type
.type_parameter
!= null) {
3927 // dup functions are optional for type parameters
3928 var cdupisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_dup_func_expression (expression_type
, node
.source_reference
), new
CCodeConstant ("NULL"));
3929 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cdupisnull
);
3932 if (expression_type
.type_parameter
!= null) {
3933 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
3934 ccall
.add_argument (new
CCodeCastExpression (ctemp
, "gpointer"));
3936 ccall
.add_argument (ctemp
);
3939 if (expression_type is ArrayType
) {
3940 var array_type
= (ArrayType
) expression_type
;
3942 CCodeExpression csizeexpr
= null;
3943 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3945 csizeexpr
= get_array_length_cexpression (expr
, dim
);
3948 csizeexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeexpr
, get_array_length_cexpression (expr
, dim
));
3952 ccall
.add_argument (csizeexpr
);
3954 if (array_type
.element_type is GenericType
) {
3955 var elem_dupexpr
= get_dup_func_expression (array_type
.element_type
, node
.source_reference
);
3956 if (elem_dupexpr
== null) {
3957 elem_dupexpr
= new
CCodeConstant ("NULL");
3959 ccall
.add_argument (elem_dupexpr
);
3963 var ccomma
= new
CCodeCommaExpression ();
3964 ccomma
.append_expression (new
CCodeAssignment (ctemp
, cexpr
));
3966 CCodeExpression cifnull
;
3967 if (expression_type
.data_type
!= null) {
3968 cifnull
= new
CCodeConstant ("NULL");
3970 // the value might be non-null even when the dup function is null,
3971 // so we may not just use NULL for type parameters
3973 // cast from gconstpointer to gpointer as methods in
3974 // generic classes may not return gconstpointer
3975 cifnull
= new
CCodeCastExpression (ctemp
, "gpointer");
3977 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, cifnull
, ccall
));
3979 // repeat temp variable at the end of the comma expression
3980 // if the ref function returns void
3981 if (is_ref_function_void (expression_type
)) {
3982 ccomma
.append_expression (ctemp
);
3989 bool is_reference_type_argument (DataType type_arg
) {
3990 if (type_arg is ErrorType
|| (type_arg
.data_type
!= null && type_arg
.data_type
.is_reference_type ())) {
3997 bool is_nullable_value_type_argument (DataType type_arg
) {
3998 if (type_arg is ValueType
&& type_arg
.nullable
) {
4005 bool is_signed_integer_type_argument (DataType type_arg
) {
4006 var st
= type_arg
.data_type as Struct
;
4007 if (type_arg
.nullable
) {
4009 } else if (st
== bool_type
.data_type
) {
4011 } else if (st
== char_type
.data_type
) {
4013 } else if (unichar_type
!= null && st
== unichar_type
.data_type
) {
4015 } else if (st
== short_type
.data_type
) {
4017 } else if (st
== int_type
.data_type
) {
4019 } else if (st
== long_type
.data_type
) {
4021 } else if (st
== int8_type
.data_type
) {
4023 } else if (st
== int16_type
.data_type
) {
4025 } else if (st
== int32_type
.data_type
) {
4027 } else if (st
== gtype_type
) {
4029 } else if (type_arg is EnumValueType
) {
4036 bool is_unsigned_integer_type_argument (DataType type_arg
) {
4037 var st
= type_arg
.data_type as Struct
;
4038 if (type_arg
.nullable
) {
4040 } else if (st
== uchar_type
.data_type
) {
4042 } else if (st
== ushort_type
.data_type
) {
4044 } else if (st
== uint_type
.data_type
) {
4046 } else if (st
== ulong_type
.data_type
) {
4048 } else if (st
== uint8_type
.data_type
) {
4050 } else if (st
== uint16_type
.data_type
) {
4052 } else if (st
== uint32_type
.data_type
) {
4059 public void check_type (DataType type
) {
4060 var array_type
= type as ArrayType
;
4061 if (array_type
!= null) {
4062 check_type (array_type
.element_type
);
4063 if (array_type
.element_type is ArrayType
) {
4064 Report
.error (type
.source_reference
, "Stacked arrays are not supported");
4065 } else if (array_type
.element_type is DelegateType
) {
4066 var delegate_type
= (DelegateType
) array_type
.element_type
;
4067 if (delegate_type
.delegate_symbol
.has_target
) {
4068 Report
.error (type
.source_reference
, "Delegates with target are not supported as array element type");
4072 foreach (var type_arg
in type
.get_type_arguments ()) {
4073 check_type (type_arg
);
4074 check_type_argument (type_arg
);
4078 void check_type_argument (DataType type_arg
) {
4079 if (type_arg is GenericType
4080 || type_arg is PointerType
4081 || is_reference_type_argument (type_arg
)
4082 || is_nullable_value_type_argument (type_arg
)
4083 || is_signed_integer_type_argument (type_arg
)
4084 || is_unsigned_integer_type_argument (type_arg
)) {
4086 } else if (type_arg is DelegateType
) {
4087 var delegate_type
= (DelegateType
) type_arg
;
4088 if (delegate_type
.delegate_symbol
.has_target
) {
4089 Report
.error (type_arg
.source_reference
, "Delegates with target are not supported as generic type arguments");
4092 Report
.error (type_arg
.source_reference
, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg
.to_string ()));
4096 public virtual void generate_class_declaration (Class cl
, CCodeFile decl_space
) {
4097 if (add_symbol_declaration (decl_space
, cl
, cl
.get_cname ())) {
4102 public virtual void generate_interface_declaration (Interface iface
, CCodeFile decl_space
) {
4105 public virtual void generate_method_declaration (Method m
, CCodeFile decl_space
) {
4108 public virtual void generate_error_domain_declaration (ErrorDomain edomain
, CCodeFile decl_space
) {
4111 public void add_generic_type_arguments (Map
<int,CCodeExpression
> arg_map
, List
<DataType
> type_args
, CodeNode expr
, bool is_chainup
= false) {
4112 int type_param_index
= 0;
4113 foreach (var type_arg
in type_args
) {
4114 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), get_type_id_expression (type_arg
, is_chainup
));
4115 if (requires_copy (type_arg
)) {
4116 var dup_func
= get_dup_func_expression (type_arg
, type_arg
.source_reference
, is_chainup
);
4117 if (dup_func
== null) {
4118 // type doesn't contain a copy function
4122 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeCastExpression (dup_func
, "GBoxedCopyFunc"));
4123 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), get_destroy_func_expression (type_arg
, is_chainup
));
4125 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeConstant ("NULL"));
4126 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeConstant ("NULL"));
4132 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
4133 CCodeExpression instance
= null;
4134 CCodeExpression creation_expr
= null;
4136 check_type (expr
.type_reference
);
4138 var st
= expr
.type_reference
.data_type as Struct
;
4139 if ((st
!= null && (!st
.is_simple_type () || st
.get_cname () == "va_list")) || expr
.get_object_initializer ().size
> 0) {
4140 // value-type initialization or object creation expression with object initializer
4142 var local
= expr
.parent_node as LocalVariable
;
4143 if (local
!= null && has_simple_struct_initializer (local
)) {
4144 if (local
.captured
) {
4145 var block
= (Block
) local
.parent_symbol
;
4146 instance
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_variable_cname (local
.name
));
4148 instance
= get_variable_cexpression (get_variable_cname (local
.name
));
4151 var temp_decl
= get_temp_variable (expr
.type_reference
, false, expr
);
4152 emit_temp_var (temp_decl
);
4154 instance
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
4158 if (expr
.symbol_reference
== null) {
4159 // no creation method
4160 if (expr
.type_reference
.data_type is Struct
) {
4161 // memset needs string.h
4162 cfile
.add_include ("string.h");
4163 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
4164 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4165 creation_call
.add_argument (new
CCodeConstant ("0"));
4166 creation_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (expr
.type_reference
.get_cname ())));
4168 creation_expr
= creation_call
;
4170 } else if (expr
.type_reference
.data_type
== glist_type
||
4171 expr
.type_reference
.data_type
== gslist_type
) {
4172 // NULL is an empty list
4173 set_cvalue (expr
, new
CCodeConstant ("NULL"));
4174 } else if (expr
.symbol_reference is Method
) {
4175 // use creation method
4176 var m
= (Method
) expr
.symbol_reference
;
4177 var params
= m
.get_parameters ();
4178 CCodeFunctionCall creation_call
;
4180 generate_method_declaration (m
, cfile
);
4182 var cl
= expr
.type_reference
.data_type as Class
;
4184 if (!m
.has_new_function
) {
4185 // use construct function directly
4186 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
4187 creation_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
4189 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_cname ()));
4192 if ((st
!= null && !st
.is_simple_type ()) && !(m
.cinstance_parameter_position
< 0)) {
4193 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4194 } else if (st
!= null && st
.get_cname () == "va_list") {
4195 creation_call
.add_argument (instance
);
4196 if (m
.get_cname () == "va_start") {
4197 Parameter last_param
= null;
4198 foreach (var param
in current_method
.get_parameters ()) {
4199 if (param
.ellipsis
) {
4204 creation_call
.add_argument (new
CCodeIdentifier (get_variable_cname (last_param
.name
)));
4208 generate_type_declaration (expr
.type_reference
, cfile
);
4210 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
4212 if (cl
!= null && !cl
.is_compact
) {
4213 add_generic_type_arguments (carg_map
, expr
.type_reference
.get_type_arguments (), expr
);
4214 } else if (cl
!= null && m
.simple_generics
) {
4215 int type_param_index
= 0;
4216 foreach (var type_arg
in expr
.type_reference
.get_type_arguments ()) {
4217 if (requires_copy (type_arg
)) {
4218 carg_map
.set (get_param_pos (-1 + 0.1 * type_param_index
+ 0.03), get_destroy0_func_expression (type_arg
));
4220 carg_map
.set (get_param_pos (-1 + 0.1 * type_param_index
+ 0.03), new
CCodeConstant ("NULL"));
4226 bool ellipsis
= false;
4230 Iterator
<Parameter
> params_it
= params
.iterator ();
4231 foreach (Expression arg
in expr
.get_argument_list ()) {
4232 CCodeExpression cexpr
= get_cvalue (arg
);
4233 Parameter param
= null;
4234 if (params_it
.next ()) {
4235 param
= params_it
.get ();
4236 ellipsis
= param
.ellipsis
;
4238 if (!param
.no_array_length
&& param
.variable_type is ArrayType
) {
4239 var array_type
= (ArrayType
) param
.variable_type
;
4240 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4241 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), get_array_length_cexpression (arg
, dim
));
4243 } else if (param
.variable_type is DelegateType
) {
4244 var deleg_type
= (DelegateType
) param
.variable_type
;
4245 var d
= deleg_type
.delegate_symbol
;
4247 CCodeExpression delegate_target_destroy_notify
;
4248 var delegate_target
= get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
);
4249 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), delegate_target
);
4250 if (deleg_type
.value_owned
) {
4251 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
+ 0.01), delegate_target_destroy_notify
);
4256 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
4258 if (param
.ctype
!= null) {
4259 cexpr
= new
CCodeCastExpression (cexpr
, param
.ctype
);
4262 cexpr
= handle_struct_argument (null, arg
, cexpr
);
4265 arg_pos
= get_param_pos (param
.cparameter_position
, ellipsis
);
4267 // default argument position
4268 cexpr
= handle_struct_argument (null, arg
, cexpr
);
4269 arg_pos
= get_param_pos (i
, ellipsis
);
4272 carg_map
.set (arg_pos
, cexpr
);
4276 while (params_it
.next ()) {
4277 var param
= params_it
.get ();
4279 if (param
.ellipsis
) {
4284 if (param
.initializer
== null) {
4285 Report
.error (expr
.source_reference
, "no default expression for argument %d".printf (i
));
4289 /* evaluate default expression here as the code
4290 * generator might not have visited the formal
4292 param
.initializer
.emit (this
);
4294 carg_map
.set (get_param_pos (param
.cparameter_position
), get_cvalue (param
.initializer
));
4298 // append C arguments in the right order
4303 foreach (int pos
in carg_map
.get_keys ()) {
4304 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
4308 if (min_pos
== -1) {
4311 creation_call
.add_argument (carg_map
.get (min_pos
));
4315 if ((st
!= null && !st
.is_simple_type ()) && m
.cinstance_parameter_position
< 0) {
4316 // instance parameter is at the end in a struct creation method
4317 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4320 if (expr
.tree_can_fail
) {
4322 current_method_inner_error
= true;
4323 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression ("_inner_error_")));
4327 /* ensure variable argument list ends with NULL
4328 * except when using printf-style arguments */
4329 if (!m
.printf_format
&& !m
.scanf_format
&& m
.sentinel
!= "") {
4330 creation_call
.add_argument (new
CCodeConstant (m
.sentinel
));
4334 creation_expr
= creation_call
;
4336 // cast the return value of the creation method back to the intended type if
4337 // it requested a special C return type
4338 if (get_custom_creturn_type (m
) != null) {
4339 creation_expr
= new
CCodeCastExpression (creation_expr
, expr
.type_reference
.get_cname ());
4341 } else if (expr
.symbol_reference is ErrorCode
) {
4342 var ecode
= (ErrorCode
) expr
.symbol_reference
;
4343 var edomain
= (ErrorDomain
) ecode
.parent_symbol
;
4344 CCodeFunctionCall creation_call
;
4346 generate_error_domain_declaration (edomain
, cfile
);
4348 if (expr
.get_argument_list ().size
== 1) {
4349 // must not be a format argument
4350 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_new_literal"));
4352 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_new"));
4354 creation_call
.add_argument (new
CCodeIdentifier (edomain
.get_upper_case_cname ()));
4355 creation_call
.add_argument (new
CCodeIdentifier (ecode
.get_cname ()));
4357 foreach (Expression arg
in expr
.get_argument_list ()) {
4358 creation_call
.add_argument (get_cvalue (arg
));
4361 creation_expr
= creation_call
;
4366 var local
= expr
.parent_node as LocalVariable
;
4367 if (local
!= null && has_simple_struct_initializer (local
)) {
4368 // no temporary variable necessary
4369 set_cvalue (expr
, creation_expr
);
4371 } else if (instance
!= null) {
4372 if (expr
.type_reference
.data_type is Struct
) {
4373 ccode
.add_expression (creation_expr
);
4375 ccode
.add_expression (new
CCodeAssignment (instance
, creation_expr
));
4378 foreach (MemberInitializer init
in expr
.get_object_initializer ()) {
4379 if (init
.symbol_reference is Field
) {
4380 var f
= (Field
) init
.symbol_reference
;
4381 var instance_target_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
4382 var typed_inst
= transform_expression (instance
, expr
.type_reference
, instance_target_type
);
4383 CCodeExpression lhs
;
4384 if (expr
.type_reference
.data_type is Struct
) {
4385 lhs
= new
CCodeMemberAccess (typed_inst
, f
.get_cname ());
4387 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, f
.get_cname ());
4389 ccode
.add_expression (new
CCodeAssignment (lhs
, get_cvalue (init
.initializer
)));
4391 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
4392 var array_type
= (ArrayType
) f
.variable_type
;
4393 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4394 if (expr
.type_reference
.data_type is Struct
) {
4395 lhs
= new
CCodeMemberAccess (typed_inst
, get_array_length_cname (f
.get_cname (), dim
));
4397 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, get_array_length_cname (f
.get_cname (), dim
));
4399 var rhs_array_len
= get_array_length_cexpression (init
.initializer
, dim
);
4400 ccode
.add_expression (new
CCodeAssignment (lhs
, rhs_array_len
));
4402 } else if (f
.variable_type is DelegateType
&& (f
.variable_type as DelegateType
).delegate_symbol
.has_target
&& !f
.no_delegate_target
) {
4403 if (expr
.type_reference
.data_type is Struct
) {
4404 lhs
= new
CCodeMemberAccess (typed_inst
, get_delegate_target_cname (f
.get_cname ()));
4406 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, get_delegate_target_cname (f
.get_cname ()));
4408 CCodeExpression rhs_delegate_target_destroy_notify
;
4409 var rhs_delegate_target
= get_delegate_target_cexpression (init
.initializer
, out rhs_delegate_target_destroy_notify
);
4410 ccode
.add_expression (new
CCodeAssignment (lhs
, rhs_delegate_target
));
4413 var cl
= f
.parent_symbol as Class
;
4415 generate_class_struct_declaration (cl
, cfile
);
4417 } else if (init
.symbol_reference is Property
) {
4418 var inst_ma
= new MemberAccess
.simple ("new");
4419 inst_ma
.value_type
= expr
.type_reference
;
4420 set_cvalue (inst_ma
, instance
);
4421 var ma
= new
MemberAccess (inst_ma
, init
.name
);
4422 store_property ((Property
) init
.symbol_reference
, ma
, get_cvalue (init
.initializer
));
4426 creation_expr
= instance
;
4429 if (creation_expr
!= null) {
4430 var temp_var
= get_temp_variable (expr
.value_type
);
4431 var temp_ref
= get_variable_cexpression (temp_var
.name
);
4433 emit_temp_var (temp_var
);
4435 ccode
.add_expression (new
CCodeAssignment (temp_ref
, creation_expr
));
4436 set_cvalue (expr
, temp_ref
);
4440 public CCodeExpression?
handle_struct_argument (Parameter? param
, Expression arg
, CCodeExpression? cexpr
) {
4442 if (param
!= null) {
4443 type
= param
.variable_type
;
4446 type
= arg
.value_type
;
4449 // pass non-simple struct instances always by reference
4450 if (!(arg
.value_type is NullType
) && type
.is_real_struct_type ()) {
4451 // we already use a reference for arguments of ref, out, and nullable parameters
4452 if ((param
== null || param
.direction
== ParameterDirection
.IN
) && !type
.nullable
) {
4453 var unary
= cexpr as CCodeUnaryExpression
;
4454 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
4457 } else if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
4458 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
4460 // if cexpr is e.g. a function call, we can't take the address of the expression
4461 // (tmp = expr, &tmp)
4462 var ccomma
= new
CCodeCommaExpression ();
4464 var temp_var
= get_temp_variable (type
, true, null, false);
4465 emit_temp_var (temp_var
);
4466 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), cexpr
));
4467 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
)));
4477 public override void visit_sizeof_expression (SizeofExpression expr
) {
4478 generate_type_declaration (expr
.type_reference
, cfile
);
4480 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
4481 csizeof
.add_argument (new
CCodeIdentifier (expr
.type_reference
.get_cname ()));
4482 set_cvalue (expr
, csizeof
);
4485 public override void visit_typeof_expression (TypeofExpression expr
) {
4486 set_cvalue (expr
, get_type_id_expression (expr
.type_reference
));
4489 public override void visit_unary_expression (UnaryExpression expr
) {
4490 if (expr
.operator
== UnaryOperator
.REF
|| expr
.operator
== UnaryOperator
.OUT
) {
4491 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (expr
.inner
)));
4493 var array_type
= expr
.value_type as ArrayType
;
4494 if (array_type
!= null) {
4495 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4496 append_array_size (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_length_cexpression (expr
.inner
, dim
)));
4500 var delegate_type
= expr
.value_type as DelegateType
;
4501 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
4502 CCodeExpression target_destroy_notify
;
4503 set_delegate_target (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_delegate_target_cexpression (expr
.inner
, out target_destroy_notify
)));
4504 if (target_destroy_notify
!= null) {
4505 set_delegate_target_destroy_notify (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, target_destroy_notify
));
4512 CCodeUnaryOperator op
;
4513 if (expr
.operator
== UnaryOperator
.PLUS
) {
4514 op
= CCodeUnaryOperator
.PLUS
;
4515 } else if (expr
.operator
== UnaryOperator
.MINUS
) {
4516 op
= CCodeUnaryOperator
.MINUS
;
4517 } else if (expr
.operator
== UnaryOperator
.LOGICAL_NEGATION
) {
4518 op
= CCodeUnaryOperator
.LOGICAL_NEGATION
;
4519 } else if (expr
.operator
== UnaryOperator
.BITWISE_COMPLEMENT
) {
4520 op
= CCodeUnaryOperator
.BITWISE_COMPLEMENT
;
4521 } else if (expr
.operator
== UnaryOperator
.INCREMENT
) {
4522 op
= CCodeUnaryOperator
.PREFIX_INCREMENT
;
4523 } else if (expr
.operator
== UnaryOperator
.DECREMENT
) {
4524 op
= CCodeUnaryOperator
.PREFIX_DECREMENT
;
4526 assert_not_reached ();
4528 set_cvalue (expr
, new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
4531 public CCodeExpression?
try_cast_value_to_type (CCodeExpression ccodeexpr
, DataType from
, DataType to
, Expression? expr
= null) {
4532 if (from
== null || gvalue_type
== null || from
.data_type
!= gvalue_type
|| to
.get_type_id () == null) {
4536 // explicit conversion from GValue
4537 var ccall
= new
CCodeFunctionCall (get_value_getter_function (to
));
4538 CCodeExpression gvalue
;
4539 if (from
.nullable
) {
4542 gvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ccodeexpr
);
4544 ccall
.add_argument (gvalue
);
4546 CCodeExpression rv
= ccall
;
4548 if (expr
!= null && to is ArrayType
) {
4549 // null-terminated string array
4550 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strv_length"));
4551 len_call
.add_argument (rv
);
4552 append_array_size (expr
, len_call
);
4553 } else if (to is StructValueType
) {
4554 var temp_decl
= get_temp_variable (to
, true, null, true);
4555 emit_temp_var (temp_decl
);
4556 var ctemp
= get_variable_cexpression (temp_decl
.name
);
4558 rv
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeCastExpression (rv
, (new
PointerType(to
)).get_cname ()));
4559 var holds
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VALUE_HOLDS"));
4560 holds
.add_argument (gvalue
);
4561 holds
.add_argument (new
CCodeIdentifier (to
.get_type_id ()));
4562 var cond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, holds
, ccall
);
4563 var warn
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_warning"));
4564 warn
.add_argument (new
CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
4565 var fail
= new
CCodeCommaExpression ();
4566 fail
.append_expression (warn
);
4567 fail
.append_expression (ctemp
);
4568 rv
= new
CCodeConditionalExpression (cond
, rv
, fail
);
4574 int next_variant_function_id
= 0;
4576 public CCodeExpression?
try_cast_variant_to_type (CCodeExpression ccodeexpr
, DataType from
, DataType to
, Expression? expr
= null) {
4577 if (from
== null || gvariant_type
== null || from
.data_type
!= gvariant_type
) {
4581 string variant_func
= "_variant_get%d".printf (++next_variant_function_id
);
4583 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (variant_func
));
4584 ccall
.add_argument (ccodeexpr
);
4586 var cfunc
= new
CCodeFunction (variant_func
);
4587 cfunc
.modifiers
= CCodeModifiers
.STATIC
;
4588 cfunc
.add_parameter (new
CCodeParameter ("value", "GVariant*"));
4590 if (!to
.is_real_non_null_struct_type ()) {
4591 cfunc
.return_type
= to
.get_cname ();
4594 if (to
.is_real_non_null_struct_type ()) {
4595 // structs are returned via out parameter
4596 cfunc
.add_parameter (new
CCodeParameter ("result", to
.get_cname () + "*"));
4597 } else if (to is ArrayType
) {
4598 // return array length if appropriate
4599 var array_type
= (ArrayType
) to
;
4601 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4602 var temp_decl
= get_temp_variable (int_type
, false, expr
);
4603 emit_temp_var (temp_decl
);
4605 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_decl
.name
)));
4606 cfunc
.add_parameter (new
CCodeParameter (get_array_length_cname ("result", dim
), "int*"));
4607 append_array_size (expr
, get_variable_cexpression (temp_decl
.name
));
4611 push_function (cfunc
);
4613 var result
= deserialize_expression (to
, new
CCodeIdentifier ("value"), new
CCodeIdentifier ("*result"));
4614 ccode
.add_return (result
);
4618 cfile
.add_function_declaration (cfunc
);
4619 cfile
.add_function (cfunc
);
4624 public virtual CCodeExpression?
deserialize_expression (DataType type
, CCodeExpression variant_expr
, CCodeExpression? expr
) {
4628 public virtual CCodeExpression?
serialize_expression (DataType type
, CCodeExpression expr
) {
4632 public override void visit_cast_expression (CastExpression expr
) {
4633 var valuecast
= try_cast_value_to_type (get_cvalue (expr
.inner
), expr
.inner
.value_type
, expr
.type_reference
, expr
);
4634 if (valuecast
!= null) {
4635 set_cvalue (expr
, valuecast
);
4639 var variantcast
= try_cast_variant_to_type (get_cvalue (expr
.inner
), expr
.inner
.value_type
, expr
.type_reference
, expr
);
4640 if (variantcast
!= null) {
4641 set_cvalue (expr
, variantcast
);
4645 generate_type_declaration (expr
.type_reference
, cfile
);
4647 var cl
= expr
.type_reference
.data_type as Class
;
4648 var iface
= expr
.type_reference
.data_type as Interface
;
4649 if (context
.profile
== Profile
.GOBJECT
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
4650 // checked cast for strict subtypes of GTypeInstance
4651 if (expr
.is_silent_cast
) {
4652 var ccomma
= new
CCodeCommaExpression ();
4653 var temp_decl
= get_temp_variable (expr
.inner
.value_type
, true, expr
, false);
4655 emit_temp_var (temp_decl
);
4657 var ctemp
= get_variable_cexpression (temp_decl
.name
);
4658 var cinit
= new
CCodeAssignment (ctemp
, get_cvalue (expr
.inner
));
4659 var ccheck
= create_type_check (ctemp
, expr
.type_reference
);
4660 var ccast
= new
CCodeCastExpression (ctemp
, expr
.type_reference
.get_cname ());
4661 var cnull
= new
CCodeConstant ("NULL");
4663 ccomma
.append_expression (cinit
);
4664 ccomma
.append_expression (new
CCodeConditionalExpression (ccheck
, ccast
, cnull
));
4666 set_cvalue (expr
, ccomma
);
4668 set_cvalue (expr
, generate_instance_cast (get_cvalue (expr
.inner
), expr
.type_reference
.data_type
));
4671 if (expr
.is_silent_cast
) {
4673 Report
.error (expr
.source_reference
, "Operation not supported for this type");
4677 // retain array length
4678 var array_type
= expr
.type_reference as ArrayType
;
4679 if (array_type
!= null && expr
.inner
.value_type is ArrayType
) {
4680 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4681 append_array_size (expr
, get_array_length_cexpression (expr
.inner
, dim
));
4683 } else if (array_type
!= null) {
4684 // cast from non-array to array, set invalid length
4685 // required by string.data, e.g.
4686 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4687 append_array_size (expr
, new
CCodeConstant ("-1"));
4691 var innercexpr
= get_cvalue (expr
.inner
);
4692 if (expr
.type_reference
.data_type is Struct
&& !expr
.type_reference
.nullable
&&
4693 expr
.inner
.value_type
.data_type is Struct
&& expr
.inner
.value_type
.nullable
) {
4694 // nullable integer or float or boolean or struct cast to non-nullable
4695 innercexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, innercexpr
);
4697 set_cvalue (expr
, new
CCodeCastExpression (innercexpr
, expr
.type_reference
.get_cname ()));
4699 if (expr
.type_reference is DelegateType
) {
4700 if (get_delegate_target (expr
.inner
) != null) {
4701 set_delegate_target (expr
, get_delegate_target (expr
.inner
));
4703 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
4705 if (get_delegate_target_destroy_notify (expr
.inner
) != null) {
4706 set_delegate_target_destroy_notify (expr
, get_delegate_target_destroy_notify (expr
.inner
));
4708 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
4714 public override void visit_named_argument (NamedArgument expr
) {
4715 set_cvalue (expr
, get_cvalue (expr
.inner
));
4718 public override void visit_pointer_indirection (PointerIndirection expr
) {
4719 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_cvalue (expr
.inner
)));
4722 public override void visit_addressof_expression (AddressofExpression expr
) {
4723 if (get_cvalue (expr
.inner
) is CCodeCommaExpression
) {
4724 var ccomma
= get_cvalue (expr
.inner
) as CCodeCommaExpression
;
4725 var inner
= ccomma
.get_inner ();
4726 var last
= inner
.get (inner
.size
- 1);
4727 ccomma
.set_expression (inner
.size
- 1, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, (CCodeExpression
) last
));
4728 set_cvalue (expr
, ccomma
);
4730 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (expr
.inner
)));
4734 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
4735 /* (tmp = var, var = null, tmp) */
4736 var temp_decl
= get_temp_variable (expr
.value_type
, true, expr
, false);
4737 emit_temp_var (temp_decl
);
4738 var cvar
= get_variable_cexpression (temp_decl
.name
);
4740 ccode
.add_expression (new
CCodeAssignment (cvar
, get_cvalue (expr
.inner
)));
4741 ccode
.add_expression (new
CCodeAssignment (get_cvalue (expr
.inner
), new
CCodeConstant ("NULL")));
4743 set_cvalue (expr
, cvar
);
4745 var array_type
= expr
.value_type as ArrayType
;
4746 if (array_type
!= null) {
4747 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4748 append_array_size (expr
, get_array_length_cexpression (expr
.inner
, dim
));
4752 var delegate_type
= expr
.value_type as DelegateType
;
4753 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
4754 CCodeExpression target_destroy_notify
;
4755 set_delegate_target (expr
, get_delegate_target_cexpression (expr
.inner
, out target_destroy_notify
));
4756 if (target_destroy_notify
!= null) {
4757 set_delegate_target_destroy_notify (expr
, target_destroy_notify
);
4762 public override void visit_binary_expression (BinaryExpression expr
) {
4763 var cleft
= get_cvalue (expr
.left
);
4764 var cright
= get_cvalue (expr
.right
);
4766 CCodeExpression? left_chain
= null;
4768 var lbe
= (BinaryExpression
) expr
.left
;
4770 var temp_decl
= get_temp_variable (lbe
.right
.value_type
, true, null, false);
4771 emit_temp_var (temp_decl
);
4772 var cvar
= get_variable_cexpression (temp_decl
.name
);
4773 var ccomma
= new
CCodeCommaExpression ();
4774 var clbe
= (CCodeBinaryExpression
) get_cvalue (lbe
);
4776 clbe
= (CCodeBinaryExpression
) clbe
.right
;
4778 ccomma
.append_expression (new
CCodeAssignment (cvar
, get_cvalue (lbe
.right
)));
4779 clbe
.right
= get_variable_cexpression (temp_decl
.name
);
4780 ccomma
.append_expression (cleft
);
4782 left_chain
= ccomma
;
4785 CCodeBinaryOperator op
;
4786 if (expr
.operator
== BinaryOperator
.PLUS
) {
4787 op
= CCodeBinaryOperator
.PLUS
;
4788 } else if (expr
.operator
== BinaryOperator
.MINUS
) {
4789 op
= CCodeBinaryOperator
.MINUS
;
4790 } else if (expr
.operator
== BinaryOperator
.MUL
) {
4791 op
= CCodeBinaryOperator
.MUL
;
4792 } else if (expr
.operator
== BinaryOperator
.DIV
) {
4793 op
= CCodeBinaryOperator
.DIV
;
4794 } else if (expr
.operator
== BinaryOperator
.MOD
) {
4795 if (expr
.value_type
.equals (double_type
)) {
4796 cfile
.add_include ("math.h");
4797 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("fmod"));
4798 ccall
.add_argument (cleft
);
4799 ccall
.add_argument (cright
);
4800 set_cvalue (expr
, ccall
);
4802 } else if (expr
.value_type
.equals (float_type
)) {
4803 cfile
.add_include ("math.h");
4804 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("fmodf"));
4805 ccall
.add_argument (cleft
);
4806 ccall
.add_argument (cright
);
4807 set_cvalue (expr
, ccall
);
4810 op
= CCodeBinaryOperator
.MOD
;
4812 } else if (expr
.operator
== BinaryOperator
.SHIFT_LEFT
) {
4813 op
= CCodeBinaryOperator
.SHIFT_LEFT
;
4814 } else if (expr
.operator
== BinaryOperator
.SHIFT_RIGHT
) {
4815 op
= CCodeBinaryOperator
.SHIFT_RIGHT
;
4816 } else if (expr
.operator
== BinaryOperator
.LESS_THAN
) {
4817 op
= CCodeBinaryOperator
.LESS_THAN
;
4818 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN
) {
4819 op
= CCodeBinaryOperator
.GREATER_THAN
;
4820 } else if (expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
) {
4821 op
= CCodeBinaryOperator
.LESS_THAN_OR_EQUAL
;
4822 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
4823 op
= CCodeBinaryOperator
.GREATER_THAN_OR_EQUAL
;
4824 } else if (expr
.operator
== BinaryOperator
.EQUALITY
) {
4825 op
= CCodeBinaryOperator
.EQUALITY
;
4826 } else if (expr
.operator
== BinaryOperator
.INEQUALITY
) {
4827 op
= CCodeBinaryOperator
.INEQUALITY
;
4828 } else if (expr
.operator
== BinaryOperator
.BITWISE_AND
) {
4829 op
= CCodeBinaryOperator
.BITWISE_AND
;
4830 } else if (expr
.operator
== BinaryOperator
.BITWISE_OR
) {
4831 op
= CCodeBinaryOperator
.BITWISE_OR
;
4832 } else if (expr
.operator
== BinaryOperator
.BITWISE_XOR
) {
4833 op
= CCodeBinaryOperator
.BITWISE_XOR
;
4834 } else if (expr
.operator
== BinaryOperator
.AND
) {
4835 op
= CCodeBinaryOperator
.AND
;
4836 } else if (expr
.operator
== BinaryOperator
.OR
) {
4837 op
= CCodeBinaryOperator
.OR
;
4838 } else if (expr
.operator
== BinaryOperator
.IN
) {
4839 if (expr
.right
.value_type is ArrayType
) {
4840 var array_type
= (ArrayType
) expr
.right
.value_type
;
4841 var node
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_contains_wrapper (array_type
)));
4842 node
.add_argument (cright
);
4843 node
.add_argument (get_array_length_cexpression (expr
.right
));
4844 if (array_type
.element_type is StructValueType
) {
4845 node
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cleft
));
4847 node
.add_argument (cleft
);
4849 set_cvalue (expr
, node
);
4851 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeBinaryExpression (CCodeBinaryOperator
.BITWISE_AND
, cright
, cleft
), cleft
));
4855 assert_not_reached ();
4858 if (expr
.operator
== BinaryOperator
.EQUALITY
||
4859 expr
.operator
== BinaryOperator
.INEQUALITY
) {
4860 var left_type
= expr
.left
.target_type
;
4861 var right_type
= expr
.right
.target_type
;
4862 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
4864 if (left_type is StructValueType
&& right_type is StructValueType
) {
4865 var equalfunc
= generate_struct_equal_function ((Struct
) left_type
.data_type as Struct
);
4866 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
4867 ccall
.add_argument (cleft
);
4868 ccall
.add_argument (cright
);
4870 cright
= new
CCodeConstant ("TRUE");
4871 } else if ((left_type is IntegerType
|| left_type is FloatingType
|| left_type is BooleanType
) && left_type
.nullable
&&
4872 (right_type is IntegerType
|| right_type is FloatingType
|| right_type is BooleanType
) && right_type
.nullable
) {
4873 var equalfunc
= generate_numeric_equal_function ((Struct
) left_type
.data_type as Struct
);
4874 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
4875 ccall
.add_argument (cleft
);
4876 ccall
.add_argument (cright
);
4878 cright
= new
CCodeConstant ("TRUE");
4882 if (!(expr
.left
.value_type is NullType
)
4883 && expr
.left
.value_type
.compatible (string_type
)
4884 && !(expr
.right
.value_type is NullType
)
4885 && expr
.right
.value_type
.compatible (string_type
)) {
4886 if (expr
.operator
== BinaryOperator
.PLUS
) {
4887 // string concatenation
4888 if (expr
.left
.is_constant () && expr
.right
.is_constant ()) {
4891 if (cleft is CCodeIdentifier
) {
4892 left
= ((CCodeIdentifier
) cleft
).name
;
4893 } else if (cleft is CCodeConstant
) {
4894 left
= ((CCodeConstant
) cleft
).name
;
4896 assert_not_reached ();
4898 if (cright is CCodeIdentifier
) {
4899 right
= ((CCodeIdentifier
) cright
).name
;
4900 } else if (cright is CCodeConstant
) {
4901 right
= ((CCodeConstant
) cright
).name
;
4903 assert_not_reached ();
4906 set_cvalue (expr
, new
CCodeConstant ("%s %s".printf (left
, right
)));
4909 if (context
.profile
== Profile
.POSIX
) {
4910 // convert to strcat(strcpy(malloc(1+strlen(a)+strlen(b)),a),b)
4911 var strcat
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcat"));
4912 var strcpy
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcpy"));
4913 var malloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("malloc"));
4915 var strlen_a
= new
CCodeFunctionCall (new
CCodeIdentifier ("strlen"));
4916 strlen_a
.add_argument(cleft
);
4917 var strlen_b
= new
CCodeFunctionCall (new
CCodeIdentifier ("strlen"));
4918 strlen_b
.add_argument(cright
);
4919 var newlength
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier("1"),
4920 new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, strlen_a
, strlen_b
));
4921 malloc
.add_argument(newlength
);
4923 strcpy
.add_argument(malloc
);
4924 strcpy
.add_argument(cleft
);
4926 strcat
.add_argument(strcpy
);
4927 strcat
.add_argument(cright
);
4928 set_cvalue (expr
, strcat
);
4930 // convert to g_strconcat (a, b, NULL)
4931 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strconcat"));
4932 ccall
.add_argument (cleft
);
4933 ccall
.add_argument (cright
);
4934 ccall
.add_argument (new
CCodeConstant("NULL"));
4935 set_cvalue (expr
, ccall
);
4939 } else if (expr
.operator
== BinaryOperator
.EQUALITY
4940 || expr
.operator
== BinaryOperator
.INEQUALITY
4941 || expr
.operator
== BinaryOperator
.LESS_THAN
4942 || expr
.operator
== BinaryOperator
.GREATER_THAN
4943 || expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
4944 || expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
4945 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
4946 ccall
.add_argument (cleft
);
4947 ccall
.add_argument (cright
);
4949 cright
= new
CCodeConstant ("0");
4953 set_cvalue (expr
, new
CCodeBinaryExpression (op
, cleft
, cright
));
4954 if (left_chain
!= null) {
4955 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, left_chain
, get_cvalue (expr
)));
4959 public string?
get_type_check_function (TypeSymbol type
) {
4960 var cl
= type as Class
;
4961 if (cl
!= null && cl
.type_check_function
!= null) {
4962 return cl
.type_check_function
;
4963 } else if ((cl
!= null && cl
.is_compact
) || type is Struct
|| type is Enum
|| type is Delegate
) {
4966 return type
.get_upper_case_cname ("IS_");
4970 CCodeExpression?
create_type_check (CCodeNode ccodenode
, DataType type
) {
4971 var et
= type as ErrorType
;
4972 if (et
!= null && et
.error_code
!= null) {
4973 var matches_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_matches"));
4974 matches_call
.add_argument ((CCodeExpression
) ccodenode
);
4975 matches_call
.add_argument (new
CCodeIdentifier (et
.error_domain
.get_upper_case_cname ()));
4976 matches_call
.add_argument (new
CCodeIdentifier (et
.error_code
.get_cname ()));
4977 return matches_call
;
4978 } else if (et
!= null && et
.error_domain
!= null) {
4979 var instance_domain
= new CCodeMemberAccess
.pointer ((CCodeExpression
) ccodenode
, "domain");
4980 var type_domain
= new
CCodeIdentifier (et
.error_domain
.get_upper_case_cname ());
4981 return new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, instance_domain
, type_domain
);
4983 string type_check_func
= get_type_check_function (type
.data_type
);
4984 if (type_check_func
== null) {
4985 return new
CCodeInvalidExpression ();
4987 var ccheck
= new
CCodeFunctionCall (new
CCodeIdentifier (type_check_func
));
4988 ccheck
.add_argument ((CCodeExpression
) ccodenode
);
4993 string generate_array_contains_wrapper (ArrayType array_type
) {
4994 string array_contains_func
= "_vala_%s_array_contains".printf (array_type
.element_type
.get_lower_case_cname ());
4996 if (!add_wrapper (array_contains_func
)) {
4997 return array_contains_func
;
5000 var function
= new
CCodeFunction (array_contains_func
, "gboolean");
5001 function
.modifiers
= CCodeModifiers
.STATIC
;
5003 function
.add_parameter (new
CCodeParameter ("stack", array_type
.get_cname ()));
5004 function
.add_parameter (new
CCodeParameter ("stack_length", "int"));
5005 if (array_type
.element_type is StructValueType
) {
5006 function
.add_parameter (new
CCodeParameter ("needle", array_type
.element_type
.get_cname () + "*"));
5008 function
.add_parameter (new
CCodeParameter ("needle", array_type
.element_type
.get_cname ()));
5011 push_function (function
);
5013 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
5015 var cloop_initializer
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
5016 var cloop_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("stack_length"));
5017 var cloop_iterator
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i"));
5018 ccode
.open_for (cloop_initializer
, cloop_condition
, cloop_iterator
);
5020 var celement
= new
CCodeElementAccess (new
CCodeIdentifier ("stack"), new
CCodeIdentifier ("i"));
5021 var cneedle
= new
CCodeIdentifier ("needle");
5022 CCodeBinaryExpression cif_condition
;
5023 if (array_type
.element_type
.compatible (string_type
)) {
5024 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
5025 ccall
.add_argument (celement
);
5026 ccall
.add_argument (cneedle
);
5027 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ccall
, new
CCodeConstant ("0"));
5028 } else if (array_type
.element_type is StructValueType
) {
5029 var equalfunc
= generate_struct_equal_function ((Struct
) array_type
.element_type
.data_type as Struct
);
5030 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
5031 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, celement
));
5032 ccall
.add_argument (cneedle
);
5033 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ccall
, new
CCodeConstant ("TRUE"));
5035 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cneedle
, celement
);
5038 ccode
.open_if (cif_condition
);
5039 ccode
.add_return (new
CCodeConstant ("TRUE"));
5044 ccode
.add_return (new
CCodeConstant ("FALSE"));
5048 cfile
.add_function_declaration (function
);
5049 cfile
.add_function (function
);
5051 return array_contains_func
;
5054 public override void visit_type_check (TypeCheck expr
) {
5055 generate_type_declaration (expr
.type_reference
, cfile
);
5057 set_cvalue (expr
, create_type_check (get_cvalue (expr
.expression
), expr
.type_reference
));
5058 if (get_cvalue (expr
) is CCodeInvalidExpression
) {
5059 Report
.error (expr
.source_reference
, "type check expressions not supported for compact classes, structs, and enums");
5063 public override void visit_lambda_expression (LambdaExpression lambda
) {
5064 // use instance position from delegate
5065 var dt
= (DelegateType
) lambda
.target_type
;
5066 lambda
.method
.cinstance_parameter_position
= dt
.delegate_symbol
.cinstance_parameter_position
;
5068 lambda
.accept_children (this
);
5070 bool expr_owned
= lambda
.value_type
.value_owned
;
5072 set_cvalue (lambda
, new
CCodeIdentifier (lambda
.method
.get_cname ()));
5074 var delegate_type
= (DelegateType
) lambda
.target_type
;
5075 if (lambda
.method
.closure
) {
5076 int block_id
= get_block_id (current_closure_block
);
5077 var delegate_target
= get_variable_cexpression ("_data%d_".printf (block_id
));
5078 if (expr_owned
|| delegate_type
.is_called_once
) {
5079 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (block_id
)));
5080 ref_call
.add_argument (delegate_target
);
5081 delegate_target
= ref_call
;
5082 set_delegate_target_destroy_notify (lambda
, new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
5084 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5086 set_delegate_target (lambda
, delegate_target
);
5087 } else if (get_this_type () != null || in_constructor
) {
5088 CCodeExpression delegate_target
= get_result_cexpression ("self");
5089 if (expr_owned
|| delegate_type
.is_called_once
) {
5090 if (get_this_type () != null) {
5091 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (get_this_type (), lambda
.source_reference
));
5092 ref_call
.add_argument (delegate_target
);
5093 delegate_target
= ref_call
;
5094 set_delegate_target_destroy_notify (lambda
, get_destroy_func_expression (get_this_type ()));
5097 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_ref"));
5098 ref_call
.add_argument (delegate_target
);
5099 delegate_target
= ref_call
;
5100 set_delegate_target_destroy_notify (lambda
, new
CCodeIdentifier ("g_object_unref"));
5103 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5105 set_delegate_target (lambda
, delegate_target
);
5107 set_delegate_target (lambda
, new
CCodeConstant ("NULL"));
5108 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5112 public CCodeExpression
convert_from_generic_pointer (CCodeExpression cexpr
, DataType actual_type
) {
5114 if (is_reference_type_argument (actual_type
) || is_nullable_value_type_argument (actual_type
)) {
5115 result
= new
CCodeCastExpression (cexpr
, actual_type
.get_cname ());
5116 } else if (is_signed_integer_type_argument (actual_type
)) {
5117 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GPOINTER_TO_INT"));
5118 cconv
.add_argument (cexpr
);
5120 } else if (is_unsigned_integer_type_argument (actual_type
)) {
5121 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GPOINTER_TO_UINT"));
5122 cconv
.add_argument (cexpr
);
5128 public CCodeExpression
convert_to_generic_pointer (CCodeExpression cexpr
, DataType actual_type
) {
5130 if (is_signed_integer_type_argument (actual_type
)) {
5131 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GINT_TO_POINTER"));
5132 cconv
.add_argument (cexpr
);
5134 } else if (is_unsigned_integer_type_argument (actual_type
)) {
5135 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GUINT_TO_POINTER"));
5136 cconv
.add_argument (cexpr
);
5142 // manage memory and implicit casts
5143 public CCodeExpression
transform_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
5144 var cexpr
= source_cexpr
;
5145 if (expression_type
== null) {
5150 if (expression_type
.value_owned
5151 && expression_type
.floating_reference
) {
5152 /* floating reference, sink it.
5154 var cl
= expression_type
.data_type as ObjectTypeSymbol
;
5155 var sink_func
= (cl
!= null) ? cl
.get_ref_sink_function () : null;
5157 if (sink_func
!= null) {
5158 var csink
= new
CCodeFunctionCall (new
CCodeIdentifier (sink_func
));
5159 csink
.add_argument (cexpr
);
5163 Report
.error (null, "type `%s' does not support floating references".printf (expression_type
.data_type
.name
));
5167 bool boxing
= (expression_type is ValueType
&& !expression_type
.nullable
5168 && target_type is ValueType
&& target_type
.nullable
);
5169 bool unboxing
= (expression_type is ValueType
&& expression_type
.nullable
5170 && target_type is ValueType
&& !target_type
.nullable
);
5172 bool gvalue_boxing
= (context
.profile
== Profile
.GOBJECT
5173 && target_type
!= null
5174 && target_type
.data_type
== gvalue_type
5175 && !(expression_type is NullType
)
5176 && expression_type
.get_type_id () != "G_TYPE_VALUE");
5177 bool gvariant_boxing
= (context
.profile
== Profile
.GOBJECT
5178 && target_type
!= null
5179 && target_type
.data_type
== gvariant_type
5180 && !(expression_type is NullType
)
5181 && expression_type
.data_type
!= gvariant_type
);
5183 if (expression_type
.value_owned
5184 && (target_type
== null || !target_type
.value_owned
|| boxing
|| unboxing
)
5185 && !gvalue_boxing
/* gvalue can assume ownership of value, no need to free it */) {
5186 // value leaked, destroy it
5187 var pointer_type
= target_type as PointerType
;
5188 if (pointer_type
!= null && !(pointer_type
.base_type is VoidType
)) {
5189 // manual memory management for non-void pointers
5190 // treat void* special to not leak memory with void* method parameters
5191 } else if (requires_destroy (expression_type
)) {
5192 var decl
= get_temp_variable (expression_type
, true, expression_type
, false);
5193 emit_temp_var (decl
);
5194 temp_ref_vars
.insert (0, decl
);
5195 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (decl
.name
), cexpr
));
5196 cexpr
= get_variable_cexpression (decl
.name
);
5198 if (expression_type is ArrayType
&& expr
!= null) {
5199 var array_type
= (ArrayType
) expression_type
;
5200 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5201 var len_decl
= new
LocalVariable (int_type
.copy (), get_array_length_cname (decl
.name
, dim
));
5202 emit_temp_var (len_decl
);
5203 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (len_decl
.name
), get_array_length_cexpression (expr
, dim
)));
5205 } else if (expression_type is DelegateType
&& expr
!= null) {
5206 var target_decl
= new
LocalVariable (new
PointerType (new
VoidType ()), get_delegate_target_cname (decl
.name
));
5207 emit_temp_var (target_decl
);
5208 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
));
5209 emit_temp_var (target_destroy_notify_decl
);
5210 CCodeExpression target_destroy_notify
;
5211 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (target_decl
.name
), get_delegate_target_cexpression (expr
, out target_destroy_notify
)));
5212 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (target_destroy_notify_decl
.name
), target_destroy_notify
));
5218 if (target_type
== null) {
5219 // value will be destroyed, no need for implicit casts
5223 if (gvalue_boxing
) {
5224 // implicit conversion to GValue
5225 var decl
= get_temp_variable (target_type
, true, target_type
);
5226 emit_temp_var (decl
);
5228 if (!target_type
.value_owned
) {
5229 // boxed GValue leaked, destroy it
5230 temp_ref_vars
.insert (0, decl
);
5233 var ccomma
= new
CCodeCommaExpression ();
5235 if (target_type
.nullable
) {
5236 var newcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
5237 newcall
.add_argument (new
CCodeConstant ("GValue"));
5238 newcall
.add_argument (new
CCodeConstant ("1"));
5239 var newassignment
= new
CCodeAssignment (get_variable_cexpression (decl
.name
), newcall
);
5240 ccomma
.append_expression (newassignment
);
5243 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
5244 if (target_type
.nullable
) {
5245 ccall
.add_argument (get_variable_cexpression (decl
.name
));
5247 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
)));
5249 ccall
.add_argument (new
CCodeIdentifier (expression_type
.get_type_id ()));
5250 ccomma
.append_expression (ccall
);
5252 if (requires_destroy (expression_type
)) {
5253 ccall
= new
CCodeFunctionCall (get_value_taker_function (expression_type
));
5255 ccall
= new
CCodeFunctionCall (get_value_setter_function (expression_type
));
5257 if (target_type
.nullable
) {
5258 ccall
.add_argument (get_variable_cexpression (decl
.name
));
5260 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
)));
5262 if (expression_type
.is_real_non_null_struct_type ()) {
5263 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
5265 ccall
.add_argument (cexpr
);
5268 ccomma
.append_expression (ccall
);
5270 ccomma
.append_expression (get_variable_cexpression (decl
.name
));
5274 } else if (gvariant_boxing
) {
5275 // implicit conversion to GVariant
5276 string variant_func
= "_variant_new%d".printf (++next_variant_function_id
);
5278 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (variant_func
));
5279 ccall
.add_argument (cexpr
);
5281 var cfunc
= new
CCodeFunction (variant_func
, "GVariant*");
5282 cfunc
.modifiers
= CCodeModifiers
.STATIC
;
5283 cfunc
.add_parameter (new
CCodeParameter ("value", expression_type
.get_cname ()));
5285 if (expression_type is ArrayType
) {
5286 // return array length if appropriate
5287 var array_type
= (ArrayType
) expression_type
;
5289 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5290 ccall
.add_argument (get_array_length_cexpression (expr
, dim
));
5291 cfunc
.add_parameter (new
CCodeParameter (get_array_length_cname ("value", dim
), "gint"));
5295 push_function (cfunc
);
5297 var result
= serialize_expression (expression_type
, new
CCodeIdentifier ("value"));
5299 // sink floating reference
5300 var sink
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_ref_sink"));
5301 sink
.add_argument (result
);
5302 ccode
.add_return (sink
);
5306 cfile
.add_function_declaration (cfunc
);
5307 cfile
.add_function (cfunc
);
5310 } else if (boxing
) {
5311 // value needs to be boxed
5313 var unary
= cexpr as CCodeUnaryExpression
;
5314 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
5316 cexpr
= unary
.inner
;
5317 } else if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
5318 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
5320 var decl
= get_temp_variable (expression_type
, expression_type
.value_owned
, expression_type
, false);
5321 emit_temp_var (decl
);
5323 var ccomma
= new
CCodeCommaExpression ();
5324 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (decl
.name
), cexpr
));
5325 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
)));
5328 } else if (unboxing
) {
5331 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cexpr
);
5333 cexpr
= get_implicit_cast_expression (cexpr
, expression_type
, target_type
, expr
);
5336 if (target_type
.value_owned
&& (!expression_type
.value_owned
|| boxing
|| unboxing
)) {
5337 // need to copy value
5338 if (requires_copy (target_type
) && !(expression_type is NullType
)) {
5339 CodeNode node
= expr
;
5341 node
= expression_type
;
5344 var decl
= get_temp_variable (target_type
, true, node
, false);
5345 emit_temp_var (decl
);
5346 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (decl
.name
), get_ref_cexpression (target_type
, cexpr
, expr
, node
)));
5347 cexpr
= get_variable_cexpression (decl
.name
);
5354 public virtual CCodeExpression
get_implicit_cast_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
5355 var cexpr
= source_cexpr
;
5357 if (expression_type
.data_type
!= null && expression_type
.data_type
== target_type
.data_type
) {
5358 // same type, no cast required
5362 if (expression_type is NullType
) {
5363 // null literal, no cast required when not converting to generic type pointer
5367 generate_type_declaration (target_type
, cfile
);
5369 var cl
= target_type
.data_type as Class
;
5370 var iface
= target_type
.data_type as Interface
;
5371 if (context
.checking
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
5372 // checked cast for strict subtypes of GTypeInstance
5373 return generate_instance_cast (cexpr
, target_type
.data_type
);
5374 } else if (target_type
.data_type
!= null && expression_type
.get_cname () != target_type
.get_cname ()) {
5375 var st
= target_type
.data_type as Struct
;
5376 if (target_type
.data_type
.is_reference_type () || (st
!= null && st
.is_simple_type ())) {
5377 // don't cast non-simple structs
5378 return new
CCodeCastExpression (cexpr
, target_type
.get_cname ());
5387 public void store_property (Property prop
, MemberAccess ma
, CCodeExpression cexpr
, Expression? rhs
= null) {
5388 if (ma
.inner is BaseAccess
) {
5389 if (prop
.base_property
!= null) {
5390 var base_class
= (Class
) prop
.base_property
.parent_symbol
;
5391 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (base_class
.get_upper_case_cname (null))));
5392 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (current_class
.get_lower_case_cname (null))));
5394 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "set_%s".printf (prop
.name
)));
5395 ccall
.add_argument ((CCodeExpression
) get_ccodenode (ma
.inner
));
5396 ccall
.add_argument (cexpr
);
5398 ccode
.add_expression (ccall
);
5399 } else if (prop
.base_interface_property
!= null) {
5400 var base_iface
= (Interface
) prop
.base_interface_property
.parent_symbol
;
5401 string parent_iface_var
= "%s_%s_parent_iface".printf (current_class
.get_lower_case_cname (null), base_iface
.get_lower_case_cname (null));
5403 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), "set_%s".printf (prop
.name
)));
5404 ccall
.add_argument ((CCodeExpression
) get_ccodenode (ma
.inner
));
5405 ccall
.add_argument (cexpr
);
5407 ccode
.add_expression (ccall
);
5412 var set_func
= "g_object_set";
5414 var base_property
= prop
;
5415 if (!prop
.no_accessor_method
) {
5416 if (prop
.base_property
!= null) {
5417 base_property
= prop
.base_property
;
5418 } else if (prop
.base_interface_property
!= null) {
5419 base_property
= prop
.base_interface_property
;
5422 if (prop is DynamicProperty
) {
5423 set_func
= get_dynamic_property_setter_cname ((DynamicProperty
) prop
);
5425 generate_property_accessor_declaration (base_property
.set_accessor
, cfile
);
5426 set_func
= base_property
.set_accessor
.get_cname ();
5430 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (set_func
));
5432 if (prop
.binding
== MemberBinding
.INSTANCE
) {
5433 /* target instance is first argument */
5434 var instance
= (CCodeExpression
) get_ccodenode (ma
.inner
);
5436 if (prop
.parent_symbol is Struct
) {
5437 // we need to pass struct instance by reference
5438 var unary
= instance as CCodeUnaryExpression
;
5439 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
5441 instance
= unary
.inner
;
5442 } else if (instance is CCodeIdentifier
|| instance is CCodeMemberAccess
) {
5443 instance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
);
5445 // if instance is e.g. a function call, we can't take the address of the expression
5446 // (tmp = expr, &tmp)
5448 var temp_var
= get_temp_variable (ma
.inner
.target_type
, true, null, false);
5449 emit_temp_var (temp_var
);
5450 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), instance
));
5452 instance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
));
5456 ccall
.add_argument (instance
);
5459 if (prop
.no_accessor_method
) {
5460 /* property name is second argument of g_object_set */
5461 ccall
.add_argument (prop
.get_canonical_cconstant ());
5464 var array_type
= prop
.property_type as ArrayType
;
5466 if (array_type
!= null && !prop
.no_array_length
) {
5467 var temp_var
= get_temp_variable (prop
.property_type
, true, null, false);
5468 emit_temp_var (temp_var
);
5469 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), cexpr
));
5470 ccall
.add_argument (get_variable_cexpression (temp_var
.name
));
5472 ccall
.add_argument (cexpr
);
5475 if (array_type
!= null && !prop
.no_array_length
&& rhs
!= null) {
5476 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5477 ccall
.add_argument (get_array_length_cexpression (rhs
, dim
));
5479 } else if (prop
.property_type is DelegateType
&& rhs
!= null) {
5480 var delegate_type
= (DelegateType
) prop
.property_type
;
5481 if (delegate_type
.delegate_symbol
.has_target
) {
5482 CCodeExpression delegate_target_destroy_notify
;
5483 ccall
.add_argument (get_delegate_target_cexpression (rhs
, out delegate_target_destroy_notify
));
5487 if (prop
.no_accessor_method
) {
5488 ccall
.add_argument (new
CCodeConstant ("NULL"));
5491 ccode
.add_expression (ccall
);
5494 /* indicates whether a given Expression eligable for an ADDRESS_OF operator
5495 * from a vala to C point of view all expressions denoting locals, fields and
5496 * parameters are eligable to an ADDRESS_OF operator */
5497 public bool is_address_of_possible (Expression e
) {
5498 if (gvalue_type
!= null && e
.target_type
.data_type
== gvalue_type
&& e
.value_type
.data_type
!= gvalue_type
) {
5499 // implicit conversion to GValue is not addressable
5503 var ma
= e as MemberAccess
;
5509 return (ma
.symbol_reference is Variable
);
5512 /* retrieve the correct address_of expression for a give expression, creates temporary variables
5513 * where necessary, ce is the corresponding ccode expression for e */
5514 public CCodeExpression
get_address_of_expression (Expression e
, CCodeExpression ce
) {
5515 // is address of trivially possible?
5516 if (is_address_of_possible (e
)) {
5517 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ce
);
5520 var ccomma
= new
CCodeCommaExpression ();
5521 DataType address_of_type
;
5522 if (gvalue_type
!= null && e
.target_type
!= null && e
.target_type
.data_type
== gvalue_type
) {
5523 // implicit conversion to GValue
5524 address_of_type
= e
.target_type
;
5526 address_of_type
= e
.value_type
;
5528 var temp_decl
= get_temp_variable (address_of_type
, true, null, false);
5529 var ctemp
= get_variable_cexpression (temp_decl
.name
);
5530 emit_temp_var (temp_decl
);
5531 ccomma
.append_expression (new
CCodeAssignment (ctemp
, ce
));
5532 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
5536 public bool add_wrapper (string wrapper_name
) {
5537 return wrappers
.add (wrapper_name
);
5540 public bool add_generated_external_symbol (Symbol external_symbol
) {
5541 return generated_external_symbols
.add (external_symbol
);
5544 public static DataType
get_data_type_for_symbol (TypeSymbol sym
) {
5545 DataType type
= null;
5548 type
= new
ObjectType ((Class
) sym
);
5549 } else if (sym is Interface
) {
5550 type
= new
ObjectType ((Interface
) sym
);
5551 } else if (sym is Struct
) {
5552 var st
= (Struct
) sym
;
5553 if (st
.is_boolean_type ()) {
5554 type
= new
BooleanType (st
);
5555 } else if (st
.is_integer_type ()) {
5556 type
= new
IntegerType (st
);
5557 } else if (st
.is_floating_type ()) {
5558 type
= new
FloatingType (st
);
5560 type
= new
StructValueType (st
);
5562 } else if (sym is Enum
) {
5563 type
= new
EnumValueType ((Enum
) sym
);
5564 } else if (sym is ErrorDomain
) {
5565 type
= new
ErrorType ((ErrorDomain
) sym
, null);
5566 } else if (sym is ErrorCode
) {
5567 type
= new
ErrorType ((ErrorDomain
) sym
.parent_symbol
, (ErrorCode
) sym
);
5569 Report
.error (null, "internal error: `%s' is not a supported type".printf (sym
.get_full_name ()));
5570 return new
InvalidType ();
5576 public CCodeExpression?
default_value_for_type (DataType type
, bool initializer_expression
) {
5577 var st
= type
.data_type as Struct
;
5578 var array_type
= type as ArrayType
;
5579 if (initializer_expression
&& !type
.nullable
&&
5580 ((st
!= null && !st
.is_simple_type ()) ||
5581 (array_type
!= null && array_type
.fixed_length
))) {
5582 // 0-initialize struct with struct initializer { 0 }
5583 // only allowed as initializer expression in C
5584 var clist
= new
CCodeInitializerList ();
5585 clist
.append (new
CCodeConstant ("0"));
5587 } else if ((type
.data_type
!= null && type
.data_type
.is_reference_type ())
5589 || type is PointerType
|| type is DelegateType
5590 || (array_type
!= null && !array_type
.fixed_length
)) {
5591 return new
CCodeConstant ("NULL");
5592 } else if (type
.data_type
!= null && type
.data_type
.get_default_value () != null) {
5593 return new
CCodeConstant (type
.data_type
.get_default_value ());
5594 } else if (type
.type_parameter
!= null) {
5595 return new
CCodeConstant ("NULL");
5596 } else if (type is ErrorType
) {
5597 return new
CCodeConstant ("NULL");
5602 private void create_property_type_check_statement (Property prop
, bool check_return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
5603 if (check_return_type
) {
5604 create_type_check_statement (prop
, prop
.property_type
, t
, non_null
, var_name
);
5606 create_type_check_statement (prop
, new
VoidType (), t
, non_null
, var_name
);
5610 public void create_type_check_statement (CodeNode method_node
, DataType ret_type
, TypeSymbol t
, bool non_null
, string var_name
) {
5611 var ccheck
= new
CCodeFunctionCall ();
5613 if (!context
.assert
) {
5615 } else if (context
.checking
&& ((t is Class
&& !((Class
) t
).is_compact
) || t is Interface
)) {
5616 var ctype_check
= new
CCodeFunctionCall (new
CCodeIdentifier (get_type_check_function (t
)));
5617 ctype_check
.add_argument (new
CCodeIdentifier (var_name
));
5619 CCodeExpression cexpr
= ctype_check
;
5621 var cnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier (var_name
), new
CCodeConstant ("NULL"));
5623 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cnull
, ctype_check
);
5625 ccheck
.add_argument (cexpr
);
5626 } else if (!non_null
) {
5628 } else if (t
== glist_type
|| t
== gslist_type
) {
5629 // NULL is empty list
5632 var cnonnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier (var_name
), new
CCodeConstant ("NULL"));
5633 ccheck
.add_argument (cnonnull
);
5636 var cm
= method_node as CreationMethod
;
5637 if (cm
!= null && cm
.parent_symbol is ObjectTypeSymbol
) {
5638 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
5639 ccheck
.add_argument (new
CCodeConstant ("NULL"));
5640 } else if (ret_type is VoidType
) {
5642 ccheck
.call
= new
CCodeIdentifier ("g_return_if_fail");
5644 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
5646 var cdefault
= default_value_for_type (ret_type
, false);
5647 if (cdefault
!= null) {
5648 ccheck
.add_argument (cdefault
);
5654 ccode
.add_expression (ccheck
);
5657 public int get_param_pos (double param_pos
, bool ellipsis
= false) {
5659 if (param_pos
>= 0) {
5660 return (int) (param_pos
* 1000);
5662 return (int) ((100 + param_pos
) * 1000);
5665 if (param_pos
>= 0) {
5666 return (int) ((100 + param_pos
) * 1000);
5668 return (int) ((200 + param_pos
) * 1000);
5673 public CCodeExpression?
get_ccodenode (Expression node
) {
5674 if (get_cvalue (node
) == null) {
5677 return get_cvalue (node
);
5680 public override void visit_class (Class cl
) {
5683 public void create_postcondition_statement (Expression postcondition
) {
5684 var cassert
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_warn_if_fail"));
5686 postcondition
.emit (this
);
5688 cassert
.add_argument (get_cvalue (postcondition
));
5690 ccode
.add_expression (cassert
);
5693 public virtual bool is_gobject_property (Property prop
) {
5697 public DataType?
get_this_type () {
5698 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) {
5699 return current_method
.this_parameter
.variable_type
;
5700 } else if (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
) {
5701 return current_property_accessor
.prop
.this_parameter
.variable_type
;
5706 public CCodeFunctionCall
generate_instance_cast (CCodeExpression expr
, TypeSymbol type
) {
5707 var result
= new
CCodeFunctionCall (new
CCodeIdentifier (type
.get_upper_case_cname (null)));
5708 result
.add_argument (expr
);
5712 void generate_struct_destroy_function (Struct st
) {
5713 if (cfile
.add_declaration (st
.get_destroy_function ())) {
5714 // only generate function once per source file
5718 var function
= new
CCodeFunction (st
.get_destroy_function (), "void");
5719 function
.modifiers
= CCodeModifiers
.STATIC
;
5720 function
.add_parameter (new
CCodeParameter ("self", st
.get_cname () + "*"));
5722 push_function (function
);
5724 foreach (Field f
in st
.get_fields ()) {
5725 if (f
.binding
== MemberBinding
.INSTANCE
) {
5726 if (requires_destroy (f
.variable_type
)) {
5727 var lhs
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.get_cname ());
5729 var this_access
= new MemberAccess
.simple ("this");
5730 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
5731 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
5733 var ma
= new
MemberAccess (this_access
, f
.name
);
5734 ma
.symbol_reference
= f
;
5735 ma
.value_type
= f
.variable_type
.copy ();
5736 visit_member_access (ma
);
5737 ccode
.add_expression (get_unref_expression (lhs
, f
.variable_type
, ma
));
5744 cfile
.add_function_declaration (function
);
5745 cfile
.add_function (function
);
5748 void generate_struct_copy_function (Struct st
) {
5749 if (cfile
.add_declaration (st
.get_copy_function ())) {
5750 // only generate function once per source file
5754 var function
= new
CCodeFunction (st
.get_copy_function (), "void");
5755 function
.modifiers
= CCodeModifiers
.STATIC
;
5756 function
.add_parameter (new
CCodeParameter ("self", "const " + st
.get_cname () + "*"));
5757 function
.add_parameter (new
CCodeParameter ("dest", st
.get_cname () + "*"));
5759 push_context (new
EmitContext ());
5760 push_function (function
);
5762 foreach (Field f
in st
.get_fields ()) {
5763 if (f
.binding
== MemberBinding
.INSTANCE
) {
5764 CCodeExpression copy
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.name
);
5765 if (requires_copy (f
.variable_type
)) {
5766 var this_access
= new MemberAccess
.simple ("this");
5767 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
5768 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
5769 var ma
= new
MemberAccess (this_access
, f
.name
);
5770 ma
.symbol_reference
= f
;
5771 ma
.value_type
= f
.variable_type
.copy ();
5772 visit_member_access (ma
);
5773 copy
= get_ref_cexpression (f
.variable_type
, copy
, ma
, f
);
5775 var dest
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("dest"), f
.name
);
5777 var array_type
= f
.variable_type as ArrayType
;
5778 if (array_type
!= null && array_type
.fixed_length
) {
5779 // fixed-length (stack-allocated) arrays
5780 cfile
.add_include ("string.h");
5782 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
5783 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
5784 var size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
);
5786 var array_copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
5787 array_copy_call
.add_argument (dest
);
5788 array_copy_call
.add_argument (copy
);
5789 array_copy_call
.add_argument (size
);
5790 ccode
.add_expression (array_copy_call
);
5792 ccode
.add_expression (new
CCodeAssignment (dest
, copy
));
5794 if (array_type
!= null && !f
.no_array_length
) {
5795 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5796 var len_src
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), get_array_length_cname (f
.name
, dim
));
5797 var len_dest
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("dest"), get_array_length_cname (f
.name
, dim
));
5798 ccode
.add_expression (new
CCodeAssignment (len_dest
, len_src
));
5808 cfile
.add_function_declaration (function
);
5809 cfile
.add_function (function
);
5812 public void return_default_value (DataType return_type
) {
5813 ccode
.add_return (default_value_for_type (return_type
, false));
5816 public virtual string?
get_custom_creturn_type (Method m
) {
5820 public virtual void generate_dynamic_method_wrapper (DynamicMethod method
) {
5823 public virtual bool method_has_wrapper (Method method
) {
5827 public virtual CCodeFunctionCall
get_param_spec (Property prop
) {
5828 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
5831 public virtual CCodeFunctionCall
get_signal_creation (Signal sig
, TypeSymbol type
) {
5832 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
5835 public virtual void register_dbus_info (ObjectTypeSymbol bindable
) {
5838 public virtual string get_dynamic_property_getter_cname (DynamicProperty node
) {
5839 Report
.error (node
.source_reference
, "dynamic properties are not supported for %s".printf (node
.dynamic_type
.to_string ()));
5843 public virtual string get_dynamic_property_setter_cname (DynamicProperty node
) {
5844 Report
.error (node
.source_reference
, "dynamic properties are not supported for %s".printf (node
.dynamic_type
.to_string ()));
5848 public virtual string get_dynamic_signal_cname (DynamicSignal node
) {
5852 public virtual string get_dynamic_signal_connect_wrapper_name (DynamicSignal node
) {
5856 public virtual string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal node
) {
5860 public virtual string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node
) {
5864 public virtual void generate_marshaller (List
<Parameter
> params
, DataType return_type
, bool dbus
= false) {
5867 public virtual string get_marshaller_function (List
<Parameter
> params
, DataType return_type
, string? prefix
= null, bool dbus
= false) {
5871 public virtual string get_array_length_cname (string array_cname
, int dim
) {
5875 public virtual string get_parameter_array_length_cname (Parameter param
, int dim
) {
5879 public virtual CCodeExpression
get_array_length_cexpression (Expression array_expr
, int dim
= -1) {
5880 return new
CCodeConstant ("");
5883 public virtual CCodeExpression
get_array_length_cvalue (TargetValue value
, int dim
= -1) {
5884 return new
CCodeInvalidExpression ();
5887 public virtual string get_array_size_cname (string array_cname
) {
5891 public virtual void add_simple_check (CodeNode node
, bool always_fails
= false) {
5894 public CCodeExpression?
get_cvalue (Expression expr
) {
5895 if (expr
.target_value
== null) {
5898 var glib_value
= (GLibValue
) expr
.target_value
;
5899 return glib_value
.cvalue
;
5902 public CCodeExpression?
get_cvalue_ (TargetValue value
) {
5903 var glib_value
= (GLibValue
) value
;
5904 return glib_value
.cvalue
;
5907 public void set_cvalue (Expression expr
, CCodeExpression? cvalue
) {
5908 var glib_value
= (GLibValue
) expr
.target_value
;
5909 if (glib_value
== null) {
5910 glib_value
= new
GLibValue (expr
.value_type
);
5911 expr
.target_value
= glib_value
;
5913 glib_value
.cvalue
= cvalue
;
5916 public CCodeExpression?
get_array_size_cvalue (TargetValue value
) {
5917 var glib_value
= (GLibValue
) value
;
5918 return glib_value
.array_size_cvalue
;
5921 public void set_array_size_cvalue (TargetValue value
, CCodeExpression? cvalue
) {
5922 var glib_value
= (GLibValue
) value
;
5923 glib_value
.array_size_cvalue
= cvalue
;
5926 public CCodeExpression?
get_delegate_target (Expression expr
) {
5927 if (expr
.target_value
== null) {
5930 var glib_value
= (GLibValue
) expr
.target_value
;
5931 return glib_value
.delegate_target_cvalue
;
5934 public void set_delegate_target (Expression expr
, CCodeExpression? delegate_target
) {
5935 var glib_value
= (GLibValue
) expr
.target_value
;
5936 if (glib_value
== null) {
5937 glib_value
= new
GLibValue (expr
.value_type
);
5938 expr
.target_value
= glib_value
;
5940 glib_value
.delegate_target_cvalue
= delegate_target
;
5943 public CCodeExpression?
get_delegate_target_destroy_notify (Expression expr
) {
5944 if (expr
.target_value
== null) {
5947 var glib_value
= (GLibValue
) expr
.target_value
;
5948 return glib_value
.delegate_target_destroy_notify_cvalue
;
5951 public void set_delegate_target_destroy_notify (Expression expr
, CCodeExpression? destroy_notify
) {
5952 var glib_value
= (GLibValue
) expr
.target_value
;
5953 if (glib_value
== null) {
5954 glib_value
= new
GLibValue (expr
.value_type
);
5955 expr
.target_value
= glib_value
;
5957 glib_value
.delegate_target_destroy_notify_cvalue
= destroy_notify
;
5960 public void append_array_size (Expression expr
, CCodeExpression size
) {
5961 var glib_value
= (GLibValue
) expr
.target_value
;
5962 if (glib_value
== null) {
5963 glib_value
= new
GLibValue (expr
.value_type
);
5964 expr
.target_value
= glib_value
;
5966 glib_value
.append_array_length_cvalue (size
);
5969 public List
<CCodeExpression
>?
get_array_sizes (Expression expr
) {
5970 var glib_value
= (GLibValue
) expr
.target_value
;
5971 if (glib_value
== null) {
5972 glib_value
= new
GLibValue (expr
.value_type
);
5973 expr
.target_value
= glib_value
;
5975 return glib_value
.array_length_cvalues
;
5979 public class Vala
.GLibValue
: TargetValue
{
5980 public CCodeExpression cvalue
;
5982 public List
<CCodeExpression
> array_length_cvalues
;
5983 public CCodeExpression? array_size_cvalue
;
5985 public CCodeExpression? delegate_target_cvalue
;
5986 public CCodeExpression? delegate_target_destroy_notify_cvalue
;
5988 public GLibValue (DataType? value_type
= null, CCodeExpression? cvalue
= null) {
5990 this
.cvalue
= cvalue
;
5993 public void append_array_length_cvalue (CCodeExpression length_cvalue
) {
5994 if (array_length_cvalues
== null) {
5995 array_length_cvalues
= new ArrayList
<CCodeExpression
> ();
5997 array_length_cvalues
.add (length_cvalue
);