From e9eec70cad5e00a647b48932bc94833d58cc06c2 Mon Sep 17 00:00:00 2001 From: "kmillikin@google.com" Date: Mon, 9 Sep 2013 10:20:55 +0000 Subject: [PATCH] Change --print-ast output to be more regular. The print-ast output is useful for debugging front end issues. It is a mix of fully-parenthesized prefix notation (i.e., Lisp S-expressions) with some infix. It is not valid S-expressions for various other reasons. Most obviously, it uses ' (single quote) instead of " (double quote) to delimit strings. This change makes the print-ast output a valid Scheme S-expression. It can be pretty printed by copying it, quoting it (by preceding it with a single quote), and evaluating it at the REPL of a Scheme implementation. Also, the AST node pretty names are changed to predictably match the class name. It doesn't seem helpful to have them be arbitrary. BUG= R=regis@google.com Review URL: https://codereview.chromium.org//23923005 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@27282 260f80e4-7a28-3924-810f-c04153c831b5 --- runtime/vm/ast.cc | 31 +++--- runtime/vm/ast.h | 114 ++++++++++---------- runtime/vm/ast_printer.cc | 178 ++++++++++++++----------------- runtime/vm/ast_printer.h | 9 +- runtime/vm/flow_graph_builder.h | 8 +- runtime/vm/flow_graph_inliner.cc | 9 +- 6 files changed, 170 insertions(+), 179 deletions(-) diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc index 0f123a5de3e..2c911eb2dc6 100644 --- a/runtime/vm/ast.cc +++ b/runtime/vm/ast.cc @@ -12,19 +12,21 @@ namespace dart { -#define DEFINE_VISIT_FUNCTION(type, name) \ - void type::Visit(AstNodeVisitor* visitor) { \ - visitor->Visit##type(this); \ - } -NODE_LIST(DEFINE_VISIT_FUNCTION) +#define DEFINE_VISIT_FUNCTION(BaseName) \ +void BaseName##Node::Visit(AstNodeVisitor* visitor) { \ + visitor->Visit##BaseName##Node(this); \ +} + +FOR_EACH_NODE(DEFINE_VISIT_FUNCTION) #undef DEFINE_VISIT_FUNCTION -#define DEFINE_NAME_FUNCTION(type, name) \ - const char* type::PrettyName() const { \ - return name; \ - } -NODE_LIST(DEFINE_NAME_FUNCTION) +#define DEFINE_NAME_FUNCTION(BaseName) \ +const char* BaseName##Node::PrettyName() const { \ + return #BaseName; \ +} + +FOR_EACH_NODE(DEFINE_NAME_FUNCTION) #undef DEFINE_NAME_FUNCTION @@ -35,12 +37,13 @@ class AstNodeCollector : public AstNodeVisitor { explicit AstNodeCollector(GrowableArray* nodes) : nodes_(nodes) { } -#define DEFINE_VISITOR_FUNCTION(type, name) \ - virtual void Visit##type(type* node) { \ +#define DEFINE_VISITOR_FUNCTION(BaseName) \ + virtual void Visit##BaseName##Node(BaseName##Node* node) { \ nodes_->Add(node); \ node->VisitChildren(this); \ } -NODE_LIST(DEFINE_VISITOR_FUNCTION) + +FOR_EACH_NODE(DEFINE_VISITOR_FUNCTION) #undef DEFINE_VISITOR_FUNCTION private: @@ -151,7 +154,7 @@ bool ComparisonNode::IsKindValid() const { const char* ComparisonNode::TokenName() const { - return Token::Str(kind_); + return (kind_ == Token::kAS) ? "as" : Token::Str(kind_); } diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h index 393db8c7655..2f7af9891f6 100644 --- a/runtime/vm/ast.h +++ b/runtime/vm/ast.h @@ -15,56 +15,56 @@ namespace dart { -#define NODE_LIST(V) \ - V(ReturnNode, "return") \ - V(LiteralNode, "literal") \ - V(TypeNode, "type") \ - V(AssignableNode, "assignable") \ - V(BinaryOpNode, "binop") \ - V(BinaryOpWithMask32Node, "binop with mask 32") \ - V(ComparisonNode, "compare") \ - V(UnaryOpNode, "unaryop") \ - V(ConditionalExprNode, "?:") \ - V(IfNode, "if") \ - V(SwitchNode, "switch") \ - V(CaseNode, "case") \ - V(WhileNode, "while") \ - V(DoWhileNode, "dowhile") \ - V(ForNode, "for") \ - V(JumpNode, "jump") \ - V(ArgumentListNode, "args") \ - V(ArrayNode, "array") \ - V(ClosureNode, "closure") \ - V(InstanceCallNode, "instance call") \ - V(StaticCallNode, "static call") \ - V(ClosureCallNode, "closure call") \ - V(CloneContextNode, "clone context") \ - V(ConstructorCallNode, "constructor call") \ - V(InstanceGetterNode, "instance getter call") \ - V(InstanceSetterNode, "instance setter call") \ - V(StaticGetterNode, "static getter") \ - V(StaticSetterNode, "static setter") \ - V(NativeBodyNode, "native body") \ - V(PrimaryNode, "primary") \ - V(LoadLocalNode, "load local") \ - V(StoreLocalNode, "store local") \ - V(LoadInstanceFieldNode, "load field") \ - V(StoreInstanceFieldNode, "store field") \ - V(LoadStaticFieldNode, "load static field") \ - V(StoreStaticFieldNode, "store static field") \ - V(LoadIndexedNode, "load indexed") \ - V(StoreIndexedNode, "store indexed") \ - V(SequenceNode, "seq") \ - V(LetNode, "let") \ - V(CatchClauseNode, "catch clause block") \ - V(TryCatchNode, "try catch block") \ - V(ThrowNode, "throw") \ - V(InlinedFinallyNode, "inlined finally") \ +#define FOR_EACH_NODE(V) \ + V(Return) \ + V(Literal) \ + V(Type) \ + V(Assignable) \ + V(BinaryOp) \ + V(BinaryOpWithMask32) \ + V(Comparison) \ + V(UnaryOp) \ + V(ConditionalExpr) \ + V(If) \ + V(Switch) \ + V(Case) \ + V(While) \ + V(DoWhile) \ + V(For) \ + V(Jump) \ + V(ArgumentList) \ + V(Array) \ + V(Closure) \ + V(InstanceCall) \ + V(StaticCall) \ + V(ClosureCall) \ + V(CloneContext) \ + V(ConstructorCall) \ + V(InstanceGetter) \ + V(InstanceSetter) \ + V(StaticGetter) \ + V(StaticSetter) \ + V(NativeBody) \ + V(Primary) \ + V(LoadLocal) \ + V(StoreLocal) \ + V(LoadInstanceField) \ + V(StoreInstanceField) \ + V(LoadStaticField) \ + V(StoreStaticField) \ + V(LoadIndexed) \ + V(StoreIndexed) \ + V(Sequence) \ + V(Let) \ + V(CatchClause) \ + V(TryCatch) \ + V(Throw) \ + V(InlinedFinally) \ -#define DEFINE_FORWARD_DECLARATION(type, name) class type; -NODE_LIST(DEFINE_FORWARD_DECLARATION) -#undef DEFINE_FORWARD_DECLARATION +#define FORWARD_DECLARATION(BaseName) class BaseName##Node; +FOR_EACH_NODE(FORWARD_DECLARATION) +#undef FORWARD_DECLARATION // Abstract class to implement an AST node visitor. An example is AstPrinter. @@ -73,9 +73,10 @@ class AstNodeVisitor : public ValueObject { AstNodeVisitor() {} virtual ~AstNodeVisitor() {} -#define DEFINE_VISITOR_FUNCTION(type, name) \ - virtual void Visit##type(type* node) { } -NODE_LIST(DEFINE_VISITOR_FUNCTION) +#define DEFINE_VISITOR_FUNCTION(BaseName) \ + virtual void Visit##BaseName##Node(BaseName##Node* node) { } + + FOR_EACH_NODE(DEFINE_VISITOR_FUNCTION) #undef DEFINE_VISITOR_FUNCTION private: @@ -99,10 +100,11 @@ class AstNode : public ZoneAllocated { intptr_t token_pos() const { return token_pos_; } -#define AST_TYPE_CHECK(type, name) \ - virtual bool Is##type() const { return false; } \ - virtual type* As##type() { return NULL; } -NODE_LIST(AST_TYPE_CHECK) +#define AST_TYPE_CHECK(BaseName) \ + virtual bool Is##BaseName##Node() const { return false; } \ + virtual BaseName##Node* As##BaseName##Node() { return NULL; } + + FOR_EACH_NODE(AST_TYPE_CHECK) #undef AST_TYPE_CHECK virtual void Visit(AstNodeVisitor* visitor) = 0; @@ -893,7 +895,7 @@ class DoWhileNode : public AstNode { }; -// initializer, condition, increment expressions can be NULL. +// The condition can be NULL. class ForNode : public AstNode { public: ForNode(intptr_t token_pos, diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc index 2ad2767c436..2847085496a 100644 --- a/runtime/vm/ast_printer.cc +++ b/runtime/vm/ast_printer.cc @@ -24,17 +24,16 @@ void AstPrinter::VisitGenericAstNode(AstNode* node) { } -void AstPrinter::VisitSequenceNode(SequenceNode* node_sequence) { +void AstPrinter::VisitSequenceNode(SequenceNode* node) { // TODO(regis): Make the output more readable by indenting the nested // sequences. This could be achieved using a AstPrinterContext similar to the // CodeGeneratorContext. - ASSERT(node_sequence != NULL); - for (int i = 0; i < node_sequence->length(); i++) { - OS::Print("scope %p: ", - node_sequence->scope()); - node_sequence->NodeAt(i)->Visit(this); + OS::Print("(%s (scope \"%p\")", node->PrettyName(), node->scope()); + for (int i = 0; i < node->length(); ++i) { OS::Print("\n"); + node->NodeAt(i)->Visit(this); } + OS::Print(")"); } @@ -55,17 +54,19 @@ void AstPrinter::VisitReturnNode(ReturnNode* node) { void AstPrinter::VisitGenericLocalNode(AstNode* node, const LocalVariable& var) { - OS::Print("(%s %s%s '%s'", + OS::Print("(%s %s%s \"%s\"", node->PrettyName(), var.is_final() ? "final " : "", String::Handle(var.type().Name()).ToCString(), var.name().ToCString()); if (var.HasIndex()) { - OS::Print(" @%d", var.index()); if (var.is_captured()) { - OS::Print(" ctx %d", var.owner()->context_level()); + OS::Print(" (context %d %d)", var.owner()->context_level(), var.index()); + } else { + OS::Print(" (stack %d)", var.index()); } } + OS::Print(" "); node->VisitChildren(this); OS::Print(")"); } @@ -82,7 +83,7 @@ void AstPrinter::VisitStoreLocalNode(StoreLocalNode* node) { void AstPrinter::VisitGenericFieldNode(AstNode* node, const Field& field) { - OS::Print("(%s %s%s '%s' ", + OS::Print("(%s %s%s \"%s\" ", node->PrettyName(), field.is_final() ? "final " : "", String::Handle(AbstractType::Handle(field.type()).Name()). @@ -125,59 +126,63 @@ void AstPrinter::VisitArrayNode(ArrayNode* node) { void AstPrinter::VisitLiteralNode(LiteralNode* node) { const Instance& literal = node->literal(); - OS::Print("'%s'", literal.ToCString()); + OS::Print("(%s \"%s\")", node->PrettyName(), literal.ToCString()); } void AstPrinter::VisitTypeNode(TypeNode* node) { const AbstractType& type = node->type(); - OS::Print("'%s'", String::Handle(type.Name()).ToCString()); + OS::Print("(%s \"%s\")", + node->PrettyName(), + String::Handle(type.Name()).ToCString()); } void AstPrinter::VisitAssignableNode(AssignableNode* node) { - OS::Print("(assignable "); - node->expr()->Visit(this); const AbstractType& type = node->type(); const String& dst_name = node->dst_name(); - OS::Print(" to type '%s' of '%s')", + OS::Print("(%s (type \"%s\") (of \"%s\") ", + node->PrettyName(), String::Handle(type.Name()).ToCString(), dst_name.ToCString()); + node->VisitChildren(this); + OS::Print(")"); } void AstPrinter::VisitPrimaryNode(PrimaryNode* node) { - OS::Print("***** PRIMARY NODE IN AST ***** (primary '%s')", + OS::Print("*****%s***** \"%s\")", + node->PrettyName(), node->primary().ToCString()); } void AstPrinter::VisitComparisonNode(ComparisonNode* node) { - if (node->kind() == Token::kAS) { - OS::Print("(as "); - node->VisitChildren(this); - OS::Print(")"); - } else { - VisitGenericAstNode(node); - } -} - - -void AstPrinter::VisitBinaryOpNode(BinaryOpNode* node) { - VisitGenericAstNode(node); -} - - -void AstPrinter::VisitBinaryOpWithMask32Node(BinaryOpWithMask32Node* node) { - OS::Print("(%s %s", node->PrettyName(), node->TokenName()); + OS::Print("(%s %s ", node->PrettyName(), node->TokenName()); node->VisitChildren(this); - OS::Print(" & 0x%" Px64 "", node->mask32()); OS::Print(")"); } +void AstPrinter::VisitBinaryOpNode(BinaryOpNode* node) { + OS::Print("(%s %s ", node->PrettyName(), node->TokenName()); + node->VisitChildren(this); + OS::Print(")"); +} + + +void AstPrinter::VisitBinaryOpWithMask32Node(BinaryOpWithMask32Node* node) { + OS::Print("(%s %s ", node->PrettyName(), node->TokenName()); + node->VisitChildren(this); + OS::Print(" & \"0x%" Px64 "", node->mask32()); + OS::Print("\")"); +} + + void AstPrinter::VisitUnaryOpNode(UnaryOpNode* node) { - VisitGenericAstNode(node); + OS::Print("(%s %s ", node->PrettyName(), node->TokenName()); + node->VisitChildren(this); + OS::Print(")"); } @@ -187,25 +192,17 @@ void AstPrinter::VisitConditionalExprNode(ConditionalExprNode* node) { void AstPrinter::VisitIfNode(IfNode* node) { - OS::Print("(if "); - node->condition()->Visit(this); - OS::Print(" then "); - node->true_branch()->Visit(this); - OS::Print(" else "); - if (node->false_branch() != NULL) { - node->false_branch()->Visit(this); - } - OS::Print(")"); + VisitGenericAstNode(node); } void AstPrinter::VisitCaseNode(CaseNode* node) { - OS::Print("(case ("); + OS::Print("(%s (", node->PrettyName()); for (int i = 0; i < node->case_expressions()->length(); i++) { node->case_expressions()->NodeAt(i)->Visit(this); } if (node->contains_default()) { - OS::Print(" default "); + OS::Print(" default"); } OS::Print(")"); node->statements()->Visit(this); @@ -214,47 +211,39 @@ void AstPrinter::VisitCaseNode(CaseNode* node) { void AstPrinter::VisitSwitchNode(SwitchNode* node) { - OS::Print("(switch "); - node->body()->Visit(this); - OS::Print(")"); + VisitGenericAstNode(node); } void AstPrinter::VisitWhileNode(WhileNode* node) { - OS::Print("(while "); - node->condition()->Visit(this); - OS::Print(" do "); - node->body()->Visit(this); - OS::Print(")"); + VisitGenericAstNode(node); } void AstPrinter::VisitForNode(ForNode* node) { - OS::Print("(for (init: "); + // Complicated because the condition is optional and so we clearly want to + // indicate the subparts. + OS::Print("(%s (init ", node->PrettyName()); node->initializer()->Visit(this); - OS::Print("; cond:"); if (node->condition() != NULL) { + OS::Print(") (cond "); node->condition()->Visit(this); } - OS::Print("; incr:"); + OS::Print(") (update "); node->increment()->Visit(this); - OS::Print(") body:"); + OS::Print(") "); node->body()->Visit(this); - OS::Print("endfor)"); -} - - -void AstPrinter::VisitDoWhileNode(DoWhileNode* node) { - OS::Print("(do "); - node->body()->Visit(this); - OS::Print(" while "); - node->condition()->Visit(this); OS::Print(")"); } +void AstPrinter::VisitDoWhileNode(DoWhileNode* node) { + VisitGenericAstNode(node); +} + + void AstPrinter::VisitJumpNode(JumpNode* node) { - OS::Print("(%s %s %s in scope %p)", + OS::Print("(%s %s %s (scope \"%p\"))", node->PrettyName(), node->TokenName(), node->label()->name().ToCString(), @@ -263,23 +252,25 @@ void AstPrinter::VisitJumpNode(JumpNode* node) { void AstPrinter::VisitInstanceCallNode(InstanceCallNode* node) { - OS::Print("(%s '%s'(", node->PrettyName(), node->function_name().ToCString()); + OS::Print("(%s \"%s\" ", + node->PrettyName(), + node->function_name().ToCString()); node->VisitChildren(this); - OS::Print("))"); + OS::Print(")"); } void AstPrinter::VisitStaticCallNode(StaticCallNode* node) { const char* function_fullname = node->function().ToFullyQualifiedCString(); - OS::Print("(%s '%s'(", node->PrettyName(), function_fullname); + OS::Print("(%s \"%s\" ", node->PrettyName(), function_fullname); node->VisitChildren(this); - OS::Print("))"); + OS::Print(")"); } void AstPrinter::VisitClosureNode(ClosureNode* node) { const char* function_fullname = node->function().ToFullyQualifiedCString(); - OS::Print("(%s '%s')", node->PrettyName(), function_fullname); + OS::Print("(%s \"%s\")", node->PrettyName(), function_fullname); } @@ -291,48 +282,47 @@ void AstPrinter::VisitClosureCallNode(ClosureCallNode* node) { void AstPrinter::VisitConstructorCallNode(ConstructorCallNode* node) { const char* kind = node->constructor().IsFactory() ? "factory " : ""; const char* constructor_name = node->constructor().ToFullyQualifiedCString(); - OS::Print("(%s %s'%s' ((this)", node->PrettyName(), kind, constructor_name); + OS::Print("(%s %s \"%s\" ", node->PrettyName(), kind, constructor_name); node->VisitChildren(this); - OS::Print("))"); + OS::Print(")"); } void AstPrinter::VisitInstanceGetterNode(InstanceGetterNode* node) { - OS::Print("(%s 'get %s'(", + OS::Print("(%s \"%s\" ", node->PrettyName(), node->field_name().ToCString()); node->VisitChildren(this); - OS::Print("))"); + OS::Print(")"); } void AstPrinter::VisitInstanceSetterNode(InstanceSetterNode* node) { - OS::Print("(%s 'set %s'(", + OS::Print("(%s \"%s\" ", node->PrettyName(), node->field_name().ToCString()); node->VisitChildren(this); - OS::Print("))"); + OS::Print(")"); } void AstPrinter::VisitStaticGetterNode(StaticGetterNode* node) { String& class_name = String::Handle(node->cls().Name()); - OS::Print("(%s '%s.%s'(", + OS::Print("(%s \"%s.%s\")", node->PrettyName(), class_name.ToCString(), node->field_name().ToCString()); - OS::Print("))"); } void AstPrinter::VisitStaticSetterNode(StaticSetterNode* node) { String& class_name = String::Handle(node->cls().Name()); - OS::Print("(%s '%s.%s'(", + OS::Print("(%s \"%s.%s\" ", node->PrettyName(), class_name.ToCString(), node->field_name().ToCString()); node->VisitChildren(this); - OS::Print("))"); + OS::Print(")"); } @@ -351,39 +341,29 @@ void AstPrinter::VisitStoreIndexedNode(StoreIndexedNode* node) { void AstPrinter::VisitNativeBodyNode(NativeBodyNode* node) { - OS::Print("(native_c call '%s'(%d args))", + OS::Print("(%s \"%s\" (%d args))", + node->PrettyName(), node->native_c_function_name().ToCString(), NativeArguments::ParameterCountForResolution(node->function())); } void AstPrinter::VisitCatchClauseNode(CatchClauseNode* node) { - node->VisitChildren(this); + VisitGenericAstNode(node); } void AstPrinter::VisitTryCatchNode(TryCatchNode* node) { - OS::Print("("); - - // First visit the try block. - OS::Print("(try block ("); + OS::Print("(%s ", node->PrettyName()); node->try_block()->Visit(this); - OS::Print("))"); - - // Now visit the catch block if it exists. if (node->catch_block() != NULL) { - OS::Print("(catch block () ("); node->catch_block()->Visit(this); - OS::Print("))"); } - - // Now visit the finally block if it exists. if (node->finally_block() != NULL) { - OS::Print("(finally block () ("); + OS::Print("(finally "); node->finally_block()->Visit(this); - OS::Print("))"); + OS::Print(")"); } - OS::Print(")"); } diff --git a/runtime/vm/ast_printer.h b/runtime/vm/ast_printer.h index d61a802be62..f64d9795802 100644 --- a/runtime/vm/ast_printer.h +++ b/runtime/vm/ast_printer.h @@ -21,10 +21,11 @@ class AstPrinter : public AstNodeVisitor { static void PrintLocalScope(const LocalScope* scope, int variable_index); -#define DEFINE_VISITOR_FUNCTION(type, name) \ - virtual void Visit##type(type* node); -NODE_LIST(DEFINE_VISITOR_FUNCTION) -#undef DEFINE_VISITOR_FUNCTION +#define DECLARE_VISITOR_FUNCTION(BaseName) \ + virtual void Visit##BaseName##Node(BaseName##Node* node); + + FOR_EACH_NODE(DECLARE_VISITOR_FUNCTION) +#undef DECLARE_VISITOR_FUNCTION private: AstPrinter(); diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h index 4a8457b021b..e3d01c30739 100644 --- a/runtime/vm/flow_graph_builder.h +++ b/runtime/vm/flow_graph_builder.h @@ -208,9 +208,11 @@ class EffectGraphVisitor : public AstNodeVisitor { entry_(NULL), exit_(NULL) { } -#define DEFINE_VISIT(type, name) virtual void Visit##type(type* node); - NODE_LIST(DEFINE_VISIT) -#undef DEFINE_VISIT +#define DECLARE_VISIT(BaseName) \ + virtual void Visit##BaseName##Node(BaseName##Node* node); + + FOR_EACH_NODE(DECLARE_VISIT) +#undef DECLARE_VISIT FlowGraphBuilder* owner() const { return owner_; } intptr_t temp_index() const { return temp_index_; } diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc index 6ecb193a03b..692c0f85825 100644 --- a/runtime/vm/flow_graph_inliner.cc +++ b/runtime/vm/flow_graph_inliner.cc @@ -77,9 +77,12 @@ static bool IsCallRecursive(const Function& function, Definition* call) { class ChildrenVisitor : public AstNodeVisitor { public: ChildrenVisitor() { } -#define DEFINE_VISIT(type, name) \ - virtual void Visit##type(type* node) { node->VisitChildren(this); } - NODE_LIST(DEFINE_VISIT); +#define DEFINE_VISIT(BaseName) \ + virtual void Visit##BaseName##Node(BaseName##Node* node) { \ + node->VisitChildren(this); \ + } + + FOR_EACH_NODE(DEFINE_VISIT); #undef DEFINE_VISIT };