Commit | Line | Data |
---|---|---|
d44e3c4f | 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 | ******************************************************************************/ | |
970ed795 EL |
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" | |
a38c6d4c | 38 | #include "ttcn3/profiler.h" |
970ed795 EL |
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 | } | |
a38c6d4c | 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); | |
af710487 | 260 | str = mputprintf(str, |
261 | "TTCN3_Stack_Depth stack_depth;\n" | |
a38c6d4c | 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); | |
af710487 | 267 | } |
970ed795 EL |
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); | |
a38c6d4c | 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); | |
af710487 | 286 | str = mputprintf(str, "ttcn3_prof.execute_line(\"%s\", %d);\n", |
a38c6d4c | 287 | file_name2, yyloc.first_line); |
288 | insert_profiler_code_line(file_name2, NULL, yyloc.first_line); | |
289 | Free(file_name2); | |
af710487 | 290 | } |
a38c6d4c | 291 | if (tcov_file_name && in_tcov_files(file_name)) { |
970ed795 EL |
292 | effective_module_lines = |
293 | mputprintf(effective_module_lines, "%s%d", | |
294 | (effective_module_lines ? ", " : ""), yyloc.first_line); | |
295 | } | |
7329404e BB |
296 | if (debugger_active) { |
297 | str = mputprintf(str, "ttcn3_debugger.breakpoint_entry(%d);\n", yyloc.first_line); | |
298 | } | |
970ed795 EL |
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 | ||
af710487 | 596 | Type *Scope::get_mtc_system_comptype(bool is_system) |
970ed795 | 597 | { |
af710487 | 598 | if (parent_scope) return parent_scope->get_mtc_system_comptype(is_system); |
970ed795 EL |
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 |