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
12#include "gogo.h"
13#include "expressions.h"
14#include "statements.h"
15#include "types.h"
16#include "ast-dump.h"
17#include "go-c.h"
18#include "go-dump.h"
19
20// The -fgo-dump-ast flag to activate AST dumps.
21
22Go_dump ast_dump_flag("ast");
23
24// This class is used to traverse the tree to look for blocks and
25// function headers.
26
27class Ast_dump_traverse_blocks_and_functions : public Traverse
28{
29 public:
30  Ast_dump_traverse_blocks_and_functions(Ast_dump_context* ast_dump_context)
31      : Traverse(traverse_blocks | traverse_functions),
32      ast_dump_context_(ast_dump_context)
33  { }
34
35 protected:
36  int
37  block(Block*);
38
39  int
40  function(Named_object*);
41
42 private:
43  Ast_dump_context* ast_dump_context_;
44};
45
46// This class is used to traverse the tree to look for statements.
47
48class Ast_dump_traverse_statements : public Traverse
49{
50 public:
51  Ast_dump_traverse_statements(Ast_dump_context* ast_dump_context)
52      : Traverse(traverse_statements),
53      ast_dump_context_(ast_dump_context)
54  { }
55
56 protected:
57  int
58  statement(Block*, size_t* pindex, Statement*);
59
60 private:
61  Ast_dump_context* ast_dump_context_;
62};
63
64// For each block we enclose it in brackets.
65
66int Ast_dump_traverse_blocks_and_functions::block(Block * block)
67{
68  this->ast_dump_context_->print_indent();
69  this->ast_dump_context_->ostream() << "{" << std::endl;
70  this->ast_dump_context_->indent();
71
72  // Dump statememts.
73  Ast_dump_traverse_statements adts(this->ast_dump_context_);
74  block->traverse(&adts);
75
76  this->ast_dump_context_->unindent();
77  this->ast_dump_context_->print_indent();
78  this->ast_dump_context_->ostream() << "}" << std::endl;
79
80  return TRAVERSE_SKIP_COMPONENTS;
81}
82
83// Dump each traversed statement.
84
85int
86Ast_dump_traverse_statements::statement(Block* block, size_t* pindex,
87                                        Statement* statement)
88{
89  statement->dump_statement(this->ast_dump_context_);
90
91  if (statement->is_block_statement())
92    {
93      Ast_dump_traverse_blocks_and_functions adtbf(this->ast_dump_context_);
94      statement->traverse(block, pindex, &adtbf);
95    }
96
97  return TRAVERSE_SKIP_COMPONENTS;
98}
99
100// Dump the function header.
101
102int
103Ast_dump_traverse_blocks_and_functions::function(Named_object* no)
104{
105  this->ast_dump_context_->ostream() << no->name();
106
107  go_assert(no->is_function());
108  Function* func = no->func_value();
109
110  this->ast_dump_context_->ostream() << "(";
111  this->ast_dump_context_->dump_typed_identifier_list(
112                              func->type()->parameters());
113
114  this->ast_dump_context_->ostream() << ")";
115
116  Function::Results* res = func->result_variables();
117  if (res != NULL && !res->empty())
118    {
119      this->ast_dump_context_->ostream() << " (";
120
121      for (Function::Results::const_iterator it = res->begin();
122          it != res->end();
123          it++)
124        {
125          if (it != res->begin())
126            this->ast_dump_context_->ostream() << ",";
127          Named_object* no = (*it);
128
129          this->ast_dump_context_->ostream() << no->name() << " ";
130          go_assert(no->is_result_variable());
131          Result_variable* resvar = no->result_var_value();
132
133          this->ast_dump_context_->dump_type(resvar->type());
134
135        }
136      this->ast_dump_context_->ostream() << ")";
137    }
138
139  this->ast_dump_context_->ostream() << " : ";
140  this->ast_dump_context_->dump_type(func->type());
141  this->ast_dump_context_->ostream() << std::endl;
142
143  return TRAVERSE_CONTINUE;
144}
145
146// Class Ast_dump_context.
147
148Ast_dump_context::Ast_dump_context(std::ostream* out /* = NULL */,
149				   bool dump_subblocks /* = true */)
150  :  indent_(0), dump_subblocks_(dump_subblocks), ostream_(out), gogo_(NULL)
151{
152}
153
154// Dump files will be named %basename%.dump.ast
155
156const char* kAstDumpFileExtension = ".dump.ast";
157
158// Dump the internal representation.
159
160void
161Ast_dump_context::dump(Gogo* gogo, const char* basename)
162{
163  std::ofstream* out = new std::ofstream();
164  std::string dumpname(basename);
165  dumpname += ".dump.ast";
166  out->open(dumpname.c_str());
167
168  if (out->fail())
169    {
170      error("cannot open %s:%m, -fgo-dump-ast ignored", dumpname.c_str());
171      return;
172    }
173
174  this->gogo_ = gogo;
175  this->ostream_ = out;
176
177  Ast_dump_traverse_blocks_and_functions adtbf(this);
178  gogo->traverse(&adtbf);
179
180  out->close();
181}
182
183// Dump a textual representation of a type to the
184// the dump file.
185
186void
187Ast_dump_context::dump_type(const Type* t)
188{
189  if (t == NULL)
190    this->ostream() << "(nil type)";
191  else
192    // FIXME: write a type pretty printer instead of
193    // using mangled names.
194    if (this->gogo_ != NULL)
195      this->ostream() << "(" << t->mangled_name(this->gogo_) <<  ")";
196}
197
198// Dump a textual representation of a block to the
199// the dump file.
200
201void
202Ast_dump_context::dump_block(Block* b)
203{
204  Ast_dump_traverse_blocks_and_functions adtbf(this);
205  b->traverse(&adtbf);
206}
207
208// Dump a textual representation of an expression to the
209// the dump file.
210
211void
212Ast_dump_context::dump_expression(const Expression* e)
213{
214  e->dump_expression(this);
215}
216
217// Dump a textual representation of an expression list to the
218// the dump file.
219
220void
221Ast_dump_context::dump_expression_list(const Expression_list* el,
222				       bool as_pairs /* = false */)
223{
224  if (el == NULL)
225    return;
226
227  for (std::vector<Expression*>::const_iterator it = el->begin();
228       it != el->end();
229       it++)
230    {
231      if ( it != el->begin())
232        this->ostream() << ",";
233      if (*it != NULL)
234	(*it)->dump_expression(this);
235      else
236        this->ostream() << "NULL";
237      if (as_pairs)
238        {
239	  this->ostream() << ":";
240	  ++it;
241	  (*it)->dump_expression(this);
242        }
243    }
244}
245
246// Dump a textual representation of a typed identifier to the
247// the dump file.
248
249void
250Ast_dump_context::dump_typed_identifier(const Typed_identifier* ti)
251{
252  this->ostream() << ti->name() << " ";
253  this->dump_type(ti->type());
254}
255
256// Dump a textual representation of a typed identifier list to the
257// the dump file.
258
259void
260Ast_dump_context::dump_typed_identifier_list(
261    const Typed_identifier_list* ti_list)
262{
263  if (ti_list == NULL)
264    return;
265
266  for (Typed_identifier_list::const_iterator it = ti_list->begin();
267       it != ti_list->end();
268       it++)
269    {
270      if (it != ti_list->begin())
271        this->ostream() << ",";
272      this->dump_typed_identifier(&(*it));
273    }
274}
275
276// Dump a textual representation of a temporary variable to the
277// the dump file.
278
279void
280Ast_dump_context::dump_temp_variable_name(const Statement* s)
281{
282  go_assert(s->classification() == Statement::STATEMENT_TEMPORARY);
283  // Use the statement address as part of the name for the temporary variable.
284  this->ostream() << "tmp." << (uintptr_t) s;
285}
286
287// Dump a textual representation of a label to the
288// the dump file.
289
290void
291Ast_dump_context::dump_label_name(const Unnamed_label* l)
292{
293  // Use the unnamed label address as part of the name for the temporary
294  // variable.
295  this->ostream() << "label." << (uintptr_t) l;
296}
297
298// Produce a textual representation of an operator symbol.
299
300static const char*
301op_string(Operator op)
302{
303// FIXME: This should be in line with symbols that are parsed,
304// exported and/or imported.
305  switch (op)
306    {
307    case OPERATOR_PLUS:
308      return "+";
309    case OPERATOR_MINUS:
310      return "-";
311    case OPERATOR_NOT:
312      return "!";
313    case OPERATOR_XOR:
314      return "^";
315    case OPERATOR_OR:
316      return "|";
317    case OPERATOR_AND:
318      return "&";
319    case OPERATOR_MULT:
320      return "*";
321    case OPERATOR_OROR:
322      return "||";
323    case OPERATOR_ANDAND:
324      return "&&";
325    case OPERATOR_EQEQ:
326      return "==";
327    case OPERATOR_NOTEQ:
328      return "!=";
329    case OPERATOR_LT:
330      return "<";
331    case OPERATOR_LE:
332      return "<=";
333    case OPERATOR_GT:
334      return ">";
335    case OPERATOR_GE:
336      return ">=";
337    case OPERATOR_DIV:
338      return "/";
339    case OPERATOR_MOD:
340      return "%";
341    case OPERATOR_LSHIFT:
342      return "<<";
343    case OPERATOR_RSHIFT:
344      return "//";
345    case OPERATOR_BITCLEAR:
346      return "&^";
347    case OPERATOR_CHANOP:
348      return "<-";
349    case OPERATOR_PLUSEQ:
350      return "+=";
351    case OPERATOR_MINUSEQ:
352      return "-=";
353    case OPERATOR_OREQ:
354      return "|=";
355    case OPERATOR_XOREQ:
356      return "^=";
357    case OPERATOR_MULTEQ:
358      return "*=";
359    case OPERATOR_DIVEQ:
360      return "/=";
361    case OPERATOR_MODEQ:
362      return "%=";
363    case OPERATOR_LSHIFTEQ:
364      return "<<=";
365    case OPERATOR_RSHIFTEQ:
366      return ">>=";
367    case OPERATOR_ANDEQ:
368      return "&=";
369    case OPERATOR_BITCLEAREQ:
370      return "&^=";
371    case OPERATOR_PLUSPLUS:
372      return "++";
373    case OPERATOR_MINUSMINUS:
374      return "--";
375    case OPERATOR_COLON:
376      return ":";
377    case OPERATOR_COLONEQ:
378      return ":=";
379    case OPERATOR_SEMICOLON:
380      return ";";
381    case OPERATOR_DOT:
382      return ".";
383    case OPERATOR_ELLIPSIS:
384      return "...";
385    case OPERATOR_COMMA:
386      return ",";
387    case OPERATOR_LPAREN:
388      return "(";
389    case OPERATOR_RPAREN:
390      return ")";
391    case OPERATOR_LCURLY:
392      return "{";
393    case OPERATOR_RCURLY:
394      return "}";
395    case OPERATOR_LSQUARE:
396      return "[";
397    case OPERATOR_RSQUARE:
398      return "]";
399    default:
400      go_unreachable();
401    }
402  return NULL;
403}
404
405// Dump a textual representation of an operator to the
406// the dump file.
407
408void
409Ast_dump_context::dump_operator(Operator op)
410{
411  this->ostream() << op_string(op);
412}
413
414// Size of a single indent.
415
416const int Ast_dump_context::offset_ = 2;
417
418// Print indenting spaces to dump file.
419
420void
421Ast_dump_context::print_indent()
422{
423  for (int i = 0; i < this->indent_ * this->offset_; i++)
424    this->ostream() << " ";
425}
426
427// Dump a textual representation of the ast to the
428// the dump file.
429
430void Gogo::dump_ast(const char* basename)
431{
432  if (::ast_dump_flag.is_enabled())
433    {
434      Ast_dump_context adc;
435      adc.dump(this, basename);
436    }
437}
438
439// Implementation of String_dump interface.
440
441void
442Ast_dump_context::write_c_string(const char* s)
443{
444  this->ostream() << s;
445}
446
447void
448Ast_dump_context::write_string(const std::string& s)
449{
450  this->ostream() << s;
451}
452
453// Dump statment to stream.
454
455void
456Ast_dump_context::dump_to_stream(const Statement* stm, std::ostream* out)
457{
458  Ast_dump_context adc(out, false);
459  stm->dump_statement(&adc);
460}
461
462// Dump expression to stream.
463
464void
465Ast_dump_context::dump_to_stream(const Expression* expr, std::ostream* out)
466{
467  Ast_dump_context adc(out, false);
468  expr->dump_expression(&adc);
469}