Sync NEWS from 0.40
[vala-gnome.git] / vala / valainitializerlist.vala
blob8a601874e2365c5ec633f9e060ba2288b5812d57
1 /* valainitializerlist.vala
3 * Copyright (C) 2006-2011 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
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.
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.
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 /**
28 * Represents an array or struct initializer list in the source code.
30 public class Vala.InitializerList : Expression {
31 private List<Expression> initializers = new ArrayList<Expression> ();
33 /**
34 * Appends the specified expression to this initializer
36 * @param expr an expression
38 public void append (Expression expr) {
39 initializers.add (expr);
40 expr.parent_node = this;
43 /**
44 * Returns a copy of the expression
46 * @return expression list
48 public List<Expression> get_initializers () {
49 return initializers;
52 /**
53 * Returns the initializer count in this initializer
55 public int size {
56 get { return initializers.size; }
59 /**
60 * Creates a new initializer
62 * @param source_reference reference to source code
63 * @return newly created initializer list
65 public InitializerList (SourceReference source_reference) {
66 this.source_reference = source_reference;
69 public override void accept_children (CodeVisitor visitor) {
70 foreach (Expression expr in initializers) {
71 expr.accept (visitor);
75 public override void accept (CodeVisitor visitor) {
76 visitor.visit_initializer_list (this);
78 visitor.visit_expression (this);
81 public override bool is_constant () {
82 foreach (Expression initializer in initializers) {
83 if (!initializer.is_constant ()) {
84 return false;
87 return true;
90 public override bool is_pure () {
91 foreach (Expression initializer in initializers) {
92 if (!initializer.is_pure ()) {
93 return false;
96 return true;
99 public override bool is_accessible (Symbol sym) {
100 foreach (Expression initializer in initializers) {
101 if (!initializer.is_accessible (sym)) {
102 return false;
106 return true;
109 public override void replace_expression (Expression old_node, Expression new_node) {
110 for (int i = 0; i < initializers.size; i++) {
111 if (initializers[i] == old_node) {
112 initializers[i] = new_node;
117 public override bool check (CodeContext context) {
118 if (checked) {
119 return !error;
122 checked = true;
124 if (target_type == null) {
125 error = true;
126 Report.error (source_reference, "initializer list used for unknown type");
127 return false;
128 } else if (target_type is ArrayType) {
129 /* initializer is used as array initializer */
130 var array_type = (ArrayType) target_type;
132 bool requires_constants_only = false;
133 unowned CodeNode? node = parent_node;
134 while (node != null) {
135 if (node is Constant) {
136 requires_constants_only = true;
137 break;
139 node = node.parent_node;
142 if (!(parent_node is ArrayCreationExpression) && !requires_constants_only
143 && (!(parent_node is InitializerList) || ((InitializerList) parent_node).target_type.data_type is Struct)) {
144 // transform shorthand form
145 // int[] array = { 42 };
146 // into
147 // int[] array = new int[] { 42 };
149 var old_parent_node = parent_node;
151 var array_creation = new ArrayCreationExpression (array_type.element_type.copy (), array_type.rank, this, source_reference);
152 array_creation.target_type = target_type;
153 old_parent_node.replace_expression (this, array_creation);
155 checked = false;
156 return array_creation.check (context);
159 DataType inner_target_type;
160 if (array_type.rank > 1) {
161 // allow initialization of multi-dimensional arrays
162 var inner_array_type = (ArrayType) array_type.copy ();
163 inner_array_type.rank--;
164 inner_target_type = inner_array_type;
165 } else {
166 inner_target_type = array_type.element_type.copy ();
169 foreach (Expression e in get_initializers ()) {
170 e.target_type = inner_target_type;
172 } else if (target_type.data_type is Struct) {
173 /* initializer is used as struct initializer */
174 var st = (Struct) target_type.data_type;
175 while (st.base_struct != null) {
176 st = st.base_struct;
179 var field_it = st.get_fields ().iterator ();
180 foreach (Expression e in get_initializers ()) {
181 Field field = null;
182 while (field == null) {
183 if (!field_it.next ()) {
184 error = true;
185 Report.error (e.source_reference, "too many expressions in initializer list for `%s'".printf (target_type.to_string ()));
186 return false;
188 field = field_it.get ();
189 if (field.binding != MemberBinding.INSTANCE) {
190 // we only initialize instance fields
191 field = null;
195 e.target_type = field.variable_type.copy ();
196 if (!target_type.value_owned) {
197 e.target_type.value_owned = false;
200 } else {
201 error = true;
202 Report.error (source_reference, "initializer list used for `%s', which is neither array nor struct".printf (target_type.to_string ()));
203 return false;
206 foreach (Expression expr in initializers) {
207 expr.check (context);
210 bool error = false;
211 foreach (Expression e in get_initializers ()) {
212 if (e.value_type == null) {
213 error = true;
214 Report.error (e.source_reference, "expression type not allowed as initializer");
215 continue;
218 var unary = e as UnaryExpression;
219 if (unary != null && (unary.operator == UnaryOperator.REF || unary.operator == UnaryOperator.OUT)) {
220 // TODO check type for ref and out expressions
221 } else if (!e.value_type.compatible (e.target_type)) {
222 error = true;
223 e.error = true;
224 Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (e.target_type.to_string (), e.value_type.to_string ()));
228 if (!error) {
229 /* everything seems to be correct */
230 value_type = target_type.copy ();
231 value_type.nullable = false;
234 return !error;
237 public override void emit (CodeGenerator codegen) {
238 foreach (Expression expr in initializers) {
239 expr.emit (codegen);
242 codegen.visit_initializer_list (this);
244 codegen.visit_expression (this);
247 public override void get_used_variables (Collection<Variable> collection) {
248 foreach (Expression expr in initializers) {
249 expr.get_used_variables (collection);