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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
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) {
35 stmt
.false_statement
.emit (this
);
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
);
64 foreach (SwitchSection section
in stmt
.get_sections ()) {
65 if (section
.has_default_label ()) {
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
) {
90 ccode
.add_expression (free_call
);
93 SwitchSection default_section
= null;
98 foreach (SwitchSection section
in stmt
.get_sections ()) {
99 if (section
.has_default_label ()) {
100 default_section
= section
;
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
);
119 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_string"));
120 ccall
.add_argument (cexpr
);
124 var ccmp
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, ctemp
, cexpr
);
129 cor
= new
CCodeBinaryExpression (CCodeBinaryOperator
.OR
, cor
, ccmp
);
139 ccode
.open_switch (new
CCodeConstant ("0"));
140 ccode
.add_default ();
149 if (default_section
!= null) {
154 ccode
.open_switch (new
CCodeConstant ("0"));
155 ccode
.add_default ();
157 default_section
.emit (this
);
167 public override void visit_switch_statement (SwitchStatement stmt
) {
168 if (stmt
.expression
.value_type
.compatible (string_type
)) {
169 visit_string_switch_statement (stmt
);
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 ();
186 // silence C compiler
187 ccode
.add_default ();
194 public override void visit_switch_label (SwitchLabel label
) {
195 if (((SwitchStatement
) label
.section
.parent_node
).expression
.value_type
.compatible (string_type
)) {
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
);
216 public override void visit_foreach_statement (ForeachStatement stmt
) {
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")),
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
);
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
))),
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");
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
);
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")),
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
);
338 foreach (LocalVariable local
in stmt
.get_local_variables ()) {
339 if (requires_destroy (local
.variable_type
)) {
340 ccode
.add_expression (destroy_local (local
));
347 public override void visit_break_statement (BreakStatement stmt
) {
348 append_local_free (current_symbol
, true);
353 public override void visit_continue_statement (ContinueStatement stmt
) {
354 append_local_free (current_symbol
, true);
356 ccode
.add_continue ();