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}