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