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 | } | |
235 | } | |
236 | return str; | |
237 | } | |
238 | ||
239 | char *Location::update_location_object(char *str) const | |
240 | { | |
241 | if (filename && yyloc.first_line > 0) { | |
242 | if (include_location_info && !transparency) { | |
243 | str = mputprintf(str, "current_location.update_lineno(%d);\n", | |
244 | yyloc.first_line); | |
245 | if (tcov_file_name && in_tcov_files(get_filename())) { | |
246 | effective_module_lines = | |
247 | mputprintf(effective_module_lines, "%s%d", | |
248 | (effective_module_lines ? ", " : ""), yyloc.first_line); | |
249 | } | |
250 | } | |
251 | ||
252 | if (include_line_info) | |
253 | str = mputprintf(str, "#line %d \"%s\"\n", yyloc.first_line, filename); | |
254 | else str = mputprintf(str, "/* %s, line %d */\n", filename, | |
255 | yyloc.first_line); | |
256 | } | |
257 | return str; | |
258 | } | |
259 | ||
260 | // ================================= | |
261 | // ===== Node | |
262 | // ================================= | |
263 | ||
264 | int Node::counter=0; | |
265 | #ifdef MEMORY_DEBUG | |
266 | static Node *list_head = 0, *list_tail = 0; | |
267 | #endif | |
268 | ||
269 | Node::Node() | |
270 | { | |
271 | #ifdef MEMORY_DEBUG | |
272 | prev_node = list_tail; | |
273 | next_node = 0; | |
274 | if (list_tail) list_tail->next_node = this; | |
275 | else list_head = this; | |
276 | list_tail = this; | |
277 | #endif | |
278 | counter++; | |
279 | } | |
280 | ||
281 | Node::Node(const Node&) | |
282 | : fullname() | |
283 | { | |
284 | #ifdef MEMORY_DEBUG | |
285 | prev_node = list_tail; | |
286 | next_node = 0; | |
287 | if (list_tail) list_tail->next_node = this; | |
288 | else list_head = this; | |
289 | list_tail = this; | |
290 | #endif | |
291 | counter++; | |
292 | } | |
293 | ||
294 | Node::~Node() | |
295 | { | |
296 | counter--; | |
297 | #ifdef MEMORY_DEBUG | |
298 | if (prev_node) prev_node->next_node = next_node; | |
299 | else list_head = next_node; | |
300 | if (next_node) next_node->prev_node = prev_node; | |
301 | else list_tail = prev_node; | |
302 | #endif | |
303 | } | |
304 | ||
305 | ||
306 | void Node::chk_counter() | |
307 | { | |
308 | DEBUG(1, "Node::counter is %d", counter); | |
309 | if(counter) | |
310 | WARNING("%d nodes were not deleted." | |
311 | " Please send a bug report including" | |
312 | " the current input file(s).", counter); | |
313 | #ifdef MEMORY_DEBUG | |
314 | for (Node *iter = list_head; iter; iter = iter->next_node) { | |
315 | fprintf(stderr, "Undeleted node: `%s' (address %p).\n", | |
316 | iter->get_fullname().c_str(), static_cast<void*>(iter)); | |
317 | } | |
318 | list_head = 0; | |
319 | list_tail = 0; | |
320 | #endif | |
321 | } | |
322 | ||
323 | void Node::set_fullname(const string& p_fullname) | |
324 | { | |
325 | fullname = p_fullname; | |
326 | } | |
327 | ||
328 | void Node::set_my_scope(Scope *) | |
329 | { | |
330 | } | |
331 | ||
332 | void Node::dump(unsigned level) const | |
333 | { | |
334 | DEBUG(level, "Node: %s", fullname.c_str()); | |
335 | } | |
336 | ||
337 | // ================================= | |
338 | // ===== Setting | |
339 | // ================================= | |
340 | ||
341 | Setting::Setting(settingtype_t p_st) | |
342 | : Node(), Location(), | |
343 | st(p_st), my_scope(0), checked(false), recurs_checked(false) | |
344 | { | |
345 | } | |
346 | ||
347 | void Setting::set_my_scope(Scope *p_scope) | |
348 | { | |
349 | my_scope = p_scope; | |
350 | } | |
351 | ||
352 | bool Setting::is_asn1() const | |
353 | { | |
354 | if (!my_scope) FATAL_ERROR("Setting::is_asn1()"); | |
355 | return my_scope->get_scope_mod()->get_moduletype() == Module::MOD_ASN; | |
356 | } | |
357 | ||
358 | string Setting::get_temporary_id() const | |
359 | { | |
360 | if (!my_scope) FATAL_ERROR("Setting::get_temporary_id()"); | |
361 | return my_scope->get_scope_mod_gen()->get_temporary_id(); | |
362 | } | |
363 | ||
364 | void Setting::set_genname(const string& p_genname) | |
365 | { | |
366 | if (p_genname.empty()) FATAL_ERROR("Setting::set_genname()"); | |
367 | genname = p_genname; | |
368 | } | |
369 | ||
370 | void Setting::set_genname(const string& p_prefix, const string& p_suffix) | |
371 | { | |
372 | if (p_prefix.empty() || p_suffix.empty()) | |
373 | FATAL_ERROR("Setting::set_genname()"); | |
374 | genname = p_prefix; | |
375 | // a single underscore character is needed as separator if neither p_prefix | |
376 | // ends nor p_suffix begins with a single underscore character | |
377 | size_t p_prefix_len = p_prefix.size(); | |
378 | if ((p_prefix[p_prefix_len - 1] != '_' || | |
379 | (p_prefix_len >= 2 && p_prefix[p_prefix_len - 2] == '_')) && | |
380 | (p_suffix[0] != '_' || | |
381 | (p_suffix.size() >= 2 && p_suffix[1] == '_'))) genname += '_'; | |
382 | genname += p_suffix; | |
383 | } | |
384 | ||
385 | const string& Setting::get_genname_own() const | |
386 | { | |
387 | if (genname.empty()) | |
388 | FATAL_ERROR("Setting::get_genname_own(): genname is not set in %s", \ | |
389 | get_fullname().c_str()); | |
390 | return genname; | |
391 | } | |
392 | ||
393 | string Setting::get_genname_own(Scope *p_scope) const | |
394 | { | |
395 | if (!p_scope || !my_scope) FATAL_ERROR("Setting::get_genname_own"); | |
396 | string ret_val; | |
397 | Module *my_mod = my_scope->get_scope_mod_gen(); | |
398 | if (my_mod != p_scope->get_scope_mod_gen() && | |
399 | !Asn::Assignments::is_spec_asss(my_mod)) { | |
400 | // when the definition is referred from another module | |
401 | // the reference shall be qualified with the namespace of my module | |
402 | ret_val = my_mod->get_modid().get_name(); | |
403 | ret_val += "::"; | |
404 | } | |
405 | ret_val += get_genname_own(); | |
406 | return ret_val; | |
407 | } | |
408 | ||
409 | string Setting::create_stringRepr() | |
410 | { | |
411 | return string("<string representation not implemented for " + | |
412 | get_fullname() + ">"); | |
413 | } | |
414 | ||
415 | // ================================= | |
416 | // ===== Setting_Error | |
417 | // ================================= | |
418 | ||
419 | Setting_Error* Setting_Error::clone() const | |
420 | { | |
421 | FATAL_ERROR("Setting_Error::clone"); | |
422 | } | |
423 | ||
424 | // ================================= | |
425 | // ===== Governor | |
426 | // ================================= | |
427 | ||
428 | // ================================= | |
429 | // ===== Governed | |
430 | // ================================= | |
431 | ||
432 | // ================================= | |
433 | // ===== GovernedSimple | |
434 | // ================================= | |
435 | ||
436 | string GovernedSimple::get_lhs_name() const | |
437 | { | |
438 | string ret_val; | |
439 | if (genname_prefix) ret_val += genname_prefix; | |
440 | ret_val += get_genname_own(); | |
441 | return ret_val; | |
442 | } | |
443 | ||
444 | bool GovernedSimple::needs_init_precede(const GovernedSimple *refd) const | |
445 | { | |
446 | if (refd->code_generated) return false; | |
447 | if (code_section == CS_UNKNOWN || refd->code_section == CS_UNKNOWN) | |
448 | FATAL_ERROR("GovernedSimple::needs_init_precede()"); | |
449 | if (code_section != refd->code_section) return false; | |
450 | if (get_my_scope()->get_scope_mod_gen() != | |
451 | refd->get_my_scope()->get_scope_mod_gen()) return false; | |
452 | else return true; | |
453 | } | |
454 | ||
455 | bool GovernedSimple::is_toplevel() const | |
456 | { | |
457 | const string& name = get_genname_own(); | |
458 | const char *name_str = name.c_str(); | |
459 | size_t name_len = name.size(); | |
460 | for (size_t i = 0; i < name_len; i++) { | |
461 | char c = name_str[i]; | |
462 | if ((c < 'A' || c > 'Z') && (c < 'a' ||c > 'z') && | |
463 | (c < '0' || c > '9') && c != '_') return false; | |
464 | } | |
465 | return true; | |
466 | } | |
467 | ||
468 | // ================================= | |
469 | // ===== GovdSet | |
470 | // ================================= | |
471 | ||
472 | // ================================= | |
473 | // ===== Scope | |
474 | // ================================= | |
475 | ||
476 | string Scope::get_scope_name() const | |
477 | { | |
478 | string s; | |
479 | if (parent_scope) s = parent_scope->get_scope_name(); | |
480 | if (!scope_name.empty()) { | |
481 | if (s.empty()) s = scope_name; | |
482 | else { | |
483 | s += '.'; | |
484 | s += scope_name; | |
485 | } | |
486 | } | |
487 | return s; | |
488 | } | |
489 | ||
490 | string Scope::get_scopeMacro_name() const | |
491 | { | |
492 | if (!scopeMacro_name.empty()) return scopeMacro_name; | |
493 | if (parent_scope) return parent_scope->get_scopeMacro_name(); | |
494 | return scopeMacro_name; | |
495 | } | |
496 | ||
497 | Ttcn::StatementBlock *Scope::get_statementblock_scope() | |
498 | { | |
499 | if (parent_scope) return parent_scope->get_statementblock_scope(); | |
500 | else return 0; | |
501 | } | |
502 | ||
503 | Ttcn::RunsOnScope *Scope::get_scope_runs_on() | |
504 | { | |
505 | if (parent_scope) return parent_scope->get_scope_runs_on(); | |
506 | else return 0; | |
507 | } | |
508 | ||
509 | Assignments *Scope::get_scope_asss() | |
510 | { | |
511 | if (parent_scope) return parent_scope->get_scope_asss(); | |
512 | else | |
513 | FATAL_ERROR("The assignments scope is not visible from this scope: " \ | |
514 | "`%s'", get_scope_name().c_str()); | |
515 | return 0; | |
516 | } | |
517 | ||
518 | Module* Scope::get_scope_mod() | |
519 | { | |
520 | if(parent_scope) return parent_scope->get_scope_mod(); | |
521 | else FATAL_ERROR("The module scope is not visible from this scope: `%s'", \ | |
522 | get_scope_name().c_str()); | |
523 | return 0; | |
524 | } | |
525 | ||
526 | Module* Scope::get_scope_mod_gen() | |
527 | { | |
528 | if(parent_scope_gen) return parent_scope_gen->get_scope_mod_gen(); | |
529 | else if(parent_scope) return parent_scope->get_scope_mod_gen(); | |
530 | else FATAL_ERROR("The module scope is not visible from this scope: `%s'", \ | |
531 | get_scope_name().c_str()); | |
532 | return 0; | |
533 | } | |
534 | ||
535 | bool Scope::has_ass_withId(const Identifier& p_id) | |
536 | { | |
537 | if (parent_scope) return parent_scope->has_ass_withId(p_id); | |
538 | else return false; | |
539 | } | |
540 | ||
541 | bool Scope::is_valid_moduleid(const Identifier& p_id) | |
542 | { | |
543 | if (parent_scope) return parent_scope->is_valid_moduleid(p_id); | |
544 | else return false; | |
545 | } | |
546 | ||
547 | Type *Scope::get_mtc_system_comptype(bool is_system, bool is_connecting) | |
548 | { | |
549 | if (parent_scope) return parent_scope->get_mtc_system_comptype(is_system, is_connecting); | |
550 | else return 0; | |
551 | } | |
552 | ||
553 | void Scope::chk_runs_on_clause(Assignment *p_ass, const Location& p_loc, | |
554 | const char *p_what) | |
555 | { | |
556 | // component type of the referred definition | |
557 | Type *refd_comptype = p_ass->get_RunsOnType(); | |
558 | // definitions without 'runs on' can be called from anywhere | |
559 | if (!refd_comptype) return; | |
560 | Ttcn::RunsOnScope *t_ros = get_scope_runs_on(); | |
561 | if (t_ros) { | |
562 | Type *local_comptype = t_ros->get_component_type(); | |
563 | if (!refd_comptype->is_compatible(local_comptype, NULL)) { | |
564 | // the 'runs on' clause of the referred definition is not compatible | |
565 | // with that of the current scope (i.e. the referring definition) | |
566 | p_loc.error("Runs on clause mismatch: A definition that runs on " | |
567 | "component type `%s' cannot %s %s, which runs on `%s'", | |
568 | local_comptype->get_typename().c_str(), p_what, | |
569 | p_ass->get_description().c_str(), | |
570 | refd_comptype->get_typename().c_str()); | |
571 | } | |
572 | } else { | |
573 | // the current scope unit (i.e. the referring definition) does not have | |
574 | // 'runs on' clause | |
575 | p_loc.error("A definition without `runs on' clause cannot %s %s, which " | |
576 | "runs on component type `%s'", p_what, p_ass->get_description().c_str(), | |
577 | refd_comptype->get_typename().c_str()); | |
578 | } | |
579 | } | |
580 | ||
581 | void Scope::chk_runs_on_clause(Type *p_fat, const Location& p_loc, | |
582 | const char *p_what) | |
583 | { | |
584 | if (!p_fat) FATAL_ERROR("Scope::chk_runs_on_clause()"); | |
585 | Type *refd_comptype = p_fat->get_fat_runs_on_type(); | |
586 | // values of function/altstep types without 'runs on' clause | |
587 | // or using 'runs on self' clause can be called from anywhere | |
588 | if (!refd_comptype) return; | |
589 | const char *typetype_name; | |
590 | switch (p_fat->get_typetype()) { | |
591 | case Type::T_FUNCTION: | |
592 | typetype_name = "function"; | |
593 | break; | |
594 | case Type::T_ALTSTEP: | |
595 | typetype_name = "altstep"; | |
596 | break; | |
597 | default: | |
598 | FATAL_ERROR("Scope::chk_runs_on_clause()"); | |
599 | typetype_name = 0; | |
600 | } | |
601 | Ttcn::RunsOnScope *t_ros = get_scope_runs_on(); | |
602 | if (t_ros) { | |
603 | Type *local_comptype = t_ros->get_component_type(); | |
604 | if (!refd_comptype->is_compatible(local_comptype, NULL)) { | |
605 | // the 'runs on' clause of the function/altstep type is not compatible | |
606 | // with that of the current scope (i.e. the referring definition) | |
607 | p_loc.error("Runs on clause mismatch: A definition that runs on " | |
608 | "component type `%s' cannot %s a value of %s type `%s', which runs " | |
609 | "on `%s'", local_comptype->get_typename().c_str(), p_what, | |
610 | typetype_name, p_fat->get_typename().c_str(), | |
611 | refd_comptype->get_typename().c_str()); | |
612 | } | |
613 | } else { | |
614 | // the current scope unit (i.e. the referring definition) does not have | |
615 | // 'runs on' clause | |
616 | p_loc.error("A definition without `runs on' clause cannot %s a value of " | |
617 | "%s type `%s', which runs on component type `%s'", p_what, | |
618 | typetype_name, p_fat->get_typename().c_str(), | |
619 | refd_comptype->get_typename().c_str()); | |
620 | } | |
621 | } | |
622 | ||
623 | // ================================= | |
624 | // ===== Reference | |
625 | // ================================= | |
626 | ||
627 | size_t Reference::_Reference_counter=0; | |
628 | Setting_Error *Reference::setting_error = 0; | |
629 | ||
630 | Reference::~Reference() | |
631 | { | |
632 | if (_Reference_counter <= 0) FATAL_ERROR("Reference::~Reference()"); | |
633 | else if (--_Reference_counter == 0) { | |
634 | delete setting_error; | |
635 | setting_error = 0; | |
636 | } | |
637 | } | |
638 | ||
639 | void Reference::set_my_scope(Scope *p_scope) | |
640 | { | |
641 | my_scope = p_scope; | |
642 | } | |
643 | ||
644 | bool Reference::get_is_erroneous() | |
645 | { | |
646 | return is_erroneous; | |
647 | } | |
648 | ||
649 | Setting* Reference::get_refd_setting_error() | |
650 | { | |
651 | is_erroneous=true; | |
652 | if(!setting_error) | |
653 | setting_error=new Setting_Error(); | |
654 | return setting_error; | |
655 | } | |
656 | ||
657 | bool Reference::refers_to_st(Setting::settingtype_t p_st, | |
658 | ReferenceChain*) | |
659 | { | |
660 | Setting *t_setting=get_refd_setting(); | |
661 | if(t_setting) return t_setting->get_st()==p_st; | |
662 | else return p_st==Setting::S_ERROR; | |
663 | } | |
664 | ||
665 | void Reference::set_code_section(GovernedSimple::code_section_t) | |
666 | { | |
667 | } | |
668 | ||
669 | Ttcn::FieldOrArrayRefs *Reference::get_subrefs() | |
670 | { | |
671 | return 0; | |
672 | } | |
673 | ||
674 | Ttcn::ActualParList *Reference::get_parlist() | |
675 | { | |
676 | return 0; | |
677 | } | |
678 | ||
679 | void Reference::dump(unsigned level) const | |
680 | { | |
681 | DEBUG(level, "Reference: %s", const_cast<Reference*>(this)->get_dispname().c_str()); | |
682 | } | |
683 | ||
684 | // ================================= | |
685 | // ===== Ref_simple | |
686 | // ================================= | |
687 | ||
688 | string Ref_simple::get_dispname() | |
689 | { | |
690 | string ret_val; | |
691 | const Identifier *t_modid = get_modid(); | |
692 | if (t_modid) { | |
693 | ret_val += t_modid->get_dispname(); | |
694 | ret_val += '.'; | |
695 | } | |
696 | ret_val += get_id()->get_dispname(); | |
697 | return ret_val; | |
698 | } | |
699 | ||
700 | Setting* Ref_simple::get_refd_setting() | |
701 | { | |
702 | if(get_is_erroneous()) return get_refd_setting_error(); | |
703 | Assignment *ass = get_refd_assignment(); | |
704 | if (ass) return ass->get_Setting(); | |
705 | else return get_refd_setting_error(); | |
706 | } | |
707 | ||
708 | Assignment* Ref_simple::get_refd_assignment(bool) | |
709 | { | |
710 | if (!refd_ass) { | |
711 | if (!my_scope) FATAL_ERROR("Common::Ref_simple::get_refd_assignment()"); | |
712 | refd_ass = my_scope->get_ass_bySRef(this); | |
713 | } | |
714 | return refd_ass; | |
715 | } | |
716 | ||
717 | bool Ref_simple::has_single_expr() | |
718 | { | |
719 | return true; | |
720 | } | |
721 | ||
722 | // ================================= | |
723 | // ===== ReferenceChain | |
724 | // ================================= | |
725 | ||
726 | ReferenceChain::ReferenceChain(const Location *p_loc, const char *p_str) | |
727 | : my_loc(p_loc), err_str(p_str), report_error(true) | |
728 | { | |
729 | if(!p_loc) | |
730 | FATAL_ERROR("ReferenceChain::ReferenceChain()"); | |
731 | } | |
732 | ||
733 | ReferenceChain::~ReferenceChain() | |
734 | { | |
735 | reset(); | |
736 | } | |
737 | ||
738 | ReferenceChain *ReferenceChain::clone() const | |
739 | { | |
740 | FATAL_ERROR("ReferenceChain::clone()"); | |
741 | return 0; | |
742 | } | |
743 | ||
744 | bool ReferenceChain::exists(const string& s) const | |
745 | { | |
746 | for (size_t i = 0; i < refs.size(); i++) | |
747 | if (*refs[i]==s) return true; | |
748 | return false; | |
749 | } | |
750 | ||
751 | bool ReferenceChain::add(const string& s) | |
752 | { | |
753 | if (!exists(s)) { | |
754 | refs.add(new string(s)); | |
755 | return true; | |
756 | } | |
757 | ||
758 | if (report_error) { | |
759 | if (err_str) { | |
760 | my_loc->error("%s: Circular reference: %s", err_str, | |
761 | get_dispstr(s).c_str()); | |
762 | } else { | |
763 | my_loc->error("Circular reference: %s", get_dispstr(s).c_str()); | |
764 | } | |
765 | } else { | |
766 | errors.add(get_dispstr(s)); | |
767 | } | |
768 | return false; | |
769 | } | |
770 | ||
771 | void ReferenceChain::set_error_reporting(bool enable) { | |
772 | report_error = enable; | |
773 | } | |
774 | ||
775 | size_t ReferenceChain::nof_errors() const { | |
776 | return errors.size() - (err_stack.empty() ? 0 : *err_stack.top()); | |
777 | } | |
778 | ||
779 | void ReferenceChain::report_errors() | |
780 | { | |
781 | if (!err_stack.empty() && *err_stack.top() > errors.size()) | |
782 | FATAL_ERROR("Common::ReferenceChain::report_errors()"); | |
783 | ||
784 | string err_msg; | |
785 | if (err_str) { | |
786 | err_msg += err_str; | |
787 | err_msg += ": "; | |
788 | } | |
789 | ||
790 | for (size_t i = (err_stack.empty() ? 0 : *err_stack.top()); | |
791 | i < errors.size(); ++i) { | |
792 | my_loc->error("%sCircular reference: %s", | |
793 | err_msg.c_str(), errors[i].c_str()); | |
794 | } | |
795 | } | |
796 | ||
797 | void ReferenceChain::mark_error_state() | |
798 | { | |
799 | err_stack.push(new size_t(errors.size())); | |
800 | } | |
801 | ||
802 | void ReferenceChain::prev_error_state() | |
803 | { | |
804 | if (err_stack.empty()) | |
805 | FATAL_ERROR("Common::ReferenceChain::prev_error_state()"); | |
806 | if (errors.size() < *err_stack.top()) | |
807 | FATAL_ERROR("Common::ReferenceChain::prev_error_state()"); | |
808 | ||
809 | int state = static_cast<int>(*err_stack.top()); | |
810 | for (int i = static_cast<int>(errors.size()) - 1; i >= state; --i) { | |
811 | errors.remove(i); | |
812 | } | |
813 | delete err_stack.pop(); | |
814 | } | |
815 | ||
816 | void ReferenceChain::mark_state() | |
817 | { | |
818 | refstack.push(new size_t(refs.size())); | |
819 | } | |
820 | ||
821 | void ReferenceChain::prev_state() | |
822 | { | |
823 | if(refstack.empty()) | |
824 | FATAL_ERROR("Common::ReferenceChain::prev_state()"); | |
825 | size_t state=*refstack.top(); | |
826 | if(refs.size()<state) | |
827 | FATAL_ERROR("Common::ReferenceChain::prev_state()"); | |
828 | for(size_t i=state; i<refs.size(); i++) delete refs[i]; | |
829 | refs.replace(state, refs.size()-state); | |
830 | delete refstack.pop(); | |
831 | } | |
832 | ||
833 | void ReferenceChain::reset() | |
834 | { | |
835 | for(size_t i=0; i<refs.size(); i++) delete refs[i]; | |
836 | refs.clear(); | |
837 | while(!refstack.empty()) delete refstack.pop(); | |
838 | ||
839 | errors.clear(); | |
840 | while(!err_stack.empty()) delete err_stack.pop(); | |
841 | } | |
842 | ||
843 | string ReferenceChain::get_dispstr(const string& s) const | |
844 | { | |
845 | size_t i = 0; | |
846 | // skip the elements before the first occurrence of s | |
847 | for ( ; i < refs.size(); i++) if (*refs[i] == s) break; | |
848 | string str; | |
849 | for( ; i < refs.size(); i++) { | |
850 | str += '`'; | |
851 | str += *refs[i]; | |
852 | str += "' -> "; | |
853 | } | |
854 | // putting s at the end | |
855 | str += '`'; | |
856 | str += s; | |
857 | str += '\''; | |
858 | return str; | |
859 | } | |
860 | ||
861 | } // namespace Common |