Line data Source code
1 : /* valainitializerlist.vala
2 : *
3 : * Copyright (C) 2006-2011 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 : * Jürg Billeter <j@bitron.ch>
22 : * Raffaele Sandrini <raffaele@sandrini.ch>
23 : */
24 :
25 : using GLib;
26 :
27 : /**
28 : * Represents an array or struct initializer list in the source code.
29 : */
30 2314 : public class Vala.InitializerList : Expression {
31 2106 : private List<Expression> initializers = new ArrayList<Expression> ();
32 :
33 : /**
34 : * Appends the specified expression to this initializer
35 : *
36 : * @param expr an expression
37 : */
38 2991 : public void append (Expression expr) {
39 2991 : initializers.add (expr);
40 2991 : expr.parent_node = this;
41 : }
42 :
43 : /**
44 : * Returns the initializer expression list
45 : *
46 : * @return expression list
47 : */
48 4518 : public unowned List<Expression> get_initializers () {
49 4518 : return initializers;
50 : }
51 :
52 : /**
53 : * Returns the initializer count in this initializer
54 : */
55 : public int size {
56 1797 : get { return initializers.size; }
57 : }
58 :
59 : /**
60 : * Creates a new initializer
61 : *
62 : * @param source_reference reference to source code
63 : * @return newly created initializer list
64 : */
65 2106 : public InitializerList (SourceReference? source_reference = null) {
66 1053 : this.source_reference = source_reference;
67 : }
68 :
69 14817 : public override void accept_children (CodeVisitor visitor) {
70 209283 : foreach (Expression expr in initializers) {
71 97233 : expr.accept (visitor);
72 : }
73 : }
74 :
75 14817 : public override void accept (CodeVisitor visitor) {
76 14817 : visitor.visit_initializer_list (this);
77 :
78 14817 : visitor.visit_expression (this);
79 : }
80 :
81 229 : public override bool is_constant () {
82 2521 : foreach (Expression initializer in initializers) {
83 1147 : if (!initializer.is_constant ()) {
84 1 : return false;
85 : }
86 : }
87 228 : return !(target_type == null || target_type.is_disposable ());
88 : }
89 :
90 0 : public override bool is_pure () {
91 0 : foreach (Expression initializer in initializers) {
92 0 : if (!initializer.is_pure ()) {
93 0 : return false;
94 : }
95 : }
96 0 : return true;
97 : }
98 :
99 217 : public override bool is_accessible (Symbol sym) {
100 2463 : foreach (Expression initializer in initializers) {
101 1123 : if (!initializer.is_accessible (sym)) {
102 0 : return false;
103 : }
104 : }
105 :
106 217 : return true;
107 : }
108 :
109 0 : public override string to_string () {
110 0 : var builder = new StringBuilder ("{");
111 0 : bool first = true;
112 0 : foreach (var initializer in initializers) {
113 0 : if (first) {
114 0 : builder.append (initializer.to_string ());
115 0 : first = false;
116 : } else {
117 0 : builder.append_printf (", %s", initializer.to_string ());
118 : }
119 : }
120 0 : builder.append_c ('}');
121 0 : return builder.str;
122 : }
123 :
124 32 : public override void replace_expression (Expression old_node, Expression new_node) {
125 114 : for (int i = 0; i < initializers.size; i++) {
126 82 : if (initializers[i] == old_node) {
127 32 : initializers[i] = new_node;
128 32 : new_node.parent_node = this;
129 : }
130 : }
131 : }
132 :
133 1611 : public override bool check (CodeContext context) {
134 1611 : if (checked) {
135 1 : return !error;
136 : }
137 :
138 1610 : checked = true;
139 :
140 1610 : if (target_type == null) {
141 0 : error = true;
142 0 : Report.error (source_reference, "initializer list used for unknown type");
143 0 : return false;
144 1610 : } else if (target_type.error) {
145 1 : error = true;
146 1 : return false;
147 2336 : } else if (target_type is ArrayType) {
148 : /* initializer is used as array initializer */
149 1294 : unowned ArrayType array_type = (ArrayType) target_type;
150 :
151 1294 : bool requires_constants_only = false;
152 1294 : bool is_global_constant_inline = false;
153 1294 : unowned CodeNode? node = parent_node;
154 10875 : while (node != null) {
155 9638 : if (node is Constant) {
156 : requires_constants_only = true;
157 : break;
158 9581 : } else if (node is Field && ((Field) node).parent_symbol is Namespace) {
159 2 : is_global_constant_inline = array_type.inline_allocated && is_constant ();
160 : }
161 9581 : node = node.parent_node;
162 : }
163 :
164 1294 : if (!(parent_node is ArrayCreationExpression) && !requires_constants_only && !is_global_constant_inline
165 618 : && (!(parent_node is InitializerList) || ((InitializerList) parent_node).target_type.type_symbol is Struct)) {
166 : // transform shorthand form
167 : // int[] array = { 42 };
168 : // into
169 : // int[] array = new int[] { 42 };
170 :
171 631 : var old_parent_node = parent_node;
172 :
173 567 : var array_creation = new ArrayCreationExpression (array_type.element_type.copy (), array_type.rank, this, source_reference);
174 567 : array_creation.length_type = array_type.length_type.copy ();
175 567 : array_creation.target_type = target_type;
176 567 : array_creation.formal_target_type = formal_target_type;
177 567 : old_parent_node.replace_expression (this, array_creation);
178 :
179 567 : checked = false;
180 567 : return array_creation.check (context);
181 : }
182 :
183 : DataType inner_target_type;
184 727 : if (array_type.rank > 1) {
185 : // allow initialization of multi-dimensional arrays
186 31 : var inner_array_type = (ArrayType) array_type.copy ();
187 31 : inner_array_type.rank--;
188 758 : inner_target_type = inner_array_type;
189 : } else {
190 696 : inner_target_type = array_type.element_type.copy ();
191 : }
192 :
193 4479 : foreach (Expression e in get_initializers ()) {
194 1876 : e.target_type = inner_target_type;
195 : }
196 601 : } else if (target_type.type_symbol is Struct) {
197 : /* initializer is used as struct initializer */
198 313 : unowned Struct st = (Struct) target_type.type_symbol;
199 323 : while (st.base_struct != null) {
200 10 : st = st.base_struct;
201 : }
202 :
203 313 : var in_array_creation_initializer = parent_node is InitializerList && parent_node.parent_node is ArrayCreationExpression;
204 27 : ObjectCreationExpression? struct_creation = null;
205 193 : if (in_array_creation_initializer) {
206 27 : unowned Symbol? sym = st;
207 27 : var ma = new MemberAccess.simple (sym.name, source_reference);
208 27 : ma.symbol_reference = sym;
209 27 : MemberAccess inner = ma;
210 39 : while (sym.parent_symbol != null && sym.parent_symbol != context.root) {
211 6 : sym = sym.parent_symbol;
212 6 : var ma_inner = new MemberAccess.simple (sym.name, source_reference);
213 6 : inner.inner = ma_inner;
214 12 : inner = ma_inner;
215 : }
216 27 : struct_creation = new ObjectCreationExpression (ma, source_reference);
217 27 : struct_creation.target_type = target_type.copy ();
218 27 : struct_creation.struct_creation = true;
219 : }
220 :
221 313 : var field_it = st.get_fields ().iterator ();
222 2525 : foreach (Expression e in get_initializers ()) {
223 1106 : Field field = null;
224 2212 : while (field == null) {
225 1106 : if (!field_it.next ()) {
226 0 : error = true;
227 0 : Report.error (e.source_reference, "too many expressions in initializer list for `%s'", target_type.to_string ());
228 0 : return false;
229 : }
230 1106 : field = field_it.get ();
231 1106 : if (field.binding != MemberBinding.INSTANCE) {
232 : // we only initialize instance fields
233 1106 : field = null;
234 : }
235 : }
236 :
237 1143 : if (in_array_creation_initializer) {
238 37 : var member_init = new MemberInitializer (field.name, e, e.source_reference);
239 37 : struct_creation.add_member_initializer (member_init);
240 : } else {
241 1069 : e.target_type = field.variable_type.copy ();
242 1069 : if (!target_type.value_owned) {
243 896 : e.target_type.value_owned = false;
244 : }
245 : }
246 : }
247 :
248 313 : if (in_array_creation_initializer) {
249 27 : parent_node.replace_expression (this, struct_creation);
250 27 : checked = false;
251 27 : return struct_creation.check (context);
252 : }
253 : } else {
254 2 : error = true;
255 2 : Report.error (source_reference, "initializer list used for `%s', which is neither array nor struct", target_type.to_string ());
256 2 : return false;
257 : }
258 :
259 6903 : foreach (Expression expr in initializers) {
260 2945 : if (!expr.check (context)) {
261 1 : error = true;
262 : }
263 : }
264 :
265 1013 : if (error) {
266 4 : return false;
267 : }
268 :
269 6900 : foreach (Expression e in get_initializers ()) {
270 2944 : if (e.value_type == null) {
271 0 : error = true;
272 0 : Report.error (e.source_reference, "expression type not allowed as initializer");
273 0 : continue;
274 : }
275 :
276 2944 : if (e is NullLiteral && e.target_type != null && e.target_type.is_real_non_null_struct_type ()) {
277 : // Allow using null instead of {} to initialize struct
278 2942 : } else if (!e.value_type.compatible (e.target_type)) {
279 1 : error = true;
280 1 : e.error = true;
281 1 : Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'", e.target_type.to_string (), e.value_type.to_string ());
282 : }
283 : }
284 :
285 1012 : if (!error) {
286 : /* everything seems to be correct */
287 1011 : value_type = target_type.copy ();
288 1011 : value_type.nullable = false;
289 : }
290 :
291 1012 : if (value_type != null) {
292 1011 : value_type.check (context);
293 : }
294 :
295 1012 : return !error;
296 : }
297 :
298 1057 : public override void emit (CodeGenerator codegen) {
299 7233 : foreach (Expression expr in initializers) {
300 3088 : expr.emit (codegen);
301 : }
302 :
303 1057 : codegen.visit_initializer_list (this);
304 :
305 1057 : codegen.visit_expression (this);
306 : }
307 :
308 757 : public override void get_used_variables (Collection<Variable> collection) {
309 4247 : foreach (Expression expr in initializers) {
310 1745 : expr.get_used_variables (collection);
311 : }
312 : }
313 : }
|