Line data Source code
1 : /* valaunaryexpression.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 :
24 : /**
25 : * Represents an expression with one operand in the source code.
26 : *
27 : * Supports +, -, !, ~, ref, out.
28 : */
29 41995 : public class Vala.UnaryExpression : Expression {
30 : /**
31 : * The unary operator.
32 : */
33 305824 : public UnaryOperator operator { get; private set; }
34 :
35 : /**
36 : * The operand.
37 : */
38 : public Expression inner {
39 816881 : get {
40 816881 : return _inner;
41 : }
42 42003 : private set {
43 42003 : _inner = value;
44 42003 : _inner.parent_node = this;
45 : }
46 : }
47 :
48 40458 : private Expression _inner;
49 :
50 : /**
51 : * Creates a new unary expression.
52 : *
53 : * @param op unary operator
54 : * @param _inner operand
55 : * @param source reference to source code
56 : * @return newly created binary expression
57 : */
58 121374 : public UnaryExpression (UnaryOperator op, Expression _inner, SourceReference? source = null) {
59 40458 : operator = op;
60 40458 : inner = _inner;
61 40458 : source_reference = source;
62 : }
63 :
64 138571 : public override void accept (CodeVisitor visitor) {
65 138571 : visitor.visit_unary_expression (this);
66 :
67 138571 : visitor.visit_expression (this);
68 : }
69 :
70 137584 : public override void accept_children (CodeVisitor visitor) {
71 137584 : inner.accept (visitor);
72 : }
73 :
74 1545 : public override void replace_expression (Expression old_node, Expression new_node) {
75 1545 : if (inner == old_node) {
76 1545 : inner = new_node;
77 : }
78 : }
79 :
80 0 : public override string to_string () {
81 0 : return operator.to_string () + _inner.to_string ();
82 : }
83 :
84 108 : public override bool is_constant () {
85 108 : if (operator == UnaryOperator.INCREMENT || operator == UnaryOperator.DECREMENT) {
86 0 : return false;
87 : }
88 :
89 108 : if (operator == UnaryOperator.REF || operator == UnaryOperator.OUT) {
90 107 : unowned Field? field = inner.symbol_reference as Field;
91 107 : if (field != null && field.binding == MemberBinding.STATIC) {
92 108 : return true;
93 : } else {
94 0 : return false;
95 : }
96 : }
97 :
98 1 : return inner.is_constant ();
99 : }
100 :
101 0 : public override bool is_pure () {
102 0 : if (operator == UnaryOperator.INCREMENT || operator == UnaryOperator.DECREMENT) {
103 0 : return false;
104 : }
105 :
106 0 : return inner.is_pure ();
107 : }
108 :
109 108 : public override bool is_accessible (Symbol sym) {
110 108 : return inner.is_accessible (sym);
111 : }
112 :
113 456 : bool is_numeric_type (DataType type) {
114 456 : unowned Struct? st = type.type_symbol as Struct;
115 456 : if (type.nullable || st == null) {
116 : return false;
117 : }
118 :
119 455 : return st.is_integer_type () || st.is_floating_type ();
120 : }
121 :
122 498 : bool is_integer_type (DataType type) {
123 498 : unowned Struct? st = type.type_symbol as Struct;
124 498 : if (type.nullable || st == null) {
125 2 : return false;
126 : }
127 :
128 496 : return st.is_integer_type ();
129 : }
130 :
131 105761 : public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
132 105761 : inner.get_error_types (collection, source_reference);
133 : }
134 :
135 39459 : public override bool check (CodeContext context) {
136 39459 : if (checked) {
137 484 : return !error;
138 : }
139 :
140 38975 : checked = true;
141 :
142 38975 : if (operator == UnaryOperator.REF || operator == UnaryOperator.OUT) {
143 18836 : inner.lvalue = true;
144 18836 : inner.target_type = target_type;
145 20139 : } else if (operator == UnaryOperator.INCREMENT || operator == UnaryOperator.DECREMENT) {
146 495 : inner.lvalue = true;
147 : }
148 :
149 38975 : if (!inner.check (context)) {
150 : /* if there was an error in the inner expression, skip type check */
151 0 : error = true;
152 0 : return false;
153 38975 : } else if (inner.value_type == null) {
154 0 : error = true;
155 0 : Report.error (inner.source_reference, "Invalid inner operand");
156 0 : return false;
157 : }
158 :
159 38975 : if (inner.value_type is FieldPrototype || inner.value_type is PropertyPrototype) {
160 1 : error = true;
161 1 : Report.error (inner.source_reference, "Access to instance member `%s' denied", inner.symbol_reference.get_full_name ());
162 1 : return false;
163 : }
164 :
165 38974 : switch (operator) {
166 : case UnaryOperator.PLUS:
167 : case UnaryOperator.MINUS:
168 : // integer or floating point type
169 456 : if (!is_numeric_type (inner.value_type)) {
170 1 : error = true;
171 1 : Report.error (source_reference, "Operator not supported for `%s'", inner.value_type.to_string ());
172 1 : return false;
173 : }
174 :
175 455 : value_type = inner.value_type;
176 455 : break;
177 : case UnaryOperator.LOGICAL_NEGATION:
178 : // boolean type
179 19184 : if (inner.value_type.nullable || !inner.value_type.compatible (context.analyzer.bool_type)) {
180 1 : error = true;
181 1 : Report.error (source_reference, "Operator not supported for `%s'", inner.value_type.to_string ());
182 1 : return false;
183 : }
184 :
185 19183 : value_type = inner.value_type;
186 19183 : break;
187 : case UnaryOperator.BITWISE_COMPLEMENT:
188 : // integer type
189 3 : if (!is_integer_type (inner.value_type) && !(inner.value_type is EnumValueType)) {
190 1 : error = true;
191 1 : Report.error (source_reference, "Operator not supported for `%s'", inner.value_type.to_string ());
192 1 : return false;
193 : }
194 :
195 2 : value_type = inner.value_type;
196 2 : break;
197 : case UnaryOperator.INCREMENT:
198 : case UnaryOperator.DECREMENT:
199 : // integer type
200 495 : if (!is_integer_type (inner.value_type)) {
201 1 : error = true;
202 1 : Report.error (source_reference, "Operator not supported for `%s'", inner.value_type.to_string ());
203 1 : return false;
204 : }
205 :
206 494 : if (!(inner is MemberAccess)) {
207 1 : error = true;
208 1 : Report.error (source_reference, "Prefix operators not supported for this expression");
209 1 : return false;
210 : }
211 :
212 493 : value_type = inner.value_type;
213 493 : break;
214 : case UnaryOperator.REF:
215 : case UnaryOperator.OUT:
216 18836 : unowned ElementAccess? ea = inner as ElementAccess;
217 18836 : if (inner.symbol_reference is Field || inner.symbol_reference is Parameter || inner.symbol_reference is LocalVariable ||
218 3 : (ea != null && ea.container.value_type is ArrayType)) {
219 : // ref and out can only be used with fields, parameters, local variables, and array element access
220 18834 : lvalue = true;
221 : // `ref foo` or `out foo` is used as synonym for `&foo`
222 18834 : if (parent_node is InitializerList || parent_node is MemberInitializer) {
223 109 : value_type = new PointerType (inner.value_type, inner.source_reference);
224 : } else {
225 18725 : value_type = inner.value_type;
226 : }
227 : } else {
228 2 : error = true;
229 2 : Report.error (source_reference, "ref and out method arguments can only be used with fields, parameters, local variables, and array element access");
230 2 : return false;
231 : }
232 18834 : if (inner.symbol_reference != null && inner.symbol_reference.has_attribute ("GtkChild")) {
233 2 : error = true;
234 2 : Report.error (source_reference, "Assignment of [GtkChild] `%s' is not allowed", inner.symbol_reference.get_full_name ());
235 2 : return false;
236 : }
237 : break;
238 : default:
239 0 : error = true;
240 0 : Report.error (source_reference, "internal error: unsupported unary operator");
241 0 : return false;
242 : }
243 :
244 38965 : value_type.check (context);
245 :
246 38965 : return !error;
247 : }
248 :
249 3684 : public override void emit (CodeGenerator codegen) {
250 3684 : inner.emit (codegen);
251 :
252 3684 : codegen.visit_unary_expression (this);
253 :
254 3684 : codegen.visit_expression (this);
255 : }
256 :
257 82638 : public override void get_defined_variables (Collection<Variable> collection) {
258 82638 : inner.get_defined_variables (collection);
259 82638 : if (operator == UnaryOperator.OUT || operator == UnaryOperator.REF) {
260 38523 : unowned LocalVariable? local = inner.symbol_reference as LocalVariable;
261 38523 : unowned Parameter? param = inner.symbol_reference as Parameter;
262 38523 : if (local != null) {
263 32631 : collection.add (local);
264 : }
265 38523 : if (param != null && param.direction == ParameterDirection.OUT) {
266 21 : collection.add (param);
267 : }
268 : }
269 : }
270 :
271 27548 : public override void get_used_variables (Collection<Variable> collection) {
272 27548 : if (operator != UnaryOperator.OUT) {
273 16730 : inner.get_used_variables (collection);
274 : }
275 : }
276 : }
277 :
278 : public enum Vala.UnaryOperator {
279 : NONE,
280 : PLUS,
281 : MINUS,
282 : LOGICAL_NEGATION,
283 : BITWISE_COMPLEMENT,
284 : INCREMENT,
285 : DECREMENT,
286 : REF,
287 : OUT;
288 :
289 : public unowned string to_string () {
290 0 : switch (this) {
291 0 : case PLUS: return "+";
292 0 : case MINUS: return "-";
293 0 : case LOGICAL_NEGATION: return "!";
294 0 : case BITWISE_COMPLEMENT: return "~";
295 0 : case INCREMENT: return "++";
296 0 : case DECREMENT: return "--";
297 0 : case REF: return "ref ";
298 0 : case OUT: return "out ";
299 0 : default: assert_not_reached ();
300 : }
301 : }
302 :
303 : }
|