1 /* valaccodebasemodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
27 * Code visitor generating C Code.
29 public abstract class Vala
.CCodeBaseModule
: CodeGenerator
{
30 public class EmitContext
{
31 public Symbol? current_symbol
;
32 public ArrayList
<Symbol
> symbol_stack
= new ArrayList
<Symbol
> ();
33 public TryStatement current_try
;
34 public CatchClause current_catch
;
35 public CCodeFunction ccode
;
36 public ArrayList
<CCodeFunction
> ccode_stack
= new ArrayList
<CCodeFunction
> ();
37 public ArrayList
<LocalVariable
> temp_ref_vars
= new ArrayList
<LocalVariable
> ();
38 public int next_temp_var_id
;
39 public bool current_method_inner_error
;
40 public bool current_method_return
;
41 public Map
<string,string> variable_name_map
= new HashMap
<string,string> (str_hash
, str_equal
);
43 public EmitContext (Symbol? symbol
= null) {
44 current_symbol
= symbol
;
47 public void push_symbol (Symbol symbol
) {
48 symbol_stack
.add (current_symbol
);
49 current_symbol
= symbol
;
52 public void pop_symbol () {
53 current_symbol
= symbol_stack
[symbol_stack
.size
- 1];
54 symbol_stack
.remove_at (symbol_stack
.size
- 1);
58 public CodeContext context
{ get; set; }
60 public Symbol root_symbol
;
62 public EmitContext emit_context
= new
EmitContext ();
64 List
<EmitContext
> emit_context_stack
= new ArrayList
<EmitContext
> ();
66 public Symbol current_symbol
{ get { return emit_context
.current_symbol
; } }
68 public TryStatement current_try
{
69 get { return emit_context
.current_try
; }
70 set { emit_context
.current_try
= value
; }
73 public CatchClause current_catch
{
74 get { return emit_context
.current_catch
; }
75 set { emit_context
.current_catch
= value
; }
78 public TypeSymbol? current_type_symbol
{
80 var sym
= current_symbol
;
82 if (sym is TypeSymbol
) {
83 return (TypeSymbol
) sym
;
85 sym
= sym
.parent_symbol
;
91 public Class? current_class
{
92 get { return current_type_symbol as Class
; }
95 public Method? current_method
{
97 var sym
= current_symbol
;
98 while (sym is Block
) {
99 sym
= sym
.parent_symbol
;
101 return sym as Method
;
105 public PropertyAccessor? current_property_accessor
{
107 var sym
= current_symbol
;
108 while (sym is Block
) {
109 sym
= sym
.parent_symbol
;
111 return sym as PropertyAccessor
;
115 public DataType? current_return_type
{
117 var m
= current_method
;
119 return m
.return_type
;
122 var acc
= current_property_accessor
;
125 return acc
.value_type
;
131 if (is_in_constructor () || is_in_destructor ()) {
139 public bool is_in_constructor () {
140 if (current_method
!= null) {
141 // make sure to not return true in lambda expression inside constructor
144 var sym
= current_symbol
;
145 while (sym
!= null) {
146 if (sym is Constructor
) {
149 sym
= sym
.parent_symbol
;
154 public bool is_in_destructor () {
155 if (current_method
!= null) {
156 // make sure to not return true in lambda expression inside constructor
159 var sym
= current_symbol
;
160 while (sym
!= null) {
161 if (sym is Destructor
) {
164 sym
= sym
.parent_symbol
;
169 public Block? current_closure_block
{
171 return next_closure_block (current_symbol
);
175 public unowned Block?
next_closure_block (Symbol sym
) {
176 unowned Block block
= null;
178 block
= sym as Block
;
179 if (!(sym is Block
|| sym is Method
)) {
183 if (block
!= null && block
.captured
) {
184 // closure block found
187 sym
= sym
.parent_symbol
;
192 public CCodeFile header_file
;
193 public CCodeFile internal_header_file
;
194 public CCodeFile cfile
;
196 public EmitContext class_init_context
;
197 public EmitContext base_init_context
;
198 public EmitContext class_finalize_context
;
199 public EmitContext base_finalize_context
;
200 public EmitContext instance_init_context
;
201 public EmitContext instance_finalize_context
;
203 public CCodeStruct param_spec_struct
;
204 public CCodeStruct closure_struct
;
205 public CCodeEnum prop_enum
;
207 public CCodeFunction ccode
{ get { return emit_context
.ccode
; } }
209 /* temporary variables that own their content */
210 public ArrayList
<LocalVariable
> temp_ref_vars
{ get { return emit_context
.temp_ref_vars
; } }
211 /* cache to check whether a certain marshaller has been created yet */
212 public Set
<string> user_marshal_set
;
213 /* (constant) hash table with all predefined marshallers */
214 public Set
<string> predefined_marshal_set
;
215 /* (constant) hash table with all reserved identifiers in the generated code */
216 Set
<string> reserved_identifiers
;
218 public int next_temp_var_id
{
219 get { return emit_context
.next_temp_var_id
; }
220 set { emit_context
.next_temp_var_id
= value
; }
223 public int next_regex_id
= 0;
224 public bool in_creation_method
{ get { return current_method is CreationMethod
; } }
225 public bool in_constructor
= false;
226 public bool in_static_or_class_context
= false;
228 public bool current_method_inner_error
{
229 get { return emit_context
.current_method_inner_error
; }
230 set { emit_context
.current_method_inner_error
= value
; }
233 public bool current_method_return
{
234 get { return emit_context
.current_method_return
; }
235 set { emit_context
.current_method_return
= value
; }
238 public int next_coroutine_state
= 1;
239 int next_block_id
= 0;
240 Map
<Block
,int> block_map
= new HashMap
<Block
,int> ();
242 public DataType void_type
= new
VoidType ();
243 public DataType bool_type
;
244 public DataType char_type
;
245 public DataType uchar_type
;
246 public DataType? unichar_type
;
247 public DataType short_type
;
248 public DataType ushort_type
;
249 public DataType int_type
;
250 public DataType uint_type
;
251 public DataType long_type
;
252 public DataType ulong_type
;
253 public DataType int8_type
;
254 public DataType uint8_type
;
255 public DataType int16_type
;
256 public DataType uint16_type
;
257 public DataType int32_type
;
258 public DataType uint32_type
;
259 public DataType int64_type
;
260 public DataType uint64_type
;
261 public DataType string_type
;
262 public DataType regex_type
;
263 public DataType float_type
;
264 public DataType double_type
;
265 public TypeSymbol gtype_type
;
266 public TypeSymbol gobject_type
;
267 public ErrorType gerror_type
;
268 public Class glist_type
;
269 public Class gslist_type
;
270 public Class gnode_type
;
271 public Class gvaluearray_type
;
272 public TypeSymbol gstringbuilder_type
;
273 public TypeSymbol garray_type
;
274 public TypeSymbol gbytearray_type
;
275 public TypeSymbol gptrarray_type
;
276 public TypeSymbol gthreadpool_type
;
277 public DataType gdestroynotify_type
;
278 public DataType gquark_type
;
279 public Struct gvalue_type
;
280 public Class gvariant_type
;
281 public Struct mutex_type
;
282 public TypeSymbol type_module_type
;
283 public TypeSymbol dbus_proxy_type
;
284 public TypeSymbol dbus_object_type
;
286 public bool in_plugin
= false;
287 public string module_init_param_name
;
289 public bool gvaluecollector_h_needed
;
290 public bool requires_array_free
;
291 public bool requires_array_move
;
292 public bool requires_array_length
;
294 public Set
<string> wrappers
;
295 Set
<Symbol
> generated_external_symbols
;
297 public Map
<string,string> variable_name_map
{ get { return emit_context
.variable_name_map
; } }
299 public CCodeBaseModule () {
300 predefined_marshal_set
= new HashSet
<string> (str_hash
, str_equal
);
301 predefined_marshal_set
.add ("VOID:VOID");
302 predefined_marshal_set
.add ("VOID:BOOLEAN");
303 predefined_marshal_set
.add ("VOID:CHAR");
304 predefined_marshal_set
.add ("VOID:UCHAR");
305 predefined_marshal_set
.add ("VOID:INT");
306 predefined_marshal_set
.add ("VOID:UINT");
307 predefined_marshal_set
.add ("VOID:LONG");
308 predefined_marshal_set
.add ("VOID:ULONG");
309 predefined_marshal_set
.add ("VOID:ENUM");
310 predefined_marshal_set
.add ("VOID:FLAGS");
311 predefined_marshal_set
.add ("VOID:FLOAT");
312 predefined_marshal_set
.add ("VOID:DOUBLE");
313 predefined_marshal_set
.add ("VOID:STRING");
314 predefined_marshal_set
.add ("VOID:POINTER");
315 predefined_marshal_set
.add ("VOID:OBJECT");
316 predefined_marshal_set
.add ("STRING:OBJECT,POINTER");
317 predefined_marshal_set
.add ("VOID:UINT,POINTER");
318 predefined_marshal_set
.add ("BOOLEAN:FLAGS");
320 reserved_identifiers
= new HashSet
<string> (str_hash
, str_equal
);
323 reserved_identifiers
.add ("_Bool");
324 reserved_identifiers
.add ("_Complex");
325 reserved_identifiers
.add ("_Imaginary");
326 reserved_identifiers
.add ("asm");
327 reserved_identifiers
.add ("auto");
328 reserved_identifiers
.add ("break");
329 reserved_identifiers
.add ("case");
330 reserved_identifiers
.add ("char");
331 reserved_identifiers
.add ("const");
332 reserved_identifiers
.add ("continue");
333 reserved_identifiers
.add ("default");
334 reserved_identifiers
.add ("do");
335 reserved_identifiers
.add ("double");
336 reserved_identifiers
.add ("else");
337 reserved_identifiers
.add ("enum");
338 reserved_identifiers
.add ("extern");
339 reserved_identifiers
.add ("float");
340 reserved_identifiers
.add ("for");
341 reserved_identifiers
.add ("goto");
342 reserved_identifiers
.add ("if");
343 reserved_identifiers
.add ("inline");
344 reserved_identifiers
.add ("int");
345 reserved_identifiers
.add ("long");
346 reserved_identifiers
.add ("register");
347 reserved_identifiers
.add ("restrict");
348 reserved_identifiers
.add ("return");
349 reserved_identifiers
.add ("short");
350 reserved_identifiers
.add ("signed");
351 reserved_identifiers
.add ("sizeof");
352 reserved_identifiers
.add ("static");
353 reserved_identifiers
.add ("struct");
354 reserved_identifiers
.add ("switch");
355 reserved_identifiers
.add ("typedef");
356 reserved_identifiers
.add ("union");
357 reserved_identifiers
.add ("unsigned");
358 reserved_identifiers
.add ("void");
359 reserved_identifiers
.add ("volatile");
360 reserved_identifiers
.add ("while");
363 reserved_identifiers
.add ("cdecl");
365 // reserved for Vala/GObject naming conventions
366 reserved_identifiers
.add ("error");
367 reserved_identifiers
.add ("result");
368 reserved_identifiers
.add ("self");
371 public override void emit (CodeContext context
) {
372 this
.context
= context
;
374 root_symbol
= context
.root
;
376 bool_type
= new
BooleanType ((Struct
) root_symbol
.scope
.lookup ("bool"));
377 char_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("char"));
378 uchar_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uchar"));
379 short_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("short"));
380 ushort_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ushort"));
381 int_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int"));
382 uint_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint"));
383 long_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("long"));
384 ulong_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ulong"));
385 int8_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int8"));
386 uint8_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint8"));
387 int16_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int16"));
388 uint16_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint16"));
389 int32_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int32"));
390 uint32_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint32"));
391 int64_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int64"));
392 uint64_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint64"));
393 float_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("float"));
394 double_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("double"));
395 string_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("string"));
396 var unichar_struct
= (Struct
) root_symbol
.scope
.lookup ("unichar");
397 if (unichar_struct
!= null) {
398 unichar_type
= new
IntegerType (unichar_struct
);
401 if (context
.profile
== Profile
.GOBJECT
) {
402 var glib_ns
= root_symbol
.scope
.lookup ("GLib");
404 gtype_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Type");
405 gobject_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Object");
406 gerror_type
= new
ErrorType (null, null);
407 glist_type
= (Class
) glib_ns
.scope
.lookup ("List");
408 gslist_type
= (Class
) glib_ns
.scope
.lookup ("SList");
409 gnode_type
= (Class
) glib_ns
.scope
.lookup ("Node");
410 gvaluearray_type
= (Class
) glib_ns
.scope
.lookup ("ValueArray");
411 gstringbuilder_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("StringBuilder");
412 garray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Array");
413 gbytearray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("ByteArray");
414 gptrarray_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("PtrArray");
415 gthreadpool_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("ThreadPool");
416 gdestroynotify_type
= new
DelegateType ((Delegate
) glib_ns
.scope
.lookup ("DestroyNotify"));
418 gquark_type
= new
IntegerType ((Struct
) glib_ns
.scope
.lookup ("Quark"));
419 gvalue_type
= (Struct
) glib_ns
.scope
.lookup ("Value");
420 gvariant_type
= (Class
) glib_ns
.scope
.lookup ("Variant");
421 mutex_type
= (Struct
) glib_ns
.scope
.lookup ("StaticRecMutex");
423 type_module_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("TypeModule");
425 regex_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("GLib").scope
.lookup ("Regex"));
427 if (context
.module_init_method
!= null) {
428 foreach (Parameter parameter
in context
.module_init_method
.get_parameters ()) {
429 if (parameter
.variable_type
.data_type
== type_module_type
) {
431 module_init_param_name
= parameter
.name
;
436 Report
.error (context
.module_init_method
.source_reference
, "[ModuleInit] requires a parameter of type `GLib.TypeModule'");
440 dbus_proxy_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("DBusProxy");
442 var dbus_ns
= root_symbol
.scope
.lookup ("DBus");
443 if (dbus_ns
!= null) {
444 dbus_object_type
= (TypeSymbol
) dbus_ns
.scope
.lookup ("Object");
448 header_file
= new
CCodeFile ();
449 header_file
.is_header
= true;
450 internal_header_file
= new
CCodeFile ();
451 internal_header_file
.is_header
= true;
453 /* we're only interested in non-pkg source files */
454 var source_files
= context
.get_source_files ();
455 foreach (SourceFile file
in source_files
) {
456 if (file
.file_type
== SourceFileType
.SOURCE
||
457 (context
.header_filename
!= null && file
.file_type
== SourceFileType
.FAST
)) {
462 // generate symbols file for public API
463 if (context
.symbols_filename
!= null) {
464 var stream
= FileStream
.open (context
.symbols_filename
, "w");
465 if (stream
== null) {
466 Report
.error (null, "unable to open `%s' for writing".printf (context
.symbols_filename
));
470 foreach (string symbol
in header_file
.get_symbols ()) {
471 stream
.puts (symbol
);
478 // generate C header file for public API
479 if (context
.header_filename
!= null) {
481 if (context
.profile
== Profile
.GOBJECT
) {
482 ret
= header_file
.store (context
.header_filename
, null, context
.version_header
, false, "G_BEGIN_DECLS", "G_END_DECLS");
484 ret
= header_file
.store (context
.header_filename
, null, context
.version_header
, false);
487 Report
.error (null, "unable to open `%s' for writing".printf (context
.header_filename
));
491 // generate C header file for internal API
492 if (context
.internal_header_filename
!= null) {
494 if (context
.profile
== Profile
.GOBJECT
) {
495 ret
= internal_header_file
.store (context
.internal_header_filename
, null, context
.version_header
, false, "G_BEGIN_DECLS", "G_END_DECLS");
497 ret
= internal_header_file
.store (context
.internal_header_filename
, null, context
.version_header
, false);
500 Report
.error (null, "unable to open `%s' for writing".printf (context
.internal_header_filename
));
505 public void push_context (EmitContext emit_context
) {
506 if (this
.emit_context
!= null) {
507 emit_context_stack
.add (this
.emit_context
);
510 this
.emit_context
= emit_context
;
513 public void pop_context () {
514 if (emit_context_stack
.size
> 0) {
515 this
.emit_context
= emit_context_stack
[emit_context_stack
.size
- 1];
516 emit_context_stack
.remove_at (emit_context_stack
.size
- 1);
518 this
.emit_context
= null;
522 public void push_function (CCodeFunction func
) {
523 emit_context
.ccode_stack
.add (ccode
);
524 emit_context
.ccode
= func
;
527 public void pop_function () {
528 emit_context
.ccode
= emit_context
.ccode_stack
[emit_context
.ccode_stack
.size
- 1];
529 emit_context
.ccode_stack
.remove_at (emit_context
.ccode_stack
.size
- 1);
532 public bool add_symbol_declaration (CCodeFile decl_space
, Symbol sym
, string name
) {
533 if (decl_space
.add_declaration (name
)) {
536 if (sym
.source_reference
!= null) {
537 sym
.source_reference
.file
.used
= true;
539 if (sym
.external_package
|| (!decl_space
.is_header
&& CodeContext
.get ().use_header
&& !sym
.is_internal_symbol ())) {
540 // add appropriate include file
541 foreach (string header_filename
in sym
.get_cheader_filenames ()) {
542 decl_space
.add_include (header_filename
, !sym
.external_package
);
544 // declaration complete
547 // require declaration
552 public CCodeIdentifier
get_value_setter_function (DataType type_reference
) {
553 var array_type
= type_reference as ArrayType
;
554 if (type_reference
.data_type
!= null) {
555 return new
CCodeIdentifier (type_reference
.data_type
.get_set_value_function ());
556 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
558 return new
CCodeIdentifier ("g_value_set_boxed");
560 return new
CCodeIdentifier ("g_value_set_pointer");
564 public CCodeIdentifier
get_value_taker_function (DataType type_reference
) {
565 var array_type
= type_reference as ArrayType
;
566 if (type_reference
.data_type
!= null) {
567 return new
CCodeIdentifier (type_reference
.data_type
.get_take_value_function ());
568 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
570 return new
CCodeIdentifier ("g_value_take_boxed");
572 return new
CCodeIdentifier ("g_value_set_pointer");
576 CCodeIdentifier
get_value_getter_function (DataType type_reference
) {
577 var array_type
= type_reference as ArrayType
;
578 if (type_reference
.data_type
!= null) {
579 return new
CCodeIdentifier (type_reference
.data_type
.get_get_value_function ());
580 } else if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
582 return new
CCodeIdentifier ("g_value_get_boxed");
584 return new
CCodeIdentifier ("g_value_get_pointer");
588 public virtual void append_vala_array_free () {
591 public virtual void append_vala_array_move () {
594 public virtual void append_vala_array_length () {
597 public override void visit_source_file (SourceFile source_file
) {
598 cfile
= new
CCodeFile ();
600 user_marshal_set
= new HashSet
<string> (str_hash
, str_equal
);
604 gvaluecollector_h_needed
= false;
605 requires_array_free
= false;
606 requires_array_move
= false;
607 requires_array_length
= false;
609 wrappers
= new HashSet
<string> (str_hash
, str_equal
);
610 generated_external_symbols
= new HashSet
<Symbol
> ();
612 if (context
.profile
== Profile
.GOBJECT
) {
613 header_file
.add_include ("glib.h");
614 internal_header_file
.add_include ("glib.h");
615 cfile
.add_include ("glib.h");
616 cfile
.add_include ("glib-object.h");
619 source_file
.accept_children (this
);
621 if (context
.report
.get_errors () > 0) {
625 /* For fast-vapi, we only wanted the header declarations
626 * to be emitted, so bail out here without writing the
629 if (source_file
.file_type
== SourceFileType
.FAST
) {
633 if (requires_array_free
) {
634 append_vala_array_free ();
636 if (requires_array_move
) {
637 append_vala_array_move ();
639 if (requires_array_length
) {
640 append_vala_array_length ();
643 if (gvaluecollector_h_needed
) {
644 cfile
.add_include ("gobject/gvaluecollector.h");
647 var comments
= source_file
.get_comments();
648 if (comments
!= null) {
649 foreach (Comment comment
in comments
) {
650 var ccomment
= new
CCodeComment (comment
.content
);
651 cfile
.add_comment (ccomment
);
655 if (!cfile
.store (source_file
.get_csource_filename (), source_file
.filename
, context
.version_header
, context
.debug
)) {
656 Report
.error (null, "unable to open `%s' for writing".printf (source_file
.get_csource_filename ()));
662 public virtual bool generate_enum_declaration (Enum en
, CCodeFile decl_space
) {
663 if (add_symbol_declaration (decl_space
, en
, en
.get_cname ())) {
667 var cenum
= new
CCodeEnum (en
.get_cname ());
669 cenum
.deprecated
= en
.deprecated
;
672 foreach (EnumValue ev
in en
.get_values ()) {
674 if (ev
.value
== null) {
675 c_ev
= new
CCodeEnumValue (ev
.get_cname ());
677 c_ev
.value
= new
CCodeConstant ("1 << %d".printf (flag_shift
));
681 ev
.value
.emit (this
);
682 c_ev
= new
CCodeEnumValue (ev
.get_cname (), get_cvalue (ev
.value
));
684 c_ev
.deprecated
= ev
.deprecated
;
685 cenum
.add_value (c_ev
);
688 decl_space
.add_type_definition (cenum
);
689 decl_space
.add_type_definition (new
CCodeNewline ());
691 if (!en
.has_type_id
) {
695 decl_space
.add_type_declaration (new
CCodeNewline ());
697 var macro
= "(%s_get_type ())".printf (en
.get_lower_case_cname (null));
698 decl_space
.add_type_declaration (new
CCodeMacroReplacement (en
.get_type_id (), macro
));
700 var fun_name
= "%s_get_type".printf (en
.get_lower_case_cname (null));
701 var regfun
= new
CCodeFunction (fun_name
, "GType");
702 regfun
.attributes
= "G_GNUC_CONST";
704 if (en
.access
== SymbolAccessibility
.PRIVATE
) {
705 regfun
.modifiers
= CCodeModifiers
.STATIC
;
706 // avoid C warning as this function is not always used
707 regfun
.attributes
= "G_GNUC_UNUSED";
710 decl_space
.add_function_declaration (regfun
);
715 public override void visit_enum (Enum en
) {
716 en
.accept_children (this
);
718 if (en
.comment
!= null) {
719 cfile
.add_type_member_definition (new
CCodeComment (en
.comment
.content
));
722 generate_enum_declaration (en
, cfile
);
724 if (!en
.is_internal_symbol ()) {
725 generate_enum_declaration (en
, header_file
);
727 if (!en
.is_private_symbol ()) {
728 generate_enum_declaration (en
, internal_header_file
);
732 public void visit_member (Symbol m
) {
733 /* stuff meant for all lockable members */
734 if (m is Lockable
&& ((Lockable
) m
).get_lock_used ()) {
735 CCodeExpression l
= new
CCodeIdentifier ("self");
736 var init_context
= class_init_context
;
737 var finalize_context
= class_finalize_context
;
739 if (m
.is_instance_member ()) {
740 l
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (l
, "priv"), get_symbol_lock_name (m
.name
));
741 init_context
= instance_init_context
;
742 finalize_context
= instance_finalize_context
;
743 } else if (m
.is_class_member ()) {
744 TypeSymbol parent
= (TypeSymbol
)m
.parent_symbol
;
746 var get_class_private_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent
.get_upper_case_cname ())));
747 get_class_private_call
.add_argument (new
CCodeIdentifier ("klass"));
748 l
= new CCodeMemberAccess
.pointer (get_class_private_call
, get_symbol_lock_name (m
.name
));
750 l
= new
CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf(m
.parent_symbol
.get_lower_case_cname (), m
.name
)));
753 push_context (init_context
);
754 var initf
= new
CCodeFunctionCall (new
CCodeIdentifier (mutex_type
.default_construction_method
.get_cname ()));
755 initf
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
756 ccode
.add_expression (initf
);
759 if (finalize_context
!= null) {
760 push_context (finalize_context
);
761 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_static_rec_mutex_free"));
762 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
763 ccode
.add_expression (fc
);
769 public void generate_constant_declaration (Constant c
, CCodeFile decl_space
, bool definition
= false) {
770 if (c
.parent_symbol is Block
) {
775 if (add_symbol_declaration (decl_space
, c
, c
.get_cname ())) {
780 generate_type_declaration (c
.type_reference
, decl_space
);
784 var initializer_list
= c
.value as InitializerList
;
785 if (initializer_list
!= null) {
786 var cdecl
= new
CCodeDeclaration (c
.type_reference
.get_const_cname ());
788 if (c
.type_reference is ArrayType
) {
789 arr
= "[%d]".printf (initializer_list
.size
);
792 var cinitializer
= get_cvalue (c
.value
);
794 // never output value in header
795 // special case needed as this method combines declaration and definition
799 cdecl
.add_declarator (new
CCodeVariableDeclarator ("%s%s".printf (c
.get_cname (), arr
), cinitializer
));
800 if (c
.is_private_symbol ()) {
801 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
803 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
806 decl_space
.add_constant_declaration (cdecl
);
808 var cdefine
= new CCodeMacroReplacement
.with_expression (c
.get_cname (), get_cvalue (c
.value
));
809 decl_space
.add_type_member_declaration (cdefine
);
814 public override void visit_constant (Constant c
) {
815 if (c
.parent_symbol is Block
) {
818 generate_type_declaration (c
.type_reference
, cfile
);
822 string type_name
= c
.type_reference
.get_const_cname ();
824 if (c
.type_reference is ArrayType
) {
828 if (c
.type_reference
.compatible (string_type
)) {
829 type_name
= "const char";
833 var cinitializer
= get_cvalue (c
.value
);
835 ccode
.add_declaration (type_name
, new
CCodeVariableDeclarator ("%s%s".printf (c
.get_cname (), arr
), cinitializer
), CCodeModifiers
.STATIC
);
840 generate_constant_declaration (c
, cfile
, true);
842 if (!c
.is_internal_symbol ()) {
843 generate_constant_declaration (c
, header_file
);
845 if (!c
.is_private_symbol ()) {
846 generate_constant_declaration (c
, internal_header_file
);
850 public void generate_field_declaration (Field f
, CCodeFile decl_space
) {
851 if (add_symbol_declaration (decl_space
, f
, f
.get_cname ())) {
855 generate_type_declaration (f
.variable_type
, decl_space
);
857 string field_ctype
= f
.variable_type
.get_cname ();
859 field_ctype
= "volatile " + field_ctype
;
862 var cdecl
= new
CCodeDeclaration (field_ctype
);
863 cdecl
.add_declarator (new
CCodeVariableDeclarator (f
.get_cname (), null, f
.variable_type
.get_cdeclarator_suffix ()));
864 if (f
.is_private_symbol ()) {
865 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
867 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
870 cdecl
.modifiers
|= CCodeModifiers
.DEPRECATED
;
872 decl_space
.add_type_member_declaration (cdecl
);
874 if (f
.get_lock_used ()) {
875 // Declare mutex for static member
876 var flock
= new
CCodeDeclaration (mutex_type
.get_cname ());
877 var flock_decl
= new
CCodeVariableDeclarator (get_symbol_lock_name (f
.get_cname ()), new
CCodeConstant ("{0}"));
878 flock
.add_declarator (flock_decl
);
880 if (f
.is_private_symbol ()) {
881 flock
.modifiers
= CCodeModifiers
.STATIC
;
883 flock
.modifiers
= CCodeModifiers
.EXTERN
;
885 decl_space
.add_type_member_declaration (flock
);
888 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
889 var array_type
= (ArrayType
) f
.variable_type
;
891 if (!array_type
.fixed_length
) {
892 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
893 var len_type
= int_type
.copy ();
895 cdecl
= new
CCodeDeclaration (len_type
.get_cname ());
896 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (f
.get_cname (), dim
)));
897 if (f
.is_private_symbol ()) {
898 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
900 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
902 decl_space
.add_type_member_declaration (cdecl
);
905 } else if (f
.variable_type is DelegateType
) {
906 var delegate_type
= (DelegateType
) f
.variable_type
;
907 if (delegate_type
.delegate_symbol
.has_target
) {
908 // create field to store delegate target
910 cdecl
= new
CCodeDeclaration ("gpointer");
911 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_cname (f
.get_cname ())));
912 if (f
.is_private_symbol ()) {
913 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
915 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
917 decl_space
.add_type_member_declaration (cdecl
);
919 if (delegate_type
.value_owned
) {
920 cdecl
= new
CCodeDeclaration ("GDestroyNotify");
921 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f
.get_cname ())));
922 if (f
.is_private_symbol ()) {
923 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
925 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
927 decl_space
.add_type_member_declaration (cdecl
);
933 public override void visit_field (Field f
) {
936 check_type (f
.variable_type
);
938 var cl
= f
.parent_symbol as Class
;
939 bool is_gtypeinstance
= (cl
!= null && !cl
.is_compact
);
941 CCodeExpression lhs
= null;
943 string field_ctype
= f
.variable_type
.get_cname ();
945 field_ctype
= "volatile " + field_ctype
;
948 if (f
.binding
== MemberBinding
.INSTANCE
) {
949 if (is_gtypeinstance
&& f
.access
== SymbolAccessibility
.PRIVATE
) {
950 lhs
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), f
.get_cname ());
952 lhs
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.get_cname ());
955 if (f
.initializer
!= null) {
956 push_context (instance_init_context
);
958 f
.initializer
.emit (this
);
960 var rhs
= get_cvalue (f
.initializer
);
962 ccode
.add_expression (new
CCodeAssignment (lhs
, rhs
));
964 if (f
.variable_type is ArrayType
&& !f
.no_array_length
&&
965 f
.initializer is ArrayCreationExpression
) {
966 var array_type
= (ArrayType
) f
.variable_type
;
967 var this_access
= new MemberAccess
.simple ("this");
968 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
969 set_cvalue (this_access
, new
CCodeIdentifier ("self"));
970 var ma
= new
MemberAccess (this_access
, f
.name
);
971 ma
.symbol_reference
= f
;
972 ma
.value_type
= f
.variable_type
.copy ();
973 visit_member_access (ma
);
975 List
<Expression
> sizes
= ((ArrayCreationExpression
) f
.initializer
).get_sizes ();
976 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
977 var array_len_lhs
= get_array_length_cexpression (ma
, dim
);
978 var size
= sizes
[dim
- 1];
979 ccode
.add_expression (new
CCodeAssignment (array_len_lhs
, get_cvalue (size
)));
982 if (array_type
.rank
== 1 && f
.is_internal_symbol ()) {
983 var lhs_array_size
= get_array_size_cvalue (ma
.target_value
);
984 var rhs_array_len
= get_array_length_cexpression (ma
, 1);
985 ccode
.add_expression (new
CCodeAssignment (lhs_array_size
, rhs_array_len
));
989 foreach (LocalVariable local
in temp_ref_vars
) {
990 ccode
.add_expression (get_unref_expression_ (local
));
993 temp_ref_vars
.clear ();
998 if (requires_destroy (f
.variable_type
) && instance_finalize_context
!= null) {
999 push_context (instance_finalize_context
);
1001 var this_access
= new MemberAccess
.simple ("this");
1002 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
1004 var field_st
= f
.parent_symbol as Struct
;
1005 if (field_st
!= null && !field_st
.is_simple_type ()) {
1006 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
1008 set_cvalue (this_access
, new
CCodeIdentifier ("self"));
1011 var ma
= new
MemberAccess (this_access
, f
.name
);
1012 ma
.symbol_reference
= f
;
1013 ma
.value_type
= f
.variable_type
.copy ();
1014 visit_member_access (ma
);
1015 ccode
.add_expression (get_unref_expression (lhs
, f
.variable_type
, ma
));
1019 } else if (f
.binding
== MemberBinding
.CLASS
) {
1020 if (!is_gtypeinstance
) {
1021 Report
.error (f
.source_reference
, "class fields are not supported in compact classes");
1026 if (f
.access
== SymbolAccessibility
.PRIVATE
) {
1027 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (cl
.get_upper_case_cname ())));
1028 ccall
.add_argument (new
CCodeIdentifier ("klass"));
1029 lhs
= new
CCodeMemberAccess (ccall
, f
.get_cname (), true);
1031 lhs
= new
CCodeMemberAccess (new
CCodeIdentifier ("klass"), f
.get_cname (), true);
1034 if (f
.initializer
!= null) {
1035 push_context (class_init_context
);
1037 f
.initializer
.emit (this
);
1039 var rhs
= get_cvalue (f
.initializer
);
1041 ccode
.add_expression (new
CCodeAssignment (lhs
, rhs
));
1043 foreach (LocalVariable local
in temp_ref_vars
) {
1044 ccode
.add_expression (get_unref_expression_ (local
));
1047 temp_ref_vars
.clear ();
1052 generate_field_declaration (f
, cfile
);
1054 if (!f
.is_internal_symbol ()) {
1055 generate_field_declaration (f
, header_file
);
1057 if (!f
.is_private_symbol ()) {
1058 generate_field_declaration (f
, internal_header_file
);
1061 lhs
= new
CCodeIdentifier (f
.get_cname ());
1063 var var_decl
= new
CCodeVariableDeclarator (f
.get_cname (), null, f
.variable_type
.get_cdeclarator_suffix ());
1064 var_decl
.initializer
= default_value_for_type (f
.variable_type
, true);
1066 if (class_init_context
!= null) {
1067 push_context (class_init_context
);
1069 push_context (new
EmitContext ());
1072 if (f
.initializer
!= null) {
1073 f
.initializer
.emit (this
);
1075 var init
= get_cvalue (f
.initializer
);
1076 if (is_constant_ccode_expression (init
)) {
1077 var_decl
.initializer
= init
;
1081 var var_def
= new
CCodeDeclaration (field_ctype
);
1082 var_def
.add_declarator (var_decl
);
1083 if (!f
.is_private_symbol ()) {
1084 var_def
.modifiers
= CCodeModifiers
.EXTERN
;
1086 var_def
.modifiers
= CCodeModifiers
.STATIC
;
1088 cfile
.add_type_member_declaration (var_def
);
1090 /* add array length fields where necessary */
1091 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
1092 var array_type
= (ArrayType
) f
.variable_type
;
1094 if (!array_type
.fixed_length
) {
1095 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1096 var len_type
= int_type
.copy ();
1098 var len_def
= new
CCodeDeclaration (len_type
.get_cname ());
1099 len_def
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (f
.get_cname (), dim
), new
CCodeConstant ("0")));
1100 if (!f
.is_private_symbol ()) {
1101 len_def
.modifiers
= CCodeModifiers
.EXTERN
;
1103 len_def
.modifiers
= CCodeModifiers
.STATIC
;
1105 cfile
.add_type_member_declaration (len_def
);
1108 if (array_type
.rank
== 1 && f
.is_internal_symbol ()) {
1109 var len_type
= int_type
.copy ();
1111 var cdecl
= new
CCodeDeclaration (len_type
.get_cname ());
1112 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_size_cname (f
.get_cname ()), new
CCodeConstant ("0")));
1113 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
1114 cfile
.add_type_member_declaration (cdecl
);
1117 } else if (f
.variable_type is DelegateType
) {
1118 var delegate_type
= (DelegateType
) f
.variable_type
;
1119 if (delegate_type
.delegate_symbol
.has_target
) {
1120 // create field to store delegate target
1122 var target_def
= new
CCodeDeclaration ("gpointer");
1123 target_def
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_cname (f
.get_cname ()), new
CCodeConstant ("NULL")));
1124 if (!f
.is_private_symbol ()) {
1125 target_def
.modifiers
= CCodeModifiers
.EXTERN
;
1127 target_def
.modifiers
= CCodeModifiers
.STATIC
;
1129 cfile
.add_type_member_declaration (target_def
);
1131 if (delegate_type
.value_owned
) {
1132 var target_destroy_notify_def
= new
CCodeDeclaration ("GDestroyNotify");
1133 target_destroy_notify_def
.add_declarator (new
CCodeVariableDeclarator (get_delegate_target_destroy_notify_cname (f
.get_cname ()), new
CCodeConstant ("NULL")));
1134 if (!f
.is_private_symbol ()) {
1135 target_destroy_notify_def
.modifiers
= CCodeModifiers
.EXTERN
;
1137 target_destroy_notify_def
.modifiers
= CCodeModifiers
.STATIC
;
1139 cfile
.add_type_member_declaration (target_destroy_notify_def
);
1145 if (f
.initializer
!= null) {
1146 var rhs
= get_cvalue (f
.initializer
);
1147 if (!is_constant_ccode_expression (rhs
)) {
1148 if (f
.parent_symbol is Class
) {
1149 if (f
.initializer is InitializerList
) {
1150 ccode
.open_block ();
1152 var temp_decl
= get_temp_variable (f
.variable_type
);
1153 var vardecl
= new CCodeVariableDeclarator
.zero (temp_decl
.name
, rhs
);
1154 ccode
.add_declaration (temp_decl
.variable_type
.get_cname (), vardecl
);
1156 var tmp
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
1157 ccode
.add_expression (new
CCodeAssignment (lhs
, tmp
));
1161 ccode
.add_expression (new
CCodeAssignment (lhs
, rhs
));
1164 if (f
.variable_type is ArrayType
&& !f
.no_array_length
&&
1165 f
.initializer is ArrayCreationExpression
) {
1166 var array_type
= (ArrayType
) f
.variable_type
;
1167 var ma
= new MemberAccess
.simple (f
.name
);
1168 ma
.symbol_reference
= f
;
1169 ma
.value_type
= f
.variable_type
.copy ();
1170 visit_member_access (ma
);
1172 List
<Expression
> sizes
= ((ArrayCreationExpression
) f
.initializer
).get_sizes ();
1173 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1174 var array_len_lhs
= get_array_length_cexpression (ma
, dim
);
1175 var size
= sizes
[dim
- 1];
1176 ccode
.add_expression (new
CCodeAssignment (array_len_lhs
, get_cvalue (size
)));
1181 Report
.error (f
.source_reference
, "Non-constant field initializers not supported in this context");
1191 public bool is_constant_ccode_expression (CCodeExpression cexpr
) {
1192 if (cexpr is CCodeConstant
) {
1194 } else if (cexpr is CCodeCastExpression
) {
1195 var ccast
= (CCodeCastExpression
) cexpr
;
1196 return is_constant_ccode_expression (ccast
.inner
);
1197 } else if (cexpr is CCodeBinaryExpression
) {
1198 var cbinary
= (CCodeBinaryExpression
) cexpr
;
1199 return is_constant_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
1202 var cparenthesized
= (cexpr as CCodeParenthesizedExpression
);
1203 return (null != cparenthesized
&& is_constant_ccode_expression (cparenthesized
.inner
));
1207 * Returns whether the passed cexpr is a pure expression, i.e. an
1208 * expression without side-effects.
1210 public bool is_pure_ccode_expression (CCodeExpression cexpr
) {
1211 if (cexpr is CCodeConstant
|| cexpr is CCodeIdentifier
) {
1213 } else if (cexpr is CCodeBinaryExpression
) {
1214 var cbinary
= (CCodeBinaryExpression
) cexpr
;
1215 return is_pure_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
1216 } else if (cexpr is CCodeUnaryExpression
) {
1217 var cunary
= (CCodeUnaryExpression
) cexpr
;
1218 switch (cunary
.operator
) {
1219 case CCodeUnaryOperator
.PREFIX_INCREMENT
:
1220 case CCodeUnaryOperator
.PREFIX_DECREMENT
:
1221 case CCodeUnaryOperator
.POSTFIX_INCREMENT
:
1222 case CCodeUnaryOperator
.POSTFIX_DECREMENT
:
1225 return is_pure_ccode_expression (cunary
.inner
);
1227 } else if (cexpr is CCodeMemberAccess
) {
1228 var cma
= (CCodeMemberAccess
) cexpr
;
1229 return is_pure_ccode_expression (cma
.inner
);
1230 } else if (cexpr is CCodeElementAccess
) {
1231 var cea
= (CCodeElementAccess
) cexpr
;
1232 return is_pure_ccode_expression (cea
.container
) && is_pure_ccode_expression (cea
.index
);
1233 } else if (cexpr is CCodeCastExpression
) {
1234 var ccast
= (CCodeCastExpression
) cexpr
;
1235 return is_pure_ccode_expression (ccast
.inner
);
1236 } else if (cexpr is CCodeParenthesizedExpression
) {
1237 var cparenthesized
= (CCodeParenthesizedExpression
) cexpr
;
1238 return is_pure_ccode_expression (cparenthesized
.inner
);
1244 public override void visit_formal_parameter (Parameter p
) {
1246 check_type (p
.variable_type
);
1250 public override void visit_property (Property prop
) {
1251 visit_member (prop
);
1253 check_type (prop
.property_type
);
1255 if (prop
.get_accessor
!= null) {
1256 prop
.get_accessor
.accept (this
);
1258 if (prop
.set_accessor
!= null) {
1259 prop
.set_accessor
.accept (this
);
1263 public void generate_type_declaration (DataType type
, CCodeFile decl_space
) {
1264 if (type is ObjectType
) {
1265 var object_type
= (ObjectType
) type
;
1266 if (object_type
.type_symbol is Class
) {
1267 generate_class_declaration ((Class
) object_type
.type_symbol
, decl_space
);
1268 } else if (object_type
.type_symbol is Interface
) {
1269 generate_interface_declaration ((Interface
) object_type
.type_symbol
, decl_space
);
1271 } else if (type is DelegateType
) {
1272 var deleg_type
= (DelegateType
) type
;
1273 var d
= deleg_type
.delegate_symbol
;
1274 generate_delegate_declaration (d
, decl_space
);
1275 } else if (type
.data_type is Enum
) {
1276 var en
= (Enum
) type
.data_type
;
1277 generate_enum_declaration (en
, decl_space
);
1278 } else if (type is ValueType
) {
1279 var value_type
= (ValueType
) type
;
1280 generate_struct_declaration ((Struct
) value_type
.type_symbol
, decl_space
);
1281 } else if (type is ArrayType
) {
1282 var array_type
= (ArrayType
) type
;
1283 generate_type_declaration (array_type
.element_type
, decl_space
);
1284 } else if (type is ErrorType
) {
1285 var error_type
= (ErrorType
) type
;
1286 if (error_type
.error_domain
!= null) {
1287 generate_error_domain_declaration (error_type
.error_domain
, decl_space
);
1289 } else if (type is PointerType
) {
1290 var pointer_type
= (PointerType
) type
;
1291 generate_type_declaration (pointer_type
.base_type
, decl_space
);
1294 foreach (DataType type_arg
in type
.get_type_arguments ()) {
1295 generate_type_declaration (type_arg
, decl_space
);
1299 public virtual void generate_class_struct_declaration (Class cl
, CCodeFile decl_space
) {
1302 public virtual void generate_struct_declaration (Struct st
, CCodeFile decl_space
) {
1305 public virtual void generate_delegate_declaration (Delegate d
, CCodeFile decl_space
) {
1308 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) {
1311 public void generate_property_accessor_declaration (PropertyAccessor acc
, CCodeFile decl_space
) {
1312 if (add_symbol_declaration (decl_space
, acc
, acc
.get_cname ())) {
1316 var prop
= (Property
) acc
.prop
;
1318 bool returns_real_struct
= acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ();
1321 CCodeParameter cvalueparam
;
1322 if (returns_real_struct
) {
1323 cvalueparam
= new
CCodeParameter ("result", acc
.value_type
.get_cname () + "*");
1324 } else if (!acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ()) {
1325 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname () + "*");
1327 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname ());
1329 generate_type_declaration (acc
.value_type
, decl_space
);
1331 CCodeFunction function
;
1332 if (acc
.readable
&& !returns_real_struct
) {
1333 function
= new
CCodeFunction (acc
.get_cname (), acc
.value_type
.get_cname ());
1335 function
= new
CCodeFunction (acc
.get_cname (), "void");
1338 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1339 var t
= (TypeSymbol
) prop
.parent_symbol
;
1340 var this_type
= get_data_type_for_symbol (t
);
1341 generate_type_declaration (this_type
, decl_space
);
1342 var cselfparam
= new
CCodeParameter ("self", this_type
.get_cname ());
1344 cselfparam
.type_name
+= "*";
1347 function
.add_parameter (cselfparam
);
1350 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1351 function
.add_parameter (cvalueparam
);
1354 if (acc
.value_type is ArrayType
) {
1355 var array_type
= (ArrayType
) acc
.value_type
;
1357 var length_ctype
= "int";
1359 length_ctype
= "int*";
1362 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1363 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1365 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1366 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1369 if (prop
.is_private_symbol () || (!acc
.readable
&& !acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1370 function
.modifiers
|= CCodeModifiers
.STATIC
;
1372 decl_space
.add_function_declaration (function
);
1375 public override void visit_property_accessor (PropertyAccessor acc
) {
1376 push_context (new
EmitContext (acc
));
1378 var prop
= (Property
) acc
.prop
;
1380 if (acc
.comment
!= null) {
1381 cfile
.add_type_member_definition (new
CCodeComment (acc
.comment
.content
));
1384 bool returns_real_struct
= acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ();
1386 if (acc
.result_var
!= null) {
1387 acc
.result_var
.accept (this
);
1390 var t
= (TypeSymbol
) prop
.parent_symbol
;
1392 if (acc
.construction
&& !t
.is_subtype_of (gobject_type
)) {
1393 Report
.error (acc
.source_reference
, "construct properties require GLib.Object");
1396 } else if (acc
.construction
&& !is_gobject_property (prop
)) {
1397 Report
.error (acc
.source_reference
, "construct properties not supported for specified property type");
1402 // do not declare overriding properties and interface implementations
1403 if (prop
.is_abstract
|| prop
.is_virtual
1404 || (prop
.base_property
== null && prop
.base_interface_property
== null)) {
1405 generate_property_accessor_declaration (acc
, cfile
);
1407 // do not declare construct-only properties in header files
1408 if (acc
.readable
|| acc
.writable
) {
1409 if (!prop
.is_internal_symbol ()
1410 && (acc
.access
== SymbolAccessibility
.PUBLIC
1411 || acc
.access
== SymbolAccessibility
.PROTECTED
)) {
1412 generate_property_accessor_declaration (acc
, header_file
);
1414 if (!prop
.is_private_symbol () && acc
.access
!= SymbolAccessibility
.PRIVATE
) {
1415 generate_property_accessor_declaration (acc
, internal_header_file
);
1420 if (acc
.source_type
== SourceFileType
.FAST
) {
1424 var this_type
= get_data_type_for_symbol (t
);
1425 var cselfparam
= new
CCodeParameter ("self", this_type
.get_cname ());
1427 cselfparam
.type_name
+= "*";
1429 CCodeParameter cvalueparam
;
1430 if (returns_real_struct
) {
1431 cvalueparam
= new
CCodeParameter ("result", acc
.value_type
.get_cname () + "*");
1432 } else if (!acc
.readable
&& prop
.property_type
.is_real_non_null_struct_type ()) {
1433 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname () + "*");
1435 cvalueparam
= new
CCodeParameter ("value", acc
.value_type
.get_cname ());
1438 if (prop
.is_abstract
|| prop
.is_virtual
) {
1439 CCodeFunction function
;
1440 if (acc
.readable
&& !returns_real_struct
) {
1441 function
= new
CCodeFunction (acc
.get_cname (), current_return_type
.get_cname ());
1443 function
= new
CCodeFunction (acc
.get_cname (), "void");
1445 function
.add_parameter (cselfparam
);
1446 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1447 function
.add_parameter (cvalueparam
);
1450 if (acc
.value_type is ArrayType
) {
1451 var array_type
= (ArrayType
) acc
.value_type
;
1453 var length_ctype
= "int";
1455 length_ctype
= "int*";
1458 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1459 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1461 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1462 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1465 if (prop
.is_private_symbol () || !(acc
.readable
|| acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1466 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1467 function
.modifiers
|= CCodeModifiers
.STATIC
;
1470 push_function (function
);
1472 CCodeFunctionCall vcast
= null;
1473 if (prop
.parent_symbol is Interface
) {
1474 var iface
= (Interface
) prop
.parent_symbol
;
1476 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (iface
.get_upper_case_cname (null))));
1478 var cl
= (Class
) prop
.parent_symbol
;
1480 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (cl
.get_upper_case_cname (null))));
1482 vcast
.add_argument (new
CCodeIdentifier ("self"));
1485 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "get_%s".printf (prop
.name
)));
1486 vcall
.add_argument (new
CCodeIdentifier ("self"));
1487 if (returns_real_struct
) {
1488 vcall
.add_argument (new
CCodeIdentifier ("result"));
1489 ccode
.add_expression (vcall
);
1491 if (acc
.value_type is ArrayType
) {
1492 var array_type
= (ArrayType
) acc
.value_type
;
1494 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1495 var len_expr
= new
CCodeIdentifier (get_array_length_cname ("result", dim
));
1496 vcall
.add_argument (len_expr
);
1498 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1499 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_cname ("result")));
1502 ccode
.add_return (vcall
);
1505 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "set_%s".printf (prop
.name
)));
1506 vcall
.add_argument (new
CCodeIdentifier ("self"));
1507 vcall
.add_argument (new
CCodeIdentifier ("value"));
1509 if (acc
.value_type is ArrayType
) {
1510 var array_type
= (ArrayType
) acc
.value_type
;
1512 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1513 var len_expr
= new
CCodeIdentifier (get_array_length_cname ("value", dim
));
1514 vcall
.add_argument (len_expr
);
1516 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1517 vcall
.add_argument (new
CCodeIdentifier (get_delegate_target_cname ("value")));
1520 ccode
.add_expression (vcall
);
1525 cfile
.add_function (function
);
1528 if (!prop
.is_abstract
) {
1529 bool is_virtual
= prop
.base_property
!= null || prop
.base_interface_property
!= null;
1534 cname
= "%s_real_get_%s".printf (t
.get_lower_case_cname (null), prop
.name
);
1536 cname
= "%s_real_set_%s".printf (t
.get_lower_case_cname (null), prop
.name
);
1539 cname
= acc
.get_cname ();
1542 CCodeFunction function
;
1543 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1544 function
= new
CCodeFunction (cname
, "void");
1546 function
= new
CCodeFunction (cname
, acc
.value_type
.get_cname ());
1549 ObjectType base_type
= null;
1550 if (prop
.binding
== MemberBinding
.INSTANCE
) {
1552 if (prop
.base_property
!= null) {
1553 base_type
= new
ObjectType ((ObjectTypeSymbol
) prop
.base_property
.parent_symbol
);
1554 } else if (prop
.base_interface_property
!= null) {
1555 base_type
= new
ObjectType ((ObjectTypeSymbol
) prop
.base_interface_property
.parent_symbol
);
1557 function
.modifiers
|= CCodeModifiers
.STATIC
;
1558 function
.add_parameter (new
CCodeParameter ("base", base_type
.get_cname ()));
1560 function
.add_parameter (cselfparam
);
1563 if (acc
.writable
|| acc
.construction
|| returns_real_struct
) {
1564 function
.add_parameter (cvalueparam
);
1567 if (acc
.value_type is ArrayType
) {
1568 var array_type
= (ArrayType
) acc
.value_type
;
1570 var length_ctype
= "int";
1572 length_ctype
= "int*";
1575 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1576 function
.add_parameter (new
CCodeParameter (get_array_length_cname (acc
.readable ?
"result" : "value", dim
), length_ctype
));
1578 } else if ((acc
.value_type is DelegateType
) && ((DelegateType
) acc
.value_type
).delegate_symbol
.has_target
) {
1579 function
.add_parameter (new
CCodeParameter (get_delegate_target_cname (acc
.readable ?
"result" : "value"), acc
.readable ?
"gpointer*" : "gpointer"));
1583 if (prop
.is_private_symbol () || !(acc
.readable
|| acc
.writable
) || acc
.access
== SymbolAccessibility
.PRIVATE
) {
1584 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1585 function
.modifiers
|= CCodeModifiers
.STATIC
;
1589 push_function (function
);
1591 if (prop
.binding
== MemberBinding
.INSTANCE
&& !is_virtual
) {
1592 if (!acc
.readable
|| returns_real_struct
) {
1593 create_property_type_check_statement (prop
, false, t
, true, "self");
1595 create_property_type_check_statement (prop
, true, t
, true, "self");
1599 if (acc
.readable
&& !returns_real_struct
) {
1600 // do not declare result variable if exit block is known to be unreachable
1601 if (acc
.return_block
== null || acc
.return_block
.get_predecessors ().size
> 0) {
1602 ccode
.add_declaration (acc
.value_type
.get_cname (), new
CCodeVariableDeclarator ("result"));
1607 ccode
.add_declaration (this_type
.get_cname (), new
CCodeVariableDeclarator ("self"));
1608 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("self"), transform_expression (new
CCodeIdentifier ("base"), base_type
, this_type
)));
1611 acc
.body
.emit (this
);
1613 if (current_method_inner_error
) {
1614 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
1617 // notify on property changes
1618 if (is_gobject_property (prop
) &&
1620 (acc
.writable
|| acc
.construction
)) {
1621 var notify_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_notify"));
1622 notify_call
.add_argument (new
CCodeCastExpression (new
CCodeIdentifier ("self"), "GObject *"));
1623 notify_call
.add_argument (prop
.get_canonical_cconstant ());
1624 ccode
.add_expression (notify_call
);
1627 cfile
.add_function (function
);
1633 public override void visit_destructor (Destructor d
) {
1634 if (d
.binding
== MemberBinding
.STATIC
&& !in_plugin
) {
1635 Report
.error (d
.source_reference
, "static destructors are only supported for dynamic types");
1641 public int get_block_id (Block b
) {
1642 int result
= block_map
[b
];
1644 result
= ++next_block_id
;
1645 block_map
[b
] = result
;
1650 void capture_parameter (Parameter param
, CCodeStruct data
, int block_id
, CCodeBlock free_block
) {
1651 generate_type_declaration (param
.variable_type
, cfile
);
1653 var param_type
= param
.variable_type
.copy ();
1654 param_type
.value_owned
= true;
1655 data
.add_field (param_type
.get_cname (), get_variable_cname (param
.name
));
1657 bool is_unowned_delegate
= param
.variable_type is DelegateType
&& !param
.variable_type
.value_owned
;
1659 // create copy if necessary as captured variables may need to be kept alive
1660 CCodeExpression cparam
= get_variable_cexpression (param
.name
);
1661 if (param
.variable_type
.is_real_non_null_struct_type ()) {
1662 cparam
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cparam
);
1664 if (requires_copy (param_type
) && !param
.variable_type
.value_owned
&& !is_unowned_delegate
) {
1665 var ma
= new MemberAccess
.simple (param
.name
);
1666 ma
.symbol_reference
= param
;
1667 ma
.value_type
= param
.variable_type
.copy ();
1668 // directly access parameters in ref expressions
1669 param
.captured
= false;
1670 visit_member_access (ma
);
1671 cparam
= get_ref_cexpression (param
.variable_type
, cparam
, ma
, param
);
1672 param
.captured
= true;
1675 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_variable_cname (param
.name
)), cparam
));
1677 if (param
.variable_type is ArrayType
) {
1678 var array_type
= (ArrayType
) param
.variable_type
;
1679 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1680 data
.add_field ("gint", get_parameter_array_length_cname (param
, dim
));
1681 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_array_length_cname (get_variable_cname (param
.name
), dim
)), new
CCodeIdentifier (get_array_length_cname (get_variable_cname (param
.name
), dim
))));
1683 } else if (param
.variable_type is DelegateType
) {
1684 CCodeExpression target_expr
;
1685 CCodeExpression delegate_target_destroy_notify
;
1686 if (current_method
!= null && current_method
.coroutine
) {
1687 target_expr
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_delegate_target_cname (get_variable_cname (param
.name
)));
1688 delegate_target_destroy_notify
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1690 target_expr
= new
CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param
.name
)));
1691 delegate_target_destroy_notify
= new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1694 data
.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (param
.name
)));
1695 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_delegate_target_cname (get_variable_cname (param
.name
))), target_expr
));
1696 if (param
.variable_type
.value_owned
) {
1697 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
1698 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
))), delegate_target_destroy_notify
));
1702 if (requires_destroy (param_type
) && !is_unowned_delegate
) {
1703 bool old_coroutine
= false;
1704 if (current_method
!= null) {
1705 old_coroutine
= current_method
.coroutine
;
1706 current_method
.coroutine
= false;
1709 var ma
= new MemberAccess
.simple (param
.name
);
1710 ma
.symbol_reference
= param
;
1711 ma
.value_type
= param_type
.copy ();
1712 visit_member_access (ma
);
1713 free_block
.add_statement (new
CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), get_variable_cname (param
.name
)), param
.variable_type
, ma
)));
1715 if (old_coroutine
) {
1716 current_method
.coroutine
= true;
1721 public override void visit_block (Block b
) {
1722 emit_context
.push_symbol (b
);
1724 var local_vars
= b
.get_local_variables ();
1726 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
) {
1727 ccode
.open_block ();
1731 var parent_block
= next_closure_block (b
.parent_symbol
);
1733 int block_id
= get_block_id (b
);
1734 string struct_name
= "Block%dData".printf (block_id
);
1736 var free_block
= new
CCodeBlock ();
1738 var data
= new
CCodeStruct ("_" + struct_name
);
1739 data
.add_field ("int", "_ref_count_");
1740 if (parent_block
!= null) {
1741 int parent_block_id
= get_block_id (parent_block
);
1743 data
.add_field ("Block%dData *".printf (parent_block_id
), "_data%d_".printf (parent_block_id
));
1745 var unref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (parent_block_id
)));
1746 unref_call
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)));
1747 free_block
.add_statement (new
CCodeExpressionStatement (unref_call
));
1749 if (in_constructor
|| (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) ||
1750 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
1751 data
.add_field ("%s *".printf (current_class
.get_cname ()), "self");
1753 var ma
= new MemberAccess
.simple ("this");
1754 ma
.symbol_reference
= current_class
;
1755 free_block
.add_statement (new
CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "self"), new
ObjectType (current_class
), ma
)));
1758 if (current_method
!= null) {
1759 // allow capturing generic type parameters
1760 foreach (var type_param
in current_method
.get_type_parameters ()) {
1763 func_name
= "%s_type".printf (type_param
.name
.down ());
1764 data
.add_field ("GType", func_name
);
1766 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
1767 data
.add_field ("GBoxedCopyFunc", func_name
);
1769 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
1770 data
.add_field ("GDestroyNotify", func_name
);
1774 foreach (var local
in local_vars
) {
1775 if (local
.captured
) {
1776 generate_type_declaration (local
.variable_type
, cfile
);
1778 data
.add_field (local
.variable_type
.get_cname (), get_variable_cname (local
.name
) + local
.variable_type
.get_cdeclarator_suffix ());
1780 if (local
.variable_type is ArrayType
) {
1781 var array_type
= (ArrayType
) local
.variable_type
;
1782 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
1783 data
.add_field ("gint", get_array_length_cname (get_variable_cname (local
.name
), dim
));
1785 data
.add_field ("gint", get_array_size_cname (get_variable_cname (local
.name
)));
1786 } else if (local
.variable_type is DelegateType
) {
1787 data
.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (local
.name
)));
1788 if (local
.variable_type
.value_owned
) {
1789 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (local
.name
)));
1794 // free in reverse order
1795 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1796 var local
= local_vars
[i
];
1797 if (local
.captured
) {
1798 if (requires_destroy (local
.variable_type
)) {
1799 bool old_coroutine
= false;
1800 if (current_method
!= null) {
1801 old_coroutine
= current_method
.coroutine
;
1802 current_method
.coroutine
= false;
1805 free_block
.add_statement (new
CCodeExpressionStatement (get_unref_expression_ (local
)));
1807 if (old_coroutine
) {
1808 current_method
.coroutine
= true;
1814 var data_alloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
1815 data_alloc
.add_argument (new
CCodeIdentifier (struct_name
));
1817 if (current_method
!= null && current_method
.coroutine
) {
1818 closure_struct
.add_field (struct_name
+ "*", "_data%d_".printf (block_id
));
1820 ccode
.add_declaration (struct_name
+ "*", new
CCodeVariableDeclarator ("_data%d_".printf (block_id
)));
1822 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression ("_data%d_".printf (block_id
)), data_alloc
));
1824 // initialize ref_count
1825 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_ref_count_"), new
CCodeIdentifier ("1")));
1827 if (parent_block
!= null) {
1828 int parent_block_id
= get_block_id (parent_block
);
1830 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (parent_block_id
)));
1831 ref_call
.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id
)));
1833 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)), ref_call
));
1835 if (in_constructor
|| (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
&&
1836 (!(current_method is CreationMethod
) || current_method
.body
!= b
)) ||
1837 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
1838 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (new
ObjectType (current_class
), b
.source_reference
));
1839 ref_call
.add_argument (get_result_cexpression ("self"));
1841 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "self"), ref_call
));
1844 if (current_method
!= null) {
1845 // allow capturing generic type parameters
1846 foreach (var type_param
in current_method
.get_type_parameters ()) {
1849 func_name
= "%s_type".printf (type_param
.name
.down ());
1850 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
)));
1852 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
1853 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
)));
1855 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
1856 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
), new
CCodeIdentifier (func_name
)));
1861 if (b
.parent_symbol is Method
) {
1862 var m
= (Method
) b
.parent_symbol
;
1864 // parameters are captured with the top-level block of the method
1865 foreach (var param
in m
.get_parameters ()) {
1866 if (param
.captured
) {
1867 capture_parameter (param
, data
, block_id
, free_block
);
1872 // capture async data to allow invoking callback from inside closure
1873 data
.add_field ("gpointer", "_async_data_");
1875 // async method is suspended while waiting for callback,
1876 // so we never need to care about memory management of async data
1877 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_async_data_"), new
CCodeIdentifier ("data")));
1879 } else if (b
.parent_symbol is PropertyAccessor
) {
1880 var acc
= (PropertyAccessor
) b
.parent_symbol
;
1882 if (!acc
.readable
&& acc
.value_parameter
.captured
) {
1883 capture_parameter (acc
.value_parameter
, data
, block_id
, free_block
);
1887 var typedef
= new
CCodeTypeDefinition ("struct _" + struct_name
, new
CCodeVariableDeclarator (struct_name
));
1888 cfile
.add_type_declaration (typedef
);
1889 cfile
.add_type_definition (data
);
1891 var data_free
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_free"));
1892 data_free
.add_argument (new
CCodeIdentifier (struct_name
));
1893 data_free
.add_argument (new
CCodeIdentifier ("_data%d_".printf (block_id
)));
1894 free_block
.add_statement (new
CCodeExpressionStatement (data_free
));
1896 // create ref/unref functions
1897 var ref_fun
= new
CCodeFunction ("block%d_data_ref".printf (block_id
), struct_name
+ "*");
1898 ref_fun
.add_parameter (new
CCodeParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
1899 ref_fun
.modifiers
= CCodeModifiers
.STATIC
;
1900 cfile
.add_function_declaration (ref_fun
);
1901 ref_fun
.block
= new
CCodeBlock ();
1903 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_atomic_int_inc"));
1904 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_ref_count_")));
1905 ref_fun
.block
.add_statement (new
CCodeExpressionStatement (ccall
));
1906 ref_fun
.block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("_data%d_".printf (block_id
))));
1907 cfile
.add_function (ref_fun
);
1909 var unref_fun
= new
CCodeFunction ("block%d_data_unref".printf (block_id
), "void");
1910 unref_fun
.add_parameter (new
CCodeParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
1911 unref_fun
.modifiers
= CCodeModifiers
.STATIC
;
1912 cfile
.add_function_declaration (unref_fun
);
1913 unref_fun
.block
= new
CCodeBlock ();
1915 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_atomic_int_dec_and_test"));
1916 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_ref_count_")));
1917 unref_fun
.block
.add_statement (new
CCodeIfStatement (ccall
, free_block
));
1919 cfile
.add_function (unref_fun
);
1922 foreach (Statement stmt
in b
.get_statements ()) {
1926 // free in reverse order
1927 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1928 var local
= local_vars
[i
];
1929 local
.active
= false;
1930 if (!local
.unreachable
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
1931 ccode
.add_expression (get_unref_expression_ (local
));
1935 if (b
.parent_symbol is Method
) {
1936 var m
= (Method
) b
.parent_symbol
;
1937 foreach (Parameter param
in m
.get_parameters ()) {
1938 if (!param
.captured
&& !param
.ellipsis
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
1939 var ma
= new MemberAccess
.simple (param
.name
);
1940 ma
.symbol_reference
= param
;
1941 ma
.value_type
= param
.variable_type
.copy ();
1942 visit_member_access (ma
);
1943 ccode
.add_expression (get_unref_expression (get_variable_cexpression (param
.name
), param
.variable_type
, ma
));
1944 } else if (param
.direction
== ParameterDirection
.OUT
&& !m
.coroutine
) {
1945 return_out_parameter (param
);
1951 int block_id
= get_block_id (b
);
1953 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
1954 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
1955 ccode
.add_expression (data_unref
);
1958 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
) {
1962 emit_context
.pop_symbol ();
1965 public override void visit_declaration_statement (DeclarationStatement stmt
) {
1966 stmt
.declaration
.accept (this
);
1969 public CCodeExpression
get_variable_cexpression (string name
) {
1970 if (current_method
!= null && current_method
.coroutine
) {
1971 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_variable_cname (name
));
1973 return new
CCodeIdentifier (get_variable_cname (name
));
1977 public string get_variable_cname (string name
) {
1978 if (name
[0] == '.') {
1979 if (name
== ".result") {
1982 // compiler-internal variable
1983 if (!variable_name_map
.contains (name
)) {
1984 variable_name_map
.set (name
, "_tmp%d_".printf (next_temp_var_id
));
1987 return variable_name_map
.get (name
);
1988 } else if (reserved_identifiers
.contains (name
)) {
1989 return "_%s_".printf (name
);
1995 public CCodeExpression
get_result_cexpression (string cname
= "result") {
1996 if (current_method
!= null && current_method
.coroutine
) {
1997 return new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), cname
);
1999 return new
CCodeIdentifier (cname
);
2003 bool has_simple_struct_initializer (LocalVariable local
) {
2004 var st
= local
.variable_type
.data_type as Struct
;
2005 var initializer
= local
.initializer as ObjectCreationExpression
;
2006 if (st
!= null && (!st
.is_simple_type () || st
.get_cname () == "va_list") && !local
.variable_type
.nullable
&&
2007 initializer
!= null && initializer
.get_object_initializer ().size
== 0) {
2014 public override void visit_local_variable (LocalVariable local
) {
2015 check_type (local
.variable_type
);
2017 if (local
.initializer
!= null) {
2018 local
.initializer
.emit (this
);
2020 visit_end_full_expression (local
.initializer
);
2023 generate_type_declaration (local
.variable_type
, cfile
);
2025 if (!local
.captured
) {
2026 if (local
.variable_type is ArrayType
) {
2027 // create variables to store array dimensions
2028 var array_type
= (ArrayType
) local
.variable_type
;
2030 if (!array_type
.fixed_length
) {
2031 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2032 var len_var
= new
LocalVariable (int_type
.copy (), get_array_length_cname (get_variable_cname (local
.name
), dim
));
2033 emit_temp_var (len_var
);
2036 if (array_type
.rank
== 1) {
2037 var size_var
= new
LocalVariable (int_type
.copy (), get_array_size_cname (get_variable_cname (local
.name
)));
2038 emit_temp_var (size_var
);
2041 } else if (local
.variable_type is DelegateType
) {
2042 var deleg_type
= (DelegateType
) local
.variable_type
;
2043 var d
= deleg_type
.delegate_symbol
;
2045 // create variable to store delegate target
2046 var target_var
= new
LocalVariable (new
PointerType (new
VoidType ()), get_delegate_target_cname (get_variable_cname (local
.name
)));
2047 emit_temp_var (target_var
);
2048 if (deleg_type
.value_owned
) {
2049 var target_destroy_notify_var
= new
LocalVariable (gdestroynotify_type
, get_delegate_target_destroy_notify_cname (get_variable_cname (local
.name
)));
2050 emit_temp_var (target_destroy_notify_var
);
2056 CCodeExpression rhs
= null;
2057 if (local
.initializer
!= null && get_cvalue (local
.initializer
) != null) {
2058 var target_value
= get_variable_cvalue (local
);
2060 rhs
= get_cvalue (local
.initializer
);
2062 if (local
.variable_type is ArrayType
) {
2063 var array_type
= (ArrayType
) local
.variable_type
;
2065 if (array_type
.fixed_length
) {
2068 var temp_var
= get_temp_variable (local
.variable_type
, true, local
, false);
2069 emit_temp_var (temp_var
);
2070 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), rhs
));
2072 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2073 var lhs_array_len
= get_array_length_cvalue (target_value
, dim
);
2074 var rhs_array_len
= get_array_length_cexpression (local
.initializer
, dim
);
2075 ccode
.add_expression (new
CCodeAssignment (lhs_array_len
, rhs_array_len
));
2077 if (array_type
.rank
== 1 && !local
.captured
) {
2078 var lhs_array_size
= get_array_size_cvalue (target_value
);
2079 var rhs_array_len
= get_array_length_cvalue (target_value
, 1);
2080 ccode
.add_expression (new
CCodeAssignment (lhs_array_size
, rhs_array_len
));
2083 rhs
= get_variable_cexpression (temp_var
.name
);
2085 } else if (local
.variable_type is DelegateType
) {
2086 var deleg_type
= (DelegateType
) local
.variable_type
;
2087 var d
= deleg_type
.delegate_symbol
;
2089 var temp_var
= get_temp_variable (local
.variable_type
, true, local
, false);
2090 emit_temp_var (temp_var
);
2091 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), rhs
));
2093 var lhs_delegate_target
= get_delegate_target_cvalue (target_value
);
2094 var lhs_delegate_target_destroy_notify
= get_delegate_target_destroy_notify_cvalue (target_value
);
2096 CCodeExpression rhs_delegate_target_destroy_notify
;
2097 var rhs_delegate_target
= get_delegate_target_cexpression (local
.initializer
, out rhs_delegate_target_destroy_notify
);
2098 ccode
.add_expression (new
CCodeAssignment (lhs_delegate_target
, rhs_delegate_target
));
2100 if (deleg_type
.value_owned
) {
2101 ccode
.add_expression (new
CCodeAssignment (lhs_delegate_target_destroy_notify
, rhs_delegate_target_destroy_notify
));
2104 rhs
= get_variable_cexpression (temp_var
.name
);
2107 } else if (local
.variable_type
.is_reference_type_or_type_parameter ()) {
2108 rhs
= new
CCodeConstant ("NULL");
2110 if (local
.variable_type is ArrayType
) {
2111 // initialize array length variables
2112 var array_type
= (ArrayType
) local
.variable_type
;
2114 if (array_type
.fixed_length
) {
2117 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
2118 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (get_array_length_cname (get_variable_cname (local
.name
), dim
)), new
CCodeConstant ("0")));
2124 if (local
.captured
) {
2125 if (local
.initializer
!= null) {
2126 if (has_simple_struct_initializer (local
)) {
2127 ccode
.add_expression (rhs
);
2129 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id ((Block
) local
.parent_symbol
))), get_variable_cname (local
.name
)), rhs
));
2132 } else if (current_method
!= null && current_method
.coroutine
) {
2133 closure_struct
.add_field (local
.variable_type
.get_cname (), get_variable_cname (local
.name
) + local
.variable_type
.get_cdeclarator_suffix ());
2135 if (local
.initializer
!= null) {
2136 if (has_simple_struct_initializer (local
)) {
2137 ccode
.add_expression (rhs
);
2139 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_variable_cname (local
.name
)), rhs
));
2143 CCodeExpression post_rhs
= null;
2144 if (has_simple_struct_initializer (local
)) {
2149 var cvar
= new
CCodeVariableDeclarator (get_variable_cname (local
.name
), rhs
, local
.variable_type
.get_cdeclarator_suffix ());
2151 cvar
.line
= rhs
.line
;
2154 // try to initialize uninitialized variables
2155 // initialization not necessary for variables stored in closure
2156 if (cvar
.initializer
== null) {
2157 cvar
.initializer
= default_value_for_type (local
.variable_type
, true);
2161 ccode
.add_declaration (local
.variable_type
.get_cname (), cvar
);
2163 if (cvar
.initializer
!= null && !cvar
.init0
) {
2164 cvar
.initializer
= null;
2165 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (local
.name
), rhs
));
2168 if (post_rhs
!= null) {
2169 ccode
.add_expression (post_rhs
);
2173 if (local
.initializer
!= null && local
.variable_type is ArrayType
) {
2174 var array_type
= (ArrayType
) local
.variable_type
;
2176 if (array_type
.fixed_length
) {
2177 cfile
.add_include ("string.h");
2179 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
2180 // simple assignments do not work in C
2181 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
2182 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
2183 var size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
);
2185 var ccopy
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
2186 ccopy
.add_argument (get_variable_cexpression (local
.name
));
2187 ccopy
.add_argument (get_cvalue (local
.initializer
));
2188 ccopy
.add_argument (size
);
2189 ccode
.add_expression (ccopy
);
2193 if (local
.initializer
!= null && local
.initializer
.tree_can_fail
) {
2194 add_simple_check (local
.initializer
);
2197 local
.active
= true;
2200 public override void visit_initializer_list (InitializerList list
) {
2201 if (list
.target_type
.data_type is Struct
) {
2202 /* initializer is used as struct initializer */
2203 var st
= (Struct
) list
.target_type
.data_type
;
2205 if (list
.parent_node is Constant
|| list
.parent_node is Field
|| list
.parent_node is InitializerList
) {
2206 var clist
= new
CCodeInitializerList ();
2208 var field_it
= st
.get_fields ().iterator ();
2209 foreach (Expression expr
in list
.get_initializers ()) {
2211 while (field
== null) {
2213 field
= field_it
.get ();
2214 if (field
.binding
!= MemberBinding
.INSTANCE
) {
2215 // we only initialize instance fields
2220 var cexpr
= get_cvalue (expr
);
2222 string ctype
= field
.get_ctype ();
2223 if (ctype
!= null) {
2224 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
2227 clist
.append (cexpr
);
2230 set_cvalue (list
, clist
);
2232 // used as expression
2233 var temp_decl
= get_temp_variable (list
.target_type
, false, list
);
2234 emit_temp_var (temp_decl
);
2236 var instance
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
2238 var ccomma
= new
CCodeCommaExpression ();
2240 var field_it
= st
.get_fields ().iterator ();
2241 foreach (Expression expr
in list
.get_initializers ()) {
2243 while (field
== null) {
2245 field
= field_it
.get ();
2246 if (field
.binding
!= MemberBinding
.INSTANCE
) {
2247 // we only initialize instance fields
2252 var cexpr
= get_cvalue (expr
);
2254 string ctype
= field
.get_ctype ();
2255 if (ctype
!= null) {
2256 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
2259 var lhs
= new
CCodeMemberAccess (instance
, field
.get_cname ());;
2260 ccomma
.append_expression (new
CCodeAssignment (lhs
, cexpr
));
2263 ccomma
.append_expression (instance
);
2264 set_cvalue (list
, ccomma
);
2267 var clist
= new
CCodeInitializerList ();
2268 foreach (Expression expr
in list
.get_initializers ()) {
2269 clist
.append (get_cvalue (expr
));
2271 set_cvalue (list
, clist
);
2275 public override LocalVariable
create_local (DataType type
) {
2276 var result
= get_temp_variable (type
, type
.value_owned
);
2277 emit_temp_var (result
);
2281 public LocalVariable
get_temp_variable (DataType type
, bool value_owned
= true, CodeNode? node_reference
= null, bool init
= true) {
2282 var var_type
= type
.copy ();
2283 var_type
.value_owned
= value_owned
;
2284 var local
= new
LocalVariable (var_type
, "_tmp%d_".printf (next_temp_var_id
));
2285 local
.no_init
= !init
;
2287 if (node_reference
!= null) {
2288 local
.source_reference
= node_reference
.source_reference
;
2296 bool is_in_generic_type (DataType type
) {
2297 if (current_symbol
!= null && type
.type_parameter
.parent_symbol is TypeSymbol
2298 && (current_method
== null || current_method
.binding
== MemberBinding
.INSTANCE
)) {
2305 public CCodeExpression
get_type_id_expression (DataType type
, bool is_chainup
= false) {
2306 if (type is GenericType
) {
2307 string var_name
= "%s_type".printf (type
.type_parameter
.name
.down ());
2308 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2309 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), var_name
);
2311 return new
CCodeIdentifier (var_name
);
2314 string type_id
= type
.get_type_id ();
2315 if (type_id
== null) {
2316 type_id
= "G_TYPE_INVALID";
2318 generate_type_declaration (type
, cfile
);
2320 return new
CCodeIdentifier (type_id
);
2324 public virtual CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
, bool is_chainup
= false) {
2325 if (type is ErrorType
) {
2326 return new
CCodeIdentifier ("g_error_copy");
2327 } else if (type
.data_type
!= null) {
2328 string dup_function
;
2329 var cl
= type
.data_type as Class
;
2330 if (type
.data_type
.is_reference_counting ()) {
2331 dup_function
= type
.data_type
.get_ref_function ();
2332 if (type
.data_type is Interface
&& dup_function
== null) {
2333 Report
.error (source_reference
, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure".printf (type
.data_type
.get_full_name ()));
2336 } else if (cl
!= null && cl
.is_immutable
) {
2337 // allow duplicates of immutable instances as for example strings
2338 dup_function
= type
.data_type
.get_dup_function ();
2339 if (dup_function
== null) {
2342 } else if (cl
!= null && cl
.is_gboxed
) {
2343 // allow duplicates of gboxed instances
2344 dup_function
= generate_dup_func_wrapper (type
);
2345 if (dup_function
== null) {
2348 } else if (type is ValueType
) {
2349 dup_function
= type
.data_type
.get_dup_function ();
2350 if (dup_function
== null && type
.nullable
) {
2351 dup_function
= generate_struct_dup_wrapper ((ValueType
) type
);
2352 } else if (dup_function
== null) {
2356 // duplicating non-reference counted objects may cause side-effects (and performance issues)
2357 Report
.error (source_reference
, "duplicating %s instance, use unowned variable or explicitly invoke copy method".printf (type
.data_type
.name
));
2361 return new
CCodeIdentifier (dup_function
);
2362 } else if (type
.type_parameter
!= null) {
2363 string func_name
= "%s_dup_func".printf (type
.type_parameter
.name
.down ());
2364 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2365 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), func_name
);
2367 return new
CCodeIdentifier (func_name
);
2369 } else if (type is PointerType
) {
2370 var pointer_type
= (PointerType
) type
;
2371 return get_dup_func_expression (pointer_type
.base_type
, source_reference
);
2373 return new
CCodeConstant ("NULL");
2377 void make_comparable_cexpression (ref DataType left_type
, ref CCodeExpression cleft
, ref DataType right_type
, ref CCodeExpression cright
) {
2378 var left_type_as_struct
= left_type
.data_type as Struct
;
2379 var right_type_as_struct
= right_type
.data_type as Struct
;
2382 var valuecast
= try_cast_value_to_type (cleft
, left_type
, right_type
);
2383 if (valuecast
!= null) {
2385 left_type
= right_type
;
2386 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
2390 valuecast
= try_cast_value_to_type (cright
, right_type
, left_type
);
2391 if (valuecast
!= null) {
2393 right_type
= left_type
;
2394 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
2398 if (left_type
.data_type is Class
&& !((Class
) left_type
.data_type
).is_compact
&&
2399 right_type
.data_type is Class
&& !((Class
) right_type
.data_type
).is_compact
) {
2400 var left_cl
= (Class
) left_type
.data_type
;
2401 var right_cl
= (Class
) right_type
.data_type
;
2403 if (left_cl
!= right_cl
) {
2404 if (left_cl
.is_subtype_of (right_cl
)) {
2405 cleft
= generate_instance_cast (cleft
, right_cl
);
2406 } else if (right_cl
.is_subtype_of (left_cl
)) {
2407 cright
= generate_instance_cast (cright
, left_cl
);
2410 } else if (left_type_as_struct
!= null && right_type_as_struct
!= null) {
2411 if (left_type is StructValueType
) {
2412 // real structs (uses compare/equal function)
2413 if (!left_type
.nullable
) {
2414 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cleft
);
2416 if (!right_type
.nullable
) {
2417 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cright
);
2420 // integer or floating or boolean type
2421 if (left_type
.nullable
&& right_type
.nullable
) {
2422 // FIXME also compare contents, not just address
2423 } else if (left_type
.nullable
) {
2424 // FIXME check left value is not null
2425 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cleft
);
2426 } else if (right_type
.nullable
) {
2427 // FIXME check right value is not null
2428 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cright
);
2434 private string generate_struct_equal_function (Struct st
) {
2435 string equal_func
= "_%sequal".printf (st
.get_lower_case_cprefix ());
2437 if (!add_wrapper (equal_func
)) {
2438 // wrapper already defined
2442 var function
= new
CCodeFunction (equal_func
, "gboolean");
2443 function
.modifiers
= CCodeModifiers
.STATIC
;
2445 function
.add_parameter (new
CCodeParameter ("s1", "const " + st
.get_cname () + "*"));
2446 function
.add_parameter (new
CCodeParameter ("s2", "const " + st
.get_cname () + "*"));
2448 push_function (function
);
2450 // if (s1 == s2) return TRUE;
2452 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
2453 ccode
.open_if (cexp
);
2454 ccode
.add_return (new
CCodeConstant ("TRUE"));
2457 // if (s1 == NULL || s2 == NULL) return FALSE;
2459 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeConstant ("NULL"));
2460 ccode
.open_if (cexp
);
2461 ccode
.add_return (new
CCodeConstant ("FALSE"));
2464 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s2"), new
CCodeConstant ("NULL"));
2465 ccode
.open_if (cexp
);
2466 ccode
.add_return (new
CCodeConstant ("FALSE"));
2470 foreach (Field f
in st
.get_fields ()) {
2471 if (f
.binding
!= MemberBinding
.INSTANCE
) {
2472 // we only compare instance fields
2476 CCodeExpression cexp
; // if (cexp) return FALSE;
2477 var s1
= (CCodeExpression
) new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("s1"), f
.name
); // s1->f
2478 var s2
= (CCodeExpression
) new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("s2"), f
.name
); // s2->f
2480 var variable_type
= f
.variable_type
.copy ();
2481 make_comparable_cexpression (ref variable_type
, ref s1
, ref variable_type
, ref s2
);
2483 if (!(f
.variable_type is NullType
) && f
.variable_type
.compatible (string_type
)) {
2484 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
2485 ccall
.add_argument (s1
);
2486 ccall
.add_argument (s2
);
2488 } else if (f
.variable_type is StructValueType
) {
2489 var equalfunc
= generate_struct_equal_function (f
.variable_type
.data_type as Struct
);
2490 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
2491 ccall
.add_argument (s1
);
2492 ccall
.add_argument (s2
);
2493 cexp
= new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, ccall
);
2495 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, s1
, s2
);
2498 ccode
.open_if (cexp
);
2499 ccode
.add_return (new
CCodeConstant ("FALSE"));
2503 if (st
.get_fields().size
== 0) {
2504 // either opaque structure or simple type
2505 if (st
.is_simple_type ()) {
2506 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s1")), new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s2")));
2507 ccode
.add_return (cexp
);
2509 ccode
.add_return (new
CCodeConstant ("FALSE"));
2512 ccode
.add_return (new
CCodeConstant ("TRUE"));
2517 cfile
.add_function_declaration (function
);
2518 cfile
.add_function (function
);
2523 private string generate_numeric_equal_function (Struct st
) {
2524 string equal_func
= "_%sequal".printf (st
.get_lower_case_cprefix ());
2526 if (!add_wrapper (equal_func
)) {
2527 // wrapper already defined
2531 var function
= new
CCodeFunction (equal_func
, "gboolean");
2532 function
.modifiers
= CCodeModifiers
.STATIC
;
2534 function
.add_parameter (new
CCodeParameter ("s1", "const " + st
.get_cname () + "*"));
2535 function
.add_parameter (new
CCodeParameter ("s2", "const " + st
.get_cname () + "*"));
2537 push_function (function
);
2539 // if (s1 == s2) return TRUE;
2541 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeIdentifier ("s2"));
2542 ccode
.open_if (cexp
);
2543 ccode
.add_return (new
CCodeConstant ("TRUE"));
2546 // if (s1 == NULL || s2 == NULL) return FALSE;
2548 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s1"), new
CCodeConstant ("NULL"));
2549 ccode
.open_if (cexp
);
2550 ccode
.add_return (new
CCodeConstant ("FALSE"));
2553 cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("s2"), new
CCodeConstant ("NULL"));
2554 ccode
.open_if (cexp
);
2555 ccode
.add_return (new
CCodeConstant ("FALSE"));
2558 // return (*s1 == *s2);
2560 var cexp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s1")), new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("s2")));
2561 ccode
.add_return (cexp
);
2566 cfile
.add_function_declaration (function
);
2567 cfile
.add_function (function
);
2572 private string generate_struct_dup_wrapper (ValueType value_type
) {
2573 string dup_func
= "_%sdup".printf (value_type
.type_symbol
.get_lower_case_cprefix ());
2575 if (!add_wrapper (dup_func
)) {
2576 // wrapper already defined
2580 var function
= new
CCodeFunction (dup_func
, value_type
.get_cname ());
2581 function
.modifiers
= CCodeModifiers
.STATIC
;
2583 function
.add_parameter (new
CCodeParameter ("self", value_type
.get_cname ()));
2585 push_function (function
);
2587 if (value_type
.type_symbol
== gvalue_type
) {
2588 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_copy"));
2589 dup_call
.add_argument (new
CCodeIdentifier ("G_TYPE_VALUE"));
2590 dup_call
.add_argument (new
CCodeIdentifier ("self"));
2592 ccode
.add_return (dup_call
);
2594 ccode
.add_declaration (value_type
.get_cname (), new
CCodeVariableDeclarator ("dup"));
2596 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
2597 creation_call
.add_argument (new
CCodeConstant (value_type
.data_type
.get_cname ()));
2598 creation_call
.add_argument (new
CCodeConstant ("1"));
2599 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("dup"), creation_call
));
2601 var st
= value_type
.data_type as Struct
;
2602 if (st
!= null && st
.is_disposable ()) {
2603 if (!st
.has_copy_function
) {
2604 generate_struct_copy_function (st
);
2607 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_copy_function ()));
2608 copy_call
.add_argument (new
CCodeIdentifier ("self"));
2609 copy_call
.add_argument (new
CCodeIdentifier ("dup"));
2610 ccode
.add_expression (copy_call
);
2612 cfile
.add_include ("string.h");
2614 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
2615 sizeof_call
.add_argument (new
CCodeConstant (value_type
.data_type
.get_cname ()));
2617 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
2618 copy_call
.add_argument (new
CCodeIdentifier ("dup"));
2619 copy_call
.add_argument (new
CCodeIdentifier ("self"));
2620 copy_call
.add_argument (sizeof_call
);
2621 ccode
.add_expression (copy_call
);
2624 ccode
.add_return (new
CCodeIdentifier ("dup"));
2629 cfile
.add_function_declaration (function
);
2630 cfile
.add_function (function
);
2635 protected string generate_dup_func_wrapper (DataType type
) {
2636 string destroy_func
= "_vala_%s_copy".printf (type
.data_type
.get_cname ());
2638 if (!add_wrapper (destroy_func
)) {
2639 // wrapper already defined
2640 return destroy_func
;
2643 var function
= new
CCodeFunction (destroy_func
, type
.get_cname ());
2644 function
.modifiers
= CCodeModifiers
.STATIC
;
2645 function
.add_parameter (new
CCodeParameter ("self", type
.get_cname ()));
2647 push_function (function
);
2649 var cl
= type
.data_type as Class
;
2650 assert (cl
!= null && cl
.is_gboxed
);
2652 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_copy"));
2653 free_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
2654 free_call
.add_argument (new
CCodeIdentifier ("self"));
2656 ccode
.add_return (free_call
);
2660 cfile
.add_function_declaration (function
);
2661 cfile
.add_function (function
);
2663 return destroy_func
;
2666 protected string generate_free_func_wrapper (DataType type
) {
2667 string destroy_func
= "_vala_%s_free".printf (type
.data_type
.get_cname ());
2669 if (!add_wrapper (destroy_func
)) {
2670 // wrapper already defined
2671 return destroy_func
;
2674 var function
= new
CCodeFunction (destroy_func
, "void");
2675 function
.modifiers
= CCodeModifiers
.STATIC
;
2676 function
.add_parameter (new
CCodeParameter ("self", type
.get_cname ()));
2678 push_function (function
);
2680 var cl
= type
.data_type as Class
;
2681 if (cl
!= null && cl
.is_gboxed
) {
2682 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_boxed_free"));
2683 free_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
2684 free_call
.add_argument (new
CCodeIdentifier ("self"));
2686 ccode
.add_expression (free_call
);
2687 } else if (cl
!= null) {
2688 assert (cl
.free_function_address_of
);
2690 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier (type
.data_type
.get_free_function ()));
2691 free_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("self")));
2693 ccode
.add_expression (free_call
);
2695 var st
= type
.data_type as Struct
;
2696 if (st
!= null && st
.is_disposable ()) {
2697 if (!st
.has_destroy_function
) {
2698 generate_struct_destroy_function (st
);
2701 var destroy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_destroy_function ()));
2702 destroy_call
.add_argument (new
CCodeIdentifier ("self"));
2703 ccode
.add_expression (destroy_call
);
2706 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
2707 free_call
.add_argument (new
CCodeIdentifier ("self"));
2709 ccode
.add_expression (free_call
);
2714 cfile
.add_function_declaration (function
);
2715 cfile
.add_function (function
);
2717 return destroy_func
;
2720 public CCodeExpression?
get_destroy0_func_expression (DataType type
, bool is_chainup
= false) {
2721 var element_destroy_func_expression
= get_destroy_func_expression (type
, is_chainup
);
2723 if (element_destroy_func_expression is CCodeIdentifier
) {
2724 var freeid
= (CCodeIdentifier
) element_destroy_func_expression
;
2725 string free0_func
= "_%s0_".printf (freeid
.name
);
2727 if (add_wrapper (free0_func
)) {
2728 var function
= new
CCodeFunction (free0_func
, "void");
2729 function
.modifiers
= CCodeModifiers
.STATIC
;
2731 function
.add_parameter (new
CCodeParameter ("var", "gpointer"));
2733 push_function (function
);
2735 ccode
.add_expression (get_unref_expression (new
CCodeIdentifier ("var"), type
, null, true));
2739 cfile
.add_function_declaration (function
);
2740 cfile
.add_function (function
);
2743 element_destroy_func_expression
= new
CCodeIdentifier (free0_func
);
2746 return element_destroy_func_expression
;
2749 public CCodeExpression?
get_destroy_func_expression (DataType type
, bool is_chainup
= false) {
2750 if (context
.profile
== Profile
.GOBJECT
&& (type
.data_type
== glist_type
|| type
.data_type
== gslist_type
|| type
.data_type
== gnode_type
)) {
2751 // create wrapper function to free list elements if necessary
2753 bool elements_require_free
= false;
2754 CCodeExpression element_destroy_func_expression
= null;
2756 foreach (DataType type_arg
in type
.get_type_arguments ()) {
2757 elements_require_free
= requires_destroy (type_arg
);
2758 if (elements_require_free
) {
2759 element_destroy_func_expression
= get_destroy0_func_expression (type_arg
);
2763 if (elements_require_free
&& element_destroy_func_expression is CCodeIdentifier
) {
2764 return new
CCodeIdentifier (generate_collection_free_wrapper (type
, (CCodeIdentifier
) element_destroy_func_expression
));
2766 return new
CCodeIdentifier (type
.data_type
.get_free_function ());
2768 } else if (type is ErrorType
) {
2769 return new
CCodeIdentifier ("g_error_free");
2770 } else if (type
.data_type
!= null) {
2771 string unref_function
;
2772 if (type is ReferenceType
) {
2773 if (type
.data_type
.is_reference_counting ()) {
2774 unref_function
= type
.data_type
.get_unref_function ();
2775 if (type
.data_type is Interface
&& unref_function
== null) {
2776 Report
.error (type
.source_reference
, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure".printf (type
.data_type
.get_full_name ()));
2780 var cl
= type
.data_type as Class
;
2781 if (cl
!= null && (cl
.free_function_address_of
|| cl
.is_gboxed
)) {
2782 unref_function
= generate_free_func_wrapper (type
);
2784 unref_function
= type
.data_type
.get_free_function ();
2788 if (type
.nullable
) {
2789 unref_function
= type
.data_type
.get_free_function ();
2790 if (unref_function
== null) {
2791 if (type
.data_type is Struct
&& ((Struct
) type
.data_type
).is_disposable ()) {
2792 unref_function
= generate_free_func_wrapper (type
);
2794 unref_function
= "g_free";
2798 var st
= (Struct
) type
.data_type
;
2799 if (!st
.has_destroy_function
) {
2800 generate_struct_destroy_function (st
);
2802 unref_function
= st
.get_destroy_function ();
2805 if (unref_function
== null) {
2806 return new
CCodeConstant ("NULL");
2808 return new
CCodeIdentifier (unref_function
);
2809 } else if (type
.type_parameter
!= null && current_type_symbol is Class
) {
2810 string func_name
= "%s_destroy_func".printf (type
.type_parameter
.name
.down ());
2811 if (is_in_generic_type (type
) && !is_chainup
&& !in_creation_method
) {
2812 return new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (get_result_cexpression ("self"), "priv"), func_name
);
2814 return new
CCodeIdentifier (func_name
);
2816 } else if (type is ArrayType
) {
2817 if (context
.profile
== Profile
.POSIX
) {
2818 return new
CCodeIdentifier ("free");
2820 return new
CCodeIdentifier ("g_free");
2822 } else if (type is PointerType
) {
2823 if (context
.profile
== Profile
.POSIX
) {
2824 return new
CCodeIdentifier ("free");
2826 return new
CCodeIdentifier ("g_free");
2829 return new
CCodeConstant ("NULL");
2833 private string generate_collection_free_wrapper (DataType collection_type
, CCodeIdentifier element_destroy_func_expression
) {
2834 string destroy_func
= "_%s_%s".printf (collection_type
.data_type
.get_free_function (), element_destroy_func_expression
.name
);
2836 if (!add_wrapper (destroy_func
)) {
2837 // wrapper already defined
2838 return destroy_func
;
2841 var function
= new
CCodeFunction (destroy_func
, "void");
2842 function
.modifiers
= CCodeModifiers
.STATIC
;
2844 function
.add_parameter (new
CCodeParameter ("self", collection_type
.get_cname ()));
2846 push_function (function
);
2848 CCodeFunctionCall element_free_call
;
2849 if (collection_type
.data_type
== gnode_type
) {
2850 /* A wrapper which converts GNodeTraverseFunc into GDestroyNotify */
2851 string destroy_node_func
= "%s_node".printf (destroy_func
);
2852 var wrapper
= new
CCodeFunction (destroy_node_func
, "gboolean");
2853 wrapper
.modifiers
= CCodeModifiers
.STATIC
;
2854 wrapper
.add_parameter (new
CCodeParameter ("node", collection_type
.get_cname ()));
2855 wrapper
.add_parameter (new
CCodeParameter ("unused", "gpointer"));
2856 var wrapper_block
= new
CCodeBlock ();
2857 var free_call
= new
CCodeFunctionCall (element_destroy_func_expression
);
2858 free_call
.add_argument (new CCodeMemberAccess
.pointer(new
CCodeIdentifier("node"), "data"));
2859 wrapper_block
.add_statement (new
CCodeExpressionStatement (free_call
));
2860 wrapper_block
.add_statement (new
CCodeReturnStatement (new
CCodeConstant ("FALSE")));
2861 cfile
.add_function_declaration (function
);
2862 wrapper
.block
= wrapper_block
;
2863 cfile
.add_function (wrapper
);
2865 /* Now the code to call g_traverse with the above */
2866 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_node_traverse"));
2867 element_free_call
.add_argument (new
CCodeIdentifier("self"));
2868 element_free_call
.add_argument (new
CCodeConstant ("G_POST_ORDER"));
2869 element_free_call
.add_argument (new
CCodeConstant ("G_TRAVERSE_ALL"));
2870 element_free_call
.add_argument (new
CCodeConstant ("-1"));
2871 element_free_call
.add_argument (new
CCodeIdentifier (destroy_node_func
));
2872 element_free_call
.add_argument (new
CCodeConstant ("NULL"));
2874 if (collection_type
.data_type
== glist_type
) {
2875 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_list_foreach"));
2877 element_free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slist_foreach"));
2880 element_free_call
.add_argument (new
CCodeIdentifier ("self"));
2881 element_free_call
.add_argument (new
CCodeCastExpression (element_destroy_func_expression
, "GFunc"));
2882 element_free_call
.add_argument (new
CCodeConstant ("NULL"));
2885 ccode
.add_expression (element_free_call
);
2887 var cfreecall
= new
CCodeFunctionCall (new
CCodeIdentifier (collection_type
.data_type
.get_free_function ()));
2888 cfreecall
.add_argument (new
CCodeIdentifier ("self"));
2889 ccode
.add_expression (cfreecall
);
2893 cfile
.add_function_declaration (function
);
2894 cfile
.add_function (function
);
2896 return destroy_func
;
2899 public virtual string?
append_struct_array_free (Struct st
) {
2903 public CCodeExpression
get_unref_expression_ (Variable variable
, CCodeExpression? inner
= null) {
2904 return destroy_value (get_variable_cvalue (variable
, inner
));
2907 public CCodeExpression
get_unref_expression (CCodeExpression cvar
, DataType type
, Expression? expr
, bool is_macro_definition
= false) {
2908 if (expr
!= null && expr
.symbol_reference is LocalVariable
) {
2909 return get_unref_expression_ ((Variable
) expr
.symbol_reference
);
2911 var value
= new
GLibValue (type
, cvar
);
2912 if (expr
!= null && expr
.target_value
!= null) {
2913 value
.array_length_cvalues
= ((GLibValue
) expr
.target_value
).array_length_cvalues
;
2914 value
.delegate_target_cvalue
= get_delegate_target_cvalue (expr
.target_value
);
2915 value
.delegate_target_destroy_notify_cvalue
= get_delegate_target_destroy_notify_cvalue (expr
.target_value
);
2917 return destroy_value (value
, is_macro_definition
);
2920 public virtual CCodeExpression
destroy_value (TargetValue value
, bool is_macro_definition
= false) {
2921 var type
= value
.value_type
;
2922 var cvar
= get_cvalue_ (value
);
2924 if (type is DelegateType
) {
2925 var delegate_target
= get_delegate_target_cvalue (value
);
2926 var delegate_target_destroy_notify
= get_delegate_target_destroy_notify_cvalue (value
);
2928 var ccall
= new
CCodeFunctionCall (delegate_target_destroy_notify
);
2929 ccall
.add_argument (delegate_target
);
2931 var destroy_call
= new
CCodeCommaExpression ();
2932 destroy_call
.append_expression (ccall
);
2933 destroy_call
.append_expression (new
CCodeConstant ("NULL"));
2935 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, delegate_target_destroy_notify
, new
CCodeConstant ("NULL"));
2937 var ccomma
= new
CCodeCommaExpression ();
2938 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), destroy_call
));
2939 ccomma
.append_expression (new
CCodeAssignment (cvar
, new
CCodeConstant ("NULL")));
2940 ccomma
.append_expression (new
CCodeAssignment (delegate_target
, new
CCodeConstant ("NULL")));
2941 ccomma
.append_expression (new
CCodeAssignment (delegate_target_destroy_notify
, new
CCodeConstant ("NULL")));
2946 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
2948 if (type is ValueType
&& !type
.nullable
) {
2949 // normal value type, no null check
2950 var st
= type
.data_type as Struct
;
2951 if (st
!= null && st
.is_simple_type ()) {
2953 ccall
.add_argument (cvar
);
2955 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
2958 if (gvalue_type
!= null && type
.data_type
== gvalue_type
) {
2959 // g_value_unset must not be called for already unset values
2960 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
2961 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
2963 var ccomma
= new
CCodeCommaExpression ();
2964 ccomma
.append_expression (ccall
);
2965 ccomma
.append_expression (new
CCodeConstant ("NULL"));
2967 return new
CCodeConditionalExpression (cisvalid
, ccomma
, new
CCodeConstant ("NULL"));
2973 if (ccall
.call is CCodeIdentifier
&& !(type is ArrayType
) && !is_macro_definition
) {
2974 // generate and use NULL-aware free macro to simplify code
2976 var freeid
= (CCodeIdentifier
) ccall
.call
;
2977 string free0_func
= "_%s0".printf (freeid
.name
);
2979 if (add_wrapper (free0_func
)) {
2980 var macro
= destroy_value (new
GLibValue (type
, new
CCodeIdentifier ("var")), true);
2981 cfile
.add_type_declaration (new CCodeMacroReplacement
.with_expression ("%s(var)".printf (free0_func
), macro
));
2984 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (free0_func
));
2985 ccall
.add_argument (cvar
);
2989 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
2991 /* can be simplified to
2992 * foo = (unref (foo), NULL)
2993 * if foo is of static type non-null
2996 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cvar
, new
CCodeConstant ("NULL"));
2997 if (type
.type_parameter
!= null) {
2998 if (!(current_type_symbol is Class
) || current_class
.is_compact
) {
2999 return new
CCodeConstant ("NULL");
3002 // unref functions are optional for type parameters
3003 var cunrefisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_destroy_func_expression (type
), new
CCodeConstant ("NULL"));
3004 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cunrefisnull
);
3007 ccall
.add_argument (cvar
);
3009 /* set freed references to NULL to prevent further use */
3010 var ccomma
= new
CCodeCommaExpression ();
3012 if (context
.profile
== Profile
.GOBJECT
) {
3013 if (type
.data_type
!= null && !type
.data_type
.is_reference_counting () &&
3014 (type
.data_type
== gstringbuilder_type
3015 || type
.data_type
== garray_type
3016 || type
.data_type
== gbytearray_type
3017 || type
.data_type
== gptrarray_type
)) {
3018 ccall
.add_argument (new
CCodeConstant ("TRUE"));
3019 } else if (type
.data_type
== gthreadpool_type
) {
3020 ccall
.add_argument (new
CCodeConstant ("FALSE"));
3021 ccall
.add_argument (new
CCodeConstant ("TRUE"));
3022 } else if (type is ArrayType
) {
3023 var array_type
= (ArrayType
) type
;
3024 if (requires_destroy (array_type
.element_type
)) {
3025 CCodeExpression csizeexpr
= null;
3027 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3029 csizeexpr
= get_array_length_cvalue (value
, dim
);
3032 csizeexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeexpr
, get_array_length_cvalue (value
, dim
));
3036 var st
= array_type
.element_type
.data_type as Struct
;
3037 if (st
!= null && !array_type
.element_type
.nullable
) {
3038 ccall
.call
= new
CCodeIdentifier (append_struct_array_free (st
));
3039 ccall
.add_argument (csizeexpr
);
3041 requires_array_free
= true;
3042 ccall
.call
= new
CCodeIdentifier ("_vala_array_free");
3043 ccall
.add_argument (csizeexpr
);
3044 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
3050 ccomma
.append_expression (ccall
);
3051 ccomma
.append_expression (new
CCodeConstant ("NULL"));
3053 var cassign
= new
CCodeAssignment (cvar
, ccomma
);
3055 // g_free (NULL) is allowed
3056 bool uses_gfree
= (type
.data_type
!= null && !type
.data_type
.is_reference_counting () && type
.data_type
.get_free_function () == "g_free");
3057 uses_gfree
= uses_gfree
|| type is ArrayType
;
3062 return new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), cassign
);
3065 public override void visit_end_full_expression (Expression expr
) {
3066 /* expr is a full expression, i.e. an initializer, the
3067 * expression in an expression statement, the controlling
3068 * expression in if, while, for, or foreach statements
3070 * we unref temporary variables at the end of a full
3073 if (((List
<LocalVariable
>) temp_ref_vars
).size
== 0) {
3074 /* nothing to do without temporary variables */
3078 var expr_list
= new
CCodeCommaExpression ();
3080 LocalVariable full_expr_var
= null;
3082 var local_decl
= expr
.parent_node as LocalVariable
;
3083 if (local_decl
!= null && has_simple_struct_initializer (local_decl
)) {
3084 expr_list
.append_expression (get_cvalue (expr
));
3086 var expr_type
= expr
.value_type
;
3087 if (expr
.target_type
!= null) {
3088 expr_type
= expr
.target_type
;
3091 full_expr_var
= get_temp_variable (expr_type
, true, expr
, false);
3092 emit_temp_var (full_expr_var
);
3094 expr_list
.append_expression (new
CCodeAssignment (get_variable_cexpression (full_expr_var
.name
), get_cvalue (expr
)));
3097 foreach (LocalVariable local
in temp_ref_vars
) {
3098 expr_list
.append_expression (get_unref_expression_ (local
));
3101 if (full_expr_var
!= null) {
3102 expr_list
.append_expression (get_variable_cexpression (full_expr_var
.name
));
3105 set_cvalue (expr
, expr_list
);
3107 temp_ref_vars
.clear ();
3110 public void emit_temp_var (LocalVariable local
) {
3111 var vardecl
= new
CCodeVariableDeclarator (local
.name
, null, local
.variable_type
.get_cdeclarator_suffix ());
3113 var st
= local
.variable_type
.data_type as Struct
;
3114 var array_type
= local
.variable_type as ArrayType
;
3116 if (local
.name
.has_prefix ("*")) {
3117 // do not dereference unintialized variable
3118 // initialization is not needed for these special
3119 // pointer temp variables
3120 // used to avoid side-effects in assignments
3121 } else if (local
.no_init
) {
3122 // no initialization necessary for this temp var
3123 } else if (!local
.variable_type
.nullable
&&
3124 (st
!= null && !st
.is_simple_type ()) ||
3125 (array_type
!= null && array_type
.fixed_length
)) {
3126 // 0-initialize struct with struct initializer { 0 }
3127 // necessary as they will be passed by reference
3128 var clist
= new
CCodeInitializerList ();
3129 clist
.append (new
CCodeConstant ("0"));
3131 vardecl
.initializer
= clist
;
3132 vardecl
.init0
= true;
3133 } else if (local
.variable_type
.is_reference_type_or_type_parameter () ||
3134 local
.variable_type
.nullable
||
3135 local
.variable_type is DelegateType
) {
3136 vardecl
.initializer
= new
CCodeConstant ("NULL");
3137 vardecl
.init0
= true;
3140 if (current_method
!= null && current_method
.coroutine
) {
3141 closure_struct
.add_field (local
.variable_type
.get_cname (), local
.name
);
3143 // even though closure struct is zerod, we need to initialize temporary variables
3144 // as they might be used multiple times when declared in a loop
3146 if (vardecl
.initializer is CCodeInitializerList
) {
3147 // C does not support initializer lists in assignments, use memset instead
3148 cfile
.add_include ("string.h");
3149 var memset_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
3150 memset_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (local
.name
)));
3151 memset_call
.add_argument (new
CCodeConstant ("0"));
3152 memset_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (local
.variable_type
.get_cname ())));
3153 ccode
.add_expression (memset_call
);
3154 } else if (vardecl
.initializer
!= null) {
3155 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (local
.name
), vardecl
.initializer
));
3158 ccode
.add_declaration (local
.variable_type
.get_cname (), vardecl
);
3162 public override void visit_expression_statement (ExpressionStatement stmt
) {
3163 if (stmt
.expression
.error
) {
3168 /* free temporary objects and handle errors */
3170 foreach (LocalVariable local
in temp_ref_vars
) {
3171 ccode
.add_expression (get_unref_expression_ (local
));
3174 if (stmt
.tree_can_fail
&& stmt
.expression
.tree_can_fail
) {
3175 // simple case, no node breakdown necessary
3176 add_simple_check (stmt
.expression
);
3179 temp_ref_vars
.clear ();
3182 public virtual void append_local_free (Symbol sym
, bool stop_at_loop
= false, CodeNode? stop_at
= null) {
3183 var b
= (Block
) sym
;
3185 var local_vars
= b
.get_local_variables ();
3186 // free in reverse order
3187 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
3188 var local
= local_vars
[i
];
3189 if (!local
.unreachable
&& local
.active
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
3190 ccode
.add_expression (get_unref_expression_ (local
));
3195 int block_id
= get_block_id (b
);
3197 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
3198 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
3199 ccode
.add_expression (data_unref
);
3203 if (b
.parent_node is Loop
||
3204 b
.parent_node is ForeachStatement
||
3205 b
.parent_node is SwitchStatement
) {
3210 if (b
.parent_node
== stop_at
) {
3214 if (sym
.parent_symbol is Block
) {
3215 append_local_free (sym
.parent_symbol
, stop_at_loop
, stop_at
);
3216 } else if (sym
.parent_symbol is Method
) {
3217 append_param_free ((Method
) sym
.parent_symbol
);
3221 private void append_param_free (Method m
) {
3222 foreach (Parameter param
in m
.get_parameters ()) {
3223 if (!param
.ellipsis
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
3224 var ma
= new MemberAccess
.simple (param
.name
);
3225 ma
.symbol_reference
= param
;
3226 ma
.value_type
= param
.variable_type
.copy ();
3227 visit_member_access (ma
);
3228 ccode
.add_expression (get_unref_expression (get_variable_cexpression (param
.name
), param
.variable_type
, ma
));
3233 public bool variable_accessible_in_finally (LocalVariable local
) {
3234 if (current_try
== null) {
3238 var sym
= current_symbol
;
3240 while (!(sym is Method
|| sym is PropertyAccessor
) && sym
.scope
.lookup (local
.name
) == null) {
3241 if ((sym
.parent_node is TryStatement
&& ((TryStatement
) sym
.parent_node
).finally_body
!= null) ||
3242 (sym
.parent_node is CatchClause
&& ((TryStatement
) sym
.parent_node
.parent_node
).finally_body
!= null)) {
3247 sym
= sym
.parent_symbol
;
3253 void return_out_parameter (Parameter param
) {
3254 var delegate_type
= param
.variable_type as DelegateType
;
3256 ccode
.open_if (get_variable_cexpression (param
.name
));
3257 ccode
.add_expression (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (param
.name
)), get_variable_cexpression ("_" + param
.name
)));
3259 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
3260 ccode
.add_expression (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_delegate_target_cname (param
.name
))), new
CCodeIdentifier (get_delegate_target_cname (get_variable_cname ("_" + param
.name
)))));
3261 if (delegate_type
.value_owned
) {
3262 ccode
.add_expression (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_delegate_target_destroy_notify_cname (param
.name
))), new
CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname ("_" + param
.name
)))));
3266 if (param
.variable_type
.is_disposable ()){
3268 var ma
= new
MemberAccess (null, param
.name
);
3269 ma
.symbol_reference
= param
;
3270 ma
.value_type
= param
.variable_type
.copy ();
3271 visit_member_access (ma
);
3272 ccode
.add_expression (get_unref_expression (get_variable_cexpression ("_" + param
.name
), param
.variable_type
, ma
));
3276 var array_type
= param
.variable_type as ArrayType
;
3277 if (array_type
!= null && !array_type
.fixed_length
&& !param
.no_array_length
) {
3278 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3279 ccode
.open_if (get_variable_cexpression (get_parameter_array_length_cname (param
, dim
)));
3280 ccode
.add_expression (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (get_parameter_array_length_cname (param
, dim
))), new
CCodeIdentifier (get_array_length_cname (get_variable_cname ("_" + param
.name
), dim
))));
3286 public override void visit_return_statement (ReturnStatement stmt
) {
3287 Symbol return_expression_symbol
= null;
3289 if (stmt
.return_expression
!= null) {
3290 // avoid unnecessary ref/unref pair
3291 var local
= stmt
.return_expression
.symbol_reference as LocalVariable
;
3292 if (current_return_type
.value_owned
3293 && local
!= null && local
.variable_type
.value_owned
3295 && !variable_accessible_in_finally (local
)) {
3296 /* return expression is local variable taking ownership and
3297 * current method is transferring ownership */
3299 return_expression_symbol
= local
;
3303 // return array length if appropriate
3304 if (((current_method
!= null && !current_method
.no_array_length
) || current_property_accessor
!= null) && current_return_type is ArrayType
) {
3305 var return_expr_decl
= get_temp_variable (stmt
.return_expression
.value_type
, true, stmt
, false);
3307 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (return_expr_decl
.name
), get_cvalue (stmt
.return_expression
)));
3309 var array_type
= (ArrayType
) current_return_type
;
3311 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3312 var len_l
= get_result_cexpression (get_array_length_cname ("result", dim
));
3313 if (current_method
== null || !current_method
.coroutine
) {
3314 len_l
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, len_l
);
3316 var len_r
= get_array_length_cexpression (stmt
.return_expression
, dim
);
3317 ccode
.add_expression (new
CCodeAssignment (len_l
, len_r
));
3320 set_cvalue (stmt
.return_expression
, get_variable_cexpression (return_expr_decl
.name
));
3322 emit_temp_var (return_expr_decl
);
3323 } else if ((current_method
!= null || current_property_accessor
!= null) && current_return_type is DelegateType
) {
3324 var delegate_type
= (DelegateType
) current_return_type
;
3325 if (delegate_type
.delegate_symbol
.has_target
) {
3326 var return_expr_decl
= get_temp_variable (stmt
.return_expression
.value_type
, true, stmt
, false);
3328 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (return_expr_decl
.name
), get_cvalue (stmt
.return_expression
)));
3330 var target_l
= get_result_cexpression (get_delegate_target_cname ("result"));
3331 if (current_method
== null || !current_method
.coroutine
) {
3332 target_l
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_l
);
3334 CCodeExpression target_r_destroy_notify
;
3335 var target_r
= get_delegate_target_cexpression (stmt
.return_expression
, out target_r_destroy_notify
);
3336 ccode
.add_expression (new
CCodeAssignment (target_l
, target_r
));
3337 if (delegate_type
.value_owned
) {
3338 var target_l_destroy_notify
= get_result_cexpression (get_delegate_target_destroy_notify_cname ("result"));
3339 if (current_method
== null || !current_method
.coroutine
) {
3340 target_l_destroy_notify
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, target_l_destroy_notify
);
3342 ccode
.add_expression (new
CCodeAssignment (target_l_destroy_notify
, target_r_destroy_notify
));
3345 set_cvalue (stmt
.return_expression
, get_variable_cexpression (return_expr_decl
.name
));
3347 emit_temp_var (return_expr_decl
);
3351 if (stmt
.return_expression
!= null) {
3352 // assign method result to `result'
3353 CCodeExpression result_lhs
= get_result_cexpression ();
3354 if (current_return_type
.is_real_non_null_struct_type () && (current_method
== null || !current_method
.coroutine
)) {
3355 result_lhs
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, result_lhs
);
3357 ccode
.add_expression (new
CCodeAssignment (result_lhs
, get_cvalue (stmt
.return_expression
)));
3360 // free local variables
3361 append_local_free (current_symbol
);
3363 if (current_method
!= null) {
3364 // check postconditions
3365 foreach (Expression postcondition
in current_method
.get_postconditions ()) {
3366 create_postcondition_statement (postcondition
);
3370 if (current_method
!= null && !current_method
.coroutine
) {
3371 // assign values to output parameters if they are not NULL
3372 // otherwise, free the value if necessary
3373 foreach (var param
in current_method
.get_parameters ()) {
3374 if (param
.direction
!= ParameterDirection
.OUT
) {
3378 return_out_parameter (param
);
3382 if (is_in_constructor ()) {
3383 ccode
.add_return (new
CCodeIdentifier ("obj"));
3384 } else if (is_in_destructor ()) {
3385 // do not call return as member cleanup and chain up to base finalizer
3386 // stil need to be executed
3387 ccode
.add_goto ("_return");
3388 } else if (current_method is CreationMethod
) {
3389 ccode
.add_return (new
CCodeIdentifier ("self"));
3390 } else if (current_method
!= null && current_method
.coroutine
) {
3391 } else if (current_return_type is VoidType
|| current_return_type
.is_real_non_null_struct_type ()) {
3392 // structs are returned via out parameter
3393 ccode
.add_return ();
3395 ccode
.add_return (new
CCodeIdentifier ("result"));
3398 if (return_expression_symbol
!= null) {
3399 return_expression_symbol
.active
= true;
3402 // required for destructors
3403 current_method_return
= true;
3406 public string get_symbol_lock_name (string symname
) {
3407 return "__lock_%s".printf (symname
);
3410 private CCodeExpression
get_lock_expression (Statement stmt
, Expression resource
) {
3411 CCodeExpression l
= null;
3412 var inner_node
= ((MemberAccess
)resource
).inner
;
3413 var member
= resource
.symbol_reference
;
3414 var parent
= (TypeSymbol
)resource
.symbol_reference
.parent_symbol
;
3416 if (member
.is_instance_member ()) {
3417 if (inner_node
== null) {
3418 l
= new
CCodeIdentifier ("self");
3419 } else if (resource
.symbol_reference
.parent_symbol
!= current_type_symbol
) {
3420 l
= generate_instance_cast (get_cvalue (inner_node
), parent
);
3422 l
= get_cvalue (inner_node
);
3425 l
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (l
, "priv"), get_symbol_lock_name (resource
.symbol_reference
.name
));
3426 } else if (member
.is_class_member ()) {
3427 CCodeExpression klass
;
3429 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
||
3430 current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
||
3431 (in_constructor
&& !in_static_or_class_context
)) {
3432 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
3433 k
.add_argument (new
CCodeIdentifier ("self"));
3436 klass
= new
CCodeIdentifier ("klass");
3439 var get_class_private_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent
.get_upper_case_cname ())));
3440 get_class_private_call
.add_argument (klass
);
3441 l
= new CCodeMemberAccess
.pointer (get_class_private_call
, get_symbol_lock_name (resource
.symbol_reference
.name
));
3443 string lock_name
= "%s_%s".printf(parent
.get_lower_case_cname (), resource
.symbol_reference
.name
);
3444 l
= new
CCodeIdentifier (get_symbol_lock_name (lock_name
));
3449 public override void visit_lock_statement (LockStatement stmt
) {
3450 var l
= get_lock_expression (stmt
, stmt
.resource
);
3452 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier (((Method
) mutex_type
.scope
.lookup ("lock")).get_cname ()));
3453 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
3455 ccode
.add_expression (fc
);
3458 public override void visit_unlock_statement (UnlockStatement stmt
) {
3459 var l
= get_lock_expression (stmt
, stmt
.resource
);
3461 var fc
= new
CCodeFunctionCall (new
CCodeIdentifier (((Method
) mutex_type
.scope
.lookup ("unlock")).get_cname ()));
3462 fc
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, l
));
3464 ccode
.add_expression (fc
);
3467 public override void visit_delete_statement (DeleteStatement stmt
) {
3468 var pointer_type
= (PointerType
) stmt
.expression
.value_type
;
3469 DataType type
= pointer_type
;
3470 if (pointer_type
.base_type
.data_type
!= null && pointer_type
.base_type
.data_type
.is_reference_type ()) {
3471 type
= pointer_type
.base_type
;
3474 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
3475 ccall
.add_argument (get_cvalue (stmt
.expression
));
3476 ccode
.add_expression (ccall
);
3479 public override void visit_expression (Expression expr
) {
3480 if (get_cvalue (expr
) != null && !expr
.lvalue
) {
3481 if (expr
.formal_value_type is GenericType
&& !(expr
.value_type is GenericType
)) {
3482 var st
= expr
.formal_value_type
.type_parameter
.parent_symbol
.parent_symbol as Struct
;
3483 if (expr
.formal_value_type
.type_parameter
.parent_symbol
!= garray_type
&&
3484 (st
== null || st
.get_cname () != "va_list")) {
3485 // GArray and va_list don't use pointer-based generics
3486 set_cvalue (expr
, convert_from_generic_pointer (get_cvalue (expr
), expr
.value_type
));
3490 // memory management, implicit casts, and boxing/unboxing
3491 set_cvalue (expr
, transform_expression (get_cvalue (expr
), expr
.value_type
, expr
.target_type
, expr
));
3493 if (expr
.formal_target_type is GenericType
&& !(expr
.target_type is GenericType
)) {
3494 if (expr
.formal_target_type
.type_parameter
.parent_symbol
!= garray_type
) {
3495 // GArray doesn't use pointer-based generics
3496 set_cvalue (expr
, convert_to_generic_pointer (get_cvalue (expr
), expr
.target_type
));
3502 public override void visit_boolean_literal (BooleanLiteral expr
) {
3503 if (context
.profile
== Profile
.GOBJECT
) {
3504 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"TRUE" : "FALSE"));
3506 cfile
.add_include ("stdbool.h");
3507 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"true" : "false"));
3511 public override void visit_character_literal (CharacterLiteral expr
) {
3512 if (expr
.get_char () >= 0x20 && expr
.get_char () < 0x80) {
3513 set_cvalue (expr
, new
CCodeConstant (expr
.value
));
3515 set_cvalue (expr
, new
CCodeConstant ("%uU".printf (expr
.get_char ())));
3519 public override void visit_integer_literal (IntegerLiteral expr
) {
3520 set_cvalue (expr
, new
CCodeConstant (expr
.value
+ expr
.type_suffix
));
3523 public override void visit_real_literal (RealLiteral expr
) {
3524 string c_literal
= expr
.value
;
3525 if (c_literal
.has_suffix ("d") || c_literal
.has_suffix ("D")) {
3526 // there is no suffix for double in C
3527 c_literal
= c_literal
.substring (0, c_literal
.length
- 1);
3529 if (!("." in c_literal
|| "e" in c_literal
|| "E" in c_literal
)) {
3530 // C requires period or exponent part for floating constants
3531 if ("f" in c_literal
|| "F" in c_literal
) {
3532 c_literal
= c_literal
.substring (0, c_literal
.length
- 1) + ".f";
3537 set_cvalue (expr
, new
CCodeConstant (c_literal
));
3540 public override void visit_string_literal (StringLiteral expr
) {
3541 set_cvalue (expr
, new CCodeConstant
.string (expr
.value
.replace ("\n", "\\n")));
3544 public override void visit_regex_literal (RegexLiteral expr
) {
3545 string[] parts
= expr
.value
.split ("/", 3);
3546 string re
= parts
[2].escape ("");
3549 if (parts
[1].contains ("i")) {
3550 flags
+= " | G_REGEX_CASELESS";
3552 if (parts
[1].contains ("m")) {
3553 flags
+= " | G_REGEX_MULTILINE";
3555 if (parts
[1].contains ("s")) {
3556 flags
+= " | G_REGEX_DOTALL";
3558 if (parts
[1].contains ("x")) {
3559 flags
+= " | G_REGEX_EXTENDED";
3562 var regex_var
= get_temp_variable (regex_type
, true, expr
, false);
3563 emit_temp_var (regex_var
);
3565 var cdecl
= new
CCodeDeclaration ("GRegex*");
3567 var cname
= regex_var
.name
+ "regex_" + next_regex_id
.to_string ();
3568 if (this
.next_regex_id
== 0) {
3569 var fun
= new
CCodeFunction ("_thread_safe_regex_init", "GRegex*");
3570 fun
.modifiers
= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
3571 fun
.add_parameter (new
CCodeParameter ("re", "GRegex**"));
3572 fun
.add_parameter (new
CCodeParameter ("pattern", "const gchar *"));
3573 fun
.add_parameter (new
CCodeParameter ("match_options", "GRegexMatchFlags"));
3575 push_function (fun
);
3577 var once_enter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_once_init_enter"));
3578 once_enter_call
.add_argument (new
CCodeConstant ("(volatile gsize*) re"));
3579 ccode
.open_if (once_enter_call
);
3581 var regex_new_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_regex_new"));
3582 regex_new_call
.add_argument (new
CCodeConstant ("pattern"));
3583 regex_new_call
.add_argument (new
CCodeConstant ("match_options"));
3584 regex_new_call
.add_argument (new
CCodeConstant ("0"));
3585 regex_new_call
.add_argument (new
CCodeConstant ("NULL"));
3586 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("GRegex* val"), regex_new_call
));
3588 var once_leave_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_once_init_leave"));
3589 once_leave_call
.add_argument (new
CCodeConstant ("(volatile gsize*) re"));
3590 once_leave_call
.add_argument (new
CCodeConstant ("(gsize) val"));
3591 ccode
.add_expression (once_leave_call
);
3595 ccode
.add_return (new
CCodeIdentifier ("*re"));
3599 cfile
.add_function (fun
);
3601 this
.next_regex_id
++;
3603 cdecl
.add_declarator (new
CCodeVariableDeclarator (cname
+ " = NULL"));
3604 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
3606 var regex_const
= new
CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname
, re
, flags
));
3608 cfile
.add_constant_declaration (cdecl
);
3609 set_cvalue (expr
, regex_const
);
3612 public override void visit_null_literal (NullLiteral expr
) {
3613 if (context
.profile
!= Profile
.GOBJECT
) {
3614 cfile
.add_include ("stddef.h");
3616 set_cvalue (expr
, new
CCodeConstant ("NULL"));
3618 var array_type
= expr
.target_type as ArrayType
;
3619 var delegate_type
= expr
.target_type as DelegateType
;
3620 if (array_type
!= null) {
3621 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3622 append_array_size (expr
, new
CCodeConstant ("0"));
3624 } else if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
3625 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
3626 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
3630 public virtual TargetValue
get_variable_cvalue (Variable variable
, CCodeExpression? inner
= null) {
3631 assert_not_reached ();
3634 public virtual string get_delegate_target_cname (string delegate_cname
) {
3635 assert_not_reached ();
3638 public virtual CCodeExpression
get_delegate_target_cexpression (Expression delegate_expr
, out CCodeExpression delegate_target_destroy_notify
) {
3639 assert_not_reached ();
3642 public virtual CCodeExpression
get_delegate_target_cvalue (TargetValue value
) {
3643 return new
CCodeInvalidExpression ();
3646 public virtual CCodeExpression
get_delegate_target_destroy_notify_cvalue (TargetValue value
) {
3647 return new
CCodeInvalidExpression ();
3650 public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname
) {
3651 assert_not_reached ();
3654 public override void visit_base_access (BaseAccess expr
) {
3655 CCodeExpression this_access
;
3656 if (current_method
!= null && current_method
.coroutine
) {
3658 this_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "self");
3660 this_access
= new
CCodeIdentifier ("self");
3663 set_cvalue (expr
, generate_instance_cast (this_access
, expr
.value_type
.data_type
));
3666 public override void visit_postfix_expression (PostfixExpression expr
) {
3667 MemberAccess ma
= find_property_access (expr
.inner
);
3669 // property postfix expression
3670 var prop
= (Property
) ma
.symbol_reference
;
3672 // assign current value to temp variable
3673 var temp_decl
= get_temp_variable (prop
.property_type
, true, expr
, false);
3674 emit_temp_var (temp_decl
);
3675 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_decl
.name
), get_cvalue (expr
.inner
)));
3677 // increment/decrement property
3678 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
3679 var cexpr
= new
CCodeBinaryExpression (op
, get_variable_cexpression (temp_decl
.name
), new
CCodeConstant ("1"));
3680 store_property (prop
, ma
.inner
, new
GLibValue (expr
.value_type
, cexpr
));
3682 // return previous value
3683 set_cvalue (expr
, get_variable_cexpression (temp_decl
.name
));
3687 if (expr
.parent_node is ExpressionStatement
) {
3688 var op
= expr
.increment ? CCodeUnaryOperator
.POSTFIX_INCREMENT
: CCodeUnaryOperator
.POSTFIX_DECREMENT
;
3690 ccode
.add_expression (new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
3692 // assign current value to temp variable
3693 var temp_decl
= get_temp_variable (expr
.inner
.value_type
, true, expr
, false);
3694 emit_temp_var (temp_decl
);
3695 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_decl
.name
), get_cvalue (expr
.inner
)));
3697 // increment/decrement variable
3698 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
3699 var cexpr
= new
CCodeBinaryExpression (op
, get_variable_cexpression (temp_decl
.name
), new
CCodeConstant ("1"));
3700 ccode
.add_expression (new
CCodeAssignment (get_cvalue (expr
.inner
), cexpr
));
3702 // return previous value
3703 set_cvalue (expr
, get_variable_cexpression (temp_decl
.name
));
3707 private MemberAccess?
find_property_access (Expression expr
) {
3708 if (!(expr is MemberAccess
)) {
3712 var ma
= (MemberAccess
) expr
;
3713 if (ma
.symbol_reference is Property
) {
3720 bool is_limited_generic_type (DataType type
) {
3721 var cl
= type
.type_parameter
.parent_symbol as Class
;
3722 var st
= type
.type_parameter
.parent_symbol as Struct
;
3723 if ((cl
!= null && cl
.is_compact
) || st
!= null) {
3724 // compact classes and structs only
3725 // have very limited generics support
3731 public bool requires_copy (DataType type
) {
3732 if (!type
.is_disposable ()) {
3736 var cl
= type
.data_type as Class
;
3737 if (cl
!= null && cl
.is_reference_counting ()
3738 && cl
.get_ref_function () == "") {
3739 // empty ref_function => no ref necessary
3743 if (type
.type_parameter
!= null) {
3744 if (is_limited_generic_type (type
)) {
3752 public bool requires_destroy (DataType type
) {
3753 if (!type
.is_disposable ()) {
3757 var array_type
= type as ArrayType
;
3758 if (array_type
!= null && array_type
.fixed_length
) {
3759 return requires_destroy (array_type
.element_type
);
3762 var cl
= type
.data_type as Class
;
3763 if (cl
!= null && cl
.is_reference_counting ()
3764 && cl
.get_unref_function () == "") {
3765 // empty unref_function => no unref necessary
3769 if (type
.type_parameter
!= null) {
3770 if (is_limited_generic_type (type
)) {
3778 bool is_ref_function_void (DataType type
) {
3779 var cl
= type
.data_type as Class
;
3780 if (cl
!= null && cl
.ref_function_void
) {
3787 public virtual CCodeExpression?
get_ref_cexpression (DataType expression_type
, CCodeExpression cexpr
, Expression? expr
, CodeNode node
) {
3788 if (expression_type is DelegateType
) {
3792 if (expression_type is ValueType
&& !expression_type
.nullable
) {
3793 // normal value type, no null check
3794 // (copy (&expr, &temp), temp)
3796 var decl
= get_temp_variable (expression_type
, false, node
);
3797 emit_temp_var (decl
);
3799 var ctemp
= get_variable_cexpression (decl
.name
);
3801 var vt
= (ValueType
) expression_type
;
3802 var st
= (Struct
) vt
.type_symbol
;
3803 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_copy_function ()));
3804 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3805 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
3807 if (!st
.has_copy_function
) {
3808 generate_struct_copy_function (st
);
3811 var ccomma
= new
CCodeCommaExpression ();
3813 if (st
.get_copy_function () == "g_value_copy") {
3814 // GValue requires g_value_init in addition to g_value_copy
3816 var value_type_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VALUE_TYPE"));
3817 value_type_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3819 var init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
3820 init_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
3821 init_call
.add_argument (value_type_call
);
3823 ccomma
.append_expression (init_call
);
3826 ccomma
.append_expression (copy_call
);
3827 ccomma
.append_expression (ctemp
);
3829 if (gvalue_type
!= null && expression_type
.data_type
== gvalue_type
) {
3830 // g_value_init/copy must not be called for uninitialized values
3831 var cisvalid
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_VALUE"));
3832 cisvalid
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
3834 return new
CCodeConditionalExpression (cisvalid
, ccomma
, cexpr
);
3840 /* (temp = expr, temp == NULL ? NULL : ref (temp))
3842 * can be simplified to
3844 * if static type of expr is non-null
3847 var dupexpr
= get_dup_func_expression (expression_type
, node
.source_reference
);
3849 if (dupexpr
== null) {
3854 if (dupexpr is CCodeIdentifier
&& !(expression_type is ArrayType
) && !(expression_type is GenericType
) && !is_ref_function_void (expression_type
)) {
3855 // generate and call NULL-aware ref function to reduce number
3856 // of temporary variables and simplify code
3858 var dupid
= (CCodeIdentifier
) dupexpr
;
3859 string dup0_func
= "_%s0".printf (dupid
.name
);
3861 // g_strdup is already NULL-safe
3862 if (dupid
.name
== "g_strdup") {
3863 dup0_func
= dupid
.name
;
3864 } else if (add_wrapper (dup0_func
)) {
3865 string pointer_cname
= "gpointer";
3866 if (context
.profile
== Profile
.POSIX
) {
3867 pointer_cname
= "void*";
3869 var dup0_fun
= new
CCodeFunction (dup0_func
, pointer_cname
);
3870 dup0_fun
.add_parameter (new
CCodeParameter ("self", pointer_cname
));
3871 dup0_fun
.modifiers
= CCodeModifiers
.STATIC
;
3873 push_function (dup0_fun
);
3875 var dup_call
= new
CCodeFunctionCall (dupexpr
);
3876 dup_call
.add_argument (new
CCodeIdentifier ("self"));
3878 ccode
.add_return (new
CCodeConditionalExpression (new
CCodeIdentifier ("self"), dup_call
, new
CCodeConstant ("NULL")));
3882 cfile
.add_function (dup0_fun
);
3885 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (dup0_func
));
3886 ccall
.add_argument (cexpr
);
3890 var ccall
= new
CCodeFunctionCall (dupexpr
);
3892 if (!(expression_type is ArrayType
) && expr
!= null && expr
.is_non_null ()
3893 && !is_ref_function_void (expression_type
)) {
3894 // expression is non-null
3895 ccall
.add_argument (get_cvalue (expr
));
3899 var decl
= get_temp_variable (expression_type
, false, node
, false);
3900 emit_temp_var (decl
);
3902 var ctemp
= get_variable_cexpression (decl
.name
);
3904 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, new
CCodeConstant ("NULL"));
3905 if (expression_type
.type_parameter
!= null) {
3906 // dup functions are optional for type parameters
3907 var cdupisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_dup_func_expression (expression_type
, node
.source_reference
), new
CCodeConstant ("NULL"));
3908 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cdupisnull
);
3911 if (expression_type
.type_parameter
!= null) {
3912 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
3913 ccall
.add_argument (new
CCodeCastExpression (ctemp
, "gpointer"));
3915 ccall
.add_argument (ctemp
);
3918 if (expression_type is ArrayType
) {
3919 var array_type
= (ArrayType
) expression_type
;
3921 CCodeExpression csizeexpr
= null;
3922 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
3924 csizeexpr
= get_array_length_cexpression (expr
, dim
);
3927 csizeexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeexpr
, get_array_length_cexpression (expr
, dim
));
3931 ccall
.add_argument (csizeexpr
);
3933 if (array_type
.element_type is GenericType
) {
3934 var elem_dupexpr
= get_dup_func_expression (array_type
.element_type
, node
.source_reference
);
3935 if (elem_dupexpr
== null) {
3936 elem_dupexpr
= new
CCodeConstant ("NULL");
3938 ccall
.add_argument (elem_dupexpr
);
3942 var ccomma
= new
CCodeCommaExpression ();
3943 ccomma
.append_expression (new
CCodeAssignment (ctemp
, cexpr
));
3945 CCodeExpression cifnull
;
3946 if (expression_type
.data_type
!= null) {
3947 cifnull
= new
CCodeConstant ("NULL");
3949 // the value might be non-null even when the dup function is null,
3950 // so we may not just use NULL for type parameters
3952 // cast from gconstpointer to gpointer as methods in
3953 // generic classes may not return gconstpointer
3954 cifnull
= new
CCodeCastExpression (ctemp
, "gpointer");
3956 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, cifnull
, ccall
));
3958 // repeat temp variable at the end of the comma expression
3959 // if the ref function returns void
3960 if (is_ref_function_void (expression_type
)) {
3961 ccomma
.append_expression (ctemp
);
3968 bool is_reference_type_argument (DataType type_arg
) {
3969 if (type_arg is ErrorType
|| (type_arg
.data_type
!= null && type_arg
.data_type
.is_reference_type ())) {
3976 bool is_nullable_value_type_argument (DataType type_arg
) {
3977 if (type_arg is ValueType
&& type_arg
.nullable
) {
3984 bool is_signed_integer_type_argument (DataType type_arg
) {
3985 var st
= type_arg
.data_type as Struct
;
3986 if (type_arg
.nullable
) {
3988 } else if (st
== bool_type
.data_type
) {
3990 } else if (st
== char_type
.data_type
) {
3992 } else if (unichar_type
!= null && st
== unichar_type
.data_type
) {
3994 } else if (st
== short_type
.data_type
) {
3996 } else if (st
== int_type
.data_type
) {
3998 } else if (st
== long_type
.data_type
) {
4000 } else if (st
== int8_type
.data_type
) {
4002 } else if (st
== int16_type
.data_type
) {
4004 } else if (st
== int32_type
.data_type
) {
4006 } else if (st
== gtype_type
) {
4008 } else if (type_arg is EnumValueType
) {
4015 bool is_unsigned_integer_type_argument (DataType type_arg
) {
4016 var st
= type_arg
.data_type as Struct
;
4017 if (type_arg
.nullable
) {
4019 } else if (st
== uchar_type
.data_type
) {
4021 } else if (st
== ushort_type
.data_type
) {
4023 } else if (st
== uint_type
.data_type
) {
4025 } else if (st
== ulong_type
.data_type
) {
4027 } else if (st
== uint8_type
.data_type
) {
4029 } else if (st
== uint16_type
.data_type
) {
4031 } else if (st
== uint32_type
.data_type
) {
4038 public void check_type (DataType type
) {
4039 var array_type
= type as ArrayType
;
4040 if (array_type
!= null) {
4041 check_type (array_type
.element_type
);
4042 if (array_type
.element_type is ArrayType
) {
4043 Report
.error (type
.source_reference
, "Stacked arrays are not supported");
4044 } else if (array_type
.element_type is DelegateType
) {
4045 var delegate_type
= (DelegateType
) array_type
.element_type
;
4046 if (delegate_type
.delegate_symbol
.has_target
) {
4047 Report
.error (type
.source_reference
, "Delegates with target are not supported as array element type");
4051 foreach (var type_arg
in type
.get_type_arguments ()) {
4052 check_type (type_arg
);
4053 check_type_argument (type_arg
);
4057 void check_type_argument (DataType type_arg
) {
4058 if (type_arg is GenericType
4059 || type_arg is PointerType
4060 || is_reference_type_argument (type_arg
)
4061 || is_nullable_value_type_argument (type_arg
)
4062 || is_signed_integer_type_argument (type_arg
)
4063 || is_unsigned_integer_type_argument (type_arg
)) {
4065 } else if (type_arg is DelegateType
) {
4066 var delegate_type
= (DelegateType
) type_arg
;
4067 if (delegate_type
.delegate_symbol
.has_target
) {
4068 Report
.error (type_arg
.source_reference
, "Delegates with target are not supported as generic type arguments");
4071 Report
.error (type_arg
.source_reference
, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg
.to_string ()));
4075 public virtual void generate_class_declaration (Class cl
, CCodeFile decl_space
) {
4076 if (add_symbol_declaration (decl_space
, cl
, cl
.get_cname ())) {
4081 public virtual void generate_interface_declaration (Interface iface
, CCodeFile decl_space
) {
4084 public virtual void generate_method_declaration (Method m
, CCodeFile decl_space
) {
4087 public virtual void generate_error_domain_declaration (ErrorDomain edomain
, CCodeFile decl_space
) {
4090 public void add_generic_type_arguments (Map
<int,CCodeExpression
> arg_map
, List
<DataType
> type_args
, CodeNode expr
, bool is_chainup
= false) {
4091 int type_param_index
= 0;
4092 foreach (var type_arg
in type_args
) {
4093 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), get_type_id_expression (type_arg
, is_chainup
));
4094 if (requires_copy (type_arg
)) {
4095 var dup_func
= get_dup_func_expression (type_arg
, type_arg
.source_reference
, is_chainup
);
4096 if (dup_func
== null) {
4097 // type doesn't contain a copy function
4101 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeCastExpression (dup_func
, "GBoxedCopyFunc"));
4102 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), get_destroy_func_expression (type_arg
, is_chainup
));
4104 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeConstant ("NULL"));
4105 arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeConstant ("NULL"));
4111 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
4112 CCodeExpression instance
= null;
4113 CCodeExpression creation_expr
= null;
4115 check_type (expr
.type_reference
);
4117 var st
= expr
.type_reference
.data_type as Struct
;
4118 if ((st
!= null && (!st
.is_simple_type () || st
.get_cname () == "va_list")) || expr
.get_object_initializer ().size
> 0) {
4119 // value-type initialization or object creation expression with object initializer
4121 var local
= expr
.parent_node as LocalVariable
;
4122 if (local
!= null && has_simple_struct_initializer (local
)) {
4123 if (local
.captured
) {
4124 var block
= (Block
) local
.parent_symbol
;
4125 instance
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), get_variable_cname (local
.name
));
4127 instance
= get_variable_cexpression (get_variable_cname (local
.name
));
4130 var temp_decl
= get_temp_variable (expr
.type_reference
, false, expr
);
4131 emit_temp_var (temp_decl
);
4133 instance
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
4137 if (expr
.symbol_reference
== null) {
4138 // no creation method
4139 if (expr
.type_reference
.data_type is Struct
) {
4140 // memset needs string.h
4141 cfile
.add_include ("string.h");
4142 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
4143 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4144 creation_call
.add_argument (new
CCodeConstant ("0"));
4145 creation_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (expr
.type_reference
.get_cname ())));
4147 creation_expr
= creation_call
;
4149 } else if (expr
.type_reference
.data_type
== glist_type
||
4150 expr
.type_reference
.data_type
== gslist_type
) {
4151 // NULL is an empty list
4152 set_cvalue (expr
, new
CCodeConstant ("NULL"));
4153 } else if (expr
.symbol_reference is Method
) {
4154 // use creation method
4155 var m
= (Method
) expr
.symbol_reference
;
4156 var params
= m
.get_parameters ();
4157 CCodeFunctionCall creation_call
;
4159 generate_method_declaration (m
, cfile
);
4161 var cl
= expr
.type_reference
.data_type as Class
;
4163 if (!m
.has_new_function
) {
4164 // use construct function directly
4165 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
4166 creation_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
4168 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_cname ()));
4171 if ((st
!= null && !st
.is_simple_type ()) && !(m
.cinstance_parameter_position
< 0)) {
4172 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4173 } else if (st
!= null && st
.get_cname () == "va_list") {
4174 creation_call
.add_argument (instance
);
4175 if (m
.get_cname () == "va_start") {
4176 Parameter last_param
= null;
4177 foreach (var param
in current_method
.get_parameters ()) {
4178 if (param
.ellipsis
) {
4183 creation_call
.add_argument (new
CCodeIdentifier (get_variable_cname (last_param
.name
)));
4187 generate_type_declaration (expr
.type_reference
, cfile
);
4189 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
4191 if (cl
!= null && !cl
.is_compact
) {
4192 add_generic_type_arguments (carg_map
, expr
.type_reference
.get_type_arguments (), expr
);
4193 } else if (cl
!= null && m
.simple_generics
) {
4194 int type_param_index
= 0;
4195 foreach (var type_arg
in expr
.type_reference
.get_type_arguments ()) {
4196 if (requires_copy (type_arg
)) {
4197 carg_map
.set (get_param_pos (-1 + 0.1 * type_param_index
+ 0.03), get_destroy0_func_expression (type_arg
));
4199 carg_map
.set (get_param_pos (-1 + 0.1 * type_param_index
+ 0.03), new
CCodeConstant ("NULL"));
4205 bool ellipsis
= false;
4209 Iterator
<Parameter
> params_it
= params
.iterator ();
4210 foreach (Expression arg
in expr
.get_argument_list ()) {
4211 CCodeExpression cexpr
= get_cvalue (arg
);
4212 Parameter param
= null;
4213 if (params_it
.next ()) {
4214 param
= params_it
.get ();
4215 ellipsis
= param
.ellipsis
;
4217 if (!param
.no_array_length
&& param
.variable_type is ArrayType
) {
4218 var array_type
= (ArrayType
) param
.variable_type
;
4219 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4220 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), get_array_length_cexpression (arg
, dim
));
4222 } else if (param
.variable_type is DelegateType
) {
4223 var deleg_type
= (DelegateType
) param
.variable_type
;
4224 var d
= deleg_type
.delegate_symbol
;
4226 CCodeExpression delegate_target_destroy_notify
;
4227 var delegate_target
= get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
);
4228 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), delegate_target
);
4229 if (deleg_type
.value_owned
) {
4230 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
+ 0.01), delegate_target_destroy_notify
);
4235 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
4237 if (param
.ctype
!= null) {
4238 cexpr
= new
CCodeCastExpression (cexpr
, param
.ctype
);
4241 cexpr
= handle_struct_argument (null, arg
, cexpr
);
4244 arg_pos
= get_param_pos (param
.cparameter_position
, ellipsis
);
4246 // default argument position
4247 cexpr
= handle_struct_argument (null, arg
, cexpr
);
4248 arg_pos
= get_param_pos (i
, ellipsis
);
4251 carg_map
.set (arg_pos
, cexpr
);
4255 while (params_it
.next ()) {
4256 var param
= params_it
.get ();
4258 if (param
.ellipsis
) {
4263 if (param
.initializer
== null) {
4264 Report
.error (expr
.source_reference
, "no default expression for argument %d".printf (i
));
4268 /* evaluate default expression here as the code
4269 * generator might not have visited the formal
4271 param
.initializer
.emit (this
);
4273 carg_map
.set (get_param_pos (param
.cparameter_position
), get_cvalue (param
.initializer
));
4277 // append C arguments in the right order
4282 foreach (int pos
in carg_map
.get_keys ()) {
4283 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
4287 if (min_pos
== -1) {
4290 creation_call
.add_argument (carg_map
.get (min_pos
));
4294 if ((st
!= null && !st
.is_simple_type ()) && m
.cinstance_parameter_position
< 0) {
4295 // instance parameter is at the end in a struct creation method
4296 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
4299 if (expr
.tree_can_fail
) {
4301 current_method_inner_error
= true;
4302 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression ("_inner_error_")));
4306 /* ensure variable argument list ends with NULL
4307 * except when using printf-style arguments */
4308 if (!m
.printf_format
&& !m
.scanf_format
&& m
.sentinel
!= "") {
4309 creation_call
.add_argument (new
CCodeConstant (m
.sentinel
));
4313 creation_expr
= creation_call
;
4315 // cast the return value of the creation method back to the intended type if
4316 // it requested a special C return type
4317 if (get_custom_creturn_type (m
) != null) {
4318 creation_expr
= new
CCodeCastExpression (creation_expr
, expr
.type_reference
.get_cname ());
4320 } else if (expr
.symbol_reference is ErrorCode
) {
4321 var ecode
= (ErrorCode
) expr
.symbol_reference
;
4322 var edomain
= (ErrorDomain
) ecode
.parent_symbol
;
4323 CCodeFunctionCall creation_call
;
4325 generate_error_domain_declaration (edomain
, cfile
);
4327 if (expr
.get_argument_list ().size
== 1) {
4328 // must not be a format argument
4329 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_new_literal"));
4331 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_new"));
4333 creation_call
.add_argument (new
CCodeIdentifier (edomain
.get_upper_case_cname ()));
4334 creation_call
.add_argument (new
CCodeIdentifier (ecode
.get_cname ()));
4336 foreach (Expression arg
in expr
.get_argument_list ()) {
4337 creation_call
.add_argument (get_cvalue (arg
));
4340 creation_expr
= creation_call
;
4345 var local
= expr
.parent_node as LocalVariable
;
4346 if (local
!= null && has_simple_struct_initializer (local
)) {
4347 // no temporary variable necessary
4348 set_cvalue (expr
, creation_expr
);
4350 } else if (instance
!= null) {
4351 if (expr
.type_reference
.data_type is Struct
) {
4352 ccode
.add_expression (creation_expr
);
4354 ccode
.add_expression (new
CCodeAssignment (instance
, creation_expr
));
4357 foreach (MemberInitializer init
in expr
.get_object_initializer ()) {
4358 if (init
.symbol_reference is Field
) {
4359 var f
= (Field
) init
.symbol_reference
;
4360 var instance_target_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
4361 var typed_inst
= transform_expression (instance
, expr
.type_reference
, instance_target_type
);
4362 CCodeExpression lhs
;
4363 if (expr
.type_reference
.data_type is Struct
) {
4364 lhs
= new
CCodeMemberAccess (typed_inst
, f
.get_cname ());
4366 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, f
.get_cname ());
4368 ccode
.add_expression (new
CCodeAssignment (lhs
, get_cvalue (init
.initializer
)));
4370 if (f
.variable_type is ArrayType
&& !f
.no_array_length
) {
4371 var array_type
= (ArrayType
) f
.variable_type
;
4372 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4373 if (expr
.type_reference
.data_type is Struct
) {
4374 lhs
= new
CCodeMemberAccess (typed_inst
, get_array_length_cname (f
.get_cname (), dim
));
4376 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, get_array_length_cname (f
.get_cname (), dim
));
4378 var rhs_array_len
= get_array_length_cexpression (init
.initializer
, dim
);
4379 ccode
.add_expression (new
CCodeAssignment (lhs
, rhs_array_len
));
4381 } else if (f
.variable_type is DelegateType
&& (f
.variable_type as DelegateType
).delegate_symbol
.has_target
&& !f
.no_delegate_target
) {
4382 if (expr
.type_reference
.data_type is Struct
) {
4383 lhs
= new
CCodeMemberAccess (typed_inst
, get_delegate_target_cname (f
.get_cname ()));
4385 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, get_delegate_target_cname (f
.get_cname ()));
4387 CCodeExpression rhs_delegate_target_destroy_notify
;
4388 var rhs_delegate_target
= get_delegate_target_cexpression (init
.initializer
, out rhs_delegate_target_destroy_notify
);
4389 ccode
.add_expression (new
CCodeAssignment (lhs
, rhs_delegate_target
));
4392 var cl
= f
.parent_symbol as Class
;
4394 generate_class_struct_declaration (cl
, cfile
);
4396 } else if (init
.symbol_reference is Property
) {
4397 var inst_ma
= new MemberAccess
.simple ("new");
4398 inst_ma
.value_type
= expr
.type_reference
;
4399 set_cvalue (inst_ma
, instance
);
4400 store_property ((Property
) init
.symbol_reference
, inst_ma
, init
.initializer
.target_value
);
4404 creation_expr
= instance
;
4407 if (creation_expr
!= null) {
4408 var temp_var
= get_temp_variable (expr
.value_type
);
4409 var temp_ref
= get_variable_cexpression (temp_var
.name
);
4411 emit_temp_var (temp_var
);
4413 ccode
.add_expression (new
CCodeAssignment (temp_ref
, creation_expr
));
4414 set_cvalue (expr
, temp_ref
);
4418 public CCodeExpression?
handle_struct_argument (Parameter? param
, Expression arg
, CCodeExpression? cexpr
) {
4420 if (param
!= null) {
4421 type
= param
.variable_type
;
4424 type
= arg
.value_type
;
4427 // pass non-simple struct instances always by reference
4428 if (!(arg
.value_type is NullType
) && type
.is_real_struct_type ()) {
4429 // we already use a reference for arguments of ref, out, and nullable parameters
4430 if ((param
== null || param
.direction
== ParameterDirection
.IN
) && !type
.nullable
) {
4431 var unary
= cexpr as CCodeUnaryExpression
;
4432 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
4435 } else if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
4436 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
4438 // if cexpr is e.g. a function call, we can't take the address of the expression
4439 // (tmp = expr, &tmp)
4440 var ccomma
= new
CCodeCommaExpression ();
4442 var temp_var
= get_temp_variable (type
, true, null, false);
4443 emit_temp_var (temp_var
);
4444 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), cexpr
));
4445 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
)));
4455 public override void visit_sizeof_expression (SizeofExpression expr
) {
4456 generate_type_declaration (expr
.type_reference
, cfile
);
4458 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
4459 csizeof
.add_argument (new
CCodeIdentifier (expr
.type_reference
.get_cname ()));
4460 set_cvalue (expr
, csizeof
);
4463 public override void visit_typeof_expression (TypeofExpression expr
) {
4464 set_cvalue (expr
, get_type_id_expression (expr
.type_reference
));
4467 public override void visit_unary_expression (UnaryExpression expr
) {
4468 if (expr
.operator
== UnaryOperator
.REF
|| expr
.operator
== UnaryOperator
.OUT
) {
4469 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (expr
.inner
)));
4471 var array_type
= expr
.value_type as ArrayType
;
4472 if (array_type
!= null) {
4473 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4474 append_array_size (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_length_cexpression (expr
.inner
, dim
)));
4478 var delegate_type
= expr
.value_type as DelegateType
;
4479 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
4480 CCodeExpression target_destroy_notify
;
4481 set_delegate_target (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_delegate_target_cexpression (expr
.inner
, out target_destroy_notify
)));
4482 if (target_destroy_notify
!= null) {
4483 set_delegate_target_destroy_notify (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, target_destroy_notify
));
4490 CCodeUnaryOperator op
;
4491 if (expr
.operator
== UnaryOperator
.PLUS
) {
4492 op
= CCodeUnaryOperator
.PLUS
;
4493 } else if (expr
.operator
== UnaryOperator
.MINUS
) {
4494 op
= CCodeUnaryOperator
.MINUS
;
4495 } else if (expr
.operator
== UnaryOperator
.LOGICAL_NEGATION
) {
4496 op
= CCodeUnaryOperator
.LOGICAL_NEGATION
;
4497 } else if (expr
.operator
== UnaryOperator
.BITWISE_COMPLEMENT
) {
4498 op
= CCodeUnaryOperator
.BITWISE_COMPLEMENT
;
4499 } else if (expr
.operator
== UnaryOperator
.INCREMENT
) {
4500 op
= CCodeUnaryOperator
.PREFIX_INCREMENT
;
4501 } else if (expr
.operator
== UnaryOperator
.DECREMENT
) {
4502 op
= CCodeUnaryOperator
.PREFIX_DECREMENT
;
4504 assert_not_reached ();
4506 set_cvalue (expr
, new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
4509 public CCodeExpression?
try_cast_value_to_type (CCodeExpression ccodeexpr
, DataType from
, DataType to
, Expression? expr
= null) {
4510 if (from
== null || gvalue_type
== null || from
.data_type
!= gvalue_type
|| to
.get_type_id () == null) {
4514 // explicit conversion from GValue
4515 var ccall
= new
CCodeFunctionCall (get_value_getter_function (to
));
4516 CCodeExpression gvalue
;
4517 if (from
.nullable
) {
4520 gvalue
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ccodeexpr
);
4522 ccall
.add_argument (gvalue
);
4524 CCodeExpression rv
= ccall
;
4526 if (expr
!= null && to is ArrayType
) {
4527 // null-terminated string array
4528 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strv_length"));
4529 len_call
.add_argument (rv
);
4530 append_array_size (expr
, len_call
);
4531 } else if (to is StructValueType
) {
4532 var temp_decl
= get_temp_variable (to
, true, null, true);
4533 emit_temp_var (temp_decl
);
4534 var ctemp
= get_variable_cexpression (temp_decl
.name
);
4536 rv
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeCastExpression (rv
, (new
PointerType(to
)).get_cname ()));
4537 var holds
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VALUE_HOLDS"));
4538 holds
.add_argument (gvalue
);
4539 holds
.add_argument (new
CCodeIdentifier (to
.get_type_id ()));
4540 var cond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, holds
, ccall
);
4541 var warn
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_warning"));
4542 warn
.add_argument (new
CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
4543 var fail
= new
CCodeCommaExpression ();
4544 fail
.append_expression (warn
);
4545 fail
.append_expression (ctemp
);
4546 rv
= new
CCodeConditionalExpression (cond
, rv
, fail
);
4552 int next_variant_function_id
= 0;
4554 public CCodeExpression?
try_cast_variant_to_type (CCodeExpression ccodeexpr
, DataType from
, DataType to
, Expression? expr
= null) {
4555 if (from
== null || gvariant_type
== null || from
.data_type
!= gvariant_type
) {
4559 string variant_func
= "_variant_get%d".printf (++next_variant_function_id
);
4561 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (variant_func
));
4562 ccall
.add_argument (ccodeexpr
);
4564 var cfunc
= new
CCodeFunction (variant_func
);
4565 cfunc
.modifiers
= CCodeModifiers
.STATIC
;
4566 cfunc
.add_parameter (new
CCodeParameter ("value", "GVariant*"));
4568 if (!to
.is_real_non_null_struct_type ()) {
4569 cfunc
.return_type
= to
.get_cname ();
4572 if (to
.is_real_non_null_struct_type ()) {
4573 // structs are returned via out parameter
4574 cfunc
.add_parameter (new
CCodeParameter ("result", to
.get_cname () + "*"));
4575 } else if (to is ArrayType
) {
4576 // return array length if appropriate
4577 var array_type
= (ArrayType
) to
;
4579 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4580 var temp_decl
= get_temp_variable (int_type
, false, expr
);
4581 emit_temp_var (temp_decl
);
4583 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_decl
.name
)));
4584 cfunc
.add_parameter (new
CCodeParameter (get_array_length_cname ("result", dim
), "int*"));
4585 append_array_size (expr
, get_variable_cexpression (temp_decl
.name
));
4589 push_function (cfunc
);
4591 var result
= deserialize_expression (to
, new
CCodeIdentifier ("value"), new
CCodeIdentifier ("*result"));
4592 ccode
.add_return (result
);
4596 cfile
.add_function_declaration (cfunc
);
4597 cfile
.add_function (cfunc
);
4602 public virtual CCodeExpression?
deserialize_expression (DataType type
, CCodeExpression variant_expr
, CCodeExpression? expr
, CCodeExpression? error_expr
= null, out bool may_fail
= null) {
4606 public virtual CCodeExpression?
serialize_expression (DataType type
, CCodeExpression expr
) {
4610 public override void visit_cast_expression (CastExpression expr
) {
4611 var valuecast
= try_cast_value_to_type (get_cvalue (expr
.inner
), expr
.inner
.value_type
, expr
.type_reference
, expr
);
4612 if (valuecast
!= null) {
4613 set_cvalue (expr
, valuecast
);
4617 var variantcast
= try_cast_variant_to_type (get_cvalue (expr
.inner
), expr
.inner
.value_type
, expr
.type_reference
, expr
);
4618 if (variantcast
!= null) {
4619 set_cvalue (expr
, variantcast
);
4623 generate_type_declaration (expr
.type_reference
, cfile
);
4625 var cl
= expr
.type_reference
.data_type as Class
;
4626 var iface
= expr
.type_reference
.data_type as Interface
;
4627 if (context
.profile
== Profile
.GOBJECT
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
4628 // checked cast for strict subtypes of GTypeInstance
4629 if (expr
.is_silent_cast
) {
4630 var ccomma
= new
CCodeCommaExpression ();
4631 var temp_decl
= get_temp_variable (expr
.inner
.value_type
, true, expr
, false);
4633 emit_temp_var (temp_decl
);
4635 var ctemp
= get_variable_cexpression (temp_decl
.name
);
4636 var cinit
= new
CCodeAssignment (ctemp
, get_cvalue (expr
.inner
));
4637 var ccheck
= create_type_check (ctemp
, expr
.type_reference
);
4638 var ccast
= new
CCodeCastExpression (ctemp
, expr
.type_reference
.get_cname ());
4639 var cnull
= new
CCodeConstant ("NULL");
4641 ccomma
.append_expression (cinit
);
4642 ccomma
.append_expression (new
CCodeConditionalExpression (ccheck
, ccast
, cnull
));
4644 set_cvalue (expr
, ccomma
);
4646 set_cvalue (expr
, generate_instance_cast (get_cvalue (expr
.inner
), expr
.type_reference
.data_type
));
4649 if (expr
.is_silent_cast
) {
4651 Report
.error (expr
.source_reference
, "Operation not supported for this type");
4655 // retain array length
4656 var array_type
= expr
.type_reference as ArrayType
;
4657 if (array_type
!= null && expr
.inner
.value_type is ArrayType
) {
4658 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4659 append_array_size (expr
, get_array_length_cexpression (expr
.inner
, dim
));
4661 } else if (array_type
!= null) {
4662 // cast from non-array to array, set invalid length
4663 // required by string.data, e.g.
4664 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4665 append_array_size (expr
, new
CCodeConstant ("-1"));
4669 var innercexpr
= get_cvalue (expr
.inner
);
4670 if (expr
.type_reference
.data_type is Struct
&& !expr
.type_reference
.nullable
&&
4671 expr
.inner
.value_type
.data_type is Struct
&& expr
.inner
.value_type
.nullable
) {
4672 // nullable integer or float or boolean or struct cast to non-nullable
4673 innercexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, innercexpr
);
4675 set_cvalue (expr
, new
CCodeCastExpression (innercexpr
, expr
.type_reference
.get_cname ()));
4677 if (expr
.type_reference is DelegateType
) {
4678 if (get_delegate_target (expr
.inner
) != null) {
4679 set_delegate_target (expr
, get_delegate_target (expr
.inner
));
4681 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
4683 if (get_delegate_target_destroy_notify (expr
.inner
) != null) {
4684 set_delegate_target_destroy_notify (expr
, get_delegate_target_destroy_notify (expr
.inner
));
4686 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
4692 public override void visit_named_argument (NamedArgument expr
) {
4693 set_cvalue (expr
, get_cvalue (expr
.inner
));
4696 public override void visit_pointer_indirection (PointerIndirection expr
) {
4697 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_cvalue (expr
.inner
)));
4700 public override void visit_addressof_expression (AddressofExpression expr
) {
4701 if (get_cvalue (expr
.inner
) is CCodeCommaExpression
) {
4702 var ccomma
= get_cvalue (expr
.inner
) as CCodeCommaExpression
;
4703 var inner
= ccomma
.get_inner ();
4704 var last
= inner
.get (inner
.size
- 1);
4705 ccomma
.set_expression (inner
.size
- 1, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, (CCodeExpression
) last
));
4706 set_cvalue (expr
, ccomma
);
4708 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (expr
.inner
)));
4712 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
4713 /* (tmp = var, var = null, tmp) */
4714 var temp_decl
= get_temp_variable (expr
.value_type
, true, expr
, false);
4715 emit_temp_var (temp_decl
);
4716 var cvar
= get_variable_cexpression (temp_decl
.name
);
4718 ccode
.add_expression (new
CCodeAssignment (cvar
, get_cvalue (expr
.inner
)));
4719 if (!(expr
.value_type is DelegateType
)) {
4720 ccode
.add_expression (new
CCodeAssignment (get_cvalue (expr
.inner
), new
CCodeConstant ("NULL")));
4723 set_cvalue (expr
, cvar
);
4725 var array_type
= expr
.value_type as ArrayType
;
4726 if (array_type
!= null) {
4727 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
4728 append_array_size (expr
, get_array_length_cexpression (expr
.inner
, dim
));
4732 var delegate_type
= expr
.value_type as DelegateType
;
4733 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
4734 var temp_target_decl
= get_temp_variable (new
PointerType (new
VoidType ()), true, expr
, false);
4735 emit_temp_var (temp_target_decl
);
4736 var target_cvar
= get_variable_cexpression (temp_target_decl
.name
);
4737 CCodeExpression target_destroy_notify
;
4738 var target
= get_delegate_target_cexpression (expr
.inner
, out target_destroy_notify
);
4739 ccode
.add_expression (new
CCodeAssignment (target_cvar
, target
));
4740 set_delegate_target (expr
, target_cvar
);
4741 if (target_destroy_notify
!= null) {
4742 var temp_target_destroy_notify_decl
= get_temp_variable (gdestroynotify_type
, true, expr
, false);
4743 emit_temp_var (temp_target_destroy_notify_decl
);
4744 var target_destroy_notify_cvar
= get_variable_cexpression (temp_target_destroy_notify_decl
.name
);
4745 ccode
.add_expression (new
CCodeAssignment (target_destroy_notify_cvar
, target_destroy_notify
));
4746 ccode
.add_expression (new
CCodeAssignment (target_destroy_notify
, new
CCodeConstant ("NULL")));
4747 set_delegate_target_destroy_notify (expr
, target_destroy_notify_cvar
);
4752 public override void visit_binary_expression (BinaryExpression expr
) {
4753 var cleft
= get_cvalue (expr
.left
);
4754 var cright
= get_cvalue (expr
.right
);
4756 CCodeExpression? left_chain
= null;
4758 var lbe
= (BinaryExpression
) expr
.left
;
4760 var temp_decl
= get_temp_variable (lbe
.right
.value_type
, true, null, false);
4761 emit_temp_var (temp_decl
);
4762 var cvar
= get_variable_cexpression (temp_decl
.name
);
4763 var ccomma
= new
CCodeCommaExpression ();
4764 var clbe
= (CCodeBinaryExpression
) get_cvalue (lbe
);
4766 clbe
= (CCodeBinaryExpression
) clbe
.right
;
4768 ccomma
.append_expression (new
CCodeAssignment (cvar
, get_cvalue (lbe
.right
)));
4769 clbe
.right
= get_variable_cexpression (temp_decl
.name
);
4770 ccomma
.append_expression (cleft
);
4772 left_chain
= ccomma
;
4775 CCodeBinaryOperator op
;
4776 if (expr
.operator
== BinaryOperator
.PLUS
) {
4777 op
= CCodeBinaryOperator
.PLUS
;
4778 } else if (expr
.operator
== BinaryOperator
.MINUS
) {
4779 op
= CCodeBinaryOperator
.MINUS
;
4780 } else if (expr
.operator
== BinaryOperator
.MUL
) {
4781 op
= CCodeBinaryOperator
.MUL
;
4782 } else if (expr
.operator
== BinaryOperator
.DIV
) {
4783 op
= CCodeBinaryOperator
.DIV
;
4784 } else if (expr
.operator
== BinaryOperator
.MOD
) {
4785 if (expr
.value_type
.equals (double_type
)) {
4786 cfile
.add_include ("math.h");
4787 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("fmod"));
4788 ccall
.add_argument (cleft
);
4789 ccall
.add_argument (cright
);
4790 set_cvalue (expr
, ccall
);
4792 } else if (expr
.value_type
.equals (float_type
)) {
4793 cfile
.add_include ("math.h");
4794 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("fmodf"));
4795 ccall
.add_argument (cleft
);
4796 ccall
.add_argument (cright
);
4797 set_cvalue (expr
, ccall
);
4800 op
= CCodeBinaryOperator
.MOD
;
4802 } else if (expr
.operator
== BinaryOperator
.SHIFT_LEFT
) {
4803 op
= CCodeBinaryOperator
.SHIFT_LEFT
;
4804 } else if (expr
.operator
== BinaryOperator
.SHIFT_RIGHT
) {
4805 op
= CCodeBinaryOperator
.SHIFT_RIGHT
;
4806 } else if (expr
.operator
== BinaryOperator
.LESS_THAN
) {
4807 op
= CCodeBinaryOperator
.LESS_THAN
;
4808 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN
) {
4809 op
= CCodeBinaryOperator
.GREATER_THAN
;
4810 } else if (expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
) {
4811 op
= CCodeBinaryOperator
.LESS_THAN_OR_EQUAL
;
4812 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
4813 op
= CCodeBinaryOperator
.GREATER_THAN_OR_EQUAL
;
4814 } else if (expr
.operator
== BinaryOperator
.EQUALITY
) {
4815 op
= CCodeBinaryOperator
.EQUALITY
;
4816 } else if (expr
.operator
== BinaryOperator
.INEQUALITY
) {
4817 op
= CCodeBinaryOperator
.INEQUALITY
;
4818 } else if (expr
.operator
== BinaryOperator
.BITWISE_AND
) {
4819 op
= CCodeBinaryOperator
.BITWISE_AND
;
4820 } else if (expr
.operator
== BinaryOperator
.BITWISE_OR
) {
4821 op
= CCodeBinaryOperator
.BITWISE_OR
;
4822 } else if (expr
.operator
== BinaryOperator
.BITWISE_XOR
) {
4823 op
= CCodeBinaryOperator
.BITWISE_XOR
;
4824 } else if (expr
.operator
== BinaryOperator
.AND
) {
4825 op
= CCodeBinaryOperator
.AND
;
4826 } else if (expr
.operator
== BinaryOperator
.OR
) {
4827 op
= CCodeBinaryOperator
.OR
;
4828 } else if (expr
.operator
== BinaryOperator
.IN
) {
4829 if (expr
.right
.value_type is ArrayType
) {
4830 var array_type
= (ArrayType
) expr
.right
.value_type
;
4831 var node
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_contains_wrapper (array_type
)));
4832 node
.add_argument (cright
);
4833 node
.add_argument (get_array_length_cexpression (expr
.right
));
4834 if (array_type
.element_type is StructValueType
) {
4835 node
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cleft
));
4837 node
.add_argument (cleft
);
4839 set_cvalue (expr
, node
);
4841 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeBinaryExpression (CCodeBinaryOperator
.BITWISE_AND
, cright
, cleft
), cleft
));
4845 assert_not_reached ();
4848 if (expr
.operator
== BinaryOperator
.EQUALITY
||
4849 expr
.operator
== BinaryOperator
.INEQUALITY
) {
4850 var left_type
= expr
.left
.target_type
;
4851 var right_type
= expr
.right
.target_type
;
4852 make_comparable_cexpression (ref left_type
, ref cleft
, ref right_type
, ref cright
);
4854 if (left_type is StructValueType
&& right_type is StructValueType
) {
4855 var equalfunc
= generate_struct_equal_function ((Struct
) left_type
.data_type as Struct
);
4856 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
4857 ccall
.add_argument (cleft
);
4858 ccall
.add_argument (cright
);
4860 cright
= new
CCodeConstant ("TRUE");
4861 } else if ((left_type is IntegerType
|| left_type is FloatingType
|| left_type is BooleanType
) && left_type
.nullable
&&
4862 (right_type is IntegerType
|| right_type is FloatingType
|| right_type is BooleanType
) && right_type
.nullable
) {
4863 var equalfunc
= generate_numeric_equal_function ((Struct
) left_type
.data_type as Struct
);
4864 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
4865 ccall
.add_argument (cleft
);
4866 ccall
.add_argument (cright
);
4868 cright
= new
CCodeConstant ("TRUE");
4872 if (!(expr
.left
.value_type is NullType
)
4873 && expr
.left
.value_type
.compatible (string_type
)
4874 && !(expr
.right
.value_type is NullType
)
4875 && expr
.right
.value_type
.compatible (string_type
)) {
4876 if (expr
.operator
== BinaryOperator
.PLUS
) {
4877 // string concatenation
4878 if (expr
.left
.is_constant () && expr
.right
.is_constant ()) {
4881 if (cleft is CCodeIdentifier
) {
4882 left
= ((CCodeIdentifier
) cleft
).name
;
4883 } else if (cleft is CCodeConstant
) {
4884 left
= ((CCodeConstant
) cleft
).name
;
4886 assert_not_reached ();
4888 if (cright is CCodeIdentifier
) {
4889 right
= ((CCodeIdentifier
) cright
).name
;
4890 } else if (cright is CCodeConstant
) {
4891 right
= ((CCodeConstant
) cright
).name
;
4893 assert_not_reached ();
4896 set_cvalue (expr
, new
CCodeConstant ("%s %s".printf (left
, right
)));
4899 if (context
.profile
== Profile
.POSIX
) {
4900 // convert to strcat(strcpy(malloc(1+strlen(a)+strlen(b)),a),b)
4901 var strcat
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcat"));
4902 var strcpy
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcpy"));
4903 var malloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("malloc"));
4905 var strlen_a
= new
CCodeFunctionCall (new
CCodeIdentifier ("strlen"));
4906 strlen_a
.add_argument(cleft
);
4907 var strlen_b
= new
CCodeFunctionCall (new
CCodeIdentifier ("strlen"));
4908 strlen_b
.add_argument(cright
);
4909 var newlength
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier("1"),
4910 new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, strlen_a
, strlen_b
));
4911 malloc
.add_argument(newlength
);
4913 strcpy
.add_argument(malloc
);
4914 strcpy
.add_argument(cleft
);
4916 strcat
.add_argument(strcpy
);
4917 strcat
.add_argument(cright
);
4918 set_cvalue (expr
, strcat
);
4920 // convert to g_strconcat (a, b, NULL)
4921 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strconcat"));
4922 ccall
.add_argument (cleft
);
4923 ccall
.add_argument (cright
);
4924 ccall
.add_argument (new
CCodeConstant("NULL"));
4925 set_cvalue (expr
, ccall
);
4929 } else if (expr
.operator
== BinaryOperator
.EQUALITY
4930 || expr
.operator
== BinaryOperator
.INEQUALITY
4931 || expr
.operator
== BinaryOperator
.LESS_THAN
4932 || expr
.operator
== BinaryOperator
.GREATER_THAN
4933 || expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
4934 || expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
4935 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
4936 ccall
.add_argument (cleft
);
4937 ccall
.add_argument (cright
);
4939 cright
= new
CCodeConstant ("0");
4943 set_cvalue (expr
, new
CCodeBinaryExpression (op
, cleft
, cright
));
4944 if (left_chain
!= null) {
4945 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, left_chain
, get_cvalue (expr
)));
4949 public string?
get_type_check_function (TypeSymbol type
) {
4950 var cl
= type as Class
;
4951 if (cl
!= null && cl
.type_check_function
!= null) {
4952 return cl
.type_check_function
;
4953 } else if ((cl
!= null && cl
.is_compact
) || type is Struct
|| type is Enum
|| type is Delegate
) {
4956 return type
.get_upper_case_cname ("IS_");
4960 CCodeExpression?
create_type_check (CCodeNode ccodenode
, DataType type
) {
4961 var et
= type as ErrorType
;
4962 if (et
!= null && et
.error_code
!= null) {
4963 var matches_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_matches"));
4964 matches_call
.add_argument ((CCodeExpression
) ccodenode
);
4965 matches_call
.add_argument (new
CCodeIdentifier (et
.error_domain
.get_upper_case_cname ()));
4966 matches_call
.add_argument (new
CCodeIdentifier (et
.error_code
.get_cname ()));
4967 return matches_call
;
4968 } else if (et
!= null && et
.error_domain
!= null) {
4969 var instance_domain
= new CCodeMemberAccess
.pointer ((CCodeExpression
) ccodenode
, "domain");
4970 var type_domain
= new
CCodeIdentifier (et
.error_domain
.get_upper_case_cname ());
4971 return new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, instance_domain
, type_domain
);
4973 string type_check_func
= get_type_check_function (type
.data_type
);
4974 if (type_check_func
== null) {
4975 return new
CCodeInvalidExpression ();
4977 var ccheck
= new
CCodeFunctionCall (new
CCodeIdentifier (type_check_func
));
4978 ccheck
.add_argument ((CCodeExpression
) ccodenode
);
4983 string generate_array_contains_wrapper (ArrayType array_type
) {
4984 string array_contains_func
= "_vala_%s_array_contains".printf (array_type
.element_type
.get_lower_case_cname ());
4986 if (!add_wrapper (array_contains_func
)) {
4987 return array_contains_func
;
4990 var function
= new
CCodeFunction (array_contains_func
, "gboolean");
4991 function
.modifiers
= CCodeModifiers
.STATIC
;
4993 function
.add_parameter (new
CCodeParameter ("stack", array_type
.get_cname ()));
4994 function
.add_parameter (new
CCodeParameter ("stack_length", "int"));
4995 if (array_type
.element_type is StructValueType
) {
4996 function
.add_parameter (new
CCodeParameter ("needle", array_type
.element_type
.get_cname () + "*"));
4998 function
.add_parameter (new
CCodeParameter ("needle", array_type
.element_type
.get_cname ()));
5001 push_function (function
);
5003 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
5005 var cloop_initializer
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
5006 var cloop_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("stack_length"));
5007 var cloop_iterator
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i"));
5008 ccode
.open_for (cloop_initializer
, cloop_condition
, cloop_iterator
);
5010 var celement
= new
CCodeElementAccess (new
CCodeIdentifier ("stack"), new
CCodeIdentifier ("i"));
5011 var cneedle
= new
CCodeIdentifier ("needle");
5012 CCodeBinaryExpression cif_condition
;
5013 if (array_type
.element_type
.compatible (string_type
)) {
5014 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strcmp0"));
5015 ccall
.add_argument (celement
);
5016 ccall
.add_argument (cneedle
);
5017 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ccall
, new
CCodeConstant ("0"));
5018 } else if (array_type
.element_type is StructValueType
) {
5019 var equalfunc
= generate_struct_equal_function ((Struct
) array_type
.element_type
.data_type as Struct
);
5020 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (equalfunc
));
5021 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, celement
));
5022 ccall
.add_argument (cneedle
);
5023 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ccall
, new
CCodeConstant ("TRUE"));
5025 cif_condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cneedle
, celement
);
5028 ccode
.open_if (cif_condition
);
5029 ccode
.add_return (new
CCodeConstant ("TRUE"));
5034 ccode
.add_return (new
CCodeConstant ("FALSE"));
5038 cfile
.add_function_declaration (function
);
5039 cfile
.add_function (function
);
5041 return array_contains_func
;
5044 public override void visit_type_check (TypeCheck expr
) {
5045 generate_type_declaration (expr
.type_reference
, cfile
);
5047 set_cvalue (expr
, create_type_check (get_cvalue (expr
.expression
), expr
.type_reference
));
5048 if (get_cvalue (expr
) is CCodeInvalidExpression
) {
5049 Report
.error (expr
.source_reference
, "type check expressions not supported for compact classes, structs, and enums");
5053 public override void visit_lambda_expression (LambdaExpression lambda
) {
5054 // use instance position from delegate
5055 var dt
= (DelegateType
) lambda
.target_type
;
5056 lambda
.method
.cinstance_parameter_position
= dt
.delegate_symbol
.cinstance_parameter_position
;
5058 lambda
.accept_children (this
);
5060 bool expr_owned
= lambda
.value_type
.value_owned
;
5062 set_cvalue (lambda
, new
CCodeIdentifier (lambda
.method
.get_cname ()));
5064 var delegate_type
= (DelegateType
) lambda
.target_type
;
5065 if (lambda
.method
.closure
) {
5066 int block_id
= get_block_id (current_closure_block
);
5067 var delegate_target
= get_variable_cexpression ("_data%d_".printf (block_id
));
5068 if (expr_owned
|| delegate_type
.is_called_once
) {
5069 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (block_id
)));
5070 ref_call
.add_argument (delegate_target
);
5071 delegate_target
= ref_call
;
5072 set_delegate_target_destroy_notify (lambda
, new
CCodeIdentifier ("block%d_data_unref".printf (block_id
)));
5074 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5076 set_delegate_target (lambda
, delegate_target
);
5077 } else if (get_this_type () != null || in_constructor
) {
5078 CCodeExpression delegate_target
= get_result_cexpression ("self");
5079 if (expr_owned
|| delegate_type
.is_called_once
) {
5080 if (get_this_type () != null) {
5081 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (get_this_type (), lambda
.source_reference
));
5082 ref_call
.add_argument (delegate_target
);
5083 delegate_target
= ref_call
;
5084 set_delegate_target_destroy_notify (lambda
, get_destroy_func_expression (get_this_type ()));
5087 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_ref"));
5088 ref_call
.add_argument (delegate_target
);
5089 delegate_target
= ref_call
;
5090 set_delegate_target_destroy_notify (lambda
, new
CCodeIdentifier ("g_object_unref"));
5093 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5095 set_delegate_target (lambda
, delegate_target
);
5097 set_delegate_target (lambda
, new
CCodeConstant ("NULL"));
5098 set_delegate_target_destroy_notify (lambda
, new
CCodeConstant ("NULL"));
5102 public CCodeExpression
convert_from_generic_pointer (CCodeExpression cexpr
, DataType actual_type
) {
5104 if (is_reference_type_argument (actual_type
) || is_nullable_value_type_argument (actual_type
)) {
5105 result
= new
CCodeCastExpression (cexpr
, actual_type
.get_cname ());
5106 } else if (is_signed_integer_type_argument (actual_type
)) {
5107 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GPOINTER_TO_INT"));
5108 cconv
.add_argument (cexpr
);
5110 } else if (is_unsigned_integer_type_argument (actual_type
)) {
5111 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GPOINTER_TO_UINT"));
5112 cconv
.add_argument (cexpr
);
5118 public CCodeExpression
convert_to_generic_pointer (CCodeExpression cexpr
, DataType actual_type
) {
5120 if (is_signed_integer_type_argument (actual_type
)) {
5121 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GINT_TO_POINTER"));
5122 cconv
.add_argument (cexpr
);
5124 } else if (is_unsigned_integer_type_argument (actual_type
)) {
5125 var cconv
= new
CCodeFunctionCall (new
CCodeIdentifier ("GUINT_TO_POINTER"));
5126 cconv
.add_argument (cexpr
);
5132 // manage memory and implicit casts
5133 public CCodeExpression
transform_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
5134 var cexpr
= source_cexpr
;
5135 if (expression_type
== null) {
5140 if (expression_type
.value_owned
5141 && expression_type
.floating_reference
) {
5142 /* floating reference, sink it.
5144 var cl
= expression_type
.data_type as ObjectTypeSymbol
;
5145 var sink_func
= (cl
!= null) ? cl
.get_ref_sink_function () : null;
5147 if (sink_func
!= null) {
5148 var csink
= new
CCodeFunctionCall (new
CCodeIdentifier (sink_func
));
5149 csink
.add_argument (cexpr
);
5153 Report
.error (null, "type `%s' does not support floating references".printf (expression_type
.data_type
.name
));
5157 bool boxing
= (expression_type is ValueType
&& !expression_type
.nullable
5158 && target_type is ValueType
&& target_type
.nullable
);
5159 bool unboxing
= (expression_type is ValueType
&& expression_type
.nullable
5160 && target_type is ValueType
&& !target_type
.nullable
);
5162 bool gvalue_boxing
= (context
.profile
== Profile
.GOBJECT
5163 && target_type
!= null
5164 && target_type
.data_type
== gvalue_type
5165 && !(expression_type is NullType
)
5166 && expression_type
.get_type_id () != "G_TYPE_VALUE");
5167 bool gvariant_boxing
= (context
.profile
== Profile
.GOBJECT
5168 && target_type
!= null
5169 && target_type
.data_type
== gvariant_type
5170 && !(expression_type is NullType
)
5171 && expression_type
.data_type
!= gvariant_type
);
5173 if (expression_type
.value_owned
5174 && (target_type
== null || !target_type
.value_owned
|| boxing
|| unboxing
)
5175 && !gvalue_boxing
/* gvalue can assume ownership of value, no need to free it */) {
5176 // value leaked, destroy it
5177 var pointer_type
= target_type as PointerType
;
5178 if (pointer_type
!= null && !(pointer_type
.base_type is VoidType
)) {
5179 // manual memory management for non-void pointers
5180 // treat void* special to not leak memory with void* method parameters
5181 } else if (requires_destroy (expression_type
)) {
5182 var decl
= get_temp_variable (expression_type
, true, expression_type
, false);
5183 emit_temp_var (decl
);
5184 temp_ref_vars
.insert (0, decl
);
5185 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (decl
.name
), cexpr
));
5186 cexpr
= get_variable_cexpression (decl
.name
);
5188 if (expression_type is ArrayType
&& expr
!= null) {
5189 var array_type
= (ArrayType
) expression_type
;
5190 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5191 var len_decl
= new
LocalVariable (int_type
.copy (), get_array_length_cname (decl
.name
, dim
));
5192 emit_temp_var (len_decl
);
5193 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (len_decl
.name
), get_array_length_cexpression (expr
, dim
)));
5195 } else if (expression_type is DelegateType
&& expr
!= null) {
5196 var target_decl
= new
LocalVariable (new
PointerType (new
VoidType ()), get_delegate_target_cname (decl
.name
));
5197 emit_temp_var (target_decl
);
5198 var target_destroy_notify_decl
= new
LocalVariable (gdestroynotify_type
, get_delegate_target_destroy_notify_cname (decl
.name
));
5199 emit_temp_var (target_destroy_notify_decl
);
5200 CCodeExpression target_destroy_notify
;
5201 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (target_decl
.name
), get_delegate_target_cexpression (expr
, out target_destroy_notify
)));
5202 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (target_destroy_notify_decl
.name
), target_destroy_notify
));
5208 if (target_type
== null) {
5209 // value will be destroyed, no need for implicit casts
5213 if (gvalue_boxing
) {
5214 // implicit conversion to GValue
5215 var decl
= get_temp_variable (target_type
, true, target_type
);
5216 emit_temp_var (decl
);
5218 if (!target_type
.value_owned
) {
5219 // boxed GValue leaked, destroy it
5220 temp_ref_vars
.insert (0, decl
);
5223 if (target_type
.nullable
) {
5224 var newcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
5225 newcall
.add_argument (new
CCodeConstant ("GValue"));
5226 newcall
.add_argument (new
CCodeConstant ("1"));
5227 var newassignment
= new
CCodeAssignment (get_variable_cexpression (decl
.name
), newcall
);
5228 ccode
.add_expression (newassignment
);
5231 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
5232 if (target_type
.nullable
) {
5233 ccall
.add_argument (get_variable_cexpression (decl
.name
));
5235 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
)));
5237 ccall
.add_argument (new
CCodeIdentifier (expression_type
.get_type_id ()));
5238 ccode
.add_expression (ccall
);
5240 if (requires_destroy (expression_type
)) {
5241 ccall
= new
CCodeFunctionCall (get_value_taker_function (expression_type
));
5243 ccall
= new
CCodeFunctionCall (get_value_setter_function (expression_type
));
5245 if (target_type
.nullable
) {
5246 ccall
.add_argument (get_variable_cexpression (decl
.name
));
5248 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
)));
5250 if (expression_type
.is_real_non_null_struct_type ()) {
5251 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
5253 ccall
.add_argument (cexpr
);
5256 ccode
.add_expression (ccall
);
5258 cexpr
= get_variable_cexpression (decl
.name
);
5261 } else if (gvariant_boxing
) {
5262 // implicit conversion to GVariant
5263 string variant_func
= "_variant_new%d".printf (++next_variant_function_id
);
5265 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (variant_func
));
5266 ccall
.add_argument (cexpr
);
5268 var cfunc
= new
CCodeFunction (variant_func
, "GVariant*");
5269 cfunc
.modifiers
= CCodeModifiers
.STATIC
;
5270 cfunc
.add_parameter (new
CCodeParameter ("value", expression_type
.get_cname ()));
5272 if (expression_type is ArrayType
) {
5273 // return array length if appropriate
5274 var array_type
= (ArrayType
) expression_type
;
5276 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5277 ccall
.add_argument (get_array_length_cexpression (expr
, dim
));
5278 cfunc
.add_parameter (new
CCodeParameter (get_array_length_cname ("value", dim
), "gint"));
5282 push_function (cfunc
);
5284 var result
= serialize_expression (expression_type
, new
CCodeIdentifier ("value"));
5286 // sink floating reference
5287 var sink
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_ref_sink"));
5288 sink
.add_argument (result
);
5289 ccode
.add_return (sink
);
5293 cfile
.add_function_declaration (cfunc
);
5294 cfile
.add_function (cfunc
);
5297 } else if (boxing
) {
5298 // value needs to be boxed
5300 var unary
= cexpr as CCodeUnaryExpression
;
5301 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
5303 cexpr
= unary
.inner
;
5304 } else if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
5305 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
5307 var decl
= get_temp_variable (expression_type
, expression_type
.value_owned
, expression_type
, false);
5308 emit_temp_var (decl
);
5310 var ccomma
= new
CCodeCommaExpression ();
5311 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (decl
.name
), cexpr
));
5312 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (decl
.name
)));
5315 } else if (unboxing
) {
5318 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cexpr
);
5320 cexpr
= get_implicit_cast_expression (cexpr
, expression_type
, target_type
, expr
);
5323 if (target_type
.value_owned
&& (!expression_type
.value_owned
|| boxing
|| unboxing
)) {
5324 // need to copy value
5325 if (requires_copy (target_type
) && !(expression_type is NullType
)) {
5326 CodeNode node
= expr
;
5328 node
= expression_type
;
5331 var decl
= get_temp_variable (target_type
, true, node
, false);
5332 emit_temp_var (decl
);
5333 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (decl
.name
), get_ref_cexpression (target_type
, cexpr
, expr
, node
)));
5334 cexpr
= get_variable_cexpression (decl
.name
);
5341 public virtual CCodeExpression
get_implicit_cast_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
5342 var cexpr
= source_cexpr
;
5344 if (expression_type
.data_type
!= null && expression_type
.data_type
== target_type
.data_type
) {
5345 // same type, no cast required
5349 if (expression_type is NullType
) {
5350 // null literal, no cast required when not converting to generic type pointer
5354 generate_type_declaration (target_type
, cfile
);
5356 var cl
= target_type
.data_type as Class
;
5357 var iface
= target_type
.data_type as Interface
;
5358 if (context
.checking
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
5359 // checked cast for strict subtypes of GTypeInstance
5360 return generate_instance_cast (cexpr
, target_type
.data_type
);
5361 } else if (target_type
.data_type
!= null && expression_type
.get_cname () != target_type
.get_cname ()) {
5362 var st
= target_type
.data_type as Struct
;
5363 if (target_type
.data_type
.is_reference_type () || (st
!= null && st
.is_simple_type ())) {
5364 // don't cast non-simple structs
5365 return new
CCodeCastExpression (cexpr
, target_type
.get_cname ());
5374 public void store_property (Property prop
, Expression? instance
, TargetValue value
) {
5375 if (instance is BaseAccess
) {
5376 if (prop
.base_property
!= null) {
5377 var base_class
= (Class
) prop
.base_property
.parent_symbol
;
5378 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (base_class
.get_upper_case_cname (null))));
5379 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (current_class
.get_lower_case_cname (null))));
5381 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, "set_%s".printf (prop
.name
)));
5382 ccall
.add_argument ((CCodeExpression
) get_ccodenode (instance
));
5383 ccall
.add_argument (get_cvalue_ (value
));
5385 ccode
.add_expression (ccall
);
5386 } else if (prop
.base_interface_property
!= null) {
5387 var base_iface
= (Interface
) prop
.base_interface_property
.parent_symbol
;
5388 string parent_iface_var
= "%s_%s_parent_iface".printf (current_class
.get_lower_case_cname (null), base_iface
.get_lower_case_cname (null));
5390 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), "set_%s".printf (prop
.name
)));
5391 ccall
.add_argument ((CCodeExpression
) get_ccodenode (instance
));
5392 ccall
.add_argument (get_cvalue_ (value
));
5394 ccode
.add_expression (ccall
);
5399 var set_func
= "g_object_set";
5401 var base_property
= prop
;
5402 if (!prop
.no_accessor_method
) {
5403 if (prop
.base_property
!= null) {
5404 base_property
= prop
.base_property
;
5405 } else if (prop
.base_interface_property
!= null) {
5406 base_property
= prop
.base_interface_property
;
5409 if (prop is DynamicProperty
) {
5410 set_func
= get_dynamic_property_setter_cname ((DynamicProperty
) prop
);
5412 generate_property_accessor_declaration (base_property
.set_accessor
, cfile
);
5413 set_func
= base_property
.set_accessor
.get_cname ();
5415 if (!prop
.external
&& prop
.external_package
) {
5416 // internal VAPI properties
5417 // only add them once per source file
5418 if (add_generated_external_symbol (prop
)) {
5419 visit_property (prop
);
5425 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (set_func
));
5427 if (prop
.binding
== MemberBinding
.INSTANCE
) {
5428 /* target instance is first argument */
5429 var cinstance
= (CCodeExpression
) get_ccodenode (instance
);
5431 if (prop
.parent_symbol is Struct
) {
5432 // we need to pass struct instance by reference
5433 var unary
= cinstance as CCodeUnaryExpression
;
5434 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
5436 cinstance
= unary
.inner
;
5437 } else if (cinstance is CCodeIdentifier
|| cinstance is CCodeMemberAccess
) {
5438 cinstance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cinstance
);
5440 // if instance is e.g. a function call, we can't take the address of the expression
5441 // (tmp = expr, &tmp)
5443 var temp_var
= get_temp_variable (instance
.target_type
, true, null, false);
5444 emit_temp_var (temp_var
);
5445 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), cinstance
));
5447 cinstance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
));
5451 ccall
.add_argument (cinstance
);
5454 if (prop
.no_accessor_method
) {
5455 /* property name is second argument of g_object_set */
5456 ccall
.add_argument (prop
.get_canonical_cconstant ());
5459 var cexpr
= get_cvalue_ (value
);
5461 if (prop
.property_type
.is_real_non_null_struct_type ()) {
5462 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
5465 var array_type
= prop
.property_type as ArrayType
;
5467 if (array_type
!= null && !prop
.no_array_length
) {
5468 var temp_var
= get_temp_variable (prop
.property_type
, true, null, false);
5469 emit_temp_var (temp_var
);
5470 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), cexpr
));
5471 ccall
.add_argument (get_variable_cexpression (temp_var
.name
));
5473 ccall
.add_argument (cexpr
);
5476 if (array_type
!= null && !prop
.no_array_length
) {
5477 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5478 ccall
.add_argument (get_array_length_cvalue (value
, dim
));
5480 } else if (prop
.property_type is DelegateType
) {
5481 var delegate_type
= (DelegateType
) prop
.property_type
;
5482 if (delegate_type
.delegate_symbol
.has_target
) {
5483 ccall
.add_argument (get_delegate_target_cvalue (value
));
5487 if (prop
.no_accessor_method
) {
5488 ccall
.add_argument (new
CCodeConstant ("NULL"));
5491 ccode
.add_expression (ccall
);
5494 /* indicates whether a given Expression eligable for an ADDRESS_OF operator
5495 * from a vala to C point of view all expressions denoting locals, fields and
5496 * parameters are eligable to an ADDRESS_OF operator */
5497 public bool is_address_of_possible (Expression e
) {
5498 if (gvalue_type
!= null && e
.target_type
.data_type
== gvalue_type
&& e
.value_type
.data_type
!= gvalue_type
) {
5499 // implicit conversion to GValue is not addressable
5503 var ma
= e as MemberAccess
;
5509 return (ma
.symbol_reference is Variable
);
5512 /* retrieve the correct address_of expression for a give expression, creates temporary variables
5513 * where necessary, ce is the corresponding ccode expression for e */
5514 public CCodeExpression
get_address_of_expression (Expression e
, CCodeExpression ce
) {
5515 // is address of trivially possible?
5516 if (is_address_of_possible (e
)) {
5517 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ce
);
5520 var ccomma
= new
CCodeCommaExpression ();
5521 DataType address_of_type
;
5522 if (gvalue_type
!= null && e
.target_type
!= null && e
.target_type
.data_type
== gvalue_type
) {
5523 // implicit conversion to GValue
5524 address_of_type
= e
.target_type
;
5526 address_of_type
= e
.value_type
;
5528 var temp_decl
= get_temp_variable (address_of_type
, true, null, false);
5529 var ctemp
= get_variable_cexpression (temp_decl
.name
);
5530 emit_temp_var (temp_decl
);
5531 ccomma
.append_expression (new
CCodeAssignment (ctemp
, ce
));
5532 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
5536 public bool add_wrapper (string wrapper_name
) {
5537 return wrappers
.add (wrapper_name
);
5540 public bool add_generated_external_symbol (Symbol external_symbol
) {
5541 return generated_external_symbols
.add (external_symbol
);
5544 public static DataType
get_data_type_for_symbol (TypeSymbol sym
) {
5545 DataType type
= null;
5548 type
= new
ObjectType ((Class
) sym
);
5549 } else if (sym is Interface
) {
5550 type
= new
ObjectType ((Interface
) sym
);
5551 } else if (sym is Struct
) {
5552 var st
= (Struct
) sym
;
5553 if (st
.is_boolean_type ()) {
5554 type
= new
BooleanType (st
);
5555 } else if (st
.is_integer_type ()) {
5556 type
= new
IntegerType (st
);
5557 } else if (st
.is_floating_type ()) {
5558 type
= new
FloatingType (st
);
5560 type
= new
StructValueType (st
);
5562 } else if (sym is Enum
) {
5563 type
= new
EnumValueType ((Enum
) sym
);
5564 } else if (sym is ErrorDomain
) {
5565 type
= new
ErrorType ((ErrorDomain
) sym
, null);
5566 } else if (sym is ErrorCode
) {
5567 type
= new
ErrorType ((ErrorDomain
) sym
.parent_symbol
, (ErrorCode
) sym
);
5569 Report
.error (null, "internal error: `%s' is not a supported type".printf (sym
.get_full_name ()));
5570 return new
InvalidType ();
5576 public CCodeExpression?
default_value_for_type (DataType type
, bool initializer_expression
) {
5577 var st
= type
.data_type as Struct
;
5578 var array_type
= type as ArrayType
;
5579 if (initializer_expression
&& !type
.nullable
&&
5580 ((st
!= null && !st
.is_simple_type ()) ||
5581 (array_type
!= null && array_type
.fixed_length
))) {
5582 // 0-initialize struct with struct initializer { 0 }
5583 // only allowed as initializer expression in C
5584 var clist
= new
CCodeInitializerList ();
5585 clist
.append (new
CCodeConstant ("0"));
5587 } else if ((type
.data_type
!= null && type
.data_type
.is_reference_type ())
5589 || type is PointerType
|| type is DelegateType
5590 || (array_type
!= null && !array_type
.fixed_length
)) {
5591 return new
CCodeConstant ("NULL");
5592 } else if (type
.data_type
!= null && type
.data_type
.get_default_value () != null) {
5593 return new
CCodeConstant (type
.data_type
.get_default_value ());
5594 } else if (type
.type_parameter
!= null) {
5595 return new
CCodeConstant ("NULL");
5596 } else if (type is ErrorType
) {
5597 return new
CCodeConstant ("NULL");
5602 private void create_property_type_check_statement (Property prop
, bool check_return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
5603 if (check_return_type
) {
5604 create_type_check_statement (prop
, prop
.property_type
, t
, non_null
, var_name
);
5606 create_type_check_statement (prop
, new
VoidType (), t
, non_null
, var_name
);
5610 public void create_type_check_statement (CodeNode method_node
, DataType ret_type
, TypeSymbol t
, bool non_null
, string var_name
) {
5611 var ccheck
= new
CCodeFunctionCall ();
5613 if (!context
.assert
) {
5615 } else if (context
.checking
&& ((t is Class
&& !((Class
) t
).is_compact
) || t is Interface
)) {
5616 var ctype_check
= new
CCodeFunctionCall (new
CCodeIdentifier (get_type_check_function (t
)));
5617 ctype_check
.add_argument (new
CCodeIdentifier (var_name
));
5619 CCodeExpression cexpr
= ctype_check
;
5621 var cnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier (var_name
), new
CCodeConstant ("NULL"));
5623 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cnull
, ctype_check
);
5625 ccheck
.add_argument (cexpr
);
5626 } else if (!non_null
) {
5628 } else if (t
== glist_type
|| t
== gslist_type
) {
5629 // NULL is empty list
5632 var cnonnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier (var_name
), new
CCodeConstant ("NULL"));
5633 ccheck
.add_argument (cnonnull
);
5636 var cm
= method_node as CreationMethod
;
5637 if (cm
!= null && cm
.parent_symbol is ObjectTypeSymbol
) {
5638 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
5639 ccheck
.add_argument (new
CCodeConstant ("NULL"));
5640 } else if (ret_type is VoidType
) {
5642 ccheck
.call
= new
CCodeIdentifier ("g_return_if_fail");
5644 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
5646 var cdefault
= default_value_for_type (ret_type
, false);
5647 if (cdefault
!= null) {
5648 ccheck
.add_argument (cdefault
);
5654 ccode
.add_expression (ccheck
);
5657 public int get_param_pos (double param_pos
, bool ellipsis
= false) {
5659 if (param_pos
>= 0) {
5660 return (int) (param_pos
* 1000);
5662 return (int) ((100 + param_pos
) * 1000);
5665 if (param_pos
>= 0) {
5666 return (int) ((100 + param_pos
) * 1000);
5668 return (int) ((200 + param_pos
) * 1000);
5673 public CCodeExpression?
get_ccodenode (Expression node
) {
5674 if (get_cvalue (node
) == null) {
5677 return get_cvalue (node
);
5680 public override void visit_class (Class cl
) {
5683 public void create_postcondition_statement (Expression postcondition
) {
5684 var cassert
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_warn_if_fail"));
5686 postcondition
.emit (this
);
5688 cassert
.add_argument (get_cvalue (postcondition
));
5690 ccode
.add_expression (cassert
);
5693 public virtual bool is_gobject_property (Property prop
) {
5697 public DataType?
get_this_type () {
5698 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) {
5699 return current_method
.this_parameter
.variable_type
;
5700 } else if (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
) {
5701 return current_property_accessor
.prop
.this_parameter
.variable_type
;
5706 public CCodeFunctionCall
generate_instance_cast (CCodeExpression expr
, TypeSymbol type
) {
5707 var result
= new
CCodeFunctionCall (new
CCodeIdentifier (type
.get_upper_case_cname (null)));
5708 result
.add_argument (expr
);
5712 void generate_struct_destroy_function (Struct st
) {
5713 if (cfile
.add_declaration (st
.get_destroy_function ())) {
5714 // only generate function once per source file
5718 var function
= new
CCodeFunction (st
.get_destroy_function (), "void");
5719 function
.modifiers
= CCodeModifiers
.STATIC
;
5720 function
.add_parameter (new
CCodeParameter ("self", st
.get_cname () + "*"));
5722 push_function (function
);
5724 foreach (Field f
in st
.get_fields ()) {
5725 if (f
.binding
== MemberBinding
.INSTANCE
) {
5726 if (requires_destroy (f
.variable_type
)) {
5727 var lhs
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.get_cname ());
5729 var this_access
= new MemberAccess
.simple ("this");
5730 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
5731 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
5733 var ma
= new
MemberAccess (this_access
, f
.name
);
5734 ma
.symbol_reference
= f
;
5735 ma
.value_type
= f
.variable_type
.copy ();
5736 visit_member_access (ma
);
5737 ccode
.add_expression (get_unref_expression (lhs
, f
.variable_type
, ma
));
5744 cfile
.add_function_declaration (function
);
5745 cfile
.add_function (function
);
5748 void generate_struct_copy_function (Struct st
) {
5749 if (cfile
.add_declaration (st
.get_copy_function ())) {
5750 // only generate function once per source file
5754 var function
= new
CCodeFunction (st
.get_copy_function (), "void");
5755 function
.modifiers
= CCodeModifiers
.STATIC
;
5756 function
.add_parameter (new
CCodeParameter ("self", "const " + st
.get_cname () + "*"));
5757 function
.add_parameter (new
CCodeParameter ("dest", st
.get_cname () + "*"));
5759 push_context (new
EmitContext ());
5760 push_function (function
);
5762 foreach (Field f
in st
.get_fields ()) {
5763 if (f
.binding
== MemberBinding
.INSTANCE
) {
5764 CCodeExpression copy
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), f
.name
);
5765 if (requires_copy (f
.variable_type
)) {
5766 var this_access
= new MemberAccess
.simple ("this");
5767 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
5768 set_cvalue (this_access
, new
CCodeIdentifier ("(*self)"));
5769 var ma
= new
MemberAccess (this_access
, f
.name
);
5770 ma
.symbol_reference
= f
;
5771 ma
.value_type
= f
.variable_type
.copy ();
5772 visit_member_access (ma
);
5773 copy
= get_ref_cexpression (f
.variable_type
, copy
, ma
, f
);
5775 var dest
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("dest"), f
.name
);
5777 var array_type
= f
.variable_type as ArrayType
;
5778 if (array_type
!= null && array_type
.fixed_length
) {
5779 // fixed-length (stack-allocated) arrays
5780 cfile
.add_include ("string.h");
5782 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
5783 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
5784 var size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
);
5786 var array_copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
5787 array_copy_call
.add_argument (dest
);
5788 array_copy_call
.add_argument (copy
);
5789 array_copy_call
.add_argument (size
);
5790 ccode
.add_expression (array_copy_call
);
5792 ccode
.add_expression (new
CCodeAssignment (dest
, copy
));
5794 if (array_type
!= null && !f
.no_array_length
) {
5795 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
5796 var len_src
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), get_array_length_cname (f
.name
, dim
));
5797 var len_dest
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("dest"), get_array_length_cname (f
.name
, dim
));
5798 ccode
.add_expression (new
CCodeAssignment (len_dest
, len_src
));
5808 cfile
.add_function_declaration (function
);
5809 cfile
.add_function (function
);
5812 public void return_default_value (DataType return_type
) {
5813 ccode
.add_return (default_value_for_type (return_type
, false));
5816 public virtual string?
get_custom_creturn_type (Method m
) {
5820 public virtual void generate_dynamic_method_wrapper (DynamicMethod method
) {
5823 public virtual bool method_has_wrapper (Method method
) {
5827 public virtual CCodeFunctionCall
get_param_spec (Property prop
) {
5828 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
5831 public virtual CCodeFunctionCall
get_signal_creation (Signal sig
, TypeSymbol type
) {
5832 return new
CCodeFunctionCall (new
CCodeIdentifier (""));
5835 public virtual void register_dbus_info (CCodeBlock block
, ObjectTypeSymbol bindable
) {
5838 public virtual string get_dynamic_property_getter_cname (DynamicProperty node
) {
5839 Report
.error (node
.source_reference
, "dynamic properties are not supported for %s".printf (node
.dynamic_type
.to_string ()));
5843 public virtual string get_dynamic_property_setter_cname (DynamicProperty node
) {
5844 Report
.error (node
.source_reference
, "dynamic properties are not supported for %s".printf (node
.dynamic_type
.to_string ()));
5848 public virtual string get_dynamic_signal_cname (DynamicSignal node
) {
5852 public virtual string get_dynamic_signal_connect_wrapper_name (DynamicSignal node
) {
5856 public virtual string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal node
) {
5860 public virtual string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node
) {
5864 public virtual void generate_marshaller (List
<Parameter
> params
, DataType return_type
, bool dbus
= false) {
5867 public virtual string get_marshaller_function (List
<Parameter
> params
, DataType return_type
, string? prefix
= null, bool dbus
= false) {
5871 public virtual string get_array_length_cname (string array_cname
, int dim
) {
5875 public virtual string get_parameter_array_length_cname (Parameter param
, int dim
) {
5879 public virtual CCodeExpression
get_array_length_cexpression (Expression array_expr
, int dim
= -1) {
5880 return new
CCodeConstant ("");
5883 public virtual CCodeExpression
get_array_length_cvalue (TargetValue value
, int dim
= -1) {
5884 return new
CCodeInvalidExpression ();
5887 public virtual string get_array_size_cname (string array_cname
) {
5891 public virtual void add_simple_check (CodeNode node
, bool always_fails
= false) {
5894 public virtual string generate_ready_function (Method m
) {
5898 public CCodeExpression?
get_cvalue (Expression expr
) {
5899 if (expr
.target_value
== null) {
5902 var glib_value
= (GLibValue
) expr
.target_value
;
5903 return glib_value
.cvalue
;
5906 public CCodeExpression?
get_cvalue_ (TargetValue value
) {
5907 var glib_value
= (GLibValue
) value
;
5908 return glib_value
.cvalue
;
5911 public void set_cvalue (Expression expr
, CCodeExpression? cvalue
) {
5912 var glib_value
= (GLibValue
) expr
.target_value
;
5913 if (glib_value
== null) {
5914 glib_value
= new
GLibValue (expr
.value_type
);
5915 expr
.target_value
= glib_value
;
5917 glib_value
.cvalue
= cvalue
;
5920 public CCodeExpression?
get_array_size_cvalue (TargetValue value
) {
5921 var glib_value
= (GLibValue
) value
;
5922 return glib_value
.array_size_cvalue
;
5925 public void set_array_size_cvalue (TargetValue value
, CCodeExpression? cvalue
) {
5926 var glib_value
= (GLibValue
) value
;
5927 glib_value
.array_size_cvalue
= cvalue
;
5930 public CCodeExpression?
get_delegate_target (Expression expr
) {
5931 if (expr
.target_value
== null) {
5934 var glib_value
= (GLibValue
) expr
.target_value
;
5935 return glib_value
.delegate_target_cvalue
;
5938 public void set_delegate_target (Expression expr
, CCodeExpression? delegate_target
) {
5939 var glib_value
= (GLibValue
) expr
.target_value
;
5940 if (glib_value
== null) {
5941 glib_value
= new
GLibValue (expr
.value_type
);
5942 expr
.target_value
= glib_value
;
5944 glib_value
.delegate_target_cvalue
= delegate_target
;
5947 public CCodeExpression?
get_delegate_target_destroy_notify (Expression expr
) {
5948 if (expr
.target_value
== null) {
5951 var glib_value
= (GLibValue
) expr
.target_value
;
5952 return glib_value
.delegate_target_destroy_notify_cvalue
;
5955 public void set_delegate_target_destroy_notify (Expression expr
, CCodeExpression? destroy_notify
) {
5956 var glib_value
= (GLibValue
) expr
.target_value
;
5957 if (glib_value
== null) {
5958 glib_value
= new
GLibValue (expr
.value_type
);
5959 expr
.target_value
= glib_value
;
5961 glib_value
.delegate_target_destroy_notify_cvalue
= destroy_notify
;
5964 public void append_array_size (Expression expr
, CCodeExpression size
) {
5965 var glib_value
= (GLibValue
) expr
.target_value
;
5966 if (glib_value
== null) {
5967 glib_value
= new
GLibValue (expr
.value_type
);
5968 expr
.target_value
= glib_value
;
5970 glib_value
.append_array_length_cvalue (size
);
5973 public List
<CCodeExpression
>?
get_array_sizes (Expression expr
) {
5974 var glib_value
= (GLibValue
) expr
.target_value
;
5975 if (glib_value
== null) {
5976 glib_value
= new
GLibValue (expr
.value_type
);
5977 expr
.target_value
= glib_value
;
5979 return glib_value
.array_length_cvalues
;
5983 public class Vala
.GLibValue
: TargetValue
{
5984 public CCodeExpression cvalue
;
5986 public List
<CCodeExpression
> array_length_cvalues
;
5987 public CCodeExpression? array_size_cvalue
;
5989 public CCodeExpression? delegate_target_cvalue
;
5990 public CCodeExpression? delegate_target_destroy_notify_cvalue
;
5992 public GLibValue (DataType? value_type
= null, CCodeExpression? cvalue
= null) {
5994 this
.cvalue
= cvalue
;
5997 public void append_array_length_cvalue (CCodeExpression length_cvalue
) {
5998 if (array_length_cvalues
== null) {
5999 array_length_cvalues
= new ArrayList
<CCodeExpression
> ();
6001 array_length_cvalues
.add (length_cvalue
);