Fix ellipsis parameter position in generated methods
[vala-lang.git] / codegen / valaccodecontrolflowmodule.vala
blobdc66708f93e7454d239d2135ecb219f670e75ba2
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;
27 public class Vala.CCodeControlFlowModule : CCodeMethodModule {
28 public override void visit_if_statement (IfStatement stmt) {
29 stmt.true_statement.emit (this);
30 if (stmt.false_statement != null) {
31 stmt.false_statement.emit (this);
34 if (stmt.false_statement != null) {
35 stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode);
36 } else {
37 stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode);
40 create_temp_decl (stmt, stmt.condition.temp_vars);
43 void visit_string_switch_statement (SwitchStatement stmt) {
44 // we need a temporary variable to save the property value
45 var temp_var = get_temp_variable (stmt.expression.value_type, stmt.expression.value_type.value_owned, stmt, false);
46 stmt.expression.add_temp_var (temp_var);
48 var ctemp = get_variable_cexpression (temp_var.name);
49 var cinit = new CCodeAssignment (ctemp, (CCodeExpression) stmt.expression.ccodenode);
50 var czero = new CCodeConstant ("0");
52 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
53 free_call.add_argument (ctemp);
55 var cswitchblock = new CCodeFragment ();
56 stmt.ccodenode = cswitchblock;
58 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("NULL"), ctemp);
59 var cquark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
60 cquark.add_argument (ctemp);
62 var ccond = new CCodeConditionalExpression (cisnull, new CCodeConstant ("0"), cquark);
64 temp_var = get_temp_variable (gquark_type);
65 stmt.expression.add_temp_var (temp_var);
67 int label_count = 0;
69 foreach (SwitchSection section in stmt.get_sections ()) {
70 if (section.has_default_label ()) {
71 continue;
74 foreach (SwitchLabel label in section.get_labels ()) {
75 var cexpr = (CCodeExpression) label.expression.ccodenode;
77 if (is_constant_ccode_expression (cexpr)) {
78 var cname = "%s_label%d".printf (temp_var.name, label_count++);
79 var cdecl = new CCodeDeclaration (gquark_type.get_cname ());
81 cdecl.modifiers = CCodeModifiers.STATIC;
82 cdecl.add_declarator (new CCodeVariableDeclarator (cname, czero));
84 cswitchblock.append (cdecl);
89 cswitchblock.append (new CCodeExpressionStatement (cinit));
91 ctemp = get_variable_cexpression (temp_var.name);
92 cinit = new CCodeAssignment (ctemp, ccond);
94 cswitchblock.append (new CCodeExpressionStatement (cinit));
95 create_temp_decl (stmt, stmt.expression.temp_vars);
97 if (stmt.expression.value_type.value_owned) {
98 // free owned string
99 cswitchblock.append (new CCodeExpressionStatement (free_call));
102 List<Statement> default_statements = null;
103 label_count = 0;
105 // generate nested if statements
106 CCodeStatement ctopstmt = null;
107 CCodeIfStatement coldif = null;
109 foreach (SwitchSection section in stmt.get_sections ()) {
110 if (section.has_default_label ()) {
111 default_statements = section.get_statements ();
112 continue;
115 CCodeBinaryExpression cor = null;
116 foreach (SwitchLabel label in section.get_labels ()) {
117 var cexpr = (CCodeExpression) label.expression.ccodenode;
119 if (is_constant_ccode_expression (cexpr)) {
120 var cname = new CCodeIdentifier ("%s_label%d".printf (temp_var.name, label_count++));
121 var ccondition = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, czero, cname);
122 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
123 cinit = new CCodeAssignment (cname, ccall);
125 ccall.add_argument (cexpr);
127 cexpr = new CCodeConditionalExpression (ccondition, cname, cinit);
128 } else {
129 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
130 ccall.add_argument (cexpr);
131 cexpr = ccall;
134 var ccmp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, cexpr);
136 if (cor == null) {
137 cor = ccmp;
138 } else {
139 cor = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cor, ccmp);
143 var cblock = new CCodeBlock ();
144 foreach (CodeNode body_stmt in section.get_statements ()) {
145 if (body_stmt.ccodenode is CCodeFragment) {
146 foreach (CCodeNode cstmt in ((CCodeFragment) body_stmt.ccodenode).get_children ()) {
147 cblock.add_statement (cstmt);
149 } else {
150 cblock.add_statement (body_stmt.ccodenode);
154 var cswitch = new CCodeSwitchStatement (new CCodeConstant ("0"));
155 cswitch.add_statement (new CCodeLabel ("default"));
156 cswitch.add_statement (cblock);
157 var cif = new CCodeIfStatement (cor, cswitch);
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 cswitch = new CCodeSwitchStatement (new CCodeConstant ("0"));
175 cswitch.add_statement (new CCodeLabel ("default"));
176 cswitch.add_statement (cblock);
178 if (coldif == null) {
179 // there is only one section and that section
180 // contains a default label
181 ctopstmt = cswitch;
182 } else {
183 coldif.false_statement = cswitch;
187 cswitchblock.append (ctopstmt);
190 public override void visit_switch_statement (SwitchStatement stmt) {
191 foreach (SwitchSection section in stmt.get_sections ()) {
192 section.emit (this);
195 if (stmt.expression.value_type.compatible (string_type)) {
196 visit_string_switch_statement (stmt);
197 return;
200 var cswitch = new CCodeSwitchStatement ((CCodeExpression) stmt.expression.ccodenode);
201 stmt.ccodenode = cswitch;
203 foreach (SwitchSection section in stmt.get_sections ()) {
204 if (section.has_default_label ()) {
205 cswitch.add_statement (new CCodeLabel ("default"));
206 var cdefaultblock = new CCodeBlock ();
207 cswitch.add_statement (cdefaultblock);
208 foreach (CodeNode default_stmt in section.get_statements ()) {
209 cdefaultblock.add_statement (default_stmt.ccodenode);
211 continue;
214 foreach (SwitchLabel label in section.get_labels ()) {
215 cswitch.add_statement (new CCodeCaseStatement ((CCodeExpression) label.expression.ccodenode));
218 cswitch.add_statement (section.ccodenode);
221 create_temp_decl (stmt, stmt.expression.temp_vars);
224 public override void visit_switch_label (SwitchLabel label) {
225 if (label.expression != null) {
226 label.expression.emit (this);
228 visit_end_full_expression (label.expression);
232 public override void visit_loop (Loop stmt) {
233 stmt.body.emit (this);
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.body.emit (this);
246 visit_block (stmt);
248 var cblock = new CCodeBlock ();
249 // sets #line
250 stmt.ccodenode = cblock;
252 var cfrag = new CCodeFragment ();
253 append_temp_decl (cfrag, stmt.collection.temp_vars);
254 cblock.add_statement (cfrag);
256 var collection_backup = stmt.collection_variable;
257 var collection_type = collection_backup.variable_type.copy ();
259 var array_type = collection_type as ArrayType;
260 if (array_type != null) {
261 // avoid assignment issues
262 array_type.fixed_length = false;
265 if (current_method != null && current_method.coroutine) {
266 closure_struct.add_field (collection_type.get_cname (), collection_backup.name);
267 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode)));
268 } else {
269 var ccoldecl = new CCodeDeclaration (collection_type.get_cname ());
270 var ccolvardecl = new CCodeVariableDeclarator (collection_backup.name, (CCodeExpression) stmt.collection.ccodenode);
271 ccolvardecl.line = cblock.line;
272 ccoldecl.add_declarator (ccolvardecl);
273 cblock.add_statement (ccoldecl);
276 if (stmt.tree_can_fail && stmt.collection.tree_can_fail) {
277 // exception handling
278 cfrag = new CCodeFragment ();
279 add_simple_check (stmt.collection, cfrag);
280 cblock.add_statement (cfrag);
283 if (stmt.collection.value_type is ArrayType) {
284 array_type = (ArrayType) stmt.collection.value_type;
286 var array_len = get_array_length_cexpression (stmt.collection);
288 // store array length for use by _vala_array_free
289 if (current_method != null && current_method.coroutine) {
290 closure_struct.add_field ("int", get_array_length_cname (collection_backup.name, 1));
291 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (get_array_length_cname (collection_backup.name, 1)), array_len)));
292 } else {
293 var clendecl = new CCodeDeclaration ("int");
294 clendecl.add_declarator (new CCodeVariableDeclarator (get_array_length_cname (collection_backup.name, 1), array_len));
295 cblock.add_statement (clendecl);
298 var it_name = (stmt.variable_name + "_it");
300 if (current_method != null && current_method.coroutine) {
301 closure_struct.add_field ("int", it_name);
302 } else {
303 var citdecl = new CCodeDeclaration ("int");
304 citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
305 cblock.add_statement (citdecl);
308 var cbody = new CCodeBlock ();
310 CCodeExpression element_expr = new CCodeElementAccess (get_variable_cexpression (collection_backup.name), get_variable_cexpression (it_name));
312 var element_type = array_type.element_type.copy ();
313 element_type.value_owned = false;
314 element_expr = transform_expression (element_expr, element_type, stmt.type_reference);
316 cfrag = new CCodeFragment ();
317 append_temp_decl (cfrag, temp_vars);
318 cbody.add_statement (cfrag);
319 temp_vars.clear ();
321 if (current_method != null && current_method.coroutine) {
322 closure_struct.add_field (stmt.type_reference.get_cname (), stmt.variable_name);
323 cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (stmt.variable_name), element_expr)));
324 } else {
325 var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
326 cdecl.add_declarator (new CCodeVariableDeclarator (stmt.variable_name, element_expr));
327 cbody.add_statement (cdecl);
330 // add array length variable for stacked arrays
331 if (stmt.type_reference is ArrayType) {
332 var inner_array_type = (ArrayType) stmt.type_reference;
333 for (int dim = 1; dim <= inner_array_type.rank; dim++) {
334 if (current_method != null && current_method.coroutine) {
335 closure_struct.add_field ("int", get_array_length_cname (stmt.variable_name, dim));
336 cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (get_array_length_cname (stmt.variable_name, dim)), new CCodeConstant ("-1"))));
337 } else {
338 var cdecl = new CCodeDeclaration ("int");
339 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_length_cname (stmt.variable_name, dim), new CCodeConstant ("-1")));
340 cbody.add_statement (cdecl);
345 cbody.add_statement (stmt.body.ccodenode);
347 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (it_name), array_len);
349 var cfor = new CCodeForStatement (ccond, cbody);
350 cfor.add_initializer (new CCodeAssignment (get_variable_cexpression (it_name), new CCodeConstant ("0")));
351 cfor.add_iterator (new CCodeAssignment (get_variable_cexpression (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (it_name), new CCodeConstant ("1"))));
352 cblock.add_statement (cfor);
353 } else if (stmt.collection.value_type.compatible (new ObjectType (glist_type)) || stmt.collection.value_type.compatible (new ObjectType (gslist_type))) {
354 // iterating over a GList or GSList
356 var it_name = "%s_it".printf (stmt.variable_name);
358 if (current_method != null && current_method.coroutine) {
359 closure_struct.add_field (collection_type.get_cname (), it_name);
360 } else {
361 var citdecl = new CCodeDeclaration (collection_type.get_cname ());
362 var citvardecl = new CCodeVariableDeclarator (it_name);
363 citvardecl.line = cblock.line;
364 citdecl.add_declarator (citvardecl);
365 cblock.add_statement (citdecl);
368 var cbody = new CCodeBlock ();
370 CCodeExpression element_expr = new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "data");
372 if (collection_type.get_type_arguments ().size != 1) {
373 Report.error (stmt.source_reference, "internal error: missing generic type argument");
374 stmt.error = true;
375 return;
378 var element_data_type = collection_type.get_type_arguments ().get (0).copy ();
379 element_data_type.value_owned = false;
380 element_expr = convert_from_generic_pointer (element_expr, element_data_type);
381 element_expr = transform_expression (element_expr, element_data_type, stmt.type_reference);
383 cfrag = new CCodeFragment ();
384 append_temp_decl (cfrag, temp_vars);
385 cbody.add_statement (cfrag);
386 temp_vars.clear ();
388 if (current_method != null && current_method.coroutine) {
389 closure_struct.add_field (stmt.type_reference.get_cname (), stmt.variable_name);
390 cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (stmt.variable_name), element_expr)));
391 } else {
392 var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
393 var cvardecl = new CCodeVariableDeclarator (stmt.variable_name, element_expr);
394 cvardecl.line = cblock.line;
395 cdecl.add_declarator (cvardecl);
396 cbody.add_statement (cdecl);
399 cbody.add_statement (stmt.body.ccodenode);
401 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_variable_cexpression (it_name), new CCodeConstant ("NULL"));
403 var cfor = new CCodeForStatement (ccond, cbody);
405 cfor.add_initializer (new CCodeAssignment (get_variable_cexpression (it_name), get_variable_cexpression (collection_backup.name)));
407 cfor.add_iterator (new CCodeAssignment (get_variable_cexpression (it_name), new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "next")));
408 cblock.add_statement (cfor);
409 } else if (stmt.collection.value_type.compatible (new ObjectType (gvaluearray_type))) {
410 // iterating over a GValueArray
412 var arr_index = "%s_index".printf (stmt.variable_name);
414 if (current_method != null && current_method.coroutine) {
415 closure_struct.add_field (uint_type.get_cname (), arr_index);
416 } else {
417 var citdecl = new CCodeDeclaration (uint_type.get_cname ());
418 var citvardecl = new CCodeVariableDeclarator (arr_index);
419 citvardecl.line = cblock.line;
420 citdecl.add_declarator (citvardecl);
421 cblock.add_statement (citdecl);
424 var cbody = new CCodeBlock ();
426 var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_get_nth"));
427 get_item.add_argument (get_variable_cexpression (collection_backup.name));
428 get_item.add_argument (get_variable_cexpression (arr_index));
430 CCodeExpression element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_item);
432 if (stmt.type_reference.value_owned) {
433 element_expr = get_ref_cexpression (stmt.type_reference, element_expr, null, new StructValueType (gvalue_type));
436 cfrag = new CCodeFragment ();
437 append_temp_decl (cfrag, temp_vars);
438 cbody.add_statement (cfrag);
439 temp_vars.clear ();
441 if (current_method != null && current_method.coroutine) {
442 closure_struct.add_field (stmt.type_reference.get_cname (), stmt.variable_name);
443 cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (stmt.variable_name), element_expr)));
444 } else {
445 var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
446 var cvardecl = new CCodeVariableDeclarator (stmt.variable_name, element_expr);
447 cvardecl.line = cblock.line;
448 cdecl.add_declarator (cvardecl);
449 cbody.add_statement (cdecl);
452 cbody.add_statement (stmt.body.ccodenode);
454 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (arr_index), new CCodeMemberAccess.pointer (get_variable_cexpression (collection_backup.name), "n_values"));
456 var cfor = new CCodeForStatement (ccond, cbody);
458 cfor.add_initializer (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeConstant ("0")));
460 cfor.add_iterator (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (arr_index), new CCodeConstant ("1"))));
462 cblock.add_statement (cfor);
465 foreach (LocalVariable local in stmt.get_local_variables ()) {
466 if (requires_destroy (local.variable_type)) {
467 var ma = new MemberAccess.simple (local.name);
468 ma.symbol_reference = local;
469 var cunref = new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma));
470 cunref.line = cblock.line;
471 cblock.add_statement (cunref);
476 public override void visit_break_statement (BreakStatement stmt) {
477 stmt.ccodenode = new CCodeBreakStatement ();
479 create_local_free (stmt, true);
482 public override void visit_continue_statement (ContinueStatement stmt) {
483 stmt.ccodenode = new CCodeContinueStatement ();
485 create_local_free (stmt, true);