Mercurial > hg > CbC > CbC_gcc
comparison gcc/go/gofrontend/ast-dump.cc @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
6 | 6 |
7 #include "go-system.h" | 7 #include "go-system.h" |
8 | 8 |
9 #include <iostream> | 9 #include <iostream> |
10 #include <fstream> | 10 #include <fstream> |
11 #include <sstream> | |
11 | 12 |
12 #include "gogo.h" | 13 #include "gogo.h" |
13 #include "expressions.h" | 14 #include "expressions.h" |
14 #include "statements.h" | 15 #include "statements.h" |
15 #include "types.h" | 16 #include "types.h" |
132 it != res->end(); | 133 it != res->end(); |
133 it++) | 134 it++) |
134 { | 135 { |
135 if (it != res->begin()) | 136 if (it != res->begin()) |
136 this->ast_dump_context_->ostream() << ","; | 137 this->ast_dump_context_->ostream() << ","; |
137 Named_object* no = (*it); | 138 Named_object* rno = (*it); |
138 | 139 |
139 this->ast_dump_context_->ostream() << no->name() << " "; | 140 this->ast_dump_context_->ostream() << rno->name() << " "; |
140 go_assert(no->is_result_variable()); | 141 go_assert(rno->is_result_variable()); |
141 Result_variable* resvar = no->result_var_value(); | 142 Result_variable* resvar = rno->result_var_value(); |
142 | 143 |
143 this->ast_dump_context_->dump_type(resvar->type()); | 144 this->ast_dump_context_->dump_type(resvar->type()); |
144 | 145 |
145 } | 146 } |
146 this->ast_dump_context_->ostream() << ")"; | 147 this->ast_dump_context_->ostream() << ")"; |
197 out.open(dumpname.c_str()); | 198 out.open(dumpname.c_str()); |
198 | 199 |
199 if (out.fail()) | 200 if (out.fail()) |
200 { | 201 { |
201 go_error_at(Linemap::unknown_location(), | 202 go_error_at(Linemap::unknown_location(), |
202 "cannot open %s:%m, -fgo-dump-ast ignored", dumpname.c_str()); | 203 "cannot open %s:%m; %<-fgo-dump-ast%> ignored", |
204 dumpname.c_str()); | |
203 return; | 205 return; |
204 } | 206 } |
205 | 207 |
206 this->gogo_ = gogo; | 208 this->gogo_ = gogo; |
207 this->ostream_ = &out; | 209 this->ostream_ = &out; |
480 Ast_dump_context::write_string(const std::string& s) | 482 Ast_dump_context::write_string(const std::string& s) |
481 { | 483 { |
482 this->ostream() << s; | 484 this->ostream() << s; |
483 } | 485 } |
484 | 486 |
485 // Dump statment to stream. | 487 // Dump statement to stream. |
486 | 488 |
487 void | 489 void |
488 Ast_dump_context::dump_to_stream(const Statement* stm, std::ostream* out) | 490 Ast_dump_context::dump_to_stream(const Statement* stm, std::ostream* out) |
489 { | 491 { |
490 Ast_dump_context adc(out, false); | 492 Ast_dump_context adc(out, false); |
497 Ast_dump_context::dump_to_stream(const Expression* expr, std::ostream* out) | 499 Ast_dump_context::dump_to_stream(const Expression* expr, std::ostream* out) |
498 { | 500 { |
499 Ast_dump_context adc(out, false); | 501 Ast_dump_context adc(out, false); |
500 expr->dump_expression(&adc); | 502 expr->dump_expression(&adc); |
501 } | 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 } |