ast-dump.cc 10 KB

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