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
20 * Jürg Billeter <j@bitron.ch>
25 * Represents an expression with one operand in the source code.
27 * Supports +, -, !, ~, ref, out.
29 public class Vala
.UnaryExpression
: Expression
{
33 public UnaryOperator operator
{ get; set; }
38 public Expression inner
{
44 _inner
.parent_node
= this
;
48 private Expression _inner
;
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
) {
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
) {
80 private unowned
string get_operator_string () {
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
) {
103 if (operator
== UnaryOperator
.REF
|| operator
== UnaryOperator
.OUT
) {
104 var field
= inner
.symbol_reference as Field
;
105 if (field
!= null && field
.binding
== MemberBinding
.STATIC
) {
112 return inner
.is_constant ();
115 public override bool is_pure () {
116 if (operator
== UnaryOperator
.INCREMENT
|| operator
== UnaryOperator
.DECREMENT
) {
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
)) {
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
)) {
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
;
153 public override bool check (CodeContext context
) {
160 if (operator
== UnaryOperator
.REF
|| operator
== UnaryOperator
.OUT
) {
162 inner
.target_type
= target_type
;
163 } else if (operator
== UnaryOperator
.INCREMENT
|| operator
== UnaryOperator
.DECREMENT
) {
167 if (!inner
.check (context
)) {
168 /* if there was an error in the inner expression, skip type check */
173 if (inner
.value_type is FieldPrototype
) {
175 Report
.error (inner
.source_reference
, "Access to instance member `%s' denied".printf (inner
.symbol_reference
.get_full_name ()));
179 if (operator
== UnaryOperator
.PLUS
|| operator
== UnaryOperator
.MINUS
) {
180 // integer or floating point type
181 if (!is_numeric_type (inner
.value_type
)) {
183 Report
.error (source_reference
, "Operator not supported for `%s'".printf (inner
.value_type
.to_string ()));
187 value_type
= inner
.value_type
;
188 } else if (operator
== UnaryOperator
.LOGICAL_NEGATION
) {
190 if (!inner
.value_type
.compatible (context
.analyzer
.bool_type
)) {
192 Report
.error (source_reference
, "Operator not supported for `%s'".printf (inner
.value_type
.to_string ()));
196 value_type
= inner
.value_type
;
197 } else if (operator
== UnaryOperator
.BITWISE_COMPLEMENT
) {
199 if (!is_integer_type (inner
.value_type
) && !(inner
.value_type is EnumValueType
)) {
201 Report
.error (source_reference
, "Operator not supported for `%s'".printf (inner
.value_type
.to_string ()));
205 value_type
= inner
.value_type
;
206 } else if (operator
== UnaryOperator
.INCREMENT
||
207 operator
== UnaryOperator
.DECREMENT
) {
209 if (!is_integer_type (inner
.value_type
)) {
211 Report
.error (source_reference
, "Operator not supported for `%s'".printf (inner
.value_type
.to_string ()));
215 var ma
= find_member_access (inner
);
218 Report
.error (source_reference
, "Prefix operators not supported for this expression");
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
);
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
237 value_type
= inner
.value_type
;
240 Report
.error (source_reference
, "ref and out method arguments can only be used with fields, parameters, local variables, and array element access");
245 Report
.error (source_reference
, "internal error: unsupported unary operator");
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
;
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
{