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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
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
> ();
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
;
44 * Returns a copy of the expression
46 * @return expression list
48 public List
<Expression
> get_initializers () {
53 * Returns the initializer count in this initializer
56 get { return initializers
.size
; }
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 ()) {
90 public override bool is_pure () {
91 foreach (Expression initializer
in initializers
) {
92 if (!initializer
.is_pure ()) {
99 public override bool is_accessible (Symbol sym
) {
100 foreach (Expression initializer
in initializers
) {
101 if (!initializer
.is_accessible (sym
)) {
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
) {
124 if (target_type
== null) {
126 Report
.error (source_reference
, "initializer list used for unknown type");
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;
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 };
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
);
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
;
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) {
179 var field_it
= st
.get_fields ().iterator ();
180 foreach (Expression e
in get_initializers ()) {
182 while (field
== null) {
183 if (!field_it
.next ()) {
185 Report
.error (e
.source_reference
, "too many expressions in initializer list for `%s'".printf (target_type
.to_string ()));
188 field
= field_it
.get ();
189 if (field
.binding
!= MemberBinding
.INSTANCE
) {
190 // we only initialize instance fields
195 e
.target_type
= field
.variable_type
.copy ();
196 if (!target_type
.value_owned
) {
197 e
.target_type
.value_owned
= false;
202 Report
.error (source_reference
, "initializer list used for `%s', which is neither array nor struct".printf (target_type
.to_string ()));
206 foreach (Expression expr
in initializers
) {
207 expr
.check (context
);
211 foreach (Expression e
in get_initializers ()) {
212 if (e
.value_type
== null) {
214 Report
.error (e
.source_reference
, "expression type not allowed as initializer");
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
)) {
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 ()));
229 /* everything seems to be correct */
230 value_type
= target_type
.copy ();
231 value_type
.nullable
= false;
237 public override void emit (CodeGenerator codegen
) {
238 foreach (Expression expr
in initializers
) {
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
);