Line data Source code
1 : /* valasliceexpression.vala
2 : *
3 : * Copyright (C) 2009 Robin Sonefors
4 : * Copyright (C) 2009-2013 Jürg Billeter
5 : *
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.
10 :
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.
15 :
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
19 : *
20 : * Author:
21 : * Robin Sonefors <ozamosi@flukkost.nu>
22 : * Jürg Billeter <j@bitron.ch>
23 : */
24 :
25 : using GLib;
26 :
27 : /**
28 : * Represents an array slice expression.
29 : *
30 : * {{{ foo[1:5] }}}
31 : */
32 51 : public class Vala.SliceExpression : Expression {
33 : public Expression container {
34 568 : get {
35 568 : return _container;
36 : }
37 40 : private set {
38 120 : _container = value;
39 40 : _container.parent_node = this;
40 : }
41 : }
42 :
43 : public Expression start {
44 399 : get {
45 399 : return _start;
46 : }
47 40 : private set {
48 80 : _start = value;
49 40 : _start.parent_node = this;
50 : }
51 : }
52 :
53 : public Expression stop {
54 399 : get {
55 399 : return _stop;
56 : }
57 40 : private set {
58 80 : _stop = value;
59 40 : _stop.parent_node = this;
60 : }
61 : }
62 :
63 : /**
64 : * Null-safe access.
65 : */
66 40 : public bool null_safe_access { get; set; }
67 :
68 40 : Expression _container;
69 40 : Expression _start;
70 40 : Expression _stop;
71 :
72 120 : public SliceExpression (Expression container, Expression start, Expression stop, SourceReference? source_reference = null) {
73 40 : this.container = container;
74 40 : this.start = start;
75 40 : this.stop = stop;
76 40 : this.source_reference = source_reference;
77 : }
78 :
79 136 : public override void accept (CodeVisitor visitor) {
80 136 : visitor.visit_slice_expression (this);
81 :
82 136 : visitor.visit_expression (this);
83 : }
84 :
85 136 : public override void accept_children (CodeVisitor visitor) {
86 136 : container.accept (visitor);
87 :
88 136 : start.accept (visitor);
89 136 : stop.accept (visitor);
90 : }
91 :
92 0 : public override void replace_expression (Expression old_node, Expression new_node) {
93 0 : if (container == old_node) {
94 0 : container = new_node;
95 : }
96 0 : if (start == old_node) {
97 0 : start = new_node;
98 : }
99 0 : if (stop == old_node) {
100 0 : stop = new_node;
101 : }
102 : }
103 :
104 0 : public override bool is_pure () {
105 0 : return false;
106 : }
107 :
108 0 : public override bool is_accessible (Symbol sym) {
109 0 : return container.is_accessible (sym) && start.is_accessible (sym) && stop.is_accessible (sym);
110 : }
111 :
112 42 : public override bool check (CodeContext context) {
113 42 : if (checked) {
114 2 : return !error;
115 : }
116 :
117 40 : checked = true;
118 :
119 40 : if (null_safe_access) {
120 2 : error = !base.check (context);
121 2 : return !error;
122 : }
123 :
124 38 : if (!container.check (context)) {
125 0 : error = true;
126 0 : return false;
127 : }
128 :
129 38 : if (container.value_type is ArrayType) {
130 28 : unowned ArrayType array_type = (ArrayType) container.value_type;
131 28 : start.target_type = array_type.length_type.copy ();
132 28 : stop.target_type = array_type.length_type.copy ();
133 : }
134 :
135 38 : if (!start.check (context)) {
136 0 : error = true;
137 0 : return false;
138 : }
139 :
140 38 : if (!stop.check (context)) {
141 0 : error = true;
142 0 : return false;
143 : }
144 :
145 38 : if (container.value_type == null) {
146 0 : error = true;
147 0 : Report.error (container.source_reference, "Invalid container expression");
148 0 : return false;
149 : }
150 :
151 38 : if (lvalue) {
152 0 : error = true;
153 0 : Report.error (container.source_reference, "Slice expressions cannot be used as lvalue");
154 0 : return false;
155 : }
156 :
157 38 : if (container.value_type is ArrayType) {
158 28 : value_type = container.value_type.copy ();
159 28 : value_type.value_owned = false;
160 :
161 : // inline allocated results are not compatible with non-constant start/stop expressions
162 28 : unowned ArrayType array_type = (ArrayType) value_type;
163 28 : array_type.fixed_length = false;
164 28 : array_type.inline_allocated = false;
165 28 : array_type.length = null;
166 :
167 28 : value_type.check (context);
168 :
169 : /* check if the index is of type integer */
170 28 : if (!(start.value_type is IntegerType || start.value_type is EnumValueType)) {
171 1 : error = true;
172 1 : Report.error (start.source_reference, "Expression of integer type expected");
173 : }
174 28 : if (!(stop.value_type is IntegerType || stop.value_type is EnumValueType)) {
175 1 : error = true;
176 1 : Report.error (stop.source_reference, "Expression of integer type expected");
177 : }
178 : } else {
179 10 : var slice_method = container.value_type.get_member ("slice") as Method;
180 9 : if (slice_method != null) {
181 9 : var slice_call = new MethodCall (new MemberAccess (container, "slice", source_reference), source_reference);
182 9 : slice_call.add_argument (start);
183 9 : slice_call.add_argument (stop);
184 9 : slice_call.target_type = this.target_type;
185 9 : parent_node.replace_expression (this, slice_call);
186 9 : return slice_call.check (context);
187 : }
188 :
189 1 : error = true;
190 1 : Report.error (source_reference, "The expression `%s' does not denote an array", container.value_type.to_string ());
191 : }
192 :
193 29 : return !error;
194 : }
195 :
196 26 : public override void emit (CodeGenerator codegen) {
197 26 : container.emit (codegen);
198 :
199 26 : start.emit (codegen);
200 26 : stop.emit (codegen);
201 :
202 26 : codegen.visit_slice_expression (this);
203 :
204 26 : codegen.visit_expression (this);
205 : }
206 :
207 78 : public override void get_defined_variables (Collection<Variable> collection) {
208 78 : container.get_defined_variables (collection);
209 78 : start.get_defined_variables (collection);
210 78 : stop.get_defined_variables (collection);
211 : }
212 :
213 26 : public override void get_used_variables (Collection<Variable> collection) {
214 26 : container.get_used_variables (collection);
215 26 : start.get_used_variables (collection);
216 26 : stop.get_used_variables (collection);
217 : }
218 : }
|