codegen: Fix floating reference regression with Variants
[vala-gnome.git] / codegen / valaccodecontrolflowmodule.vala
blob1936d512d5ca88038c540cc6d0d36b2a8ecf4ee3
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_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);
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 = "_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) {
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 ("_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);
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 ccode.close ();
162 if (n > 0) {
163 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;
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_array_length_cexpression (stmt.collection);
247 // store array length for use by _vala_array_free
248 ccode.add_assignment (get_variable_cexpression (get_array_length_cname (get_local_cname (collection_backup), 1)), array_len);
250 var iterator_variable = new LocalVariable (int_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")),
257 ccond,
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);
279 ccode.close ();
280 } else if (stmt.collection.value_type.compatible (new ObjectType (glist_type)) || stmt.collection.value_type.compatible (new ObjectType (gslist_type))) {
281 // iterating over a GList or GSList
283 var iterator_variable = new LocalVariable (collection_type.copy (), stmt.variable_name + "_it");
284 visit_local_variable (iterator_variable);
285 var it_name = get_local_cname (iterator_variable);
287 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_variable_cexpression (it_name), new CCodeConstant ("NULL"));
289 ccode.open_for (new CCodeAssignment (get_variable_cexpression (it_name), get_variable_cexpression (get_local_cname (collection_backup))),
290 ccond,
291 new CCodeAssignment (get_variable_cexpression (it_name), new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "next")));
293 CCodeExpression element_expr = new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "data");
295 if (collection_type.get_type_arguments ().size != 1) {
296 Report.error (stmt.source_reference, "internal error: missing generic type argument");
297 stmt.error = true;
298 return;
301 var element_data_type = collection_type.get_type_arguments ().get (0).copy ();
302 element_data_type.value_owned = false;
303 element_expr = convert_from_generic_pointer (element_expr, element_data_type);
304 element_expr = get_cvalue_ (transform_value (new GLibValue (element_data_type, element_expr), stmt.type_reference, stmt));
306 visit_local_variable (stmt.element_variable);
307 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
309 stmt.body.emit (this);
311 ccode.close ();
312 } else if (stmt.collection.value_type.compatible (new ObjectType (gvaluearray_type))) {
313 // iterating over a GValueArray
315 var iterator_variable = new LocalVariable (uint_type.copy (), "%s_index".printf (stmt.variable_name));
316 visit_local_variable (iterator_variable);
317 var arr_index = get_variable_cname (get_local_cname (iterator_variable));
319 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"));
321 ccode.open_for (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeConstant ("0")),
322 ccond,
323 new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (arr_index), new CCodeConstant ("1"))));
325 var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_get_nth"));
326 get_item.add_argument (get_variable_cexpression (get_local_cname (collection_backup)));
327 get_item.add_argument (get_variable_cexpression (arr_index));
329 CCodeExpression element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_item);
331 if (stmt.type_reference.value_owned) {
332 element_expr = get_cvalue_ (copy_value (new GLibValue (stmt.type_reference, element_expr), new StructValueType (gvalue_type)));
335 visit_local_variable (stmt.element_variable);
336 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
338 stmt.body.emit (this);
340 ccode.close ();
343 foreach (LocalVariable local in stmt.get_local_variables ()) {
344 if (requires_destroy (local.variable_type)) {
345 ccode.add_expression (destroy_local (local));
349 ccode.close ();
352 public override void visit_break_statement (BreakStatement stmt) {
353 append_local_free (current_symbol, true);
355 ccode.add_break ();
358 public override void visit_continue_statement (ContinueStatement stmt) {
359 append_local_free (current_symbol, true);
361 ccode.add_continue ();