| 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 "../../common/dbgnew.hh" |
| 9 | #include "Templatestuff.hh" |
| 10 | #include "../Identifier.hh" |
| 11 | #include "TtcnTemplate.hh" |
| 12 | #include "ArrayDimensions.hh" |
| 13 | |
| 14 | #include <limits.h> |
| 15 | |
| 16 | namespace Ttcn { |
| 17 | |
| 18 | // ================================= |
| 19 | // ===== ValueRange |
| 20 | // ================================= |
| 21 | |
| 22 | ValueRange::~ValueRange() |
| 23 | { |
| 24 | delete min_v; |
| 25 | delete max_v; |
| 26 | } |
| 27 | |
| 28 | ValueRange *ValueRange::clone() const |
| 29 | { |
| 30 | return new ValueRange(*this); |
| 31 | } |
| 32 | |
| 33 | ValueRange::ValueRange(const ValueRange& other) |
| 34 | : Node(other) |
| 35 | , min_v(other.min_v ? other.min_v->clone() : 0) |
| 36 | , max_v(other.max_v ? other.max_v->clone() : 0) |
| 37 | {} |
| 38 | |
| 39 | void ValueRange::set_fullname(const string& p_fullname) |
| 40 | { |
| 41 | Node::set_fullname(p_fullname); |
| 42 | if (min_v) min_v->set_fullname(p_fullname + ".<lower_bound>"); |
| 43 | if (max_v) max_v->set_fullname(p_fullname + ".<upper_bound>"); |
| 44 | } |
| 45 | |
| 46 | void ValueRange::set_my_scope(Scope *p_scope) |
| 47 | { |
| 48 | Node::set_my_scope(p_scope); |
| 49 | if (min_v) min_v->set_my_scope(p_scope); |
| 50 | if (max_v) max_v->set_my_scope(p_scope); |
| 51 | } |
| 52 | |
| 53 | void ValueRange::set_lowerid_to_ref() |
| 54 | { |
| 55 | if (min_v) min_v->set_lowerid_to_ref(); |
| 56 | if (max_v) max_v->set_lowerid_to_ref(); |
| 57 | } |
| 58 | |
| 59 | Type::typetype_t ValueRange::get_expr_returntype( |
| 60 | Type::expected_value_t exp_val) |
| 61 | { |
| 62 | if (min_v) { |
| 63 | Type::typetype_t tt = min_v->get_expr_returntype(exp_val); |
| 64 | if (tt != Type::T_UNDEF) return tt; |
| 65 | } |
| 66 | if (max_v) { |
| 67 | Type::typetype_t tt = max_v->get_expr_returntype(exp_val); |
| 68 | if (tt != Type::T_UNDEF) return tt; |
| 69 | } |
| 70 | return Type::T_UNDEF; |
| 71 | } |
| 72 | |
| 73 | Type *ValueRange::get_expr_governor(Type::expected_value_t exp_val) |
| 74 | { |
| 75 | if (min_v) { |
| 76 | Type *t = min_v->get_expr_governor(exp_val); |
| 77 | if (t) return t; |
| 78 | } |
| 79 | if (max_v) { |
| 80 | Type *t = max_v->get_expr_governor(exp_val); |
| 81 | if (t) return t; |
| 82 | } |
| 83 | return 0; |
| 84 | } |
| 85 | |
| 86 | void ValueRange::set_code_section |
| 87 | (GovernedSimple::code_section_t p_code_section) |
| 88 | { |
| 89 | if (min_v) min_v->set_code_section(p_code_section); |
| 90 | if (max_v) max_v->set_code_section(p_code_section); |
| 91 | } |
| 92 | |
| 93 | char *ValueRange::generate_code_init(char *str, const char *name) |
| 94 | { |
| 95 | expression_struct expr; |
| 96 | Code::init_expr(&expr); |
| 97 | char *init_stmt = mprintf("%s.set_type(VALUE_RANGE);\n", name); |
| 98 | if (min_v) { |
| 99 | min_v->generate_code_expr(&expr); |
| 100 | init_stmt = mputprintf(init_stmt, "%s.set_min(%s);\n", name, expr.expr); |
| 101 | } |
| 102 | if (max_v) { |
| 103 | Code::clean_expr(&expr); |
| 104 | max_v->generate_code_expr(&expr); |
| 105 | init_stmt = mputprintf(init_stmt, "%s.set_max(%s);\n", name, expr.expr); |
| 106 | } |
| 107 | if (expr.preamble || expr.postamble) { |
| 108 | str = mputstr(str, "{\n"); |
| 109 | str = mputstr(str, expr.preamble); |
| 110 | str = mputstr(str, init_stmt); |
| 111 | str = mputstr(str, expr.postamble); |
| 112 | str = mputstr(str, "}\n"); |
| 113 | } else str = mputstr(str, init_stmt); |
| 114 | Code::free_expr(&expr); |
| 115 | Free(init_stmt); |
| 116 | return str; |
| 117 | } |
| 118 | |
| 119 | char *ValueRange::rearrange_init_code(char *str) |
| 120 | { |
| 121 | if (min_v) str = min_v->rearrange_init_code(str); |
| 122 | if (max_v) str = max_v->rearrange_init_code(str); |
| 123 | return str; |
| 124 | } |
| 125 | |
| 126 | void ValueRange::append_stringRepr(string& str) const |
| 127 | { |
| 128 | str += "("; |
| 129 | if (min_v) str += min_v->get_stringRepr(); |
| 130 | else str += "-infinity"; |
| 131 | str += " .. "; |
| 132 | if (max_v) str += max_v->get_stringRepr(); |
| 133 | else str += "infinity"; |
| 134 | str += ")"; |
| 135 | } |
| 136 | |
| 137 | void ValueRange::dump(unsigned level) const |
| 138 | { |
| 139 | DEBUG(level, "("); |
| 140 | if (min_v) min_v->dump(level + 1); |
| 141 | else DEBUG(level + 1, "-infinity"); |
| 142 | DEBUG(level + 1, ".."); |
| 143 | if (max_v) max_v->dump(level + 1); |
| 144 | else DEBUG(level + 1, "infinity"); |
| 145 | DEBUG(level, ")"); |
| 146 | } |
| 147 | |
| 148 | // ================================= |
| 149 | // ===== Templates |
| 150 | // ================================= |
| 151 | |
| 152 | Templates::~Templates() |
| 153 | { |
| 154 | for (size_t i = 0; i < ts.size(); i++) delete ts[i]; |
| 155 | ts.clear(); |
| 156 | } |
| 157 | |
| 158 | Templates::Templates(const Templates& other) |
| 159 | : Node(), ts() |
| 160 | { |
| 161 | for (size_t i = 0, lim = other.ts.size(); i < lim; ++i) { |
| 162 | ts.add(other.ts[i]->clone()); |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | Templates *Templates::clone() const |
| 167 | { |
| 168 | return new Templates(*this); |
| 169 | } |
| 170 | |
| 171 | void Templates::set_my_scope(Scope *p_scope) |
| 172 | { |
| 173 | for (size_t i = 0; i < ts.size(); i++) ts[i]->set_my_scope(p_scope); |
| 174 | } |
| 175 | |
| 176 | void Templates::add_t(Template *p_t) |
| 177 | { |
| 178 | if (!p_t) FATAL_ERROR("NULL pointer:Templates::add_t()"); |
| 179 | ts.add(p_t); |
| 180 | } |
| 181 | |
| 182 | void Templates::add_front_t(Template *p_t) |
| 183 | { |
| 184 | if (!p_t) FATAL_ERROR("NULL pointer:Templates::add_front_t()"); |
| 185 | ts.add_front(p_t); |
| 186 | } |
| 187 | |
| 188 | void Templates::append_stringRepr(string& str) const |
| 189 | { |
| 190 | for (size_t i = 0; i < ts.size(); i++) { |
| 191 | if (i > 0) str += ", "; |
| 192 | str += ts[i]->get_stringRepr(); |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | // ================================= |
| 197 | // ===== IndexedTemplate |
| 198 | // ================================= |
| 199 | |
| 200 | IndexedTemplate::IndexedTemplate(const IndexedTemplate& p) |
| 201 | { |
| 202 | index = p.index->clone(); |
| 203 | temp = p.temp->clone(); |
| 204 | } |
| 205 | |
| 206 | IndexedTemplate::IndexedTemplate(FieldOrArrayRef *p_i, Template *p_t) |
| 207 | { |
| 208 | if (!p_i || !p_t) FATAL_ERROR("IndexedTemplate::IndexedTemplate()"); |
| 209 | index = p_i; |
| 210 | temp = p_t; |
| 211 | } |
| 212 | |
| 213 | IndexedTemplate::~IndexedTemplate() |
| 214 | { |
| 215 | delete index; |
| 216 | delete temp; |
| 217 | } |
| 218 | |
| 219 | IndexedTemplate *IndexedTemplate::clone() const |
| 220 | { |
| 221 | return new IndexedTemplate(*this); |
| 222 | } |
| 223 | |
| 224 | void IndexedTemplate::set_fullname(const string& p_fullname) |
| 225 | { |
| 226 | Node::set_fullname(p_fullname); |
| 227 | temp->set_fullname(p_fullname); |
| 228 | index->set_fullname(p_fullname); |
| 229 | } |
| 230 | |
| 231 | void IndexedTemplate::set_my_scope(Scope *p_scope) |
| 232 | { |
| 233 | Node::set_my_scope(p_scope); |
| 234 | temp->set_my_scope(p_scope); |
| 235 | index->set_my_scope(p_scope); |
| 236 | } |
| 237 | |
| 238 | void IndexedTemplate::set_code_section |
| 239 | (GovernedSimple::code_section_t p_code_section) |
| 240 | { |
| 241 | index->get_val()->set_code_section(p_code_section); |
| 242 | temp->set_code_section(p_code_section); |
| 243 | } |
| 244 | |
| 245 | void IndexedTemplate::dump(unsigned level) const |
| 246 | { |
| 247 | index->dump(level); |
| 248 | temp->dump(level); |
| 249 | } |
| 250 | |
| 251 | // ================================= |
| 252 | // ===== IndexedTemplates |
| 253 | // ================================= |
| 254 | |
| 255 | IndexedTemplates::IndexedTemplates(const IndexedTemplates& p) |
| 256 | : Node(p) |
| 257 | { |
| 258 | for (size_t i = 0; i < p.its_v.size(); i++) { |
| 259 | its_v.add(p.its_v[i]->clone()); |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | IndexedTemplates::~IndexedTemplates() |
| 264 | { |
| 265 | for (size_t i = 0; i < its_v.size(); i++) delete its_v[i]; |
| 266 | its_v.clear(); |
| 267 | } |
| 268 | |
| 269 | IndexedTemplates *IndexedTemplates::clone() const |
| 270 | { |
| 271 | return new IndexedTemplates(*this); |
| 272 | } |
| 273 | |
| 274 | void IndexedTemplates::set_fullname(const string& p_fullname) |
| 275 | { |
| 276 | Node::set_fullname(p_fullname); |
| 277 | for(size_t i = 0; i < its_v.size(); i++) { |
| 278 | IndexedTemplate *it = its_v[i]; |
| 279 | string t_fullname = p_fullname; |
| 280 | (it->get_index()).append_stringRepr(t_fullname); |
| 281 | it->set_fullname(t_fullname); |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | void IndexedTemplates::set_my_scope(Scope *p_scope) |
| 286 | { |
| 287 | Node::set_my_scope(p_scope); |
| 288 | for (size_t i = 0; i < its_v.size(); i++) |
| 289 | its_v[i]->set_my_scope(p_scope); |
| 290 | } |
| 291 | |
| 292 | void IndexedTemplates::add_it(IndexedTemplate *p_it) |
| 293 | { |
| 294 | if (!p_it) FATAL_ERROR("NULL pointer: IndexedTemplates::add_it()"); |
| 295 | its_v.add(p_it); |
| 296 | } |
| 297 | |
| 298 | IndexedTemplate *IndexedTemplates::get_it_byIndex(size_t p_i) |
| 299 | { |
| 300 | return its_v[p_i]; |
| 301 | } |
| 302 | |
| 303 | // ================================= |
| 304 | // ===== NamedTemplate |
| 305 | // ================================= |
| 306 | |
| 307 | NamedTemplate::NamedTemplate(Identifier *p_n, Template *p_t) |
| 308 | { |
| 309 | if (!p_n || !p_t) FATAL_ERROR("NamedTemplate::NamedTemplate()"); |
| 310 | name = p_n; |
| 311 | temp = p_t; |
| 312 | } |
| 313 | |
| 314 | NamedTemplate::NamedTemplate(const NamedTemplate& p) |
| 315 | { |
| 316 | name = p.name->clone(); |
| 317 | temp = p.temp->clone(); |
| 318 | } |
| 319 | |
| 320 | NamedTemplate::~NamedTemplate() |
| 321 | { |
| 322 | delete name; |
| 323 | delete temp; |
| 324 | } |
| 325 | |
| 326 | NamedTemplate *NamedTemplate::clone() const |
| 327 | { |
| 328 | return new NamedTemplate(*this); |
| 329 | } |
| 330 | |
| 331 | void NamedTemplate::set_fullname(const string& p_fullname) |
| 332 | { |
| 333 | Node::set_fullname(p_fullname); |
| 334 | temp->set_fullname(p_fullname); |
| 335 | } |
| 336 | |
| 337 | void NamedTemplate::set_my_scope(Scope *p_scope) |
| 338 | { |
| 339 | Node::set_my_scope(p_scope); |
| 340 | temp->set_my_scope(p_scope); |
| 341 | } |
| 342 | |
| 343 | void NamedTemplate::set_name_to_lowercase() |
| 344 | { |
| 345 | string new_name = name->get_name(); |
| 346 | if (isupper(new_name[0])) { |
| 347 | new_name[0] = tolower(new_name[0]); |
| 348 | if (new_name[new_name.size() - 1] == '_') { |
| 349 | // an underscore is inserted at the end of the alternative name if it's |
| 350 | // a basic type's name (since it would conflict with the class generated |
| 351 | // for that type) |
| 352 | // remove the underscore, it won't conflict with anything if its name |
| 353 | // starts with a lowercase letter |
| 354 | new_name.replace(new_name.size() - 1, 1, ""); |
| 355 | } |
| 356 | delete name; |
| 357 | name = new Identifier(Identifier::ID_NAME, new_name); |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | Template* NamedTemplate::extract_template() |
| 362 | { |
| 363 | Template * ret = temp; |
| 364 | temp = 0; |
| 365 | return ret; |
| 366 | } |
| 367 | |
| 368 | void NamedTemplate::dump(unsigned level) const |
| 369 | { |
| 370 | name->dump(level); |
| 371 | temp->dump(level); |
| 372 | } |
| 373 | |
| 374 | // ================================= |
| 375 | // ===== NamedTemplates |
| 376 | // ================================= |
| 377 | |
| 378 | NamedTemplates::NamedTemplates(const NamedTemplates& p) |
| 379 | : Node(p), checked(p.checked) |
| 380 | { |
| 381 | for (size_t i = 0; i < p.nts_v.size(); i++) { |
| 382 | NamedTemplate* nt = p.nts_v[i]->clone(); |
| 383 | nts_v.add(nt); |
| 384 | if (checked) { |
| 385 | nts_m.add(p.nts_m.get_nth_key(i), nt); |
| 386 | } |
| 387 | } |
| 388 | } |
| 389 | |
| 390 | NamedTemplates::~NamedTemplates() |
| 391 | { |
| 392 | for (size_t i = 0; i < nts_v.size(); i++) delete nts_v[i]; |
| 393 | nts_v.clear(); |
| 394 | nts_m.clear(); |
| 395 | } |
| 396 | |
| 397 | NamedTemplates *NamedTemplates::clone() const |
| 398 | { |
| 399 | return new NamedTemplates(*this); |
| 400 | } |
| 401 | |
| 402 | void NamedTemplates::set_fullname(const string& p_fullname) |
| 403 | { |
| 404 | Node::set_fullname(p_fullname); |
| 405 | for(size_t i = 0; i < nts_v.size(); i++) { |
| 406 | NamedTemplate *nt = nts_v[i]; |
| 407 | nt->set_fullname(p_fullname + "." + nt->get_name().get_dispname()); |
| 408 | } |
| 409 | } |
| 410 | |
| 411 | void NamedTemplates::set_my_scope(Scope *p_scope) |
| 412 | { |
| 413 | Node::set_my_scope(p_scope); |
| 414 | for(size_t i = 0; i < nts_v.size(); i++) nts_v[i]->set_my_scope(p_scope); |
| 415 | } |
| 416 | |
| 417 | void NamedTemplates::add_nt(NamedTemplate *p_nt) |
| 418 | { |
| 419 | if (!p_nt) FATAL_ERROR("NULL pointer:NamedTemplates::add_nt()"); |
| 420 | nts_v.add(p_nt); |
| 421 | if (checked) { |
| 422 | const string& name = p_nt->get_name().get_name(); |
| 423 | if (!nts_m.has_key(name)) nts_m.add(name, p_nt); |
| 424 | } |
| 425 | } |
| 426 | |
| 427 | bool NamedTemplates::has_nt_withName(const Identifier& p_name) |
| 428 | { |
| 429 | if (!checked) chk_dupl_id(false); |
| 430 | return nts_m.has_key(p_name.get_name()); |
| 431 | } |
| 432 | |
| 433 | NamedTemplate *NamedTemplates::get_nt_byName(const Identifier& p_name) |
| 434 | { |
| 435 | if (!checked) chk_dupl_id(false); |
| 436 | return nts_m[p_name.get_name()]; |
| 437 | } |
| 438 | |
| 439 | void NamedTemplates::chk_dupl_id(bool report_errors) |
| 440 | { |
| 441 | if (checked) nts_m.clear(); |
| 442 | for (size_t i = 0; i < nts_v.size(); i++) { |
| 443 | NamedTemplate *nt = nts_v[i]; |
| 444 | const Identifier& id = nt->get_name(); |
| 445 | const string& name = id.get_name(); |
| 446 | if (!nts_m.has_key(name)) nts_m.add(name, nt); |
| 447 | else if (report_errors) { |
| 448 | const char *disp_name = id.get_dispname().c_str(); |
| 449 | nt->error("Duplicate field name `%s'", disp_name); |
| 450 | nts_m[name]->note("Field `%s' is already given here", disp_name); |
| 451 | } |
| 452 | } |
| 453 | checked = true; |
| 454 | } |
| 455 | |
| 456 | // ================================= |
| 457 | // ===== LengthRestriction |
| 458 | // ================================= |
| 459 | |
| 460 | LengthRestriction::LengthRestriction(Value* p_val) |
| 461 | : Node(), checked(false), is_range(false) |
| 462 | { |
| 463 | if (!p_val) |
| 464 | FATAL_ERROR("LengthRestriction::LengthRestriction()"); |
| 465 | single = p_val; |
| 466 | } |
| 467 | |
| 468 | LengthRestriction::LengthRestriction(Value* p_lower, Value* p_upper) |
| 469 | : Node(), checked(false), is_range(true) |
| 470 | { |
| 471 | if (!p_lower) |
| 472 | FATAL_ERROR("LengthRestriction::LengthRestriction()"); |
| 473 | range.lower = p_lower; |
| 474 | range.upper = p_upper; |
| 475 | } |
| 476 | |
| 477 | LengthRestriction::~LengthRestriction() |
| 478 | { |
| 479 | if (is_range) { |
| 480 | delete range.lower; |
| 481 | delete range.upper; |
| 482 | } else delete single; |
| 483 | } |
| 484 | |
| 485 | LengthRestriction *LengthRestriction::clone() const |
| 486 | { |
| 487 | FATAL_ERROR("LengthRestriction::clone"); |
| 488 | } |
| 489 | |
| 490 | void LengthRestriction::set_fullname(const string& p_fullname) |
| 491 | { |
| 492 | Node::set_fullname(p_fullname); |
| 493 | if (is_range) { |
| 494 | range.lower->set_fullname(p_fullname + ".<lower>"); |
| 495 | if (range.upper) range.upper->set_fullname(p_fullname + ".<upper>"); |
| 496 | } else single->set_fullname(p_fullname); |
| 497 | } |
| 498 | |
| 499 | void LengthRestriction::set_my_scope(Scope *p_scope) |
| 500 | { |
| 501 | if (is_range) { |
| 502 | range.lower->set_my_scope(p_scope); |
| 503 | if (range.upper) range.upper->set_my_scope(p_scope); |
| 504 | } else single->set_my_scope(p_scope); |
| 505 | } |
| 506 | |
| 507 | void LengthRestriction::chk(Type::expected_value_t expected_value) |
| 508 | { |
| 509 | if (checked) return; |
| 510 | checked = true; |
| 511 | Type *pool_int = Type::get_pooltype(Type::T_INT); |
| 512 | if (is_range) { |
| 513 | range.lower->set_my_governor(pool_int); |
| 514 | { |
| 515 | Error_Context cntxt(range.lower, "In lower boundary of the length " |
| 516 | "restriction"); |
| 517 | pool_int->chk_this_value_ref(range.lower); |
| 518 | pool_int->chk_this_value(range.lower, 0, expected_value, |
| 519 | INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); |
| 520 | } |
| 521 | Value *v_lower = range.lower->get_value_refd_last(); |
| 522 | int_val_t v_int_lower_int; |
| 523 | if (v_lower->get_valuetype() == Value::V_INT) { |
| 524 | v_int_lower_int = *(v_lower->get_val_Int()); |
| 525 | if (v_int_lower_int < 0) { |
| 526 | range.lower->error("The lower boundary of the length restriction " |
| 527 | "must be a non-negative integer value instead of %s", |
| 528 | v_int_lower_int.t_str().c_str()); |
| 529 | range.lower->set_valuetype(Value::V_ERROR); |
| 530 | v_int_lower_int = int_val_t((Int)0); |
| 531 | } |
| 532 | } else { |
| 533 | v_int_lower_int = int_val_t((Int)0); |
| 534 | } |
| 535 | if (range.upper) { |
| 536 | range.upper->set_my_governor(pool_int); |
| 537 | { |
| 538 | Error_Context cntxt(range.lower, "In upper boundary of the length " |
| 539 | "restriction"); |
| 540 | pool_int->chk_this_value_ref(range.upper); |
| 541 | pool_int->chk_this_value(range.upper, 0, expected_value, |
| 542 | INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); |
| 543 | } |
| 544 | Value *v_upper = range.upper->get_value_refd_last(); |
| 545 | if (v_upper->get_valuetype() == Value::V_INT) { |
| 546 | int_val_t v_int_upper_int(*(v_upper->get_val_Int())); |
| 547 | if (v_int_upper_int < 0) { |
| 548 | range.upper->error("The upper boundary of the length " |
| 549 | "restriction must be a non-negative integer value instead " |
| 550 | "of %s", v_int_upper_int.t_str().c_str()); |
| 551 | range.upper->set_valuetype(Value::V_ERROR); |
| 552 | } else if (v_int_upper_int < v_int_lower_int) { |
| 553 | error("The upper boundary of the length restriction (%s) " |
| 554 | "cannot be smaller than the lower boundary (%s)", |
| 555 | v_int_upper_int.t_str().c_str(), |
| 556 | v_int_lower_int.t_str().c_str()); |
| 557 | range.upper->set_valuetype(Value::V_ERROR); |
| 558 | } |
| 559 | } |
| 560 | } |
| 561 | } else { |
| 562 | single->set_my_governor(pool_int); |
| 563 | { |
| 564 | Error_Context cntxt(single, "In length restriction"); |
| 565 | pool_int->chk_this_value_ref(single); |
| 566 | pool_int->chk_this_value(single, 0, expected_value, |
| 567 | INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); |
| 568 | } |
| 569 | Value *v_single = single->get_value_refd_last(); |
| 570 | if (v_single->get_valuetype() == Value::V_INT) { |
| 571 | const int_val_t *v_int_int = v_single->get_val_Int(); |
| 572 | if (*v_int_int < 0) { |
| 573 | single->error("The length restriction must be a non-negative " |
| 574 | "integer value instead of %s", (v_int_int->t_str()).c_str()); |
| 575 | single->set_valuetype(Value::V_ERROR); |
| 576 | } |
| 577 | } |
| 578 | } |
| 579 | } |
| 580 | |
| 581 | void LengthRestriction::chk_array_size(ArrayDimension *p_dim) |
| 582 | { |
| 583 | if (!checked) FATAL_ERROR("LengthRestriction::chk_array_size()"); |
| 584 | bool error_flag = false; |
| 585 | if (!p_dim->get_has_error()) { |
| 586 | size_t array_size = p_dim->get_size(); |
| 587 | if (is_range) { |
| 588 | Value *v_lower_last = range.lower->get_value_refd_last(); |
| 589 | if (v_lower_last->get_valuetype() == Value::V_INT) { |
| 590 | const int_val_t *lower_len_int = v_lower_last->get_val_Int(); |
| 591 | if (*lower_len_int > INT_MAX) { |
| 592 | range.lower->error("An integer value less than `%d' was expected " |
| 593 | "as the lower boundary of the length restriction instead of " |
| 594 | "`%s'", INT_MAX, (lower_len_int->t_str()).c_str()); |
| 595 | error_flag = true; |
| 596 | } else { |
| 597 | Int lower_len = lower_len_int->get_val(); |
| 598 | if (lower_len > static_cast<Int>(array_size)) { |
| 599 | range.lower->error("The number of elements allowed by the " |
| 600 | "length restriction (at least %s) contradicts the array size " |
| 601 | "(%lu)", Int2string(lower_len).c_str(), |
| 602 | (unsigned long)array_size); |
| 603 | error_flag = true; |
| 604 | } |
| 605 | } |
| 606 | } |
| 607 | if (range.upper) { |
| 608 | Value *v_upper_last = range.upper->get_value_refd_last(); |
| 609 | if (v_upper_last->get_valuetype() == Value::V_INT) { |
| 610 | const int_val_t *upper_len_int = v_upper_last->get_val_Int(); |
| 611 | if (*upper_len_int > INT_MAX) { |
| 612 | range.upper->error("An integer value less than `%d' was " |
| 613 | "expected as the upper boundary of the length restriction " |
| 614 | "instead of `%s'", INT_MAX, (upper_len_int->t_str()).c_str()); |
| 615 | error_flag = true; |
| 616 | } else { |
| 617 | Int upper_len = upper_len_int->get_val(); |
| 618 | if (upper_len < static_cast<Int>(array_size)) { |
| 619 | range.upper->error("The number of elements allowed by the " |
| 620 | "length restriction (at most %s) contradicts the array " |
| 621 | "size (%lu)", Int2string(upper_len).c_str(), |
| 622 | (unsigned long)array_size); |
| 623 | error_flag = true; |
| 624 | } |
| 625 | } |
| 626 | } |
| 627 | } |
| 628 | } else { |
| 629 | Value *v_last = single->get_value_refd_last(); |
| 630 | if (v_last->get_valuetype() == Value::V_INT) { |
| 631 | int_val_t single_len_int(*(v_last->get_val_Int())); |
| 632 | if (single_len_int != static_cast<Int>(array_size)) { |
| 633 | single->error("The number of elements allowed by the length " |
| 634 | "restriction (%s) contradicts the array size (%lu)", |
| 635 | single_len_int.t_str().c_str(), (unsigned long)array_size); |
| 636 | error_flag = true; |
| 637 | } |
| 638 | } |
| 639 | } |
| 640 | } |
| 641 | if (!error_flag) |
| 642 | warning("Length restriction is useless for an array template"); |
| 643 | } |
| 644 | |
| 645 | void LengthRestriction::chk_nof_elements(size_t nof_elements, |
| 646 | bool has_anyornone, const Location& p_loc, const char *p_what) |
| 647 | { |
| 648 | if (!checked) FATAL_ERROR("LengthRestriction::chk_nof_elements()"); |
| 649 | if (is_range) { |
| 650 | if (!has_anyornone) { |
| 651 | Value *v_lower_last = range.lower->get_value_refd_last(); |
| 652 | if (v_lower_last->get_valuetype() == Value::V_INT) { |
| 653 | const int_val_t *lower_len_int = v_lower_last->get_val_Int(); |
| 654 | if (*lower_len_int > static_cast<Int>(nof_elements)) { |
| 655 | p_loc.error("There are fewer (%lu) elements in the %s than it " |
| 656 | "is allowed by the length restriction (at least %s)", |
| 657 | (unsigned long)nof_elements, p_what, |
| 658 | (lower_len_int->t_str()).c_str()); |
| 659 | } |
| 660 | } |
| 661 | } |
| 662 | if (range.upper) { |
| 663 | Value *v_upper_last = range.upper->get_value_refd_last(); |
| 664 | if (v_upper_last->get_valuetype() == Value::V_INT) { |
| 665 | const int_val_t *upper_len_int = v_upper_last->get_val_Int(); |
| 666 | if (*upper_len_int < static_cast<Int>(nof_elements)) { |
| 667 | p_loc.error("There are more (%s%lu) elements in the %s than it " |
| 668 | "is allowed by the length restriction (at most %s)", |
| 669 | has_anyornone ? "at least " : "", (unsigned long)nof_elements, |
| 670 | p_what, (upper_len_int->t_str()).c_str()); |
| 671 | } |
| 672 | } |
| 673 | } |
| 674 | } else { |
| 675 | Value *v_last = single->get_value_refd_last(); |
| 676 | if (v_last->get_valuetype() == Value::V_INT) { |
| 677 | // Cheaper than creating a local variable? |
| 678 | const int_val_t *single_len_int = v_last->get_val_Int(); |
| 679 | if (*single_len_int < static_cast<Int>(nof_elements)) { |
| 680 | p_loc.error("There are more (%s%lu) elements in the %s than it " |
| 681 | "is allowed by the length restriction (%s)", has_anyornone ? |
| 682 | "at least " : "", (unsigned long)nof_elements, p_what, |
| 683 | (single_len_int->t_str()).c_str()); |
| 684 | } else if (*single_len_int > static_cast<Int>(nof_elements) && |
| 685 | !has_anyornone) { |
| 686 | p_loc.error("There are fewer (%lu) elements in the %s than it " |
| 687 | "is allowed by the length restriction (%s)", |
| 688 | (unsigned long)nof_elements, p_what, |
| 689 | (single_len_int->t_str()).c_str()); |
| 690 | } |
| 691 | } |
| 692 | } |
| 693 | } |
| 694 | |
| 695 | Value* LengthRestriction::get_single_value() |
| 696 | { |
| 697 | if (is_range) FATAL_ERROR("LengthRestriction::get_single_value()"); |
| 698 | if (!checked) FATAL_ERROR("LengthRestriction::get_single_value()"); |
| 699 | return single->get_value_refd_last(); |
| 700 | } |
| 701 | |
| 702 | Value *LengthRestriction::get_lower_value() |
| 703 | { |
| 704 | if (!is_range) FATAL_ERROR("LengthRestriction::get_lower_value()"); |
| 705 | if (!checked) FATAL_ERROR("LengthRestriction::get_lower_value()"); |
| 706 | return range.lower->get_value_refd_last(); |
| 707 | } |
| 708 | |
| 709 | Value *LengthRestriction::get_upper_value() |
| 710 | { |
| 711 | if (!is_range) FATAL_ERROR("LengthRestriction::get_upper_value()"); |
| 712 | if (!checked) FATAL_ERROR("LengthRestriction::get_upper_value()"); |
| 713 | return range.upper ? range.upper->get_value_refd_last() : 0; |
| 714 | } |
| 715 | |
| 716 | void LengthRestriction::set_code_section |
| 717 | (GovernedSimple::code_section_t p_code_section) |
| 718 | { |
| 719 | if (is_range) { |
| 720 | range.lower->set_code_section(p_code_section); |
| 721 | if (range.upper) range.upper->set_code_section(p_code_section); |
| 722 | } else single->set_code_section(p_code_section); |
| 723 | } |
| 724 | |
| 725 | char *LengthRestriction::generate_code_init(char *str, const char *name) |
| 726 | { |
| 727 | expression_struct expr; |
| 728 | Code::init_expr(&expr); |
| 729 | char *init_stmt; |
| 730 | if (is_range) { |
| 731 | range.lower->generate_code_expr(&expr); |
| 732 | init_stmt = mprintf("%s.set_min_length(%s);\n", name, expr.expr); |
| 733 | if (range.upper) { |
| 734 | Code::clean_expr(&expr); |
| 735 | range.upper->generate_code_expr(&expr); |
| 736 | init_stmt = mputprintf(init_stmt, "%s.set_max_length(%s);\n", name, |
| 737 | expr.expr); |
| 738 | } |
| 739 | } else { |
| 740 | single->generate_code_expr(&expr); |
| 741 | init_stmt = mprintf("%s.set_single_length(%s);\n", name, expr.expr); |
| 742 | } |
| 743 | if (expr.preamble || expr.postamble) { |
| 744 | str = mputstr(str, "{\n"); |
| 745 | str = mputstr(str, expr.preamble); |
| 746 | str = mputstr(str, init_stmt); |
| 747 | str = mputstr(str, expr.postamble); |
| 748 | str = mputstr(str, "}\n"); |
| 749 | } else str = mputstr(str, init_stmt); |
| 750 | Code::free_expr(&expr); |
| 751 | Free(init_stmt); |
| 752 | return str; |
| 753 | } |
| 754 | |
| 755 | char *LengthRestriction::rearrange_init_code(char *str) |
| 756 | { |
| 757 | if (is_range) { |
| 758 | str = range.lower->rearrange_init_code(str); |
| 759 | if (range.upper) str = range.upper->rearrange_init_code(str); |
| 760 | } else str = single->rearrange_init_code(str); |
| 761 | return str; |
| 762 | } |
| 763 | |
| 764 | void LengthRestriction::append_stringRepr(string& str) const |
| 765 | { |
| 766 | str += "length("; |
| 767 | if (is_range) { |
| 768 | str += range.lower->get_stringRepr(); |
| 769 | str += " .. "; |
| 770 | if (range.upper) str += range.upper->get_stringRepr(); |
| 771 | else str += "infinity"; |
| 772 | } else str += single->get_stringRepr(); |
| 773 | str += ")"; |
| 774 | } |
| 775 | |
| 776 | void LengthRestriction::dump(unsigned level) const |
| 777 | { |
| 778 | DEBUG(level, "length restriction:"); |
| 779 | if (is_range) { |
| 780 | range.lower->dump(level + 1); |
| 781 | DEBUG(level, ".."); |
| 782 | if (range.upper) range.upper->dump(level + 1); |
| 783 | else DEBUG(level + 1, "infinity"); |
| 784 | } else single->dump(level + 1); |
| 785 | } |
| 786 | |
| 787 | // ================================= |
| 788 | // ===== TemplateInstances |
| 789 | // ================================= |
| 790 | |
| 791 | TemplateInstances::TemplateInstances(const TemplateInstances& p) |
| 792 | : Node(p), Location(p), tis() |
| 793 | { |
| 794 | for (size_t i = 0; i < p.tis.size(); i++) |
| 795 | tis.add(p.tis[i]->clone()); |
| 796 | } |
| 797 | |
| 798 | TemplateInstances::~TemplateInstances() |
| 799 | { |
| 800 | for (size_t i = 0; i < tis.size(); i++) delete tis[i]; |
| 801 | tis.clear(); |
| 802 | } |
| 803 | |
| 804 | TemplateInstances *TemplateInstances::clone() const |
| 805 | { |
| 806 | return new TemplateInstances(*this); |
| 807 | } |
| 808 | |
| 809 | void TemplateInstances::set_fullname(const string& p_fullname) |
| 810 | { |
| 811 | Node::set_fullname(p_fullname); |
| 812 | for (size_t i = 0; i < tis.size(); i++) |
| 813 | tis[i]->set_fullname(p_fullname + "[" + Int2string(i + 1) + "]"); |
| 814 | } |
| 815 | |
| 816 | void TemplateInstances::set_my_scope(Scope *p_scope) |
| 817 | { |
| 818 | for (size_t i = 0; i < tis.size(); i++) |
| 819 | { |
| 820 | TemplateInstance*& tir = tis[i]; |
| 821 | tir->set_my_scope(p_scope); |
| 822 | } |
| 823 | } |
| 824 | |
| 825 | void TemplateInstances::add_ti(TemplateInstance *p_ti) |
| 826 | { |
| 827 | if (!p_ti) FATAL_ERROR("NULL pointer:TemplateInstances::add_ti()"); |
| 828 | tis.add(p_ti); |
| 829 | } |
| 830 | |
| 831 | void TemplateInstances::set_code_section |
| 832 | (GovernedSimple::code_section_t p_code_section) |
| 833 | { |
| 834 | for (size_t i=0; i<tis.size(); i++) |
| 835 | tis[i]->set_code_section(p_code_section); |
| 836 | } |
| 837 | |
| 838 | void TemplateInstances::dump(unsigned level) const |
| 839 | { |
| 840 | DEBUG(level, "TemplateInstances %p, has %lu", (const void*)this, |
| 841 | (unsigned long) tis.size()); |
| 842 | for (size_t i = 0; i < tis.size(); ++i) { |
| 843 | tis[i]->dump(level+1); |
| 844 | } |
| 845 | } |
| 846 | // ================================= |
| 847 | // ===== NamedParam |
| 848 | // ================================= |
| 849 | |
| 850 | NamedParam::NamedParam(Identifier *id, TemplateInstance *t) |
| 851 | : Node(), Location(), name(id), tmpl(t) |
| 852 | { |
| 853 | } |
| 854 | |
| 855 | NamedParam::NamedParam(const NamedParam& p) |
| 856 | : Node(p), Location(p), name(p.name->clone()), tmpl(p.tmpl->clone()) |
| 857 | { |
| 858 | } |
| 859 | |
| 860 | NamedParam::~NamedParam() |
| 861 | { |
| 862 | delete tmpl; |
| 863 | delete name; |
| 864 | } |
| 865 | |
| 866 | NamedParam * NamedParam::clone() const { |
| 867 | return new NamedParam(*this); |
| 868 | } |
| 869 | |
| 870 | void NamedParam::set_my_scope(Scope *p_scope) |
| 871 | { |
| 872 | tmpl->set_my_scope(p_scope); |
| 873 | } |
| 874 | |
| 875 | void NamedParam::set_fullname(const string& p_fullname) |
| 876 | { |
| 877 | Node::set_fullname(p_fullname); |
| 878 | tmpl->set_fullname(p_fullname); |
| 879 | } |
| 880 | |
| 881 | TemplateInstance * NamedParam::extract_ti() |
| 882 | { |
| 883 | TemplateInstance *retval = tmpl; |
| 884 | tmpl = 0; |
| 885 | return retval; |
| 886 | } |
| 887 | |
| 888 | void NamedParam::dump(unsigned int level) const |
| 889 | { |
| 890 | name->dump(level+1); |
| 891 | tmpl->dump(level+1); |
| 892 | } |
| 893 | // ================================= |
| 894 | // ===== NamedParams |
| 895 | // ================================= |
| 896 | |
| 897 | NamedParams::NamedParams() |
| 898 | : Node(), Location(), nps() |
| 899 | { |
| 900 | } |
| 901 | |
| 902 | NamedParams * NamedParams::clone() const |
| 903 | { |
| 904 | FATAL_ERROR("NamedParams::clone"); |
| 905 | } |
| 906 | |
| 907 | NamedParams::~NamedParams() |
| 908 | { |
| 909 | for (size_t i = 0; i < nps.size(); i++) delete nps[i]; |
| 910 | nps.clear(); |
| 911 | } |
| 912 | |
| 913 | void NamedParams::set_my_scope(Scope *p_scope) |
| 914 | { |
| 915 | for (size_t i = 0; i < nps.size(); i++) nps[i]->set_my_scope(p_scope); |
| 916 | } |
| 917 | |
| 918 | void NamedParams::set_fullname(const string& p_fullname) |
| 919 | { |
| 920 | for (size_t i = 0; i < nps.size(); i++) nps[i]->set_fullname(p_fullname); |
| 921 | } |
| 922 | |
| 923 | void NamedParams::add_np(NamedParam *p) |
| 924 | { |
| 925 | if (!p) FATAL_ERROR("NULL pointer: NamedParams::add_np()"); |
| 926 | nps.add(p); |
| 927 | } |
| 928 | |
| 929 | size_t NamedParams::get_nof_nps() const |
| 930 | { |
| 931 | return nps.size(); |
| 932 | } |
| 933 | |
| 934 | NamedParam *NamedParams::extract_np_byIndex(size_t p_i) |
| 935 | { |
| 936 | NamedParam * retval = nps[p_i]; |
| 937 | nps[p_i] = 0; |
| 938 | return retval; |
| 939 | } |
| 940 | |
| 941 | void NamedParams::dump(unsigned int level) const |
| 942 | { |
| 943 | DEBUG(level, "NamedParams %p, has %lu", (const void*)this, |
| 944 | (unsigned long) nps.size()); |
| 945 | for (unsigned int i = 0; i < nps.size(); ++i) { |
| 946 | if (nps[i] != 0) { |
| 947 | nps[i]->dump(level+1); |
| 948 | } else { |
| 949 | DEBUG(level+1, "NULL"); |
| 950 | } |
| 951 | } |
| 952 | } |
| 953 | // ================================= |
| 954 | // ===== ParsedActualParameters |
| 955 | // ================================= |
| 956 | |
| 957 | ParsedActualParameters::ParsedActualParameters(TemplateInstances *p_ti, |
| 958 | NamedParams *p_np) |
| 959 | : Node(), Location(), unnamedpart(p_ti ? p_ti : new TemplateInstances), namedpart(p_np) |
| 960 | { |
| 961 | } |
| 962 | |
| 963 | ParsedActualParameters::ParsedActualParameters(const ParsedActualParameters& p) |
| 964 | : Node(p), Location(p), unnamedpart(p.unnamedpart->clone()), |
| 965 | namedpart (p.namedpart ? p.namedpart->clone() : 0) |
| 966 | { |
| 967 | } |
| 968 | |
| 969 | ParsedActualParameters* ParsedActualParameters::clone() const |
| 970 | { |
| 971 | return new ParsedActualParameters(*this); |
| 972 | } |
| 973 | |
| 974 | ParsedActualParameters::~ParsedActualParameters() |
| 975 | { |
| 976 | delete namedpart; |
| 977 | delete unnamedpart; |
| 978 | } |
| 979 | |
| 980 | void ParsedActualParameters::add_np(NamedParam *np) |
| 981 | { |
| 982 | if (!namedpart) // we got away without one until now |
| 983 | { |
| 984 | namedpart = new NamedParams; |
| 985 | } |
| 986 | namedpart->add_np(np); |
| 987 | } |
| 988 | |
| 989 | TemplateInstances* ParsedActualParameters::steal_tis() |
| 990 | { |
| 991 | TemplateInstances* temp = unnamedpart; |
| 992 | unnamedpart = new TemplateInstances; |
| 993 | return temp; |
| 994 | } |
| 995 | |
| 996 | size_t ParsedActualParameters::get_nof_nps() const |
| 997 | { |
| 998 | return namedpart ? namedpart->get_nof_nps() : 0; |
| 999 | } |
| 1000 | |
| 1001 | void ParsedActualParameters::set_my_scope(Common::Scope *p_scope) |
| 1002 | { |
| 1003 | unnamedpart->set_my_scope(p_scope); |
| 1004 | if (namedpart) { |
| 1005 | namedpart->set_my_scope(p_scope); |
| 1006 | } |
| 1007 | } |
| 1008 | |
| 1009 | void ParsedActualParameters::set_fullname(const string& p_fullname) |
| 1010 | { |
| 1011 | unnamedpart->set_fullname(p_fullname); |
| 1012 | if (namedpart) { |
| 1013 | namedpart->set_fullname(p_fullname); |
| 1014 | } |
| 1015 | } |
| 1016 | |
| 1017 | void ParsedActualParameters::set_location(const char *p_filename, int p_lineno) |
| 1018 | { |
| 1019 | Location ::set_location(p_filename, p_lineno); |
| 1020 | if (namedpart) |
| 1021 | namedpart->set_location(p_filename, p_lineno); |
| 1022 | unnamedpart->set_location(p_filename, p_lineno); |
| 1023 | } |
| 1024 | |
| 1025 | void ParsedActualParameters::set_location(const char *p_filename, |
| 1026 | const YYLTYPE& p_yyloc) |
| 1027 | { |
| 1028 | Location ::set_location(p_filename, p_yyloc); |
| 1029 | if (namedpart) |
| 1030 | namedpart->set_location(p_filename, p_yyloc); |
| 1031 | unnamedpart->set_location(p_filename, p_yyloc); |
| 1032 | } |
| 1033 | |
| 1034 | void ParsedActualParameters::set_location(const char *p_filename, |
| 1035 | const YYLTYPE& p_firstloc, |
| 1036 | const YYLTYPE & p_lastloc) |
| 1037 | { |
| 1038 | Location ::set_location(p_filename, p_firstloc, p_lastloc); |
| 1039 | if (namedpart) |
| 1040 | namedpart->set_location(p_filename, p_firstloc, p_lastloc); |
| 1041 | unnamedpart->set_location(p_filename, p_firstloc, p_lastloc); |
| 1042 | } |
| 1043 | |
| 1044 | void ParsedActualParameters::set_location(const char *p_filename, int p_first_line, |
| 1045 | int p_first_column, int p_last_line, int p_last_column) |
| 1046 | { |
| 1047 | Location ::set_location(p_filename, p_first_line, p_first_column, |
| 1048 | p_last_line, p_last_column); |
| 1049 | if (namedpart) |
| 1050 | namedpart->set_location(p_filename, p_first_line, p_first_column, |
| 1051 | p_last_line, p_last_column); |
| 1052 | unnamedpart->set_location(p_filename, p_first_line, p_first_column, |
| 1053 | p_last_line, p_last_column); |
| 1054 | } |
| 1055 | |
| 1056 | |
| 1057 | void ParsedActualParameters::dump(unsigned int level) const |
| 1058 | { |
| 1059 | DEBUG(level, "ParsedActualParameters at %p", (const void*)this); |
| 1060 | unnamedpart->dump(level+1); |
| 1061 | if (namedpart) { |
| 1062 | namedpart->dump(level+1); |
| 1063 | } |
| 1064 | } |
| 1065 | } |