1 /* valaccodecontrolflowmodule.vala
3 * Copyright (C) 2006-2011 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 abstract class Vala
.CCodeControlFlowModule
: CCodeMethodModule
{
28 public override void visit_if_statement (IfStatement stmt
) {
29 ccode
.open_if (get_cvalue (stmt
.condition
));
31 stmt
.true_statement
.emit (this
);
33 if (stmt
.false_statement
!= null) {
35 stmt
.false_statement
.emit (this
);
41 void visit_string_switch_statement (SwitchStatement stmt
) {
42 // we need a temporary variable to save the property value
43 var temp_var
= get_temp_variable (stmt
.expression
.value_type
, stmt
.expression
.value_type
.value_owned
, stmt
, false);
44 emit_temp_var (temp_var
);
46 var ctemp
= get_variable_cexpression (temp_var
.name
);
47 var cinit
= new
CCodeAssignment (ctemp
, get_cvalue (stmt
.expression
));
48 var czero
= new
CCodeConstant ("0");
50 var free_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
51 free_call
.add_argument (ctemp
);
53 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeConstant ("NULL"), ctemp
);
54 var cquark
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_string"));
55 cquark
.add_argument (ctemp
);
57 var ccond
= new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("0"), cquark
);
59 temp_var
= get_temp_variable (gquark_type
);
60 emit_temp_var (temp_var
);
64 foreach (SwitchSection section
in stmt
.get_sections ()) {
65 if (section
.has_default_label ()) {
69 foreach (SwitchLabel label
in section
.get_labels ()) {
70 label
.expression
.emit (this
);
71 var cexpr
= get_cvalue (label
.expression
);
73 if (is_constant_ccode_expression (cexpr
)) {
74 var cname
= "%s_label%d".printf (temp_var
.name
, label_count
++);
76 ccode
.add_declaration (gquark_type
.get_cname (), new
CCodeVariableDeclarator (cname
, czero
), CCodeModifiers
.STATIC
);
81 ccode
.add_expression (cinit
);
83 ctemp
= get_variable_cexpression (temp_var
.name
);
84 cinit
= new
CCodeAssignment (ctemp
, ccond
);
86 ccode
.add_expression (cinit
);
88 if (stmt
.expression
.value_type
.value_owned
) {
90 ccode
.add_expression (free_call
);
93 SwitchSection default_section
= null;
98 foreach (SwitchSection section
in stmt
.get_sections ()) {
99 if (section
.has_default_label ()) {
100 default_section
= section
;
104 CCodeBinaryExpression cor
= null;
105 foreach (SwitchLabel label
in section
.get_labels ()) {
106 label
.expression
.emit (this
);
107 var cexpr
= get_cvalue (label
.expression
);
109 if (is_constant_ccode_expression (cexpr
)) {
110 var cname
= new
CCodeIdentifier ("%s_label%d".printf (temp_var
.name
, label_count
++));
111 var ccondition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, czero
, cname
);
112 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_static_string"));
113 cinit
= new
CCodeAssignment (cname
, ccall
);
115 ccall
.add_argument (cexpr
);
117 cexpr
= new
CCodeConditionalExpression (ccondition
, cname
, cinit
);
119 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_string"));
120 ccall
.add_argument (cexpr
);
124 var ccmp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, cexpr
);
129 cor
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cor
, ccmp
);
139 ccode
.open_switch (new
CCodeConstant ("0"));
140 ccode
.add_default ();
149 if (default_section
!= null) {
154 ccode
.open_switch (new
CCodeConstant ("0"));
155 ccode
.add_default ();
157 default_section
.emit (this
);
167 public override void visit_switch_statement (SwitchStatement stmt
) {
168 if (stmt
.expression
.value_type
.compatible (string_type
)) {
169 visit_string_switch_statement (stmt
);
173 ccode
.open_switch (get_cvalue (stmt
.expression
));
175 bool has_default
= false;
177 foreach (SwitchSection section
in stmt
.get_sections ()) {
178 if (section
.has_default_label ()) {
179 ccode
.add_default ();
186 // silence C compiler
187 ccode
.add_default ();
194 public override void visit_switch_label (SwitchLabel label
) {
195 if (((SwitchStatement
) label
.section
.parent_node
).expression
.value_type
.compatible (string_type
)) {
199 if (label
.expression
!= null) {
200 label
.expression
.emit (this
);
202 visit_end_full_expression (label
.expression
);
204 ccode
.add_case (get_cvalue (label
.expression
));
208 public override void visit_loop (Loop stmt
) {
209 if (context
.profile
== Profile
.GOBJECT
) {
210 ccode
.open_while (new
CCodeConstant ("TRUE"));
212 cfile
.add_include ("stdbool.h");
213 ccode
.open_while (new
CCodeConstant ("true"));
216 stmt
.body
.emit (this
);
221 public override void visit_foreach_statement (ForeachStatement stmt
) {
224 var collection_backup
= stmt
.collection_variable
;
225 var collection_type
= collection_backup
.variable_type
.copy ();
227 var array_type
= collection_type as ArrayType
;
228 if (array_type
!= null) {
229 // avoid assignment issues
230 array_type
.fixed_length
= false;
233 if (is_in_coroutine ()) {
234 closure_struct
.add_field (collection_type
.get_cname (), collection_backup
.name
);
236 var ccolvardecl
= new
CCodeVariableDeclarator (collection_backup
.name
);
237 ccode
.add_declaration (collection_type
.get_cname (), ccolvardecl
);
239 ccode
.add_assignment (get_variable_cexpression (collection_backup
.name
), get_cvalue (stmt
.collection
));
241 if (stmt
.tree_can_fail
&& stmt
.collection
.tree_can_fail
) {
242 // exception handling
243 add_simple_check (stmt
.collection
);
246 if (stmt
.collection
.value_type is ArrayType
) {
247 array_type
= (ArrayType
) stmt
.collection
.value_type
;
249 var array_len
= get_array_length_cexpression (stmt
.collection
);
251 // store array length for use by _vala_array_free
252 if (is_in_coroutine ()) {
253 closure_struct
.add_field ("int", get_array_length_cname (collection_backup
.name
, 1));
255 ccode
.add_declaration ("int", new
CCodeVariableDeclarator (get_array_length_cname (collection_backup
.name
, 1)));
257 ccode
.add_assignment (get_variable_cexpression (get_array_length_cname (collection_backup
.name
, 1)), array_len
);
259 var it_name
= (stmt
.variable_name
+ "_it");
261 if (is_in_coroutine ()) {
262 closure_struct
.add_field ("int", it_name
);
264 ccode
.add_declaration ("int", new
CCodeVariableDeclarator (it_name
));
267 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, get_variable_cexpression (it_name
), array_len
);
269 ccode
.open_for (new
CCodeAssignment (get_variable_cexpression (it_name
), new
CCodeConstant ("0")),
271 new
CCodeAssignment (get_variable_cexpression (it_name
), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, get_variable_cexpression (it_name
), new
CCodeConstant ("1"))));
273 CCodeExpression element_expr
= new
CCodeElementAccess (get_variable_cexpression (collection_backup
.name
), get_variable_cexpression (it_name
));
275 var element_type
= array_type
.element_type
.copy ();
276 element_type
.value_owned
= false;
277 element_expr
= transform_expression (element_expr
, element_type
, stmt
.type_reference
);
279 if (is_in_coroutine ()) {
280 closure_struct
.add_field (stmt
.type_reference
.get_cname (), stmt
.variable_name
);
282 ccode
.add_declaration (stmt
.type_reference
.get_cname (), new
CCodeVariableDeclarator (stmt
.variable_name
));
284 ccode
.add_assignment (get_variable_cexpression (stmt
.variable_name
), element_expr
);
286 // add array length variable for stacked arrays
287 if (stmt
.type_reference is ArrayType
) {
288 var inner_array_type
= (ArrayType
) stmt
.type_reference
;
289 for (int dim
= 1; dim
<= inner_array_type
.rank
; dim
++) {
290 if (is_in_coroutine ()) {
291 closure_struct
.add_field ("int", get_array_length_cname (stmt
.variable_name
, dim
));
292 ccode
.add_assignment (get_variable_cexpression (get_array_length_cname (stmt
.variable_name
, dim
)), new
CCodeConstant ("-1"));
294 ccode
.add_declaration ("int", new
CCodeVariableDeclarator (get_array_length_cname (stmt
.variable_name
, dim
), new
CCodeConstant ("-1")));
299 stmt
.body
.emit (this
);
302 } else if (stmt
.collection
.value_type
.compatible (new
ObjectType (glist_type
)) || stmt
.collection
.value_type
.compatible (new
ObjectType (gslist_type
))) {
303 // iterating over a GList or GSList
305 var it_name
= "%s_it".printf (stmt
.variable_name
);
307 if (is_in_coroutine ()) {
308 closure_struct
.add_field (collection_type
.get_cname (), it_name
);
310 ccode
.add_declaration (collection_type
.get_cname (), new
CCodeVariableDeclarator (it_name
));
313 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, get_variable_cexpression (it_name
), new
CCodeConstant ("NULL"));
315 ccode
.open_for (new
CCodeAssignment (get_variable_cexpression (it_name
), get_variable_cexpression (collection_backup
.name
)),
317 new
CCodeAssignment (get_variable_cexpression (it_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression (it_name
), "next")));
319 CCodeExpression element_expr
= new CCodeMemberAccess
.pointer (get_variable_cexpression (it_name
), "data");
321 if (collection_type
.get_type_arguments ().size
!= 1) {
322 Report
.error (stmt
.source_reference
, "internal error: missing generic type argument");
327 var element_data_type
= collection_type
.get_type_arguments ().get (0).copy ();
328 element_data_type
.value_owned
= false;
329 element_expr
= convert_from_generic_pointer (element_expr
, element_data_type
);
330 element_expr
= transform_expression (element_expr
, element_data_type
, stmt
.type_reference
);
332 if (is_in_coroutine ()) {
333 closure_struct
.add_field (stmt
.type_reference
.get_cname (), stmt
.variable_name
);
335 ccode
.add_declaration (stmt
.type_reference
.get_cname (), new
CCodeVariableDeclarator (stmt
.variable_name
));
337 ccode
.add_assignment (get_variable_cexpression (stmt
.variable_name
), element_expr
);
339 stmt
.body
.emit (this
);
342 } else if (stmt
.collection
.value_type
.compatible (new
ObjectType (gvaluearray_type
))) {
343 // iterating over a GValueArray
345 var arr_index
= "%s_index".printf (stmt
.variable_name
);
347 if (is_in_coroutine ()) {
348 closure_struct
.add_field (uint_type
.get_cname (), arr_index
);
350 ccode
.add_declaration (uint_type
.get_cname (), new
CCodeVariableDeclarator (arr_index
));
353 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, get_variable_cexpression (arr_index
), new CCodeMemberAccess
.pointer (get_variable_cexpression (collection_backup
.name
), "n_values"));
355 ccode
.open_for (new
CCodeAssignment (get_variable_cexpression (arr_index
), new
CCodeConstant ("0")),
357 new
CCodeAssignment (get_variable_cexpression (arr_index
), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, get_variable_cexpression (arr_index
), new
CCodeConstant ("1"))));
359 var get_item
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_array_get_nth"));
360 get_item
.add_argument (get_variable_cexpression (collection_backup
.name
));
361 get_item
.add_argument (get_variable_cexpression (arr_index
));
363 CCodeExpression element_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_item
);
365 if (stmt
.type_reference
.value_owned
) {
366 element_expr
= get_ref_cexpression (stmt
.type_reference
, element_expr
, null, new
StructValueType (gvalue_type
));
369 if (is_in_coroutine ()) {
370 closure_struct
.add_field (stmt
.type_reference
.get_cname (), stmt
.variable_name
);
372 ccode
.add_declaration (stmt
.type_reference
.get_cname (), new
CCodeVariableDeclarator (stmt
.variable_name
));
374 ccode
.add_assignment (get_variable_cexpression (stmt
.variable_name
), element_expr
);
376 stmt
.body
.emit (this
);
381 foreach (LocalVariable local
in stmt
.get_local_variables ()) {
382 if (requires_destroy (local
.variable_type
)) {
383 ccode
.add_expression (destroy_local (local
));
390 public override void visit_break_statement (BreakStatement stmt
) {
391 append_local_free (current_symbol
, true);
396 public override void visit_continue_statement (ContinueStatement stmt
) {
397 append_local_free (current_symbol
, true);
399 ccode
.add_continue ();