Line data Source code
1 : /* valaarraytype.vala
2 : *
3 : * Copyright (C) 2007-2012 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 : * An array type.
27 : */
28 764086 : public class Vala.ArrayType : ReferenceType {
29 : /**
30 : * The element type.
31 : */
32 : public DataType element_type {
33 6150274 : get { return _element_type; }
34 1308635 : private set {
35 1996060 : _element_type = value;
36 1308635 : _element_type.parent_node = this;
37 : }
38 : }
39 :
40 : /**
41 : * The length type.
42 : */
43 : public DataType? length_type {
44 5439523 : get { return _length_type; }
45 666864 : set {
46 1333728 : _length_type = value;
47 666864 : if (_length_type != null) {
48 666864 : _length_type.parent_node = this;
49 : }
50 : }
51 : }
52 :
53 751205 : public bool invalid_syntax { get; set; }
54 :
55 655923 : public bool inline_allocated { get; set; }
56 :
57 47628 : public bool fixed_length { get; set; }
58 :
59 : /**
60 : * The length of this fixed-length array.
61 : */
62 : public Expression? length {
63 13979 : get { return _length; }
64 3190 : set {
65 6345 : _length = value;
66 3190 : if (_length != null) {
67 3155 : _length.parent_node = this;
68 : }
69 : }
70 : }
71 :
72 : /**
73 : * The rank of this array.
74 : */
75 861729 : public int rank { get; set; }
76 :
77 762549 : private DataType _element_type;
78 762549 : private DataType _length_type;
79 762549 : private Expression _length;
80 :
81 762549 : private ArrayLengthField length_field;
82 762549 : private ArrayResizeMethod resize_method;
83 762549 : private ArrayMoveMethod move_method;
84 762549 : private ArrayCopyMethod copy_method;
85 :
86 2287647 : public ArrayType (DataType element_type, int rank, SourceReference? source_reference = null) {
87 762549 : base (null, source_reference);
88 762549 : this.element_type = element_type;
89 762549 : this.rank = rank;
90 : }
91 :
92 18845 : public override Symbol? get_member (string member_name) {
93 18845 : if (member_name == "length") {
94 34640 : return get_length_field ();
95 1525 : } else if (member_name == "move") {
96 4 : return get_move_method ();
97 1523 : } else if (member_name == "resize") {
98 18 : if (rank > 1) {
99 1503 : return null;
100 : }
101 36 : return get_resize_method ();
102 1505 : } else if (member_name == "copy") {
103 4 : return get_copy_method ();
104 : }
105 18845 : return null;
106 : }
107 :
108 17320 : unowned ArrayLengthField get_length_field () {
109 17320 : if (length_field == null) {
110 17318 : length_field = new ArrayLengthField (source_reference);
111 :
112 17318 : length_field.access = SymbolAccessibility.PUBLIC;
113 :
114 17318 : if (rank > 1) {
115 : // length is an int[] containing the dimensions of the array, starting at 0
116 50 : length_field.variable_type = new ArrayType (length_type.copy (), 1, source_reference);
117 : } else {
118 17268 : length_field.variable_type = length_type.copy ();
119 : }
120 :
121 : }
122 17320 : return length_field;
123 : }
124 :
125 18 : unowned ArrayResizeMethod get_resize_method () {
126 18 : if (resize_method == null) {
127 18 : resize_method = new ArrayResizeMethod (source_reference);
128 :
129 18 : resize_method.return_type = new VoidType ();
130 18 : resize_method.access = SymbolAccessibility.PUBLIC;
131 :
132 18 : if (CodeContext.get ().profile == Profile.POSIX) {
133 1 : resize_method.set_attribute_string ("CCode", "cname", "realloc");
134 : } else {
135 17 : resize_method.set_attribute_string ("CCode", "cname", "g_renew");
136 : }
137 :
138 18 : resize_method.add_parameter (new Parameter ("length", length_type));
139 :
140 18 : resize_method.returns_modified_pointer = true;
141 : }
142 18 : return resize_method;
143 : }
144 :
145 2 : unowned ArrayMoveMethod get_move_method () {
146 2 : if (move_method == null) {
147 2 : move_method = new ArrayMoveMethod (source_reference);
148 :
149 2 : move_method.return_type = new VoidType ();
150 2 : move_method.access = SymbolAccessibility.PUBLIC;
151 :
152 2 : move_method.set_attribute_string ("CCode", "cname", "_vala_array_move");
153 :
154 2 : move_method.add_parameter (new Parameter ("src", length_type));
155 2 : move_method.add_parameter (new Parameter ("dest", length_type));
156 2 : move_method.add_parameter (new Parameter ("length", length_type));
157 : }
158 2 : return move_method;
159 : }
160 :
161 2 : unowned ArrayCopyMethod get_copy_method () {
162 2 : if (copy_method == null) {
163 2 : copy_method = new ArrayCopyMethod (source_reference);
164 :
165 2 : copy_method.return_type = this.copy ();
166 2 : copy_method.return_type.value_owned = true;
167 2 : copy_method.access = SymbolAccessibility.PUBLIC;
168 :
169 2 : copy_method.set_attribute_string ("CCode", "cname", "_vala_array_copy");
170 : }
171 2 : return copy_method;
172 : }
173 :
174 185765 : public override DataType copy () {
175 185765 : var result = new ArrayType (element_type.copy (), rank, source_reference);
176 185765 : if (length_type != null) {
177 120162 : result.length_type = length_type.copy ();
178 : }
179 :
180 185765 : result.value_owned = value_owned;
181 185765 : result.nullable = nullable;
182 185765 : result.floating_reference = floating_reference;
183 :
184 185765 : result.inline_allocated = inline_allocated;
185 185765 : if (fixed_length) {
186 714 : result.fixed_length = true;
187 714 : result.length = length;
188 : }
189 :
190 185765 : result.invalid_syntax = invalid_syntax;
191 :
192 185765 : return result;
193 : }
194 :
195 430 : public override string to_qualified_string (Scope? scope) {
196 430 : var elem_str = element_type.to_qualified_string (scope);
197 430 : if (element_type.is_weak () && !(parent_node is Constant)) {
198 3 : elem_str = "(unowned %s)".printf (elem_str);
199 : }
200 :
201 430 : if (!fixed_length) {
202 418 : var length_str = length_type == null ? "int" : length_type.to_qualified_string (scope);
203 418 : if (length_str != "int") {
204 3 : length_str = ":%s".printf (length_str);
205 : } else {
206 415 : length_str = "";
207 : }
208 418 : return "%s[%s%s]%s".printf (elem_str, string.nfill (rank - 1, ','), length_str, nullable ? "?" : "");
209 : } else {
210 430 : return elem_str;
211 : }
212 : }
213 :
214 25725 : public override bool compatible (DataType target_type) {
215 25725 : var context = CodeContext.get ();
216 :
217 25725 : if (context.profile == Profile.GOBJECT && target_type.type_symbol != null) {
218 134 : if (target_type.type_symbol.is_subtype_of (context.analyzer.gvalue_type.type_symbol) && element_type.type_symbol == context.analyzer.string_type.type_symbol) {
219 : // allow implicit conversion from string[] to GValue
220 1 : return true;
221 : }
222 :
223 133 : if (target_type.type_symbol.is_subtype_of (context.analyzer.gvariant_type.type_symbol)) {
224 : // allow implicit conversion to GVariant
225 11 : return true;
226 : }
227 : }
228 :
229 25713 : if (target_type is PointerType || (target_type.type_symbol != null && target_type.type_symbol.get_attribute ("PointerType") != null)) {
230 : /* any array type can be cast to a generic pointer */
231 4245 : return true;
232 : }
233 :
234 : /* temporarily ignore type parameters */
235 21468 : if (target_type is GenericType) {
236 0 : return true;
237 : }
238 :
239 21468 : unowned ArrayType? target_array_type = target_type as ArrayType;
240 21468 : if (target_array_type == null) {
241 131 : return false;
242 : }
243 :
244 21337 : if (target_array_type.rank != rank) {
245 0 : return false;
246 : }
247 :
248 21337 : if (element_type is ValueType && element_type.nullable != target_array_type.element_type.nullable) {
249 0 : return false;
250 : }
251 :
252 21337 : if (!length_type.compatible (target_array_type.length_type)) {
253 0 : return false;
254 : }
255 :
256 42672 : if (element_type.compatible (target_array_type.element_type)
257 21335 : && target_array_type.element_type.compatible (element_type)) {
258 21329 : return true;
259 8 : } else if (element_type.type_symbol is Class) {
260 7 : unowned Class cl = (Class) element_type.type_symbol;
261 14 : if ((!cl.is_compact || cl == context.analyzer.string_type.type_symbol)
262 7 : && element_type.compatible (target_array_type.element_type)) {
263 6 : return true;
264 : }
265 : }
266 :
267 2 : return false;
268 : }
269 :
270 10708 : public override bool is_reference_type_or_type_parameter () {
271 10708 : return true;
272 : }
273 :
274 955175 : public override void accept_children (CodeVisitor visitor) {
275 955175 : element_type.accept (visitor);
276 955175 : if (length_type != null) {
277 409029 : length_type.accept (visitor);
278 : }
279 : }
280 :
281 540422 : public override void replace_type (DataType old_type, DataType new_type) {
282 540422 : if (element_type == old_type) {
283 540397 : element_type = new_type;
284 : }
285 540422 : if (length_type == old_type) {
286 25 : length_type = new_type;
287 : }
288 : }
289 :
290 506611 : public override bool is_accessible (Symbol sym) {
291 506611 : if (length_type != null && !length_type.is_accessible (sym)) {
292 0 : return false;
293 : }
294 506611 : return element_type.is_accessible (sym);
295 : }
296 :
297 936812 : public override bool check (CodeContext context) {
298 936812 : if (invalid_syntax) {
299 4 : Report.error (source_reference, "syntax error, no expression allowed between array brackets");
300 4 : error = true;
301 4 : return false;
302 : }
303 :
304 936808 : if (fixed_length && length != null) {
305 2535 : length.check (context);
306 :
307 2535 : if (length.value_type == null || !(length.value_type is IntegerType || length.value_type is EnumValueType)
308 2535 : || !length.is_constant ()) {
309 1 : error = true;
310 1 : Report.error (length.source_reference, "Expression of constant integer type expected");
311 1 : return false;
312 : }
313 : }
314 :
315 936807 : if (element_type is ArrayType) {
316 1 : error = true;
317 1 : Report.error (source_reference, "Stacked arrays are not supported");
318 1 : return false;
319 936834 : } else if (element_type is DelegateType) {
320 29 : var delegate_type = (DelegateType) element_type;
321 29 : if (delegate_type.delegate_symbol.has_target) {
322 1 : error = true;
323 1 : Report.error (source_reference, "Delegates with target are not supported as array element type");
324 1 : return false;
325 : }
326 : }
327 :
328 936805 : if (length_type == null) {
329 : // Make sure that "int" is still picked up as default
330 538231 : length_type = context.analyzer.int_type.copy ();
331 : } else {
332 398574 : length_type.check (context);
333 398574 : if (!(length_type is IntegerType) || length_type.nullable) {
334 1 : error = true;
335 1 : Report.error (length_type.source_reference, "Expected integer type as length type of array");
336 1 : return false;
337 : }
338 : }
339 :
340 936804 : if (!element_type.check (context)) {
341 1 : error = true;
342 1 : return false;
343 : }
344 :
345 : // check whether there is the expected amount of type-arguments
346 936803 : if (!element_type.check_type_arguments (context, true)) {
347 0 : error = true;
348 0 : return false;
349 : }
350 :
351 936812 : return true;
352 : }
353 :
354 14456 : public override DataType get_actual_type (DataType? derived_instance_type, List<DataType>? method_type_arguments, CodeNode? node_reference) {
355 14456 : ArrayType result = (ArrayType) this.copy ();
356 :
357 14456 : if (derived_instance_type == null && method_type_arguments == null) {
358 : return result;
359 : }
360 :
361 14426 : if (element_type is GenericType || element_type.has_type_arguments ()) {
362 5689 : result.element_type = result.element_type.get_actual_type (derived_instance_type, method_type_arguments, node_reference);
363 : }
364 :
365 : return result;
366 : }
367 :
368 1 : public override DataType? infer_type_argument (TypeParameter type_param, DataType value_type) {
369 1 : unowned ArrayType? array_type = value_type as ArrayType;
370 1 : if (array_type != null) {
371 1 : return element_type.infer_type_argument (type_param, array_type.element_type);
372 : }
373 :
374 1 : return null;
375 : }
376 :
377 29502 : public override bool is_disposable () {
378 29502 : if (fixed_length) {
379 746 : return element_type.is_disposable ();
380 : } else {
381 28756 : return base.is_disposable ();
382 : }
383 : }
384 : }
|