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