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_value = create_temp_value (stmt.expression.value_type, false, stmt);
44 var ctemp = get_cvalue_ (temp_value);
46 var cinit = new CCodeAssignment (ctemp, get_cvalue (stmt.expression));
47 var czero = new CCodeConstant ("0");
49 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
50 free_call.add_argument (ctemp);
52 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("NULL"), ctemp);
53 var cquark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
54 cquark.add_argument (ctemp);
56 var ccond = new CCodeConditionalExpression (cisnull, new CCodeConstant ("0"), cquark);
58 int label_temp_id = next_temp_var_id++;
60 temp_value = create_temp_value (gquark_type, true, stmt);
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 = "_tmp%d_label%d".printf (label_temp_id, label_count++);
76 ccode.add_declaration (get_ccode_name (gquark_type), new CCodeVariableDeclarator (cname, czero), CCodeModifiers.STATIC);
81 ccode.add_expression (cinit);
83 ctemp = get_cvalue_ (temp_value);
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 ("_tmp%d_label%d".printf (label_temp_id, 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_statement (LoopStatement 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;
227 var array_type = collection_type as ArrayType;
228 if (array_type != null) {
229 // avoid assignment issues
230 array_type.inline_allocated = false;
231 array_type.fixed_length = false;
234 visit_local_variable (collection_backup);
235 ccode.add_assignment (get_variable_cexpression (get_local_cname (collection_backup)), get_cvalue (stmt.collection));
237 if (stmt.tree_can_fail && stmt.collection.tree_can_fail) {
238 // exception handling
239 add_simple_check (stmt.collection);
242 if (stmt.collection.value_type is ArrayType) {
243 array_type = (ArrayType) stmt.collection.value_type;
245 var array_len = get_variable_cexpression (get_array_length_cname (get_local_cname (collection_backup), 1));
247 // store array length for use by _vala_array_free
248 ccode.add_assignment (array_len, get_array_length_cexpression (stmt.collection));
250 var iterator_variable = new LocalVariable (array_type.length_type.copy (), stmt.variable_name + "_it");
251 visit_local_variable (iterator_variable);
252 var it_name = get_local_cname (iterator_variable);
254 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (it_name), array_len);
256 ccode.open_for (new CCodeAssignment (get_variable_cexpression (it_name), new CCodeConstant ("0")),
258 new CCodeAssignment (get_variable_cexpression (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (it_name), new CCodeConstant ("1"))));
260 CCodeExpression element_expr = new CCodeElementAccess (get_variable_cexpression (get_local_cname (collection_backup)), get_variable_cexpression (it_name));
262 var element_type = array_type.element_type.copy ();
263 element_type.value_owned = false;
264 element_expr = get_cvalue_ (transform_value (new GLibValue (element_type, element_expr, true), stmt.type_reference, stmt));
266 visit_local_variable (stmt.element_variable);
267 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
269 // set array length for stacked arrays
270 if (stmt.type_reference is ArrayType) {
271 var inner_array_type = (ArrayType) stmt.type_reference;
272 for (int dim = 1; dim <= inner_array_type.rank; dim++) {
273 ccode.add_assignment (get_variable_cexpression (get_array_length_cname (get_local_cname (stmt.element_variable), dim)), new CCodeConstant ("-1"));
277 stmt.body.emit (this);
280 } else if (stmt.collection.value_type.compatible (new ObjectType (garray_type))) {
281 // iterating over a GArray
283 var iterator_variable = new LocalVariable (uint_type.copy (), "%s_index".printf (stmt.variable_name));
284 visit_local_variable (iterator_variable);
285 var arr_index = get_variable_cname (get_local_cname (iterator_variable));
287 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (arr_index), new CCodeMemberAccess.pointer (get_variable_cexpression (get_local_cname (collection_backup)), "len"));
289 ccode.open_for (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeConstant ("0")),
291 new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (arr_index), new CCodeConstant ("1"))));
293 var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_array_index"));
294 get_item.add_argument (get_variable_cexpression (get_local_cname (collection_backup)));
295 get_item.add_argument (new CCodeIdentifier (get_ccode_name (stmt.type_reference)));
296 get_item.add_argument (get_variable_cexpression (arr_index));
298 if (collection_type.get_type_arguments ().size != 1) {
299 Report.error (stmt.source_reference, "internal error: missing generic type argument");
304 var element_type = collection_type.get_type_arguments ().get (0).copy ();
305 element_type.value_owned = false;
306 var element_expr = get_cvalue_ (transform_value (new GLibValue (element_type, get_item, true), stmt.type_reference, stmt));
308 visit_local_variable (stmt.element_variable);
309 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
311 stmt.body.emit (this);
314 } else if (stmt.collection.value_type.compatible (new ObjectType (glist_type)) || stmt.collection.value_type.compatible (new ObjectType (gslist_type))) {
315 // iterating over a GList or GSList
317 var iterator_variable = new LocalVariable (collection_type.copy (), stmt.variable_name + "_it");
318 visit_local_variable (iterator_variable);
319 var it_name = get_local_cname (iterator_variable);
321 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_variable_cexpression (it_name), new CCodeConstant ("NULL"));
323 ccode.open_for (new CCodeAssignment (get_variable_cexpression (it_name), get_variable_cexpression (get_local_cname (collection_backup))),
325 new CCodeAssignment (get_variable_cexpression (it_name), new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "next")));
327 CCodeExpression element_expr = new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "data");
329 if (collection_type.get_type_arguments ().size != 1) {
330 Report.error (stmt.source_reference, "internal error: missing generic type argument");
335 var element_data_type = collection_type.get_type_arguments ().get (0).copy ();
336 element_data_type.value_owned = false;
337 element_expr = convert_from_generic_pointer (element_expr, element_data_type);
338 element_expr = get_cvalue_ (transform_value (new GLibValue (element_data_type, element_expr), stmt.type_reference, stmt));
340 visit_local_variable (stmt.element_variable);
341 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
343 stmt.body.emit (this);
346 } else if (stmt.collection.value_type.compatible (new ObjectType ((Class) genericarray_type))) {
347 // iterating over a GenericArray / GPtrArray
349 var iterator_variable = new LocalVariable (uint_type.copy (), "%s_index".printf (stmt.variable_name));
350 visit_local_variable (iterator_variable);
351 var arr_index = get_variable_cname (get_local_cname (iterator_variable));
353 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (arr_index), new CCodeMemberAccess.pointer (get_variable_cexpression (get_local_cname (collection_backup)), "len"));
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_ptr_array_index"));
360 get_item.add_argument (get_variable_cexpression (get_local_cname (collection_backup)));
361 get_item.add_argument (get_variable_cexpression (arr_index));
363 CCodeExpression element_expr = get_item;
365 if (stmt.type_reference.value_owned) {
366 element_expr = get_cvalue_ (copy_value (new GLibValue (stmt.type_reference, element_expr), stmt.element_variable));
369 visit_local_variable (stmt.element_variable);
370 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
372 stmt.body.emit (this);
375 } else if (stmt.collection.value_type.compatible (new ObjectType (gvaluearray_type))) {
376 // iterating over a GValueArray
378 var iterator_variable = new LocalVariable (uint_type.copy (), "%s_index".printf (stmt.variable_name));
379 visit_local_variable (iterator_variable);
380 var arr_index = get_variable_cname (get_local_cname (iterator_variable));
382 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (arr_index), new CCodeMemberAccess.pointer (get_variable_cexpression (get_local_cname (collection_backup)), "n_values"));
384 ccode.open_for (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeConstant ("0")),
386 new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (arr_index), new CCodeConstant ("1"))));
388 var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_get_nth"));
389 get_item.add_argument (get_variable_cexpression (get_local_cname (collection_backup)));
390 get_item.add_argument (get_variable_cexpression (arr_index));
392 CCodeExpression element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_item);
394 if (stmt.type_reference.value_owned) {
395 element_expr = get_cvalue_ (copy_value (new GLibValue (stmt.type_reference, element_expr), new StructValueType (gvalue_type)));
398 visit_local_variable (stmt.element_variable);
399 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
401 stmt.body.emit (this);
404 } else if (stmt.collection.value_type.compatible (new ObjectType (gsequence_type))) {
405 // iterating over a GSequence
407 var iterator_variable = new LocalVariable (new ObjectType (gsequence_iter_type), "%s_iter".printf (stmt.variable_name));
408 visit_local_variable (iterator_variable);
409 var sequence_iter = get_variable_cname (get_local_cname (iterator_variable));
411 var ccond_is_end = new CCodeFunctionCall (new CCodeIdentifier ("g_sequence_iter_is_end"));
412 ccond_is_end.add_argument (get_variable_cexpression (sequence_iter));
413 var ccond = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccond_is_end);
414 var cbegin = new CCodeFunctionCall (new CCodeIdentifier ("g_sequence_get_begin_iter"));
415 cbegin.add_argument (get_variable_cexpression (get_local_cname (collection_backup)));
416 var cnext = new CCodeFunctionCall (new CCodeIdentifier ("g_sequence_iter_next"));
417 cnext.add_argument (get_variable_cexpression (sequence_iter));
419 ccode.open_for (new CCodeAssignment (get_variable_cexpression (sequence_iter), cbegin),
421 new CCodeAssignment (get_variable_cexpression (sequence_iter), cnext));
423 var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_sequence_get"));
424 get_item.add_argument (get_variable_cexpression (sequence_iter));
426 CCodeExpression element_expr = get_item;
428 if (collection_type.get_type_arguments ().size != 1) {
429 Report.error (stmt.source_reference, "internal error: missing generic type argument");
434 var element_type = collection_type.get_type_arguments ().get (0).copy ();
435 element_type.value_owned = false;
436 element_expr = convert_from_generic_pointer (element_expr, element_type);
437 element_expr = get_cvalue_ (transform_value (new GLibValue (element_type, element_expr), stmt.type_reference, stmt));
439 visit_local_variable (stmt.element_variable);
440 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
442 stmt.body.emit (this);
446 Report.error (stmt.source_reference, "internal error: unsupported collection type");
451 foreach (LocalVariable local in stmt.get_local_variables ()) {
452 if (requires_destroy (local.variable_type)) {
453 ccode.add_expression (destroy_local (local));
460 public override void visit_break_statement (BreakStatement stmt) {
461 append_local_free (current_symbol, stmt);
466 public override void visit_continue_statement (ContinueStatement stmt) {
467 append_local_free (current_symbol, stmt);
469 ccode.add_continue ();