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
) {
181 unowned Method method
= sym as Method
;
182 if (method
!= null && !method
.closure
) {
183 // parent blocks are not captured by this method
187 unowned Block block
= sym as Block
;
188 if (method
== null && block
== null) {
193 if (block
!= null && block
.captured
) {
194 // closure block found
197 sym
= sym
.parent_symbol
;
202 public CCodeFile header_file
;
203 public CCodeFile internal_header_file
;
204 public CCodeFile cfile
;
206 public EmitContext class_init_context
;
207 public EmitContext base_init_context
;
208 public EmitContext class_finalize_context
;
209 public EmitContext base_finalize_context
;
210 public EmitContext instance_init_context
;
211 public EmitContext instance_finalize_context
;
213 public CCodeStruct param_spec_struct
;
214 public CCodeStruct closure_struct
;
215 public CCodeEnum prop_enum
;
217 public CCodeFunction ccode
{ get { return emit_context
.ccode
; } }
219 /* temporary variables that own their content */
220 public ArrayList
<LocalVariable
> temp_ref_vars
{ get { return emit_context
.temp_ref_vars
; } }
221 /* cache to check whether a certain marshaller has been created yet */
222 public Set
<string> user_marshal_set
;
223 /* (constant) hash table with all predefined marshallers */
224 public Set
<string> predefined_marshal_set
;
225 /* (constant) hash table with all reserved identifiers in the generated code */
226 Set
<string> reserved_identifiers
;
228 public int next_temp_var_id
{
229 get { return emit_context
.next_temp_var_id
; }
230 set { emit_context
.next_temp_var_id
= value
; }
233 public int next_regex_id
= 0;
234 public bool in_creation_method
{ get { return current_method is CreationMethod
; } }
235 public bool in_constructor
= false;
236 public bool in_static_or_class_context
= false;
238 public bool current_method_inner_error
{
239 get { return emit_context
.current_method_inner_error
; }
240 set { emit_context
.current_method_inner_error
= value
; }
243 public bool current_method_return
{
244 get { return emit_context
.current_method_return
; }
245 set { emit_context
.current_method_return
= value
; }
248 public int next_coroutine_state
= 1;
249 int next_block_id
= 0;
250 Map
<Block
,int> block_map
= new HashMap
<Block
,int> ();
252 public DataType void_type
= new
VoidType ();
253 public DataType bool_type
;
254 public DataType char_type
;
255 public DataType uchar_type
;
256 public DataType? unichar_type
;
257 public DataType short_type
;
258 public DataType ushort_type
;
259 public DataType int_type
;
260 public DataType uint_type
;
261 public DataType long_type
;
262 public DataType ulong_type
;
263 public DataType int8_type
;
264 public DataType uint8_type
;
265 public DataType int16_type
;
266 public DataType uint16_type
;
267 public DataType int32_type
;
268 public DataType uint32_type
;
269 public DataType int64_type
;
270 public DataType uint64_type
;
271 public DataType string_type
;
272 public DataType regex_type
;
273 public DataType float_type
;
274 public DataType double_type
;
275 public TypeSymbol gtype_type
;
276 public TypeSymbol gobject_type
;
277 public ErrorType gerror_type
;
278 public Class glist_type
;
279 public Class gslist_type
;
280 public Class gnode_type
;
281 public Class gvaluearray_type
;
282 public TypeSymbol gstringbuilder_type
;
283 public TypeSymbol garray_type
;
284 public TypeSymbol gbytearray_type
;
285 public TypeSymbol gptrarray_type
;
286 public TypeSymbol gthreadpool_type
;
287 public DataType gdestroynotify_type
;
288 public DataType gquark_type
;
289 public Struct gvalue_type
;
290 public Class gvariant_type
;
291 public Struct mutex_type
;
292 public TypeSymbol type_module_type
;
293 public TypeSymbol dbus_proxy_type
;
294 public TypeSymbol dbus_object_type
;
296 public bool in_plugin
= false;
297 public string module_init_param_name
;
299 public bool gvaluecollector_h_needed
;
300 public bool requires_array_free
;
301 public bool requires_array_move
;
302 public bool requires_array_length
;
304 public Set
<string> wrappers
;
305 Set
<Symbol
> generated_external_symbols
;
307 public Map
<string,string> variable_name_map
{ get { return emit_context
.variable_name_map
; } }
309 public CCodeBaseModule () {
310 predefined_marshal_set
= new HashSet
<string> (str_hash
, str_equal
);
311 predefined_marshal_set
.add ("VOID:VOID");
312 predefined_marshal_set
.add ("VOID:BOOLEAN");
313 predefined_marshal_set
.add ("VOID:CHAR");
314 predefined_marshal_set
.add ("VOID:UCHAR");
315 predefined_marshal_set
.add ("VOID:INT");
316 predefined_marshal_set
.add ("VOID:UINT");
317 predefined_marshal_set
.add ("VOID:LONG");
318 predefined_marshal_set
.add ("VOID:ULONG");
319 predefined_marshal_set
.add ("VOID:ENUM");
320 predefined_marshal_set
.add ("VOID:FLAGS");
321 predefined_marshal_set
.add ("VOID:FLOAT");
322 predefined_marshal_set
.add ("VOID:DOUBLE");
323 predefined_marshal_set
.add ("VOID:STRING");
324 predefined_marshal_set
.add ("VOID:POINTER");
325 predefined_marshal_set
.add ("VOID:OBJECT");
326 predefined_marshal_set
.add ("STRING:OBJECT,POINTER");
327 predefined_marshal_set
.add ("VOID:UINT,POINTER");
328 predefined_marshal_set
.add ("BOOLEAN:FLAGS");
330 reserved_identifiers
= new HashSet
<string> (str_hash
, str_equal
);
333 reserved_identifiers
.add ("_Bool");
334 reserved_identifiers
.add ("_Complex");
335 reserved_identifiers
.add ("_Imaginary");
336 reserved_identifiers
.add ("asm");
337 reserved_identifiers
.add ("auto");
338 reserved_identifiers
.add ("break");
339 reserved_identifiers
.add ("case");
340 reserved_identifiers
.add ("char");
341 reserved_identifiers
.add ("const");
342 reserved_identifiers
.add ("continue");
343 reserved_identifiers
.add ("default");
344 reserved_identifiers
.add ("do");
345 reserved_identifiers
.add ("double");
346 reserved_identifiers
.add ("else");
347 reserved_identifiers
.add ("enum");
348 reserved_identifiers
.add ("extern");
349 reserved_identifiers
.add ("float");
350 reserved_identifiers
.add ("for");
351 reserved_identifiers
.add ("goto");
352 reserved_identifiers
.add ("if");
353 reserved_identifiers
.add ("inline");
354 reserved_identifiers
.add ("int");
355 reserved_identifiers
.add ("long");
356 reserved_identifiers
.add ("register");
357 reserved_identifiers
.add ("restrict");
358 reserved_identifiers
.add ("return");
359 reserved_identifiers
.add ("short");
360 reserved_identifiers
.add ("signed");
361 reserved_identifiers
.add ("sizeof");
362 reserved_identifiers
.add ("static");
363 reserved_identifiers
.add ("struct");
364 reserved_identifiers
.add ("switch");
365 reserved_identifiers
.add ("typedef");
366 reserved_identifiers
.add ("union");
367 reserved_identifiers
.add ("unsigned");
368 reserved_identifiers
.add ("void");
369 reserved_identifiers
.add ("volatile");
370 reserved_identifiers
.add ("while");
373 reserved_identifiers
.add ("cdecl");
375 // reserved for Vala/GObject naming conventions
376 reserved_identifiers
.add ("error");
377 reserved_identifiers
.add ("result");
378 reserved_identifiers
.add ("self");
381 public override void emit (CodeContext context
) {
382 this
.context
= context
;
384 root_symbol
= context
.root
;
386 bool_type
= new
BooleanType ((Struct
) root_symbol
.scope
.lookup ("bool"));
387 char_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("char"));
388 uchar_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uchar"));
389 short_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("short"));
390 ushort_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ushort"));
391 int_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int"));
392 uint_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint"));
393 long_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("long"));
394 ulong_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ulong"));
395 int8_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int8"));
396 uint8_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint8"));
397 int16_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int16"));
398 uint16_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint16"));
399 int32_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int32"));
400 uint32_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint32"));
401 int64_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int64"));
402 uint64_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint64"));
403 float_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("float"));
404 double_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("double"));
405 string_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("string"));
406 var unichar_struct
= (Struct
) root_symbol
.scope
.lookup ("unichar");
407 if (unichar_struct
!= null) {
408 unichar_type
= new
IntegerType (unichar_struct
);
411 if (context
.profile
== Profile
.GOBJECT
) {
412 var glib_ns
= root_symbol
.scope
.lookup ("GLib");
414 gtype_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Type");
415 gobject_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Object");
416 gerror_type
= new
ErrorType (null, null);
417 glist_type
= (Class
) glib_ns
.scope
.lookup ("List");
418 gslist_type
= (Class
) glib_ns
.scope
.lookup ("SList");
419 gnode_type
= (Class
) glib_ns
.scope
.lookup ("Node");
420 gvaluearray_type
= (Class
) glib_ns
.scope
.lookup ("ValueArray");
421 gstringbuilder_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("StringBuilder");
422 garray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Array");
423 gbytearray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("ByteArray");
424 gptrarray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("PtrArray");
425 gthreadpool_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("ThreadPool");
426 gdestroynotify_type
= new
DelegateType ((Delegate
) glib_ns
.scope
.lookup ("DestroyNotify"));
428 gquark_type
= new
IntegerType ((Struct
) glib_ns
.scope
.lookup ("Quark"));
429 gvalue_type
= (Struct
) glib_ns
.scope
.lookup ("Value");
430 gvariant_type
= (Class
) glib_ns
.scope
.lookup ("Variant");
431 mutex_type
= (Struct
) glib_ns
.scope
.lookup ("StaticRecMutex");
433 type_module_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("TypeModule");
435 regex_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("GLib").scope
.lookup ("Regex"));
437 if (context
.module_init_method
!= null) {
438 foreach (Parameter parameter
in context
.module_init_method
.get_parameters ()) {
439 if (parameter
.variable_type
.data_type
== type_module_type
) {
441 module_init_param_name
= parameter
.name
;
446 Report
.error (context
.module_init_method
.source_reference
, "[ModuleInit] requires a parameter of type `GLib.TypeModule'");
450 dbus_proxy_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("DBusProxy");
452 var dbus_ns
= root_symbol
.scope
.lookup ("DBus");
453 if (dbus_ns
!= null) {
454 dbus_object_type
= (TypeSymbol
) dbus_ns
.scope
.lookup ("Object");
458 header_file
= new
CCodeFile ();
459 header_file
.is_header
= true;
460 internal_header_file
= new
CCodeFile ();
461 internal_header_file
.is_header
= true;
463 /* we're only interested in non-pkg source files */
464 var source_files
= context
.get_source_files ();
465 foreach (SourceFile file
in source_files
) {
466 if (file
.file_type
== SourceFileType
.SOURCE
||
467 (context
.header_filename
!= null && file
.file_type
== SourceFileType
.FAST
)) {
472 // generate symbols file for public API
473 if (context
.symbols_filename
!= null) {
474 var stream
= FileStream
.open (context
.symbols_filename
, "w");
475 if (stream
== null) {
476 Report
.error (null, "unable to open `%s' for writing".printf (context
.symbols_filename
));
480 foreach (string symbol
in header_file
.get_symbols ()) {
481 stream
.puts (symbol
);
488 // generate C header file for public API
489 if (context
.header_filename
!= null) {
491 if (context
.profile
== Profile
.GOBJECT
) {
492 ret
= header_file
.store (context
.header_filename
, null, context
.version_header
, false, "G_BEGIN_DECLS", "G_END_DECLS");
494 ret
= header_file
.store (context
.header_filename
, null, context
.version_header
, false);
497 Report
.error (null, "unable to open `%s' for writing".printf (context
.header_filename
));
501 // generate C header file for internal API
502 if (context
.internal_header_filename
!= null) {
504 if (context
.profile
== Profile
.GOBJECT
) {
505 ret
= internal_header_file
.store (context
.internal_header_filename
, null, context
.version_header
, false, "G_BEGIN_DECLS", "G_END_DECLS");
507 ret
= internal_header_file
.store (context
.internal_header_filename
, null, context
.version_header
, false);
510 Report
.error (null, "unable to open `%s' for writing".printf (context
.internal_header_filename
));
515 public void push_context (EmitContext emit_context
) {
516 if (this
.emit_context
!= null) {
517 emit_context_stack
.add (this
.emit_context
);
520 this
.emit_context
= emit_context
;
523 public void pop_context () {
524 if (emit_context_stack
.size
> 0) {
525 this
.emit_context
= emit_context_stack
[emit_context_stack
.size
- 1];
526 emit_context_stack
.remove_at (emit_context_stack
.size
- 1);
528 this
.emit_context
= null;
532 public void push_function (CCodeFunction func
) {
533 emit_context
.ccode_stack
.add (ccode
);
534 emit_context
.ccode
= func
;
537 public void pop_function () {
538 emit_context
.ccode
= emit_context
.ccode_stack
[emit_context
.ccode_stack
.size
- 1];
539 emit_context
.ccode_stack
.remove_at (emit_context
.ccode_stack
.size
- 1);
542 public bool add_symbol_declaration (CCodeFile decl_space
, Symbol sym
, string name
) {
543 if (decl_space
.add_declaration (name
)) {
546 if (sym
.source_reference
!= null) {
547 sym
.source_reference
.file
.used
= true;
549 if (sym
.external_package
|| (!decl_space
.is_header
&& CodeContext
.get ().use_header
&& !sym
.is_internal_symbol ())) {
550 // add appropriate include file
551 foreach (string header_filename
in sym
.get_cheader_filenames ()) {
552 decl_space
.add_include (header_filename
, !sym
.external_package
);
554 // declaration complete
557 // require declaration
562 public CCodeIdentifier
get_value_setter_function (DataType type_reference
) {
563 var array_type
= type_reference as ArrayType
;
564 if (type_reference
.data_type
!= null) {
565 return new
CCodeIdentifier (type_reference
.data_type
.get_set_value_function ());
566 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
568 return new
CCodeIdentifier ("g_value_set_boxed");
570 return new
CCodeIdentifier ("g_value_set_pointer");
574 public CCodeIdentifier
get_value_taker_function (DataType type_reference
) {
575 var array_type
= type_reference as ArrayType
;
576 if (type_reference
.data_type
!= null) {
577 return new
CCodeIdentifier (type_reference
.data_type
.get_take_value_function ());
578 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
580 return new
CCodeIdentifier ("g_value_take_boxed");
582 return new
CCodeIdentifier ("g_value_set_pointer");
586 CCodeIdentifier
get_value_getter_function (DataType type_reference
) {
587 var array_type
= type_reference as ArrayType
;
588 if (type_reference
.data_type
!= null) {
589 return new
CCodeIdentifier (type_reference
.data_type
.get_get_value_function ());
590 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
592 return new
CCodeIdentifier ("g_value_get_boxed");
594 return new
CCodeIdentifier ("g_value_get_pointer");
598 public virtual void append_vala_array_free () {
601 public virtual void append_vala_array_move () {
604 public virtual void append_vala_array_length () {
607 public override void visit_source_file (SourceFile source_file
) {
608 cfile
= new
CCodeFile ();
610 user_marshal_set
= new HashSet
<string> (str_hash
, str_equal
);
614 gvaluecollector_h_needed
= false;
615 requires_array_free
= false;
616 requires_array_move
= false;
617 requires_array_length
= false;
619 wrappers
= new HashSet
<string> (str_hash
, str_equal
);
620 generated_external_symbols
= new HashSet
<Symbol
> ();
622 if (context
.profile
== Profile
.GOBJECT
) {
623 header_file
.add_include ("glib.h");
624 internal_header_file
.add_include ("glib.h");
625 cfile
.add_include ("glib.h");
626 cfile
.add_include ("glib-object.h");
629 source_file
.accept_children (this
);
631 if (context
.report
.get_errors () > 0) {
635 /* For fast-vapi, we only wanted the header declarations
636 * to be emitted, so bail out here without writing the
639 if (source_file
.file_type
== SourceFileType
.FAST
) {
643 if (requires_array_free
) {
644 append_vala_array_free ();
646 if (requires_array_move
) {
647 append_vala_array_move ();
649 if (requires_array_length
) {
650 append_vala_array_length ();
653 if (gvaluecollector_h_needed
) {
654 cfile
.add_include ("gobject/gvaluecollector.h");
657 var comments
= source_file
.get_comments();
658 if (comments
!= null) {
659 foreach (Comment comment
in comments
) {
660 var ccomment
= new
CCodeComment (comment
.content
);
661 cfile
.add_comment (ccomment
);
665 if (!cfile
.store (source_file
.get_csource_filename (), source_file
.filename
, context
.version_header
, context
.debug
)) {
666 Report
.error (null, "unable to open `%s' for writing".printf (source_file
.get_csource_filename ()));
672 public virtual bool generate_enum_declaration (Enum en
, CCodeFile decl_space
) {
673 if (add_symbol_declaration (decl_space
, en
, en
.get_cname ())) {
677 var cenum
= new
CCodeEnum (en
.get_cname ());
679 cenum
.deprecated
= en
.deprecated
;
682 foreach (EnumValue ev
in en
.get_values ()) {
684 if (ev
.value
== null) {
685 c_ev
= new
CCodeEnumValue (ev
.get_cname ());
687 c_ev
.value
= new
CCodeConstant ("1 << %d".printf (flag_shift
));
691 ev
.value
.emit (this
);
692 c_ev
= new
CCodeEnumValue (ev
.get_cname (), get_cvalue (ev
.value
));
694 c_ev
.deprecated
= ev
.deprecated
;
695 cenum
.add_value (c_ev
);
698 decl_space
.add_type_definition (cenum
);
699 decl_space
.add_type_definition (new
CCodeNewline ());
701 if (!en
.has_type_id
) {
705 decl_space
.add_type_declaration (new
CCodeNewline ());
707 var macro
= "(%s_get_type ())".printf (en
.get_lower_case_cname (null));
708 decl_space
.add_type_declaration (new
CCodeMacroReplacement (en
.get_type_id (), macro
));
710 var fun_name
= "%s_get_type".printf (en
.get_lower_case_cname (null));
711 var regfun
= new
CCodeFunction (fun_name
, "GType");
712 regfun
.attributes
= "G_GNUC_CONST";
714 if (en
.access
== SymbolAccessibility
.PRIVATE
) {
715 regfun
.modifiers
= CCodeModifiers
.STATIC
;
716 // avoid C warning as this function is not always used
717 regfun
.attributes
= "G_GNUC_UNUSED";
720 decl_space
.add_function_declaration (regfun
);
725 public override void visit_enum (Enum en
) {
726 en
.accept_children (this
);
728 if (en
.comment
!= null) {
729 cfile
.add_type_member_definition (new
CCodeComment (en
.comment
.content
));
732 generate_enum_declaration (en
, cfile
);
734 if (!en
.is_internal_symbol ()) {
735 generate_enum_declaration (en
, header_file
);
737 if (!en
.is_private_symbol ()) {
738 generate_enum_declaration (en
, internal_header_file
);
742 public void visit_member (Symbol m
) {
743 /* stuff meant for all lockable members */
744 if (m is Lockable
&& ((Lockable
) m
).get_lock_used ()) {
745 CCodeExpression l
= new
CCodeIdentifier ("self");
746 var init_context
= class_init_context
;
747 var finalize_context
= class_finalize_context
;
749 if (m
.is_instance_member ()) {
750 l
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (l
, "priv"), get_symbol_lock_name (m
.name
));
751 init_context
= instance_init_context
;
752 finalize_context
= instance_finalize_context
;
753 } else if (m
.is_class_member ()) {
754 TypeSymbol parent
= (TypeSymbol
)m
.parent_symbol
;
756 var get_class_private_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent
.get_upper_case_cname ())));
757 get_class_private_call
.add_argument (new
CCodeIdentifier ("klass"));
758 l
= new CCodeMemberAccess
.pointer (get_class_private_call
, get_symbol_lock_name (m
.name
));
760 l
= new
CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf(m
.parent_symbol
.get_lower_case_cname (), m
.name
)));
763 push_context (init_context
);
764 var initf
= new
CCodeFunctionCall (new
CCodeIdentifier (mutex_type
.default_construction_method
.get_cname ()));
765 initf
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
766 ccode
.add_expression (initf
);
769 if (finalize_context
!= null) {
770 push_context (finalize_context
);
771 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_static_rec_mutex_free"));
772 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
773 ccode
.add_expression (fc
);
779 public void generate_constant_declaration (Constant c
, CCodeFile decl_space
, bool definition
= false) {
780 if (c
.parent_symbol is Block
) {
785 if (add_symbol_declaration (decl_space
, c
, c
.get_cname ())) {
790 generate_type_declaration (c
.type_reference
, decl_space
);
794 var initializer_list
= c
.value as InitializerList
;
795 if (initializer_list
!= null) {
796 var cdecl
= new
CCodeDeclaration (c
.type_reference
.get_const_cname ());
798 if (c
.type_reference is ArrayType
) {
799 arr
= "[%d]".printf (initializer_list
.size
);
802 var cinitializer
= get_cvalue (c
.value
);
804 // never output value in header
805 // special case needed as this method combines declaration and definition
809 cdecl
.add_declarator (new
CCodeVariableDeclarator ("%s%s".printf (c
.get_cname (), arr
), cinitializer
));
810 if (c
.is_private_symbol ()) {
811 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
813 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
816 decl_space
.add_constant_declaration (cdecl
);
818 var cdefine
= new CCodeMacroReplacement
.with_expression (c
.get_cname (), get_cvalue (c
.value
));
819 decl_space
.add_type_member_declaration (cdefine
);
824 public override void visit_constant (Constant c
) {
825 if (c
.parent_symbol is Block
) {
828 generate_type_declaration (c
.type_reference
, cfile
);
832 string type_name
= c
.type_reference
.get_const_cname ();
834 if (c
.type_reference is ArrayType
) {
838 if (c
.type_reference
.compatible (string_type
)) {
839 type_name
= "const char";
843 var cinitializer
= get_cvalue (c
.value
);
845 ccode
.add_declaration (type_name
, new
CCodeVariableDeclarator ("%s%s".printf (c
.get_cname (), arr
), cinitializer
), CCodeModifiers
.STATIC
);
850 generate_constant_declaration (c
, cfile
, true);
852 if (!c
.is_internal_symbol ()) {
853 generate_constant_declaration (c
, header_file
);
855 if (!c
.is_private_symbol ()) {
856 generate_constant_declaration (c
, internal_header_file
);
860 public void generate_field_declaration (Field f
, CCodeFile decl_space
) {
861 if (add_symbol_declaration (decl_space
, f
, f
.get_cname ())) {
865 generate_type_declaration (f
.variable_type
, decl_space
);
867 string field_ctype
= f
.variable_type
.get_cname ();
869 field_ctype
= "volatile " + field_ctype
;
872 var cdecl
= new
CCodeDeclaration (field_ctype
);
873 cdecl
.add_declarator (new
CCodeVariableDeclarator (f
.get_cname (), null, f
.variable_type
.get_cdeclarator_suffix ()));
874 if (f
.is_private_symbol ()) {
875 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
877 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
880 cdecl
.modifiers
|= CCodeModifiers
.DEPRECATED
;
882 decl_space
.add_type_member_declaration (cdecl
);
884 if (f
.get_lock_used ()) {
885 // Declare mutex for static member
886 var flock
= new
CCodeDeclaration (mutex_type
.get_cname ());
887 var flock_decl
= new
CCodeVariableDeclarator (get_symbol_lock_name (f
.get_cname ()), new
CCodeConstant ("{0}"));
888 flock
.add_declarator (flock_decl
);
890 if (f
.is_private_symbol ()) {
891 flock
.modifiers
= CCodeModifiers
.STATIC
;
893 flock
.modifiers
= CCodeModifiers
.EXTERN
;
895 decl_space
.add_type_member_declaration (flock
);
898 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
899 var array_type
= (ArrayType
) f
.variable_type
;
901 if (!array_type
.fixed_length
) {
902 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
903 var len_type
= int_type
.copy ();
905 cdecl
= new
CCodeDeclaration (len_type
.get_cname ());
906 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (f
.get_cname (), dim
)));
907 if (f
.is_private_symbol ()) {
908 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
910 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
912 decl_space
.add_type_member_declaration (cdecl
);
915 } else if (f
.variable_type is DelegateType
) {
916 var delegate_type
= (DelegateType
) f
.variable_type
;
917 if (delegate_type
.delegate_symbol
.has_target
) {
918 // create field to store delegate target
920 cdecl
= new
CCodeDeclaration ("gpointer");
921 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_cname (f
.get_cname ())));
922 if (f
.is_private_symbol ()) {
923 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
925 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
927 decl_space
.add_type_member_declaration (cdecl
);
929 if (delegate_type
.value_owned
) {
930 cdecl
= new
CCodeDeclaration ("GDestroyNotify");
931 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f
.get_cname ())));
932 if (f
.is_private_symbol ()) {
933 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
935 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
937 decl_space
.add_type_member_declaration (cdecl
);
943 public override void visit_field (Field f
) {
946 check_type (f
.variable_type
);
948 var cl
= f
.parent_symbol as Class
;
949 bool is_gtypeinstance
= (cl
!= null && !cl
.is_compact
);
951 CCodeExpression lhs
= null;
953 string field_ctype
= f
.variable_type
.get_cname ();
955 field_ctype
= "volatile " + field_ctype
;
958 if (f
.binding
== MemberBinding
.INSTANCE
) {
959 if (is_gtypeinstance
&& f
.access
== SymbolAccessibility
.PRIVATE
) {
960 lhs
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), f
.get_cname ());
962 lhs
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.get_cname ());
965 if (f
.initializer
!= null) {
966 push_context (instance_init_context
);
968 f
.initializer
.emit (this
);
970 var rhs
= get_cvalue (f
.initializer
);
972 ccode
.add_assignment (lhs
, rhs
);
974 if (f
.variable_type is ArrayType
&& !f
.no_array_length
&&
975 f
.initializer is ArrayCreationExpression
) {
976 var array_type
= (ArrayType
) f
.variable_type
;
977 var field_value
= get_field_cvalue (f
, load_this_parameter ((TypeSymbol
) f
.parent_symbol
));
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_cvalue (field_value
, 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 (field_value
);
988 var rhs_array_len
= get_array_length_cvalue (field_value
, 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
);
1004 ccode
.add_expression (destroy_field (f
, load_this_parameter ((TypeSymbol
) f
.parent_symbol
)));
1007 } else if (f
.binding
== MemberBinding
.CLASS
) {
1008 if (!is_gtypeinstance
) {
1009 Report
.error (f
.source_reference
, "class fields are not supported in compact classes");
1014 if (f
.access
== SymbolAccessibility
.PRIVATE
) {
1015 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (cl
.get_upper_case_cname ())));
1016 ccall
.add_argument (new
CCodeIdentifier ("klass"));
1017 lhs
= new
CCodeMemberAccess (ccall
, f
.get_cname (), true);
1019 lhs
= new
CCodeMemberAccess (new
CCodeIdentifier ("klass"), f
.get_cname (), true);
1022 if (f
.initializer
!= null) {
1023 push_context (class_init_context
);
1025 f
.initializer
.emit (this
);
1027 var rhs
= get_cvalue (f
.initializer
);
1029 ccode
.add_assignment (lhs
, rhs
);
1031 foreach (LocalVariable local
in temp_ref_vars
) {
1032 ccode
.add_expression (destroy_local (local
));
1035 temp_ref_vars
.clear ();
1040 generate_field_declaration (f
, cfile
);
1042 if (!f
.is_internal_symbol ()) {
1043 generate_field_declaration (f
, header_file
);
1045 if (!f
.is_private_symbol ()) {
1046 generate_field_declaration (f
, internal_header_file
);
1049 lhs
= new
CCodeIdentifier (f
.get_cname ());
1051 var var_decl
= new
CCodeVariableDeclarator (f
.get_cname (), null, f
.variable_type
.get_cdeclarator_suffix ());
1052 var_decl
.initializer
= default_value_for_type (f
.variable_type
, true);
1054 if (class_init_context
!= null) {
1055 push_context (class_init_context
);
1057 push_context (new
EmitContext ());
1060 if (f
.initializer
!= null) {
1061 f
.initializer
.emit (this
);
1063 var init
= get_cvalue (f
.initializer
);
1064 if (is_constant_ccode_expression (init
)) {
1065 var_decl
.initializer
= init
;
1069 var var_def
= new
CCodeDeclaration (field_ctype
);
1070 var_def
.add_declarator (var_decl
);
1071 if (!f
.is_private_symbol ()) {
1072 var_def
.modifiers
= CCodeModifiers
.EXTERN
;
1074 var_def
.modifiers
= CCodeModifiers
.STATIC
;
1076 cfile
.add_type_member_declaration (var_def
);
1078 /* add array length fields where necessary */
1079 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
1080 var array_type
= (ArrayType
) f
.variable_type
;
1082 if (!array_type
.fixed_length
) {
1083 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1084 var len_type
= int_type
.copy ();
1086 var len_def
= new
CCodeDeclaration (len_type
.get_cname ());
1087 len_def
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (f
.get_cname (), dim
), new
CCodeConstant ("0")));
1088 if (!f
.is_private_symbol ()) {
1089 len_def
.modifiers
= CCodeModifiers
.EXTERN
;
1091 len_def
.modifiers
= CCodeModifiers
.STATIC
;
1093 cfile
.add_type_member_declaration (len_def
);
1096 if (array_type
.rank
== 1 && f
.is_internal_symbol ()) {
1097 var len_type
= int_type
.copy ();
1099 var cdecl
= new
CCodeDeclaration (len_type
.get_cname ());
1100 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_size_cname (f
.get_cname ()), new
CCodeConstant ("0")));
1101 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
1102 cfile
.add_type_member_declaration (cdecl
);
1105 } else if (f
.variable_type is DelegateType
) {
1106 var delegate_type
= (DelegateType
) f
.variable_type
;
1107 if (delegate_type
.delegate_symbol
.has_target
) {
1108 // create field to store delegate target
1110 var target_def
= new
CCodeDeclaration ("gpointer");
1111 target_def
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_cname (f
.get_cname ()), new
CCodeConstant ("NULL")));
1112 if (!f
.is_private_symbol ()) {
1113 target_def
.modifiers
= CCodeModifiers
.EXTERN
;
1115 target_def
.modifiers
= CCodeModifiers
.STATIC
;
1117 cfile
.add_type_member_declaration (target_def
);
1119 if (delegate_type
.value_owned
) {
1120 var target_destroy_notify_def
= new
CCodeDeclaration ("GDestroyNotify");
1121 target_destroy_notify_def
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f
.get_cname ()), new
CCodeConstant ("NULL")));
1122 if (!f
.is_private_symbol ()) {
1123 target_destroy_notify_def
.modifiers
= CCodeModifiers
.EXTERN
;
1125 target_destroy_notify_def
.modifiers
= CCodeModifiers
.STATIC
;
1127 cfile
.add_type_member_declaration (target_destroy_notify_def
);
1133 if (f
.initializer
!= null) {
1134 var rhs
= get_cvalue (f
.initializer
);
1135 if (!is_constant_ccode_expression (rhs
)) {
1136 if (f
.parent_symbol is Class
) {
1137 if (f
.initializer is InitializerList
) {
1138 ccode
.open_block ();
1140 var temp_decl
= get_temp_variable (f
.variable_type
);
1141 var vardecl
= new CCodeVariableDeclarator
.zero (temp_decl
.name
, rhs
);
1142 ccode
.add_declaration (temp_decl
.variable_type
.get_cname (), vardecl
);
1144 var tmp
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
1145 ccode
.add_assignment (lhs
, tmp
);
1149 ccode
.add_assignment (lhs
, rhs
);
1152 if (f
.variable_type is ArrayType
&& !f
.no_array_length
&&
1153 f
.initializer is ArrayCreationExpression
) {
1154 var array_type
= (ArrayType
) f
.variable_type
;
1155 var ma
= new MemberAccess
.simple (f
.name
);
1156 ma
.symbol_reference
= f
;
1157 ma
.value_type
= f
.variable_type
.copy ();
1158 visit_member_access (ma
);
1160 List
<Expression
> sizes
= ((ArrayCreationExpression
) f
.initializer
).get_sizes ();
1161 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1162 var array_len_lhs
= get_array_length_cexpression (ma
, dim
);
1163 var size
= sizes
[dim
- 1];
1164 ccode
.add_assignment (array_len_lhs
, get_cvalue (size
));
1169 Report
.error (f
.source_reference
, "Non-constant field initializers not supported in this context");
1179 public bool is_constant_ccode_expression (CCodeExpression cexpr
) {
1180 if (cexpr is CCodeConstant
) {
1182 } else if (cexpr is CCodeCastExpression
) {
1183 var ccast
= (CCodeCastExpression
) cexpr
;
1184 return is_constant_ccode_expression (ccast
.inner
);
1185 } else if (cexpr is CCodeBinaryExpression
) {
1186 var cbinary
= (CCodeBinaryExpression
) cexpr
;
1187 return is_constant_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
1190 var cparenthesized
= (cexpr as CCodeParenthesizedExpression
);
1191 return (null != cparenthesized
&& is_constant_ccode_expression (cparenthesized
.inner
));
1195 * Returns whether the passed cexpr is a pure expression, i.e. an
1196 * expression without side-effects.
1198 public bool is_pure_ccode_expression (CCodeExpression cexpr
) {
1199 if (cexpr is CCodeConstant
|| cexpr is CCodeIdentifier
) {
1201 } else if (cexpr is CCodeBinaryExpression
) {
1202 var cbinary
= (CCodeBinaryExpression
) cexpr
;
1203 return is_pure_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
1204 } else if (cexpr is CCodeUnaryExpression
) {
1205 var cunary
= (CCodeUnaryExpression
) cexpr
;
1206 switch (cunary
.operator
) {
1207 case CCodeUnaryOperator
.PREFIX_INCREMENT
:
1208 case CCodeUnaryOperator
.PREFIX_DECREMENT
:
1209 case CCodeUnaryOperator
.POSTFIX_INCREMENT
:
1210 case CCodeUnaryOperator
.POSTFIX_DECREMENT
:
1213 return is_pure_ccode_expression (cunary
.inner
);
1215 } else if (cexpr is CCodeMemberAccess
) {
1216 var cma
= (CCodeMemberAccess
) cexpr
;
1217 return is_pure_ccode_expression (cma
.inner
);
1218 } else if (cexpr is CCodeElementAccess
) {
1219 var cea
= (CCodeElementAccess
) cexpr
;
1220 return is_pure_ccode_expression (cea
.container
) && is_pure_ccode_expression (cea
.index
);
1221 } else if (cexpr is CCodeCastExpression
) {
1222 var ccast
= (CCodeCastExpression
) cexpr
;
1223 return is_pure_ccode_expression (ccast
.inner
);
1224 } else if (cexpr is CCodeParenthesizedExpression
) {
1225 var cparenthesized
= (CCodeParenthesizedExpression
) cexpr
;
1226 return is_pure_ccode_expression (cparenthesized
.inner
);
1232 public override void visit_formal_parameter (Parameter p
) {
1234 check_type (p
.variable_type
);
1238 public override void visit_property (Property prop
) {
1239 visit_member (prop
);
1241 check_type (prop
.property_type
);
1243 if (prop
.get_accessor
!= null) {
1244 prop
.get_accessor
.accept (this
);
1246 if (prop
.set_accessor
!= null) {
1247 prop
.set_accessor
.accept (this
);
1251 public void generate_type_declaration (DataType type
, CCodeFile decl_space
) {
1252 if (type is ObjectType
) {
1253 var object_type
= (ObjectType
) type
;
1254 if (object_type
.type_symbol is Class
) {
1255 generate_class_declaration ((Class
) object_type
.type_symbol
, decl_space
);
1256 } else if (object_type
.type_symbol is Interface
) {
1257 generate_interface_declaration ((Interface
) object_type
.type_symbol
, decl_space
);
1259 } else if (type is DelegateType
) {
1260 var deleg_type
= (DelegateType
) type
;
1261 var d
= deleg_type
.delegate_symbol
;
1262 generate_delegate_declaration (d
, decl_space
);
1263 } else if (type
.data_type is Enum
) {
1264 var en
= (Enum
) type
.data_type
;
1265 generate_enum_declaration (en
, decl_space
);
1266 } else if (type is ValueType
) {
1267 var value_type
= (ValueType
) type
;
1268 generate_struct_declaration ((Struct
) value_type
.type_symbol
, decl_space
);
1269 } else if (type is ArrayType
) {
1270 var array_type
= (ArrayType
) type
;
1271 generate_type_declaration (array_type
.element_type
, decl_space
);
1272 } else if (type is ErrorType
) {
1273 var error_type
= (ErrorType
) type
;
1274 if (error_type
.error_domain
!= null) {
1275 generate_error_domain_declaration (error_type
.error_domain
, decl_space
);
1277 } else if (type is PointerType
) {
1278 var pointer_type
= (PointerType
) type
;
1279 generate_type_declaration (pointer_type
.base_type
, decl_space
);
1282 foreach (DataType type_arg
in type
.get_type_arguments ()) {
1283 generate_type_declaration (type_arg
, decl_space
);
1287 public virtual void generate_class_struct_declaration (Class cl
, CCodeFile decl_space
) {
1290 public virtual void generate_struct_declaration (Struct st
, CCodeFile decl_space
) {
1293 public virtual void generate_delegate_declaration (Delegate d
, CCodeFile decl_space
) {
1296 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) {
1299 public void generate_property_accessor_declaration (PropertyAccessor acc
, CCodeFile decl_space
) {
1300 if (add_symbol_declaration (decl_space
, acc
, acc
.get_cname ())) {
1304 var prop
= (Property
) acc
.prop
;
1306 bool returns_real_struct
= acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ();
1309 CCodeParameter cvalueparam
;
1310 if (returns_real_struct
) {
1311 cvalueparam
= new
CCodeParameter ("result", acc
.value_type
.get_cname () + "*");
1312 } else if (!acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ()) {
1313 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname () + "*");
1315 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname ());
1317 generate_type_declaration (acc
.value_type
, decl_space
);
1319 CCodeFunction function
;
1320 if (acc
.readable
&& !returns_real_struct
) {
1321 function
= new
CCodeFunction (acc
.get_cname (), acc
.value_type
.get_cname ());
1323 function
= new
CCodeFunction (acc
.get_cname (), "void");
1326 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1327 var t
= (TypeSymbol
) prop
.parent_symbol
;
1328 var this_type
= get_data_type_for_symbol (t
);
1329 generate_type_declaration (this_type
, decl_space
);
1330 var cselfparam
= new
CCodeParameter ("self", this_type
.get_cname ());
1332 cselfparam
.type_name
+= "*";
1335 function
.add_parameter (cselfparam
);
1338 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1339 function
.add_parameter (cvalueparam
);
1342 if (acc
.value_type is ArrayType
) {
1343 var array_type
= (ArrayType
) acc
.value_type
;
1345 var length_ctype
= "int";
1347 length_ctype
= "int*";
1350 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1351 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1353 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1354 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1357 if (prop
.is_private_symbol () || (!acc
.readable
&& !acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1358 function
.modifiers
|= CCodeModifiers
.STATIC
;
1360 decl_space
.add_function_declaration (function
);
1363 public override void visit_property_accessor (PropertyAccessor acc
) {
1364 push_context (new
EmitContext (acc
));
1366 var prop
= (Property
) acc
.prop
;
1368 if (acc
.comment
!= null) {
1369 cfile
.add_type_member_definition (new
CCodeComment (acc
.comment
.content
));
1372 bool returns_real_struct
= acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ();
1374 if (acc
.result_var
!= null) {
1375 acc
.result_var
.accept (this
);
1378 var t
= (TypeSymbol
) prop
.parent_symbol
;
1380 if (acc
.construction
&& !t
.is_subtype_of (gobject_type
)) {
1381 Report
.error (acc
.source_reference
, "construct properties require GLib.Object");
1384 } else if (acc
.construction
&& !is_gobject_property (prop
)) {
1385 Report
.error (acc
.source_reference
, "construct properties not supported for specified property type");
1390 // do not declare overriding properties and interface implementations
1391 if (prop
.is_abstract
|| prop
.is_virtual
1392 || (prop
.base_property
== null && prop
.base_interface_property
== null)) {
1393 generate_property_accessor_declaration (acc
, cfile
);
1395 // do not declare construct-only properties in header files
1396 if (acc
.readable
|| acc
.writable
) {
1397 if (!prop
.is_internal_symbol ()
1398 && (acc
.access
== SymbolAccessibility
.PUBLIC
1399 || acc
.access
== SymbolAccessibility
.PROTECTED
)) {
1400 generate_property_accessor_declaration (acc
, header_file
);
1402 if (!prop
.is_private_symbol () && acc
.access
!= SymbolAccessibility
.PRIVATE
) {
1403 generate_property_accessor_declaration (acc
, internal_header_file
);
1408 if (acc
.source_type
== SourceFileType
.FAST
) {
1412 var this_type
= get_data_type_for_symbol (t
);
1413 var cselfparam
= new
CCodeParameter ("self", this_type
.get_cname ());
1415 cselfparam
.type_name
+= "*";
1417 CCodeParameter cvalueparam
;
1418 if (returns_real_struct
) {
1419 cvalueparam
= new
CCodeParameter ("result", acc
.value_type
.get_cname () + "*");
1420 } else if (!acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ()) {
1421 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname () + "*");
1423 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname ());
1426 if (prop
.is_abstract
|| prop
.is_virtual
) {
1427 CCodeFunction function
;
1428 if (acc
.readable
&& !returns_real_struct
) {
1429 function
= new
CCodeFunction (acc
.get_cname (), current_return_type
.get_cname ());
1431 function
= new
CCodeFunction (acc
.get_cname (), "void");
1433 function
.add_parameter (cselfparam
);
1434 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1435 function
.add_parameter (cvalueparam
);
1438 if (acc
.value_type is ArrayType
) {
1439 var array_type
= (ArrayType
) acc
.value_type
;
1441 var length_ctype
= "int";
1443 length_ctype
= "int*";
1446 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1447 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1449 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1450 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1453 if (prop
.is_private_symbol () || !(acc
.readable
|| acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1454 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1455 function
.modifiers
|= CCodeModifiers
.STATIC
;
1458 push_function (function
);
1460 CCodeFunctionCall vcast
= null;
1461 if (prop
.parent_symbol is Interface
) {
1462 var iface
= (Interface
) prop
.parent_symbol
;
1464 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (iface
.get_upper_case_cname (null))));
1466 var cl
= (Class
) prop
.parent_symbol
;
1468 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (cl
.get_upper_case_cname (null))));
1470 vcast
.add_argument (new
CCodeIdentifier ("self"));
1473 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "get_%s".printf (prop
.name
)));
1474 vcall
.add_argument (new
CCodeIdentifier ("self"));
1475 if (returns_real_struct
) {
1476 vcall
.add_argument (new
CCodeIdentifier ("result"));
1477 ccode
.add_expression (vcall
);
1479 if (acc
.value_type is ArrayType
) {
1480 var array_type
= (ArrayType
) acc
.value_type
;
1482 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1483 var len_expr
= new
CCodeIdentifier (get_array_length_cname ("result", dim
));
1484 vcall
.add_argument (len_expr
);
1486 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1487 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_cname ("result")));
1490 ccode
.add_return (vcall
);
1493 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "set_%s".printf (prop
.name
)));
1494 vcall
.add_argument (new
CCodeIdentifier ("self"));
1495 vcall
.add_argument (new
CCodeIdentifier ("value"));
1497 if (acc
.value_type is ArrayType
) {
1498 var array_type
= (ArrayType
) acc
.value_type
;
1500 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1501 var len_expr
= new
CCodeIdentifier (get_array_length_cname ("value", dim
));
1502 vcall
.add_argument (len_expr
);
1504 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1505 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_cname ("value")));
1508 ccode
.add_expression (vcall
);
1513 cfile
.add_function (function
);
1516 if (!prop
.is_abstract
) {
1517 bool is_virtual
= prop
.base_property
!= null || prop
.base_interface_property
!= null;
1522 cname
= "%s_real_get_%s".printf (t
.get_lower_case_cname (null), prop
.name
);
1524 cname
= "%s_real_set_%s".printf (t
.get_lower_case_cname (null), prop
.name
);
1527 cname
= acc
.get_cname ();
1530 CCodeFunction function
;
1531 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1532 function
= new
CCodeFunction (cname
, "void");
1534 function
= new
CCodeFunction (cname
, acc
.value_type
.get_cname ());
1537 ObjectType base_type
= null;
1538 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1540 if (prop
.base_property
!= null) {
1541 base_type
= new
ObjectType ((ObjectTypeSymbol
) prop
.base_property
.parent_symbol
);
1542 } else if (prop
.base_interface_property
!= null) {
1543 base_type
= new
ObjectType ((ObjectTypeSymbol
) prop
.base_interface_property
.parent_symbol
);
1545 function
.modifiers
|= CCodeModifiers
.STATIC
;
1546 function
.add_parameter (new
CCodeParameter ("base", base_type
.get_cname ()));
1548 function
.add_parameter (cselfparam
);
1551 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1552 function
.add_parameter (cvalueparam
);
1555 if (acc
.value_type is ArrayType
) {
1556 var array_type
= (ArrayType
) acc
.value_type
;
1558 var length_ctype
= "int";
1560 length_ctype
= "int*";
1563 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1564 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1566 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1567 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1571 if (prop
.is_private_symbol () || !(acc
.readable
|| acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1572 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1573 function
.modifiers
|= CCodeModifiers
.STATIC
;
1577 push_function (function
);
1579 if (prop
.binding
== MemberBinding
.INSTANCE
&& !is_virtual
) {
1580 if (!acc
.readable
|| returns_real_struct
) {
1581 create_property_type_check_statement (prop
, false, t
, true, "self");
1583 create_property_type_check_statement (prop
, true, t
, true, "self");
1587 if (acc
.readable
&& !returns_real_struct
) {
1588 // do not declare result variable if exit block is known to be unreachable
1589 if (acc
.return_block
== null || acc
.return_block
.get_predecessors ().size
> 0) {
1590 ccode
.add_declaration (acc
.value_type
.get_cname (), new
CCodeVariableDeclarator ("result"));
1595 ccode
.add_declaration (this_type
.get_cname (), new
CCodeVariableDeclarator ("self"));
1596 ccode
.add_assignment (new
CCodeIdentifier ("self"), transform_expression (new
CCodeIdentifier ("base"), base_type
, this_type
));
1599 acc
.body
.emit (this
);
1601 if (current_method_inner_error
) {
1602 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
1605 // notify on property changes
1606 if (is_gobject_property (prop
) &&
1608 (acc
.writable
|| acc
.construction
)) {
1609 var notify_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_notify"));
1610 notify_call
.add_argument (new
CCodeCastExpression (new
CCodeIdentifier ("self"), "GObject *"));
1611 notify_call
.add_argument (prop
.get_canonical_cconstant ());
1612 ccode
.add_expression (notify_call
);
1615 cfile
.add_function (function
);
1621 public override void visit_destructor (Destructor d
) {
1622 if (d
.binding
== MemberBinding
.STATIC
&& !in_plugin
) {
1623 Report
.error (d
.source_reference
, "static destructors are only supported for dynamic types");
1629 public int get_block_id (Block b
) {
1630 int result
= block_map
[b
];
1632 result
= ++next_block_id
;
1633 block_map
[b
] = result
;
1638 void capture_parameter (Parameter param
, CCodeStruct data
, int block_id
) {
1639 generate_type_declaration (param
.variable_type
, cfile
);
1641 var param_type
= param
.variable_type
.copy ();
1642 param_type
.value_owned
= true;
1643 data
.add_field (param_type
.get_cname (), get_variable_cname (param
.name
));
1645 bool is_unowned_delegate
= param
.variable_type is DelegateType
&& !param
.variable_type
.value_owned
;
1647 // create copy if necessary as captured variables may need to be kept alive
1648 CCodeExpression cparam
= get_variable_cexpression (param
.name
);
1649 if (param
.variable_type
.is_real_non_null_struct_type ()) {
1650 cparam
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cparam
);
1652 if (requires_copy (param_type
) && !param
.variable_type
.value_owned
&& !is_unowned_delegate
) {
1653 var ma
= new MemberAccess
.simple (param
.name
);
1654 ma
.symbol_reference
= param
;
1655 ma
.value_type
= param
.variable_type
.copy ();
1656 // directly access parameters in ref expressions
1657 param
.captured
= false;
1658 visit_member_access (ma
);
1659 cparam
= get_ref_cexpression (param
.variable_type
, cparam
, ma
, param
);
1660 param
.captured
= true;
1663 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_variable_cname (param
.name
)), cparam
);
1665 if (param
.variable_type is ArrayType
) {
1666 var array_type
= (ArrayType
) param
.variable_type
;
1667 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1668 data
.add_field ("gint", get_parameter_array_length_cname (param
, dim
));
1669 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
)));
1671 } else if (param
.variable_type is DelegateType
) {
1672 CCodeExpression target_expr
;
1673 CCodeExpression delegate_target_destroy_notify
;
1674 if (is_in_coroutine ()) {
1675 target_expr
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_delegate_target_cname (get_variable_cname (param
.name
)));
1676 delegate_target_destroy_notify
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1678 target_expr
= new
CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param
.name
)));
1679 delegate_target_destroy_notify
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1682 data
.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (param
.name
)));
1683 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
);
1684 if (param
.variable_type
.value_owned
) {
1685 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1686 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
);
1691 public override void visit_block (Block b
) {
1692 emit_context
.push_symbol (b
);
1694 var local_vars
= b
.get_local_variables ();
1696 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
) {
1697 ccode
.open_block ();
1701 var parent_block
= next_closure_block (b
.parent_symbol
);
1703 int block_id
= get_block_id (b
);
1704 string struct_name
= "Block%dData".printf (block_id
);
1706 var data
= new
CCodeStruct ("_" + struct_name
);
1707 data
.add_field ("int", "_ref_count_");
1708 if (parent_block
!= null) {
1709 int parent_block_id
= get_block_id (parent_block
);
1711 data
.add_field ("Block%dData *".printf (parent_block_id
), "_data%d_".printf (parent_block_id
));
1713 if (in_constructor
|| (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) ||
1714 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
1715 data
.add_field ("%s *".printf (current_class
.get_cname ()), "self");
1718 if (current_method
!= null) {
1719 // allow capturing generic type parameters
1720 foreach (var type_param
in current_method
.get_type_parameters ()) {
1723 func_name
= "%s_type".printf (type_param
.name
.down ());
1724 data
.add_field ("GType", func_name
);
1726 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
1727 data
.add_field ("GBoxedCopyFunc", func_name
);
1729 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
1730 data
.add_field ("GDestroyNotify", func_name
);
1734 foreach (var local
in local_vars
) {
1735 if (local
.captured
) {
1736 generate_type_declaration (local
.variable_type
, cfile
);
1738 data
.add_field (local
.variable_type
.get_cname (), get_variable_cname (local
.name
) + local
.variable_type
.get_cdeclarator_suffix ());
1740 if (local
.variable_type is ArrayType
) {
1741 var array_type
= (ArrayType
) local
.variable_type
;
1742 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1743 data
.add_field ("gint", get_array_length_cname (get_variable_cname (local
.name
), dim
));
1745 data
.add_field ("gint", get_array_size_cname (get_variable_cname (local
.name
)));
1746 } else if (local
.variable_type is DelegateType
) {
1747 data
.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (local
.name
)));
1748 if (local
.variable_type
.value_owned
) {
1749 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (local
.name
)));
1755 var data_alloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
1756 data_alloc
.add_argument (new
CCodeIdentifier (struct_name
));
1758 if (is_in_coroutine ()) {
1759 closure_struct
.add_field (struct_name
+ "*", "_data%d_".printf (block_id
));
1761 ccode
.add_declaration (struct_name
+ "*", new
CCodeVariableDeclarator ("_data%d_".printf (block_id
)));
1763 ccode
.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id
)), data_alloc
);
1765 // initialize ref_count
1766 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_ref_count_"), new
CCodeIdentifier ("1"));
1768 if (parent_block
!= null) {
1769 int parent_block_id
= get_block_id (parent_block
);
1771 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (parent_block_id
)));
1772 ref_call
.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id
)));
1774 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)), ref_call
);
1776 if (in_constructor
|| (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
&&
1777 (!(current_method is CreationMethod
) || current_method
.body
!= b
)) ||
1778 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
1779 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (new
ObjectType (current_class
), b
.source_reference
));
1780 ref_call
.add_argument (get_result_cexpression ("self"));
1782 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "self"), ref_call
);
1785 if (current_method
!= null) {
1786 // allow capturing generic type parameters
1787 foreach (var type_param
in current_method
.get_type_parameters ()) {
1790 func_name
= "%s_type".printf (type_param
.name
.down ());
1791 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
));
1793 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
1794 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
));
1796 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
1797 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
));
1802 if (b
.parent_symbol is Method
) {
1803 var m
= (Method
) b
.parent_symbol
;
1805 // parameters are captured with the top-level block of the method
1806 foreach (var param
in m
.get_parameters ()) {
1807 if (param
.captured
) {
1808 capture_parameter (param
, data
, block_id
);
1813 // capture async data to allow invoking callback from inside closure
1814 data
.add_field ("gpointer", "_async_data_");
1816 // async method is suspended while waiting for callback,
1817 // so we never need to care about memory management of async data
1818 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_async_data_"), new
CCodeIdentifier ("data"));
1820 } else if (b
.parent_symbol is PropertyAccessor
) {
1821 var acc
= (PropertyAccessor
) b
.parent_symbol
;
1823 if (!acc
.readable
&& acc
.value_parameter
.captured
) {
1824 capture_parameter (acc
.value_parameter
, data
, block_id
);
1828 var typedef
= new
CCodeTypeDefinition ("struct _" + struct_name
, new
CCodeVariableDeclarator (struct_name
));
1829 cfile
.add_type_declaration (typedef
);
1830 cfile
.add_type_definition (data
);
1832 // create ref/unref functions
1833 var ref_fun
= new
CCodeFunction ("block%d_data_ref".printf (block_id
), struct_name
+ "*");
1834 ref_fun
.add_parameter (new
CCodeParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
1835 ref_fun
.modifiers
= CCodeModifiers
.STATIC
;
1836 cfile
.add_function_declaration (ref_fun
);
1837 ref_fun
.block
= new
CCodeBlock ();
1839 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_atomic_int_inc"));
1840 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_ref_count_")));
1841 ref_fun
.block
.add_statement (new
CCodeExpressionStatement (ccall
));
1842 ref_fun
.block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("_data%d_".printf (block_id
))));
1843 cfile
.add_function (ref_fun
);
1845 var unref_fun
= new
CCodeFunction ("block%d_data_unref".printf (block_id
), "void");
1846 unref_fun
.add_parameter (new
CCodeParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
1847 unref_fun
.modifiers
= CCodeModifiers
.STATIC
;
1848 cfile
.add_function_declaration (unref_fun
);
1850 push_function (unref_fun
);
1852 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_atomic_int_dec_and_test"));
1853 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_ref_count_")));
1854 ccode
.open_if (ccall
);
1856 if (parent_block
!= null) {
1857 int parent_block_id
= get_block_id (parent_block
);
1859 var unref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (parent_block_id
)));
1860 unref_call
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)));
1861 ccode
.add_expression (unref_call
);
1862 ccode
.add_assignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)), new
CCodeConstant ("NULL"));
1864 if (in_constructor
|| (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) ||
1865 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
1866 var ma
= new MemberAccess
.simple ("this");
1867 ma
.symbol_reference
= current_class
;
1868 ccode
.add_expression (get_unref_expression (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "self"), new
ObjectType (current_class
), ma
));
1872 // free in reverse order
1873 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1874 var local
= local_vars
[i
];
1875 if (local
.captured
) {
1876 if (requires_destroy (local
.variable_type
)) {
1877 bool old_coroutine
= false;
1878 if (current_method
!= null) {
1879 old_coroutine
= current_method
.coroutine
;
1880 current_method
.coroutine
= false;
1883 ccode
.add_expression (destroy_local (local
));
1885 if (old_coroutine
) {
1886 current_method
.coroutine
= true;
1892 if (b
.parent_symbol is Method
) {
1893 var m
= (Method
) b
.parent_symbol
;
1895 // parameters are captured with the top-level block of the method
1896 foreach (var param
in m
.get_parameters ()) {
1897 if (param
.captured
) {
1898 var param_type
= param
.variable_type
.copy ();
1899 param_type
.value_owned
= true;
1901 bool is_unowned_delegate
= param
.variable_type is DelegateType
&& !param
.variable_type
.value_owned
;
1903 if (requires_destroy (param_type
) && !is_unowned_delegate
) {
1904 bool old_coroutine
= false;
1906 old_coroutine
= m
.coroutine
;
1907 m
.coroutine
= false;
1910 ccode
.add_expression (destroy_parameter (param
));
1912 if (old_coroutine
) {
1918 } else if (b
.parent_symbol is PropertyAccessor
) {
1919 var acc
= (PropertyAccessor
) b
.parent_symbol
;
1921 if (!acc
.readable
&& acc
.value_parameter
.captured
) {
1922 var param_type
= acc
.value_parameter
.variable_type
.copy ();
1923 param_type
.value_owned
= true;
1925 bool is_unowned_delegate
= acc
.value_parameter
.variable_type is DelegateType
&& !acc
.value_parameter
.variable_type
.value_owned
;
1927 if (requires_destroy (param_type
) && !is_unowned_delegate
) {
1928 ccode
.add_expression (destroy_parameter (acc
.value_parameter
));
1933 var data_free
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_free"));
1934 data_free
.add_argument (new
CCodeIdentifier (struct_name
));
1935 data_free
.add_argument (new
CCodeIdentifier ("_data%d_".printf (block_id
)));
1936 ccode
.add_expression (data_free
);
1942 cfile
.add_function (unref_fun
);
1945 foreach (Statement stmt
in b
.get_statements ()) {
1949 // free in reverse order
1950 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1951 var local
= local_vars
[i
];
1952 local
.active
= false;
1953 if (!local
.unreachable
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
1954 ccode
.add_expression (destroy_local (local
));
1958 if (b
.parent_symbol is Method
) {
1959 var m
= (Method
) b
.parent_symbol
;
1960 foreach (Parameter param
in m
.get_parameters ()) {
1961 if (!param
.captured
&& !param
.ellipsis
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
1962 ccode
.add_expression (destroy_parameter (param
));
1963 } else if (param
.direction
== ParameterDirection
.OUT
&& !m
.coroutine
) {
1964 return_out_parameter (param
);
1970 int block_id
= get_block_id (b
);
1972 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
1973 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
1974 ccode
.add_expression (data_unref
);
1975 ccode
.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id
)), new
CCodeConstant ("NULL"));
1978 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
) {
1982 emit_context
.pop_symbol ();
1985 public override void visit_declaration_statement (DeclarationStatement stmt
) {
1986 stmt
.declaration
.accept (this
);
1989 public CCodeExpression
get_variable_cexpression (string name
) {
1990 if (is_in_coroutine ()) {
1991 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_variable_cname (name
));
1993 return new
CCodeIdentifier (get_variable_cname (name
));
1997 public string get_variable_cname (string name
) {
1998 if (name
[0] == '.') {
1999 if (name
== ".result") {
2002 // compiler-internal variable
2003 if (!variable_name_map
.contains (name
)) {
2004 variable_name_map
.set (name
, "_tmp%d_".printf (next_temp_var_id
));
2007 return variable_name_map
.get (name
);
2008 } else if (reserved_identifiers
.contains (name
)) {
2009 return "_%s_".printf (name
);
2015 public CCodeExpression
get_result_cexpression (string cname
= "result") {
2016 if (is_in_coroutine ()) {
2017 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), cname
);
2019 return new
CCodeIdentifier (cname
);
2023 bool has_simple_struct_initializer (LocalVariable local
) {
2024 var st
= local
.variable_type
.data_type as Struct
;
2025 var initializer
= local
.initializer as ObjectCreationExpression
;
2026 if (st
!= null && (!st
.is_simple_type () || st
.get_cname () == "va_list") && !local
.variable_type
.nullable
&&
2027 initializer
!= null && initializer
.get_object_initializer ().size
== 0) {
2034 public override void visit_local_variable (LocalVariable local
) {
2035 check_type (local
.variable_type
);
2037 if (local
.initializer
!= null) {
2038 local
.initializer
.emit (this
);
2040 visit_end_full_expression (local
.initializer
);
2043 generate_type_declaration (local
.variable_type
, cfile
);
2045 CCodeExpression rhs
= null;
2046 if (local
.initializer
!= null && get_cvalue (local
.initializer
) != null) {
2047 rhs
= get_cvalue (local
.initializer
);
2050 if (!local
.captured
) {
2051 if (current_method
!= null && current_method
.coroutine
) {
2052 closure_struct
.add_field (local
.variable_type
.get_cname (), get_variable_cname (local
.name
) + local
.variable_type
.get_cdeclarator_suffix ());
2054 var cvar
= new
CCodeVariableDeclarator (get_variable_cname (local
.name
), null, local
.variable_type
.get_cdeclarator_suffix ());
2056 // try to initialize uninitialized variables
2057 // initialization not necessary for variables stored in closure
2058 if (rhs
== null || has_simple_struct_initializer (local
)) {
2059 cvar
.initializer
= default_value_for_type (local
.variable_type
, true);
2063 ccode
.add_declaration (local
.variable_type
.get_cname (), cvar
);
2066 if (local
.variable_type is ArrayType
) {
2067 // create variables to store array dimensions
2068 var array_type
= (ArrayType
) local
.variable_type
;
2070 if (!array_type
.fixed_length
) {
2071 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2072 var len_var
= new
LocalVariable (int_type
.copy (), get_array_length_cname (get_variable_cname (local
.name
), dim
));
2073 emit_temp_var (len_var
, local
.initializer
== null);
2076 if (array_type
.rank
== 1) {
2077 var size_var
= new
LocalVariable (int_type
.copy (), get_array_size_cname (get_variable_cname (local
.name
)));
2078 emit_temp_var (size_var
, local
.initializer
== null);
2081 } else if (local
.variable_type is DelegateType
) {
2082 var deleg_type
= (DelegateType
) local
.variable_type
;
2083 var d
= deleg_type
.delegate_symbol
;
2085 // create variable to store delegate target
2086 var target_var
= new
LocalVariable (new
PointerType (new
VoidType ()), get_delegate_target_cname (get_variable_cname (local
.name
)));
2087 emit_temp_var (target_var
, local
.initializer
== null);
2088 if (deleg_type
.value_owned
) {
2089 var target_destroy_notify_var
= new
LocalVariable (gdestroynotify_type
, get_delegate_target_destroy_notify_cname (get_variable_cname (local
.name
)));
2090 emit_temp_var (target_destroy_notify_var
, local
.initializer
== null);
2097 if (!has_simple_struct_initializer (local
)) {
2098 store_local (local
, local
.initializer
.target_value
, true);
2102 if (local
.initializer
!= null && local
.initializer
.tree_can_fail
) {
2103 add_simple_check (local
.initializer
);
2106 local
.active
= true;
2109 public override void visit_initializer_list (InitializerList list
) {
2110 if (list
.target_type
.data_type is Struct
) {
2111 /* initializer is used as struct initializer */
2112 var st
= (Struct
) list
.target_type
.data_type
;
2114 if (list
.parent_node is Constant
|| list
.parent_node is Field
|| list
.parent_node is InitializerList
) {
2115 var clist
= new
CCodeInitializerList ();
2117 var field_it
= st
.get_fields ().iterator ();
2118 foreach (Expression expr
in list
.get_initializers ()) {
2120 while (field
== null) {
2122 field
= field_it
.get ();
2123 if (field
.binding
!= MemberBinding
.INSTANCE
) {
2124 // we only initialize instance fields
2129 var cexpr
= get_cvalue (expr
);
2131 string ctype
= field
.get_ctype ();
2132 if (ctype
!= null) {
2133 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
2136 clist
.append (cexpr
);
2139 set_cvalue (list
, clist
);
2141 // used as expression
2142 var temp_decl
= get_temp_variable (list
.target_type
, false, list
);
2143 emit_temp_var (temp_decl
);
2145 var instance
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
2147 var field_it
= st
.get_fields ().iterator ();
2148 foreach (Expression expr
in list
.get_initializers ()) {
2150 while (field
== null) {
2152 field
= field_it
.get ();
2153 if (field
.binding
!= MemberBinding
.INSTANCE
) {
2154 // we only initialize instance fields
2159 var cexpr
= get_cvalue (expr
);
2161 string ctype
= field
.get_ctype ();
2162 if (ctype
!= null) {
2163 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
2166 var lhs
= new
CCodeMemberAccess (instance
, field
.get_cname ());;
2167 ccode
.add_assignment (lhs
, cexpr
);
2170 set_cvalue (list
, instance
);
2173 var clist
= new
CCodeInitializerList ();
2174 foreach (Expression expr
in list
.get_initializers ()) {
2175 clist
.append (get_cvalue (expr
));
2177 set_cvalue (list
, clist
);
2181 public override LocalVariable
create_local (DataType type
) {
2182 var result
= get_temp_variable (type
, type
.value_owned
);
2183 emit_temp_var (result
);
2187 public LocalVariable
get_temp_variable (DataType type
, bool value_owned
= true, CodeNode? node_reference
= null, bool init
= true) {
2188 var var_type
= type
.copy ();
2189 var_type
.value_owned
= value_owned
;
2190 var local
= new
LocalVariable (var_type
, "_tmp%d_".printf (next_temp_var_id
));
2191 local
.no_init
= !init
;
2193 if (node_reference
!= null) {
2194 local
.source_reference
= node_reference
.source_reference
;
2202 bool is_in_generic_type (DataType type
) {
2203 if (current_symbol
!= null && type
.type_parameter
.parent_symbol is TypeSymbol
2204 && (current_method
== null || current_method
.binding
== MemberBinding
.INSTANCE
)) {
2211 public CCodeExpression
get_type_id_expression (DataType type
, bool is_chainup
= false) {
2212 if (type is GenericType
) {
2213 string var_name
= "%s_type".printf (type
.type_parameter
.name
.down ());
2214 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2215 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), var_name
);
2217 return new
CCodeIdentifier (var_name
);
2220 string type_id
= type
.get_type_id ();
2221 if (type_id
== null) {
2222 type_id
= "G_TYPE_INVALID";
2224 generate_type_declaration (type
, cfile
);
2226 return new
CCodeIdentifier (type_id
);
2230 public virtual CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
, bool is_chainup
= false) {
2231 if (type is ErrorType
) {
2232 return new
CCodeIdentifier ("g_error_copy");
2233 } else if (type
.data_type
!= null) {
2234 string dup_function
;
2235 var cl
= type
.data_type as Class
;
2236 if (type
.data_type
.is_reference_counting ()) {
2237 dup_function
= type
.data_type
.get_ref_function ();
2238 if (type
.data_type is Interface
&& dup_function
== null) {
2239 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 ()));
2242 } else if (cl
!= null && cl
.is_immutable
) {
2243 // allow duplicates of immutable instances as for example strings
2244 dup_function
= type
.data_type
.get_dup_function ();
2245 if (dup_function
== null) {
2248 } else if (cl
!= null && cl
.is_gboxed
) {
2249 // allow duplicates of gboxed instances
2250 dup_function
= generate_dup_func_wrapper (type
);
2251 if (dup_function
== null) {
2254 } else if (type is ValueType
) {
2255 dup_function
= type
.data_type
.get_dup_function ();
2256 if (dup_function
== null && type
.nullable
) {
2257 dup_function
= generate_struct_dup_wrapper ((ValueType
) type
);
2258 } else if (dup_function
== null) {
2262 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2263 Report
.error (source_reference
, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type
.data_type
.name
));
2267 return new
CCodeIdentifier (dup_function
);
2268 } else if (type
.type_parameter
!= null) {
2269 string func_name
= "%s_dup_func".printf (type
.type_parameter
.name
.down ());
2270 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2271 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), func_name
);
2273 return new
CCodeIdentifier (func_name
);
2275 } else if (type is PointerType
) {
2276 var pointer_type
= (PointerType
) type
;
2277 return get_dup_func_expression (pointer_type
.base_type
, source_reference
);
2279 return new
CCodeConstant ("NULL");
2283 void make_comparable_cexpression (ref DataType left_type
, ref CCodeExpression cleft
, ref DataType right_type
, ref CCodeExpression cright
) {
2284 var left_type_as_struct
= left_type
.data_type as Struct
;
2285 var right_type_as_struct
= right_type
.data_type as Struct
;
2288 var valuecast
= try_cast_value_to_type (cleft
, left_type
, right_type
);
2289 if (valuecast
!= null) {
2291 left_type
= right_type
;
2292 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
2296 valuecast
= try_cast_value_to_type (cright
, right_type
, left_type
);
2297 if (valuecast
!= null) {
2299 right_type
= left_type
;
2300 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
2304 if (left_type
.data_type is Class
&& !((Class
) left_type
.data_type
).is_compact
&&
2305 right_type
.data_type is Class
&& !((Class
) right_type
.data_type
).is_compact
) {
2306 var left_cl
= (Class
) left_type
.data_type
;
2307 var right_cl
= (Class
) right_type
.data_type
;
2309 if (left_cl
!= right_cl
) {
2310 if (left_cl
.is_subtype_of (right_cl
)) {
2311 cleft
= generate_instance_cast (cleft
, right_cl
);
2312 } else if (right_cl
.is_subtype_of (left_cl
)) {
2313 cright
= generate_instance_cast (cright
, left_cl
);
2316 } else if (left_type_as_struct
!= null && right_type_as_struct
!= null) {
2317 if (left_type is StructValueType
) {
2318 // real structs (uses compare/equal function)
2319 if (!left_type
.nullable
) {
2320 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cleft
);
2322 if (!right_type
.nullable
) {
2323 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cright
);
2326 // integer or floating or boolean type
2327 if (left_type
.nullable
&& right_type
.nullable
) {
2328 // FIXME also compare contents, not just address
2329 } else if (left_type
.nullable
) {
2330 // FIXME check left value is not null
2331 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cleft
);
2332 } else if (right_type
.nullable
) {
2333 // FIXME check right value is not null
2334 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cright
);
2340 private string generate_struct_equal_function (Struct st
) {
2341 string equal_func
= "_%sequal".printf (st
.get_lower_case_cprefix ());
2343 if (!add_wrapper (equal_func
)) {
2344 // wrapper already defined
2348 var function
= new
CCodeFunction (equal_func
, "gboolean");
2349 function
.modifiers
= CCodeModifiers
.STATIC
;
2351 function
.add_parameter (new
CCodeParameter ("s1", "const " + st
.get_cname () + "*"));
2352 function
.add_parameter (new
CCodeParameter ("s2", "const " + st
.get_cname () + "*"));
2354 push_function (function
);
2356 // if (s1 == s2) return TRUE;
2358 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
2359 ccode
.open_if (cexp
);
2360 ccode
.add_return (new
CCodeConstant ("TRUE"));
2363 // if (s1 == NULL || s2 == NULL) return FALSE;
2365 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeConstant ("NULL"));
2366 ccode
.open_if (cexp
);
2367 ccode
.add_return (new
CCodeConstant ("FALSE"));
2370 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s2"), new
CCodeConstant ("NULL"));
2371 ccode
.open_if (cexp
);
2372 ccode
.add_return (new
CCodeConstant ("FALSE"));
2376 foreach (Field f
in st
.get_fields ()) {
2377 if (f
.binding
!= MemberBinding
.INSTANCE
) {
2378 // we only compare instance fields
2382 CCodeExpression cexp
; // if (cexp) return FALSE;
2383 var s1
= (CCodeExpression
) new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("s1"), f
.name
); // s1->f
2384 var s2
= (CCodeExpression
) new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("s2"), f
.name
); // s2->f
2386 var variable_type
= f
.variable_type
.copy ();
2387 make_comparable_cexpression (ref variable_type
, ref s1
, ref variable_type
, ref s2
);
2389 if (!(f
.variable_type is NullType
) && f
.variable_type
.compatible (string_type
)) {
2390 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
2391 ccall
.add_argument (s1
);
2392 ccall
.add_argument (s2
);
2394 } else if (f
.variable_type is StructValueType
) {
2395 var equalfunc
= generate_struct_equal_function (f
.variable_type
.data_type as Struct
);
2396 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
2397 ccall
.add_argument (s1
);
2398 ccall
.add_argument (s2
);
2399 cexp
= new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, ccall
);
2401 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, s1
, s2
);
2404 ccode
.open_if (cexp
);
2405 ccode
.add_return (new
CCodeConstant ("FALSE"));
2409 if (st
.get_fields().size
== 0) {
2410 // either opaque structure or simple type
2411 if (st
.is_simple_type ()) {
2412 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s1")), new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s2")));
2413 ccode
.add_return (cexp
);
2415 ccode
.add_return (new
CCodeConstant ("FALSE"));
2418 ccode
.add_return (new
CCodeConstant ("TRUE"));
2423 cfile
.add_function_declaration (function
);
2424 cfile
.add_function (function
);
2429 private string generate_numeric_equal_function (Struct st
) {
2430 string equal_func
= "_%sequal".printf (st
.get_lower_case_cprefix ());
2432 if (!add_wrapper (equal_func
)) {
2433 // wrapper already defined
2437 var function
= new
CCodeFunction (equal_func
, "gboolean");
2438 function
.modifiers
= CCodeModifiers
.STATIC
;
2440 function
.add_parameter (new
CCodeParameter ("s1", "const " + st
.get_cname () + "*"));
2441 function
.add_parameter (new
CCodeParameter ("s2", "const " + st
.get_cname () + "*"));
2443 push_function (function
);
2445 // if (s1 == s2) return TRUE;
2447 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
2448 ccode
.open_if (cexp
);
2449 ccode
.add_return (new
CCodeConstant ("TRUE"));
2452 // if (s1 == NULL || s2 == NULL) return FALSE;
2454 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeConstant ("NULL"));
2455 ccode
.open_if (cexp
);
2456 ccode
.add_return (new
CCodeConstant ("FALSE"));
2459 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s2"), new
CCodeConstant ("NULL"));
2460 ccode
.open_if (cexp
);
2461 ccode
.add_return (new
CCodeConstant ("FALSE"));
2464 // return (*s1 == *s2);
2466 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s1")), new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s2")));
2467 ccode
.add_return (cexp
);
2472 cfile
.add_function_declaration (function
);
2473 cfile
.add_function (function
);
2478 private string generate_struct_dup_wrapper (ValueType value_type
) {
2479 string dup_func
= "_%sdup".printf (value_type
.type_symbol
.get_lower_case_cprefix ());
2481 if (!add_wrapper (dup_func
)) {
2482 // wrapper already defined
2486 var function
= new
CCodeFunction (dup_func
, value_type
.get_cname ());
2487 function
.modifiers
= CCodeModifiers
.STATIC
;
2489 function
.add_parameter (new
CCodeParameter ("self", value_type
.get_cname ()));
2491 push_function (function
);
2493 if (value_type
.type_symbol
== gvalue_type
) {
2494 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_copy"));
2495 dup_call
.add_argument (new
CCodeIdentifier ("G_TYPE_VALUE"));
2496 dup_call
.add_argument (new
CCodeIdentifier ("self"));
2498 ccode
.add_return (dup_call
);
2500 ccode
.add_declaration (value_type
.get_cname (), new
CCodeVariableDeclarator ("dup"));
2502 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
2503 creation_call
.add_argument (new
CCodeConstant (value_type
.data_type
.get_cname ()));
2504 creation_call
.add_argument (new
CCodeConstant ("1"));
2505 ccode
.add_assignment (new
CCodeIdentifier ("dup"), creation_call
);
2507 var st
= value_type
.data_type as Struct
;
2508 if (st
!= null && st
.is_disposable ()) {
2509 if (!st
.has_copy_function
) {
2510 generate_struct_copy_function (st
);
2513 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_copy_function ()));
2514 copy_call
.add_argument (new
CCodeIdentifier ("self"));
2515 copy_call
.add_argument (new
CCodeIdentifier ("dup"));
2516 ccode
.add_expression (copy_call
);
2518 cfile
.add_include ("string.h");
2520 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
2521 sizeof_call
.add_argument (new
CCodeConstant (value_type
.data_type
.get_cname ()));
2523 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
2524 copy_call
.add_argument (new
CCodeIdentifier ("dup"));
2525 copy_call
.add_argument (new
CCodeIdentifier ("self"));
2526 copy_call
.add_argument (sizeof_call
);
2527 ccode
.add_expression (copy_call
);
2530 ccode
.add_return (new
CCodeIdentifier ("dup"));
2535 cfile
.add_function_declaration (function
);
2536 cfile
.add_function (function
);
2541 protected string generate_dup_func_wrapper (DataType type
) {
2542 string destroy_func
= "_vala_%s_copy".printf (type
.data_type
.get_cname ());
2544 if (!add_wrapper (destroy_func
)) {
2545 // wrapper already defined
2546 return destroy_func
;
2549 var function
= new
CCodeFunction (destroy_func
, type
.get_cname ());
2550 function
.modifiers
= CCodeModifiers
.STATIC
;
2551 function
.add_parameter (new
CCodeParameter ("self", type
.get_cname ()));
2553 push_function (function
);
2555 var cl
= type
.data_type as Class
;
2556 assert (cl
!= null && cl
.is_gboxed
);
2558 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_copy"));
2559 free_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
2560 free_call
.add_argument (new
CCodeIdentifier ("self"));
2562 ccode
.add_return (free_call
);
2566 cfile
.add_function_declaration (function
);
2567 cfile
.add_function (function
);
2569 return destroy_func
;
2572 protected string generate_free_func_wrapper (DataType type
) {
2573 string destroy_func
= "_vala_%s_free".printf (type
.data_type
.get_cname ());
2575 if (!add_wrapper (destroy_func
)) {
2576 // wrapper already defined
2577 return destroy_func
;
2580 var function
= new
CCodeFunction (destroy_func
, "void");
2581 function
.modifiers
= CCodeModifiers
.STATIC
;
2582 function
.add_parameter (new
CCodeParameter ("self", type
.get_cname ()));
2584 push_function (function
);
2586 var cl
= type
.data_type as Class
;
2587 if (cl
!= null && cl
.is_gboxed
) {
2588 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_free"));
2589 free_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
2590 free_call
.add_argument (new
CCodeIdentifier ("self"));
2592 ccode
.add_expression (free_call
);
2593 } else if (cl
!= null) {
2594 assert (cl
.free_function_address_of
);
2596 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier (type
.data_type
.get_free_function ()));
2597 free_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("self")));
2599 ccode
.add_expression (free_call
);
2601 var st
= type
.data_type as Struct
;
2602 if (st
!= null && st
.is_disposable ()) {
2603 if (!st
.has_destroy_function
) {
2604 generate_struct_destroy_function (st
);
2607 var destroy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_destroy_function ()));
2608 destroy_call
.add_argument (new
CCodeIdentifier ("self"));
2609 ccode
.add_expression (destroy_call
);
2612 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
2613 free_call
.add_argument (new
CCodeIdentifier ("self"));
2615 ccode
.add_expression (free_call
);
2620 cfile
.add_function_declaration (function
);
2621 cfile
.add_function (function
);
2623 return destroy_func
;
2626 public CCodeExpression?
get_destroy0_func_expression (DataType type
, bool is_chainup
= false) {
2627 var element_destroy_func_expression
= get_destroy_func_expression (type
, is_chainup
);
2629 if (element_destroy_func_expression is CCodeIdentifier
) {
2630 var freeid
= (CCodeIdentifier
) element_destroy_func_expression
;
2631 string free0_func
= "_%s0_".printf (freeid
.name
);
2633 if (add_wrapper (free0_func
)) {
2634 var function
= new
CCodeFunction (free0_func
, "void");
2635 function
.modifiers
= CCodeModifiers
.STATIC
;
2637 function
.add_parameter (new
CCodeParameter ("var", "gpointer"));
2639 push_function (function
);
2641 ccode
.add_expression (get_unref_expression (new
CCodeIdentifier ("var"), type
, null, true));
2645 cfile
.add_function_declaration (function
);
2646 cfile
.add_function (function
);
2649 element_destroy_func_expression
= new
CCodeIdentifier (free0_func
);
2652 return element_destroy_func_expression
;
2655 public CCodeExpression?
get_destroy_func_expression (DataType type
, bool is_chainup
= false) {
2656 if (context
.profile
== Profile
.GOBJECT
&& (type
.data_type
== glist_type
|| type
.data_type
== gslist_type
|| type
.data_type
== gnode_type
)) {
2657 // create wrapper function to free list elements if necessary
2659 bool elements_require_free
= false;
2660 CCodeExpression element_destroy_func_expression
= null;
2662 foreach (DataType type_arg
in type
.get_type_arguments ()) {
2663 elements_require_free
= requires_destroy (type_arg
);
2664 if (elements_require_free
) {
2665 element_destroy_func_expression
= get_destroy0_func_expression (type_arg
);
2669 if (elements_require_free
&& element_destroy_func_expression is CCodeIdentifier
) {
2670 return new
CCodeIdentifier (generate_collection_free_wrapper (type
, (CCodeIdentifier
) element_destroy_func_expression
));
2672 return new
CCodeIdentifier (type
.data_type
.get_free_function ());
2674 } else if (type is ErrorType
) {
2675 return new
CCodeIdentifier ("g_error_free");
2676 } else if (type
.data_type
!= null) {
2677 string unref_function
;
2678 if (type is ReferenceType
) {
2679 if (type
.data_type
.is_reference_counting ()) {
2680 unref_function
= type
.data_type
.get_unref_function ();
2681 if (type
.data_type is Interface
&& unref_function
== null) {
2682 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 ()));
2686 var cl
= type
.data_type as Class
;
2687 if (cl
!= null && (cl
.free_function_address_of
|| cl
.is_gboxed
)) {
2688 unref_function
= generate_free_func_wrapper (type
);
2690 unref_function
= type
.data_type
.get_free_function ();
2694 if (type
.nullable
) {
2695 unref_function
= type
.data_type
.get_free_function ();
2696 if (unref_function
== null) {
2697 if (type
.data_type is Struct
&& ((Struct
) type
.data_type
).is_disposable ()) {
2698 unref_function
= generate_free_func_wrapper (type
);
2700 unref_function
= "g_free";
2704 var st
= (Struct
) type
.data_type
;
2705 if (!st
.has_destroy_function
) {
2706 generate_struct_destroy_function (st
);
2708 unref_function
= st
.get_destroy_function ();
2711 if (unref_function
== null) {
2712 return new
CCodeConstant ("NULL");
2714 return new
CCodeIdentifier (unref_function
);
2715 } else if (type
.type_parameter
!= null && current_type_symbol is Class
) {
2716 string func_name
= "%s_destroy_func".printf (type
.type_parameter
.name
.down ());
2717 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2718 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), func_name
);
2720 return new
CCodeIdentifier (func_name
);
2722 } else if (type is ArrayType
) {
2723 if (context
.profile
== Profile
.POSIX
) {
2724 return new
CCodeIdentifier ("free");
2726 return new
CCodeIdentifier ("g_free");
2728 } else if (type is PointerType
) {
2729 if (context
.profile
== Profile
.POSIX
) {
2730 return new
CCodeIdentifier ("free");
2732 return new
CCodeIdentifier ("g_free");
2735 return new
CCodeConstant ("NULL");
2739 private string generate_collection_free_wrapper (DataType collection_type
, CCodeIdentifier element_destroy_func_expression
) {
2740 string destroy_func
= "_%s_%s".printf (collection_type
.data_type
.get_free_function (), element_destroy_func_expression
.name
);
2742 if (!add_wrapper (destroy_func
)) {
2743 // wrapper already defined
2744 return destroy_func
;
2747 var function
= new
CCodeFunction (destroy_func
, "void");
2748 function
.modifiers
= CCodeModifiers
.STATIC
;
2750 function
.add_parameter (new
CCodeParameter ("self", collection_type
.get_cname ()));
2752 push_function (function
);
2754 CCodeFunctionCall element_free_call
;
2755 if (collection_type
.data_type
== gnode_type
) {
2756 /* A wrapper which converts GNodeTraverseFunc into GDestroyNotify */
2757 string destroy_node_func
= "%s_node".printf (destroy_func
);
2758 var wrapper
= new
CCodeFunction (destroy_node_func
, "gboolean");
2759 wrapper
.modifiers
= CCodeModifiers
.STATIC
;
2760 wrapper
.add_parameter (new
CCodeParameter ("node", collection_type
.get_cname ()));
2761 wrapper
.add_parameter (new
CCodeParameter ("unused", "gpointer"));
2762 var wrapper_block
= new
CCodeBlock ();
2763 var free_call
= new
CCodeFunctionCall (element_destroy_func_expression
);
2764 free_call
.add_argument (new CCodeMemberAccess
.pointer(new
CCodeIdentifier("node"), "data"));
2765 wrapper_block
.add_statement (new
CCodeExpressionStatement (free_call
));
2766 wrapper_block
.add_statement (new
CCodeReturnStatement (new
CCodeConstant ("FALSE")));
2767 cfile
.add_function_declaration (function
);
2768 wrapper
.block
= wrapper_block
;
2769 cfile
.add_function (wrapper
);
2771 /* Now the code to call g_traverse with the above */
2772 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_node_traverse"));
2773 element_free_call
.add_argument (new
CCodeIdentifier("self"));
2774 element_free_call
.add_argument (new
CCodeConstant ("G_POST_ORDER"));
2775 element_free_call
.add_argument (new
CCodeConstant ("G_TRAVERSE_ALL"));
2776 element_free_call
.add_argument (new
CCodeConstant ("-1"));
2777 element_free_call
.add_argument (new
CCodeIdentifier (destroy_node_func
));
2778 element_free_call
.add_argument (new
CCodeConstant ("NULL"));
2780 if (collection_type
.data_type
== glist_type
) {
2781 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_list_foreach"));
2783 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slist_foreach"));
2786 element_free_call
.add_argument (new
CCodeIdentifier ("self"));
2787 element_free_call
.add_argument (new
CCodeCastExpression (element_destroy_func_expression
, "GFunc"));
2788 element_free_call
.add_argument (new
CCodeConstant ("NULL"));
2791 ccode
.add_expression (element_free_call
);
2793 var cfreecall
= new
CCodeFunctionCall (new
CCodeIdentifier (collection_type
.data_type
.get_free_function ()));
2794 cfreecall
.add_argument (new
CCodeIdentifier ("self"));
2795 ccode
.add_expression (cfreecall
);
2799 cfile
.add_function_declaration (function
);
2800 cfile
.add_function (function
);
2802 return destroy_func
;
2805 public virtual string?
append_struct_array_free (Struct st
) {
2809 // logic in this method is temporarily duplicated in destroy_value
2810 // apply changes to both methods
2811 public virtual CCodeExpression
destroy_variable (Variable variable
, TargetValue target_lvalue
) {
2812 var type
= target_lvalue
.value_type
;
2813 var cvar
= get_cvalue_ (target_lvalue
);
2815 if (type is DelegateType
) {
2816 var delegate_target
= get_delegate_target_cvalue (target_lvalue
);
2817 var delegate_target_destroy_notify
= get_delegate_target_destroy_notify_cvalue (target_lvalue
);
2819 var ccall
= new
CCodeFunctionCall (delegate_target_destroy_notify
);
2820 ccall
.add_argument (delegate_target
);
2822 var destroy_call
= new
CCodeCommaExpression ();
2823 destroy_call
.append_expression (ccall
);
2824 destroy_call
.append_expression (new
CCodeConstant ("NULL"));
2826 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, delegate_target_destroy_notify
, new
CCodeConstant ("NULL"));
2828 var ccomma
= new
CCodeCommaExpression ();
2829 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), destroy_call
));
2830 ccomma
.append_expression (new
CCodeAssignment (cvar
, new
CCodeConstant ("NULL")));
2831 ccomma
.append_expression (new
CCodeAssignment (delegate_target
, new
CCodeConstant ("NULL")));
2832 ccomma
.append_expression (new
CCodeAssignment (delegate_target_destroy_notify
, new
CCodeConstant ("NULL")));
2837 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
2839 if (type is ValueType
&& !type
.nullable
) {
2840 // normal value type, no null check
2841 var st
= type
.data_type as Struct
;
2842 if (st
!= null && st
.is_simple_type ()) {
2844 ccall
.add_argument (cvar
);
2846 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
2849 if (gvalue_type
!= null && type
.data_type
== gvalue_type
) {
2850 // g_value_unset must not be called for already unset values
2851 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
2852 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
2854 var ccomma
= new
CCodeCommaExpression ();
2855 ccomma
.append_expression (ccall
);
2856 ccomma
.append_expression (new
CCodeConstant ("NULL"));
2858 return new
CCodeConditionalExpression (cisvalid
, ccomma
, new
CCodeConstant ("NULL"));
2864 if (ccall
.call is CCodeIdentifier
&& !(type is ArrayType
)) {
2865 // generate and use NULL-aware free macro to simplify code
2867 var freeid
= (CCodeIdentifier
) ccall
.call
;
2868 string free0_func
= "_%s0".printf (freeid
.name
);
2870 if (add_wrapper (free0_func
)) {
2871 var macro
= destroy_value (new
GLibValue (type
, new
CCodeIdentifier ("var")), true);
2872 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("%s(var)".printf (free0_func
), macro
));
2875 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (free0_func
));
2876 ccall
.add_argument (cvar
);
2880 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
2882 /* can be simplified to
2883 * foo = (unref (foo), NULL)
2884 * if foo is of static type non-null
2887 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cvar
, new
CCodeConstant ("NULL"));
2888 if (type
.type_parameter
!= null) {
2889 if (!(current_type_symbol is Class
) || current_class
.is_compact
) {
2890 return new
CCodeConstant ("NULL");
2893 // unref functions are optional for type parameters
2894 var cunrefisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_destroy_func_expression (type
), new
CCodeConstant ("NULL"));
2895 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cunrefisnull
);
2898 ccall
.add_argument (cvar
);
2900 /* set freed references to NULL to prevent further use */
2901 var ccomma
= new
CCodeCommaExpression ();
2903 if (context
.profile
== Profile
.GOBJECT
) {
2904 if (type
.data_type
!= null && !type
.data_type
.is_reference_counting () &&
2905 (type
.data_type
== gstringbuilder_type
2906 || type
.data_type
== garray_type
2907 || type
.data_type
== gbytearray_type
2908 || type
.data_type
== gptrarray_type
)) {
2909 ccall
.add_argument (new
CCodeConstant ("TRUE"));
2910 } else if (type
.data_type
== gthreadpool_type
) {
2911 ccall
.add_argument (new
CCodeConstant ("FALSE"));
2912 ccall
.add_argument (new
CCodeConstant ("TRUE"));
2913 } else if (type is ArrayType
) {
2914 var array_type
= (ArrayType
) type
;
2915 if (requires_destroy (array_type
.element_type
)) {
2916 CCodeExpression csizeexpr
= null;
2917 if (variable
.array_null_terminated
) {
2918 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
2919 len_call
.add_argument (cvar
);
2920 csizeexpr
= len_call
;
2921 } else if (variable
.has_array_length_cexpr
) {
2922 csizeexpr
= new
CCodeConstant (variable
.get_array_length_cexpr ());
2923 } else if (!variable
.no_array_length
) {
2925 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2927 csizeexpr
= get_array_length_cvalue (target_lvalue
, dim
);
2930 csizeexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeexpr
, get_array_length_cvalue (target_lvalue
, dim
));
2935 if (csizeexpr
!= null) {
2936 var st
= array_type
.element_type
.data_type as Struct
;
2937 if (st
!= null && !array_type
.element_type
.nullable
) {
2938 ccall
.call
= new
CCodeIdentifier (append_struct_array_free (st
));
2939 ccall
.add_argument (csizeexpr
);
2941 requires_array_free
= true;
2942 ccall
.call
= new
CCodeIdentifier ("_vala_array_free");
2943 ccall
.add_argument (csizeexpr
);
2944 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
2951 ccomma
.append_expression (ccall
);
2952 ccomma
.append_expression (new
CCodeConstant ("NULL"));
2954 var cassign
= new
CCodeAssignment (cvar
, ccomma
);
2956 // g_free (NULL) is allowed
2957 bool uses_gfree
= (type
.data_type
!= null && !type
.data_type
.is_reference_counting () && type
.data_type
.get_free_function () == "g_free");
2958 uses_gfree
= uses_gfree
|| type is ArrayType
;
2963 return new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), cassign
);
2966 public CCodeExpression
destroy_local (LocalVariable local
) {
2967 return destroy_variable (local
, get_local_cvalue (local
));
2970 public CCodeExpression
destroy_parameter (Parameter param
) {
2971 return destroy_variable (param
, get_parameter_cvalue (param
));
2974 public CCodeExpression
destroy_field (Field field
, TargetValue? instance
) {
2975 return destroy_variable (field
, get_field_cvalue (field
, instance
));
2978 public CCodeExpression
get_unref_expression (CCodeExpression cvar
, DataType type
, Expression? expr
, bool is_macro_definition
= false) {
2980 if (expr
.symbol_reference is LocalVariable
) {
2981 return destroy_local ((LocalVariable
) expr
.symbol_reference
);
2982 } else if (expr
.symbol_reference is Parameter
) {
2983 return destroy_parameter ((Parameter
) expr
.symbol_reference
);
2986 var value
= new
GLibValue (type
, cvar
);
2987 if (expr
!= null && expr
.target_value
!= null) {
2988 value
.array_length_cvalues
= ((GLibValue
) expr
.target_value
).array_length_cvalues
;
2989 value
.delegate_target_cvalue
= get_delegate_target_cvalue (expr
.target_value
);
2990 value
.delegate_target_destroy_notify_cvalue
= get_delegate_target_destroy_notify_cvalue (expr
.target_value
);
2992 return destroy_value (value
, is_macro_definition
);
2995 // logic in this method is temporarily duplicated in destroy_variable
2996 // apply changes to both methods
2997 public virtual CCodeExpression
destroy_value (TargetValue value
, bool is_macro_definition
= false) {
2998 var type
= value
.value_type
;
2999 var cvar
= get_cvalue_ (value
);
3001 if (type is DelegateType
) {
3002 var delegate_target
= get_delegate_target_cvalue (value
);
3003 var delegate_target_destroy_notify
= get_delegate_target_destroy_notify_cvalue (value
);
3005 var ccall
= new
CCodeFunctionCall (delegate_target_destroy_notify
);
3006 ccall
.add_argument (delegate_target
);
3008 var destroy_call
= new
CCodeCommaExpression ();
3009 destroy_call
.append_expression (ccall
);
3010 destroy_call
.append_expression (new
CCodeConstant ("NULL"));
3012 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, delegate_target_destroy_notify
, new
CCodeConstant ("NULL"));
3014 var ccomma
= new
CCodeCommaExpression ();
3015 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), destroy_call
));
3016 ccomma
.append_expression (new
CCodeAssignment (cvar
, new
CCodeConstant ("NULL")));
3017 ccomma
.append_expression (new
CCodeAssignment (delegate_target
, new
CCodeConstant ("NULL")));
3018 ccomma
.append_expression (new
CCodeAssignment (delegate_target_destroy_notify
, new
CCodeConstant ("NULL")));
3023 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
3025 if (type is ValueType
&& !type
.nullable
) {
3026 // normal value type, no null check
3027 var st
= type
.data_type as Struct
;
3028 if (st
!= null && st
.is_simple_type ()) {
3030 ccall
.add_argument (cvar
);
3032 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
3035 if (gvalue_type
!= null && type
.data_type
== gvalue_type
) {
3036 // g_value_unset must not be called for already unset values
3037 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
3038 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
3040 var ccomma
= new
CCodeCommaExpression ();
3041 ccomma
.append_expression (ccall
);
3042 ccomma
.append_expression (new
CCodeConstant ("NULL"));
3044 return new
CCodeConditionalExpression (cisvalid
, ccomma
, new
CCodeConstant ("NULL"));
3050 if (ccall
.call is CCodeIdentifier
&& !(type is ArrayType
) && !is_macro_definition
) {
3051 // generate and use NULL-aware free macro to simplify code
3053 var freeid
= (CCodeIdentifier
) ccall
.call
;
3054 string free0_func
= "_%s0".printf (freeid
.name
);
3056 if (add_wrapper (free0_func
)) {
3057 var macro
= destroy_value (new
GLibValue (type
, new
CCodeIdentifier ("var")), true);
3058 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("%s(var)".printf (free0_func
), macro
));
3061 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (free0_func
));
3062 ccall
.add_argument (cvar
);
3066 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
3068 /* can be simplified to
3069 * foo = (unref (foo), NULL)
3070 * if foo is of static type non-null
3073 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cvar
, new
CCodeConstant ("NULL"));
3074 if (type
.type_parameter
!= null) {
3075 if (!(current_type_symbol is Class
) || current_class
.is_compact
) {
3076 return new
CCodeConstant ("NULL");
3079 // unref functions are optional for type parameters
3080 var cunrefisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_destroy_func_expression (type
), new
CCodeConstant ("NULL"));
3081 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cunrefisnull
);
3084 ccall
.add_argument (cvar
);
3086 /* set freed references to NULL to prevent further use */
3087 var ccomma
= new
CCodeCommaExpression ();
3089 if (context
.profile
== Profile
.GOBJECT
) {
3090 if (type
.data_type
!= null && !type
.data_type
.is_reference_counting () &&
3091 (type
.data_type
== gstringbuilder_type
3092 || type
.data_type
== garray_type
3093 || type
.data_type
== gbytearray_type
3094 || type
.data_type
== gptrarray_type
)) {
3095 ccall
.add_argument (new
CCodeConstant ("TRUE"));
3096 } else if (type
.data_type
== gthreadpool_type
) {
3097 ccall
.add_argument (new
CCodeConstant ("FALSE"));
3098 ccall
.add_argument (new
CCodeConstant ("TRUE"));
3099 } else if (type is ArrayType
) {
3100 var array_type
= (ArrayType
) type
;
3101 if (requires_destroy (array_type
.element_type
)) {
3102 CCodeExpression csizeexpr
= null;
3104 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3106 csizeexpr
= get_array_length_cvalue (value
, dim
);
3109 csizeexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeexpr
, get_array_length_cvalue (value
, dim
));
3113 var st
= array_type
.element_type
.data_type as Struct
;
3114 if (st
!= null && !array_type
.element_type
.nullable
) {
3115 ccall
.call
= new
CCodeIdentifier (append_struct_array_free (st
));
3116 ccall
.add_argument (csizeexpr
);
3118 requires_array_free
= true;
3119 ccall
.call
= new
CCodeIdentifier ("_vala_array_free");
3120 ccall
.add_argument (csizeexpr
);
3121 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
3127 ccomma
.append_expression (ccall
);
3128 ccomma
.append_expression (new
CCodeConstant ("NULL"));
3130 var cassign
= new
CCodeAssignment (cvar
, ccomma
);
3132 // g_free (NULL) is allowed
3133 bool uses_gfree
= (type
.data_type
!= null && !type
.data_type
.is_reference_counting () && type
.data_type
.get_free_function () == "g_free");
3134 uses_gfree
= uses_gfree
|| type is ArrayType
;
3139 return new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), cassign
);
3142 public override void visit_end_full_expression (Expression expr
) {
3143 /* expr is a full expression, i.e. an initializer, the
3144 * expression in an expression statement, the controlling
3145 * expression in if, while, for, or foreach statements
3147 * we unref temporary variables at the end of a full
3150 if (temp_ref_vars
.size
== 0) {
3151 /* nothing to do without temporary variables */
3155 LocalVariable full_expr_var
= null;
3157 var local_decl
= expr
.parent_node as LocalVariable
;
3158 if (!(local_decl
!= null && has_simple_struct_initializer (local_decl
))) {
3159 var expr_type
= expr
.value_type
;
3160 if (expr
.target_type
!= null) {
3161 expr_type
= expr
.target_type
;
3164 full_expr_var
= get_temp_variable (expr_type
, true, expr
, false);
3165 emit_temp_var (full_expr_var
);
3167 ccode
.add_assignment (get_variable_cexpression (full_expr_var
.name
), get_cvalue (expr
));
3170 foreach (LocalVariable local
in temp_ref_vars
) {
3171 ccode
.add_expression (destroy_local (local
));
3174 if (full_expr_var
!= null) {
3175 set_cvalue (expr
, get_variable_cexpression (full_expr_var
.name
));
3178 temp_ref_vars
.clear ();
3181 public void emit_temp_var (LocalVariable local
, bool always_init
= false) {
3182 var vardecl
= new
CCodeVariableDeclarator (local
.name
, null, local
.variable_type
.get_cdeclarator_suffix ());
3184 var st
= local
.variable_type
.data_type as Struct
;
3185 var array_type
= local
.variable_type as ArrayType
;
3187 if (local
.name
.has_prefix ("*")) {
3188 // do not dereference unintialized variable
3189 // initialization is not needed for these special
3190 // pointer temp variables
3191 // used to avoid side-effects in assignments
3192 } else if (local
.no_init
) {
3193 // no initialization necessary for this temp var
3194 } else if (!local
.variable_type
.nullable
&&
3195 (st
!= null && !st
.is_simple_type ()) ||
3196 (array_type
!= null && array_type
.fixed_length
)) {
3197 // 0-initialize struct with struct initializer { 0 }
3198 // necessary as they will be passed by reference
3199 var clist
= new
CCodeInitializerList ();
3200 clist
.append (new
CCodeConstant ("0"));
3202 vardecl
.initializer
= clist
;
3203 vardecl
.init0
= true;
3204 } else if (local
.variable_type
.is_reference_type_or_type_parameter () ||
3205 local
.variable_type
.nullable
||
3206 local
.variable_type is DelegateType
) {
3207 vardecl
.initializer
= new
CCodeConstant ("NULL");
3208 vardecl
.init0
= true;
3209 } else if (always_init
) {
3210 vardecl
.initializer
= default_value_for_type (local
.variable_type
, true);
3211 vardecl
.init0
= true;
3214 if (is_in_coroutine ()) {
3215 closure_struct
.add_field (local
.variable_type
.get_cname (), local
.name
);
3217 // even though closure struct is zerod, we need to initialize temporary variables
3218 // as they might be used multiple times when declared in a loop
3220 if (vardecl
.initializer is CCodeInitializerList
) {
3221 // C does not support initializer lists in assignments, use memset instead
3222 cfile
.add_include ("string.h");
3223 var memset_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
3224 memset_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (local
.name
)));
3225 memset_call
.add_argument (new
CCodeConstant ("0"));
3226 memset_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (local
.variable_type
.get_cname ())));
3227 ccode
.add_expression (memset_call
);
3228 } else if (vardecl
.initializer
!= null) {
3229 ccode
.add_assignment (get_variable_cexpression (local
.name
), vardecl
.initializer
);
3232 ccode
.add_declaration (local
.variable_type
.get_cname (), vardecl
);
3236 public override void visit_expression_statement (ExpressionStatement stmt
) {
3237 if (stmt
.expression
.error
) {
3242 /* free temporary objects and handle errors */
3244 foreach (LocalVariable local
in temp_ref_vars
) {
3245 ccode
.add_expression (destroy_local (local
));
3248 if (stmt
.tree_can_fail
&& stmt
.expression
.tree_can_fail
) {
3249 // simple case, no node breakdown necessary
3250 add_simple_check (stmt
.expression
);
3253 temp_ref_vars
.clear ();
3256 public virtual void append_local_free (Symbol sym
, bool stop_at_loop
= false, CodeNode? stop_at
= null) {
3257 var b
= (Block
) sym
;
3259 var local_vars
= b
.get_local_variables ();
3260 // free in reverse order
3261 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
3262 var local
= local_vars
[i
];
3263 if (!local
.unreachable
&& local
.active
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
3264 ccode
.add_expression (destroy_local (local
));
3269 int block_id
= get_block_id (b
);
3271 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
3272 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
3273 ccode
.add_expression (data_unref
);
3274 ccode
.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id
)), new
CCodeConstant ("NULL"));
3278 if (b
.parent_node is Loop
||
3279 b
.parent_node is ForeachStatement
||
3280 b
.parent_node is SwitchStatement
) {
3285 if (stop_at
!= null && b
.parent_node
== stop_at
) {
3289 if (sym
.parent_symbol is Block
) {
3290 append_local_free (sym
.parent_symbol
, stop_at_loop
, stop_at
);
3291 } else if (sym
.parent_symbol is Method
) {
3292 append_param_free ((Method
) sym
.parent_symbol
);
3296 private void append_param_free (Method m
) {
3297 foreach (Parameter param
in m
.get_parameters ()) {
3298 if (!param
.ellipsis
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
3299 ccode
.add_expression (destroy_parameter (param
));
3304 public bool variable_accessible_in_finally (LocalVariable local
) {
3305 if (current_try
== null) {
3309 var sym
= current_symbol
;
3311 while (!(sym is Method
|| sym is PropertyAccessor
) && sym
.scope
.lookup (local
.name
) == null) {
3312 if ((sym
.parent_node is TryStatement
&& ((TryStatement
) sym
.parent_node
).finally_body
!= null) ||
3313 (sym
.parent_node is CatchClause
&& ((TryStatement
) sym
.parent_node
.parent_node
).finally_body
!= null)) {
3318 sym
= sym
.parent_symbol
;
3324 void return_out_parameter (Parameter param
) {
3325 var delegate_type
= param
.variable_type as DelegateType
;
3327 ccode
.open_if (get_variable_cexpression (param
.name
));
3328 ccode
.add_assignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (param
.name
)), get_variable_cexpression ("_" + param
.name
));
3330 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
3331 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
))));
3332 if (delegate_type
.value_owned
) {
3333 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
))));
3337 if (param
.variable_type
.is_disposable ()){
3339 ccode
.add_expression (destroy_parameter (param
));
3343 var array_type
= param
.variable_type as ArrayType
;
3344 if (array_type
!= null && !array_type
.fixed_length
&& !param
.no_array_length
) {
3345 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3346 ccode
.open_if (get_variable_cexpression (get_parameter_array_length_cname (param
, dim
)));
3347 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
)));
3353 public override void visit_return_statement (ReturnStatement stmt
) {
3354 Symbol return_expression_symbol
= null;
3356 if (stmt
.return_expression
!= null) {
3357 // avoid unnecessary ref/unref pair
3358 var local
= stmt
.return_expression
.symbol_reference as LocalVariable
;
3359 if (current_return_type
.value_owned
3360 && local
!= null && local
.variable_type
.value_owned
3362 && !variable_accessible_in_finally (local
)) {
3363 /* return expression is local variable taking ownership and
3364 * current method is transferring ownership */
3366 return_expression_symbol
= local
;
3370 // return array length if appropriate
3371 if (((current_method
!= null && !current_method
.no_array_length
) || current_property_accessor
!= null) && current_return_type is ArrayType
) {
3372 var return_expr_decl
= get_temp_variable (stmt
.return_expression
.value_type
, true, stmt
, false);
3374 ccode
.add_assignment (get_variable_cexpression (return_expr_decl
.name
), get_cvalue (stmt
.return_expression
));
3376 var array_type
= (ArrayType
) current_return_type
;
3378 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3379 var len_l
= get_result_cexpression (get_array_length_cname ("result", dim
));
3380 if (!is_in_coroutine ()) {
3381 len_l
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, len_l
);
3383 var len_r
= get_array_length_cexpression (stmt
.return_expression
, dim
);
3384 ccode
.add_assignment (len_l
, len_r
);
3387 set_cvalue (stmt
.return_expression
, get_variable_cexpression (return_expr_decl
.name
));
3389 emit_temp_var (return_expr_decl
);
3390 } else if ((current_method
!= null || current_property_accessor
!= null) && current_return_type is DelegateType
) {
3391 var delegate_type
= (DelegateType
) current_return_type
;
3392 if (delegate_type
.delegate_symbol
.has_target
) {
3393 var return_expr_decl
= get_temp_variable (stmt
.return_expression
.value_type
, true, stmt
, false);
3395 ccode
.add_assignment (get_variable_cexpression (return_expr_decl
.name
), get_cvalue (stmt
.return_expression
));
3397 var target_l
= get_result_cexpression (get_delegate_target_cname ("result"));
3398 if (!is_in_coroutine ()) {
3399 target_l
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_l
);
3401 CCodeExpression target_r_destroy_notify
;
3402 var target_r
= get_delegate_target_cexpression (stmt
.return_expression
, out target_r_destroy_notify
);
3403 ccode
.add_assignment (target_l
, target_r
);
3404 if (delegate_type
.value_owned
) {
3405 var target_l_destroy_notify
= get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3406 if (!is_in_coroutine ()) {
3407 target_l_destroy_notify
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_l_destroy_notify
);
3409 ccode
.add_assignment (target_l_destroy_notify
, target_r_destroy_notify
);
3412 set_cvalue (stmt
.return_expression
, get_variable_cexpression (return_expr_decl
.name
));
3414 emit_temp_var (return_expr_decl
);
3418 if (stmt
.return_expression
!= null) {
3419 // assign method result to `result'
3420 CCodeExpression result_lhs
= get_result_cexpression ();
3421 if (current_return_type
.is_real_non_null_struct_type () && !is_in_coroutine ()) {
3422 result_lhs
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, result_lhs
);
3424 ccode
.add_assignment (result_lhs
, get_cvalue (stmt
.return_expression
));
3427 // free local variables
3428 append_local_free (current_symbol
);
3430 if (current_method
!= null) {
3431 // check postconditions
3432 foreach (Expression postcondition
in current_method
.get_postconditions ()) {
3433 create_postcondition_statement (postcondition
);
3437 if (current_method
!= null && !current_method
.coroutine
) {
3438 // assign values to output parameters if they are not NULL
3439 // otherwise, free the value if necessary
3440 foreach (var param
in current_method
.get_parameters ()) {
3441 if (param
.direction
!= ParameterDirection
.OUT
) {
3445 return_out_parameter (param
);
3449 if (is_in_constructor ()) {
3450 ccode
.add_return (new
CCodeIdentifier ("obj"));
3451 } else if (is_in_destructor ()) {
3452 // do not call return as member cleanup and chain up to base finalizer
3453 // stil need to be executed
3454 ccode
.add_goto ("_return");
3455 } else if (current_method is CreationMethod
) {
3456 ccode
.add_return (new
CCodeIdentifier ("self"));
3457 } else if (is_in_coroutine ()) {
3458 } else if (current_return_type is VoidType
|| current_return_type
.is_real_non_null_struct_type ()) {
3459 // structs are returned via out parameter
3460 ccode
.add_return ();
3462 ccode
.add_return (new
CCodeIdentifier ("result"));
3465 if (return_expression_symbol
!= null) {
3466 return_expression_symbol
.active
= true;
3469 // required for destructors
3470 current_method_return
= true;
3473 public string get_symbol_lock_name (string symname
) {
3474 return "__lock_%s".printf (symname
);
3477 private CCodeExpression
get_lock_expression (Statement stmt
, Expression resource
) {
3478 CCodeExpression l
= null;
3479 var inner_node
= ((MemberAccess
)resource
).inner
;
3480 var member
= resource
.symbol_reference
;
3481 var parent
= (TypeSymbol
)resource
.symbol_reference
.parent_symbol
;
3483 if (member
.is_instance_member ()) {
3484 if (inner_node
== null) {
3485 l
= new
CCodeIdentifier ("self");
3486 } else if (resource
.symbol_reference
.parent_symbol
!= current_type_symbol
) {
3487 l
= generate_instance_cast (get_cvalue (inner_node
), parent
);
3489 l
= get_cvalue (inner_node
);
3492 l
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (l
, "priv"), get_symbol_lock_name (resource
.symbol_reference
.name
));
3493 } else if (member
.is_class_member ()) {
3494 CCodeExpression klass
;
3496 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
||
3497 current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
||
3498 (in_constructor
&& !in_static_or_class_context
)) {
3499 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3500 k
.add_argument (new
CCodeIdentifier ("self"));
3503 klass
= new
CCodeIdentifier ("klass");
3506 var get_class_private_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent
.get_upper_case_cname ())));
3507 get_class_private_call
.add_argument (klass
);
3508 l
= new CCodeMemberAccess
.pointer (get_class_private_call
, get_symbol_lock_name (resource
.symbol_reference
.name
));
3510 string lock_name
= "%s_%s".printf(parent
.get_lower_case_cname (), resource
.symbol_reference
.name
);
3511 l
= new
CCodeIdentifier (get_symbol_lock_name (lock_name
));
3516 public override void visit_lock_statement (LockStatement stmt
) {
3517 var l
= get_lock_expression (stmt
, stmt
.resource
);
3519 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier (((Method
) mutex_type
.scope
.lookup ("lock")).get_cname ()));
3520 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
3522 ccode
.add_expression (fc
);
3525 public override void visit_unlock_statement (UnlockStatement stmt
) {
3526 var l
= get_lock_expression (stmt
, stmt
.resource
);
3528 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier (((Method
) mutex_type
.scope
.lookup ("unlock")).get_cname ()));
3529 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
3531 ccode
.add_expression (fc
);
3534 public override void visit_delete_statement (DeleteStatement stmt
) {
3535 var pointer_type
= (PointerType
) stmt
.expression
.value_type
;
3536 DataType type
= pointer_type
;
3537 if (pointer_type
.base_type
.data_type
!= null && pointer_type
.base_type
.data_type
.is_reference_type ()) {
3538 type
= pointer_type
.base_type
;
3541 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
3542 ccall
.add_argument (get_cvalue (stmt
.expression
));
3543 ccode
.add_expression (ccall
);
3546 public override void visit_expression (Expression expr
) {
3547 if (get_cvalue (expr
) != null && !expr
.lvalue
) {
3548 if (expr
.formal_value_type is GenericType
&& !(expr
.value_type is GenericType
)) {
3549 var st
= expr
.formal_value_type
.type_parameter
.parent_symbol
.parent_symbol as Struct
;
3550 if (expr
.formal_value_type
.type_parameter
.parent_symbol
!= garray_type
&&
3551 (st
== null || st
.get_cname () != "va_list")) {
3552 // GArray and va_list don't use pointer-based generics
3553 set_cvalue (expr
, convert_from_generic_pointer (get_cvalue (expr
), expr
.value_type
));
3557 // memory management, implicit casts, and boxing/unboxing
3558 set_cvalue (expr
, transform_expression (get_cvalue (expr
), expr
.value_type
, expr
.target_type
, expr
));
3560 if (expr
.formal_target_type is GenericType
&& !(expr
.target_type is GenericType
)) {
3561 if (expr
.formal_target_type
.type_parameter
.parent_symbol
!= garray_type
) {
3562 // GArray doesn't use pointer-based generics
3563 set_cvalue (expr
, convert_to_generic_pointer (get_cvalue (expr
), expr
.target_type
));
3569 public override void visit_boolean_literal (BooleanLiteral expr
) {
3570 if (context
.profile
== Profile
.GOBJECT
) {
3571 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"TRUE" : "FALSE"));
3573 cfile
.add_include ("stdbool.h");
3574 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"true" : "false"));
3578 public override void visit_character_literal (CharacterLiteral expr
) {
3579 if (expr
.get_char () >= 0x20 && expr
.get_char () < 0x80) {
3580 set_cvalue (expr
, new
CCodeConstant (expr
.value
));
3582 set_cvalue (expr
, new
CCodeConstant ("%uU".printf (expr
.get_char ())));
3586 public override void visit_integer_literal (IntegerLiteral expr
) {
3587 set_cvalue (expr
, new
CCodeConstant (expr
.value
+ expr
.type_suffix
));
3590 public override void visit_real_literal (RealLiteral expr
) {
3591 string c_literal
= expr
.value
;
3592 if (c_literal
.has_suffix ("d") || c_literal
.has_suffix ("D")) {
3593 // there is no suffix for double in C
3594 c_literal
= c_literal
.substring (0, c_literal
.length
- 1);
3596 if (!("." in c_literal
|| "e" in c_literal
|| "E" in c_literal
)) {
3597 // C requires period or exponent part for floating constants
3598 if ("f" in c_literal
|| "F" in c_literal
) {
3599 c_literal
= c_literal
.substring (0, c_literal
.length
- 1) + ".f";
3604 set_cvalue (expr
, new
CCodeConstant (c_literal
));
3607 public override void visit_string_literal (StringLiteral expr
) {
3608 set_cvalue (expr
, new CCodeConstant
.string (expr
.value
.replace ("\n", "\\n")));
3610 if (expr
.translate
) {
3611 // translated string constant
3613 var m
= (Method
) root_symbol
.scope
.lookup ("GLib").scope
.lookup ("_");
3614 add_symbol_declaration (cfile
, m
, m
.get_cname ());
3616 var translate
= new
CCodeFunctionCall (new
CCodeIdentifier ("_"));
3617 translate
.add_argument (get_cvalue (expr
));
3618 set_cvalue (expr
, translate
);
3622 public override void visit_regex_literal (RegexLiteral expr
) {
3623 string[] parts
= expr
.value
.split ("/", 3);
3624 string re
= parts
[2].escape ("");
3627 if (parts
[1].contains ("i")) {
3628 flags
+= " | G_REGEX_CASELESS";
3630 if (parts
[1].contains ("m")) {
3631 flags
+= " | G_REGEX_MULTILINE";
3633 if (parts
[1].contains ("s")) {
3634 flags
+= " | G_REGEX_DOTALL";
3636 if (parts
[1].contains ("x")) {
3637 flags
+= " | G_REGEX_EXTENDED";
3640 var regex_var
= get_temp_variable (regex_type
, true, expr
, false);
3641 emit_temp_var (regex_var
);
3643 var cdecl
= new
CCodeDeclaration ("GRegex*");
3645 var cname
= regex_var
.name
+ "regex_" + next_regex_id
.to_string ();
3646 if (this
.next_regex_id
== 0) {
3647 var fun
= new
CCodeFunction ("_thread_safe_regex_init", "GRegex*");
3648 fun
.modifiers
= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
3649 fun
.add_parameter (new
CCodeParameter ("re", "GRegex**"));
3650 fun
.add_parameter (new
CCodeParameter ("pattern", "const gchar *"));
3651 fun
.add_parameter (new
CCodeParameter ("match_options", "GRegexMatchFlags"));
3653 push_function (fun
);
3655 var once_enter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_once_init_enter"));
3656 once_enter_call
.add_argument (new
CCodeConstant ("(volatile gsize*) re"));
3657 ccode
.open_if (once_enter_call
);
3659 var regex_new_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_regex_new"));
3660 regex_new_call
.add_argument (new
CCodeConstant ("pattern"));
3661 regex_new_call
.add_argument (new
CCodeConstant ("match_options"));
3662 regex_new_call
.add_argument (new
CCodeConstant ("0"));
3663 regex_new_call
.add_argument (new
CCodeConstant ("NULL"));
3664 ccode
.add_assignment (new
CCodeIdentifier ("GRegex* val"), regex_new_call
);
3666 var once_leave_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_once_init_leave"));
3667 once_leave_call
.add_argument (new
CCodeConstant ("(volatile gsize*) re"));
3668 once_leave_call
.add_argument (new
CCodeConstant ("(gsize) val"));
3669 ccode
.add_expression (once_leave_call
);
3673 ccode
.add_return (new
CCodeIdentifier ("*re"));
3677 cfile
.add_function (fun
);
3679 this
.next_regex_id
++;
3681 cdecl
.add_declarator (new
CCodeVariableDeclarator (cname
+ " = NULL"));
3682 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
3684 var regex_const
= new
CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname
, re
, flags
));
3686 cfile
.add_constant_declaration (cdecl
);
3687 set_cvalue (expr
, regex_const
);
3690 public override void visit_null_literal (NullLiteral expr
) {
3691 if (context
.profile
!= Profile
.GOBJECT
) {
3692 cfile
.add_include ("stddef.h");
3694 set_cvalue (expr
, new
CCodeConstant ("NULL"));
3696 var array_type
= expr
.target_type as ArrayType
;
3697 var delegate_type
= expr
.target_type as DelegateType
;
3698 if (array_type
!= null) {
3699 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3700 append_array_length (expr
, new
CCodeConstant ("0"));
3702 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
3703 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
3704 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
3708 public abstract TargetValue
get_local_cvalue (LocalVariable local
);
3710 public abstract TargetValue
get_parameter_cvalue (Parameter param
);
3712 public abstract TargetValue
get_field_cvalue (Field field
, TargetValue? instance
);
3714 public abstract TargetValue
load_this_parameter (TypeSymbol sym
);
3716 public virtual string get_delegate_target_cname (string delegate_cname
) {
3717 assert_not_reached ();
3720 public virtual CCodeExpression
get_delegate_target_cexpression (Expression delegate_expr
, out CCodeExpression delegate_target_destroy_notify
) {
3721 assert_not_reached ();
3724 public virtual CCodeExpression
get_delegate_target_cvalue (TargetValue value
) {
3725 return new
CCodeInvalidExpression ();
3728 public virtual CCodeExpression
get_delegate_target_destroy_notify_cvalue (TargetValue value
) {
3729 return new
CCodeInvalidExpression ();
3732 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname
) {
3733 assert_not_reached ();
3736 public override void visit_base_access (BaseAccess expr
) {
3737 CCodeExpression this_access
;
3738 if (is_in_coroutine ()) {
3740 this_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "self");
3742 this_access
= new
CCodeIdentifier ("self");
3745 set_cvalue (expr
, generate_instance_cast (this_access
, expr
.value_type
.data_type
));
3748 public override void visit_postfix_expression (PostfixExpression expr
) {
3749 MemberAccess ma
= find_property_access (expr
.inner
);
3751 // property postfix expression
3752 var prop
= (Property
) ma
.symbol_reference
;
3754 // assign current value to temp variable
3755 var temp_decl
= get_temp_variable (prop
.property_type
, true, expr
, false);
3756 emit_temp_var (temp_decl
);
3757 ccode
.add_assignment (get_variable_cexpression (temp_decl
.name
), get_cvalue (expr
.inner
));
3759 // increment/decrement property
3760 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
3761 var cexpr
= new
CCodeBinaryExpression (op
, get_variable_cexpression (temp_decl
.name
), new
CCodeConstant ("1"));
3762 store_property (prop
, ma
.inner
, new
GLibValue (expr
.value_type
, cexpr
));
3764 // return previous value
3765 set_cvalue (expr
, get_variable_cexpression (temp_decl
.name
));
3769 if (expr
.parent_node is ExpressionStatement
) {
3770 var op
= expr
.increment ? CCodeUnaryOperator
.POSTFIX_INCREMENT
: CCodeUnaryOperator
.POSTFIX_DECREMENT
;
3772 ccode
.add_expression (new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
3774 // assign current value to temp variable
3775 var temp_decl
= get_temp_variable (expr
.inner
.value_type
, true, expr
, false);
3776 emit_temp_var (temp_decl
);
3777 ccode
.add_assignment (get_variable_cexpression (temp_decl
.name
), get_cvalue (expr
.inner
));
3779 // increment/decrement variable
3780 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
3781 var cexpr
= new
CCodeBinaryExpression (op
, get_variable_cexpression (temp_decl
.name
), new
CCodeConstant ("1"));
3782 ccode
.add_assignment (get_cvalue (expr
.inner
), cexpr
);
3784 // return previous value
3785 set_cvalue (expr
, get_variable_cexpression (temp_decl
.name
));
3789 private MemberAccess?
find_property_access (Expression expr
) {
3790 if (!(expr is MemberAccess
)) {
3794 var ma
= (MemberAccess
) expr
;
3795 if (ma
.symbol_reference is Property
) {
3802 bool is_limited_generic_type (DataType type
) {
3803 var cl
= type
.type_parameter
.parent_symbol as Class
;
3804 var st
= type
.type_parameter
.parent_symbol as Struct
;
3805 if ((cl
!= null && cl
.is_compact
) || st
!= null) {
3806 // compact classes and structs only
3807 // have very limited generics support
3813 public bool requires_copy (DataType type
) {
3814 if (!type
.is_disposable ()) {
3818 var cl
= type
.data_type as Class
;
3819 if (cl
!= null && cl
.is_reference_counting ()
3820 && cl
.get_ref_function () == "") {
3821 // empty ref_function => no ref necessary
3825 if (type
.type_parameter
!= null) {
3826 if (is_limited_generic_type (type
)) {
3834 public bool requires_destroy (DataType type
) {
3835 if (!type
.is_disposable ()) {
3839 var array_type
= type as ArrayType
;
3840 if (array_type
!= null && array_type
.fixed_length
) {
3841 return requires_destroy (array_type
.element_type
);
3844 var cl
= type
.data_type as Class
;
3845 if (cl
!= null && cl
.is_reference_counting ()
3846 && cl
.get_unref_function () == "") {
3847 // empty unref_function => no unref necessary
3851 if (type
.type_parameter
!= null) {
3852 if (is_limited_generic_type (type
)) {
3860 bool is_ref_function_void (DataType type
) {
3861 var cl
= type
.data_type as Class
;
3862 if (cl
!= null && cl
.ref_function_void
) {
3869 public virtual CCodeExpression?
get_ref_cexpression (DataType expression_type
, CCodeExpression cexpr
, Expression? expr
, CodeNode node
) {
3870 if (expression_type is DelegateType
) {
3874 if (expression_type is ValueType
&& !expression_type
.nullable
) {
3875 // normal value type, no null check
3877 var decl
= get_temp_variable (expression_type
, false, node
);
3878 emit_temp_var (decl
);
3879 var ctemp
= get_variable_cexpression (decl
.name
);
3881 var vt
= (ValueType
) expression_type
;
3882 var st
= (Struct
) vt
.type_symbol
;
3883 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_copy_function ()));
3884 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3885 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
3887 if (!st
.has_copy_function
) {
3888 generate_struct_copy_function (st
);
3891 if (gvalue_type
!= null && expression_type
.data_type
== gvalue_type
) {
3892 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
3893 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3895 ccode
.open_if (cisvalid
);
3897 // GValue requires g_value_init in addition to g_value_copy
3898 var value_type_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VALUE_TYPE"));
3899 value_type_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3901 var init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
3902 init_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
3903 init_call
.add_argument (value_type_call
);
3904 ccode
.add_expression (init_call
);
3905 ccode
.add_expression (copy_call
);
3909 // g_value_init/copy must not be called for uninitialized values
3910 ccode
.add_assignment (ctemp
, cexpr
);
3913 ccode
.add_expression (copy_call
);
3919 /* (temp = expr, temp == NULL ? NULL : ref (temp))
3921 * can be simplified to
3923 * if static type of expr is non-null
3926 var dupexpr
= get_dup_func_expression (expression_type
, node
.source_reference
);
3928 if (dupexpr
== null) {
3933 if (dupexpr is CCodeIdentifier
&& !(expression_type is ArrayType
) && !(expression_type is GenericType
) && !is_ref_function_void (expression_type
)) {
3934 // generate and call NULL-aware ref function to reduce number
3935 // of temporary variables and simplify code
3937 var dupid
= (CCodeIdentifier
) dupexpr
;
3938 string dup0_func
= "_%s0".printf (dupid
.name
);
3940 // g_strdup is already NULL-safe
3941 if (dupid
.name
== "g_strdup") {
3942 dup0_func
= dupid
.name
;
3943 } else if (add_wrapper (dup0_func
)) {
3944 string pointer_cname
= "gpointer";
3945 if (context
.profile
== Profile
.POSIX
) {
3946 pointer_cname
= "void*";
3948 var dup0_fun
= new
CCodeFunction (dup0_func
, pointer_cname
);
3949 dup0_fun
.add_parameter (new
CCodeParameter ("self", pointer_cname
));
3950 dup0_fun
.modifiers
= CCodeModifiers
.STATIC
;
3952 push_function (dup0_fun
);
3954 var dup_call
= new
CCodeFunctionCall (dupexpr
);
3955 dup_call
.add_argument (new
CCodeIdentifier ("self"));
3957 ccode
.add_return (new
CCodeConditionalExpression (new
CCodeIdentifier ("self"), dup_call
, new
CCodeConstant ("NULL")));
3961 cfile
.add_function (dup0_fun
);
3964 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (dup0_func
));
3965 ccall
.add_argument (cexpr
);
3969 var ccall
= new
CCodeFunctionCall (dupexpr
);
3971 if (!(expression_type is ArrayType
) && expr
!= null && expr
.is_non_null ()
3972 && !is_ref_function_void (expression_type
)) {
3973 // expression is non-null
3974 ccall
.add_argument (get_cvalue (expr
));
3978 var decl
= get_temp_variable (expression_type
, false, node
, false);
3979 emit_temp_var (decl
);
3981 var ctemp
= get_variable_cexpression (decl
.name
);
3983 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, new
CCodeConstant ("NULL"));
3984 if (expression_type
.type_parameter
!= null) {
3985 // dup functions are optional for type parameters
3986 var cdupisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_dup_func_expression (expression_type
, node
.source_reference
), new
CCodeConstant ("NULL"));
3987 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cdupisnull
);
3990 if (expression_type
.type_parameter
!= null) {
3991 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
3992 ccall
.add_argument (new
CCodeCastExpression (ctemp
, "gpointer"));
3994 ccall
.add_argument (ctemp
);
3997 if (expression_type is ArrayType
) {
3998 var array_type
= (ArrayType
) expression_type
;
4000 CCodeExpression csizeexpr
= null;
4001 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4003 csizeexpr
= get_array_length_cexpression (expr
, dim
);
4006 csizeexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeexpr
, get_array_length_cexpression (expr
, dim
));
4010 ccall
.add_argument (csizeexpr
);
4012 if (array_type
.element_type is GenericType
) {
4013 var elem_dupexpr
= get_dup_func_expression (array_type
.element_type
, node
.source_reference
);
4014 if (elem_dupexpr
== null) {
4015 elem_dupexpr
= new
CCodeConstant ("NULL");
4017 ccall
.add_argument (elem_dupexpr
);
4021 var ccomma
= new
CCodeCommaExpression ();
4022 ccomma
.append_expression (new
CCodeAssignment (ctemp
, cexpr
));
4024 CCodeExpression cifnull
;
4025 if (expression_type
.data_type
!= null) {
4026 cifnull
= new
CCodeConstant ("NULL");
4028 // the value might be non-null even when the dup function is null,
4029 // so we may not just use NULL for type parameters
4031 // cast from gconstpointer to gpointer as methods in
4032 // generic classes may not return gconstpointer
4033 cifnull
= new
CCodeCastExpression (ctemp
, "gpointer");
4035 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, cifnull
, ccall
));
4037 // repeat temp variable at the end of the comma expression
4038 // if the ref function returns void
4039 if (is_ref_function_void (expression_type
)) {
4040 ccomma
.append_expression (ctemp
);
4047 bool is_reference_type_argument (DataType type_arg
) {
4048 if (type_arg is ErrorType
|| (type_arg
.data_type
!= null && type_arg
.data_type
.is_reference_type ())) {
4055 bool is_nullable_value_type_argument (DataType type_arg
) {
4056 if (type_arg is ValueType
&& type_arg
.nullable
) {
4063 bool is_signed_integer_type_argument (DataType type_arg
) {
4064 var st
= type_arg
.data_type as Struct
;
4065 if (type_arg
.nullable
) {
4067 } else if (st
== bool_type
.data_type
) {
4069 } else if (st
== char_type
.data_type
) {
4071 } else if (unichar_type
!= null && st
== unichar_type
.data_type
) {
4073 } else if (st
== short_type
.data_type
) {
4075 } else if (st
== int_type
.data_type
) {
4077 } else if (st
== long_type
.data_type
) {
4079 } else if (st
== int8_type
.data_type
) {
4081 } else if (st
== int16_type
.data_type
) {
4083 } else if (st
== int32_type
.data_type
) {
4085 } else if (st
== gtype_type
) {
4087 } else if (type_arg is EnumValueType
) {
4094 bool is_unsigned_integer_type_argument (DataType type_arg
) {
4095 var st
= type_arg
.data_type as Struct
;
4096 if (type_arg
.nullable
) {
4098 } else if (st
== uchar_type
.data_type
) {
4100 } else if (st
== ushort_type
.data_type
) {
4102 } else if (st
== uint_type
.data_type
) {
4104 } else if (st
== ulong_type
.data_type
) {
4106 } else if (st
== uint8_type
.data_type
) {
4108 } else if (st
== uint16_type
.data_type
) {
4110 } else if (st
== uint32_type
.data_type
) {
4117 public void check_type (DataType type
) {
4118 var array_type
= type as ArrayType
;
4119 if (array_type
!= null) {
4120 check_type (array_type
.element_type
);
4121 if (array_type
.element_type is ArrayType
) {
4122 Report
.error (type
.source_reference
, "Stacked arrays are not supported");
4123 } else if (array_type
.element_type is DelegateType
) {
4124 var delegate_type
= (DelegateType
) array_type
.element_type
;
4125 if (delegate_type
.delegate_symbol
.has_target
) {
4126 Report
.error (type
.source_reference
, "Delegates with target are not supported as array element type");
4130 foreach (var type_arg
in type
.get_type_arguments ()) {
4131 check_type (type_arg
);
4132 check_type_argument (type_arg
);
4136 void check_type_argument (DataType type_arg
) {
4137 if (type_arg is GenericType
4138 || type_arg is PointerType
4139 || is_reference_type_argument (type_arg
)
4140 || is_nullable_value_type_argument (type_arg
)
4141 || is_signed_integer_type_argument (type_arg
)
4142 || is_unsigned_integer_type_argument (type_arg
)) {
4144 } else if (type_arg is DelegateType
) {
4145 var delegate_type
= (DelegateType
) type_arg
;
4146 if (delegate_type
.delegate_symbol
.has_target
) {
4147 Report
.error (type_arg
.source_reference
, "Delegates with target are not supported as generic type arguments");
4150 Report
.error (type_arg
.source_reference
, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg
.to_string ()));
4154 public virtual void generate_class_declaration (Class cl
, CCodeFile decl_space
) {
4155 if (add_symbol_declaration (decl_space
, cl
, cl
.get_cname ())) {
4160 public virtual void generate_interface_declaration (Interface iface
, CCodeFile decl_space
) {
4163 public virtual void generate_method_declaration (Method m
, CCodeFile decl_space
) {
4166 public virtual void generate_error_domain_declaration (ErrorDomain edomain
, CCodeFile decl_space
) {
4169 public void add_generic_type_arguments (Map
<int,CCodeExpression
> arg_map
, List
<DataType
> type_args
, CodeNode expr
, bool is_chainup
= false) {
4170 int type_param_index
= 0;
4171 foreach (var type_arg
in type_args
) {
4172 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), get_type_id_expression (type_arg
, is_chainup
));
4173 if (requires_copy (type_arg
)) {
4174 var dup_func
= get_dup_func_expression (type_arg
, type_arg
.source_reference
, is_chainup
);
4175 if (dup_func
== null) {
4176 // type doesn't contain a copy function
4180 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeCastExpression (dup_func
, "GBoxedCopyFunc"));
4181 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), get_destroy_func_expression (type_arg
, is_chainup
));
4183 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeConstant ("NULL"));
4184 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeConstant ("NULL"));
4190 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
4191 CCodeExpression instance
= null;
4192 CCodeExpression creation_expr
= null;
4194 check_type (expr
.type_reference
);
4196 var st
= expr
.type_reference
.data_type as Struct
;
4197 if ((st
!= null && (!st
.is_simple_type () || st
.get_cname () == "va_list")) || expr
.get_object_initializer ().size
> 0) {
4198 // value-type initialization or object creation expression with object initializer
4200 var local
= expr
.parent_node as LocalVariable
;
4201 if (local
!= null && has_simple_struct_initializer (local
)) {
4202 if (local
.captured
) {
4203 var block
= (Block
) local
.parent_symbol
;
4204 instance
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_variable_cname (local
.name
));
4206 instance
= get_variable_cexpression (get_variable_cname (local
.name
));
4209 var temp_decl
= get_temp_variable (expr
.type_reference
, false, expr
);
4210 emit_temp_var (temp_decl
);
4212 instance
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
4216 if (expr
.symbol_reference
== null) {
4217 // no creation method
4218 if (expr
.type_reference
.data_type is Struct
) {
4219 // memset needs string.h
4220 cfile
.add_include ("string.h");
4221 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
4222 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4223 creation_call
.add_argument (new
CCodeConstant ("0"));
4224 creation_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (expr
.type_reference
.get_cname ())));
4226 creation_expr
= creation_call
;
4228 } else if (expr
.type_reference
.data_type
== glist_type
||
4229 expr
.type_reference
.data_type
== gslist_type
) {
4230 // NULL is an empty list
4231 set_cvalue (expr
, new
CCodeConstant ("NULL"));
4232 } else if (expr
.symbol_reference is Method
) {
4233 // use creation method
4234 var m
= (Method
) expr
.symbol_reference
;
4235 var params
= m
.get_parameters ();
4236 CCodeFunctionCall creation_call
;
4238 generate_method_declaration (m
, cfile
);
4240 var cl
= expr
.type_reference
.data_type as Class
;
4242 if (!m
.has_new_function
) {
4243 // use construct function directly
4244 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
4245 creation_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
4247 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_cname ()));
4250 if ((st
!= null && !st
.is_simple_type ()) && !(m
.cinstance_parameter_position
< 0)) {
4251 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4252 } else if (st
!= null && st
.get_cname () == "va_list") {
4253 creation_call
.add_argument (instance
);
4254 if (m
.get_cname () == "va_start") {
4255 Parameter last_param
= null;
4256 foreach (var param
in current_method
.get_parameters ()) {
4257 if (param
.ellipsis
) {
4262 creation_call
.add_argument (new
CCodeIdentifier (get_variable_cname (last_param
.name
)));
4266 generate_type_declaration (expr
.type_reference
, cfile
);
4268 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
4270 if (cl
!= null && !cl
.is_compact
) {
4271 add_generic_type_arguments (carg_map
, expr
.type_reference
.get_type_arguments (), expr
);
4272 } else if (cl
!= null && m
.simple_generics
) {
4273 int type_param_index
= 0;
4274 foreach (var type_arg
in expr
.type_reference
.get_type_arguments ()) {
4275 if (requires_copy (type_arg
)) {
4276 carg_map
.set (get_param_pos (-1 + 0.1 * type_param_index
+ 0.03), get_destroy0_func_expression (type_arg
));
4278 carg_map
.set (get_param_pos (-1 + 0.1 * type_param_index
+ 0.03), new
CCodeConstant ("NULL"));
4284 bool ellipsis
= false;
4288 Iterator
<Parameter
> params_it
= params
.iterator ();
4289 foreach (Expression arg
in expr
.get_argument_list ()) {
4290 CCodeExpression cexpr
= get_cvalue (arg
);
4291 Parameter param
= null;
4292 if (params_it
.next ()) {
4293 param
= params_it
.get ();
4294 ellipsis
= param
.ellipsis
;
4296 if (!param
.no_array_length
&& param
.variable_type is ArrayType
) {
4297 var array_type
= (ArrayType
) param
.variable_type
;
4298 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4299 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), get_array_length_cexpression (arg
, dim
));
4301 } else if (param
.variable_type is DelegateType
) {
4302 var deleg_type
= (DelegateType
) param
.variable_type
;
4303 var d
= deleg_type
.delegate_symbol
;
4305 CCodeExpression delegate_target_destroy_notify
;
4306 var delegate_target
= get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
);
4307 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), delegate_target
);
4308 if (deleg_type
.value_owned
) {
4309 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
+ 0.01), delegate_target_destroy_notify
);
4314 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
4316 if (param
.ctype
!= null) {
4317 cexpr
= new
CCodeCastExpression (cexpr
, param
.ctype
);
4320 cexpr
= handle_struct_argument (null, arg
, cexpr
);
4323 arg_pos
= get_param_pos (param
.cparameter_position
, ellipsis
);
4325 // default argument position
4326 cexpr
= handle_struct_argument (null, arg
, cexpr
);
4327 arg_pos
= get_param_pos (i
, ellipsis
);
4330 carg_map
.set (arg_pos
, cexpr
);
4334 while (params_it
.next ()) {
4335 var param
= params_it
.get ();
4337 if (param
.ellipsis
) {
4342 if (param
.initializer
== null) {
4343 Report
.error (expr
.source_reference
, "no default expression for argument %d".printf (i
));
4347 /* evaluate default expression here as the code
4348 * generator might not have visited the formal
4350 param
.initializer
.emit (this
);
4352 carg_map
.set (get_param_pos (param
.cparameter_position
), get_cvalue (param
.initializer
));
4356 // append C arguments in the right order
4361 foreach (int pos
in carg_map
.get_keys ()) {
4362 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
4366 if (min_pos
== -1) {
4369 creation_call
.add_argument (carg_map
.get (min_pos
));
4373 if ((st
!= null && !st
.is_simple_type ()) && m
.cinstance_parameter_position
< 0) {
4374 // instance parameter is at the end in a struct creation method
4375 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4378 if (expr
.tree_can_fail
) {
4380 current_method_inner_error
= true;
4381 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression ("_inner_error_")));
4385 /* ensure variable argument list ends with NULL
4386 * except when using printf-style arguments */
4387 if (!m
.printf_format
&& !m
.scanf_format
&& m
.sentinel
!= "") {
4388 creation_call
.add_argument (new
CCodeConstant (m
.sentinel
));
4392 creation_expr
= creation_call
;
4394 // cast the return value of the creation method back to the intended type if
4395 // it requested a special C return type
4396 if (get_custom_creturn_type (m
) != null) {
4397 creation_expr
= new
CCodeCastExpression (creation_expr
, expr
.type_reference
.get_cname ());
4399 } else if (expr
.symbol_reference is ErrorCode
) {
4400 var ecode
= (ErrorCode
) expr
.symbol_reference
;
4401 var edomain
= (ErrorDomain
) ecode
.parent_symbol
;
4402 CCodeFunctionCall creation_call
;
4404 generate_error_domain_declaration (edomain
, cfile
);
4406 if (expr
.get_argument_list ().size
== 1) {
4407 // must not be a format argument
4408 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_new_literal"));
4410 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_new"));
4412 creation_call
.add_argument (new
CCodeIdentifier (edomain
.get_upper_case_cname ()));
4413 creation_call
.add_argument (new
CCodeIdentifier (ecode
.get_cname ()));
4415 foreach (Expression arg
in expr
.get_argument_list ()) {
4416 creation_call
.add_argument (get_cvalue (arg
));
4419 creation_expr
= creation_call
;
4424 var local
= expr
.parent_node as LocalVariable
;
4425 if (local
!= null && has_simple_struct_initializer (local
)) {
4426 // no temporary variable necessary
4427 ccode
.add_expression (creation_expr
);
4428 set_cvalue (expr
, instance
);
4430 } else if (instance
!= null) {
4431 if (expr
.type_reference
.data_type is Struct
) {
4432 ccode
.add_expression (creation_expr
);
4434 ccode
.add_assignment (instance
, creation_expr
);
4437 foreach (MemberInitializer init
in expr
.get_object_initializer ()) {
4438 if (init
.symbol_reference is Field
) {
4439 var f
= (Field
) init
.symbol_reference
;
4440 var instance_target_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
4441 var typed_inst
= transform_expression (instance
, expr
.type_reference
, instance_target_type
);
4442 CCodeExpression lhs
;
4443 if (expr
.type_reference
.data_type is Struct
) {
4444 lhs
= new
CCodeMemberAccess (typed_inst
, f
.get_cname ());
4446 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, f
.get_cname ());
4448 ccode
.add_assignment (lhs
, get_cvalue (init
.initializer
));
4450 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
4451 var array_type
= (ArrayType
) f
.variable_type
;
4452 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4453 if (expr
.type_reference
.data_type is Struct
) {
4454 lhs
= new
CCodeMemberAccess (typed_inst
, get_array_length_cname (f
.get_cname (), dim
));
4456 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, get_array_length_cname (f
.get_cname (), dim
));
4458 var rhs_array_len
= get_array_length_cexpression (init
.initializer
, dim
);
4459 ccode
.add_assignment (lhs
, rhs_array_len
);
4461 } else if (f
.variable_type is DelegateType
&& (f
.variable_type as DelegateType
).delegate_symbol
.has_target
&& !f
.no_delegate_target
) {
4462 if (expr
.type_reference
.data_type is Struct
) {
4463 lhs
= new
CCodeMemberAccess (typed_inst
, get_delegate_target_cname (f
.get_cname ()));
4465 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, get_delegate_target_cname (f
.get_cname ()));
4467 CCodeExpression rhs_delegate_target_destroy_notify
;
4468 var rhs_delegate_target
= get_delegate_target_cexpression (init
.initializer
, out rhs_delegate_target_destroy_notify
);
4469 ccode
.add_assignment (lhs
, rhs_delegate_target
);
4472 var cl
= f
.parent_symbol as Class
;
4474 generate_class_struct_declaration (cl
, cfile
);
4476 } else if (init
.symbol_reference is Property
) {
4477 var inst_ma
= new MemberAccess
.simple ("new");
4478 inst_ma
.value_type
= expr
.type_reference
;
4479 set_cvalue (inst_ma
, instance
);
4480 store_property ((Property
) init
.symbol_reference
, inst_ma
, init
.initializer
.target_value
);
4484 creation_expr
= instance
;
4487 if (creation_expr
!= null) {
4488 var temp_var
= get_temp_variable (expr
.value_type
);
4489 var temp_ref
= get_variable_cexpression (temp_var
.name
);
4491 emit_temp_var (temp_var
);
4493 ccode
.add_assignment (temp_ref
, creation_expr
);
4494 set_cvalue (expr
, temp_ref
);
4498 public CCodeExpression?
handle_struct_argument (Parameter? param
, Expression arg
, CCodeExpression? cexpr
) {
4500 if (param
!= null) {
4501 type
= param
.variable_type
;
4504 type
= arg
.value_type
;
4507 // pass non-simple struct instances always by reference
4508 if (!(arg
.value_type is NullType
) && type
.is_real_struct_type ()) {
4509 // we already use a reference for arguments of ref, out, and nullable parameters
4510 if ((param
== null || param
.direction
== ParameterDirection
.IN
) && !type
.nullable
) {
4511 var unary
= cexpr as CCodeUnaryExpression
;
4512 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
4515 } else if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
4516 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
4518 // if cexpr is e.g. a function call, we can't take the address of the expression
4519 var temp_var
= get_temp_variable (type
, true, null, false);
4520 emit_temp_var (temp_var
);
4522 ccode
.add_assignment (get_variable_cexpression (temp_var
.name
), cexpr
);
4523 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
));
4531 public override void visit_sizeof_expression (SizeofExpression expr
) {
4532 generate_type_declaration (expr
.type_reference
, cfile
);
4534 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
4535 csizeof
.add_argument (new
CCodeIdentifier (expr
.type_reference
.get_cname ()));
4536 set_cvalue (expr
, csizeof
);
4539 public override void visit_typeof_expression (TypeofExpression expr
) {
4540 set_cvalue (expr
, get_type_id_expression (expr
.type_reference
));
4543 public override void visit_unary_expression (UnaryExpression expr
) {
4544 if (expr
.operator
== UnaryOperator
.REF
|| expr
.operator
== UnaryOperator
.OUT
) {
4545 var glib_value
= (GLibValue
) expr
.inner
.target_value
;
4547 var ref_value
= new
GLibValue (glib_value
.value_type
);
4548 ref_value
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.cvalue
);
4550 if (glib_value
.array_length_cvalues
!= null) {
4551 for (int i
= 0; i
< glib_value
.array_length_cvalues
.size
; i
++) {
4552 ref_value
.append_array_length_cvalue (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.array_length_cvalues
[i
]));
4556 if (glib_value
.delegate_target_cvalue
!= null) {
4557 ref_value
.delegate_target_cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.delegate_target_cvalue
);
4559 if (glib_value
.delegate_target_destroy_notify_cvalue
!= null) {
4560 ref_value
.delegate_target_destroy_notify_cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.delegate_target_destroy_notify_cvalue
);
4563 expr
.target_value
= ref_value
;
4567 CCodeUnaryOperator op
;
4568 if (expr
.operator
== UnaryOperator
.PLUS
) {
4569 op
= CCodeUnaryOperator
.PLUS
;
4570 } else if (expr
.operator
== UnaryOperator
.MINUS
) {
4571 op
= CCodeUnaryOperator
.MINUS
;
4572 } else if (expr
.operator
== UnaryOperator
.LOGICAL_NEGATION
) {
4573 op
= CCodeUnaryOperator
.LOGICAL_NEGATION
;
4574 } else if (expr
.operator
== UnaryOperator
.BITWISE_COMPLEMENT
) {
4575 op
= CCodeUnaryOperator
.BITWISE_COMPLEMENT
;
4576 } else if (expr
.operator
== UnaryOperator
.INCREMENT
) {
4577 op
= CCodeUnaryOperator
.PREFIX_INCREMENT
;
4578 } else if (expr
.operator
== UnaryOperator
.DECREMENT
) {
4579 op
= CCodeUnaryOperator
.PREFIX_DECREMENT
;
4581 assert_not_reached ();
4583 set_cvalue (expr
, new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
4586 public CCodeExpression?
try_cast_value_to_type (CCodeExpression ccodeexpr
, DataType from
, DataType to
, Expression? expr
= null) {
4587 if (from
== null || gvalue_type
== null || from
.data_type
!= gvalue_type
|| to
.get_type_id () == null) {
4591 // explicit conversion from GValue
4592 var ccall
= new
CCodeFunctionCall (get_value_getter_function (to
));
4593 CCodeExpression gvalue
;
4594 if (from
.nullable
) {
4597 gvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ccodeexpr
);
4599 ccall
.add_argument (gvalue
);
4601 CCodeExpression rv
= ccall
;
4603 if (expr
!= null && to is ArrayType
) {
4604 // null-terminated string array
4605 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strv_length"));
4606 len_call
.add_argument (rv
);
4607 append_array_length (expr
, len_call
);
4608 } else if (to is StructValueType
) {
4609 var temp_decl
= get_temp_variable (to
, true, null, true);
4610 emit_temp_var (temp_decl
);
4611 var ctemp
= get_variable_cexpression (temp_decl
.name
);
4613 rv
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeCastExpression (rv
, (new
PointerType(to
)).get_cname ()));
4614 var holds
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VALUE_HOLDS"));
4615 holds
.add_argument (gvalue
);
4616 holds
.add_argument (new
CCodeIdentifier (to
.get_type_id ()));
4617 var cond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, holds
, ccall
);
4618 var warn
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_warning"));
4619 warn
.add_argument (new
CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
4620 var fail
= new
CCodeCommaExpression ();
4621 fail
.append_expression (warn
);
4622 fail
.append_expression (ctemp
);
4623 rv
= new
CCodeConditionalExpression (cond
, rv
, fail
);
4629 int next_variant_function_id
= 0;
4631 public CCodeExpression?
try_cast_variant_to_type (CCodeExpression ccodeexpr
, DataType from
, DataType to
, Expression? expr
= null) {
4632 if (from
== null || gvariant_type
== null || from
.data_type
!= gvariant_type
) {
4636 string variant_func
= "_variant_get%d".printf (++next_variant_function_id
);
4638 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (variant_func
));
4639 ccall
.add_argument (ccodeexpr
);
4641 var cfunc
= new
CCodeFunction (variant_func
);
4642 cfunc
.modifiers
= CCodeModifiers
.STATIC
;
4643 cfunc
.add_parameter (new
CCodeParameter ("value", "GVariant*"));
4645 if (!to
.is_real_non_null_struct_type ()) {
4646 cfunc
.return_type
= to
.get_cname ();
4649 if (to
.is_real_non_null_struct_type ()) {
4650 // structs are returned via out parameter
4651 cfunc
.add_parameter (new
CCodeParameter ("result", to
.get_cname () + "*"));
4652 } else if (to is ArrayType
) {
4653 // return array length if appropriate
4654 var array_type
= (ArrayType
) to
;
4656 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4657 var temp_decl
= get_temp_variable (int_type
, false, expr
);
4658 emit_temp_var (temp_decl
);
4660 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_decl
.name
)));
4661 cfunc
.add_parameter (new
CCodeParameter (get_array_length_cname ("result", dim
), "int*"));
4662 append_array_length (expr
, get_variable_cexpression (temp_decl
.name
));
4666 push_function (cfunc
);
4668 var result
= deserialize_expression (to
, new
CCodeIdentifier ("value"), new
CCodeIdentifier ("*result"));
4669 ccode
.add_return (result
);
4673 cfile
.add_function_declaration (cfunc
);
4674 cfile
.add_function (cfunc
);
4679 public virtual CCodeExpression?
deserialize_expression (DataType type
, CCodeExpression variant_expr
, CCodeExpression? expr
, CCodeExpression? error_expr
= null, out bool may_fail
= null) {
4683 public virtual CCodeExpression?
serialize_expression (DataType type
, CCodeExpression expr
) {
4687 public override void visit_cast_expression (CastExpression expr
) {
4688 var valuecast
= try_cast_value_to_type (get_cvalue (expr
.inner
), expr
.inner
.value_type
, expr
.type_reference
, expr
);
4689 if (valuecast
!= null) {
4690 set_cvalue (expr
, valuecast
);
4694 var variantcast
= try_cast_variant_to_type (get_cvalue (expr
.inner
), expr
.inner
.value_type
, expr
.type_reference
, expr
);
4695 if (variantcast
!= null) {
4696 set_cvalue (expr
, variantcast
);
4700 generate_type_declaration (expr
.type_reference
, cfile
);
4702 var cl
= expr
.type_reference
.data_type as Class
;
4703 var iface
= expr
.type_reference
.data_type as Interface
;
4704 if (context
.profile
== Profile
.GOBJECT
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
4705 // checked cast for strict subtypes of GTypeInstance
4706 if (expr
.is_silent_cast
) {
4707 var temp_decl
= get_temp_variable (expr
.inner
.value_type
, expr
.inner
.value_type
.value_owned
, expr
, false);
4708 emit_temp_var (temp_decl
);
4709 var ctemp
= get_variable_cexpression (temp_decl
.name
);
4711 ccode
.add_assignment (ctemp
, get_cvalue (expr
.inner
));
4712 var ccheck
= create_type_check (ctemp
, expr
.type_reference
);
4713 var ccast
= new
CCodeCastExpression (ctemp
, expr
.type_reference
.get_cname ());
4714 var cnull
= new
CCodeConstant ("NULL");
4716 set_cvalue (expr
, new
CCodeConditionalExpression (ccheck
, ccast
, cnull
));
4718 set_cvalue (expr
, generate_instance_cast (get_cvalue (expr
.inner
), expr
.type_reference
.data_type
));
4721 if (expr
.is_silent_cast
) {
4723 Report
.error (expr
.source_reference
, "Operation not supported for this type");
4727 // retain array length
4728 var array_type
= expr
.type_reference as ArrayType
;
4729 if (array_type
!= null && expr
.inner
.value_type is ArrayType
) {
4730 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4731 append_array_length (expr
, get_array_length_cexpression (expr
.inner
, dim
));
4733 } else if (array_type
!= null) {
4734 // cast from non-array to array, set invalid length
4735 // required by string.data, e.g.
4736 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4737 append_array_length (expr
, new
CCodeConstant ("-1"));
4741 var innercexpr
= get_cvalue (expr
.inner
);
4742 if (expr
.type_reference
.data_type is Struct
&& !expr
.type_reference
.nullable
&&
4743 expr
.inner
.value_type
.data_type is Struct
&& expr
.inner
.value_type
.nullable
) {
4744 // nullable integer or float or boolean or struct cast to non-nullable
4745 innercexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, innercexpr
);
4747 set_cvalue (expr
, new
CCodeCastExpression (innercexpr
, expr
.type_reference
.get_cname ()));
4749 if (expr
.type_reference is DelegateType
) {
4750 if (get_delegate_target (expr
.inner
) != null) {
4751 set_delegate_target (expr
, get_delegate_target (expr
.inner
));
4753 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
4755 if (get_delegate_target_destroy_notify (expr
.inner
) != null) {
4756 set_delegate_target_destroy_notify (expr
, get_delegate_target_destroy_notify (expr
.inner
));
4758 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
4764 public override void visit_named_argument (NamedArgument expr
) {
4765 set_cvalue (expr
, get_cvalue (expr
.inner
));
4768 public override void visit_pointer_indirection (PointerIndirection expr
) {
4769 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_cvalue (expr
.inner
)));
4772 public override void visit_addressof_expression (AddressofExpression expr
) {
4773 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (expr
.inner
)));
4776 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
4777 /* (tmp = var, var = null, tmp) */
4778 var temp_decl
= get_temp_variable (expr
.value_type
, true, expr
, false);
4779 emit_temp_var (temp_decl
);
4780 var cvar
= get_variable_cexpression (temp_decl
.name
);
4782 ccode
.add_assignment (cvar
, get_cvalue (expr
.inner
));
4783 if (!(expr
.value_type is DelegateType
)) {
4784 ccode
.add_assignment (get_cvalue (expr
.inner
), new
CCodeConstant ("NULL"));
4787 set_cvalue (expr
, cvar
);
4789 var array_type
= expr
.value_type as ArrayType
;
4790 if (array_type
!= null) {
4791 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4792 append_array_length (expr
, get_array_length_cexpression (expr
.inner
, dim
));
4796 var delegate_type
= expr
.value_type as DelegateType
;
4797 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
4798 var temp_target_decl
= get_temp_variable (new
PointerType (new
VoidType ()), true, expr
, false);
4799 emit_temp_var (temp_target_decl
);
4800 var target_cvar
= get_variable_cexpression (temp_target_decl
.name
);
4801 CCodeExpression target_destroy_notify
;
4802 var target
= get_delegate_target_cexpression (expr
.inner
, out target_destroy_notify
);
4803 ccode
.add_assignment (target_cvar
, target
);
4804 set_delegate_target (expr
, target_cvar
);
4805 if (target_destroy_notify
!= null) {
4806 var temp_target_destroy_notify_decl
= get_temp_variable (gdestroynotify_type
, true, expr
, false);
4807 emit_temp_var (temp_target_destroy_notify_decl
);
4808 var target_destroy_notify_cvar
= get_variable_cexpression (temp_target_destroy_notify_decl
.name
);
4809 ccode
.add_assignment (target_destroy_notify_cvar
, target_destroy_notify
);
4810 ccode
.add_assignment (target_destroy_notify
, new
CCodeConstant ("NULL"));
4811 set_delegate_target_destroy_notify (expr
, target_destroy_notify_cvar
);
4816 public override void visit_binary_expression (BinaryExpression expr
) {
4817 var cleft
= get_cvalue (expr
.left
);
4818 var cright
= get_cvalue (expr
.right
);
4820 CCodeExpression? left_chain
= null;
4822 var lbe
= (BinaryExpression
) expr
.left
;
4824 var temp_decl
= get_temp_variable (lbe
.right
.value_type
, true, null, false);
4825 emit_temp_var (temp_decl
);
4826 var cvar
= get_variable_cexpression (temp_decl
.name
);
4827 var clbe
= (CCodeBinaryExpression
) get_cvalue (lbe
);
4829 clbe
= (CCodeBinaryExpression
) clbe
.right
;
4831 ccode
.add_assignment (cvar
, get_cvalue (lbe
.right
));
4832 clbe
.right
= get_variable_cexpression (temp_decl
.name
);
4837 CCodeBinaryOperator op
;
4838 if (expr
.operator
== BinaryOperator
.PLUS
) {
4839 op
= CCodeBinaryOperator
.PLUS
;
4840 } else if (expr
.operator
== BinaryOperator
.MINUS
) {
4841 op
= CCodeBinaryOperator
.MINUS
;
4842 } else if (expr
.operator
== BinaryOperator
.MUL
) {
4843 op
= CCodeBinaryOperator
.MUL
;
4844 } else if (expr
.operator
== BinaryOperator
.DIV
) {
4845 op
= CCodeBinaryOperator
.DIV
;
4846 } else if (expr
.operator
== BinaryOperator
.MOD
) {
4847 if (expr
.value_type
.equals (double_type
)) {
4848 cfile
.add_include ("math.h");
4849 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("fmod"));
4850 ccall
.add_argument (cleft
);
4851 ccall
.add_argument (cright
);
4852 set_cvalue (expr
, ccall
);
4854 } else if (expr
.value_type
.equals (float_type
)) {
4855 cfile
.add_include ("math.h");
4856 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("fmodf"));
4857 ccall
.add_argument (cleft
);
4858 ccall
.add_argument (cright
);
4859 set_cvalue (expr
, ccall
);
4862 op
= CCodeBinaryOperator
.MOD
;
4864 } else if (expr
.operator
== BinaryOperator
.SHIFT_LEFT
) {
4865 op
= CCodeBinaryOperator
.SHIFT_LEFT
;
4866 } else if (expr
.operator
== BinaryOperator
.SHIFT_RIGHT
) {
4867 op
= CCodeBinaryOperator
.SHIFT_RIGHT
;
4868 } else if (expr
.operator
== BinaryOperator
.LESS_THAN
) {
4869 op
= CCodeBinaryOperator
.LESS_THAN
;
4870 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN
) {
4871 op
= CCodeBinaryOperator
.GREATER_THAN
;
4872 } else if (expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
) {
4873 op
= CCodeBinaryOperator
.LESS_THAN_OR_EQUAL
;
4874 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
4875 op
= CCodeBinaryOperator
.GREATER_THAN_OR_EQUAL
;
4876 } else if (expr
.operator
== BinaryOperator
.EQUALITY
) {
4877 op
= CCodeBinaryOperator
.EQUALITY
;
4878 } else if (expr
.operator
== BinaryOperator
.INEQUALITY
) {
4879 op
= CCodeBinaryOperator
.INEQUALITY
;
4880 } else if (expr
.operator
== BinaryOperator
.BITWISE_AND
) {
4881 op
= CCodeBinaryOperator
.BITWISE_AND
;
4882 } else if (expr
.operator
== BinaryOperator
.BITWISE_OR
) {
4883 op
= CCodeBinaryOperator
.BITWISE_OR
;
4884 } else if (expr
.operator
== BinaryOperator
.BITWISE_XOR
) {
4885 op
= CCodeBinaryOperator
.BITWISE_XOR
;
4886 } else if (expr
.operator
== BinaryOperator
.AND
) {
4887 op
= CCodeBinaryOperator
.AND
;
4888 } else if (expr
.operator
== BinaryOperator
.OR
) {
4889 op
= CCodeBinaryOperator
.OR
;
4890 } else if (expr
.operator
== BinaryOperator
.IN
) {
4891 if (expr
.right
.value_type is ArrayType
) {
4892 var array_type
= (ArrayType
) expr
.right
.value_type
;
4893 var node
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_contains_wrapper (array_type
)));
4894 node
.add_argument (cright
);
4895 node
.add_argument (get_array_length_cexpression (expr
.right
));
4896 if (array_type
.element_type is StructValueType
) {
4897 node
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cleft
));
4899 node
.add_argument (cleft
);
4901 set_cvalue (expr
, node
);
4903 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeBinaryExpression (CCodeBinaryOperator
.BITWISE_AND
, cright
, cleft
), cleft
));
4907 assert_not_reached ();
4910 if (expr
.operator
== BinaryOperator
.EQUALITY
||
4911 expr
.operator
== BinaryOperator
.INEQUALITY
) {
4912 var left_type
= expr
.left
.target_type
;
4913 var right_type
= expr
.right
.target_type
;
4914 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
4916 if (left_type is StructValueType
&& right_type is StructValueType
) {
4917 var equalfunc
= generate_struct_equal_function ((Struct
) left_type
.data_type as Struct
);
4918 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
4919 ccall
.add_argument (cleft
);
4920 ccall
.add_argument (cright
);
4922 cright
= new
CCodeConstant ("TRUE");
4923 } else if ((left_type is IntegerType
|| left_type is FloatingType
|| left_type is BooleanType
) && left_type
.nullable
&&
4924 (right_type is IntegerType
|| right_type is FloatingType
|| right_type is BooleanType
) && right_type
.nullable
) {
4925 var equalfunc
= generate_numeric_equal_function ((Struct
) left_type
.data_type as Struct
);
4926 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
4927 ccall
.add_argument (cleft
);
4928 ccall
.add_argument (cright
);
4930 cright
= new
CCodeConstant ("TRUE");
4934 if (!(expr
.left
.value_type is NullType
)
4935 && expr
.left
.value_type
.compatible (string_type
)
4936 && !(expr
.right
.value_type is NullType
)
4937 && expr
.right
.value_type
.compatible (string_type
)) {
4938 if (expr
.operator
== BinaryOperator
.PLUS
) {
4939 // string concatenation
4940 if (expr
.left
.is_constant () && expr
.right
.is_constant ()) {
4943 if (cleft is CCodeIdentifier
) {
4944 left
= ((CCodeIdentifier
) cleft
).name
;
4945 } else if (cleft is CCodeConstant
) {
4946 left
= ((CCodeConstant
) cleft
).name
;
4948 assert_not_reached ();
4950 if (cright is CCodeIdentifier
) {
4951 right
= ((CCodeIdentifier
) cright
).name
;
4952 } else if (cright is CCodeConstant
) {
4953 right
= ((CCodeConstant
) cright
).name
;
4955 assert_not_reached ();
4958 set_cvalue (expr
, new
CCodeConstant ("%s %s".printf (left
, right
)));
4961 if (context
.profile
== Profile
.POSIX
) {
4962 // convert to strcat(strcpy(malloc(1+strlen(a)+strlen(b)),a),b)
4963 var strcat
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcat"));
4964 var strcpy
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcpy"));
4965 var malloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("malloc"));
4967 var strlen_a
= new
CCodeFunctionCall (new
CCodeIdentifier ("strlen"));
4968 strlen_a
.add_argument(cleft
);
4969 var strlen_b
= new
CCodeFunctionCall (new
CCodeIdentifier ("strlen"));
4970 strlen_b
.add_argument(cright
);
4971 var newlength
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier("1"),
4972 new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, strlen_a
, strlen_b
));
4973 malloc
.add_argument(newlength
);
4975 strcpy
.add_argument(malloc
);
4976 strcpy
.add_argument(cleft
);
4978 strcat
.add_argument(strcpy
);
4979 strcat
.add_argument(cright
);
4980 set_cvalue (expr
, strcat
);
4982 // convert to g_strconcat (a, b, NULL)
4983 var temp_var
= get_temp_variable (expr
.value_type
, true, null, false);
4984 var temp_ref
= get_variable_cexpression (temp_var
.name
);
4985 emit_temp_var (temp_var
);
4987 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strconcat"));
4988 ccall
.add_argument (cleft
);
4989 ccall
.add_argument (cright
);
4990 ccall
.add_argument (new
CCodeConstant("NULL"));
4992 ccode
.add_assignment (temp_ref
, ccall
);
4993 set_cvalue (expr
, temp_ref
);
4997 } else if (expr
.operator
== BinaryOperator
.EQUALITY
4998 || expr
.operator
== BinaryOperator
.INEQUALITY
4999 || expr
.operator
== BinaryOperator
.LESS_THAN
5000 || expr
.operator
== BinaryOperator
.GREATER_THAN
5001 || expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
5002 || expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
5003 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
5004 ccall
.add_argument (cleft
);
5005 ccall
.add_argument (cright
);
5007 cright
= new
CCodeConstant ("0");
5011 set_cvalue (expr
, new
CCodeBinaryExpression (op
, cleft
, cright
));
5012 if (left_chain
!= null) {
5013 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, left_chain
, get_cvalue (expr
)));
5017 public string?
get_type_check_function (TypeSymbol type
) {
5018 var cl
= type as Class
;
5019 if (cl
!= null && cl
.type_check_function
!= null) {
5020 return cl
.type_check_function
;
5021 } else if ((cl
!= null && cl
.is_compact
) || type is Struct
|| type is Enum
|| type is Delegate
) {
5024 return type
.get_upper_case_cname ("IS_");
5028 CCodeExpression?
create_type_check (CCodeNode ccodenode
, DataType type
) {
5029 var et
= type as ErrorType
;
5030 if (et
!= null && et
.error_code
!= null) {
5031 var matches_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_matches"));
5032 matches_call
.add_argument ((CCodeExpression
) ccodenode
);
5033 matches_call
.add_argument (new
CCodeIdentifier (et
.error_domain
.get_upper_case_cname ()));
5034 matches_call
.add_argument (new
CCodeIdentifier (et
.error_code
.get_cname ()));
5035 return matches_call
;
5036 } else if (et
!= null && et
.error_domain
!= null) {
5037 var instance_domain
= new CCodeMemberAccess
.pointer ((CCodeExpression
) ccodenode
, "domain");
5038 var type_domain
= new
CCodeIdentifier (et
.error_domain
.get_upper_case_cname ());
5039 return new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, instance_domain
, type_domain
);
5041 string type_check_func
= get_type_check_function (type
.data_type
);
5042 if (type_check_func
== null) {
5043 return new
CCodeInvalidExpression ();
5045 var ccheck
= new
CCodeFunctionCall (new
CCodeIdentifier (type_check_func
));
5046 ccheck
.add_argument ((CCodeExpression
) ccodenode
);
5051 string generate_array_contains_wrapper (ArrayType array_type
) {
5052 string array_contains_func
= "_vala_%s_array_contains".printf (array_type
.element_type
.get_lower_case_cname ());
5054 if (!add_wrapper (array_contains_func
)) {
5055 return array_contains_func
;
5058 var function
= new
CCodeFunction (array_contains_func
, "gboolean");
5059 function
.modifiers
= CCodeModifiers
.STATIC
;
5061 function
.add_parameter (new
CCodeParameter ("stack", array_type
.get_cname ()));
5062 function
.add_parameter (new
CCodeParameter ("stack_length", "int"));
5063 if (array_type
.element_type is StructValueType
) {
5064 function
.add_parameter (new
CCodeParameter ("needle", array_type
.element_type
.get_cname () + "*"));
5066 function
.add_parameter (new
CCodeParameter ("needle", array_type
.element_type
.get_cname ()));
5069 push_function (function
);
5071 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
5073 var cloop_initializer
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
5074 var cloop_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("stack_length"));
5075 var cloop_iterator
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i"));
5076 ccode
.open_for (cloop_initializer
, cloop_condition
, cloop_iterator
);
5078 var celement
= new
CCodeElementAccess (new
CCodeIdentifier ("stack"), new
CCodeIdentifier ("i"));
5079 var cneedle
= new
CCodeIdentifier ("needle");
5080 CCodeBinaryExpression cif_condition
;
5081 if (array_type
.element_type
.compatible (string_type
)) {
5082 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
5083 ccall
.add_argument (celement
);
5084 ccall
.add_argument (cneedle
);
5085 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ccall
, new
CCodeConstant ("0"));
5086 } else if (array_type
.element_type is StructValueType
) {
5087 var equalfunc
= generate_struct_equal_function ((Struct
) array_type
.element_type
.data_type as Struct
);
5088 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
5089 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, celement
));
5090 ccall
.add_argument (cneedle
);
5091 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ccall
, new
CCodeConstant ("TRUE"));
5093 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cneedle
, celement
);
5096 ccode
.open_if (cif_condition
);
5097 ccode
.add_return (new
CCodeConstant ("TRUE"));
5102 ccode
.add_return (new
CCodeConstant ("FALSE"));
5106 cfile
.add_function_declaration (function
);
5107 cfile
.add_function (function
);
5109 return array_contains_func
;
5112 public override void visit_type_check (TypeCheck expr
) {
5113 generate_type_declaration (expr
.type_reference
, cfile
);
5115 set_cvalue (expr
, create_type_check (get_cvalue (expr
.expression
), expr
.type_reference
));
5116 if (get_cvalue (expr
) is CCodeInvalidExpression
) {
5117 Report
.error (expr
.source_reference
, "type check expressions not supported for compact classes, structs, and enums");
5121 public override void visit_lambda_expression (LambdaExpression lambda
) {
5122 // use instance position from delegate
5123 var dt
= (DelegateType
) lambda
.target_type
;
5124 lambda
.method
.cinstance_parameter_position
= dt
.delegate_symbol
.cinstance_parameter_position
;
5126 lambda
.accept_children (this
);
5128 bool expr_owned
= lambda
.value_type
.value_owned
;
5130 set_cvalue (lambda
, new
CCodeIdentifier (lambda
.method
.get_cname ()));
5132 var delegate_type
= (DelegateType
) lambda
.target_type
;
5133 if (lambda
.method
.closure
) {
5134 int block_id
= get_block_id (current_closure_block
);
5135 var delegate_target
= get_variable_cexpression ("_data%d_".printf (block_id
));
5136 if (expr_owned
|| delegate_type
.is_called_once
) {
5137 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (block_id
)));
5138 ref_call
.add_argument (delegate_target
);
5139 delegate_target
= ref_call
;
5140 set_delegate_target_destroy_notify (lambda
, new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
5142 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5144 set_delegate_target (lambda
, delegate_target
);
5145 } else if (get_this_type () != null || in_constructor
) {
5146 CCodeExpression delegate_target
= get_result_cexpression ("self");
5147 if (expr_owned
|| delegate_type
.is_called_once
) {
5148 if (get_this_type () != null) {
5149 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (get_this_type (), lambda
.source_reference
));
5150 ref_call
.add_argument (delegate_target
);
5151 delegate_target
= ref_call
;
5152 set_delegate_target_destroy_notify (lambda
, get_destroy_func_expression (get_this_type ()));
5155 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_ref"));
5156 ref_call
.add_argument (delegate_target
);
5157 delegate_target
= ref_call
;
5158 set_delegate_target_destroy_notify (lambda
, new
CCodeIdentifier ("g_object_unref"));
5161 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5163 set_delegate_target (lambda
, delegate_target
);
5165 set_delegate_target (lambda
, new
CCodeConstant ("NULL"));
5166 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5170 public CCodeExpression
convert_from_generic_pointer (CCodeExpression cexpr
, DataType actual_type
) {
5172 if (is_reference_type_argument (actual_type
) || is_nullable_value_type_argument (actual_type
)) {
5173 result
= new
CCodeCastExpression (cexpr
, actual_type
.get_cname ());
5174 } else if (is_signed_integer_type_argument (actual_type
)) {
5175 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GPOINTER_TO_INT"));
5176 cconv
.add_argument (cexpr
);
5178 } else if (is_unsigned_integer_type_argument (actual_type
)) {
5179 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GPOINTER_TO_UINT"));
5180 cconv
.add_argument (cexpr
);
5186 public CCodeExpression
convert_to_generic_pointer (CCodeExpression cexpr
, DataType actual_type
) {
5188 if (is_signed_integer_type_argument (actual_type
)) {
5189 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GINT_TO_POINTER"));
5190 cconv
.add_argument (cexpr
);
5192 } else if (is_unsigned_integer_type_argument (actual_type
)) {
5193 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GUINT_TO_POINTER"));
5194 cconv
.add_argument (cexpr
);
5200 // manage memory and implicit casts
5201 public CCodeExpression
transform_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
5202 var cexpr
= source_cexpr
;
5203 if (expression_type
== null) {
5208 if (expression_type
.value_owned
5209 && expression_type
.floating_reference
) {
5210 /* floating reference, sink it.
5212 var cl
= expression_type
.data_type as ObjectTypeSymbol
;
5213 var sink_func
= (cl
!= null) ? cl
.get_ref_sink_function () : null;
5215 if (sink_func
!= null) {
5216 var csink
= new
CCodeFunctionCall (new
CCodeIdentifier (sink_func
));
5217 csink
.add_argument (cexpr
);
5221 Report
.error (null, "type `%s' does not support floating references".printf (expression_type
.data_type
.name
));
5225 bool boxing
= (expression_type is ValueType
&& !expression_type
.nullable
5226 && target_type is ValueType
&& target_type
.nullable
);
5227 bool unboxing
= (expression_type is ValueType
&& expression_type
.nullable
5228 && target_type is ValueType
&& !target_type
.nullable
);
5230 bool gvalue_boxing
= (context
.profile
== Profile
.GOBJECT
5231 && target_type
!= null
5232 && target_type
.data_type
== gvalue_type
5233 && !(expression_type is NullType
)
5234 && expression_type
.get_type_id () != "G_TYPE_VALUE");
5235 bool gvariant_boxing
= (context
.profile
== Profile
.GOBJECT
5236 && target_type
!= null
5237 && target_type
.data_type
== gvariant_type
5238 && !(expression_type is NullType
)
5239 && expression_type
.data_type
!= gvariant_type
);
5241 if (expression_type
.value_owned
5242 && (target_type
== null || !target_type
.value_owned
|| boxing
|| unboxing
)
5243 && !gvalue_boxing
/* gvalue can assume ownership of value, no need to free it */) {
5244 // value leaked, destroy it
5245 var pointer_type
= target_type as PointerType
;
5246 if (pointer_type
!= null && !(pointer_type
.base_type is VoidType
)) {
5247 // manual memory management for non-void pointers
5248 // treat void* special to not leak memory with void* method parameters
5249 } else if (requires_destroy (expression_type
)) {
5250 var decl
= get_temp_variable (expression_type
, true, expression_type
, false);
5251 emit_temp_var (decl
);
5252 temp_ref_vars
.insert (0, decl
);
5253 ccode
.add_assignment (get_variable_cexpression (decl
.name
), cexpr
);
5254 cexpr
= get_variable_cexpression (decl
.name
);
5256 if (expression_type is ArrayType
&& expr
!= null) {
5257 var array_type
= (ArrayType
) expression_type
;
5258 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5259 var len_decl
= new
LocalVariable (int_type
.copy (), get_array_length_cname (decl
.name
, dim
));
5260 emit_temp_var (len_decl
);
5261 ccode
.add_assignment (get_variable_cexpression (len_decl
.name
), get_array_length_cexpression (expr
, dim
));
5263 } else if (expression_type is DelegateType
&& expr
!= null) {
5264 var target_decl
= new
LocalVariable (new
PointerType (new
VoidType ()), get_delegate_target_cname (decl
.name
));
5265 emit_temp_var (target_decl
);
5266 var target_destroy_notify_decl
= new
LocalVariable (gdestroynotify_type
, get_delegate_target_destroy_notify_cname (decl
.name
));
5267 emit_temp_var (target_destroy_notify_decl
);
5268 CCodeExpression target_destroy_notify
;
5269 ccode
.add_assignment (get_variable_cexpression (target_decl
.name
), get_delegate_target_cexpression (expr
, out target_destroy_notify
));
5270 ccode
.add_assignment (get_variable_cexpression (target_destroy_notify_decl
.name
), target_destroy_notify
);
5276 if (target_type
== null) {
5277 // value will be destroyed, no need for implicit casts
5281 if (gvalue_boxing
) {
5282 // implicit conversion to GValue
5283 var decl
= get_temp_variable (target_type
, true, target_type
);
5284 emit_temp_var (decl
);
5286 if (!target_type
.value_owned
) {
5287 // boxed GValue leaked, destroy it
5288 temp_ref_vars
.insert (0, decl
);
5291 if (target_type
.nullable
) {
5292 var newcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
5293 newcall
.add_argument (new
CCodeConstant ("GValue"));
5294 newcall
.add_argument (new
CCodeConstant ("1"));
5295 var newassignment
= new
CCodeAssignment (get_variable_cexpression (decl
.name
), newcall
);
5296 ccode
.add_expression (newassignment
);
5299 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
5300 if (target_type
.nullable
) {
5301 ccall
.add_argument (get_variable_cexpression (decl
.name
));
5303 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
)));
5305 ccall
.add_argument (new
CCodeIdentifier (expression_type
.get_type_id ()));
5306 ccode
.add_expression (ccall
);
5308 if (requires_destroy (expression_type
)) {
5309 ccall
= new
CCodeFunctionCall (get_value_taker_function (expression_type
));
5311 ccall
= new
CCodeFunctionCall (get_value_setter_function (expression_type
));
5313 if (target_type
.nullable
) {
5314 ccall
.add_argument (get_variable_cexpression (decl
.name
));
5316 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
)));
5318 if (expression_type
.is_real_non_null_struct_type ()) {
5319 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
5321 ccall
.add_argument (cexpr
);
5324 ccode
.add_expression (ccall
);
5326 cexpr
= get_variable_cexpression (decl
.name
);
5329 } else if (gvariant_boxing
) {
5330 // implicit conversion to GVariant
5331 string variant_func
= "_variant_new%d".printf (++next_variant_function_id
);
5333 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (variant_func
));
5334 ccall
.add_argument (cexpr
);
5336 var cfunc
= new
CCodeFunction (variant_func
, "GVariant*");
5337 cfunc
.modifiers
= CCodeModifiers
.STATIC
;
5338 cfunc
.add_parameter (new
CCodeParameter ("value", expression_type
.get_cname ()));
5340 if (expression_type is ArrayType
) {
5341 // return array length if appropriate
5342 var array_type
= (ArrayType
) expression_type
;
5344 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5345 ccall
.add_argument (get_array_length_cexpression (expr
, dim
));
5346 cfunc
.add_parameter (new
CCodeParameter (get_array_length_cname ("value", dim
), "gint"));
5350 push_function (cfunc
);
5352 var result
= serialize_expression (expression_type
, new
CCodeIdentifier ("value"));
5354 // sink floating reference
5355 var sink
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_ref_sink"));
5356 sink
.add_argument (result
);
5357 ccode
.add_return (sink
);
5361 cfile
.add_function_declaration (cfunc
);
5362 cfile
.add_function (cfunc
);
5365 } else if (boxing
) {
5366 // value needs to be boxed
5368 var unary
= cexpr as CCodeUnaryExpression
;
5369 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
5371 cexpr
= unary
.inner
;
5372 } else if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
5373 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
5375 var decl
= get_temp_variable (expression_type
, expression_type
.value_owned
, expression_type
, false);
5376 emit_temp_var (decl
);
5378 ccode
.add_assignment (get_variable_cexpression (decl
.name
), cexpr
);
5379 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
));
5381 } else if (unboxing
) {
5384 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cexpr
);
5386 cexpr
= get_implicit_cast_expression (cexpr
, expression_type
, target_type
, expr
);
5389 if (target_type
.value_owned
&& (!expression_type
.value_owned
|| boxing
|| unboxing
)) {
5390 // need to copy value
5391 if (requires_copy (target_type
) && !(expression_type is NullType
)) {
5392 CodeNode node
= expr
;
5394 node
= expression_type
;
5397 var decl
= get_temp_variable (target_type
, true, node
, false);
5398 emit_temp_var (decl
);
5399 ccode
.add_assignment (get_variable_cexpression (decl
.name
), get_ref_cexpression (target_type
, cexpr
, expr
, node
));
5400 cexpr
= get_variable_cexpression (decl
.name
);
5407 public virtual CCodeExpression
get_implicit_cast_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
5408 var cexpr
= source_cexpr
;
5410 if (expression_type
.data_type
!= null && expression_type
.data_type
== target_type
.data_type
) {
5411 // same type, no cast required
5415 if (expression_type is NullType
) {
5416 // null literal, no cast required when not converting to generic type pointer
5420 generate_type_declaration (target_type
, cfile
);
5422 var cl
= target_type
.data_type as Class
;
5423 var iface
= target_type
.data_type as Interface
;
5424 if (context
.checking
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
5425 // checked cast for strict subtypes of GTypeInstance
5426 return generate_instance_cast (cexpr
, target_type
.data_type
);
5427 } else if (target_type
.data_type
!= null && expression_type
.get_cname () != target_type
.get_cname ()) {
5428 var st
= target_type
.data_type as Struct
;
5429 if (target_type
.data_type
.is_reference_type () || (st
!= null && st
.is_simple_type ())) {
5430 // don't cast non-simple structs
5431 return new
CCodeCastExpression (cexpr
, target_type
.get_cname ());
5440 public void store_property (Property prop
, Expression? instance
, TargetValue value
) {
5441 if (instance is BaseAccess
) {
5442 if (prop
.base_property
!= null) {
5443 var base_class
= (Class
) prop
.base_property
.parent_symbol
;
5444 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (base_class
.get_upper_case_cname (null))));
5445 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (current_class
.get_lower_case_cname (null))));
5447 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "set_%s".printf (prop
.name
)));
5448 ccall
.add_argument ((CCodeExpression
) get_ccodenode (instance
));
5449 ccall
.add_argument (get_cvalue_ (value
));
5451 ccode
.add_expression (ccall
);
5452 } else if (prop
.base_interface_property
!= null) {
5453 var base_iface
= (Interface
) prop
.base_interface_property
.parent_symbol
;
5454 string parent_iface_var
= "%s_%s_parent_iface".printf (current_class
.get_lower_case_cname (null), base_iface
.get_lower_case_cname (null));
5456 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), "set_%s".printf (prop
.name
)));
5457 ccall
.add_argument ((CCodeExpression
) get_ccodenode (instance
));
5458 ccall
.add_argument (get_cvalue_ (value
));
5460 ccode
.add_expression (ccall
);
5465 var set_func
= "g_object_set";
5467 var base_property
= prop
;
5468 if (!prop
.no_accessor_method
) {
5469 if (prop
.base_property
!= null) {
5470 base_property
= prop
.base_property
;
5471 } else if (prop
.base_interface_property
!= null) {
5472 base_property
= prop
.base_interface_property
;
5475 if (prop is DynamicProperty
) {
5476 set_func
= get_dynamic_property_setter_cname ((DynamicProperty
) prop
);
5478 generate_property_accessor_declaration (base_property
.set_accessor
, cfile
);
5479 set_func
= base_property
.set_accessor
.get_cname ();
5481 if (!prop
.external
&& prop
.external_package
) {
5482 // internal VAPI properties
5483 // only add them once per source file
5484 if (add_generated_external_symbol (prop
)) {
5485 visit_property (prop
);
5491 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (set_func
));
5493 if (prop
.binding
== MemberBinding
.INSTANCE
) {
5494 /* target instance is first argument */
5495 var cinstance
= (CCodeExpression
) get_ccodenode (instance
);
5497 if (prop
.parent_symbol is Struct
) {
5498 // we need to pass struct instance by reference
5499 var unary
= cinstance as CCodeUnaryExpression
;
5500 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
5502 cinstance
= unary
.inner
;
5503 } else if (cinstance is CCodeIdentifier
|| cinstance is CCodeMemberAccess
) {
5504 cinstance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cinstance
);
5506 // if instance is e.g. a function call, we can't take the address of the expression
5507 // (tmp = expr, &tmp)
5509 var temp_var
= get_temp_variable (instance
.target_type
, true, null, false);
5510 emit_temp_var (temp_var
);
5511 ccode
.add_assignment (get_variable_cexpression (temp_var
.name
), cinstance
);
5513 cinstance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
));
5517 ccall
.add_argument (cinstance
);
5520 if (prop
.no_accessor_method
) {
5521 /* property name is second argument of g_object_set */
5522 ccall
.add_argument (prop
.get_canonical_cconstant ());
5525 var cexpr
= get_cvalue_ (value
);
5527 if (prop
.property_type
.is_real_non_null_struct_type ()) {
5528 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
5531 var array_type
= prop
.property_type as ArrayType
;
5533 if (array_type
!= null && !prop
.no_array_length
) {
5534 var temp_var
= get_temp_variable (prop
.property_type
, true, null, false);
5535 emit_temp_var (temp_var
);
5536 ccode
.add_assignment (get_variable_cexpression (temp_var
.name
), cexpr
);
5537 ccall
.add_argument (get_variable_cexpression (temp_var
.name
));
5539 ccall
.add_argument (cexpr
);
5542 if (array_type
!= null && !prop
.no_array_length
) {
5543 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5544 ccall
.add_argument (get_array_length_cvalue (value
, dim
));
5546 } else if (prop
.property_type is DelegateType
) {
5547 var delegate_type
= (DelegateType
) prop
.property_type
;
5548 if (delegate_type
.delegate_symbol
.has_target
) {
5549 ccall
.add_argument (get_delegate_target_cvalue (value
));
5553 if (prop
.no_accessor_method
) {
5554 ccall
.add_argument (new
CCodeConstant ("NULL"));
5557 ccode
.add_expression (ccall
);
5560 public bool add_wrapper (string wrapper_name
) {
5561 return wrappers
.add (wrapper_name
);
5564 public bool add_generated_external_symbol (Symbol external_symbol
) {
5565 return generated_external_symbols
.add (external_symbol
);
5568 public static DataType
get_data_type_for_symbol (TypeSymbol sym
) {
5569 DataType type
= null;
5572 type
= new
ObjectType ((Class
) sym
);
5573 } else if (sym is Interface
) {
5574 type
= new
ObjectType ((Interface
) sym
);
5575 } else if (sym is Struct
) {
5576 var st
= (Struct
) sym
;
5577 if (st
.is_boolean_type ()) {
5578 type
= new
BooleanType (st
);
5579 } else if (st
.is_integer_type ()) {
5580 type
= new
IntegerType (st
);
5581 } else if (st
.is_floating_type ()) {
5582 type
= new
FloatingType (st
);
5584 type
= new
StructValueType (st
);
5586 } else if (sym is Enum
) {
5587 type
= new
EnumValueType ((Enum
) sym
);
5588 } else if (sym is ErrorDomain
) {
5589 type
= new
ErrorType ((ErrorDomain
) sym
, null);
5590 } else if (sym is ErrorCode
) {
5591 type
= new
ErrorType ((ErrorDomain
) sym
.parent_symbol
, (ErrorCode
) sym
);
5593 Report
.error (null, "internal error: `%s' is not a supported type".printf (sym
.get_full_name ()));
5594 return new
InvalidType ();
5600 public CCodeExpression?
default_value_for_type (DataType type
, bool initializer_expression
) {
5601 var st
= type
.data_type as Struct
;
5602 var array_type
= type as ArrayType
;
5603 if (initializer_expression
&& !type
.nullable
&&
5604 ((st
!= null && !st
.is_simple_type ()) ||
5605 (array_type
!= null && array_type
.fixed_length
))) {
5606 // 0-initialize struct with struct initializer { 0 }
5607 // only allowed as initializer expression in C
5608 var clist
= new
CCodeInitializerList ();
5609 clist
.append (new
CCodeConstant ("0"));
5611 } else if ((type
.data_type
!= null && type
.data_type
.is_reference_type ())
5613 || type is PointerType
|| type is DelegateType
5614 || (array_type
!= null && !array_type
.fixed_length
)) {
5615 return new
CCodeConstant ("NULL");
5616 } else if (type
.data_type
!= null && type
.data_type
.get_default_value () != null) {
5617 return new
CCodeConstant (type
.data_type
.get_default_value ());
5618 } else if (type
.type_parameter
!= null) {
5619 return new
CCodeConstant ("NULL");
5620 } else if (type is ErrorType
) {
5621 return new
CCodeConstant ("NULL");
5626 private void create_property_type_check_statement (Property prop
, bool check_return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
5627 if (check_return_type
) {
5628 create_type_check_statement (prop
, prop
.property_type
, t
, non_null
, var_name
);
5630 create_type_check_statement (prop
, new
VoidType (), t
, non_null
, var_name
);
5634 public void create_type_check_statement (CodeNode method_node
, DataType ret_type
, TypeSymbol t
, bool non_null
, string var_name
) {
5635 var ccheck
= new
CCodeFunctionCall ();
5637 if (!context
.assert
) {
5639 } else if (context
.checking
&& ((t is Class
&& !((Class
) t
).is_compact
) || t is Interface
)) {
5640 var ctype_check
= new
CCodeFunctionCall (new
CCodeIdentifier (get_type_check_function (t
)));
5641 ctype_check
.add_argument (new
CCodeIdentifier (var_name
));
5643 CCodeExpression cexpr
= ctype_check
;
5645 var cnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier (var_name
), new
CCodeConstant ("NULL"));
5647 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cnull
, ctype_check
);
5649 ccheck
.add_argument (cexpr
);
5650 } else if (!non_null
) {
5652 } else if (t
== glist_type
|| t
== gslist_type
) {
5653 // NULL is empty list
5656 var cnonnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier (var_name
), new
CCodeConstant ("NULL"));
5657 ccheck
.add_argument (cnonnull
);
5660 var cm
= method_node as CreationMethod
;
5661 if (cm
!= null && cm
.parent_symbol is ObjectTypeSymbol
) {
5662 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
5663 ccheck
.add_argument (new
CCodeConstant ("NULL"));
5664 } else if (ret_type is VoidType
) {
5666 ccheck
.call
= new
CCodeIdentifier ("g_return_if_fail");
5668 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
5670 var cdefault
= default_value_for_type (ret_type
, false);
5671 if (cdefault
!= null) {
5672 ccheck
.add_argument (cdefault
);
5678 ccode
.add_expression (ccheck
);
5681 public int get_param_pos (double param_pos
, bool ellipsis
= false) {
5683 if (param_pos
>= 0) {
5684 return (int) (param_pos
* 1000);
5686 return (int) ((100 + param_pos
) * 1000);
5689 if (param_pos
>= 0) {
5690 return (int) ((100 + param_pos
) * 1000);
5692 return (int) ((200 + param_pos
) * 1000);
5697 public CCodeExpression?
get_ccodenode (Expression node
) {
5698 if (get_cvalue (node
) == null) {
5701 return get_cvalue (node
);
5704 public override void visit_class (Class cl
) {
5707 public void create_postcondition_statement (Expression postcondition
) {
5708 var cassert
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_warn_if_fail"));
5710 postcondition
.emit (this
);
5712 cassert
.add_argument (get_cvalue (postcondition
));
5714 ccode
.add_expression (cassert
);
5717 public virtual bool is_gobject_property (Property prop
) {
5721 public DataType?
get_this_type () {
5722 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) {
5723 return current_method
.this_parameter
.variable_type
;
5724 } else if (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
) {
5725 return current_property_accessor
.prop
.this_parameter
.variable_type
;
5730 public CCodeFunctionCall
generate_instance_cast (CCodeExpression expr
, TypeSymbol type
) {
5731 var result
= new
CCodeFunctionCall (new
CCodeIdentifier (type
.get_upper_case_cname (null)));
5732 result
.add_argument (expr
);
5736 void generate_struct_destroy_function (Struct st
) {
5737 if (cfile
.add_declaration (st
.get_destroy_function ())) {
5738 // only generate function once per source file
5742 var function
= new
CCodeFunction (st
.get_destroy_function (), "void");
5743 function
.modifiers
= CCodeModifiers
.STATIC
;
5744 function
.add_parameter (new
CCodeParameter ("self", st
.get_cname () + "*"));
5746 push_function (function
);
5748 foreach (Field f
in st
.get_fields ()) {
5749 if (f
.binding
== MemberBinding
.INSTANCE
) {
5750 if (requires_destroy (f
.variable_type
)) {
5751 var this_access
= new MemberAccess
.simple ("this");
5752 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
5753 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
5755 ccode
.add_expression (destroy_field (f
, this_access
.target_value
));
5762 cfile
.add_function_declaration (function
);
5763 cfile
.add_function (function
);
5766 void generate_struct_copy_function (Struct st
) {
5767 if (cfile
.add_declaration (st
.get_copy_function ())) {
5768 // only generate function once per source file
5772 var function
= new
CCodeFunction (st
.get_copy_function (), "void");
5773 function
.modifiers
= CCodeModifiers
.STATIC
;
5774 function
.add_parameter (new
CCodeParameter ("self", "const " + st
.get_cname () + "*"));
5775 function
.add_parameter (new
CCodeParameter ("dest", st
.get_cname () + "*"));
5777 push_context (new
EmitContext ());
5778 push_function (function
);
5780 foreach (Field f
in st
.get_fields ()) {
5781 if (f
.binding
== MemberBinding
.INSTANCE
) {
5782 CCodeExpression copy
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.name
);
5783 if (requires_copy (f
.variable_type
)) {
5784 var this_access
= new MemberAccess
.simple ("this");
5785 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
5786 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
5787 var ma
= new
MemberAccess (this_access
, f
.name
);
5788 ma
.symbol_reference
= f
;
5789 ma
.value_type
= f
.variable_type
.copy ();
5790 visit_member_access (ma
);
5791 copy
= get_ref_cexpression (f
.variable_type
, copy
, ma
, f
);
5793 var dest
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("dest"), f
.name
);
5795 var array_type
= f
.variable_type as ArrayType
;
5796 if (array_type
!= null && array_type
.fixed_length
) {
5797 // fixed-length (stack-allocated) arrays
5798 cfile
.add_include ("string.h");
5800 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
5801 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
5802 var size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
);
5804 var array_copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
5805 array_copy_call
.add_argument (dest
);
5806 array_copy_call
.add_argument (copy
);
5807 array_copy_call
.add_argument (size
);
5808 ccode
.add_expression (array_copy_call
);
5810 ccode
.add_assignment (dest
, copy
);
5812 if (array_type
!= null && !f
.no_array_length
) {
5813 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5814 var len_src
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), get_array_length_cname (f
.name
, dim
));
5815 var len_dest
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("dest"), get_array_length_cname (f
.name
, dim
));
5816 ccode
.add_assignment (len_dest
, len_src
);
5826 cfile
.add_function_declaration (function
);
5827 cfile
.add_function (function
);
5830 public void return_default_value (DataType return_type
) {
5831 ccode
.add_return (default_value_for_type (return_type
, false));
5834 public virtual string?
get_custom_creturn_type (Method m
) {
5838 public virtual void generate_dynamic_method_wrapper (DynamicMethod method
) {
5841 public virtual bool method_has_wrapper (Method method
) {
5845 public virtual CCodeFunctionCall
get_param_spec (Property prop
) {
5846 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
5849 public virtual CCodeFunctionCall
get_signal_creation (Signal sig
, TypeSymbol type
) {
5850 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
5853 public virtual void register_dbus_info (CCodeBlock block
, ObjectTypeSymbol bindable
) {
5856 public virtual string get_dynamic_property_getter_cname (DynamicProperty node
) {
5857 Report
.error (node
.source_reference
, "dynamic properties are not supported for %s".printf (node
.dynamic_type
.to_string ()));
5861 public virtual string get_dynamic_property_setter_cname (DynamicProperty node
) {
5862 Report
.error (node
.source_reference
, "dynamic properties are not supported for %s".printf (node
.dynamic_type
.to_string ()));
5866 public virtual string get_dynamic_signal_cname (DynamicSignal node
) {
5870 public virtual string get_dynamic_signal_connect_wrapper_name (DynamicSignal node
) {
5874 public virtual string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal node
) {
5878 public virtual string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node
) {
5882 public virtual void generate_marshaller (List
<Parameter
> params
, DataType return_type
, bool dbus
= false) {
5885 public virtual string get_marshaller_function (List
<Parameter
> params
, DataType return_type
, string? prefix
= null, bool dbus
= false) {
5889 public virtual string get_array_length_cname (string array_cname
, int dim
) {
5893 public virtual string get_parameter_array_length_cname (Parameter param
, int dim
) {
5897 public virtual CCodeExpression
get_array_length_cexpression (Expression array_expr
, int dim
= -1) {
5898 return new
CCodeConstant ("");
5901 public virtual CCodeExpression
get_array_length_cvalue (TargetValue value
, int dim
= -1) {
5902 return new
CCodeInvalidExpression ();
5905 public virtual string get_array_size_cname (string array_cname
) {
5909 public virtual void add_simple_check (CodeNode node
, bool always_fails
= false) {
5912 public virtual string generate_ready_function (Method m
) {
5916 public CCodeExpression?
get_cvalue (Expression expr
) {
5917 if (expr
.target_value
== null) {
5920 var glib_value
= (GLibValue
) expr
.target_value
;
5921 return glib_value
.cvalue
;
5924 public CCodeExpression?
get_cvalue_ (TargetValue value
) {
5925 var glib_value
= (GLibValue
) value
;
5926 return glib_value
.cvalue
;
5929 public void set_cvalue (Expression expr
, CCodeExpression? cvalue
) {
5930 var glib_value
= (GLibValue
) expr
.target_value
;
5931 if (glib_value
== null) {
5932 glib_value
= new
GLibValue (expr
.value_type
);
5933 expr
.target_value
= glib_value
;
5935 glib_value
.cvalue
= cvalue
;
5938 public CCodeExpression?
get_array_size_cvalue (TargetValue value
) {
5939 var glib_value
= (GLibValue
) value
;
5940 return glib_value
.array_size_cvalue
;
5943 public void set_array_size_cvalue (TargetValue value
, CCodeExpression? cvalue
) {
5944 var glib_value
= (GLibValue
) value
;
5945 glib_value
.array_size_cvalue
= cvalue
;
5948 public CCodeExpression?
get_delegate_target (Expression expr
) {
5949 if (expr
.target_value
== null) {
5952 var glib_value
= (GLibValue
) expr
.target_value
;
5953 return glib_value
.delegate_target_cvalue
;
5956 public void set_delegate_target (Expression expr
, CCodeExpression? delegate_target
) {
5957 var glib_value
= (GLibValue
) expr
.target_value
;
5958 if (glib_value
== null) {
5959 glib_value
= new
GLibValue (expr
.value_type
);
5960 expr
.target_value
= glib_value
;
5962 glib_value
.delegate_target_cvalue
= delegate_target
;
5965 public CCodeExpression?
get_delegate_target_destroy_notify (Expression expr
) {
5966 if (expr
.target_value
== null) {
5969 var glib_value
= (GLibValue
) expr
.target_value
;
5970 return glib_value
.delegate_target_destroy_notify_cvalue
;
5973 public void set_delegate_target_destroy_notify (Expression expr
, CCodeExpression? destroy_notify
) {
5974 var glib_value
= (GLibValue
) expr
.target_value
;
5975 if (glib_value
== null) {
5976 glib_value
= new
GLibValue (expr
.value_type
);
5977 expr
.target_value
= glib_value
;
5979 glib_value
.delegate_target_destroy_notify_cvalue
= destroy_notify
;
5982 public void append_array_length (Expression expr
, CCodeExpression size
) {
5983 var glib_value
= (GLibValue
) expr
.target_value
;
5984 if (glib_value
== null) {
5985 glib_value
= new
GLibValue (expr
.value_type
);
5986 expr
.target_value
= glib_value
;
5988 glib_value
.append_array_length_cvalue (size
);
5991 public List
<CCodeExpression
>?
get_array_lengths (Expression expr
) {
5992 var glib_value
= (GLibValue
) expr
.target_value
;
5993 if (glib_value
== null) {
5994 glib_value
= new
GLibValue (expr
.value_type
);
5995 expr
.target_value
= glib_value
;
5997 return glib_value
.array_length_cvalues
;
6001 public class Vala
.GLibValue
: TargetValue
{
6002 public CCodeExpression cvalue
;
6004 public List
<CCodeExpression
> array_length_cvalues
;
6005 public CCodeExpression? array_size_cvalue
;
6007 public CCodeExpression? delegate_target_cvalue
;
6008 public CCodeExpression? delegate_target_destroy_notify_cvalue
;
6010 public GLibValue (DataType? value_type
= null, CCodeExpression? cvalue
= null) {
6012 this
.cvalue
= cvalue
;
6015 public void append_array_length_cvalue (CCodeExpression length_cvalue
) {
6016 if (array_length_cvalues
== null) {
6017 array_length_cvalues
= new ArrayList
<CCodeExpression
> ();
6019 array_length_cvalues
.add (length_cvalue
);
6022 public GLibValue
copy () {
6023 var result
= new
GLibValue (value_type
.copy (), cvalue
);
6025 if (array_length_cvalues
!= null) {
6026 foreach (var cexpr
in array_length_cvalues
) {
6027 result
.append_array_length_cvalue (cexpr
);
6030 result
.array_size_cvalue
= array_size_cvalue
;
6032 result
.delegate_target_cvalue
= delegate_target_cvalue
;
6033 result
.delegate_target_destroy_notify_cvalue
= delegate_target_destroy_notify_cvalue
;