1 /* valaccodebasemodule.vala
3 * Copyright (C) 2006-2011 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 CatchClause current_catch
;
35 public CCodeFunction ccode
;
36 public ArrayList
<CCodeFunction
> ccode_stack
= new ArrayList
<CCodeFunction
> ();
37 public ArrayList
<LocalVariable
> temp_ref_vars
= new ArrayList
<LocalVariable
> ();
38 public int next_temp_var_id
;
39 public bool current_method_inner_error
;
40 public bool current_method_return
;
41 public Map
<string,string> variable_name_map
= new HashMap
<string,string> (str_hash
, str_equal
);
43 public EmitContext (Symbol? symbol
= null) {
44 current_symbol
= symbol
;
47 public void push_symbol (Symbol symbol
) {
48 symbol_stack
.add (current_symbol
);
49 current_symbol
= symbol
;
52 public void pop_symbol () {
53 current_symbol
= symbol_stack
[symbol_stack
.size
- 1];
54 symbol_stack
.remove_at (symbol_stack
.size
- 1);
58 public CodeContext context
{ get; set; }
60 public Symbol root_symbol
;
62 public EmitContext emit_context
= new
EmitContext ();
64 List
<EmitContext
> emit_context_stack
= new ArrayList
<EmitContext
> ();
66 public Symbol current_symbol
{ get { return emit_context
.current_symbol
; } }
68 public TryStatement current_try
{
69 get { return emit_context
.current_try
; }
70 set { emit_context
.current_try
= value
; }
73 public CatchClause current_catch
{
74 get { return emit_context
.current_catch
; }
75 set { emit_context
.current_catch
= value
; }
78 public TypeSymbol? current_type_symbol
{
80 var sym
= current_symbol
;
82 if (sym is TypeSymbol
) {
83 return (TypeSymbol
) sym
;
85 sym
= sym
.parent_symbol
;
91 public Class? current_class
{
92 get { return current_type_symbol as Class
; }
95 public Method? current_method
{
97 var sym
= current_symbol
;
98 while (sym is Block
) {
99 sym
= sym
.parent_symbol
;
101 return sym as Method
;
105 public PropertyAccessor? current_property_accessor
{
107 var sym
= current_symbol
;
108 while (sym is Block
) {
109 sym
= sym
.parent_symbol
;
111 return sym as PropertyAccessor
;
115 public DataType? current_return_type
{
117 var m
= current_method
;
119 return m
.return_type
;
122 var acc
= current_property_accessor
;
125 return acc
.value_type
;
131 if (is_in_constructor () || is_in_destructor ()) {
139 public bool is_in_coroutine () {
140 return current_method
!= null && current_method
.coroutine
;
143 public bool is_in_constructor () {
144 if (current_method
!= null) {
145 // make sure to not return true in lambda expression inside constructor
148 var sym
= current_symbol
;
149 while (sym
!= null) {
150 if (sym is Constructor
) {
153 sym
= sym
.parent_symbol
;
158 public bool is_in_destructor () {
159 if (current_method
!= null) {
160 // make sure to not return true in lambda expression inside constructor
163 var sym
= current_symbol
;
164 while (sym
!= null) {
165 if (sym is Destructor
) {
168 sym
= sym
.parent_symbol
;
173 public Block? current_closure_block
{
175 return next_closure_block (current_symbol
);
179 public unowned Block?
next_closure_block (Symbol sym
) {
180 unowned Block block
= null;
182 block
= sym as Block
;
183 if (!(sym is Block
|| sym is Method
)) {
187 if (block
!= null && block
.captured
) {
188 // closure block found
191 sym
= sym
.parent_symbol
;
196 public CCodeFile header_file
;
197 public CCodeFile internal_header_file
;
198 public CCodeFile cfile
;
200 public EmitContext class_init_context
;
201 public EmitContext base_init_context
;
202 public EmitContext class_finalize_context
;
203 public EmitContext base_finalize_context
;
204 public EmitContext instance_init_context
;
205 public EmitContext instance_finalize_context
;
207 public CCodeStruct param_spec_struct
;
208 public CCodeStruct closure_struct
;
209 public CCodeEnum prop_enum
;
211 public CCodeFunction ccode
{ get { return emit_context
.ccode
; } }
213 /* temporary variables that own their content */
214 public ArrayList
<LocalVariable
> temp_ref_vars
{ get { return emit_context
.temp_ref_vars
; } }
215 /* cache to check whether a certain marshaller has been created yet */
216 public Set
<string> user_marshal_set
;
217 /* (constant) hash table with all predefined marshallers */
218 public Set
<string> predefined_marshal_set
;
219 /* (constant) hash table with all reserved identifiers in the generated code */
220 Set
<string> reserved_identifiers
;
222 public int next_temp_var_id
{
223 get { return emit_context
.next_temp_var_id
; }
224 set { emit_context
.next_temp_var_id
= value
; }
227 public int next_regex_id
= 0;
228 public bool in_creation_method
{ get { return current_method is CreationMethod
; } }
229 public bool in_constructor
= false;
230 public bool in_static_or_class_context
= false;
232 public bool current_method_inner_error
{
233 get { return emit_context
.current_method_inner_error
; }
234 set { emit_context
.current_method_inner_error
= value
; }
237 public bool current_method_return
{
238 get { return emit_context
.current_method_return
; }
239 set { emit_context
.current_method_return
= value
; }
242 public int next_coroutine_state
= 1;
243 int next_block_id
= 0;
244 Map
<Block
,int> block_map
= new HashMap
<Block
,int> ();
246 public DataType void_type
= new
VoidType ();
247 public DataType bool_type
;
248 public DataType char_type
;
249 public DataType uchar_type
;
250 public DataType? unichar_type
;
251 public DataType short_type
;
252 public DataType ushort_type
;
253 public DataType int_type
;
254 public DataType uint_type
;
255 public DataType long_type
;
256 public DataType ulong_type
;
257 public DataType int8_type
;
258 public DataType uint8_type
;
259 public DataType int16_type
;
260 public DataType uint16_type
;
261 public DataType int32_type
;
262 public DataType uint32_type
;
263 public DataType int64_type
;
264 public DataType uint64_type
;
265 public DataType string_type
;
266 public DataType regex_type
;
267 public DataType float_type
;
268 public DataType double_type
;
269 public TypeSymbol gtype_type
;
270 public TypeSymbol gobject_type
;
271 public ErrorType gerror_type
;
272 public Class glist_type
;
273 public Class gslist_type
;
274 public Class gnode_type
;
275 public Class gvaluearray_type
;
276 public TypeSymbol gstringbuilder_type
;
277 public TypeSymbol garray_type
;
278 public TypeSymbol gbytearray_type
;
279 public TypeSymbol gptrarray_type
;
280 public TypeSymbol gthreadpool_type
;
281 public DataType gdestroynotify_type
;
282 public DataType gquark_type
;
283 public Struct gvalue_type
;
284 public Class gvariant_type
;
285 public Struct mutex_type
;
286 public TypeSymbol type_module_type
;
287 public TypeSymbol dbus_proxy_type
;
288 public TypeSymbol dbus_object_type
;
290 public bool in_plugin
= false;
291 public string module_init_param_name
;
293 public bool gvaluecollector_h_needed
;
294 public bool requires_array_free
;
295 public bool requires_array_move
;
296 public bool requires_array_length
;
298 public Set
<string> wrappers
;
299 Set
<Symbol
> generated_external_symbols
;
301 public Map
<string,string> variable_name_map
{ get { return emit_context
.variable_name_map
; } }
303 public CCodeBaseModule () {
304 predefined_marshal_set
= new HashSet
<string> (str_hash
, str_equal
);
305 predefined_marshal_set
.add ("VOID:VOID");
306 predefined_marshal_set
.add ("VOID:BOOLEAN");
307 predefined_marshal_set
.add ("VOID:CHAR");
308 predefined_marshal_set
.add ("VOID:UCHAR");
309 predefined_marshal_set
.add ("VOID:INT");
310 predefined_marshal_set
.add ("VOID:UINT");
311 predefined_marshal_set
.add ("VOID:LONG");
312 predefined_marshal_set
.add ("VOID:ULONG");
313 predefined_marshal_set
.add ("VOID:ENUM");
314 predefined_marshal_set
.add ("VOID:FLAGS");
315 predefined_marshal_set
.add ("VOID:FLOAT");
316 predefined_marshal_set
.add ("VOID:DOUBLE");
317 predefined_marshal_set
.add ("VOID:STRING");
318 predefined_marshal_set
.add ("VOID:POINTER");
319 predefined_marshal_set
.add ("VOID:OBJECT");
320 predefined_marshal_set
.add ("STRING:OBJECT,POINTER");
321 predefined_marshal_set
.add ("VOID:UINT,POINTER");
322 predefined_marshal_set
.add ("BOOLEAN:FLAGS");
324 reserved_identifiers
= new HashSet
<string> (str_hash
, str_equal
);
327 reserved_identifiers
.add ("_Bool");
328 reserved_identifiers
.add ("_Complex");
329 reserved_identifiers
.add ("_Imaginary");
330 reserved_identifiers
.add ("asm");
331 reserved_identifiers
.add ("auto");
332 reserved_identifiers
.add ("break");
333 reserved_identifiers
.add ("case");
334 reserved_identifiers
.add ("char");
335 reserved_identifiers
.add ("const");
336 reserved_identifiers
.add ("continue");
337 reserved_identifiers
.add ("default");
338 reserved_identifiers
.add ("do");
339 reserved_identifiers
.add ("double");
340 reserved_identifiers
.add ("else");
341 reserved_identifiers
.add ("enum");
342 reserved_identifiers
.add ("extern");
343 reserved_identifiers
.add ("float");
344 reserved_identifiers
.add ("for");
345 reserved_identifiers
.add ("goto");
346 reserved_identifiers
.add ("if");
347 reserved_identifiers
.add ("inline");
348 reserved_identifiers
.add ("int");
349 reserved_identifiers
.add ("long");
350 reserved_identifiers
.add ("register");
351 reserved_identifiers
.add ("restrict");
352 reserved_identifiers
.add ("return");
353 reserved_identifiers
.add ("short");
354 reserved_identifiers
.add ("signed");
355 reserved_identifiers
.add ("sizeof");
356 reserved_identifiers
.add ("static");
357 reserved_identifiers
.add ("struct");
358 reserved_identifiers
.add ("switch");
359 reserved_identifiers
.add ("typedef");
360 reserved_identifiers
.add ("union");
361 reserved_identifiers
.add ("unsigned");
362 reserved_identifiers
.add ("void");
363 reserved_identifiers
.add ("volatile");
364 reserved_identifiers
.add ("while");
367 reserved_identifiers
.add ("cdecl");
369 // reserved for Vala/GObject naming conventions
370 reserved_identifiers
.add ("error");
371 reserved_identifiers
.add ("result");
372 reserved_identifiers
.add ("self");
375 public override void emit (CodeContext context
) {
376 this
.context
= context
;
378 root_symbol
= context
.root
;
380 bool_type
= new
BooleanType ((Struct
) root_symbol
.scope
.lookup ("bool"));
381 char_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("char"));
382 uchar_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uchar"));
383 short_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("short"));
384 ushort_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ushort"));
385 int_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int"));
386 uint_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint"));
387 long_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("long"));
388 ulong_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ulong"));
389 int8_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int8"));
390 uint8_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint8"));
391 int16_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int16"));
392 uint16_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint16"));
393 int32_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int32"));
394 uint32_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint32"));
395 int64_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int64"));
396 uint64_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint64"));
397 float_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("float"));
398 double_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("double"));
399 string_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("string"));
400 var unichar_struct
= (Struct
) root_symbol
.scope
.lookup ("unichar");
401 if (unichar_struct
!= null) {
402 unichar_type
= new
IntegerType (unichar_struct
);
405 if (context
.profile
== Profile
.GOBJECT
) {
406 var glib_ns
= root_symbol
.scope
.lookup ("GLib");
408 gtype_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Type");
409 gobject_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Object");
410 gerror_type
= new
ErrorType (null, null);
411 glist_type
= (Class
) glib_ns
.scope
.lookup ("List");
412 gslist_type
= (Class
) glib_ns
.scope
.lookup ("SList");
413 gnode_type
= (Class
) glib_ns
.scope
.lookup ("Node");
414 gvaluearray_type
= (Class
) glib_ns
.scope
.lookup ("ValueArray");
415 gstringbuilder_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("StringBuilder");
416 garray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Array");
417 gbytearray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("ByteArray");
418 gptrarray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("PtrArray");
419 gthreadpool_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("ThreadPool");
420 gdestroynotify_type
= new
DelegateType ((Delegate
) glib_ns
.scope
.lookup ("DestroyNotify"));
422 gquark_type
= new
IntegerType ((Struct
) glib_ns
.scope
.lookup ("Quark"));
423 gvalue_type
= (Struct
) glib_ns
.scope
.lookup ("Value");
424 gvariant_type
= (Class
) glib_ns
.scope
.lookup ("Variant");
425 mutex_type
= (Struct
) glib_ns
.scope
.lookup ("StaticRecMutex");
427 type_module_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("TypeModule");
429 regex_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("GLib").scope
.lookup ("Regex"));
431 if (context
.module_init_method
!= null) {
432 foreach (Parameter parameter
in context
.module_init_method
.get_parameters ()) {
433 if (parameter
.variable_type
.data_type
== type_module_type
) {
435 module_init_param_name
= parameter
.name
;
440 Report
.error (context
.module_init_method
.source_reference
, "[ModuleInit] requires a parameter of type `GLib.TypeModule'");
444 dbus_proxy_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("DBusProxy");
446 var dbus_ns
= root_symbol
.scope
.lookup ("DBus");
447 if (dbus_ns
!= null) {
448 dbus_object_type
= (TypeSymbol
) dbus_ns
.scope
.lookup ("Object");
452 header_file
= new
CCodeFile ();
453 header_file
.is_header
= true;
454 internal_header_file
= new
CCodeFile ();
455 internal_header_file
.is_header
= true;
457 /* we're only interested in non-pkg source files */
458 var source_files
= context
.get_source_files ();
459 foreach (SourceFile file
in source_files
) {
460 if (file
.file_type
== SourceFileType
.SOURCE
||
461 (context
.header_filename
!= null && file
.file_type
== SourceFileType
.FAST
)) {
466 // generate symbols file for public API
467 if (context
.symbols_filename
!= null) {
468 var stream
= FileStream
.open (context
.symbols_filename
, "w");
469 if (stream
== null) {
470 Report
.error (null, "unable to open `%s' for writing".printf (context
.symbols_filename
));
474 foreach (string symbol
in header_file
.get_symbols ()) {
475 stream
.puts (symbol
);
482 // generate C header file for public API
483 if (context
.header_filename
!= null) {
485 if (context
.profile
== Profile
.GOBJECT
) {
486 ret
= header_file
.store (context
.header_filename
, null, context
.version_header
, false, "G_BEGIN_DECLS", "G_END_DECLS");
488 ret
= header_file
.store (context
.header_filename
, null, context
.version_header
, false);
491 Report
.error (null, "unable to open `%s' for writing".printf (context
.header_filename
));
495 // generate C header file for internal API
496 if (context
.internal_header_filename
!= null) {
498 if (context
.profile
== Profile
.GOBJECT
) {
499 ret
= internal_header_file
.store (context
.internal_header_filename
, null, context
.version_header
, false, "G_BEGIN_DECLS", "G_END_DECLS");
501 ret
= internal_header_file
.store (context
.internal_header_filename
, null, context
.version_header
, false);
504 Report
.error (null, "unable to open `%s' for writing".printf (context
.internal_header_filename
));
509 public void push_context (EmitContext emit_context
) {
510 if (this
.emit_context
!= null) {
511 emit_context_stack
.add (this
.emit_context
);
514 this
.emit_context
= emit_context
;
517 public void pop_context () {
518 if (emit_context_stack
.size
> 0) {
519 this
.emit_context
= emit_context_stack
[emit_context_stack
.size
- 1];
520 emit_context_stack
.remove_at (emit_context_stack
.size
- 1);
522 this
.emit_context
= null;
526 public void push_function (CCodeFunction func
) {
527 emit_context
.ccode_stack
.add (ccode
);
528 emit_context
.ccode
= func
;
531 public void pop_function () {
532 emit_context
.ccode
= emit_context
.ccode_stack
[emit_context
.ccode_stack
.size
- 1];
533 emit_context
.ccode_stack
.remove_at (emit_context
.ccode_stack
.size
- 1);
536 public bool add_symbol_declaration (CCodeFile decl_space
, Symbol sym
, string name
) {
537 if (decl_space
.add_declaration (name
)) {
540 if (sym
.source_reference
!= null) {
541 sym
.source_reference
.file
.used
= true;
543 if (sym
.external_package
|| (!decl_space
.is_header
&& CodeContext
.get ().use_header
&& !sym
.is_internal_symbol ())) {
544 // add appropriate include file
545 foreach (string header_filename
in sym
.get_cheader_filenames ()) {
546 decl_space
.add_include (header_filename
, !sym
.external_package
);
548 // declaration complete
551 // require declaration
556 public CCodeIdentifier
get_value_setter_function (DataType type_reference
) {
557 var array_type
= type_reference as ArrayType
;
558 if (type_reference
.data_type
!= null) {
559 return new
CCodeIdentifier (type_reference
.data_type
.get_set_value_function ());
560 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
562 return new
CCodeIdentifier ("g_value_set_boxed");
564 return new
CCodeIdentifier ("g_value_set_pointer");
568 public CCodeIdentifier
get_value_taker_function (DataType type_reference
) {
569 var array_type
= type_reference as ArrayType
;
570 if (type_reference
.data_type
!= null) {
571 return new
CCodeIdentifier (type_reference
.data_type
.get_take_value_function ());
572 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
574 return new
CCodeIdentifier ("g_value_take_boxed");
576 return new
CCodeIdentifier ("g_value_set_pointer");
580 CCodeIdentifier
get_value_getter_function (DataType type_reference
) {
581 var array_type
= type_reference as ArrayType
;
582 if (type_reference
.data_type
!= null) {
583 return new
CCodeIdentifier (type_reference
.data_type
.get_get_value_function ());
584 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
586 return new
CCodeIdentifier ("g_value_get_boxed");
588 return new
CCodeIdentifier ("g_value_get_pointer");
592 public virtual void append_vala_array_free () {
595 public virtual void append_vala_array_move () {
598 public virtual void append_vala_array_length () {
601 public override void visit_source_file (SourceFile source_file
) {
602 cfile
= new
CCodeFile ();
604 user_marshal_set
= new HashSet
<string> (str_hash
, str_equal
);
608 gvaluecollector_h_needed
= false;
609 requires_array_free
= false;
610 requires_array_move
= false;
611 requires_array_length
= false;
613 wrappers
= new HashSet
<string> (str_hash
, str_equal
);
614 generated_external_symbols
= new HashSet
<Symbol
> ();
616 if (context
.profile
== Profile
.GOBJECT
) {
617 header_file
.add_include ("glib.h");
618 internal_header_file
.add_include ("glib.h");
619 cfile
.add_include ("glib.h");
620 cfile
.add_include ("glib-object.h");
623 source_file
.accept_children (this
);
625 if (context
.report
.get_errors () > 0) {
629 /* For fast-vapi, we only wanted the header declarations
630 * to be emitted, so bail out here without writing the
633 if (source_file
.file_type
== SourceFileType
.FAST
) {
637 if (requires_array_free
) {
638 append_vala_array_free ();
640 if (requires_array_move
) {
641 append_vala_array_move ();
643 if (requires_array_length
) {
644 append_vala_array_length ();
647 if (gvaluecollector_h_needed
) {
648 cfile
.add_include ("gobject/gvaluecollector.h");
651 var comments
= source_file
.get_comments();
652 if (comments
!= null) {
653 foreach (Comment comment
in comments
) {
654 var ccomment
= new
CCodeComment (comment
.content
);
655 cfile
.add_comment (ccomment
);
659 if (!cfile
.store (source_file
.get_csource_filename (), source_file
.filename
, context
.version_header
, context
.debug
)) {
660 Report
.error (null, "unable to open `%s' for writing".printf (source_file
.get_csource_filename ()));
666 public virtual bool generate_enum_declaration (Enum en
, CCodeFile decl_space
) {
667 if (add_symbol_declaration (decl_space
, en
, en
.get_cname ())) {
671 var cenum
= new
CCodeEnum (en
.get_cname ());
673 cenum
.deprecated
= en
.deprecated
;
676 foreach (EnumValue ev
in en
.get_values ()) {
678 if (ev
.value
== null) {
679 c_ev
= new
CCodeEnumValue (ev
.get_cname ());
681 c_ev
.value
= new
CCodeConstant ("1 << %d".printf (flag_shift
));
685 ev
.value
.emit (this
);
686 c_ev
= new
CCodeEnumValue (ev
.get_cname (), get_cvalue (ev
.value
));
688 c_ev
.deprecated
= ev
.deprecated
;
689 cenum
.add_value (c_ev
);
692 decl_space
.add_type_definition (cenum
);
693 decl_space
.add_type_definition (new
CCodeNewline ());
695 if (!en
.has_type_id
) {
699 decl_space
.add_type_declaration (new
CCodeNewline ());
701 var macro
= "(%s_get_type ())".printf (en
.get_lower_case_cname (null));
702 decl_space
.add_type_declaration (new
CCodeMacroReplacement (en
.get_type_id (), macro
));
704 var fun_name
= "%s_get_type".printf (en
.get_lower_case_cname (null));
705 var regfun
= new
CCodeFunction (fun_name
, "GType");
706 regfun
.attributes
= "G_GNUC_CONST";
708 if (en
.access
== SymbolAccessibility
.PRIVATE
) {
709 regfun
.modifiers
= CCodeModifiers
.STATIC
;
710 // avoid C warning as this function is not always used
711 regfun
.attributes
= "G_GNUC_UNUSED";
714 decl_space
.add_function_declaration (regfun
);
719 public override void visit_enum (Enum en
) {
720 en
.accept_children (this
);
722 if (en
.comment
!= null) {
723 cfile
.add_type_member_definition (new
CCodeComment (en
.comment
.content
));
726 generate_enum_declaration (en
, cfile
);
728 if (!en
.is_internal_symbol ()) {
729 generate_enum_declaration (en
, header_file
);
731 if (!en
.is_private_symbol ()) {
732 generate_enum_declaration (en
, internal_header_file
);
736 public void visit_member (Symbol m
) {
737 /* stuff meant for all lockable members */
738 if (m is Lockable
&& ((Lockable
) m
).get_lock_used ()) {
739 CCodeExpression l
= new
CCodeIdentifier ("self");
740 var init_context
= class_init_context
;
741 var finalize_context
= class_finalize_context
;
743 if (m
.is_instance_member ()) {
744 l
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (l
, "priv"), get_symbol_lock_name (m
.name
));
745 init_context
= instance_init_context
;
746 finalize_context
= instance_finalize_context
;
747 } else if (m
.is_class_member ()) {
748 TypeSymbol parent
= (TypeSymbol
)m
.parent_symbol
;
750 var get_class_private_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent
.get_upper_case_cname ())));
751 get_class_private_call
.add_argument (new
CCodeIdentifier ("klass"));
752 l
= new CCodeMemberAccess
.pointer (get_class_private_call
, get_symbol_lock_name (m
.name
));
754 l
= new
CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf(m
.parent_symbol
.get_lower_case_cname (), m
.name
)));
757 push_context (init_context
);
758 var initf
= new
CCodeFunctionCall (new
CCodeIdentifier (mutex_type
.default_construction_method
.get_cname ()));
759 initf
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
760 ccode
.add_expression (initf
);
763 if (finalize_context
!= null) {
764 push_context (finalize_context
);
765 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_static_rec_mutex_free"));
766 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
767 ccode
.add_expression (fc
);
773 public void generate_constant_declaration (Constant c
, CCodeFile decl_space
, bool definition
= false) {
774 if (c
.parent_symbol is Block
) {
779 if (add_symbol_declaration (decl_space
, c
, c
.get_cname ())) {
784 generate_type_declaration (c
.type_reference
, decl_space
);
788 var initializer_list
= c
.value as InitializerList
;
789 if (initializer_list
!= null) {
790 var cdecl
= new
CCodeDeclaration (c
.type_reference
.get_const_cname ());
792 if (c
.type_reference is ArrayType
) {
793 arr
= "[%d]".printf (initializer_list
.size
);
796 var cinitializer
= get_cvalue (c
.value
);
798 // never output value in header
799 // special case needed as this method combines declaration and definition
803 cdecl
.add_declarator (new
CCodeVariableDeclarator ("%s%s".printf (c
.get_cname (), arr
), cinitializer
));
804 if (c
.is_private_symbol ()) {
805 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
807 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
810 decl_space
.add_constant_declaration (cdecl
);
812 var cdefine
= new CCodeMacroReplacement
.with_expression (c
.get_cname (), get_cvalue (c
.value
));
813 decl_space
.add_type_member_declaration (cdefine
);
818 public override void visit_constant (Constant c
) {
819 if (c
.parent_symbol is Block
) {
822 generate_type_declaration (c
.type_reference
, cfile
);
826 string type_name
= c
.type_reference
.get_const_cname ();
828 if (c
.type_reference is ArrayType
) {
832 if (c
.type_reference
.compatible (string_type
)) {
833 type_name
= "const char";
837 var cinitializer
= get_cvalue (c
.value
);
839 ccode
.add_declaration (type_name
, new
CCodeVariableDeclarator ("%s%s".printf (c
.get_cname (), arr
), cinitializer
), CCodeModifiers
.STATIC
);
844 generate_constant_declaration (c
, cfile
, true);
846 if (!c
.is_internal_symbol ()) {
847 generate_constant_declaration (c
, header_file
);
849 if (!c
.is_private_symbol ()) {
850 generate_constant_declaration (c
, internal_header_file
);
854 public void generate_field_declaration (Field f
, CCodeFile decl_space
) {
855 if (add_symbol_declaration (decl_space
, f
, f
.get_cname ())) {
859 generate_type_declaration (f
.variable_type
, decl_space
);
861 string field_ctype
= f
.variable_type
.get_cname ();
863 field_ctype
= "volatile " + field_ctype
;
866 var cdecl
= new
CCodeDeclaration (field_ctype
);
867 cdecl
.add_declarator (new
CCodeVariableDeclarator (f
.get_cname (), null, f
.variable_type
.get_cdeclarator_suffix ()));
868 if (f
.is_private_symbol ()) {
869 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
871 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
874 cdecl
.modifiers
|= CCodeModifiers
.DEPRECATED
;
876 decl_space
.add_type_member_declaration (cdecl
);
878 if (f
.get_lock_used ()) {
879 // Declare mutex for static member
880 var flock
= new
CCodeDeclaration (mutex_type
.get_cname ());
881 var flock_decl
= new
CCodeVariableDeclarator (get_symbol_lock_name (f
.get_cname ()), new
CCodeConstant ("{0}"));
882 flock
.add_declarator (flock_decl
);
884 if (f
.is_private_symbol ()) {
885 flock
.modifiers
= CCodeModifiers
.STATIC
;
887 flock
.modifiers
= CCodeModifiers
.EXTERN
;
889 decl_space
.add_type_member_declaration (flock
);
892 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
893 var array_type
= (ArrayType
) f
.variable_type
;
895 if (!array_type
.fixed_length
) {
896 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
897 var len_type
= int_type
.copy ();
899 cdecl
= new
CCodeDeclaration (len_type
.get_cname ());
900 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (f
.get_cname (), dim
)));
901 if (f
.is_private_symbol ()) {
902 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
904 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
906 decl_space
.add_type_member_declaration (cdecl
);
909 } else if (f
.variable_type is DelegateType
) {
910 var delegate_type
= (DelegateType
) f
.variable_type
;
911 if (delegate_type
.delegate_symbol
.has_target
) {
912 // create field to store delegate target
914 cdecl
= new
CCodeDeclaration ("gpointer");
915 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_cname (f
.get_cname ())));
916 if (f
.is_private_symbol ()) {
917 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
919 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
921 decl_space
.add_type_member_declaration (cdecl
);
923 if (delegate_type
.value_owned
) {
924 cdecl
= new
CCodeDeclaration ("GDestroyNotify");
925 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f
.get_cname ())));
926 if (f
.is_private_symbol ()) {
927 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
929 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
931 decl_space
.add_type_member_declaration (cdecl
);
937 public override void visit_field (Field f
) {
940 check_type (f
.variable_type
);
942 var cl
= f
.parent_symbol as Class
;
943 bool is_gtypeinstance
= (cl
!= null && !cl
.is_compact
);
945 CCodeExpression lhs
= null;
947 string field_ctype
= f
.variable_type
.get_cname ();
949 field_ctype
= "volatile " + field_ctype
;
952 if (f
.binding
== MemberBinding
.INSTANCE
) {
953 if (is_gtypeinstance
&& f
.access
== SymbolAccessibility
.PRIVATE
) {
954 lhs
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), f
.get_cname ());
956 lhs
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.get_cname ());
959 if (f
.initializer
!= null) {
960 push_context (instance_init_context
);
962 f
.initializer
.emit (this
);
964 var rhs
= get_cvalue (f
.initializer
);
966 ccode
.add_assignment (lhs
, rhs
);
968 if (f
.variable_type is ArrayType
&& !f
.no_array_length
&&
969 f
.initializer is ArrayCreationExpression
) {
970 var array_type
= (ArrayType
) f
.variable_type
;
971 var this_access
= new MemberAccess
.simple ("this");
972 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
973 set_cvalue (this_access
, new
CCodeIdentifier ("self"));
974 var ma
= new
MemberAccess (this_access
, f
.name
);
975 ma
.symbol_reference
= f
;
976 ma
.value_type
= f
.variable_type
.copy ();
977 visit_member_access (ma
);
979 List
<Expression
> sizes
= ((ArrayCreationExpression
) f
.initializer
).get_sizes ();
980 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
981 var array_len_lhs
= get_array_length_cexpression (ma
, dim
);
982 var size
= sizes
[dim
- 1];
983 ccode
.add_assignment (array_len_lhs
, get_cvalue (size
));
986 if (array_type
.rank
== 1 && f
.is_internal_symbol ()) {
987 var lhs_array_size
= get_array_size_cvalue (ma
.target_value
);
988 var rhs_array_len
= get_array_length_cexpression (ma
, 1);
989 ccode
.add_assignment (lhs_array_size
, rhs_array_len
);
993 foreach (LocalVariable local
in temp_ref_vars
) {
994 ccode
.add_expression (destroy_local (local
));
997 temp_ref_vars
.clear ();
1002 if (requires_destroy (f
.variable_type
) && instance_finalize_context
!= null) {
1003 push_context (instance_finalize_context
);
1005 var this_access
= new MemberAccess
.simple ("this");
1006 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
1008 var field_st
= f
.parent_symbol as Struct
;
1009 if (field_st
!= null && !field_st
.is_simple_type ()) {
1010 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
1012 set_cvalue (this_access
, new
CCodeIdentifier ("self"));
1015 var ma
= new
MemberAccess (this_access
, f
.name
);
1016 ma
.symbol_reference
= f
;
1017 ma
.value_type
= f
.variable_type
.copy ();
1018 visit_member_access (ma
);
1019 ccode
.add_expression (get_unref_expression (lhs
, f
.variable_type
, ma
));
1023 } else if (f
.binding
== MemberBinding
.CLASS
) {
1024 if (!is_gtypeinstance
) {
1025 Report
.error (f
.source_reference
, "class fields are not supported in compact classes");
1030 if (f
.access
== SymbolAccessibility
.PRIVATE
) {
1031 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (cl
.get_upper_case_cname ())));
1032 ccall
.add_argument (new
CCodeIdentifier ("klass"));
1033 lhs
= new
CCodeMemberAccess (ccall
, f
.get_cname (), true);
1035 lhs
= new
CCodeMemberAccess (new
CCodeIdentifier ("klass"), f
.get_cname (), true);
1038 if (f
.initializer
!= null) {
1039 push_context (class_init_context
);
1041 f
.initializer
.emit (this
);
1043 var rhs
= get_cvalue (f
.initializer
);
1045 ccode
.add_assignment (lhs
, rhs
);
1047 foreach (LocalVariable local
in temp_ref_vars
) {
1048 ccode
.add_expression (destroy_local (local
));
1051 temp_ref_vars
.clear ();
1056 generate_field_declaration (f
, cfile
);
1058 if (!f
.is_internal_symbol ()) {
1059 generate_field_declaration (f
, header_file
);
1061 if (!f
.is_private_symbol ()) {
1062 generate_field_declaration (f
, internal_header_file
);
1065 lhs
= new
CCodeIdentifier (f
.get_cname ());
1067 var var_decl
= new
CCodeVariableDeclarator (f
.get_cname (), null, f
.variable_type
.get_cdeclarator_suffix ());
1068 var_decl
.initializer
= default_value_for_type (f
.variable_type
, true);
1070 if (class_init_context
!= null) {
1071 push_context (class_init_context
);
1073 push_context (new
EmitContext ());
1076 if (f
.initializer
!= null) {
1077 f
.initializer
.emit (this
);
1079 var init
= get_cvalue (f
.initializer
);
1080 if (is_constant_ccode_expression (init
)) {
1081 var_decl
.initializer
= init
;
1085 var var_def
= new
CCodeDeclaration (field_ctype
);
1086 var_def
.add_declarator (var_decl
);
1087 if (!f
.is_private_symbol ()) {
1088 var_def
.modifiers
= CCodeModifiers
.EXTERN
;
1090 var_def
.modifiers
= CCodeModifiers
.STATIC
;
1092 cfile
.add_type_member_declaration (var_def
);
1094 /* add array length fields where necessary */
1095 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
1096 var array_type
= (ArrayType
) f
.variable_type
;
1098 if (!array_type
.fixed_length
) {
1099 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1100 var len_type
= int_type
.copy ();
1102 var len_def
= new
CCodeDeclaration (len_type
.get_cname ());
1103 len_def
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (f
.get_cname (), dim
), new
CCodeConstant ("0")));
1104 if (!f
.is_private_symbol ()) {
1105 len_def
.modifiers
= CCodeModifiers
.EXTERN
;
1107 len_def
.modifiers
= CCodeModifiers
.STATIC
;
1109 cfile
.add_type_member_declaration (len_def
);
1112 if (array_type
.rank
== 1 && f
.is_internal_symbol ()) {
1113 var len_type
= int_type
.copy ();
1115 var cdecl
= new
CCodeDeclaration (len_type
.get_cname ());
1116 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_size_cname (f
.get_cname ()), new
CCodeConstant ("0")));
1117 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
1118 cfile
.add_type_member_declaration (cdecl
);
1121 } else if (f
.variable_type is DelegateType
) {
1122 var delegate_type
= (DelegateType
) f
.variable_type
;
1123 if (delegate_type
.delegate_symbol
.has_target
) {
1124 // create field to store delegate target
1126 var target_def
= new
CCodeDeclaration ("gpointer");
1127 target_def
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_cname (f
.get_cname ()), new
CCodeConstant ("NULL")));
1128 if (!f
.is_private_symbol ()) {
1129 target_def
.modifiers
= CCodeModifiers
.EXTERN
;
1131 target_def
.modifiers
= CCodeModifiers
.STATIC
;
1133 cfile
.add_type_member_declaration (target_def
);
1135 if (delegate_type
.value_owned
) {
1136 var target_destroy_notify_def
= new
CCodeDeclaration ("GDestroyNotify");
1137 target_destroy_notify_def
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f
.get_cname ()), new
CCodeConstant ("NULL")));
1138 if (!f
.is_private_symbol ()) {
1139 target_destroy_notify_def
.modifiers
= CCodeModifiers
.EXTERN
;
1141 target_destroy_notify_def
.modifiers
= CCodeModifiers
.STATIC
;
1143 cfile
.add_type_member_declaration (target_destroy_notify_def
);
1149 if (f
.initializer
!= null) {
1150 var rhs
= get_cvalue (f
.initializer
);
1151 if (!is_constant_ccode_expression (rhs
)) {
1152 if (f
.parent_symbol is Class
) {
1153 if (f
.initializer is InitializerList
) {
1154 ccode
.open_block ();
1156 var temp_decl
= get_temp_variable (f
.variable_type
);
1157 var vardecl
= new CCodeVariableDeclarator
.zero (temp_decl
.name
, rhs
);
1158 ccode
.add_declaration (temp_decl
.variable_type
.get_cname (), vardecl
);
1160 var tmp
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
1161 ccode
.add_assignment (lhs
, tmp
);
1165 ccode
.add_assignment (lhs
, rhs
);
1168 if (f
.variable_type is ArrayType
&& !f
.no_array_length
&&
1169 f
.initializer is ArrayCreationExpression
) {
1170 var array_type
= (ArrayType
) f
.variable_type
;
1171 var ma
= new MemberAccess
.simple (f
.name
);
1172 ma
.symbol_reference
= f
;
1173 ma
.value_type
= f
.variable_type
.copy ();
1174 visit_member_access (ma
);
1176 List
<Expression
> sizes
= ((ArrayCreationExpression
) f
.initializer
).get_sizes ();
1177 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1178 var array_len_lhs
= get_array_length_cexpression (ma
, dim
);
1179 var size
= sizes
[dim
- 1];
1180 ccode
.add_assignment (array_len_lhs
, get_cvalue (size
));
1185 Report
.error (f
.source_reference
, "Non-constant field initializers not supported in this context");
1195 public bool is_constant_ccode_expression (CCodeExpression cexpr
) {
1196 if (cexpr is CCodeConstant
) {
1198 } else if (cexpr is CCodeCastExpression
) {
1199 var ccast
= (CCodeCastExpression
) cexpr
;
1200 return is_constant_ccode_expression (ccast
.inner
);
1201 } else if (cexpr is CCodeBinaryExpression
) {
1202 var cbinary
= (CCodeBinaryExpression
) cexpr
;
1203 return is_constant_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
1206 var cparenthesized
= (cexpr as CCodeParenthesizedExpression
);
1207 return (null != cparenthesized
&& is_constant_ccode_expression (cparenthesized
.inner
));
1211 * Returns whether the passed cexpr is a pure expression, i.e. an
1212 * expression without side-effects.
1214 public bool is_pure_ccode_expression (CCodeExpression cexpr
) {
1215 if (cexpr is CCodeConstant
|| cexpr is CCodeIdentifier
) {
1217 } else if (cexpr is CCodeBinaryExpression
) {
1218 var cbinary
= (CCodeBinaryExpression
) cexpr
;
1219 return is_pure_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
1220 } else if (cexpr is CCodeUnaryExpression
) {
1221 var cunary
= (CCodeUnaryExpression
) cexpr
;
1222 switch (cunary
.operator
) {
1223 case CCodeUnaryOperator
.PREFIX_INCREMENT
:
1224 case CCodeUnaryOperator
.PREFIX_DECREMENT
:
1225 case CCodeUnaryOperator
.POSTFIX_INCREMENT
:
1226 case CCodeUnaryOperator
.POSTFIX_DECREMENT
:
1229 return is_pure_ccode_expression (cunary
.inner
);
1231 } else if (cexpr is CCodeMemberAccess
) {
1232 var cma
= (CCodeMemberAccess
) cexpr
;
1233 return is_pure_ccode_expression (cma
.inner
);
1234 } else if (cexpr is CCodeElementAccess
) {
1235 var cea
= (CCodeElementAccess
) cexpr
;
1236 return is_pure_ccode_expression (cea
.container
) && is_pure_ccode_expression (cea
.index
);
1237 } else if (cexpr is CCodeCastExpression
) {
1238 var ccast
= (CCodeCastExpression
) cexpr
;
1239 return is_pure_ccode_expression (ccast
.inner
);
1240 } else if (cexpr is CCodeParenthesizedExpression
) {
1241 var cparenthesized
= (CCodeParenthesizedExpression
) cexpr
;
1242 return is_pure_ccode_expression (cparenthesized
.inner
);
1248 public override void visit_formal_parameter (Parameter p
) {
1250 check_type (p
.variable_type
);
1254 public override void visit_property (Property prop
) {
1255 visit_member (prop
);
1257 check_type (prop
.property_type
);
1259 if (prop
.get_accessor
!= null) {
1260 prop
.get_accessor
.accept (this
);
1262 if (prop
.set_accessor
!= null) {
1263 prop
.set_accessor
.accept (this
);
1267 public void generate_type_declaration (DataType type
, CCodeFile decl_space
) {
1268 if (type is ObjectType
) {
1269 var object_type
= (ObjectType
) type
;
1270 if (object_type
.type_symbol is Class
) {
1271 generate_class_declaration ((Class
) object_type
.type_symbol
, decl_space
);
1272 } else if (object_type
.type_symbol is Interface
) {
1273 generate_interface_declaration ((Interface
) object_type
.type_symbol
, decl_space
);
1275 } else if (type is DelegateType
) {
1276 var deleg_type
= (DelegateType
) type
;
1277 var d
= deleg_type
.delegate_symbol
;
1278 generate_delegate_declaration (d
, decl_space
);
1279 } else if (type
.data_type is Enum
) {
1280 var en
= (Enum
) type
.data_type
;
1281 generate_enum_declaration (en
, decl_space
);
1282 } else if (type is ValueType
) {
1283 var value_type
= (ValueType
) type
;
1284 generate_struct_declaration ((Struct
) value_type
.type_symbol
, decl_space
);
1285 } else if (type is ArrayType
) {
1286 var array_type
= (ArrayType
) type
;
1287 generate_type_declaration (array_type
.element_type
, decl_space
);
1288 } else if (type is ErrorType
) {
1289 var error_type
= (ErrorType
) type
;
1290 if (error_type
.error_domain
!= null) {
1291 generate_error_domain_declaration (error_type
.error_domain
, decl_space
);
1293 } else if (type is PointerType
) {
1294 var pointer_type
= (PointerType
) type
;
1295 generate_type_declaration (pointer_type
.base_type
, decl_space
);
1298 foreach (DataType type_arg
in type
.get_type_arguments ()) {
1299 generate_type_declaration (type_arg
, decl_space
);
1303 public virtual void generate_class_struct_declaration (Class cl
, CCodeFile decl_space
) {
1306 public virtual void generate_struct_declaration (Struct st
, CCodeFile decl_space
) {
1309 public virtual void generate_delegate_declaration (Delegate d
, CCodeFile decl_space
) {
1312 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) {
1315 public void generate_property_accessor_declaration (PropertyAccessor acc
, CCodeFile decl_space
) {
1316 if (add_symbol_declaration (decl_space
, acc
, acc
.get_cname ())) {
1320 var prop
= (Property
) acc
.prop
;
1322 bool returns_real_struct
= acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ();
1325 CCodeParameter cvalueparam
;
1326 if (returns_real_struct
) {
1327 cvalueparam
= new
CCodeParameter ("result", acc
.value_type
.get_cname () + "*");
1328 } else if (!acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ()) {
1329 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname () + "*");
1331 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname ());
1333 generate_type_declaration (acc
.value_type
, decl_space
);
1335 CCodeFunction function
;
1336 if (acc
.readable
&& !returns_real_struct
) {
1337 function
= new
CCodeFunction (acc
.get_cname (), acc
.value_type
.get_cname ());
1339 function
= new
CCodeFunction (acc
.get_cname (), "void");
1342 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1343 var t
= (TypeSymbol
) prop
.parent_symbol
;
1344 var this_type
= get_data_type_for_symbol (t
);
1345 generate_type_declaration (this_type
, decl_space
);
1346 var cselfparam
= new
CCodeParameter ("self", this_type
.get_cname ());
1348 cselfparam
.type_name
+= "*";
1351 function
.add_parameter (cselfparam
);
1354 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1355 function
.add_parameter (cvalueparam
);
1358 if (acc
.value_type is ArrayType
) {
1359 var array_type
= (ArrayType
) acc
.value_type
;
1361 var length_ctype
= "int";
1363 length_ctype
= "int*";
1366 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1367 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1369 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1370 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1373 if (prop
.is_private_symbol () || (!acc
.readable
&& !acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1374 function
.modifiers
|= CCodeModifiers
.STATIC
;
1376 decl_space
.add_function_declaration (function
);
1379 public override void visit_property_accessor (PropertyAccessor acc
) {
1380 push_context (new
EmitContext (acc
));
1382 var prop
= (Property
) acc
.prop
;
1384 if (acc
.comment
!= null) {
1385 cfile
.add_type_member_definition (new
CCodeComment (acc
.comment
.content
));
1388 bool returns_real_struct
= acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ();
1390 if (acc
.result_var
!= null) {
1391 acc
.result_var
.accept (this
);
1394 var t
= (TypeSymbol
) prop
.parent_symbol
;
1396 if (acc
.construction
&& !t
.is_subtype_of (gobject_type
)) {
1397 Report
.error (acc
.source_reference
, "construct properties require GLib.Object");
1400 } else if (acc
.construction
&& !is_gobject_property (prop
)) {
1401 Report
.error (acc
.source_reference
, "construct properties not supported for specified property type");
1406 // do not declare overriding properties and interface implementations
1407 if (prop
.is_abstract
|| prop
.is_virtual
1408 || (prop
.base_property
== null && prop
.base_interface_property
== null)) {
1409 generate_property_accessor_declaration (acc
, cfile
);
1411 // do not declare construct-only properties in header files
1412 if (acc
.readable
|| acc
.writable
) {
1413 if (!prop
.is_internal_symbol ()
1414 && (acc
.access
== SymbolAccessibility
.PUBLIC
1415 || acc
.access
== SymbolAccessibility
.PROTECTED
)) {
1416 generate_property_accessor_declaration (acc
, header_file
);
1418 if (!prop
.is_private_symbol () && acc
.access
!= SymbolAccessibility
.PRIVATE
) {
1419 generate_property_accessor_declaration (acc
, internal_header_file
);
1424 if (acc
.source_type
== SourceFileType
.FAST
) {
1428 var this_type
= get_data_type_for_symbol (t
);
1429 var cselfparam
= new
CCodeParameter ("self", this_type
.get_cname ());
1431 cselfparam
.type_name
+= "*";
1433 CCodeParameter cvalueparam
;
1434 if (returns_real_struct
) {
1435 cvalueparam
= new
CCodeParameter ("result", acc
.value_type
.get_cname () + "*");
1436 } else if (!acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ()) {
1437 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname () + "*");
1439 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname ());
1442 if (prop
.is_abstract
|| prop
.is_virtual
) {
1443 CCodeFunction function
;
1444 if (acc
.readable
&& !returns_real_struct
) {
1445 function
= new
CCodeFunction (acc
.get_cname (), current_return_type
.get_cname ());
1447 function
= new
CCodeFunction (acc
.get_cname (), "void");
1449 function
.add_parameter (cselfparam
);
1450 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1451 function
.add_parameter (cvalueparam
);
1454 if (acc
.value_type is ArrayType
) {
1455 var array_type
= (ArrayType
) acc
.value_type
;
1457 var length_ctype
= "int";
1459 length_ctype
= "int*";
1462 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1463 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1465 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1466 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1469 if (prop
.is_private_symbol () || !(acc
.readable
|| acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1470 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1471 function
.modifiers
|= CCodeModifiers
.STATIC
;
1474 push_function (function
);
1476 CCodeFunctionCall vcast
= null;
1477 if (prop
.parent_symbol is Interface
) {
1478 var iface
= (Interface
) prop
.parent_symbol
;
1480 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (iface
.get_upper_case_cname (null))));
1482 var cl
= (Class
) prop
.parent_symbol
;
1484 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (cl
.get_upper_case_cname (null))));
1486 vcast
.add_argument (new
CCodeIdentifier ("self"));
1489 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "get_%s".printf (prop
.name
)));
1490 vcall
.add_argument (new
CCodeIdentifier ("self"));
1491 if (returns_real_struct
) {
1492 vcall
.add_argument (new
CCodeIdentifier ("result"));
1493 ccode
.add_expression (vcall
);
1495 if (acc
.value_type is ArrayType
) {
1496 var array_type
= (ArrayType
) acc
.value_type
;
1498 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1499 var len_expr
= new
CCodeIdentifier (get_array_length_cname ("result", dim
));
1500 vcall
.add_argument (len_expr
);
1502 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1503 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_cname ("result")));
1506 ccode
.add_return (vcall
);
1509 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "set_%s".printf (prop
.name
)));
1510 vcall
.add_argument (new
CCodeIdentifier ("self"));
1511 vcall
.add_argument (new
CCodeIdentifier ("value"));
1513 if (acc
.value_type is ArrayType
) {
1514 var array_type
= (ArrayType
) acc
.value_type
;
1516 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1517 var len_expr
= new
CCodeIdentifier (get_array_length_cname ("value", dim
));
1518 vcall
.add_argument (len_expr
);
1520 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1521 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_cname ("value")));
1524 ccode
.add_expression (vcall
);
1529 cfile
.add_function (function
);
1532 if (!prop
.is_abstract
) {
1533 bool is_virtual
= prop
.base_property
!= null || prop
.base_interface_property
!= null;
1538 cname
= "%s_real_get_%s".printf (t
.get_lower_case_cname (null), prop
.name
);
1540 cname
= "%s_real_set_%s".printf (t
.get_lower_case_cname (null), prop
.name
);
1543 cname
= acc
.get_cname ();
1546 CCodeFunction function
;
1547 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1548 function
= new
CCodeFunction (cname
, "void");
1550 function
= new
CCodeFunction (cname
, acc
.value_type
.get_cname ());
1553 ObjectType base_type
= null;
1554 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1556 if (prop
.base_property
!= null) {
1557 base_type
= new
ObjectType ((ObjectTypeSymbol
) prop
.base_property
.parent_symbol
);
1558 } else if (prop
.base_interface_property
!= null) {
1559 base_type
= new
ObjectType ((ObjectTypeSymbol
) prop
.base_interface_property
.parent_symbol
);
1561 function
.modifiers
|= CCodeModifiers
.STATIC
;
1562 function
.add_parameter (new
CCodeParameter ("base", base_type
.get_cname ()));
1564 function
.add_parameter (cselfparam
);
1567 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1568 function
.add_parameter (cvalueparam
);
1571 if (acc
.value_type is ArrayType
) {
1572 var array_type
= (ArrayType
) acc
.value_type
;
1574 var length_ctype
= "int";
1576 length_ctype
= "int*";
1579 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1580 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1582 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1583 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1587 if (prop
.is_private_symbol () || !(acc
.readable
|| acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1588 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1589 function
.modifiers
|= CCodeModifiers
.STATIC
;
1593 push_function (function
);
1595 if (prop
.binding
== MemberBinding
.INSTANCE
&& !is_virtual
) {
1596 if (!acc
.readable
|| returns_real_struct
) {
1597 create_property_type_check_statement (prop
, false, t
, true, "self");
1599 create_property_type_check_statement (prop
, true, t
, true, "self");
1603 if (acc
.readable
&& !returns_real_struct
) {
1604 // do not declare result variable if exit block is known to be unreachable
1605 if (acc
.return_block
== null || acc
.return_block
.get_predecessors ().size
> 0) {
1606 ccode
.add_declaration (acc
.value_type
.get_cname (), new
CCodeVariableDeclarator ("result"));
1611 ccode
.add_declaration (this_type
.get_cname (), new
CCodeVariableDeclarator ("self"));
1612 ccode
.add_assignment (new
CCodeIdentifier ("self"), transform_expression (new
CCodeIdentifier ("base"), base_type
, this_type
));
1615 acc
.body
.emit (this
);
1617 if (current_method_inner_error
) {
1618 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
1621 // notify on property changes
1622 if (is_gobject_property (prop
) &&
1624 (acc
.writable
|| acc
.construction
)) {
1625 var notify_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_notify"));
1626 notify_call
.add_argument (new
CCodeCastExpression (new
CCodeIdentifier ("self"), "GObject *"));
1627 notify_call
.add_argument (prop
.get_canonical_cconstant ());
1628 ccode
.add_expression (notify_call
);
1631 cfile
.add_function (function
);
1637 public override void visit_destructor (Destructor d
) {
1638 if (d
.binding
== MemberBinding
.STATIC
&& !in_plugin
) {
1639 Report
.error (d
.source_reference
, "static destructors are only supported for dynamic types");
1645 public int get_block_id (Block b
) {
1646 int result
= block_map
[b
];
1648 result
= ++next_block_id
;
1649 block_map
[b
] = result
;
1654 void capture_parameter (Parameter param
, CCodeStruct data
, int block_id
) {
1655 generate_type_declaration (param
.variable_type
, cfile
);
1657 var param_type
= param
.variable_type
.copy ();
1658 param_type
.value_owned
= true;
1659 data
.add_field (param_type
.get_cname (), get_variable_cname (param
.name
));
1661 bool is_unowned_delegate
= param
.variable_type is DelegateType
&& !param
.variable_type
.value_owned
;
1663 // create copy if necessary as captured variables may need to be kept alive
1664 CCodeExpression cparam
= get_variable_cexpression (param
.name
);
1665 if (param
.variable_type
.is_real_non_null_struct_type ()) {
1666 cparam
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cparam
);
1668 if (requires_copy (param_type
) && !param
.variable_type
.value_owned
&& !is_unowned_delegate
) {
1669 var ma
= new MemberAccess
.simple (param
.name
);
1670 ma
.symbol_reference
= param
;
1671 ma
.value_type
= param
.variable_type
.copy ();
1672 // directly access parameters in ref expressions
1673 param
.captured
= false;
1674 visit_member_access (ma
);
1675 cparam
= get_ref_cexpression (param
.variable_type
, cparam
, ma
, param
);
1676 param
.captured
= true;
1679 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_variable_cname (param
.name
)), cparam
);
1681 if (param
.variable_type is ArrayType
) {
1682 var array_type
= (ArrayType
) param
.variable_type
;
1683 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1684 data
.add_field ("gint", get_parameter_array_length_cname (param
, dim
));
1685 ccode
.add_assignment (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
)));
1687 } else if (param
.variable_type is DelegateType
) {
1688 CCodeExpression target_expr
;
1689 CCodeExpression delegate_target_destroy_notify
;
1690 if (is_in_coroutine ()) {
1691 target_expr
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_delegate_target_cname (get_variable_cname (param
.name
)));
1692 delegate_target_destroy_notify
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1694 target_expr
= new
CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param
.name
)));
1695 delegate_target_destroy_notify
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1698 data
.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (param
.name
)));
1699 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_delegate_target_cname (get_variable_cname (param
.name
))), target_expr
);
1700 if (param
.variable_type
.value_owned
) {
1701 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1702 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
))), delegate_target_destroy_notify
);
1707 public override void visit_block (Block b
) {
1708 emit_context
.push_symbol (b
);
1710 var local_vars
= b
.get_local_variables ();
1712 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
) {
1713 ccode
.open_block ();
1717 var parent_block
= next_closure_block (b
.parent_symbol
);
1719 int block_id
= get_block_id (b
);
1720 string struct_name
= "Block%dData".printf (block_id
);
1722 var data
= new
CCodeStruct ("_" + struct_name
);
1723 data
.add_field ("int", "_ref_count_");
1724 if (parent_block
!= null) {
1725 int parent_block_id
= get_block_id (parent_block
);
1727 data
.add_field ("Block%dData *".printf (parent_block_id
), "_data%d_".printf (parent_block_id
));
1729 if (in_constructor
|| (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) ||
1730 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
1731 data
.add_field ("%s *".printf (current_class
.get_cname ()), "self");
1734 if (current_method
!= null) {
1735 // allow capturing generic type parameters
1736 foreach (var type_param
in current_method
.get_type_parameters ()) {
1739 func_name
= "%s_type".printf (type_param
.name
.down ());
1740 data
.add_field ("GType", func_name
);
1742 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
1743 data
.add_field ("GBoxedCopyFunc", func_name
);
1745 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
1746 data
.add_field ("GDestroyNotify", func_name
);
1750 foreach (var local
in local_vars
) {
1751 if (local
.captured
) {
1752 generate_type_declaration (local
.variable_type
, cfile
);
1754 data
.add_field (local
.variable_type
.get_cname (), get_variable_cname (local
.name
) + local
.variable_type
.get_cdeclarator_suffix ());
1756 if (local
.variable_type is ArrayType
) {
1757 var array_type
= (ArrayType
) local
.variable_type
;
1758 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1759 data
.add_field ("gint", get_array_length_cname (get_variable_cname (local
.name
), dim
));
1761 data
.add_field ("gint", get_array_size_cname (get_variable_cname (local
.name
)));
1762 } else if (local
.variable_type is DelegateType
) {
1763 data
.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (local
.name
)));
1764 if (local
.variable_type
.value_owned
) {
1765 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (local
.name
)));
1771 var data_alloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
1772 data_alloc
.add_argument (new
CCodeIdentifier (struct_name
));
1774 if (is_in_coroutine ()) {
1775 closure_struct
.add_field (struct_name
+ "*", "_data%d_".printf (block_id
));
1777 ccode
.add_declaration (struct_name
+ "*", new
CCodeVariableDeclarator ("_data%d_".printf (block_id
)));
1779 ccode
.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id
)), data_alloc
);
1781 // initialize ref_count
1782 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_ref_count_"), new
CCodeIdentifier ("1"));
1784 if (parent_block
!= null) {
1785 int parent_block_id
= get_block_id (parent_block
);
1787 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (parent_block_id
)));
1788 ref_call
.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id
)));
1790 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)), ref_call
);
1792 if (in_constructor
|| (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
&&
1793 (!(current_method is CreationMethod
) || current_method
.body
!= b
)) ||
1794 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
1795 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (new
ObjectType (current_class
), b
.source_reference
));
1796 ref_call
.add_argument (get_result_cexpression ("self"));
1798 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "self"), ref_call
);
1801 if (current_method
!= null) {
1802 // allow capturing generic type parameters
1803 foreach (var type_param
in current_method
.get_type_parameters ()) {
1806 func_name
= "%s_type".printf (type_param
.name
.down ());
1807 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
));
1809 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
1810 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
));
1812 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
1813 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
));
1818 if (b
.parent_symbol is Method
) {
1819 var m
= (Method
) b
.parent_symbol
;
1821 // parameters are captured with the top-level block of the method
1822 foreach (var param
in m
.get_parameters ()) {
1823 if (param
.captured
) {
1824 capture_parameter (param
, data
, block_id
);
1829 // capture async data to allow invoking callback from inside closure
1830 data
.add_field ("gpointer", "_async_data_");
1832 // async method is suspended while waiting for callback,
1833 // so we never need to care about memory management of async data
1834 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_async_data_"), new
CCodeIdentifier ("data"));
1836 } else if (b
.parent_symbol is PropertyAccessor
) {
1837 var acc
= (PropertyAccessor
) b
.parent_symbol
;
1839 if (!acc
.readable
&& acc
.value_parameter
.captured
) {
1840 capture_parameter (acc
.value_parameter
, data
, block_id
);
1844 var typedef
= new
CCodeTypeDefinition ("struct _" + struct_name
, new
CCodeVariableDeclarator (struct_name
));
1845 cfile
.add_type_declaration (typedef
);
1846 cfile
.add_type_definition (data
);
1848 // create ref/unref functions
1849 var ref_fun
= new
CCodeFunction ("block%d_data_ref".printf (block_id
), struct_name
+ "*");
1850 ref_fun
.add_parameter (new
CCodeParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
1851 ref_fun
.modifiers
= CCodeModifiers
.STATIC
;
1852 cfile
.add_function_declaration (ref_fun
);
1853 ref_fun
.block
= new
CCodeBlock ();
1855 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_atomic_int_inc"));
1856 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_ref_count_")));
1857 ref_fun
.block
.add_statement (new
CCodeExpressionStatement (ccall
));
1858 ref_fun
.block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("_data%d_".printf (block_id
))));
1859 cfile
.add_function (ref_fun
);
1861 var unref_fun
= new
CCodeFunction ("block%d_data_unref".printf (block_id
), "void");
1862 unref_fun
.add_parameter (new
CCodeParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
1863 unref_fun
.modifiers
= CCodeModifiers
.STATIC
;
1864 cfile
.add_function_declaration (unref_fun
);
1866 push_function (unref_fun
);
1868 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_atomic_int_dec_and_test"));
1869 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_ref_count_")));
1870 ccode
.open_if (ccall
);
1872 if (parent_block
!= null) {
1873 int parent_block_id
= get_block_id (parent_block
);
1875 var unref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (parent_block_id
)));
1876 unref_call
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)));
1877 ccode
.add_expression (unref_call
);
1878 ccode
.add_assignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)), new
CCodeConstant ("NULL"));
1880 if (in_constructor
|| (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) ||
1881 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
1882 var ma
= new MemberAccess
.simple ("this");
1883 ma
.symbol_reference
= current_class
;
1884 ccode
.add_expression (get_unref_expression (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "self"), new
ObjectType (current_class
), ma
));
1888 // free in reverse order
1889 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1890 var local
= local_vars
[i
];
1891 if (local
.captured
) {
1892 if (requires_destroy (local
.variable_type
)) {
1893 bool old_coroutine
= false;
1894 if (current_method
!= null) {
1895 old_coroutine
= current_method
.coroutine
;
1896 current_method
.coroutine
= false;
1899 ccode
.add_expression (destroy_local (local
));
1901 if (old_coroutine
) {
1902 current_method
.coroutine
= true;
1908 if (b
.parent_symbol is Method
) {
1909 var m
= (Method
) b
.parent_symbol
;
1911 // parameters are captured with the top-level block of the method
1912 foreach (var param
in m
.get_parameters ()) {
1913 if (param
.captured
) {
1914 var param_type
= param
.variable_type
.copy ();
1915 param_type
.value_owned
= true;
1917 bool is_unowned_delegate
= param
.variable_type is DelegateType
&& !param
.variable_type
.value_owned
;
1919 if (requires_destroy (param_type
) && !is_unowned_delegate
) {
1920 bool old_coroutine
= false;
1922 old_coroutine
= m
.coroutine
;
1923 m
.coroutine
= false;
1926 ccode
.add_expression (destroy_parameter (param
));
1928 if (old_coroutine
) {
1934 } else if (b
.parent_symbol is PropertyAccessor
) {
1935 var acc
= (PropertyAccessor
) b
.parent_symbol
;
1937 if (!acc
.readable
&& acc
.value_parameter
.captured
) {
1938 var param_type
= acc
.value_parameter
.variable_type
.copy ();
1939 param_type
.value_owned
= true;
1941 bool is_unowned_delegate
= acc
.value_parameter
.variable_type is DelegateType
&& !acc
.value_parameter
.variable_type
.value_owned
;
1943 if (requires_destroy (param_type
) && !is_unowned_delegate
) {
1944 ccode
.add_expression (destroy_parameter (acc
.value_parameter
));
1949 var data_free
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_free"));
1950 data_free
.add_argument (new
CCodeIdentifier (struct_name
));
1951 data_free
.add_argument (new
CCodeIdentifier ("_data%d_".printf (block_id
)));
1952 ccode
.add_expression (data_free
);
1958 cfile
.add_function (unref_fun
);
1961 foreach (Statement stmt
in b
.get_statements ()) {
1965 // free in reverse order
1966 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1967 var local
= local_vars
[i
];
1968 local
.active
= false;
1969 if (!local
.unreachable
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
1970 ccode
.add_expression (destroy_local (local
));
1974 if (b
.parent_symbol is Method
) {
1975 var m
= (Method
) b
.parent_symbol
;
1976 foreach (Parameter param
in m
.get_parameters ()) {
1977 if (!param
.captured
&& !param
.ellipsis
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
1978 ccode
.add_expression (destroy_parameter (param
));
1979 } else if (param
.direction
== ParameterDirection
.OUT
&& !m
.coroutine
) {
1980 return_out_parameter (param
);
1986 int block_id
= get_block_id (b
);
1988 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
1989 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
1990 ccode
.add_expression (data_unref
);
1991 ccode
.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id
)), new
CCodeConstant ("NULL"));
1994 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
) {
1998 emit_context
.pop_symbol ();
2001 public override void visit_declaration_statement (DeclarationStatement stmt
) {
2002 stmt
.declaration
.accept (this
);
2005 public CCodeExpression
get_variable_cexpression (string name
) {
2006 if (is_in_coroutine ()) {
2007 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_variable_cname (name
));
2009 return new
CCodeIdentifier (get_variable_cname (name
));
2013 public string get_variable_cname (string name
) {
2014 if (name
[0] == '.') {
2015 if (name
== ".result") {
2018 // compiler-internal variable
2019 if (!variable_name_map
.contains (name
)) {
2020 variable_name_map
.set (name
, "_tmp%d_".printf (next_temp_var_id
));
2023 return variable_name_map
.get (name
);
2024 } else if (reserved_identifiers
.contains (name
)) {
2025 return "_%s_".printf (name
);
2031 public CCodeExpression
get_result_cexpression (string cname
= "result") {
2032 if (is_in_coroutine ()) {
2033 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), cname
);
2035 return new
CCodeIdentifier (cname
);
2039 bool has_simple_struct_initializer (LocalVariable local
) {
2040 var st
= local
.variable_type
.data_type as Struct
;
2041 var initializer
= local
.initializer as ObjectCreationExpression
;
2042 if (st
!= null && (!st
.is_simple_type () || st
.get_cname () == "va_list") && !local
.variable_type
.nullable
&&
2043 initializer
!= null && initializer
.get_object_initializer ().size
== 0) {
2050 public override void visit_local_variable (LocalVariable local
) {
2051 check_type (local
.variable_type
);
2053 if (local
.initializer
!= null) {
2054 local
.initializer
.emit (this
);
2056 visit_end_full_expression (local
.initializer
);
2059 generate_type_declaration (local
.variable_type
, cfile
);
2061 CCodeExpression rhs
= null;
2062 if (local
.initializer
!= null && get_cvalue (local
.initializer
) != null) {
2063 rhs
= get_cvalue (local
.initializer
);
2066 if (!local
.captured
) {
2067 if (current_method
!= null && current_method
.coroutine
) {
2068 closure_struct
.add_field (local
.variable_type
.get_cname (), get_variable_cname (local
.name
) + local
.variable_type
.get_cdeclarator_suffix ());
2070 var cvar
= new
CCodeVariableDeclarator (get_variable_cname (local
.name
), null, local
.variable_type
.get_cdeclarator_suffix ());
2072 // try to initialize uninitialized variables
2073 // initialization not necessary for variables stored in closure
2074 if (rhs
== null || has_simple_struct_initializer (local
)) {
2075 cvar
.initializer
= default_value_for_type (local
.variable_type
, true);
2079 ccode
.add_declaration (local
.variable_type
.get_cname (), cvar
);
2082 if (local
.variable_type is ArrayType
) {
2083 // create variables to store array dimensions
2084 var array_type
= (ArrayType
) local
.variable_type
;
2086 if (!array_type
.fixed_length
) {
2087 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2088 var len_var
= new
LocalVariable (int_type
.copy (), get_array_length_cname (get_variable_cname (local
.name
), dim
));
2089 emit_temp_var (len_var
, local
.initializer
== null);
2092 if (array_type
.rank
== 1) {
2093 var size_var
= new
LocalVariable (int_type
.copy (), get_array_size_cname (get_variable_cname (local
.name
)));
2094 emit_temp_var (size_var
, local
.initializer
== null);
2097 } else if (local
.variable_type is DelegateType
) {
2098 var deleg_type
= (DelegateType
) local
.variable_type
;
2099 var d
= deleg_type
.delegate_symbol
;
2101 // create variable to store delegate target
2102 var target_var
= new
LocalVariable (new
PointerType (new
VoidType ()), get_delegate_target_cname (get_variable_cname (local
.name
)));
2103 emit_temp_var (target_var
, local
.initializer
== null);
2104 if (deleg_type
.value_owned
) {
2105 var target_destroy_notify_var
= new
LocalVariable (gdestroynotify_type
, get_delegate_target_destroy_notify_cname (get_variable_cname (local
.name
)));
2106 emit_temp_var (target_destroy_notify_var
, local
.initializer
== null);
2113 if (!has_simple_struct_initializer (local
)) {
2114 store_local (local
, local
.initializer
.target_value
, true);
2118 if (local
.initializer
!= null && local
.initializer
.tree_can_fail
) {
2119 add_simple_check (local
.initializer
);
2122 local
.active
= true;
2125 public override void visit_initializer_list (InitializerList list
) {
2126 if (list
.target_type
.data_type is Struct
) {
2127 /* initializer is used as struct initializer */
2128 var st
= (Struct
) list
.target_type
.data_type
;
2130 if (list
.parent_node is Constant
|| list
.parent_node is Field
|| list
.parent_node is InitializerList
) {
2131 var clist
= new
CCodeInitializerList ();
2133 var field_it
= st
.get_fields ().iterator ();
2134 foreach (Expression expr
in list
.get_initializers ()) {
2136 while (field
== null) {
2138 field
= field_it
.get ();
2139 if (field
.binding
!= MemberBinding
.INSTANCE
) {
2140 // we only initialize instance fields
2145 var cexpr
= get_cvalue (expr
);
2147 string ctype
= field
.get_ctype ();
2148 if (ctype
!= null) {
2149 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
2152 clist
.append (cexpr
);
2155 set_cvalue (list
, clist
);
2157 // used as expression
2158 var temp_decl
= get_temp_variable (list
.target_type
, false, list
);
2159 emit_temp_var (temp_decl
);
2161 var instance
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
2163 var field_it
= st
.get_fields ().iterator ();
2164 foreach (Expression expr
in list
.get_initializers ()) {
2166 while (field
== null) {
2168 field
= field_it
.get ();
2169 if (field
.binding
!= MemberBinding
.INSTANCE
) {
2170 // we only initialize instance fields
2175 var cexpr
= get_cvalue (expr
);
2177 string ctype
= field
.get_ctype ();
2178 if (ctype
!= null) {
2179 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
2182 var lhs
= new
CCodeMemberAccess (instance
, field
.get_cname ());;
2183 ccode
.add_assignment (lhs
, cexpr
);
2186 set_cvalue (list
, instance
);
2189 var clist
= new
CCodeInitializerList ();
2190 foreach (Expression expr
in list
.get_initializers ()) {
2191 clist
.append (get_cvalue (expr
));
2193 set_cvalue (list
, clist
);
2197 public override LocalVariable
create_local (DataType type
) {
2198 var result
= get_temp_variable (type
, type
.value_owned
);
2199 emit_temp_var (result
);
2203 public LocalVariable
get_temp_variable (DataType type
, bool value_owned
= true, CodeNode? node_reference
= null, bool init
= true) {
2204 var var_type
= type
.copy ();
2205 var_type
.value_owned
= value_owned
;
2206 var local
= new
LocalVariable (var_type
, "_tmp%d_".printf (next_temp_var_id
));
2207 local
.no_init
= !init
;
2209 if (node_reference
!= null) {
2210 local
.source_reference
= node_reference
.source_reference
;
2218 bool is_in_generic_type (DataType type
) {
2219 if (current_symbol
!= null && type
.type_parameter
.parent_symbol is TypeSymbol
2220 && (current_method
== null || current_method
.binding
== MemberBinding
.INSTANCE
)) {
2227 public CCodeExpression
get_type_id_expression (DataType type
, bool is_chainup
= false) {
2228 if (type is GenericType
) {
2229 string var_name
= "%s_type".printf (type
.type_parameter
.name
.down ());
2230 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2231 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), var_name
);
2233 return new
CCodeIdentifier (var_name
);
2236 string type_id
= type
.get_type_id ();
2237 if (type_id
== null) {
2238 type_id
= "G_TYPE_INVALID";
2240 generate_type_declaration (type
, cfile
);
2242 return new
CCodeIdentifier (type_id
);
2246 public virtual CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
, bool is_chainup
= false) {
2247 if (type is ErrorType
) {
2248 return new
CCodeIdentifier ("g_error_copy");
2249 } else if (type
.data_type
!= null) {
2250 string dup_function
;
2251 var cl
= type
.data_type as Class
;
2252 if (type
.data_type
.is_reference_counting ()) {
2253 dup_function
= type
.data_type
.get_ref_function ();
2254 if (type
.data_type is Interface
&& dup_function
== null) {
2255 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 ()));
2258 } else if (cl
!= null && cl
.is_immutable
) {
2259 // allow duplicates of immutable instances as for example strings
2260 dup_function
= type
.data_type
.get_dup_function ();
2261 if (dup_function
== null) {
2264 } else if (cl
!= null && cl
.is_gboxed
) {
2265 // allow duplicates of gboxed instances
2266 dup_function
= generate_dup_func_wrapper (type
);
2267 if (dup_function
== null) {
2270 } else if (type is ValueType
) {
2271 dup_function
= type
.data_type
.get_dup_function ();
2272 if (dup_function
== null && type
.nullable
) {
2273 dup_function
= generate_struct_dup_wrapper ((ValueType
) type
);
2274 } else if (dup_function
== null) {
2278 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2279 Report
.error (source_reference
, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type
.data_type
.name
));
2283 return new
CCodeIdentifier (dup_function
);
2284 } else if (type
.type_parameter
!= null) {
2285 string func_name
= "%s_dup_func".printf (type
.type_parameter
.name
.down ());
2286 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2287 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), func_name
);
2289 return new
CCodeIdentifier (func_name
);
2291 } else if (type is PointerType
) {
2292 var pointer_type
= (PointerType
) type
;
2293 return get_dup_func_expression (pointer_type
.base_type
, source_reference
);
2295 return new
CCodeConstant ("NULL");
2299 void make_comparable_cexpression (ref DataType left_type
, ref CCodeExpression cleft
, ref DataType right_type
, ref CCodeExpression cright
) {
2300 var left_type_as_struct
= left_type
.data_type as Struct
;
2301 var right_type_as_struct
= right_type
.data_type as Struct
;
2304 var valuecast
= try_cast_value_to_type (cleft
, left_type
, right_type
);
2305 if (valuecast
!= null) {
2307 left_type
= right_type
;
2308 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
2312 valuecast
= try_cast_value_to_type (cright
, right_type
, left_type
);
2313 if (valuecast
!= null) {
2315 right_type
= left_type
;
2316 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
2320 if (left_type
.data_type is Class
&& !((Class
) left_type
.data_type
).is_compact
&&
2321 right_type
.data_type is Class
&& !((Class
) right_type
.data_type
).is_compact
) {
2322 var left_cl
= (Class
) left_type
.data_type
;
2323 var right_cl
= (Class
) right_type
.data_type
;
2325 if (left_cl
!= right_cl
) {
2326 if (left_cl
.is_subtype_of (right_cl
)) {
2327 cleft
= generate_instance_cast (cleft
, right_cl
);
2328 } else if (right_cl
.is_subtype_of (left_cl
)) {
2329 cright
= generate_instance_cast (cright
, left_cl
);
2332 } else if (left_type_as_struct
!= null && right_type_as_struct
!= null) {
2333 if (left_type is StructValueType
) {
2334 // real structs (uses compare/equal function)
2335 if (!left_type
.nullable
) {
2336 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cleft
);
2338 if (!right_type
.nullable
) {
2339 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cright
);
2342 // integer or floating or boolean type
2343 if (left_type
.nullable
&& right_type
.nullable
) {
2344 // FIXME also compare contents, not just address
2345 } else if (left_type
.nullable
) {
2346 // FIXME check left value is not null
2347 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cleft
);
2348 } else if (right_type
.nullable
) {
2349 // FIXME check right value is not null
2350 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cright
);
2356 private string generate_struct_equal_function (Struct st
) {
2357 string equal_func
= "_%sequal".printf (st
.get_lower_case_cprefix ());
2359 if (!add_wrapper (equal_func
)) {
2360 // wrapper already defined
2364 var function
= new
CCodeFunction (equal_func
, "gboolean");
2365 function
.modifiers
= CCodeModifiers
.STATIC
;
2367 function
.add_parameter (new
CCodeParameter ("s1", "const " + st
.get_cname () + "*"));
2368 function
.add_parameter (new
CCodeParameter ("s2", "const " + st
.get_cname () + "*"));
2370 push_function (function
);
2372 // if (s1 == s2) return TRUE;
2374 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
2375 ccode
.open_if (cexp
);
2376 ccode
.add_return (new
CCodeConstant ("TRUE"));
2379 // if (s1 == NULL || s2 == NULL) return FALSE;
2381 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeConstant ("NULL"));
2382 ccode
.open_if (cexp
);
2383 ccode
.add_return (new
CCodeConstant ("FALSE"));
2386 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s2"), new
CCodeConstant ("NULL"));
2387 ccode
.open_if (cexp
);
2388 ccode
.add_return (new
CCodeConstant ("FALSE"));
2392 foreach (Field f
in st
.get_fields ()) {
2393 if (f
.binding
!= MemberBinding
.INSTANCE
) {
2394 // we only compare instance fields
2398 CCodeExpression cexp
; // if (cexp) return FALSE;
2399 var s1
= (CCodeExpression
) new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("s1"), f
.name
); // s1->f
2400 var s2
= (CCodeExpression
) new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("s2"), f
.name
); // s2->f
2402 var variable_type
= f
.variable_type
.copy ();
2403 make_comparable_cexpression (ref variable_type
, ref s1
, ref variable_type
, ref s2
);
2405 if (!(f
.variable_type is NullType
) && f
.variable_type
.compatible (string_type
)) {
2406 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
2407 ccall
.add_argument (s1
);
2408 ccall
.add_argument (s2
);
2410 } else if (f
.variable_type is StructValueType
) {
2411 var equalfunc
= generate_struct_equal_function (f
.variable_type
.data_type as Struct
);
2412 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
2413 ccall
.add_argument (s1
);
2414 ccall
.add_argument (s2
);
2415 cexp
= new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, ccall
);
2417 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, s1
, s2
);
2420 ccode
.open_if (cexp
);
2421 ccode
.add_return (new
CCodeConstant ("FALSE"));
2425 if (st
.get_fields().size
== 0) {
2426 // either opaque structure or simple type
2427 if (st
.is_simple_type ()) {
2428 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s1")), new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s2")));
2429 ccode
.add_return (cexp
);
2431 ccode
.add_return (new
CCodeConstant ("FALSE"));
2434 ccode
.add_return (new
CCodeConstant ("TRUE"));
2439 cfile
.add_function_declaration (function
);
2440 cfile
.add_function (function
);
2445 private string generate_numeric_equal_function (Struct st
) {
2446 string equal_func
= "_%sequal".printf (st
.get_lower_case_cprefix ());
2448 if (!add_wrapper (equal_func
)) {
2449 // wrapper already defined
2453 var function
= new
CCodeFunction (equal_func
, "gboolean");
2454 function
.modifiers
= CCodeModifiers
.STATIC
;
2456 function
.add_parameter (new
CCodeParameter ("s1", "const " + st
.get_cname () + "*"));
2457 function
.add_parameter (new
CCodeParameter ("s2", "const " + st
.get_cname () + "*"));
2459 push_function (function
);
2461 // if (s1 == s2) return TRUE;
2463 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
2464 ccode
.open_if (cexp
);
2465 ccode
.add_return (new
CCodeConstant ("TRUE"));
2468 // if (s1 == NULL || s2 == NULL) return FALSE;
2470 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeConstant ("NULL"));
2471 ccode
.open_if (cexp
);
2472 ccode
.add_return (new
CCodeConstant ("FALSE"));
2475 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s2"), new
CCodeConstant ("NULL"));
2476 ccode
.open_if (cexp
);
2477 ccode
.add_return (new
CCodeConstant ("FALSE"));
2480 // return (*s1 == *s2);
2482 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s1")), new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s2")));
2483 ccode
.add_return (cexp
);
2488 cfile
.add_function_declaration (function
);
2489 cfile
.add_function (function
);
2494 private string generate_struct_dup_wrapper (ValueType value_type
) {
2495 string dup_func
= "_%sdup".printf (value_type
.type_symbol
.get_lower_case_cprefix ());
2497 if (!add_wrapper (dup_func
)) {
2498 // wrapper already defined
2502 var function
= new
CCodeFunction (dup_func
, value_type
.get_cname ());
2503 function
.modifiers
= CCodeModifiers
.STATIC
;
2505 function
.add_parameter (new
CCodeParameter ("self", value_type
.get_cname ()));
2507 push_function (function
);
2509 if (value_type
.type_symbol
== gvalue_type
) {
2510 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_copy"));
2511 dup_call
.add_argument (new
CCodeIdentifier ("G_TYPE_VALUE"));
2512 dup_call
.add_argument (new
CCodeIdentifier ("self"));
2514 ccode
.add_return (dup_call
);
2516 ccode
.add_declaration (value_type
.get_cname (), new
CCodeVariableDeclarator ("dup"));
2518 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
2519 creation_call
.add_argument (new
CCodeConstant (value_type
.data_type
.get_cname ()));
2520 creation_call
.add_argument (new
CCodeConstant ("1"));
2521 ccode
.add_assignment (new
CCodeIdentifier ("dup"), creation_call
);
2523 var st
= value_type
.data_type as Struct
;
2524 if (st
!= null && st
.is_disposable ()) {
2525 if (!st
.has_copy_function
) {
2526 generate_struct_copy_function (st
);
2529 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_copy_function ()));
2530 copy_call
.add_argument (new
CCodeIdentifier ("self"));
2531 copy_call
.add_argument (new
CCodeIdentifier ("dup"));
2532 ccode
.add_expression (copy_call
);
2534 cfile
.add_include ("string.h");
2536 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
2537 sizeof_call
.add_argument (new
CCodeConstant (value_type
.data_type
.get_cname ()));
2539 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
2540 copy_call
.add_argument (new
CCodeIdentifier ("dup"));
2541 copy_call
.add_argument (new
CCodeIdentifier ("self"));
2542 copy_call
.add_argument (sizeof_call
);
2543 ccode
.add_expression (copy_call
);
2546 ccode
.add_return (new
CCodeIdentifier ("dup"));
2551 cfile
.add_function_declaration (function
);
2552 cfile
.add_function (function
);
2557 protected string generate_dup_func_wrapper (DataType type
) {
2558 string destroy_func
= "_vala_%s_copy".printf (type
.data_type
.get_cname ());
2560 if (!add_wrapper (destroy_func
)) {
2561 // wrapper already defined
2562 return destroy_func
;
2565 var function
= new
CCodeFunction (destroy_func
, type
.get_cname ());
2566 function
.modifiers
= CCodeModifiers
.STATIC
;
2567 function
.add_parameter (new
CCodeParameter ("self", type
.get_cname ()));
2569 push_function (function
);
2571 var cl
= type
.data_type as Class
;
2572 assert (cl
!= null && cl
.is_gboxed
);
2574 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_copy"));
2575 free_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
2576 free_call
.add_argument (new
CCodeIdentifier ("self"));
2578 ccode
.add_return (free_call
);
2582 cfile
.add_function_declaration (function
);
2583 cfile
.add_function (function
);
2585 return destroy_func
;
2588 protected string generate_free_func_wrapper (DataType type
) {
2589 string destroy_func
= "_vala_%s_free".printf (type
.data_type
.get_cname ());
2591 if (!add_wrapper (destroy_func
)) {
2592 // wrapper already defined
2593 return destroy_func
;
2596 var function
= new
CCodeFunction (destroy_func
, "void");
2597 function
.modifiers
= CCodeModifiers
.STATIC
;
2598 function
.add_parameter (new
CCodeParameter ("self", type
.get_cname ()));
2600 push_function (function
);
2602 var cl
= type
.data_type as Class
;
2603 if (cl
!= null && cl
.is_gboxed
) {
2604 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_free"));
2605 free_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
2606 free_call
.add_argument (new
CCodeIdentifier ("self"));
2608 ccode
.add_expression (free_call
);
2609 } else if (cl
!= null) {
2610 assert (cl
.free_function_address_of
);
2612 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier (type
.data_type
.get_free_function ()));
2613 free_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("self")));
2615 ccode
.add_expression (free_call
);
2617 var st
= type
.data_type as Struct
;
2618 if (st
!= null && st
.is_disposable ()) {
2619 if (!st
.has_destroy_function
) {
2620 generate_struct_destroy_function (st
);
2623 var destroy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_destroy_function ()));
2624 destroy_call
.add_argument (new
CCodeIdentifier ("self"));
2625 ccode
.add_expression (destroy_call
);
2628 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
2629 free_call
.add_argument (new
CCodeIdentifier ("self"));
2631 ccode
.add_expression (free_call
);
2636 cfile
.add_function_declaration (function
);
2637 cfile
.add_function (function
);
2639 return destroy_func
;
2642 public CCodeExpression?
get_destroy0_func_expression (DataType type
, bool is_chainup
= false) {
2643 var element_destroy_func_expression
= get_destroy_func_expression (type
, is_chainup
);
2645 if (element_destroy_func_expression is CCodeIdentifier
) {
2646 var freeid
= (CCodeIdentifier
) element_destroy_func_expression
;
2647 string free0_func
= "_%s0_".printf (freeid
.name
);
2649 if (add_wrapper (free0_func
)) {
2650 var function
= new
CCodeFunction (free0_func
, "void");
2651 function
.modifiers
= CCodeModifiers
.STATIC
;
2653 function
.add_parameter (new
CCodeParameter ("var", "gpointer"));
2655 push_function (function
);
2657 ccode
.add_expression (get_unref_expression (new
CCodeIdentifier ("var"), type
, null, true));
2661 cfile
.add_function_declaration (function
);
2662 cfile
.add_function (function
);
2665 element_destroy_func_expression
= new
CCodeIdentifier (free0_func
);
2668 return element_destroy_func_expression
;
2671 public CCodeExpression?
get_destroy_func_expression (DataType type
, bool is_chainup
= false) {
2672 if (context
.profile
== Profile
.GOBJECT
&& (type
.data_type
== glist_type
|| type
.data_type
== gslist_type
|| type
.data_type
== gnode_type
)) {
2673 // create wrapper function to free list elements if necessary
2675 bool elements_require_free
= false;
2676 CCodeExpression element_destroy_func_expression
= null;
2678 foreach (DataType type_arg
in type
.get_type_arguments ()) {
2679 elements_require_free
= requires_destroy (type_arg
);
2680 if (elements_require_free
) {
2681 element_destroy_func_expression
= get_destroy0_func_expression (type_arg
);
2685 if (elements_require_free
&& element_destroy_func_expression is CCodeIdentifier
) {
2686 return new
CCodeIdentifier (generate_collection_free_wrapper (type
, (CCodeIdentifier
) element_destroy_func_expression
));
2688 return new
CCodeIdentifier (type
.data_type
.get_free_function ());
2690 } else if (type is ErrorType
) {
2691 return new
CCodeIdentifier ("g_error_free");
2692 } else if (type
.data_type
!= null) {
2693 string unref_function
;
2694 if (type is ReferenceType
) {
2695 if (type
.data_type
.is_reference_counting ()) {
2696 unref_function
= type
.data_type
.get_unref_function ();
2697 if (type
.data_type is Interface
&& unref_function
== null) {
2698 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 ()));
2702 var cl
= type
.data_type as Class
;
2703 if (cl
!= null && (cl
.free_function_address_of
|| cl
.is_gboxed
)) {
2704 unref_function
= generate_free_func_wrapper (type
);
2706 unref_function
= type
.data_type
.get_free_function ();
2710 if (type
.nullable
) {
2711 unref_function
= type
.data_type
.get_free_function ();
2712 if (unref_function
== null) {
2713 if (type
.data_type is Struct
&& ((Struct
) type
.data_type
).is_disposable ()) {
2714 unref_function
= generate_free_func_wrapper (type
);
2716 unref_function
= "g_free";
2720 var st
= (Struct
) type
.data_type
;
2721 if (!st
.has_destroy_function
) {
2722 generate_struct_destroy_function (st
);
2724 unref_function
= st
.get_destroy_function ();
2727 if (unref_function
== null) {
2728 return new
CCodeConstant ("NULL");
2730 return new
CCodeIdentifier (unref_function
);
2731 } else if (type
.type_parameter
!= null && current_type_symbol is Class
) {
2732 string func_name
= "%s_destroy_func".printf (type
.type_parameter
.name
.down ());
2733 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2734 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), func_name
);
2736 return new
CCodeIdentifier (func_name
);
2738 } else if (type is ArrayType
) {
2739 if (context
.profile
== Profile
.POSIX
) {
2740 return new
CCodeIdentifier ("free");
2742 return new
CCodeIdentifier ("g_free");
2744 } else if (type is PointerType
) {
2745 if (context
.profile
== Profile
.POSIX
) {
2746 return new
CCodeIdentifier ("free");
2748 return new
CCodeIdentifier ("g_free");
2751 return new
CCodeConstant ("NULL");
2755 private string generate_collection_free_wrapper (DataType collection_type
, CCodeIdentifier element_destroy_func_expression
) {
2756 string destroy_func
= "_%s_%s".printf (collection_type
.data_type
.get_free_function (), element_destroy_func_expression
.name
);
2758 if (!add_wrapper (destroy_func
)) {
2759 // wrapper already defined
2760 return destroy_func
;
2763 var function
= new
CCodeFunction (destroy_func
, "void");
2764 function
.modifiers
= CCodeModifiers
.STATIC
;
2766 function
.add_parameter (new
CCodeParameter ("self", collection_type
.get_cname ()));
2768 push_function (function
);
2770 CCodeFunctionCall element_free_call
;
2771 if (collection_type
.data_type
== gnode_type
) {
2772 /* A wrapper which converts GNodeTraverseFunc into GDestroyNotify */
2773 string destroy_node_func
= "%s_node".printf (destroy_func
);
2774 var wrapper
= new
CCodeFunction (destroy_node_func
, "gboolean");
2775 wrapper
.modifiers
= CCodeModifiers
.STATIC
;
2776 wrapper
.add_parameter (new
CCodeParameter ("node", collection_type
.get_cname ()));
2777 wrapper
.add_parameter (new
CCodeParameter ("unused", "gpointer"));
2778 var wrapper_block
= new
CCodeBlock ();
2779 var free_call
= new
CCodeFunctionCall (element_destroy_func_expression
);
2780 free_call
.add_argument (new CCodeMemberAccess
.pointer(new
CCodeIdentifier("node"), "data"));
2781 wrapper_block
.add_statement (new
CCodeExpressionStatement (free_call
));
2782 wrapper_block
.add_statement (new
CCodeReturnStatement (new
CCodeConstant ("FALSE")));
2783 cfile
.add_function_declaration (function
);
2784 wrapper
.block
= wrapper_block
;
2785 cfile
.add_function (wrapper
);
2787 /* Now the code to call g_traverse with the above */
2788 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_node_traverse"));
2789 element_free_call
.add_argument (new
CCodeIdentifier("self"));
2790 element_free_call
.add_argument (new
CCodeConstant ("G_POST_ORDER"));
2791 element_free_call
.add_argument (new
CCodeConstant ("G_TRAVERSE_ALL"));
2792 element_free_call
.add_argument (new
CCodeConstant ("-1"));
2793 element_free_call
.add_argument (new
CCodeIdentifier (destroy_node_func
));
2794 element_free_call
.add_argument (new
CCodeConstant ("NULL"));
2796 if (collection_type
.data_type
== glist_type
) {
2797 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_list_foreach"));
2799 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slist_foreach"));
2802 element_free_call
.add_argument (new
CCodeIdentifier ("self"));
2803 element_free_call
.add_argument (new
CCodeCastExpression (element_destroy_func_expression
, "GFunc"));
2804 element_free_call
.add_argument (new
CCodeConstant ("NULL"));
2807 ccode
.add_expression (element_free_call
);
2809 var cfreecall
= new
CCodeFunctionCall (new
CCodeIdentifier (collection_type
.data_type
.get_free_function ()));
2810 cfreecall
.add_argument (new
CCodeIdentifier ("self"));
2811 ccode
.add_expression (cfreecall
);
2815 cfile
.add_function_declaration (function
);
2816 cfile
.add_function (function
);
2818 return destroy_func
;
2821 public virtual string?
append_struct_array_free (Struct st
) {
2825 // logic in this method is temporarily duplicated in destroy_value
2826 // apply changes to both methods
2827 public virtual CCodeExpression
destroy_variable (Variable variable
, TargetValue target_lvalue
) {
2828 var type
= variable
.variable_type
;
2829 var cvar
= get_cvalue_ (target_lvalue
);
2831 if (type is DelegateType
) {
2832 var delegate_target
= get_delegate_target_cvalue (target_lvalue
);
2833 var delegate_target_destroy_notify
= get_delegate_target_destroy_notify_cvalue (target_lvalue
);
2835 var ccall
= new
CCodeFunctionCall (delegate_target_destroy_notify
);
2836 ccall
.add_argument (delegate_target
);
2838 var destroy_call
= new
CCodeCommaExpression ();
2839 destroy_call
.append_expression (ccall
);
2840 destroy_call
.append_expression (new
CCodeConstant ("NULL"));
2842 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, delegate_target_destroy_notify
, new
CCodeConstant ("NULL"));
2844 var ccomma
= new
CCodeCommaExpression ();
2845 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), destroy_call
));
2846 ccomma
.append_expression (new
CCodeAssignment (cvar
, new
CCodeConstant ("NULL")));
2847 ccomma
.append_expression (new
CCodeAssignment (delegate_target
, new
CCodeConstant ("NULL")));
2848 ccomma
.append_expression (new
CCodeAssignment (delegate_target_destroy_notify
, new
CCodeConstant ("NULL")));
2853 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
2855 if (type is ValueType
&& !type
.nullable
) {
2856 // normal value type, no null check
2857 var st
= type
.data_type as Struct
;
2858 if (st
!= null && st
.is_simple_type ()) {
2860 ccall
.add_argument (cvar
);
2862 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
2865 if (gvalue_type
!= null && type
.data_type
== gvalue_type
) {
2866 // g_value_unset must not be called for already unset values
2867 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
2868 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
2870 var ccomma
= new
CCodeCommaExpression ();
2871 ccomma
.append_expression (ccall
);
2872 ccomma
.append_expression (new
CCodeConstant ("NULL"));
2874 return new
CCodeConditionalExpression (cisvalid
, ccomma
, new
CCodeConstant ("NULL"));
2880 if (ccall
.call is CCodeIdentifier
&& !(type is ArrayType
)) {
2881 // generate and use NULL-aware free macro to simplify code
2883 var freeid
= (CCodeIdentifier
) ccall
.call
;
2884 string free0_func
= "_%s0".printf (freeid
.name
);
2886 if (add_wrapper (free0_func
)) {
2887 var macro
= destroy_value (new
GLibValue (type
, new
CCodeIdentifier ("var")), true);
2888 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("%s(var)".printf (free0_func
), macro
));
2891 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (free0_func
));
2892 ccall
.add_argument (cvar
);
2896 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
2898 /* can be simplified to
2899 * foo = (unref (foo), NULL)
2900 * if foo is of static type non-null
2903 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cvar
, new
CCodeConstant ("NULL"));
2904 if (type
.type_parameter
!= null) {
2905 if (!(current_type_symbol is Class
) || current_class
.is_compact
) {
2906 return new
CCodeConstant ("NULL");
2909 // unref functions are optional for type parameters
2910 var cunrefisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_destroy_func_expression (type
), new
CCodeConstant ("NULL"));
2911 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cunrefisnull
);
2914 ccall
.add_argument (cvar
);
2916 /* set freed references to NULL to prevent further use */
2917 var ccomma
= new
CCodeCommaExpression ();
2919 if (context
.profile
== Profile
.GOBJECT
) {
2920 if (type
.data_type
!= null && !type
.data_type
.is_reference_counting () &&
2921 (type
.data_type
== gstringbuilder_type
2922 || type
.data_type
== garray_type
2923 || type
.data_type
== gbytearray_type
2924 || type
.data_type
== gptrarray_type
)) {
2925 ccall
.add_argument (new
CCodeConstant ("TRUE"));
2926 } else if (type
.data_type
== gthreadpool_type
) {
2927 ccall
.add_argument (new
CCodeConstant ("FALSE"));
2928 ccall
.add_argument (new
CCodeConstant ("TRUE"));
2929 } else if (type is ArrayType
) {
2930 var array_type
= (ArrayType
) type
;
2931 if (requires_destroy (array_type
.element_type
) && !variable
.no_array_length
) {
2932 CCodeExpression csizeexpr
= null;
2933 if (variable
.array_null_terminated
) {
2934 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
2935 len_call
.add_argument (cvar
);
2936 csizeexpr
= len_call
;
2937 } else if (variable
.has_array_length_cexpr
) {
2938 csizeexpr
= new
CCodeConstant (variable
.get_array_length_cexpr ());
2941 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2943 csizeexpr
= get_array_length_cvalue (target_lvalue
, dim
);
2946 csizeexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeexpr
, get_array_length_cvalue (target_lvalue
, dim
));
2951 var st
= array_type
.element_type
.data_type as Struct
;
2952 if (st
!= null && !array_type
.element_type
.nullable
) {
2953 ccall
.call
= new
CCodeIdentifier (append_struct_array_free (st
));
2954 ccall
.add_argument (csizeexpr
);
2956 requires_array_free
= true;
2957 ccall
.call
= new
CCodeIdentifier ("_vala_array_free");
2958 ccall
.add_argument (csizeexpr
);
2959 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
2965 ccomma
.append_expression (ccall
);
2966 ccomma
.append_expression (new
CCodeConstant ("NULL"));
2968 var cassign
= new
CCodeAssignment (cvar
, ccomma
);
2970 // g_free (NULL) is allowed
2971 bool uses_gfree
= (type
.data_type
!= null && !type
.data_type
.is_reference_counting () && type
.data_type
.get_free_function () == "g_free");
2972 uses_gfree
= uses_gfree
|| type is ArrayType
;
2977 return new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), cassign
);
2980 public CCodeExpression
destroy_local (LocalVariable local
) {
2981 return destroy_variable (local
, get_local_cvalue (local
));
2984 public CCodeExpression
destroy_parameter (Parameter param
) {
2985 return destroy_variable (param
, get_parameter_cvalue (param
));
2988 public CCodeExpression
destroy_field (Field field
, Expression? instance
) {
2989 return destroy_variable (field
, get_field_cvalue (field
, instance
));
2992 public CCodeExpression
get_unref_expression (CCodeExpression cvar
, DataType type
, Expression? expr
, bool is_macro_definition
= false) {
2994 if (expr
.symbol_reference is LocalVariable
) {
2995 return destroy_local ((LocalVariable
) expr
.symbol_reference
);
2996 } else if (expr
.symbol_reference is Parameter
) {
2997 return destroy_parameter ((Parameter
) expr
.symbol_reference
);
3000 var value
= new
GLibValue (type
, cvar
);
3001 if (expr
!= null && expr
.target_value
!= null) {
3002 value
.array_length_cvalues
= ((GLibValue
) expr
.target_value
).array_length_cvalues
;
3003 value
.delegate_target_cvalue
= get_delegate_target_cvalue (expr
.target_value
);
3004 value
.delegate_target_destroy_notify_cvalue
= get_delegate_target_destroy_notify_cvalue (expr
.target_value
);
3006 return destroy_value (value
, is_macro_definition
);
3009 // logic in this method is temporarily duplicated in destroy_variable
3010 // apply changes to both methods
3011 public virtual CCodeExpression
destroy_value (TargetValue value
, bool is_macro_definition
= false) {
3012 var type
= value
.value_type
;
3013 var cvar
= get_cvalue_ (value
);
3015 if (type is DelegateType
) {
3016 var delegate_target
= get_delegate_target_cvalue (value
);
3017 var delegate_target_destroy_notify
= get_delegate_target_destroy_notify_cvalue (value
);
3019 var ccall
= new
CCodeFunctionCall (delegate_target_destroy_notify
);
3020 ccall
.add_argument (delegate_target
);
3022 var destroy_call
= new
CCodeCommaExpression ();
3023 destroy_call
.append_expression (ccall
);
3024 destroy_call
.append_expression (new
CCodeConstant ("NULL"));
3026 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, delegate_target_destroy_notify
, new
CCodeConstant ("NULL"));
3028 var ccomma
= new
CCodeCommaExpression ();
3029 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), destroy_call
));
3030 ccomma
.append_expression (new
CCodeAssignment (cvar
, new
CCodeConstant ("NULL")));
3031 ccomma
.append_expression (new
CCodeAssignment (delegate_target
, new
CCodeConstant ("NULL")));
3032 ccomma
.append_expression (new
CCodeAssignment (delegate_target_destroy_notify
, new
CCodeConstant ("NULL")));
3037 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
3039 if (type is ValueType
&& !type
.nullable
) {
3040 // normal value type, no null check
3041 var st
= type
.data_type as Struct
;
3042 if (st
!= null && st
.is_simple_type ()) {
3044 ccall
.add_argument (cvar
);
3046 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
3049 if (gvalue_type
!= null && type
.data_type
== gvalue_type
) {
3050 // g_value_unset must not be called for already unset values
3051 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
3052 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
3054 var ccomma
= new
CCodeCommaExpression ();
3055 ccomma
.append_expression (ccall
);
3056 ccomma
.append_expression (new
CCodeConstant ("NULL"));
3058 return new
CCodeConditionalExpression (cisvalid
, ccomma
, new
CCodeConstant ("NULL"));
3064 if (ccall
.call is CCodeIdentifier
&& !(type is ArrayType
) && !is_macro_definition
) {
3065 // generate and use NULL-aware free macro to simplify code
3067 var freeid
= (CCodeIdentifier
) ccall
.call
;
3068 string free0_func
= "_%s0".printf (freeid
.name
);
3070 if (add_wrapper (free0_func
)) {
3071 var macro
= destroy_value (new
GLibValue (type
, new
CCodeIdentifier ("var")), true);
3072 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("%s(var)".printf (free0_func
), macro
));
3075 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (free0_func
));
3076 ccall
.add_argument (cvar
);
3080 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
3082 /* can be simplified to
3083 * foo = (unref (foo), NULL)
3084 * if foo is of static type non-null
3087 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cvar
, new
CCodeConstant ("NULL"));
3088 if (type
.type_parameter
!= null) {
3089 if (!(current_type_symbol is Class
) || current_class
.is_compact
) {
3090 return new
CCodeConstant ("NULL");
3093 // unref functions are optional for type parameters
3094 var cunrefisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_destroy_func_expression (type
), new
CCodeConstant ("NULL"));
3095 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cunrefisnull
);
3098 ccall
.add_argument (cvar
);
3100 /* set freed references to NULL to prevent further use */
3101 var ccomma
= new
CCodeCommaExpression ();
3103 if (context
.profile
== Profile
.GOBJECT
) {
3104 if (type
.data_type
!= null && !type
.data_type
.is_reference_counting () &&
3105 (type
.data_type
== gstringbuilder_type
3106 || type
.data_type
== garray_type
3107 || type
.data_type
== gbytearray_type
3108 || type
.data_type
== gptrarray_type
)) {
3109 ccall
.add_argument (new
CCodeConstant ("TRUE"));
3110 } else if (type
.data_type
== gthreadpool_type
) {
3111 ccall
.add_argument (new
CCodeConstant ("FALSE"));
3112 ccall
.add_argument (new
CCodeConstant ("TRUE"));
3113 } else if (type is ArrayType
) {
3114 var array_type
= (ArrayType
) type
;
3115 if (requires_destroy (array_type
.element_type
)) {
3116 CCodeExpression csizeexpr
= null;
3118 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3120 csizeexpr
= get_array_length_cvalue (value
, dim
);
3123 csizeexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeexpr
, get_array_length_cvalue (value
, dim
));
3127 var st
= array_type
.element_type
.data_type as Struct
;
3128 if (st
!= null && !array_type
.element_type
.nullable
) {
3129 ccall
.call
= new
CCodeIdentifier (append_struct_array_free (st
));
3130 ccall
.add_argument (csizeexpr
);
3132 requires_array_free
= true;
3133 ccall
.call
= new
CCodeIdentifier ("_vala_array_free");
3134 ccall
.add_argument (csizeexpr
);
3135 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
3141 ccomma
.append_expression (ccall
);
3142 ccomma
.append_expression (new
CCodeConstant ("NULL"));
3144 var cassign
= new
CCodeAssignment (cvar
, ccomma
);
3146 // g_free (NULL) is allowed
3147 bool uses_gfree
= (type
.data_type
!= null && !type
.data_type
.is_reference_counting () && type
.data_type
.get_free_function () == "g_free");
3148 uses_gfree
= uses_gfree
|| type is ArrayType
;
3153 return new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), cassign
);
3156 public override void visit_end_full_expression (Expression expr
) {
3157 /* expr is a full expression, i.e. an initializer, the
3158 * expression in an expression statement, the controlling
3159 * expression in if, while, for, or foreach statements
3161 * we unref temporary variables at the end of a full
3164 if (temp_ref_vars
.size
== 0) {
3165 /* nothing to do without temporary variables */
3169 LocalVariable full_expr_var
= null;
3171 var local_decl
= expr
.parent_node as LocalVariable
;
3172 if (!(local_decl
!= null && has_simple_struct_initializer (local_decl
))) {
3173 var expr_type
= expr
.value_type
;
3174 if (expr
.target_type
!= null) {
3175 expr_type
= expr
.target_type
;
3178 full_expr_var
= get_temp_variable (expr_type
, true, expr
, false);
3179 emit_temp_var (full_expr_var
);
3181 ccode
.add_assignment (get_variable_cexpression (full_expr_var
.name
), get_cvalue (expr
));
3184 foreach (LocalVariable local
in temp_ref_vars
) {
3185 ccode
.add_expression (destroy_local (local
));
3188 if (full_expr_var
!= null) {
3189 set_cvalue (expr
, get_variable_cexpression (full_expr_var
.name
));
3192 temp_ref_vars
.clear ();
3195 public void emit_temp_var (LocalVariable local
, bool always_init
= false) {
3196 var vardecl
= new
CCodeVariableDeclarator (local
.name
, null, local
.variable_type
.get_cdeclarator_suffix ());
3198 var st
= local
.variable_type
.data_type as Struct
;
3199 var array_type
= local
.variable_type as ArrayType
;
3201 if (local
.name
.has_prefix ("*")) {
3202 // do not dereference unintialized variable
3203 // initialization is not needed for these special
3204 // pointer temp variables
3205 // used to avoid side-effects in assignments
3206 } else if (local
.no_init
) {
3207 // no initialization necessary for this temp var
3208 } else if (!local
.variable_type
.nullable
&&
3209 (st
!= null && !st
.is_simple_type ()) ||
3210 (array_type
!= null && array_type
.fixed_length
)) {
3211 // 0-initialize struct with struct initializer { 0 }
3212 // necessary as they will be passed by reference
3213 var clist
= new
CCodeInitializerList ();
3214 clist
.append (new
CCodeConstant ("0"));
3216 vardecl
.initializer
= clist
;
3217 vardecl
.init0
= true;
3218 } else if (local
.variable_type
.is_reference_type_or_type_parameter () ||
3219 local
.variable_type
.nullable
||
3220 local
.variable_type is DelegateType
) {
3221 vardecl
.initializer
= new
CCodeConstant ("NULL");
3222 vardecl
.init0
= true;
3223 } else if (always_init
) {
3224 vardecl
.initializer
= default_value_for_type (local
.variable_type
, true);
3225 vardecl
.init0
= true;
3228 if (is_in_coroutine ()) {
3229 closure_struct
.add_field (local
.variable_type
.get_cname (), local
.name
);
3231 // even though closure struct is zerod, we need to initialize temporary variables
3232 // as they might be used multiple times when declared in a loop
3234 if (vardecl
.initializer is CCodeInitializerList
) {
3235 // C does not support initializer lists in assignments, use memset instead
3236 cfile
.add_include ("string.h");
3237 var memset_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
3238 memset_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (local
.name
)));
3239 memset_call
.add_argument (new
CCodeConstant ("0"));
3240 memset_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (local
.variable_type
.get_cname ())));
3241 ccode
.add_expression (memset_call
);
3242 } else if (vardecl
.initializer
!= null) {
3243 ccode
.add_assignment (get_variable_cexpression (local
.name
), vardecl
.initializer
);
3246 ccode
.add_declaration (local
.variable_type
.get_cname (), vardecl
);
3250 public override void visit_expression_statement (ExpressionStatement stmt
) {
3251 if (stmt
.expression
.error
) {
3256 /* free temporary objects and handle errors */
3258 foreach (LocalVariable local
in temp_ref_vars
) {
3259 ccode
.add_expression (destroy_local (local
));
3262 if (stmt
.tree_can_fail
&& stmt
.expression
.tree_can_fail
) {
3263 // simple case, no node breakdown necessary
3264 add_simple_check (stmt
.expression
);
3267 temp_ref_vars
.clear ();
3270 public virtual void append_local_free (Symbol sym
, bool stop_at_loop
= false, CodeNode? stop_at
= null) {
3271 var b
= (Block
) sym
;
3273 var local_vars
= b
.get_local_variables ();
3274 // free in reverse order
3275 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
3276 var local
= local_vars
[i
];
3277 if (!local
.unreachable
&& local
.active
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
3278 ccode
.add_expression (destroy_local (local
));
3283 int block_id
= get_block_id (b
);
3285 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
3286 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
3287 ccode
.add_expression (data_unref
);
3288 ccode
.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id
)), new
CCodeConstant ("NULL"));
3292 if (b
.parent_node is Loop
||
3293 b
.parent_node is ForeachStatement
||
3294 b
.parent_node is SwitchStatement
) {
3299 if (b
.parent_node
== stop_at
) {
3303 if (sym
.parent_symbol is Block
) {
3304 append_local_free (sym
.parent_symbol
, stop_at_loop
, stop_at
);
3305 } else if (sym
.parent_symbol is Method
) {
3306 append_param_free ((Method
) sym
.parent_symbol
);
3310 private void append_param_free (Method m
) {
3311 foreach (Parameter param
in m
.get_parameters ()) {
3312 if (!param
.ellipsis
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
3313 ccode
.add_expression (destroy_parameter (param
));
3318 public bool variable_accessible_in_finally (LocalVariable local
) {
3319 if (current_try
== null) {
3323 var sym
= current_symbol
;
3325 while (!(sym is Method
|| sym is PropertyAccessor
) && sym
.scope
.lookup (local
.name
) == null) {
3326 if ((sym
.parent_node is TryStatement
&& ((TryStatement
) sym
.parent_node
).finally_body
!= null) ||
3327 (sym
.parent_node is CatchClause
&& ((TryStatement
) sym
.parent_node
.parent_node
).finally_body
!= null)) {
3332 sym
= sym
.parent_symbol
;
3338 void return_out_parameter (Parameter param
) {
3339 var delegate_type
= param
.variable_type as DelegateType
;
3341 ccode
.open_if (get_variable_cexpression (param
.name
));
3342 ccode
.add_assignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (param
.name
)), get_variable_cexpression ("_" + param
.name
));
3344 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
3345 ccode
.add_assignment (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
))));
3346 if (delegate_type
.value_owned
) {
3347 ccode
.add_assignment (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
))));
3351 if (param
.variable_type
.is_disposable ()){
3353 ccode
.add_expression (destroy_parameter (param
));
3357 var array_type
= param
.variable_type as ArrayType
;
3358 if (array_type
!= null && !array_type
.fixed_length
&& !param
.no_array_length
) {
3359 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3360 ccode
.open_if (get_variable_cexpression (get_parameter_array_length_cname (param
, dim
)));
3361 ccode
.add_assignment (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
)));
3367 public override void visit_return_statement (ReturnStatement stmt
) {
3368 Symbol return_expression_symbol
= null;
3370 if (stmt
.return_expression
!= null) {
3371 // avoid unnecessary ref/unref pair
3372 var local
= stmt
.return_expression
.symbol_reference as LocalVariable
;
3373 if (current_return_type
.value_owned
3374 && local
!= null && local
.variable_type
.value_owned
3376 && !variable_accessible_in_finally (local
)) {
3377 /* return expression is local variable taking ownership and
3378 * current method is transferring ownership */
3380 return_expression_symbol
= local
;
3384 // return array length if appropriate
3385 if (((current_method
!= null && !current_method
.no_array_length
) || current_property_accessor
!= null) && current_return_type is ArrayType
) {
3386 var return_expr_decl
= get_temp_variable (stmt
.return_expression
.value_type
, true, stmt
, false);
3388 ccode
.add_assignment (get_variable_cexpression (return_expr_decl
.name
), get_cvalue (stmt
.return_expression
));
3390 var array_type
= (ArrayType
) current_return_type
;
3392 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3393 var len_l
= get_result_cexpression (get_array_length_cname ("result", dim
));
3394 if (!is_in_coroutine ()) {
3395 len_l
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, len_l
);
3397 var len_r
= get_array_length_cexpression (stmt
.return_expression
, dim
);
3398 ccode
.add_assignment (len_l
, len_r
);
3401 set_cvalue (stmt
.return_expression
, get_variable_cexpression (return_expr_decl
.name
));
3403 emit_temp_var (return_expr_decl
);
3404 } else if ((current_method
!= null || current_property_accessor
!= null) && current_return_type is DelegateType
) {
3405 var delegate_type
= (DelegateType
) current_return_type
;
3406 if (delegate_type
.delegate_symbol
.has_target
) {
3407 var return_expr_decl
= get_temp_variable (stmt
.return_expression
.value_type
, true, stmt
, false);
3409 ccode
.add_assignment (get_variable_cexpression (return_expr_decl
.name
), get_cvalue (stmt
.return_expression
));
3411 var target_l
= get_result_cexpression (get_delegate_target_cname ("result"));
3412 if (!is_in_coroutine ()) {
3413 target_l
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_l
);
3415 CCodeExpression target_r_destroy_notify
;
3416 var target_r
= get_delegate_target_cexpression (stmt
.return_expression
, out target_r_destroy_notify
);
3417 ccode
.add_assignment (target_l
, target_r
);
3418 if (delegate_type
.value_owned
) {
3419 var target_l_destroy_notify
= get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3420 if (!is_in_coroutine ()) {
3421 target_l_destroy_notify
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_l_destroy_notify
);
3423 ccode
.add_assignment (target_l_destroy_notify
, target_r_destroy_notify
);
3426 set_cvalue (stmt
.return_expression
, get_variable_cexpression (return_expr_decl
.name
));
3428 emit_temp_var (return_expr_decl
);
3432 if (stmt
.return_expression
!= null) {
3433 // assign method result to `result'
3434 CCodeExpression result_lhs
= get_result_cexpression ();
3435 if (current_return_type
.is_real_non_null_struct_type () && !is_in_coroutine ()) {
3436 result_lhs
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, result_lhs
);
3438 ccode
.add_assignment (result_lhs
, get_cvalue (stmt
.return_expression
));
3441 // free local variables
3442 append_local_free (current_symbol
);
3444 if (current_method
!= null) {
3445 // check postconditions
3446 foreach (Expression postcondition
in current_method
.get_postconditions ()) {
3447 create_postcondition_statement (postcondition
);
3451 if (current_method
!= null && !current_method
.coroutine
) {
3452 // assign values to output parameters if they are not NULL
3453 // otherwise, free the value if necessary
3454 foreach (var param
in current_method
.get_parameters ()) {
3455 if (param
.direction
!= ParameterDirection
.OUT
) {
3459 return_out_parameter (param
);
3463 if (is_in_constructor ()) {
3464 ccode
.add_return (new
CCodeIdentifier ("obj"));
3465 } else if (is_in_destructor ()) {
3466 // do not call return as member cleanup and chain up to base finalizer
3467 // stil need to be executed
3468 ccode
.add_goto ("_return");
3469 } else if (current_method is CreationMethod
) {
3470 ccode
.add_return (new
CCodeIdentifier ("self"));
3471 } else if (is_in_coroutine ()) {
3472 } else if (current_return_type is VoidType
|| current_return_type
.is_real_non_null_struct_type ()) {
3473 // structs are returned via out parameter
3474 ccode
.add_return ();
3476 ccode
.add_return (new
CCodeIdentifier ("result"));
3479 if (return_expression_symbol
!= null) {
3480 return_expression_symbol
.active
= true;
3483 // required for destructors
3484 current_method_return
= true;
3487 public string get_symbol_lock_name (string symname
) {
3488 return "__lock_%s".printf (symname
);
3491 private CCodeExpression
get_lock_expression (Statement stmt
, Expression resource
) {
3492 CCodeExpression l
= null;
3493 var inner_node
= ((MemberAccess
)resource
).inner
;
3494 var member
= resource
.symbol_reference
;
3495 var parent
= (TypeSymbol
)resource
.symbol_reference
.parent_symbol
;
3497 if (member
.is_instance_member ()) {
3498 if (inner_node
== null) {
3499 l
= new
CCodeIdentifier ("self");
3500 } else if (resource
.symbol_reference
.parent_symbol
!= current_type_symbol
) {
3501 l
= generate_instance_cast (get_cvalue (inner_node
), parent
);
3503 l
= get_cvalue (inner_node
);
3506 l
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (l
, "priv"), get_symbol_lock_name (resource
.symbol_reference
.name
));
3507 } else if (member
.is_class_member ()) {
3508 CCodeExpression klass
;
3510 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
||
3511 current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
||
3512 (in_constructor
&& !in_static_or_class_context
)) {
3513 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3514 k
.add_argument (new
CCodeIdentifier ("self"));
3517 klass
= new
CCodeIdentifier ("klass");
3520 var get_class_private_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent
.get_upper_case_cname ())));
3521 get_class_private_call
.add_argument (klass
);
3522 l
= new CCodeMemberAccess
.pointer (get_class_private_call
, get_symbol_lock_name (resource
.symbol_reference
.name
));
3524 string lock_name
= "%s_%s".printf(parent
.get_lower_case_cname (), resource
.symbol_reference
.name
);
3525 l
= new
CCodeIdentifier (get_symbol_lock_name (lock_name
));
3530 public override void visit_lock_statement (LockStatement stmt
) {
3531 var l
= get_lock_expression (stmt
, stmt
.resource
);
3533 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier (((Method
) mutex_type
.scope
.lookup ("lock")).get_cname ()));
3534 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
3536 ccode
.add_expression (fc
);
3539 public override void visit_unlock_statement (UnlockStatement stmt
) {
3540 var l
= get_lock_expression (stmt
, stmt
.resource
);
3542 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier (((Method
) mutex_type
.scope
.lookup ("unlock")).get_cname ()));
3543 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
3545 ccode
.add_expression (fc
);
3548 public override void visit_delete_statement (DeleteStatement stmt
) {
3549 var pointer_type
= (PointerType
) stmt
.expression
.value_type
;
3550 DataType type
= pointer_type
;
3551 if (pointer_type
.base_type
.data_type
!= null && pointer_type
.base_type
.data_type
.is_reference_type ()) {
3552 type
= pointer_type
.base_type
;
3555 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
3556 ccall
.add_argument (get_cvalue (stmt
.expression
));
3557 ccode
.add_expression (ccall
);
3560 public override void visit_expression (Expression expr
) {
3561 if (get_cvalue (expr
) != null && !expr
.lvalue
) {
3562 if (expr
.formal_value_type is GenericType
&& !(expr
.value_type is GenericType
)) {
3563 var st
= expr
.formal_value_type
.type_parameter
.parent_symbol
.parent_symbol as Struct
;
3564 if (expr
.formal_value_type
.type_parameter
.parent_symbol
!= garray_type
&&
3565 (st
== null || st
.get_cname () != "va_list")) {
3566 // GArray and va_list don't use pointer-based generics
3567 set_cvalue (expr
, convert_from_generic_pointer (get_cvalue (expr
), expr
.value_type
));
3571 // memory management, implicit casts, and boxing/unboxing
3572 set_cvalue (expr
, transform_expression (get_cvalue (expr
), expr
.value_type
, expr
.target_type
, expr
));
3574 if (expr
.formal_target_type is GenericType
&& !(expr
.target_type is GenericType
)) {
3575 if (expr
.formal_target_type
.type_parameter
.parent_symbol
!= garray_type
) {
3576 // GArray doesn't use pointer-based generics
3577 set_cvalue (expr
, convert_to_generic_pointer (get_cvalue (expr
), expr
.target_type
));
3583 public override void visit_boolean_literal (BooleanLiteral expr
) {
3584 if (context
.profile
== Profile
.GOBJECT
) {
3585 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"TRUE" : "FALSE"));
3587 cfile
.add_include ("stdbool.h");
3588 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"true" : "false"));
3592 public override void visit_character_literal (CharacterLiteral expr
) {
3593 if (expr
.get_char () >= 0x20 && expr
.get_char () < 0x80) {
3594 set_cvalue (expr
, new
CCodeConstant (expr
.value
));
3596 set_cvalue (expr
, new
CCodeConstant ("%uU".printf (expr
.get_char ())));
3600 public override void visit_integer_literal (IntegerLiteral expr
) {
3601 set_cvalue (expr
, new
CCodeConstant (expr
.value
+ expr
.type_suffix
));
3604 public override void visit_real_literal (RealLiteral expr
) {
3605 string c_literal
= expr
.value
;
3606 if (c_literal
.has_suffix ("d") || c_literal
.has_suffix ("D")) {
3607 // there is no suffix for double in C
3608 c_literal
= c_literal
.substring (0, c_literal
.length
- 1);
3610 if (!("." in c_literal
|| "e" in c_literal
|| "E" in c_literal
)) {
3611 // C requires period or exponent part for floating constants
3612 if ("f" in c_literal
|| "F" in c_literal
) {
3613 c_literal
= c_literal
.substring (0, c_literal
.length
- 1) + ".f";
3618 set_cvalue (expr
, new
CCodeConstant (c_literal
));
3621 public override void visit_string_literal (StringLiteral expr
) {
3622 set_cvalue (expr
, new CCodeConstant
.string (expr
.value
.replace ("\n", "\\n")));
3624 if (expr
.translate
) {
3625 // translated string constant
3627 var m
= (Method
) root_symbol
.scope
.lookup ("GLib").scope
.lookup ("_");
3628 add_symbol_declaration (cfile
, m
, m
.get_cname ());
3630 var translate
= new
CCodeFunctionCall (new
CCodeIdentifier ("_"));
3631 translate
.add_argument (get_cvalue (expr
));
3632 set_cvalue (expr
, translate
);
3636 public override void visit_regex_literal (RegexLiteral expr
) {
3637 string[] parts
= expr
.value
.split ("/", 3);
3638 string re
= parts
[2].escape ("");
3641 if (parts
[1].contains ("i")) {
3642 flags
+= " | G_REGEX_CASELESS";
3644 if (parts
[1].contains ("m")) {
3645 flags
+= " | G_REGEX_MULTILINE";
3647 if (parts
[1].contains ("s")) {
3648 flags
+= " | G_REGEX_DOTALL";
3650 if (parts
[1].contains ("x")) {
3651 flags
+= " | G_REGEX_EXTENDED";
3654 var regex_var
= get_temp_variable (regex_type
, true, expr
, false);
3655 emit_temp_var (regex_var
);
3657 var cdecl
= new
CCodeDeclaration ("GRegex*");
3659 var cname
= regex_var
.name
+ "regex_" + next_regex_id
.to_string ();
3660 if (this
.next_regex_id
== 0) {
3661 var fun
= new
CCodeFunction ("_thread_safe_regex_init", "GRegex*");
3662 fun
.modifiers
= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
3663 fun
.add_parameter (new
CCodeParameter ("re", "GRegex**"));
3664 fun
.add_parameter (new
CCodeParameter ("pattern", "const gchar *"));
3665 fun
.add_parameter (new
CCodeParameter ("match_options", "GRegexMatchFlags"));
3667 push_function (fun
);
3669 var once_enter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_once_init_enter"));
3670 once_enter_call
.add_argument (new
CCodeConstant ("(volatile gsize*) re"));
3671 ccode
.open_if (once_enter_call
);
3673 var regex_new_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_regex_new"));
3674 regex_new_call
.add_argument (new
CCodeConstant ("pattern"));
3675 regex_new_call
.add_argument (new
CCodeConstant ("match_options"));
3676 regex_new_call
.add_argument (new
CCodeConstant ("0"));
3677 regex_new_call
.add_argument (new
CCodeConstant ("NULL"));
3678 ccode
.add_assignment (new
CCodeIdentifier ("GRegex* val"), regex_new_call
);
3680 var once_leave_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_once_init_leave"));
3681 once_leave_call
.add_argument (new
CCodeConstant ("(volatile gsize*) re"));
3682 once_leave_call
.add_argument (new
CCodeConstant ("(gsize) val"));
3683 ccode
.add_expression (once_leave_call
);
3687 ccode
.add_return (new
CCodeIdentifier ("*re"));
3691 cfile
.add_function (fun
);
3693 this
.next_regex_id
++;
3695 cdecl
.add_declarator (new
CCodeVariableDeclarator (cname
+ " = NULL"));
3696 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
3698 var regex_const
= new
CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname
, re
, flags
));
3700 cfile
.add_constant_declaration (cdecl
);
3701 set_cvalue (expr
, regex_const
);
3704 public override void visit_null_literal (NullLiteral expr
) {
3705 if (context
.profile
!= Profile
.GOBJECT
) {
3706 cfile
.add_include ("stddef.h");
3708 set_cvalue (expr
, new
CCodeConstant ("NULL"));
3710 var array_type
= expr
.target_type as ArrayType
;
3711 var delegate_type
= expr
.target_type as DelegateType
;
3712 if (array_type
!= null) {
3713 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3714 append_array_length (expr
, new
CCodeConstant ("0"));
3716 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
3717 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
3718 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
3722 public abstract TargetValue
get_local_cvalue (LocalVariable local
);
3724 public abstract TargetValue
get_parameter_cvalue (Parameter param
);
3726 public abstract TargetValue
get_field_cvalue (Field field
, Expression? instance
);
3728 public virtual string get_delegate_target_cname (string delegate_cname
) {
3729 assert_not_reached ();
3732 public virtual CCodeExpression
get_delegate_target_cexpression (Expression delegate_expr
, out CCodeExpression delegate_target_destroy_notify
) {
3733 assert_not_reached ();
3736 public virtual CCodeExpression
get_delegate_target_cvalue (TargetValue value
) {
3737 return new
CCodeInvalidExpression ();
3740 public virtual CCodeExpression
get_delegate_target_destroy_notify_cvalue (TargetValue value
) {
3741 return new
CCodeInvalidExpression ();
3744 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname
) {
3745 assert_not_reached ();
3748 public override void visit_base_access (BaseAccess expr
) {
3749 CCodeExpression this_access
;
3750 if (is_in_coroutine ()) {
3752 this_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "self");
3754 this_access
= new
CCodeIdentifier ("self");
3757 set_cvalue (expr
, generate_instance_cast (this_access
, expr
.value_type
.data_type
));
3760 public override void visit_postfix_expression (PostfixExpression expr
) {
3761 MemberAccess ma
= find_property_access (expr
.inner
);
3763 // property postfix expression
3764 var prop
= (Property
) ma
.symbol_reference
;
3766 // assign current value to temp variable
3767 var temp_decl
= get_temp_variable (prop
.property_type
, true, expr
, false);
3768 emit_temp_var (temp_decl
);
3769 ccode
.add_assignment (get_variable_cexpression (temp_decl
.name
), get_cvalue (expr
.inner
));
3771 // increment/decrement property
3772 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
3773 var cexpr
= new
CCodeBinaryExpression (op
, get_variable_cexpression (temp_decl
.name
), new
CCodeConstant ("1"));
3774 store_property (prop
, ma
.inner
, new
GLibValue (expr
.value_type
, cexpr
));
3776 // return previous value
3777 set_cvalue (expr
, get_variable_cexpression (temp_decl
.name
));
3781 if (expr
.parent_node is ExpressionStatement
) {
3782 var op
= expr
.increment ? CCodeUnaryOperator
.POSTFIX_INCREMENT
: CCodeUnaryOperator
.POSTFIX_DECREMENT
;
3784 ccode
.add_expression (new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
3786 // assign current value to temp variable
3787 var temp_decl
= get_temp_variable (expr
.inner
.value_type
, true, expr
, false);
3788 emit_temp_var (temp_decl
);
3789 ccode
.add_assignment (get_variable_cexpression (temp_decl
.name
), get_cvalue (expr
.inner
));
3791 // increment/decrement variable
3792 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
3793 var cexpr
= new
CCodeBinaryExpression (op
, get_variable_cexpression (temp_decl
.name
), new
CCodeConstant ("1"));
3794 ccode
.add_assignment (get_cvalue (expr
.inner
), cexpr
);
3796 // return previous value
3797 set_cvalue (expr
, get_variable_cexpression (temp_decl
.name
));
3801 private MemberAccess?
find_property_access (Expression expr
) {
3802 if (!(expr is MemberAccess
)) {
3806 var ma
= (MemberAccess
) expr
;
3807 if (ma
.symbol_reference is Property
) {
3814 bool is_limited_generic_type (DataType type
) {
3815 var cl
= type
.type_parameter
.parent_symbol as Class
;
3816 var st
= type
.type_parameter
.parent_symbol as Struct
;
3817 if ((cl
!= null && cl
.is_compact
) || st
!= null) {
3818 // compact classes and structs only
3819 // have very limited generics support
3825 public bool requires_copy (DataType type
) {
3826 if (!type
.is_disposable ()) {
3830 var cl
= type
.data_type as Class
;
3831 if (cl
!= null && cl
.is_reference_counting ()
3832 && cl
.get_ref_function () == "") {
3833 // empty ref_function => no ref necessary
3837 if (type
.type_parameter
!= null) {
3838 if (is_limited_generic_type (type
)) {
3846 public bool requires_destroy (DataType type
) {
3847 if (!type
.is_disposable ()) {
3851 var array_type
= type as ArrayType
;
3852 if (array_type
!= null && array_type
.fixed_length
) {
3853 return requires_destroy (array_type
.element_type
);
3856 var cl
= type
.data_type as Class
;
3857 if (cl
!= null && cl
.is_reference_counting ()
3858 && cl
.get_unref_function () == "") {
3859 // empty unref_function => no unref necessary
3863 if (type
.type_parameter
!= null) {
3864 if (is_limited_generic_type (type
)) {
3872 bool is_ref_function_void (DataType type
) {
3873 var cl
= type
.data_type as Class
;
3874 if (cl
!= null && cl
.ref_function_void
) {
3881 public virtual CCodeExpression?
get_ref_cexpression (DataType expression_type
, CCodeExpression cexpr
, Expression? expr
, CodeNode node
) {
3882 if (expression_type is DelegateType
) {
3886 if (expression_type is ValueType
&& !expression_type
.nullable
) {
3887 // normal value type, no null check
3888 // (copy (&expr, &temp), temp)
3890 var decl
= get_temp_variable (expression_type
, false, node
);
3891 emit_temp_var (decl
);
3893 var ctemp
= get_variable_cexpression (decl
.name
);
3895 var vt
= (ValueType
) expression_type
;
3896 var st
= (Struct
) vt
.type_symbol
;
3897 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_copy_function ()));
3898 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3899 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
3901 if (!st
.has_copy_function
) {
3902 generate_struct_copy_function (st
);
3905 var ccomma
= new
CCodeCommaExpression ();
3907 if (st
.get_copy_function () == "g_value_copy") {
3908 // GValue requires g_value_init in addition to g_value_copy
3910 var value_type_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VALUE_TYPE"));
3911 value_type_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3913 var init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
3914 init_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
3915 init_call
.add_argument (value_type_call
);
3917 ccomma
.append_expression (init_call
);
3920 ccomma
.append_expression (copy_call
);
3921 ccomma
.append_expression (ctemp
);
3923 if (gvalue_type
!= null && expression_type
.data_type
== gvalue_type
) {
3924 // g_value_init/copy must not be called for uninitialized values
3925 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
3926 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3928 return new
CCodeConditionalExpression (cisvalid
, ccomma
, cexpr
);
3934 /* (temp = expr, temp == NULL ? NULL : ref (temp))
3936 * can be simplified to
3938 * if static type of expr is non-null
3941 var dupexpr
= get_dup_func_expression (expression_type
, node
.source_reference
);
3943 if (dupexpr
== null) {
3948 if (dupexpr is CCodeIdentifier
&& !(expression_type is ArrayType
) && !(expression_type is GenericType
) && !is_ref_function_void (expression_type
)) {
3949 // generate and call NULL-aware ref function to reduce number
3950 // of temporary variables and simplify code
3952 var dupid
= (CCodeIdentifier
) dupexpr
;
3953 string dup0_func
= "_%s0".printf (dupid
.name
);
3955 // g_strdup is already NULL-safe
3956 if (dupid
.name
== "g_strdup") {
3957 dup0_func
= dupid
.name
;
3958 } else if (add_wrapper (dup0_func
)) {
3959 string pointer_cname
= "gpointer";
3960 if (context
.profile
== Profile
.POSIX
) {
3961 pointer_cname
= "void*";
3963 var dup0_fun
= new
CCodeFunction (dup0_func
, pointer_cname
);
3964 dup0_fun
.add_parameter (new
CCodeParameter ("self", pointer_cname
));
3965 dup0_fun
.modifiers
= CCodeModifiers
.STATIC
;
3967 push_function (dup0_fun
);
3969 var dup_call
= new
CCodeFunctionCall (dupexpr
);
3970 dup_call
.add_argument (new
CCodeIdentifier ("self"));
3972 ccode
.add_return (new
CCodeConditionalExpression (new
CCodeIdentifier ("self"), dup_call
, new
CCodeConstant ("NULL")));
3976 cfile
.add_function (dup0_fun
);
3979 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (dup0_func
));
3980 ccall
.add_argument (cexpr
);
3984 var ccall
= new
CCodeFunctionCall (dupexpr
);
3986 if (!(expression_type is ArrayType
) && expr
!= null && expr
.is_non_null ()
3987 && !is_ref_function_void (expression_type
)) {
3988 // expression is non-null
3989 ccall
.add_argument (get_cvalue (expr
));
3993 var decl
= get_temp_variable (expression_type
, false, node
, false);
3994 emit_temp_var (decl
);
3996 var ctemp
= get_variable_cexpression (decl
.name
);
3998 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, new
CCodeConstant ("NULL"));
3999 if (expression_type
.type_parameter
!= null) {
4000 // dup functions are optional for type parameters
4001 var cdupisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_dup_func_expression (expression_type
, node
.source_reference
), new
CCodeConstant ("NULL"));
4002 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cdupisnull
);
4005 if (expression_type
.type_parameter
!= null) {
4006 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
4007 ccall
.add_argument (new
CCodeCastExpression (ctemp
, "gpointer"));
4009 ccall
.add_argument (ctemp
);
4012 if (expression_type is ArrayType
) {
4013 var array_type
= (ArrayType
) expression_type
;
4015 CCodeExpression csizeexpr
= null;
4016 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4018 csizeexpr
= get_array_length_cexpression (expr
, dim
);
4021 csizeexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeexpr
, get_array_length_cexpression (expr
, dim
));
4025 ccall
.add_argument (csizeexpr
);
4027 if (array_type
.element_type is GenericType
) {
4028 var elem_dupexpr
= get_dup_func_expression (array_type
.element_type
, node
.source_reference
);
4029 if (elem_dupexpr
== null) {
4030 elem_dupexpr
= new
CCodeConstant ("NULL");
4032 ccall
.add_argument (elem_dupexpr
);
4036 var ccomma
= new
CCodeCommaExpression ();
4037 ccomma
.append_expression (new
CCodeAssignment (ctemp
, cexpr
));
4039 CCodeExpression cifnull
;
4040 if (expression_type
.data_type
!= null) {
4041 cifnull
= new
CCodeConstant ("NULL");
4043 // the value might be non-null even when the dup function is null,
4044 // so we may not just use NULL for type parameters
4046 // cast from gconstpointer to gpointer as methods in
4047 // generic classes may not return gconstpointer
4048 cifnull
= new
CCodeCastExpression (ctemp
, "gpointer");
4050 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, cifnull
, ccall
));
4052 // repeat temp variable at the end of the comma expression
4053 // if the ref function returns void
4054 if (is_ref_function_void (expression_type
)) {
4055 ccomma
.append_expression (ctemp
);
4062 bool is_reference_type_argument (DataType type_arg
) {
4063 if (type_arg is ErrorType
|| (type_arg
.data_type
!= null && type_arg
.data_type
.is_reference_type ())) {
4070 bool is_nullable_value_type_argument (DataType type_arg
) {
4071 if (type_arg is ValueType
&& type_arg
.nullable
) {
4078 bool is_signed_integer_type_argument (DataType type_arg
) {
4079 var st
= type_arg
.data_type as Struct
;
4080 if (type_arg
.nullable
) {
4082 } else if (st
== bool_type
.data_type
) {
4084 } else if (st
== char_type
.data_type
) {
4086 } else if (unichar_type
!= null && st
== unichar_type
.data_type
) {
4088 } else if (st
== short_type
.data_type
) {
4090 } else if (st
== int_type
.data_type
) {
4092 } else if (st
== long_type
.data_type
) {
4094 } else if (st
== int8_type
.data_type
) {
4096 } else if (st
== int16_type
.data_type
) {
4098 } else if (st
== int32_type
.data_type
) {
4100 } else if (st
== gtype_type
) {
4102 } else if (type_arg is EnumValueType
) {
4109 bool is_unsigned_integer_type_argument (DataType type_arg
) {
4110 var st
= type_arg
.data_type as Struct
;
4111 if (type_arg
.nullable
) {
4113 } else if (st
== uchar_type
.data_type
) {
4115 } else if (st
== ushort_type
.data_type
) {
4117 } else if (st
== uint_type
.data_type
) {
4119 } else if (st
== ulong_type
.data_type
) {
4121 } else if (st
== uint8_type
.data_type
) {
4123 } else if (st
== uint16_type
.data_type
) {
4125 } else if (st
== uint32_type
.data_type
) {
4132 public void check_type (DataType type
) {
4133 var array_type
= type as ArrayType
;
4134 if (array_type
!= null) {
4135 check_type (array_type
.element_type
);
4136 if (array_type
.element_type is ArrayType
) {
4137 Report
.error (type
.source_reference
, "Stacked arrays are not supported");
4138 } else if (array_type
.element_type is DelegateType
) {
4139 var delegate_type
= (DelegateType
) array_type
.element_type
;
4140 if (delegate_type
.delegate_symbol
.has_target
) {
4141 Report
.error (type
.source_reference
, "Delegates with target are not supported as array element type");
4145 foreach (var type_arg
in type
.get_type_arguments ()) {
4146 check_type (type_arg
);
4147 check_type_argument (type_arg
);
4151 void check_type_argument (DataType type_arg
) {
4152 if (type_arg is GenericType
4153 || type_arg is PointerType
4154 || is_reference_type_argument (type_arg
)
4155 || is_nullable_value_type_argument (type_arg
)
4156 || is_signed_integer_type_argument (type_arg
)
4157 || is_unsigned_integer_type_argument (type_arg
)) {
4159 } else if (type_arg is DelegateType
) {
4160 var delegate_type
= (DelegateType
) type_arg
;
4161 if (delegate_type
.delegate_symbol
.has_target
) {
4162 Report
.error (type_arg
.source_reference
, "Delegates with target are not supported as generic type arguments");
4165 Report
.error (type_arg
.source_reference
, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg
.to_string ()));
4169 public virtual void generate_class_declaration (Class cl
, CCodeFile decl_space
) {
4170 if (add_symbol_declaration (decl_space
, cl
, cl
.get_cname ())) {
4175 public virtual void generate_interface_declaration (Interface iface
, CCodeFile decl_space
) {
4178 public virtual void generate_method_declaration (Method m
, CCodeFile decl_space
) {
4181 public virtual void generate_error_domain_declaration (ErrorDomain edomain
, CCodeFile decl_space
) {
4184 public void add_generic_type_arguments (Map
<int,CCodeExpression
> arg_map
, List
<DataType
> type_args
, CodeNode expr
, bool is_chainup
= false) {
4185 int type_param_index
= 0;
4186 foreach (var type_arg
in type_args
) {
4187 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), get_type_id_expression (type_arg
, is_chainup
));
4188 if (requires_copy (type_arg
)) {
4189 var dup_func
= get_dup_func_expression (type_arg
, type_arg
.source_reference
, is_chainup
);
4190 if (dup_func
== null) {
4191 // type doesn't contain a copy function
4195 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeCastExpression (dup_func
, "GBoxedCopyFunc"));
4196 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), get_destroy_func_expression (type_arg
, is_chainup
));
4198 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeConstant ("NULL"));
4199 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeConstant ("NULL"));
4205 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
4206 CCodeExpression instance
= null;
4207 CCodeExpression creation_expr
= null;
4209 check_type (expr
.type_reference
);
4211 var st
= expr
.type_reference
.data_type as Struct
;
4212 if ((st
!= null && (!st
.is_simple_type () || st
.get_cname () == "va_list")) || expr
.get_object_initializer ().size
> 0) {
4213 // value-type initialization or object creation expression with object initializer
4215 var local
= expr
.parent_node as LocalVariable
;
4216 if (local
!= null && has_simple_struct_initializer (local
)) {
4217 if (local
.captured
) {
4218 var block
= (Block
) local
.parent_symbol
;
4219 instance
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_variable_cname (local
.name
));
4221 instance
= get_variable_cexpression (get_variable_cname (local
.name
));
4224 var temp_decl
= get_temp_variable (expr
.type_reference
, false, expr
);
4225 emit_temp_var (temp_decl
);
4227 instance
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
4231 if (expr
.symbol_reference
== null) {
4232 // no creation method
4233 if (expr
.type_reference
.data_type is Struct
) {
4234 // memset needs string.h
4235 cfile
.add_include ("string.h");
4236 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
4237 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4238 creation_call
.add_argument (new
CCodeConstant ("0"));
4239 creation_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (expr
.type_reference
.get_cname ())));
4241 creation_expr
= creation_call
;
4243 } else if (expr
.type_reference
.data_type
== glist_type
||
4244 expr
.type_reference
.data_type
== gslist_type
) {
4245 // NULL is an empty list
4246 set_cvalue (expr
, new
CCodeConstant ("NULL"));
4247 } else if (expr
.symbol_reference is Method
) {
4248 // use creation method
4249 var m
= (Method
) expr
.symbol_reference
;
4250 var params
= m
.get_parameters ();
4251 CCodeFunctionCall creation_call
;
4253 generate_method_declaration (m
, cfile
);
4255 var cl
= expr
.type_reference
.data_type as Class
;
4257 if (!m
.has_new_function
) {
4258 // use construct function directly
4259 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
4260 creation_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
4262 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_cname ()));
4265 if ((st
!= null && !st
.is_simple_type ()) && !(m
.cinstance_parameter_position
< 0)) {
4266 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4267 } else if (st
!= null && st
.get_cname () == "va_list") {
4268 creation_call
.add_argument (instance
);
4269 if (m
.get_cname () == "va_start") {
4270 Parameter last_param
= null;
4271 foreach (var param
in current_method
.get_parameters ()) {
4272 if (param
.ellipsis
) {
4277 creation_call
.add_argument (new
CCodeIdentifier (get_variable_cname (last_param
.name
)));
4281 generate_type_declaration (expr
.type_reference
, cfile
);
4283 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
4285 if (cl
!= null && !cl
.is_compact
) {
4286 add_generic_type_arguments (carg_map
, expr
.type_reference
.get_type_arguments (), expr
);
4287 } else if (cl
!= null && m
.simple_generics
) {
4288 int type_param_index
= 0;
4289 foreach (var type_arg
in expr
.type_reference
.get_type_arguments ()) {
4290 if (requires_copy (type_arg
)) {
4291 carg_map
.set (get_param_pos (-1 + 0.1 * type_param_index
+ 0.03), get_destroy0_func_expression (type_arg
));
4293 carg_map
.set (get_param_pos (-1 + 0.1 * type_param_index
+ 0.03), new
CCodeConstant ("NULL"));
4299 bool ellipsis
= false;
4303 Iterator
<Parameter
> params_it
= params
.iterator ();
4304 foreach (Expression arg
in expr
.get_argument_list ()) {
4305 CCodeExpression cexpr
= get_cvalue (arg
);
4306 Parameter param
= null;
4307 if (params_it
.next ()) {
4308 param
= params_it
.get ();
4309 ellipsis
= param
.ellipsis
;
4311 if (!param
.no_array_length
&& param
.variable_type is ArrayType
) {
4312 var array_type
= (ArrayType
) param
.variable_type
;
4313 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4314 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), get_array_length_cexpression (arg
, dim
));
4316 } else if (param
.variable_type is DelegateType
) {
4317 var deleg_type
= (DelegateType
) param
.variable_type
;
4318 var d
= deleg_type
.delegate_symbol
;
4320 CCodeExpression delegate_target_destroy_notify
;
4321 var delegate_target
= get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
);
4322 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), delegate_target
);
4323 if (deleg_type
.value_owned
) {
4324 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
+ 0.01), delegate_target_destroy_notify
);
4329 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
4331 if (param
.ctype
!= null) {
4332 cexpr
= new
CCodeCastExpression (cexpr
, param
.ctype
);
4335 cexpr
= handle_struct_argument (null, arg
, cexpr
);
4338 arg_pos
= get_param_pos (param
.cparameter_position
, ellipsis
);
4340 // default argument position
4341 cexpr
= handle_struct_argument (null, arg
, cexpr
);
4342 arg_pos
= get_param_pos (i
, ellipsis
);
4345 carg_map
.set (arg_pos
, cexpr
);
4349 while (params_it
.next ()) {
4350 var param
= params_it
.get ();
4352 if (param
.ellipsis
) {
4357 if (param
.initializer
== null) {
4358 Report
.error (expr
.source_reference
, "no default expression for argument %d".printf (i
));
4362 /* evaluate default expression here as the code
4363 * generator might not have visited the formal
4365 param
.initializer
.emit (this
);
4367 carg_map
.set (get_param_pos (param
.cparameter_position
), get_cvalue (param
.initializer
));
4371 // append C arguments in the right order
4376 foreach (int pos
in carg_map
.get_keys ()) {
4377 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
4381 if (min_pos
== -1) {
4384 creation_call
.add_argument (carg_map
.get (min_pos
));
4388 if ((st
!= null && !st
.is_simple_type ()) && m
.cinstance_parameter_position
< 0) {
4389 // instance parameter is at the end in a struct creation method
4390 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4393 if (expr
.tree_can_fail
) {
4395 current_method_inner_error
= true;
4396 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression ("_inner_error_")));
4400 /* ensure variable argument list ends with NULL
4401 * except when using printf-style arguments */
4402 if (!m
.printf_format
&& !m
.scanf_format
&& m
.sentinel
!= "") {
4403 creation_call
.add_argument (new
CCodeConstant (m
.sentinel
));
4407 creation_expr
= creation_call
;
4409 // cast the return value of the creation method back to the intended type if
4410 // it requested a special C return type
4411 if (get_custom_creturn_type (m
) != null) {
4412 creation_expr
= new
CCodeCastExpression (creation_expr
, expr
.type_reference
.get_cname ());
4414 } else if (expr
.symbol_reference is ErrorCode
) {
4415 var ecode
= (ErrorCode
) expr
.symbol_reference
;
4416 var edomain
= (ErrorDomain
) ecode
.parent_symbol
;
4417 CCodeFunctionCall creation_call
;
4419 generate_error_domain_declaration (edomain
, cfile
);
4421 if (expr
.get_argument_list ().size
== 1) {
4422 // must not be a format argument
4423 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_new_literal"));
4425 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_new"));
4427 creation_call
.add_argument (new
CCodeIdentifier (edomain
.get_upper_case_cname ()));
4428 creation_call
.add_argument (new
CCodeIdentifier (ecode
.get_cname ()));
4430 foreach (Expression arg
in expr
.get_argument_list ()) {
4431 creation_call
.add_argument (get_cvalue (arg
));
4434 creation_expr
= creation_call
;
4439 var local
= expr
.parent_node as LocalVariable
;
4440 if (local
!= null && has_simple_struct_initializer (local
)) {
4441 // no temporary variable necessary
4442 ccode
.add_expression (creation_expr
);
4443 set_cvalue (expr
, instance
);
4445 } else if (instance
!= null) {
4446 if (expr
.type_reference
.data_type is Struct
) {
4447 ccode
.add_expression (creation_expr
);
4449 ccode
.add_assignment (instance
, creation_expr
);
4452 foreach (MemberInitializer init
in expr
.get_object_initializer ()) {
4453 if (init
.symbol_reference is Field
) {
4454 var f
= (Field
) init
.symbol_reference
;
4455 var instance_target_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
4456 var typed_inst
= transform_expression (instance
, expr
.type_reference
, instance_target_type
);
4457 CCodeExpression lhs
;
4458 if (expr
.type_reference
.data_type is Struct
) {
4459 lhs
= new
CCodeMemberAccess (typed_inst
, f
.get_cname ());
4461 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, f
.get_cname ());
4463 ccode
.add_assignment (lhs
, get_cvalue (init
.initializer
));
4465 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
4466 var array_type
= (ArrayType
) f
.variable_type
;
4467 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4468 if (expr
.type_reference
.data_type is Struct
) {
4469 lhs
= new
CCodeMemberAccess (typed_inst
, get_array_length_cname (f
.get_cname (), dim
));
4471 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, get_array_length_cname (f
.get_cname (), dim
));
4473 var rhs_array_len
= get_array_length_cexpression (init
.initializer
, dim
);
4474 ccode
.add_assignment (lhs
, rhs_array_len
);
4476 } else if (f
.variable_type is DelegateType
&& (f
.variable_type as DelegateType
).delegate_symbol
.has_target
&& !f
.no_delegate_target
) {
4477 if (expr
.type_reference
.data_type is Struct
) {
4478 lhs
= new
CCodeMemberAccess (typed_inst
, get_delegate_target_cname (f
.get_cname ()));
4480 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, get_delegate_target_cname (f
.get_cname ()));
4482 CCodeExpression rhs_delegate_target_destroy_notify
;
4483 var rhs_delegate_target
= get_delegate_target_cexpression (init
.initializer
, out rhs_delegate_target_destroy_notify
);
4484 ccode
.add_assignment (lhs
, rhs_delegate_target
);
4487 var cl
= f
.parent_symbol as Class
;
4489 generate_class_struct_declaration (cl
, cfile
);
4491 } else if (init
.symbol_reference is Property
) {
4492 var inst_ma
= new MemberAccess
.simple ("new");
4493 inst_ma
.value_type
= expr
.type_reference
;
4494 set_cvalue (inst_ma
, instance
);
4495 store_property ((Property
) init
.symbol_reference
, inst_ma
, init
.initializer
.target_value
);
4499 creation_expr
= instance
;
4502 if (creation_expr
!= null) {
4503 var temp_var
= get_temp_variable (expr
.value_type
);
4504 var temp_ref
= get_variable_cexpression (temp_var
.name
);
4506 emit_temp_var (temp_var
);
4508 ccode
.add_assignment (temp_ref
, creation_expr
);
4509 set_cvalue (expr
, temp_ref
);
4513 public CCodeExpression?
handle_struct_argument (Parameter? param
, Expression arg
, CCodeExpression? cexpr
) {
4515 if (param
!= null) {
4516 type
= param
.variable_type
;
4519 type
= arg
.value_type
;
4522 // pass non-simple struct instances always by reference
4523 if (!(arg
.value_type is NullType
) && type
.is_real_struct_type ()) {
4524 // we already use a reference for arguments of ref, out, and nullable parameters
4525 if ((param
== null || param
.direction
== ParameterDirection
.IN
) && !type
.nullable
) {
4526 var unary
= cexpr as CCodeUnaryExpression
;
4527 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
4530 } else if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
4531 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
4533 // if cexpr is e.g. a function call, we can't take the address of the expression
4534 // (tmp = expr, &tmp)
4535 var ccomma
= new
CCodeCommaExpression ();
4537 var temp_var
= get_temp_variable (type
, true, null, false);
4538 emit_temp_var (temp_var
);
4539 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), cexpr
));
4540 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
)));
4550 public override void visit_sizeof_expression (SizeofExpression expr
) {
4551 generate_type_declaration (expr
.type_reference
, cfile
);
4553 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
4554 csizeof
.add_argument (new
CCodeIdentifier (expr
.type_reference
.get_cname ()));
4555 set_cvalue (expr
, csizeof
);
4558 public override void visit_typeof_expression (TypeofExpression expr
) {
4559 set_cvalue (expr
, get_type_id_expression (expr
.type_reference
));
4562 public override void visit_unary_expression (UnaryExpression expr
) {
4563 if (expr
.operator
== UnaryOperator
.REF
|| expr
.operator
== UnaryOperator
.OUT
) {
4564 var glib_value
= (GLibValue
) expr
.inner
.target_value
;
4566 var ref_value
= new
GLibValue (glib_value
.value_type
);
4567 ref_value
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.cvalue
);
4569 if (glib_value
.array_length_cvalues
!= null) {
4570 for (int i
= 0; i
< glib_value
.array_length_cvalues
.size
; i
++) {
4571 ref_value
.append_array_length_cvalue (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.array_length_cvalues
[i
]));
4575 if (glib_value
.delegate_target_cvalue
!= null) {
4576 ref_value
.delegate_target_cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.delegate_target_cvalue
);
4578 if (glib_value
.delegate_target_destroy_notify_cvalue
!= null) {
4579 ref_value
.delegate_target_destroy_notify_cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.delegate_target_destroy_notify_cvalue
);
4582 expr
.target_value
= ref_value
;
4586 CCodeUnaryOperator op
;
4587 if (expr
.operator
== UnaryOperator
.PLUS
) {
4588 op
= CCodeUnaryOperator
.PLUS
;
4589 } else if (expr
.operator
== UnaryOperator
.MINUS
) {
4590 op
= CCodeUnaryOperator
.MINUS
;
4591 } else if (expr
.operator
== UnaryOperator
.LOGICAL_NEGATION
) {
4592 op
= CCodeUnaryOperator
.LOGICAL_NEGATION
;
4593 } else if (expr
.operator
== UnaryOperator
.BITWISE_COMPLEMENT
) {
4594 op
= CCodeUnaryOperator
.BITWISE_COMPLEMENT
;
4595 } else if (expr
.operator
== UnaryOperator
.INCREMENT
) {
4596 op
= CCodeUnaryOperator
.PREFIX_INCREMENT
;
4597 } else if (expr
.operator
== UnaryOperator
.DECREMENT
) {
4598 op
= CCodeUnaryOperator
.PREFIX_DECREMENT
;
4600 assert_not_reached ();
4602 set_cvalue (expr
, new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
4605 public CCodeExpression?
try_cast_value_to_type (CCodeExpression ccodeexpr
, DataType from
, DataType to
, Expression? expr
= null) {
4606 if (from
== null || gvalue_type
== null || from
.data_type
!= gvalue_type
|| to
.get_type_id () == null) {
4610 // explicit conversion from GValue
4611 var ccall
= new
CCodeFunctionCall (get_value_getter_function (to
));
4612 CCodeExpression gvalue
;
4613 if (from
.nullable
) {
4616 gvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ccodeexpr
);
4618 ccall
.add_argument (gvalue
);
4620 CCodeExpression rv
= ccall
;
4622 if (expr
!= null && to is ArrayType
) {
4623 // null-terminated string array
4624 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strv_length"));
4625 len_call
.add_argument (rv
);
4626 append_array_length (expr
, len_call
);
4627 } else if (to is StructValueType
) {
4628 var temp_decl
= get_temp_variable (to
, true, null, true);
4629 emit_temp_var (temp_decl
);
4630 var ctemp
= get_variable_cexpression (temp_decl
.name
);
4632 rv
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeCastExpression (rv
, (new
PointerType(to
)).get_cname ()));
4633 var holds
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VALUE_HOLDS"));
4634 holds
.add_argument (gvalue
);
4635 holds
.add_argument (new
CCodeIdentifier (to
.get_type_id ()));
4636 var cond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, holds
, ccall
);
4637 var warn
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_warning"));
4638 warn
.add_argument (new
CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
4639 var fail
= new
CCodeCommaExpression ();
4640 fail
.append_expression (warn
);
4641 fail
.append_expression (ctemp
);
4642 rv
= new
CCodeConditionalExpression (cond
, rv
, fail
);
4648 int next_variant_function_id
= 0;
4650 public CCodeExpression?
try_cast_variant_to_type (CCodeExpression ccodeexpr
, DataType from
, DataType to
, Expression? expr
= null) {
4651 if (from
== null || gvariant_type
== null || from
.data_type
!= gvariant_type
) {
4655 string variant_func
= "_variant_get%d".printf (++next_variant_function_id
);
4657 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (variant_func
));
4658 ccall
.add_argument (ccodeexpr
);
4660 var cfunc
= new
CCodeFunction (variant_func
);
4661 cfunc
.modifiers
= CCodeModifiers
.STATIC
;
4662 cfunc
.add_parameter (new
CCodeParameter ("value", "GVariant*"));
4664 if (!to
.is_real_non_null_struct_type ()) {
4665 cfunc
.return_type
= to
.get_cname ();
4668 if (to
.is_real_non_null_struct_type ()) {
4669 // structs are returned via out parameter
4670 cfunc
.add_parameter (new
CCodeParameter ("result", to
.get_cname () + "*"));
4671 } else if (to is ArrayType
) {
4672 // return array length if appropriate
4673 var array_type
= (ArrayType
) to
;
4675 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4676 var temp_decl
= get_temp_variable (int_type
, false, expr
);
4677 emit_temp_var (temp_decl
);
4679 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_decl
.name
)));
4680 cfunc
.add_parameter (new
CCodeParameter (get_array_length_cname ("result", dim
), "int*"));
4681 append_array_length (expr
, get_variable_cexpression (temp_decl
.name
));
4685 push_function (cfunc
);
4687 var result
= deserialize_expression (to
, new
CCodeIdentifier ("value"), new
CCodeIdentifier ("*result"));
4688 ccode
.add_return (result
);
4692 cfile
.add_function_declaration (cfunc
);
4693 cfile
.add_function (cfunc
);
4698 public virtual CCodeExpression?
deserialize_expression (DataType type
, CCodeExpression variant_expr
, CCodeExpression? expr
, CCodeExpression? error_expr
= null, out bool may_fail
= null) {
4702 public virtual CCodeExpression?
serialize_expression (DataType type
, CCodeExpression expr
) {
4706 public override void visit_cast_expression (CastExpression expr
) {
4707 var valuecast
= try_cast_value_to_type (get_cvalue (expr
.inner
), expr
.inner
.value_type
, expr
.type_reference
, expr
);
4708 if (valuecast
!= null) {
4709 set_cvalue (expr
, valuecast
);
4713 var variantcast
= try_cast_variant_to_type (get_cvalue (expr
.inner
), expr
.inner
.value_type
, expr
.type_reference
, expr
);
4714 if (variantcast
!= null) {
4715 set_cvalue (expr
, variantcast
);
4719 generate_type_declaration (expr
.type_reference
, cfile
);
4721 var cl
= expr
.type_reference
.data_type as Class
;
4722 var iface
= expr
.type_reference
.data_type as Interface
;
4723 if (context
.profile
== Profile
.GOBJECT
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
4724 // checked cast for strict subtypes of GTypeInstance
4725 if (expr
.is_silent_cast
) {
4726 var temp_decl
= get_temp_variable (expr
.inner
.value_type
, expr
.inner
.value_type
.value_owned
, expr
, false);
4727 emit_temp_var (temp_decl
);
4728 var ctemp
= get_variable_cexpression (temp_decl
.name
);
4730 ccode
.add_assignment (ctemp
, get_cvalue (expr
.inner
));
4731 var ccheck
= create_type_check (ctemp
, expr
.type_reference
);
4732 var ccast
= new
CCodeCastExpression (ctemp
, expr
.type_reference
.get_cname ());
4733 var cnull
= new
CCodeConstant ("NULL");
4735 set_cvalue (expr
, new
CCodeConditionalExpression (ccheck
, ccast
, cnull
));
4737 set_cvalue (expr
, generate_instance_cast (get_cvalue (expr
.inner
), expr
.type_reference
.data_type
));
4740 if (expr
.is_silent_cast
) {
4742 Report
.error (expr
.source_reference
, "Operation not supported for this type");
4746 // retain array length
4747 var array_type
= expr
.type_reference as ArrayType
;
4748 if (array_type
!= null && expr
.inner
.value_type is ArrayType
) {
4749 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4750 append_array_length (expr
, get_array_length_cexpression (expr
.inner
, dim
));
4752 } else if (array_type
!= null) {
4753 // cast from non-array to array, set invalid length
4754 // required by string.data, e.g.
4755 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4756 append_array_length (expr
, new
CCodeConstant ("-1"));
4760 var innercexpr
= get_cvalue (expr
.inner
);
4761 if (expr
.type_reference
.data_type is Struct
&& !expr
.type_reference
.nullable
&&
4762 expr
.inner
.value_type
.data_type is Struct
&& expr
.inner
.value_type
.nullable
) {
4763 // nullable integer or float or boolean or struct cast to non-nullable
4764 innercexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, innercexpr
);
4766 set_cvalue (expr
, new
CCodeCastExpression (innercexpr
, expr
.type_reference
.get_cname ()));
4768 if (expr
.type_reference is DelegateType
) {
4769 if (get_delegate_target (expr
.inner
) != null) {
4770 set_delegate_target (expr
, get_delegate_target (expr
.inner
));
4772 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
4774 if (get_delegate_target_destroy_notify (expr
.inner
) != null) {
4775 set_delegate_target_destroy_notify (expr
, get_delegate_target_destroy_notify (expr
.inner
));
4777 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
4783 public override void visit_named_argument (NamedArgument expr
) {
4784 set_cvalue (expr
, get_cvalue (expr
.inner
));
4787 public override void visit_pointer_indirection (PointerIndirection expr
) {
4788 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_cvalue (expr
.inner
)));
4791 public override void visit_addressof_expression (AddressofExpression expr
) {
4792 if (get_cvalue (expr
.inner
) is CCodeCommaExpression
) {
4793 var ccomma
= get_cvalue (expr
.inner
) as CCodeCommaExpression
;
4794 var inner
= ccomma
.get_inner ();
4795 var last
= inner
.get (inner
.size
- 1);
4796 ccomma
.set_expression (inner
.size
- 1, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, (CCodeExpression
) last
));
4797 set_cvalue (expr
, ccomma
);
4799 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (expr
.inner
)));
4803 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
4804 /* (tmp = var, var = null, tmp) */
4805 var temp_decl
= get_temp_variable (expr
.value_type
, true, expr
, false);
4806 emit_temp_var (temp_decl
);
4807 var cvar
= get_variable_cexpression (temp_decl
.name
);
4809 ccode
.add_assignment (cvar
, get_cvalue (expr
.inner
));
4810 if (!(expr
.value_type is DelegateType
)) {
4811 ccode
.add_assignment (get_cvalue (expr
.inner
), new
CCodeConstant ("NULL"));
4814 set_cvalue (expr
, cvar
);
4816 var array_type
= expr
.value_type as ArrayType
;
4817 if (array_type
!= null) {
4818 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4819 append_array_length (expr
, get_array_length_cexpression (expr
.inner
, dim
));
4823 var delegate_type
= expr
.value_type as DelegateType
;
4824 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
4825 var temp_target_decl
= get_temp_variable (new
PointerType (new
VoidType ()), true, expr
, false);
4826 emit_temp_var (temp_target_decl
);
4827 var target_cvar
= get_variable_cexpression (temp_target_decl
.name
);
4828 CCodeExpression target_destroy_notify
;
4829 var target
= get_delegate_target_cexpression (expr
.inner
, out target_destroy_notify
);
4830 ccode
.add_assignment (target_cvar
, target
);
4831 set_delegate_target (expr
, target_cvar
);
4832 if (target_destroy_notify
!= null) {
4833 var temp_target_destroy_notify_decl
= get_temp_variable (gdestroynotify_type
, true, expr
, false);
4834 emit_temp_var (temp_target_destroy_notify_decl
);
4835 var target_destroy_notify_cvar
= get_variable_cexpression (temp_target_destroy_notify_decl
.name
);
4836 ccode
.add_assignment (target_destroy_notify_cvar
, target_destroy_notify
);
4837 ccode
.add_assignment (target_destroy_notify
, new
CCodeConstant ("NULL"));
4838 set_delegate_target_destroy_notify (expr
, target_destroy_notify_cvar
);
4843 public override void visit_binary_expression (BinaryExpression expr
) {
4844 var cleft
= get_cvalue (expr
.left
);
4845 var cright
= get_cvalue (expr
.right
);
4847 CCodeExpression? left_chain
= null;
4849 var lbe
= (BinaryExpression
) expr
.left
;
4851 var temp_decl
= get_temp_variable (lbe
.right
.value_type
, true, null, false);
4852 emit_temp_var (temp_decl
);
4853 var cvar
= get_variable_cexpression (temp_decl
.name
);
4854 var ccomma
= new
CCodeCommaExpression ();
4855 var clbe
= (CCodeBinaryExpression
) get_cvalue (lbe
);
4857 clbe
= (CCodeBinaryExpression
) clbe
.right
;
4859 ccomma
.append_expression (new
CCodeAssignment (cvar
, get_cvalue (lbe
.right
)));
4860 clbe
.right
= get_variable_cexpression (temp_decl
.name
);
4861 ccomma
.append_expression (cleft
);
4863 left_chain
= ccomma
;
4866 CCodeBinaryOperator op
;
4867 if (expr
.operator
== BinaryOperator
.PLUS
) {
4868 op
= CCodeBinaryOperator
.PLUS
;
4869 } else if (expr
.operator
== BinaryOperator
.MINUS
) {
4870 op
= CCodeBinaryOperator
.MINUS
;
4871 } else if (expr
.operator
== BinaryOperator
.MUL
) {
4872 op
= CCodeBinaryOperator
.MUL
;
4873 } else if (expr
.operator
== BinaryOperator
.DIV
) {
4874 op
= CCodeBinaryOperator
.DIV
;
4875 } else if (expr
.operator
== BinaryOperator
.MOD
) {
4876 if (expr
.value_type
.equals (double_type
)) {
4877 cfile
.add_include ("math.h");
4878 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("fmod"));
4879 ccall
.add_argument (cleft
);
4880 ccall
.add_argument (cright
);
4881 set_cvalue (expr
, ccall
);
4883 } else if (expr
.value_type
.equals (float_type
)) {
4884 cfile
.add_include ("math.h");
4885 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("fmodf"));
4886 ccall
.add_argument (cleft
);
4887 ccall
.add_argument (cright
);
4888 set_cvalue (expr
, ccall
);
4891 op
= CCodeBinaryOperator
.MOD
;
4893 } else if (expr
.operator
== BinaryOperator
.SHIFT_LEFT
) {
4894 op
= CCodeBinaryOperator
.SHIFT_LEFT
;
4895 } else if (expr
.operator
== BinaryOperator
.SHIFT_RIGHT
) {
4896 op
= CCodeBinaryOperator
.SHIFT_RIGHT
;
4897 } else if (expr
.operator
== BinaryOperator
.LESS_THAN
) {
4898 op
= CCodeBinaryOperator
.LESS_THAN
;
4899 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN
) {
4900 op
= CCodeBinaryOperator
.GREATER_THAN
;
4901 } else if (expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
) {
4902 op
= CCodeBinaryOperator
.LESS_THAN_OR_EQUAL
;
4903 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
4904 op
= CCodeBinaryOperator
.GREATER_THAN_OR_EQUAL
;
4905 } else if (expr
.operator
== BinaryOperator
.EQUALITY
) {
4906 op
= CCodeBinaryOperator
.EQUALITY
;
4907 } else if (expr
.operator
== BinaryOperator
.INEQUALITY
) {
4908 op
= CCodeBinaryOperator
.INEQUALITY
;
4909 } else if (expr
.operator
== BinaryOperator
.BITWISE_AND
) {
4910 op
= CCodeBinaryOperator
.BITWISE_AND
;
4911 } else if (expr
.operator
== BinaryOperator
.BITWISE_OR
) {
4912 op
= CCodeBinaryOperator
.BITWISE_OR
;
4913 } else if (expr
.operator
== BinaryOperator
.BITWISE_XOR
) {
4914 op
= CCodeBinaryOperator
.BITWISE_XOR
;
4915 } else if (expr
.operator
== BinaryOperator
.AND
) {
4916 op
= CCodeBinaryOperator
.AND
;
4917 } else if (expr
.operator
== BinaryOperator
.OR
) {
4918 op
= CCodeBinaryOperator
.OR
;
4919 } else if (expr
.operator
== BinaryOperator
.IN
) {
4920 if (expr
.right
.value_type is ArrayType
) {
4921 var array_type
= (ArrayType
) expr
.right
.value_type
;
4922 var node
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_contains_wrapper (array_type
)));
4923 node
.add_argument (cright
);
4924 node
.add_argument (get_array_length_cexpression (expr
.right
));
4925 if (array_type
.element_type is StructValueType
) {
4926 node
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cleft
));
4928 node
.add_argument (cleft
);
4930 set_cvalue (expr
, node
);
4932 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeBinaryExpression (CCodeBinaryOperator
.BITWISE_AND
, cright
, cleft
), cleft
));
4936 assert_not_reached ();
4939 if (expr
.operator
== BinaryOperator
.EQUALITY
||
4940 expr
.operator
== BinaryOperator
.INEQUALITY
) {
4941 var left_type
= expr
.left
.target_type
;
4942 var right_type
= expr
.right
.target_type
;
4943 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
4945 if (left_type is StructValueType
&& right_type is StructValueType
) {
4946 var equalfunc
= generate_struct_equal_function ((Struct
) left_type
.data_type as Struct
);
4947 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
4948 ccall
.add_argument (cleft
);
4949 ccall
.add_argument (cright
);
4951 cright
= new
CCodeConstant ("TRUE");
4952 } else if ((left_type is IntegerType
|| left_type is FloatingType
|| left_type is BooleanType
) && left_type
.nullable
&&
4953 (right_type is IntegerType
|| right_type is FloatingType
|| right_type is BooleanType
) && right_type
.nullable
) {
4954 var equalfunc
= generate_numeric_equal_function ((Struct
) left_type
.data_type as Struct
);
4955 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
4956 ccall
.add_argument (cleft
);
4957 ccall
.add_argument (cright
);
4959 cright
= new
CCodeConstant ("TRUE");
4963 if (!(expr
.left
.value_type is NullType
)
4964 && expr
.left
.value_type
.compatible (string_type
)
4965 && !(expr
.right
.value_type is NullType
)
4966 && expr
.right
.value_type
.compatible (string_type
)) {
4967 if (expr
.operator
== BinaryOperator
.PLUS
) {
4968 // string concatenation
4969 if (expr
.left
.is_constant () && expr
.right
.is_constant ()) {
4972 if (cleft is CCodeIdentifier
) {
4973 left
= ((CCodeIdentifier
) cleft
).name
;
4974 } else if (cleft is CCodeConstant
) {
4975 left
= ((CCodeConstant
) cleft
).name
;
4977 assert_not_reached ();
4979 if (cright is CCodeIdentifier
) {
4980 right
= ((CCodeIdentifier
) cright
).name
;
4981 } else if (cright is CCodeConstant
) {
4982 right
= ((CCodeConstant
) cright
).name
;
4984 assert_not_reached ();
4987 set_cvalue (expr
, new
CCodeConstant ("%s %s".printf (left
, right
)));
4990 if (context
.profile
== Profile
.POSIX
) {
4991 // convert to strcat(strcpy(malloc(1+strlen(a)+strlen(b)),a),b)
4992 var strcat
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcat"));
4993 var strcpy
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcpy"));
4994 var malloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("malloc"));
4996 var strlen_a
= new
CCodeFunctionCall (new
CCodeIdentifier ("strlen"));
4997 strlen_a
.add_argument(cleft
);
4998 var strlen_b
= new
CCodeFunctionCall (new
CCodeIdentifier ("strlen"));
4999 strlen_b
.add_argument(cright
);
5000 var newlength
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier("1"),
5001 new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, strlen_a
, strlen_b
));
5002 malloc
.add_argument(newlength
);
5004 strcpy
.add_argument(malloc
);
5005 strcpy
.add_argument(cleft
);
5007 strcat
.add_argument(strcpy
);
5008 strcat
.add_argument(cright
);
5009 set_cvalue (expr
, strcat
);
5011 // convert to g_strconcat (a, b, NULL)
5012 var temp_var
= get_temp_variable (expr
.value_type
, true, null, false);
5013 var temp_ref
= get_variable_cexpression (temp_var
.name
);
5014 emit_temp_var (temp_var
);
5016 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strconcat"));
5017 ccall
.add_argument (cleft
);
5018 ccall
.add_argument (cright
);
5019 ccall
.add_argument (new
CCodeConstant("NULL"));
5021 ccode
.add_assignment (temp_ref
, ccall
);
5022 set_cvalue (expr
, temp_ref
);
5026 } else if (expr
.operator
== BinaryOperator
.EQUALITY
5027 || expr
.operator
== BinaryOperator
.INEQUALITY
5028 || expr
.operator
== BinaryOperator
.LESS_THAN
5029 || expr
.operator
== BinaryOperator
.GREATER_THAN
5030 || expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
5031 || expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
5032 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
5033 ccall
.add_argument (cleft
);
5034 ccall
.add_argument (cright
);
5036 cright
= new
CCodeConstant ("0");
5040 set_cvalue (expr
, new
CCodeBinaryExpression (op
, cleft
, cright
));
5041 if (left_chain
!= null) {
5042 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, left_chain
, get_cvalue (expr
)));
5046 public string?
get_type_check_function (TypeSymbol type
) {
5047 var cl
= type as Class
;
5048 if (cl
!= null && cl
.type_check_function
!= null) {
5049 return cl
.type_check_function
;
5050 } else if ((cl
!= null && cl
.is_compact
) || type is Struct
|| type is Enum
|| type is Delegate
) {
5053 return type
.get_upper_case_cname ("IS_");
5057 CCodeExpression?
create_type_check (CCodeNode ccodenode
, DataType type
) {
5058 var et
= type as ErrorType
;
5059 if (et
!= null && et
.error_code
!= null) {
5060 var matches_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_matches"));
5061 matches_call
.add_argument ((CCodeExpression
) ccodenode
);
5062 matches_call
.add_argument (new
CCodeIdentifier (et
.error_domain
.get_upper_case_cname ()));
5063 matches_call
.add_argument (new
CCodeIdentifier (et
.error_code
.get_cname ()));
5064 return matches_call
;
5065 } else if (et
!= null && et
.error_domain
!= null) {
5066 var instance_domain
= new CCodeMemberAccess
.pointer ((CCodeExpression
) ccodenode
, "domain");
5067 var type_domain
= new
CCodeIdentifier (et
.error_domain
.get_upper_case_cname ());
5068 return new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, instance_domain
, type_domain
);
5070 string type_check_func
= get_type_check_function (type
.data_type
);
5071 if (type_check_func
== null) {
5072 return new
CCodeInvalidExpression ();
5074 var ccheck
= new
CCodeFunctionCall (new
CCodeIdentifier (type_check_func
));
5075 ccheck
.add_argument ((CCodeExpression
) ccodenode
);
5080 string generate_array_contains_wrapper (ArrayType array_type
) {
5081 string array_contains_func
= "_vala_%s_array_contains".printf (array_type
.element_type
.get_lower_case_cname ());
5083 if (!add_wrapper (array_contains_func
)) {
5084 return array_contains_func
;
5087 var function
= new
CCodeFunction (array_contains_func
, "gboolean");
5088 function
.modifiers
= CCodeModifiers
.STATIC
;
5090 function
.add_parameter (new
CCodeParameter ("stack", array_type
.get_cname ()));
5091 function
.add_parameter (new
CCodeParameter ("stack_length", "int"));
5092 if (array_type
.element_type is StructValueType
) {
5093 function
.add_parameter (new
CCodeParameter ("needle", array_type
.element_type
.get_cname () + "*"));
5095 function
.add_parameter (new
CCodeParameter ("needle", array_type
.element_type
.get_cname ()));
5098 push_function (function
);
5100 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
5102 var cloop_initializer
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
5103 var cloop_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("stack_length"));
5104 var cloop_iterator
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i"));
5105 ccode
.open_for (cloop_initializer
, cloop_condition
, cloop_iterator
);
5107 var celement
= new
CCodeElementAccess (new
CCodeIdentifier ("stack"), new
CCodeIdentifier ("i"));
5108 var cneedle
= new
CCodeIdentifier ("needle");
5109 CCodeBinaryExpression cif_condition
;
5110 if (array_type
.element_type
.compatible (string_type
)) {
5111 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
5112 ccall
.add_argument (celement
);
5113 ccall
.add_argument (cneedle
);
5114 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ccall
, new
CCodeConstant ("0"));
5115 } else if (array_type
.element_type is StructValueType
) {
5116 var equalfunc
= generate_struct_equal_function ((Struct
) array_type
.element_type
.data_type as Struct
);
5117 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
5118 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, celement
));
5119 ccall
.add_argument (cneedle
);
5120 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ccall
, new
CCodeConstant ("TRUE"));
5122 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cneedle
, celement
);
5125 ccode
.open_if (cif_condition
);
5126 ccode
.add_return (new
CCodeConstant ("TRUE"));
5131 ccode
.add_return (new
CCodeConstant ("FALSE"));
5135 cfile
.add_function_declaration (function
);
5136 cfile
.add_function (function
);
5138 return array_contains_func
;
5141 public override void visit_type_check (TypeCheck expr
) {
5142 generate_type_declaration (expr
.type_reference
, cfile
);
5144 set_cvalue (expr
, create_type_check (get_cvalue (expr
.expression
), expr
.type_reference
));
5145 if (get_cvalue (expr
) is CCodeInvalidExpression
) {
5146 Report
.error (expr
.source_reference
, "type check expressions not supported for compact classes, structs, and enums");
5150 public override void visit_lambda_expression (LambdaExpression lambda
) {
5151 // use instance position from delegate
5152 var dt
= (DelegateType
) lambda
.target_type
;
5153 lambda
.method
.cinstance_parameter_position
= dt
.delegate_symbol
.cinstance_parameter_position
;
5155 lambda
.accept_children (this
);
5157 bool expr_owned
= lambda
.value_type
.value_owned
;
5159 set_cvalue (lambda
, new
CCodeIdentifier (lambda
.method
.get_cname ()));
5161 var delegate_type
= (DelegateType
) lambda
.target_type
;
5162 if (lambda
.method
.closure
) {
5163 int block_id
= get_block_id (current_closure_block
);
5164 var delegate_target
= get_variable_cexpression ("_data%d_".printf (block_id
));
5165 if (expr_owned
|| delegate_type
.is_called_once
) {
5166 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (block_id
)));
5167 ref_call
.add_argument (delegate_target
);
5168 delegate_target
= ref_call
;
5169 set_delegate_target_destroy_notify (lambda
, new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
5171 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5173 set_delegate_target (lambda
, delegate_target
);
5174 } else if (get_this_type () != null || in_constructor
) {
5175 CCodeExpression delegate_target
= get_result_cexpression ("self");
5176 if (expr_owned
|| delegate_type
.is_called_once
) {
5177 if (get_this_type () != null) {
5178 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (get_this_type (), lambda
.source_reference
));
5179 ref_call
.add_argument (delegate_target
);
5180 delegate_target
= ref_call
;
5181 set_delegate_target_destroy_notify (lambda
, get_destroy_func_expression (get_this_type ()));
5184 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_ref"));
5185 ref_call
.add_argument (delegate_target
);
5186 delegate_target
= ref_call
;
5187 set_delegate_target_destroy_notify (lambda
, new
CCodeIdentifier ("g_object_unref"));
5190 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5192 set_delegate_target (lambda
, delegate_target
);
5194 set_delegate_target (lambda
, new
CCodeConstant ("NULL"));
5195 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5199 public CCodeExpression
convert_from_generic_pointer (CCodeExpression cexpr
, DataType actual_type
) {
5201 if (is_reference_type_argument (actual_type
) || is_nullable_value_type_argument (actual_type
)) {
5202 result
= new
CCodeCastExpression (cexpr
, actual_type
.get_cname ());
5203 } else if (is_signed_integer_type_argument (actual_type
)) {
5204 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GPOINTER_TO_INT"));
5205 cconv
.add_argument (cexpr
);
5207 } else if (is_unsigned_integer_type_argument (actual_type
)) {
5208 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GPOINTER_TO_UINT"));
5209 cconv
.add_argument (cexpr
);
5215 public CCodeExpression
convert_to_generic_pointer (CCodeExpression cexpr
, DataType actual_type
) {
5217 if (is_signed_integer_type_argument (actual_type
)) {
5218 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GINT_TO_POINTER"));
5219 cconv
.add_argument (cexpr
);
5221 } else if (is_unsigned_integer_type_argument (actual_type
)) {
5222 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GUINT_TO_POINTER"));
5223 cconv
.add_argument (cexpr
);
5229 // manage memory and implicit casts
5230 public CCodeExpression
transform_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
5231 var cexpr
= source_cexpr
;
5232 if (expression_type
== null) {
5237 if (expression_type
.value_owned
5238 && expression_type
.floating_reference
) {
5239 /* floating reference, sink it.
5241 var cl
= expression_type
.data_type as ObjectTypeSymbol
;
5242 var sink_func
= (cl
!= null) ? cl
.get_ref_sink_function () : null;
5244 if (sink_func
!= null) {
5245 var csink
= new
CCodeFunctionCall (new
CCodeIdentifier (sink_func
));
5246 csink
.add_argument (cexpr
);
5250 Report
.error (null, "type `%s' does not support floating references".printf (expression_type
.data_type
.name
));
5254 bool boxing
= (expression_type is ValueType
&& !expression_type
.nullable
5255 && target_type is ValueType
&& target_type
.nullable
);
5256 bool unboxing
= (expression_type is ValueType
&& expression_type
.nullable
5257 && target_type is ValueType
&& !target_type
.nullable
);
5259 bool gvalue_boxing
= (context
.profile
== Profile
.GOBJECT
5260 && target_type
!= null
5261 && target_type
.data_type
== gvalue_type
5262 && !(expression_type is NullType
)
5263 && expression_type
.get_type_id () != "G_TYPE_VALUE");
5264 bool gvariant_boxing
= (context
.profile
== Profile
.GOBJECT
5265 && target_type
!= null
5266 && target_type
.data_type
== gvariant_type
5267 && !(expression_type is NullType
)
5268 && expression_type
.data_type
!= gvariant_type
);
5270 if (expression_type
.value_owned
5271 && (target_type
== null || !target_type
.value_owned
|| boxing
|| unboxing
)
5272 && !gvalue_boxing
/* gvalue can assume ownership of value, no need to free it */) {
5273 // value leaked, destroy it
5274 var pointer_type
= target_type as PointerType
;
5275 if (pointer_type
!= null && !(pointer_type
.base_type is VoidType
)) {
5276 // manual memory management for non-void pointers
5277 // treat void* special to not leak memory with void* method parameters
5278 } else if (requires_destroy (expression_type
)) {
5279 var decl
= get_temp_variable (expression_type
, true, expression_type
, false);
5280 emit_temp_var (decl
);
5281 temp_ref_vars
.insert (0, decl
);
5282 ccode
.add_assignment (get_variable_cexpression (decl
.name
), cexpr
);
5283 cexpr
= get_variable_cexpression (decl
.name
);
5285 if (expression_type is ArrayType
&& expr
!= null) {
5286 var array_type
= (ArrayType
) expression_type
;
5287 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5288 var len_decl
= new
LocalVariable (int_type
.copy (), get_array_length_cname (decl
.name
, dim
));
5289 emit_temp_var (len_decl
);
5290 ccode
.add_assignment (get_variable_cexpression (len_decl
.name
), get_array_length_cexpression (expr
, dim
));
5292 } else if (expression_type is DelegateType
&& expr
!= null) {
5293 var target_decl
= new
LocalVariable (new
PointerType (new
VoidType ()), get_delegate_target_cname (decl
.name
));
5294 emit_temp_var (target_decl
);
5295 var target_destroy_notify_decl
= new
LocalVariable (gdestroynotify_type
, get_delegate_target_destroy_notify_cname (decl
.name
));
5296 emit_temp_var (target_destroy_notify_decl
);
5297 CCodeExpression target_destroy_notify
;
5298 ccode
.add_assignment (get_variable_cexpression (target_decl
.name
), get_delegate_target_cexpression (expr
, out target_destroy_notify
));
5299 ccode
.add_assignment (get_variable_cexpression (target_destroy_notify_decl
.name
), target_destroy_notify
);
5305 if (target_type
== null) {
5306 // value will be destroyed, no need for implicit casts
5310 if (gvalue_boxing
) {
5311 // implicit conversion to GValue
5312 var decl
= get_temp_variable (target_type
, true, target_type
);
5313 emit_temp_var (decl
);
5315 if (!target_type
.value_owned
) {
5316 // boxed GValue leaked, destroy it
5317 temp_ref_vars
.insert (0, decl
);
5320 if (target_type
.nullable
) {
5321 var newcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
5322 newcall
.add_argument (new
CCodeConstant ("GValue"));
5323 newcall
.add_argument (new
CCodeConstant ("1"));
5324 var newassignment
= new
CCodeAssignment (get_variable_cexpression (decl
.name
), newcall
);
5325 ccode
.add_expression (newassignment
);
5328 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
5329 if (target_type
.nullable
) {
5330 ccall
.add_argument (get_variable_cexpression (decl
.name
));
5332 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
)));
5334 ccall
.add_argument (new
CCodeIdentifier (expression_type
.get_type_id ()));
5335 ccode
.add_expression (ccall
);
5337 if (requires_destroy (expression_type
)) {
5338 ccall
= new
CCodeFunctionCall (get_value_taker_function (expression_type
));
5340 ccall
= new
CCodeFunctionCall (get_value_setter_function (expression_type
));
5342 if (target_type
.nullable
) {
5343 ccall
.add_argument (get_variable_cexpression (decl
.name
));
5345 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
)));
5347 if (expression_type
.is_real_non_null_struct_type ()) {
5348 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
5350 ccall
.add_argument (cexpr
);
5353 ccode
.add_expression (ccall
);
5355 cexpr
= get_variable_cexpression (decl
.name
);
5358 } else if (gvariant_boxing
) {
5359 // implicit conversion to GVariant
5360 string variant_func
= "_variant_new%d".printf (++next_variant_function_id
);
5362 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (variant_func
));
5363 ccall
.add_argument (cexpr
);
5365 var cfunc
= new
CCodeFunction (variant_func
, "GVariant*");
5366 cfunc
.modifiers
= CCodeModifiers
.STATIC
;
5367 cfunc
.add_parameter (new
CCodeParameter ("value", expression_type
.get_cname ()));
5369 if (expression_type is ArrayType
) {
5370 // return array length if appropriate
5371 var array_type
= (ArrayType
) expression_type
;
5373 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5374 ccall
.add_argument (get_array_length_cexpression (expr
, dim
));
5375 cfunc
.add_parameter (new
CCodeParameter (get_array_length_cname ("value", dim
), "gint"));
5379 push_function (cfunc
);
5381 var result
= serialize_expression (expression_type
, new
CCodeIdentifier ("value"));
5383 // sink floating reference
5384 var sink
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_ref_sink"));
5385 sink
.add_argument (result
);
5386 ccode
.add_return (sink
);
5390 cfile
.add_function_declaration (cfunc
);
5391 cfile
.add_function (cfunc
);
5394 } else if (boxing
) {
5395 // value needs to be boxed
5397 var unary
= cexpr as CCodeUnaryExpression
;
5398 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
5400 cexpr
= unary
.inner
;
5401 } else if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
5402 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
5404 var decl
= get_temp_variable (expression_type
, expression_type
.value_owned
, expression_type
, false);
5405 emit_temp_var (decl
);
5407 ccode
.add_assignment (get_variable_cexpression (decl
.name
), cexpr
);
5408 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
));
5410 } else if (unboxing
) {
5413 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cexpr
);
5415 cexpr
= get_implicit_cast_expression (cexpr
, expression_type
, target_type
, expr
);
5418 if (target_type
.value_owned
&& (!expression_type
.value_owned
|| boxing
|| unboxing
)) {
5419 // need to copy value
5420 if (requires_copy (target_type
) && !(expression_type is NullType
)) {
5421 CodeNode node
= expr
;
5423 node
= expression_type
;
5426 var decl
= get_temp_variable (target_type
, true, node
, false);
5427 emit_temp_var (decl
);
5428 ccode
.add_assignment (get_variable_cexpression (decl
.name
), get_ref_cexpression (target_type
, cexpr
, expr
, node
));
5429 cexpr
= get_variable_cexpression (decl
.name
);
5436 public virtual CCodeExpression
get_implicit_cast_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
5437 var cexpr
= source_cexpr
;
5439 if (expression_type
.data_type
!= null && expression_type
.data_type
== target_type
.data_type
) {
5440 // same type, no cast required
5444 if (expression_type is NullType
) {
5445 // null literal, no cast required when not converting to generic type pointer
5449 generate_type_declaration (target_type
, cfile
);
5451 var cl
= target_type
.data_type as Class
;
5452 var iface
= target_type
.data_type as Interface
;
5453 if (context
.checking
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
5454 // checked cast for strict subtypes of GTypeInstance
5455 return generate_instance_cast (cexpr
, target_type
.data_type
);
5456 } else if (target_type
.data_type
!= null && expression_type
.get_cname () != target_type
.get_cname ()) {
5457 var st
= target_type
.data_type as Struct
;
5458 if (target_type
.data_type
.is_reference_type () || (st
!= null && st
.is_simple_type ())) {
5459 // don't cast non-simple structs
5460 return new
CCodeCastExpression (cexpr
, target_type
.get_cname ());
5469 public void store_property (Property prop
, Expression? instance
, TargetValue value
) {
5470 if (instance is BaseAccess
) {
5471 if (prop
.base_property
!= null) {
5472 var base_class
= (Class
) prop
.base_property
.parent_symbol
;
5473 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (base_class
.get_upper_case_cname (null))));
5474 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (current_class
.get_lower_case_cname (null))));
5476 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "set_%s".printf (prop
.name
)));
5477 ccall
.add_argument ((CCodeExpression
) get_ccodenode (instance
));
5478 ccall
.add_argument (get_cvalue_ (value
));
5480 ccode
.add_expression (ccall
);
5481 } else if (prop
.base_interface_property
!= null) {
5482 var base_iface
= (Interface
) prop
.base_interface_property
.parent_symbol
;
5483 string parent_iface_var
= "%s_%s_parent_iface".printf (current_class
.get_lower_case_cname (null), base_iface
.get_lower_case_cname (null));
5485 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), "set_%s".printf (prop
.name
)));
5486 ccall
.add_argument ((CCodeExpression
) get_ccodenode (instance
));
5487 ccall
.add_argument (get_cvalue_ (value
));
5489 ccode
.add_expression (ccall
);
5494 var set_func
= "g_object_set";
5496 var base_property
= prop
;
5497 if (!prop
.no_accessor_method
) {
5498 if (prop
.base_property
!= null) {
5499 base_property
= prop
.base_property
;
5500 } else if (prop
.base_interface_property
!= null) {
5501 base_property
= prop
.base_interface_property
;
5504 if (prop is DynamicProperty
) {
5505 set_func
= get_dynamic_property_setter_cname ((DynamicProperty
) prop
);
5507 generate_property_accessor_declaration (base_property
.set_accessor
, cfile
);
5508 set_func
= base_property
.set_accessor
.get_cname ();
5510 if (!prop
.external
&& prop
.external_package
) {
5511 // internal VAPI properties
5512 // only add them once per source file
5513 if (add_generated_external_symbol (prop
)) {
5514 visit_property (prop
);
5520 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (set_func
));
5522 if (prop
.binding
== MemberBinding
.INSTANCE
) {
5523 /* target instance is first argument */
5524 var cinstance
= (CCodeExpression
) get_ccodenode (instance
);
5526 if (prop
.parent_symbol is Struct
) {
5527 // we need to pass struct instance by reference
5528 var unary
= cinstance as CCodeUnaryExpression
;
5529 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
5531 cinstance
= unary
.inner
;
5532 } else if (cinstance is CCodeIdentifier
|| cinstance is CCodeMemberAccess
) {
5533 cinstance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cinstance
);
5535 // if instance is e.g. a function call, we can't take the address of the expression
5536 // (tmp = expr, &tmp)
5538 var temp_var
= get_temp_variable (instance
.target_type
, true, null, false);
5539 emit_temp_var (temp_var
);
5540 ccode
.add_assignment (get_variable_cexpression (temp_var
.name
), cinstance
);
5542 cinstance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
));
5546 ccall
.add_argument (cinstance
);
5549 if (prop
.no_accessor_method
) {
5550 /* property name is second argument of g_object_set */
5551 ccall
.add_argument (prop
.get_canonical_cconstant ());
5554 var cexpr
= get_cvalue_ (value
);
5556 if (prop
.property_type
.is_real_non_null_struct_type ()) {
5557 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
5560 var array_type
= prop
.property_type as ArrayType
;
5562 if (array_type
!= null && !prop
.no_array_length
) {
5563 var temp_var
= get_temp_variable (prop
.property_type
, true, null, false);
5564 emit_temp_var (temp_var
);
5565 ccode
.add_assignment (get_variable_cexpression (temp_var
.name
), cexpr
);
5566 ccall
.add_argument (get_variable_cexpression (temp_var
.name
));
5568 ccall
.add_argument (cexpr
);
5571 if (array_type
!= null && !prop
.no_array_length
) {
5572 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5573 ccall
.add_argument (get_array_length_cvalue (value
, dim
));
5575 } else if (prop
.property_type is DelegateType
) {
5576 var delegate_type
= (DelegateType
) prop
.property_type
;
5577 if (delegate_type
.delegate_symbol
.has_target
) {
5578 ccall
.add_argument (get_delegate_target_cvalue (value
));
5582 if (prop
.no_accessor_method
) {
5583 ccall
.add_argument (new
CCodeConstant ("NULL"));
5586 ccode
.add_expression (ccall
);
5589 /* indicates whether a given Expression eligable for an ADDRESS_OF operator
5590 * from a vala to C point of view all expressions denoting locals, fields and
5591 * parameters are eligable to an ADDRESS_OF operator */
5592 public bool is_address_of_possible (Expression e
) {
5593 if (gvalue_type
!= null && e
.target_type
.data_type
== gvalue_type
&& e
.value_type
.data_type
!= gvalue_type
) {
5594 // implicit conversion to GValue is not addressable
5598 var ma
= e as MemberAccess
;
5604 return (ma
.symbol_reference is Variable
);
5607 /* retrieve the correct address_of expression for a give expression, creates temporary variables
5608 * where necessary, ce is the corresponding ccode expression for e */
5609 public CCodeExpression
get_address_of_expression (Expression e
, CCodeExpression ce
) {
5610 // is address of trivially possible?
5611 if (is_address_of_possible (e
)) {
5612 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ce
);
5615 var ccomma
= new
CCodeCommaExpression ();
5616 DataType address_of_type
;
5617 if (gvalue_type
!= null && e
.target_type
!= null && e
.target_type
.data_type
== gvalue_type
) {
5618 // implicit conversion to GValue
5619 address_of_type
= e
.target_type
;
5621 address_of_type
= e
.value_type
;
5623 var temp_decl
= get_temp_variable (address_of_type
, true, null, false);
5624 var ctemp
= get_variable_cexpression (temp_decl
.name
);
5625 emit_temp_var (temp_decl
);
5626 ccomma
.append_expression (new
CCodeAssignment (ctemp
, ce
));
5627 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
5631 public bool add_wrapper (string wrapper_name
) {
5632 return wrappers
.add (wrapper_name
);
5635 public bool add_generated_external_symbol (Symbol external_symbol
) {
5636 return generated_external_symbols
.add (external_symbol
);
5639 public static DataType
get_data_type_for_symbol (TypeSymbol sym
) {
5640 DataType type
= null;
5643 type
= new
ObjectType ((Class
) sym
);
5644 } else if (sym is Interface
) {
5645 type
= new
ObjectType ((Interface
) sym
);
5646 } else if (sym is Struct
) {
5647 var st
= (Struct
) sym
;
5648 if (st
.is_boolean_type ()) {
5649 type
= new
BooleanType (st
);
5650 } else if (st
.is_integer_type ()) {
5651 type
= new
IntegerType (st
);
5652 } else if (st
.is_floating_type ()) {
5653 type
= new
FloatingType (st
);
5655 type
= new
StructValueType (st
);
5657 } else if (sym is Enum
) {
5658 type
= new
EnumValueType ((Enum
) sym
);
5659 } else if (sym is ErrorDomain
) {
5660 type
= new
ErrorType ((ErrorDomain
) sym
, null);
5661 } else if (sym is ErrorCode
) {
5662 type
= new
ErrorType ((ErrorDomain
) sym
.parent_symbol
, (ErrorCode
) sym
);
5664 Report
.error (null, "internal error: `%s' is not a supported type".printf (sym
.get_full_name ()));
5665 return new
InvalidType ();
5671 public CCodeExpression?
default_value_for_type (DataType type
, bool initializer_expression
) {
5672 var st
= type
.data_type as Struct
;
5673 var array_type
= type as ArrayType
;
5674 if (initializer_expression
&& !type
.nullable
&&
5675 ((st
!= null && !st
.is_simple_type ()) ||
5676 (array_type
!= null && array_type
.fixed_length
))) {
5677 // 0-initialize struct with struct initializer { 0 }
5678 // only allowed as initializer expression in C
5679 var clist
= new
CCodeInitializerList ();
5680 clist
.append (new
CCodeConstant ("0"));
5682 } else if ((type
.data_type
!= null && type
.data_type
.is_reference_type ())
5684 || type is PointerType
|| type is DelegateType
5685 || (array_type
!= null && !array_type
.fixed_length
)) {
5686 return new
CCodeConstant ("NULL");
5687 } else if (type
.data_type
!= null && type
.data_type
.get_default_value () != null) {
5688 return new
CCodeConstant (type
.data_type
.get_default_value ());
5689 } else if (type
.type_parameter
!= null) {
5690 return new
CCodeConstant ("NULL");
5691 } else if (type is ErrorType
) {
5692 return new
CCodeConstant ("NULL");
5697 private void create_property_type_check_statement (Property prop
, bool check_return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
5698 if (check_return_type
) {
5699 create_type_check_statement (prop
, prop
.property_type
, t
, non_null
, var_name
);
5701 create_type_check_statement (prop
, new
VoidType (), t
, non_null
, var_name
);
5705 public void create_type_check_statement (CodeNode method_node
, DataType ret_type
, TypeSymbol t
, bool non_null
, string var_name
) {
5706 var ccheck
= new
CCodeFunctionCall ();
5708 if (!context
.assert
) {
5710 } else if (context
.checking
&& ((t is Class
&& !((Class
) t
).is_compact
) || t is Interface
)) {
5711 var ctype_check
= new
CCodeFunctionCall (new
CCodeIdentifier (get_type_check_function (t
)));
5712 ctype_check
.add_argument (new
CCodeIdentifier (var_name
));
5714 CCodeExpression cexpr
= ctype_check
;
5716 var cnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier (var_name
), new
CCodeConstant ("NULL"));
5718 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cnull
, ctype_check
);
5720 ccheck
.add_argument (cexpr
);
5721 } else if (!non_null
) {
5723 } else if (t
== glist_type
|| t
== gslist_type
) {
5724 // NULL is empty list
5727 var cnonnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier (var_name
), new
CCodeConstant ("NULL"));
5728 ccheck
.add_argument (cnonnull
);
5731 var cm
= method_node as CreationMethod
;
5732 if (cm
!= null && cm
.parent_symbol is ObjectTypeSymbol
) {
5733 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
5734 ccheck
.add_argument (new
CCodeConstant ("NULL"));
5735 } else if (ret_type is VoidType
) {
5737 ccheck
.call
= new
CCodeIdentifier ("g_return_if_fail");
5739 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
5741 var cdefault
= default_value_for_type (ret_type
, false);
5742 if (cdefault
!= null) {
5743 ccheck
.add_argument (cdefault
);
5749 ccode
.add_expression (ccheck
);
5752 public int get_param_pos (double param_pos
, bool ellipsis
= false) {
5754 if (param_pos
>= 0) {
5755 return (int) (param_pos
* 1000);
5757 return (int) ((100 + param_pos
) * 1000);
5760 if (param_pos
>= 0) {
5761 return (int) ((100 + param_pos
) * 1000);
5763 return (int) ((200 + param_pos
) * 1000);
5768 public CCodeExpression?
get_ccodenode (Expression node
) {
5769 if (get_cvalue (node
) == null) {
5772 return get_cvalue (node
);
5775 public override void visit_class (Class cl
) {
5778 public void create_postcondition_statement (Expression postcondition
) {
5779 var cassert
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_warn_if_fail"));
5781 postcondition
.emit (this
);
5783 cassert
.add_argument (get_cvalue (postcondition
));
5785 ccode
.add_expression (cassert
);
5788 public virtual bool is_gobject_property (Property prop
) {
5792 public DataType?
get_this_type () {
5793 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) {
5794 return current_method
.this_parameter
.variable_type
;
5795 } else if (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
) {
5796 return current_property_accessor
.prop
.this_parameter
.variable_type
;
5801 public CCodeFunctionCall
generate_instance_cast (CCodeExpression expr
, TypeSymbol type
) {
5802 var result
= new
CCodeFunctionCall (new
CCodeIdentifier (type
.get_upper_case_cname (null)));
5803 result
.add_argument (expr
);
5807 void generate_struct_destroy_function (Struct st
) {
5808 if (cfile
.add_declaration (st
.get_destroy_function ())) {
5809 // only generate function once per source file
5813 var function
= new
CCodeFunction (st
.get_destroy_function (), "void");
5814 function
.modifiers
= CCodeModifiers
.STATIC
;
5815 function
.add_parameter (new
CCodeParameter ("self", st
.get_cname () + "*"));
5817 push_function (function
);
5819 foreach (Field f
in st
.get_fields ()) {
5820 if (f
.binding
== MemberBinding
.INSTANCE
) {
5821 if (requires_destroy (f
.variable_type
)) {
5822 var lhs
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.get_cname ());
5824 var this_access
= new MemberAccess
.simple ("this");
5825 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
5826 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
5828 var ma
= new
MemberAccess (this_access
, f
.name
);
5829 ma
.symbol_reference
= f
;
5830 ma
.value_type
= f
.variable_type
.copy ();
5831 visit_member_access (ma
);
5832 ccode
.add_expression (get_unref_expression (lhs
, f
.variable_type
, ma
));
5839 cfile
.add_function_declaration (function
);
5840 cfile
.add_function (function
);
5843 void generate_struct_copy_function (Struct st
) {
5844 if (cfile
.add_declaration (st
.get_copy_function ())) {
5845 // only generate function once per source file
5849 var function
= new
CCodeFunction (st
.get_copy_function (), "void");
5850 function
.modifiers
= CCodeModifiers
.STATIC
;
5851 function
.add_parameter (new
CCodeParameter ("self", "const " + st
.get_cname () + "*"));
5852 function
.add_parameter (new
CCodeParameter ("dest", st
.get_cname () + "*"));
5854 push_context (new
EmitContext ());
5855 push_function (function
);
5857 foreach (Field f
in st
.get_fields ()) {
5858 if (f
.binding
== MemberBinding
.INSTANCE
) {
5859 CCodeExpression copy
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.name
);
5860 if (requires_copy (f
.variable_type
)) {
5861 var this_access
= new MemberAccess
.simple ("this");
5862 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
5863 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
5864 var ma
= new
MemberAccess (this_access
, f
.name
);
5865 ma
.symbol_reference
= f
;
5866 ma
.value_type
= f
.variable_type
.copy ();
5867 visit_member_access (ma
);
5868 copy
= get_ref_cexpression (f
.variable_type
, copy
, ma
, f
);
5870 var dest
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("dest"), f
.name
);
5872 var array_type
= f
.variable_type as ArrayType
;
5873 if (array_type
!= null && array_type
.fixed_length
) {
5874 // fixed-length (stack-allocated) arrays
5875 cfile
.add_include ("string.h");
5877 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
5878 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
5879 var size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
);
5881 var array_copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
5882 array_copy_call
.add_argument (dest
);
5883 array_copy_call
.add_argument (copy
);
5884 array_copy_call
.add_argument (size
);
5885 ccode
.add_expression (array_copy_call
);
5887 ccode
.add_assignment (dest
, copy
);
5889 if (array_type
!= null && !f
.no_array_length
) {
5890 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5891 var len_src
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), get_array_length_cname (f
.name
, dim
));
5892 var len_dest
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("dest"), get_array_length_cname (f
.name
, dim
));
5893 ccode
.add_assignment (len_dest
, len_src
);
5903 cfile
.add_function_declaration (function
);
5904 cfile
.add_function (function
);
5907 public void return_default_value (DataType return_type
) {
5908 ccode
.add_return (default_value_for_type (return_type
, false));
5911 public virtual string?
get_custom_creturn_type (Method m
) {
5915 public virtual void generate_dynamic_method_wrapper (DynamicMethod method
) {
5918 public virtual bool method_has_wrapper (Method method
) {
5922 public virtual CCodeFunctionCall
get_param_spec (Property prop
) {
5923 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
5926 public virtual CCodeFunctionCall
get_signal_creation (Signal sig
, TypeSymbol type
) {
5927 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
5930 public virtual void register_dbus_info (CCodeBlock block
, ObjectTypeSymbol bindable
) {
5933 public virtual string get_dynamic_property_getter_cname (DynamicProperty node
) {
5934 Report
.error (node
.source_reference
, "dynamic properties are not supported for %s".printf (node
.dynamic_type
.to_string ()));
5938 public virtual string get_dynamic_property_setter_cname (DynamicProperty node
) {
5939 Report
.error (node
.source_reference
, "dynamic properties are not supported for %s".printf (node
.dynamic_type
.to_string ()));
5943 public virtual string get_dynamic_signal_cname (DynamicSignal node
) {
5947 public virtual string get_dynamic_signal_connect_wrapper_name (DynamicSignal node
) {
5951 public virtual string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal node
) {
5955 public virtual string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node
) {
5959 public virtual void generate_marshaller (List
<Parameter
> params
, DataType return_type
, bool dbus
= false) {
5962 public virtual string get_marshaller_function (List
<Parameter
> params
, DataType return_type
, string? prefix
= null, bool dbus
= false) {
5966 public virtual string get_array_length_cname (string array_cname
, int dim
) {
5970 public virtual string get_parameter_array_length_cname (Parameter param
, int dim
) {
5974 public virtual CCodeExpression
get_array_length_cexpression (Expression array_expr
, int dim
= -1) {
5975 return new
CCodeConstant ("");
5978 public virtual CCodeExpression
get_array_length_cvalue (TargetValue value
, int dim
= -1) {
5979 return new
CCodeInvalidExpression ();
5982 public virtual string get_array_size_cname (string array_cname
) {
5986 public virtual void add_simple_check (CodeNode node
, bool always_fails
= false) {
5989 public virtual string generate_ready_function (Method m
) {
5993 public CCodeExpression?
get_cvalue (Expression expr
) {
5994 if (expr
.target_value
== null) {
5997 var glib_value
= (GLibValue
) expr
.target_value
;
5998 return glib_value
.cvalue
;
6001 public CCodeExpression?
get_cvalue_ (TargetValue value
) {
6002 var glib_value
= (GLibValue
) value
;
6003 return glib_value
.cvalue
;
6006 public void set_cvalue (Expression expr
, CCodeExpression? cvalue
) {
6007 var glib_value
= (GLibValue
) expr
.target_value
;
6008 if (glib_value
== null) {
6009 glib_value
= new
GLibValue (expr
.value_type
);
6010 expr
.target_value
= glib_value
;
6012 glib_value
.cvalue
= cvalue
;
6015 public CCodeExpression?
get_array_size_cvalue (TargetValue value
) {
6016 var glib_value
= (GLibValue
) value
;
6017 return glib_value
.array_size_cvalue
;
6020 public void set_array_size_cvalue (TargetValue value
, CCodeExpression? cvalue
) {
6021 var glib_value
= (GLibValue
) value
;
6022 glib_value
.array_size_cvalue
= cvalue
;
6025 public CCodeExpression?
get_delegate_target (Expression expr
) {
6026 if (expr
.target_value
== null) {
6029 var glib_value
= (GLibValue
) expr
.target_value
;
6030 return glib_value
.delegate_target_cvalue
;
6033 public void set_delegate_target (Expression expr
, CCodeExpression? delegate_target
) {
6034 var glib_value
= (GLibValue
) expr
.target_value
;
6035 if (glib_value
== null) {
6036 glib_value
= new
GLibValue (expr
.value_type
);
6037 expr
.target_value
= glib_value
;
6039 glib_value
.delegate_target_cvalue
= delegate_target
;
6042 public CCodeExpression?
get_delegate_target_destroy_notify (Expression expr
) {
6043 if (expr
.target_value
== null) {
6046 var glib_value
= (GLibValue
) expr
.target_value
;
6047 return glib_value
.delegate_target_destroy_notify_cvalue
;
6050 public void set_delegate_target_destroy_notify (Expression expr
, CCodeExpression? destroy_notify
) {
6051 var glib_value
= (GLibValue
) expr
.target_value
;
6052 if (glib_value
== null) {
6053 glib_value
= new
GLibValue (expr
.value_type
);
6054 expr
.target_value
= glib_value
;
6056 glib_value
.delegate_target_destroy_notify_cvalue
= destroy_notify
;
6059 public void append_array_length (Expression expr
, CCodeExpression size
) {
6060 var glib_value
= (GLibValue
) expr
.target_value
;
6061 if (glib_value
== null) {
6062 glib_value
= new
GLibValue (expr
.value_type
);
6063 expr
.target_value
= glib_value
;
6065 glib_value
.append_array_length_cvalue (size
);
6068 public List
<CCodeExpression
>?
get_array_lengths (Expression expr
) {
6069 var glib_value
= (GLibValue
) expr
.target_value
;
6070 if (glib_value
== null) {
6071 glib_value
= new
GLibValue (expr
.value_type
);
6072 expr
.target_value
= glib_value
;
6074 return glib_value
.array_length_cvalues
;
6078 public class Vala
.GLibValue
: TargetValue
{
6079 public CCodeExpression cvalue
;
6081 public List
<CCodeExpression
> array_length_cvalues
;
6082 public CCodeExpression? array_size_cvalue
;
6084 public CCodeExpression? delegate_target_cvalue
;
6085 public CCodeExpression? delegate_target_destroy_notify_cvalue
;
6087 public GLibValue (DataType? value_type
= null, CCodeExpression? cvalue
= null) {
6089 this
.cvalue
= cvalue
;
6092 public void append_array_length_cvalue (CCodeExpression length_cvalue
) {
6093 if (array_length_cvalues
== null) {
6094 array_length_cvalues
= new ArrayList
<CCodeExpression
> ();
6096 array_length_cvalues
.add (length_cvalue
);