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 if (context
.profile
== Profile
.GOBJECT
) {
210 ccode
.open_while (new
CCodeConstant ("TRUE"));
212 cfile
.add_include ("stdbool.h");
213 ccode
.open_while (new
CCodeConstant ("true"));
216 stmt
.body
.emit (this
);
221 public override void visit_foreach_statement (ForeachStatement stmt
) {
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")),
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
);
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
))),
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");
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
);
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")),
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
);
343 foreach (LocalVariable local
in stmt
.get_local_variables ()) {
344 if (requires_destroy (local
.variable_type
)) {
345 ccode
.add_expression (destroy_local (local
));
352 public override void visit_break_statement (BreakStatement stmt
) {
353 append_local_free (current_symbol
, true);
358 public override void visit_continue_statement (ContinueStatement stmt
) {
359 append_local_free (current_symbol
, true);
361 ccode
.add_continue ();