github.com/kidsbmilk/gofronted_all@v0.0.0-20220701224323-6479d5976c5d/go/ast-dump.cc (about)

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