Sync with 5.4.0
[deliverable/titan.core.git] / compiler2 / ttcn3 / ArrayDimensions.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "ArrayDimensions.hh"
9 #include "../string.hh"
10 #include "../CompilerError.hh"
11 #include "../Type.hh"
12 #include "../Value.hh"
13 #include "AST_ttcn3.hh"
14
15 #include <limits.h>
16
17 namespace Ttcn {
18
19 using namespace Common;
20
21 // =================================
22 // ===== ArrayDimension
23 // =================================
24
25 ArrayDimension::ArrayDimension(const ArrayDimension& p)
26 : Node(p), Location(p), checked(false), is_range(p.is_range),
27 has_error(false), size(0), offset(0)
28 {
29 if (is_range) {
30 u.range.lower = p.u.range.lower->clone();
31 u.range.upper = p.u.range.upper->clone();
32 } else {
33 u.single = p.u.single->clone();
34 }
35 }
36
37 ArrayDimension::ArrayDimension(Value *p_single)
38 : Node(), checked(false), is_range(false), has_error(false),
39 size(0), offset(0)
40 {
41 if (!p_single) FATAL_ERROR("ArrayDimension::ArrayDimension()");
42 u.single = p_single;
43 }
44
45 ArrayDimension::ArrayDimension(Value *p_lower, Value *p_upper)
46 : Node(), checked(false), is_range(true), has_error(false),
47 size(0), offset(0)
48 {
49 if (!p_lower || !p_upper) FATAL_ERROR("ArrayDimension::ArrayDimension()");
50 u.range.lower = p_lower;
51 u.range.upper = p_upper;
52 }
53
54 ArrayDimension::~ArrayDimension()
55 {
56 if (is_range) {
57 delete u.range.lower;
58 delete u.range.upper;
59 } else {
60 delete u.single;
61 }
62 }
63
64 ArrayDimension *ArrayDimension::clone() const
65 {
66 return new ArrayDimension(*this);
67 }
68
69 void ArrayDimension::set_my_scope(Scope *p_scope)
70 {
71 if (!p_scope) FATAL_ERROR("ArrayDimension::set_my_scope()");
72 my_scope = p_scope;
73 if (is_range) {
74 u.range.lower->set_my_scope(p_scope);
75 u.range.upper->set_my_scope(p_scope);
76 } else {
77 u.single->set_my_scope(p_scope);
78 }
79 }
80
81 void ArrayDimension::set_fullname(const string& p_fullname)
82 {
83 Node::set_fullname(p_fullname);
84 if (is_range) {
85 u.range.lower->set_fullname(p_fullname + ".<lower>");
86 u.range.upper->set_fullname(p_fullname + ".<upper>");
87 } else {
88 u.single->set_fullname(p_fullname);
89 }
90 }
91
92 void ArrayDimension::chk()
93 {
94 if (checked) return;
95 checked = true;
96 Int int_size = 0;
97 has_error = false;
98 if (is_range) {
99 {
100 Error_Context cntxt(u.range.lower, "In lower bound of array indices");
101 u.range.lower->chk_expr_int(Type::EXPECTED_CONSTANT);
102 }
103 {
104 Error_Context cntxt(u.range.upper, "In upper bound of array indices");
105 u.range.upper->chk_expr_int(Type::EXPECTED_CONSTANT);
106 }
107 Value *v_lower = u.range.lower->get_value_refd_last();
108 if (v_lower->get_valuetype() != Value::V_INT) has_error = true;
109 Value *v_upper = u.range.upper->get_value_refd_last();
110 if (v_upper->get_valuetype() != Value::V_INT) has_error = true;
111 if (!has_error) {
112 const int_val_t *lower_int = v_lower->get_val_Int();
113 const int_val_t *upper_int = v_upper->get_val_Int();
114 if (*lower_int > INT_MAX) {
115 u.range.lower->error("The lower bound of an array index should be "
116 "less than `%d' instead of `%s'", INT_MAX,
117 (lower_int->t_str()).c_str());
118 has_error = true;
119 }
120 if (*upper_int > INT_MAX) {
121 u.range.upper->error("The upper bound of an array index should be "
122 "less than `%d' instead of `%s'", INT_MAX,
123 (upper_int->t_str()).c_str());
124 has_error = true;
125 }
126 if (!has_error) {
127 Int lower = lower_int->get_val();
128 Int upper = upper_int->get_val();
129 if (lower > upper) {
130 error("The lower bound of array index (%s) is "
131 "greater than the upper bound (%s)", Int2string(lower).c_str(),
132 Int2string(upper).c_str());
133 has_error = true;
134 } else {
135 int_size = upper - lower + 1;
136 offset = lower;
137 }
138 }
139 }
140 } else {
141 {
142 Error_Context cntxt(u.single, "In array size");
143 u.single->chk_expr_int(Type::EXPECTED_CONSTANT);
144 }
145 Value *v = u.single->get_value_refd_last();
146 if (v->get_valuetype() != Value::V_INT) has_error = true;
147 if (!has_error) {
148 const int_val_t *int_size_int = v->get_val_Int();
149 if (*int_size_int > INT_MAX) {
150 u.single->error("The array size should be less than `%d' instead "
151 "of `%s'", INT_MAX, (int_size_int->t_str()).c_str());
152 has_error = true;
153 }
154 if (!has_error) {
155 int_size = int_size_int->get_val();
156 if (int_size <= 0) {
157 u.single->error("A positive integer value was expected as array "
158 "size instead of `%s'", Int2string(int_size).c_str());
159 has_error = true;
160 } else {
161 size = int_size;
162 offset = 0;
163 }
164 }
165 }
166 }
167 if (!has_error) {
168 size = static_cast<size_t>(int_size);
169 if (static_cast<Int>(size) != int_size) {
170 error("Array size `%s' is too large for being represented in memory",
171 Int2string(int_size).c_str());
172 has_error = true;
173 }
174 }
175 }
176
177 void ArrayDimension::chk_index(Value *index, Type::expected_value_t exp_val)
178 {
179 if (!checked) chk();
180 index->chk_expr_int(exp_val);
181 if (has_error || index->is_unfoldable()) return;
182 const int_val_t *v_index_int = index->get_value_refd_last()
183 ->get_val_Int();
184 if (*v_index_int < offset) {
185 index->error("Array index underflow: the index value must be at least "
186 "`%s' instead of `%s'", Int2string(offset).c_str(),
187 (v_index_int->t_str()).c_str());
188 index->set_valuetype(Value::V_ERROR);
189 } else if (*v_index_int >= offset + static_cast<Int>(size)) {
190 index->error("Array index overflow: the index value must be at most "
191 "`%s' instead of `%s'", Int2string(offset + size - 1).c_str(),
192 (v_index_int->t_str()).c_str());
193 index->set_valuetype(Value::V_ERROR);
194 }
195 }
196
197 size_t ArrayDimension::get_size()
198 {
199 if (!checked) chk();
200 if (has_error) return 0;
201 else return size;
202 }
203
204 Int ArrayDimension::get_offset()
205 {
206 if (!checked) chk();
207 if (has_error) return 0;
208 else return offset;
209 }
210
211 string ArrayDimension::get_stringRepr()
212 {
213 if (!checked) chk();
214 string ret_val("[");
215 if (has_error) ret_val += "<erroneous>";
216 else if (is_range) {
217 ret_val += Int2string(offset);
218 ret_val += "..";
219 ret_val += Int2string(offset + size - 1);
220 } else ret_val += Int2string(size);
221 ret_val += "]";
222 return ret_val;
223 }
224
225 bool ArrayDimension::is_identical(ArrayDimension *p_dim)
226 {
227 if (!p_dim) FATAL_ERROR("ArrayDimension::is_identical()");
228 if (!checked) chk();
229 if (!p_dim->checked) p_dim->chk();
230 if (has_error || p_dim->has_error) return true;
231 else return size == p_dim->size && offset == p_dim->offset;
232 }
233
234 string ArrayDimension::get_value_type(Type *p_element_type, Scope *p_scope)
235 {
236 if (!checked) chk();
237 if (has_error) FATAL_ERROR("ArrayDimension::get_value_type()");
238 string ret_val("VALUE_ARRAY<");
239 ret_val += p_element_type->get_genname_value(p_scope);
240 ret_val += ", ";
241 ret_val += Int2string(size);
242 ret_val += ", ";
243 ret_val += Int2string(offset);
244 ret_val += '>';
245 return ret_val;
246 }
247
248 string ArrayDimension::get_template_type(Type *p_element_type, Scope *p_scope)
249 {
250 if (!checked) chk();
251 if (has_error) FATAL_ERROR("ArrayDimension::get_template_type()");
252 string ret_val("TEMPLATE_ARRAY<");
253 ret_val += p_element_type->get_genname_value(p_scope);
254 ret_val += ", ";
255 ret_val += p_element_type->get_genname_template(p_scope);
256 ret_val += ", ";
257 ret_val += Int2string(size);
258 ret_val += ", ";
259 ret_val += Int2string(offset);
260 ret_val += '>';
261 return ret_val;
262 }
263
264 void ArrayDimension::dump(unsigned level) const
265 {
266 DEBUG(level, "Array dimension:");
267 if (is_range) {
268 u.range.lower->dump(level + 1);
269 DEBUG(level, "..");
270 u.range.upper->dump(level + 1);
271 } else {
272 u.single->dump(level + 1);
273 }
274 }
275
276 // =================================
277 // ===== ArrayDimensions
278 // =================================
279
280 ArrayDimensions::~ArrayDimensions()
281 {
282 for (size_t i = 0; i < dims.size(); i++) delete dims[i];
283 dims.clear();
284 }
285
286 ArrayDimensions *ArrayDimensions::clone() const
287 {
288 FATAL_ERROR("ArrayDimensions::clone");
289 }
290
291 void ArrayDimensions::set_my_scope(Scope *p_scope)
292 {
293 for (size_t i = 0; i < dims.size(); i++) dims[i]->set_my_scope(p_scope);
294 }
295
296 void ArrayDimensions::set_fullname(const string& p_fullname)
297 {
298 Node::set_fullname(p_fullname);
299 for (size_t i = 0; i < dims.size(); i++)
300 dims[i]->set_fullname(p_fullname + "." + Int2string(i + 1));
301 }
302
303 void ArrayDimensions::add(ArrayDimension *dim)
304 {
305 if (!dim) FATAL_ERROR("ArrayDimensions::add()");
306 dims.add(dim);
307 }
308
309 void ArrayDimensions::chk()
310 {
311 for (size_t i = 0; i < dims.size(); i++) {
312 ArrayDimension *dim = dims[i];
313 Error_Context cntxt(dim, "In array dimension #%lu", (unsigned long)(i+1));
314 dim->chk();
315 }
316 }
317
318 void ArrayDimensions::chk_indices(Common::Reference *ref, const char *def_name,
319 bool allow_slicing, Type::expected_value_t exp_val)
320 {
321 FieldOrArrayRefs *subrefs = ref->get_subrefs();
322 if (!subrefs) {
323 if (!allow_slicing)
324 ref->error("Reference to a %s array without array index", def_name);
325 return;
326 }
327 size_t nof_refs = subrefs->get_nof_refs(), nof_dims = dims.size();
328 size_t upper_limit = nof_refs > nof_dims ? nof_dims : nof_refs;
329 for (size_t i = 0; i < upper_limit; i++) {
330 FieldOrArrayRef *subref = subrefs->get_ref(i);
331 if (subref->get_type() != FieldOrArrayRef::ARRAY_REF) {
332 subref->error("Invalid field reference `%s' in a %s array",
333 subref->get_id()->get_dispname().c_str(), def_name);
334 return;
335 }
336 Error_Context cntxt(subref, "In array index #%lu", (unsigned long)(i+1));
337 dims[i]->chk_index(subref->get_val(), exp_val);
338 }
339 if (nof_refs < nof_dims) {
340 if (!allow_slicing) ref->error("Too few indices in a reference to a %s "
341 "array: the array has %lu dimensions, but the reference has only %lu "
342 "array %s", def_name, (unsigned long)nof_dims, (unsigned long)nof_refs,
343 nof_refs > 1 ? "indices" : "index");
344 } else if (nof_refs > nof_dims) {
345 ref->error("Too many indices in a reference to a %s array: the reference "
346 "has %lu array indices, but the array has only %lu dimension%s",
347 def_name, (unsigned long) nof_refs, (unsigned long) nof_dims,
348 nof_dims > 1 ? "s" : "");
349 }
350 }
351
352 size_t ArrayDimensions::get_array_size()
353 {
354 size_t ret_val = 1;
355 for (size_t i = 0; i < dims.size(); i++)
356 ret_val *= dims[i]->get_size();
357 return ret_val;
358 }
359
360 char *ArrayDimensions::generate_element_names(char *str,
361 const string& p_name, size_t start_dim)
362 {
363 ArrayDimension *dim = dims[start_dim];
364 size_t dim_size = dim->get_size();
365 Int dim_offset = dim->get_offset();
366 if (start_dim + 1 < dims.size()) {
367 // there are more dimensions to generate
368 for (size_t i = 0; i < dim_size; i++) {
369 if (i > 0) str = mputstr(str, ", ");
370 str = generate_element_names(str,
371 p_name + "[" + Int2string(dim_offset + i) + "]", start_dim + 1);
372 }
373 } else {
374 // we are in the last dimension
375 for (size_t i = 0; i < dim_size; i++) {
376 if (i > 0) str = mputstr(str, ", ");
377 str = mputprintf(str, "\"%s[%s]\"", p_name.c_str(),
378 Int2string(dim_offset + i).c_str());
379 }
380 }
381 return str;
382 }
383
384 string ArrayDimensions::get_timer_type(size_t start_dim)
385 {
386 string ret_val("TIMER");
387 // the wrapping is started with the rightmost array dimension
388 for (size_t i = dims.size(); i > start_dim; i--) {
389 ArrayDimension *dim = dims[i - 1];
390 ret_val = "TIMER_ARRAY<" + ret_val + ", " + Int2string(dim->get_size()) +
391 ", " + Int2string(dim->get_offset()) + ">";
392 }
393 return ret_val;
394 }
395
396 string ArrayDimensions::get_port_type(const string& p_genname)
397 {
398 string ret_val(p_genname);
399 // the wrapping is started with the rightmost array dimension
400 for (size_t i = dims.size(); i > 0; i--) {
401 ArrayDimension *dim = dims[i - 1];
402 ret_val = "PORT_ARRAY<" + ret_val + ", " + Int2string(dim->get_size()) +
403 ", " + Int2string(dim->get_offset()) + ">";
404 }
405 return ret_val;
406 }
407
408 void ArrayDimensions::dump(unsigned level) const
409 {
410 DEBUG(level, "Array dimensions: (%lu pcs.)", (unsigned long) dims.size());
411 for (size_t i = 0; i < dims.size(); i++) dims[i]->dump(level + 1);
412 }
413
414 bool ArrayDimensions::is_identical(ArrayDimensions *other)
415 {
416 if (!other) FATAL_ERROR("ArrayDimensions::is_identical()");
417 if (dims.size()!=other->dims.size()) return false;
418 for (size_t i = 0; i < dims.size(); i++)
419 if (!dims[i]->is_identical(other->dims[i])) return false;
420 return true;
421 }
422
423 }
This page took 0.055556 seconds and 5 git commands to generate.