1 /* valaccodecontrolflowmodule.vala
3 * Copyright (C) 2006-2009 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>
28 internal class Vala
.CCodeControlFlowModule
: CCodeMethodModule
{
29 public CCodeControlFlowModule (CCodeGenerator codegen
, CCodeModule? next
) {
33 public override void visit_if_statement (IfStatement stmt
) {
34 stmt
.accept_children (codegen
);
36 if (stmt
.false_statement
!= null) {
37 stmt
.ccodenode
= new
CCodeIfStatement ((CCodeExpression
) stmt
.condition
.ccodenode
, (CCodeStatement
) stmt
.true_statement
.ccodenode
, (CCodeStatement
) stmt
.false_statement
.ccodenode
);
39 stmt
.ccodenode
= new
CCodeIfStatement ((CCodeExpression
) stmt
.condition
.ccodenode
, (CCodeStatement
) stmt
.true_statement
.ccodenode
);
42 create_temp_decl (stmt
, stmt
.condition
.temp_vars
);
45 void visit_string_switch_statement (SwitchStatement stmt
) {
46 // we need a temporary variable to save the property value
47 var temp_var
= get_temp_variable (stmt
.expression
.value_type
, stmt
.expression
.value_type
.value_owned
, stmt
, false);
48 stmt
.expression
.temp_vars
.insert (0, temp_var
);
50 var ctemp
= get_variable_cexpression (temp_var
.name
);
51 var cinit
= new
CCodeAssignment (ctemp
, (CCodeExpression
) stmt
.expression
.ccodenode
);
52 var czero
= new
CCodeConstant ("0");
54 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
55 free_call
.add_argument (ctemp
);
57 var cswitchblock
= new
CCodeFragment ();
58 stmt
.ccodenode
= cswitchblock
;
60 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeConstant ("NULL"), ctemp
);
61 var cquark
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_string"));
62 cquark
.add_argument (ctemp
);
64 var ccond
= new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("0"), cquark
);
66 temp_var
= get_temp_variable (gquark_type
);
67 stmt
.expression
.temp_vars
.insert (0, temp_var
);
71 foreach (SwitchSection section
in stmt
.get_sections ()) {
72 if (section
.has_default_label ()) {
76 foreach (SwitchLabel label
in section
.get_labels ()) {
77 var cexpr
= (CCodeExpression
) label
.expression
.ccodenode
;
79 if (is_constant_ccode_expression (cexpr
)) {
80 var cname
= "%s_label%d".printf (temp_var
.name
, label_count
++);
81 var cdecl
= new
CCodeDeclaration (gquark_type
.get_cname ());
83 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
84 cdecl
.add_declarator (new
CCodeVariableDeclarator (cname
, czero
));
86 cswitchblock
.append (cdecl
);
91 cswitchblock
.append (new
CCodeExpressionStatement (cinit
));
93 ctemp
= get_variable_cexpression (temp_var
.name
);
94 cinit
= new
CCodeAssignment (ctemp
, ccond
);
96 cswitchblock
.append (new
CCodeExpressionStatement (cinit
));
97 create_temp_decl (stmt
, stmt
.expression
.temp_vars
);
99 if (stmt
.expression
.value_type
.value_owned
) {
101 cswitchblock
.append (new
CCodeExpressionStatement (free_call
));
104 Gee
.List
<Statement
> default_statements
= null;
107 // generate nested if statements
108 CCodeStatement ctopstmt
= null;
109 CCodeIfStatement coldif
= null;
111 foreach (SwitchSection section
in stmt
.get_sections ()) {
112 if (section
.has_default_label ()) {
113 default_statements
= section
.get_statements ();
117 CCodeBinaryExpression cor
= null;
118 foreach (SwitchLabel label
in section
.get_labels ()) {
119 var cexpr
= (CCodeExpression
) label
.expression
.ccodenode
;
121 if (is_constant_ccode_expression (cexpr
)) {
122 var cname
= new
CCodeIdentifier ("%s_label%d".printf (temp_var
.name
, label_count
++));
123 var ccondition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, czero
, cname
);
124 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_static_string"));
125 cinit
= new
CCodeAssignment (cname
, ccall
);
127 ccall
.add_argument (cexpr
);
129 cexpr
= new
CCodeConditionalExpression (ccondition
, cname
, cinit
);
131 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_string"));
132 ccall
.add_argument (cexpr
);
136 var ccmp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, cexpr
);
141 cor
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cor
, ccmp
);
145 var cblock
= new
CCodeBlock ();
146 foreach (CodeNode body_stmt
in section
.get_statements ()) {
147 if (body_stmt
.ccodenode is CCodeFragment
) {
148 foreach (CCodeNode cstmt
in ((CCodeFragment
) body_stmt
.ccodenode
).get_children ()) {
149 cblock
.add_statement (cstmt
);
152 cblock
.add_statement (body_stmt
.ccodenode
);
156 var cdo
= new
CCodeDoStatement (cblock
, new
CCodeConstant ("0"));
157 var cif
= new
CCodeIfStatement (cor
, cdo
);
159 if (coldif
!= null) {
160 coldif
.false_statement
= cif
;
168 if (default_statements
!= null) {
169 var cblock
= new
CCodeBlock ();
170 foreach (CodeNode body_stmt
in default_statements
) {
171 cblock
.add_statement (body_stmt
.ccodenode
);
174 var cdo
= new
CCodeDoStatement (cblock
, new
CCodeConstant ("0"));
176 if (coldif
== null) {
177 // there is only one section and that section
178 // contains a default label
181 coldif
.false_statement
= cdo
;
185 cswitchblock
.append (ctopstmt
);
188 public override void visit_switch_statement (SwitchStatement stmt
) {
189 stmt
.accept_children (codegen
);
191 if (stmt
.expression
.value_type
.compatible (string_type
)) {
192 visit_string_switch_statement (stmt
);
196 var cswitch
= new
CCodeSwitchStatement ((CCodeExpression
) stmt
.expression
.ccodenode
);
197 stmt
.ccodenode
= cswitch
;
199 foreach (SwitchSection section
in stmt
.get_sections ()) {
200 if (section
.has_default_label ()) {
201 cswitch
.add_statement (new
CCodeLabel ("default"));
202 var cdefaultblock
= new
CCodeBlock ();
203 cswitch
.add_statement (cdefaultblock
);
204 foreach (CodeNode default_stmt
in section
.get_statements ()) {
205 cdefaultblock
.add_statement (default_stmt
.ccodenode
);
210 foreach (SwitchLabel label
in section
.get_labels ()) {
211 cswitch
.add_statement (new
CCodeCaseStatement ((CCodeExpression
) label
.expression
.ccodenode
));
214 var cblock
= new
CCodeBlock ();
215 cswitch
.add_statement (cblock
);
216 foreach (CodeNode body_stmt
in section
.get_statements ()) {
217 cblock
.add_statement (body_stmt
.ccodenode
);
221 create_temp_decl (stmt
, stmt
.expression
.temp_vars
);
224 public override void visit_switch_section (SwitchSection section
) {
225 visit_block (section
);
228 public override void visit_switch_label (SwitchLabel label
) {
229 label
.accept_children (codegen
);
232 public override void visit_loop (Loop stmt
) {
233 stmt
.accept_children (codegen
);
235 if (context
.profile
== Profile
.GOBJECT
) {
236 stmt
.ccodenode
= new
CCodeWhileStatement (new
CCodeConstant ("TRUE"), (CCodeStatement
) stmt
.body
.ccodenode
);
238 source_declarations
.add_include ("stdbool.h");
239 stmt
.ccodenode
= new
CCodeWhileStatement (new
CCodeConstant ("true"), (CCodeStatement
) stmt
.body
.ccodenode
);
243 public override void visit_foreach_statement (ForeachStatement stmt
) {
244 stmt
.element_variable
.active
= true;
245 stmt
.collection_variable
.active
= true;
246 if (stmt
.iterator_variable
!= null) {
247 stmt
.iterator_variable
.active
= true;
252 var cblock
= new
CCodeBlock ();
254 stmt
.ccodenode
= cblock
;
256 var cfrag
= new
CCodeFragment ();
257 append_temp_decl (cfrag
, stmt
.collection
.temp_vars
);
258 cblock
.add_statement (cfrag
);
260 var collection_backup
= stmt
.collection_variable
;
261 var collection_type
= collection_backup
.variable_type
.copy ();
263 var array_type
= collection_type as ArrayType
;
264 if (array_type
!= null) {
265 // avoid assignment issues
266 array_type
.fixed_length
= false;
269 if (current_method
!= null && current_method
.coroutine
) {
270 closure_struct
.add_field (collection_type
.get_cname (), collection_backup
.name
);
271 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (collection_backup
.name
), (CCodeExpression
) stmt
.collection
.ccodenode
)));
273 var ccoldecl
= new
CCodeDeclaration (collection_type
.get_cname ());
274 var ccolvardecl
= new
CCodeVariableDeclarator (collection_backup
.name
, (CCodeExpression
) stmt
.collection
.ccodenode
);
275 ccolvardecl
.line
= cblock
.line
;
276 ccoldecl
.add_declarator (ccolvardecl
);
277 cblock
.add_statement (ccoldecl
);
280 if (stmt
.tree_can_fail
&& stmt
.collection
.tree_can_fail
) {
281 // exception handling
282 cfrag
= new
CCodeFragment ();
283 head
.add_simple_check (stmt
.collection
, cfrag
);
284 cblock
.add_statement (cfrag
);
287 if (stmt
.collection
.value_type is ArrayType
) {
288 array_type
= (ArrayType
) stmt
.collection
.value_type
;
290 var array_len
= head
.get_array_length_cexpression (stmt
.collection
);
292 // store array length for use by _vala_array_free
293 if (current_method
!= null && current_method
.coroutine
) {
294 closure_struct
.add_field ("int", head
.get_array_length_cname (collection_backup
.name
, 1));
295 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (head
.get_array_length_cname (collection_backup
.name
, 1)), array_len
)));
297 var clendecl
= new
CCodeDeclaration ("int");
298 clendecl
.add_declarator (new
CCodeVariableDeclarator (head
.get_array_length_cname (collection_backup
.name
, 1), array_len
));
299 cblock
.add_statement (clendecl
);
302 var it_name
= (stmt
.variable_name
+ "_it");
304 if (current_method
!= null && current_method
.coroutine
) {
305 closure_struct
.add_field ("int", it_name
);
307 var citdecl
= new
CCodeDeclaration ("int");
308 citdecl
.add_declarator (new
CCodeVariableDeclarator (it_name
));
309 cblock
.add_statement (citdecl
);
312 var cbody
= new
CCodeBlock ();
314 CCodeExpression element_expr
= new
CCodeElementAccess (get_variable_cexpression (collection_backup
.name
), get_variable_cexpression (it_name
));
316 var element_type
= array_type
.element_type
.copy ();
317 element_type
.value_owned
= false;
318 element_expr
= transform_expression (element_expr
, element_type
, stmt
.type_reference
);
320 cfrag
= new
CCodeFragment ();
321 append_temp_decl (cfrag
, temp_vars
);
322 cbody
.add_statement (cfrag
);
325 if (current_method
!= null && current_method
.coroutine
) {
326 closure_struct
.add_field (stmt
.type_reference
.get_cname (), stmt
.variable_name
);
327 cbody
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (stmt
.variable_name
), element_expr
)));
329 var cdecl
= new
CCodeDeclaration (stmt
.type_reference
.get_cname ());
330 cdecl
.add_declarator (new
CCodeVariableDeclarator (stmt
.variable_name
, element_expr
));
331 cbody
.add_statement (cdecl
);
334 // add array length variable for stacked arrays
335 if (stmt
.type_reference is ArrayType
) {
336 var inner_array_type
= (ArrayType
) stmt
.type_reference
;
337 for (int dim
= 1; dim
<= inner_array_type
.rank
; dim
++) {
338 if (current_method
!= null && current_method
.coroutine
) {
339 closure_struct
.add_field ("int", head
.get_array_length_cname (stmt
.variable_name
, dim
));
340 cbody
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (head
.get_array_length_cname (stmt
.variable_name
, dim
)), new
CCodeConstant ("-1"))));
342 var cdecl
= new
CCodeDeclaration ("int");
343 cdecl
.add_declarator (new
CCodeVariableDeclarator (head
.get_array_length_cname (stmt
.variable_name
, dim
), new
CCodeConstant ("-1")));
344 cbody
.add_statement (cdecl
);
349 cbody
.add_statement (stmt
.body
.ccodenode
);
351 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, get_variable_cexpression (it_name
), array_len
);
353 var cfor
= new
CCodeForStatement (ccond
, cbody
);
354 cfor
.add_initializer (new
CCodeAssignment (get_variable_cexpression (it_name
), new
CCodeConstant ("0")));
355 cfor
.add_iterator (new
CCodeAssignment (get_variable_cexpression (it_name
), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, get_variable_cexpression (it_name
), new
CCodeConstant ("1"))));
356 cblock
.add_statement (cfor
);
357 } else if (stmt
.collection
.value_type
.compatible (new
ObjectType (glist_type
)) || stmt
.collection
.value_type
.compatible (new
ObjectType (gslist_type
))) {
358 // iterating over a GList or GSList
360 var it_name
= "%s_it".printf (stmt
.variable_name
);
362 if (current_method
!= null && current_method
.coroutine
) {
363 closure_struct
.add_field (collection_type
.get_cname (), it_name
);
365 var citdecl
= new
CCodeDeclaration (collection_type
.get_cname ());
366 var citvardecl
= new
CCodeVariableDeclarator (it_name
);
367 citvardecl
.line
= cblock
.line
;
368 citdecl
.add_declarator (citvardecl
);
369 cblock
.add_statement (citdecl
);
372 var cbody
= new
CCodeBlock ();
374 CCodeExpression element_expr
= new CCodeMemberAccess
.pointer (get_variable_cexpression (it_name
), "data");
376 if (collection_type
.get_type_arguments ().size
!= 1) {
377 Report
.error (stmt
.source_reference
, "internal error: missing generic type argument");
382 var element_data_type
= collection_type
.get_type_arguments ().get (0).copy ();
383 element_data_type
.value_owned
= false;
384 element_expr
= convert_from_generic_pointer (element_expr
, element_data_type
);
385 element_expr
= transform_expression (element_expr
, element_data_type
, stmt
.type_reference
);
387 cfrag
= new
CCodeFragment ();
388 append_temp_decl (cfrag
, temp_vars
);
389 cbody
.add_statement (cfrag
);
392 if (current_method
!= null && current_method
.coroutine
) {
393 closure_struct
.add_field (stmt
.type_reference
.get_cname (), stmt
.variable_name
);
394 cbody
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (stmt
.variable_name
), element_expr
)));
396 var cdecl
= new
CCodeDeclaration (stmt
.type_reference
.get_cname ());
397 var cvardecl
= new
CCodeVariableDeclarator (stmt
.variable_name
, element_expr
);
398 cvardecl
.line
= cblock
.line
;
399 cdecl
.add_declarator (cvardecl
);
400 cbody
.add_statement (cdecl
);
403 cbody
.add_statement (stmt
.body
.ccodenode
);
405 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, get_variable_cexpression (it_name
), new
CCodeConstant ("NULL"));
407 var cfor
= new
CCodeForStatement (ccond
, cbody
);
409 cfor
.add_initializer (new
CCodeAssignment (get_variable_cexpression (it_name
), get_variable_cexpression (collection_backup
.name
)));
411 cfor
.add_iterator (new
CCodeAssignment (get_variable_cexpression (it_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression (it_name
), "next")));
412 cblock
.add_statement (cfor
);
413 } else if (stmt
.collection
.value_type
.compatible (new
ObjectType (gvaluearray_type
))) {
414 // iterating over a GValueArray
416 var arr_index
= "%s_index".printf (stmt
.variable_name
);
418 if (current_method
!= null && current_method
.coroutine
) {
419 closure_struct
.add_field (uint_type
.get_cname (), arr_index
);
421 var citdecl
= new
CCodeDeclaration (uint_type
.get_cname ());
422 var citvardecl
= new
CCodeVariableDeclarator (arr_index
);
423 citvardecl
.line
= cblock
.line
;
424 citdecl
.add_declarator (citvardecl
);
425 cblock
.add_statement (citdecl
);
428 var cbody
= new
CCodeBlock ();
430 var get_item
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_array_get_nth"));
431 get_item
.add_argument (get_variable_cexpression (collection_backup
.name
));
432 get_item
.add_argument (get_variable_cexpression (arr_index
));
434 CCodeExpression element_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_item
);
436 if (stmt
.type_reference
.value_owned
) {
437 element_expr
= get_ref_cexpression (stmt
.type_reference
, element_expr
, null, new
StructValueType (gvalue_type
));
440 cfrag
= new
CCodeFragment ();
441 append_temp_decl (cfrag
, temp_vars
);
442 cbody
.add_statement (cfrag
);
445 if (current_method
!= null && current_method
.coroutine
) {
446 closure_struct
.add_field (stmt
.type_reference
.get_cname (), stmt
.variable_name
);
447 cbody
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (stmt
.variable_name
), element_expr
)));
449 var cdecl
= new
CCodeDeclaration (stmt
.type_reference
.get_cname ());
450 var cvardecl
= new
CCodeVariableDeclarator (stmt
.variable_name
, element_expr
);
451 cvardecl
.line
= cblock
.line
;
452 cdecl
.add_declarator (cvardecl
);
453 cbody
.add_statement (cdecl
);
456 cbody
.add_statement (stmt
.body
.ccodenode
);
458 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, get_variable_cexpression (arr_index
), new CCodeMemberAccess
.pointer (get_variable_cexpression (collection_backup
.name
), "n_values"));
460 var cfor
= new
CCodeForStatement (ccond
, cbody
);
462 cfor
.add_initializer (new
CCodeAssignment (get_variable_cexpression (arr_index
), new
CCodeConstant ("0")));
464 cfor
.add_iterator (new
CCodeAssignment (get_variable_cexpression (arr_index
), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, get_variable_cexpression (arr_index
), new
CCodeConstant ("1"))));
466 cblock
.add_statement (cfor
);
469 foreach (LocalVariable local
in stmt
.get_local_variables ()) {
470 if (requires_destroy (local
.variable_type
)) {
471 var ma
= new MemberAccess
.simple (local
.name
);
472 ma
.symbol_reference
= local
;
473 var cunref
= new
CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
474 cunref
.line
= cblock
.line
;
475 cblock
.add_statement (cunref
);
480 public override void visit_break_statement (BreakStatement stmt
) {
481 stmt
.ccodenode
= new
CCodeBreakStatement ();
483 create_local_free (stmt
, true);
486 public override void visit_continue_statement (ContinueStatement stmt
) {
487 stmt
.ccodenode
= new
CCodeContinueStatement ();
489 create_local_free (stmt
, true);