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