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>
27 public class Vala
.CCodeControlFlowModule
: CCodeMethodModule
{
28 public override void visit_if_statement (IfStatement stmt
) {
29 stmt
.true_statement
.emit (this
);
30 if (stmt
.false_statement
!= null) {
31 stmt
.false_statement
.emit (this
);
34 if (stmt
.false_statement
!= null) {
35 stmt
.ccodenode
= new
CCodeIfStatement ((CCodeExpression
) stmt
.condition
.ccodenode
, (CCodeStatement
) stmt
.true_statement
.ccodenode
, (CCodeStatement
) stmt
.false_statement
.ccodenode
);
37 stmt
.ccodenode
= new
CCodeIfStatement ((CCodeExpression
) stmt
.condition
.ccodenode
, (CCodeStatement
) stmt
.true_statement
.ccodenode
);
40 create_temp_decl (stmt
, stmt
.condition
.temp_vars
);
43 void visit_string_switch_statement (SwitchStatement stmt
) {
44 // we need a temporary variable to save the property value
45 var temp_var
= get_temp_variable (stmt
.expression
.value_type
, stmt
.expression
.value_type
.value_owned
, stmt
, false);
46 stmt
.expression
.add_temp_var (temp_var
);
48 var ctemp
= get_variable_cexpression (temp_var
.name
);
49 var cinit
= new
CCodeAssignment (ctemp
, (CCodeExpression
) stmt
.expression
.ccodenode
);
50 var czero
= new
CCodeConstant ("0");
52 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
53 free_call
.add_argument (ctemp
);
55 var cswitchblock
= new
CCodeFragment ();
56 stmt
.ccodenode
= cswitchblock
;
58 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeConstant ("NULL"), ctemp
);
59 var cquark
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_string"));
60 cquark
.add_argument (ctemp
);
62 var ccond
= new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("0"), cquark
);
64 temp_var
= get_temp_variable (gquark_type
);
65 stmt
.expression
.add_temp_var (temp_var
);
69 foreach (SwitchSection section
in stmt
.get_sections ()) {
70 if (section
.has_default_label ()) {
74 foreach (SwitchLabel label
in section
.get_labels ()) {
75 var cexpr
= (CCodeExpression
) label
.expression
.ccodenode
;
77 if (is_constant_ccode_expression (cexpr
)) {
78 var cname
= "%s_label%d".printf (temp_var
.name
, label_count
++);
79 var cdecl
= new
CCodeDeclaration (gquark_type
.get_cname ());
81 cdecl
.modifiers
= CCodeModifiers
.STATIC
;
82 cdecl
.add_declarator (new
CCodeVariableDeclarator (cname
, czero
));
84 cswitchblock
.append (cdecl
);
89 cswitchblock
.append (new
CCodeExpressionStatement (cinit
));
91 ctemp
= get_variable_cexpression (temp_var
.name
);
92 cinit
= new
CCodeAssignment (ctemp
, ccond
);
94 cswitchblock
.append (new
CCodeExpressionStatement (cinit
));
95 create_temp_decl (stmt
, stmt
.expression
.temp_vars
);
97 if (stmt
.expression
.value_type
.value_owned
) {
99 cswitchblock
.append (new
CCodeExpressionStatement (free_call
));
102 List
<Statement
> default_statements
= null;
105 // generate nested if statements
106 CCodeStatement ctopstmt
= null;
107 CCodeIfStatement coldif
= null;
109 foreach (SwitchSection section
in stmt
.get_sections ()) {
110 if (section
.has_default_label ()) {
111 default_statements
= section
.get_statements ();
115 CCodeBinaryExpression cor
= null;
116 foreach (SwitchLabel label
in section
.get_labels ()) {
117 var cexpr
= (CCodeExpression
) label
.expression
.ccodenode
;
119 if (is_constant_ccode_expression (cexpr
)) {
120 var cname
= new
CCodeIdentifier ("%s_label%d".printf (temp_var
.name
, label_count
++));
121 var ccondition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, czero
, cname
);
122 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_static_string"));
123 cinit
= new
CCodeAssignment (cname
, ccall
);
125 ccall
.add_argument (cexpr
);
127 cexpr
= new
CCodeConditionalExpression (ccondition
, cname
, cinit
);
129 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_string"));
130 ccall
.add_argument (cexpr
);
134 var ccmp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, cexpr
);
139 cor
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cor
, ccmp
);
143 var cblock
= new
CCodeBlock ();
144 foreach (CodeNode body_stmt
in section
.get_statements ()) {
145 if (body_stmt
.ccodenode is CCodeFragment
) {
146 foreach (CCodeNode cstmt
in ((CCodeFragment
) body_stmt
.ccodenode
).get_children ()) {
147 cblock
.add_statement (cstmt
);
150 cblock
.add_statement (body_stmt
.ccodenode
);
154 var cswitch
= new
CCodeSwitchStatement (new
CCodeConstant ("0"));
155 cswitch
.add_statement (new
CCodeLabel ("default"));
156 cswitch
.add_statement (cblock
);
157 var cif
= new
CCodeIfStatement (cor
, cswitch
);
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 cswitch
= new
CCodeSwitchStatement (new
CCodeConstant ("0"));
175 cswitch
.add_statement (new
CCodeLabel ("default"));
176 cswitch
.add_statement (cblock
);
178 if (coldif
== null) {
179 // there is only one section and that section
180 // contains a default label
183 coldif
.false_statement
= cswitch
;
187 cswitchblock
.append (ctopstmt
);
190 public override void visit_switch_statement (SwitchStatement stmt
) {
191 foreach (SwitchSection section
in stmt
.get_sections ()) {
195 if (stmt
.expression
.value_type
.compatible (string_type
)) {
196 visit_string_switch_statement (stmt
);
200 var cswitch
= new
CCodeSwitchStatement ((CCodeExpression
) stmt
.expression
.ccodenode
);
201 stmt
.ccodenode
= cswitch
;
203 foreach (SwitchSection section
in stmt
.get_sections ()) {
204 if (section
.has_default_label ()) {
205 cswitch
.add_statement (new
CCodeLabel ("default"));
206 var cdefaultblock
= new
CCodeBlock ();
207 cswitch
.add_statement (cdefaultblock
);
208 foreach (CodeNode default_stmt
in section
.get_statements ()) {
209 cdefaultblock
.add_statement (default_stmt
.ccodenode
);
214 foreach (SwitchLabel label
in section
.get_labels ()) {
215 cswitch
.add_statement (new
CCodeCaseStatement ((CCodeExpression
) label
.expression
.ccodenode
));
218 cswitch
.add_statement (section
.ccodenode
);
221 create_temp_decl (stmt
, stmt
.expression
.temp_vars
);
224 public override void visit_switch_label (SwitchLabel label
) {
225 if (label
.expression
!= null) {
226 label
.expression
.emit (this
);
228 visit_end_full_expression (label
.expression
);
232 public override void visit_loop (Loop stmt
) {
233 stmt
.body
.emit (this
);
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
.body
.emit (this
);
248 var cblock
= new
CCodeBlock ();
250 stmt
.ccodenode
= cblock
;
252 var cfrag
= new
CCodeFragment ();
253 append_temp_decl (cfrag
, stmt
.collection
.temp_vars
);
254 cblock
.add_statement (cfrag
);
256 var collection_backup
= stmt
.collection_variable
;
257 var collection_type
= collection_backup
.variable_type
.copy ();
259 var array_type
= collection_type as ArrayType
;
260 if (array_type
!= null) {
261 // avoid assignment issues
262 array_type
.fixed_length
= false;
265 if (current_method
!= null && current_method
.coroutine
) {
266 closure_struct
.add_field (collection_type
.get_cname (), collection_backup
.name
);
267 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (collection_backup
.name
), (CCodeExpression
) stmt
.collection
.ccodenode
)));
269 var ccoldecl
= new
CCodeDeclaration (collection_type
.get_cname ());
270 var ccolvardecl
= new
CCodeVariableDeclarator (collection_backup
.name
, (CCodeExpression
) stmt
.collection
.ccodenode
);
271 ccolvardecl
.line
= cblock
.line
;
272 ccoldecl
.add_declarator (ccolvardecl
);
273 cblock
.add_statement (ccoldecl
);
276 if (stmt
.tree_can_fail
&& stmt
.collection
.tree_can_fail
) {
277 // exception handling
278 cfrag
= new
CCodeFragment ();
279 add_simple_check (stmt
.collection
, cfrag
);
280 cblock
.add_statement (cfrag
);
283 if (stmt
.collection
.value_type is ArrayType
) {
284 array_type
= (ArrayType
) stmt
.collection
.value_type
;
286 var array_len
= get_array_length_cexpression (stmt
.collection
);
288 // store array length for use by _vala_array_free
289 if (current_method
!= null && current_method
.coroutine
) {
290 closure_struct
.add_field ("int", get_array_length_cname (collection_backup
.name
, 1));
291 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (get_array_length_cname (collection_backup
.name
, 1)), array_len
)));
293 var clendecl
= new
CCodeDeclaration ("int");
294 clendecl
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (collection_backup
.name
, 1), array_len
));
295 cblock
.add_statement (clendecl
);
298 var it_name
= (stmt
.variable_name
+ "_it");
300 if (current_method
!= null && current_method
.coroutine
) {
301 closure_struct
.add_field ("int", it_name
);
303 var citdecl
= new
CCodeDeclaration ("int");
304 citdecl
.add_declarator (new
CCodeVariableDeclarator (it_name
));
305 cblock
.add_statement (citdecl
);
308 var cbody
= new
CCodeBlock ();
310 CCodeExpression element_expr
= new
CCodeElementAccess (get_variable_cexpression (collection_backup
.name
), get_variable_cexpression (it_name
));
312 var element_type
= array_type
.element_type
.copy ();
313 element_type
.value_owned
= false;
314 element_expr
= transform_expression (element_expr
, element_type
, stmt
.type_reference
);
316 cfrag
= new
CCodeFragment ();
317 append_temp_decl (cfrag
, temp_vars
);
318 cbody
.add_statement (cfrag
);
321 if (current_method
!= null && current_method
.coroutine
) {
322 closure_struct
.add_field (stmt
.type_reference
.get_cname (), stmt
.variable_name
);
323 cbody
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (stmt
.variable_name
), element_expr
)));
325 var cdecl
= new
CCodeDeclaration (stmt
.type_reference
.get_cname ());
326 cdecl
.add_declarator (new
CCodeVariableDeclarator (stmt
.variable_name
, element_expr
));
327 cbody
.add_statement (cdecl
);
330 // add array length variable for stacked arrays
331 if (stmt
.type_reference is ArrayType
) {
332 var inner_array_type
= (ArrayType
) stmt
.type_reference
;
333 for (int dim
= 1; dim
<= inner_array_type
.rank
; dim
++) {
334 if (current_method
!= null && current_method
.coroutine
) {
335 closure_struct
.add_field ("int", get_array_length_cname (stmt
.variable_name
, dim
));
336 cbody
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (get_array_length_cname (stmt
.variable_name
, dim
)), new
CCodeConstant ("-1"))));
338 var cdecl
= new
CCodeDeclaration ("int");
339 cdecl
.add_declarator (new
CCodeVariableDeclarator (get_array_length_cname (stmt
.variable_name
, dim
), new
CCodeConstant ("-1")));
340 cbody
.add_statement (cdecl
);
345 cbody
.add_statement (stmt
.body
.ccodenode
);
347 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, get_variable_cexpression (it_name
), array_len
);
349 var cfor
= new
CCodeForStatement (ccond
, cbody
);
350 cfor
.add_initializer (new
CCodeAssignment (get_variable_cexpression (it_name
), new
CCodeConstant ("0")));
351 cfor
.add_iterator (new
CCodeAssignment (get_variable_cexpression (it_name
), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, get_variable_cexpression (it_name
), new
CCodeConstant ("1"))));
352 cblock
.add_statement (cfor
);
353 } else if (stmt
.collection
.value_type
.compatible (new
ObjectType (glist_type
)) || stmt
.collection
.value_type
.compatible (new
ObjectType (gslist_type
))) {
354 // iterating over a GList or GSList
356 var it_name
= "%s_it".printf (stmt
.variable_name
);
358 if (current_method
!= null && current_method
.coroutine
) {
359 closure_struct
.add_field (collection_type
.get_cname (), it_name
);
361 var citdecl
= new
CCodeDeclaration (collection_type
.get_cname ());
362 var citvardecl
= new
CCodeVariableDeclarator (it_name
);
363 citvardecl
.line
= cblock
.line
;
364 citdecl
.add_declarator (citvardecl
);
365 cblock
.add_statement (citdecl
);
368 var cbody
= new
CCodeBlock ();
370 CCodeExpression element_expr
= new CCodeMemberAccess
.pointer (get_variable_cexpression (it_name
), "data");
372 if (collection_type
.get_type_arguments ().size
!= 1) {
373 Report
.error (stmt
.source_reference
, "internal error: missing generic type argument");
378 var element_data_type
= collection_type
.get_type_arguments ().get (0).copy ();
379 element_data_type
.value_owned
= false;
380 element_expr
= convert_from_generic_pointer (element_expr
, element_data_type
);
381 element_expr
= transform_expression (element_expr
, element_data_type
, stmt
.type_reference
);
383 cfrag
= new
CCodeFragment ();
384 append_temp_decl (cfrag
, temp_vars
);
385 cbody
.add_statement (cfrag
);
388 if (current_method
!= null && current_method
.coroutine
) {
389 closure_struct
.add_field (stmt
.type_reference
.get_cname (), stmt
.variable_name
);
390 cbody
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (stmt
.variable_name
), element_expr
)));
392 var cdecl
= new
CCodeDeclaration (stmt
.type_reference
.get_cname ());
393 var cvardecl
= new
CCodeVariableDeclarator (stmt
.variable_name
, element_expr
);
394 cvardecl
.line
= cblock
.line
;
395 cdecl
.add_declarator (cvardecl
);
396 cbody
.add_statement (cdecl
);
399 cbody
.add_statement (stmt
.body
.ccodenode
);
401 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, get_variable_cexpression (it_name
), new
CCodeConstant ("NULL"));
403 var cfor
= new
CCodeForStatement (ccond
, cbody
);
405 cfor
.add_initializer (new
CCodeAssignment (get_variable_cexpression (it_name
), get_variable_cexpression (collection_backup
.name
)));
407 cfor
.add_iterator (new
CCodeAssignment (get_variable_cexpression (it_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression (it_name
), "next")));
408 cblock
.add_statement (cfor
);
409 } else if (stmt
.collection
.value_type
.compatible (new
ObjectType (gvaluearray_type
))) {
410 // iterating over a GValueArray
412 var arr_index
= "%s_index".printf (stmt
.variable_name
);
414 if (current_method
!= null && current_method
.coroutine
) {
415 closure_struct
.add_field (uint_type
.get_cname (), arr_index
);
417 var citdecl
= new
CCodeDeclaration (uint_type
.get_cname ());
418 var citvardecl
= new
CCodeVariableDeclarator (arr_index
);
419 citvardecl
.line
= cblock
.line
;
420 citdecl
.add_declarator (citvardecl
);
421 cblock
.add_statement (citdecl
);
424 var cbody
= new
CCodeBlock ();
426 var get_item
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_array_get_nth"));
427 get_item
.add_argument (get_variable_cexpression (collection_backup
.name
));
428 get_item
.add_argument (get_variable_cexpression (arr_index
));
430 CCodeExpression element_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_item
);
432 if (stmt
.type_reference
.value_owned
) {
433 element_expr
= get_ref_cexpression (stmt
.type_reference
, element_expr
, null, new
StructValueType (gvalue_type
));
436 cfrag
= new
CCodeFragment ();
437 append_temp_decl (cfrag
, temp_vars
);
438 cbody
.add_statement (cfrag
);
441 if (current_method
!= null && current_method
.coroutine
) {
442 closure_struct
.add_field (stmt
.type_reference
.get_cname (), stmt
.variable_name
);
443 cbody
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (get_variable_cexpression (stmt
.variable_name
), element_expr
)));
445 var cdecl
= new
CCodeDeclaration (stmt
.type_reference
.get_cname ());
446 var cvardecl
= new
CCodeVariableDeclarator (stmt
.variable_name
, element_expr
);
447 cvardecl
.line
= cblock
.line
;
448 cdecl
.add_declarator (cvardecl
);
449 cbody
.add_statement (cdecl
);
452 cbody
.add_statement (stmt
.body
.ccodenode
);
454 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, get_variable_cexpression (arr_index
), new CCodeMemberAccess
.pointer (get_variable_cexpression (collection_backup
.name
), "n_values"));
456 var cfor
= new
CCodeForStatement (ccond
, cbody
);
458 cfor
.add_initializer (new
CCodeAssignment (get_variable_cexpression (arr_index
), new
CCodeConstant ("0")));
460 cfor
.add_iterator (new
CCodeAssignment (get_variable_cexpression (arr_index
), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, get_variable_cexpression (arr_index
), new
CCodeConstant ("1"))));
462 cblock
.add_statement (cfor
);
465 foreach (LocalVariable local
in stmt
.get_local_variables ()) {
466 if (requires_destroy (local
.variable_type
)) {
467 var ma
= new MemberAccess
.simple (local
.name
);
468 ma
.symbol_reference
= local
;
469 var cunref
= new
CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
));
470 cunref
.line
= cblock
.line
;
471 cblock
.add_statement (cunref
);
476 public override void visit_break_statement (BreakStatement stmt
) {
477 stmt
.ccodenode
= new
CCodeBreakStatement ();
479 create_local_free (stmt
, true);
482 public override void visit_continue_statement (ContinueStatement stmt
) {
483 stmt
.ccodenode
= new
CCodeContinueStatement ();
485 create_local_free (stmt
, true);