1 /* valaelementaccess.vala
3 * Copyright (C) 2006-2008 Raffaele Sandrini, Jürg Billeter
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.
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.
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
20 * Raffaele Sandrini <raffaele@sandrini.ch>
21 * 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 Gee
.List
<Expression
> indices
= new ArrayList
<Expression
> ();
49 Expression _container
;
51 public void append_index (Expression index
) {
53 index
.parent_node
= this
;
56 public Gee
.List
<Expression
> get_indices () {
57 return new ReadOnlyList
<Expression
> (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 (SemanticAnalyzer analyzer
) {
106 container
.check (analyzer
);
108 if (container
.value_type
== null) {
109 /* don't proceed if a child expression failed */
114 var container_type
= container
.value_type
.data_type
;
116 if (container is MemberAccess
&& container
.symbol_reference is Signal
) {
117 // signal detail access
118 if (get_indices ().size
!= 1) {
120 Report
.error (source_reference
, "Element access with more than one dimension is not supported for signals");
123 get_indices ().get (0).target_type
= analyzer
.string_type
.copy ();
126 foreach (Expression index
in get_indices ()) {
127 index
.check (analyzer
);
130 bool index_int_type_check
= true;
132 var pointer_type
= container
.value_type as PointerType
;
134 /* assign a value_type when possible */
135 if (container
.value_type is ArrayType
) {
136 var array_type
= (ArrayType
) container
.value_type
;
137 value_type
= array_type
.element_type
.copy ();
139 value_type
.value_owned
= false;
141 } else if (pointer_type
!= null && !pointer_type
.base_type
.is_reference_type_or_type_parameter ()) {
142 value_type
= pointer_type
.base_type
.copy ();
143 } else if (container_type
== analyzer
.string_type
.data_type
) {
144 if (get_indices ().size
!= 1) {
146 Report
.error (source_reference
, "Element access with more than one dimension is not supported for strings");
150 value_type
= analyzer
.unichar_type
;
151 } else if (container_type
!= null && analyzer
.list_type
!= null && analyzer
.map_type
!= null &&
152 (container_type
.is_subtype_of (analyzer
.list_type
) || container_type
.is_subtype_of (analyzer
.map_type
))) {
153 Gee
.List
<Expression
> indices
= get_indices ();
154 if (indices
.size
!= 1) {
156 Report
.error (source_reference
, "Element access with more than one dimension is not supported for the specified type");
159 Iterator
<Expression
> indices_it
= indices
.iterator ();
161 var index
= indices_it
.get ();
162 index_int_type_check
= false;
164 // lookup symbol in interface instead of class as implemented interface methods are not in VAPI files
165 Symbol get_sym
= null;
166 if (container_type
.is_subtype_of (analyzer
.list_type
)) {
167 get_sym
= analyzer
.list_type
.scope
.lookup ("get");
168 } else if (container_type
.is_subtype_of (analyzer
.map_type
)) {
169 get_sym
= analyzer
.map_type
.scope
.lookup ("get");
171 var get_method
= (Method
) get_sym
;
172 Gee
.List
<FormalParameter
> get_params
= get_method
.get_parameters ();
173 Iterator
<FormalParameter
> get_params_it
= get_params
.iterator ();
174 get_params_it
.next ();
175 var get_param
= get_params_it
.get ();
177 var index_type
= get_param
.parameter_type
;
178 if (index_type is GenericType
) {
179 index_type
= analyzer
.get_actual_type (container
.value_type
, (GenericType
) index_type
, this
);
182 if (!index
.value_type
.compatible (index_type
)) {
184 Report
.error (source_reference
, "index expression: Cannot convert from `%s' to `%s'".printf (index
.value_type
.to_string (), index_type
.to_string ()));
188 value_type
= analyzer
.get_actual_type (container
.value_type
, (GenericType
) get_method
.return_type
, this
).copy ();
190 // get () returns owned value, set () accepts unowned value
191 value_type
.value_owned
= false;
193 } else if (container is MemberAccess
&& container
.symbol_reference is Signal
) {
194 index_int_type_check
= false;
196 symbol_reference
= container
.symbol_reference
;
197 value_type
= container
.value_type
;
200 Report
.error (source_reference
, "The expression `%s' does not denote an Array".printf (container
.value_type
.to_string ()));
203 if (index_int_type_check
) {
204 /* check if the index is of type integer */
205 foreach (Expression e
in get_indices ()) {
206 /* don't proceed if a child expression failed */
207 if (e
.value_type
== null) {
211 /* check if the index is of type integer */
212 if (!e
.value_type
.compatible (analyzer
.uint64_type
)) {
214 Report
.error (e
.source_reference
, "Expression of integer type expected");
222 public override void get_defined_variables (Collection
<LocalVariable
> collection
) {
223 container
.get_defined_variables (collection
);
224 foreach (Expression index
in indices
) {
225 index
.get_defined_variables (collection
);
229 public override void get_used_variables (Collection
<LocalVariable
> collection
) {
230 container
.get_used_variables (collection
);
231 foreach (Expression index
in indices
) {
232 index
.get_used_variables (collection
);