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