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