]>
Commit | Line | Data |
---|---|---|
2b066ec1 | 1 | // elaboration functions |
69c68955 FCE |
2 | // Copyright (C) 2005 Red Hat Inc. |
3 | // | |
4 | // This file is part of systemtap, and is free software. You can | |
5 | // redistribute it and/or modify it under the terms of the GNU General | |
6 | // Public License (GPL); either version 2, or (at your option) any | |
7 | // later version. | |
2b066ec1 FCE |
8 | |
9 | #include "config.h" | |
10 | #include "elaborate.h" | |
11 | #include "parse.h" | |
12 | ||
13 | extern "C" { | |
14 | #include <sys/utsname.h> | |
15 | } | |
16 | ||
17 | #include <fstream> | |
18 | #include <algorithm> | |
19 | ||
20 | #if 0 | |
21 | #ifdef HAVE_ELFUTILS_LIBDW_H | |
22 | #include <elfutils/libdw.h> | |
23 | #else | |
24 | #error "need <elfutils/libdw.h>" | |
25 | #endif | |
26 | #endif | |
27 | ||
28 | using namespace std; | |
29 | ||
30 | ||
31 | // ------------------------------------------------------------------------ | |
32 | ||
33 | ||
34 | derived_probe::derived_probe (probe *p): | |
35 | base (p) | |
36 | { | |
37 | this->locations = p->locations; | |
38 | this->tok = p->tok; | |
39 | this->body = p->body; | |
40 | this->locals = p->locals; | |
41 | } | |
42 | ||
43 | ||
44 | derived_probe::derived_probe (probe *p, probe_point *l): | |
45 | base (p) | |
46 | { | |
47 | this->locations.push_back (l); | |
48 | this->tok = p->tok; | |
49 | this->body = p->body; | |
50 | this->locals = p->locals; | |
51 | } | |
52 | ||
53 | ||
54 | // ------------------------------------------------------------------------ | |
55 | ||
56 | ||
57 | static int semantic_pass_symbols (systemtap_session&); | |
58 | static int semantic_pass_types (systemtap_session&); | |
59 | ||
60 | ||
61 | ||
62 | // Link up symbols to their declarations. Set the session's | |
63 | // files/probes/functions/globals vectors from the transitively | |
64 | // reached set of stapfiles in s.library_files, starting from | |
65 | // s.user_file. Perform automatic tapset inclusion and XXX: probe | |
66 | // alias expansion. | |
67 | static int | |
68 | semantic_pass_symbols (systemtap_session& s) | |
69 | { | |
70 | symresolution_info sym (s); | |
71 | ||
72 | // NB: s.files can grow during this iteration, so size() can | |
73 | // return gradually increasing numbers. | |
74 | s.files.push_back (s.user_file); | |
75 | for (unsigned i = 0; i < s.files.size(); i++) | |
76 | { | |
77 | stapfile* dome = s.files[i]; | |
78 | ||
79 | // Pass 1: add globals and functions to systemtap-session master list, | |
80 | // so the find_* functions find them | |
81 | ||
82 | for (unsigned i=0; i<dome->globals.size(); i++) | |
83 | s.globals.push_back (dome->globals[i]); | |
84 | ||
85 | for (unsigned i=0; i<dome->functions.size(); i++) | |
86 | s.functions.push_back (dome->functions[i]); | |
87 | ||
88 | // Pass 2: process functions | |
89 | ||
90 | for (unsigned i=0; i<dome->functions.size(); i++) | |
91 | { | |
92 | functiondecl* fd = dome->functions[i]; | |
93 | ||
94 | try | |
95 | { | |
96 | sym.current_function = fd; | |
97 | sym.current_probe = 0; | |
98 | fd->body->visit (& sym); | |
99 | } | |
100 | catch (const semantic_error& e) | |
101 | { | |
102 | s.print_error (e); | |
103 | } | |
104 | } | |
105 | ||
106 | // Pass 3: process probes | |
107 | ||
108 | for (unsigned i=0; i<dome->probes.size(); i++) | |
109 | { | |
110 | probe* p = dome->probes [i]; | |
111 | vector<derived_probe*> dps; | |
112 | ||
113 | try | |
114 | { | |
115 | // much magic happens here: probe alias expansion, | |
116 | // provider identification | |
117 | sym.derive_probes (p, dps); | |
118 | } | |
119 | catch (const semantic_error& e) | |
120 | { | |
121 | s.print_error (e); | |
122 | // dps.erase (dps.begin(), dps.end()); | |
123 | } | |
124 | ||
125 | for (unsigned j=0; j<dps.size(); j++) | |
126 | { | |
127 | derived_probe* dp = dps[j]; | |
128 | s.probes.push_back (dp); | |
129 | ||
130 | try | |
131 | { | |
132 | sym.current_function = 0; | |
133 | sym.current_probe = dp; | |
134 | dp->body->visit (& sym); | |
135 | } | |
136 | catch (const semantic_error& e) | |
137 | { | |
138 | s.print_error (e); | |
139 | } | |
140 | } | |
141 | } | |
142 | } | |
143 | ||
144 | return s.num_errors; // all those print_error calls | |
145 | } | |
146 | ||
147 | ||
148 | ||
149 | int | |
150 | semantic_pass (systemtap_session& s) | |
151 | { | |
152 | int rc = semantic_pass_symbols (s); | |
153 | if (rc == 0) rc = semantic_pass_types (s); | |
154 | return rc; | |
155 | } | |
156 | ||
157 | ||
158 | // ------------------------------------------------------------------------ | |
159 | ||
160 | ||
161 | systemtap_session::systemtap_session (): | |
162 | user_file (0), op (0), up (0), num_errors (0) | |
163 | { | |
164 | } | |
165 | ||
166 | ||
167 | void | |
168 | systemtap_session::print_error (const semantic_error& e) | |
169 | { | |
170 | cerr << "semantic error: " << e.what () << ": "; | |
171 | if (e.tok1) cerr << *e.tok1; | |
172 | cerr << e.msg2; | |
173 | if (e.tok2) cerr << *e.tok2; | |
174 | cerr << endl; | |
175 | num_errors ++; | |
176 | } | |
177 | ||
178 | ||
179 | // ------------------------------------------------------------------------ | |
180 | // semantic processing: symbol resolution | |
181 | ||
182 | ||
183 | symresolution_info::symresolution_info (systemtap_session& s): | |
184 | session (s), current_function (0), current_probe (0) | |
185 | { | |
186 | } | |
187 | ||
188 | ||
189 | void | |
190 | symresolution_info::visit_block (block* e) | |
191 | { | |
192 | for (unsigned i=0; i<e->statements.size(); i++) | |
193 | { | |
194 | try | |
195 | { | |
196 | e->statements[i]->visit (this); | |
197 | } | |
198 | catch (const semantic_error& e) | |
199 | { | |
200 | session.print_error (e); | |
201 | } | |
202 | } | |
203 | } | |
204 | ||
205 | ||
69c68955 FCE |
206 | void |
207 | symresolution_info::visit_foreach_loop (foreach_loop* e) | |
208 | { | |
209 | for (unsigned i=0; i<e->indexes.size(); i++) | |
210 | e->indexes[i]->visit (this); | |
211 | ||
212 | if (e->base_referent) | |
213 | return; | |
214 | ||
215 | vardecl* d = find_array (e->base, e->indexes.size ()); | |
216 | if (d) | |
217 | e->base_referent = d; | |
218 | else | |
219 | throw semantic_error ("unresolved global array " + e->base, e->tok); | |
220 | ||
221 | e->block->visit (this); | |
222 | } | |
223 | ||
224 | ||
2b066ec1 FCE |
225 | void |
226 | symresolution_info::visit_symbol (symbol* e) | |
227 | { | |
228 | if (e->referent) | |
229 | return; | |
230 | ||
231 | vardecl* d = find_scalar (e->name); | |
232 | if (d) | |
233 | e->referent = d; | |
234 | else | |
235 | { | |
236 | // new local | |
237 | vardecl* v = new vardecl; | |
238 | v->name = e->name; | |
239 | v->tok = e->tok; | |
240 | if (current_function) | |
241 | current_function->locals.push_back (v); | |
242 | else if (current_probe) | |
243 | current_probe->locals.push_back (v); | |
244 | else | |
ce10591c FCE |
245 | // must not happen |
246 | throw semantic_error ("no current probe/function", e->tok); | |
2b066ec1 FCE |
247 | e->referent = v; |
248 | } | |
249 | } | |
250 | ||
251 | ||
252 | void | |
253 | symresolution_info::visit_arrayindex (arrayindex* e) | |
254 | { | |
255 | for (unsigned i=0; i<e->indexes.size(); i++) | |
256 | e->indexes[i]->visit (this); | |
257 | ||
258 | if (e->referent) | |
259 | return; | |
260 | ||
261 | vardecl* d = find_array (e->base, e->indexes.size ()); | |
262 | if (d) | |
263 | e->referent = d; | |
264 | else | |
265 | throw semantic_error ("unresolved global array", e->tok); | |
266 | } | |
267 | ||
268 | ||
269 | void | |
270 | symresolution_info::visit_functioncall (functioncall* e) | |
271 | { | |
272 | for (unsigned i=0; i<e->args.size(); i++) | |
273 | e->args[i]->visit (this); | |
274 | ||
275 | if (e->referent) | |
276 | return; | |
277 | ||
278 | functiondecl* d = find_function (e->function, e->args.size ()); | |
279 | if (d) | |
280 | e->referent = d; | |
281 | else | |
282 | throw semantic_error ("unresolved function call", e->tok); | |
283 | } | |
284 | ||
285 | ||
286 | vardecl* | |
287 | symresolution_info::find_scalar (const string& name) | |
288 | { | |
289 | // search locals | |
290 | vector<vardecl*>& locals = (current_function ? | |
291 | current_function->locals : | |
292 | current_probe->locals); | |
293 | for (unsigned i=0; i<locals.size(); i++) | |
294 | if (locals[i]->name == name) | |
295 | // NB: no need to check arity here: locals always scalar | |
296 | return locals[i]; | |
297 | ||
298 | // search function formal parameters (if any) | |
299 | if (current_function) | |
300 | for (unsigned i=0; i<current_function->formal_args.size(); i++) | |
301 | if (current_function->formal_args[i]->name == name) | |
302 | // NB: no need to check arity here: formal args always scalar | |
303 | return current_function->formal_args[i]; | |
304 | ||
305 | // search globals | |
306 | for (unsigned i=0; i<session.globals.size(); i++) | |
307 | if (session.globals[i]->name == name) | |
308 | if (session.globals[i]->arity <= 0) | |
309 | { | |
310 | session.globals[i]->set_arity (0); | |
311 | return session.globals[i]; | |
312 | } | |
313 | ||
314 | // search library globals | |
315 | for (unsigned i=0; i<session.library_files.size(); i++) | |
316 | { | |
317 | stapfile* f = session.library_files[i]; | |
318 | for (unsigned j=0; j<f->globals.size(); j++) | |
319 | if (f->globals[j]->name == name && | |
320 | f->globals[j]->index_types.size() == 0) | |
321 | { | |
322 | // put library into the queue if not already there | |
323 | if (0) // (session.verbose_resolution) | |
324 | cerr << " scalar " << name << " " | |
325 | << "is defined from " << f->name << endl; | |
326 | ||
327 | if (find (session.files.begin(), session.files.end(), f) | |
328 | == session.files.end()) | |
329 | session.files.push_back (f); | |
330 | // else .. print different message? | |
331 | ||
332 | return f->globals[j]; | |
333 | } | |
334 | } | |
335 | ||
336 | // search builtins that become locals | |
337 | // XXX: need to invent a proper formalism for this | |
338 | if (name == "$pid" || name == "$tid") | |
339 | { | |
340 | vardecl_builtin* vb = new vardecl_builtin; | |
341 | vb->name = name; | |
342 | vb->type = pe_long; | |
343 | ||
344 | // XXX: need a better way to synthesize tokens | |
345 | token* t = new token; | |
346 | t->type = tok_identifier; | |
347 | t->content = name; | |
348 | t->location.file = "<builtin>"; | |
349 | vb->tok = t; | |
350 | ||
351 | locals.push_back (vb); | |
352 | return vb; | |
353 | } | |
354 | ||
355 | return 0; | |
356 | // XXX: add checking for conflicting array or function | |
357 | } | |
358 | ||
359 | ||
360 | vardecl* | |
361 | symresolution_info::find_array (const string& name, unsigned arity) | |
362 | { | |
363 | // search processed globals | |
364 | for (unsigned i=0; i<session.globals.size(); i++) | |
365 | if (session.globals[i]->name == name) | |
ce10591c | 366 | if ((arity > 0 && (session.globals[i]->arity == (int) arity)) || |
2b066ec1 FCE |
367 | session.globals[i]->arity < 0) |
368 | { | |
ce10591c FCE |
369 | if (arity > 0) |
370 | session.globals[i]->set_arity (arity); | |
2b066ec1 FCE |
371 | return session.globals[i]; |
372 | } | |
373 | ||
374 | // search library globals | |
375 | for (unsigned i=0; i<session.library_files.size(); i++) | |
376 | { | |
377 | stapfile* f = session.library_files[i]; | |
378 | for (unsigned j=0; j<f->globals.size(); j++) | |
bed7c0af | 379 | if (f->globals[j]->name == name) |
ce10591c | 380 | if ((arity > 0 && (f->globals[j]->arity == (int) arity)) || |
bed7c0af | 381 | f->globals[j]->arity < 0) |
2b066ec1 | 382 | { |
ce10591c FCE |
383 | if (arity > 0) |
384 | f->globals[j]->set_arity (arity); | |
bed7c0af | 385 | |
2b066ec1 FCE |
386 | // put library into the queue if not already there |
387 | if (0) // (session.verbose_resolution) | |
388 | cerr << " array " << name << " " | |
389 | << "is defined from " << f->name << endl; | |
390 | ||
391 | if (find (session.files.begin(), session.files.end(), f) | |
392 | == session.files.end()) | |
393 | session.files.push_back (f); | |
394 | // else .. print different message? | |
395 | ||
396 | return f->globals[j]; | |
397 | } | |
398 | } | |
399 | ||
400 | return 0; | |
401 | // XXX: add checking for conflicting scalar or function | |
402 | } | |
403 | ||
404 | ||
405 | functiondecl* | |
406 | symresolution_info::find_function (const string& name, unsigned arity) | |
407 | { | |
408 | for (unsigned j = 0; j < session.functions.size(); j++) | |
409 | { | |
410 | functiondecl* fd = session.functions[j]; | |
411 | if (fd->name == name && | |
412 | fd->formal_args.size() == arity) | |
413 | return fd; | |
414 | } | |
415 | ||
416 | // search library globals | |
417 | for (unsigned i=0; i<session.library_files.size(); i++) | |
418 | { | |
419 | stapfile* f = session.library_files[i]; | |
420 | for (unsigned j=0; j<f->functions.size(); j++) | |
421 | if (f->functions[j]->name == name && | |
422 | f->functions[j]->formal_args.size() == arity) | |
423 | { | |
424 | // put library into the queue if not already there | |
425 | if (0) // session.verbose_resolution | |
426 | cerr << " function " << name << " " | |
427 | << "is defined from " << f->name << endl; | |
428 | ||
429 | if (find (session.files.begin(), session.files.end(), f) | |
430 | == session.files.end()) | |
431 | session.files.push_back (f); | |
432 | // else .. print different message? | |
433 | ||
434 | return f->functions[j]; | |
435 | } | |
436 | } | |
437 | ||
438 | return 0; | |
439 | // XXX: add checking for conflicting variables | |
440 | } | |
441 | ||
442 | ||
443 | // ------------------------------------------------------------------------ | |
444 | // type resolution | |
445 | ||
446 | ||
447 | static int | |
448 | semantic_pass_types (systemtap_session& s) | |
449 | { | |
450 | int rc = 0; | |
451 | ||
452 | // next pass: type inference | |
453 | unsigned iterations = 0; | |
454 | typeresolution_info ti (s); | |
455 | ||
456 | ti.assert_resolvability = false; | |
457 | // XXX: maybe convert to exception-based error signalling | |
458 | while (1) | |
459 | { | |
460 | iterations ++; | |
461 | // cerr << "Type resolution, iteration " << iterations << endl; | |
462 | ti.num_newly_resolved = 0; | |
463 | ti.num_still_unresolved = 0; | |
464 | ||
465 | for (unsigned j=0; j<s.functions.size(); j++) | |
466 | { | |
467 | functiondecl* fn = s.functions[j]; | |
468 | ti.current_function = fn; | |
469 | ti.t = pe_unknown; | |
470 | fn->body->visit (& ti); | |
471 | // NB: we don't have to assert a known type for | |
472 | // functions here, to permit a "void" function. | |
473 | // The translator phase will omit the "retvalue". | |
474 | // | |
475 | // if (fn->type == pe_unknown) | |
476 | // ti.unresolved (fn->tok); | |
477 | } | |
478 | ||
479 | for (unsigned j=0; j<s.probes.size(); j++) | |
480 | { | |
481 | derived_probe* pn = s.probes[j]; | |
482 | ti.current_function = 0; | |
483 | ti.t = pe_unknown; | |
484 | pn->body->visit (& ti); | |
485 | } | |
486 | ||
487 | for (unsigned j=0; j<s.globals.size(); j++) | |
488 | { | |
489 | vardecl* gd = s.globals[j]; | |
490 | if (gd->type == pe_unknown) | |
491 | ti.unresolved (gd->tok); | |
492 | } | |
493 | ||
494 | if (ti.num_newly_resolved == 0) // converged | |
495 | if (ti.num_still_unresolved == 0) | |
496 | break; // successfully | |
497 | else if (! ti.assert_resolvability) | |
498 | ti.assert_resolvability = true; // last pass, with error msgs | |
499 | else | |
500 | { // unsuccessful conclusion | |
501 | rc ++; | |
502 | break; | |
503 | } | |
504 | } | |
505 | ||
506 | return rc + s.num_errors; | |
507 | } | |
508 | ||
509 | ||
510 | void | |
511 | typeresolution_info::visit_literal_number (literal_number* e) | |
512 | { | |
513 | assert (e->type == pe_long); | |
514 | if ((t == e->type) || (t == pe_unknown)) | |
515 | return; | |
516 | ||
517 | mismatch (e->tok, e->type, t); | |
518 | } | |
519 | ||
520 | ||
521 | void | |
522 | typeresolution_info::visit_literal_string (literal_string* e) | |
523 | { | |
524 | assert (e->type == pe_string); | |
525 | if ((t == e->type) || (t == pe_unknown)) | |
526 | return; | |
527 | ||
528 | mismatch (e->tok, e->type, t); | |
529 | } | |
530 | ||
531 | ||
532 | void | |
533 | typeresolution_info::visit_logical_or_expr (logical_or_expr *e) | |
534 | { | |
535 | visit_binary_expression (e); | |
536 | } | |
537 | ||
538 | ||
539 | void | |
540 | typeresolution_info::visit_logical_and_expr (logical_and_expr *e) | |
541 | { | |
542 | visit_binary_expression (e); | |
543 | } | |
544 | ||
545 | ||
546 | void | |
547 | typeresolution_info::visit_comparison (comparison *e) | |
548 | { | |
549 | visit_binary_expression (e); | |
550 | } | |
551 | ||
552 | ||
553 | void | |
554 | typeresolution_info::visit_concatenation (concatenation *e) | |
555 | { | |
556 | visit_binary_expression (e); | |
557 | } | |
558 | ||
559 | ||
560 | void | |
561 | typeresolution_info::visit_exponentiation (exponentiation *e) | |
562 | { | |
563 | visit_binary_expression (e); | |
564 | } | |
565 | ||
566 | ||
567 | void | |
568 | typeresolution_info::visit_assignment (assignment *e) | |
569 | { | |
570 | visit_binary_expression (e); | |
571 | } | |
572 | ||
573 | ||
574 | void | |
575 | typeresolution_info::visit_binary_expression (binary_expression* e) | |
576 | { | |
577 | if (e->op == "<<<") // stats aggregation | |
578 | { | |
579 | exp_type t1 = t; | |
580 | t = pe_stats; | |
581 | e->left->visit (this); | |
582 | t = pe_long; | |
583 | e->right->visit (this); | |
584 | if (t1 == pe_stats || t1 == pe_string) | |
585 | invalid (e->tok, t1); | |
586 | else if (e->type == pe_unknown) | |
587 | { | |
588 | e->type = pe_long; | |
589 | resolved (e->tok, e->type); | |
590 | } | |
591 | } | |
592 | else if (e->op == ".") // string concatenation | |
593 | { | |
594 | exp_type t1 = t; | |
595 | t = pe_string; | |
596 | e->left->visit (this); | |
597 | t = pe_string; | |
598 | e->right->visit (this); | |
599 | if (t1 == pe_long || t1 == pe_stats) | |
600 | mismatch (e->tok, t1, pe_string); | |
601 | else if (e->type == pe_unknown) | |
602 | { | |
603 | e->type = pe_string; | |
604 | resolved (e->tok, e->type); | |
605 | } | |
606 | } | |
607 | else if (e->op == "==" | |
608 | || false) // XXX: other comparison operators | |
609 | { | |
610 | exp_type t1 = t; | |
611 | t = pe_unknown; | |
612 | e->left->visit (this); | |
613 | t = pe_unknown; | |
614 | e->right->visit (this); | |
615 | if (t1 == pe_string || t1 == pe_stats) | |
616 | mismatch (e->tok, t1, pe_long); | |
617 | else if (e->type == pe_unknown) | |
618 | { | |
619 | e->type = pe_long; | |
620 | resolved (e->tok, e->type); | |
621 | } | |
622 | } | |
623 | else // general arithmetic operators? | |
624 | { | |
625 | // propagate e->type downward | |
626 | exp_type sub_type = t; | |
627 | if ((sub_type == pe_unknown) && (e->type != pe_unknown)) | |
628 | sub_type = e->type; | |
629 | t = sub_type; | |
630 | e->left->visit (this); | |
631 | t = sub_type; | |
632 | e->right->visit (this); | |
633 | ||
634 | if ((sub_type == pe_unknown) && (e->type != pe_unknown)) | |
635 | ; // already resolved | |
636 | else if ((sub_type != pe_unknown) && (e->type == pe_unknown)) | |
637 | { | |
638 | e->type = sub_type; | |
639 | resolved (e->tok, e->type); | |
640 | } | |
641 | else if ((sub_type == pe_unknown) && (e->left->type != pe_unknown)) | |
642 | { | |
643 | e->type = e->left->type; | |
644 | resolved (e->tok, e->type); | |
645 | } | |
646 | else if ((sub_type == pe_unknown) && (e->right->type != pe_unknown)) | |
647 | { | |
648 | e->type = e->right->type; | |
649 | resolved (e->tok, e->type); | |
650 | } | |
651 | else if (e->type != sub_type) | |
652 | mismatch (e->tok, sub_type, e->type); | |
653 | } | |
654 | } | |
655 | ||
656 | ||
657 | void | |
658 | typeresolution_info::visit_pre_crement (pre_crement *e) | |
659 | { | |
660 | visit_unary_expression (e); | |
661 | } | |
662 | ||
663 | ||
664 | void | |
665 | typeresolution_info::visit_post_crement (post_crement *e) | |
666 | { | |
667 | visit_unary_expression (e); | |
668 | } | |
669 | ||
670 | ||
671 | void | |
672 | typeresolution_info::visit_unary_expression (unary_expression* e) | |
673 | { | |
674 | // all unary operators only work on numerics | |
675 | exp_type t1 = t; | |
676 | t = pe_long; | |
677 | e->operand->visit (this); | |
678 | ||
679 | if (t1 == pe_unknown && e->type != pe_unknown) | |
680 | ; // already resolved | |
681 | else if (t1 == pe_string || t1 == pe_stats) | |
682 | mismatch (e->tok, t1, pe_long); | |
683 | else if (e->type == pe_unknown) | |
684 | { | |
685 | e->type = pe_long; | |
686 | resolved (e->tok, e->type); | |
687 | } | |
688 | } | |
689 | ||
690 | ||
691 | ||
692 | void | |
693 | typeresolution_info::visit_ternary_expression (ternary_expression* e) | |
694 | { | |
695 | exp_type sub_type = t; | |
696 | ||
697 | t = pe_long; | |
698 | e->cond->visit (this); | |
699 | ||
700 | // Match ordinary binary_expression type inference for the true/false | |
701 | // arms of the ternary expression. | |
702 | ||
703 | if (sub_type == pe_unknown && e->type != pe_unknown) | |
704 | sub_type = e->type; | |
705 | t = sub_type; | |
706 | e->truevalue->visit (this); | |
707 | t = sub_type; | |
708 | e->falsevalue->visit (this); | |
709 | ||
710 | if ((sub_type == pe_unknown) && (e->type != pe_unknown)) | |
711 | ; // already resolved | |
712 | else if ((sub_type != pe_unknown) && (e->type == pe_unknown)) | |
713 | { | |
714 | e->type = sub_type; | |
715 | resolved (e->tok, e->type); | |
716 | } | |
717 | else if ((sub_type == pe_unknown) && (e->truevalue->type != pe_unknown)) | |
718 | { | |
719 | e->type = e->truevalue->type; | |
720 | resolved (e->tok, e->type); | |
721 | } | |
722 | else if ((sub_type == pe_unknown) && (e->falsevalue->type != pe_unknown)) | |
723 | { | |
724 | e->type = e->falsevalue->type; | |
725 | resolved (e->tok, e->type); | |
726 | } | |
727 | else if (e->type != sub_type) | |
728 | mismatch (e->tok, sub_type, e->type); | |
729 | } | |
730 | ||
731 | ||
732 | template <class Referrer, class Referent> | |
733 | void resolve_2types (Referrer* referrer, Referent* referent, | |
734 | typeresolution_info* r, exp_type t) | |
735 | { | |
736 | exp_type& re_type = referrer->type; | |
737 | const token* re_tok = referrer->tok; | |
738 | exp_type& te_type = referent->type; | |
739 | const token* te_tok = referent->tok; | |
740 | ||
741 | if (t != pe_unknown && re_type == t && re_type == te_type) | |
742 | ; // do nothing: all three e->types in agreement | |
743 | else if (t == pe_unknown && re_type != pe_unknown && re_type == te_type) | |
744 | ; // do nothing: two known e->types in agreement | |
745 | else if (re_type != pe_unknown && te_type != pe_unknown && re_type != te_type) | |
746 | r->mismatch (re_tok, re_type, te_type); | |
747 | else if (re_type != pe_unknown && t != pe_unknown && re_type != t) | |
748 | r->mismatch (re_tok, re_type, t); | |
749 | else if (te_type != pe_unknown && t != pe_unknown && te_type != t) | |
750 | r->mismatch (te_tok, te_type, t); | |
751 | else if (re_type == pe_unknown && t != pe_unknown) | |
752 | { | |
753 | // propagate from upstream | |
754 | re_type = t; | |
755 | r->resolved (re_tok, re_type); | |
756 | // catch re_type/te_type mismatch later | |
757 | } | |
758 | else if (re_type == pe_unknown && te_type != pe_unknown) | |
759 | { | |
760 | // propagate from referent | |
761 | re_type = te_type; | |
762 | r->resolved (re_tok, re_type); | |
763 | // catch re_type/t mismatch later | |
764 | } | |
765 | else if (re_type != pe_unknown && te_type == pe_unknown) | |
766 | { | |
767 | // propagate to referent | |
768 | te_type = re_type; | |
769 | r->resolved (te_tok, te_type); | |
770 | // catch re_type/t mismatch later | |
771 | } | |
772 | else | |
773 | r->unresolved (re_tok); | |
774 | } | |
775 | ||
776 | ||
777 | void | |
778 | typeresolution_info::visit_symbol (symbol* e) | |
779 | { | |
780 | assert (e->referent != 0); | |
781 | ||
782 | if (e->referent->arity > 0) | |
783 | unresolved (e->tok); // symbol resolution should not permit this | |
784 | // XXX: but consider "delete <array>;" and similar constructs | |
785 | else | |
786 | resolve_2types (e, e->referent, this, t); | |
787 | } | |
788 | ||
789 | ||
790 | void | |
791 | typeresolution_info::visit_arrayindex (arrayindex* e) | |
792 | { | |
793 | assert (e->referent != 0); | |
794 | ||
795 | resolve_2types (e, e->referent, this, t); | |
796 | ||
797 | // now resolve the array indexes | |
69c68955 FCE |
798 | |
799 | // if (e->referent->index_types.size() == 0) | |
800 | // // redesignate referent as array | |
801 | // e->referent->set_arity (e->indexes.size ()); | |
2b066ec1 FCE |
802 | |
803 | if (e->indexes.size() != e->referent->index_types.size()) | |
804 | unresolved (e->tok); // symbol resolution should prevent this | |
805 | else for (unsigned i=0; i<e->indexes.size(); i++) | |
806 | { | |
807 | expression* ee = e->indexes[i]; | |
808 | exp_type& ft = e->referent->index_types [i]; | |
809 | t = ft; | |
810 | ee->visit (this); | |
811 | exp_type at = ee->type; | |
812 | ||
813 | if ((at == pe_string || at == pe_long) && ft == pe_unknown) | |
814 | { | |
815 | // propagate to formal type | |
816 | ft = at; | |
817 | resolved (e->referent->tok, ft); | |
818 | // uses array decl as there is no token for "formal type" | |
819 | } | |
820 | if (at == pe_stats) | |
821 | invalid (ee->tok, at); | |
822 | if (ft == pe_stats) | |
823 | invalid (ee->tok, ft); | |
824 | if (at != pe_unknown && ft != pe_unknown && ft != at) | |
825 | mismatch (e->tok, at, ft); | |
826 | if (at == pe_unknown) | |
827 | unresolved (ee->tok); | |
828 | } | |
829 | } | |
830 | ||
831 | ||
832 | void | |
833 | typeresolution_info::visit_functioncall (functioncall* e) | |
834 | { | |
835 | assert (e->referent != 0); | |
836 | ||
837 | resolve_2types (e, e->referent, this, t); | |
838 | ||
839 | if (e->type == pe_stats) | |
840 | invalid (e->tok, e->type); | |
841 | ||
842 | // XXX: but what about functions that return no value, | |
843 | // and are used only as an expression-statement for side effects? | |
844 | ||
845 | // now resolve the function parameters | |
846 | if (e->args.size() != e->referent->formal_args.size()) | |
847 | unresolved (e->tok); // symbol resolution should prevent this | |
848 | else for (unsigned i=0; i<e->args.size(); i++) | |
849 | { | |
850 | expression* ee = e->args[i]; | |
851 | exp_type& ft = e->referent->formal_args[i]->type; | |
852 | const token* fe_tok = e->referent->formal_args[i]->tok; | |
853 | t = ft; | |
854 | ee->visit (this); | |
855 | exp_type at = ee->type; | |
856 | ||
857 | if (((at == pe_string) || (at == pe_long)) && ft == pe_unknown) | |
858 | { | |
859 | // propagate to formal arg | |
860 | ft = at; | |
861 | resolved (e->referent->formal_args[i]->tok, ft); | |
862 | } | |
863 | if (at == pe_stats) | |
864 | invalid (e->tok, at); | |
865 | if (ft == pe_stats) | |
866 | invalid (fe_tok, ft); | |
867 | if (at != pe_unknown && ft != pe_unknown && ft != at) | |
868 | mismatch (e->tok, at, ft); | |
869 | if (at == pe_unknown) | |
870 | unresolved (e->tok); | |
871 | } | |
872 | } | |
873 | ||
874 | ||
875 | void | |
876 | typeresolution_info::visit_block (block* e) | |
877 | { | |
878 | for (unsigned i=0; i<e->statements.size(); i++) | |
879 | { | |
880 | try | |
881 | { | |
882 | t = pe_unknown; | |
883 | e->statements[i]->visit (this); | |
884 | } | |
885 | catch (const semantic_error& e) | |
886 | { | |
887 | session.print_error (e); | |
888 | } | |
889 | } | |
890 | } | |
891 | ||
892 | ||
893 | void | |
894 | typeresolution_info::visit_if_statement (if_statement* e) | |
895 | { | |
896 | t = pe_long; | |
897 | e->condition->visit (this); | |
898 | ||
899 | t = pe_unknown; | |
900 | e->thenblock->visit (this); | |
901 | ||
902 | if (e->elseblock) | |
903 | { | |
904 | t = pe_unknown; | |
905 | e->elseblock->visit (this); | |
906 | } | |
907 | } | |
908 | ||
909 | ||
910 | void | |
911 | typeresolution_info::visit_for_loop (for_loop* e) | |
912 | { | |
913 | t = pe_unknown; | |
914 | e->init->visit (this); | |
915 | t = pe_long; | |
916 | e->cond->visit (this); | |
917 | t = pe_unknown; | |
918 | e->incr->visit (this); | |
919 | t = pe_unknown; | |
920 | e->block->visit (this); | |
921 | } | |
922 | ||
923 | ||
69c68955 FCE |
924 | void |
925 | typeresolution_info::visit_foreach_loop (foreach_loop* e) | |
926 | { | |
927 | // See also visit_arrayindex. | |
928 | // This is different in that, being a statement, we can't assign | |
929 | // a type to the outer array, only propagate to/from the indexes | |
930 | ||
931 | // if (e->referent->index_types.size() == 0) | |
932 | // // redesignate referent as array | |
933 | // e->referent->set_arity (e->indexes.size ()); | |
934 | ||
935 | if (e->indexes.size() != e->base_referent->index_types.size()) | |
936 | unresolved (e->tok); // symbol resolution should prevent this | |
937 | else for (unsigned i=0; i<e->indexes.size(); i++) | |
938 | { | |
939 | expression* ee = e->indexes[i]; | |
940 | exp_type& ft = e->base_referent->index_types [i]; | |
941 | t = ft; | |
942 | ee->visit (this); | |
943 | exp_type at = ee->type; | |
944 | ||
945 | if ((at == pe_string || at == pe_long) && ft == pe_unknown) | |
946 | { | |
947 | // propagate to formal type | |
948 | ft = at; | |
949 | resolved (e->base_referent->tok, ft); | |
950 | // uses array decl as there is no token for "formal type" | |
951 | } | |
952 | if (at == pe_stats) | |
953 | invalid (ee->tok, at); | |
954 | if (ft == pe_stats) | |
955 | invalid (ee->tok, ft); | |
956 | if (at != pe_unknown && ft != pe_unknown && ft != at) | |
957 | mismatch (e->tok, at, ft); | |
958 | if (at == pe_unknown) | |
959 | unresolved (ee->tok); | |
960 | } | |
961 | ||
962 | t = pe_unknown; | |
963 | e->block->visit (this); | |
964 | } | |
965 | ||
966 | ||
2b066ec1 FCE |
967 | void |
968 | typeresolution_info::visit_null_statement (null_statement* e) | |
969 | { | |
970 | } | |
971 | ||
972 | ||
973 | void | |
974 | typeresolution_info::visit_expr_statement (expr_statement* e) | |
975 | { | |
976 | t = pe_unknown; | |
977 | e->value->visit (this); | |
978 | } | |
979 | ||
980 | ||
981 | void | |
982 | typeresolution_info::visit_delete_statement (delete_statement* e) | |
983 | { | |
984 | // XXX: not yet supported | |
985 | unresolved (e->tok); | |
986 | } | |
987 | ||
988 | ||
989 | void | |
990 | typeresolution_info::visit_array_in (array_in* e) | |
991 | { | |
ce10591c FCE |
992 | // all unary operators only work on numerics |
993 | exp_type t1 = t; | |
994 | t = pe_unknown; // array value can be anything | |
995 | e->operand->visit (this); | |
996 | ||
997 | if (t1 == pe_unknown && e->type != pe_unknown) | |
998 | ; // already resolved | |
999 | else if (t1 == pe_string || t1 == pe_stats) | |
1000 | mismatch (e->tok, t1, pe_long); | |
1001 | else if (e->type == pe_unknown) | |
1002 | { | |
1003 | e->type = pe_long; | |
1004 | resolved (e->tok, e->type); | |
1005 | } | |
2b066ec1 FCE |
1006 | } |
1007 | ||
1008 | ||
1009 | void | |
1010 | typeresolution_info::visit_return_statement (return_statement* e) | |
1011 | { | |
1012 | // This is like symbol, where the referent is | |
1013 | // the return value of the function. | |
1014 | ||
1015 | // XXX: need control flow semantic checking; until then: | |
1016 | if (current_function == 0) | |
1017 | { | |
1018 | unresolved (e->tok); | |
1019 | return; | |
1020 | } | |
1021 | ||
1022 | exp_type& e_type = current_function->type; | |
1023 | t = current_function->type; | |
1024 | e->value->visit (this); | |
1025 | ||
1026 | if (e_type != pe_unknown && e->value->type != pe_unknown | |
1027 | && e_type != e->value->type) | |
1028 | mismatch (current_function->tok, e_type, e->value->type); | |
1029 | if (e_type == pe_unknown && | |
1030 | (e->value->type == pe_long || e->value->type == pe_string)) | |
1031 | { | |
1032 | // propagate non-statistics from value | |
1033 | e_type = e->value->type; | |
1034 | resolved (current_function->tok, e->value->type); | |
1035 | } | |
1036 | if (e->value->type == pe_stats) | |
1037 | invalid (e->value->tok, e->value->type); | |
1038 | } | |
1039 | ||
1040 | ||
1041 | void | |
1042 | typeresolution_info::unresolved (const token* tok) | |
1043 | { | |
1044 | num_still_unresolved ++; | |
1045 | ||
1046 | if (assert_resolvability) | |
1047 | { | |
1048 | cerr << "error: unresolved type for "; | |
1049 | if (tok) | |
1050 | cerr << *tok; | |
1051 | else | |
1052 | cerr << "a token"; | |
1053 | cerr << endl; | |
1054 | } | |
1055 | } | |
1056 | ||
1057 | ||
1058 | void | |
1059 | typeresolution_info::invalid (const token* tok, exp_type pe) | |
1060 | { | |
1061 | num_still_unresolved ++; | |
1062 | ||
1063 | if (assert_resolvability) | |
1064 | { | |
1065 | cerr << "error: invalid type " << pe << " for "; | |
1066 | if (tok) | |
1067 | cerr << *tok; | |
1068 | else | |
1069 | cerr << "a token"; | |
1070 | cerr << endl; | |
1071 | } | |
1072 | } | |
1073 | ||
1074 | ||
1075 | void | |
1076 | typeresolution_info::mismatch (const token* tok, exp_type t1, exp_type t2) | |
1077 | { | |
1078 | num_still_unresolved ++; | |
1079 | ||
1080 | if (assert_resolvability) | |
1081 | { | |
1082 | cerr << "error: type mismatch for "; | |
1083 | if (tok) | |
1084 | cerr << *tok; | |
1085 | else | |
1086 | cerr << "a token"; | |
1087 | cerr << ": " << t1 << " vs. " << t2 << endl; | |
1088 | } | |
1089 | } | |
1090 | ||
1091 | ||
1092 | void | |
1093 | typeresolution_info::resolved (const token* tok, exp_type t) | |
1094 | { | |
1095 | num_newly_resolved ++; | |
1096 | // cerr << "resolved " << *e->tok << " type " << t << endl; | |
1097 | } | |
1098 |