codegen: Use temporary variable for string concatenation
[vala-lang.git] / vala / valaelementaccess.vala
blobd8c769997f6f64e7d81925428a38a6c3bb95517a
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
20 * Author:
21 * Raffaele Sandrini <raffaele@sandrini.ch>
22 * Jürg Billeter <j@bitron.ch>
25 using GLib;
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 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 List<Expression> get_indices () {
57 return 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 (CodeContext context) {
100 if (checked) {
101 return !error;
104 checked = true;
106 if (!container.check (context)) {
107 /* don't proceed if a child expression failed */
108 error = true;
109 return false;
112 if (container.value_type == null) {
113 error = true;
114 Report.error (container.source_reference, "Invalid container expression");
115 return false;
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) {
123 error = true;
124 Report.error (source_reference, "Element access with more than one dimension is not supported for signals");
125 return false;
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 ();
142 if (!lvalue) {
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) {
149 error = true;
150 Report.error (source_reference, "Element access with more than one dimension is not supported for tuples");
151 return false;
153 var index = get_indices ().get (0) as IntegerLiteral;
154 if (index == null) {
155 error = true;
156 Report.error (source_reference, "Element access with non-literal index is not supported for tuples");
157 return false;
159 int i = int.parse (index.value);
160 if (container.value_type.get_type_arguments ().size == 0) {
161 error = true;
162 Report.error (source_reference, "Element access is not supported for untyped tuples");
163 return false;
165 if (i < 0 || i >= container.value_type.get_type_arguments ().size) {
166 error = true;
167 Report.error (source_reference, "Index out of range");
168 return false;
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", source_reference);
175 ma.add_type_argument (value_type);
176 var get_call = new MethodCall (ma, source_reference);
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;
186 } else {
187 if (lvalue) {
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) {
191 return !error;
193 } else {
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", source_reference), source_reference);
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);
207 error = true;
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) {
216 return false;
219 /* check if the index is of type integer */
220 if (!(e.value_type is IntegerType || e.value_type is EnumValueType)) {
221 error = true;
222 Report.error (e.source_reference, "Expression of integer type expected");
227 return !error;
230 public override void emit (CodeGenerator codegen) {
231 container.emit (codegen);
232 foreach (Expression e in indices) {
233 e.emit (codegen);
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);