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 }