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