1 /* valaelementaccess.vala
3 * Copyright (C) 2006-2010 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 * Raffaele Sandrini <raffaele@sandrini.ch>
22 * Jürg Billeter <j@bitron.ch>
28 * Represents an array access expression e.g. "a[1,2]".
30 public class Vala
.ElementAccess
: Expression
{
32 * Expression representing the container on wich we want to access.
34 public Expression container
{
40 _container
.parent_node
= this
;
45 * Expressions representing the indices we want to access inside the container.
47 private List
<Expression
> indices
= new ArrayList
<Expression
> ();
49 Expression _container
;
51 public void append_index (Expression index
) {
53 index
.parent_node
= this
;
56 public List
<Expression
> get_indices () {
60 public ElementAccess (Expression container
, SourceReference source_reference
) {
61 this
.source_reference
= source_reference
;
62 this
.container
= container
;
65 public override void accept (CodeVisitor visitor
) {
66 visitor
.visit_element_access (this
);
68 visitor
.visit_expression (this
);
71 public override void accept_children (CodeVisitor visitor
) {
72 container
.accept (visitor
);
73 foreach (Expression e
in indices
) {
78 public override void replace_expression (Expression old_node
, Expression new_node
) {
79 if (container
== old_node
) {
83 int index
= indices
.index_of (old_node
);
84 if (index
>= 0 && new_node
.parent_node
== null) {
85 indices
[index
] = new_node
;
86 new_node
.parent_node
= this
;
90 public override bool is_pure () {
91 foreach (Expression index
in indices
) {
92 if (!index
.is_pure ()) {
96 return container
.is_pure ();
99 public override bool check (CodeContext context
) {
106 if (!container
.check (context
)) {
107 /* don't proceed if a child expression failed */
112 if (container
.value_type
== null) {
114 Report
.error (container
.source_reference
, "Invalid container expression");
118 var container_type
= container
.value_type
.data_type
;
120 if (container is MemberAccess
&& container
.symbol_reference is Signal
) {
121 // signal detail access
122 if (get_indices ().size
!= 1) {
124 Report
.error (source_reference
, "Element access with more than one dimension is not supported for signals");
127 get_indices ().get (0).target_type
= context
.analyzer
.string_type
.copy ();
130 foreach (Expression index
in get_indices ()) {
131 index
.check (context
);
134 bool index_int_type_check
= true;
136 var pointer_type
= container
.value_type as PointerType
;
138 /* assign a value_type when possible */
139 if (container
.value_type is ArrayType
) {
140 var array_type
= (ArrayType
) container
.value_type
;
141 value_type
= array_type
.element_type
.copy ();
143 value_type
.value_owned
= false;
145 } else if (pointer_type
!= null && !pointer_type
.base_type
.is_reference_type_or_type_parameter ()) {
146 value_type
= pointer_type
.base_type
.copy ();
147 } else if (context
.profile
== Profile
.DOVA
&& container_type
== context
.analyzer
.tuple_type
.data_type
) {
148 if (get_indices ().size
!= 1) {
150 Report
.error (source_reference
, "Element access with more than one dimension is not supported for tuples");
153 var index
= get_indices ().get (0) as IntegerLiteral
;
156 Report
.error (source_reference
, "Element access with non-literal index is not supported for tuples");
159 int i
= index
.value
.to_int ();
160 if (container
.value_type
.get_type_arguments ().size
== 0) {
162 Report
.error (source_reference
, "Element access is not supported for untyped tuples");
165 if (i
< 0 || i
>= container
.value_type
.get_type_arguments ().size
) {
167 Report
.error (source_reference
, "Index out of range");
171 value_type
= container
.value_type
.get_type_arguments ().get (i
);
173 // replace element access by call to generic get method
174 var ma
= new
MemberAccess (container
, "get");
175 ma
.add_type_argument (value_type
);
176 var get_call
= new
MethodCall (ma
);
177 get_call
.add_argument (index
);
178 get_call
.target_type
= this
.target_type
;
179 parent_node
.replace_expression (this
, get_call
);
180 return get_call
.check (context
);
181 } else if (container is MemberAccess
&& container
.symbol_reference is Signal
) {
182 index_int_type_check
= false;
184 symbol_reference
= container
.symbol_reference
;
185 value_type
= container
.value_type
;
188 var set_method
= container
.value_type
.get_member ("set") as Method
;
189 var assignment
= parent_node as Assignment
;
190 if (set_method
!= null && set_method
.return_type is VoidType
&& assignment
!= null) {
194 var get_method
= container
.value_type
.get_member ("get") as Method
;
195 if (get_method
!= null) {
196 var get_call
= new
MethodCall (new
MemberAccess (container
, "get"));
197 foreach (Expression e
in get_indices ()) {
198 get_call
.add_argument (e
);
200 get_call
.formal_target_type
= this
.formal_target_type
;
201 get_call
.target_type
= this
.target_type
;
202 parent_node
.replace_expression (this
, get_call
);
203 return get_call
.check (context
);
208 Report
.error (source_reference
, "The expression `%s' does not denote an array".printf (container
.value_type
.to_string ()));
211 if (index_int_type_check
) {
212 /* check if the index is of type integer */
213 foreach (Expression e
in get_indices ()) {
214 /* don't proceed if a child expression failed */
215 if (e
.value_type
== null) {
219 /* check if the index is of type integer */
220 if (!(e
.value_type is IntegerType
|| e
.value_type is EnumValueType
)) {
222 Report
.error (e
.source_reference
, "Expression of integer type expected");
230 public override void emit (CodeGenerator codegen
) {
231 container
.emit (codegen
);
232 foreach (Expression e
in indices
) {
236 codegen
.visit_element_access (this
);
238 codegen
.visit_expression (this
);
241 public override void get_defined_variables (Collection
<LocalVariable
> collection
) {
242 container
.get_defined_variables (collection
);
243 foreach (Expression index
in indices
) {
244 index
.get_defined_variables (collection
);
248 public override void get_used_variables (Collection
<LocalVariable
> collection
) {
249 container
.get_used_variables (collection
);
250 foreach (Expression index
in indices
) {
251 index
.get_used_variables (collection
);