Fix gtk_text_iter_forward_find_char binding, patch by Nicolas Joseph,
[vala-lang.git] / vala / valaelementaccess.vala
blobc5cb02b189f65f84a70dc5926d200ff58071c86a
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
19 * Author:
20 * Raffaele Sandrini <raffaele@sandrini.ch>
21 * Jürg Billeter <j@bitron.ch>
24 using GLib;
25 using Gee;
27 /**
28 * Represents an array access expression e.g. "a[1,2]".
30 public class Vala.ElementAccess : Expression {
31 /**
32 * Expression representing the container on wich we want to access.
34 public Expression container {
35 get {
36 return _container;
38 set {
39 _container = value;
40 _container.parent_node = this;
44 /**
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) {
52 indices.add (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) {
74 e.accept (visitor);
78 public override void replace_expression (Expression old_node, Expression new_node) {
79 if (container == old_node) {
80 container = new_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 ()) {
93 return false;
96 return container.is_pure ();
99 public override bool check (SemanticAnalyzer analyzer) {
100 if (checked) {
101 return !error;
104 checked = true;
106 container.check (analyzer);
108 if (container.value_type == null) {
109 /* don't proceed if a child expression failed */
110 error = true;
111 return false;
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) {
119 error = true;
120 Report.error (source_reference, "Element access with more than one dimension is not supported for signals");
121 return false;
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 ();
138 if (!lvalue) {
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) {
145 error = true;
146 Report.error (source_reference, "Element access with more than one dimension is not supported for strings");
147 return false;
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) {
155 error = true;
156 Report.error (source_reference, "Element access with more than one dimension is not supported for the specified type");
157 return false;
159 Iterator<Expression> indices_it = indices.iterator ();
160 indices_it.next ();
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)) {
183 error = true;
184 Report.error (source_reference, "index expression: Cannot convert from `%s' to `%s'".printf (index.value_type.to_string (), index_type.to_string ()));
185 return false;
188 value_type = analyzer.get_actual_type (container.value_type, (GenericType) get_method.return_type, this).copy ();
189 if (lvalue) {
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;
198 } else {
199 error = true;
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) {
208 return false;
211 /* check if the index is of type integer */
212 if (!e.value_type.compatible (analyzer.uint64_type)) {
213 error = true;
214 Report.error (e.source_reference, "Expression of integer type expected");
219 return !error;
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);