Branch data Line data Source code
1 : : // ast-dump.cc -- AST debug dump. -*- C++ -*-
2 : :
3 : : // Copyright 2011 The Go Authors. All rights reserved.
4 : : // Use of this source code is governed by a BSD-style
5 : : // license that can be found in the LICENSE file.
6 : :
7 : : #include "go-system.h"
8 : :
9 : : #include <iostream>
10 : : #include <fstream>
11 : : #include <sstream>
12 : :
13 : : #include "gogo.h"
14 : : #include "expressions.h"
15 : : #include "statements.h"
16 : : #include "types.h"
17 : : #include "ast-dump.h"
18 : : #include "go-c.h"
19 : : #include "go-dump.h"
20 : : #include "go-diagnostics.h"
21 : :
22 : : // The -fgo-dump-ast flag to activate AST dumps.
23 : :
24 : : Go_dump ast_dump_flag("ast");
25 : :
26 : : // This class is used to traverse the tree to look for blocks and
27 : : // function headers.
28 : :
29 : 0 : class Ast_dump_traverse_blocks_and_functions : public Traverse
30 : : {
31 : : public:
32 : 0 : Ast_dump_traverse_blocks_and_functions(Ast_dump_context* ast_dump_context)
33 : 0 : : Traverse(traverse_blocks | traverse_functions | traverse_variables),
34 : 0 : ast_dump_context_(ast_dump_context)
35 : : { }
36 : :
37 : : protected:
38 : : int
39 : : block(Block*);
40 : :
41 : : int
42 : : function(Named_object*);
43 : :
44 : : int
45 : : variable(Named_object*);
46 : :
47 : : private:
48 : : Ast_dump_context* ast_dump_context_;
49 : : };
50 : :
51 : : // This class is used to traverse the tree to look for statements.
52 : :
53 : 0 : class Ast_dump_traverse_statements : public Traverse
54 : : {
55 : : public:
56 : 0 : Ast_dump_traverse_statements(Ast_dump_context* ast_dump_context)
57 : 0 : : Traverse(traverse_statements),
58 : 0 : ast_dump_context_(ast_dump_context)
59 : : { }
60 : :
61 : : protected:
62 : : int
63 : : statement(Block*, size_t* pindex, Statement*);
64 : :
65 : : private:
66 : : Ast_dump_context* ast_dump_context_;
67 : : };
68 : :
69 : : // For each block we enclose it in brackets.
70 : :
71 : 0 : int Ast_dump_traverse_blocks_and_functions::block(Block * block)
72 : : {
73 : 0 : if (block == NULL)
74 : : {
75 : 0 : this->ast_dump_context_->ostream() << std::endl;
76 : 0 : return TRAVERSE_EXIT;
77 : : }
78 : :
79 : 0 : this->ast_dump_context_->print_indent();
80 : 0 : this->ast_dump_context_->ostream() << "{" << std::endl;
81 : 0 : this->ast_dump_context_->indent();
82 : :
83 : : // Dump statememts.
84 : 0 : Ast_dump_traverse_statements adts(this->ast_dump_context_);
85 : 0 : block->traverse(&adts);
86 : :
87 : 0 : this->ast_dump_context_->unindent();
88 : 0 : this->ast_dump_context_->print_indent();
89 : 0 : this->ast_dump_context_->ostream() << "}" << std::endl;
90 : :
91 : 0 : return TRAVERSE_SKIP_COMPONENTS;
92 : 0 : }
93 : :
94 : : // Dump each traversed statement.
95 : :
96 : : int
97 : 0 : Ast_dump_traverse_statements::statement(Block* block, size_t* pindex,
98 : : Statement* statement)
99 : : {
100 : 0 : statement->dump_statement(this->ast_dump_context_);
101 : :
102 : 0 : if (statement->is_block_statement())
103 : : {
104 : 0 : Ast_dump_traverse_blocks_and_functions adtbf(this->ast_dump_context_);
105 : 0 : statement->traverse(block, pindex, &adtbf);
106 : 0 : }
107 : :
108 : 0 : return TRAVERSE_SKIP_COMPONENTS;
109 : : }
110 : :
111 : : // Dump the function header.
112 : :
113 : : int
114 : 0 : Ast_dump_traverse_blocks_and_functions::function(Named_object* no)
115 : : {
116 : 0 : this->ast_dump_context_->ostream() << no->name();
117 : :
118 : 0 : go_assert(no->is_function());
119 : 0 : Function* func = no->func_value();
120 : :
121 : 0 : this->ast_dump_context_->ostream() << "(";
122 : 0 : this->ast_dump_context_->dump_typed_identifier_list(
123 : : func->type()->parameters());
124 : :
125 : 0 : this->ast_dump_context_->ostream() << ")";
126 : :
127 : 0 : Function::Results* res = func->result_variables();
128 : 0 : if (res != NULL && !res->empty())
129 : : {
130 : 0 : this->ast_dump_context_->ostream() << " (";
131 : :
132 : 0 : for (Function::Results::const_iterator it = res->begin();
133 : 0 : it != res->end();
134 : 0 : it++)
135 : : {
136 : 0 : if (it != res->begin())
137 : 0 : this->ast_dump_context_->ostream() << ",";
138 : 0 : Named_object* rno = (*it);
139 : :
140 : 0 : this->ast_dump_context_->ostream() << rno->name() << " ";
141 : 0 : go_assert(rno->is_result_variable());
142 : 0 : Result_variable* resvar = rno->result_var_value();
143 : :
144 : 0 : this->ast_dump_context_->dump_type(resvar->type());
145 : :
146 : : }
147 : 0 : this->ast_dump_context_->ostream() << ")";
148 : : }
149 : :
150 : 0 : this->ast_dump_context_->ostream() << " : ";
151 : 0 : this->ast_dump_context_->dump_type(func->type());
152 : 0 : this->ast_dump_context_->ostream() << std::endl;
153 : :
154 : 0 : return TRAVERSE_CONTINUE;
155 : : }
156 : :
157 : : // Dump variable preinits
158 : :
159 : : int
160 : 0 : Ast_dump_traverse_blocks_and_functions::variable(Named_object* no)
161 : : {
162 : 0 : if (!no->is_variable())
163 : : return TRAVERSE_CONTINUE;
164 : :
165 : 0 : Variable* var = no->var_value();
166 : 0 : if (var->has_pre_init())
167 : : {
168 : 0 : this->ast_dump_context_->ostream() << "// preinit block for var "
169 : 0 : << no->message_name() << "\n";
170 : 0 : var->preinit()->traverse(this);
171 : : }
172 : :
173 : : return TRAVERSE_CONTINUE;
174 : : }
175 : :
176 : :
177 : :
178 : : // Class Ast_dump_context.
179 : :
180 : 0 : Ast_dump_context::Ast_dump_context(std::ostream* out /* = NULL */,
181 : 0 : bool dump_subblocks /* = true */)
182 : 0 : : indent_(0), dump_subblocks_(dump_subblocks), ostream_(out), gogo_(NULL)
183 : : {
184 : 0 : }
185 : :
186 : : // Dump files will be named %basename%.dump.ast
187 : :
188 : : const char* kAstDumpFileExtension = ".dump.ast";
189 : :
190 : : // Dump the internal representation.
191 : :
192 : : void
193 : 0 : Ast_dump_context::dump(Gogo* gogo, const char* basename)
194 : : {
195 : 0 : std::ofstream out;
196 : 0 : std::string dumpname(basename);
197 : 0 : dumpname += ".dump.ast";
198 : 0 : out.open(dumpname.c_str());
199 : :
200 : 0 : if (out.fail())
201 : : {
202 : 0 : go_error_at(Linemap::unknown_location(),
203 : : "cannot open %s:%m; %<-fgo-dump-ast%> ignored",
204 : : dumpname.c_str());
205 : 0 : return;
206 : : }
207 : :
208 : 0 : this->gogo_ = gogo;
209 : 0 : this->ostream_ = &out;
210 : :
211 : 0 : Ast_dump_traverse_blocks_and_functions adtbf(this);
212 : 0 : gogo->traverse(&adtbf);
213 : :
214 : 0 : out.close();
215 : 0 : }
216 : :
217 : : // Dump a textual representation of a type to the
218 : : // the dump file.
219 : :
220 : : void
221 : 0 : Ast_dump_context::dump_type(const Type* t)
222 : : {
223 : 0 : if (t == NULL)
224 : 0 : this->ostream() << "(nil type)";
225 : : else
226 : 0 : this->ostream() << "(" << t->message_name() << ")";
227 : 0 : }
228 : :
229 : : // Dump a textual representation of a block to the
230 : : // the dump file.
231 : :
232 : : void
233 : 0 : Ast_dump_context::dump_block(Block* b)
234 : : {
235 : 0 : Ast_dump_traverse_blocks_and_functions adtbf(this);
236 : 0 : b->traverse(&adtbf);
237 : 0 : }
238 : :
239 : : // Dump a textual representation of an expression to the
240 : : // the dump file.
241 : :
242 : : void
243 : 0 : Ast_dump_context::dump_expression(const Expression* e)
244 : : {
245 : 0 : e->dump_expression(this);
246 : 0 : }
247 : :
248 : : // Dump a textual representation of an expression list to the
249 : : // the dump file.
250 : :
251 : : void
252 : 0 : Ast_dump_context::dump_expression_list(const Expression_list* el,
253 : : bool as_pairs /* = false */)
254 : : {
255 : 0 : if (el == NULL)
256 : : return;
257 : :
258 : 0 : for (std::vector<Expression*>::const_iterator it = el->begin();
259 : 0 : it != el->end();
260 : 0 : it++)
261 : : {
262 : 0 : if ( it != el->begin())
263 : 0 : this->ostream() << ",";
264 : 0 : if (*it != NULL)
265 : 0 : (*it)->dump_expression(this);
266 : : else
267 : 0 : this->ostream() << "NULL";
268 : 0 : if (as_pairs)
269 : : {
270 : 0 : this->ostream() << ":";
271 : 0 : ++it;
272 : 0 : (*it)->dump_expression(this);
273 : : }
274 : : }
275 : : }
276 : :
277 : : // Dump a textual representation of a typed identifier to the
278 : : // the dump file.
279 : :
280 : : void
281 : 0 : Ast_dump_context::dump_typed_identifier(const Typed_identifier* ti)
282 : : {
283 : 0 : this->ostream() << ti->name() << " ";
284 : 0 : this->dump_type(ti->type());
285 : 0 : }
286 : :
287 : : // Dump a textual representation of a typed identifier list to the
288 : : // the dump file.
289 : :
290 : : void
291 : 0 : Ast_dump_context::dump_typed_identifier_list(
292 : : const Typed_identifier_list* ti_list)
293 : : {
294 : 0 : if (ti_list == NULL)
295 : : return;
296 : :
297 : 0 : for (Typed_identifier_list::const_iterator it = ti_list->begin();
298 : 0 : it != ti_list->end();
299 : 0 : it++)
300 : : {
301 : 0 : if (it != ti_list->begin())
302 : 0 : this->ostream() << ",";
303 : 0 : this->dump_typed_identifier(&(*it));
304 : : }
305 : : }
306 : :
307 : : // Dump a textual representation of a temporary variable to the
308 : : // the dump file.
309 : :
310 : : void
311 : 0 : Ast_dump_context::dump_temp_variable_name(const Statement* s)
312 : : {
313 : 0 : go_assert(s->classification() == Statement::STATEMENT_TEMPORARY);
314 : : // Use the statement address as part of the name for the temporary variable.
315 : 0 : this->ostream() << "tmp." << (uintptr_t) s;
316 : 0 : }
317 : :
318 : : // Dump a textual representation of a label to the
319 : : // the dump file.
320 : :
321 : : void
322 : 0 : Ast_dump_context::dump_label_name(const Unnamed_label* l)
323 : : {
324 : : // Use the unnamed label address as part of the name for the temporary
325 : : // variable.
326 : 0 : this->ostream() << "label." << (uintptr_t) l;
327 : 0 : }
328 : :
329 : : // Produce a textual representation of an operator symbol.
330 : :
331 : : static const char*
332 : 0 : op_string(Operator op)
333 : : {
334 : : // FIXME: This should be in line with symbols that are parsed,
335 : : // exported and/or imported.
336 : 0 : switch (op)
337 : : {
338 : : case OPERATOR_PLUS:
339 : : return "+";
340 : 0 : case OPERATOR_MINUS:
341 : 0 : return "-";
342 : 0 : case OPERATOR_NOT:
343 : 0 : return "!";
344 : 0 : case OPERATOR_XOR:
345 : 0 : return "^";
346 : 0 : case OPERATOR_OR:
347 : 0 : return "|";
348 : 0 : case OPERATOR_AND:
349 : 0 : return "&";
350 : 0 : case OPERATOR_MULT:
351 : 0 : return "*";
352 : 0 : case OPERATOR_OROR:
353 : 0 : return "||";
354 : 0 : case OPERATOR_ANDAND:
355 : 0 : return "&&";
356 : 0 : case OPERATOR_EQEQ:
357 : 0 : return "==";
358 : 0 : case OPERATOR_NOTEQ:
359 : 0 : return "!=";
360 : 0 : case OPERATOR_LT:
361 : 0 : return "<";
362 : 0 : case OPERATOR_LE:
363 : 0 : return "<=";
364 : 0 : case OPERATOR_GT:
365 : 0 : return ">";
366 : 0 : case OPERATOR_GE:
367 : 0 : return ">=";
368 : 0 : case OPERATOR_DIV:
369 : 0 : return "/";
370 : 0 : case OPERATOR_MOD:
371 : 0 : return "%";
372 : 0 : case OPERATOR_LSHIFT:
373 : 0 : return "<<";
374 : 0 : case OPERATOR_RSHIFT:
375 : 0 : return "//";
376 : 0 : case OPERATOR_BITCLEAR:
377 : 0 : return "&^";
378 : 0 : case OPERATOR_CHANOP:
379 : 0 : return "<-";
380 : 0 : case OPERATOR_PLUSEQ:
381 : 0 : return "+=";
382 : 0 : case OPERATOR_MINUSEQ:
383 : 0 : return "-=";
384 : 0 : case OPERATOR_OREQ:
385 : 0 : return "|=";
386 : 0 : case OPERATOR_XOREQ:
387 : 0 : return "^=";
388 : 0 : case OPERATOR_MULTEQ:
389 : 0 : return "*=";
390 : 0 : case OPERATOR_DIVEQ:
391 : 0 : return "/=";
392 : 0 : case OPERATOR_MODEQ:
393 : 0 : return "%=";
394 : 0 : case OPERATOR_LSHIFTEQ:
395 : 0 : return "<<=";
396 : 0 : case OPERATOR_RSHIFTEQ:
397 : 0 : return ">>=";
398 : 0 : case OPERATOR_ANDEQ:
399 : 0 : return "&=";
400 : 0 : case OPERATOR_BITCLEAREQ:
401 : 0 : return "&^=";
402 : 0 : case OPERATOR_PLUSPLUS:
403 : 0 : return "++";
404 : 0 : case OPERATOR_MINUSMINUS:
405 : 0 : return "--";
406 : 0 : case OPERATOR_COLON:
407 : 0 : return ":";
408 : 0 : case OPERATOR_COLONEQ:
409 : 0 : return ":=";
410 : 0 : case OPERATOR_SEMICOLON:
411 : 0 : return ";";
412 : 0 : case OPERATOR_DOT:
413 : 0 : return ".";
414 : 0 : case OPERATOR_ELLIPSIS:
415 : 0 : return "...";
416 : 0 : case OPERATOR_COMMA:
417 : 0 : return ",";
418 : 0 : case OPERATOR_LPAREN:
419 : 0 : return "(";
420 : 0 : case OPERATOR_RPAREN:
421 : 0 : return ")";
422 : 0 : case OPERATOR_LCURLY:
423 : 0 : return "{";
424 : 0 : case OPERATOR_RCURLY:
425 : 0 : return "}";
426 : 0 : case OPERATOR_LSQUARE:
427 : 0 : return "[";
428 : 0 : case OPERATOR_RSQUARE:
429 : 0 : return "]";
430 : 0 : default:
431 : 0 : go_unreachable();
432 : : }
433 : : return NULL;
434 : : }
435 : :
436 : : // Dump a textual representation of an operator to the
437 : : // the dump file.
438 : :
439 : : void
440 : 0 : Ast_dump_context::dump_operator(Operator op)
441 : : {
442 : 0 : this->ostream() << op_string(op);
443 : 0 : }
444 : :
445 : : // Size of a single indent.
446 : :
447 : : const int Ast_dump_context::offset_ = 2;
448 : :
449 : : // Print indenting spaces to dump file.
450 : :
451 : : void
452 : 0 : Ast_dump_context::print_indent()
453 : : {
454 : 0 : for (int i = 0; i < this->indent_ * this->offset_; i++)
455 : 0 : this->ostream() << " ";
456 : 0 : }
457 : :
458 : : // Dump a textual representation of the ast to the
459 : : // the dump file.
460 : :
461 : 4645 : void Gogo::dump_ast(const char* basename)
462 : : {
463 : 4645 : if (::ast_dump_flag.is_enabled())
464 : : {
465 : 0 : Ast_dump_context adc;
466 : 0 : adc.dump(this, basename);
467 : : }
468 : 4645 : }
469 : :
470 : : // Implementation of String_dump interface.
471 : :
472 : : void
473 : 0 : Ast_dump_context::write_c_string(const char* s)
474 : : {
475 : 0 : this->ostream() << s;
476 : 0 : }
477 : :
478 : : void
479 : 0 : Ast_dump_context::write_string(const std::string& s)
480 : : {
481 : 0 : this->ostream() << s;
482 : 0 : }
483 : :
484 : : // Dump statement to stream.
485 : :
486 : : void
487 : 0 : Ast_dump_context::dump_to_stream(const Statement* stm, std::ostream* out)
488 : : {
489 : 0 : Ast_dump_context adc(out, false);
490 : 0 : stm->dump_statement(&adc);
491 : 0 : }
492 : :
493 : : // Dump expression to stream.
494 : :
495 : : void
496 : 0 : Ast_dump_context::dump_to_stream(const Expression* expr, std::ostream* out)
497 : : {
498 : 0 : Ast_dump_context adc(out, false);
499 : 0 : expr->dump_expression(&adc);
500 : 0 : }
501 : :
502 : : // Dump an expression to std::cerr. This is intended to be used
503 : : // from within a debugging session.
504 : :
505 : : void
506 : 0 : debug_go_expression(const Expression* expr)
507 : : {
508 : 0 : if (expr == NULL)
509 : 0 : std::cerr << "<null>";
510 : : else
511 : : {
512 : 0 : Ast_dump_context::dump_to_stream(expr, &std::cerr);
513 : 0 : std::string lstr = Linemap::location_to_string(expr->location());
514 : 0 : std::cerr << " // loc " << lstr << std::endl;
515 : 0 : }
516 : 0 : }
517 : :
518 : : // Shallow dump of stmt to std::cerr. This is intended to be used
519 : : // from within a debugging session.
520 : :
521 : : void
522 : 0 : debug_go_statement(const Statement* stmt)
523 : : {
524 : 0 : if (stmt == NULL)
525 : 0 : std::cerr << "<null>\n";
526 : : else
527 : : {
528 : 0 : std::string lstr = Linemap::location_to_string(stmt->location());
529 : 0 : Statement *ncstmt = const_cast<Statement*>(stmt);
530 : 0 : Block_statement* bs = ncstmt->block_statement();
531 : 0 : if (bs != NULL)
532 : 0 : std::cerr << "Block " << bs->block()
533 : 0 : << " // location: " << lstr << std::endl;
534 : : else
535 : 0 : Ast_dump_context::dump_to_stream(stmt, &std::cerr);
536 : 0 : }
537 : 0 : }
538 : :
539 : : // Deep dump of statement to std::cerr. This is intended to be used
540 : : // from within a debugging session.
541 : :
542 : : void
543 : 0 : debug_go_statement_deep(const Statement* statement)
544 : : {
545 : 0 : Ast_dump_context adc(&std::cerr, true);
546 : 0 : statement->dump_statement(&adc);
547 : 0 : }
548 : :
549 : : // Shallow dump of a block to std::cerr. This is intended to be used
550 : : // from within a debugging session.
551 : :
552 : : void
553 : 0 : debug_go_block(const Block* block)
554 : : {
555 : 0 : if (block == NULL)
556 : 0 : std::cerr << "<null>";
557 : : else
558 : : {
559 : 0 : std::cerr << "Block " << block
560 : 0 : << " (enclosing " << block->enclosing() << "):\n";
561 : 0 : const std::vector<Statement*>* stmts = block->statements();
562 : 0 : if (stmts != NULL)
563 : : {
564 : 0 : for (size_t i = 0; i < stmts->size(); ++i)
565 : : {
566 : 0 : debug_go_statement(stmts->at(i));
567 : : }
568 : : }
569 : : }
570 : 0 : }
571 : :
572 : : // Deep dump of a block to std:cerr. This is intended to be used
573 : : // from within a debugging session.
574 : :
575 : : void
576 : 0 : debug_go_block_deep(const Block* block)
577 : : {
578 : 0 : Ast_dump_context adc(&std::cerr, true);
579 : 0 : Block* ncblock = const_cast<Block*>(block);
580 : 0 : adc.dump_block(ncblock);
581 : 0 : }
582 : :
583 : : class Type_dumper
584 : : {
585 : : typedef Unordered_map(const Type*, unsigned) idx_map;
586 : : public:
587 : 0 : Type_dumper(const Type* type)
588 : 0 : : top_(type), ntypes_(0)
589 : : {
590 : 0 : this->worklist_.push_back(type);
591 : 0 : }
592 : :
593 : : void visit();
594 : :
595 : 0 : std::string stringResult() { return ss_.str(); }
596 : :
597 : : private:
598 : : void emitpre(unsigned tag, const Type* addr);
599 : : void typeref(const char*, const Type*, const char *);
600 : : void visit_forward_declaration_type(const Forward_declaration_type* fdt);
601 : : void visit_function_type(const Function_type* ft);
602 : : void visit_struct_type(const Struct_type* st);
603 : : void visit_array_type(const Array_type* at);
604 : : void visit_map_type(const Map_type* mt);
605 : : void visit_channel_type(const Channel_type* mt);
606 : : void visit_interface_type(const Interface_type* mt);
607 : : void visit_methods(const Typed_identifier_list* methods,
608 : : const char *tag);
609 : : std::pair<bool, unsigned> lookup(const Type*);
610 : :
611 : : static const unsigned notag = 0xffffffff;
612 : :
613 : : private:
614 : : const Type* top_;
615 : : idx_map types_;
616 : : unsigned ntypes_;
617 : : std::list<const Type*> worklist_;
618 : : std::ostringstream ss_;
619 : : };
620 : :
621 : : // Look up a type, installing it in 'types_'. Return is <found, N>
622 : : // where 'found' is true if type had been previously recorded, and N
623 : : // is the index/tag assigned to N. The input argument is appended to
624 : : // the work list if this is the first time we've seen it.
625 : :
626 : 0 : std::pair<bool, unsigned> Type_dumper::lookup(const Type* t)
627 : : {
628 : 0 : std::pair<const Type*, unsigned> entry = std::make_pair(t, this->ntypes_);
629 : 0 : std::pair<idx_map::iterator, bool> ins = this->types_.insert(entry);
630 : 0 : if (ins.second)
631 : : {
632 : 0 : this->ntypes_++;
633 : 0 : if (t != this->top_)
634 : 0 : this->worklist_.push_back(t);
635 : : }
636 : 0 : return std::make_pair(ins.second, ins.first->second);
637 : : }
638 : :
639 : : // Emit preamble prior to dumping a type, including the type
640 : : // pointer itself and the tag we've assigned it. If no
641 : : // tag is specified (via special "notag" value) and/or the
642 : : // pointer is null, then just emit an equivalent amount
643 : : // of spaces.
644 : :
645 : 0 : void Type_dumper::emitpre(unsigned tag, const Type* ptr)
646 : : {
647 : 0 : char tbuf[50], pbuf[50], buf[200];
648 : :
649 : 0 : tbuf[0] = '\0';
650 : 0 : if (tag != notag)
651 : 0 : snprintf(tbuf, sizeof tbuf, "T%u", tag);
652 : :
653 : 0 : pbuf[0] = '\0';
654 : 0 : if (ptr != NULL)
655 : 0 : snprintf(pbuf, sizeof pbuf, "%p", (const void*) ptr);
656 : :
657 : 0 : snprintf(buf, sizeof buf, "%8s %16s ", tbuf, pbuf);
658 : 0 : this->ss_ << buf;
659 : 0 : }
660 : :
661 : : // Emit a reference to a type into the dump buffer. In most cases this means
662 : : // just the type tag, but for named types we also emit the name, and for
663 : : // simple/primitive types (ex: int64) we emit the type itself. If "pref" is
664 : : // non-NULL, emit the string prior to the reference, and if "suf" is non-NULL,
665 : : // emit it following the reference.
666 : :
667 : 0 : void Type_dumper::typeref(const char* pref, const Type* t, const char* suf)
668 : : {
669 : 0 : if (pref != NULL)
670 : 0 : this->ss_ << pref;
671 : 0 : std::pair<bool, unsigned> p = this->lookup(t);
672 : 0 : unsigned tag = p.second;
673 : 0 : switch (t->classification())
674 : : {
675 : 0 : case Type::TYPE_NAMED:
676 : 0 : {
677 : 0 : const Named_type* nt = t->named_type();
678 : 0 : const Named_object* no = nt->named_object();
679 : 0 : this->ss_ << "'" << no->message_name() << "' -> ";
680 : 0 : const Type* underlying = nt->real_type();
681 : 0 : this->typeref(NULL, underlying, NULL);
682 : 0 : break;
683 : : }
684 : 0 : case Type::TYPE_POINTER:
685 : 0 : this->typeref("*", t->points_to(), NULL);
686 : 0 : break;
687 : 0 : case Type::TYPE_ERROR:
688 : 0 : this->ss_ << "error_type";
689 : 0 : break;
690 : 0 : case Type::TYPE_INTEGER:
691 : 0 : {
692 : 0 : const Integer_type* it = t->integer_type();
693 : 0 : if (it->is_abstract())
694 : 0 : this->ss_ << "abstract_int";
695 : : else
696 : 0 : this->ss_ << (it->is_unsigned() ? "u" : "") << "int" << it->bits();
697 : : break;
698 : : }
699 : 0 : case Type::TYPE_FLOAT:
700 : 0 : {
701 : 0 : const Float_type* ft = t->float_type();
702 : 0 : if (ft->is_abstract())
703 : 0 : this->ss_ << "abstract_float";
704 : : else
705 : 0 : this->ss_ << "float" << ft->bits();
706 : : break;
707 : : }
708 : 0 : case Type::TYPE_COMPLEX:
709 : 0 : {
710 : 0 : const Complex_type* ct = t->complex_type();
711 : 0 : if (ct->is_abstract())
712 : 0 : this->ss_ << "abstract_complex";
713 : : else
714 : 0 : this->ss_ << "complex" << ct->bits();
715 : : break;
716 : : }
717 : 0 : case Type::TYPE_BOOLEAN:
718 : 0 : this->ss_ << "bool";
719 : 0 : break;
720 : 0 : case Type::TYPE_STRING:
721 : 0 : this->ss_ << "string";
722 : 0 : break;
723 : 0 : case Type::TYPE_NIL:
724 : 0 : this->ss_ << "nil_type";
725 : 0 : break;
726 : 0 : case Type::TYPE_VOID:
727 : 0 : this->ss_ << "void_type";
728 : 0 : break;
729 : 0 : case Type::TYPE_FUNCTION:
730 : 0 : case Type::TYPE_STRUCT:
731 : 0 : case Type::TYPE_ARRAY:
732 : 0 : case Type::TYPE_MAP:
733 : 0 : case Type::TYPE_CHANNEL:
734 : 0 : case Type::TYPE_FORWARD:
735 : 0 : case Type::TYPE_INTERFACE:
736 : 0 : this->ss_ << "T" << tag;
737 : 0 : break;
738 : :
739 : 0 : default:
740 : : // This is a debugging routine, so instead of a go_unreachable()
741 : : // issue a warning/error, to allow for the possibility that the
742 : : // compiler we're debugging is in a bad state.
743 : 0 : this->ss_ << "<??? " << ((unsigned)t->classification()) << "> "
744 : 0 : << "T" << tag;
745 : : }
746 : 0 : if (suf != NULL)
747 : 0 : this->ss_ << suf;
748 : 0 : }
749 : :
750 : 0 : void Type_dumper::visit_forward_declaration_type(const Forward_declaration_type* fdt)
751 : : {
752 : 0 : this->ss_ << "forward_declaration_type ";
753 : 0 : if (fdt->is_defined())
754 : 0 : this->typeref("-> ", fdt->real_type(), NULL);
755 : : else
756 : 0 : this->ss_ << "'" << fdt->name() << "'";
757 : 0 : this->ss_ << "\n";
758 : 0 : }
759 : :
760 : 0 : void Type_dumper::visit_function_type(const Function_type* ft)
761 : : {
762 : 0 : this->ss_ << "function\n";
763 : 0 : const Typed_identifier* rec = ft->receiver();
764 : 0 : if (rec != NULL)
765 : : {
766 : 0 : this->emitpre(notag, NULL);
767 : 0 : this->typeref("receiver ", rec->type(), "\n");
768 : : }
769 : 0 : const Typed_identifier_list* parameters = ft->parameters();
770 : 0 : if (parameters != NULL)
771 : : {
772 : 0 : for (Typed_identifier_list::const_iterator p = parameters->begin();
773 : 0 : p != parameters->end();
774 : 0 : ++p)
775 : : {
776 : 0 : this->emitpre(notag, NULL);
777 : 0 : this->typeref(" param ", p->type(), "\n");
778 : : }
779 : : }
780 : 0 : const Typed_identifier_list* results = ft->results();
781 : 0 : if (results != NULL)
782 : : {
783 : 0 : for (Typed_identifier_list::const_iterator p = results->begin();
784 : 0 : p != results->end();
785 : 0 : ++p)
786 : : {
787 : 0 : this->emitpre(notag, NULL);
788 : 0 : this->typeref(" result ", p->type(), "\n");
789 : : }
790 : : }
791 : 0 : }
792 : :
793 : 0 : void Type_dumper::visit_struct_type(const Struct_type* st)
794 : : {
795 : 0 : this->ss_ << "struct\n";
796 : 0 : const Struct_field_list* fields = st->fields();
797 : 0 : if (fields != NULL)
798 : : {
799 : 0 : for (Struct_field_list::const_iterator p = fields->begin();
800 : 0 : p != fields->end();
801 : 0 : ++p)
802 : : {
803 : 0 : this->emitpre(notag, NULL);
804 : 0 : this->typeref(" field ", p->type(), "\n");
805 : : }
806 : : }
807 : 0 : }
808 : :
809 : 0 : void Type_dumper::visit_array_type(const Array_type* at)
810 : : {
811 : 0 : this->ss_ << "array [";
812 : 0 : if (at->length() != NULL)
813 : : {
814 : 0 : int64_t len = 0;
815 : 0 : if (at->int_length(&len))
816 : 0 : this->ss_ << len;
817 : : }
818 : 0 : this->typeref("] ", at->element_type(), "\n");
819 : 0 : }
820 : :
821 : 0 : void Type_dumper::visit_map_type(const Map_type* mt)
822 : : {
823 : 0 : this->ss_ << "map [";
824 : 0 : this->typeref(NULL, mt->key_type(), NULL);
825 : 0 : this->typeref("] ", mt->val_type(), "\n");
826 : 0 : }
827 : :
828 : 0 : void Type_dumper::visit_methods(const Typed_identifier_list* methods,
829 : : const char *tag)
830 : : {
831 : 0 : if (tag != NULL)
832 : : {
833 : 0 : this->emitpre(notag, NULL);
834 : 0 : this->ss_ << tag << "\n";
835 : : }
836 : 0 : for (Typed_identifier_list::const_iterator p = methods->begin();
837 : 0 : p != methods->end();
838 : 0 : ++p)
839 : : {
840 : 0 : this->emitpre(notag, NULL);
841 : 0 : if (p->name().empty())
842 : 0 : this->typeref(" embedded method ", p->type(), "\n");
843 : : else
844 : : {
845 : 0 : this->ss_ << " method '" << p->name() << "' ";
846 : 0 : this->typeref(NULL, p->type(), "\n");
847 : : }
848 : : }
849 : 0 : }
850 : :
851 : 0 : void Type_dumper::visit_interface_type(const Interface_type* it)
852 : : {
853 : 0 : const Typed_identifier_list* methods =
854 : 0 : (it->methods_are_finalized() ? it->methods() : it->local_methods());
855 : 0 : if (methods == NULL)
856 : : {
857 : 0 : this->ss_ << "empty_interface\n";
858 : 0 : return;
859 : : }
860 : 0 : this->ss_ << "interface";
861 : 0 : if (! it->methods_are_finalized())
862 : : {
863 : 0 : this->ss_ << " [unfinalized]\n";
864 : 0 : visit_methods(it->local_methods(), NULL);
865 : : }
866 : : else
867 : : {
868 : 0 : this->ss_ << "\n";
869 : 0 : visit_methods(it->local_methods(), "[parse_methods]");
870 : 0 : visit_methods(it->methods(), "[all_methods]");
871 : : }
872 : : }
873 : :
874 : 0 : void Type_dumper::visit_channel_type(const Channel_type* ct)
875 : : {
876 : 0 : this->ss_ << "channel {";
877 : 0 : if (ct->may_send())
878 : 0 : this->ss_ << " send";
879 : 0 : if (ct->may_receive())
880 : 0 : this->ss_ << " receive";
881 : 0 : this->typeref(" } ", ct->element_type(), "\n");
882 : 0 : }
883 : :
884 : 0 : void Type_dumper::visit()
885 : : {
886 : 0 : while (! this->worklist_.empty()) {
887 : 0 : const Type* t = this->worklist_.front();
888 : 0 : this->worklist_.pop_front();
889 : :
890 : 0 : std::pair<bool, unsigned> p = this->lookup(t);
891 : 0 : unsigned tag = p.second;
892 : 0 : this->emitpre(tag, t);
893 : :
894 : 0 : switch(t->classification())
895 : : {
896 : 0 : case Type::TYPE_ERROR:
897 : 0 : case Type::TYPE_INTEGER:
898 : 0 : case Type::TYPE_FLOAT:
899 : 0 : case Type::TYPE_COMPLEX:
900 : 0 : case Type::TYPE_BOOLEAN:
901 : 0 : case Type::TYPE_STRING:
902 : 0 : case Type::TYPE_VOID:
903 : 0 : case Type::TYPE_POINTER:
904 : 0 : case Type::TYPE_NIL:
905 : 0 : case Type::TYPE_NAMED:
906 : 0 : this->typeref(NULL, t, "\n");
907 : 0 : break;
908 : 0 : case Type::TYPE_FORWARD:
909 : 0 : this->visit_forward_declaration_type(t->forward_declaration_type());
910 : 0 : break;
911 : :
912 : 0 : case Type::TYPE_FUNCTION:
913 : 0 : this->visit_function_type(t->function_type());
914 : 0 : break;
915 : 0 : case Type::TYPE_STRUCT:
916 : 0 : this->visit_struct_type(t->struct_type());
917 : 0 : break;
918 : 0 : case Type::TYPE_ARRAY:
919 : 0 : this->visit_array_type(t->array_type());
920 : 0 : break;
921 : 0 : case Type::TYPE_MAP:
922 : 0 : this->visit_map_type(t->map_type());
923 : 0 : break;
924 : 0 : case Type::TYPE_CHANNEL:
925 : 0 : this->visit_channel_type(t->channel_type());
926 : 0 : break;
927 : 0 : case Type::TYPE_INTERFACE:
928 : 0 : this->visit_interface_type(t->interface_type());
929 : 0 : break;
930 : 0 : default:
931 : : // This is a debugging routine, so instead of a go_unreachable()
932 : : // issue a warning/error, to allow for the possibility that the
933 : : // compiler we're debugging is in a bad state.
934 : 0 : this->ss_ << "<unknown/unrecognized classification "
935 : 0 : << ((unsigned)t->classification()) << ">\n";
936 : : }
937 : : }
938 : 0 : }
939 : :
940 : : // Dump a Go type for debugging purposes. This is a deep as opposed
941 : : // to shallow dump; all of the types reachable from the specified
942 : : // type will be dumped in addition to the type itself.
943 : :
944 : 0 : void debug_go_type(const Type* type)
945 : : {
946 : 0 : if (type == NULL)
947 : : {
948 : 0 : std::cerr << "<NULL type>\n";
949 : 0 : return;
950 : : }
951 : 0 : Type_dumper dumper(type);
952 : 0 : dumper.visit();
953 : 0 : std::cerr << dumper.stringResult();
954 : 0 : }
955 : :
956 : 0 : void debug_go_type(Type* type)
957 : : {
958 : 0 : const Type* ctype = type;
959 : 0 : debug_go_type(ctype);
960 : 0 : }
|