gtk+-4.0: Update to 3.90.0
[vala-gnome.git] / vala / valaunaryexpression.vala
blob95b0d4fc48c27f689ba142aaf165dbdf85842dda
1 /* valaunaryexpression.vala
3 * Copyright (C) 2006-2011 Jürg Billeter
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.
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.
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
24 /**
25 * Represents an expression with one operand in the source code.
27 * Supports +, -, !, ~, ref, out.
29 public class Vala.UnaryExpression : Expression {
30 /**
31 * The unary operator.
33 public UnaryOperator operator { get; set; }
35 /**
36 * The operand.
38 public Expression inner {
39 get {
40 return _inner;
42 set {
43 _inner = value;
44 _inner.parent_node = this;
48 private Expression _inner;
50 /**
51 * Creates a new unary expression.
53 * @param op unary operator
54 * @param _inner operand
55 * @param source reference to source code
56 * @return newly created binary expression
58 public UnaryExpression (UnaryOperator op, Expression _inner, SourceReference source) {
59 operator = op;
60 inner = _inner;
61 source_reference = source;
64 public override void accept (CodeVisitor visitor) {
65 visitor.visit_unary_expression (this);
67 visitor.visit_expression (this);
70 public override void accept_children (CodeVisitor visitor) {
71 inner.accept (visitor);
74 public override void replace_expression (Expression old_node, Expression new_node) {
75 if (inner == old_node) {
76 inner = new_node;
80 private unowned string get_operator_string () {
81 switch (_operator) {
82 case UnaryOperator.PLUS: return "+";
83 case UnaryOperator.MINUS: return "-";
84 case UnaryOperator.LOGICAL_NEGATION: return "!";
85 case UnaryOperator.BITWISE_COMPLEMENT: return "~";
86 case UnaryOperator.INCREMENT: return "++";
87 case UnaryOperator.DECREMENT: return "--";
88 case UnaryOperator.REF: return "ref ";
89 case UnaryOperator.OUT: return "out ";
90 default: assert_not_reached ();
94 public override string to_string () {
95 return get_operator_string () + _inner.to_string ();
98 public override bool is_constant () {
99 if (operator == UnaryOperator.INCREMENT || operator == UnaryOperator.DECREMENT) {
100 return false;
103 if (operator == UnaryOperator.REF || operator == UnaryOperator.OUT) {
104 var field = inner.symbol_reference as Field;
105 if (field != null && field.binding == MemberBinding.STATIC) {
106 return true;
107 } else {
108 return false;
112 return inner.is_constant ();
115 public override bool is_pure () {
116 if (operator == UnaryOperator.INCREMENT || operator == UnaryOperator.DECREMENT) {
117 return false;
120 return inner.is_pure ();
123 public override bool is_accessible (Symbol sym) {
124 return inner.is_accessible (sym);
127 bool is_numeric_type (DataType type) {
128 if (!(type.data_type is Struct)) {
129 return false;
132 var st = (Struct) type.data_type;
133 return st.is_integer_type () || st.is_floating_type ();
136 bool is_integer_type (DataType type) {
137 if (!(type.data_type is Struct)) {
138 return false;
141 var st = (Struct) type.data_type;
142 return st.is_integer_type ();
145 MemberAccess? find_member_access (Expression expr) {
146 if (expr is MemberAccess) {
147 return (MemberAccess) expr;
150 return null;
153 public override bool check (CodeContext context) {
154 if (checked) {
155 return !error;
158 checked = true;
160 if (operator == UnaryOperator.REF || operator == UnaryOperator.OUT) {
161 inner.lvalue = true;
162 inner.target_type = target_type;
163 } else if (operator == UnaryOperator.INCREMENT || operator == UnaryOperator.DECREMENT) {
164 inner.lvalue = true;
167 if (!inner.check (context)) {
168 /* if there was an error in the inner expression, skip type check */
169 error = true;
170 return false;
173 if (inner.value_type is FieldPrototype) {
174 error = true;
175 Report.error (inner.source_reference, "Access to instance member `%s' denied".printf (inner.symbol_reference.get_full_name ()));
176 return false;
179 if (operator == UnaryOperator.PLUS || operator == UnaryOperator.MINUS) {
180 // integer or floating point type
181 if (!is_numeric_type (inner.value_type)) {
182 error = true;
183 Report.error (source_reference, "Operator not supported for `%s'".printf (inner.value_type.to_string ()));
184 return false;
187 value_type = inner.value_type;
188 } else if (operator == UnaryOperator.LOGICAL_NEGATION) {
189 // boolean type
190 if (!inner.value_type.compatible (context.analyzer.bool_type)) {
191 error = true;
192 Report.error (source_reference, "Operator not supported for `%s'".printf (inner.value_type.to_string ()));
193 return false;
196 value_type = inner.value_type;
197 } else if (operator == UnaryOperator.BITWISE_COMPLEMENT) {
198 // integer type
199 if (!is_integer_type (inner.value_type) && !(inner.value_type is EnumValueType)) {
200 error = true;
201 Report.error (source_reference, "Operator not supported for `%s'".printf (inner.value_type.to_string ()));
202 return false;
205 value_type = inner.value_type;
206 } else if (operator == UnaryOperator.INCREMENT ||
207 operator == UnaryOperator.DECREMENT) {
208 // integer type
209 if (!is_integer_type (inner.value_type)) {
210 error = true;
211 Report.error (source_reference, "Operator not supported for `%s'".printf (inner.value_type.to_string ()));
212 return false;
215 var ma = find_member_access (inner);
216 if (ma == null) {
217 error = true;
218 Report.error (source_reference, "Prefix operators not supported for this expression");
219 return false;
222 var old_value = new MemberAccess (ma.inner, ma.member_name, inner.source_reference);
223 var bin = new BinaryExpression (operator == UnaryOperator.INCREMENT ? BinaryOperator.PLUS : BinaryOperator.MINUS, old_value, new IntegerLiteral ("1"), source_reference);
225 var assignment = new Assignment (ma, bin, AssignmentOperator.SIMPLE, source_reference);
226 assignment.target_type = target_type;
227 context.analyzer.replaced_nodes.add (this);
228 parent_node.replace_expression (this, assignment);
229 assignment.check (context);
230 return true;
231 } else if (operator == UnaryOperator.REF || operator == UnaryOperator.OUT) {
232 var ea = inner as ElementAccess;
233 if (inner.symbol_reference is Field || inner.symbol_reference is Parameter || inner.symbol_reference is LocalVariable ||
234 (ea != null && ea.container.value_type is ArrayType)) {
235 // ref and out can only be used with fields, parameters, local variables, and array element access
236 lvalue = true;
237 value_type = inner.value_type;
238 } else {
239 error = true;
240 Report.error (source_reference, "ref and out method arguments can only be used with fields, parameters, local variables, and array element access");
241 return false;
243 } else {
244 error = true;
245 Report.error (source_reference, "internal error: unsupported unary operator");
246 return false;
249 return !error;
252 public override void emit (CodeGenerator codegen) {
253 inner.emit (codegen);
255 codegen.visit_unary_expression (this);
257 codegen.visit_expression (this);
260 public override void get_defined_variables (Collection<Variable> collection) {
261 inner.get_defined_variables (collection);
262 if (operator == UnaryOperator.OUT || operator == UnaryOperator.REF) {
263 var local = inner.symbol_reference as LocalVariable;
264 var param = inner.symbol_reference as Parameter;
265 if (local != null) {
266 collection.add (local);
268 if (param != null && param.direction == ParameterDirection.OUT) {
269 collection.add (param);
274 public override void get_used_variables (Collection<Variable> collection) {
275 if (operator != UnaryOperator.OUT) {
276 inner.get_used_variables (collection);
281 public enum Vala.UnaryOperator {
282 NONE,
283 PLUS,
284 MINUS,
285 LOGICAL_NEGATION,
286 BITWISE_COMPLEMENT,
287 INCREMENT,
288 DECREMENT,
289 REF,