codegen: Infer error parameter from abstract/virtual method implementations
[vala-gnome.git] / codegen / valaccodecontrolflowmodule.vala
blob91268e7d1112595b55fca5bd6efd32a77255a06e
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 ccode.open_while (new CCodeConstant ("TRUE"));
211 stmt.body.emit (this);
213 ccode.close ();
216 public override void visit_foreach_statement (ForeachStatement stmt) {
217 ccode.open_block ();
219 var collection_backup = stmt.collection_variable;
220 var collection_type = collection_backup.variable_type;
222 var array_type = collection_type as ArrayType;
223 if (array_type != null) {
224 // avoid assignment issues
225 array_type.inline_allocated = false;
226 array_type.fixed_length = false;
229 visit_local_variable (collection_backup);
230 ccode.add_assignment (get_variable_cexpression (get_local_cname (collection_backup)), get_cvalue (stmt.collection));
232 if (stmt.tree_can_fail && stmt.collection.tree_can_fail) {
233 // exception handling
234 add_simple_check (stmt.collection);
237 if (stmt.collection.value_type is ArrayType) {
238 array_type = (ArrayType) stmt.collection.value_type;
240 var array_len = get_array_length_cexpression (stmt.collection);
242 // store array length for use by _vala_array_free
243 ccode.add_assignment (get_variable_cexpression (get_array_length_cname (get_local_cname (collection_backup), 1)), array_len);
245 var iterator_variable = new LocalVariable (int_type.copy (), stmt.variable_name + "_it");
246 visit_local_variable (iterator_variable);
247 var it_name = get_local_cname (iterator_variable);
249 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (it_name), array_len);
251 ccode.open_for (new CCodeAssignment (get_variable_cexpression (it_name), new CCodeConstant ("0")),
252 ccond,
253 new CCodeAssignment (get_variable_cexpression (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (it_name), new CCodeConstant ("1"))));
255 CCodeExpression element_expr = new CCodeElementAccess (get_variable_cexpression (get_local_cname (collection_backup)), get_variable_cexpression (it_name));
257 var element_type = array_type.element_type.copy ();
258 element_type.value_owned = false;
259 element_expr = get_cvalue_ (transform_value (new GLibValue (element_type, element_expr, true), stmt.type_reference, stmt));
261 visit_local_variable (stmt.element_variable);
262 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
264 // set array length for stacked arrays
265 if (stmt.type_reference is ArrayType) {
266 var inner_array_type = (ArrayType) stmt.type_reference;
267 for (int dim = 1; dim <= inner_array_type.rank; dim++) {
268 ccode.add_assignment (get_variable_cexpression (get_array_length_cname (get_local_cname (stmt.element_variable), dim)), new CCodeConstant ("-1"));
272 stmt.body.emit (this);
274 ccode.close ();
275 } else if (stmt.collection.value_type.compatible (new ObjectType (glist_type)) || stmt.collection.value_type.compatible (new ObjectType (gslist_type))) {
276 // iterating over a GList or GSList
278 var iterator_variable = new LocalVariable (collection_type.copy (), stmt.variable_name + "_it");
279 visit_local_variable (iterator_variable);
280 var it_name = get_local_cname (iterator_variable);
282 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_variable_cexpression (it_name), new CCodeConstant ("NULL"));
284 ccode.open_for (new CCodeAssignment (get_variable_cexpression (it_name), get_variable_cexpression (get_local_cname (collection_backup))),
285 ccond,
286 new CCodeAssignment (get_variable_cexpression (it_name), new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "next")));
288 CCodeExpression element_expr = new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "data");
290 if (collection_type.get_type_arguments ().size != 1) {
291 Report.error (stmt.source_reference, "internal error: missing generic type argument");
292 stmt.error = true;
293 return;
296 var element_data_type = collection_type.get_type_arguments ().get (0).copy ();
297 element_data_type.value_owned = false;
298 element_expr = convert_from_generic_pointer (element_expr, element_data_type);
299 element_expr = get_cvalue_ (transform_value (new GLibValue (element_data_type, element_expr), stmt.type_reference, stmt));
301 visit_local_variable (stmt.element_variable);
302 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
304 stmt.body.emit (this);
306 ccode.close ();
307 } else if (stmt.collection.value_type.compatible (new ObjectType (gvaluearray_type))) {
308 // iterating over a GValueArray
310 var iterator_variable = new LocalVariable (uint_type.copy (), "%s_index".printf (stmt.variable_name));
311 visit_local_variable (iterator_variable);
312 var arr_index = get_variable_cname (get_local_cname (iterator_variable));
314 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"));
316 ccode.open_for (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeConstant ("0")),
317 ccond,
318 new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (arr_index), new CCodeConstant ("1"))));
320 var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_get_nth"));
321 get_item.add_argument (get_variable_cexpression (get_local_cname (collection_backup)));
322 get_item.add_argument (get_variable_cexpression (arr_index));
324 CCodeExpression element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_item);
326 if (stmt.type_reference.value_owned) {
327 element_expr = get_cvalue_ (copy_value (new GLibValue (stmt.type_reference, element_expr), new StructValueType (gvalue_type)));
330 visit_local_variable (stmt.element_variable);
331 ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
333 stmt.body.emit (this);
335 ccode.close ();
338 foreach (LocalVariable local in stmt.get_local_variables ()) {
339 if (requires_destroy (local.variable_type)) {
340 ccode.add_expression (destroy_local (local));
344 ccode.close ();
347 public override void visit_break_statement (BreakStatement stmt) {
348 append_local_free (current_symbol, true);
350 ccode.add_break ();
353 public override void visit_continue_statement (ContinueStatement stmt) {
354 append_local_free (current_symbol, true);
356 ccode.add_continue ();