1 /* valadovabasemodule.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>
26 * Code visitor generating C Code.
28 public class Vala
.DovaBaseModule
: CodeGenerator
{
29 public class EmitContext
{
30 public Symbol? current_symbol
;
31 public ArrayList
<Symbol
> symbol_stack
= new ArrayList
<Symbol
> ();
32 public TryStatement current_try
;
33 public ArrayList
<LocalVariable
> temp_vars
= new ArrayList
<LocalVariable
> ();
34 public ArrayList
<LocalVariable
> temp_ref_vars
= new ArrayList
<LocalVariable
> ();
35 public int next_temp_var_id
;
36 public Map
<string,string> variable_name_map
= new HashMap
<string,string> (str_hash
, str_equal
);
38 public EmitContext (Symbol? symbol
= null) {
39 current_symbol
= symbol
;
42 public void push_symbol (Symbol symbol
) {
43 symbol_stack
.add (current_symbol
);
44 current_symbol
= symbol
;
47 public void pop_symbol () {
48 current_symbol
= symbol_stack
[symbol_stack
.size
- 1];
49 symbol_stack
.remove_at (symbol_stack
.size
- 1);
53 public CodeContext context
{ get; set; }
55 public Symbol root_symbol
;
57 public EmitContext emit_context
= new
EmitContext ();
59 List
<EmitContext
> emit_context_stack
= new ArrayList
<EmitContext
> ();
61 public Symbol current_symbol
{ get { return emit_context
.current_symbol
; } }
63 public TryStatement current_try
{
64 get { return emit_context
.current_try
; }
65 set { emit_context
.current_try
= value
; }
68 public TypeSymbol? current_type_symbol
{
70 var sym
= current_symbol
;
72 if (sym is TypeSymbol
) {
73 return (TypeSymbol
) sym
;
75 sym
= sym
.parent_symbol
;
81 public Class? current_class
{
82 get { return current_type_symbol as Class
; }
85 public Method? current_method
{
87 var sym
= current_symbol
;
88 while (sym is Block
) {
89 sym
= sym
.parent_symbol
;
95 public PropertyAccessor? current_property_accessor
{
97 var sym
= current_symbol
;
98 while (sym is Block
) {
99 sym
= sym
.parent_symbol
;
101 return sym as PropertyAccessor
;
105 public DataType? current_return_type
{
107 var m
= current_method
;
109 return m
.return_type
;
112 var acc
= current_property_accessor
;
115 return acc
.value_type
;
125 public Block? current_closure_block
{
127 return next_closure_block (current_symbol
);
131 public unowned Block?
next_closure_block (Symbol sym
) {
132 unowned Block block
= null;
134 block
= sym as Block
;
135 if (!(sym is Block
|| sym is Method
)) {
139 if (block
!= null && block
.captured
) {
140 // closure block found
143 sym
= sym
.parent_symbol
;
148 public CCodeDeclarationSpace header_declarations
;
149 public CCodeDeclarationSpace source_declarations
;
151 string? csource_filename
;
153 public CCodeFragment source_type_member_definition
;
154 public CCodeFragment module_init_fragment
;
155 public CCodeFragment instance_init_fragment
;
156 public CCodeFragment instance_finalize_fragment
;
158 // code nodes to be inserted before the current statement
159 // used by async method calls in coroutines
160 public CCodeFragment pre_statement_fragment
;
162 /* all temporary variables */
163 public ArrayList
<LocalVariable
> temp_vars
{ get { return emit_context
.temp_vars
; } }
164 /* temporary variables that own their content */
165 public ArrayList
<LocalVariable
> temp_ref_vars
{ get { return emit_context
.temp_ref_vars
; } }
166 /* (constant) hash table with all reserved identifiers in the generated code */
167 Set
<string> reserved_identifiers
;
169 public int next_temp_var_id
{
170 get { return emit_context
.next_temp_var_id
; }
171 set { emit_context
.next_temp_var_id
= value
; }
174 public int next_wrapper_id
= 0;
175 public bool in_creation_method
{ get { return current_method is CreationMethod
; } }
176 int next_block_id
= 0;
177 Map
<Block
,int> block_map
= new HashMap
<Block
,int> ();
179 public DataType void_type
= new
VoidType ();
180 public DataType bool_type
;
181 public DataType char_type
;
182 public DataType short_type
;
183 public DataType ushort_type
;
184 public DataType int_type
;
185 public DataType uint_type
;
186 public DataType long_type
;
187 public DataType ulong_type
;
188 public DataType string_type
;
189 public DataType float_type
;
190 public DataType double_type
;
191 public Class object_class
;
192 public Class type_class
;
193 public Class value_class
;
194 public Class string_class
;
195 public Class array_class
;
196 public Class delegate_class
;
197 public Class error_class
;
199 Set
<Symbol
> generated_external_symbols
;
201 public Map
<string,string> variable_name_map
{ get { return emit_context
.variable_name_map
; } }
203 public DovaBaseModule () {
204 reserved_identifiers
= new HashSet
<string> (str_hash
, str_equal
);
207 reserved_identifiers
.add ("_Bool");
208 reserved_identifiers
.add ("_Complex");
209 reserved_identifiers
.add ("_Imaginary");
210 reserved_identifiers
.add ("auto");
211 reserved_identifiers
.add ("break");
212 reserved_identifiers
.add ("case");
213 reserved_identifiers
.add ("char");
214 reserved_identifiers
.add ("const");
215 reserved_identifiers
.add ("continue");
216 reserved_identifiers
.add ("default");
217 reserved_identifiers
.add ("do");
218 reserved_identifiers
.add ("double");
219 reserved_identifiers
.add ("else");
220 reserved_identifiers
.add ("enum");
221 reserved_identifiers
.add ("extern");
222 reserved_identifiers
.add ("float");
223 reserved_identifiers
.add ("for");
224 reserved_identifiers
.add ("goto");
225 reserved_identifiers
.add ("if");
226 reserved_identifiers
.add ("inline");
227 reserved_identifiers
.add ("int");
228 reserved_identifiers
.add ("long");
229 reserved_identifiers
.add ("register");
230 reserved_identifiers
.add ("restrict");
231 reserved_identifiers
.add ("return");
232 reserved_identifiers
.add ("short");
233 reserved_identifiers
.add ("signed");
234 reserved_identifiers
.add ("sizeof");
235 reserved_identifiers
.add ("static");
236 reserved_identifiers
.add ("struct");
237 reserved_identifiers
.add ("switch");
238 reserved_identifiers
.add ("typedef");
239 reserved_identifiers
.add ("union");
240 reserved_identifiers
.add ("unsigned");
241 reserved_identifiers
.add ("void");
242 reserved_identifiers
.add ("volatile");
243 reserved_identifiers
.add ("while");
245 // reserved for Vala naming conventions
246 reserved_identifiers
.add ("result");
247 reserved_identifiers
.add ("this");
250 public override void emit (CodeContext context
) {
251 this
.context
= context
;
253 root_symbol
= context
.root
;
255 bool_type
= new
BooleanType ((Struct
) root_symbol
.scope
.lookup ("bool"));
256 char_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("char"));
257 short_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("short"));
258 ushort_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ushort"));
259 int_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int"));
260 uint_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint"));
261 long_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("long"));
262 ulong_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("ulong"));
263 float_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("float"));
264 double_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("double"));
265 string_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("string"));
267 var dova_ns
= (Namespace
) root_symbol
.scope
.lookup ("Dova");
268 object_class
= (Class
) dova_ns
.scope
.lookup ("Object");
269 type_class
= (Class
) dova_ns
.scope
.lookup ("Type");
270 value_class
= (Class
) dova_ns
.scope
.lookup ("Value");
271 string_class
= (Class
) root_symbol
.scope
.lookup ("string");
272 array_class
= (Class
) dova_ns
.scope
.lookup ("Array");
273 delegate_class
= (Class
) dova_ns
.scope
.lookup ("Delegate");
274 error_class
= (Class
) dova_ns
.scope
.lookup ("Error");
276 header_declarations
= new
CCodeDeclarationSpace ();
278 source_declarations
= new
CCodeDeclarationSpace ();
279 module_init_fragment
= new
CCodeFragment ();
280 source_type_member_definition
= new
CCodeFragment ();
282 if (context
.nostdpkg
) {
283 header_declarations
.add_include ("dova-types.h");
284 source_declarations
.add_include ("dova-types.h");
286 header_declarations
.add_include ("dova-base.h");
287 source_declarations
.add_include ("dova-base.h");
290 generated_external_symbols
= new HashSet
<Symbol
> ();
293 /* we're only interested in non-pkg source files */
294 var source_files
= context
.get_source_files ();
295 foreach (SourceFile file
in source_files
) {
296 if (!file
.external_package
) {
301 if (csource_filename
!= null) {
302 var writer
= new
CCodeWriter (csource_filename
);
303 if (!writer
.open (context
.version_header
)) {
304 Report
.error (null, "unable to open `%s' for writing".printf (writer
.filename
));
307 writer
.line_directives
= context
.debug
;
309 writer
.write_newline ();
310 source_declarations
.include_directives
.write (writer
);
311 writer
.write_newline ();
312 source_declarations
.type_declaration
.write_combined (writer
);
313 writer
.write_newline ();
314 source_declarations
.type_definition
.write_combined (writer
);
315 writer
.write_newline ();
316 source_declarations
.type_member_declaration
.write_declaration (writer
);
317 writer
.write_newline ();
318 source_declarations
.type_member_declaration
.write (writer
);
319 writer
.write_newline ();
320 source_declarations
.constant_declaration
.write_combined (writer
);
321 writer
.write_newline ();
322 source_type_member_definition
.write (writer
);
323 writer
.write_newline ();
327 source_declarations
= null;
328 source_type_member_definition
= null;
331 // generate C header file for public API
332 if (context
.header_filename
!= null) {
333 var writer
= new
CCodeWriter (context
.header_filename
);
334 if (!writer
.open (context
.version_header
)) {
335 Report
.error (null, "unable to open `%s' for writing".printf (writer
.filename
));
338 writer
.write_newline ();
340 var once
= new
CCodeOnceSection (get_define_for_filename (writer
.filename
));
341 once
.append (new
CCodeNewline ());
342 once
.append (header_declarations
.include_directives
);
343 once
.append (new
CCodeNewline ());
345 once
.append (new
CCodeNewline ());
346 once
.append (header_declarations
.type_declaration
);
347 once
.append (new
CCodeNewline ());
348 once
.append (header_declarations
.type_definition
);
349 once
.append (new
CCodeNewline ());
350 once
.append (header_declarations
.type_member_declaration
);
351 once
.append (new
CCodeNewline ());
352 once
.append (header_declarations
.constant_declaration
);
353 once
.append (new
CCodeNewline ());
355 once
.append (new
CCodeNewline ());
361 public void push_context (EmitContext emit_context
) {
362 if (this
.emit_context
!= null) {
363 emit_context_stack
.add (this
.emit_context
);
366 this
.emit_context
= emit_context
;
369 public void pop_context () {
370 if (emit_context_stack
.size
> 0) {
371 this
.emit_context
= emit_context_stack
[emit_context_stack
.size
- 1];
372 emit_context_stack
.remove_at (emit_context_stack
.size
- 1);
374 this
.emit_context
= null;
378 public override void visit_source_file (SourceFile source_file
) {
379 if (csource_filename
== null) {
380 csource_filename
= source_file
.get_csource_filename ();
382 var writer
= new
CCodeWriter (source_file
.get_csource_filename ());
383 if (!writer
.open (context
.version_header
)) {
384 Report
.error (null, "unable to open `%s' for writing".printf (writer
.filename
));
390 source_file
.accept_children (this
);
392 if (context
.report
.get_errors () > 0) {
397 private static string get_define_for_filename (string filename
) {
398 var define
= new
StringBuilder ("__");
401 while (i
.len () > 0) {
402 var c
= i
.get_char ();
403 if (c
.isalnum () && c
< 0x80) {
404 define
.append_unichar (c
.toupper ());
406 define
.append_c ('_');
412 define
.append ("__");
417 public void generate_enum_declaration (Enum en
, CCodeDeclarationSpace decl_space
) {
418 if (decl_space
.add_symbol_declaration (en
, en
.get_cname ())) {
422 var cenum
= new
CCodeEnum (en
.get_cname ());
424 foreach (EnumValue ev
in en
.get_values ()) {
425 if (ev
.value
== null) {
426 cenum
.add_value (new
CCodeEnumValue (ev
.get_cname ()));
428 ev
.value
.emit (this
);
429 cenum
.add_value (new
CCodeEnumValue (ev
.get_cname (), (CCodeExpression
) ev
.value
.ccodenode
));
433 decl_space
.add_type_definition (cenum
);
434 decl_space
.add_type_definition (new
CCodeNewline ());
437 public override void visit_enum (Enum en
) {
438 en
.accept_children (this
);
440 generate_enum_declaration (en
, source_declarations
);
442 if (!en
.is_internal_symbol ()) {
443 generate_enum_declaration (en
, header_declarations
);
447 public void generate_constant_declaration (Constant c
, CCodeDeclarationSpace decl_space
) {
448 if (decl_space
.add_symbol_declaration (c
, c
.get_cname ())) {
455 if (c
.value is InitializerList
) {
456 var cdecl
= new
CCodeDeclaration (c
.type_reference
.get_const_cname ());
458 if (c
.type_reference is ArrayType
) {
461 cdecl
.add_declarator (new
CCodeVariableDeclarator ("%s%s".printf (c
.get_cname (), arr
), (CCodeExpression
) c
.value
.ccodenode
));
462 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
464 decl_space
.add_constant_declaration (cdecl
);
466 var cdefine
= new CCodeMacroReplacement
.with_expression (c
.get_cname (), (CCodeExpression
) c
.value
.ccodenode
);
467 decl_space
.add_type_member_declaration (cdefine
);
472 public override void visit_constant (Constant c
) {
473 generate_constant_declaration (c
, source_declarations
);
475 if (!c
.is_internal_symbol ()) {
476 generate_constant_declaration (c
, header_declarations
);
480 public void generate_field_declaration (Field f
, CCodeDeclarationSpace decl_space
) {
481 if (decl_space
.add_symbol_declaration (f
, f
.get_cname ())) {
485 generate_type_declaration (f
.variable_type
, decl_space
);
487 string field_ctype
= f
.variable_type
.get_cname ();
489 field_ctype
= "volatile " + field_ctype
;
492 var cdecl
= new
CCodeDeclaration (field_ctype
);
493 cdecl
.add_declarator (new
CCodeVariableDeclarator (f
.get_cname ()));
494 if (f
.is_internal_symbol ()) {
495 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
497 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
500 if (f
.get_attribute ("ThreadLocal") != null) {
501 cdecl
.modifiers
|= CCodeModifiers
.THREAD_LOCAL
;
504 decl_space
.add_type_member_declaration (cdecl
);
507 public override void visit_field (Field f
) {
508 if (f
.initializer
!= null) {
509 f
.initializer
.emit (this
);
512 var cl
= f
.parent_symbol as Class
;
514 CCodeExpression lhs
= null;
516 string field_ctype
= f
.variable_type
.get_cname ();
518 field_ctype
= "volatile " + field_ctype
;
521 if (f
.binding
== MemberBinding
.INSTANCE
) {
522 if (cl
!= null && f
.is_internal_symbol ()) {
523 var priv_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_PRIVATE".printf (cl
.get_upper_case_cname (null))));
524 priv_call
.add_argument (new
CCodeIdentifier ("this"));
525 lhs
= new CCodeMemberAccess
.pointer (priv_call
, f
.get_cname ());
527 lhs
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("this"), f
.get_cname ());
530 if (f
.initializer
!= null) {
531 var rhs
= (CCodeExpression
) f
.initializer
.ccodenode
;
533 instance_init_fragment
.append (new
CCodeExpressionStatement (new
CCodeAssignment (lhs
, rhs
)));
535 append_temp_decl (instance_init_fragment
, temp_vars
);
539 if (requires_destroy (f
.variable_type
) && instance_finalize_fragment
!= null) {
540 var this_access
= new MemberAccess
.simple ("this");
541 this_access
.value_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
543 var field_st
= f
.parent_symbol as Struct
;
544 if (field_st
!= null && !field_st
.is_simple_type ()) {
545 this_access
.ccodenode
= new
CCodeIdentifier ("(*this)");
547 this_access
.ccodenode
= new
CCodeIdentifier ("this");
550 var ma
= new
MemberAccess (this_access
, f
.name
);
551 ma
.symbol_reference
= f
;
552 instance_finalize_fragment
.append (new
CCodeExpressionStatement (get_unref_expression (lhs
, f
.variable_type
, ma
)));
555 generate_field_declaration (f
, source_declarations
);
557 if (!f
.is_internal_symbol ()) {
558 generate_field_declaration (f
, header_declarations
);
561 lhs
= new
CCodeIdentifier (f
.get_cname ());
563 var var_decl
= new
CCodeVariableDeclarator (f
.get_cname ());
564 var_decl
.initializer
= default_value_for_type (f
.variable_type
, true);
566 if (f
.initializer
!= null) {
567 var rhs
= (CCodeExpression
) f
.initializer
.ccodenode
;
569 module_init_fragment
.append (new
CCodeExpressionStatement (new
CCodeAssignment (lhs
, rhs
)));
571 append_temp_decl (module_init_fragment
, temp_vars
);
575 var var_def
= new
CCodeDeclaration (field_ctype
);
576 var_def
.add_declarator (var_decl
);
577 if (!f
.is_internal_symbol ()) {
578 var_def
.modifiers
= CCodeModifiers
.EXTERN
;
580 var_def
.modifiers
= CCodeModifiers
.STATIC
;
583 if (f
.get_attribute ("ThreadLocal") != null) {
584 var_def
.modifiers
|= CCodeModifiers
.THREAD_LOCAL
;
587 source_declarations
.add_type_member_declaration (var_def
);
591 public bool is_constant_ccode_expression (CCodeExpression cexpr
) {
592 if (cexpr is CCodeConstant
) {
594 } else if (cexpr is CCodeCastExpression
) {
595 var ccast
= (CCodeCastExpression
) cexpr
;
596 return is_constant_ccode_expression (ccast
.inner
);
597 } else if (cexpr is CCodeBinaryExpression
) {
598 var cbinary
= (CCodeBinaryExpression
) cexpr
;
599 return is_constant_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
602 var cparenthesized
= (cexpr as CCodeParenthesizedExpression
);
603 return (null != cparenthesized
&& is_constant_ccode_expression (cparenthesized
.inner
));
607 * Returns whether the passed cexpr is a pure expression, i.e. an
608 * expression without side-effects.
610 public bool is_pure_ccode_expression (CCodeExpression cexpr
) {
611 if (cexpr is CCodeConstant
|| cexpr is CCodeIdentifier
) {
613 } else if (cexpr is CCodeBinaryExpression
) {
614 var cbinary
= (CCodeBinaryExpression
) cexpr
;
615 return is_pure_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
616 } else if (cexpr is CCodeUnaryExpression
) {
617 var cunary
= (CCodeUnaryExpression
) cexpr
;
618 switch (cunary
.operator
) {
619 case CCodeUnaryOperator
.PREFIX_INCREMENT
:
620 case CCodeUnaryOperator
.PREFIX_DECREMENT
:
621 case CCodeUnaryOperator
.POSTFIX_INCREMENT
:
622 case CCodeUnaryOperator
.POSTFIX_DECREMENT
:
625 return is_pure_ccode_expression (cunary
.inner
);
627 } else if (cexpr is CCodeMemberAccess
) {
628 var cma
= (CCodeMemberAccess
) cexpr
;
629 return is_pure_ccode_expression (cma
.inner
);
630 } else if (cexpr is CCodeElementAccess
) {
631 var cea
= (CCodeElementAccess
) cexpr
;
632 return is_pure_ccode_expression (cea
.container
) && is_pure_ccode_expression (cea
.index
);
633 } else if (cexpr is CCodeCastExpression
) {
634 var ccast
= (CCodeCastExpression
) cexpr
;
635 return is_pure_ccode_expression (ccast
.inner
);
636 } else if (cexpr is CCodeParenthesizedExpression
) {
637 var cparenthesized
= (CCodeParenthesizedExpression
) cexpr
;
638 return is_pure_ccode_expression (cparenthesized
.inner
);
644 public override void visit_formal_parameter (FormalParameter p
) {
647 public override void visit_property (Property prop
) {
648 prop
.accept_children (this
);
651 public void generate_type_declaration (DataType type
, CCodeDeclarationSpace decl_space
) {
652 if (type is ObjectType
) {
653 var object_type
= (ObjectType
) type
;
654 if (object_type
.type_symbol is Class
) {
655 generate_class_declaration ((Class
) object_type
.type_symbol
, decl_space
);
656 } else if (object_type
.type_symbol is Interface
) {
657 generate_interface_declaration ((Interface
) object_type
.type_symbol
, decl_space
);
659 } else if (type is DelegateType
) {
660 var deleg_type
= (DelegateType
) type
;
661 var d
= deleg_type
.delegate_symbol
;
662 generate_delegate_declaration (d
, decl_space
);
663 } else if (type
.data_type is Enum
) {
664 var en
= (Enum
) type
.data_type
;
665 generate_enum_declaration (en
, decl_space
);
666 } else if (type is ValueType
) {
667 var value_type
= (ValueType
) type
;
668 generate_struct_declaration ((Struct
) value_type
.type_symbol
, decl_space
);
669 } else if (type is ArrayType
) {
670 var array_type
= (ArrayType
) type
;
671 generate_type_declaration (array_type
.element_type
, decl_space
);
672 } else if (type is PointerType
) {
673 var pointer_type
= (PointerType
) type
;
674 generate_type_declaration (pointer_type
.base_type
, decl_space
);
677 foreach (DataType type_arg
in type
.get_type_arguments ()) {
678 generate_type_declaration (type_arg
, decl_space
);
682 public virtual void generate_struct_declaration (Struct st
, CCodeDeclarationSpace decl_space
) {
685 public virtual void generate_delegate_declaration (Delegate d
, CCodeDeclarationSpace decl_space
) {
688 public virtual void generate_cparameters (Method m
, CCodeDeclarationSpace decl_space
, CCodeFunction func
, CCodeFunctionDeclarator? vdeclarator
= null, CCodeFunctionCall? vcall
= null) {
691 public virtual void generate_property_accessor_declaration (PropertyAccessor acc
, CCodeDeclarationSpace decl_space
) {
694 public override void visit_destructor (Destructor d
) {
697 CCodeFragment cfrag
= new
CCodeFragment ();
699 cfrag
.append (d
.body
.ccodenode
);
704 public int get_block_id (Block b
) {
705 int result
= block_map
[b
];
707 result
= ++next_block_id
;
708 block_map
[b
] = result
;
713 void capture_parameter (FormalParameter param
, CCodeStruct data
, CCodeBlock cblock
, int block_id
, CCodeBlock free_block
) {
714 generate_type_declaration (param
.variable_type
, source_declarations
);
716 var param_type
= param
.variable_type
.copy ();
717 param_type
.value_owned
= true;
718 data
.add_field (param_type
.get_cname (), get_variable_cname (param
.name
));
720 // create copy if necessary as captured variables may need to be kept alive
721 CCodeExpression cparam
= get_variable_cexpression (param
.name
);
722 if (requires_copy (param_type
) && !param
.variable_type
.value_owned
) {
723 var ma
= new MemberAccess
.simple (param
.name
);
724 ma
.symbol_reference
= param
;
725 ma
.value_type
= param
.variable_type
.copy ();
726 // directly access parameters in ref expressions
727 param
.captured
= false;
728 cparam
= get_ref_cexpression (param
.variable_type
, cparam
, ma
, param
);
729 param
.captured
= true;
732 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_variable_cname (param
.name
)), cparam
)));
734 if (requires_destroy (param_type
)) {
735 var ma
= new MemberAccess
.simple (param
.name
);
736 ma
.symbol_reference
= param
;
737 ma
.value_type
= param_type
.copy ();
738 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
)));
742 public override void visit_block (Block b
) {
743 emit_context
.push_symbol (b
);
745 foreach (Statement stmt
in b
.get_statements ()) {
749 var local_vars
= b
.get_local_variables ();
750 foreach (LocalVariable local
in local_vars
) {
751 local
.active
= false;
754 var cblock
= new
CCodeBlock ();
758 var parent_block
= next_closure_block (b
.parent_symbol
);
760 int block_id
= get_block_id (b
);
761 string struct_name
= "Block%dData".printf (block_id
);
763 var free_block
= new
CCodeBlock ();
765 var data
= new
CCodeStruct ("_" + struct_name
);
766 data
.add_field ("DovaType*", "type");
767 data
.add_field ("int", "_ref_count_");
768 if (parent_block
!= null) {
769 int parent_block_id
= get_block_id (parent_block
);
771 data
.add_field ("Block%dData *".printf (parent_block_id
), "_data%d_".printf (parent_block_id
));
773 var unref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_unref"));
774 unref_call
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)));
775 free_block
.add_statement (new
CCodeExpressionStatement (unref_call
));
776 } else if ((current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) ||
777 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
778 data
.add_field ("%s *".printf (current_class
.get_cname ()), "this");
780 var ma
= new MemberAccess
.simple ("this");
781 ma
.symbol_reference
= current_class
;
782 free_block
.add_statement (new
CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "this"), new
ObjectType (current_class
), ma
)));
784 foreach (var local
in local_vars
) {
785 if (local
.captured
) {
786 generate_type_declaration (local
.variable_type
, source_declarations
);
788 data
.add_field (local
.variable_type
.get_cname (), get_variable_cname (local
.name
) + local
.variable_type
.get_cdeclarator_suffix ());
791 // free in reverse order
792 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
793 var local
= local_vars
[i
];
794 if (local
.captured
) {
795 if (requires_destroy (local
.variable_type
)) {
796 var ma
= new MemberAccess
.simple (local
.name
);
797 ma
.symbol_reference
= local
;
798 ma
.value_type
= local
.variable_type
.copy ();
799 free_block
.add_statement (new
CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), get_variable_cname (local
.name
)), local
.variable_type
, ma
)));
804 var data_alloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_alloc"));
805 data_alloc
.add_argument (new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_type_get".printf (block_id
))));
807 var data_decl
= new
CCodeDeclaration (struct_name
+ "*");
808 data_decl
.add_declarator (new
CCodeVariableDeclarator ("_data%d_".printf (block_id
), data_alloc
));
809 cblock
.add_statement (data_decl
);
811 if (parent_block
!= null) {
812 int parent_block_id
= get_block_id (parent_block
);
814 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_ref"));
815 ref_call
.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id
)));
817 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)), ref_call
)));
818 } else if ((current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) ||
819 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
820 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (new
ObjectType (current_class
), b
.source_reference
));
821 ref_call
.add_argument (new
CCodeIdentifier ("this"));
823 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "this"), ref_call
)));
826 if (b
.parent_symbol is Method
) {
827 var m
= (Method
) b
.parent_symbol
;
829 // parameters are captured with the top-level block of the method
830 foreach (var param
in m
.get_parameters ()) {
831 if (param
.captured
) {
832 capture_parameter (param
, data
, cblock
, block_id
, free_block
);
836 var cfrag
= new
CCodeFragment ();
837 append_temp_decl (cfrag
, temp_vars
);
839 cblock
.add_statement (cfrag
);
840 } else if (b
.parent_symbol is PropertyAccessor
) {
841 var acc
= (PropertyAccessor
) b
.parent_symbol
;
843 if (!acc
.readable
&& acc
.value_parameter
.captured
) {
844 capture_parameter (acc
.value_parameter
, data
, cblock
, block_id
, free_block
);
847 var cfrag
= new
CCodeFragment ();
848 append_temp_decl (cfrag
, temp_vars
);
850 cblock
.add_statement (cfrag
);
853 var typedef
= new
CCodeTypeDefinition ("struct _" + struct_name
, new
CCodeVariableDeclarator (struct_name
));
854 source_declarations
.add_type_declaration (typedef
);
855 source_declarations
.add_type_definition (data
);
857 var data_free
= new
CCodeFunctionCall (new
CCodeIdentifier ("free"));
858 data_free
.add_argument (new
CCodeIdentifier ("_data%d_".printf (block_id
)));
859 free_block
.add_statement (new
CCodeExpressionStatement (data_free
));
861 // create type_get/finalize functions
862 var type_get_fun
= new
CCodeFunction ("block%d_data_type_get".printf (block_id
), "DovaType*");
863 type_get_fun
.modifiers
= CCodeModifiers
.STATIC
;
864 source_declarations
.add_type_member_declaration (type_get_fun
.copy ());
865 type_get_fun
.block
= new
CCodeBlock ();
867 var cdecl
= new
CCodeDeclaration ("int");
868 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_block%d_data_object_offset".printf (block_id
), new
CCodeConstant ("0")));
869 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
870 source_declarations
.add_type_member_declaration (cdecl
);
872 cdecl
= new
CCodeDeclaration ("int");
873 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_block%d_data_type_offset".printf (block_id
), new
CCodeConstant ("0")));
874 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
875 source_declarations
.add_type_member_declaration (cdecl
);
877 cdecl
= new
CCodeDeclaration ("DovaType *");
878 cdecl
.add_declarator (new
CCodeVariableDeclarator ("block%d_data_type".printf (block_id
), new
CCodeConstant ("NULL")));
879 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
880 source_declarations
.add_type_member_declaration (cdecl
);
882 var type_init_block
= new
CCodeBlock ();
883 var alloc_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_alloc"));
884 alloc_call
.add_argument (new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_type_get")));
885 alloc_call
.add_argument (new
CCodeConstant ("sizeof (%s)".printf (struct_name
)));
886 alloc_call
.add_argument (new
CCodeConstant ("0"));
887 alloc_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("block%d_data_type".printf (block_id
))));
888 alloc_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("_block%d_data_object_offset".printf (block_id
))));
889 alloc_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("_block%d_data_type_offset".printf (block_id
))));
890 type_init_block
.add_statement (new
CCodeExpressionStatement (alloc_call
));
891 var type_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_type_init"));
892 type_init_call
.add_argument (new
CCodeIdentifier ("block%d_data_type".printf (block_id
)));
893 type_init_block
.add_statement (new
CCodeExpressionStatement (type_init_call
));
894 type_get_fun
.block
.add_statement (new
CCodeIfStatement (new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, new
CCodeIdentifier ("block%d_data_type".printf (block_id
))), type_init_block
));
895 type_get_fun
.block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("block%d_data_type".printf (block_id
))));
897 source_type_member_definition
.append (type_get_fun
);
899 var unref_fun
= new
CCodeFunction ("block%d_data_finalize".printf (block_id
), "void");
900 unref_fun
.add_parameter (new
CCodeFormalParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
901 unref_fun
.modifiers
= CCodeModifiers
.STATIC
;
902 source_declarations
.add_type_member_declaration (unref_fun
.copy ());
903 unref_fun
.block
= free_block
;
905 source_type_member_definition
.append (unref_fun
);
908 foreach (CodeNode stmt
in b
.get_statements ()) {
913 if (stmt
.ccodenode is CCodeFragment
) {
914 foreach (CCodeNode cstmt
in ((CCodeFragment
) stmt
.ccodenode
).get_children ()) {
915 cblock
.add_statement (cstmt
);
918 cblock
.add_statement (stmt
.ccodenode
);
922 // free in reverse order
923 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
924 var local
= local_vars
[i
];
925 if (!local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
926 var ma
= new MemberAccess
.simple (local
.name
);
927 ma
.symbol_reference
= local
;
928 cblock
.add_statement (new
CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
)));
932 if (b
.parent_symbol is Method
) {
933 var m
= (Method
) b
.parent_symbol
;
934 foreach (FormalParameter param
in m
.get_parameters ()) {
935 if (!param
.captured
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
936 var ma
= new MemberAccess
.simple (param
.name
);
937 ma
.symbol_reference
= param
;
938 cblock
.add_statement (new
CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param
.name
), param
.variable_type
, ma
)));
944 int block_id
= get_block_id (b
);
946 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_unref"));
947 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
948 cblock
.add_statement (new
CCodeExpressionStatement (data_unref
));
951 b
.ccodenode
= cblock
;
953 emit_context
.pop_symbol ();
956 public override void visit_empty_statement (EmptyStatement stmt
) {
957 stmt
.ccodenode
= new
CCodeEmptyStatement ();
960 public override void visit_declaration_statement (DeclarationStatement stmt
) {
961 stmt
.declaration
.accept (this
);
963 stmt
.ccodenode
= stmt
.declaration
.ccodenode
;
965 var local
= stmt
.declaration as LocalVariable
;
966 if (local
!= null && local
.initializer
!= null) {
967 create_temp_decl (stmt
, local
.initializer
.temp_vars
);
970 create_temp_decl (stmt
, temp_vars
);
974 public CCodeExpression
get_variable_cexpression (string name
) {
975 return new
CCodeIdentifier (get_variable_cname (name
));
978 public string get_variable_cname (string name
) {
979 if (name
[0] == '.') {
980 // compiler-internal variable
981 if (!variable_name_map
.contains (name
)) {
982 variable_name_map
.set (name
, "_tmp%d_".printf (next_temp_var_id
));
985 return variable_name_map
.get (name
);
986 } else if (reserved_identifiers
.contains (name
)) {
987 return "_%s_".printf (name
);
993 public override void visit_local_variable (LocalVariable local
) {
994 if (local
.initializer
!= null) {
995 local
.initializer
.emit (this
);
997 visit_end_full_expression (local
.initializer
);
1000 generate_type_declaration (local
.variable_type
, source_declarations
);
1002 CCodeExpression rhs
= null;
1003 if (local
.initializer
!= null && local
.initializer
.ccodenode
!= null) {
1004 rhs
= (CCodeExpression
) local
.initializer
.ccodenode
;
1007 var cfrag
= new
CCodeFragment ();
1009 if (pre_statement_fragment
!= null) {
1010 cfrag
.append (pre_statement_fragment
);
1011 pre_statement_fragment
= null;
1014 if (local
.captured
) {
1015 if (local
.initializer
!= null) {
1016 cfrag
.append (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id ((Block
) local
.parent_symbol
))), get_variable_cname (local
.name
)), rhs
)));
1019 var cvar
= new
CCodeVariableDeclarator (get_variable_cname (local
.name
), rhs
, local
.variable_type
.get_cdeclarator_suffix ());
1021 var cdecl
= new
CCodeDeclaration (local
.variable_type
.get_cname ());
1022 cdecl
.add_declarator (cvar
);
1023 cfrag
.append (cdecl
);
1025 // try to initialize uninitialized variables
1026 // initialization not necessary for variables stored in closure
1027 if (cvar
.initializer
== null) {
1028 cvar
.initializer
= default_value_for_type (local
.variable_type
, true);
1033 if (local
.initializer
!= null && local
.initializer
.tree_can_fail
) {
1034 add_simple_check (local
.initializer
, cfrag
);
1037 local
.ccodenode
= cfrag
;
1039 local
.active
= true;
1042 public override void visit_initializer_list (InitializerList list
) {
1043 if (list
.target_type
.data_type is Struct
) {
1044 /* initializer is used as struct initializer */
1045 var st
= (Struct
) list
.target_type
.data_type
;
1047 var clist
= new
CCodeInitializerList ();
1049 var field_it
= st
.get_fields ().iterator ();
1050 foreach (Expression expr
in list
.get_initializers ()) {
1052 while (field
== null) {
1054 field
= field_it
.get ();
1055 if (field
.binding
!= MemberBinding
.INSTANCE
) {
1056 // we only initialize instance fields
1061 var cexpr
= (CCodeExpression
) expr
.ccodenode
;
1063 string ctype
= field
.get_ctype ();
1064 if (ctype
!= null) {
1065 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
1068 clist
.append (cexpr
);
1071 list
.ccodenode
= clist
;
1073 var clist
= new
CCodeInitializerList ();
1074 foreach (Expression expr
in list
.get_initializers ()) {
1075 clist
.append ((CCodeExpression
) expr
.ccodenode
);
1077 list
.ccodenode
= clist
;
1081 public LocalVariable
get_temp_variable (DataType type
, bool value_owned
= true, CodeNode? node_reference
= null) {
1082 var var_type
= type
.copy ();
1083 var_type
.value_owned
= value_owned
;
1084 var local
= new
LocalVariable (var_type
, "_tmp%d_".printf (next_temp_var_id
));
1086 if (node_reference
!= null) {
1087 local
.source_reference
= node_reference
.source_reference
;
1095 bool is_in_generic_type (DataType type
) {
1096 if (type
.type_parameter
.parent_symbol is TypeSymbol
1097 && (current_method
== null || current_method
.binding
== MemberBinding
.INSTANCE
)) {
1104 public CCodeExpression
get_type_private_from_type (ObjectTypeSymbol type_symbol
, CCodeExpression type_expression
) {
1105 if (type_symbol is Class
) {
1107 return new
CCodeCastExpression (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeCastExpression (type_expression
, "char *"), new
CCodeIdentifier ("_%s_type_offset".printf (((Class
) type_symbol
).get_lower_case_cname ()))), "%sTypePrivate *".printf (((Class
) type_symbol
).get_cname ()));
1110 var get_interface
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_get_interface"));
1111 get_interface
.add_argument (type_expression
);
1112 get_interface
.add_argument (new
CCodeIdentifier ("%s_type".printf (((Interface
) type_symbol
).get_lower_case_cname ())));
1113 return new
CCodeCastExpression (get_interface
, "%sTypePrivate *".printf (((Interface
) type_symbol
).get_cname ()));
1117 public CCodeExpression
get_type_id_expression (DataType type
, bool is_chainup
= false) {
1118 if (type is GenericType
) {
1119 string var_name
= "%s_type".printf (type
.type_parameter
.name
.down ());
1120 if (is_in_generic_type (type
) && !is_chainup
) {
1121 return new CCodeMemberAccess
.pointer (get_type_private_from_type ((ObjectTypeSymbol
) type
.type_parameter
.parent_symbol
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("this"), "type")), var_name
);
1123 return new
CCodeIdentifier (var_name
);
1126 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_type_get".printf (type
.data_type
.get_lower_case_cname ())));
1127 var object_type_symbol
= type
.data_type as ObjectTypeSymbol
;
1128 if (object_type_symbol
!= null) {
1129 for (int i
= 0; i
< object_type_symbol
.get_type_parameters ().size
; i
++) {
1130 if (type
.get_type_arguments ().size
== 0) {
1131 ccall
.add_argument (new
CCodeConstant ("NULL"));
1133 ccall
.add_argument (get_type_id_expression (type
.get_type_arguments ().get (i
)));
1141 public virtual CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
, bool is_chainup
= false) {
1142 if (type
.data_type
!= null) {
1143 string dup_function
= "";
1144 if (type
.data_type
.is_reference_counting ()) {
1145 dup_function
= type
.data_type
.get_ref_function ();
1146 } else if (type is ValueType
) {
1147 dup_function
= type
.data_type
.get_dup_function ();
1148 if (dup_function
== null) {
1153 return new
CCodeIdentifier (dup_function
);
1154 } else if (type
.type_parameter
!= null) {
1156 } else if (type is ArrayType
) {
1157 return new
CCodeIdentifier ("dova_object_ref");
1158 } else if (type is DelegateType
) {
1159 return new
CCodeIdentifier ("dova_object_ref");
1160 } else if (type is PointerType
) {
1161 var pointer_type
= (PointerType
) type
;
1162 return get_dup_func_expression (pointer_type
.base_type
, source_reference
);
1164 return new
CCodeConstant ("NULL");
1168 public CCodeExpression?
get_destroy_func_expression (DataType type
, bool is_chainup
= false) {
1169 if (type
.data_type
!= null) {
1170 string unref_function
;
1171 if (type is ReferenceType
) {
1172 if (type
.data_type
.is_reference_counting ()) {
1173 unref_function
= type
.data_type
.get_unref_function ();
1175 unref_function
= type
.data_type
.get_free_function ();
1178 if (type
.nullable
) {
1179 unref_function
= type
.data_type
.get_free_function ();
1180 if (unref_function
== null) {
1181 unref_function
= "free";
1184 var st
= (Struct
) type
.data_type
;
1185 unref_function
= st
.get_copy_function ();
1188 if (unref_function
== null) {
1189 return new
CCodeConstant ("NULL");
1191 return new
CCodeIdentifier (unref_function
);
1192 } else if (type
.type_parameter
!= null && current_type_symbol is Class
) {
1193 // FIXME ask type for dup/ref function
1194 return new
CCodeIdentifier ("dova_object_unref");
1195 } else if (type is ArrayType
) {
1196 return new
CCodeIdentifier ("dova_object_unref");
1197 } else if (type is DelegateType
) {
1198 return new
CCodeIdentifier ("dova_object_unref");
1199 } else if (type is PointerType
) {
1200 return new
CCodeIdentifier ("free");
1202 return new
CCodeConstant ("NULL");
1206 public virtual CCodeExpression
get_unref_expression (CCodeExpression cvar
, DataType type
, Expression? expr
= null) {
1207 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
1209 if (type is ValueType
&& !type
.nullable
) {
1210 // normal value type, no null check
1211 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
1212 ccall
.add_argument (new
CCodeConstant ("0"));
1213 ccall
.add_argument (new
CCodeConstant ("NULL"));
1214 ccall
.add_argument (new
CCodeConstant ("0"));
1219 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
1221 /* can be simplified to
1222 * foo = (unref (foo), NULL)
1223 * if foo is of static type non-null
1226 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cvar
, new
CCodeConstant ("NULL"));
1227 if (type
.type_parameter
!= null) {
1228 if (!(current_type_symbol is Class
) || current_class
.is_compact
) {
1229 return new
CCodeConstant ("NULL");
1232 // unref functions are optional for type parameters
1233 var cunrefisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_destroy_func_expression (type
), new
CCodeConstant ("NULL"));
1234 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cunrefisnull
);
1237 ccall
.add_argument (cvar
);
1239 /* set freed references to NULL to prevent further use */
1240 var ccomma
= new
CCodeCommaExpression ();
1242 ccomma
.append_expression (ccall
);
1243 ccomma
.append_expression (new
CCodeConstant ("NULL"));
1245 var cassign
= new
CCodeAssignment (cvar
, ccomma
);
1247 return new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), cassign
);
1250 public override void visit_end_full_expression (Expression expr
) {
1251 /* expr is a full expression, i.e. an initializer, the
1252 * expression in an expression statement, the controlling
1253 * expression in if, while, for, or foreach statements
1255 * we unref temporary variables at the end of a full
1259 /* can't automatically deep copy lists yet, so do it
1262 * expr.temp_vars = temp_vars;
1263 * when deep list copying works
1265 if (temp_vars
.size
> 0) {
1266 if (expr
.temp_vars
== null) {
1267 expr
.temp_vars
= new ArrayList
<LocalVariable
> ();
1269 expr
.temp_vars
.clear ();
1271 foreach (LocalVariable local
in temp_vars
) {
1272 expr
.temp_vars
.add (local
);
1277 if (((List
<LocalVariable
>) temp_ref_vars
).size
== 0) {
1278 /* nothing to do without temporary variables */
1282 var expr_type
= expr
.value_type
;
1283 if (expr
.target_type
!= null) {
1284 expr_type
= expr
.target_type
;
1287 var full_expr_var
= get_temp_variable (expr_type
, true, expr
);
1288 expr
.add_temp_var (full_expr_var
);
1290 var expr_list
= new
CCodeCommaExpression ();
1291 expr_list
.append_expression (new
CCodeAssignment (get_variable_cexpression (full_expr_var
.name
), (CCodeExpression
) expr
.ccodenode
));
1293 foreach (LocalVariable local
in temp_ref_vars
) {
1294 var ma
= new MemberAccess
.simple (local
.name
);
1295 ma
.symbol_reference
= local
;
1296 expr_list
.append_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
1299 expr_list
.append_expression (get_variable_cexpression (full_expr_var
.name
));
1301 expr
.ccodenode
= expr_list
;
1303 temp_ref_vars
.clear ();
1306 public void append_temp_decl (CCodeFragment cfrag
, List
<LocalVariable
>? temp_vars
) {
1307 if (temp_vars
== null) {
1310 foreach (LocalVariable local
in temp_vars
) {
1311 var cdecl
= new
CCodeDeclaration (local
.variable_type
.get_cname ());
1313 var vardecl
= new
CCodeVariableDeclarator (local
.name
, null, local
.variable_type
.get_cdeclarator_suffix ());
1315 local
.ccodenode
= vardecl
;
1316 cdecl
.add_declarator (vardecl
);
1318 var st
= local
.variable_type
.data_type as Struct
;
1319 var array_type
= local
.variable_type as ArrayType
;
1321 if (local
.name
.has_prefix ("*")) {
1322 // do not dereference unintialized variable
1323 // initialization is not needed for these special
1324 // pointer temp variables
1325 // used to avoid side-effects in assignments
1326 } else if (local
.variable_type is GenericType
) {
1327 var value_size
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_get_value_size"));
1328 value_size
.add_argument (get_type_id_expression (local
.variable_type
));
1330 var alloca_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("alloca"));
1331 alloca_call
.add_argument (value_size
);
1333 var memset_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
1334 memset_call
.add_argument (alloca_call
);
1335 memset_call
.add_argument (new
CCodeConstant ("0"));
1336 memset_call
.add_argument (value_size
);
1338 vardecl
.initializer
= memset_call
;
1339 vardecl
.init0
= true;
1340 } else if (!local
.variable_type
.nullable
&&
1341 (st
!= null && st
.get_fields ().size
> 0) ||
1342 (array_type
!= null && array_type
.fixed_length
)) {
1343 // 0-initialize struct with struct initializer { 0 }
1344 // necessary as they will be passed by reference
1345 var clist
= new
CCodeInitializerList ();
1346 clist
.append (new
CCodeConstant ("0"));
1348 vardecl
.initializer
= clist
;
1349 vardecl
.init0
= true;
1350 } else if (local
.variable_type
.is_reference_type_or_type_parameter () ||
1351 local
.variable_type
.nullable
) {
1352 vardecl
.initializer
= new
CCodeConstant ("NULL");
1353 vardecl
.init0
= true;
1356 cfrag
.append (cdecl
);
1360 public override void visit_expression_statement (ExpressionStatement stmt
) {
1361 if (stmt
.expression
.error
) {
1366 stmt
.ccodenode
= new
CCodeExpressionStatement ((CCodeExpression
) stmt
.expression
.ccodenode
);
1368 if (stmt
.tree_can_fail
&& stmt
.expression
.tree_can_fail
) {
1369 // simple case, no node breakdown necessary
1371 var cfrag
= new
CCodeFragment ();
1373 cfrag
.append (stmt
.ccodenode
);
1375 add_simple_check (stmt
.expression
, cfrag
);
1377 stmt
.ccodenode
= cfrag
;
1380 /* free temporary objects */
1382 if (((List
<LocalVariable
>) temp_vars
).size
== 0
1383 && pre_statement_fragment
== null) {
1384 /* nothing to do without temporary variables */
1388 var cfrag
= new
CCodeFragment ();
1389 append_temp_decl (cfrag
, temp_vars
);
1391 if (pre_statement_fragment
!= null) {
1392 cfrag
.append (pre_statement_fragment
);
1393 pre_statement_fragment
= null;
1396 cfrag
.append (stmt
.ccodenode
);
1398 foreach (LocalVariable local
in temp_ref_vars
) {
1399 var ma
= new MemberAccess
.simple (local
.name
);
1400 ma
.symbol_reference
= local
;
1401 cfrag
.append (new
CCodeExpressionStatement (get_unref_expression (new
CCodeIdentifier (local
.name
), local
.variable_type
, ma
)));
1404 stmt
.ccodenode
= cfrag
;
1407 temp_ref_vars
.clear ();
1410 public void create_temp_decl (Statement stmt
, List
<LocalVariable
>? temp_vars
) {
1411 /* declare temporary variables */
1413 if (temp_vars
== null || temp_vars
.size
== 0) {
1414 /* nothing to do without temporary variables */
1418 var cfrag
= new
CCodeFragment ();
1419 append_temp_decl (cfrag
, temp_vars
);
1421 cfrag
.append (stmt
.ccodenode
);
1423 stmt
.ccodenode
= cfrag
;
1426 public virtual void append_local_free (Symbol sym
, CCodeFragment cfrag
, bool stop_at_loop
= false) {
1427 var b
= (Block
) sym
;
1429 var local_vars
= b
.get_local_variables ();
1430 // free in reverse order
1431 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1432 var local
= local_vars
[i
];
1433 if (local
.active
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
1434 var ma
= new MemberAccess
.simple (local
.name
);
1435 ma
.symbol_reference
= local
;
1436 cfrag
.append (new
CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
)));
1441 int block_id
= get_block_id (b
);
1443 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_unref"));
1444 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
1445 cfrag
.append (new
CCodeExpressionStatement (data_unref
));
1449 if (b
.parent_node is Loop
||
1450 b
.parent_node is ForeachStatement
||
1451 b
.parent_node is SwitchStatement
) {
1456 if (sym
.parent_symbol is Block
) {
1457 append_local_free (sym
.parent_symbol
, cfrag
, stop_at_loop
);
1458 } else if (sym
.parent_symbol is Method
) {
1459 append_param_free ((Method
) sym
.parent_symbol
, cfrag
);
1463 public void append_error_free (Symbol sym
, CCodeFragment cfrag
, TryStatement current_try
) {
1464 var b
= (Block
) sym
;
1466 var local_vars
= b
.get_local_variables ();
1467 // free in reverse order
1468 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1469 var local
= local_vars
[i
];
1470 if (local
.active
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
1471 var ma
= new MemberAccess
.simple (local
.name
);
1472 ma
.symbol_reference
= local
;
1473 cfrag
.append (new
CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
)));
1478 int block_id
= get_block_id (b
);
1480 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_unref"));
1481 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
1482 cfrag
.append (new
CCodeExpressionStatement (data_unref
));
1485 if (sym
== current_try
.body
) {
1489 if (sym
.parent_symbol is Block
) {
1490 append_error_free (sym
.parent_symbol
, cfrag
, current_try
);
1491 } else if (sym
.parent_symbol is Method
) {
1492 append_param_free ((Method
) sym
.parent_symbol
, cfrag
);
1496 private void append_param_free (Method m
, CCodeFragment cfrag
) {
1497 foreach (FormalParameter param
in m
.get_parameters ()) {
1498 if (requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
1499 var ma
= new MemberAccess
.simple (param
.name
);
1500 ma
.symbol_reference
= param
;
1501 cfrag
.append (new
CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param
.name
), param
.variable_type
, ma
)));
1506 public void create_local_free (CodeNode stmt
, bool stop_at_loop
= false) {
1507 var cfrag
= new
CCodeFragment ();
1509 append_local_free (current_symbol
, cfrag
, stop_at_loop
);
1511 cfrag
.append (stmt
.ccodenode
);
1512 stmt
.ccodenode
= cfrag
;
1515 public override void visit_return_statement (ReturnStatement stmt
) {
1516 var cfrag
= new
CCodeFragment ();
1518 // free local variables
1519 append_local_free (current_symbol
, cfrag
);
1521 cfrag
.append (new
CCodeReturnStatement ((current_return_type is VoidType
) ?
null : new
CCodeIdentifier ("result")));
1523 stmt
.ccodenode
= cfrag
;
1526 public override void visit_delete_statement (DeleteStatement stmt
) {
1527 var pointer_type
= (PointerType
) stmt
.expression
.value_type
;
1528 DataType type
= pointer_type
;
1529 if (pointer_type
.base_type
.data_type
!= null && pointer_type
.base_type
.data_type
.is_reference_type ()) {
1530 type
= pointer_type
.base_type
;
1533 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
1534 ccall
.add_argument ((CCodeExpression
) stmt
.expression
.ccodenode
);
1535 stmt
.ccodenode
= new
CCodeExpressionStatement (ccall
);
1538 public override void visit_expression (Expression expr
) {
1539 if (expr
.ccodenode
!= null && !expr
.lvalue
) {
1540 // memory management, implicit casts, and boxing/unboxing
1541 expr
.ccodenode
= transform_expression ((CCodeExpression
) expr
.ccodenode
, expr
.value_type
, expr
.target_type
, expr
);
1545 public override void visit_boolean_literal (BooleanLiteral expr
) {
1546 expr
.ccodenode
= new
CCodeConstant (expr
.value ?
"true" : "false");
1549 public override void visit_character_literal (CharacterLiteral expr
) {
1550 if (expr
.get_char () >= 0x20 && expr
.get_char () < 0x80) {
1551 expr
.ccodenode
= new
CCodeConstant (expr
.value
);
1553 expr
.ccodenode
= new
CCodeConstant ("%uU".printf (expr
.get_char ()));
1557 public override void visit_integer_literal (IntegerLiteral expr
) {
1558 expr
.ccodenode
= new
CCodeConstant (expr
.value
);
1561 public override void visit_real_literal (RealLiteral expr
) {
1562 string c_literal
= expr
.value
;
1563 if (c_literal
.has_suffix ("d") || c_literal
.has_suffix ("D")) {
1564 // there is no suffix for double in C
1565 c_literal
= c_literal
.substring (0, c_literal
.length
- 1);
1567 if (!("." in c_literal
|| "e" in c_literal
|| "E" in c_literal
)) {
1568 // C requires period or exponent part for floating constants
1569 if ("f" in c_literal
|| "F" in c_literal
) {
1570 c_literal
= c_literal
.substring (0, c_literal
.length
- 1) + ".f";
1575 expr
.ccodenode
= new
CCodeConstant (c_literal
);
1578 public override void visit_string_literal (StringLiteral expr
) {
1579 // FIXME handle escaped characters in scanner/parser and escape them here again for C
1580 var cliteral
= new
CCodeConstant ("\"\\0\" " + expr
.value
);
1582 var cbinary
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, cliteral
, new
CCodeConstant ("1"));
1583 expr
.ccodenode
= new
CCodeCastExpression (cbinary
, "string_t");
1586 public override void visit_null_literal (NullLiteral expr
) {
1587 expr
.ccodenode
= new
CCodeConstant ("NULL");
1590 public override void visit_base_access (BaseAccess expr
) {
1591 generate_type_declaration (expr
.value_type
, source_declarations
);
1592 expr
.ccodenode
= new
CCodeCastExpression (new
CCodeIdentifier ("this"), expr
.value_type
.get_cname ());
1595 public override void visit_postfix_expression (PostfixExpression expr
) {
1596 MemberAccess ma
= find_property_access (expr
.inner
);
1598 // property postfix expression
1599 var prop
= (Property
) ma
.symbol_reference
;
1601 var ccomma
= new
CCodeCommaExpression ();
1603 // assign current value to temp variable
1604 var temp_decl
= get_temp_variable (prop
.property_type
, true, expr
);
1605 temp_vars
.add (temp_decl
);
1606 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_decl
.name
), (CCodeExpression
) expr
.inner
.ccodenode
));
1608 // increment/decrement property
1609 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
1610 var cexpr
= new
CCodeBinaryExpression (op
, get_variable_cexpression (temp_decl
.name
), new
CCodeConstant ("1"));
1611 var ccall
= get_property_set_call (prop
, ma
, cexpr
);
1612 ccomma
.append_expression (ccall
);
1614 // return previous value
1615 ccomma
.append_expression (new
CCodeIdentifier (temp_decl
.name
));
1617 expr
.ccodenode
= ccomma
;
1621 var op
= expr
.increment ? CCodeUnaryOperator
.POSTFIX_INCREMENT
: CCodeUnaryOperator
.POSTFIX_DECREMENT
;
1623 expr
.ccodenode
= new
CCodeUnaryExpression (op
, (CCodeExpression
) expr
.inner
.ccodenode
);
1626 private MemberAccess?
find_property_access (Expression expr
) {
1627 if (!(expr is MemberAccess
)) {
1631 var ma
= (MemberAccess
) expr
;
1632 if (ma
.symbol_reference is Property
) {
1639 public bool requires_copy (DataType type
) {
1640 if (!type
.is_disposable ()) {
1644 var cl
= type
.data_type as Class
;
1645 if (cl
!= null && cl
.is_reference_counting ()
1646 && cl
.get_ref_function () == "") {
1647 // empty ref_function => no ref necessary
1651 if (type
.type_parameter
!= null) {
1658 public bool requires_destroy (DataType type
) {
1659 if (!type
.is_disposable ()) {
1663 var array_type
= type as ArrayType
;
1664 if (array_type
!= null && array_type
.inline_allocated
) {
1665 return requires_destroy (array_type
.element_type
);
1668 var cl
= type
.data_type as Class
;
1669 if (cl
!= null && cl
.is_reference_counting ()
1670 && cl
.get_unref_function () == "") {
1671 // empty unref_function => no unref necessary
1675 if (type
.type_parameter
!= null) {
1682 bool is_ref_function_void (DataType type
) {
1683 var cl
= type
.data_type as Class
;
1684 if (cl
!= null && cl
.ref_function_void
) {
1691 public virtual CCodeExpression?
get_ref_cexpression (DataType expression_type
, CCodeExpression cexpr
, Expression? expr
, CodeNode node
) {
1692 if (expression_type is ValueType
&& !expression_type
.nullable
) {
1693 // normal value type, no null check
1694 // (copy (&temp, 0, &expr, 0), temp)
1696 var decl
= get_temp_variable (expression_type
, false, node
);
1697 temp_vars
.add (decl
);
1699 var ctemp
= get_variable_cexpression (decl
.name
);
1701 var vt
= (ValueType
) expression_type
;
1702 var st
= (Struct
) vt
.type_symbol
;
1703 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_copy_function ()));
1704 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
1705 copy_call
.add_argument (new
CCodeConstant ("0"));
1706 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
1707 copy_call
.add_argument (new
CCodeConstant ("0"));
1709 var ccomma
= new
CCodeCommaExpression ();
1711 ccomma
.append_expression (copy_call
);
1712 ccomma
.append_expression (ctemp
);
1717 /* (temp = expr, temp == NULL ? NULL : ref (temp))
1719 * can be simplified to
1721 * if static type of expr is non-null
1724 var dupexpr
= get_dup_func_expression (expression_type
, node
.source_reference
);
1726 if (dupexpr
== null) {
1731 var ccall
= new
CCodeFunctionCall (dupexpr
);
1733 if (expr
!= null && expr
.is_non_null ()
1734 && !is_ref_function_void (expression_type
)) {
1735 // expression is non-null
1736 ccall
.add_argument ((CCodeExpression
) expr
.ccodenode
);
1740 var decl
= get_temp_variable (expression_type
, false, node
);
1741 temp_vars
.add (decl
);
1743 var ctemp
= get_variable_cexpression (decl
.name
);
1745 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, new
CCodeConstant ("NULL"));
1746 if (expression_type
.type_parameter
!= null) {
1747 // dup functions are optional for type parameters
1748 var cdupisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_dup_func_expression (expression_type
, node
.source_reference
), new
CCodeConstant ("NULL"));
1749 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cdupisnull
);
1752 ccall
.add_argument (ctemp
);
1754 var ccomma
= new
CCodeCommaExpression ();
1755 ccomma
.append_expression (new
CCodeAssignment (ctemp
, cexpr
));
1757 var cifnull
= new
CCodeConstant ("NULL");
1758 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, cifnull
, ccall
));
1760 // repeat temp variable at the end of the comma expression
1761 // if the ref function returns void
1762 if (is_ref_function_void (expression_type
)) {
1763 ccomma
.append_expression (ctemp
);
1770 public virtual void generate_class_declaration (Class cl
, CCodeDeclarationSpace decl_space
) {
1771 if (decl_space
.add_symbol_declaration (cl
, cl
.get_cname ())) {
1776 public virtual void generate_interface_declaration (Interface iface
, CCodeDeclarationSpace decl_space
) {
1779 public virtual void generate_method_declaration (Method m
, CCodeDeclarationSpace decl_space
) {
1782 public void add_generic_type_arguments (CCodeFunctionCall ccall
, List
<DataType
> type_args
, CodeNode expr
, bool is_chainup
= false) {
1783 foreach (var type_arg
in type_args
) {
1784 ccall
.add_argument (get_type_id_expression (type_arg
, is_chainup
));
1788 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
1789 CCodeExpression instance
= null;
1790 CCodeExpression creation_expr
= null;
1792 var st
= expr
.type_reference
.data_type as Struct
;
1794 bool struct_by_ref
= false;
1795 if (st
!= null && !st
.is_boolean_type () && !st
.is_integer_type () && !st
.is_floating_type ()) {
1796 struct_by_ref
= true;
1799 if (struct_by_ref
|| expr
.get_object_initializer ().size
> 0) {
1800 // value-type initialization or object creation expression with object initializer
1801 var temp_decl
= get_temp_variable (expr
.type_reference
, false, expr
);
1802 temp_vars
.add (temp_decl
);
1804 instance
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
1807 if (expr
.symbol_reference
== null) {
1808 // no creation method
1809 if (expr
.type_reference
.data_type is Struct
) {
1810 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
1811 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
1812 creation_call
.add_argument (new
CCodeConstant ("0"));
1813 creation_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (expr
.type_reference
.get_cname ())));
1815 creation_expr
= creation_call
;
1817 } else if (expr
.symbol_reference is Method
) {
1818 // use creation method
1819 var m
= (Method
) expr
.symbol_reference
;
1820 var params
= m
.get_parameters ();
1821 CCodeFunctionCall creation_call
;
1823 generate_method_declaration (m
, source_declarations
);
1825 var cl
= expr
.type_reference
.data_type as Class
;
1827 if (!m
.has_new_function
) {
1828 // use construct function directly
1829 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
1830 creation_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
1832 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_cname ()));
1835 if (struct_by_ref
&& !(m
.cinstance_parameter_position
< 0)) {
1836 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
1839 generate_type_declaration (expr
.type_reference
, source_declarations
);
1841 if (cl
!= null && !cl
.is_compact
) {
1842 add_generic_type_arguments (creation_call
, expr
.type_reference
.get_type_arguments (), expr
);
1845 bool ellipsis
= false;
1848 Iterator
<FormalParameter
> params_it
= params
.iterator ();
1849 foreach (Expression arg
in expr
.get_argument_list ()) {
1850 CCodeExpression cexpr
= (CCodeExpression
) arg
.ccodenode
;
1851 FormalParameter param
= null;
1852 if (params_it
.next ()) {
1853 param
= params_it
.get ();
1854 ellipsis
= param
.ellipsis
;
1856 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
1860 creation_call
.add_argument (cexpr
);
1864 while (params_it
.next ()) {
1865 var param
= params_it
.get ();
1867 if (param
.ellipsis
) {
1872 if (param
.initializer
== null) {
1873 Report
.error (expr
.source_reference
, "no default expression for argument %d".printf (i
));
1877 /* evaluate default expression here as the code
1878 * generator might not have visited the formal
1880 param
.initializer
.emit (this
);
1882 creation_call
.add_argument ((CCodeExpression
) param
.initializer
.ccodenode
);
1886 if (struct_by_ref
&& m
.cinstance_parameter_position
< 0) {
1887 // instance parameter is at the end in a struct creation method
1888 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
1892 /* ensure variable argument list ends with NULL
1893 * except when using printf-style arguments */
1894 if (!m
.printf_format
&& !m
.scanf_format
&& m
.sentinel
!= "") {
1895 creation_call
.add_argument (new
CCodeConstant (m
.sentinel
));
1899 creation_expr
= creation_call
;
1901 // cast the return value of the creation method back to the intended type if
1902 // it requested a special C return type
1903 if (get_custom_creturn_type (m
) != null) {
1904 creation_expr
= new
CCodeCastExpression (creation_expr
, expr
.type_reference
.get_cname ());
1910 if (instance
!= null) {
1911 var ccomma
= new
CCodeCommaExpression ();
1913 if (expr
.type_reference
.data_type is Struct
) {
1914 ccomma
.append_expression (creation_expr
);
1916 ccomma
.append_expression (new
CCodeAssignment (instance
, creation_expr
));
1919 foreach (MemberInitializer init
in expr
.get_object_initializer ()) {
1920 if (init
.symbol_reference is Field
) {
1921 var f
= (Field
) init
.symbol_reference
;
1922 var instance_target_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
1923 var typed_inst
= transform_expression (instance
, expr
.type_reference
, instance_target_type
);
1924 CCodeExpression lhs
;
1925 if (expr
.type_reference
.data_type is Struct
) {
1926 lhs
= new
CCodeMemberAccess (typed_inst
, f
.get_cname ());
1928 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, f
.get_cname ());
1930 ccomma
.append_expression (new
CCodeAssignment (lhs
, (CCodeExpression
) init
.initializer
.ccodenode
));
1931 } else if (init
.symbol_reference is Property
) {
1932 var inst_ma
= new MemberAccess
.simple ("new");
1933 inst_ma
.value_type
= expr
.type_reference
;
1934 inst_ma
.ccodenode
= instance
;
1935 var ma
= new
MemberAccess (inst_ma
, init
.name
);
1936 ccomma
.append_expression (get_property_set_call ((Property
) init
.symbol_reference
, ma
, (CCodeExpression
) init
.initializer
.ccodenode
));
1940 ccomma
.append_expression (instance
);
1942 expr
.ccodenode
= ccomma
;
1943 } else if (creation_expr
!= null) {
1944 expr
.ccodenode
= creation_expr
;
1948 public CCodeExpression?
handle_struct_argument (FormalParameter param
, Expression arg
, CCodeExpression? cexpr
) {
1949 if (arg
.formal_target_type is GenericType
&& !(arg
.target_type is GenericType
)) {
1950 // we already use a reference for arguments of ref and out parameters
1951 if (param
.direction
== ParameterDirection
.IN
) {
1952 var unary
= cexpr as CCodeUnaryExpression
;
1953 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
1956 } else if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
1957 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
1959 // if cexpr is e.g. a function call, we can't take the address of the expression
1960 // (tmp = expr, &tmp)
1961 var ccomma
= new
CCodeCommaExpression ();
1963 var temp_var
= get_temp_variable (arg
.target_type
);
1964 temp_vars
.add (temp_var
);
1965 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), cexpr
));
1966 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (temp_var
.name
)));
1976 public override void visit_sizeof_expression (SizeofExpression expr
) {
1977 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
1978 csizeof
.add_argument (new
CCodeIdentifier (expr
.type_reference
.get_cname ()));
1979 expr
.ccodenode
= csizeof
;
1982 public override void visit_typeof_expression (TypeofExpression expr
) {
1983 expr
.ccodenode
= get_type_id_expression (expr
.type_reference
);
1986 public override void visit_unary_expression (UnaryExpression expr
) {
1987 CCodeUnaryOperator op
;
1988 if (expr
.operator
== UnaryOperator
.PLUS
) {
1989 op
= CCodeUnaryOperator
.PLUS
;
1990 } else if (expr
.operator
== UnaryOperator
.MINUS
) {
1991 op
= CCodeUnaryOperator
.MINUS
;
1992 } else if (expr
.operator
== UnaryOperator
.LOGICAL_NEGATION
) {
1993 op
= CCodeUnaryOperator
.LOGICAL_NEGATION
;
1994 } else if (expr
.operator
== UnaryOperator
.BITWISE_COMPLEMENT
) {
1995 op
= CCodeUnaryOperator
.BITWISE_COMPLEMENT
;
1996 } else if (expr
.operator
== UnaryOperator
.INCREMENT
) {
1997 op
= CCodeUnaryOperator
.PREFIX_INCREMENT
;
1998 } else if (expr
.operator
== UnaryOperator
.DECREMENT
) {
1999 op
= CCodeUnaryOperator
.PREFIX_DECREMENT
;
2000 } else if (expr
.operator
== UnaryOperator
.REF
) {
2001 op
= CCodeUnaryOperator
.ADDRESS_OF
;
2002 } else if (expr
.operator
== UnaryOperator
.OUT
) {
2003 op
= CCodeUnaryOperator
.ADDRESS_OF
;
2005 assert_not_reached ();
2007 expr
.ccodenode
= new
CCodeUnaryExpression (op
, (CCodeExpression
) expr
.inner
.ccodenode
);
2010 public override void visit_cast_expression (CastExpression expr
) {
2011 if (expr
.is_silent_cast
) {
2013 Report
.error (expr
.source_reference
, "Operation not supported for this type");
2017 if (expr
.type_reference
.data_type
!= null && expr
.type_reference
.data_type
.get_full_name () == "Dova.Value") {
2019 var temp_decl
= get_temp_variable (expr
.inner
.value_type
, true, expr
);
2020 temp_vars
.add (temp_decl
);
2021 var cvar
= get_variable_cexpression (temp_decl
.name
);
2023 var ccomma
= new
CCodeCommaExpression ();
2024 ccomma
.append_expression (new
CCodeAssignment (cvar
, (CCodeExpression
) expr
.inner
.ccodenode
));
2026 var to_any
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_value_to_any"));
2027 to_any
.add_argument (get_type_id_expression (expr
.inner
.value_type
));
2028 to_any
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
2029 to_any
.add_argument (new
CCodeConstant ("0"));
2030 ccomma
.append_expression (to_any
);
2032 expr
.ccodenode
= ccomma
;
2034 } else if (expr
.inner
.value_type
.data_type
!= null && expr
.inner
.value_type
.data_type
.get_full_name () == "Dova.Value") {
2036 var temp_decl
= get_temp_variable (expr
.type_reference
, true, expr
);
2037 temp_vars
.add (temp_decl
);
2038 var cvar
= get_variable_cexpression (temp_decl
.name
);
2040 var ccomma
= new
CCodeCommaExpression ();
2042 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
2043 sizeof_call
.add_argument (new
CCodeIdentifier (expr
.type_reference
.get_cname ()));
2045 var to_any
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_value_from_any"));
2046 to_any
.add_argument (get_type_id_expression (expr
.type_reference
));
2047 to_any
.add_argument ((CCodeExpression
) expr
.inner
.ccodenode
);
2048 to_any
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
2049 to_any
.add_argument (new
CCodeConstant ("0"));
2050 ccomma
.append_expression (to_any
);
2052 ccomma
.append_expression (cvar
);
2054 expr
.ccodenode
= ccomma
;
2058 generate_type_declaration (expr
.type_reference
, source_declarations
);
2060 if (expr
.inner
.value_type is GenericType
&& !(expr
.type_reference is GenericType
)) {
2061 // generic types use an extra pointer, dereference that pointer
2062 expr
.ccodenode
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeCastExpression ((CCodeExpression
) expr
.inner
.ccodenode
, expr
.type_reference
.get_cname () + "*"));
2064 expr
.ccodenode
= new
CCodeCastExpression ((CCodeExpression
) expr
.inner
.ccodenode
, expr
.type_reference
.get_cname ());
2068 public override void visit_pointer_indirection (PointerIndirection expr
) {
2069 expr
.ccodenode
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, (CCodeExpression
) expr
.inner
.ccodenode
);
2072 public override void visit_addressof_expression (AddressofExpression expr
) {
2073 expr
.ccodenode
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, (CCodeExpression
) expr
.inner
.ccodenode
);
2076 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
2077 /* (tmp = var, var = null, tmp) */
2078 var ccomma
= new
CCodeCommaExpression ();
2079 var temp_decl
= get_temp_variable (expr
.value_type
, true, expr
);
2080 temp_vars
.add (temp_decl
);
2081 var cvar
= get_variable_cexpression (temp_decl
.name
);
2083 ccomma
.append_expression (new
CCodeAssignment (cvar
, (CCodeExpression
) expr
.inner
.ccodenode
));
2084 ccomma
.append_expression (new
CCodeAssignment ((CCodeExpression
) expr
.inner
.ccodenode
, new
CCodeConstant ("NULL")));
2085 ccomma
.append_expression (cvar
);
2086 expr
.ccodenode
= ccomma
;
2089 public override void visit_binary_expression (BinaryExpression expr
) {
2090 var cleft
= (CCodeExpression
) expr
.left
.ccodenode
;
2091 var cright
= (CCodeExpression
) expr
.right
.ccodenode
;
2093 CCodeBinaryOperator op
;
2094 if (expr
.operator
== BinaryOperator
.PLUS
) {
2095 op
= CCodeBinaryOperator
.PLUS
;
2096 } else if (expr
.operator
== BinaryOperator
.MINUS
) {
2097 op
= CCodeBinaryOperator
.MINUS
;
2098 } else if (expr
.operator
== BinaryOperator
.MUL
) {
2099 op
= CCodeBinaryOperator
.MUL
;
2100 } else if (expr
.operator
== BinaryOperator
.DIV
) {
2101 op
= CCodeBinaryOperator
.DIV
;
2102 } else if (expr
.operator
== BinaryOperator
.MOD
) {
2103 op
= CCodeBinaryOperator
.MOD
;
2104 } else if (expr
.operator
== BinaryOperator
.SHIFT_LEFT
) {
2105 op
= CCodeBinaryOperator
.SHIFT_LEFT
;
2106 } else if (expr
.operator
== BinaryOperator
.SHIFT_RIGHT
) {
2107 op
= CCodeBinaryOperator
.SHIFT_RIGHT
;
2108 } else if (expr
.operator
== BinaryOperator
.LESS_THAN
) {
2109 op
= CCodeBinaryOperator
.LESS_THAN
;
2110 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN
) {
2111 op
= CCodeBinaryOperator
.GREATER_THAN
;
2112 } else if (expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
) {
2113 op
= CCodeBinaryOperator
.LESS_THAN_OR_EQUAL
;
2114 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
2115 op
= CCodeBinaryOperator
.GREATER_THAN_OR_EQUAL
;
2116 } else if (expr
.operator
== BinaryOperator
.EQUALITY
) {
2117 op
= CCodeBinaryOperator
.EQUALITY
;
2118 } else if (expr
.operator
== BinaryOperator
.INEQUALITY
) {
2119 op
= CCodeBinaryOperator
.INEQUALITY
;
2120 } else if (expr
.operator
== BinaryOperator
.BITWISE_AND
) {
2121 op
= CCodeBinaryOperator
.BITWISE_AND
;
2122 } else if (expr
.operator
== BinaryOperator
.BITWISE_OR
) {
2123 op
= CCodeBinaryOperator
.BITWISE_OR
;
2124 } else if (expr
.operator
== BinaryOperator
.BITWISE_XOR
) {
2125 op
= CCodeBinaryOperator
.BITWISE_XOR
;
2126 } else if (expr
.operator
== BinaryOperator
.AND
) {
2127 op
= CCodeBinaryOperator
.AND
;
2128 } else if (expr
.operator
== BinaryOperator
.OR
) {
2129 op
= CCodeBinaryOperator
.OR
;
2130 } else if (expr
.operator
== BinaryOperator
.IN
) {
2131 expr
.ccodenode
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeBinaryExpression (CCodeBinaryOperator
.BITWISE_AND
, cright
, cleft
), cleft
);
2134 assert_not_reached ();
2137 if (expr
.operator
== BinaryOperator
.EQUALITY
||
2138 expr
.operator
== BinaryOperator
.INEQUALITY
) {
2139 var left_type_as_struct
= expr
.left
.value_type
.data_type as Struct
;
2140 var right_type_as_struct
= expr
.right
.value_type
.data_type as Struct
;
2142 if (expr
.left
.value_type
.data_type is Class
&& !((Class
) expr
.left
.value_type
.data_type
).is_compact
&&
2143 expr
.right
.value_type
.data_type is Class
&& !((Class
) expr
.right
.value_type
.data_type
).is_compact
) {
2144 var left_cl
= (Class
) expr
.left
.value_type
.data_type
;
2145 var right_cl
= (Class
) expr
.right
.value_type
.data_type
;
2147 if (left_cl
!= right_cl
) {
2148 if (left_cl
.is_subtype_of (right_cl
)) {
2149 cleft
= generate_instance_cast (cleft
, right_cl
);
2150 } else if (right_cl
.is_subtype_of (left_cl
)) {
2151 cright
= generate_instance_cast (cright
, left_cl
);
2154 } else if (left_type_as_struct
!= null && right_type_as_struct
!= null) {
2155 // FIXME generate and use compare/equal function for real structs
2156 if (expr
.left
.value_type
.nullable
&& expr
.right
.value_type
.nullable
) {
2157 // FIXME also compare contents, not just address
2158 } else if (expr
.left
.value_type
.nullable
) {
2159 // FIXME check left value is not null
2160 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cleft
);
2161 } else if (expr
.right
.value_type
.nullable
) {
2162 // FIXME check right value is not null
2163 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cright
);
2168 expr
.ccodenode
= new
CCodeBinaryExpression (op
, cleft
, cright
);
2171 public string?
get_type_check_function (TypeSymbol type
) {
2172 var cl
= type as Class
;
2173 if (cl
!= null && cl
.type_check_function
!= null) {
2174 return cl
.type_check_function
;
2175 } else if ((cl
!= null && cl
.is_compact
) || type is Struct
|| type is Enum
|| type is Delegate
) {
2178 return type
.get_upper_case_cname ("IS_");
2182 CCodeExpression?
create_type_check (CCodeNode ccodenode
, DataType type
) {
2183 string type_check_func
= get_type_check_function (type
.data_type
);
2184 if (type_check_func
== null) {
2185 return new
CCodeInvalidExpression ();
2187 var ccheck
= new
CCodeFunctionCall (new
CCodeIdentifier (type_check_func
));
2188 ccheck
.add_argument ((CCodeExpression
) ccodenode
);
2192 public override void visit_type_check (TypeCheck expr
) {
2193 generate_type_declaration (expr
.type_reference
, source_declarations
);
2195 expr
.ccodenode
= create_type_check (expr
.expression
.ccodenode
, expr
.type_reference
);
2196 if (expr
.ccodenode is CCodeInvalidExpression
) {
2197 Report
.error (expr
.source_reference
, "type check expressions not supported for compact classes, structs, and enums");
2201 public override void visit_lambda_expression (LambdaExpression l
) {
2202 // use instance position from delegate
2203 var dt
= (DelegateType
) l
.target_type
;
2204 l
.method
.cinstance_parameter_position
= dt
.delegate_symbol
.cinstance_parameter_position
;
2206 l
.accept_children (this
);
2208 l
.ccodenode
= new
CCodeIdentifier (l
.method
.get_cname ());
2211 // manage memory and implicit casts
2212 public CCodeExpression
transform_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
2213 var cexpr
= source_cexpr
;
2214 if (expression_type
== null) {
2219 if (expression_type
.value_owned
2220 && (target_type
== null || !target_type
.value_owned
)) {
2221 // value leaked, destroy it
2222 var pointer_type
= target_type as PointerType
;
2223 if (pointer_type
!= null && !(pointer_type
.base_type is VoidType
)) {
2224 // manual memory management for non-void pointers
2225 // treat void* special to not leak memory with void* method parameters
2226 } else if (requires_destroy (expression_type
)) {
2227 var decl
= get_temp_variable (expression_type
, true, expression_type
);
2228 temp_vars
.add (decl
);
2229 temp_ref_vars
.insert (0, decl
);
2230 cexpr
= new
CCodeAssignment (get_variable_cexpression (decl
.name
), cexpr
);
2234 if (target_type
== null) {
2235 // value will be destroyed, no need for implicit casts
2239 cexpr
= get_implicit_cast_expression (cexpr
, expression_type
, target_type
, expr
);
2241 if (target_type
.value_owned
&& !expression_type
.value_owned
) {
2242 // need to copy value
2243 if (requires_copy (target_type
) && !(expression_type is NullType
)) {
2244 CodeNode node
= expr
;
2246 node
= expression_type
;
2248 cexpr
= get_ref_cexpression (target_type
, cexpr
, expr
, node
);
2255 public virtual CCodeExpression
get_implicit_cast_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
2256 var cexpr
= source_cexpr
;
2258 if (expression_type
.data_type
!= null && expression_type
.data_type
== target_type
.data_type
) {
2259 // same type, no cast required
2263 if (expression_type is NullType
) {
2264 // null literal, no cast required when not converting to generic type pointer
2268 generate_type_declaration (target_type
, source_declarations
);
2270 if (target_type is DelegateType
&& expression_type is MethodType
) {
2271 var deleg_type
= (DelegateType
) target_type
;
2272 var method_type
= (MethodType
) expression_type
;
2273 CCodeExpression delegate_target
;
2274 if (expr is LambdaExpression
) {
2275 var lambda
= (LambdaExpression
) expr
;
2276 if (lambda
.method
.closure
) {
2277 int block_id
= get_block_id (current_closure_block
);
2278 delegate_target
= get_variable_cexpression ("_data%d_".printf (block_id
));
2279 } else if (get_this_type () != null) {
2280 delegate_target
= new
CCodeIdentifier ("this");
2282 delegate_target
= new
CCodeConstant ("NULL");
2285 if (method_type
.method_symbol
.binding
== MemberBinding
.INSTANCE
) {
2286 var ma
= (MemberAccess
) expr
;
2287 delegate_target
= (CCodeExpression
) get_ccodenode (ma
.inner
);
2289 delegate_target
= new
CCodeConstant ("NULL");
2293 var d
= deleg_type
.delegate_symbol
;
2295 string wrapper_name
= "_wrapper%d_".printf (next_wrapper_id
++);
2296 var wrapper
= new
CCodeFunction (wrapper_name
);
2297 wrapper
.modifiers
= CCodeModifiers
.STATIC
;
2298 var call
= new
CCodeFunctionCall (source_cexpr
);
2300 if (method_type
.method_symbol
.binding
== MemberBinding
.INSTANCE
) {
2301 wrapper
.add_parameter (new
CCodeFormalParameter ("this", "void *"));
2302 call
.add_argument (new
CCodeIdentifier ("this"));
2305 var method_param_iter
= method_type
.method_symbol
.get_parameters ().iterator ();
2306 foreach (FormalParameter param
in d
.get_parameters ()) {
2307 method_param_iter
.next ();
2308 var method_param
= method_param_iter
.get ();
2309 string ctype
= param
.variable_type
.get_cname ();
2310 if (param
.variable_type is GenericType
&& !(method_param
.variable_type is GenericType
)) {
2311 ctype
= method_param
.variable_type
.get_cname () + "*";
2312 call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier (param
.name
)));
2313 } else if (!(param
.variable_type is GenericType
) && method_param
.variable_type is GenericType
) {
2314 call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (param
.name
)));
2316 call
.add_argument (new
CCodeIdentifier (param
.name
));
2319 wrapper
.add_parameter (new
CCodeFormalParameter (param
.name
, ctype
));
2322 wrapper
.block
= new
CCodeBlock ();
2323 if (d
.return_type is VoidType
) {
2324 wrapper
.block
.add_statement (new
CCodeExpressionStatement (call
));
2326 var method_return_type
= method_type
.method_symbol
.return_type
;
2327 if (d
.return_type is GenericType
&& !(method_return_type is GenericType
)) {
2328 wrapper
.add_parameter (new
CCodeFormalParameter ("result", method_return_type
.get_cname () + "*"));
2329 wrapper
.block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("result")), call
)));
2330 } else if (!(d
.return_type is GenericType
) && method_return_type is GenericType
) {
2331 wrapper
.return_type
= d
.return_type
.get_cname ();
2332 var cdecl
= new
CCodeDeclaration (d
.return_type
.get_cname ());
2333 cdecl
.add_declarator (new
CCodeVariableDeclarator ("result"));
2334 call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("result")));
2335 wrapper
.block
.add_statement (new
CCodeExpressionStatement (call
));
2336 wrapper
.block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("result")));
2337 } else if (d
.return_type is GenericType
) {
2338 wrapper
.add_parameter (new
CCodeFormalParameter ("result", "void *"));
2339 wrapper
.block
.add_statement (new
CCodeExpressionStatement (call
));
2341 wrapper
.return_type
= d
.return_type
.get_cname ();
2342 wrapper
.block
.add_statement (new
CCodeReturnStatement (call
));
2346 source_type_member_definition
.append (wrapper
);
2348 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_new".printf (deleg_type
.delegate_symbol
.get_lower_case_cname ())));
2349 ccall
.add_argument (delegate_target
);
2350 ccall
.add_argument (new
CCodeIdentifier (wrapper_name
));
2354 var cl
= target_type
.data_type as Class
;
2355 var iface
= target_type
.data_type as Interface
;
2356 if (context
.checking
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
2357 // checked cast for strict subtypes of GTypeInstance
2358 return generate_instance_cast (cexpr
, target_type
.data_type
);
2359 } else if (target_type
.data_type
!= null && expression_type
.get_cname () != target_type
.get_cname ()) {
2360 var st
= target_type
.data_type as Struct
;
2361 if (target_type
.data_type
.is_reference_type () || (st
!= null && st
.is_simple_type ())) {
2362 // don't cast non-simple structs
2363 return new
CCodeCastExpression (cexpr
, target_type
.get_cname ());
2372 public CCodeFunctionCall
get_property_set_call (Property prop
, MemberAccess ma
, CCodeExpression cexpr
, Expression? rhs
= null) {
2375 var base_property
= prop
;
2376 if (prop
.base_property
!= null) {
2377 base_property
= prop
.base_property
;
2378 } else if (prop
.base_interface_property
!= null) {
2379 base_property
= prop
.base_interface_property
;
2382 generate_property_accessor_declaration (base_property
.set_accessor
, source_declarations
);
2383 set_func
= base_property
.set_accessor
.get_cname ();
2385 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (set_func
));
2387 if (prop
.binding
== MemberBinding
.INSTANCE
) {
2388 /* target instance is first argument */
2389 ccall
.add_argument ((CCodeExpression
) get_ccodenode (ma
.inner
));
2392 ccall
.add_argument (cexpr
);
2397 public bool add_generated_external_symbol (Symbol external_symbol
) {
2398 return generated_external_symbols
.add (external_symbol
);
2401 public static DataType
get_data_type_for_symbol (TypeSymbol sym
) {
2402 DataType type
= null;
2405 type
= new
ObjectType ((Class
) sym
);
2406 } else if (sym is Interface
) {
2407 type
= new
ObjectType ((Interface
) sym
);
2408 } else if (sym is Struct
) {
2409 var st
= (Struct
) sym
;
2410 if (st
.is_boolean_type ()) {
2411 type
= new
BooleanType (st
);
2412 } else if (st
.is_integer_type ()) {
2413 type
= new
IntegerType (st
);
2414 } else if (st
.is_floating_type ()) {
2415 type
= new
FloatingType (st
);
2417 type
= new
StructValueType (st
);
2419 } else if (sym is Enum
) {
2420 type
= new
EnumValueType ((Enum
) sym
);
2422 Report
.error (null, "internal error: `%s' is not a supported type".printf (sym
.get_full_name ()));
2423 return new
InvalidType ();
2429 public CCodeExpression?
default_value_for_type (DataType type
, bool initializer_expression
) {
2430 var st
= type
.data_type as Struct
;
2431 var array_type
= type as ArrayType
;
2432 if (type is GenericType
) {
2433 var value_size
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_get_value_size"));
2434 value_size
.add_argument (get_type_id_expression (type
));
2436 var alloca_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("alloca"));
2437 alloca_call
.add_argument (value_size
);
2439 var memset_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
2440 memset_call
.add_argument (alloca_call
);
2441 memset_call
.add_argument (new
CCodeConstant ("0"));
2442 memset_call
.add_argument (value_size
);
2445 } else if (initializer_expression
&& !type
.nullable
&&
2446 ((st
!= null && st
.get_fields ().size
> 0) ||
2447 (array_type
!= null && array_type
.fixed_length
))) {
2448 // 0-initialize struct with struct initializer { 0 }
2449 // only allowed as initializer expression in C
2450 var clist
= new
CCodeInitializerList ();
2451 clist
.append (new
CCodeConstant ("0"));
2453 } else if ((type
.data_type
!= null && type
.data_type
.is_reference_type ())
2455 || type is PointerType
|| type is DelegateType
2456 || (array_type
!= null && !array_type
.fixed_length
)) {
2457 return new
CCodeConstant ("NULL");
2458 } else if (type
.data_type
!= null && type
.data_type
.get_default_value () != null) {
2459 return new
CCodeConstant (type
.data_type
.get_default_value ());
2464 public CCodeNode?
get_ccodenode (CodeNode node
) {
2465 if (node
.ccodenode
== null) {
2468 return node
.ccodenode
;
2471 public DataType?
get_this_type () {
2472 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) {
2473 return current_method
.this_parameter
.variable_type
;
2474 } else if (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
) {
2475 return current_property_accessor
.prop
.this_parameter
.variable_type
;
2480 public CCodeExpression
generate_instance_cast (CCodeExpression expr
, TypeSymbol type
) {
2481 return new
CCodeCastExpression (expr
, type
.get_cname () + "*");
2484 public virtual string?
get_custom_creturn_type (Method m
) {
2488 public virtual bool method_has_wrapper (Method method
) {
2492 public virtual void add_simple_check (CodeNode node
, CCodeFragment cfrag
, bool always_fails
= false) {