diff --git a/js/src/frontend/ParseNode-inl.h b/js/src/frontend/ParseNode-inl.h index 4de49569f3b..e6c43c019b6 100644 --- a/js/src/frontend/ParseNode-inl.h +++ b/js/src/frontend/ParseNode-inl.h @@ -64,6 +64,131 @@ ParseNode::isConstant() } } +#ifdef DEBUG +inline void +IndentNewLine(int indent) +{ + fputc('\n', stderr); + for (int i = 0; i < indent; ++i) + fputc(' ', stderr); +} + +inline void +ParseNode::dump(int indent) +{ + switch (pn_arity) { + case PN_NULLARY: + ((NullaryNode *) this)->dump(); + break; + case PN_UNARY: + ((UnaryNode *) this)->dump(indent); + break; + case PN_BINARY: + ((BinaryNode *) this)->dump(indent); + break; + case PN_TERNARY: + ((TernaryNode *) this)->dump(indent); + break; + case PN_FUNC: + ((FunctionNode *) this)->dump(indent); + break; + case PN_LIST: + ((ListNode *) this)->dump(indent); + break; + case PN_NAME: + ((NameNode *) this)->dump(indent); + break; + default: + fprintf(stderr, "?"); + break; + } +} + +inline void +NullaryNode::dump() +{ + fprintf(stderr, "(%s)", js_CodeName[getOp()]); +} + +inline void +UnaryNode::dump(int indent) +{ + const char *name = js_CodeName[getOp()]; + fprintf(stderr, "(%s ", name); + indent += strlen(name) + 2; + DumpParseTree(pn_kid, indent); + fprintf(stderr, ")"); +} + +inline void +BinaryNode::dump(int indent) +{ + const char *name = js_CodeName[getOp()]; + fprintf(stderr, "(%s ", name); + indent += strlen(name) + 2; + DumpParseTree(pn_left, indent); + IndentNewLine(indent); + DumpParseTree(pn_right, indent); + fprintf(stderr, ")"); +} + +inline void +TernaryNode::dump(int indent) +{ + const char *name = js_CodeName[getOp()]; + fprintf(stderr, "(%s ", name); + indent += strlen(name) + 2; + DumpParseTree(pn_kid1, indent); + IndentNewLine(indent); + DumpParseTree(pn_kid2, indent); + IndentNewLine(indent); + DumpParseTree(pn_kid3, indent); + fprintf(stderr, ")"); +} + +inline void +FunctionNode::dump(int indent) +{ + const char *name = js_CodeName[getOp()]; + fprintf(stderr, "(%s ", name); + indent += strlen(name) + 2; + DumpParseTree(pn_body, indent); + fprintf(stderr, ")"); +} + +inline void +ListNode::dump(int indent) +{ + const char *name = js_CodeName[getOp()]; + fprintf(stderr, "(%s ", name); + if (pn_head != NULL) { + indent += strlen(name) + 2; + DumpParseTree(pn_head, indent); + ParseNode *pn = pn_head->pn_next; + while (pn != NULL) { + IndentNewLine(indent); + DumpParseTree(pn, indent); + pn = pn->pn_next; + } + } + fprintf(stderr, ")"); +} + +inline void +NameNode::dump(int indent) +{ + const char *name = js_CodeName[getOp()]; + if (isUsed()) + fprintf(stderr, "(%s)", name); + else { + fprintf(stderr, "(%s ", name); + indent += strlen(name) + 2; + DumpParseTree(expr(), indent); + fprintf(stderr, ")"); + } +} +#endif + inline void NameNode::initCommon(TreeContext *tc) { diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 8c4132dd4c0..c3534a21bee 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -660,3 +660,14 @@ js::CloneLeftHandSide(ParseNode *opn, TreeContext *tc) } return pn; } + +#ifdef DEBUG +void +js::DumpParseTree(ParseNode *pn, int indent) +{ + if (pn == NULL) + fprintf(stderr, "()"); + else + pn->dump(indent); +} +#endif diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 96c2cb90357..ce5d219d4ea 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -929,12 +929,20 @@ struct ParseNode { #endif inline ConditionalExpression &asConditionalExpression(); inline PropertyAccess &asPropertyAccess(); + +#ifdef DEBUG + inline void dump(int indent); +#endif }; struct NullaryNode : public ParseNode { static inline NullaryNode *create(ParseNodeKind kind, TreeContext *tc) { return (NullaryNode *)ParseNode::create(kind, PN_NULLARY, tc); } + +#ifdef DEBUG + inline void dump(); +#endif }; struct UnaryNode : public ParseNode { @@ -947,6 +955,10 @@ struct UnaryNode : public ParseNode { static inline UnaryNode *create(ParseNodeKind kind, TreeContext *tc) { return (UnaryNode *)ParseNode::create(kind, PN_UNARY, tc); } + +#ifdef DEBUG + inline void dump(int indent); +#endif }; struct BinaryNode : public ParseNode { @@ -967,6 +979,10 @@ struct BinaryNode : public ParseNode { static inline BinaryNode *create(ParseNodeKind kind, TreeContext *tc) { return (BinaryNode *)ParseNode::create(kind, PN_BINARY, tc); } + +#ifdef DEBUG + inline void dump(int indent); +#endif }; struct TernaryNode : public ParseNode { @@ -983,24 +999,40 @@ struct TernaryNode : public ParseNode { static inline TernaryNode *create(ParseNodeKind kind, TreeContext *tc) { return (TernaryNode *)ParseNode::create(kind, PN_TERNARY, tc); } + +#ifdef DEBUG + inline void dump(int indent); +#endif }; struct ListNode : public ParseNode { static inline ListNode *create(ParseNodeKind kind, TreeContext *tc) { return (ListNode *)ParseNode::create(kind, PN_LIST, tc); } + +#ifdef DEBUG + inline void dump(int indent); +#endif }; struct FunctionNode : public ParseNode { static inline FunctionNode *create(ParseNodeKind kind, TreeContext *tc) { return (FunctionNode *)ParseNode::create(kind, PN_FUNC, tc); } + +#ifdef DEBUG + inline void dump(int indent); +#endif }; struct NameNode : public ParseNode { static NameNode *create(ParseNodeKind kind, JSAtom *atom, TreeContext *tc); inline void initCommon(TreeContext *tc); + +#ifdef DEBUG + inline void dump(int indent); +#endif }; struct NameSetNode : public ParseNode { @@ -1254,6 +1286,10 @@ class PropertyByValue : public ParseNode { ParseNode * CloneLeftHandSide(ParseNode *opn, TreeContext *tc); +#ifdef DEBUG +void DumpParseTree(ParseNode *pn, int indent = 0); +#endif + /* * js::Definition is a degenerate subtype of the PN_FUNC and PN_NAME variants * of js::ParseNode, allocated only for function, var, const, and let diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index a21cf9db94e..b0feda55fd6 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3704,8 +3704,12 @@ Parse(JSContext *cx, uintN argc, jsval *vp) js::Parser parser(cx); parser.init(JS_GetStringCharsZ(cx, scriptContents), JS_GetStringLength(scriptContents), "", 0, cx->findVersion()); - if (!parser.parse(NULL)) + ParseNode *pn = parser.parse(NULL); + if (!pn) return JS_FALSE; +#ifdef DEBUG + DumpParseTree(pn); +#endif JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; }