codegen: Fix array size variable on assignment
[vala-lang.git] / codegen / valaccodecontrolflowmodule.vala
blob70f7a5ac7ecd846528d21559244549a1601f2689
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
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) {
34 ccode.add_else ();
35 stmt.false_statement.emit (this);
38 ccode.close ();
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);
62 int label_count = 0;
64 foreach (SwitchSection section in stmt.get_sections ()) {
65 if (section.has_default_label ()) {
66 continue;
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) {
89 // free owned string
90 ccode.add_expression (free_call);
93 SwitchSection default_section = null;
94 label_count = 0;
96 int n = 0;
98 foreach (SwitchSection section in stmt.get_sections ()) {
99 if (section.has_default_label ()) {
100 default_section = section;
101 continue;
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);
118 } else {
119 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
120 ccall.add_argument (cexpr);
121 cexpr = ccall;
124 var ccmp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, cexpr);
126 if (cor == null) {
127 cor = ccmp;
128 } else {
129 cor = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cor, ccmp);
133 if (n > 0) {
134 ccode.else_if (cor);
135 } else {
136 ccode.open_if (cor);
139 ccode.open_switch (new CCodeConstant ("0"));
140 ccode.add_default ();
142 section.emit (this);
144 ccode.close ();
146 n++;
149 if (default_section != null) {
150 if (n > 0) {
151 ccode.add_else ();
154 ccode.open_switch (new CCodeConstant ("0"));
155 ccode.add_default ();
157 default_section.emit (this);
159 if (n > 0) {
160 ccode.close ();
164 ccode.close ();
167 public override void visit_switch_statement (SwitchStatement stmt) {
168 if (stmt.expression.value_type.compatible (string_type)) {
169 visit_string_switch_statement (stmt);
170 return;
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 ();
180 has_default = true;
182 section.emit (this);
185 if (!has_default) {
186 // silence C compiler
187 ccode.add_default ();
188 ccode.add_break ();
191 ccode.close ();
194 public override void visit_switch_label (SwitchLabel label) {
195 if (((SwitchStatement) label.section.parent_node).expression.value_type.compatible (string_type)) {
196 return;
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"));
211 } else {
212 cfile.add_include ("stdbool.h");
213 ccode.open_while (new CCodeConstant ("true"));
216 stmt.body.emit (this);
218 ccode.close ();
221 public override void visit_foreach_statement (ForeachStatement stmt) {
222 ccode.open_block ();
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);
235 } else {
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));
254 } else {
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);
263 } else {
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")),
270 ccond,
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);
281 } else {
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"));
293 } else {
294 ccode.add_declaration ("int", new CCodeVariableDeclarator (get_array_length_cname (stmt.variable_name, dim), new CCodeConstant ("-1")));
299 stmt.body.emit (this);
301 ccode.close ();
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);
309 } else {
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)),
316 ccond,
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");
323 stmt.error = true;
324 return;
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);
334 } else {
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);
341 ccode.close ();
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);
349 } else {
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")),
356 ccond,
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);
371 } else {
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);
378 ccode.close ();
381 foreach (LocalVariable local in stmt.get_local_variables ()) {
382 if (requires_destroy (local.variable_type)) {
383 ccode.add_expression (destroy_local (local));
387 ccode.close ();
390 public override void visit_break_statement (BreakStatement stmt) {
391 append_local_free (current_symbol, true);
393 ccode.add_break ();
396 public override void visit_continue_statement (ContinueStatement stmt) {
397 append_local_free (current_symbol, true);
399 ccode.add_continue ();