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 abstract 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 CCodeFunction ccode
;
34 public ArrayList
<CCodeFunction
> ccode_stack
= new ArrayList
<CCodeFunction
> ();
35 public ArrayList
<LocalVariable
> temp_ref_vars
= new ArrayList
<LocalVariable
> ();
36 public int next_temp_var_id
;
37 public Map
<string,string> variable_name_map
= new HashMap
<string,string> (str_hash
, str_equal
);
39 public EmitContext (Symbol? symbol
= null) {
40 current_symbol
= symbol
;
43 public void push_symbol (Symbol symbol
) {
44 symbol_stack
.add (current_symbol
);
45 current_symbol
= symbol
;
48 public void pop_symbol () {
49 current_symbol
= symbol_stack
[symbol_stack
.size
- 1];
50 symbol_stack
.remove_at (symbol_stack
.size
- 1);
54 public CodeContext context
{ get; set; }
56 public Symbol root_symbol
;
58 public EmitContext emit_context
= new
EmitContext ();
60 List
<EmitContext
> emit_context_stack
= new ArrayList
<EmitContext
> ();
62 public Symbol current_symbol
{ get { return emit_context
.current_symbol
; } }
64 public TryStatement current_try
{
65 get { return emit_context
.current_try
; }
66 set { emit_context
.current_try
= value
; }
69 public TypeSymbol? current_type_symbol
{
71 var sym
= current_symbol
;
73 if (sym is TypeSymbol
) {
74 return (TypeSymbol
) sym
;
76 sym
= sym
.parent_symbol
;
82 public Class? current_class
{
83 get { return current_type_symbol as Class
; }
86 public Method? current_method
{
88 var sym
= current_symbol
;
89 while (sym is Block
) {
90 sym
= sym
.parent_symbol
;
96 public PropertyAccessor? current_property_accessor
{
98 var sym
= current_symbol
;
99 while (sym is Block
) {
100 sym
= sym
.parent_symbol
;
102 return sym as PropertyAccessor
;
106 public DataType? current_return_type
{
108 var m
= current_method
;
110 return m
.return_type
;
113 var acc
= current_property_accessor
;
116 return acc
.value_type
;
126 public Block? current_closure_block
{
128 return next_closure_block (current_symbol
);
132 public unowned Block?
next_closure_block (Symbol sym
) {
133 unowned Block block
= null;
135 block
= sym as Block
;
136 if (!(sym is Block
|| sym is Method
)) {
140 if (block
!= null && block
.captured
) {
141 // closure block found
144 sym
= sym
.parent_symbol
;
149 public CCodeFile header_file
;
150 public CCodeFile cfile
;
152 string? csource_filename
;
154 public CCodeFunction ccode
{ get { return emit_context
.ccode
; } }
156 /* temporary variables that own their content */
157 public ArrayList
<LocalVariable
> temp_ref_vars
{ get { return emit_context
.temp_ref_vars
; } }
158 /* (constant) hash table with all reserved identifiers in the generated code */
159 Set
<string> reserved_identifiers
;
161 public List
<Field
> static_fields
= new ArrayList
<Field
> ();
163 public int next_temp_var_id
{
164 get { return emit_context
.next_temp_var_id
; }
165 set { emit_context
.next_temp_var_id
= value
; }
168 public int next_wrapper_id
= 0;
169 public bool in_creation_method
{ get { return current_method is CreationMethod
; } }
170 int next_block_id
= 0;
171 Map
<Block
,int> block_map
= new HashMap
<Block
,int> ();
173 public DataType void_type
= new
VoidType ();
174 public DataType bool_type
;
175 public DataType char_type
;
176 public DataType int_type
;
177 public DataType uint_type
;
178 public DataType string_type
;
179 public DataType float_type
;
180 public DataType double_type
;
181 public Class object_class
;
182 public Class type_class
;
183 public Class value_class
;
184 public Class string_class
;
185 public Class array_class
;
186 public Class delegate_class
;
187 public Class error_class
;
189 Set
<Symbol
> generated_external_symbols
;
191 public Map
<string,string> variable_name_map
{ get { return emit_context
.variable_name_map
; } }
193 public DovaBaseModule () {
194 reserved_identifiers
= new HashSet
<string> (str_hash
, str_equal
);
197 reserved_identifiers
.add ("_Bool");
198 reserved_identifiers
.add ("_Complex");
199 reserved_identifiers
.add ("_Imaginary");
200 reserved_identifiers
.add ("auto");
201 reserved_identifiers
.add ("break");
202 reserved_identifiers
.add ("case");
203 reserved_identifiers
.add ("char");
204 reserved_identifiers
.add ("const");
205 reserved_identifiers
.add ("continue");
206 reserved_identifiers
.add ("default");
207 reserved_identifiers
.add ("do");
208 reserved_identifiers
.add ("double");
209 reserved_identifiers
.add ("else");
210 reserved_identifiers
.add ("enum");
211 reserved_identifiers
.add ("extern");
212 reserved_identifiers
.add ("float");
213 reserved_identifiers
.add ("for");
214 reserved_identifiers
.add ("goto");
215 reserved_identifiers
.add ("if");
216 reserved_identifiers
.add ("inline");
217 reserved_identifiers
.add ("int");
218 reserved_identifiers
.add ("long");
219 reserved_identifiers
.add ("register");
220 reserved_identifiers
.add ("restrict");
221 reserved_identifiers
.add ("return");
222 reserved_identifiers
.add ("short");
223 reserved_identifiers
.add ("signed");
224 reserved_identifiers
.add ("sizeof");
225 reserved_identifiers
.add ("static");
226 reserved_identifiers
.add ("struct");
227 reserved_identifiers
.add ("switch");
228 reserved_identifiers
.add ("typedef");
229 reserved_identifiers
.add ("union");
230 reserved_identifiers
.add ("unsigned");
231 reserved_identifiers
.add ("void");
232 reserved_identifiers
.add ("volatile");
233 reserved_identifiers
.add ("while");
235 // reserved for Vala naming conventions
236 reserved_identifiers
.add ("result");
237 reserved_identifiers
.add ("this");
240 public override void emit (CodeContext context
) {
241 this
.context
= context
;
243 root_symbol
= context
.root
;
245 bool_type
= new
BooleanType ((Struct
) root_symbol
.scope
.lookup ("bool"));
246 char_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("char"));
247 int_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("int"));
248 uint_type
= new
IntegerType ((Struct
) root_symbol
.scope
.lookup ("uint"));
249 float_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("float"));
250 double_type
= new
FloatingType ((Struct
) root_symbol
.scope
.lookup ("double"));
251 string_type
= new
ObjectType ((Class
) root_symbol
.scope
.lookup ("string"));
253 var dova_ns
= (Namespace
) root_symbol
.scope
.lookup ("Dova");
254 object_class
= (Class
) dova_ns
.scope
.lookup ("Object");
255 type_class
= (Class
) dova_ns
.scope
.lookup ("Type");
256 value_class
= (Class
) dova_ns
.scope
.lookup ("Value");
257 string_class
= (Class
) root_symbol
.scope
.lookup ("string");
258 array_class
= (Class
) dova_ns
.scope
.lookup ("Array");
259 delegate_class
= (Class
) dova_ns
.scope
.lookup ("Delegate");
260 error_class
= (Class
) dova_ns
.scope
.lookup ("Error");
262 header_file
= new
CCodeFile ();
263 header_file
.is_header
= true;
265 cfile
= new
CCodeFile ();
267 if (context
.nostdpkg
) {
268 header_file
.add_include ("dova-types.h");
269 cfile
.add_include ("dova-types.h");
271 header_file
.add_include ("dova-base.h");
272 cfile
.add_include ("dova-base.h");
275 generated_external_symbols
= new HashSet
<Symbol
> ();
278 /* we're only interested in non-pkg source files */
279 var source_files
= context
.get_source_files ();
280 foreach (SourceFile file
in source_files
) {
281 if (file
.file_type
== SourceFileType
.SOURCE
) {
286 if (csource_filename
!= null) {
287 if (!cfile
.store (csource_filename
, null, context
.version_header
, context
.debug
)) {
288 Report
.error (null, "unable to open `%s' for writing".printf (csource_filename
));
295 // generate C header file for public API
296 if (context
.header_filename
!= null) {
297 if (!header_file
.store (context
.header_filename
, null, context
.version_header
, false)) {
298 Report
.error (null, "unable to open `%s' for writing".printf (context
.header_filename
));
303 public void push_context (EmitContext emit_context
) {
304 if (this
.emit_context
!= null) {
305 emit_context_stack
.add (this
.emit_context
);
308 this
.emit_context
= emit_context
;
311 public void pop_context () {
312 if (emit_context_stack
.size
> 0) {
313 this
.emit_context
= emit_context_stack
[emit_context_stack
.size
- 1];
314 emit_context_stack
.remove_at (emit_context_stack
.size
- 1);
316 this
.emit_context
= null;
320 public void push_function (CCodeFunction func
) {
321 emit_context
.ccode_stack
.add (ccode
);
322 emit_context
.ccode
= func
;
325 public void pop_function () {
326 emit_context
.ccode
= emit_context
.ccode_stack
[emit_context
.ccode_stack
.size
- 1];
327 emit_context
.ccode_stack
.remove_at (emit_context
.ccode_stack
.size
- 1);
330 public bool add_symbol_declaration (CCodeFile decl_space
, Symbol sym
, string name
) {
331 if (decl_space
.add_declaration (name
)) {
334 if (sym
.external_package
|| (!decl_space
.is_header
&& CodeContext
.get ().use_header
&& !sym
.is_internal_symbol ())) {
335 // add appropriate include file
336 foreach (string header_filename
in sym
.get_cheader_filenames ()) {
337 decl_space
.add_include (header_filename
, !sym
.external_package
);
339 // declaration complete
342 // require declaration
347 public override void visit_source_file (SourceFile source_file
) {
348 if (csource_filename
== null) {
349 csource_filename
= source_file
.get_csource_filename ();
351 var writer
= new
CCodeWriter (source_file
.get_csource_filename ());
352 if (!writer
.open (context
.version_header
)) {
353 Report
.error (null, "unable to open `%s' for writing".printf (writer
.filename
));
359 source_file
.accept_children (this
);
361 if (context
.report
.get_errors () > 0) {
366 public void generate_enum_declaration (Enum en
, CCodeFile decl_space
) {
367 if (add_symbol_declaration (decl_space
, en
, en
.get_cname ())) {
371 var cenum
= new
CCodeEnum (en
.get_cname ());
373 foreach (EnumValue ev
in en
.get_values ()) {
374 if (ev
.value
== null) {
375 cenum
.add_value (new
CCodeEnumValue (ev
.get_cname ()));
377 ev
.value
.emit (this
);
378 cenum
.add_value (new
CCodeEnumValue (ev
.get_cname (), get_cvalue (ev
.value
)));
382 decl_space
.add_type_definition (cenum
);
383 decl_space
.add_type_definition (new
CCodeNewline ());
386 public override void visit_enum (Enum en
) {
387 en
.accept_children (this
);
389 generate_enum_declaration (en
, cfile
);
391 if (!en
.is_internal_symbol ()) {
392 generate_enum_declaration (en
, header_file
);
396 public void generate_constant_declaration (Constant c
, CCodeFile decl_space
) {
397 if (add_symbol_declaration (decl_space
, c
, c
.get_cname ())) {
404 if (c
.value is InitializerList
) {
405 var cdecl
= new
CCodeDeclaration (c
.type_reference
.get_const_cname ());
407 if (c
.type_reference is ArrayType
) {
410 cdecl
.add_declarator (new
CCodeVariableDeclarator ("%s%s".printf (c
.get_cname (), arr
), get_cvalue (c
.value
)));
411 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
413 decl_space
.add_constant_declaration (cdecl
);
415 var cdefine
= new CCodeMacroReplacement
.with_expression (c
.get_cname (), get_cvalue (c
.value
));
416 decl_space
.add_type_member_declaration (cdefine
);
421 public override void visit_constant (Constant c
) {
422 generate_constant_declaration (c
, cfile
);
424 if (!c
.is_internal_symbol ()) {
425 generate_constant_declaration (c
, header_file
);
429 public void generate_field_declaration (Field f
, CCodeFile decl_space
) {
430 if (add_symbol_declaration (decl_space
, f
, f
.get_cname ())) {
434 generate_type_declaration (f
.variable_type
, decl_space
);
436 string field_ctype
= f
.variable_type
.get_cname ();
438 field_ctype
= "volatile " + field_ctype
;
441 var cdecl
= new
CCodeDeclaration (field_ctype
);
442 cdecl
.add_declarator (new
CCodeVariableDeclarator (f
.get_cname ()));
443 if (f
.is_internal_symbol ()) {
444 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
446 cdecl
.modifiers
= CCodeModifiers
.EXTERN
;
449 if (f
.get_attribute ("ThreadLocal") != null) {
450 cdecl
.modifiers
|= CCodeModifiers
.THREAD_LOCAL
;
453 decl_space
.add_type_member_declaration (cdecl
);
456 public override void visit_field (Field f
) {
457 if (f
.binding
== MemberBinding
.STATIC
) {
458 generate_field_declaration (f
, cfile
);
460 if (!f
.is_internal_symbol ()) {
461 generate_field_declaration (f
, header_file
);
464 var var_decl
= new
CCodeVariableDeclarator (f
.get_cname ());
465 var_decl
.initializer
= default_value_for_type (f
.variable_type
, true);
467 if (f
.initializer
!= null) {
468 static_fields
.add (f
);
471 string field_ctype
= f
.variable_type
.get_cname ();
473 field_ctype
= "volatile " + field_ctype
;
476 var var_def
= new
CCodeDeclaration (field_ctype
);
477 var_def
.add_declarator (var_decl
);
478 if (!f
.is_internal_symbol ()) {
479 var_def
.modifiers
= CCodeModifiers
.EXTERN
;
481 var_def
.modifiers
= CCodeModifiers
.STATIC
;
484 if (f
.get_attribute ("ThreadLocal") != null) {
485 var_def
.modifiers
|= CCodeModifiers
.THREAD_LOCAL
;
488 cfile
.add_type_member_declaration (var_def
);
492 public bool is_constant_ccode_expression (CCodeExpression cexpr
) {
493 if (cexpr is CCodeConstant
) {
495 } else if (cexpr is CCodeCastExpression
) {
496 var ccast
= (CCodeCastExpression
) cexpr
;
497 return is_constant_ccode_expression (ccast
.inner
);
498 } else if (cexpr is CCodeBinaryExpression
) {
499 var cbinary
= (CCodeBinaryExpression
) cexpr
;
500 return is_constant_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
503 var cparenthesized
= (cexpr as CCodeParenthesizedExpression
);
504 return (null != cparenthesized
&& is_constant_ccode_expression (cparenthesized
.inner
));
508 * Returns whether the passed cexpr is a pure expression, i.e. an
509 * expression without side-effects.
511 public bool is_pure_ccode_expression (CCodeExpression cexpr
) {
512 if (cexpr is CCodeConstant
|| cexpr is CCodeIdentifier
) {
514 } else if (cexpr is CCodeBinaryExpression
) {
515 var cbinary
= (CCodeBinaryExpression
) cexpr
;
516 return is_pure_ccode_expression (cbinary
.left
) && is_constant_ccode_expression (cbinary
.right
);
517 } else if (cexpr is CCodeUnaryExpression
) {
518 var cunary
= (CCodeUnaryExpression
) cexpr
;
519 switch (cunary
.operator
) {
520 case CCodeUnaryOperator
.PREFIX_INCREMENT
:
521 case CCodeUnaryOperator
.PREFIX_DECREMENT
:
522 case CCodeUnaryOperator
.POSTFIX_INCREMENT
:
523 case CCodeUnaryOperator
.POSTFIX_DECREMENT
:
526 return is_pure_ccode_expression (cunary
.inner
);
528 } else if (cexpr is CCodeMemberAccess
) {
529 var cma
= (CCodeMemberAccess
) cexpr
;
530 return is_pure_ccode_expression (cma
.inner
);
531 } else if (cexpr is CCodeElementAccess
) {
532 var cea
= (CCodeElementAccess
) cexpr
;
533 return is_pure_ccode_expression (cea
.container
) && is_pure_ccode_expression (cea
.index
);
534 } else if (cexpr is CCodeCastExpression
) {
535 var ccast
= (CCodeCastExpression
) cexpr
;
536 return is_pure_ccode_expression (ccast
.inner
);
537 } else if (cexpr is CCodeParenthesizedExpression
) {
538 var cparenthesized
= (CCodeParenthesizedExpression
) cexpr
;
539 return is_pure_ccode_expression (cparenthesized
.inner
);
545 public override void visit_formal_parameter (Parameter p
) {
548 public override void visit_property (Property prop
) {
549 if (prop
.get_accessor
!= null) {
550 prop
.get_accessor
.accept (this
);
552 if (prop
.set_accessor
!= null) {
553 prop
.set_accessor
.accept (this
);
557 public void generate_type_declaration (DataType type
, CCodeFile decl_space
) {
558 if (type is ObjectType
) {
559 var object_type
= (ObjectType
) type
;
560 if (object_type
.type_symbol is Class
) {
561 generate_class_declaration ((Class
) object_type
.type_symbol
, decl_space
);
562 } else if (object_type
.type_symbol is Interface
) {
563 generate_interface_declaration ((Interface
) object_type
.type_symbol
, decl_space
);
565 } else if (type is DelegateType
) {
566 var deleg_type
= (DelegateType
) type
;
567 var d
= deleg_type
.delegate_symbol
;
568 generate_delegate_declaration (d
, decl_space
);
569 } else if (type
.data_type is Enum
) {
570 var en
= (Enum
) type
.data_type
;
571 generate_enum_declaration (en
, decl_space
);
572 } else if (type is ValueType
) {
573 var value_type
= (ValueType
) type
;
574 generate_struct_declaration ((Struct
) value_type
.type_symbol
, decl_space
);
575 } else if (type is ArrayType
) {
576 var array_type
= (ArrayType
) type
;
577 generate_type_declaration (array_type
.element_type
, decl_space
);
578 } else if (type is PointerType
) {
579 var pointer_type
= (PointerType
) type
;
580 generate_type_declaration (pointer_type
.base_type
, decl_space
);
583 foreach (DataType type_arg
in type
.get_type_arguments ()) {
584 generate_type_declaration (type_arg
, decl_space
);
588 public virtual void generate_struct_declaration (Struct st
, CCodeFile decl_space
) {
591 public virtual void generate_delegate_declaration (Delegate d
, CCodeFile decl_space
) {
594 public virtual void generate_cparameters (Method m
, CCodeFile decl_space
, CCodeFunction func
, CCodeFunctionDeclarator? vdeclarator
= null, CCodeFunctionCall? vcall
= null) {
597 public virtual void generate_property_accessor_declaration (PropertyAccessor acc
, CCodeFile decl_space
) {
600 public int get_block_id (Block b
) {
601 int result
= block_map
[b
];
603 result
= ++next_block_id
;
604 block_map
[b
] = result
;
609 void capture_parameter (Parameter param
, CCodeStruct data
, int block_id
, CCodeBlock free_block
) {
610 generate_type_declaration (param
.variable_type
, cfile
);
612 var param_type
= param
.variable_type
.copy ();
613 param_type
.value_owned
= true;
614 data
.add_field (param_type
.get_cname (), get_variable_cname (param
.name
));
616 // create copy if necessary as captured variables may need to be kept alive
617 CCodeExpression cparam
= get_variable_cexpression (param
.name
);
618 if (requires_copy (param_type
) && !param
.variable_type
.value_owned
) {
619 var ma
= new MemberAccess
.simple (param
.name
);
620 ma
.symbol_reference
= param
;
621 ma
.value_type
= param
.variable_type
.copy ();
622 // directly access parameters in ref expressions
623 param
.captured
= false;
624 cparam
= get_ref_cexpression (param
.variable_type
, cparam
, ma
, param
);
625 param
.captured
= true;
628 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), get_variable_cname (param
.name
)), cparam
);
630 if (requires_destroy (param_type
)) {
631 var ma
= new MemberAccess
.simple (param
.name
);
632 ma
.symbol_reference
= param
;
633 ma
.value_type
= param_type
.copy ();
634 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
)));
638 public override void visit_block (Block b
) {
639 emit_context
.push_symbol (b
);
641 var local_vars
= b
.get_local_variables ();
643 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
) {
648 var parent_block
= next_closure_block (b
.parent_symbol
);
650 int block_id
= get_block_id (b
);
651 string struct_name
= "Block%dData".printf (block_id
);
653 var free_block
= new
CCodeBlock ();
655 var data
= new
CCodeStruct ("_" + struct_name
);
656 data
.add_field ("DovaType*", "type");
657 data
.add_field ("int32_t", "_ref_count_");
658 if (parent_block
!= null) {
659 int parent_block_id
= get_block_id (parent_block
);
661 data
.add_field ("Block%dData *".printf (parent_block_id
), "_data%d_".printf (parent_block_id
));
663 var unref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_unref"));
664 unref_call
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
)));
665 free_block
.add_statement (new
CCodeExpressionStatement (unref_call
));
666 } else if ((current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) ||
667 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
668 data
.add_field ("%s *".printf (current_class
.get_cname ()), "this");
670 var ma
= new MemberAccess
.simple ("this");
671 ma
.symbol_reference
= current_class
;
672 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
)));
674 foreach (var local
in local_vars
) {
675 if (local
.captured
) {
676 generate_type_declaration (local
.variable_type
, cfile
);
678 data
.add_field (local
.variable_type
.get_cname (), get_variable_cname (local
.name
) + local
.variable_type
.get_cdeclarator_suffix ());
681 // free in reverse order
682 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
683 var local
= local_vars
[i
];
684 if (local
.captured
) {
685 if (requires_destroy (local
.variable_type
)) {
686 var ma
= new MemberAccess
.simple (local
.name
);
687 ma
.symbol_reference
= local
;
688 ma
.value_type
= local
.variable_type
.copy ();
689 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
)));
694 var data_alloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_alloc"));
695 data_alloc
.add_argument (new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_type_get".printf (block_id
))));
697 var data_decl
= new
CCodeDeclaration (struct_name
+ "*");
698 data_decl
.add_declarator (new
CCodeVariableDeclarator ("_data%d_".printf (block_id
), data_alloc
));
699 ccode
.add_statement (data_decl
);
701 if (parent_block
!= null) {
702 int parent_block_id
= get_block_id (parent_block
);
704 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_ref"));
705 ref_call
.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id
)));
707 ccode
.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
)));
708 } else if ((current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) ||
709 (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
)) {
710 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (new
ObjectType (current_class
), b
.source_reference
));
711 ref_call
.add_argument (new
CCodeIdentifier ("this"));
713 ccode
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), "this"), ref_call
)));
716 if (b
.parent_symbol is Method
) {
717 var m
= (Method
) b
.parent_symbol
;
719 // parameters are captured with the top-level block of the method
720 foreach (var param
in m
.get_parameters ()) {
721 if (param
.captured
) {
722 capture_parameter (param
, data
, block_id
, free_block
);
725 } else if (b
.parent_symbol is PropertyAccessor
) {
726 var acc
= (PropertyAccessor
) b
.parent_symbol
;
728 if (!acc
.readable
&& acc
.value_parameter
.captured
) {
729 capture_parameter (acc
.value_parameter
, data
, block_id
, free_block
);
733 var typedef
= new
CCodeTypeDefinition ("struct _" + struct_name
, new
CCodeVariableDeclarator (struct_name
));
734 cfile
.add_type_declaration (typedef
);
735 cfile
.add_type_definition (data
);
737 var data_free
= new
CCodeFunctionCall (new
CCodeIdentifier ("free"));
738 data_free
.add_argument (new
CCodeIdentifier ("_data%d_".printf (block_id
)));
739 free_block
.add_statement (new
CCodeExpressionStatement (data_free
));
741 // create type_get/finalize functions
742 var type_get_fun
= new
CCodeFunction ("block%d_data_type_get".printf (block_id
), "DovaType*");
743 type_get_fun
.modifiers
= CCodeModifiers
.STATIC
;
744 cfile
.add_function_declaration (type_get_fun
);
745 type_get_fun
.block
= new
CCodeBlock ();
747 var cdecl
= new
CCodeDeclaration ("intptr_t");
748 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_block%d_data_object_offset".printf (block_id
), new
CCodeConstant ("0")));
749 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
750 cfile
.add_type_member_declaration (cdecl
);
752 cdecl
= new
CCodeDeclaration ("intptr_t");
753 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_block%d_data_type_offset".printf (block_id
), new
CCodeConstant ("0")));
754 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
755 cfile
.add_type_member_declaration (cdecl
);
757 cdecl
= new
CCodeDeclaration ("DovaType *");
758 cdecl
.add_declarator (new
CCodeVariableDeclarator ("block%d_data_type".printf (block_id
), new
CCodeConstant ("NULL")));
759 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
760 cfile
.add_type_member_declaration (cdecl
);
762 var type_init_block
= new
CCodeBlock ();
763 var alloc_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_alloc"));
764 alloc_call
.add_argument (new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_type_get")));
765 alloc_call
.add_argument (new
CCodeConstant ("sizeof (%s)".printf (struct_name
)));
766 alloc_call
.add_argument (new
CCodeConstant ("0"));
767 alloc_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("block%d_data_type".printf (block_id
))));
768 alloc_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("_block%d_data_object_offset".printf (block_id
))));
769 alloc_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("_block%d_data_type_offset".printf (block_id
))));
770 type_init_block
.add_statement (new
CCodeExpressionStatement (alloc_call
));
771 var type_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_type_init"));
772 type_init_call
.add_argument (new
CCodeIdentifier ("block%d_data_type".printf (block_id
)));
773 type_init_block
.add_statement (new
CCodeExpressionStatement (type_init_call
));
774 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
));
775 type_get_fun
.block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("block%d_data_type".printf (block_id
))));
777 cfile
.add_function (type_get_fun
);
779 var unref_fun
= new
CCodeFunction ("block%d_data_finalize".printf (block_id
), "void");
780 unref_fun
.add_parameter (new
CCodeParameter ("_data%d_".printf (block_id
), struct_name
+ "*"));
781 unref_fun
.modifiers
= CCodeModifiers
.STATIC
;
782 cfile
.add_function_declaration (unref_fun
);
783 unref_fun
.block
= free_block
;
785 cfile
.add_function (unref_fun
);
788 foreach (Statement stmt
in b
.get_statements ()) {
792 // free in reverse order
793 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
794 var local
= local_vars
[i
];
795 if (!local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
796 var ma
= new MemberAccess
.simple (local
.name
);
797 ma
.symbol_reference
= local
;
798 ccode
.add_statement (new
CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
)));
802 if (b
.parent_symbol is Method
) {
803 var m
= (Method
) b
.parent_symbol
;
804 foreach (Parameter param
in m
.get_parameters ()) {
805 if (!param
.captured
&& requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
806 var ma
= new MemberAccess
.simple (param
.name
);
807 ma
.symbol_reference
= param
;
808 ccode
.add_statement (new
CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param
.name
), param
.variable_type
, ma
)));
814 int block_id
= get_block_id (b
);
816 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_unref"));
817 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
818 ccode
.add_statement (new
CCodeExpressionStatement (data_unref
));
821 if (b
.parent_node is Block
|| b
.parent_node is SwitchStatement
) {
825 emit_context
.pop_symbol ();
828 public override void visit_declaration_statement (DeclarationStatement stmt
) {
829 stmt
.declaration
.accept (this
);
832 public CCodeExpression
get_variable_cexpression (string name
) {
833 return new
CCodeIdentifier (get_variable_cname (name
));
836 public string get_variable_cname (string name
) {
837 if (name
[0] == '.') {
838 // compiler-internal variable
839 if (!variable_name_map
.contains (name
)) {
840 variable_name_map
.set (name
, "_tmp%d_".printf (next_temp_var_id
));
843 return variable_name_map
.get (name
);
844 } else if (reserved_identifiers
.contains (name
)) {
845 return "_%s_".printf (name
);
851 public override void visit_local_variable (LocalVariable local
) {
852 if (local
.initializer
!= null) {
853 local
.initializer
.emit (this
);
855 visit_end_full_expression (local
.initializer
);
858 generate_type_declaration (local
.variable_type
, cfile
);
860 CCodeExpression rhs
= null;
861 if (local
.initializer
!= null && get_cvalue (local
.initializer
) != null) {
862 rhs
= get_cvalue (local
.initializer
);
865 if (local
.captured
) {
866 if (local
.initializer
!= null) {
867 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id ((Block
) local
.parent_symbol
))), get_variable_cname (local
.name
)), rhs
);
870 var cvar
= new
CCodeVariableDeclarator (get_variable_cname (local
.name
), rhs
, local
.variable_type
.get_cdeclarator_suffix ());
872 var cdecl
= new
CCodeDeclaration (local
.variable_type
.get_cname ());
873 cdecl
.add_declarator (cvar
);
874 ccode
.add_statement (cdecl
);
876 // try to initialize uninitialized variables
877 // initialization not necessary for variables stored in closure
878 if (cvar
.initializer
== null) {
879 cvar
.initializer
= default_value_for_type (local
.variable_type
, true);
884 if (local
.initializer
!= null && local
.initializer
.tree_can_fail
) {
885 add_simple_check (local
.initializer
);
891 public override void visit_initializer_list (InitializerList list
) {
892 if (list
.target_type
.data_type is Struct
) {
893 /* initializer is used as struct initializer */
894 var st
= (Struct
) list
.target_type
.data_type
;
896 var clist
= new
CCodeInitializerList ();
898 var field_it
= st
.get_fields ().iterator ();
899 foreach (Expression expr
in list
.get_initializers ()) {
901 while (field
== null) {
903 field
= field_it
.get ();
904 if (field
.binding
!= MemberBinding
.INSTANCE
) {
905 // we only initialize instance fields
910 var cexpr
= get_cvalue (expr
);
912 string ctype
= field
.get_ctype ();
914 cexpr
= new
CCodeCastExpression (cexpr
, ctype
);
917 clist
.append (cexpr
);
920 set_cvalue (list
, clist
);
922 var clist
= new
CCodeInitializerList ();
923 foreach (Expression expr
in list
.get_initializers ()) {
924 clist
.append (get_cvalue (expr
));
926 set_cvalue (list
, clist
);
930 public override LocalVariable
create_local (DataType type
) {
931 var result
= get_temp_variable (type
, type
.value_owned
);
932 emit_temp_var (result
);
936 public LocalVariable
get_temp_variable (DataType type
, bool value_owned
= true, CodeNode? node_reference
= null) {
937 var var_type
= type
.copy ();
938 var_type
.value_owned
= value_owned
;
939 var local
= new
LocalVariable (var_type
, "_tmp%d_".printf (next_temp_var_id
));
941 if (node_reference
!= null) {
942 local
.source_reference
= node_reference
.source_reference
;
950 bool is_in_generic_type (DataType type
) {
951 if (type
.type_parameter
.parent_symbol is TypeSymbol
952 && (current_method
== null || current_method
.binding
== MemberBinding
.INSTANCE
)) {
959 public CCodeExpression
get_type_private_from_type (ObjectTypeSymbol type_symbol
, CCodeExpression type_expression
) {
960 if (type_symbol is Class
) {
962 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 ()));
965 var get_interface
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_get_interface"));
966 get_interface
.add_argument (type_expression
);
967 get_interface
.add_argument (new
CCodeIdentifier ("%s_type".printf (((Interface
) type_symbol
).get_lower_case_cname ())));
968 return new
CCodeCastExpression (get_interface
, "%sTypePrivate *".printf (((Interface
) type_symbol
).get_cname ()));
972 public CCodeExpression
get_type_id_expression (DataType type
, bool is_chainup
= false) {
973 if (type is GenericType
) {
974 string var_name
= "%s_type".printf (type
.type_parameter
.name
.down ());
975 if (is_in_generic_type (type
) && !is_chainup
) {
976 return new CCodeMemberAccess
.pointer (get_type_private_from_type ((ObjectTypeSymbol
) type
.type_parameter
.parent_symbol
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("this"), "type")), var_name
);
978 return new
CCodeIdentifier (var_name
);
981 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_type_get".printf (type
.data_type
.get_lower_case_cname ())));
982 var object_type_symbol
= type
.data_type as ObjectTypeSymbol
;
983 if (object_type_symbol
!= null) {
984 for (int i
= 0; i
< object_type_symbol
.get_type_parameters ().size
; i
++) {
985 if (type
.get_type_arguments ().size
== 0) {
986 ccall
.add_argument (new
CCodeConstant ("NULL"));
988 ccall
.add_argument (get_type_id_expression (type
.get_type_arguments ().get (i
)));
996 public virtual CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
, bool is_chainup
= false) {
997 if (type
.data_type
!= null) {
998 string dup_function
= "";
999 if (type
.data_type
.is_reference_counting ()) {
1000 dup_function
= type
.data_type
.get_ref_function ();
1001 } else if (type is ValueType
) {
1002 dup_function
= type
.data_type
.get_dup_function ();
1003 if (dup_function
== null) {
1008 return new
CCodeIdentifier (dup_function
);
1009 } else if (type
.type_parameter
!= null) {
1011 } else if (type is ArrayType
) {
1012 return new
CCodeIdentifier ("dova_object_ref");
1013 } else if (type is DelegateType
) {
1014 return new
CCodeIdentifier ("dova_object_ref");
1015 } else if (type is PointerType
) {
1016 var pointer_type
= (PointerType
) type
;
1017 return get_dup_func_expression (pointer_type
.base_type
, source_reference
);
1019 return new
CCodeConstant ("NULL");
1023 public CCodeExpression?
get_destroy_func_expression (DataType type
, bool is_chainup
= false) {
1024 if (type
.data_type
!= null) {
1025 string unref_function
;
1026 if (type is ReferenceType
) {
1027 if (type
.data_type
.is_reference_counting ()) {
1028 unref_function
= type
.data_type
.get_unref_function ();
1030 unref_function
= type
.data_type
.get_free_function ();
1033 if (type
.nullable
) {
1034 unref_function
= type
.data_type
.get_free_function ();
1035 if (unref_function
== null) {
1036 unref_function
= "free";
1039 var st
= (Struct
) type
.data_type
;
1040 unref_function
= st
.get_copy_function ();
1043 if (unref_function
== null) {
1044 return new
CCodeConstant ("NULL");
1046 return new
CCodeIdentifier (unref_function
);
1047 } else if (type
.type_parameter
!= null && current_type_symbol is Class
) {
1048 // FIXME ask type for dup/ref function
1049 return new
CCodeIdentifier ("dova_object_unref");
1050 } else if (type is ArrayType
) {
1051 return new
CCodeIdentifier ("dova_object_unref");
1052 } else if (type is DelegateType
) {
1053 return new
CCodeIdentifier ("dova_object_unref");
1054 } else if (type is PointerType
) {
1055 return new
CCodeIdentifier ("free");
1057 return new
CCodeConstant ("NULL");
1061 public CCodeExpression
get_unref_expression (CCodeExpression cvar
, DataType type
, Expression? expr
= null) {
1062 return destroy_value (new
DovaValue (type
, cvar
));
1065 public CCodeExpression
destroy_value (TargetValue value
) {
1066 var type
= value
.value_type
;
1067 var cvar
= get_cvalue_ (value
);
1069 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
1071 if (type is ValueType
&& !type
.nullable
) {
1072 // normal value type, no null check
1073 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
1074 ccall
.add_argument (new
CCodeConstant ("0"));
1075 ccall
.add_argument (new
CCodeConstant ("NULL"));
1076 ccall
.add_argument (new
CCodeConstant ("0"));
1081 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
1083 /* can be simplified to
1084 * foo = (unref (foo), NULL)
1085 * if foo is of static type non-null
1088 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cvar
, new
CCodeConstant ("NULL"));
1089 if (type
.type_parameter
!= null) {
1090 if (!(current_type_symbol is Class
) || current_class
.is_compact
) {
1091 return new
CCodeConstant ("NULL");
1094 // unref functions are optional for type parameters
1095 var cunrefisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_destroy_func_expression (type
), new
CCodeConstant ("NULL"));
1096 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cunrefisnull
);
1099 ccall
.add_argument (cvar
);
1101 /* set freed references to NULL to prevent further use */
1102 var ccomma
= new
CCodeCommaExpression ();
1104 ccomma
.append_expression (ccall
);
1105 ccomma
.append_expression (new
CCodeConstant ("NULL"));
1107 var cassign
= new
CCodeAssignment (cvar
, ccomma
);
1109 return new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("NULL"), cassign
);
1112 public override void visit_end_full_expression (Expression expr
) {
1113 /* expr is a full expression, i.e. an initializer, the
1114 * expression in an expression statement, the controlling
1115 * expression in if, while, for, or foreach statements
1117 * we unref temporary variables at the end of a full
1121 if (((List
<LocalVariable
>) temp_ref_vars
).size
== 0) {
1122 /* nothing to do without temporary variables */
1126 var expr_type
= expr
.value_type
;
1127 if (expr
.target_type
!= null) {
1128 expr_type
= expr
.target_type
;
1131 var full_expr_var
= get_temp_variable (expr_type
, true, expr
);
1132 emit_temp_var (full_expr_var
);
1134 var expr_list
= new
CCodeCommaExpression ();
1135 expr_list
.append_expression (new
CCodeAssignment (get_variable_cexpression (full_expr_var
.name
), get_cvalue (expr
)));
1137 foreach (LocalVariable local
in temp_ref_vars
) {
1138 var ma
= new MemberAccess
.simple (local
.name
);
1139 ma
.symbol_reference
= local
;
1140 expr_list
.append_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
1143 expr_list
.append_expression (get_variable_cexpression (full_expr_var
.name
));
1145 set_cvalue (expr
, expr_list
);
1147 temp_ref_vars
.clear ();
1150 public void emit_temp_var (LocalVariable local
) {
1151 var cdecl
= new
CCodeDeclaration (local
.variable_type
.get_cname ());
1153 var vardecl
= new
CCodeVariableDeclarator (local
.name
, null, local
.variable_type
.get_cdeclarator_suffix ());
1154 cdecl
.add_declarator (vardecl
);
1156 var st
= local
.variable_type
.data_type as Struct
;
1157 var array_type
= local
.variable_type as ArrayType
;
1159 if (local
.name
.has_prefix ("*")) {
1160 // do not dereference unintialized variable
1161 // initialization is not needed for these special
1162 // pointer temp variables
1163 // used to avoid side-effects in assignments
1164 } else if (local
.variable_type is GenericType
) {
1165 var value_size
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_get_value_size"));
1166 value_size
.add_argument (get_type_id_expression (local
.variable_type
));
1168 var alloca_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("alloca"));
1169 alloca_call
.add_argument (value_size
);
1171 var memset_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
1172 memset_call
.add_argument (alloca_call
);
1173 memset_call
.add_argument (new
CCodeConstant ("0"));
1174 memset_call
.add_argument (value_size
);
1176 vardecl
.initializer
= memset_call
;
1177 vardecl
.init0
= true;
1178 } else if (!local
.variable_type
.nullable
&&
1179 (st
!= null && st
.get_fields ().size
> 0) ||
1180 (array_type
!= null && array_type
.fixed_length
)) {
1181 // 0-initialize struct with struct initializer { 0 }
1182 // necessary as they will be passed by reference
1183 var clist
= new
CCodeInitializerList ();
1184 clist
.append (new
CCodeConstant ("0"));
1186 vardecl
.initializer
= clist
;
1187 vardecl
.init0
= true;
1188 } else if (local
.variable_type
.is_reference_type_or_type_parameter () ||
1189 local
.variable_type
.nullable
) {
1190 vardecl
.initializer
= new
CCodeConstant ("NULL");
1191 vardecl
.init0
= true;
1194 ccode
.add_statement (cdecl
);
1197 public override void visit_expression_statement (ExpressionStatement stmt
) {
1198 if (stmt
.expression
.error
) {
1203 if (get_cvalue (stmt
.expression
) != null) {
1204 ccode
.add_expression (get_cvalue (stmt
.expression
));
1206 /* free temporary objects and handle errors */
1208 foreach (LocalVariable local
in temp_ref_vars
) {
1209 var ma
= new MemberAccess
.simple (local
.name
);
1210 ma
.symbol_reference
= local
;
1211 ma
.value_type
= local
.variable_type
.copy ();
1212 ccode
.add_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
1215 if (stmt
.tree_can_fail
&& stmt
.expression
.tree_can_fail
) {
1216 // simple case, no node breakdown necessary
1217 add_simple_check (stmt
.expression
);
1220 temp_ref_vars
.clear ();
1223 public virtual void append_local_free (Symbol sym
, bool stop_at_loop
= false, CodeNode? stop_at
= null) {
1224 var b
= (Block
) sym
;
1226 var local_vars
= b
.get_local_variables ();
1227 // free in reverse order
1228 for (int i
= local_vars
.size
- 1; i
>= 0; i
--) {
1229 var local
= local_vars
[i
];
1230 if (local
.active
&& !local
.floating
&& !local
.captured
&& requires_destroy (local
.variable_type
)) {
1231 var ma
= new MemberAccess
.simple (local
.name
);
1232 ma
.symbol_reference
= local
;
1233 ccode
.add_expression (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
1238 int block_id
= get_block_id (b
);
1240 var data_unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_object_unref"));
1241 data_unref
.add_argument (get_variable_cexpression ("_data%d_".printf (block_id
)));
1242 ccode
.add_expression (data_unref
);
1246 if (b
.parent_node is Loop
||
1247 b
.parent_node is ForeachStatement
||
1248 b
.parent_node is SwitchStatement
) {
1253 if (b
.parent_node
== stop_at
) {
1257 if (sym
.parent_symbol is Block
) {
1258 append_local_free (sym
.parent_symbol
, stop_at_loop
, stop_at
);
1259 } else if (sym
.parent_symbol is Method
) {
1260 append_param_free ((Method
) sym
.parent_symbol
);
1264 private void append_param_free (Method m
) {
1265 foreach (Parameter param
in m
.get_parameters ()) {
1266 if (requires_destroy (param
.variable_type
) && param
.direction
== ParameterDirection
.IN
) {
1267 var ma
= new MemberAccess
.simple (param
.name
);
1268 ma
.symbol_reference
= param
;
1269 ccode
.add_expression (get_unref_expression (get_variable_cexpression (param
.name
), param
.variable_type
, ma
));
1274 public override void visit_return_statement (ReturnStatement stmt
) {
1275 // free local variables
1276 append_local_free (current_symbol
);
1278 ccode
.add_return ((current_return_type is VoidType
) ?
null : new
CCodeIdentifier ("result"));
1281 public override void visit_delete_statement (DeleteStatement stmt
) {
1282 var pointer_type
= (PointerType
) stmt
.expression
.value_type
;
1283 DataType type
= pointer_type
;
1284 if (pointer_type
.base_type
.data_type
!= null && pointer_type
.base_type
.data_type
.is_reference_type ()) {
1285 type
= pointer_type
.base_type
;
1288 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
1289 ccall
.add_argument (get_cvalue (stmt
.expression
));
1290 ccode
.add_expression (ccall
);
1293 public override void visit_expression (Expression expr
) {
1294 if (get_cvalue (expr
) != null && !expr
.lvalue
) {
1295 // memory management, implicit casts, and boxing/unboxing
1296 set_cvalue (expr
, transform_expression (get_cvalue (expr
), expr
.value_type
, expr
.target_type
, expr
));
1300 public override void visit_boolean_literal (BooleanLiteral expr
) {
1301 set_cvalue (expr
, new
CCodeConstant (expr
.value ?
"true" : "false"));
1304 public override void visit_character_literal (CharacterLiteral expr
) {
1305 if (expr
.get_char () >= 0x20 && expr
.get_char () < 0x80) {
1306 set_cvalue (expr
, new
CCodeConstant (expr
.value
));
1308 set_cvalue (expr
, new
CCodeConstant ("%uU".printf (expr
.get_char ())));
1312 public override void visit_integer_literal (IntegerLiteral expr
) {
1313 set_cvalue (expr
, new
CCodeConstant (expr
.value
));
1316 public override void visit_real_literal (RealLiteral expr
) {
1317 string c_literal
= expr
.value
;
1318 if (c_literal
.has_suffix ("d") || c_literal
.has_suffix ("D")) {
1319 // there is no suffix for double in C
1320 c_literal
= c_literal
.substring (0, c_literal
.length
- 1);
1322 if (!("." in c_literal
|| "e" in c_literal
|| "E" in c_literal
)) {
1323 // C requires period or exponent part for floating constants
1324 if ("f" in c_literal
|| "F" in c_literal
) {
1325 c_literal
= c_literal
.substring (0, c_literal
.length
- 1) + ".f";
1330 set_cvalue (expr
, new
CCodeConstant (c_literal
));
1333 public override void visit_string_literal (StringLiteral expr
) {
1334 // FIXME handle escaped characters in scanner/parser and escape them here again for C
1335 var cliteral
= new
CCodeConstant ("\"\\0\" " + expr
.value
);
1337 var cbinary
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, cliteral
, new
CCodeConstant ("1"));
1338 set_cvalue (expr
, new
CCodeCastExpression (cbinary
, "string_t"));
1341 public override void visit_null_literal (NullLiteral expr
) {
1342 set_cvalue (expr
, new
CCodeConstant ("NULL"));
1345 public override void visit_base_access (BaseAccess expr
) {
1346 generate_type_declaration (expr
.value_type
, cfile
);
1347 set_cvalue (expr
, new
CCodeCastExpression (new
CCodeIdentifier ("this"), expr
.value_type
.get_cname ()));
1350 public override void visit_postfix_expression (PostfixExpression expr
) {
1351 MemberAccess ma
= find_property_access (expr
.inner
);
1353 // property postfix expression
1354 var prop
= (Property
) ma
.symbol_reference
;
1356 // assign current value to temp variable
1357 var temp_decl
= get_temp_variable (prop
.property_type
, true, expr
);
1358 emit_temp_var (temp_decl
);
1359 ccode
.add_assignment (get_variable_cexpression (temp_decl
.name
), get_cvalue (expr
.inner
));
1361 // increment/decrement property
1362 var op
= expr
.increment ? CCodeBinaryOperator
.PLUS
: CCodeBinaryOperator
.MINUS
;
1363 var cexpr
= new
CCodeBinaryExpression (op
, get_variable_cexpression (temp_decl
.name
), new
CCodeConstant ("1"));
1364 store_property (prop
, ma
.inner
, new
DovaValue (expr
.value_type
, cexpr
));
1366 // return previous value
1367 set_cvalue (expr
, new
CCodeIdentifier (temp_decl
.name
));
1371 var op
= expr
.increment ? CCodeUnaryOperator
.POSTFIX_INCREMENT
: CCodeUnaryOperator
.POSTFIX_DECREMENT
;
1373 set_cvalue (expr
, new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
1376 private MemberAccess?
find_property_access (Expression expr
) {
1377 if (!(expr is MemberAccess
)) {
1381 var ma
= (MemberAccess
) expr
;
1382 if (ma
.symbol_reference is Property
) {
1389 public bool requires_copy (DataType type
) {
1390 if (!type
.is_disposable ()) {
1394 var cl
= type
.data_type as Class
;
1395 if (cl
!= null && cl
.is_reference_counting ()
1396 && cl
.get_ref_function () == "") {
1397 // empty ref_function => no ref necessary
1401 if (type
.type_parameter
!= null) {
1408 public bool requires_destroy (DataType type
) {
1409 if (!type
.is_disposable ()) {
1413 var array_type
= type as ArrayType
;
1414 if (array_type
!= null && array_type
.inline_allocated
) {
1415 return requires_destroy (array_type
.element_type
);
1418 var cl
= type
.data_type as Class
;
1419 if (cl
!= null && cl
.is_reference_counting ()
1420 && cl
.get_unref_function () == "") {
1421 // empty unref_function => no unref necessary
1425 if (type
.type_parameter
!= null) {
1432 bool is_ref_function_void (DataType type
) {
1433 var cl
= type
.data_type as Class
;
1434 if (cl
!= null && cl
.ref_function_void
) {
1441 public virtual CCodeExpression?
get_ref_cexpression (DataType expression_type
, CCodeExpression cexpr
, Expression? expr
, CodeNode node
) {
1442 if (expression_type is ValueType
&& !expression_type
.nullable
) {
1443 // normal value type, no null check
1444 // (copy (&temp, 0, &expr, 0), temp)
1446 var decl
= get_temp_variable (expression_type
, false, node
);
1447 emit_temp_var (decl
);
1449 var ctemp
= get_variable_cexpression (decl
.name
);
1451 var vt
= (ValueType
) expression_type
;
1452 var st
= (Struct
) vt
.type_symbol
;
1453 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (st
.get_copy_function ()));
1454 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, ctemp
));
1455 copy_call
.add_argument (new
CCodeConstant ("0"));
1456 copy_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
));
1457 copy_call
.add_argument (new
CCodeConstant ("0"));
1459 var ccomma
= new
CCodeCommaExpression ();
1461 ccomma
.append_expression (copy_call
);
1462 ccomma
.append_expression (ctemp
);
1467 /* (temp = expr, temp == NULL ? NULL : ref (temp))
1469 * can be simplified to
1471 * if static type of expr is non-null
1474 var dupexpr
= get_dup_func_expression (expression_type
, node
.source_reference
);
1476 if (dupexpr
== null) {
1481 var ccall
= new
CCodeFunctionCall (dupexpr
);
1483 if (expr
!= null && expr
.is_non_null ()
1484 && !is_ref_function_void (expression_type
)) {
1485 // expression is non-null
1486 ccall
.add_argument (get_cvalue (expr
));
1490 var decl
= get_temp_variable (expression_type
, false, node
);
1491 emit_temp_var (decl
);
1493 var ctemp
= get_variable_cexpression (decl
.name
);
1495 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, new
CCodeConstant ("NULL"));
1496 if (expression_type
.type_parameter
!= null) {
1497 // dup functions are optional for type parameters
1498 var cdupisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, get_dup_func_expression (expression_type
, node
.source_reference
), new
CCodeConstant ("NULL"));
1499 cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cisnull
, cdupisnull
);
1502 ccall
.add_argument (ctemp
);
1504 var ccomma
= new
CCodeCommaExpression ();
1505 ccomma
.append_expression (new
CCodeAssignment (ctemp
, cexpr
));
1507 var cifnull
= new
CCodeConstant ("NULL");
1508 ccomma
.append_expression (new
CCodeConditionalExpression (cisnull
, cifnull
, ccall
));
1510 // repeat temp variable at the end of the comma expression
1511 // if the ref function returns void
1512 if (is_ref_function_void (expression_type
)) {
1513 ccomma
.append_expression (ctemp
);
1520 public virtual void generate_class_declaration (Class cl
, CCodeFile decl_space
) {
1521 if (add_symbol_declaration (decl_space
, cl
, cl
.get_cname ())) {
1526 public virtual void generate_interface_declaration (Interface iface
, CCodeFile decl_space
) {
1529 public virtual void generate_method_declaration (Method m
, CCodeFile decl_space
) {
1532 public void add_generic_type_arguments (CCodeFunctionCall ccall
, List
<DataType
> type_args
, CodeNode expr
, bool is_chainup
= false) {
1533 foreach (var type_arg
in type_args
) {
1534 ccall
.add_argument (get_type_id_expression (type_arg
, is_chainup
));
1538 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
1539 CCodeExpression instance
= null;
1540 CCodeExpression creation_expr
= null;
1542 var st
= expr
.type_reference
.data_type as Struct
;
1544 bool struct_by_ref
= false;
1545 if (st
!= null && !st
.is_boolean_type () && !st
.is_integer_type () && !st
.is_floating_type ()) {
1546 struct_by_ref
= true;
1549 if (struct_by_ref
|| expr
.get_object_initializer ().size
> 0) {
1550 // value-type initialization or object creation expression with object initializer
1551 var temp_decl
= get_temp_variable (expr
.type_reference
, false, expr
);
1552 emit_temp_var (temp_decl
);
1554 instance
= get_variable_cexpression (get_variable_cname (temp_decl
.name
));
1557 if (expr
.symbol_reference
== null) {
1558 // no creation method
1559 if (expr
.type_reference
.data_type is Struct
) {
1560 var creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
1561 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
1562 creation_call
.add_argument (new
CCodeConstant ("0"));
1563 creation_call
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (expr
.type_reference
.get_cname ())));
1565 creation_expr
= creation_call
;
1567 } else if (expr
.symbol_reference is Method
) {
1568 // use creation method
1569 var m
= (Method
) expr
.symbol_reference
;
1570 var params
= m
.get_parameters ();
1571 CCodeFunctionCall creation_call
;
1573 generate_method_declaration (m
, cfile
);
1575 var cl
= expr
.type_reference
.data_type as Class
;
1577 if (!m
.has_new_function
) {
1578 // use construct function directly
1579 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
1580 creation_call
.add_argument (new
CCodeIdentifier (cl
.get_type_id ()));
1582 creation_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_cname ()));
1585 if (struct_by_ref
&& !(m
.cinstance_parameter_position
< 0)) {
1586 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
1589 generate_type_declaration (expr
.type_reference
, cfile
);
1591 if (cl
!= null && !cl
.is_compact
) {
1592 add_generic_type_arguments (creation_call
, expr
.type_reference
.get_type_arguments (), expr
);
1595 bool ellipsis
= false;
1598 Iterator
<Parameter
> params_it
= params
.iterator ();
1599 foreach (Expression arg
in expr
.get_argument_list ()) {
1600 CCodeExpression cexpr
= get_cvalue (arg
);
1601 Parameter param
= null;
1602 if (params_it
.next ()) {
1603 param
= params_it
.get ();
1604 ellipsis
= param
.ellipsis
;
1606 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
1610 creation_call
.add_argument (cexpr
);
1614 while (params_it
.next ()) {
1615 var param
= params_it
.get ();
1617 if (param
.ellipsis
) {
1622 if (param
.initializer
== null) {
1623 Report
.error (expr
.source_reference
, "no default expression for argument %d".printf (i
));
1627 /* evaluate default expression here as the code
1628 * generator might not have visited the formal
1630 param
.initializer
.emit (this
);
1632 creation_call
.add_argument (get_cvalue (param
.initializer
));
1636 if (struct_by_ref
&& m
.cinstance_parameter_position
< 0) {
1637 // instance parameter is at the end in a struct creation method
1638 creation_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
));
1642 /* ensure variable argument list ends with NULL
1643 * except when using printf-style arguments */
1644 if (!m
.printf_format
&& !m
.scanf_format
&& m
.sentinel
!= "") {
1645 creation_call
.add_argument (new
CCodeConstant (m
.sentinel
));
1649 creation_expr
= creation_call
;
1651 // cast the return value of the creation method back to the intended type if
1652 // it requested a special C return type
1653 if (get_custom_creturn_type (m
) != null) {
1654 creation_expr
= new
CCodeCastExpression (creation_expr
, expr
.type_reference
.get_cname ());
1660 if (instance
!= null) {
1661 if (expr
.type_reference
.data_type is Struct
) {
1662 ccode
.add_expression (creation_expr
);
1664 ccode
.add_assignment (instance
, creation_expr
);
1667 foreach (MemberInitializer init
in expr
.get_object_initializer ()) {
1668 if (init
.symbol_reference is Field
) {
1669 var f
= (Field
) init
.symbol_reference
;
1670 var instance_target_type
= get_data_type_for_symbol ((TypeSymbol
) f
.parent_symbol
);
1671 var typed_inst
= transform_expression (instance
, expr
.type_reference
, instance_target_type
);
1672 CCodeExpression lhs
;
1673 if (expr
.type_reference
.data_type is Struct
) {
1674 lhs
= new
CCodeMemberAccess (typed_inst
, f
.get_cname ());
1676 lhs
= new CCodeMemberAccess
.pointer (typed_inst
, f
.get_cname ());
1678 ccode
.add_assignment (lhs
, get_cvalue (init
.initializer
));
1679 } else if (init
.symbol_reference is Property
) {
1680 var inst_ma
= new MemberAccess
.simple ("new");
1681 inst_ma
.value_type
= expr
.type_reference
;
1682 set_cvalue (inst_ma
, instance
);
1683 store_property ((Property
) init
.symbol_reference
, inst_ma
, init
.initializer
.target_value
);
1687 creation_expr
= instance
;
1690 if (creation_expr
!= null) {
1691 var temp_var
= get_temp_variable (expr
.value_type
);
1692 var temp_ref
= get_variable_cexpression (temp_var
.name
);
1694 emit_temp_var (temp_var
);
1696 ccode
.add_assignment (temp_ref
, creation_expr
);
1697 set_cvalue (expr
, temp_ref
);
1701 public CCodeExpression?
handle_struct_argument (Parameter param
, Expression arg
, CCodeExpression? cexpr
) {
1702 if (arg
.formal_target_type is GenericType
&& !(arg
.target_type is GenericType
)) {
1703 // we already use a reference for arguments of ref and out parameters
1704 if (param
.direction
== ParameterDirection
.IN
) {
1705 var unary
= cexpr as CCodeUnaryExpression
;
1706 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
1709 } else if (cexpr is CCodeIdentifier
|| cexpr is CCodeMemberAccess
) {
1710 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cexpr
);
1712 // if cexpr is e.g. a function call, we can't take the address of the expression
1713 // (tmp = expr, &tmp)
1714 var ccomma
= new
CCodeCommaExpression ();
1716 var temp_var
= get_temp_variable (arg
.target_type
);
1717 emit_temp_var (temp_var
);
1718 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), cexpr
));
1719 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (temp_var
.name
)));
1729 public override void visit_sizeof_expression (SizeofExpression expr
) {
1730 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
1731 csizeof
.add_argument (new
CCodeIdentifier (expr
.type_reference
.get_cname ()));
1732 set_cvalue (expr
, csizeof
);
1735 public override void visit_typeof_expression (TypeofExpression expr
) {
1736 set_cvalue (expr
, get_type_id_expression (expr
.type_reference
));
1739 public override void visit_unary_expression (UnaryExpression expr
) {
1740 CCodeUnaryOperator op
;
1741 if (expr
.operator
== UnaryOperator
.PLUS
) {
1742 op
= CCodeUnaryOperator
.PLUS
;
1743 } else if (expr
.operator
== UnaryOperator
.MINUS
) {
1744 op
= CCodeUnaryOperator
.MINUS
;
1745 } else if (expr
.operator
== UnaryOperator
.LOGICAL_NEGATION
) {
1746 op
= CCodeUnaryOperator
.LOGICAL_NEGATION
;
1747 } else if (expr
.operator
== UnaryOperator
.BITWISE_COMPLEMENT
) {
1748 op
= CCodeUnaryOperator
.BITWISE_COMPLEMENT
;
1749 } else if (expr
.operator
== UnaryOperator
.INCREMENT
) {
1750 op
= CCodeUnaryOperator
.PREFIX_INCREMENT
;
1751 } else if (expr
.operator
== UnaryOperator
.DECREMENT
) {
1752 op
= CCodeUnaryOperator
.PREFIX_DECREMENT
;
1753 } else if (expr
.operator
== UnaryOperator
.REF
) {
1754 op
= CCodeUnaryOperator
.ADDRESS_OF
;
1755 } else if (expr
.operator
== UnaryOperator
.OUT
) {
1756 op
= CCodeUnaryOperator
.ADDRESS_OF
;
1758 assert_not_reached ();
1760 set_cvalue (expr
, new
CCodeUnaryExpression (op
, get_cvalue (expr
.inner
)));
1763 public override void visit_cast_expression (CastExpression expr
) {
1764 if (expr
.is_silent_cast
) {
1765 if (expr
.inner
.value_type is ObjectType
) {
1766 var ccomma
= new
CCodeCommaExpression ();
1767 var temp_decl
= get_temp_variable (expr
.inner
.value_type
, true, expr
);
1769 emit_temp_var (temp_decl
);
1771 var ctemp
= get_variable_cexpression (temp_decl
.name
);
1772 var cinit
= new
CCodeAssignment (ctemp
, get_cvalue (expr
.inner
));
1773 var ccheck
= create_type_check (ctemp
, expr
.type_reference
);
1774 var ccast
= new
CCodeCastExpression (ctemp
, expr
.type_reference
.get_cname ());
1775 var cnull
= new
CCodeConstant ("NULL");
1777 ccomma
.append_expression (cinit
);
1778 ccomma
.append_expression (new
CCodeConditionalExpression (ccheck
, ccast
, cnull
));
1780 set_cvalue (expr
, ccomma
);
1783 Report
.error (expr
.source_reference
, "Operation not supported for this type");
1788 if (expr
.type_reference
.data_type
!= null && expr
.type_reference
.data_type
.get_full_name () == "Dova.Value") {
1790 var temp_decl
= get_temp_variable (expr
.inner
.value_type
, true, expr
);
1791 emit_temp_var (temp_decl
);
1792 var cvar
= get_variable_cexpression (temp_decl
.name
);
1794 var ccomma
= new
CCodeCommaExpression ();
1795 ccomma
.append_expression (new
CCodeAssignment (cvar
, get_cvalue (expr
.inner
)));
1797 var to_any
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_value_to_any"));
1798 to_any
.add_argument (get_type_id_expression (expr
.inner
.value_type
));
1799 to_any
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
1800 to_any
.add_argument (new
CCodeConstant ("0"));
1801 ccomma
.append_expression (to_any
);
1803 set_cvalue (expr
, ccomma
);
1805 } else if (expr
.inner
.value_type
.data_type
!= null && expr
.inner
.value_type
.data_type
.get_full_name () == "Dova.Value") {
1807 var temp_decl
= get_temp_variable (expr
.type_reference
, true, expr
);
1808 emit_temp_var (temp_decl
);
1809 var cvar
= get_variable_cexpression (temp_decl
.name
);
1811 var ccomma
= new
CCodeCommaExpression ();
1813 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
1814 sizeof_call
.add_argument (new
CCodeIdentifier (expr
.type_reference
.get_cname ()));
1816 var to_any
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_value_from_any"));
1817 to_any
.add_argument (get_type_id_expression (expr
.type_reference
));
1818 to_any
.add_argument (get_cvalue (expr
.inner
));
1819 to_any
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cvar
));
1820 to_any
.add_argument (new
CCodeConstant ("0"));
1821 ccomma
.append_expression (to_any
);
1823 ccomma
.append_expression (cvar
);
1825 set_cvalue (expr
, ccomma
);
1829 generate_type_declaration (expr
.type_reference
, cfile
);
1831 if (expr
.inner
.value_type is GenericType
&& !(expr
.type_reference is GenericType
)) {
1832 // generic types use an extra pointer, dereference that pointer
1833 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeCastExpression (get_cvalue (expr
.inner
), expr
.type_reference
.get_cname () + "*")));
1835 set_cvalue (expr
, new
CCodeCastExpression (get_cvalue (expr
.inner
), expr
.type_reference
.get_cname ()));
1839 public override void visit_pointer_indirection (PointerIndirection expr
) {
1840 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_cvalue (expr
.inner
)));
1843 public override void visit_addressof_expression (AddressofExpression expr
) {
1844 set_cvalue (expr
, new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (expr
.inner
)));
1847 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
1848 /* (tmp = var, var = null, tmp) */
1849 var ccomma
= new
CCodeCommaExpression ();
1850 var temp_decl
= get_temp_variable (expr
.value_type
, true, expr
);
1851 emit_temp_var (temp_decl
);
1852 var cvar
= get_variable_cexpression (temp_decl
.name
);
1854 ccomma
.append_expression (new
CCodeAssignment (cvar
, get_cvalue (expr
.inner
)));
1855 ccomma
.append_expression (new
CCodeAssignment (get_cvalue (expr
.inner
), new
CCodeConstant ("NULL")));
1856 ccomma
.append_expression (cvar
);
1857 set_cvalue (expr
, ccomma
);
1860 public override void visit_binary_expression (BinaryExpression expr
) {
1861 var cleft
= get_cvalue (expr
.left
);
1862 var cright
= get_cvalue (expr
.right
);
1864 CCodeBinaryOperator op
;
1865 if (expr
.operator
== BinaryOperator
.PLUS
) {
1866 op
= CCodeBinaryOperator
.PLUS
;
1867 } else if (expr
.operator
== BinaryOperator
.MINUS
) {
1868 op
= CCodeBinaryOperator
.MINUS
;
1869 } else if (expr
.operator
== BinaryOperator
.MUL
) {
1870 op
= CCodeBinaryOperator
.MUL
;
1871 } else if (expr
.operator
== BinaryOperator
.DIV
) {
1872 op
= CCodeBinaryOperator
.DIV
;
1873 } else if (expr
.operator
== BinaryOperator
.MOD
) {
1874 op
= CCodeBinaryOperator
.MOD
;
1875 } else if (expr
.operator
== BinaryOperator
.SHIFT_LEFT
) {
1876 op
= CCodeBinaryOperator
.SHIFT_LEFT
;
1877 } else if (expr
.operator
== BinaryOperator
.SHIFT_RIGHT
) {
1878 op
= CCodeBinaryOperator
.SHIFT_RIGHT
;
1879 } else if (expr
.operator
== BinaryOperator
.LESS_THAN
) {
1880 op
= CCodeBinaryOperator
.LESS_THAN
;
1881 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN
) {
1882 op
= CCodeBinaryOperator
.GREATER_THAN
;
1883 } else if (expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
) {
1884 op
= CCodeBinaryOperator
.LESS_THAN_OR_EQUAL
;
1885 } else if (expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
1886 op
= CCodeBinaryOperator
.GREATER_THAN_OR_EQUAL
;
1887 } else if (expr
.operator
== BinaryOperator
.EQUALITY
) {
1888 op
= CCodeBinaryOperator
.EQUALITY
;
1889 } else if (expr
.operator
== BinaryOperator
.INEQUALITY
) {
1890 op
= CCodeBinaryOperator
.INEQUALITY
;
1891 } else if (expr
.operator
== BinaryOperator
.BITWISE_AND
) {
1892 op
= CCodeBinaryOperator
.BITWISE_AND
;
1893 } else if (expr
.operator
== BinaryOperator
.BITWISE_OR
) {
1894 op
= CCodeBinaryOperator
.BITWISE_OR
;
1895 } else if (expr
.operator
== BinaryOperator
.BITWISE_XOR
) {
1896 op
= CCodeBinaryOperator
.BITWISE_XOR
;
1897 } else if (expr
.operator
== BinaryOperator
.AND
) {
1898 op
= CCodeBinaryOperator
.AND
;
1899 } else if (expr
.operator
== BinaryOperator
.OR
) {
1900 op
= CCodeBinaryOperator
.OR
;
1901 } else if (expr
.operator
== BinaryOperator
.IN
) {
1902 set_cvalue (expr
, new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeBinaryExpression (CCodeBinaryOperator
.BITWISE_AND
, cright
, cleft
), cleft
));
1905 assert_not_reached ();
1908 if (expr
.operator
== BinaryOperator
.EQUALITY
||
1909 expr
.operator
== BinaryOperator
.INEQUALITY
) {
1910 var left_type_as_struct
= expr
.left
.value_type
.data_type as Struct
;
1911 var right_type_as_struct
= expr
.right
.value_type
.data_type as Struct
;
1913 if (expr
.left
.value_type
.data_type is Class
&& !((Class
) expr
.left
.value_type
.data_type
).is_compact
&&
1914 expr
.right
.value_type
.data_type is Class
&& !((Class
) expr
.right
.value_type
.data_type
).is_compact
) {
1915 var left_cl
= (Class
) expr
.left
.value_type
.data_type
;
1916 var right_cl
= (Class
) expr
.right
.value_type
.data_type
;
1918 if (left_cl
!= right_cl
) {
1919 if (left_cl
.is_subtype_of (right_cl
)) {
1920 cleft
= generate_instance_cast (cleft
, right_cl
);
1921 } else if (right_cl
.is_subtype_of (left_cl
)) {
1922 cright
= generate_instance_cast (cright
, left_cl
);
1925 } else if (left_type_as_struct
!= null && right_type_as_struct
!= null) {
1926 // FIXME generate and use compare/equal function for real structs
1927 if (expr
.left
.value_type
.nullable
&& expr
.right
.value_type
.nullable
) {
1928 // FIXME also compare contents, not just address
1929 } else if (expr
.left
.value_type
.nullable
) {
1930 // FIXME check left value is not null
1931 cleft
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cleft
);
1932 } else if (expr
.right
.value_type
.nullable
) {
1933 // FIXME check right value is not null
1934 cright
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cright
);
1939 set_cvalue (expr
, new
CCodeBinaryExpression (op
, cleft
, cright
));
1942 CCodeExpression?
create_type_check (CCodeNode ccodenode
, DataType type
) {
1943 var ccheck
= new
CCodeFunctionCall (new
CCodeIdentifier ("any_is_a"));
1944 ccheck
.add_argument ((CCodeExpression
) ccodenode
);
1945 ccheck
.add_argument (get_type_id_expression (type
));
1949 public override void visit_type_check (TypeCheck expr
) {
1950 generate_type_declaration (expr
.type_reference
, cfile
);
1952 set_cvalue (expr
, create_type_check (get_cvalue (expr
.expression
), expr
.type_reference
));
1953 if (get_cvalue (expr
) is CCodeInvalidExpression
) {
1954 Report
.error (expr
.source_reference
, "type check expressions not supported for compact classes, structs, and enums");
1958 public override void visit_lambda_expression (LambdaExpression l
) {
1959 // use instance position from delegate
1960 var dt
= (DelegateType
) l
.target_type
;
1961 l
.method
.cinstance_parameter_position
= dt
.delegate_symbol
.cinstance_parameter_position
;
1963 l
.accept_children (this
);
1965 set_cvalue (l
, new
CCodeIdentifier (l
.method
.get_cname ()));
1968 // manage memory and implicit casts
1969 public CCodeExpression
transform_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
1970 var cexpr
= source_cexpr
;
1971 if (expression_type
== null) {
1976 if (expression_type
.value_owned
1977 && (target_type
== null || !target_type
.value_owned
)) {
1978 // value leaked, destroy it
1979 var pointer_type
= target_type as PointerType
;
1980 if (pointer_type
!= null && !(pointer_type
.base_type is VoidType
)) {
1981 // manual memory management for non-void pointers
1982 // treat void* special to not leak memory with void* method parameters
1983 } else if (requires_destroy (expression_type
)) {
1984 var decl
= get_temp_variable (expression_type
, true, expression_type
);
1985 emit_temp_var (decl
);
1986 temp_ref_vars
.insert (0, decl
);
1987 cexpr
= new
CCodeAssignment (get_variable_cexpression (decl
.name
), cexpr
);
1991 if (target_type
== null) {
1992 // value will be destroyed, no need for implicit casts
1996 cexpr
= get_implicit_cast_expression (cexpr
, expression_type
, target_type
, expr
);
1998 if (target_type
.value_owned
&& !expression_type
.value_owned
) {
1999 // need to copy value
2000 if (requires_copy (target_type
) && !(expression_type is NullType
)) {
2001 CodeNode node
= expr
;
2003 node
= expression_type
;
2005 cexpr
= get_ref_cexpression (target_type
, cexpr
, expr
, node
);
2012 public virtual CCodeExpression
get_implicit_cast_expression (CCodeExpression source_cexpr
, DataType? expression_type
, DataType? target_type
, Expression? expr
= null) {
2013 var cexpr
= source_cexpr
;
2015 if (expression_type
.data_type
!= null && expression_type
.data_type
== target_type
.data_type
) {
2016 // same type, no cast required
2020 if (expression_type is NullType
) {
2021 // null literal, no cast required when not converting to generic type pointer
2025 generate_type_declaration (target_type
, cfile
);
2027 if (target_type is DelegateType
&& expression_type is MethodType
) {
2028 var deleg_type
= (DelegateType
) target_type
;
2029 var method_type
= (MethodType
) expression_type
;
2030 CCodeExpression delegate_target
;
2031 if (expr is LambdaExpression
) {
2032 var lambda
= (LambdaExpression
) expr
;
2033 if (lambda
.method
.closure
) {
2034 int block_id
= get_block_id (current_closure_block
);
2035 delegate_target
= get_variable_cexpression ("_data%d_".printf (block_id
));
2036 } else if (get_this_type () != null) {
2037 delegate_target
= new
CCodeIdentifier ("this");
2039 delegate_target
= new
CCodeConstant ("NULL");
2042 if (method_type
.method_symbol
.binding
== MemberBinding
.INSTANCE
) {
2043 var ma
= (MemberAccess
) expr
;
2044 delegate_target
= (CCodeExpression
) get_ccodenode (ma
.inner
);
2046 delegate_target
= new
CCodeConstant ("NULL");
2050 var d
= deleg_type
.delegate_symbol
;
2052 string wrapper_name
= "_wrapper%d_".printf (next_wrapper_id
++);
2053 var wrapper
= new
CCodeFunction (wrapper_name
);
2054 wrapper
.modifiers
= CCodeModifiers
.STATIC
;
2055 var call
= new
CCodeFunctionCall (source_cexpr
);
2057 if (method_type
.method_symbol
.binding
== MemberBinding
.INSTANCE
) {
2058 wrapper
.add_parameter (new
CCodeParameter ("this", "void *"));
2059 call
.add_argument (new
CCodeIdentifier ("this"));
2062 var method_param_iter
= method_type
.method_symbol
.get_parameters ().iterator ();
2063 foreach (Parameter param
in d
.get_parameters ()) {
2064 method_param_iter
.next ();
2065 var method_param
= method_param_iter
.get ();
2066 string ctype
= param
.variable_type
.get_cname ();
2067 if (param
.variable_type is GenericType
&& !(method_param
.variable_type is GenericType
)) {
2068 ctype
= method_param
.variable_type
.get_cname () + "*";
2069 call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier (param
.name
)));
2070 } else if (!(param
.variable_type is GenericType
) && method_param
.variable_type is GenericType
) {
2071 call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (param
.name
)));
2073 call
.add_argument (new
CCodeIdentifier (param
.name
));
2076 wrapper
.add_parameter (new
CCodeParameter (param
.name
, ctype
));
2079 wrapper
.block
= new
CCodeBlock ();
2080 if (d
.return_type is VoidType
) {
2081 wrapper
.block
.add_statement (new
CCodeExpressionStatement (call
));
2083 var method_return_type
= method_type
.method_symbol
.return_type
;
2084 if (d
.return_type is GenericType
&& !(method_return_type is GenericType
)) {
2085 wrapper
.add_parameter (new
CCodeParameter ("result", method_return_type
.get_cname () + "*"));
2086 wrapper
.block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("result")), call
)));
2087 } else if (!(d
.return_type is GenericType
) && method_return_type is GenericType
) {
2088 wrapper
.return_type
= d
.return_type
.get_cname ();
2089 var cdecl
= new
CCodeDeclaration (d
.return_type
.get_cname ());
2090 cdecl
.add_declarator (new
CCodeVariableDeclarator ("result"));
2091 call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("result")));
2092 wrapper
.block
.add_statement (new
CCodeExpressionStatement (call
));
2093 wrapper
.block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("result")));
2094 } else if (d
.return_type is GenericType
) {
2095 wrapper
.add_parameter (new
CCodeParameter ("result", "void *"));
2096 wrapper
.block
.add_statement (new
CCodeExpressionStatement (call
));
2098 wrapper
.return_type
= d
.return_type
.get_cname ();
2099 wrapper
.block
.add_statement (new
CCodeReturnStatement (call
));
2103 cfile
.add_function (wrapper
);
2105 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_new".printf (deleg_type
.delegate_symbol
.get_lower_case_cname ())));
2106 ccall
.add_argument (delegate_target
);
2107 ccall
.add_argument (new
CCodeIdentifier (wrapper_name
));
2111 var cl
= target_type
.data_type as Class
;
2112 var iface
= target_type
.data_type as Interface
;
2113 if (context
.checking
&& (iface
!= null || (cl
!= null && !cl
.is_compact
))) {
2114 // checked cast for strict subtypes of GTypeInstance
2115 return generate_instance_cast (cexpr
, target_type
.data_type
);
2116 } else if (target_type
.data_type
!= null && expression_type
.get_cname () != target_type
.get_cname ()) {
2117 var st
= target_type
.data_type as Struct
;
2118 if (target_type
.data_type
.is_reference_type () || (st
!= null && st
.is_simple_type ())) {
2119 // don't cast non-simple structs
2120 return new
CCodeCastExpression (cexpr
, target_type
.get_cname ());
2129 public void store_property (Property prop
, Expression? instance
, TargetValue value
) {
2132 var base_property
= prop
;
2133 if (prop
.base_property
!= null) {
2134 base_property
= prop
.base_property
;
2135 } else if (prop
.base_interface_property
!= null) {
2136 base_property
= prop
.base_interface_property
;
2139 generate_property_accessor_declaration (base_property
.set_accessor
, cfile
);
2140 set_func
= base_property
.set_accessor
.get_cname ();
2142 if (!prop
.external
&& prop
.external_package
) {
2143 // internal VAPI properties
2144 // only add them once per source file
2145 if (add_generated_external_symbol (prop
)) {
2146 visit_property (prop
);
2150 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (set_func
));
2152 if (prop
.binding
== MemberBinding
.INSTANCE
) {
2153 /* target instance is first argument */
2154 ccall
.add_argument ((CCodeExpression
) get_ccodenode (instance
));
2157 ccall
.add_argument (get_cvalue_ (value
));
2159 ccode
.add_expression (ccall
);
2162 public bool add_generated_external_symbol (Symbol external_symbol
) {
2163 return generated_external_symbols
.add (external_symbol
);
2166 public static DataType
get_data_type_for_symbol (TypeSymbol sym
) {
2167 DataType type
= null;
2170 type
= new
ObjectType ((Class
) sym
);
2171 } else if (sym is Interface
) {
2172 type
= new
ObjectType ((Interface
) sym
);
2173 } else if (sym is Struct
) {
2174 var st
= (Struct
) sym
;
2175 if (st
.is_boolean_type ()) {
2176 type
= new
BooleanType (st
);
2177 } else if (st
.is_integer_type ()) {
2178 type
= new
IntegerType (st
);
2179 } else if (st
.is_floating_type ()) {
2180 type
= new
FloatingType (st
);
2182 type
= new
StructValueType (st
);
2184 } else if (sym is Enum
) {
2185 type
= new
EnumValueType ((Enum
) sym
);
2187 Report
.error (null, "internal error: `%s' is not a supported type".printf (sym
.get_full_name ()));
2188 return new
InvalidType ();
2194 public CCodeExpression?
default_value_for_type (DataType type
, bool initializer_expression
) {
2195 var st
= type
.data_type as Struct
;
2196 var array_type
= type as ArrayType
;
2197 if (type is GenericType
) {
2198 var value_size
= new
CCodeFunctionCall (new
CCodeIdentifier ("dova_type_get_value_size"));
2199 value_size
.add_argument (get_type_id_expression (type
));
2201 var alloca_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("alloca"));
2202 alloca_call
.add_argument (value_size
);
2204 var memset_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
2205 memset_call
.add_argument (alloca_call
);
2206 memset_call
.add_argument (new
CCodeConstant ("0"));
2207 memset_call
.add_argument (value_size
);
2210 } else if (initializer_expression
&& !type
.nullable
&&
2211 ((st
!= null && st
.get_fields ().size
> 0) ||
2212 (array_type
!= null && array_type
.fixed_length
))) {
2213 // 0-initialize struct with struct initializer { 0 }
2214 // only allowed as initializer expression in C
2215 var clist
= new
CCodeInitializerList ();
2216 clist
.append (new
CCodeConstant ("0"));
2218 } else if ((type
.data_type
!= null && type
.data_type
.is_reference_type ())
2220 || type is PointerType
|| type is DelegateType
2221 || (array_type
!= null && !array_type
.fixed_length
)) {
2222 return new
CCodeConstant ("NULL");
2223 } else if (type
.data_type
!= null && type
.data_type
.get_default_value () != null) {
2224 return new
CCodeConstant (type
.data_type
.get_default_value ());
2229 public CCodeExpression?
get_ccodenode (Expression node
) {
2230 if (get_cvalue (node
) == null) {
2233 return get_cvalue (node
);
2236 public DataType?
get_this_type () {
2237 if (current_method
!= null && current_method
.binding
== MemberBinding
.INSTANCE
) {
2238 return current_method
.this_parameter
.variable_type
;
2239 } else if (current_property_accessor
!= null && current_property_accessor
.prop
.binding
== MemberBinding
.INSTANCE
) {
2240 return current_property_accessor
.prop
.this_parameter
.variable_type
;
2245 public CCodeExpression
generate_instance_cast (CCodeExpression expr
, TypeSymbol type
) {
2246 return new
CCodeCastExpression (expr
, type
.get_cname () + "*");
2249 public virtual string?
get_custom_creturn_type (Method m
) {
2253 public virtual bool method_has_wrapper (Method method
) {
2257 public virtual void add_simple_check (CodeNode node
, bool always_fails
= false) {
2260 public CCodeExpression?
get_cvalue (Expression expr
) {
2261 if (expr
.target_value
== null) {
2264 var dova_value
= (DovaValue
) expr
.target_value
;
2265 return dova_value
.cvalue
;
2268 public CCodeExpression?
get_cvalue_ (TargetValue value
) {
2269 var dova_value
= (DovaValue
) value
;
2270 return dova_value
.cvalue
;
2273 public void set_cvalue (Expression expr
, CCodeExpression? cvalue
) {
2274 var dova_value
= (DovaValue
) expr
.target_value
;
2275 if (dova_value
== null) {
2276 dova_value
= new
DovaValue (expr
.value_type
);
2277 expr
.target_value
= dova_value
;
2279 dova_value
.cvalue
= cvalue
;
2283 public class Vala
.DovaValue
: TargetValue
{
2284 public CCodeExpression cvalue
;
2286 public DovaValue (DataType? value_type
= null, CCodeExpression? cvalue
= null) {
2288 this
.cvalue
= cvalue
;