1 /* valaccodebasemodule.vala
3 * Copyright (C) 2006-2012 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
<TargetValue
> temp_ref_values
= new ArrayList
<TargetValue
> ();
38 public int next_temp_var_id
;
39 public bool current_method_inner_error
;
40 public bool current_method_return
;
41 public int next_coroutine_state
= 1;
42 public Map
<string,string> variable_name_map
= new HashMap
<string,string> (str_hash
, str_equal
);
43 public Map
<string,int> closure_variable_count_map
= new HashMap
<string,int> (str_hash
, str_equal
);
44 public Map
<LocalVariable
,int> closure_variable_clash_map
= new HashMap
<LocalVariable
,int> ();
46 public EmitContext (Symbol? symbol
= null) {
47 current_symbol
= symbol
;
50 public void push_symbol (Symbol symbol
) {
51 symbol_stack
.add (current_symbol
);
52 current_symbol
= symbol
;
55 public void pop_symbol () {
56 current_symbol
= symbol_stack
.remove_at (symbol_stack
.size
- 1);
60 public CodeContext context
{ get; set; }
62 public Symbol root_symbol
;
64 public EmitContext emit_context
= new
EmitContext ();
66 List
<EmitContext
> emit_context_stack
= new ArrayList
<EmitContext
> ();
68 public CCodeLineDirective? current_line
= null;
70 List
<CCodeLineDirective
> line_directive_stack
= new ArrayList
<CCodeLineDirective
> ();
72 public Symbol current_symbol
{ get { return emit_context
.current_symbol
; } }
74 public TryStatement current_try
{
75 get { return emit_context
.current_try
; }
76 set { emit_context
.current_try
= value
; }
79 public CatchClause current_catch
{
80 get { return emit_context
.current_catch
; }
81 set { emit_context
.current_catch
= value
; }
84 public TypeSymbol? current_type_symbol
{
86 var sym
= current_symbol
;
88 if (sym is TypeSymbol
) {
89 return (TypeSymbol
) sym
;
91 sym
= sym
.parent_symbol
;
97 public Class? current_class
{
98 get { return current_type_symbol as Class
; }
101 public Method? current_method
{
103 var sym
= current_symbol
;
104 while (sym is Block
) {
105 sym
= sym
.parent_symbol
;
107 return sym as Method
;
111 public PropertyAccessor? current_property_accessor
{
113 var sym
= current_symbol
;
114 while (sym is Block
) {
115 sym
= sym
.parent_symbol
;
117 return sym as PropertyAccessor
;
121 public Constructor? current_constructor
{
123 var sym
= current_symbol
;
124 while (sym is Block
) {
125 sym
= sym
.parent_symbol
;
127 return sym as Constructor
;
131 public Destructor? current_destructor
{
133 var sym
= current_symbol
;
134 while (sym is Block
) {
135 sym
= sym
.parent_symbol
;
137 return sym as Destructor
;
141 public DataType? current_return_type
{
143 var m
= current_method
;
145 return m
.return_type
;
148 var acc
= current_property_accessor
;
151 return acc
.value_type
;
157 if (is_in_constructor () || is_in_destructor ()) {
165 public bool is_in_coroutine () {
166 return current_method
!= null && current_method
.coroutine
;
169 public bool is_in_constructor () {
170 if (current_method
!= null) {
171 // make sure to not return true in lambda expression inside constructor
174 var sym
= current_symbol
;
175 while (sym
!= null) {
176 if (sym is Constructor
) {
179 sym
= sym
.parent_symbol
;
184 public bool is_in_destructor () {
185 if (current_method
!= null) {
186 // make sure to not return true in lambda expression inside constructor
189 var sym
= current_symbol
;
190 while (sym
!= null) {
191 if (sym is Destructor
) {
194 sym
= sym
.parent_symbol
;
199 public Block? current_closure_block
{
201 return next_closure_block (current_symbol
);
205 public unowned Block?
next_closure_block (Symbol sym
) {
207 unowned Method method
= sym as Method
;
208 if (method
!= null && !method
.closure
) {
209 // parent blocks are not captured by this method
213 unowned Block block
= sym as Block
;
214 if (method
== null && block
== null) {
219 if (block
!= null && block
.captured
) {
220 // closure block found
223 sym
= sym
.parent_symbol
;
228 public CCodeFile header_file
;
229 public CCodeFile internal_header_file
;
230 public CCodeFile cfile
;
232 public EmitContext class_init_context
;
233 public EmitContext base_init_context
;
234 public EmitContext class_finalize_context
;
235 public EmitContext base_finalize_context
;
236 public EmitContext instance_init_context
;
237 public EmitContext instance_finalize_context
;
239 public CCodeStruct param_spec_struct
;
240 public CCodeStruct closure_struct
;
241 public CCodeEnum prop_enum
;
242 public CCodeEnum signal_enum
;
244 public CCodeFunction ccode
{ get { return emit_context
.ccode
; } }
246 /* temporary variables that own their content */
247 public ArrayList
<TargetValue
> temp_ref_values
{ get { return emit_context
.temp_ref_values
; } }
248 /* cache to check whether a certain marshaller has been created yet */
249 public Set
<string> user_marshal_set
;
250 /* (constant) hash table with all predefined marshallers */
251 public Set
<string> predefined_marshal_set
;
252 /* (constant) hash table with all reserved identifiers in the generated code */
253 Set
<string> reserved_identifiers
;
255 public int next_temp_var_id
{
256 get { return emit_context
.next_temp_var_id
; }
257 set { emit_context
.next_temp_var_id
= value
; }
260 public int next_regex_id
= 0;
261 public bool in_creation_method
{ get { return current_method is CreationMethod
; } }
263 public bool current_method_inner_error
{
264 get { return emit_context
.current_method_inner_error
; }
265 set { emit_context
.current_method_inner_error
= value
; }
268 public bool current_method_return
{
269 get { return emit_context
.current_method_return
; }
270 set { emit_context
.current_method_return
= value
; }
273 int next_block_id
= 0;
274 Map
<Block
,int> block_map
= new HashMap
<Block
,int> ();
276 public DataType void_type
= new
VoidType ();
277 public DataType bool_type
;
278 public DataType char_type
;
279 public DataType uchar_type
;
280 public DataType? unichar_type
;
281 public DataType short_type
;
282 public DataType ushort_type
;
283 public DataType int_type
;
284 public DataType uint_type
;
285 public DataType long_type
;
286 public DataType ulong_type
;
287 public DataType int8_type
;
288 public DataType uint8_type
;
289 public DataType int16_type
;
290 public DataType uint16_type
;
291 public DataType int32_type
;
292 public DataType uint32_type
;
293 public DataType int64_type
;
294 public DataType uint64_type
;
295 public DataType string_type
;
296 public DataType regex_type
;
297 public DataType float_type
;
298 public DataType double_type
;
299 public TypeSymbol gtype_type
;
300 public TypeSymbol gobject_type
;
301 public ErrorType gerror_type
;
302 public Class glist_type
;
303 public Class gslist_type
;
304 public Class gnode_type
;
305 public Class gqueue_type
;
306 public Class gvaluearray_type
;
307 public TypeSymbol gstringbuilder_type
;
308 public TypeSymbol garray_type
;
309 public TypeSymbol gbytearray_type
;
310 public TypeSymbol gptrarray_type
;
311 public TypeSymbol gthreadpool_type
;
312 public DataType gdestroynotify_type
;
313 public DataType gquark_type
;
314 public Struct gvalue_type
;
315 public Class gvariant_type
;
316 public Struct mutex_type
;
317 public Struct gmutex_type
;
318 public Struct grecmutex_type
;
319 public Struct grwlock_type
;
320 public Struct gcond_type
;
321 public Class gsource_type
;
322 public TypeSymbol type_module_type
;
323 public TypeSymbol dbus_proxy_type
;
324 public Class gtk_widget_type
;
326 public bool in_plugin
= false;
327 public string module_init_param_name
;
329 public bool gvaluecollector_h_needed
;
330 public bool requires_assert
;
331 public bool requires_array_free
;
332 public bool requires_array_move
;
333 public bool requires_array_length
;
334 public bool requires_clear_mutex
;
336 public Set
<string> wrappers
;
337 Set
<Symbol
> generated_external_symbols
;
339 public Map
<string,string> variable_name_map
{ get { return emit_context
.variable_name_map
; } }
341 public static int ccode_attribute_cache_index
= CodeNode
.get_attribute_cache_index ();
343 public CCodeBaseModule () {
344 predefined_marshal_set
= new HashSet
<string> (str_hash
, str_equal
);
345 predefined_marshal_set
.add ("VOID:VOID");
346 predefined_marshal_set
.add ("VOID:BOOLEAN");
347 predefined_marshal_set
.add ("VOID:CHAR");
348 predefined_marshal_set
.add ("VOID:UCHAR");
349 predefined_marshal_set
.add ("VOID:INT");
350 predefined_marshal_set
.add ("VOID:UINT");
351 predefined_marshal_set
.add ("VOID:LONG");
352 predefined_marshal_set
.add ("VOID:ULONG");
353 predefined_marshal_set
.add ("VOID:ENUM");
354 predefined_marshal_set
.add ("VOID:FLAGS");
355 predefined_marshal_set
.add ("VOID:FLOAT");
356 predefined_marshal_set
.add ("VOID:DOUBLE");
357 predefined_marshal_set
.add ("VOID:STRING");
358 predefined_marshal_set
.add ("VOID:POINTER");
359 predefined_marshal_set
.add ("VOID:OBJECT");
360 predefined_marshal_set
.add ("STRING:OBJECT,POINTER");
361 predefined_marshal_set
.add ("VOID:UINT,POINTER");
362 predefined_marshal_set
.add ("BOOLEAN:FLAGS");
363 predefined_marshal_set
.add ("VOID:BOXED");
364 predefined_marshal_set
.add ("VOID:VARIANT");
365 predefined_marshal_set
.add ("BOOLEAN:BOXED,BOXED");
367 reserved_identifiers
= new HashSet
<string> (str_hash
, str_equal
);
370 reserved_identifiers
.add ("_Bool");
371 reserved_identifiers
.add ("_Complex");
372 reserved_identifiers
.add ("_Imaginary");
373 reserved_identifiers
.add ("asm");
374 reserved_identifiers
.add ("auto");
375 reserved_identifiers
.add ("break");
376 reserved_identifiers
.add ("case");
377 reserved_identifiers
.add ("char");
378 reserved_identifiers
.add ("const");
379 reserved_identifiers
.add ("continue");
380 reserved_identifiers
.add ("default");
381 reserved_identifiers
.add ("do");
382 reserved_identifiers
.add ("double");
383 reserved_identifiers
.add ("else");
384 reserved_identifiers
.add ("enum");
385 reserved_identifiers
.add ("extern");
386 reserved_identifiers
.add ("float");
387 reserved_identifiers
.add ("for");
388 reserved_identifiers
.add ("goto");
389 reserved_identifiers
.add ("if");
390 reserved_identifiers
.add ("inline");
391 reserved_identifiers
.add ("int");
392 reserved_identifiers
.add ("long");
393 reserved_identifiers
.add ("register");
394 reserved_identifiers
.add ("restrict");
395 reserved_identifiers
.add ("return");
396 reserved_identifiers
.add ("short");
397 reserved_identifiers
.add ("signed");
398 reserved_identifiers
.add ("sizeof");
399 reserved_identifiers
.add ("static");
400 reserved_identifiers
.add ("struct");
401 reserved_identifiers
.add ("switch");
402 reserved_identifiers
.add ("typedef");
403 reserved_identifiers
.add ("union");
404 reserved_identifiers
.add ("unsigned");
405 reserved_identifiers
.add ("void");
406 reserved_identifiers
.add ("volatile");
407 reserved_identifiers
.add ("while");
410 reserved_identifiers
.add ("_Alignas");
411 reserved_identifiers
.add ("_Alignof");
412 reserved_identifiers
.add ("_Atomic");
413 reserved_identifiers
.add ("_Generic");
414 reserved_identifiers
.add ("_Noreturn");
415 reserved_identifiers
.add ("_Static_assert");
416 reserved_identifiers
.add ("_Thread_local");
419 reserved_identifiers
.add ("cdecl");
421 // reserved for Vala/GObject naming conventions
422 reserved_identifiers
.add ("error");
423 reserved_identifiers
.add ("result");
424 reserved_identifiers
.add ("self");
427 public override void emit (CodeContext context
) {
428 this
.context
= context
;
430 root_symbol
= context
.root
;
432 bool_type
= new
BooleanType ((Struct
) root_symbol
.scope
.lookup ("bool"));
433 char_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("char"));
434 uchar_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uchar"));
435 short_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("short"));
436 ushort_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ushort"));
437 int_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int"));
438 uint_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint"));
439 long_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("long"));
440 ulong_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ulong"));
441 int8_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int8"));
442 uint8_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint8"));
443 int16_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int16"));
444 uint16_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint16"));
445 int32_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int32"));
446 uint32_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint32"));
447 int64_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int64"));
448 uint64_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint64"));
449 float_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("float"));
450 double_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("double"));
451 string_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("string"));
452 var unichar_struct
= (Struct
) root_symbol
.scope
.lookup ("unichar");
453 if (unichar_struct
!= null) {
454 unichar_type
= new
IntegerType (unichar_struct
);
457 if (context
.profile
== Profile
.GOBJECT
) {
458 var glib_ns
= root_symbol
.scope
.lookup ("GLib");
460 gtype_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Type");
461 gobject_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Object");
462 gerror_type
= new
ErrorType (null, null);
463 glist_type
= (Class
) glib_ns
.scope
.lookup ("List");
464 gslist_type
= (Class
) glib_ns
.scope
.lookup ("SList");
465 gnode_type
= (Class
) glib_ns
.scope
.lookup ("Node");
466 gqueue_type
= (Class
) glib_ns
.scope
.lookup ("Queue");
467 gvaluearray_type
= (Class
) glib_ns
.scope
.lookup ("ValueArray");
468 gstringbuilder_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("StringBuilder");
469 garray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Array");
470 gbytearray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("ByteArray");
471 gptrarray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("PtrArray");
472 gthreadpool_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("ThreadPool");
473 gdestroynotify_type
= new
DelegateType ((Delegate
) glib_ns
.scope
.lookup ("DestroyNotify"));
475 gquark_type
= new
IntegerType ((Struct
) glib_ns
.scope
.lookup ("Quark"));
476 gvalue_type
= (Struct
) glib_ns
.scope
.lookup ("Value");
477 gvariant_type
= (Class
) glib_ns
.scope
.lookup ("Variant");
478 gsource_type
= (Class
) glib_ns
.scope
.lookup ("Source");
480 gmutex_type
= (Struct
) glib_ns
.scope
.lookup ("Mutex");
481 grecmutex_type
= (Struct
) glib_ns
.scope
.lookup ("RecMutex");
482 grwlock_type
= (Struct
) glib_ns
.scope
.lookup ("RWLock");
483 gcond_type
= (Struct
) glib_ns
.scope
.lookup ("Cond");
485 mutex_type
= grecmutex_type
;
487 type_module_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("TypeModule");
489 regex_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("GLib").scope
.lookup ("Regex"));
491 if (context
.module_init_method
!= null) {
492 foreach (Parameter parameter
in context
.module_init_method
.get_parameters ()) {
493 if (parameter
.variable_type
.data_type
.is_subtype_of (type_module_type
)) {
495 module_init_param_name
= parameter
.name
;
502 dbus_proxy_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("DBusProxy");
505 var gtk_ns
= root_symbol
.scope
.lookup ("Gtk");
506 if (gtk_ns
!= null) {
507 gtk_widget_type
= (Class
) gtk_ns
.scope
.lookup ("Widget");
510 header_file
= new
CCodeFile ();
511 header_file
.is_header
= true;
512 internal_header_file
= new
CCodeFile ();
513 internal_header_file
.is_header
= true;
515 /* we're only interested in non-pkg source files */
516 var source_files
= context
.get_source_files ();
517 foreach (SourceFile file
in source_files
) {
518 if (file
.file_type
== SourceFileType
.SOURCE
||
519 (context
.header_filename
!= null && file
.file_type
== SourceFileType
.FAST
)) {
524 // generate symbols file for public API
525 if (context
.symbols_filename
!= null) {
526 var stream
= FileStream
.open (context
.symbols_filename
, "w");
527 if (stream
== null) {
528 Report
.error (null, "unable to open `%s' for writing".printf (context
.symbols_filename
));
533 foreach (string symbol
in header_file
.get_symbols ()) {
534 stream
.puts (symbol
);
541 // generate C header file for public API
542 if (context
.header_filename
!= null) {
544 if (context
.profile
== Profile
.GOBJECT
) {
545 ret
= header_file
.store (context
.header_filename
, null, context
.version_header
, false, "G_BEGIN_DECLS", "G_END_DECLS");
547 ret
= header_file
.store (context
.header_filename
, null, context
.version_header
, false);
550 Report
.error (null, "unable to open `%s' for writing".printf (context
.header_filename
));
554 // generate C header file for internal API
555 if (context
.internal_header_filename
!= null) {
557 if (context
.profile
== Profile
.GOBJECT
) {
558 ret
= internal_header_file
.store (context
.internal_header_filename
, null, context
.version_header
, false, "G_BEGIN_DECLS", "G_END_DECLS");
560 ret
= internal_header_file
.store (context
.internal_header_filename
, null, context
.version_header
, false);
563 Report
.error (null, "unable to open `%s' for writing".printf (context
.internal_header_filename
));
570 public void push_context (EmitContext emit_context
) {
571 if (this
.emit_context
!= null) {
572 emit_context_stack
.add (this
.emit_context
);
575 this
.emit_context
= emit_context
;
577 ccode
.current_line
= current_line
;
581 public void pop_context () {
582 if (emit_context_stack
.size
> 0) {
583 this
.emit_context
= emit_context_stack
.remove_at (emit_context_stack
.size
- 1);
585 ccode
.current_line
= current_line
;
588 this
.emit_context
= null;
592 public void push_line (SourceReference? source_reference
) {
593 line_directive_stack
.add (current_line
);
594 if (source_reference
!= null) {
595 current_line
= new
CCodeLineDirective (source_reference
.file
.get_relative_filename (), source_reference
.begin
.line
);
597 ccode
.current_line
= current_line
;
602 public void pop_line () {
603 current_line
= line_directive_stack
.remove_at (line_directive_stack
.size
- 1);
605 ccode
.current_line
= current_line
;
609 public void push_function (CCodeFunction func
) {
610 emit_context
.ccode_stack
.add (ccode
);
611 emit_context
.ccode
= func
;
612 ccode
.current_line
= current_line
;
615 public void pop_function () {
616 emit_context
.ccode
= emit_context
.ccode_stack
.remove_at (emit_context
.ccode_stack
.size
- 1);
618 ccode
.current_line
= current_line
;
622 public bool add_symbol_declaration (CCodeFile decl_space
, Symbol sym
, string name
) {
623 if (decl_space
.add_declaration (name
)) {
626 if (sym
.source_reference
!= null) {
627 sym
.source_reference
.file
.used
= true;
630 return !decl_space
.is_header
&& CodeContext
.get ().use_header
;
632 if (sym
.external_package
|| (!decl_space
.is_header
&& CodeContext
.get ().use_header
&& !sym
.is_internal_symbol ())) {
633 // add feature test macros
634 foreach (unowned
string feature_test_macro
in get_ccode_feature_test_macros (sym
).split (",")) {
635 decl_space
.add_feature_test_macro (feature_test_macro
);
637 // add appropriate include file
638 foreach (unowned
string header_filename
in get_ccode_header_filenames (sym
).split (",")) {
639 decl_space
.add_include (header_filename
, !sym
.external_package
||
640 (sym
.external_package
&&
641 sym
.from_commandline
));
643 // declaration complete
646 // require declaration
651 public CCodeIdentifier
get_value_setter_function (DataType type_reference
) {
652 var array_type
= type_reference as ArrayType
;
653 if (type_reference
.data_type
!= null) {
654 return new
CCodeIdentifier (get_ccode_set_value_function (type_reference
.data_type
));
655 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
657 return new
CCodeIdentifier ("g_value_set_boxed");
659 return new
CCodeIdentifier ("g_value_set_pointer");
663 public CCodeIdentifier
get_value_taker_function (DataType type_reference
) {
664 var array_type
= type_reference as ArrayType
;
665 if (type_reference
.data_type
!= null) {
666 return new
CCodeIdentifier (get_ccode_take_value_function (type_reference
.data_type
));
667 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
669 return new
CCodeIdentifier ("g_value_take_boxed");
671 return new
CCodeIdentifier ("g_value_set_pointer");
675 CCodeIdentifier
get_value_getter_function (DataType type_reference
) {
676 var array_type
= type_reference as ArrayType
;
677 if (type_reference
.data_type
!= null) {
678 return new
CCodeIdentifier (get_ccode_get_value_function (type_reference
.data_type
));
679 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
681 return new
CCodeIdentifier ("g_value_get_boxed");
683 return new
CCodeIdentifier ("g_value_get_pointer");
687 public virtual void append_vala_array_free () {
690 public virtual void append_vala_array_move () {
693 public virtual void append_vala_array_length () {
696 public void append_vala_clear_mutex (string typename
, string funcprefix
) {
698 cfile
.add_include ("string.h");
700 var fun
= new
CCodeFunction ("_vala_clear_" + typename
);
701 fun
.modifiers
= CCodeModifiers
.STATIC
;
702 fun
.add_parameter (new
CCodeParameter ("mutex", typename
+ " *"));
706 ccode
.add_declaration (typename
, new CCodeVariableDeclarator
.zero ("zero_mutex", new
CCodeConstant ("{ 0 }")));
708 var cmp
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcmp"));
709 cmp
.add_argument (new
CCodeIdentifier ("mutex"));
710 cmp
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("zero_mutex")));
711 cmp
.add_argument (new
CCodeIdentifier ("sizeof (" + typename
+ ")"));
714 var mutex_clear
= new
CCodeFunctionCall (new
CCodeIdentifier (funcprefix
+ "_clear"));
715 mutex_clear
.add_argument (new
CCodeIdentifier ("mutex"));
716 ccode
.add_expression (mutex_clear
);
718 var mset
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
719 mset
.add_argument (new
CCodeIdentifier ("mutex"));
720 mset
.add_argument (new
CCodeConstant ("0"));
721 mset
.add_argument (new
CCodeIdentifier ("sizeof (" + typename
+ ")"));
722 ccode
.add_expression (mset
);
728 cfile
.add_function_declaration (fun
);
729 cfile
.add_function (fun
);
732 public override void visit_source_file (SourceFile source_file
) {
733 cfile
= new
CCodeFile ();
735 user_marshal_set
= new HashSet
<string> (str_hash
, str_equal
);
739 gvaluecollector_h_needed
= false;
740 requires_assert
= false;
741 requires_array_free
= false;
742 requires_array_move
= false;
743 requires_array_length
= false;
744 requires_clear_mutex
= false;
746 wrappers
= new HashSet
<string> (str_hash
, str_equal
);
747 generated_external_symbols
= new HashSet
<Symbol
> ();
749 if (context
.profile
== Profile
.GOBJECT
) {
750 header_file
.add_include ("glib.h");
751 internal_header_file
.add_include ("glib.h");
752 cfile
.add_include ("glib.h");
753 cfile
.add_include ("glib-object.h");
756 source_file
.accept_children (this
);
758 if (context
.report
.get_errors () > 0) {
762 /* For fast-vapi, we only wanted the header declarations
763 * to be emitted, so bail out here without writing the
766 if (source_file
.file_type
== SourceFileType
.FAST
) {
770 if (requires_assert
) {
771 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("_vala_assert(expr, msg)", new
CCodeConstant ("if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);")));
772 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("_vala_return_if_fail(expr, msg)", new
CCodeConstant ("if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }")));
773 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("_vala_return_val_if_fail(expr, msg, val)", new
CCodeConstant ("if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }")));
774 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("_vala_warn_if_fail(expr, msg)", new
CCodeConstant ("if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);")));
776 if (requires_array_free
) {
777 append_vala_array_free ();
779 if (requires_array_move
) {
780 append_vala_array_move ();
782 if (requires_array_length
) {
783 append_vala_array_length ();
785 if (requires_clear_mutex
) {
786 append_vala_clear_mutex ("GMutex", "g_mutex");
787 append_vala_clear_mutex ("GRecMutex", "g_rec_mutex");
788 append_vala_clear_mutex ("GRWLock", "g_rw_lock");
789 append_vala_clear_mutex ("GCond", "g_cond");
792 if (gvaluecollector_h_needed
) {
793 cfile
.add_include ("gobject/gvaluecollector.h");
796 var comments
= source_file
.get_comments();
797 if (comments
!= null) {
798 foreach (Comment comment
in comments
) {
799 var ccomment
= new
CCodeComment (comment
.content
);
800 cfile
.add_comment (ccomment
);
804 if (!cfile
.store (source_file
.get_csource_filename (), source_file
.filename
, context
.version_header
, context
.debug
)) {
805 Report
.error (null, "unable to open `%s' for writing".printf (source_file
.get_csource_filename ()));
811 public virtual bool generate_enum_declaration (Enum en
, CCodeFile decl_space
) {
812 if (add_symbol_declaration (decl_space
, en
, get_ccode_name (en
))) {
816 var cenum
= new
CCodeEnum (get_ccode_name (en
));
818 cenum
.modifiers
|= (en
.version
.deprecated ? CCodeModifiers
.DEPRECATED
: 0);
821 foreach (EnumValue ev
in en
.get_values ()) {
823 if (ev
.value
== null) {
824 c_ev
= new
CCodeEnumValue (get_ccode_name (ev
));
826 c_ev
.value
= new
CCodeConstant ("1 << %d".printf (flag_shift
));
830 ev
.value
.emit (this
);
831 c_ev
= new
CCodeEnumValue (get_ccode_name (ev
), get_cvalue (ev
.value
));
833 c_ev
.modifiers
|= (ev
.version
.deprecated ? CCodeModifiers
.DEPRECATED
: 0);
834 cenum
.add_value (c_ev
);
837 decl_space
.add_type_definition (cenum
);
838 decl_space
.add_type_definition (new
CCodeNewline ());
840 if (!get_ccode_has_type_id (en
)) {
844 decl_space
.add_include ("glib-object.h");
845 decl_space
.add_type_declaration (new
CCodeNewline ());
847 var macro
= "(%s_get_type ())".printf (get_ccode_lower_case_name (en
, null));
848 decl_space
.add_type_declaration (new
CCodeMacroReplacement (get_ccode_type_id (en
), macro
));
850 var fun_name
= "%s_get_type".printf (get_ccode_lower_case_name (en
, null));
851 var regfun
= new
CCodeFunction (fun_name
, "GType");
852 regfun
.modifiers
= CCodeModifiers
.CONST
;
854 if (en
.is_private_symbol ()) {
855 // avoid C warning as this function is not always used
856 regfun
.modifiers
|= CCodeModifiers
.STATIC
| CCodeModifiers
.UNUSED
;
857 } else if (context
.hide_internal
&& en
.is_internal_symbol ()) {
858 regfun
.modifiers
|= CCodeModifiers
.INTERNAL
;
861 decl_space
.add_function_declaration (regfun
);
866 public override void visit_enum (Enum en
) {
867 push_line (en
.source_reference
);
869 en
.accept_children (this
);
871 if (en
.comment
!= null) {
872 cfile
.add_type_member_definition (new
CCodeComment (en
.comment
.content
));
875 generate_enum_declaration (en
, cfile
);
877 if (!en
.is_internal_symbol ()) {
878 generate_enum_declaration (en
, header_file
);
880 if (!en
.is_private_symbol ()) {
881 generate_enum_declaration (en
, internal_header_file
);
887 public void visit_member (Symbol m
) {
888 /* stuff meant for all lockable members */
889 if (m is Lockable
&& ((Lockable
) m
).lock_used
) {
890 CCodeExpression l
= new
CCodeIdentifier ("self");
891 var init_context
= class_init_context
;
892 var finalize_context
= class_finalize_context
;
894 if (m
.is_instance_member ()) {
895 l
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (l
, "priv"), get_symbol_lock_name (get_ccode_name (m
)));
896 init_context
= instance_init_context
;
897 finalize_context
= instance_finalize_context
;
898 } else if (m
.is_class_member ()) {
899 TypeSymbol parent
= (TypeSymbol
)m
.parent_symbol
;
901 var get_class_private_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(get_ccode_upper_case_name (parent
))));
902 get_class_private_call
.add_argument (new
CCodeIdentifier ("klass"));
903 l
= new CCodeMemberAccess
.pointer (get_class_private_call
, get_symbol_lock_name (get_ccode_name (m
)));
905 l
= new
CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf (get_ccode_lower_case_name (m
.parent_symbol
), get_ccode_name (m
))));
908 push_context (init_context
);
909 var initf
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_name (mutex_type
.default_construction_method
)));
910 initf
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
911 ccode
.add_expression (initf
);
914 if (finalize_context
!= null) {
915 push_context (finalize_context
);
916 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_rec_mutex_clear"));
917 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
918 ccode
.add_expression (fc
);
924 private void constant_array_ranks_sizes (InitializerList initializer_list
, int[] sizes
, int rank
= 0) {
925 sizes
[rank
] = int.max (sizes
[rank
], initializer_list
.size
);
927 foreach (var expr
in initializer_list
.get_initializers()) {
928 if (expr is InitializerList
&& ((InitializerList
) expr
).target_type is ArrayType
) {
929 constant_array_ranks_sizes ((InitializerList
) expr
, sizes
, rank
);
934 public void generate_constant_declaration (Constant c
, CCodeFile decl_space
, bool definition
= false) {
935 if (c
.parent_symbol is Block
) {
940 if (add_symbol_declaration (decl_space
, c
, get_ccode_name (c
))) {
945 generate_type_declaration (c
.type_reference
, decl_space
);
949 var initializer_list
= c
.value as InitializerList
;
950 if (initializer_list
!= null) {
951 var cdecl
= new
CCodeDeclaration (get_ccode_const_name (c
.type_reference
));
953 if (c
.type_reference is ArrayType
) {
954 var array
= (ArrayType
) c
.type_reference
;
955 int[] sizes
= new
int[array
.rank
];
956 constant_array_ranks_sizes (initializer_list
, sizes
);
957 for (int i
= 0; i
< array
.rank
; i
++) {
958 arr
+= "[%d]".printf (sizes
[i
]);
962 var cinitializer
= get_cvalue (c
.value
);
964 // never output value in header
965 // special case needed as this method combines declaration and definition
969 cdecl
.add_declarator (new
CCodeVariableDeclarator ("%s%s".printf (get_ccode_name (c
), arr
), cinitializer
));
970 if (c
.is_private_symbol ()) {
971 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
973 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
976 decl_space
.add_constant_declaration (cdecl
);
978 var cdefine
= new CCodeMacroReplacement
.with_expression (get_ccode_name (c
), get_cvalue (c
.value
));
979 decl_space
.add_type_member_declaration (cdefine
);
984 public override void visit_constant (Constant c
) {
985 push_line (c
.source_reference
);
987 if (c
.parent_symbol is Block
) {
990 generate_type_declaration (c
.type_reference
, cfile
);
994 string type_name
= get_ccode_const_name (c
.type_reference
);
996 if (c
.type_reference is ArrayType
) {
997 var array
= (ArrayType
) c
.type_reference
;
998 var initializer_list
= c
.value as InitializerList
;
999 if (initializer_list
!= null) {
1000 int[] sizes
= new
int[array
.rank
];
1001 constant_array_ranks_sizes (initializer_list
, sizes
);
1002 for (int i
= 0; i
< array
.rank
; i
++) {
1003 arr
+= "[%d]".printf (sizes
[i
]);
1008 if (c
.type_reference
.compatible (string_type
)) {
1009 type_name
= "const char";
1013 var cinitializer
= get_cvalue (c
.value
);
1015 ccode
.add_declaration (type_name
, new
CCodeVariableDeclarator ("%s%s".printf (get_ccode_name (c
), arr
), cinitializer
), CCodeModifiers
.STATIC
);
1017 generate_constant_declaration (c
, cfile
, true);
1019 if (!c
.is_internal_symbol ()) {
1020 generate_constant_declaration (c
, header_file
);
1022 if (!c
.is_private_symbol ()) {
1023 generate_constant_declaration (c
, internal_header_file
);
1030 public void generate_field_declaration (Field f
, CCodeFile decl_space
) {
1031 if (add_symbol_declaration (decl_space
, f
, get_ccode_name (f
))) {
1035 generate_type_declaration (f
.variable_type
, decl_space
);
1037 var cdecl
= new
CCodeDeclaration (get_ccode_name (f
.variable_type
));
1038 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_ccode_name (f
), null, get_ccode_declarator_suffix (f
.variable_type
)));
1039 if (f
.is_private_symbol ()) {
1040 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
1042 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
1044 if (f
.version
.deprecated
) {
1045 cdecl
.modifiers
|= CCodeModifiers
.DEPRECATED
;
1047 if (f
.is_volatile
) {
1048 cdecl
.modifiers
|= CCodeModifiers
.VOLATILE
;
1050 decl_space
.add_type_member_declaration (cdecl
);
1053 // Declare mutex for static member
1054 var flock
= new
CCodeDeclaration (get_ccode_name (mutex_type
));
1055 var flock_decl
= new
CCodeVariableDeclarator (get_symbol_lock_name ("%s_%s".printf (get_ccode_lower_case_name (f
.parent_symbol
), get_ccode_name (f
))), new
CCodeConstant ("{0}"));
1056 flock
.add_declarator (flock_decl
);
1058 if (f
.is_private_symbol ()) {
1059 flock
.modifiers
= CCodeModifiers
.STATIC
;
1060 } else if (context
.hide_internal
&& f
.is_internal_symbol ()) {
1061 flock
.modifiers
= CCodeModifiers
.INTERNAL
;
1063 flock
.modifiers
= CCodeModifiers
.EXTERN
;
1065 decl_space
.add_type_member_declaration (flock
);
1068 if (f
.variable_type is ArrayType
&& get_ccode_array_length (f
)) {
1069 var array_type
= (ArrayType
) f
.variable_type
;
1071 if (!array_type
.fixed_length
) {
1072 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1073 var len_type
= int_type
.copy ();
1075 cdecl
= new
CCodeDeclaration (get_ccode_name (len_type
));
1076 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (get_ccode_name (f
), dim
)));
1077 if (f
.is_private_symbol ()) {
1078 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
1079 } else if (context
.hide_internal
&& f
.is_internal_symbol ()) {
1080 cdecl
.modifiers
= CCodeModifiers
.INTERNAL
;
1082 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
1084 decl_space
.add_type_member_declaration (cdecl
);
1087 } else if (f
.variable_type is DelegateType
&& get_ccode_delegate_target (f
)) {
1088 var delegate_type
= (DelegateType
) f
.variable_type
;
1089 if (delegate_type
.delegate_symbol
.has_target
) {
1090 // create field to store delegate target
1092 cdecl
= new
CCodeDeclaration ("gpointer");
1093 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_ccode_delegate_target_name (f
)));
1094 if (f
.is_private_symbol ()) {
1095 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
1096 } else if (context
.hide_internal
&& f
.is_internal_symbol ()) {
1097 cdecl
.modifiers
= CCodeModifiers
.INTERNAL
;
1099 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
1101 decl_space
.add_type_member_declaration (cdecl
);
1103 if (delegate_type
.is_disposable ()) {
1104 cdecl
= new
CCodeDeclaration ("GDestroyNotify");
1105 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (get_ccode_name (f
))));
1106 if (f
.is_private_symbol ()) {
1107 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
1108 } else if (context
.hide_internal
&& f
.is_internal_symbol ()) {
1109 cdecl
.modifiers
= CCodeModifiers
.INTERNAL
;
1111 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
1113 decl_space
.add_type_member_declaration (cdecl
);
1119 public override void visit_field (Field f
) {
1120 push_line (f
.source_reference
);
1123 check_type (f
.variable_type
);
1125 var cl
= f
.parent_symbol as Class
;
1126 bool is_gtypeinstance
= (cl
!= null && !cl
.is_compact
);
1128 CCodeExpression lhs
= null;
1130 if (f
.binding
== MemberBinding
.INSTANCE
) {
1131 if (is_gtypeinstance
&& f
.access
== SymbolAccessibility
.PRIVATE
) {
1132 lhs
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), get_ccode_name (f
));
1134 lhs
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), get_ccode_name (f
));
1137 if (f
.initializer
!= null) {
1138 push_context (instance_init_context
);
1140 f
.initializer
.emit (this
);
1142 var rhs
= get_cvalue (f
.initializer
);
1143 if (!is_simple_struct_creation (f
, f
.initializer
)) {
1144 // otherwise handled in visit_object_creation_expression
1146 ccode
.add_assignment (lhs
, rhs
);
1148 if (f
.variable_type is ArrayType
&& get_ccode_array_length (f
)) {
1149 var array_type
= (ArrayType
) f
.variable_type
;
1150 var field_value
= get_field_cvalue (f
, load_this_parameter ((TypeSymbol
) f
.parent_symbol
));
1152 var glib_value
= (GLibValue
) f
.initializer
.target_value
;
1153 if (glib_value
.array_length_cvalues
!= null) {
1154 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1155 var array_len_lhs
= get_array_length_cvalue (field_value
, dim
);
1156 ccode
.add_assignment (array_len_lhs
, get_array_length_cvalue (glib_value
, dim
));
1158 } else if (glib_value
.array_null_terminated
) {
1159 requires_array_length
= true;
1160 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
1161 len_call
.add_argument (get_cvalue_ (glib_value
));
1163 ccode
.add_assignment (get_array_length_cvalue (field_value
, 1), len_call
);
1165 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1166 ccode
.add_assignment (get_array_length_cvalue (field_value
, dim
), new
CCodeConstant ("-1"));
1170 if (array_type
.rank
== 1 && f
.is_internal_symbol ()) {
1171 var lhs_array_size
= get_array_size_cvalue (field_value
);
1172 var rhs_array_len
= get_array_length_cvalue (field_value
, 1);
1173 ccode
.add_assignment (lhs_array_size
, rhs_array_len
);
1175 } else if (f
.variable_type is DelegateType
&& get_ccode_delegate_target (f
)) {
1176 var delegate_type
= (DelegateType
) f
.variable_type
;
1177 if (delegate_type
.delegate_symbol
.has_target
) {
1178 var field_value
= get_field_cvalue (f
, load_this_parameter ((TypeSymbol
) f
.parent_symbol
));
1180 ccode
.add_assignment (get_delegate_target_cvalue (field_value
), new
CCodeIdentifier ("self"));
1181 if (delegate_type
.is_disposable ()) {
1182 ccode
.add_assignment (get_delegate_target_destroy_notify_cvalue (field_value
), new
CCodeIdentifier ("NULL"));
1188 foreach (var value
in temp_ref_values
) {
1189 ccode
.add_expression (destroy_value (value
));
1192 temp_ref_values
.clear ();
1197 if (get_ccode_delegate_target (f
) && requires_destroy (f
.variable_type
) && instance_finalize_context
!= null) {
1198 push_context (instance_finalize_context
);
1199 ccode
.add_expression (destroy_field (f
, load_this_parameter ((TypeSymbol
) f
.parent_symbol
)));
1202 } else if (f
.binding
== MemberBinding
.CLASS
) {
1203 if (!is_gtypeinstance
) {
1204 Report
.error (f
.source_reference
, "class fields are not supported in compact classes");
1209 if (f
.access
== SymbolAccessibility
.PRIVATE
) {
1210 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (get_ccode_upper_case_name (cl
))));
1211 ccall
.add_argument (new
CCodeIdentifier ("klass"));
1212 lhs
= new
CCodeMemberAccess (ccall
, get_ccode_name (f
), true);
1214 lhs
= new
CCodeMemberAccess (new
CCodeIdentifier ("klass"), get_ccode_name (f
), true);
1217 if (f
.initializer
!= null) {
1218 push_context (class_init_context
);
1220 f
.initializer
.emit (this
);
1222 var rhs
= get_cvalue (f
.initializer
);
1224 ccode
.add_assignment (lhs
, rhs
);
1226 foreach (var value
in temp_ref_values
) {
1227 ccode
.add_expression (destroy_value (value
));
1230 temp_ref_values
.clear ();
1235 generate_field_declaration (f
, cfile
);
1237 if (!f
.is_internal_symbol ()) {
1238 generate_field_declaration (f
, header_file
);
1240 if (!f
.is_private_symbol ()) {
1241 generate_field_declaration (f
, internal_header_file
);
1245 lhs
= new
CCodeIdentifier (get_ccode_name (f
));
1247 var var_decl
= new
CCodeVariableDeclarator (get_ccode_name (f
), null, get_ccode_declarator_suffix (f
.variable_type
));
1248 var_decl
.initializer
= default_value_for_type (f
.variable_type
, true);
1250 if (class_init_context
!= null) {
1251 push_context (class_init_context
);
1253 push_context (new
EmitContext ());
1256 if (f
.initializer
!= null) {
1257 f
.initializer
.emit (this
);
1259 var init
= get_cvalue (f
.initializer
);
1260 if (is_constant_ccode_expression (init
)) {
1261 var_decl
.initializer
= init
;
1265 var var_def
= new
CCodeDeclaration (get_ccode_name (f
.variable_type
));
1266 var_def
.add_declarator (var_decl
);
1267 if (!f
.is_private_symbol ()) {
1268 var_def
.modifiers
= CCodeModifiers
.EXTERN
;
1270 var_def
.modifiers
= CCodeModifiers
.STATIC
;
1272 if (f
.version
.deprecated
) {
1273 var_def
.modifiers
|= CCodeModifiers
.DEPRECATED
;
1275 if (f
.is_volatile
) {
1276 var_def
.modifiers
|= CCodeModifiers
.VOLATILE
;
1278 cfile
.add_type_member_declaration (var_def
);
1280 /* add array length fields where necessary */
1281 if (f
.variable_type is ArrayType
&& get_ccode_array_length (f
)) {
1282 var array_type
= (ArrayType
) f
.variable_type
;
1284 if (!array_type
.fixed_length
) {
1285 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1286 var len_type
= int_type
.copy ();
1288 var len_def
= new
CCodeDeclaration (get_ccode_name (len_type
));
1289 len_def
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (get_ccode_name (f
), dim
), new
CCodeConstant ("0")));
1290 if (!f
.is_private_symbol ()) {
1291 len_def
.modifiers
= CCodeModifiers
.EXTERN
;
1293 len_def
.modifiers
= CCodeModifiers
.STATIC
;
1295 cfile
.add_type_member_declaration (len_def
);
1298 if (array_type
.rank
== 1 && f
.is_internal_symbol ()) {
1299 var len_type
= int_type
.copy ();
1301 var cdecl
= new
CCodeDeclaration (get_ccode_name (len_type
));
1302 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_size_cname (get_ccode_name (f
)), new
CCodeConstant ("0")));
1303 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
1304 cfile
.add_type_member_declaration (cdecl
);
1307 } else if (f
.variable_type is DelegateType
&& get_ccode_delegate_target (f
)) {
1308 var delegate_type
= (DelegateType
) f
.variable_type
;
1309 if (delegate_type
.delegate_symbol
.has_target
) {
1310 // create field to store delegate target
1312 var target_def
= new
CCodeDeclaration ("gpointer");
1313 target_def
.add_declarator (new
CCodeVariableDeclarator (get_ccode_delegate_target_name (f
), new
CCodeConstant ("NULL")));
1314 if (!f
.is_private_symbol ()) {
1315 target_def
.modifiers
= CCodeModifiers
.EXTERN
;
1317 target_def
.modifiers
= CCodeModifiers
.STATIC
;
1319 cfile
.add_type_member_declaration (target_def
);
1321 if (delegate_type
.is_disposable ()) {
1322 var target_destroy_notify_def
= new
CCodeDeclaration ("GDestroyNotify");
1323 target_destroy_notify_def
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (get_ccode_name (f
)), new
CCodeConstant ("NULL")));
1324 if (!f
.is_private_symbol ()) {
1325 target_destroy_notify_def
.modifiers
= CCodeModifiers
.EXTERN
;
1327 target_destroy_notify_def
.modifiers
= CCodeModifiers
.STATIC
;
1329 cfile
.add_type_member_declaration (target_destroy_notify_def
);
1335 if (f
.initializer
!= null) {
1336 var rhs
= get_cvalue (f
.initializer
);
1337 if (!is_constant_ccode_expression (rhs
)) {
1338 if (is_gtypeinstance
) {
1339 if (f
.initializer is InitializerList
) {
1340 ccode
.open_block ();
1342 var temp_decl
= get_temp_variable (f
.variable_type
);
1343 var vardecl
= new CCodeVariableDeclarator
.zero (temp_decl
.name
, rhs
);
1344 ccode
.add_declaration (get_ccode_name (temp_decl
.variable_type
), vardecl
);
1346 var tmp
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
1347 ccode
.add_assignment (lhs
, tmp
);
1351 ccode
.add_assignment (lhs
, rhs
);
1354 if (f
.variable_type is ArrayType
&& get_ccode_array_length (f
)) {
1355 var array_type
= (ArrayType
) f
.variable_type
;
1356 var field_value
= get_field_cvalue (f
, null);
1358 var glib_value
= (GLibValue
) f
.initializer
.target_value
;
1359 if (glib_value
.array_length_cvalues
!= null) {
1360 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1361 var array_len_lhs
= get_array_length_cvalue (field_value
, dim
);
1362 ccode
.add_assignment (array_len_lhs
, get_array_length_cvalue (glib_value
, dim
));
1364 } else if (glib_value
.array_null_terminated
) {
1365 requires_array_length
= true;
1366 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
1367 len_call
.add_argument (get_cvalue_ (glib_value
));
1369 ccode
.add_assignment (get_array_length_cvalue (field_value
, 1), len_call
);
1371 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1372 ccode
.add_assignment (get_array_length_cvalue (field_value
, dim
), new
CCodeConstant ("-1"));
1378 Report
.error (f
.source_reference
, "Non-constant field initializers not supported in this context");
1391 public bool is_constant_ccode_expression (CCodeExpression cexpr
) {
1392 if (cexpr is CCodeConstant
) {
1394 } else if (cexpr is CCodeCastExpression
) {
1395 var ccast
= (CCodeCastExpression
) cexpr
;
1396 return is_constant_ccode_expression (ccast
.inner
);
1397 } else if (cexpr is CCodeUnaryExpression
) {
1398 var cunary
= (CCodeUnaryExpression
) cexpr
;
1399 switch (cunary
.operator
) {
1400 case CCodeUnaryOperator
.PREFIX_INCREMENT
:
1401 case CCodeUnaryOperator
.PREFIX_DECREMENT
:
1402 case CCodeUnaryOperator
.POSTFIX_INCREMENT
:
1403 case CCodeUnaryOperator
.POSTFIX_DECREMENT
:
1406 return is_constant_ccode_expression (cunary
.inner
);
1407 } else if (cexpr is CCodeBinaryExpression
) {
1408 var cbinary
= (CCodeBinaryExpression
) cexpr
;
1409 return is_constant_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
1412 var cparenthesized
= (cexpr as CCodeParenthesizedExpression
);
1413 return (null != cparenthesized
&& is_constant_ccode_expression (cparenthesized
.inner
));
1417 * Returns whether the passed cexpr is a pure expression, i.e. an
1418 * expression without side-effects.
1420 public bool is_pure_ccode_expression (CCodeExpression cexpr
) {
1421 if (cexpr is CCodeConstant
|| cexpr is CCodeIdentifier
) {
1423 } else if (cexpr is CCodeBinaryExpression
) {
1424 var cbinary
= (CCodeBinaryExpression
) cexpr
;
1425 return is_pure_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
1426 } else if (cexpr is CCodeUnaryExpression
) {
1427 var cunary
= (CCodeUnaryExpression
) cexpr
;
1428 switch (cunary
.operator
) {
1429 case CCodeUnaryOperator
.PREFIX_INCREMENT
:
1430 case CCodeUnaryOperator
.PREFIX_DECREMENT
:
1431 case CCodeUnaryOperator
.POSTFIX_INCREMENT
:
1432 case CCodeUnaryOperator
.POSTFIX_DECREMENT
:
1435 return is_pure_ccode_expression (cunary
.inner
);
1437 } else if (cexpr is CCodeMemberAccess
) {
1438 var cma
= (CCodeMemberAccess
) cexpr
;
1439 return is_pure_ccode_expression (cma
.inner
);
1440 } else if (cexpr is CCodeElementAccess
) {
1441 var cea
= (CCodeElementAccess
) cexpr
;
1442 return is_pure_ccode_expression (cea
.container
) && is_pure_ccode_expression (cea
.index
);
1443 } else if (cexpr is CCodeCastExpression
) {
1444 var ccast
= (CCodeCastExpression
) cexpr
;
1445 return is_pure_ccode_expression (ccast
.inner
);
1446 } else if (cexpr is CCodeParenthesizedExpression
) {
1447 var cparenthesized
= (CCodeParenthesizedExpression
) cexpr
;
1448 return is_pure_ccode_expression (cparenthesized
.inner
);
1454 public override void visit_formal_parameter (Parameter p
) {
1456 check_type (p
.variable_type
);
1460 public override void visit_property (Property prop
) {
1461 visit_member (prop
);
1463 check_type (prop
.property_type
);
1465 if (prop
.get_accessor
!= null) {
1466 prop
.get_accessor
.accept (this
);
1468 if (prop
.set_accessor
!= null) {
1469 prop
.set_accessor
.accept (this
);
1473 public void generate_type_declaration (DataType type
, CCodeFile decl_space
) {
1474 if (type is ObjectType
) {
1475 var object_type
= (ObjectType
) type
;
1476 if (object_type
.type_symbol is Class
) {
1477 generate_class_declaration ((Class
) object_type
.type_symbol
, decl_space
);
1478 } else if (object_type
.type_symbol is Interface
) {
1479 generate_interface_declaration ((Interface
) object_type
.type_symbol
, decl_space
);
1481 } else if (type is DelegateType
) {
1482 var deleg_type
= (DelegateType
) type
;
1483 var d
= deleg_type
.delegate_symbol
;
1484 generate_delegate_declaration (d
, decl_space
);
1485 } else if (type
.data_type is Enum
) {
1486 var en
= (Enum
) type
.data_type
;
1487 generate_enum_declaration (en
, decl_space
);
1488 } else if (type is ValueType
) {
1489 var value_type
= (ValueType
) type
;
1490 generate_struct_declaration ((Struct
) value_type
.type_symbol
, decl_space
);
1491 } else if (type is ArrayType
) {
1492 var array_type
= (ArrayType
) type
;
1493 generate_type_declaration (array_type
.element_type
, decl_space
);
1494 } else if (type is ErrorType
) {
1495 var error_type
= (ErrorType
) type
;
1496 if (error_type
.error_domain
!= null) {
1497 generate_error_domain_declaration (error_type
.error_domain
, decl_space
);
1499 } else if (type is PointerType
) {
1500 var pointer_type
= (PointerType
) type
;
1501 generate_type_declaration (pointer_type
.base_type
, decl_space
);
1504 foreach (DataType type_arg
in type
.get_type_arguments ()) {
1505 generate_type_declaration (type_arg
, decl_space
);
1509 public virtual void generate_class_struct_declaration (Class cl
, CCodeFile decl_space
) {
1512 public virtual void generate_struct_declaration (Struct st
, CCodeFile decl_space
) {
1515 public virtual void generate_delegate_declaration (Delegate d
, CCodeFile decl_space
) {
1518 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) {
1521 public void generate_property_accessor_declaration (PropertyAccessor acc
, CCodeFile decl_space
) {
1522 if (add_symbol_declaration (decl_space
, acc
, get_ccode_name (acc
))) {
1526 var prop
= (Property
) acc
.prop
;
1528 bool returns_real_struct
= acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ();
1531 CCodeParameter cvalueparam
;
1532 if (returns_real_struct
) {
1533 cvalueparam
= new
CCodeParameter ("result", "%s *".printf (get_ccode_name (acc
.value_type
)));
1534 } else if (!acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ()) {
1535 cvalueparam
= new
CCodeParameter ("value", "%s *".printf (get_ccode_name (acc
.value_type
)));
1537 cvalueparam
= new
CCodeParameter ("value", get_ccode_name (acc
.value_type
));
1539 generate_type_declaration (acc
.value_type
, decl_space
);
1541 CCodeFunction function
;
1542 if (acc
.readable
&& !returns_real_struct
) {
1543 function
= new
CCodeFunction (get_ccode_name (acc
), get_ccode_name (acc
.value_type
));
1545 function
= new
CCodeFunction (get_ccode_name (acc
), "void");
1548 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1549 var t
= (TypeSymbol
) prop
.parent_symbol
;
1550 var this_type
= get_data_type_for_symbol (t
);
1551 generate_type_declaration (this_type
, decl_space
);
1552 var cselfparam
= new
CCodeParameter ("self", get_ccode_name (this_type
));
1553 if (t is Struct
&& !((Struct
) t
).is_simple_type ()) {
1554 cselfparam
.type_name
+= "*";
1557 function
.add_parameter (cselfparam
);
1560 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1561 function
.add_parameter (cvalueparam
);
1564 if (acc
.value_type is ArrayType
) {
1565 var array_type
= (ArrayType
) acc
.value_type
;
1566 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1567 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), acc
.readable ?
"int*" : "int"));
1569 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1570 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1571 if (!acc
.readable
&& acc
.value_type
.value_owned
) {
1572 function
.add_parameter (new
CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1576 if (prop
.version
.deprecated
) {
1577 function
.modifiers
|= CCodeModifiers
.DEPRECATED
;
1580 if (!prop
.is_abstract
1581 && (prop
.is_private_symbol () || (!acc
.readable
&& !acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
)) {
1582 function
.modifiers
|= CCodeModifiers
.STATIC
;
1583 } else if (context
.hide_internal
&& (prop
.is_internal_symbol () || acc
.access
== SymbolAccessibility
.INTERNAL
)) {
1584 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
1586 decl_space
.add_function_declaration (function
);
1589 public override void visit_property_accessor (PropertyAccessor acc
) {
1590 push_context (new
EmitContext (acc
));
1591 push_line (acc
.source_reference
);
1593 var prop
= (Property
) acc
.prop
;
1595 if (acc
.comment
!= null) {
1596 cfile
.add_type_member_definition (new
CCodeComment (acc
.comment
.content
));
1599 bool returns_real_struct
= acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ();
1601 if (acc
.result_var
!= null) {
1602 acc
.result_var
.accept (this
);
1605 var t
= (TypeSymbol
) prop
.parent_symbol
;
1607 if (acc
.construction
&& !t
.is_subtype_of (gobject_type
)) {
1608 Report
.error (acc
.source_reference
, "construct properties require GLib.Object");
1611 } else if (acc
.construction
&& !is_gobject_property (prop
)) {
1612 Report
.error (acc
.source_reference
, "construct properties not supported for specified property type");
1617 // do not declare overriding properties and interface implementations
1618 if (prop
.is_abstract
|| prop
.is_virtual
1619 || (prop
.base_property
== null && prop
.base_interface_property
== null)) {
1620 generate_property_accessor_declaration (acc
, cfile
);
1622 // do not declare construct-only properties in header files
1623 if (acc
.readable
|| acc
.writable
) {
1624 if (!prop
.is_internal_symbol ()
1625 && (acc
.access
== SymbolAccessibility
.PUBLIC
1626 || acc
.access
== SymbolAccessibility
.PROTECTED
)) {
1627 generate_property_accessor_declaration (acc
, header_file
);
1629 if (!prop
.is_private_symbol () && acc
.access
!= SymbolAccessibility
.PRIVATE
) {
1630 generate_property_accessor_declaration (acc
, internal_header_file
);
1635 if (acc
.source_type
== SourceFileType
.FAST
) {
1640 var this_type
= get_data_type_for_symbol (t
);
1641 var cselfparam
= new
CCodeParameter ("self", get_ccode_name (this_type
));
1642 if (t is Struct
&& !((Struct
) t
).is_simple_type ()) {
1643 cselfparam
.type_name
+= "*";
1645 CCodeParameter cvalueparam
;
1646 if (returns_real_struct
) {
1647 cvalueparam
= new
CCodeParameter ("result", "%s *".printf (get_ccode_name (acc
.value_type
)));
1648 } else if (!acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ()) {
1649 cvalueparam
= new
CCodeParameter ("value", "%s *".printf (get_ccode_name (acc
.value_type
)));
1651 cvalueparam
= new
CCodeParameter ("value", get_ccode_name (acc
.value_type
));
1654 if (prop
.is_abstract
|| prop
.is_virtual
) {
1655 CCodeFunction function
;
1656 if (acc
.readable
&& !returns_real_struct
) {
1657 function
= new
CCodeFunction (get_ccode_name (acc
), get_ccode_name (current_return_type
));
1659 function
= new
CCodeFunction (get_ccode_name (acc
), "void");
1661 function
.add_parameter (cselfparam
);
1662 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1663 function
.add_parameter (cvalueparam
);
1666 if (acc
.value_type is ArrayType
) {
1667 var array_type
= (ArrayType
) acc
.value_type
;
1668 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1669 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), acc
.readable ?
"int*" : "int"));
1671 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1672 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1673 if (!acc
.readable
&& acc
.value_type
.value_owned
) {
1674 function
.add_parameter (new
CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1678 if (!prop
.is_abstract
1679 && (prop
.is_private_symbol () || !(acc
.readable
|| acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
)) {
1680 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1681 function
.modifiers
|= CCodeModifiers
.STATIC
;
1682 } else if (context
.hide_internal
&& (prop
.is_internal_symbol () || acc
.access
== SymbolAccessibility
.INTERNAL
)) {
1683 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
1686 push_function (function
);
1688 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1689 if (!acc
.readable
|| returns_real_struct
) {
1690 create_property_type_check_statement (prop
, false, t
, true, "self");
1692 create_property_type_check_statement (prop
, true, t
, true, "self");
1696 CCodeExpression vcast
;
1697 if (prop
.parent_symbol is Interface
) {
1698 var iface
= (Interface
) prop
.parent_symbol
;
1700 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface
, null))));
1701 ((CCodeFunctionCall
) vcast
).add_argument (new
CCodeIdentifier ("self"));
1703 var cl
= (Class
) prop
.parent_symbol
;
1704 if (!cl
.is_compact
) {
1705 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (cl
, null))));
1706 ((CCodeFunctionCall
) vcast
).add_argument (new
CCodeIdentifier ("self"));
1708 vcast
= new
CCodeIdentifier ("self");
1713 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "get_%s".printf (prop
.name
)));
1714 vcall
.add_argument (new
CCodeIdentifier ("self"));
1715 if (returns_real_struct
) {
1716 vcall
.add_argument (new
CCodeIdentifier ("result"));
1717 ccode
.add_expression (vcall
);
1719 if (acc
.value_type is ArrayType
) {
1720 var array_type
= (ArrayType
) acc
.value_type
;
1722 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1723 var len_expr
= new
CCodeIdentifier (get_array_length_cname ("result", dim
));
1724 vcall
.add_argument (len_expr
);
1726 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1727 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_cname ("result")));
1730 ccode
.add_return (vcall
);
1733 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "set_%s".printf (prop
.name
)));
1734 vcall
.add_argument (new
CCodeIdentifier ("self"));
1735 vcall
.add_argument (new
CCodeIdentifier ("value"));
1737 if (acc
.value_type is ArrayType
) {
1738 var array_type
= (ArrayType
) acc
.value_type
;
1740 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1741 var len_expr
= new
CCodeIdentifier (get_array_length_cname ("value", dim
));
1742 vcall
.add_argument (len_expr
);
1744 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1745 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_cname ("value")));
1746 if (!acc
.readable
&& acc
.value_type
.value_owned
) {
1747 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_destroy_notify_cname ("value")));
1751 ccode
.add_expression (vcall
);
1756 cfile
.add_function (function
);
1759 if (!prop
.is_abstract
&& acc
.body
!= null) {
1760 bool is_virtual
= prop
.base_property
!= null || prop
.base_interface_property
!= null;
1762 string cname
= get_ccode_real_name (acc
);
1764 CCodeFunction function
;
1765 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1766 function
= new
CCodeFunction (cname
, "void");
1768 function
= new
CCodeFunction (cname
, get_ccode_name (acc
.value_type
));
1771 ObjectType base_type
= null;
1772 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1774 if (prop
.base_property
!= null) {
1775 base_type
= new
ObjectType ((ObjectTypeSymbol
) prop
.base_property
.parent_symbol
);
1776 } else if (prop
.base_interface_property
!= null) {
1777 base_type
= new
ObjectType ((ObjectTypeSymbol
) prop
.base_interface_property
.parent_symbol
);
1779 function
.modifiers
|= CCodeModifiers
.STATIC
;
1780 function
.add_parameter (new
CCodeParameter ("base", get_ccode_name (base_type
)));
1782 function
.add_parameter (cselfparam
);
1785 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1786 function
.add_parameter (cvalueparam
);
1789 if (acc
.value_type is ArrayType
) {
1790 var array_type
= (ArrayType
) acc
.value_type
;
1791 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1792 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), acc
.readable ?
"int*" : "int"));
1794 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1795 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1796 if (!acc
.readable
&& acc
.value_type
.value_owned
) {
1797 function
.add_parameter (new
CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), "GDestroyNotify"));
1802 if (prop
.is_private_symbol () || !(acc
.readable
|| acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1803 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1804 function
.modifiers
|= CCodeModifiers
.STATIC
;
1805 } else if (context
.hide_internal
&& (prop
.is_internal_symbol () || acc
.access
== SymbolAccessibility
.INTERNAL
)) {
1806 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
1810 push_function (function
);
1812 if (prop
.binding
== MemberBinding
.INSTANCE
&& !is_virtual
) {
1813 if (!acc
.readable
|| returns_real_struct
) {
1814 create_property_type_check_statement (prop
, false, t
, true, "self");
1816 create_property_type_check_statement (prop
, true, t
, true, "self");
1820 if (acc
.readable
&& !returns_real_struct
) {
1821 // do not declare result variable if exit block is known to be unreachable
1822 if (acc
.return_block
== null || acc
.return_block
.get_predecessors ().size
> 0) {
1823 ccode
.add_declaration (get_ccode_name (acc
.value_type
), new
CCodeVariableDeclarator ("result"));
1828 ccode
.add_declaration (get_ccode_name (this_type
), new
CCodeVariableDeclarator ("self"));
1829 ccode
.add_assignment (new
CCodeIdentifier ("self"), get_cvalue_ (transform_value (new
GLibValue (base_type
, new
CCodeIdentifier ("base"), true), this_type
, acc
)));
1832 // notify on property changes
1833 if (is_gobject_property (prop
) &&
1835 (acc
.writable
|| acc
.construction
)) {
1836 var notify_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_notify_by_pspec"));
1837 notify_call
.add_argument (new
CCodeCastExpression (new
CCodeIdentifier ("self"), "GObject *"));
1838 notify_call
.add_argument (get_param_spec_cexpression (prop
));
1840 var get_accessor
= prop
.get_accessor
;
1841 if (get_accessor
!= null && get_accessor
.automatic_body
) {
1842 var property_type
= prop
.property_type
;
1843 var get_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (get_accessor
)));
1844 get_call
.add_argument (new
CCodeIdentifier (is_virtual ?
"base" : "self"));
1846 if (property_type is ArrayType
) {
1847 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("old_value_length"));
1848 get_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("old_value_length")));
1849 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, get_call
, new
CCodeIdentifier ("value")));
1850 } else if (property_type
.compatible (string_type
)) {
1851 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
1852 ccall
.add_argument (new
CCodeIdentifier ("value"));
1853 ccall
.add_argument (get_call
);
1854 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, ccall
, new
CCodeConstant ("0")));
1855 } else if (property_type is StructValueType
) {
1856 ccode
.add_declaration (get_ccode_name (property_type
), new
CCodeVariableDeclarator ("old_value"));
1857 get_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("old_value")));
1859 var get_expr
= new
CCodeCommaExpression ();
1860 get_expr
.append_expression (get_call
);
1861 get_expr
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("old_value")));
1863 var equalfunc
= generate_struct_equal_function ((Struct
) property_type
.data_type
);
1864 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
1865 ccall
.add_argument (new
CCodeIdentifier ("value"));
1866 ccall
.add_argument (get_expr
);
1867 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, ccall
, new
CCodeConstant ("TRUE")));
1869 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, get_call
, new
CCodeIdentifier ("value")));
1872 acc
.body
.emit (this
);
1873 ccode
.add_expression (notify_call
);
1876 acc
.body
.emit (this
);
1877 ccode
.add_expression (notify_call
);
1880 acc
.body
.emit (this
);
1883 if (current_method_inner_error
) {
1884 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
1887 cfile
.add_function (function
);
1894 public override void visit_destructor (Destructor d
) {
1895 if (d
.binding
== MemberBinding
.STATIC
&& !in_plugin
) {
1896 Report
.error (d
.source_reference
, "static destructors are only supported for dynamic types");
1902 public int get_block_id (Block b
) {
1903 int result
= block_map
[b
];
1905 result
= ++next_block_id
;
1906 block_map
[b
] = result
;
1911 public bool no_implicit_copy (DataType type
) {
1912 // note: implicit copy of array is planned to be forbidden
1913 var cl
= type
.data_type as Class
;
1914 return (type is DelegateType
||
1916 (cl
!= null && !cl
.is_immutable
&& !is_reference_counting (cl
) && !get_ccode_is_gboxed (cl
)));
1919 void capture_parameter (Parameter param
, CCodeStruct data
, int block_id
) {
1920 generate_type_declaration (param
.variable_type
, cfile
);
1922 var param_type
= param
.variable_type
.copy ();
1923 if (!param
.variable_type
.value_owned
) {
1924 param_type
.value_owned
= !no_implicit_copy (param
.variable_type
);
1926 data
.add_field (get_ccode_name (param_type
), get_variable_cname (param
.name
));
1928 // create copy if necessary as captured variables may need to be kept alive
1929 param
.captured
= false;
1930 var value
= load_parameter (param
);
1932 var array_type
= param
.variable_type as ArrayType
;
1933 var deleg_type
= param
.variable_type as DelegateType
;
1935 if (array_type
!= null && get_ccode_array_length (param
)) {
1936 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1937 data
.add_field ("gint", get_parameter_array_length_cname (param
, dim
));
1939 } else if (deleg_type
!= null && deleg_type
.delegate_symbol
.has_target
) {
1940 data
.add_field ("gpointer", get_ccode_delegate_target_name (param
));
1941 if (param
.variable_type
.is_disposable ()) {
1942 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1943 // reference transfer for delegates
1944 var lvalue
= get_parameter_cvalue (param
);
1945 ((GLibValue
) value
).delegate_target_destroy_notify_cvalue
= get_delegate_target_destroy_notify_cvalue (lvalue
);
1948 param
.captured
= true;
1950 store_parameter (param
, value
, true);
1953 public override void visit_block (Block b
) {
1954 emit_context
.push_symbol (b
);
1956 var local_vars
= b
.get_local_variables ();
1958 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
|| b
.parent_node is TryStatement
) {
1959 ccode
.open_block ();
1963 var parent_block
= next_closure_block (b
.parent_symbol
);
1965 int block_id
= get_block_id (b
);
1966 string struct_name
= "Block%dData".printf (block_id
);
1968 var data
= new
CCodeStruct ("_" + struct_name
);
1969 data
.add_field ("int", "_ref_count_");
1970 if (parent_block
!= null) {
1971 int parent_block_id
= get_block_id (parent_block
);
1973 data
.add_field ("Block%dData *".printf (parent_block_id
), "_data%d_".printf (parent_block_id
));
1975 if (get_this_type () != null) {
1976 data
.add_field (get_ccode_name (get_data_type_for_symbol (current_type_symbol
)), "self");
1979 if (current_method
!= null) {
1980 // allow capturing generic type parameters
1981 foreach (var type_param
in current_method
.get_type_parameters ()) {
1984 func_name
= "%s_type".printf (type_param
.name
.down ());
1985 data
.add_field ("GType", func_name
);
1987 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
1988 data
.add_field ("GBoxedCopyFunc", func_name
);
1990 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
1991 data
.add_field ("GDestroyNotify", func_name
);
1995 foreach (var local
in local_vars
) {
1996 if (local
.captured
) {
1997 generate_type_declaration (local
.variable_type
, cfile
);
1999 data
.add_field (get_ccode_name (local
.variable_type
), get_local_cname (local
), 0, get_ccode_declarator_suffix (local
.variable_type
));
2001 if (local
.variable_type is ArrayType
&& !((ArrayType
) local
.variable_type
).fixed_length
) {
2002 var array_type
= (ArrayType
) local
.variable_type
;
2003 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2004 data
.add_field ("gint", get_array_length_cname (get_local_cname (local
), dim
));
2006 data
.add_field ("gint", get_array_size_cname (get_local_cname (local
)));
2007 } else if (local
.variable_type is DelegateType
&& ((DelegateType
) local
.variable_type
).delegate_symbol
.has_target
) {
2008 data
.add_field ("gpointer", get_delegate_target_cname (get_local_cname (local
)));
2009 if (local
.variable_type
.is_disposable ()) {
2010 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_local_cname (local
)));
2016 var data_alloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
2017 data_alloc
.add_argument (new
CCodeIdentifier (struct_name
));
2019 if (is_in_coroutine ()) {
2020 closure_struct
.add_field (struct_name
+ "*", "_data%d_".printf (block_id
));
2022 ccode
.add_declaration (struct_name
+ "*", new
CCodeVariableDeclarator ("_data%d_".printf (block_id
)));
2024 ccode
.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id
)), data_alloc
);
2026 // initialize ref_count
2027 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_ref_count_"), new
CCodeIdentifier ("1"));
2029 if (parent_block
!= null) {
2030 int parent_block_id
= get_block_id (parent_block
);
2032 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (parent_block_id
)));
2033 ref_call
.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id
)));
2035 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)), ref_call
);
2037 // skip self assignment in toplevel block of creation methods with chainup as self is not set at the beginning of the method
2038 // the chainup statement takes care of assigning self in the closure struct
2039 bool in_creation_method_with_chainup
= (current_method is CreationMethod
&& current_class
!= null && current_class
.base_class
!= null);
2041 if (get_this_type () != null && (!in_creation_method_with_chainup
|| current_method
.body
!= b
)) {
2042 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (get_data_type_for_symbol (current_type_symbol
), b
.source_reference
));
2043 ref_call
.add_argument (get_result_cexpression ("self"));
2045 // never increase reference count for self in finalizers to avoid infinite recursion on following unref
2046 var instance
= (is_in_destructor () ?
(CCodeExpression
) new
CCodeIdentifier ("self") : (CCodeExpression
) ref_call
);
2048 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "self"), instance
);
2051 if (current_method
!= null) {
2052 // allow capturing generic type parameters
2053 var suffices
= new
string[] {"type", "dup_func", "destroy_func"};
2054 foreach (var type_param
in current_method
.get_type_parameters ()) {
2055 foreach (string suffix
in suffices
) {
2056 string func_name
= "%s_%s".printf (type_param
.name
.down (), suffix
);
2057 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), get_variable_cexpression (func_name
));
2063 if (b
.parent_symbol is Method
) {
2064 var m
= (Method
) b
.parent_symbol
;
2066 // parameters are captured with the top-level block of the method
2067 foreach (var param
in m
.get_parameters ()) {
2068 if (param
.captured
) {
2069 capture_parameter (param
, data
, block_id
);
2074 // capture async data to allow invoking callback from inside closure
2075 data
.add_field ("gpointer", "_async_data_");
2077 // async method is suspended while waiting for callback,
2078 // so we never need to care about memory management of async data
2079 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_async_data_"), new
CCodeIdentifier ("_data_"));
2081 } else if (b
.parent_symbol is PropertyAccessor
) {
2082 var acc
= (PropertyAccessor
) b
.parent_symbol
;
2084 if (!acc
.readable
&& acc
.value_parameter
.captured
) {
2085 capture_parameter (acc
.value_parameter
, data
, block_id
);
2087 } else if (b
.parent_symbol is ForeachStatement
) {
2088 var stmt
= (ForeachStatement
) b
.parent_symbol
;
2089 if (!stmt
.use_iterator
&& stmt
.element_variable
.captured
) {
2090 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_local_cname (stmt
.element_variable
)), get_variable_cexpression (get_local_cname (stmt
.element_variable
)));
2094 var typedef
= new
CCodeTypeDefinition ("struct _" + struct_name
, new
CCodeVariableDeclarator (struct_name
));
2095 cfile
.add_type_declaration (typedef
);
2096 cfile
.add_type_definition (data
);
2098 // create ref/unref functions
2099 var ref_fun
= new
CCodeFunction ("block%d_data_ref".printf (block_id
), struct_name
+ "*");
2100 ref_fun
.add_parameter (new
CCodeParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
2101 ref_fun
.modifiers
= CCodeModifiers
.STATIC
;
2103 push_function (ref_fun
);
2105 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_atomic_int_inc"));
2106 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_ref_count_")));
2107 ccode
.add_expression (ccall
);
2108 ccode
.add_return (new
CCodeIdentifier ("_data%d_".printf (block_id
)));
2112 cfile
.add_function_declaration (ref_fun
);
2113 cfile
.add_function (ref_fun
);
2115 var unref_fun
= new
CCodeFunction ("block%d_data_unref".printf (block_id
), "void");
2116 unref_fun
.add_parameter (new
CCodeParameter ("_userdata_", "void *"));
2117 unref_fun
.modifiers
= CCodeModifiers
.STATIC
;
2119 push_function (unref_fun
);
2121 ccode
.add_declaration (struct_name
+ "*", new
CCodeVariableDeclarator ("_data%d_".printf (block_id
), new
CCodeCastExpression (new
CCodeIdentifier ("_userdata_"), struct_name
+ "*")));
2122 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_atomic_int_dec_and_test"));
2123 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_ref_count_")));
2124 ccode
.open_if (ccall
);
2126 CCodeExpression outer_block
= new
CCodeIdentifier ("_data%d_".printf (block_id
));
2127 unowned Block parent_closure_block
= b
;
2129 parent_closure_block
= next_closure_block (parent_closure_block
.parent_symbol
);
2130 if (parent_closure_block
== null) {
2133 int parent_block_id
= get_block_id (parent_closure_block
);
2134 outer_block
= new CCodeMemberAccess
.pointer (outer_block
, "_data%d_".printf (parent_block_id
));
2137 if (get_this_type () != null) {
2138 // assign "self" for type parameters
2139 ccode
.add_declaration(get_ccode_name (get_data_type_for_symbol (current_type_symbol
)), new
CCodeVariableDeclarator ("self"));
2140 ccode
.add_assignment (new
CCodeIdentifier ("self"), new CCodeMemberAccess
.pointer (outer_block
, "self"));
2143 if (current_method
!= null) {
2144 // assign captured generic type parameters
2145 foreach (var type_param
in current_method
.get_type_parameters ()) {
2148 func_name
= "%s_type".printf (type_param
.name
.down ());
2149 ccode
.add_declaration ("GType", new
CCodeVariableDeclarator (func_name
));
2150 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (outer_block
, func_name
));
2152 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
2153 ccode
.add_declaration ("GBoxedCopyFunc", new
CCodeVariableDeclarator (func_name
));
2154 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (outer_block
, func_name
));
2156 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
2157 ccode
.add_declaration ("GDestroyNotify", new
CCodeVariableDeclarator (func_name
));
2158 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (outer_block
, func_name
));
2162 // free in reverse order
2163 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
2164 var local
= local_vars
[i
];
2165 if (local
.captured
) {
2166 if (requires_destroy (local
.variable_type
)) {
2167 bool old_coroutine
= false;
2168 if (current_method
!= null) {
2169 old_coroutine
= current_method
.coroutine
;
2170 current_method
.coroutine
= false;
2173 ccode
.add_expression (destroy_local (local
));
2175 if (old_coroutine
) {
2176 current_method
.coroutine
= true;
2182 if (b
.parent_symbol is Method
) {
2183 var m
= (Method
) b
.parent_symbol
;
2185 // parameters are captured with the top-level block of the method
2186 foreach (var param
in m
.get_parameters ()) {
2187 if (param
.captured
) {
2188 var param_type
= param
.variable_type
.copy ();
2189 if (!param_type
.value_owned
) {
2190 param_type
.value_owned
= !no_implicit_copy (param_type
);
2193 if (requires_destroy (param_type
)) {
2194 bool old_coroutine
= false;
2196 old_coroutine
= m
.coroutine
;
2197 m
.coroutine
= false;
2200 ccode
.add_expression (destroy_parameter (param
));
2202 if (old_coroutine
) {
2208 } else if (b
.parent_symbol is PropertyAccessor
) {
2209 var acc
= (PropertyAccessor
) b
.parent_symbol
;
2211 if (!acc
.readable
&& acc
.value_parameter
.captured
) {
2212 var param_type
= acc
.value_parameter
.variable_type
.copy ();
2213 if (!param_type
.value_owned
) {
2214 param_type
.value_owned
= !no_implicit_copy (param_type
);
2217 if (requires_destroy (param_type
)) {
2218 ccode
.add_expression (destroy_parameter (acc
.value_parameter
));
2223 // free parent block and "self" after captured variables
2224 // because they may require type parameters
2225 if (parent_block
!= null) {
2226 int parent_block_id
= get_block_id (parent_block
);
2228 var unref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (parent_block_id
)));
2229 unref_call
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)));
2230 ccode
.add_expression (unref_call
);
2231 ccode
.add_assignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)), new
CCodeConstant ("NULL"));
2233 var this_type
= get_this_type ();
2234 if (this_type
!= null) {
2235 this_type
= this_type
.copy ();
2236 this_type
.value_owned
= true;
2237 if (this_type
.is_disposable () && !is_in_destructor ()) {
2238 // reference count for self is not increased in finalizers
2239 var this_value
= new
GLibValue (get_data_type_for_symbol (current_type_symbol
), new
CCodeIdentifier ("self"), true);
2240 ccode
.add_expression (destroy_value (this_value
));
2245 var data_free
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_free"));
2246 data_free
.add_argument (new
CCodeIdentifier (struct_name
));
2247 data_free
.add_argument (new
CCodeIdentifier ("_data%d_".printf (block_id
)));
2248 ccode
.add_expression (data_free
);
2254 cfile
.add_function_declaration (unref_fun
);
2255 cfile
.add_function (unref_fun
);
2258 foreach (Statement stmt
in b
.get_statements ()) {
2259 push_line (stmt
.source_reference
);
2264 // free in reverse order
2265 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
2266 var local
= local_vars
[i
];
2267 local
.active
= false;
2268 if (!local
.unreachable
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
2269 ccode
.add_expression (destroy_local (local
));
2273 if (b
.parent_symbol is Method
) {
2274 var m
= (Method
) b
.parent_symbol
;
2275 foreach (Parameter param
in m
.get_parameters ()) {
2276 if (!param
.captured
&& !param
.ellipsis
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
2277 ccode
.add_expression (destroy_parameter (param
));
2278 } else if (param
.direction
== ParameterDirection
.OUT
&& !m
.coroutine
) {
2279 return_out_parameter (param
);
2282 // check postconditions
2283 foreach (var postcondition
in m
.get_postconditions ()) {
2284 create_postcondition_statement (postcondition
);
2286 } else if (b
.parent_symbol is PropertyAccessor
) {
2287 var acc
= (PropertyAccessor
) b
.parent_symbol
;
2288 if (acc
.value_parameter
!= null && !acc
.value_parameter
.captured
&& requires_destroy (acc
.value_parameter
.variable_type
)) {
2289 ccode
.add_expression (destroy_parameter (acc
.value_parameter
));
2294 int block_id
= get_block_id (b
);
2296 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
2297 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
2298 ccode
.add_expression (data_unref
);
2299 ccode
.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id
)), new
CCodeConstant ("NULL"));
2302 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
|| b
.parent_node is TryStatement
) {
2306 emit_context
.pop_symbol ();
2309 public override void visit_declaration_statement (DeclarationStatement stmt
) {
2310 stmt
.declaration
.accept (this
);
2313 public CCodeExpression
get_local_cexpression (LocalVariable local
) {
2314 if (is_in_coroutine ()) {
2315 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), get_local_cname (local
));
2317 return new
CCodeIdentifier (get_local_cname (local
));
2321 public CCodeExpression
get_variable_cexpression (string name
) {
2322 if (is_in_coroutine ()) {
2323 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), get_variable_cname (name
));
2325 return new
CCodeIdentifier (get_variable_cname (name
));
2329 public CCodeExpression
get_this_cexpression () {
2330 if (is_in_coroutine ()) {
2331 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "self");
2333 return new
CCodeIdentifier ("self");
2337 public string get_local_cname (LocalVariable local
) {
2338 var cname
= get_variable_cname (local
.name
);
2339 if (cname
[0].isdigit ()) {
2340 cname
= "_%s_".printf (cname
);
2342 if (is_in_coroutine ()) {
2343 var clash_index
= emit_context
.closure_variable_clash_map
.get (local
);
2344 if (clash_index
> 0) {
2345 cname
= "_vala%d_%s".printf (clash_index
, cname
);
2351 public string get_variable_cname (string name
) {
2352 if (name
[0] == '.') {
2353 if (name
== ".result") {
2356 // compiler-internal variable
2357 if (!variable_name_map
.contains (name
)) {
2358 variable_name_map
.set (name
, "_tmp%d_".printf (next_temp_var_id
));
2361 return variable_name_map
.get (name
);
2362 } else if (reserved_identifiers
.contains (name
)) {
2363 return "_%s_".printf (name
);
2369 public CCodeExpression
get_result_cexpression (string cname
= "result") {
2370 if (is_in_coroutine ()) {
2371 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), cname
);
2373 return new
CCodeIdentifier (cname
);
2377 public bool is_simple_struct_creation (Variable variable
, Expression expr
) {
2378 var st
= variable
.variable_type
.data_type as Struct
;
2379 var creation
= expr as ObjectCreationExpression
;
2380 if (creation
!= null && st
!= null && (!st
.is_simple_type () || get_ccode_name (st
) == "va_list") && !variable
.variable_type
.nullable
&&
2381 variable
.variable_type
.data_type
!= gvalue_type
&& creation
.get_object_initializer ().size
== 0) {
2388 bool is_foreach_element_variable (LocalVariable local
) {
2389 var block
= local
.parent_symbol
;
2390 if (block
!= null) {
2391 var stmt
= block
.parent_symbol as ForeachStatement
;
2392 if (stmt
!= null && !stmt
.use_iterator
&& stmt
.element_variable
== local
) {
2399 public override void visit_local_variable (LocalVariable local
) {
2400 check_type (local
.variable_type
);
2404 generate_type_declaration (local
.variable_type
, cfile
);
2406 // captured element variables of foreach statements (without iterator) require local declaration
2407 var declared
= !local
.captured
|| is_foreach_element_variable (local
);
2409 if (is_in_coroutine ()) {
2410 var count
= emit_context
.closure_variable_count_map
.get (local
.name
);
2412 emit_context
.closure_variable_clash_map
.set (local
, count
);
2414 emit_context
.closure_variable_count_map
.set (local
.name
, count
+ 1);
2416 closure_struct
.add_field (get_ccode_name (local
.variable_type
), get_local_cname (local
), 0, get_ccode_declarator_suffix (local
.variable_type
));
2418 var cvar
= new
CCodeVariableDeclarator (get_local_cname (local
), null, get_ccode_declarator_suffix (local
.variable_type
));
2420 // try to initialize uninitialized variables
2421 // initialization not necessary for variables stored in closure
2422 cvar
.initializer
= default_value_for_type (local
.variable_type
, true);
2425 ccode
.add_declaration (get_ccode_name (local
.variable_type
), cvar
);
2429 /* Emit initializer */
2430 if (local
.initializer
!= null) {
2431 local
.initializer
.emit (this
);
2433 visit_end_full_expression (local
.initializer
);
2437 CCodeExpression rhs
= null;
2438 if (local
.initializer
!= null && get_cvalue (local
.initializer
) != null) {
2439 rhs
= get_cvalue (local
.initializer
);
2442 /* Additional temp variables */
2445 if (local
.variable_type is ArrayType
) {
2446 // create variables to store array dimensions
2447 var array_type
= (ArrayType
) local
.variable_type
;
2449 if (!array_type
.fixed_length
) {
2450 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2451 var len_var
= new
LocalVariable (int_type
.copy (), get_array_length_cname (get_local_cname (local
), dim
));
2452 len_var
.init
= local
.initializer
== null;
2453 emit_temp_var (len_var
);
2456 if (array_type
.rank
== 1) {
2457 var size_var
= new
LocalVariable (int_type
.copy (), get_array_size_cname (get_local_cname (local
)));
2458 size_var
.init
= local
.initializer
== null;
2459 emit_temp_var (size_var
);
2462 } else if (local
.variable_type is DelegateType
) {
2463 var deleg_type
= (DelegateType
) local
.variable_type
;
2464 if (deleg_type
.delegate_symbol
.has_target
) {
2465 // create variable to store delegate target
2466 var target_var
= new
LocalVariable (new
PointerType (new
VoidType ()), get_delegate_target_cname (get_local_cname (local
)));
2467 target_var
.init
= local
.initializer
== null;
2468 emit_temp_var (target_var
);
2469 if (deleg_type
.is_disposable ()) {
2470 var target_destroy_notify_var
= new
LocalVariable (gdestroynotify_type
, get_delegate_target_destroy_notify_cname (get_local_cname (local
)));
2471 target_destroy_notify_var
.init
= local
.initializer
== null;
2472 emit_temp_var (target_destroy_notify_var
);
2478 /* Store the initializer */
2481 if (!is_simple_struct_creation (local
, local
.initializer
)) {
2482 store_local (local
, local
.initializer
.target_value
, true, local
.source_reference
);
2486 if (local
.initializer
!= null && local
.initializer
.tree_can_fail
) {
2487 add_simple_check (local
.initializer
);
2490 local
.active
= true;
2494 * Create a temporary variable and return lvalue access to it
2496 public TargetValue
create_temp_value (DataType type
, bool init
, CodeNode node_reference
, bool? value_owned
= null) {
2497 var local
= new
LocalVariable (type
.copy (), "_tmp%d_".printf (next_temp_var_id
++), null, node_reference
.source_reference
);
2499 if (value_owned
!= null) {
2500 local
.variable_type
.value_owned
= value_owned
;
2503 var array_type
= local
.variable_type as ArrayType
;
2504 var deleg_type
= local
.variable_type as DelegateType
;
2506 emit_temp_var (local
);
2507 if (array_type
!= null) {
2508 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2509 var len_var
= new
LocalVariable (int_type
.copy (), get_array_length_cname (local
.name
, dim
), null, node_reference
.source_reference
);
2510 len_var
.init
= init
;
2511 emit_temp_var (len_var
);
2513 } else if (deleg_type
!= null && deleg_type
.delegate_symbol
.has_target
) {
2514 var target_var
= new
LocalVariable (new
PointerType (new
VoidType ()), get_delegate_target_cname (local
.name
), null, node_reference
.source_reference
);
2515 target_var
.init
= init
;
2516 emit_temp_var (target_var
);
2517 if (deleg_type
.is_disposable ()) {
2518 var target_destroy_notify_var
= new
LocalVariable (gdestroynotify_type
.copy (), get_delegate_target_destroy_notify_cname (local
.name
), null, node_reference
.source_reference
);
2519 target_destroy_notify_var
.init
= init
;
2520 emit_temp_var (target_destroy_notify_var
);
2524 var value
= get_local_cvalue (local
);
2525 set_array_size_cvalue (value
, null);
2530 * Load a temporary variable returning unowned or owned rvalue access to it, depending on the ownership of the value type.
2532 public TargetValue
load_temp_value (TargetValue lvalue
) {
2533 var value
= ((GLibValue
) lvalue
).copy ();
2534 var deleg_type
= value
.value_type as DelegateType
;
2535 if (deleg_type
!= null) {
2536 if (!deleg_type
.delegate_symbol
.has_target
) {
2537 value
.delegate_target_cvalue
= new
CCodeConstant ("NULL");
2538 ((GLibValue
) value
).lvalue
= false;
2539 } else if (!deleg_type
.is_disposable ()) {
2540 value
.delegate_target_destroy_notify_cvalue
= new
CCodeConstant ("NULL");
2541 ((GLibValue
) value
).lvalue
= false;
2548 * Store a value in a temporary variable and return unowned or owned rvalue access to it, depending on the ownership of the given type.
2550 public TargetValue
store_temp_value (TargetValue initializer
, CodeNode node_reference
, bool? value_owned
= null) {
2551 var lvalue
= create_temp_value (initializer
.value_type
, false, node_reference
, value_owned
);
2552 store_value (lvalue
, initializer
, node_reference
.source_reference
);
2553 return load_temp_value (lvalue
);
2556 public override void visit_initializer_list (InitializerList list
) {
2557 if (list
.target_type
.data_type is Struct
) {
2558 /* initializer is used as struct initializer */
2559 var st
= (Struct
) list
.target_type
.data_type
;
2560 while (st
.base_struct
!= null) {
2561 st
= st
.base_struct
;
2564 if (list
.parent_node is Constant
|| list
.parent_node is Field
|| list
.parent_node is InitializerList
) {
2565 var clist
= new
CCodeInitializerList ();
2567 var field_it
= st
.get_fields ().iterator ();
2568 foreach (Expression expr
in list
.get_initializers ()) {
2570 while (field
== null) {
2572 field
= field_it
.get ();
2573 if (field
.binding
!= MemberBinding
.INSTANCE
) {
2574 // we only initialize instance fields
2579 var cexpr
= get_cvalue (expr
);
2581 string ctype
= get_ccode_type (field
);
2582 if (ctype
!= null) {
2583 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
2586 clist
.append (cexpr
);
2588 var array_type
= field
.variable_type as ArrayType
;
2589 if (array_type
!= null && !array_type
.fixed_length
&& get_ccode_array_length (field
) && !get_ccode_array_null_terminated (field
)) {
2590 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2591 clist
.append (get_array_length_cvalue (expr
.target_value
, dim
));
2596 set_cvalue (list
, clist
);
2598 // used as expression
2599 var instance
= create_temp_value (list
.value_type
, true, list
);
2601 var field_it
= st
.get_fields ().iterator ();
2602 foreach (Expression expr
in list
.get_initializers ()) {
2604 while (field
== null) {
2606 field
= field_it
.get ();
2607 if (field
.binding
!= MemberBinding
.INSTANCE
) {
2608 // we only initialize instance fields
2613 store_field (field
, instance
, expr
.target_value
, expr
.source_reference
);
2616 list
.target_value
= instance
;
2619 var clist
= new
CCodeInitializerList ();
2620 foreach (Expression expr
in list
.get_initializers ()) {
2621 clist
.append (get_cvalue (expr
));
2623 set_cvalue (list
, clist
);
2627 public LocalVariable
get_temp_variable (DataType type
, bool value_owned
= true, CodeNode? node_reference
= null, bool init
= false) {
2628 var var_type
= type
.copy ();
2629 var_type
.value_owned
= value_owned
;
2630 var local
= new
LocalVariable (var_type
, "_tmp%d_".printf (next_temp_var_id
));
2633 if (node_reference
!= null) {
2634 local
.source_reference
= node_reference
.source_reference
;
2642 bool is_in_generic_type (GenericType type
) {
2643 if (current_symbol
!= null && type
.type_parameter
.parent_symbol is TypeSymbol
2644 && (current_method
== null || current_method
.binding
== MemberBinding
.INSTANCE
)) {
2651 void require_generic_accessors (Interface iface
) {
2652 if (iface
.get_attribute ("GenericAccessors") == null) {
2653 Report
.error (iface
.source_reference
,
2654 "missing generic type for interface `%s', add GenericAccessors attribute to interface declaration"
2655 .printf (iface
.get_full_name ()));
2659 public CCodeExpression
get_type_id_expression (DataType type
, bool is_chainup
= false) {
2660 if (type is GenericType
) {
2661 var type_parameter
= ((GenericType
) type
).type_parameter
;
2662 string var_name
= "%s_type".printf (type_parameter
.name
.down ());
2664 if (type_parameter
.parent_symbol is Interface
) {
2665 var iface
= (Interface
) type_parameter
.parent_symbol
;
2666 require_generic_accessors (iface
);
2668 string method_name
= "get_%s_type".printf (type_parameter
.name
.down ());
2669 var cast_self
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface
))));
2670 cast_self
.add_argument (new
CCodeIdentifier ("self"));
2671 var function_call
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (cast_self
, method_name
));
2672 function_call
.add_argument (new
CCodeIdentifier ("self"));
2673 return function_call
;
2676 if (is_in_generic_type ((GenericType
) type
) && !is_chainup
&& !in_creation_method
) {
2677 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), var_name
);
2679 return get_variable_cexpression (var_name
);
2682 string type_id
= get_ccode_type_id (type
);
2683 if (type_id
== "") {
2684 type_id
= "G_TYPE_INVALID";
2686 generate_type_declaration (type
, cfile
);
2688 return new
CCodeIdentifier (type_id
);
2692 public virtual CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
, bool is_chainup
= false) {
2693 if (type is ErrorType
) {
2694 return new
CCodeIdentifier ("g_error_copy");
2695 } else if (type
.data_type
!= null) {
2696 string dup_function
;
2697 var cl
= type
.data_type as Class
;
2698 if (is_reference_counting (type
.data_type
)) {
2699 dup_function
= get_ccode_ref_function ((ObjectTypeSymbol
) type
.data_type
);
2700 if (type
.data_type is Interface
&& dup_function
== null) {
2701 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 ()));
2702 return new
CCodeInvalidExpression();
2704 } else if (cl
!= null && cl
.is_immutable
) {
2705 // allow duplicates of immutable instances as for example strings
2706 dup_function
= get_ccode_dup_function (type
.data_type
);
2707 if (dup_function
== null) {
2710 } else if (cl
!= null && get_ccode_is_gboxed (cl
)) {
2711 // allow duplicates of gboxed instances
2712 dup_function
= generate_dup_func_wrapper (type
);
2713 if (dup_function
== null) {
2716 } else if (type is ValueType
) {
2717 dup_function
= get_ccode_dup_function (type
.data_type
);
2718 if (dup_function
== null && type
.nullable
) {
2719 dup_function
= generate_struct_dup_wrapper ((ValueType
) type
);
2720 } else if (dup_function
== null) {
2724 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2725 Report
.error (source_reference
, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type
.data_type
.name
));
2726 return new
CCodeInvalidExpression();
2729 return new
CCodeIdentifier (dup_function
);
2730 } else if (type is GenericType
) {
2731 var type_parameter
= ((GenericType
) type
).type_parameter
;
2732 string func_name
= "%s_dup_func".printf (type_parameter
.name
.down ());
2734 if (type_parameter
.parent_symbol is Interface
) {
2735 var iface
= (Interface
) type_parameter
.parent_symbol
;
2736 require_generic_accessors (iface
);
2738 string method_name
= "get_%s_dup_func".printf (type_parameter
.name
.down ());
2739 var cast_self
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface
))));
2740 cast_self
.add_argument (new
CCodeIdentifier ("self"));
2741 var function_call
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (cast_self
, method_name
));
2742 function_call
.add_argument (new
CCodeIdentifier ("self"));
2743 return function_call
;
2746 if (is_in_generic_type ((GenericType
) type
) && !is_chainup
&& !in_creation_method
) {
2747 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), func_name
);
2749 return get_variable_cexpression (func_name
);
2751 } else if (type is PointerType
) {
2752 var pointer_type
= (PointerType
) type
;
2753 return get_dup_func_expression (pointer_type
.base_type
, source_reference
);
2755 return new
CCodeConstant ("NULL");
2759 void make_comparable_cexpression (ref DataType left_type
, ref CCodeExpression cleft
, ref DataType right_type
, ref CCodeExpression cright
) {
2760 var left_type_as_struct
= left_type
.data_type as Struct
;
2761 var right_type_as_struct
= right_type
.data_type as Struct
;
2764 var valuecast
= try_cast_value_to_type (cleft
, left_type
, right_type
);
2765 if (valuecast
!= null) {
2767 left_type
= right_type
;
2768 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
2772 valuecast
= try_cast_value_to_type (cright
, right_type
, left_type
);
2773 if (valuecast
!= null) {
2775 right_type
= left_type
;
2776 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
2780 if (left_type
.data_type is Class
&& !((Class
) left_type
.data_type
).is_compact
&&
2781 right_type
.data_type is Class
&& !((Class
) right_type
.data_type
).is_compact
) {
2782 var left_cl
= (Class
) left_type
.data_type
;
2783 var right_cl
= (Class
) right_type
.data_type
;
2785 if (left_cl
!= right_cl
) {
2786 if (left_cl
.is_subtype_of (right_cl
)) {
2787 cleft
= generate_instance_cast (cleft
, right_cl
);
2788 } else if (right_cl
.is_subtype_of (left_cl
)) {
2789 cright
= generate_instance_cast (cright
, left_cl
);
2792 } else if (left_type_as_struct
!= null && right_type_as_struct
!= null) {
2793 if (left_type is StructValueType
) {
2794 // real structs (uses compare/equal function)
2795 if (!left_type
.nullable
) {
2796 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cleft
);
2798 if (!right_type
.nullable
) {
2799 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cright
);
2802 // integer or floating or boolean type
2803 if (left_type
.nullable
&& right_type
.nullable
) {
2804 // FIXME also compare contents, not just address
2805 } else if (left_type
.nullable
) {
2806 // FIXME check left value is not null
2807 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cleft
);
2808 } else if (right_type
.nullable
) {
2809 // FIXME check right value is not null
2810 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cright
);
2816 private string generate_struct_equal_function (Struct st
) {
2817 if (st
.base_struct
!= null) {
2818 return generate_struct_equal_function (st
.base_struct
);
2821 string equal_func
= "_%sequal".printf (get_ccode_lower_case_prefix (st
));
2823 if (!add_wrapper (equal_func
)) {
2824 // wrapper already defined
2828 var function
= new
CCodeFunction (equal_func
, "gboolean");
2829 function
.modifiers
= CCodeModifiers
.STATIC
;
2831 function
.add_parameter (new
CCodeParameter ("s1", "const %s *".printf (get_ccode_name (st
))));
2832 function
.add_parameter (new
CCodeParameter ("s2", "const %s *".printf (get_ccode_name (st
))));
2834 push_function (function
);
2836 // if (s1 == s2) return TRUE;
2838 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
2839 ccode
.open_if (cexp
);
2840 ccode
.add_return (new
CCodeConstant ("TRUE"));
2843 // if (s1 == NULL || s2 == NULL) return FALSE;
2845 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeConstant ("NULL"));
2846 ccode
.open_if (cexp
);
2847 ccode
.add_return (new
CCodeConstant ("FALSE"));
2850 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s2"), new
CCodeConstant ("NULL"));
2851 ccode
.open_if (cexp
);
2852 ccode
.add_return (new
CCodeConstant ("FALSE"));
2856 bool has_instance_fields
= false;
2857 foreach (Field f
in st
.get_fields ()) {
2858 if (f
.binding
!= MemberBinding
.INSTANCE
) {
2859 // we only compare instance fields
2863 has_instance_fields
= true;
2865 CCodeExpression cexp
; // if (cexp) return FALSE;
2866 var s1
= (CCodeExpression
) new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("s1"), get_ccode_name (f
)); // s1->f
2867 var s2
= (CCodeExpression
) new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("s2"), get_ccode_name (f
)); // s2->f
2869 var variable_type
= f
.variable_type
.copy ();
2870 make_comparable_cexpression (ref variable_type
, ref s1
, ref variable_type
, ref s2
);
2872 if (!(f
.variable_type is NullType
) && f
.variable_type
.compatible (string_type
)) {
2873 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
2874 ccall
.add_argument (s1
);
2875 ccall
.add_argument (s2
);
2877 } else if (f
.variable_type is StructValueType
) {
2878 var equalfunc
= generate_struct_equal_function (f
.variable_type
.data_type as Struct
);
2879 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
2880 ccall
.add_argument (s1
);
2881 ccall
.add_argument (s2
);
2882 cexp
= new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, ccall
);
2884 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, s1
, s2
);
2887 ccode
.open_if (cexp
);
2888 ccode
.add_return (new
CCodeConstant ("FALSE"));
2892 if (!has_instance_fields
) {
2893 // either opaque structure or simple type
2894 if (st
.is_simple_type ()) {
2895 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s1")), new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s2")));
2896 ccode
.add_return (cexp
);
2898 ccode
.add_return (new
CCodeConstant ("FALSE"));
2901 ccode
.add_return (new
CCodeConstant ("TRUE"));
2906 cfile
.add_function_declaration (function
);
2907 cfile
.add_function (function
);
2912 private string generate_numeric_equal_function (TypeSymbol sym
) {
2913 string equal_func
= "_%sequal".printf (get_ccode_lower_case_prefix (sym
));
2915 if (!add_wrapper (equal_func
)) {
2916 // wrapper already defined
2920 var function
= new
CCodeFunction (equal_func
, "gboolean");
2921 function
.modifiers
= CCodeModifiers
.STATIC
;
2923 function
.add_parameter (new
CCodeParameter ("s1", "const %s *".printf (get_ccode_name (sym
))));
2924 function
.add_parameter (new
CCodeParameter ("s2", "const %s *".printf (get_ccode_name (sym
))));
2926 push_function (function
);
2928 // if (s1 == s2) return TRUE;
2930 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
2931 ccode
.open_if (cexp
);
2932 ccode
.add_return (new
CCodeConstant ("TRUE"));
2935 // if (s1 == NULL || s2 == NULL) return FALSE;
2937 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeConstant ("NULL"));
2938 ccode
.open_if (cexp
);
2939 ccode
.add_return (new
CCodeConstant ("FALSE"));
2942 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s2"), new
CCodeConstant ("NULL"));
2943 ccode
.open_if (cexp
);
2944 ccode
.add_return (new
CCodeConstant ("FALSE"));
2947 // return (*s1 == *s2);
2949 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s1")), new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s2")));
2950 ccode
.add_return (cexp
);
2955 cfile
.add_function_declaration (function
);
2956 cfile
.add_function (function
);
2961 private string generate_struct_dup_wrapper (ValueType value_type
) {
2962 string dup_func
= "_%sdup".printf (get_ccode_lower_case_prefix (value_type
.type_symbol
));
2964 if (!add_wrapper (dup_func
)) {
2965 // wrapper already defined
2969 var function
= new
CCodeFunction (dup_func
, get_ccode_name (value_type
));
2970 function
.modifiers
= CCodeModifiers
.STATIC
;
2972 function
.add_parameter (new
CCodeParameter ("self", get_ccode_name (value_type
)));
2974 push_function (function
);
2976 if (value_type
.type_symbol
== gvalue_type
) {
2977 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_copy"));
2978 dup_call
.add_argument (new
CCodeIdentifier ("G_TYPE_VALUE"));
2979 dup_call
.add_argument (new
CCodeIdentifier ("self"));
2981 ccode
.add_return (dup_call
);
2983 ccode
.add_declaration (get_ccode_name (value_type
), new
CCodeVariableDeclarator ("dup"));
2985 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
2986 creation_call
.add_argument (new
CCodeConstant (get_ccode_name (value_type
.data_type
)));
2987 creation_call
.add_argument (new
CCodeConstant ("1"));
2988 ccode
.add_assignment (new
CCodeIdentifier ("dup"), creation_call
);
2990 var st
= value_type
.data_type as Struct
;
2991 if (st
!= null && st
.is_disposable ()) {
2992 if (!get_ccode_has_copy_function (st
)) {
2993 generate_struct_copy_function (st
);
2996 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_copy_function (st
)));
2997 copy_call
.add_argument (new
CCodeIdentifier ("self"));
2998 copy_call
.add_argument (new
CCodeIdentifier ("dup"));
2999 ccode
.add_expression (copy_call
);
3001 cfile
.add_include ("string.h");
3003 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
3004 sizeof_call
.add_argument (new
CCodeConstant (get_ccode_name (value_type
.data_type
)));
3006 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
3007 copy_call
.add_argument (new
CCodeIdentifier ("dup"));
3008 copy_call
.add_argument (new
CCodeIdentifier ("self"));
3009 copy_call
.add_argument (sizeof_call
);
3010 ccode
.add_expression (copy_call
);
3013 ccode
.add_return (new
CCodeIdentifier ("dup"));
3018 cfile
.add_function_declaration (function
);
3019 cfile
.add_function (function
);
3024 protected string generate_dup_func_wrapper (DataType type
) {
3025 string destroy_func
= "_vala_%s_copy".printf (get_ccode_name (type
.data_type
));
3027 if (!add_wrapper (destroy_func
)) {
3028 // wrapper already defined
3029 return destroy_func
;
3032 var function
= new
CCodeFunction (destroy_func
, get_ccode_name (type
));
3033 function
.modifiers
= CCodeModifiers
.STATIC
;
3034 function
.add_parameter (new
CCodeParameter ("self", get_ccode_name (type
)));
3036 push_function (function
);
3038 var cl
= type
.data_type as Class
;
3039 assert (cl
!= null && get_ccode_is_gboxed (cl
));
3041 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_copy"));
3042 free_call
.add_argument (new
CCodeIdentifier (get_ccode_type_id (cl
)));
3043 free_call
.add_argument (new
CCodeIdentifier ("self"));
3045 ccode
.add_return (free_call
);
3049 cfile
.add_function_declaration (function
);
3050 cfile
.add_function (function
);
3052 return destroy_func
;
3055 protected string generate_free_function_address_of_wrapper (DataType type
) {
3056 string destroy_func
= "_vala_%s_free_function_address_of".printf (get_ccode_name (type
.data_type
));
3058 if (!add_wrapper (destroy_func
)) {
3059 // wrapper already defined
3060 return destroy_func
;
3063 var function
= new
CCodeFunction (destroy_func
, "void");
3064 function
.modifiers
= CCodeModifiers
.STATIC
;
3065 function
.add_parameter (new
CCodeParameter ("self", get_ccode_name (type
)));
3067 push_function (function
);
3069 var cl
= type
.data_type as Class
;
3070 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_free_function (cl
)));
3071 free_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("self")));
3073 ccode
.add_expression (free_call
);
3077 cfile
.add_function_declaration (function
);
3078 cfile
.add_function (function
);
3080 return destroy_func
;
3083 protected string generate_free_func_wrapper (DataType type
) {
3084 string destroy_func
= "_vala_%s_free".printf (get_ccode_name (type
.data_type
));
3086 if (!add_wrapper (destroy_func
)) {
3087 // wrapper already defined
3088 return destroy_func
;
3091 var function
= new
CCodeFunction (destroy_func
, "void");
3092 function
.modifiers
= CCodeModifiers
.STATIC
;
3093 function
.add_parameter (new
CCodeParameter ("self", get_ccode_name (type
)));
3095 push_function (function
);
3097 var cl
= type
.data_type as Class
;
3098 if (cl
!= null && get_ccode_is_gboxed (cl
)) {
3099 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_free"));
3100 free_call
.add_argument (new
CCodeIdentifier (get_ccode_type_id (cl
)));
3101 free_call
.add_argument (new
CCodeIdentifier ("self"));
3103 ccode
.add_expression (free_call
);
3105 var st
= type
.data_type as Struct
;
3106 if (st
!= null && st
.is_disposable ()) {
3107 if (!get_ccode_has_destroy_function (st
)) {
3108 generate_struct_destroy_function (st
);
3111 var destroy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_destroy_function (st
)));
3112 destroy_call
.add_argument (new
CCodeIdentifier ("self"));
3113 ccode
.add_expression (destroy_call
);
3116 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
3117 free_call
.add_argument (new
CCodeIdentifier ("self"));
3119 ccode
.add_expression (free_call
);
3124 cfile
.add_function_declaration (function
);
3125 cfile
.add_function (function
);
3127 return destroy_func
;
3130 public CCodeExpression?
get_destroy0_func_expression (DataType type
, bool is_chainup
= false) {
3131 var element_destroy_func_expression
= get_destroy_func_expression (type
, is_chainup
);
3133 if (!(type is GenericType
) && element_destroy_func_expression is CCodeIdentifier
) {
3134 var freeid
= (CCodeIdentifier
) element_destroy_func_expression
;
3135 string free0_func
= "_%s0_".printf (freeid
.name
);
3137 if (add_wrapper (free0_func
)) {
3138 var function
= new
CCodeFunction (free0_func
, "void");
3139 function
.modifiers
= CCodeModifiers
.STATIC
;
3141 function
.add_parameter (new
CCodeParameter ("var", "gpointer"));
3143 push_function (function
);
3145 ccode
.add_expression (destroy_value (new
GLibValue (type
, new
CCodeIdentifier ("var"), true), true));
3149 cfile
.add_function_declaration (function
);
3150 cfile
.add_function (function
);
3153 element_destroy_func_expression
= new
CCodeIdentifier (free0_func
);
3156 return element_destroy_func_expression
;
3159 public CCodeExpression?
get_destroy_func_expression (DataType type
, bool is_chainup
= false) {
3160 if (context
.profile
== Profile
.GOBJECT
&& (type
.data_type
== glist_type
|| type
.data_type
== gslist_type
|| type
.data_type
== gnode_type
|| type
.data_type
== gqueue_type
)) {
3161 // create wrapper function to free list elements if necessary
3163 bool elements_require_free
= false;
3164 bool generic_elements
= false;
3165 CCodeExpression element_destroy_func_expression
= null;
3167 foreach (DataType type_arg
in type
.get_type_arguments ()) {
3168 elements_require_free
= requires_destroy (type_arg
);
3169 if (elements_require_free
) {
3170 element_destroy_func_expression
= get_destroy0_func_expression (type_arg
);
3171 generic_elements
= (type_arg is GenericType
);
3175 if (elements_require_free
) {
3176 CCodeExpression? cexpr
= null;
3177 if (element_destroy_func_expression is CCodeIdentifier
|| element_destroy_func_expression is CCodeMemberAccess
) {
3178 cexpr
= new
CCodeIdentifier (generate_collection_free_wrapper (type
, (generic_elements ?
null : element_destroy_func_expression as CCodeIdentifier
)));
3179 if (generic_elements
) {
3180 // adding second argument early, instance parameter will be inserted by destroy_value()
3181 cexpr
= new
CCodeFunctionCall (cexpr
);
3182 ((CCodeFunctionCall
) cexpr
).add_argument (element_destroy_func_expression
);
3185 Report
.error (null, "internal error: No useable element_destroy_function found");
3189 return new
CCodeIdentifier (get_ccode_free_function (type
.data_type
));
3191 } else if (type is ErrorType
) {
3192 return new
CCodeIdentifier ("g_error_free");
3193 } else if (type
.data_type
!= null) {
3194 string unref_function
;
3195 if (type is ReferenceType
) {
3196 if (is_reference_counting (type
.data_type
)) {
3197 unref_function
= get_ccode_unref_function ((ObjectTypeSymbol
) type
.data_type
);
3198 if (type
.data_type is Interface
&& unref_function
== null) {
3199 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 ()));
3203 var cl
= type
.data_type as Class
;
3204 if (cl
!= null && get_ccode_is_gboxed (cl
)) {
3205 unref_function
= generate_free_func_wrapper (type
);
3207 if (is_free_function_address_of (type
)) {
3208 unref_function
= generate_free_function_address_of_wrapper (type
);
3210 unref_function
= get_ccode_free_function (type
.data_type
);
3215 if (type
.nullable
) {
3216 unref_function
= get_ccode_free_function (type
.data_type
);
3217 if (unref_function
== null) {
3218 if (type
.data_type is Struct
&& ((Struct
) type
.data_type
).is_disposable ()) {
3219 unref_function
= generate_free_func_wrapper (type
);
3221 unref_function
= "g_free";
3224 } else if (type is EnumValueType
) {
3225 unref_function
= null;
3227 var st
= (Struct
) type
.data_type
;
3228 if (st
.is_disposable ()) {
3229 if (!get_ccode_has_destroy_function (st
)) {
3230 generate_struct_destroy_function (st
);
3232 unref_function
= get_ccode_destroy_function (st
);
3234 unref_function
= null;
3238 if (unref_function
== null) {
3239 return new
CCodeConstant ("NULL");
3241 return new
CCodeIdentifier (unref_function
);
3242 } else if (type is GenericType
) {
3243 var type_parameter
= ((GenericType
) type
).type_parameter
;
3244 string func_name
= "%s_destroy_func".printf (type_parameter
.name
.down ());
3246 if (type_parameter
.parent_symbol is Interface
) {
3247 var iface
= (Interface
) type_parameter
.parent_symbol
;
3248 require_generic_accessors (iface
);
3250 string method_name
= "get_%s_destroy_func".printf (type_parameter
.name
.down ());
3251 var cast_self
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface
))));
3252 cast_self
.add_argument (new
CCodeIdentifier ("self"));
3253 var function_call
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (cast_self
, method_name
));
3254 function_call
.add_argument (new
CCodeIdentifier ("self"));
3255 return function_call
;
3258 if (is_in_generic_type ((GenericType
) type
) && !is_chainup
&& !in_creation_method
) {
3259 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), func_name
);
3261 return get_variable_cexpression (func_name
);
3263 } else if (type is ArrayType
) {
3264 if (context
.profile
== Profile
.POSIX
) {
3265 return new
CCodeIdentifier ("free");
3267 return new
CCodeIdentifier ("g_free");
3269 } else if (type is PointerType
) {
3270 if (context
.profile
== Profile
.POSIX
) {
3271 return new
CCodeIdentifier ("free");
3273 return new
CCodeIdentifier ("g_free");
3276 return new
CCodeConstant ("NULL");
3280 private string generate_collection_free_wrapper (DataType collection_type
, CCodeIdentifier? element_destroy_func_expression
) {
3281 string destroy_func
;
3283 string? destroy_func_wrapper
= null;
3284 if (element_destroy_func_expression
!= null) {
3285 destroy_func_wrapper
= "_%s_%s".printf (get_ccode_free_function (collection_type
.data_type
), element_destroy_func_expression
.name
);
3286 if (!add_wrapper (destroy_func_wrapper
)) {
3287 // wrapper already defined
3288 return destroy_func_wrapper
;
3292 if (collection_type
.data_type
== gnode_type
) {
3293 destroy_func
= "_g_node_free_all";
3294 if (!add_wrapper (destroy_func
)) {
3295 // wrapper already defined
3296 return destroy_func
;
3299 var function
= new
CCodeFunction (destroy_func
, "void");
3300 function
.add_parameter (new
CCodeParameter ("self", get_ccode_name (collection_type
)));
3301 function
.add_parameter (new
CCodeParameter ("free_func", "GDestroyNotify"));
3303 push_function (function
);
3305 CCodeFunctionCall element_free_call
;
3306 string destroy_node_func
= "%s_node".printf (destroy_func
);
3307 var wrapper
= new
CCodeFunction (destroy_node_func
, "gboolean");
3308 wrapper
.modifiers
= CCodeModifiers
.STATIC
;
3309 wrapper
.add_parameter (new
CCodeParameter ("node", get_ccode_name (collection_type
)));
3310 wrapper
.add_parameter (new
CCodeParameter ("free_func", "GDestroyNotify"));
3311 push_function (wrapper
);
3313 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("free_func"));
3314 free_call
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier("node"), "data"));
3316 var data_isnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier("node"), "data"), new
CCodeConstant ("NULL"));
3317 var ccomma_data
= new
CCodeCommaExpression ();
3318 ccomma_data
.append_expression (new
CCodeConditionalExpression (data_isnull
, new
CCodeConstant ("NULL"), free_call
));
3319 ccode
.add_expression (ccomma_data
);
3321 ccode
.add_return (new
CCodeConstant ("FALSE"));
3324 cfile
.add_function_declaration (wrapper
);
3325 cfile
.add_function (wrapper
);
3327 /* Now the code to call g_traverse with the above */
3328 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_node_traverse"));
3329 element_free_call
.add_argument (new
CCodeIdentifier("self"));
3330 element_free_call
.add_argument (new
CCodeConstant ("G_POST_ORDER"));
3331 element_free_call
.add_argument (new
CCodeConstant ("G_TRAVERSE_ALL"));
3332 element_free_call
.add_argument (new
CCodeConstant ("-1"));
3333 element_free_call
.add_argument (new
CCodeCastExpression (new
CCodeIdentifier (destroy_node_func
), "GNodeTraverseFunc"));
3334 element_free_call
.add_argument (new
CCodeIdentifier ("free_func"));
3336 var free_func_isnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("free_func"), new
CCodeConstant ("NULL"));
3337 var ccomma
= new
CCodeCommaExpression ();
3338 ccomma
.append_expression (new
CCodeConditionalExpression (free_func_isnull
, new
CCodeConstant ("NULL"), element_free_call
));
3340 ccode
.add_expression (ccomma
);
3342 var cfreecall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_free_function (gnode_type
)));
3343 cfreecall
.add_argument (new
CCodeIdentifier ("self"));
3344 ccode
.add_expression (cfreecall
);
3346 function
.modifiers
= CCodeModifiers
.STATIC
;
3349 cfile
.add_function_declaration (function
);
3350 cfile
.add_function (function
);
3351 } else if (collection_type
.data_type
== glist_type
) {
3352 destroy_func
= "g_list_free_full";
3353 } else if (collection_type
.data_type
== gslist_type
) {
3354 destroy_func
= "g_slist_free_full";
3355 } else if (collection_type
.data_type
== gqueue_type
) {
3356 destroy_func
= "g_queue_free_full";
3358 Report
.error (null, "internal error: type of collection not supported");
3362 if (element_destroy_func_expression
!= null) {
3363 var function
= new
CCodeFunction (destroy_func_wrapper
, "void");
3364 function
.add_parameter (new
CCodeParameter ("self", get_ccode_name (collection_type
)));
3366 push_function (function
);
3368 var collection_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier (destroy_func
));
3369 collection_free_call
.add_argument (new
CCodeIdentifier ("self"));
3370 collection_free_call
.add_argument (new
CCodeCastExpression (element_destroy_func_expression
, "GDestroyNotify"));
3371 ccode
.add_expression (collection_free_call
);
3373 function
.modifiers
= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
3376 cfile
.add_function_declaration (function
);
3377 cfile
.add_function (function
);
3379 return destroy_func_wrapper
;
3382 return destroy_func
;
3385 public virtual string?
append_struct_array_free (Struct st
) {
3389 public CCodeExpression
destroy_local (LocalVariable local
) {
3390 return destroy_value (get_local_cvalue (local
));
3393 public CCodeExpression
destroy_parameter (Parameter param
) {
3394 return destroy_value (get_parameter_cvalue (param
));
3397 public CCodeExpression
destroy_field (Field field
, TargetValue? instance
) {
3398 return destroy_value (get_field_cvalue (field
, instance
));
3401 public virtual CCodeExpression
destroy_value (TargetValue value
, bool is_macro_definition
= false) {
3402 var type
= value
.value_type
;
3403 if (value
.actual_value_type
!= null) {
3404 type
= value
.actual_value_type
;
3406 var cvar
= get_cvalue_ (value
);
3408 if (type is DelegateType
) {
3409 var delegate_target
= get_delegate_target_cvalue (value
);
3410 var delegate_target_destroy_notify
= get_delegate_target_destroy_notify_cvalue (value
);
3412 var ccall
= new
CCodeFunctionCall (delegate_target_destroy_notify
);
3413 ccall
.add_argument (delegate_target
);
3415 var destroy_call
= new
CCodeCommaExpression ();
3416 destroy_call
.append_expression (ccall
);
3417 destroy_call
.append_expression (new
CCodeConstant ("NULL"));
3419 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, delegate_target_destroy_notify
, new
CCodeConstant ("NULL"));
3421 var ccomma
= new
CCodeCommaExpression ();
3422 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), destroy_call
));
3423 ccomma
.append_expression (new
CCodeAssignment (cvar
, new
CCodeConstant ("NULL")));
3424 ccomma
.append_expression (new
CCodeAssignment (delegate_target
, new
CCodeConstant ("NULL")));
3425 ccomma
.append_expression (new
CCodeAssignment (delegate_target_destroy_notify
, new
CCodeConstant ("NULL")));
3430 bool is_gcollection
= (type
.data_type
== glist_type
|| type
.data_type
== gslist_type
|| type
.data_type
== gnode_type
|| type
.data_type
== gqueue_type
);
3431 CCodeFunctionCall ccall
;
3432 var cexpr
= get_destroy_func_expression (type
);
3433 if (is_gcollection
&& cexpr is CCodeFunctionCall
) {
3434 ccall
= (CCodeFunctionCall
) cexpr
;
3436 ccall
= new
CCodeFunctionCall (cexpr
);
3439 if (type is ValueType
&& !type
.nullable
) {
3440 // normal value type, no null check
3441 var st
= type
.data_type as Struct
;
3442 if (st
!= null && st
.is_simple_type ()) {
3444 ccall
.add_argument (cvar
);
3446 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
3449 if (gvalue_type
!= null && type
.data_type
== gvalue_type
) {
3450 // g_value_unset must not be called for already unset values
3451 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
3452 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
3454 var ccomma
= new
CCodeCommaExpression ();
3455 ccomma
.append_expression (ccall
);
3456 ccomma
.append_expression (new
CCodeConstant ("NULL"));
3458 return new
CCodeConditionalExpression (cisvalid
, ccomma
, new
CCodeConstant ("NULL"));
3459 } else if ((type
.data_type
== gmutex_type
||
3460 type
.data_type
== grecmutex_type
||
3461 type
.data_type
== grwlock_type
||
3462 type
.data_type
== gcond_type
)) {
3463 // g_mutex_clear must not be called for uninitialized mutex
3464 // also, g_mutex_clear does not clear the struct
3465 requires_clear_mutex
= true;
3466 ccall
.call
= new
CCodeIdentifier ("_vala_clear_" + get_ccode_name (type
.data_type
));
3473 if (!is_gcollection
&& ccall
.call is CCodeIdentifier
&& !(type is ArrayType
) && !is_macro_definition
) {
3474 // generate and use NULL-aware free macro to simplify code
3476 var freeid
= (CCodeIdentifier
) ccall
.call
;
3477 string free0_func
= "_%s0".printf (freeid
.name
);
3479 if (add_wrapper (free0_func
)) {
3480 var macro
= destroy_value (new
GLibValue (type
, new
CCodeIdentifier ("var"), true), true);
3481 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("%s(var)".printf (free0_func
), macro
));
3484 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (free0_func
));
3485 ccall
.add_argument (cvar
);
3489 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
3491 /* can be simplified to
3492 * foo = (unref (foo), NULL)
3493 * if foo is of static type non-null
3496 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cvar
, new
CCodeConstant ("NULL"));
3497 if (type is GenericType
) {
3498 var parent
= ((GenericType
) type
).type_parameter
.parent_symbol
;
3499 var cl
= parent as Class
;
3500 if ((!(parent is Method
) && !(parent is ObjectTypeSymbol
)) || (cl
!= null && cl
.is_compact
)) {
3501 return new
CCodeConstant ("NULL");
3504 // unref functions are optional for type parameters
3505 var cunrefisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_destroy_func_expression (type
), new
CCodeConstant ("NULL"));
3506 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cunrefisnull
);
3509 // glib collections already have the free_func argument, so make sure the instance parameter gets first
3510 ccall
.insert_argument (0, cvar
);
3512 /* set freed references to NULL to prevent further use */
3513 var ccomma
= new
CCodeCommaExpression ();
3515 if (context
.profile
== Profile
.GOBJECT
) {
3516 if (type
.data_type
!= null && !is_reference_counting (type
.data_type
) &&
3517 (type
.data_type
.is_subtype_of (gstringbuilder_type
)
3518 || type
.data_type
.is_subtype_of (garray_type
)
3519 || type
.data_type
.is_subtype_of (gbytearray_type
)
3520 || type
.data_type
.is_subtype_of (gptrarray_type
))) {
3521 ccall
.add_argument (new
CCodeConstant ("TRUE"));
3522 } else if (type
.data_type
== gthreadpool_type
) {
3523 ccall
.add_argument (new
CCodeConstant ("FALSE"));
3524 ccall
.add_argument (new
CCodeConstant ("TRUE"));
3525 } else if (type is ArrayType
) {
3526 var array_type
= (ArrayType
) type
;
3527 if (requires_destroy (array_type
.element_type
)) {
3528 CCodeExpression csizeexpr
= null;
3529 if (((GLibValue
) value
).array_length_cvalues
!= null) {
3530 csizeexpr
= get_array_length_cvalue (value
);
3531 } else if (get_array_null_terminated (value
)) {
3532 requires_array_length
= true;
3533 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
3534 len_call
.add_argument (cvar
);
3535 csizeexpr
= len_call
;
3537 csizeexpr
= get_array_length_cexpr (value
);
3540 if (csizeexpr
!= null) {
3541 var st
= array_type
.element_type
.data_type as Struct
;
3542 if (st
!= null && !array_type
.element_type
.nullable
) {
3543 ccall
.call
= new
CCodeIdentifier (append_struct_array_free (st
));
3544 ccall
.add_argument (csizeexpr
);
3546 requires_array_free
= true;
3547 ccall
.call
= new
CCodeIdentifier ("_vala_array_free");
3548 ccall
.add_argument (csizeexpr
);
3549 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
3556 ccomma
.append_expression (ccall
);
3557 ccomma
.append_expression (new
CCodeConstant ("NULL"));
3559 var cassign
= new
CCodeAssignment (cvar
, ccomma
);
3561 // g_free (NULL) is allowed
3562 bool uses_gfree
= (type
.data_type
!= null && !is_reference_counting (type
.data_type
) && get_ccode_free_function (type
.data_type
) == "g_free");
3563 uses_gfree
= uses_gfree
|| type is ArrayType
;
3568 return new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), cassign
);
3571 public override void visit_end_full_expression (Expression expr
) {
3572 /* expr is a full expression, i.e. an initializer, the
3573 * expression in an expression statement, the controlling
3574 * expression in if, while, for, or foreach statements
3576 * we unref temporary variables at the end of a full
3579 if (temp_ref_values
.size
== 0) {
3580 /* nothing to do without temporary variables */
3584 var local_decl
= expr
.parent_node as LocalVariable
;
3585 if (!(local_decl
!= null && is_simple_struct_creation (local_decl
, local_decl
.initializer
))) {
3586 expr
.target_value
= store_temp_value (expr
.target_value
, expr
);
3589 foreach (var value
in temp_ref_values
) {
3590 ccode
.add_expression (destroy_value (value
));
3593 temp_ref_values
.clear ();
3596 public void emit_temp_var (LocalVariable local
, bool on_error
= false) {
3597 var init
= (!local
.name
.has_prefix ("*") && local
.init
);
3598 if (is_in_coroutine ()) {
3599 closure_struct
.add_field (get_ccode_name (local
.variable_type
), local
.name
);
3601 // even though closure struct is zerod, we need to initialize temporary variables
3602 // as they might be used multiple times when declared in a loop
3605 var initializer
= default_value_for_type (local
.variable_type
, false, on_error
);
3606 if (initializer
== null) {
3607 cfile
.add_include ("string.h");
3608 var memset_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
3609 memset_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (local
.name
)));
3610 memset_call
.add_argument (new
CCodeConstant ("0"));
3611 memset_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (local
.variable_type
))));
3612 ccode
.add_expression (memset_call
);
3614 ccode
.add_assignment (get_variable_cexpression (local
.name
), initializer
);
3618 var cvar
= new
CCodeVariableDeclarator (local
.name
, null, get_ccode_declarator_suffix (local
.variable_type
));
3620 cvar
.initializer
= default_value_for_type (local
.variable_type
, true, on_error
);
3623 ccode
.add_declaration (get_ccode_name (local
.variable_type
), cvar
);
3627 public override void visit_expression_statement (ExpressionStatement stmt
) {
3628 if (stmt
.expression
.error
) {
3633 /* free temporary objects and handle errors */
3635 foreach (var value
in temp_ref_values
) {
3636 ccode
.add_expression (destroy_value (value
));
3639 if (stmt
.tree_can_fail
&& stmt
.expression
.tree_can_fail
) {
3640 // simple case, no node breakdown necessary
3641 add_simple_check (stmt
.expression
);
3644 temp_ref_values
.clear ();
3647 protected virtual void append_scope_free (Symbol sym
, CodeNode? stop_at
= null) {
3648 var b
= (Block
) sym
;
3650 var local_vars
= b
.get_local_variables ();
3651 // free in reverse order
3652 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
3653 var local
= local_vars
[i
];
3654 if (!local
.unreachable
&& local
.active
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
3655 ccode
.add_expression (destroy_local (local
));
3660 int block_id
= get_block_id (b
);
3662 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
3663 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
3664 ccode
.add_expression (data_unref
);
3665 ccode
.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id
)), new
CCodeConstant ("NULL"));
3669 public void append_local_free (Symbol sym
, bool stop_at_loop
= false, CodeNode? stop_at
= null) {
3670 var b
= (Block
) sym
;
3672 append_scope_free (sym
, stop_at
);
3675 if (b
.parent_node is Loop
||
3676 b
.parent_node is ForeachStatement
||
3677 b
.parent_node is SwitchStatement
) {
3682 if (stop_at
!= null && b
.parent_node
== stop_at
) {
3686 if (sym
.parent_symbol is Block
) {
3687 append_local_free (sym
.parent_symbol
, stop_at_loop
, stop_at
);
3688 } else if (sym
.parent_symbol is Method
) {
3689 append_param_free ((Method
) sym
.parent_symbol
);
3690 } else if (sym
.parent_symbol is PropertyAccessor
) {
3691 var acc
= (PropertyAccessor
) sym
.parent_symbol
;
3692 if (acc
.value_parameter
!= null && requires_destroy (acc
.value_parameter
.variable_type
)) {
3693 ccode
.add_expression (destroy_parameter (acc
.value_parameter
));
3698 private void append_param_free (Method m
) {
3699 foreach (Parameter param
in m
.get_parameters ()) {
3700 if (!param
.captured
&& !param
.ellipsis
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
3701 ccode
.add_expression (destroy_parameter (param
));
3706 public bool variable_accessible_in_finally (LocalVariable local
) {
3707 if (current_try
== null) {
3711 var sym
= current_symbol
;
3713 while (!(sym is Method
|| sym is PropertyAccessor
) && sym
.scope
.lookup (local
.name
) == null) {
3714 if ((sym
.parent_node is TryStatement
&& ((TryStatement
) sym
.parent_node
).finally_body
!= null) ||
3715 (sym
.parent_node is CatchClause
&& ((TryStatement
) sym
.parent_node
.parent_node
).finally_body
!= null)) {
3720 sym
= sym
.parent_symbol
;
3726 public void return_out_parameter (Parameter param
) {
3727 var delegate_type
= param
.variable_type as DelegateType
;
3729 var value
= get_parameter_cvalue (param
);
3731 var old_coroutine
= is_in_coroutine ();
3732 current_method
.coroutine
= false;
3734 ccode
.open_if (get_variable_cexpression (param
.name
));
3735 ccode
.add_assignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (param
.name
)), get_cvalue_ (value
));
3737 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
3738 ccode
.add_assignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_ccode_delegate_target_name (param
))), get_delegate_target_cvalue (value
));
3739 if (delegate_type
.is_disposable ()) {
3740 ccode
.add_assignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_delegate_target_destroy_notify_cname (param
.name
))), get_delegate_target_destroy_notify_cvalue (get_parameter_cvalue (param
)));
3744 if (param
.variable_type
.is_disposable ()){
3746 current_method
.coroutine
= old_coroutine
;
3747 ccode
.add_expression (destroy_parameter (param
));
3748 current_method
.coroutine
= false;
3752 var array_type
= param
.variable_type as ArrayType
;
3753 if (array_type
!= null && !array_type
.fixed_length
&& get_ccode_array_length (param
)) {
3754 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3755 ccode
.open_if (get_variable_cexpression (get_parameter_array_length_cname (param
, dim
)));
3756 ccode
.add_assignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_parameter_array_length_cname (param
, dim
))), get_array_length_cvalue (value
, dim
));
3761 current_method
.coroutine
= old_coroutine
;
3764 public override void visit_return_statement (ReturnStatement stmt
) {
3765 Symbol return_expression_symbol
= null;
3767 if (stmt
.return_expression
!= null) {
3768 // avoid unnecessary ref/unref pair
3769 var local
= stmt
.return_expression
.symbol_reference as LocalVariable
;
3770 if (local
!= null && !local
.active
) {
3771 /* return expression is local variable taking ownership and
3772 * current method is transferring ownership */
3774 return_expression_symbol
= local
;
3778 // return array length if appropriate
3779 if (((current_method
!= null && get_ccode_array_length (current_method
)) || current_property_accessor
!= null) && current_return_type is ArrayType
) {
3780 var temp_value
= store_temp_value (stmt
.return_expression
.target_value
, stmt
);
3782 var array_type
= (ArrayType
) current_return_type
;
3783 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3784 var len_l
= get_result_cexpression (get_array_length_cname ("result", dim
));
3785 var len_r
= get_array_length_cvalue (temp_value
, dim
);
3786 if (!is_in_coroutine ()) {
3787 ccode
.open_if (len_l
);
3788 len_l
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, len_l
);
3789 ccode
.add_assignment (len_l
, len_r
);
3792 ccode
.add_assignment (len_l
, len_r
);
3796 stmt
.return_expression
.target_value
= temp_value
;
3797 } else if ((current_method
!= null || current_property_accessor
!= null) && current_return_type is DelegateType
) {
3798 var delegate_type
= (DelegateType
) current_return_type
;
3799 if (delegate_type
.delegate_symbol
.has_target
) {
3800 var temp_value
= store_temp_value (stmt
.return_expression
.target_value
, stmt
);
3802 var target_l
= get_result_cexpression (get_delegate_target_cname ("result"));
3803 if (!is_in_coroutine ()) {
3804 target_l
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_l
);
3806 var target_r
= get_delegate_target_cvalue (temp_value
);
3807 ccode
.add_assignment (target_l
, target_r
);
3808 if (delegate_type
.is_disposable ()) {
3809 var target_l_destroy_notify
= get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3810 if (!is_in_coroutine ()) {
3811 target_l_destroy_notify
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_l_destroy_notify
);
3813 var target_r_destroy_notify
= get_delegate_target_destroy_notify_cvalue (temp_value
);
3814 ccode
.add_assignment (target_l_destroy_notify
, target_r_destroy_notify
);
3817 stmt
.return_expression
.target_value
= temp_value
;
3821 if (stmt
.return_expression
!= null) {
3822 // assign method result to `result'
3823 CCodeExpression result_lhs
= get_result_cexpression ();
3824 if (current_return_type
.is_real_non_null_struct_type () && !is_in_coroutine ()) {
3825 result_lhs
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, result_lhs
);
3827 ccode
.add_assignment (result_lhs
, get_cvalue (stmt
.return_expression
));
3830 // free local variables
3831 append_local_free (current_symbol
);
3833 if (current_method
!= null) {
3834 // check postconditions
3835 foreach (Expression postcondition
in current_method
.get_postconditions ()) {
3836 create_postcondition_statement (postcondition
);
3840 if (current_method
!= null && !current_method
.coroutine
) {
3841 // assign values to output parameters if they are not NULL
3842 // otherwise, free the value if necessary
3843 foreach (var param
in current_method
.get_parameters ()) {
3844 if (param
.direction
!= ParameterDirection
.OUT
) {
3848 return_out_parameter (param
);
3852 // TODO: don't duplicate the code in CCodeMethodModule, we do this right now because it needs to be before return
3853 if (current_method
!= null && current_method
.get_attribute ("Profile") != null) {
3854 string prefix
= "_vala_prof_%s".printf (get_ccode_real_name (current_method
));
3856 var level
= new
CCodeIdentifier (prefix
+ "_level");
3857 ccode
.open_if (new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, new
CCodeUnaryExpression (CCodeUnaryOperator
.PREFIX_DECREMENT
, level
)));
3859 var timer
= new
CCodeIdentifier (prefix
+ "_timer");
3861 var stop_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_timer_stop"));
3862 stop_call
.add_argument (timer
);
3863 ccode
.add_expression (stop_call
);
3868 if (is_in_constructor ()) {
3869 ccode
.add_return (new
CCodeIdentifier ("obj"));
3870 } else if (is_in_destructor ()) {
3871 // do not call return as member cleanup and chain up to base finalizer
3872 // stil need to be executed
3873 ccode
.add_goto ("_return");
3874 } else if (is_in_coroutine ()) {
3875 } else if (current_method is CreationMethod
) {
3876 ccode
.add_return (new
CCodeIdentifier ("self"));
3877 } else if (current_return_type is VoidType
|| current_return_type
.is_real_non_null_struct_type ()) {
3878 // structs are returned via out parameter
3879 ccode
.add_return ();
3881 ccode
.add_return (new
CCodeIdentifier ("result"));
3884 if (return_expression_symbol
!= null) {
3885 return_expression_symbol
.active
= true;
3888 // required for destructors
3889 current_method_return
= true;
3892 public string get_symbol_lock_name (string symname
) {
3893 return "__lock_%s".printf (symname
);
3896 private CCodeExpression
get_lock_expression (Statement stmt
, Expression resource
) {
3897 CCodeExpression l
= null;
3898 var inner_node
= ((MemberAccess
)resource
).inner
;
3899 var member
= resource
.symbol_reference
;
3900 var parent
= (TypeSymbol
)resource
.symbol_reference
.parent_symbol
;
3902 if (member
.is_instance_member ()) {
3903 if (inner_node
== null) {
3904 l
= new
CCodeIdentifier ("self");
3905 } else if (parent
!= current_type_symbol
) {
3906 l
= generate_instance_cast (get_cvalue (inner_node
), parent
);
3908 l
= get_cvalue (inner_node
);
3911 l
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (l
, "priv"), get_symbol_lock_name (get_ccode_name (member
)));
3912 } else if (member
.is_class_member ()) {
3913 CCodeExpression klass
;
3915 if (get_this_type () != null) {
3916 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3917 k
.add_argument (new
CCodeIdentifier ("self"));
3920 klass
= new
CCodeIdentifier ("klass");
3923 var get_class_private_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(get_ccode_upper_case_name (parent
))));
3924 get_class_private_call
.add_argument (klass
);
3925 l
= new CCodeMemberAccess
.pointer (get_class_private_call
, get_symbol_lock_name (get_ccode_name (member
)));
3927 string lock_name
= "%s_%s".printf (get_ccode_lower_case_name (parent
), get_ccode_name (member
));
3928 l
= new
CCodeIdentifier (get_symbol_lock_name (lock_name
));
3933 public override void visit_lock_statement (LockStatement stmt
) {
3934 var l
= get_lock_expression (stmt
, stmt
.resource
);
3936 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_name (mutex_type
.scope
.lookup ("lock"))));
3937 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
3939 ccode
.add_expression (fc
);
3942 public override void visit_unlock_statement (UnlockStatement stmt
) {
3943 var l
= get_lock_expression (stmt
, stmt
.resource
);
3945 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_name (mutex_type
.scope
.lookup ("unlock"))));
3946 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
3948 ccode
.add_expression (fc
);
3951 public override void visit_delete_statement (DeleteStatement stmt
) {
3952 var pointer_type
= (PointerType
) stmt
.expression
.value_type
;
3953 DataType type
= pointer_type
;
3954 if (pointer_type
.base_type
.data_type
!= null && pointer_type
.base_type
.data_type
.is_reference_type ()) {
3955 type
= pointer_type
.base_type
;
3958 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
3959 ccall
.add_argument (get_cvalue (stmt
.expression
));
3960 ccode
.add_expression (ccall
);
3963 public override void visit_expression (Expression expr
) {
3964 if (get_cvalue (expr
) != null && !expr
.lvalue
) {
3965 if (expr
.formal_value_type is GenericType
&& !(expr
.value_type is GenericType
)) {
3966 var type_parameter
= ((GenericType
) expr
.formal_value_type
).type_parameter
;
3967 var st
= type_parameter
.parent_symbol
.parent_symbol as Struct
;
3968 if (type_parameter
.parent_symbol
!= garray_type
&&
3969 (st
== null || get_ccode_name (st
) != "va_list")) {
3970 // GArray and va_list don't use pointer-based generics
3971 set_cvalue (expr
, convert_from_generic_pointer (get_cvalue (expr
), expr
.value_type
));
3972 ((GLibValue
) expr
.target_value
).lvalue
= false;
3976 // memory management, implicit casts, and boxing/unboxing
3977 if (expr
.value_type
!= null) {
3978 // FIXME: temporary workaround until the refactoring is complete, not all target_value have a value_type
3979 expr
.target_value
.value_type
= expr
.value_type
;
3980 expr
.target_value
= transform_value (expr
.target_value
, expr
.target_type
, expr
);
3983 if (expr
.target_value
== null) {
3987 if (expr
.formal_target_type is GenericType
&& !(expr
.target_type is GenericType
)) {
3988 if (((GenericType
) expr
.formal_target_type
).type_parameter
.parent_symbol
!= garray_type
) {
3989 // GArray doesn't use pointer-based generics
3990 set_cvalue (expr
, convert_to_generic_pointer (get_cvalue (expr
), expr
.target_type
));
3991 ((GLibValue
) expr
.target_value
).lvalue
= false;
3995 if (!(expr
.value_type is ValueType
&& !expr
.value_type
.nullable
)) {
3996 ((GLibValue
) expr
.target_value
).non_null
= expr
.is_non_null ();
4001 public override void visit_boolean_literal (BooleanLiteral expr
) {
4002 if (context
.profile
== Profile
.GOBJECT
) {
4003 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"TRUE" : "FALSE"));
4005 cfile
.add_include ("stdbool.h");
4006 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"true" : "false"));
4010 public override void visit_character_literal (CharacterLiteral expr
) {
4011 if (expr
.get_char () >= 0x20 && expr
.get_char () < 0x80) {
4012 set_cvalue (expr
, new
CCodeConstant (expr
.value
));
4014 set_cvalue (expr
, new
CCodeConstant ("%uU".printf (expr
.get_char ())));
4018 public override void visit_integer_literal (IntegerLiteral expr
) {
4019 set_cvalue (expr
, new
CCodeConstant (expr
.value
+ expr
.type_suffix
));
4022 public override void visit_real_literal (RealLiteral expr
) {
4023 string c_literal
= expr
.value
;
4024 if (c_literal
.has_suffix ("d") || c_literal
.has_suffix ("D")) {
4025 // there is no suffix for double in C
4026 c_literal
= c_literal
.substring (0, c_literal
.length
- 1);
4028 if (!("." in c_literal
|| "e" in c_literal
|| "E" in c_literal
)) {
4029 // C requires period or exponent part for floating constants
4030 if ("f" in c_literal
|| "F" in c_literal
) {
4031 c_literal
= c_literal
.substring (0, c_literal
.length
- 1) + ".f";
4036 set_cvalue (expr
, new
CCodeConstant (c_literal
));
4039 public override void visit_string_literal (StringLiteral expr
) {
4040 set_cvalue (expr
, new CCodeConstant
.string (expr
.value
.replace ("\n", "\\n")));
4042 if (expr
.translate
) {
4043 // translated string constant
4045 var m
= (Method
) root_symbol
.scope
.lookup ("GLib").scope
.lookup ("_");
4046 add_symbol_declaration (cfile
, m
, get_ccode_name (m
));
4048 var translate
= new
CCodeFunctionCall (new
CCodeIdentifier ("_"));
4049 translate
.add_argument (get_cvalue (expr
));
4050 set_cvalue (expr
, translate
);
4054 public override void visit_regex_literal (RegexLiteral expr
) {
4055 string[] parts
= expr
.value
.split ("/", 3);
4056 string re
= parts
[2].escape ("");
4059 if (parts
[1].contains ("i")) {
4060 flags
+= " | G_REGEX_CASELESS";
4062 if (parts
[1].contains ("m")) {
4063 flags
+= " | G_REGEX_MULTILINE";
4065 if (parts
[1].contains ("s")) {
4066 flags
+= " | G_REGEX_DOTALL";
4068 if (parts
[1].contains ("x")) {
4069 flags
+= " | G_REGEX_EXTENDED";
4072 var cdecl
= new
CCodeDeclaration ("GRegex*");
4074 var cname
= "_tmp_regex_%d".printf (next_regex_id
);
4075 if (this
.next_regex_id
== 0) {
4076 var fun
= new
CCodeFunction ("_thread_safe_regex_init", "GRegex*");
4077 fun
.modifiers
= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
4078 fun
.add_parameter (new
CCodeParameter ("re", "GRegex**"));
4079 fun
.add_parameter (new
CCodeParameter ("pattern", "const gchar *"));
4080 fun
.add_parameter (new
CCodeParameter ("match_options", "GRegexMatchFlags"));
4082 push_function (fun
);
4084 var once_enter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_once_init_enter"));
4085 once_enter_call
.add_argument (new
CCodeConstant ("(volatile gsize*) re"));
4086 ccode
.open_if (once_enter_call
);
4088 var regex_new_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_regex_new"));
4089 regex_new_call
.add_argument (new
CCodeConstant ("pattern"));
4090 regex_new_call
.add_argument (new
CCodeConstant ("match_options"));
4091 regex_new_call
.add_argument (new
CCodeConstant ("0"));
4092 regex_new_call
.add_argument (new
CCodeConstant ("NULL"));
4093 ccode
.add_assignment (new
CCodeIdentifier ("GRegex* val"), regex_new_call
);
4095 var once_leave_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_once_init_leave"));
4096 once_leave_call
.add_argument (new
CCodeConstant ("(volatile gsize*) re"));
4097 once_leave_call
.add_argument (new
CCodeConstant ("(gsize) val"));
4098 ccode
.add_expression (once_leave_call
);
4102 ccode
.add_return (new
CCodeIdentifier ("*re"));
4106 cfile
.add_function (fun
);
4108 this
.next_regex_id
++;
4110 cdecl
.add_declarator (new
CCodeVariableDeclarator (cname
+ " = NULL"));
4111 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
4113 var regex_const
= new
CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname
, re
, flags
));
4115 cfile
.add_constant_declaration (cdecl
);
4116 set_cvalue (expr
, regex_const
);
4119 public override void visit_null_literal (NullLiteral expr
) {
4120 if (context
.profile
!= Profile
.GOBJECT
) {
4121 cfile
.add_include ("stddef.h");
4123 set_cvalue (expr
, new
CCodeConstant ("NULL"));
4125 var array_type
= expr
.target_type as ArrayType
;
4126 var delegate_type
= expr
.target_type as DelegateType
;
4127 if (array_type
!= null) {
4128 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4129 append_array_length (expr
, new
CCodeConstant ("0"));
4131 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
4132 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
4133 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
4137 public abstract TargetValue
get_local_cvalue (LocalVariable local
);
4139 public abstract TargetValue
get_parameter_cvalue (Parameter param
);
4141 public abstract TargetValue
get_field_cvalue (Field field
, TargetValue? instance
);
4143 public abstract TargetValue
load_variable (Variable variable
, TargetValue value
);
4145 public abstract TargetValue
load_this_parameter (TypeSymbol sym
);
4147 public abstract void store_value (TargetValue lvalue
, TargetValue value
, SourceReference? source_reference
= null);
4149 public virtual string get_delegate_target_cname (string delegate_cname
) {
4150 assert_not_reached ();
4153 public virtual CCodeExpression
get_delegate_target_cexpression (Expression delegate_expr
, out CCodeExpression delegate_target_destroy_notify
) {
4154 assert_not_reached ();
4157 public virtual CCodeExpression
get_delegate_target_cvalue (TargetValue value
) {
4158 return new
CCodeInvalidExpression ();
4161 public virtual CCodeExpression
get_delegate_target_destroy_notify_cvalue (TargetValue value
) {
4162 return new
CCodeInvalidExpression ();
4165 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname
) {
4166 assert_not_reached ();
4169 public override void visit_base_access (BaseAccess expr
) {
4170 CCodeExpression this_access
;
4171 if (is_in_coroutine ()) {
4173 this_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "self");
4175 this_access
= new
CCodeIdentifier ("self");
4178 set_cvalue (expr
, generate_instance_cast (this_access
, expr
.value_type
.data_type
));
4181 public override void visit_postfix_expression (PostfixExpression expr
) {
4182 MemberAccess ma
= find_property_access (expr
.inner
);
4184 // property postfix expression
4185 var prop
= (Property
) ma
.symbol_reference
;
4187 // increment/decrement property
4188 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
4189 var cexpr
= new
CCodeBinaryExpression (op
, get_cvalue (expr
.inner
), new
CCodeConstant ("1"));
4190 store_property (prop
, ma
.inner
, new
GLibValue (expr
.value_type
, cexpr
));
4192 // return previous value
4193 expr
.target_value
= expr
.inner
.target_value
;
4197 // assign current value to temp variable
4198 var temp_value
= store_temp_value (expr
.inner
.target_value
, expr
);
4200 // increment/decrement variable
4201 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
4202 var cexpr
= new
CCodeBinaryExpression (op
, get_cvalue_ (temp_value
), new
CCodeConstant ("1"));
4203 ccode
.add_assignment (get_cvalue (expr
.inner
), cexpr
);
4205 // return previous value
4206 expr
.target_value
= temp_value
;
4209 private MemberAccess?
find_property_access (Expression expr
) {
4210 if (!(expr is MemberAccess
)) {
4214 var ma
= (MemberAccess
) expr
;
4215 if (ma
.symbol_reference is Property
) {
4222 bool is_limited_generic_type (GenericType type
) {
4223 var cl
= type
.type_parameter
.parent_symbol as Class
;
4224 var st
= type
.type_parameter
.parent_symbol as Struct
;
4225 if ((cl
!= null && cl
.is_compact
) || st
!= null) {
4226 // compact classes and structs only
4227 // have very limited generics support
4233 public bool requires_copy (DataType type
) {
4234 if (!type
.is_disposable ()) {
4238 var cl
= type
.data_type as Class
;
4239 if (cl
!= null && is_reference_counting (cl
)
4240 && get_ccode_ref_function (cl
) == "") {
4241 // empty ref_function => no ref necessary
4245 if (type is GenericType
) {
4246 if (is_limited_generic_type ((GenericType
) type
)) {
4254 public bool requires_destroy (DataType type
) {
4255 if (!type
.is_disposable ()) {
4259 var array_type
= type as ArrayType
;
4260 if (array_type
!= null && array_type
.fixed_length
) {
4261 return requires_destroy (array_type
.element_type
);
4264 var cl
= type
.data_type as Class
;
4265 if (cl
!= null && is_reference_counting (cl
)
4266 && get_ccode_unref_function (cl
) == "") {
4267 // empty unref_function => no unref necessary
4271 if (type is GenericType
) {
4272 if (is_limited_generic_type ((GenericType
) type
)) {
4280 bool is_ref_function_void (DataType type
) {
4281 var cl
= type
.data_type as Class
;
4283 return get_ccode_ref_function_void (cl
);
4289 bool is_free_function_address_of (DataType type
) {
4290 var cl
= type
.data_type as Class
;
4292 return get_ccode_free_function_address_of (cl
);
4298 public virtual TargetValue?
copy_value (TargetValue value
, CodeNode node
) {
4299 var type
= value
.value_type
;
4300 var cexpr
= get_cvalue_ (value
);
4301 var result
= ((GLibValue
) value
).copy ();
4303 if (type is DelegateType
) {
4304 var delegate_type
= (DelegateType
) type
;
4305 if (delegate_type
.delegate_symbol
.has_target
&& !context
.deprecated
) {
4306 Report
.deprecated (node
.source_reference
, "copying delegates is not supported");
4308 result
.delegate_target_destroy_notify_cvalue
= new
CCodeConstant ("NULL");
4312 if (type is ValueType
&& !type
.nullable
) {
4313 // normal value type, no null check
4315 var temp_value
= create_temp_value (type
, true, node
, true);
4316 var ctemp
= get_cvalue_ (temp_value
);
4318 var vt
= (ValueType
) type
;
4319 var st
= (Struct
) vt
.type_symbol
;
4320 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_copy_function (st
)));
4321 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
4322 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
4324 if (!get_ccode_has_copy_function (st
)) {
4325 generate_struct_copy_function (st
);
4328 if (gvalue_type
!= null && type
.data_type
== gvalue_type
) {
4329 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
4330 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
4332 ccode
.open_if (cisvalid
);
4334 // GValue requires g_value_init in addition to g_value_copy
4335 var value_type_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VALUE_TYPE"));
4336 value_type_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
4338 var init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
4339 init_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
4340 init_call
.add_argument (value_type_call
);
4341 ccode
.add_expression (init_call
);
4342 ccode
.add_expression (copy_call
);
4346 // g_value_init/copy must not be called for uninitialized values
4347 store_value (temp_value
, value
, node
.source_reference
);
4350 ccode
.add_expression (copy_call
);
4356 /* (temp = expr, temp == NULL ? NULL : ref (temp))
4358 * can be simplified to
4360 * if static type of expr is non-null
4363 var dupexpr
= get_dup_func_expression (type
, node
.source_reference
);
4365 if (dupexpr
== null) {
4370 if (dupexpr is CCodeIdentifier
&& !(type is ArrayType
) && !(type is GenericType
) && !is_ref_function_void (type
)) {
4371 // generate and call NULL-aware ref function to reduce number
4372 // of temporary variables and simplify code
4374 var dupid
= (CCodeIdentifier
) dupexpr
;
4375 string dup0_func
= "_%s0".printf (dupid
.name
);
4377 // g_strdup is already NULL-safe
4378 if (dupid
.name
== "g_strdup") {
4379 dup0_func
= dupid
.name
;
4380 } else if (add_wrapper (dup0_func
)) {
4381 string pointer_cname
= "gpointer";
4382 if (context
.profile
== Profile
.POSIX
) {
4383 pointer_cname
= "void *";
4385 var dup0_fun
= new
CCodeFunction (dup0_func
, pointer_cname
);
4386 dup0_fun
.add_parameter (new
CCodeParameter ("self", pointer_cname
));
4387 dup0_fun
.modifiers
= CCodeModifiers
.STATIC
;
4389 push_function (dup0_fun
);
4391 var dup_call
= new
CCodeFunctionCall (dupexpr
);
4392 dup_call
.add_argument (new
CCodeIdentifier ("self"));
4394 ccode
.add_return (new
CCodeConditionalExpression (new
CCodeIdentifier ("self"), dup_call
, new
CCodeConstant ("NULL")));
4398 cfile
.add_function (dup0_fun
);
4401 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (dup0_func
));
4402 ccall
.add_argument (cexpr
);
4403 result
.cvalue
= ccall
;
4404 result
.value_type
.value_owned
= true;
4405 return store_temp_value (result
, node
);
4408 var ccall
= new
CCodeFunctionCall (dupexpr
);
4410 if (!(type is ArrayType
) && get_non_null (value
) && !is_ref_function_void (type
)) {
4411 // expression is non-null
4412 ccall
.add_argument (cexpr
);
4414 return store_temp_value (new
GLibValue (type
, ccall
), node
);
4416 var cnotnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, cexpr
, new
CCodeConstant ("NULL"));
4417 if (type is GenericType
) {
4418 // dup functions are optional for type parameters
4419 var cdupnotnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, get_dup_func_expression (type
, node
.source_reference
), new
CCodeConstant ("NULL"));
4420 cnotnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, cnotnull
, cdupnotnull
);
4423 if (type is GenericType
) {
4424 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
4425 ccall
.add_argument (new
CCodeCastExpression (cexpr
, "gpointer"));
4427 ccall
.add_argument (cexpr
);
4430 if (type is ArrayType
) {
4431 var array_type
= (ArrayType
) type
;
4432 ccall
.add_argument (get_array_length_cvalue (value
));
4434 if (array_type
.element_type is GenericType
) {
4435 var elem_dupexpr
= get_dup_func_expression (array_type
.element_type
, node
.source_reference
);
4436 if (elem_dupexpr
== null) {
4437 elem_dupexpr
= new
CCodeConstant ("NULL");
4439 ccall
.add_argument (elem_dupexpr
);
4443 CCodeExpression cifnull
;
4444 if (type
.data_type
!= null) {
4445 cifnull
= new
CCodeConstant ("NULL");
4447 // the value might be non-null even when the dup function is null,
4448 // so we may not just use NULL for type parameters
4450 // cast from gconstpointer to gpointer as methods in
4451 // generic classes may not return gconstpointer
4452 cifnull
= new
CCodeCastExpression (cexpr
, "gpointer");
4455 if (is_ref_function_void (type
)) {
4456 ccode
.open_if (cnotnull
);
4457 ccode
.add_expression (ccall
);
4460 var ccond
= new
CCodeConditionalExpression (cnotnull
, ccall
, cifnull
);
4461 result
.cvalue
= ccond
;
4462 result
= (GLibValue
) store_temp_value (result
, node
, true);
4468 bool is_reference_type_argument (DataType type_arg
) {
4469 if (type_arg is ErrorType
|| (type_arg
.data_type
!= null && type_arg
.data_type
.is_reference_type ())) {
4476 bool is_nullable_value_type_argument (DataType type_arg
) {
4477 if (type_arg is ValueType
&& type_arg
.nullable
) {
4484 bool is_signed_integer_type_argument (DataType type_arg
) {
4485 var st
= type_arg
.data_type as Struct
;
4486 if (type_arg is EnumValueType
) {
4488 } else if (type_arg
.nullable
) {
4490 } else if (st
== null) {
4492 } else if (st
.is_subtype_of (bool_type
.data_type
)) {
4494 } else if (st
.is_subtype_of (char_type
.data_type
)) {
4496 } else if (unichar_type
!= null && st
.is_subtype_of (unichar_type
.data_type
)) {
4498 } else if (st
.is_subtype_of (short_type
.data_type
)) {
4500 } else if (st
.is_subtype_of (int_type
.data_type
)) {
4502 } else if (st
.is_subtype_of (long_type
.data_type
)) {
4504 } else if (st
.is_subtype_of (int8_type
.data_type
)) {
4506 } else if (st
.is_subtype_of (int16_type
.data_type
)) {
4508 } else if (st
.is_subtype_of (int32_type
.data_type
)) {
4510 } else if (st
.is_subtype_of (gtype_type
)) {
4517 bool is_unsigned_integer_type_argument (DataType type_arg
) {
4518 var st
= type_arg
.data_type as Struct
;
4521 } else if (type_arg
.nullable
) {
4523 } else if (st
.is_subtype_of (uchar_type
.data_type
)) {
4525 } else if (st
.is_subtype_of (ushort_type
.data_type
)) {
4527 } else if (st
.is_subtype_of (uint_type
.data_type
)) {
4529 } else if (st
.is_subtype_of (ulong_type
.data_type
)) {
4531 } else if (st
.is_subtype_of (uint8_type
.data_type
)) {
4533 } else if (st
.is_subtype_of (uint16_type
.data_type
)) {
4535 } else if (st
.is_subtype_of (uint32_type
.data_type
)) {
4542 public void check_type (DataType type
) {
4543 var array_type
= type as ArrayType
;
4544 if (array_type
!= null) {
4545 check_type (array_type
.element_type
);
4546 if (array_type
.element_type is ArrayType
) {
4547 Report
.error (type
.source_reference
, "Stacked arrays are not supported");
4548 } else if (array_type
.element_type is DelegateType
) {
4549 var delegate_type
= (DelegateType
) array_type
.element_type
;
4550 if (delegate_type
.delegate_symbol
.has_target
) {
4551 Report
.error (type
.source_reference
, "Delegates with target are not supported as array element type");
4555 foreach (var type_arg
in type
.get_type_arguments ()) {
4556 check_type (type_arg
);
4557 check_type_argument (type_arg
);
4561 public void check_type_arguments (MemberAccess access
) {
4562 foreach (var type_arg
in access
.get_type_arguments ()) {
4563 check_type (type_arg
);
4564 check_type_argument (type_arg
);
4568 void check_type_argument (DataType type_arg
) {
4569 if (type_arg is GenericType
4570 || type_arg is PointerType
4571 || is_reference_type_argument (type_arg
)
4572 || is_nullable_value_type_argument (type_arg
)
4573 || is_signed_integer_type_argument (type_arg
)
4574 || is_unsigned_integer_type_argument (type_arg
)) {
4576 } else if (type_arg is DelegateType
) {
4577 var delegate_type
= (DelegateType
) type_arg
;
4578 if (delegate_type
.delegate_symbol
.has_target
) {
4579 Report
.error (type_arg
.source_reference
, "Delegates with target are not supported as generic type arguments");
4582 Report
.error (type_arg
.source_reference
, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg
.to_string ()));
4586 public virtual void generate_class_declaration (Class cl
, CCodeFile decl_space
) {
4587 if (add_symbol_declaration (decl_space
, cl
, get_ccode_name (cl
))) {
4592 public virtual void generate_interface_declaration (Interface iface
, CCodeFile decl_space
) {
4595 public virtual void generate_method_declaration (Method m
, CCodeFile decl_space
) {
4598 public virtual void generate_error_domain_declaration (ErrorDomain edomain
, CCodeFile decl_space
) {
4601 public void add_generic_type_arguments (Map
<int,CCodeExpression
> arg_map
, List
<DataType
> type_args
, CodeNode expr
, bool is_chainup
= false, List
<TypeParameter
>? type_parameters
= null) {
4602 int type_param_index
= 0;
4603 foreach (var type_arg
in type_args
) {
4604 if (type_parameters
!= null) {
4605 var type_param_name
= type_parameters
.get (type_param_index
).name
.down ();
4606 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeConstant ("\"%s_type\"".printf (type_param_name
)));
4607 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeConstant ("\"%s_dup_func\"".printf (type_param_name
)));
4608 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.05), new
CCodeConstant ("\"%s_destroy_func\"".printf (type_param_name
)));
4611 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), get_type_id_expression (type_arg
, is_chainup
));
4612 if (requires_copy (type_arg
)) {
4613 var dup_func
= get_dup_func_expression (type_arg
, type_arg
.source_reference
, is_chainup
);
4614 if (dup_func
== null) {
4615 // type doesn't contain a copy function
4619 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.04), new
CCodeCastExpression (dup_func
, "GBoxedCopyFunc"));
4620 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.06), new
CCodeCastExpression (get_destroy_func_expression (type_arg
, is_chainup
), "GDestroyNotify"));
4622 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.04), new
CCodeConstant ("NULL"));
4623 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.06), new
CCodeConstant ("NULL"));
4629 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
4630 CCodeExpression instance
= null;
4631 CCodeExpression creation_expr
= null;
4633 check_type (expr
.type_reference
);
4635 var st
= expr
.type_reference
.data_type as Struct
;
4636 if ((st
!= null && (!st
.is_simple_type () || get_ccode_name (st
) == "va_list")) || expr
.get_object_initializer ().size
> 0) {
4637 // value-type initialization or object creation expression with object initializer
4639 var local
= expr
.parent_node as LocalVariable
;
4640 var field
= expr
.parent_node as Field
;
4641 var a
= expr
.parent_node as Assignment
;
4642 if (local
!= null && is_simple_struct_creation (local
, local
.initializer
)) {
4643 instance
= get_cvalue_ (get_local_cvalue (local
));
4644 } else if (field
!= null && is_simple_struct_creation (field
, field
.initializer
)) {
4645 // field initialization
4646 var thisparam
= load_this_parameter ((TypeSymbol
) field
.parent_symbol
);
4647 instance
= get_cvalue_ (get_field_cvalue (field
, thisparam
));
4648 } else if (a
!= null && a
.left
.symbol_reference is Variable
&& is_simple_struct_creation ((Variable
) a
.left
.symbol_reference
, a
.right
)) {
4649 if (requires_destroy (a
.left
.value_type
)) {
4650 /* unref old value */
4651 ccode
.add_expression (destroy_value (a
.left
.target_value
));
4654 local
= a
.left
.symbol_reference as LocalVariable
;
4655 field
= a
.left
.symbol_reference as Field
;
4656 var param
= a
.left
.symbol_reference as Parameter
;
4657 if (local
!= null) {
4658 instance
= get_cvalue_ (get_local_cvalue (local
));
4659 } else if (field
!= null) {
4660 var inner
= ((MemberAccess
) a
.left
).inner
;
4661 instance
= get_cvalue_ (get_field_cvalue (field
, inner
!= null ? inner
.target_value
: null));
4662 } else if (param
!= null) {
4663 instance
= get_cvalue_ (get_parameter_cvalue (param
));
4666 var temp_value
= create_temp_value (expr
.type_reference
, true, expr
);
4667 instance
= get_cvalue_ (temp_value
);
4671 if (expr
.symbol_reference
== null) {
4672 // no creation method
4673 if (expr
.type_reference
.data_type is Struct
) {
4674 // memset needs string.h
4675 cfile
.add_include ("string.h");
4676 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
4677 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4678 creation_call
.add_argument (new
CCodeConstant ("0"));
4679 creation_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr
.type_reference
))));
4681 creation_expr
= creation_call
;
4683 } else if (expr
.type_reference
.data_type
== glist_type
||
4684 expr
.type_reference
.data_type
== gslist_type
) {
4685 // NULL is an empty list
4686 set_cvalue (expr
, new
CCodeConstant ("NULL"));
4687 } else if (expr
.symbol_reference is Method
) {
4688 // use creation method
4689 var m
= (Method
) expr
.symbol_reference
;
4690 var params
= m
.get_parameters ();
4691 CCodeFunctionCall creation_call
;
4693 CCodeFunctionCall async_call
= null;
4694 CCodeFunctionCall finish_call
= null;
4696 generate_method_declaration (m
, cfile
);
4698 var cl
= expr
.type_reference
.data_type as Class
;
4700 if (!get_ccode_has_new_function (m
)) {
4701 // use construct function directly
4702 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
)));
4703 creation_call
.add_argument (new
CCodeIdentifier (get_ccode_type_id (cl
)));
4705 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_name (m
)));
4708 if ((st
!= null && !st
.is_simple_type ()) && !(get_ccode_instance_pos (m
) < 0)) {
4709 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4710 } else if (st
!= null && get_ccode_name (st
) == "va_list") {
4711 creation_call
.add_argument (instance
);
4712 if (get_ccode_name (m
) == "va_start") {
4713 if (in_creation_method
) {
4714 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("va_copy"));
4715 creation_call
.add_argument (instance
);
4716 creation_call
.add_argument (new
CCodeIdentifier ("_vala_va_list"));
4718 Parameter last_param
= null;
4719 // FIXME: this doesn't take into account exception handling parameters
4720 foreach (var param
in current_method
.get_parameters ()) {
4721 if (param
.ellipsis
) {
4726 int nParams
= ccode
.get_parameter_count ();
4727 if (nParams
== 0 || !ccode
.get_parameter (nParams
- 1).ellipsis
) {
4728 Report
.error (expr
.source_reference
, "`va_list' used in method with fixed args");
4729 } else if (nParams
== 1) {
4730 Report
.error (expr
.source_reference
, "`va_list' used in method without parameter");
4732 creation_call
.add_argument (new
CCodeIdentifier (ccode
.get_parameter (nParams
- 2).name
));
4738 generate_type_declaration (expr
.type_reference
, cfile
);
4740 var in_arg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
4741 var out_arg_map
= in_arg_map
;
4743 if (m
!= null && m
.coroutine
) {
4746 async_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_name (m
)));
4747 finish_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_finish_name (m
)));
4749 creation_call
= finish_call
;
4751 // output arguments used separately
4752 out_arg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
4753 // pass GAsyncResult stored in closure to finish function
4754 out_arg_map
.set (get_param_pos (0.1), new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_res_"));
4757 if (cl
!= null && !cl
.is_compact
) {
4758 add_generic_type_arguments (in_arg_map
, expr
.type_reference
.get_type_arguments (), expr
);
4759 } else if (cl
!= null && get_ccode_simple_generics (m
)) {
4760 int type_param_index
= 0;
4761 foreach (var type_arg
in expr
.type_reference
.get_type_arguments ()) {
4762 if (requires_copy (type_arg
)) {
4763 in_arg_map
.set (get_param_pos (-1 + 0.1 * type_param_index
+ 0.03), get_destroy0_func_expression (type_arg
));
4765 in_arg_map
.set (get_param_pos (-1 + 0.1 * type_param_index
+ 0.03), new
CCodeConstant ("NULL"));
4771 bool ellipsis
= false;
4775 Iterator
<Parameter
> params_it
= params
.iterator ();
4776 foreach (Expression arg
in expr
.get_argument_list ()) {
4777 CCodeExpression cexpr
= get_cvalue (arg
);
4779 var carg_map
= in_arg_map
;
4781 Parameter param
= null;
4782 if (params_it
.next ()) {
4783 param
= params_it
.get ();
4784 ellipsis
= param
.ellipsis
;
4786 if (param
.direction
== ParameterDirection
.OUT
) {
4787 carg_map
= out_arg_map
;
4790 // g_array_new: element size
4791 if (cl
== garray_type
&& param
.name
== "element_size") {
4792 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
4793 csizeof
.add_argument (new
CCodeIdentifier (get_ccode_name (expr
.type_reference
.get_type_arguments ().get (0))));
4797 if (get_ccode_array_length (param
) && param
.variable_type is ArrayType
) {
4798 var array_type
= (ArrayType
) param
.variable_type
;
4799 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4800 carg_map
.set (get_param_pos (get_ccode_array_length_pos (param
) + 0.01 * dim
), get_array_length_cexpression (arg
, dim
));
4802 } else if (param
.variable_type is DelegateType
) {
4803 var deleg_type
= (DelegateType
) param
.variable_type
;
4804 var d
= deleg_type
.delegate_symbol
;
4806 CCodeExpression delegate_target_destroy_notify
;
4807 var delegate_target
= get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
);
4808 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
)), delegate_target
);
4809 if (deleg_type
.is_disposable ()) {
4810 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
) + 0.01), delegate_target_destroy_notify
);
4815 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
4817 if (get_ccode_type (param
) != null) {
4818 cexpr
= new
CCodeCastExpression (cexpr
, get_ccode_type (param
));
4821 cexpr
= handle_struct_argument (null, arg
, cexpr
);
4824 arg_pos
= get_param_pos (get_ccode_pos (param
), ellipsis
);
4826 // default argument position
4827 cexpr
= handle_struct_argument (null, arg
, cexpr
);
4828 arg_pos
= get_param_pos (i
, ellipsis
);
4831 carg_map
.set (arg_pos
, cexpr
);
4835 if (params_it
.next ()) {
4836 var param
= params_it
.get ();
4838 /* if there are more parameters than arguments,
4839 * the additional parameter is an ellipsis parameter
4840 * otherwise there is a bug in the semantic analyzer
4842 assert (param
.params_array
|| param
.ellipsis
);
4846 if (expr
.tree_can_fail
) {
4848 current_method_inner_error
= true;
4849 // add &inner_error before the ellipsis arguments
4850 out_arg_map
.set (get_param_pos (-1), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression ("_inner_error_")));
4854 /* ensure variable argument list ends with NULL
4855 * except when using printf-style arguments */
4857 in_arg_map
.set (get_param_pos (-1, true), new
CCodeConstant ("NULL"));
4858 } else if (!m
.printf_format
&& !m
.scanf_format
&& get_ccode_sentinel (m
) != "") {
4859 in_arg_map
.set (get_param_pos (-1, true), new
CCodeConstant (get_ccode_sentinel (m
)));
4863 if ((st
!= null && !st
.is_simple_type ()) && get_ccode_instance_pos (m
) < 0) {
4864 // instance parameter is at the end in a struct creation method
4865 out_arg_map
.set (get_param_pos (-3), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4868 if (m
!= null && m
.coroutine
) {
4869 if (expr
.is_yield_expression
) {
4870 // asynchronous call
4871 in_arg_map
.set (get_param_pos (-1), new
CCodeIdentifier (generate_ready_function (current_method
)));
4872 in_arg_map
.set (get_param_pos (-0.9), new
CCodeIdentifier ("_data_"));
4876 if (m
!= null && m
.parent_symbol is Class
) {
4877 if (get_ccode_finish_instance (m
)) {
4878 var tmp
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_source_object_");
4879 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), tmp
);
4883 // append C arguments in the right order
4888 if (async_call
!= creation_call
) {
4889 // don't append out arguments for .begin() calls
4893 foreach (int pos
in out_arg_map
.get_keys ()) {
4894 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
4898 if (min_pos
== -1) {
4901 creation_call
.add_argument (out_arg_map
.get (min_pos
));
4906 if (async_call
!= null) {
4910 foreach (int pos
in in_arg_map
.get_keys ()) {
4911 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
4915 if (min_pos
== -1) {
4918 async_call
.add_argument (in_arg_map
.get (min_pos
));
4923 if (expr
.is_yield_expression
) {
4924 // set state before calling async function to support immediate callbacks
4925 int state
= emit_context
.next_coroutine_state
++;
4927 ccode
.add_assignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_state_"), new
CCodeConstant (state
.to_string ()));
4928 ccode
.add_expression (async_call
);
4929 ccode
.add_return (new
CCodeConstant ("FALSE"));
4930 ccode
.add_label ("_state_%d".printf (state
));
4933 creation_expr
= creation_call
;
4935 // cast the return value of the creation method back to the intended type if
4936 // it requested a special C return type
4937 if (get_ccode_type (m
) != null) {
4938 creation_expr
= new
CCodeCastExpression (creation_expr
, get_ccode_name (expr
.type_reference
));
4940 } else if (expr
.symbol_reference is ErrorCode
) {
4941 var ecode
= (ErrorCode
) expr
.symbol_reference
;
4942 var edomain
= (ErrorDomain
) ecode
.parent_symbol
;
4943 CCodeFunctionCall creation_call
;
4945 generate_error_domain_declaration (edomain
, cfile
);
4947 if (expr
.get_argument_list ().size
== 1) {
4948 // must not be a format argument
4949 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_new_literal"));
4951 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_new"));
4953 creation_call
.add_argument (new
CCodeIdentifier (get_ccode_upper_case_name (edomain
)));
4954 creation_call
.add_argument (new
CCodeIdentifier (get_ccode_name (ecode
)));
4956 foreach (Expression arg
in expr
.get_argument_list ()) {
4957 creation_call
.add_argument (get_cvalue (arg
));
4960 creation_expr
= creation_call
;
4965 var local
= expr
.parent_node as LocalVariable
;
4966 if (local
!= null && is_simple_struct_creation (local
, local
.initializer
)) {
4967 // no temporary variable necessary
4968 ccode
.add_expression (creation_expr
);
4969 set_cvalue (expr
, instance
);
4970 } else if (instance
!= null) {
4971 if (expr
.type_reference
.data_type is Struct
) {
4972 ccode
.add_expression (creation_expr
);
4974 ccode
.add_assignment (instance
, creation_expr
);
4977 foreach (MemberInitializer init
in expr
.get_object_initializer ()) {
4978 if (init
.symbol_reference is Field
) {
4979 var f
= (Field
) init
.symbol_reference
;
4980 var instance_target_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
4981 var typed_inst
= transform_value (new
GLibValue (expr
.type_reference
, instance
, true), instance_target_type
, init
);
4982 store_field (f
, typed_inst
, init
.initializer
.target_value
, init
.source_reference
);
4984 var cl
= f
.parent_symbol as Class
;
4986 generate_class_struct_declaration (cl
, cfile
);
4988 } else if (init
.symbol_reference is Property
) {
4989 var inst_ma
= new MemberAccess
.simple ("new");
4990 inst_ma
.value_type
= expr
.type_reference
;
4991 set_cvalue (inst_ma
, instance
);
4992 store_property ((Property
) init
.symbol_reference
, inst_ma
, init
.initializer
.target_value
);
4993 // FIXME Do not ref/copy in the first place
4994 if (requires_destroy (init
.initializer
.target_value
.value_type
)) {
4995 ccode
.add_expression (destroy_value (init
.initializer
.target_value
));
5000 set_cvalue (expr
, instance
);
5001 } else if (creation_expr
!= null) {
5002 var temp_value
= create_temp_value (expr
.value_type
, false, expr
);
5003 ccode
.add_assignment (get_cvalue_ (temp_value
), creation_expr
);
5004 expr
.target_value
= temp_value
;
5006 if (context
.gobject_tracing
) {
5007 // GObject creation tracing enabled
5009 var cl
= expr
.type_reference
.data_type as Class
;
5010 if (cl
!= null && cl
.is_subtype_of (gobject_type
)) {
5013 // instance can be NULL in error cases
5014 ccode
.open_if (get_cvalue_ (expr
.target_value
));
5016 var set_data_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_set_data"));
5017 set_data_call
.add_argument (new
CCodeCastExpression (get_cvalue_ (expr
.target_value
), "GObject *"));
5018 set_data_call
.add_argument (new
CCodeConstant ("\"vala-creation-function\""));
5020 string func_name
= "";
5021 if (current_method
!= null) {
5022 func_name
= current_method
.get_full_name ();
5023 } else if (current_property_accessor
!= null) {
5024 func_name
= current_property_accessor
.get_full_name ();
5027 set_data_call
.add_argument (new
CCodeConstant ("\"%s\"".printf (func_name
)));
5029 ccode
.add_expression (set_data_call
);
5036 ((GLibValue
) expr
.target_value
).lvalue
= true;
5039 public CCodeExpression?
handle_struct_argument (Parameter? param
, Expression arg
, CCodeExpression? cexpr
) {
5041 if (param
!= null) {
5042 type
= param
.variable_type
;
5045 type
= arg
.value_type
;
5048 var unary
= arg as UnaryExpression
;
5049 // pass non-simple struct instances always by reference
5050 if (!(arg
.value_type is NullType
) && type
.is_real_struct_type ()) {
5051 // we already use a reference for arguments of ref, out, and nullable parameters
5052 if (!(unary
!= null && (unary
.operator
== UnaryOperator
.OUT
|| unary
.operator
== UnaryOperator
.REF
)) && !type
.nullable
) {
5053 if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
5054 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
5056 // if cexpr is e.g. a function call, we can't take the address of the expression
5057 var temp_value
= create_temp_value (type
, false, arg
);
5058 ccode
.add_assignment (get_cvalue_ (temp_value
), cexpr
);
5059 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue_ (temp_value
));
5067 public override void visit_sizeof_expression (SizeofExpression expr
) {
5068 generate_type_declaration (expr
.type_reference
, cfile
);
5070 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
5071 csizeof
.add_argument (new
CCodeIdentifier (get_ccode_name (expr
.type_reference
)));
5072 set_cvalue (expr
, csizeof
);
5075 public override void visit_typeof_expression (TypeofExpression expr
) {
5076 set_cvalue (expr
, get_type_id_expression (expr
.type_reference
));
5079 public override void visit_unary_expression (UnaryExpression expr
) {
5080 if (expr
.operator
== UnaryOperator
.REF
|| expr
.operator
== UnaryOperator
.OUT
) {
5081 var glib_value
= (GLibValue
) expr
.inner
.target_value
;
5083 var ref_value
= new
GLibValue (glib_value
.value_type
);
5084 if (expr
.target_type
!= null && glib_value
.value_type
.is_real_struct_type () && glib_value
.value_type
.nullable
!= expr
.target_type
.nullable
) {
5085 // the only possibility is that value_type is nullable and target_type is non-nullable
5086 ref_value
.cvalue
= glib_value
.cvalue
;
5088 ref_value
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.cvalue
);
5091 if (glib_value
.array_length_cvalues
!= null) {
5092 for (int i
= 0; i
< glib_value
.array_length_cvalues
.size
; i
++) {
5093 ref_value
.append_array_length_cvalue (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.array_length_cvalues
[i
]));
5097 if (glib_value
.delegate_target_cvalue
!= null) {
5098 ref_value
.delegate_target_cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.delegate_target_cvalue
);
5100 if (glib_value
.delegate_target_destroy_notify_cvalue
!= null) {
5101 ref_value
.delegate_target_destroy_notify_cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, glib_value
.delegate_target_destroy_notify_cvalue
);
5104 expr
.target_value
= ref_value
;
5108 CCodeUnaryOperator op
;
5109 if (expr
.operator
== UnaryOperator
.PLUS
) {
5110 op
= CCodeUnaryOperator
.PLUS
;
5111 } else if (expr
.operator
== UnaryOperator
.MINUS
) {
5112 op
= CCodeUnaryOperator
.MINUS
;
5113 } else if (expr
.operator
== UnaryOperator
.LOGICAL_NEGATION
) {
5114 op
= CCodeUnaryOperator
.LOGICAL_NEGATION
;
5115 } else if (expr
.operator
== UnaryOperator
.BITWISE_COMPLEMENT
) {
5116 op
= CCodeUnaryOperator
.BITWISE_COMPLEMENT
;
5117 } else if (expr
.operator
== UnaryOperator
.INCREMENT
) {
5118 op
= CCodeUnaryOperator
.PREFIX_INCREMENT
;
5119 } else if (expr
.operator
== UnaryOperator
.DECREMENT
) {
5120 op
= CCodeUnaryOperator
.PREFIX_DECREMENT
;
5122 assert_not_reached ();
5124 set_cvalue (expr
, new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
5127 public CCodeExpression?
try_cast_value_to_type (CCodeExpression ccodeexpr
, DataType from
, DataType to
, Expression? expr
= null) {
5128 if (from
== null || gvalue_type
== null || from
.data_type
!= gvalue_type
|| to
.data_type
== gvalue_type
|| get_ccode_type_id (to
) == "") {
5132 // explicit conversion from GValue
5133 var ccall
= new
CCodeFunctionCall (get_value_getter_function (to
));
5134 CCodeExpression gvalue
;
5135 if (from
.nullable
) {
5138 gvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ccodeexpr
);
5140 ccall
.add_argument (gvalue
);
5142 CCodeExpression rv
= ccall
;
5144 if (expr
!= null && to is ArrayType
) {
5145 // null-terminated string array
5146 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strv_length"));
5147 len_call
.add_argument (rv
);
5148 append_array_length (expr
, len_call
);
5149 } else if (to is StructValueType
) {
5150 CodeNode node
= expr
!= null ?
(CodeNode
) expr
: to
;
5151 var temp_value
= create_temp_value (to
, true, node
, true);
5152 var ctemp
= get_cvalue_ (temp_value
);
5154 rv
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeCastExpression (rv
, get_ccode_name (new
PointerType (to
))));
5155 var holds
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VALUE_HOLDS"));
5156 holds
.add_argument (gvalue
);
5157 holds
.add_argument (new
CCodeIdentifier (get_ccode_type_id (to
)));
5158 var cond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, holds
, ccall
);
5159 var warn
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_warning"));
5160 warn
.add_argument (new
CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
5161 var fail
= new
CCodeCommaExpression ();
5162 fail
.append_expression (warn
);
5163 fail
.append_expression (ctemp
);
5164 rv
= new
CCodeConditionalExpression (cond
, rv
, fail
);
5170 int next_variant_function_id
= 0;
5172 public TargetValue?
try_cast_variant_to_type (TargetValue value
, DataType to
, CodeNode? node
= null) {
5173 if (value
.value_type
== null || gvariant_type
== null || value
.value_type
.data_type
!= gvariant_type
) {
5177 string variant_func
= "_variant_get%d".printf (++next_variant_function_id
);
5179 var variant
= value
;
5180 if (value
.value_type
.value_owned
) {
5181 // value leaked, destroy it
5182 var temp_value
= store_temp_value (value
, node
);
5183 temp_ref_values
.insert (0, ((GLibValue
) temp_value
).copy ());
5184 variant
= temp_value
;
5187 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (variant_func
));
5188 ccall
.add_argument (get_cvalue_ (variant
));
5190 var result
= create_temp_value (to
, false, node
);
5192 var cfunc
= new
CCodeFunction (variant_func
);
5193 cfunc
.modifiers
= CCodeModifiers
.STATIC
;
5194 cfunc
.add_parameter (new
CCodeParameter ("value", "GVariant*"));
5196 if (!to
.is_real_non_null_struct_type ()) {
5197 cfunc
.return_type
= get_ccode_name (to
);
5200 if (to
.is_real_non_null_struct_type ()) {
5201 // structs are returned via out parameter
5202 cfunc
.add_parameter (new
CCodeParameter ("result", "%s *".printf (get_ccode_name (to
))));
5203 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue_ (result
)));
5204 } else if (to is ArrayType
) {
5205 // return array length if appropriate
5206 // tmp = _variant_get (variant, &tmp_length);
5207 var array_type
= (ArrayType
) to
;
5209 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5210 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_length_cvalue (result
, dim
)));
5211 cfunc
.add_parameter (new
CCodeParameter (get_array_length_cname ("result", dim
), "int*"));
5215 if (!to
.is_real_non_null_struct_type ()) {
5216 ccode
.add_assignment (get_cvalue_ (result
), ccall
);
5218 ccode
.add_expression (ccall
);
5221 push_function (cfunc
);
5223 CCodeExpression func_result
= deserialize_expression (to
, new
CCodeIdentifier ("value"), new
CCodeIdentifier ("*result"));
5224 if (to
.is_real_non_null_struct_type ()) {
5225 ccode
.add_assignment (new
CCodeIdentifier ("*result"), func_result
);
5227 ccode
.add_return (func_result
);
5232 cfile
.add_function_declaration (cfunc
);
5233 cfile
.add_function (cfunc
);
5235 return load_temp_value (result
);
5238 public virtual CCodeExpression?
deserialize_expression (DataType type
, CCodeExpression variant_expr
, CCodeExpression? expr
, CCodeExpression? error_expr
= null, out bool may_fail
= null) {
5239 assert_not_reached ();
5242 public virtual CCodeExpression?
serialize_expression (DataType type
, CCodeExpression expr
) {
5243 assert_not_reached ();
5246 public override void visit_cast_expression (CastExpression expr
) {
5247 generate_type_declaration (expr
.type_reference
, cfile
);
5249 if (!expr
.is_non_null_cast
) {
5250 var valuecast
= try_cast_value_to_type (get_cvalue (expr
.inner
), expr
.inner
.value_type
, expr
.type_reference
, expr
);
5251 if (valuecast
!= null) {
5252 set_cvalue (expr
, valuecast
);
5256 var variantcast
= try_cast_variant_to_type (expr
.inner
.target_value
, expr
.type_reference
, expr
);
5257 if (variantcast
!= null) {
5258 expr
.target_value
= variantcast
;
5263 var cl
= expr
.type_reference
.data_type as Class
;
5264 var iface
= expr
.type_reference
.data_type as Interface
;
5265 if (context
.profile
== Profile
.GOBJECT
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
5266 // checked cast for strict subtypes of GTypeInstance
5267 if (expr
.is_silent_cast
) {
5268 TargetValue to_cast
= expr
.inner
.target_value
;
5269 CCodeExpression cexpr
;
5270 if (!get_lvalue (to_cast
)) {
5271 to_cast
= store_temp_value (to_cast
, expr
);
5273 cexpr
= get_cvalue_ (to_cast
);
5274 var ccheck
= create_type_check (cexpr
, expr
.type_reference
);
5275 var ccast
= new
CCodeCastExpression (cexpr
, get_ccode_name (expr
.type_reference
));
5276 var cnull
= new
CCodeConstant ("NULL");
5277 var cast_value
= new
GLibValue (expr
.value_type
, new
CCodeConditionalExpression (ccheck
, ccast
, cnull
));
5278 if (requires_destroy (expr
.inner
.value_type
)) {
5279 var casted
= store_temp_value (cast_value
, expr
);
5280 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_cvalue_ (casted
), new
CCodeConstant ("NULL")));
5281 ccode
.add_expression (destroy_value (to_cast
));
5283 expr
.target_value
= ((GLibValue
) casted
).copy ();
5285 expr
.target_value
= cast_value
;
5288 set_cvalue (expr
, generate_instance_cast (get_cvalue (expr
.inner
), expr
.type_reference
.data_type
));
5291 if (expr
.is_silent_cast
) {
5292 set_cvalue (expr
, new
CCodeInvalidExpression ());
5294 Report
.error (expr
.source_reference
, "Operation not supported for this type");
5298 // recompute array length when casting to other array type
5299 var array_type
= expr
.type_reference as ArrayType
;
5300 if (array_type
!= null && expr
.inner
.value_type is ArrayType
) {
5301 if (array_type
.element_type is GenericType
|| ((ArrayType
) expr
.inner
.value_type
).element_type is GenericType
) {
5302 // element size unknown for generic arrays, retain array length as is
5303 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5304 append_array_length (expr
, get_array_length_cexpression (expr
.inner
, dim
));
5307 var sizeof_to
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
5308 sizeof_to
.add_argument (new
CCodeConstant (get_ccode_name (array_type
.element_type
)));
5310 var sizeof_from
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
5311 sizeof_from
.add_argument (new
CCodeConstant (get_ccode_name (((ArrayType
) expr
.inner
.value_type
).element_type
)));
5313 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5314 append_array_length (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.DIV
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, get_array_length_cexpression (expr
.inner
, dim
), sizeof_from
), sizeof_to
));
5317 } else if (array_type
!= null) {
5318 CCodeExpression array_length_expr
;
5320 var sizeof_to
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
5321 sizeof_to
.add_argument (new
CCodeConstant (get_ccode_name (array_type
.element_type
)));
5322 var sizeof_from
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
5324 var value_type
= expr
.inner
.value_type
;
5325 if (value_type is ValueType
) {
5326 var data_type
= ((ValueType
) value_type
).data_type
;
5327 sizeof_from
.add_argument (new
CCodeConstant (get_ccode_name (data_type
)));
5328 array_length_expr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.DIV
, sizeof_from
, sizeof_to
);
5329 } else if (value_type is PointerType
&& ((PointerType
) value_type
).base_type is ValueType
) {
5330 var data_type
= ((ValueType
) (((PointerType
) value_type
).base_type
)).data_type
;
5331 sizeof_from
.add_argument (new
CCodeConstant (get_ccode_name (data_type
)));
5332 array_length_expr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.DIV
, sizeof_from
, sizeof_to
);
5334 // cast from unsupported non-array to array, set invalid length
5335 // required by string.data, e.g.
5336 array_length_expr
= new
CCodeConstant ("-1");
5339 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5340 append_array_length (expr
, array_length_expr
);
5344 var innercexpr
= get_cvalue (expr
.inner
);
5345 if (expr
.type_reference is ValueType
&& !expr
.type_reference
.nullable
&&
5346 expr
.inner
.value_type is ValueType
&& expr
.inner
.value_type
.nullable
) {
5347 // nullable integer or float or boolean or struct or enum cast to non-nullable
5348 innercexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, innercexpr
);
5349 } else if (expr
.type_reference is ArrayType
5350 && expr
.inner
.value_type is ValueType
&& !expr
.inner
.value_type
.nullable
) {
5351 // integer or float or boolean or struct or enum to array cast
5352 innercexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, innercexpr
);
5354 set_cvalue (expr
, new
CCodeCastExpression (innercexpr
, get_ccode_name (expr
.type_reference
)));
5356 if (expr
.type_reference is DelegateType
) {
5357 if (get_delegate_target (expr
.inner
) != null) {
5358 set_delegate_target (expr
, get_delegate_target (expr
.inner
));
5360 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
5362 if (get_delegate_target_destroy_notify (expr
.inner
) != null) {
5363 set_delegate_target_destroy_notify (expr
, get_delegate_target_destroy_notify (expr
.inner
));
5365 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
5371 public override void visit_named_argument (NamedArgument expr
) {
5372 set_cvalue (expr
, get_cvalue (expr
.inner
));
5375 public override void visit_pointer_indirection (PointerIndirection expr
) {
5376 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_cvalue (expr
.inner
)));
5377 ((GLibValue
) expr
.target_value
).lvalue
= get_lvalue (expr
.inner
.target_value
);
5380 public override void visit_addressof_expression (AddressofExpression expr
) {
5381 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (expr
.inner
)));
5384 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
5385 /* tmp = expr.inner; expr.inner = NULL; expr = tmp; */
5386 expr
.target_value
= store_temp_value (expr
.inner
.target_value
, expr
);
5388 if (expr
.inner
.value_type is StructValueType
&& !expr
.inner
.value_type
.nullable
) {
5389 // memset needs string.h
5390 cfile
.add_include ("string.h");
5391 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
5392 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (expr
.inner
)));
5393 creation_call
.add_argument (new
CCodeConstant ("0"));
5394 creation_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr
.inner
.value_type
))));
5395 ccode
.add_expression (creation_call
);
5396 } else if (expr
.value_type is DelegateType
) {
5397 ccode
.add_assignment (get_cvalue (expr
.inner
), new
CCodeConstant ("NULL"));
5398 var target
= get_delegate_target_cvalue (expr
.inner
.target_value
);
5399 if (target
!= null) {
5400 ccode
.add_assignment (target
, new
CCodeConstant ("NULL"));
5402 var target_destroy_notify
= get_delegate_target_destroy_notify_cvalue (expr
.inner
.target_value
);
5403 if (target_destroy_notify
!= null) {
5404 ccode
.add_assignment (target_destroy_notify
, new
CCodeConstant ("NULL"));
5406 } else if (expr
.inner
.value_type is ArrayType
) {
5407 var array_type
= (ArrayType
) expr
.inner
.value_type
;
5408 var glib_value
= (GLibValue
) expr
.inner
.target_value
;
5410 ccode
.add_assignment (get_cvalue (expr
.inner
), new
CCodeConstant ("NULL"));
5411 if (glib_value
.array_length_cvalues
!= null) {
5412 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5413 ccode
.add_assignment (get_array_length_cvalue (glib_value
, dim
), new
CCodeConstant ("0"));
5417 ccode
.add_assignment (get_cvalue (expr
.inner
), new
CCodeConstant ("NULL"));
5421 public override void visit_binary_expression (BinaryExpression expr
) {
5422 var cleft
= get_cvalue (expr
.left
);
5423 var cright
= get_cvalue (expr
.right
);
5425 CCodeExpression? left_chain
= null;
5426 if (expr
.is_chained
) {
5427 var lbe
= (BinaryExpression
) expr
.left
;
5429 var temp_decl
= get_temp_variable (lbe
.right
.target_type
, true, null, false);
5430 emit_temp_var (temp_decl
);
5431 var cvar
= get_variable_cexpression (temp_decl
.name
);
5432 var clbe
= (CCodeBinaryExpression
) get_cvalue (lbe
);
5433 if (lbe
.is_chained
) {
5434 clbe
= (CCodeBinaryExpression
) clbe
.right
;
5436 ccode
.add_assignment (cvar
, get_cvalue (lbe
.right
));
5437 clbe
.right
= get_variable_cexpression (temp_decl
.name
);
5442 CCodeBinaryOperator op
;
5443 if (expr
.operator
== BinaryOperator
.PLUS
) {
5444 op
= CCodeBinaryOperator
.PLUS
;
5445 } else if (expr
.operator
== BinaryOperator
.MINUS
) {
5446 op
= CCodeBinaryOperator
.MINUS
;
5447 } else if (expr
.operator
== BinaryOperator
.MUL
) {
5448 op
= CCodeBinaryOperator
.MUL
;
5449 } else if (expr
.operator
== BinaryOperator
.DIV
) {
5450 op
= CCodeBinaryOperator
.DIV
;
5451 } else if (expr
.operator
== BinaryOperator
.MOD
) {
5452 if (expr
.value_type
.equals (double_type
)) {
5453 cfile
.add_include ("math.h");
5454 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("fmod"));
5455 ccall
.add_argument (cleft
);
5456 ccall
.add_argument (cright
);
5457 set_cvalue (expr
, ccall
);
5459 } else if (expr
.value_type
.equals (float_type
)) {
5460 cfile
.add_include ("math.h");
5461 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("fmodf"));
5462 ccall
.add_argument (cleft
);
5463 ccall
.add_argument (cright
);
5464 set_cvalue (expr
, ccall
);
5467 op
= CCodeBinaryOperator
.MOD
;
5469 } else if (expr
.operator
== BinaryOperator
.SHIFT_LEFT
) {
5470 op
= CCodeBinaryOperator
.SHIFT_LEFT
;
5471 } else if (expr
.operator
== BinaryOperator
.SHIFT_RIGHT
) {
5472 op
= CCodeBinaryOperator
.SHIFT_RIGHT
;
5473 } else if (expr
.operator
== BinaryOperator
.LESS_THAN
) {
5474 op
= CCodeBinaryOperator
.LESS_THAN
;
5475 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN
) {
5476 op
= CCodeBinaryOperator
.GREATER_THAN
;
5477 } else if (expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
) {
5478 op
= CCodeBinaryOperator
.LESS_THAN_OR_EQUAL
;
5479 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
5480 op
= CCodeBinaryOperator
.GREATER_THAN_OR_EQUAL
;
5481 } else if (expr
.operator
== BinaryOperator
.EQUALITY
) {
5482 op
= CCodeBinaryOperator
.EQUALITY
;
5483 } else if (expr
.operator
== BinaryOperator
.INEQUALITY
) {
5484 op
= CCodeBinaryOperator
.INEQUALITY
;
5485 } else if (expr
.operator
== BinaryOperator
.BITWISE_AND
) {
5486 op
= CCodeBinaryOperator
.BITWISE_AND
;
5487 } else if (expr
.operator
== BinaryOperator
.BITWISE_OR
) {
5488 op
= CCodeBinaryOperator
.BITWISE_OR
;
5489 } else if (expr
.operator
== BinaryOperator
.BITWISE_XOR
) {
5490 op
= CCodeBinaryOperator
.BITWISE_XOR
;
5491 } else if (expr
.operator
== BinaryOperator
.AND
) {
5492 op
= CCodeBinaryOperator
.AND
;
5493 } else if (expr
.operator
== BinaryOperator
.OR
) {
5494 op
= CCodeBinaryOperator
.OR
;
5495 } else if (expr
.operator
== BinaryOperator
.IN
) {
5496 if (expr
.right
.value_type is ArrayType
) {
5497 var array_type
= (ArrayType
) expr
.right
.value_type
;
5498 var node
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_contains_wrapper (array_type
)));
5499 node
.add_argument (cright
);
5500 node
.add_argument (get_array_length_cexpression (expr
.right
));
5501 if (array_type
.element_type is StructValueType
) {
5502 node
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cleft
));
5504 node
.add_argument (cleft
);
5506 set_cvalue (expr
, node
);
5508 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeBinaryExpression (CCodeBinaryOperator
.BITWISE_AND
, cright
, cleft
), cleft
));
5512 assert_not_reached ();
5515 if (expr
.operator
== BinaryOperator
.EQUALITY
||
5516 expr
.operator
== BinaryOperator
.INEQUALITY
) {
5517 var left_type
= expr
.left
.target_type
;
5518 var right_type
= expr
.right
.target_type
;
5519 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
5521 if (left_type is StructValueType
&& right_type is StructValueType
) {
5522 var equalfunc
= generate_struct_equal_function ((Struct
) left_type
.data_type
);
5523 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
5524 ccall
.add_argument (cleft
);
5525 ccall
.add_argument (cright
);
5527 cright
= new
CCodeConstant ("TRUE");
5528 } else if ((left_type is IntegerType
|| left_type is FloatingType
|| left_type is BooleanType
|| left_type is EnumValueType
) && left_type
.nullable
&&
5529 (right_type is IntegerType
|| right_type is FloatingType
|| right_type is BooleanType
|| right_type is EnumValueType
) && right_type
.nullable
) {
5530 var equalfunc
= generate_numeric_equal_function ((TypeSymbol
) left_type
.data_type
);
5531 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
5532 ccall
.add_argument (cleft
);
5533 ccall
.add_argument (cright
);
5535 cright
= new
CCodeConstant ("TRUE");
5539 if (!(expr
.left
.value_type is NullType
)
5540 && expr
.left
.value_type
.compatible (string_type
)
5541 && !(expr
.right
.value_type is NullType
)
5542 && expr
.right
.value_type
.compatible (string_type
)) {
5543 if (expr
.operator
== BinaryOperator
.PLUS
) {
5544 // string concatenation
5545 if (expr
.left
.is_constant () && expr
.right
.is_constant ()) {
5548 if (cleft is CCodeIdentifier
) {
5549 left
= ((CCodeIdentifier
) cleft
).name
;
5550 } else if (cleft is CCodeConstant
) {
5551 left
= ((CCodeConstant
) cleft
).name
;
5553 assert_not_reached ();
5555 if (cright is CCodeIdentifier
) {
5556 right
= ((CCodeIdentifier
) cright
).name
;
5557 } else if (cright is CCodeConstant
) {
5558 right
= ((CCodeConstant
) cright
).name
;
5560 assert_not_reached ();
5563 set_cvalue (expr
, new
CCodeConstant ("%s %s".printf (left
, right
)));
5566 var temp_value
= create_temp_value (expr
.value_type
, false, expr
);
5567 CCodeFunctionCall ccall
;
5569 if (context
.profile
== Profile
.POSIX
) {
5570 // convert to strcat (strcpy (malloc (1 + strlen (a) + strlen (b)), a), b)
5571 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcat"));
5572 var strcpy
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcpy"));
5573 var malloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("malloc"));
5575 var strlen_a
= new
CCodeFunctionCall (new
CCodeIdentifier ("strlen"));
5576 strlen_a
.add_argument (cleft
);
5577 var strlen_b
= new
CCodeFunctionCall (new
CCodeIdentifier ("strlen"));
5578 strlen_b
.add_argument (cright
);
5579 var newlength
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("1"),
5580 new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, strlen_a
, strlen_b
));
5581 malloc
.add_argument (newlength
);
5583 strcpy
.add_argument (malloc
);
5584 strcpy
.add_argument (cleft
);
5586 ccall
.add_argument (strcpy
);
5587 ccall
.add_argument (cright
);
5589 // convert to g_strconcat (a, b, NULL)
5590 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strconcat"));
5591 ccall
.add_argument (cleft
);
5592 ccall
.add_argument (cright
);
5593 ccall
.add_argument (new
CCodeConstant("NULL"));
5596 ccode
.add_assignment (get_cvalue_ (temp_value
), ccall
);
5597 expr
.target_value
= temp_value
;
5600 } else if (expr
.operator
== BinaryOperator
.EQUALITY
5601 || expr
.operator
== BinaryOperator
.INEQUALITY
5602 || expr
.operator
== BinaryOperator
.LESS_THAN
5603 || expr
.operator
== BinaryOperator
.GREATER_THAN
5604 || expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
5605 || expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
5606 CCodeFunctionCall ccall
;
5607 if (context
.profile
== Profile
.POSIX
) {
5608 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_cmp_wrapper (new
CCodeIdentifier ("strcmp"))));
5610 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
5612 ccall
.add_argument (cleft
);
5613 ccall
.add_argument (cright
);
5615 cright
= new
CCodeConstant ("0");
5619 set_cvalue (expr
, new
CCodeBinaryExpression (op
, cleft
, cright
));
5620 if (left_chain
!= null) {
5621 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, left_chain
, get_cvalue (expr
)));
5625 CCodeExpression?
create_type_check (CCodeNode ccodenode
, DataType type
) {
5626 var et
= type as ErrorType
;
5627 if (et
!= null && et
.error_code
!= null) {
5628 var matches_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_matches"));
5629 matches_call
.add_argument ((CCodeExpression
) ccodenode
);
5630 matches_call
.add_argument (new
CCodeIdentifier (get_ccode_upper_case_name (et
.error_domain
)));
5631 matches_call
.add_argument (new
CCodeIdentifier (get_ccode_name (et
.error_code
)));
5632 return matches_call
;
5633 } else if (et
!= null && et
.error_domain
!= null) {
5634 var instance_domain
= new CCodeMemberAccess
.pointer ((CCodeExpression
) ccodenode
, "domain");
5635 var type_domain
= new
CCodeIdentifier (get_ccode_upper_case_name (et
.error_domain
));
5636 return new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, instance_domain
, type_domain
);
5638 var type_id
= get_type_id_expression (type
);
5639 if (type_id
== null) {
5640 return new
CCodeInvalidExpression ();
5642 var ccheck
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
5643 ccheck
.add_argument ((CCodeExpression
) ccodenode
);
5644 ccheck
.add_argument (type_id
);
5649 string generate_array_contains_wrapper (ArrayType array_type
) {
5650 string array_contains_func
= "_vala_%s_array_contains".printf (get_ccode_lower_case_name (array_type
.element_type
));
5652 if (!add_wrapper (array_contains_func
)) {
5653 return array_contains_func
;
5656 var function
= new
CCodeFunction (array_contains_func
, "gboolean");
5657 function
.modifiers
= CCodeModifiers
.STATIC
;
5659 function
.add_parameter (new
CCodeParameter ("stack", "%s *".printf (get_ccode_name (array_type
.element_type
))));
5660 function
.add_parameter (new
CCodeParameter ("stack_length", "int"));
5661 if (array_type
.element_type is StructValueType
) {
5662 function
.add_parameter (new
CCodeParameter ("needle", "%s *".printf (get_ccode_name (array_type
.element_type
))));
5664 function
.add_parameter (new
CCodeParameter ("needle", get_ccode_name (array_type
.element_type
)));
5667 push_function (function
);
5669 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
5671 var cloop_initializer
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
5672 var cloop_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("stack_length"));
5673 var cloop_iterator
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i"));
5674 ccode
.open_for (cloop_initializer
, cloop_condition
, cloop_iterator
);
5676 var celement
= new
CCodeElementAccess (new
CCodeIdentifier ("stack"), new
CCodeIdentifier ("i"));
5677 var cneedle
= new
CCodeIdentifier ("needle");
5678 CCodeBinaryExpression cif_condition
;
5679 if (array_type
.element_type
.compatible (string_type
)) {
5680 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
5681 ccall
.add_argument (celement
);
5682 ccall
.add_argument (cneedle
);
5683 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ccall
, new
CCodeConstant ("0"));
5684 } else if (array_type
.element_type is StructValueType
) {
5685 var equalfunc
= generate_struct_equal_function ((Struct
) array_type
.element_type
.data_type
);
5686 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
5687 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, celement
));
5688 ccall
.add_argument (cneedle
);
5689 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ccall
, new
CCodeConstant ("TRUE"));
5691 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cneedle
, celement
);
5694 ccode
.open_if (cif_condition
);
5695 ccode
.add_return (new
CCodeConstant ("TRUE"));
5700 ccode
.add_return (new
CCodeConstant ("FALSE"));
5704 cfile
.add_function_declaration (function
);
5705 cfile
.add_function (function
);
5707 return array_contains_func
;
5710 string generate_cmp_wrapper (CCodeIdentifier cmpid
) {
5711 // generate and call NULL-aware cmp function to reduce number
5712 // of temporary variables and simplify code
5714 string cmp0_func
= "_%s0".printf (cmpid
.name
);
5716 // g_strcmp0 is already NULL-safe
5717 if (cmpid
.name
== "g_strcmp0") {
5718 cmp0_func
= cmpid
.name
;
5719 } else if (add_wrapper (cmp0_func
)) {
5720 var cmp0_fun
= new
CCodeFunction (cmp0_func
, "int");
5721 cmp0_fun
.add_parameter (new
CCodeParameter ("s1", "const void *"));
5722 cmp0_fun
.add_parameter (new
CCodeParameter ("s2", "const void *"));
5723 cmp0_fun
.modifiers
= CCodeModifiers
.STATIC
;
5725 push_function (cmp0_fun
);
5728 var noteq
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
5730 // if (!s1) return -(s1 != s2);
5732 var cexp
= new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, new
CCodeIdentifier ("s1"));
5733 ccode
.open_if (cexp
);
5734 ccode
.add_return (new
CCodeUnaryExpression (CCodeUnaryOperator
.MINUS
, noteq
));
5737 // if (!s2) return s1 != s2;
5739 var cexp
= new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, new
CCodeIdentifier ("s2"));
5740 ccode
.open_if (cexp
);
5741 ccode
.add_return (noteq
);
5744 // return strcmp (s1, s2);
5745 var cmp_call
= new
CCodeFunctionCall (cmpid
);
5746 cmp_call
.add_argument (new
CCodeIdentifier ("s1"));
5747 cmp_call
.add_argument (new
CCodeIdentifier ("s2"));
5748 ccode
.add_return (cmp_call
);
5752 cfile
.add_function (cmp0_fun
);
5758 public override void visit_type_check (TypeCheck expr
) {
5759 generate_type_declaration (expr
.type_reference
, cfile
);
5761 var type
= expr
.expression
.value_type
;
5762 var pointer_type
= type as PointerType
;
5763 if (pointer_type
!= null) {
5764 type
= pointer_type
.base_type
;
5766 var cl
= type
.data_type as Class
;
5767 var iface
= type
.data_type as Interface
;
5768 if ((cl
!= null && !cl
.is_compact
) || iface
!= null || type is GenericType
|| type is ErrorType
) {
5769 set_cvalue (expr
, create_type_check (get_cvalue (expr
.expression
), expr
.type_reference
));
5771 set_cvalue (expr
, new
CCodeInvalidExpression ());
5774 if (get_cvalue (expr
) is CCodeInvalidExpression
) {
5775 Report
.error (expr
.source_reference
, "type check expressions not supported for compact classes, structs, and enums");
5779 public override void visit_lambda_expression (LambdaExpression lambda
) {
5780 var delegate_type
= (DelegateType
) lambda
.target_type
;
5781 var d
= delegate_type
.delegate_symbol
;
5783 lambda
.method
.set_attribute_bool ("CCode", "array_length", get_ccode_array_length (d
));
5784 lambda
.method
.set_attribute_bool ("CCode", "array_null_terminated", get_ccode_array_null_terminated (d
));
5785 lambda
.method
.set_attribute_string ("CCode", "array_length_type", get_ccode_array_length_type (d
));
5787 lambda
.accept_children (this
);
5789 bool expr_owned
= lambda
.value_type
.value_owned
;
5791 set_cvalue (lambda
, new
CCodeIdentifier (get_ccode_name (lambda
.method
)));
5793 if (lambda
.method
.closure
) {
5794 int block_id
= get_block_id (current_closure_block
);
5795 var delegate_target
= get_variable_cexpression ("_data%d_".printf (block_id
));
5796 if (expr_owned
|| delegate_type
.is_called_once
) {
5797 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (block_id
)));
5798 ref_call
.add_argument (delegate_target
);
5799 delegate_target
= ref_call
;
5800 set_delegate_target_destroy_notify (lambda
, new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
5802 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5804 set_delegate_target (lambda
, delegate_target
);
5805 } else if (get_this_type () != null) {
5806 CCodeExpression delegate_target
= get_result_cexpression ("self");
5807 delegate_target
= convert_to_generic_pointer (delegate_target
, get_this_type ());
5808 if (expr_owned
|| delegate_type
.is_called_once
) {
5809 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (get_this_type (), lambda
.source_reference
));
5810 ref_call
.add_argument (delegate_target
);
5811 delegate_target
= ref_call
;
5812 set_delegate_target_destroy_notify (lambda
, get_destroy_func_expression (get_this_type ()));
5814 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5816 set_delegate_target (lambda
, delegate_target
);
5818 set_delegate_target (lambda
, new
CCodeConstant ("NULL"));
5819 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5823 public CCodeExpression
convert_from_generic_pointer (CCodeExpression cexpr
, DataType actual_type
) {
5825 if (is_reference_type_argument (actual_type
) || is_nullable_value_type_argument (actual_type
)) {
5826 result
= new
CCodeCastExpression (cexpr
, get_ccode_name (actual_type
));
5827 } else if (is_signed_integer_type_argument (actual_type
)) {
5828 result
= new
CCodeCastExpression (new
CCodeCastExpression (cexpr
, "gintptr"), get_ccode_name (actual_type
));
5829 } else if (is_unsigned_integer_type_argument (actual_type
)) {
5830 result
= new
CCodeCastExpression (new
CCodeCastExpression (cexpr
, "guintptr"), get_ccode_name (actual_type
));
5835 public CCodeExpression
convert_to_generic_pointer (CCodeExpression cexpr
, DataType actual_type
) {
5837 if (is_signed_integer_type_argument (actual_type
)) {
5838 result
= new
CCodeCastExpression (new
CCodeCastExpression (cexpr
, "gintptr"), "gpointer");
5839 } else if (is_unsigned_integer_type_argument (actual_type
)) {
5840 result
= new
CCodeCastExpression (new
CCodeCastExpression (cexpr
, "guintptr"), "gpointer");
5845 public TargetValue
transform_value (TargetValue value
, DataType? target_type
, CodeNode node
) {
5846 var type
= value
.value_type
;
5847 var result
= ((GLibValue
) value
).copy ();
5849 if (type
.value_owned
5850 && (target_type
== null || target_type is GenericType
|| !target_type
.floating_reference
)
5851 && type
.floating_reference
) {
5852 /* floating reference, sink it.
5854 var cl
= type
.data_type as ObjectTypeSymbol
;
5855 var sink_func
= (cl
!= null) ?
get_ccode_ref_sink_function (cl
) : "";
5857 if (sink_func
!= "") {
5858 if (type
.nullable
) {
5859 var is_not_null
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, result
.cvalue
, new
CCodeIdentifier ("NULL"));
5860 ccode
.open_if (is_not_null
);
5863 var csink
= new
CCodeFunctionCall (new
CCodeIdentifier (sink_func
));
5864 csink
.add_argument (result
.cvalue
);
5865 ccode
.add_expression (csink
);
5867 if (type
.nullable
) {
5871 Report
.error (node
.source_reference
, "type `%s' does not support floating references".printf (type
.data_type
.name
));
5875 bool boxing
= (type is ValueType
&& !type
.nullable
5876 && target_type is ValueType
&& target_type
.nullable
);
5877 bool unboxing
= (type is ValueType
&& type
.nullable
5878 && target_type is ValueType
&& !target_type
.nullable
);
5880 bool gvalue_boxing
= (context
.profile
== Profile
.GOBJECT
5881 && target_type
!= null
5882 && target_type
.data_type
== gvalue_type
5883 && !(type is NullType
)
5884 && get_ccode_type_id (type
) != "G_TYPE_VALUE");
5885 bool gvariant_boxing
= (context
.profile
== Profile
.GOBJECT
5886 && target_type
!= null
5887 && target_type
.data_type
== gvariant_type
5888 && !(type is NullType
)
5889 && type
.data_type
!= gvariant_type
);
5891 if (type
.value_owned
5892 && (target_type
== null || !target_type
.value_owned
|| boxing
|| unboxing
|| gvariant_boxing
)
5893 && !gvalue_boxing
/* gvalue can assume ownership of value, no need to free it */) {
5894 // value leaked, destroy it
5895 if (target_type is PointerType
) {
5896 // manual memory management for pointers
5897 } else if (requires_destroy (type
)) {
5898 if (!is_lvalue_access_allowed (type
)) {
5899 // cannot assign to a temporary variable
5900 temp_ref_values
.insert (0, result
.copy ());
5902 var temp_value
= create_temp_value (type
, false, node
);
5903 temp_ref_values
.insert (0, ((GLibValue
) temp_value
).copy ());
5904 store_value (temp_value
, result
, node
.source_reference
);
5905 result
.cvalue
= get_cvalue_ (temp_value
);
5910 if (target_type
== null) {
5911 // value will be destroyed, no need for implicit casts
5915 result
.value_type
= target_type
.copy ();
5917 if (gvalue_boxing
) {
5918 // implicit conversion to GValue
5919 var temp_value
= create_temp_value (target_type
, true, node
, true);
5921 if (!target_type
.value_owned
) {
5922 // boxed GValue leaked, destroy it
5923 temp_ref_values
.insert (0, ((GLibValue
) temp_value
).copy ());
5926 if (target_type
.nullable
) {
5927 var newcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
5928 newcall
.add_argument (new
CCodeConstant ("GValue"));
5929 newcall
.add_argument (new
CCodeConstant ("1"));
5930 var newassignment
= new
CCodeAssignment (get_cvalue_ (temp_value
), newcall
);
5931 ccode
.add_expression (newassignment
);
5934 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
5935 if (target_type
.nullable
) {
5936 ccall
.add_argument (get_cvalue_ (temp_value
));
5938 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue_ (temp_value
)));
5940 var type_id
= get_ccode_type_id (type
);
5941 if (type_id
== "") {
5942 Report
.error (node
.source_reference
, "GValue boxing of type `%s' is not supported".printf (type
.to_string ()));
5944 ccall
.add_argument (new
CCodeIdentifier (type_id
));
5945 ccode
.add_expression (ccall
);
5947 if (requires_destroy (type
)) {
5948 ccall
= new
CCodeFunctionCall (get_value_taker_function (type
));
5950 ccall
= new
CCodeFunctionCall (get_value_setter_function (type
));
5952 if (target_type
.nullable
) {
5953 ccall
.add_argument (get_cvalue_ (temp_value
));
5955 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue_ (temp_value
)));
5957 if (type
.is_real_non_null_struct_type ()) {
5958 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, result
.cvalue
));
5960 ccall
.add_argument (result
.cvalue
);
5963 ccode
.add_expression (ccall
);
5965 result
= (GLibValue
) temp_value
;
5966 } else if (gvariant_boxing
) {
5967 // implicit conversion to GVariant
5968 string variant_func
= "_variant_new%d".printf (++next_variant_function_id
);
5970 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (variant_func
));
5971 ccall
.add_argument (result
.cvalue
);
5973 var cfunc
= new
CCodeFunction (variant_func
, "GVariant*");
5974 cfunc
.modifiers
= CCodeModifiers
.STATIC
;
5975 cfunc
.add_parameter (new
CCodeParameter ("value", get_ccode_name (type
)));
5977 if (type is ArrayType
) {
5978 // return array length if appropriate
5979 var array_type
= (ArrayType
) type
;
5981 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5982 ccall
.add_argument (get_array_length_cvalue (value
, dim
));
5983 cfunc
.add_parameter (new
CCodeParameter (get_array_length_cname ("value", dim
), "gint"));
5987 push_function (cfunc
);
5989 // sink floating reference
5990 var sink
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_ref_sink"));
5991 sink
.add_argument (serialize_expression (type
, new
CCodeIdentifier ("value")));
5992 ccode
.add_return (sink
);
5996 cfile
.add_function_declaration (cfunc
);
5997 cfile
.add_function (cfunc
);
5999 result
.cvalue
= ccall
;
6000 result
.value_type
.value_owned
= true;
6002 result
= (GLibValue
) store_temp_value (result
, node
);
6003 if (!target_type
.value_owned
) {
6005 temp_ref_values
.insert (0, ((GLibValue
) result
).copy ());
6007 } else if (boxing
) {
6008 // value needs to be boxed
6010 result
.value_type
.nullable
= false;
6011 if (!result
.lvalue
|| !result
.value_type
.equals (value
.value_type
)) {
6012 result
.cvalue
= get_implicit_cast_expression (result
.cvalue
, value
.value_type
, result
.value_type
, node
);
6013 result
= (GLibValue
) store_temp_value (result
, node
);
6015 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, result
.cvalue
);
6016 result
.lvalue
= false;
6017 result
.value_type
.nullable
= true;
6018 } else if (unboxing
) {
6021 result
.cvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, result
.cvalue
);
6023 // TODO: rewrite get_implicit_cast_expression to return a GLibValue
6024 var old_cexpr
= result
.cvalue
;
6025 result
.cvalue
= get_implicit_cast_expression (result
.cvalue
, type
, target_type
, node
);
6026 result
.lvalue
= result
.lvalue
&& result
.cvalue
== old_cexpr
;
6029 bool array_needs_copy
= false;
6030 if (type is ArrayType
&& target_type is ArrayType
) {
6031 var array
= (ArrayType
) type
;
6032 var target_array
= (ArrayType
) target_type
;
6033 if (target_array
.element_type
.value_owned
&& !array
.element_type
.value_owned
) {
6034 array_needs_copy
= requires_copy (target_array
.element_type
);
6038 if (!gvalue_boxing
&& !gvariant_boxing
&& target_type
.value_owned
&& (!type
.value_owned
|| boxing
|| unboxing
|| array_needs_copy
) && requires_copy (target_type
) && !(type is NullType
)) {
6039 // need to copy value
6040 var copy
= (GLibValue
) copy_value (result
, node
);
6041 if (target_type
.data_type is Interface
&& copy
== null) {
6042 Report
.error (node
.source_reference
, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure".printf (target_type
.data_type
.get_full_name ()));
6047 // implicit array copying is deprecated, but allow it for internal codegen usage
6048 var prop_acc
= node as PropertyAccessor
;
6049 if ((prop_acc
!= null && !prop_acc
.automatic_body
)
6050 && result
.value_type is ArrayType
) {
6051 Report
.deprecated (node
.source_reference
, "implicit copy of array is deprecated, explicitly invoke the copy method instead");
6058 public virtual CCodeExpression
get_implicit_cast_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, CodeNode? node
) {
6059 var cexpr
= source_cexpr
;
6061 if (expression_type
.data_type
!= null && expression_type
.data_type
== target_type
.data_type
) {
6062 // same type, no cast required
6066 if (expression_type is NullType
) {
6067 // null literal, no cast required when not converting to generic type pointer
6071 generate_type_declaration (target_type
, cfile
);
6073 var cl
= target_type
.data_type as Class
;
6074 var iface
= target_type
.data_type as Interface
;
6075 if (context
.checking
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
6076 // checked cast for strict subtypes of GTypeInstance
6077 return generate_instance_cast (cexpr
, target_type
.data_type
);
6078 } else if (target_type
.data_type
!= null && get_ccode_name (expression_type
) != get_ccode_name (target_type
)) {
6079 var st
= target_type
.data_type as Struct
;
6080 if (target_type
.data_type
.is_reference_type () || (st
!= null && st
.is_simple_type ())) {
6081 // don't cast non-simple structs
6082 return new
CCodeCastExpression (cexpr
, get_ccode_name (target_type
));
6091 public void store_property (Property prop
, Expression? instance
, TargetValue value
) {
6092 if (instance is BaseAccess
) {
6093 if (prop
.base_property
!= null) {
6094 var base_class
= (Class
) prop
.base_property
.parent_symbol
;
6095 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class
, null))));
6096 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class
, null))));
6098 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "set_%s".printf (prop
.name
)));
6099 ccall
.add_argument ((CCodeExpression
) get_ccodenode (instance
));
6100 var cexpr
= get_cvalue_ (value
);
6101 if (prop
.property_type
.is_real_non_null_struct_type ()) {
6102 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
6104 ccall
.add_argument (cexpr
);
6106 ccode
.add_expression (ccall
);
6107 } else if (prop
.base_interface_property
!= null) {
6108 var base_iface
= (Interface
) prop
.base_interface_property
.parent_symbol
;
6109 string parent_iface_var
= "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class
), get_ccode_lower_case_name (base_iface
));
6111 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), "set_%s".printf (prop
.name
)));
6112 ccall
.add_argument ((CCodeExpression
) get_ccodenode (instance
));
6113 var cexpr
= get_cvalue_ (value
);
6114 if (prop
.property_type
.is_real_non_null_struct_type ()) {
6115 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
6117 ccall
.add_argument (cexpr
);
6119 ccode
.add_expression (ccall
);
6124 var set_func
= "g_object_set";
6126 var base_property
= prop
;
6127 if (!get_ccode_no_accessor_method (prop
)) {
6128 if (prop
.base_property
!= null) {
6129 base_property
= prop
.base_property
;
6130 } else if (prop
.base_interface_property
!= null) {
6131 base_property
= prop
.base_interface_property
;
6134 if (prop is DynamicProperty
) {
6135 set_func
= get_dynamic_property_setter_cname ((DynamicProperty
) prop
);
6137 generate_property_accessor_declaration (base_property
.set_accessor
, cfile
);
6138 set_func
= get_ccode_name (base_property
.set_accessor
);
6140 if (!prop
.external
&& prop
.external_package
) {
6141 // internal VAPI properties
6142 // only add them once per source file
6143 if (add_generated_external_symbol (prop
)) {
6144 visit_property (prop
);
6150 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (set_func
));
6152 if (prop
.binding
== MemberBinding
.INSTANCE
) {
6153 /* target instance is first argument */
6154 var cinstance
= (CCodeExpression
) get_ccodenode (instance
);
6156 if (prop
.parent_symbol is Struct
&& !((Struct
) prop
.parent_symbol
).is_simple_type ()) {
6157 // we need to pass struct instance by reference if it isn't a simple-type
6158 var instance_value
= instance
.target_value
;
6159 if (!get_lvalue (instance_value
)) {
6160 instance_value
= store_temp_value (instance_value
, instance
);
6162 cinstance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue_ (instance_value
));
6165 ccall
.add_argument (cinstance
);
6168 if (get_ccode_no_accessor_method (prop
)) {
6169 /* property name is second argument of g_object_set */
6170 ccall
.add_argument (get_property_canonical_cconstant (prop
));
6173 var cexpr
= get_cvalue_ (value
);
6175 if (prop
.property_type
.is_real_non_null_struct_type ()) {
6176 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
6179 var array_type
= prop
.property_type as ArrayType
;
6181 ccall
.add_argument (cexpr
);
6183 if (array_type
!= null && get_ccode_array_length (prop
)) {
6184 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
6185 ccall
.add_argument (get_array_length_cvalue (value
, dim
));
6187 } else if (prop
.property_type is DelegateType
) {
6188 var delegate_type
= (DelegateType
) prop
.property_type
;
6189 if (delegate_type
.delegate_symbol
.has_target
) {
6190 ccall
.add_argument (get_delegate_target_cvalue (value
));
6191 if (base_property
.set_accessor
.value_type
.value_owned
) {
6192 ccall
.add_argument (get_delegate_target_destroy_notify_cvalue (value
));
6197 if (get_ccode_no_accessor_method (prop
)) {
6198 ccall
.add_argument (new
CCodeConstant ("NULL"));
6201 ccode
.add_expression (ccall
);
6204 public bool add_wrapper (string wrapper_name
) {
6205 return wrappers
.add (wrapper_name
);
6208 public bool add_generated_external_symbol (Symbol external_symbol
) {
6209 return generated_external_symbols
.add (external_symbol
);
6212 public static DataType
get_data_type_for_symbol (TypeSymbol sym
) {
6213 DataType type
= null;
6216 type
= new
ObjectType ((Class
) sym
);
6217 } else if (sym is Interface
) {
6218 type
= new
ObjectType ((Interface
) sym
);
6219 } else if (sym is Struct
) {
6220 var st
= (Struct
) sym
;
6221 if (st
.is_boolean_type ()) {
6222 type
= new
BooleanType (st
);
6223 } else if (st
.is_integer_type ()) {
6224 type
= new
IntegerType (st
);
6225 } else if (st
.is_floating_type ()) {
6226 type
= new
FloatingType (st
);
6228 type
= new
StructValueType (st
);
6230 } else if (sym is Enum
) {
6231 type
= new
EnumValueType ((Enum
) sym
);
6232 } else if (sym is ErrorDomain
) {
6233 type
= new
ErrorType ((ErrorDomain
) sym
, null);
6234 } else if (sym is ErrorCode
) {
6235 type
= new
ErrorType ((ErrorDomain
) sym
.parent_symbol
, (ErrorCode
) sym
);
6237 Report
.error (null, "internal error: `%s' is not a supported type".printf (sym
.get_full_name ()));
6238 return new
InvalidType ();
6244 public CCodeExpression?
default_value_for_type (DataType type
, bool initializer_expression
, bool on_error
= false) {
6245 var st
= type
.data_type as Struct
;
6246 var array_type
= type as ArrayType
;
6247 if (type
.data_type
!= null && !type
.nullable
6248 && (on_error ?
get_ccode_default_value_on_error (type
.data_type
) : get_ccode_default_value (type
.data_type
)) != "") {
6249 return new
CCodeConstant (on_error ?
get_ccode_default_value_on_error (type
.data_type
) : get_ccode_default_value (type
.data_type
));
6250 } else if (initializer_expression
&& !type
.nullable
&&
6251 (st
!= null || (array_type
!= null && array_type
.fixed_length
))) {
6252 // 0-initialize struct with struct initializer { 0 }
6253 // only allowed as initializer expression in C
6254 var clist
= new
CCodeInitializerList ();
6255 clist
.append (new
CCodeConstant ("0"));
6257 } else if ((type
.data_type
!= null && type
.data_type
.is_reference_type ())
6259 || type is PointerType
|| type is DelegateType
6260 || (array_type
!= null && !array_type
.fixed_length
)) {
6261 return new
CCodeConstant ("NULL");
6262 } else if (type is GenericType
) {
6263 return new
CCodeConstant ("NULL");
6264 } else if (type is ErrorType
) {
6265 return new
CCodeConstant ("NULL");
6270 private void create_property_type_check_statement (Property prop
, bool check_return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
6271 if (check_return_type
) {
6272 create_type_check_statement (prop
, prop
.property_type
, t
, non_null
, var_name
);
6274 create_type_check_statement (prop
, new
VoidType (), t
, non_null
, var_name
);
6278 public virtual void create_type_check_statement (CodeNode method_node
, DataType ret_type
, TypeSymbol t
, bool non_null
, string var_name
) {
6281 public int get_param_pos (double param_pos
, bool ellipsis
= false) {
6283 if (param_pos
>= 0) {
6284 return (int) (param_pos
* 1000);
6286 return (int) ((100 + param_pos
) * 1000);
6289 if (param_pos
>= 0) {
6290 return (int) ((100 + param_pos
) * 1000);
6292 return (int) ((200 + param_pos
) * 1000);
6297 public CCodeExpression?
get_ccodenode (Expression node
) {
6298 if (get_cvalue (node
) == null) {
6301 return get_cvalue (node
);
6304 public bool is_lvalue_access_allowed (DataType type
) {
6305 var array_type
= type as ArrayType
;
6306 if (array_type
!= null && array_type
.inline_allocated
) {
6309 if (type
.data_type
!= null) {
6310 return type
.data_type
.get_attribute_bool ("CCode", "lvalue_access", true);
6315 public CCodeDeclaratorSuffix?
get_ccode_declarator_suffix (DataType type
) {
6316 var array_type
= type as ArrayType
;
6317 if (array_type
!= null) {
6318 if (array_type
.fixed_length
) {
6319 return new CCodeDeclaratorSuffix
.with_array (get_ccodenode (array_type
.length
));
6320 } else if (array_type
.inline_allocated
) {
6321 return new CCodeDeclaratorSuffix
.with_array ();
6327 public CCodeConstant
get_signal_canonical_constant (Signal sig
, string? detail
= null) {
6328 return new
CCodeConstant ("\"%s%s\"".printf (get_ccode_name (sig
), (detail
!= null ?
"::%s".printf (detail
) : "")));
6331 public bool get_signal_has_emitter (Signal sig
) {
6332 return sig
.get_attribute ("HasEmitter") != null;
6335 public CCodeConstant
get_property_canonical_cconstant (Property prop
) {
6336 return new
CCodeConstant ("\"%s\"".printf (prop
.name
.replace ("_", "-")));
6339 public override void visit_class (Class cl
) {
6342 public void create_postcondition_statement (Expression postcondition
) {
6343 var cassert
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_warn_if_fail"));
6345 postcondition
.emit (this
);
6347 string message
= ((string) postcondition
.source_reference
.begin
.pos
).substring (0, (int) (postcondition
.source_reference
.end
.pos
- postcondition
.source_reference
.begin
.pos
));
6348 cassert
.add_argument (get_cvalue (postcondition
));
6349 cassert
.add_argument (new
CCodeConstant ("\"%s\"".printf (message
.replace ("\n", " ").escape (""))));
6350 requires_assert
= true;
6352 ccode
.add_expression (cassert
);
6355 public virtual bool is_gobject_property (Property prop
) {
6359 public DataType?
get_this_type () {
6360 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) {
6361 return current_method
.this_parameter
.variable_type
;
6362 } else if (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
) {
6363 return current_property_accessor
.prop
.this_parameter
.variable_type
;
6364 } else if (current_constructor
!= null && current_constructor
.binding
== MemberBinding
.INSTANCE
) {
6365 return current_constructor
.this_parameter
.variable_type
;
6366 } else if (current_destructor
!= null && current_destructor
.binding
== MemberBinding
.INSTANCE
) {
6367 return current_destructor
.this_parameter
.variable_type
;
6372 public CCodeFunctionCall
generate_instance_cast (CCodeExpression expr
, TypeSymbol type
) {
6373 var result
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_CAST"));
6374 result
.add_argument (expr
);
6375 result
.add_argument (new
CCodeIdentifier (get_ccode_type_id (type
)));
6376 result
.add_argument (new
CCodeIdentifier (get_ccode_name (type
)));
6380 void generate_struct_destroy_function (Struct st
) {
6381 if (cfile
.add_declaration (get_ccode_destroy_function (st
))) {
6382 // only generate function once per source file
6386 var function
= new
CCodeFunction (get_ccode_destroy_function (st
), "void");
6387 function
.modifiers
= CCodeModifiers
.STATIC
;
6388 function
.add_parameter (new
CCodeParameter ("self", "%s *".printf (get_ccode_name (st
))));
6390 push_context (new
EmitContext ());
6391 push_function (function
);
6393 var this_value
= load_this_parameter (st
);
6394 foreach (Field f
in st
.get_fields ()) {
6395 if (f
.binding
== MemberBinding
.INSTANCE
) {
6396 if (get_ccode_delegate_target (f
) && requires_destroy (f
.variable_type
)) {
6397 ccode
.add_expression (destroy_field (f
, this_value
));
6405 cfile
.add_function_declaration (function
);
6406 cfile
.add_function (function
);
6409 void generate_struct_copy_function (Struct st
) {
6410 if (cfile
.add_declaration (get_ccode_copy_function (st
))) {
6411 // only generate function once per source file
6415 var function
= new
CCodeFunction (get_ccode_copy_function (st
), "void");
6416 function
.modifiers
= CCodeModifiers
.STATIC
;
6417 function
.add_parameter (new
CCodeParameter ("self", "const %s *".printf (get_ccode_name (st
))));
6418 function
.add_parameter (new
CCodeParameter ("dest", "%s *".printf (get_ccode_name (st
))));
6420 push_context (new
EmitContext ());
6421 push_function (function
);
6423 var dest_struct
= new
GLibValue (get_data_type_for_symbol (st
), new
CCodeIdentifier ("(*dest)"), true);
6424 foreach (Field f
in st
.get_fields ()) {
6425 if (f
.binding
== MemberBinding
.INSTANCE
) {
6426 var value
= load_field (f
, load_this_parameter ((TypeSymbol
) st
));
6427 if (get_ccode_delegate_target (f
) && requires_copy (f
.variable_type
)) {
6428 value
= copy_value (value
, f
);
6429 if (value
== null) {
6430 // error case, continue to avoid critical
6434 store_field (f
, dest_struct
, value
);
6441 cfile
.add_function_declaration (function
);
6442 cfile
.add_function (function
);
6445 public void return_default_value (DataType return_type
, bool on_error
= false) {
6446 var st
= return_type
.data_type as Struct
;
6447 if (st
!= null && st
.is_simple_type () && !return_type
.nullable
) {
6448 // 0-initialize struct with struct initializer { 0 }
6449 // only allowed as initializer expression in C
6450 var ret_temp_var
= get_temp_variable (return_type
, true, null, true);
6451 emit_temp_var (ret_temp_var
, on_error
);
6452 ccode
.add_return (new
CCodeIdentifier (ret_temp_var
.name
));
6454 ccode
.add_return (default_value_for_type (return_type
, false, on_error
));
6458 public virtual void generate_dynamic_method_wrapper (DynamicMethod method
) {
6461 public virtual bool method_has_wrapper (Method method
) {
6465 public virtual CCodeExpression
get_param_spec_cexpression (Property prop
) {
6466 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
6469 public virtual CCodeExpression
get_param_spec (Property prop
) {
6470 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
6473 public virtual CCodeExpression
get_signal_creation (Signal sig
, TypeSymbol type
) {
6474 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
6477 public virtual void register_dbus_info (CCodeBlock block
, ObjectTypeSymbol bindable
) {
6480 public virtual string get_dynamic_property_getter_cname (DynamicProperty node
) {
6481 Report
.error (node
.source_reference
, "dynamic properties are not supported for %s".printf (node
.dynamic_type
.to_string ()));
6485 public virtual string get_dynamic_property_setter_cname (DynamicProperty node
) {
6486 Report
.error (node
.source_reference
, "dynamic properties are not supported for %s".printf (node
.dynamic_type
.to_string ()));
6490 public virtual string get_dynamic_signal_cname (DynamicSignal node
) {
6494 public virtual string get_dynamic_signal_connect_wrapper_name (DynamicSignal node
) {
6498 public virtual string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal node
) {
6502 public virtual string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node
) {
6506 public virtual string get_array_length_cname (string array_cname
, int dim
) {
6510 public virtual string get_parameter_array_length_cname (Parameter param
, int dim
) {
6514 public virtual CCodeExpression
get_array_length_cexpression (Expression array_expr
, int dim
= -1) {
6515 return new
CCodeConstant ("");
6518 public virtual CCodeExpression
get_array_length_cvalue (TargetValue value
, int dim
= -1) {
6519 return new
CCodeInvalidExpression ();
6522 public virtual string get_array_size_cname (string array_cname
) {
6526 public virtual void add_simple_check (CodeNode node
, bool always_fails
= false) {
6529 public virtual string generate_ready_function (Method m
) {
6533 public CCodeExpression?
get_cvalue (Expression expr
) {
6534 if (expr
.target_value
== null) {
6537 var glib_value
= (GLibValue
) expr
.target_value
;
6538 return glib_value
.cvalue
;
6541 public CCodeExpression?
get_cvalue_ (TargetValue value
) {
6542 var glib_value
= (GLibValue
) value
;
6543 return glib_value
.cvalue
;
6546 public void set_cvalue (Expression expr
, CCodeExpression? cvalue
) {
6547 var glib_value
= (GLibValue
) expr
.target_value
;
6548 if (glib_value
== null) {
6549 glib_value
= new
GLibValue (expr
.value_type
);
6550 expr
.target_value
= glib_value
;
6552 glib_value
.cvalue
= cvalue
;
6555 public CCodeExpression?
get_array_size_cvalue (TargetValue value
) {
6556 var glib_value
= (GLibValue
) value
;
6557 return glib_value
.array_size_cvalue
;
6560 public void set_array_size_cvalue (TargetValue value
, CCodeExpression? cvalue
) {
6561 var glib_value
= (GLibValue
) value
;
6562 glib_value
.array_size_cvalue
= cvalue
;
6565 public CCodeExpression?
get_delegate_target (Expression expr
) {
6566 if (expr
.target_value
== null) {
6569 var glib_value
= (GLibValue
) expr
.target_value
;
6570 return glib_value
.delegate_target_cvalue
;
6573 public void set_delegate_target (Expression expr
, CCodeExpression? delegate_target
) {
6574 var glib_value
= (GLibValue
) expr
.target_value
;
6575 if (glib_value
== null) {
6576 glib_value
= new
GLibValue (expr
.value_type
);
6577 expr
.target_value
= glib_value
;
6579 glib_value
.delegate_target_cvalue
= delegate_target
;
6582 public CCodeExpression?
get_delegate_target_destroy_notify (Expression expr
) {
6583 if (expr
.target_value
== null) {
6586 var glib_value
= (GLibValue
) expr
.target_value
;
6587 return glib_value
.delegate_target_destroy_notify_cvalue
;
6590 public void set_delegate_target_destroy_notify (Expression expr
, CCodeExpression? destroy_notify
) {
6591 var glib_value
= (GLibValue
) expr
.target_value
;
6592 if (glib_value
== null) {
6593 glib_value
= new
GLibValue (expr
.value_type
);
6594 expr
.target_value
= glib_value
;
6596 glib_value
.delegate_target_destroy_notify_cvalue
= destroy_notify
;
6599 public void append_array_length (Expression expr
, CCodeExpression size
) {
6600 var glib_value
= (GLibValue
) expr
.target_value
;
6601 if (glib_value
== null) {
6602 glib_value
= new
GLibValue (expr
.value_type
);
6603 expr
.target_value
= glib_value
;
6605 glib_value
.append_array_length_cvalue (size
);
6608 public List
<CCodeExpression
>?
get_array_lengths (Expression expr
) {
6609 var glib_value
= (GLibValue
) expr
.target_value
;
6610 if (glib_value
== null) {
6611 glib_value
= new
GLibValue (expr
.value_type
);
6612 expr
.target_value
= glib_value
;
6614 return glib_value
.array_length_cvalues
;
6617 public bool get_lvalue (TargetValue value
) {
6618 var glib_value
= (GLibValue
) value
;
6619 return glib_value
.lvalue
;
6622 public bool get_non_null (TargetValue value
) {
6623 var glib_value
= (GLibValue
) value
;
6624 return glib_value
.non_null
;
6627 public string?
get_ctype (TargetValue value
) {
6628 var glib_value
= (GLibValue
) value
;
6629 return glib_value
.ctype
;
6632 public bool get_array_null_terminated (TargetValue value
) {
6633 var glib_value
= (GLibValue
) value
;
6634 return glib_value
.array_null_terminated
;
6637 public CCodeExpression
get_array_length_cexpr (TargetValue value
) {
6638 var glib_value
= (GLibValue
) value
;
6639 return glib_value
.array_length_cexpr
;
6643 internal class Vala
.GLibValue
: TargetValue
{
6644 public CCodeExpression cvalue
;
6646 public bool non_null
;
6647 public string? ctype
;
6649 public List
<CCodeExpression
> array_length_cvalues
;
6650 public CCodeExpression? array_size_cvalue
;
6651 public bool array_null_terminated
;
6652 public CCodeExpression? array_length_cexpr
;
6654 public CCodeExpression? delegate_target_cvalue
;
6655 public CCodeExpression? delegate_target_destroy_notify_cvalue
;
6657 public GLibValue (DataType? value_type
= null, CCodeExpression? cvalue
= null, bool lvalue
= false) {
6659 this
.cvalue
= cvalue
;
6660 this
.lvalue
= lvalue
;
6663 public void append_array_length_cvalue (CCodeExpression length_cvalue
) {
6664 if (array_length_cvalues
== null) {
6665 array_length_cvalues
= new ArrayList
<CCodeExpression
> ();
6667 array_length_cvalues
.add (length_cvalue
);
6670 public GLibValue
copy () {
6671 var result
= new
GLibValue (value_type
.copy (), cvalue
, lvalue
);
6672 result
.actual_value_type
= actual_value_type
;
6673 result
.non_null
= non_null
;
6674 result
.ctype
= ctype
;
6676 if (array_length_cvalues
!= null) {
6677 foreach (var cexpr
in array_length_cvalues
) {
6678 result
.append_array_length_cvalue (cexpr
);
6681 result
.array_size_cvalue
= array_size_cvalue
;
6682 result
.array_null_terminated
= array_null_terminated
;
6683 result
.array_length_cexpr
= array_length_cexpr
;
6685 result
.delegate_target_cvalue
= delegate_target_cvalue
;
6686 result
.delegate_target_destroy_notify_cvalue
= delegate_target_destroy_notify_cvalue
;