Line data Source code
1 : /* valapostfixexpression.vala
2 : *
3 : * Copyright (C) 2006-2010 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 postfix increment or decrement expression.
27 : */
28 8131 : public class Vala.PostfixExpression : Expression {
29 : /**
30 : * The operand, must be a variable or a property.
31 : */
32 : public Expression inner {
33 105115 : get { return _inner; }
34 6602 : private set {
35 6602 : _inner = value;
36 6602 : _inner.parent_node = this;
37 : }
38 : }
39 :
40 : /**
41 : * Specifies whether value should be incremented or decremented.
42 : */
43 7130 : public bool increment { get; private set; }
44 :
45 6602 : private Expression _inner;
46 :
47 : /**
48 : * Creates a new postfix expression.
49 : *
50 : * @param _inner operand expression
51 : * @param inc true for increment, false for decrement
52 : * @param source reference to source code
53 : * @return newly created postfix expression
54 : */
55 19806 : public PostfixExpression (Expression _inner, bool inc, SourceReference? source = null) {
56 6602 : inner = _inner;
57 6602 : increment = inc;
58 6602 : source_reference = source;
59 : }
60 :
61 16726 : public override void accept (CodeVisitor visitor) {
62 16726 : visitor.visit_postfix_expression (this);
63 :
64 16726 : visitor.visit_expression (this);
65 : }
66 :
67 10502 : public override void accept_children (CodeVisitor visitor) {
68 10502 : inner.accept (visitor);
69 : }
70 :
71 0 : public override bool is_pure () {
72 0 : return false;
73 : }
74 :
75 0 : public override bool is_accessible (Symbol sym) {
76 0 : return inner.is_accessible (sym);
77 : }
78 :
79 13002 : public override void get_defined_variables (Collection<Variable> collection) {
80 13002 : inner.get_defined_variables (collection);
81 13002 : unowned LocalVariable? local = inner.symbol_reference as LocalVariable;
82 13002 : unowned Parameter? param = inner.symbol_reference as Parameter;
83 13002 : if (local != null) {
84 9402 : collection.add (local);
85 3600 : } else if (param != null && param.direction == ParameterDirection.OUT) {
86 27 : collection.add (param);
87 : }
88 : }
89 :
90 4334 : public override void get_used_variables (Collection<Variable> collection) {
91 4334 : inner.get_used_variables (collection);
92 : }
93 :
94 0 : public override void replace_expression (Expression old_node, Expression new_node) {
95 0 : if (inner == old_node) {
96 0 : inner = new_node;
97 : }
98 : }
99 :
100 6179 : public override bool check (CodeContext context) {
101 6179 : if (checked) {
102 35 : return !error;
103 : }
104 :
105 6144 : checked = true;
106 :
107 6144 : inner.lvalue = true;
108 6144 : if (!inner.check (context)) {
109 0 : error = true;
110 0 : return false;
111 : }
112 :
113 6144 : if (!(inner.value_type is IntegerType) && !(inner.value_type is FloatingType) && !(inner.value_type is PointerType)) {
114 0 : error = true;
115 0 : Report.error (source_reference, "unsupported lvalue in postfix expression");
116 0 : return false;
117 : }
118 :
119 6144 : if (inner is MemberAccess) {
120 6143 : unowned MemberAccess ma = (MemberAccess) inner;
121 :
122 6143 : if (ma.prototype_access) {
123 0 : error = true;
124 0 : Report.error (source_reference, "Access to instance member `%s' denied", ma.symbol_reference.get_full_name ());
125 0 : return false;
126 : }
127 :
128 6143 : if (ma.error || ma.symbol_reference == null) {
129 0 : error = true;
130 : /* if no symbol found, skip this check */
131 0 : return false;
132 : }
133 1 : } else if (inner is ElementAccess) {
134 1 : unowned ElementAccess ea = (ElementAccess) inner;
135 1 : if (!(ea.container.value_type is ArrayType)) {
136 0 : error = true;
137 0 : Report.error (source_reference, "unsupported lvalue in postfix expression");
138 0 : return false;
139 : }
140 : } else {
141 0 : error = true;
142 0 : Report.error (source_reference, "unsupported lvalue in postfix expression");
143 0 : return false;
144 : }
145 :
146 6144 : if (inner is MemberAccess) {
147 6143 : unowned MemberAccess ma = (MemberAccess) inner;
148 :
149 6143 : if (ma.symbol_reference is Property) {
150 39 : unowned Property prop = (Property) ma.symbol_reference;
151 :
152 39 : if (prop.set_accessor == null || !prop.set_accessor.writable) {
153 0 : ma.error = true;
154 0 : Report.error (ma.source_reference, "Property `%s' is read-only", prop.get_full_name ());
155 0 : return false;
156 : }
157 : }
158 : }
159 :
160 6144 : value_type = inner.value_type;
161 :
162 6144 : return !error;
163 : }
164 :
165 528 : public override void emit (CodeGenerator codegen) {
166 528 : inner.emit (codegen);
167 :
168 528 : codegen.visit_postfix_expression (this);
169 :
170 528 : codegen.visit_expression (this);
171 : }
172 :
173 0 : public override string to_string () {
174 0 : return "(%s%s)".printf (inner.to_string (), increment ? "++" : "--");
175 : }
176 : }
|