Commit | Line | Data |
---|---|---|
970ed795 EL |
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 | } | |
af710487 | 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 | } | |
970ed795 EL |
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); | |
af710487 | 251 | if (profiler_enabled) { |
252 | str = mputprintf(str, "ttcn3_prof.execute_line(\"%s\", %d);\n", | |
253 | get_filename(), yyloc.first_line); | |
254 | } | |
970ed795 EL |
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 | ||
af710487 | 557 | Type *Scope::get_mtc_system_comptype(bool is_system) |
970ed795 | 558 | { |
af710487 | 559 | if (parent_scope) return parent_scope->get_mtc_system_comptype(is_system); |
970ed795 EL |
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 |