Sync with 5.2.0
[deliverable/titan.core.git] / compiler2 / Setting.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 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 "Setting.hh"
10 #include <stdio.h>
11 #include <stdarg.h>
12 #include "map.hh"
13 #include "Identifier.hh"
14 #include "CompilerError.hh"
15 #include "AST.hh"
16 #include "asn1/AST_asn1.hh"
17 #include "ttcn3/AST_ttcn3.hh"
18 #include "Value.hh"
19 #include "Int.hh"
20 #include "main.hh"
21
22 namespace Common {
23
24 // =================================
25 // ===== Location
26 // =================================
27
28 map<string,void> *Location::source_file_names = NULL;
29 bool Location::transparency = false;
30
31 const char* Location::add_source_file_name(const string& file_name)
32 {
33 if (source_file_names==NULL)
34 source_file_names = new map<string,void>();
35 if (!source_file_names->has_key(file_name))
36 source_file_names->add(file_name, NULL);
37 return source_file_names->get_key(file_name).c_str();
38 }
39
40 void Location::delete_source_file_names()
41 {
42 if (source_file_names!=NULL)
43 {
44 source_file_names->clear();
45 delete source_file_names;
46 source_file_names = NULL;
47 }
48 }
49
50 Location::Location()
51 {
52 filename = NULL;
53 yyloc.first_line = 0;
54 yyloc.last_line = 0;
55 yyloc.first_column = 0;
56 yyloc.last_column = 0;
57 }
58
59 void Location::set_location(const char *p_filename, int p_lineno)
60 {
61 filename = p_filename;
62 yyloc.first_line = p_lineno;
63 yyloc.first_column = 0;
64 yyloc.last_line = p_lineno;
65 yyloc.last_column = 0;
66 }
67
68 void Location::set_location(const char *p_filename, const YYLTYPE& p_yyloc)
69 {
70 filename = p_filename;
71 yyloc = p_yyloc;
72 }
73
74 void Location::set_location(const char *p_filename, const YYLTYPE& p_firstloc,
75 const YYLTYPE& p_lastloc)
76 {
77 filename = p_filename;
78 yyloc.first_line = p_firstloc.first_line;
79 yyloc.first_column = p_firstloc.first_column;
80 yyloc.last_line = p_lastloc.last_line;
81 yyloc.last_column = p_lastloc.last_column;
82 }
83
84 void Location::set_location(const char *p_filename, int p_first_line,
85 int p_first_column, int p_last_line, int p_last_column)
86 {
87 filename = p_filename;
88 yyloc.first_line = p_first_line;
89 yyloc.first_column = p_first_column;
90 yyloc.last_line = p_last_line;
91 yyloc.last_column = p_last_column;
92 }
93
94 void Location::join_location(const Location& p)
95 {
96 // do nothing if this and p refer to different files
97 if (filename) {
98 if (!p.filename) return;
99 else if (strcmp(filename, p.filename)) return;
100 } else if (p.filename) return;
101 if (yyloc.last_line < p.yyloc.first_line ||
102 (yyloc.last_line == p.yyloc.first_line &&
103 yyloc.last_column <= p.yyloc.first_column)) {
104 // p is after this
105 yyloc.last_line = p.yyloc.last_line;
106 yyloc.last_column = p.yyloc.last_column;
107 } else if (yyloc.first_line > p.yyloc.last_line ||
108 (yyloc.first_line == p.yyloc.last_line &&
109 yyloc.first_column >= p.yyloc.last_column)) {
110 // p is before this
111 yyloc.first_line = p.yyloc.first_line;
112 yyloc.first_column = p.yyloc.first_column;
113 }
114 }
115
116 void Location::print_line_info(FILE *fp) const
117 {
118 if (yyloc.first_line > 0) {
119 // at least partial line/column information is available
120 if (output_only_linenum || (yyloc.first_line == yyloc.last_line &&
121 yyloc.first_column <= 0 && yyloc.last_column <= 0)) {
122 // print only the first line
123 fprintf(fp, "%d", yyloc.first_line);
124 } else if (yyloc.last_line > yyloc.first_line) {
125 // multi-line area
126 if (yyloc.first_column >= 0 && yyloc.last_column >= 0) {
127 // all line/column fields are valid
128 if (gcc_compat) {
129 fprintf(fp, "%d:%d", yyloc.first_line, yyloc.first_column + 1);
130 }
131 else {
132 fprintf(fp, "%d.%d-%d.%d", yyloc.first_line,
133 yyloc.first_column + 1, yyloc.last_line, yyloc.last_column);
134 }
135 } else {
136 // only the line numbers are valid
137 if (gcc_compat) {
138 fprintf(fp, "%d", yyloc.first_line);
139 }
140 else {
141 fprintf(fp, "%d-%d", yyloc.first_line, yyloc.last_line);
142 }
143 }
144 } else if (yyloc.first_line == yyloc.last_line) {
145 // single line area
146 if (yyloc.first_column >= 0 && yyloc.last_column > yyloc.first_column) {
147 if (gcc_compat) {
148 fprintf(fp, "%d:%d", yyloc.first_line, yyloc.first_column + 1);
149 }
150 else {
151 if (yyloc.last_column > yyloc.first_column + 1) {
152 // more characters are covered
153 fprintf(fp, "%d.%d-%d", yyloc.first_line, yyloc.first_column + 1,
154 yyloc.last_column);
155 } else {
156 // only a single character is covered
157 fprintf(fp, "%d.%d", yyloc.first_line, yyloc.first_column + 1);
158 }
159 }
160 } else {
161 // the column information is invalid, print the line number only
162 fprintf(fp, "%d", yyloc.first_line);
163 }
164 } else {
165 // the last line is smaller than the first line
166 // print only the first line
167 fprintf(fp, "%d", yyloc.first_line);
168 }
169 } else {
170 // line information is not available
171 fputs("<unknown>", fp);
172 }
173 }
174
175 void Location::print_location(FILE *fp) const
176 {
177 if (filename) {
178 fputs(filename, fp);
179 if (yyloc.first_line > 0) {
180 // print the line information only if it is available
181 putc(':', fp);
182 print_line_info(fp);
183 }
184 fputs(": ", fp);
185 }
186 // do not print anything if the file name is unknown
187 }
188
189 void Location::error(const char *fmt, ...) const
190 {
191 va_list args;
192 va_start(args, fmt);
193 Error_Context::report_error(this, fmt, args);
194 va_end(args);
195 }
196
197 void Location::warning(const char *fmt, ...) const
198 {
199 va_list args;
200 va_start(args, fmt);
201 Error_Context::report_warning(this, fmt, args);
202 va_end(args);
203 }
204
205 void Location::note(const char *fmt, ...) const
206 {
207 va_list args;
208 va_start(args, fmt);
209 Error_Context::report_note(this, fmt, args);
210 va_end(args);
211 }
212
213 char *Location::create_location_object(char *str, const char *entitytype,
214 const char *entityname) const
215 {
216 if (!filename || yyloc.first_line <= 0)
217 FATAL_ERROR("Location::create_location_object()");
218 if (include_location_info && !transparency) {
219 bool tcov_enabled = tcov_file_name && in_tcov_files(get_filename());
220 str = mputstr(str,
221 !tcov_enabled ? "TTCN_Location current_location(\""
222 : "TTCN_Location_Statistics current_location(\"");
223 str = Code::translate_string(str, filename);
224 str = mputprintf(str,
225 !tcov_enabled ? "\", %d, TTCN_Location::LOCATION_%s, \"%s\");\n"
226 : "\", %d, TTCN_Location_Statistics::LOCATION_%s, \"%s\");\n", yyloc.first_line, entitytype, entityname);
227 if (tcov_enabled) {
228 effective_module_lines =
229 mputprintf(effective_module_lines, "%s%d",
230 (effective_module_lines ? ", " : ""), yyloc.first_line);
231 effective_module_functions =
232 mputprintf(effective_module_functions, "%s\"%s\"",
233 (effective_module_functions ? ", " : ""), entityname);
234 }
235 if (profiler_enabled) {
236 str = mputprintf(str,
237 "TTCN3_Stack_Depth stack_depth;\n"
238 "ttcn3_prof.enter_function(\"%s\", %d, \"%s\");\n",
239 filename, yyloc.first_line, entityname);
240 }
241 }
242 return str;
243 }
244
245 char *Location::update_location_object(char *str) const
246 {
247 if (filename && yyloc.first_line > 0) {
248 if (include_location_info && !transparency) {
249 str = mputprintf(str, "current_location.update_lineno(%d);\n",
250 yyloc.first_line);
251 if (profiler_enabled) {
252 str = mputprintf(str, "ttcn3_prof.execute_line(\"%s\", %d);\n",
253 get_filename(), yyloc.first_line);
254 }
255 if (tcov_file_name && in_tcov_files(get_filename())) {
256 effective_module_lines =
257 mputprintf(effective_module_lines, "%s%d",
258 (effective_module_lines ? ", " : ""), yyloc.first_line);
259 }
260 }
261
262 if (include_line_info)
263 str = mputprintf(str, "#line %d \"%s\"\n", yyloc.first_line, filename);
264 else str = mputprintf(str, "/* %s, line %d */\n", filename,
265 yyloc.first_line);
266 }
267 return str;
268 }
269
270 // =================================
271 // ===== Node
272 // =================================
273
274 int Node::counter=0;
275 #ifdef MEMORY_DEBUG
276 static Node *list_head = 0, *list_tail = 0;
277 #endif
278
279 Node::Node()
280 {
281 #ifdef MEMORY_DEBUG
282 prev_node = list_tail;
283 next_node = 0;
284 if (list_tail) list_tail->next_node = this;
285 else list_head = this;
286 list_tail = this;
287 #endif
288 counter++;
289 }
290
291 Node::Node(const Node&)
292 : fullname()
293 {
294 #ifdef MEMORY_DEBUG
295 prev_node = list_tail;
296 next_node = 0;
297 if (list_tail) list_tail->next_node = this;
298 else list_head = this;
299 list_tail = this;
300 #endif
301 counter++;
302 }
303
304 Node::~Node()
305 {
306 counter--;
307 #ifdef MEMORY_DEBUG
308 if (prev_node) prev_node->next_node = next_node;
309 else list_head = next_node;
310 if (next_node) next_node->prev_node = prev_node;
311 else list_tail = prev_node;
312 #endif
313 }
314
315
316 void Node::chk_counter()
317 {
318 DEBUG(1, "Node::counter is %d", counter);
319 if(counter)
320 WARNING("%d nodes were not deleted."
321 " Please send a bug report including"
322 " the current input file(s).", counter);
323 #ifdef MEMORY_DEBUG
324 for (Node *iter = list_head; iter; iter = iter->next_node) {
325 fprintf(stderr, "Undeleted node: `%s' (address %p).\n",
326 iter->get_fullname().c_str(), static_cast<void*>(iter));
327 }
328 list_head = 0;
329 list_tail = 0;
330 #endif
331 }
332
333 void Node::set_fullname(const string& p_fullname)
334 {
335 fullname = p_fullname;
336 }
337
338 void Node::set_my_scope(Scope *)
339 {
340 }
341
342 void Node::dump(unsigned level) const
343 {
344 DEBUG(level, "Node: %s", fullname.c_str());
345 }
346
347 // =================================
348 // ===== Setting
349 // =================================
350
351 Setting::Setting(settingtype_t p_st)
352 : Node(), Location(),
353 st(p_st), my_scope(0), checked(false), recurs_checked(false)
354 {
355 }
356
357 void Setting::set_my_scope(Scope *p_scope)
358 {
359 my_scope = p_scope;
360 }
361
362 bool Setting::is_asn1() const
363 {
364 if (!my_scope) FATAL_ERROR("Setting::is_asn1()");
365 return my_scope->get_scope_mod()->get_moduletype() == Module::MOD_ASN;
366 }
367
368 string Setting::get_temporary_id() const
369 {
370 if (!my_scope) FATAL_ERROR("Setting::get_temporary_id()");
371 return my_scope->get_scope_mod_gen()->get_temporary_id();
372 }
373
374 void Setting::set_genname(const string& p_genname)
375 {
376 if (p_genname.empty()) FATAL_ERROR("Setting::set_genname()");
377 genname = p_genname;
378 }
379
380 void Setting::set_genname(const string& p_prefix, const string& p_suffix)
381 {
382 if (p_prefix.empty() || p_suffix.empty())
383 FATAL_ERROR("Setting::set_genname()");
384 genname = p_prefix;
385 // a single underscore character is needed as separator if neither p_prefix
386 // ends nor p_suffix begins with a single underscore character
387 size_t p_prefix_len = p_prefix.size();
388 if ((p_prefix[p_prefix_len - 1] != '_' ||
389 (p_prefix_len >= 2 && p_prefix[p_prefix_len - 2] == '_')) &&
390 (p_suffix[0] != '_' ||
391 (p_suffix.size() >= 2 && p_suffix[1] == '_'))) genname += '_';
392 genname += p_suffix;
393 }
394
395 const string& Setting::get_genname_own() const
396 {
397 if (genname.empty())
398 FATAL_ERROR("Setting::get_genname_own(): genname is not set in %s", \
399 get_fullname().c_str());
400 return genname;
401 }
402
403 string Setting::get_genname_own(Scope *p_scope) const
404 {
405 if (!p_scope || !my_scope) FATAL_ERROR("Setting::get_genname_own");
406 string ret_val;
407 Module *my_mod = my_scope->get_scope_mod_gen();
408 if (my_mod != p_scope->get_scope_mod_gen() &&
409 !Asn::Assignments::is_spec_asss(my_mod)) {
410 // when the definition is referred from another module
411 // the reference shall be qualified with the namespace of my module
412 ret_val = my_mod->get_modid().get_name();
413 ret_val += "::";
414 }
415 ret_val += get_genname_own();
416 return ret_val;
417 }
418
419 string Setting::create_stringRepr()
420 {
421 return string("<string representation not implemented for " +
422 get_fullname() + ">");
423 }
424
425 // =================================
426 // ===== Setting_Error
427 // =================================
428
429 Setting_Error* Setting_Error::clone() const
430 {
431 FATAL_ERROR("Setting_Error::clone");
432 }
433
434 // =================================
435 // ===== Governor
436 // =================================
437
438 // =================================
439 // ===== Governed
440 // =================================
441
442 // =================================
443 // ===== GovernedSimple
444 // =================================
445
446 string GovernedSimple::get_lhs_name() const
447 {
448 string ret_val;
449 if (genname_prefix) ret_val += genname_prefix;
450 ret_val += get_genname_own();
451 return ret_val;
452 }
453
454 bool GovernedSimple::needs_init_precede(const GovernedSimple *refd) const
455 {
456 if (refd->code_generated) return false;
457 if (code_section == CS_UNKNOWN || refd->code_section == CS_UNKNOWN)
458 FATAL_ERROR("GovernedSimple::needs_init_precede()");
459 if (code_section != refd->code_section) return false;
460 if (get_my_scope()->get_scope_mod_gen() !=
461 refd->get_my_scope()->get_scope_mod_gen()) return false;
462 else return true;
463 }
464
465 bool GovernedSimple::is_toplevel() const
466 {
467 const string& name = get_genname_own();
468 const char *name_str = name.c_str();
469 size_t name_len = name.size();
470 for (size_t i = 0; i < name_len; i++) {
471 char c = name_str[i];
472 if ((c < 'A' || c > 'Z') && (c < 'a' ||c > 'z') &&
473 (c < '0' || c > '9') && c != '_') return false;
474 }
475 return true;
476 }
477
478 // =================================
479 // ===== GovdSet
480 // =================================
481
482 // =================================
483 // ===== Scope
484 // =================================
485
486 string Scope::get_scope_name() const
487 {
488 string s;
489 if (parent_scope) s = parent_scope->get_scope_name();
490 if (!scope_name.empty()) {
491 if (s.empty()) s = scope_name;
492 else {
493 s += '.';
494 s += scope_name;
495 }
496 }
497 return s;
498 }
499
500 string Scope::get_scopeMacro_name() const
501 {
502 if (!scopeMacro_name.empty()) return scopeMacro_name;
503 if (parent_scope) return parent_scope->get_scopeMacro_name();
504 return scopeMacro_name;
505 }
506
507 Ttcn::StatementBlock *Scope::get_statementblock_scope()
508 {
509 if (parent_scope) return parent_scope->get_statementblock_scope();
510 else return 0;
511 }
512
513 Ttcn::RunsOnScope *Scope::get_scope_runs_on()
514 {
515 if (parent_scope) return parent_scope->get_scope_runs_on();
516 else return 0;
517 }
518
519 Assignments *Scope::get_scope_asss()
520 {
521 if (parent_scope) return parent_scope->get_scope_asss();
522 else
523 FATAL_ERROR("The assignments scope is not visible from this scope: " \
524 "`%s'", get_scope_name().c_str());
525 return 0;
526 }
527
528 Module* Scope::get_scope_mod()
529 {
530 if(parent_scope) return parent_scope->get_scope_mod();
531 else FATAL_ERROR("The module scope is not visible from this scope: `%s'", \
532 get_scope_name().c_str());
533 return 0;
534 }
535
536 Module* Scope::get_scope_mod_gen()
537 {
538 if(parent_scope_gen) return parent_scope_gen->get_scope_mod_gen();
539 else if(parent_scope) return parent_scope->get_scope_mod_gen();
540 else FATAL_ERROR("The module scope is not visible from this scope: `%s'", \
541 get_scope_name().c_str());
542 return 0;
543 }
544
545 bool Scope::has_ass_withId(const Identifier& p_id)
546 {
547 if (parent_scope) return parent_scope->has_ass_withId(p_id);
548 else return false;
549 }
550
551 bool Scope::is_valid_moduleid(const Identifier& p_id)
552 {
553 if (parent_scope) return parent_scope->is_valid_moduleid(p_id);
554 else return false;
555 }
556
557 Type *Scope::get_mtc_system_comptype(bool is_system)
558 {
559 if (parent_scope) return parent_scope->get_mtc_system_comptype(is_system);
560 else return 0;
561 }
562
563 void Scope::chk_runs_on_clause(Assignment *p_ass, const Location& p_loc,
564 const char *p_what)
565 {
566 // component type of the referred definition
567 Type *refd_comptype = p_ass->get_RunsOnType();
568 // definitions without 'runs on' can be called from anywhere
569 if (!refd_comptype) return;
570 Ttcn::RunsOnScope *t_ros = get_scope_runs_on();
571 if (t_ros) {
572 Type *local_comptype = t_ros->get_component_type();
573 if (!refd_comptype->is_compatible(local_comptype, NULL)) {
574 // the 'runs on' clause of the referred definition is not compatible
575 // with that of the current scope (i.e. the referring definition)
576 p_loc.error("Runs on clause mismatch: A definition that runs on "
577 "component type `%s' cannot %s %s, which runs on `%s'",
578 local_comptype->get_typename().c_str(), p_what,
579 p_ass->get_description().c_str(),
580 refd_comptype->get_typename().c_str());
581 }
582 } else {
583 // the current scope unit (i.e. the referring definition) does not have
584 // 'runs on' clause
585 p_loc.error("A definition without `runs on' clause cannot %s %s, which "
586 "runs on component type `%s'", p_what, p_ass->get_description().c_str(),
587 refd_comptype->get_typename().c_str());
588 }
589 }
590
591 void Scope::chk_runs_on_clause(Type *p_fat, const Location& p_loc,
592 const char *p_what)
593 {
594 if (!p_fat) FATAL_ERROR("Scope::chk_runs_on_clause()");
595 Type *refd_comptype = p_fat->get_fat_runs_on_type();
596 // values of function/altstep types without 'runs on' clause
597 // or using 'runs on self' clause can be called from anywhere
598 if (!refd_comptype) return;
599 const char *typetype_name;
600 switch (p_fat->get_typetype()) {
601 case Type::T_FUNCTION:
602 typetype_name = "function";
603 break;
604 case Type::T_ALTSTEP:
605 typetype_name = "altstep";
606 break;
607 default:
608 FATAL_ERROR("Scope::chk_runs_on_clause()");
609 typetype_name = 0;
610 }
611 Ttcn::RunsOnScope *t_ros = get_scope_runs_on();
612 if (t_ros) {
613 Type *local_comptype = t_ros->get_component_type();
614 if (!refd_comptype->is_compatible(local_comptype, NULL)) {
615 // the 'runs on' clause of the function/altstep type is not compatible
616 // with that of the current scope (i.e. the referring definition)
617 p_loc.error("Runs on clause mismatch: A definition that runs on "
618 "component type `%s' cannot %s a value of %s type `%s', which runs "
619 "on `%s'", local_comptype->get_typename().c_str(), p_what,
620 typetype_name, p_fat->get_typename().c_str(),
621 refd_comptype->get_typename().c_str());
622 }
623 } else {
624 // the current scope unit (i.e. the referring definition) does not have
625 // 'runs on' clause
626 p_loc.error("A definition without `runs on' clause cannot %s a value of "
627 "%s type `%s', which runs on component type `%s'", p_what,
628 typetype_name, p_fat->get_typename().c_str(),
629 refd_comptype->get_typename().c_str());
630 }
631 }
632
633 // =================================
634 // ===== Reference
635 // =================================
636
637 size_t Reference::_Reference_counter=0;
638 Setting_Error *Reference::setting_error = 0;
639
640 Reference::~Reference()
641 {
642 if (_Reference_counter <= 0) FATAL_ERROR("Reference::~Reference()");
643 else if (--_Reference_counter == 0) {
644 delete setting_error;
645 setting_error = 0;
646 }
647 }
648
649 void Reference::set_my_scope(Scope *p_scope)
650 {
651 my_scope = p_scope;
652 }
653
654 bool Reference::get_is_erroneous()
655 {
656 return is_erroneous;
657 }
658
659 Setting* Reference::get_refd_setting_error()
660 {
661 is_erroneous=true;
662 if(!setting_error)
663 setting_error=new Setting_Error();
664 return setting_error;
665 }
666
667 bool Reference::refers_to_st(Setting::settingtype_t p_st,
668 ReferenceChain*)
669 {
670 Setting *t_setting=get_refd_setting();
671 if(t_setting) return t_setting->get_st()==p_st;
672 else return p_st==Setting::S_ERROR;
673 }
674
675 void Reference::set_code_section(GovernedSimple::code_section_t)
676 {
677 }
678
679 Ttcn::FieldOrArrayRefs *Reference::get_subrefs()
680 {
681 return 0;
682 }
683
684 Ttcn::ActualParList *Reference::get_parlist()
685 {
686 return 0;
687 }
688
689 void Reference::dump(unsigned level) const
690 {
691 DEBUG(level, "Reference: %s", const_cast<Reference*>(this)->get_dispname().c_str());
692 }
693
694 // =================================
695 // ===== Ref_simple
696 // =================================
697
698 string Ref_simple::get_dispname()
699 {
700 string ret_val;
701 const Identifier *t_modid = get_modid();
702 if (t_modid) {
703 ret_val += t_modid->get_dispname();
704 ret_val += '.';
705 }
706 ret_val += get_id()->get_dispname();
707 return ret_val;
708 }
709
710 Setting* Ref_simple::get_refd_setting()
711 {
712 if(get_is_erroneous()) return get_refd_setting_error();
713 Assignment *ass = get_refd_assignment();
714 if (ass) return ass->get_Setting();
715 else return get_refd_setting_error();
716 }
717
718 Assignment* Ref_simple::get_refd_assignment(bool)
719 {
720 if (!refd_ass) {
721 if (!my_scope) FATAL_ERROR("Common::Ref_simple::get_refd_assignment()");
722 refd_ass = my_scope->get_ass_bySRef(this);
723 }
724 return refd_ass;
725 }
726
727 bool Ref_simple::has_single_expr()
728 {
729 return true;
730 }
731
732 // =================================
733 // ===== ReferenceChain
734 // =================================
735
736 ReferenceChain::ReferenceChain(const Location *p_loc, const char *p_str)
737 : my_loc(p_loc), err_str(p_str), report_error(true)
738 {
739 if(!p_loc)
740 FATAL_ERROR("ReferenceChain::ReferenceChain()");
741 }
742
743 ReferenceChain::~ReferenceChain()
744 {
745 reset();
746 }
747
748 ReferenceChain *ReferenceChain::clone() const
749 {
750 FATAL_ERROR("ReferenceChain::clone()");
751 return 0;
752 }
753
754 bool ReferenceChain::exists(const string& s) const
755 {
756 for (size_t i = 0; i < refs.size(); i++)
757 if (*refs[i]==s) return true;
758 return false;
759 }
760
761 bool ReferenceChain::add(const string& s)
762 {
763 if (!exists(s)) {
764 refs.add(new string(s));
765 return true;
766 }
767
768 if (report_error) {
769 if (err_str) {
770 my_loc->error("%s: Circular reference: %s", err_str,
771 get_dispstr(s).c_str());
772 } else {
773 my_loc->error("Circular reference: %s", get_dispstr(s).c_str());
774 }
775 } else {
776 errors.add(get_dispstr(s));
777 }
778 return false;
779 }
780
781 void ReferenceChain::set_error_reporting(bool enable) {
782 report_error = enable;
783 }
784
785 size_t ReferenceChain::nof_errors() const {
786 return errors.size() - (err_stack.empty() ? 0 : *err_stack.top());
787 }
788
789 void ReferenceChain::report_errors()
790 {
791 if (!err_stack.empty() && *err_stack.top() > errors.size())
792 FATAL_ERROR("Common::ReferenceChain::report_errors()");
793
794 string err_msg;
795 if (err_str) {
796 err_msg += err_str;
797 err_msg += ": ";
798 }
799
800 for (size_t i = (err_stack.empty() ? 0 : *err_stack.top());
801 i < errors.size(); ++i) {
802 my_loc->error("%sCircular reference: %s",
803 err_msg.c_str(), errors[i].c_str());
804 }
805 }
806
807 void ReferenceChain::mark_error_state()
808 {
809 err_stack.push(new size_t(errors.size()));
810 }
811
812 void ReferenceChain::prev_error_state()
813 {
814 if (err_stack.empty())
815 FATAL_ERROR("Common::ReferenceChain::prev_error_state()");
816 if (errors.size() < *err_stack.top())
817 FATAL_ERROR("Common::ReferenceChain::prev_error_state()");
818
819 int state = static_cast<int>(*err_stack.top());
820 for (int i = static_cast<int>(errors.size()) - 1; i >= state; --i) {
821 errors.remove(i);
822 }
823 delete err_stack.pop();
824 }
825
826 void ReferenceChain::mark_state()
827 {
828 refstack.push(new size_t(refs.size()));
829 }
830
831 void ReferenceChain::prev_state()
832 {
833 if(refstack.empty())
834 FATAL_ERROR("Common::ReferenceChain::prev_state()");
835 size_t state=*refstack.top();
836 if(refs.size()<state)
837 FATAL_ERROR("Common::ReferenceChain::prev_state()");
838 for(size_t i=state; i<refs.size(); i++) delete refs[i];
839 refs.replace(state, refs.size()-state);
840 delete refstack.pop();
841 }
842
843 void ReferenceChain::reset()
844 {
845 for(size_t i=0; i<refs.size(); i++) delete refs[i];
846 refs.clear();
847 while(!refstack.empty()) delete refstack.pop();
848
849 errors.clear();
850 while(!err_stack.empty()) delete err_stack.pop();
851 }
852
853 string ReferenceChain::get_dispstr(const string& s) const
854 {
855 size_t i = 0;
856 // skip the elements before the first occurrence of s
857 for ( ; i < refs.size(); i++) if (*refs[i] == s) break;
858 string str;
859 for( ; i < refs.size(); i++) {
860 str += '`';
861 str += *refs[i];
862 str += "' -> ";
863 }
864 // putting s at the end
865 str += '`';
866 str += s;
867 str += '\'';
868 return str;
869 }
870
871 } // namespace Common
This page took 0.079948 seconds and 5 git commands to generate.