GAsync: Various fixes for temp variables in coroutines
[vala-lang.git] / codegen / valaccodecontrolflowmodule.vala
blob0a7d2742dc20cc800731346c6d8a7d2f2e2f5c1b
1 /* valaccodecontrolflowmodule.vala
3 * Copyright (C) 2006-2009 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;
26 using Gee;
28 internal class Vala.CCodeControlFlowModule : CCodeMethodModule {
29 public CCodeControlFlowModule (CCodeGenerator codegen, CCodeModule? next) {
30 base (codegen, next);
33 public override void visit_if_statement (IfStatement stmt) {
34 stmt.accept_children (codegen);
36 if (stmt.false_statement != null) {
37 stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode);
38 } else {
39 stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode);
42 create_temp_decl (stmt, stmt.condition.temp_vars);
45 void visit_string_switch_statement (SwitchStatement stmt) {
46 // we need a temporary variable to save the property value
47 var temp_var = get_temp_variable (stmt.expression.value_type, stmt.expression.value_type.value_owned, stmt);
48 stmt.expression.temp_vars.insert (0, temp_var);
50 var ctemp = get_variable_cexpression (temp_var.name);
51 var cinit = new CCodeAssignment (ctemp, (CCodeExpression) stmt.expression.ccodenode);
52 var czero = new CCodeConstant ("0");
54 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
55 free_call.add_argument (ctemp);
57 var cswitchblock = new CCodeFragment ();
58 stmt.ccodenode = cswitchblock;
60 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("NULL"), ctemp);
61 var cquark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
62 cquark.add_argument (ctemp);
64 var ccond = new CCodeConditionalExpression (cisnull, new CCodeConstant ("0"), cquark);
66 temp_var = get_temp_variable (gquark_type);
67 stmt.expression.temp_vars.insert (0, temp_var);
69 int label_count = 0;
71 foreach (SwitchSection section in stmt.get_sections ()) {
72 if (section.has_default_label ()) {
73 continue;
76 foreach (SwitchLabel label in section.get_labels ()) {
77 var cexpr = (CCodeExpression) label.expression.ccodenode;
79 if (is_constant_ccode_expression (cexpr)) {
80 var cname = "%s_label%d".printf (temp_var.name, label_count++);
81 var cdecl = new CCodeDeclaration (gquark_type.get_cname ());
83 cdecl.modifiers = CCodeModifiers.STATIC;
84 cdecl.add_declarator (new CCodeVariableDeclarator (cname, czero));
86 cswitchblock.append (cdecl);
91 cswitchblock.append (new CCodeExpressionStatement (cinit));
93 ctemp = get_variable_cexpression (temp_var.name);
94 cinit = new CCodeAssignment (ctemp, ccond);
96 cswitchblock.append (new CCodeExpressionStatement (cinit));
97 create_temp_decl (stmt, stmt.expression.temp_vars);
99 if (stmt.expression.value_type.value_owned) {
100 // free owned string
101 cswitchblock.append (new CCodeExpressionStatement (free_call));
104 Gee.List<Statement> default_statements = null;
105 label_count = 0;
107 // generate nested if statements
108 CCodeStatement ctopstmt = null;
109 CCodeIfStatement coldif = null;
111 foreach (SwitchSection section in stmt.get_sections ()) {
112 if (section.has_default_label ()) {
113 default_statements = section.get_statements ();
114 continue;
117 CCodeBinaryExpression cor = null;
118 foreach (SwitchLabel label in section.get_labels ()) {
119 var cexpr = (CCodeExpression) label.expression.ccodenode;
121 if (is_constant_ccode_expression (cexpr)) {
122 var cname = new CCodeIdentifier ("%s_label%d".printf (temp_var.name, label_count++));
123 var ccondition = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, czero, cname);
124 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
125 cinit = new CCodeAssignment (cname, ccall);
127 ccall.add_argument (cexpr);
129 cexpr = new CCodeConditionalExpression (ccondition, cname, cinit);
130 } else {
131 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
132 ccall.add_argument (cexpr);
133 cexpr = ccall;
136 var ccmp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, cexpr);
138 if (cor == null) {
139 cor = ccmp;
140 } else {
141 cor = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cor, ccmp);
145 var cblock = new CCodeBlock ();
146 foreach (CodeNode body_stmt in section.get_statements ()) {
147 if (body_stmt.ccodenode is CCodeFragment) {
148 foreach (CCodeNode cstmt in ((CCodeFragment) body_stmt.ccodenode).get_children ()) {
149 cblock.add_statement (cstmt);
151 } else {
152 cblock.add_statement (body_stmt.ccodenode);
156 var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
157 var cif = new CCodeIfStatement (cor, cdo);
159 if (coldif != null) {
160 coldif.false_statement = cif;
161 } else {
162 ctopstmt = cif;
165 coldif = cif;
168 if (default_statements != null) {
169 var cblock = new CCodeBlock ();
170 foreach (CodeNode body_stmt in default_statements) {
171 cblock.add_statement (body_stmt.ccodenode);
174 var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
176 if (coldif == null) {
177 // there is only one section and that section
178 // contains a default label
179 ctopstmt = cdo;
180 } else {
181 coldif.false_statement = cdo;
185 cswitchblock.append (ctopstmt);
188 public override void visit_switch_statement (SwitchStatement stmt) {
189 stmt.accept_children (codegen);
191 if (stmt.expression.value_type.compatible (string_type)) {
192 visit_string_switch_statement (stmt);
193 return;
196 var cswitch = new CCodeSwitchStatement ((CCodeExpression) stmt.expression.ccodenode);
197 stmt.ccodenode = cswitch;
199 foreach (SwitchSection section in stmt.get_sections ()) {
200 if (section.has_default_label ()) {
201 cswitch.add_statement (new CCodeLabel ("default"));
202 var cdefaultblock = new CCodeBlock ();
203 cswitch.add_statement (cdefaultblock);
204 foreach (CodeNode default_stmt in section.get_statements ()) {
205 cdefaultblock.add_statement (default_stmt.ccodenode);
207 continue;
210 foreach (SwitchLabel label in section.get_labels ()) {
211 cswitch.add_statement (new CCodeCaseStatement ((CCodeExpression) label.expression.ccodenode));
214 var cblock = new CCodeBlock ();
215 cswitch.add_statement (cblock);
216 foreach (CodeNode body_stmt in section.get_statements ()) {
217 cblock.add_statement (body_stmt.ccodenode);
221 create_temp_decl (stmt, stmt.expression.temp_vars);
224 public override void visit_switch_section (SwitchSection section) {
225 visit_block (section);
228 public override void visit_switch_label (SwitchLabel label) {
229 label.accept_children (codegen);
232 public override void visit_loop (Loop stmt) {
233 stmt.accept_children (codegen);
235 if (context.profile == Profile.GOBJECT) {
236 stmt.ccodenode = new CCodeWhileStatement (new CCodeConstant ("TRUE"), (CCodeStatement) stmt.body.ccodenode);
237 } else {
238 source_declarations.add_include ("stdbool.h");
239 stmt.ccodenode = new CCodeWhileStatement (new CCodeConstant ("true"), (CCodeStatement) stmt.body.ccodenode);
243 public override void visit_foreach_statement (ForeachStatement stmt) {
244 stmt.element_variable.active = true;
245 stmt.collection_variable.active = true;
246 if (stmt.iterator_variable != null) {
247 stmt.iterator_variable.active = true;
250 visit_block (stmt);
252 var cblock = new CCodeBlock ();
253 // sets #line
254 stmt.ccodenode = cblock;
256 var cfrag = new CCodeFragment ();
257 append_temp_decl (cfrag, stmt.collection.temp_vars);
258 cblock.add_statement (cfrag);
260 var collection_backup = stmt.collection_variable;
261 var collection_type = collection_backup.variable_type.copy ();
263 var array_type = collection_type as ArrayType;
264 if (array_type != null) {
265 // avoid assignment issues
266 array_type.fixed_length = false;
269 if (current_method != null && current_method.coroutine) {
270 closure_struct.add_field (collection_type.get_cname (), collection_backup.name);
271 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode)));
272 } else {
273 var ccoldecl = new CCodeDeclaration (collection_type.get_cname ());
274 var ccolvardecl = new CCodeVariableDeclarator (collection_backup.name, (CCodeExpression) stmt.collection.ccodenode);
275 ccolvardecl.line = cblock.line;
276 ccoldecl.add_declarator (ccolvardecl);
277 cblock.add_statement (ccoldecl);
280 if (stmt.tree_can_fail && stmt.collection.tree_can_fail) {
281 // exception handling
282 cfrag = new CCodeFragment ();
283 head.add_simple_check (stmt.collection, cfrag);
284 cblock.add_statement (cfrag);
287 if (stmt.collection.value_type is ArrayType) {
288 array_type = (ArrayType) stmt.collection.value_type;
290 var array_len = head.get_array_length_cexpression (stmt.collection);
292 // store array length for use by _vala_array_free
293 if (current_method != null && current_method.coroutine) {
294 closure_struct.add_field ("int", head.get_array_length_cname (collection_backup.name, 1));
295 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (head.get_array_length_cname (collection_backup.name, 1)), array_len)));
296 } else {
297 var clendecl = new CCodeDeclaration ("int");
298 clendecl.add_declarator (new CCodeVariableDeclarator (head.get_array_length_cname (collection_backup.name, 1), array_len));
299 cblock.add_statement (clendecl);
302 var it_name = (stmt.variable_name + "_it");
304 if (current_method != null && current_method.coroutine) {
305 closure_struct.add_field ("int", it_name);
306 } else {
307 var citdecl = new CCodeDeclaration ("int");
308 citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
309 cblock.add_statement (citdecl);
312 var cbody = new CCodeBlock ();
314 CCodeExpression element_expr = new CCodeElementAccess (get_variable_cexpression (collection_backup.name), get_variable_cexpression (it_name));
316 var element_type = array_type.element_type.copy ();
317 element_type.value_owned = false;
318 element_expr = transform_expression (element_expr, element_type, stmt.type_reference);
320 cfrag = new CCodeFragment ();
321 append_temp_decl (cfrag, temp_vars);
322 cbody.add_statement (cfrag);
323 temp_vars.clear ();
325 if (current_method != null && current_method.coroutine) {
326 closure_struct.add_field (stmt.type_reference.get_cname (), stmt.variable_name);
327 cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (stmt.variable_name), element_expr)));
328 } else {
329 var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
330 cdecl.add_declarator (new CCodeVariableDeclarator (stmt.variable_name, element_expr));
331 cbody.add_statement (cdecl);
334 // add array length variable for stacked arrays
335 if (stmt.type_reference is ArrayType) {
336 var inner_array_type = (ArrayType) stmt.type_reference;
337 for (int dim = 1; dim <= inner_array_type.rank; dim++) {
338 if (current_method != null && current_method.coroutine) {
339 closure_struct.add_field ("int", head.get_array_length_cname (stmt.variable_name, dim));
340 cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (head.get_array_length_cname (stmt.variable_name, dim)), new CCodeConstant ("-1"))));
341 } else {
342 var cdecl = new CCodeDeclaration ("int");
343 cdecl.add_declarator (new CCodeVariableDeclarator (head.get_array_length_cname (stmt.variable_name, dim), new CCodeConstant ("-1")));
344 cbody.add_statement (cdecl);
349 cbody.add_statement (stmt.body.ccodenode);
351 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (it_name), array_len);
353 var cfor = new CCodeForStatement (ccond, cbody);
354 cfor.add_initializer (new CCodeAssignment (get_variable_cexpression (it_name), new CCodeConstant ("0")));
355 cfor.add_iterator (new CCodeAssignment (get_variable_cexpression (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (it_name), new CCodeConstant ("1"))));
356 cblock.add_statement (cfor);
357 } else if (stmt.collection.value_type.compatible (new ObjectType (glist_type)) || stmt.collection.value_type.compatible (new ObjectType (gslist_type))) {
358 // iterating over a GList or GSList
360 var it_name = "%s_it".printf (stmt.variable_name);
362 if (current_method != null && current_method.coroutine) {
363 closure_struct.add_field (collection_type.get_cname (), it_name);
364 } else {
365 var citdecl = new CCodeDeclaration (collection_type.get_cname ());
366 var citvardecl = new CCodeVariableDeclarator (it_name);
367 citvardecl.line = cblock.line;
368 citdecl.add_declarator (citvardecl);
369 cblock.add_statement (citdecl);
372 var cbody = new CCodeBlock ();
374 CCodeExpression element_expr = new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "data");
376 if (collection_type.get_type_arguments ().size != 1) {
377 Report.error (stmt.source_reference, "internal error: missing generic type argument");
378 stmt.error = true;
379 return;
382 var element_data_type = collection_type.get_type_arguments ().get (0).copy ();
383 element_data_type.value_owned = false;
384 element_expr = convert_from_generic_pointer (element_expr, element_data_type);
385 element_expr = transform_expression (element_expr, element_data_type, stmt.type_reference);
387 cfrag = new CCodeFragment ();
388 append_temp_decl (cfrag, temp_vars);
389 cbody.add_statement (cfrag);
390 temp_vars.clear ();
392 if (current_method != null && current_method.coroutine) {
393 closure_struct.add_field (stmt.type_reference.get_cname (), stmt.variable_name);
394 cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (stmt.variable_name), element_expr)));
395 } else {
396 var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
397 var cvardecl = new CCodeVariableDeclarator (stmt.variable_name, element_expr);
398 cvardecl.line = cblock.line;
399 cdecl.add_declarator (cvardecl);
400 cbody.add_statement (cdecl);
403 cbody.add_statement (stmt.body.ccodenode);
405 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_variable_cexpression (it_name), new CCodeConstant ("NULL"));
407 var cfor = new CCodeForStatement (ccond, cbody);
409 cfor.add_initializer (new CCodeAssignment (get_variable_cexpression (it_name), get_variable_cexpression (collection_backup.name)));
411 cfor.add_iterator (new CCodeAssignment (get_variable_cexpression (it_name), new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "next")));
412 cblock.add_statement (cfor);
413 } else if (stmt.collection.value_type.compatible (new ObjectType (gvaluearray_type))) {
414 // iterating over a GValueArray
416 var arr_index = "%s_index".printf (stmt.variable_name);
418 if (current_method != null && current_method.coroutine) {
419 closure_struct.add_field (uint_type.get_cname (), arr_index);
420 } else {
421 var citdecl = new CCodeDeclaration (uint_type.get_cname ());
422 var citvardecl = new CCodeVariableDeclarator (arr_index);
423 citvardecl.line = cblock.line;
424 citdecl.add_declarator (citvardecl);
425 cblock.add_statement (citdecl);
428 var cbody = new CCodeBlock ();
430 var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_get_nth"));
431 get_item.add_argument (get_variable_cexpression (collection_backup.name));
432 get_item.add_argument (get_variable_cexpression (arr_index));
434 CCodeExpression element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_item);
436 if (stmt.type_reference.value_owned) {
437 element_expr = get_ref_cexpression (stmt.type_reference, element_expr, null, new StructValueType (gvalue_type));
440 cfrag = new CCodeFragment ();
441 append_temp_decl (cfrag, temp_vars);
442 cbody.add_statement (cfrag);
443 temp_vars.clear ();
445 if (current_method != null && current_method.coroutine) {
446 closure_struct.add_field (stmt.type_reference.get_cname (), stmt.variable_name);
447 cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (stmt.variable_name), element_expr)));
448 } else {
449 var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
450 var cvardecl = new CCodeVariableDeclarator (stmt.variable_name, element_expr);
451 cvardecl.line = cblock.line;
452 cdecl.add_declarator (cvardecl);
453 cbody.add_statement (cdecl);
456 cbody.add_statement (stmt.body.ccodenode);
458 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (arr_index), new CCodeMemberAccess.pointer (get_variable_cexpression (collection_backup.name), "n_values"));
460 var cfor = new CCodeForStatement (ccond, cbody);
462 cfor.add_initializer (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeConstant ("0")));
464 cfor.add_iterator (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (arr_index), new CCodeConstant ("1"))));
466 cblock.add_statement (cfor);
469 foreach (LocalVariable local in stmt.get_local_variables ()) {
470 if (requires_destroy (local.variable_type)) {
471 var ma = new MemberAccess.simple (local.name);
472 ma.symbol_reference = local;
473 var cunref = new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma));
474 cunref.line = cblock.line;
475 cblock.add_statement (cunref);
480 public override void visit_break_statement (BreakStatement stmt) {
481 stmt.ccodenode = new CCodeBreakStatement ();
483 create_local_free (stmt, true);
486 public override void visit_continue_statement (ContinueStatement stmt) {
487 stmt.ccodenode = new CCodeContinueStatement ();
489 create_local_free (stmt, true);