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