Line data Source code
1 : /* valaconditionalexpression.vala
2 : *
3 : * Copyright (C) 2006-2011 Jürg Billeter
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2.1 of the License, or (at your option) any later version.
9 :
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 :
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents a conditional expression in the source code.
27 : */
28 7826 : public class Vala.ConditionalExpression : Expression {
29 : /**
30 : * The condition.
31 : */
32 : public Expression condition {
33 20399 : get {
34 20399 : return _condition;
35 : }
36 6297 : private set {
37 30571 : _condition = value;
38 6297 : _condition.parent_node = this;
39 : }
40 : }
41 :
42 : /**
43 : * The expression to be evaluated if the condition holds.
44 : */
45 : public Expression true_expression {
46 96316 : get {
47 96316 : return _true_expression;
48 : }
49 12137 : private set {
50 24274 : _true_expression = value;
51 12137 : _true_expression.parent_node = this;
52 : }
53 : }
54 :
55 : /**
56 : * The expression to be evaluated if the condition doesn't hold.
57 : */
58 : public Expression false_expression {
59 90451 : get {
60 90451 : return _false_expression;
61 : }
62 12137 : private set {
63 24274 : _false_expression = value;
64 12137 : _false_expression.parent_node = this;
65 : }
66 : }
67 :
68 6297 : Expression _condition;
69 6297 : Expression _true_expression;
70 6297 : Expression _false_expression;
71 :
72 : /**
73 : * Creates a new conditional expression.
74 : *
75 : * @param cond a condition
76 : * @param true_expr expression to be evaluated if condition is true
77 : * @param false_expr expression to be evaluated if condition is false
78 : * @return newly created conditional expression
79 : */
80 18891 : public ConditionalExpression (Expression cond, Expression true_expr, Expression false_expr, SourceReference? source = null) {
81 6297 : condition = cond;
82 6297 : true_expression = true_expr;
83 6297 : false_expression = false_expr;
84 6297 : source_reference = source;
85 : }
86 :
87 14559 : public override void accept (CodeVisitor visitor) {
88 14559 : visitor.visit_conditional_expression (this);
89 :
90 14559 : visitor.visit_expression (this);
91 : }
92 :
93 14559 : public override void accept_children (CodeVisitor visitor) {
94 14559 : condition.accept (visitor);
95 14559 : true_expression.accept (visitor);
96 14559 : false_expression.accept (visitor);
97 : }
98 :
99 0 : public override bool is_pure () {
100 0 : return condition.is_pure () && true_expression.is_pure () && false_expression.is_pure ();
101 : }
102 :
103 0 : public override bool is_accessible (Symbol sym) {
104 0 : return condition.is_accessible (sym) && true_expression.is_accessible (sym) && false_expression.is_accessible (sym);
105 : }
106 :
107 0 : public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
108 0 : condition.get_error_types (collection, source_reference);
109 0 : true_expression.get_error_types (collection, source_reference);
110 0 : false_expression.get_error_types (collection, source_reference);
111 : }
112 :
113 0 : public override string to_string () {
114 0 : return "(%s ? %s : %s)".printf (condition.to_string (), true_expression.to_string (), false_expression.to_string ());
115 : }
116 :
117 0 : public override void replace_expression (Expression old_node, Expression new_node) {
118 0 : if (condition == old_node) {
119 0 : condition = new_node;
120 : }
121 0 : if (true_expression == old_node) {
122 0 : true_expression = new_node;
123 : }
124 0 : if (false_expression == old_node) {
125 0 : false_expression = new_node;
126 : }
127 : }
128 :
129 0 : public override void get_defined_variables (Collection<Variable> collection) {
130 0 : condition.get_defined_variables (collection);
131 0 : true_expression.get_defined_variables (collection);
132 0 : false_expression.get_defined_variables (collection);
133 : }
134 :
135 0 : public override void get_used_variables (Collection<Variable> collection) {
136 0 : condition.get_used_variables (collection);
137 0 : true_expression.get_used_variables (collection);
138 0 : false_expression.get_used_variables (collection);
139 : }
140 :
141 5841 : public override bool check (CodeContext context) {
142 5841 : if (checked) {
143 0 : return !error;
144 : }
145 :
146 5841 : checked = true;
147 :
148 5841 : if (!(context.analyzer.current_symbol is Block)) {
149 1 : Report.error (source_reference, "Conditional expressions may only be used in blocks");
150 1 : error = true;
151 1 : return false;
152 : }
153 :
154 : // convert ternary expression into if statement
155 : // required for flow analysis and exception handling
156 :
157 5840 : string temp_name = get_temp_name ();
158 :
159 5840 : true_expression.target_type = target_type;
160 5840 : false_expression.target_type = target_type;
161 :
162 5840 : var local = new LocalVariable (null, temp_name, null, source_reference);
163 5840 : var decl = new DeclarationStatement (local, source_reference);
164 :
165 5840 : var true_local = new LocalVariable (null, temp_name, true_expression, true_expression.source_reference);
166 5840 : var true_block = new Block (true_expression.source_reference);
167 5840 : var true_decl = new DeclarationStatement (true_local, true_expression.source_reference);
168 5840 : true_block.add_statement (true_decl);
169 :
170 5840 : var false_local = new LocalVariable (null, temp_name, false_expression, false_expression.source_reference);
171 5840 : var false_block = new Block (false_expression.source_reference);
172 5840 : var false_decl = new DeclarationStatement (false_local, false_expression.source_reference);
173 5840 : false_block.add_statement (false_decl);
174 :
175 5840 : var if_stmt = new IfStatement (condition, true_block, false_block, source_reference);
176 :
177 5840 : insert_statement (context.analyzer.insert_block, decl);
178 5840 : insert_statement (context.analyzer.insert_block, if_stmt);
179 :
180 5840 : if (!if_stmt.check (context) || true_expression.error || false_expression.error) {
181 0 : error = true;
182 0 : return false;
183 : }
184 :
185 5840 : true_expression = true_local.initializer;
186 5840 : false_expression = false_local.initializer;
187 :
188 5840 : true_block.remove_local_variable (true_local);
189 5840 : false_block.remove_local_variable (false_local);
190 :
191 5840 : if (false_expression.value_type.compatible (true_expression.value_type)) {
192 5832 : value_type = true_expression.value_type.copy ();
193 8 : } else if (true_expression.value_type.compatible (false_expression.value_type)) {
194 7 : value_type = false_expression.value_type.copy ();
195 : } else {
196 1 : error = true;
197 1 : var source_reference = new SourceReference (true_expression.source_reference.file, true_expression.source_reference.begin, false_expression.source_reference.end);
198 1 : Report.error (source_reference, "Cannot resolve target type from `%s' and `%s'", true_expression.value_type.to_prototype_string (), false_expression.value_type.to_prototype_string ());
199 1 : return false;
200 : }
201 :
202 5839 : value_type.value_owned = (true_expression.value_type.value_owned || false_expression.value_type.value_owned);
203 5839 : value_type.floating_reference = false;
204 5839 : value_type.check (context);
205 :
206 5839 : local.variable_type = value_type;
207 5839 : decl.check (context);
208 :
209 5839 : true_expression.target_type = value_type;
210 5839 : false_expression.target_type = value_type;
211 :
212 5839 : var true_stmt = new ExpressionStatement (new Assignment (new MemberAccess.simple (local.name, true_expression.source_reference), true_expression, AssignmentOperator.SIMPLE, true_expression.source_reference), true_expression.source_reference);
213 :
214 5839 : var false_stmt = new ExpressionStatement (new Assignment (new MemberAccess.simple (local.name, false_expression.source_reference), false_expression, AssignmentOperator.SIMPLE, false_expression.source_reference), false_expression.source_reference);
215 :
216 5839 : true_block.replace_statement (true_decl, true_stmt);
217 5839 : false_block.replace_statement (false_decl, false_stmt);
218 5839 : true_stmt.check (context);
219 5839 : false_stmt.check (context);
220 :
221 5839 : var ma = new MemberAccess.simple (local.name, source_reference);
222 5839 : ma.formal_target_type = formal_target_type;
223 5839 : ma.target_type = target_type;
224 :
225 5839 : parent_node.replace_expression (this, ma);
226 5839 : ma.check (context);
227 :
228 5839 : return true;
229 : }
230 : }
|