Line data Source code
1 : /* valaarraycreationexpression.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 creation expression.
29 : *
30 : * {{{ new int[] { 1, 2, 3 } }}}
31 : */
32 18299 : public class Vala.ArrayCreationExpression : Expression {
33 : /**
34 : * The type of the elements of the array.
35 : */
36 : public DataType element_type {
37 88025 : get { return _element_type; }
38 15653 : private set {
39 39661 : _element_type = value;
40 15653 : _element_type.parent_node = this;
41 : }
42 : }
43 :
44 : /**
45 : * The length type.
46 : */
47 : public DataType? length_type {
48 55609 : get { return _length_type; }
49 7817 : set {
50 15634 : _length_type = value;
51 7817 : if (_length_type != null) {
52 7817 : _length_type.parent_node = this;
53 : }
54 : }
55 : }
56 :
57 : /**
58 : * The rank of the array.
59 : */
60 8987 : public int rank { get; private set; }
61 :
62 : /**
63 : * The size for each dimension ascending from left to right.
64 : */
65 16762 : private List<Expression> sizes = new ArrayList<Expression> ();
66 :
67 : /**
68 : * The root array initializer list.
69 : */
70 : public InitializerList? initializer_list {
71 46163 : get { return _initializer_list; }
72 8381 : private set {
73 9000 : _initializer_list = value;
74 8381 : if (_initializer_list != null) {
75 619 : _initializer_list.parent_node = this;
76 : }
77 : }
78 : }
79 :
80 8381 : private DataType _element_type;
81 8381 : private DataType _length_type;
82 8381 : private InitializerList? _initializer_list;
83 :
84 : /**
85 : * Add a size expression.
86 : */
87 8400 : public void append_size (Expression size) {
88 8400 : sizes.add (size);
89 8400 : if (size != null) {
90 8400 : size.parent_node = this;
91 : }
92 : }
93 :
94 : /**
95 : * Get the sizes for all dimensions ascending from left to right.
96 : */
97 8480 : public unowned List<Expression> get_sizes () {
98 8480 : return sizes;
99 : }
100 :
101 25143 : public ArrayCreationExpression (DataType element_type, int rank, InitializerList? initializer_list, SourceReference? source_reference = null) {
102 8381 : this.element_type = element_type;
103 8381 : this.rank = rank;
104 8381 : this.initializer_list = initializer_list;
105 8381 : this.source_reference = source_reference;
106 : }
107 :
108 19542 : public override void accept_children (CodeVisitor visitor) {
109 19542 : if (element_type != null) {
110 19542 : element_type.accept (visitor);
111 : }
112 :
113 19542 : if (length_type != null) {
114 10828 : length_type.accept (visitor);
115 : }
116 :
117 57500 : foreach (Expression e in sizes) {
118 18979 : e.accept (visitor);
119 : }
120 :
121 19542 : if (initializer_list != null) {
122 1699 : initializer_list.accept (visitor);
123 : }
124 : }
125 :
126 19542 : public override void accept (CodeVisitor visitor) {
127 19542 : visitor.visit_array_creation_expression (this);
128 :
129 19542 : visitor.visit_expression (this);
130 : }
131 :
132 0 : public override bool is_pure () {
133 0 : return false;
134 : }
135 :
136 0 : public override bool is_accessible (Symbol sym) {
137 0 : if (element_type != null && !element_type.is_accessible (sym)) {
138 0 : return false;
139 : }
140 :
141 0 : if (length_type != null && !length_type.is_accessible (sym)) {
142 0 : return false;
143 : }
144 :
145 0 : foreach (Expression e in sizes) {
146 0 : if (!e.is_accessible (sym)) {
147 0 : return false;
148 : }
149 : }
150 :
151 0 : if (initializer_list != null) {
152 0 : return initializer_list.is_accessible (sym);
153 : }
154 :
155 0 : return true;
156 : }
157 :
158 0 : public override string to_string () {
159 0 : var builder = new StringBuilder ("new ");
160 0 : builder.append_printf ("%s[", element_type.to_string ());
161 0 : bool first = true;
162 0 : foreach (var size in sizes) {
163 0 : if (first) {
164 0 : builder.append (size.to_string ());
165 0 : first = false;
166 : } else {
167 0 : builder.append_printf (", %s", size.to_string ());
168 : }
169 : }
170 0 : var length_str = length_type.to_string ();
171 0 : if (length_str != "int") {
172 0 : builder.append_printf (":%s", length_str);
173 : }
174 0 : builder.append_c (']');
175 0 : if (initializer_list != null) {
176 0 : builder.append (initializer_list.to_string ());
177 : }
178 0 : return builder.str;
179 : }
180 :
181 0 : public override void replace_expression (Expression old_node, Expression new_node) {
182 0 : for (int i = 0; i < sizes.size; i++) {
183 0 : if (sizes[i] == old_node) {
184 0 : sizes[i] = new_node;
185 0 : new_node.parent_node = this;
186 0 : return;
187 : }
188 : }
189 : }
190 :
191 7281 : public override void replace_type (DataType old_type, DataType new_type) {
192 7281 : if (element_type == old_type) {
193 7272 : element_type = new_type;
194 : }
195 7281 : if (length_type == old_type) {
196 9 : length_type = new_type;
197 : }
198 : }
199 :
200 668 : private int create_sizes_from_initializer_list (CodeContext context, InitializerList il, int rank, List<Literal> sl) {
201 1305 : if (sl.size == (this.rank - rank)) {
202 : // only add size if this is the first initializer list of the current dimension
203 637 : var init = new IntegerLiteral (il.size.to_string (), il.source_reference);
204 637 : init.check (context);
205 637 : sl.add (init);
206 : }
207 :
208 668 : int subsize = -1;
209 3898 : foreach (Expression e in il.get_initializers ()) {
210 1616 : if (e is InitializerList && e.target_type is ArrayType) {
211 51 : if (rank == 1) {
212 0 : il.error = true;
213 0 : e.error = true;
214 0 : Report.error (e.source_reference, "Expected array element, got array initializer list");
215 0 : return -1;
216 : }
217 51 : int size = create_sizes_from_initializer_list (context, (InitializerList) e, rank - 1, sl);
218 51 : if (size == -1) {
219 0 : return -1;
220 : }
221 51 : if (subsize >= 0 && subsize != size) {
222 0 : il.error = true;
223 0 : Report.error (il.source_reference, "Expected initializer list of size %d, got size %d", subsize, size);
224 0 : return -1;
225 : } else {
226 : subsize = size;
227 : }
228 : } else {
229 1565 : if (rank != 1) {
230 1 : il.error = true;
231 1 : e.error = true;
232 1 : Report.error (e.source_reference, "Expected array initializer list, got array element");
233 1 : return -1;
234 : }
235 : }
236 : }
237 667 : return il.size;
238 : }
239 :
240 7810 : public override bool check (CodeContext context) {
241 7810 : if (checked) {
242 0 : return !error;
243 : }
244 :
245 7810 : checked = true;
246 :
247 7810 : List<Expression> sizes = get_sizes ();
248 7810 : var initlist = initializer_list;
249 :
250 7810 : if (element_type != null) {
251 7810 : element_type.check (context);
252 :
253 : // check whether there is the expected amount of type-arguments
254 7810 : if (!element_type.check_type_arguments (context, true)) {
255 2 : error = true;
256 2 : return false;
257 : }
258 : }
259 :
260 7808 : if (length_type == null) {
261 : // Make sure that "int" is still picked up as default
262 7232 : length_type = context.analyzer.int_type.copy ();
263 : } else {
264 576 : length_type.check (context);
265 576 : if (!(length_type is IntegerType) || length_type.nullable) {
266 2 : error = true;
267 2 : Report.error (length_type.source_reference, "Expected integer type as length type of array");
268 : }
269 : }
270 :
271 22198 : foreach (Expression e in sizes) {
272 7195 : e.check (context);
273 : }
274 :
275 7808 : var calc_sizes = new ArrayList<Literal> ();
276 7808 : if (initlist != null) {
277 617 : initlist.target_type = new ArrayType (element_type, rank, source_reference);
278 617 : ((ArrayType) initlist.target_type).length_type = length_type.copy ();
279 :
280 617 : if (!initlist.check (context)) {
281 2 : error = true;
282 : }
283 :
284 617 : var ret = create_sizes_from_initializer_list (context, initlist, rank, calc_sizes);
285 617 : if (ret == -1) {
286 1 : error = true;
287 : }
288 :
289 619 : if (calc_sizes.size != rank) {
290 2 : error = true;
291 2 : var actual_type = new ArrayType (element_type, calc_sizes.size, source_reference);
292 2 : ((ArrayType) actual_type).length_type = length_type;
293 2 : Report.error (initlist.source_reference, "Expected initializer for `%s' but got `%s'", target_type.to_string (), actual_type.to_string ());
294 : }
295 : }
296 :
297 7808 : if (sizes.size > 0) {
298 : /* check for errors in the size list */
299 21583 : foreach (Expression e in sizes) {
300 7195 : if (e.value_type == null) {
301 : /* return on previous error */
302 0 : return false;
303 7195 : } else if (!(e.value_type is IntegerType || e.value_type is EnumValueType)) {
304 1 : error = true;
305 1 : Report.error (e.source_reference, "Expression of integer type expected");
306 : }
307 : }
308 : } else {
309 615 : if (initlist == null) {
310 0 : error = true;
311 : /* this is an internal error because it is already handled by the parser */
312 0 : Report.error (source_reference, "internal error: initializer list expected");
313 : } else {
314 1885 : foreach (Expression size in calc_sizes) {
315 635 : append_size (size);
316 : }
317 : }
318 : }
319 :
320 7808 : if (error) {
321 6 : return false;
322 : }
323 :
324 : /* check for wrong elements inside the initializer */
325 7802 : if (initializer_list != null && initializer_list.value_type == null) {
326 0 : return false;
327 : }
328 :
329 : /* try to construct the type of the array */
330 7802 : if (element_type == null) {
331 0 : error = true;
332 0 : Report.error (source_reference, "Cannot determine the element type of the created array");
333 0 : return false;
334 : }
335 :
336 7802 : value_type = new ArrayType (element_type, rank, source_reference);
337 7802 : ((ArrayType) value_type).length_type = length_type.copy ();
338 7802 : if (formal_target_type is ArrayType) {
339 1855 : ((ArrayType) value_type).fixed_length = ((ArrayType) formal_target_type).fixed_length;
340 1855 : ((ArrayType) value_type).inline_allocated = ((ArrayType) formal_target_type).inline_allocated;
341 : }
342 7802 : value_type.value_owned = true;
343 :
344 7802 : if (!value_type.check (context)) {
345 1 : return false;
346 : }
347 :
348 7801 : return !error;
349 : }
350 :
351 697 : public override void emit (CodeGenerator codegen) {
352 2133 : foreach (Expression e in sizes) {
353 718 : e.emit (codegen);
354 : }
355 :
356 697 : if (initializer_list != null) {
357 606 : initializer_list.emit (codegen);
358 : }
359 :
360 697 : codegen.visit_array_creation_expression (this);
361 :
362 697 : codegen.visit_expression (this);
363 : }
364 :
365 5506 : public override void get_used_variables (Collection<Variable> collection) {
366 16560 : foreach (Expression e in sizes) {
367 5527 : e.get_used_variables (collection);
368 : }
369 :
370 5506 : if (initializer_list != null) {
371 589 : initializer_list.get_used_variables (collection);
372 : }
373 : }
374 : }
|