Line data Source code
1 : /* valaelementaccess.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : * Copyright (C) 2006-2008 Raffaele Sandrini
5 : *
6 : * This library is free software; you can redistribute it and/or
7 : * modify it under the terms of the GNU Lesser General Public
8 : * License as published by the Free Software Foundation; either
9 : * version 2.1 of the License, or (at your option) any later version.
10 :
11 : * This library is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 :
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this library; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 : *
20 : * Author:
21 : * Raffaele Sandrini <raffaele@sandrini.ch>
22 : * Jürg Billeter <j@bitron.ch>
23 : */
24 :
25 : using GLib;
26 :
27 : /**
28 : * Represents an array access expression.
29 : *
30 : * {{{ foo[1,2] }}}
31 : */
32 50604 : public class Vala.ElementAccess : Expression {
33 : /**
34 : * Expression representing the container on which we want to access.
35 : */
36 : public Expression container {
37 349700 : get {
38 349700 : return _container;
39 : }
40 24539 : set {
41 24539 : _container = value;
42 24539 : _container.parent_node = this;
43 : }
44 : }
45 :
46 : /**
47 : * Null-safe access.
48 : */
49 24522 : public bool null_safe_access { get; set; }
50 :
51 : /**
52 : * Expressions representing the indices we want to access inside the container.
53 : */
54 49074 : private List<Expression> indices = new ArrayList<Expression> ();
55 :
56 24537 : Expression _container;
57 :
58 24605 : public void append_index (Expression index) {
59 24605 : indices.add (index);
60 24605 : index.parent_node = this;
61 : }
62 :
63 86414 : public unowned List<Expression> get_indices () {
64 86414 : return indices;
65 : }
66 :
67 73611 : public ElementAccess (Expression container, SourceReference? source_reference = null) {
68 24537 : this.source_reference = source_reference;
69 24537 : this.container = container;
70 : }
71 :
72 74924 : public override void accept (CodeVisitor visitor) {
73 74924 : visitor.visit_element_access (this);
74 :
75 74924 : visitor.visit_expression (this);
76 : }
77 :
78 74924 : public override void accept_children (CodeVisitor visitor) {
79 74924 : container.accept (visitor);
80 225200 : foreach (Expression e in indices) {
81 75138 : e.accept (visitor);
82 : }
83 : }
84 :
85 0 : public override string to_string () {
86 0 : var s = "%s[".printf (container.to_string ());
87 0 : bool first = true;
88 0 : foreach (var index in indices) {
89 0 : if (first) {
90 0 : s += index.to_string ();
91 0 : first = false;
92 : } else {
93 0 : s += ", %s".printf (index.to_string ());
94 : }
95 : }
96 0 : return s + "]";
97 : }
98 :
99 2 : public override void replace_expression (Expression old_node, Expression new_node) {
100 2 : if (container == old_node) {
101 2 : container = new_node;
102 : }
103 :
104 2 : int index = indices.index_of (old_node);
105 2 : if (index >= 0) {
106 0 : indices[index] = new_node;
107 0 : new_node.parent_node = this;
108 : }
109 : }
110 :
111 0 : public override bool is_pure () {
112 0 : foreach (Expression index in indices) {
113 0 : if (!index.is_pure ()) {
114 0 : return false;
115 : }
116 : }
117 0 : return container.is_pure ();
118 : }
119 :
120 0 : public override bool is_accessible (Symbol sym) {
121 0 : foreach (Expression index in indices) {
122 0 : if (!index.is_accessible (sym)) {
123 0 : return false;
124 : }
125 : }
126 :
127 0 : return container.is_accessible (sym);
128 : }
129 :
130 34916 : public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
131 34916 : container.get_error_types (collection, source_reference);
132 105480 : foreach (Expression e in indices) {
133 35282 : e.get_error_types (collection, source_reference);
134 : }
135 : }
136 :
137 30634 : public override bool check (CodeContext context) {
138 30634 : if (checked) {
139 7808 : return !error;
140 : }
141 :
142 22826 : checked = true;
143 :
144 22826 : if (null_safe_access) {
145 3 : error = !base.check (context);
146 3 : return !error;
147 : }
148 :
149 22823 : if (!container.check (context)) {
150 : /* don't proceed if a child expression failed */
151 0 : error = true;
152 0 : return false;
153 : }
154 :
155 22823 : if (container.value_type == null) {
156 0 : error = true;
157 0 : Report.error (container.source_reference, "Invalid container expression");
158 0 : return false;
159 : }
160 :
161 22839 : if (container is MemberAccess && container.symbol_reference is Signal) {
162 : // signal detail access
163 18 : if (get_indices ().size != 1) {
164 1 : error = true;
165 1 : Report.error (source_reference, "Element access with more than one dimension is not supported for signals");
166 1 : return false;
167 : }
168 :
169 17 : var detail_expr = get_indices ().get (0);
170 17 : detail_expr.target_type = context.analyzer.string_type.copy ();
171 17 : detail_expr.check (context);
172 :
173 17 : if (detail_expr.value_type is NullType || !detail_expr.value_type.compatible (context.analyzer.string_type)) {
174 1 : error = true;
175 1 : Report.error (detail_expr.source_reference, "only string details are supported");
176 1 : return false;
177 : }
178 : }
179 :
180 68597 : foreach (Expression index in get_indices ()) {
181 22888 : index.check (context);
182 : }
183 :
184 22821 : bool index_int_type_check = true;
185 :
186 22821 : unowned PointerType? pointer_type = container.value_type as PointerType;
187 :
188 : /* assign a value_type when possible */
189 22821 : if (container.value_type is ArrayType) {
190 19636 : unowned ArrayType array_type = (ArrayType) container.value_type;
191 19636 : value_type = array_type.element_type.copy ();
192 19636 : if (!lvalue) {
193 13883 : value_type.value_owned = false;
194 : } else {
195 5753 : unowned MemberAccess? ma = container as MemberAccess;
196 5753 : if (context.profile == Profile.GOBJECT && ma != null && ma.symbol_reference is ArrayLengthField) {
197 : // propagate lvalue for gobject length access
198 1 : ma.inner.lvalue = true;
199 1 : ((MemberAccess) ma.inner).check_lvalue_access ();
200 5752 : } else if (ma != null && ma.symbol_reference is Field &&
201 4251 : ma.inner != null && ma.inner.symbol_reference is Variable &&
202 4249 : ma.inner.value_type is StructValueType && !ma.inner.value_type.nullable) {
203 : // propagate lvalue if container is a field and container.inner is a struct variable
204 1 : ma.lvalue = true;
205 1 : ma.check_lvalue_access ();
206 : }
207 : }
208 :
209 19636 : if (array_type.rank < get_indices ().size) {
210 0 : error = true;
211 0 : Report.error (source_reference, "%d extra indices for element access", get_indices ().size - array_type.rank);
212 19636 : } else if (array_type.rank > get_indices ().size) {
213 0 : error = true;
214 0 : Report.error (source_reference, "%d missing indices for element access", array_type.rank - get_indices ().size);
215 : }
216 3185 : } else if (pointer_type != null && !pointer_type.base_type.is_reference_type_or_type_parameter ()) {
217 2842 : value_type = pointer_type.base_type.copy ();
218 343 : } else if (container is MemberAccess && container.symbol_reference is Signal) {
219 16 : index_int_type_check = false;
220 :
221 16 : symbol_reference = container.symbol_reference;
222 16 : value_type = container.value_type;
223 : } else {
224 327 : if (lvalue) {
225 13 : var set_method = container.value_type.get_member ("set") as Method;
226 13 : unowned Assignment? assignment = parent_node as Assignment;
227 13 : if (assignment != null && set_method != null
228 13 : && (set_method.return_type is VoidType || set_method.return_type is BooleanType)) {
229 13 : return !error;
230 : }
231 : } else {
232 314 : var get_method = container.value_type.get_member ("get") as Method;
233 313 : if (get_method != null) {
234 313 : var get_call = new MethodCall (new MemberAccess (container, "get", source_reference), source_reference);
235 939 : foreach (Expression e in get_indices ()) {
236 313 : get_call.add_argument (e);
237 : }
238 313 : get_call.formal_target_type = this.formal_target_type;
239 313 : get_call.target_type = this.target_type;
240 313 : parent_node.replace_expression (this, get_call);
241 313 : return get_call.check (context);
242 : }
243 : }
244 :
245 1 : error = true;
246 1 : Report.error (source_reference, "The expression `%s' does not denote an array", container.value_type.to_string ());
247 1 : return false;
248 : }
249 :
250 2858 : if (index_int_type_check) {
251 : /* check if the index is of type integer */
252 67568 : foreach (Expression e in get_indices ()) {
253 : /* don't proceed if a child expression failed */
254 22545 : if (e.value_type == null) {
255 0 : return false;
256 : }
257 :
258 : /* check if the index is of type integer */
259 22545 : if (!(e.value_type is IntegerType || e.value_type is EnumValueType)) {
260 0 : error = true;
261 0 : Report.error (e.source_reference, "Expression of integer type expected");
262 : }
263 : }
264 : }
265 :
266 22494 : value_type.check (context);
267 :
268 22494 : return !error;
269 : }
270 :
271 1469 : public override void emit (CodeGenerator codegen) {
272 1469 : container.emit (codegen);
273 4541 : foreach (Expression e in indices) {
274 1536 : e.emit (codegen);
275 : }
276 :
277 1469 : codegen.visit_element_access (this);
278 :
279 1469 : codegen.visit_expression (this);
280 : }
281 :
282 47085 : public override void get_defined_variables (Collection<Variable> collection) {
283 47085 : container.get_defined_variables (collection);
284 141657 : foreach (Expression index in indices) {
285 47286 : index.get_defined_variables (collection);
286 : }
287 : }
288 :
289 15695 : public override void get_used_variables (Collection<Variable> collection) {
290 15695 : container.get_used_variables (collection);
291 47219 : foreach (Expression index in indices) {
292 15762 : index.get_used_variables (collection);
293 : }
294 : }
295 : }
|