diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index 60694aa1ef1a..24ac6fd3b9f5 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -509,7 +509,7 @@ class NodeBuilder bool switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPos *pos, Value *dst); - bool tryStatement(Value body, NodeVector &catches, Value finally, TokenPos *pos, Value *dst); + bool tryStatement(Value body, NodeVector &guarded, Value unguarded, Value finally, TokenPos *pos, Value *dst); bool debuggerStatement(TokenPos *pos, Value *dst); @@ -916,23 +916,24 @@ NodeBuilder::switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPo } bool -NodeBuilder::tryStatement(Value body, NodeVector &catches, Value finally, +NodeBuilder::tryStatement(Value body, NodeVector &guarded, Value unguarded, Value finally, TokenPos *pos, Value *dst) { - Value handlers; + Value guardedHandlers; Value cb = callbacks[AST_TRY_STMT]; if (!cb.isNull()) { - return newArray(catches, &handlers) && - callback(cb, body, handlers, opt(finally), pos, dst); + return newArray(guarded, &guardedHandlers) && + callback(cb, body, guardedHandlers, unguarded, opt(finally), pos, dst); } - if (!newArray(catches, &handlers)) + if (!newArray(guarded, &guardedHandlers)) return false; return newNode(AST_TRY_STMT, pos, "block", body, - "handlers", handlers, + "guardedHandlers", guardedHandlers, + "handler", unguarded, "finalizer", finally, dst); } @@ -1637,7 +1638,7 @@ class ASTSerializer bool switchStatement(ParseNode *pn, Value *dst); bool switchCase(ParseNode *pn, Value *dst); bool tryStatement(ParseNode *pn, Value *dst); - bool catchClause(ParseNode *pn, Value *dst); + bool catchClause(ParseNode *pn, bool *isGuarded, Value *dst); bool optExpression(ParseNode *pn, Value *dst) { if (!pn) { @@ -2066,7 +2067,7 @@ ASTSerializer::switchStatement(ParseNode *pn, Value *dst) } bool -ASTSerializer::catchClause(ParseNode *pn, Value *dst) +ASTSerializer::catchClause(ParseNode *pn, bool *isGuarded, Value *dst) { JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos)); JS_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos)); @@ -2074,9 +2075,14 @@ ASTSerializer::catchClause(ParseNode *pn, Value *dst) Value var, guard, body; - return pattern(pn->pn_kid1, NULL, &var) && - optExpression(pn->pn_kid2, &guard) && - statement(pn->pn_kid3, &body) && + if (!pattern(pn->pn_kid1, NULL, &var) || + !optExpression(pn->pn_kid2, &guard)) { + return false; + } + + *isGuarded = !guard.isMagic(JS_SERIALIZE_NO_NODE); + + return statement(pn->pn_kid3, &body) && builder.catchClause(var, guard, body, &pn->pn_pos, dst); } @@ -2091,22 +2097,28 @@ ASTSerializer::tryStatement(ParseNode *pn, Value *dst) if (!statement(pn->pn_kid1, &body)) return false; - NodeVector clauses(cx); + NodeVector guarded(cx); + Value unguarded = NullValue(); + if (pn->pn_kid2) { - if (!clauses.reserve(pn->pn_kid2->pn_count)) + if (!guarded.reserve(pn->pn_kid2->pn_count)) return false; for (ParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) { Value clause; - if (!catchClause(next->pn_expr, &clause)) + bool isGuarded; + if (!catchClause(next->pn_expr, &isGuarded, &clause)) return false; - clauses.infallibleAppend(clause); + if (isGuarded) + guarded.infallibleAppend(clause); + else + unguarded = clause; } } Value finally; return optStatement(pn->pn_kid3, &finally) && - builder.tryStatement(body, clauses, finally, &pn->pn_pos, dst); + builder.tryStatement(body, guarded, unguarded, finally, &pn->pn_pos, dst); } bool diff --git a/js/src/tests/js1_8_5/extensions/reflect-parse.js b/js/src/tests/js1_8_5/extensions/reflect-parse.js index 927298ca0eec..abbf55b4f7eb 100644 --- a/js/src/tests/js1_8_5/extensions/reflect-parse.js +++ b/js/src/tests/js1_8_5/extensions/reflect-parse.js @@ -63,7 +63,7 @@ function switchStmt(disc, cases) Pattern({ type: "SwitchStatement", discriminant function caseClause(test, stmts) Pattern({ type: "SwitchCase", test: test, consequent: stmts }) function defaultClause(stmts) Pattern({ type: "SwitchCase", test: null, consequent: stmts }) function catchClause(id, guard, body) Pattern({ type: "CatchClause", param: id, guard: guard, body: body }) -function tryStmt(body, catches, fin) Pattern({ type: "TryStatement", block: body, handlers: catches, finalizer: fin }) +function tryStmt(body, guarded, unguarded, fin) Pattern({ type: "TryStatement", block: body, guardedHandlers: guarded, handler: unguarded, finalizer: fin }) function letStmt(head, body) Pattern({ type: "LetStatement", head: head, body: body }) function funExpr(id, args, body, gen) Pattern({ type: "FunctionExpression", id: id, @@ -414,26 +414,30 @@ assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; case caseClause(lit(42), [ exprStmt(lit(42)) ]) ])); assertStmt("try { } catch (e) { }", tryStmt(blockStmt([]), - [ catchClause(ident("e"), null, blockStmt([])) ], + [], + catchClause(ident("e"), null, blockStmt([])), null)); assertStmt("try { } catch (e) { } finally { }", tryStmt(blockStmt([]), - [ catchClause(ident("e"), null, blockStmt([])) ], + [], + catchClause(ident("e"), null, blockStmt([])), blockStmt([]))); assertStmt("try { } finally { }", tryStmt(blockStmt([]), [], + null, blockStmt([]))); assertStmt("try { } catch (e if foo) { } catch (e if bar) { } finally { }", tryStmt(blockStmt([]), [ catchClause(ident("e"), ident("foo"), blockStmt([])), catchClause(ident("e"), ident("bar"), blockStmt([])) ], + null, blockStmt([]))); assertStmt("try { } catch (e if foo) { } catch (e if bar) { } catch (e) { } finally { }", tryStmt(blockStmt([]), [ catchClause(ident("e"), ident("foo"), blockStmt([])), - catchClause(ident("e"), ident("bar"), blockStmt([])), - catchClause(ident("e"), null, blockStmt([])) ], + catchClause(ident("e"), ident("bar"), blockStmt([])) ], + catchClause(ident("e"), null, blockStmt([])), blockStmt([]))); // Bug 632028: yield outside of a function should throw @@ -1037,9 +1041,11 @@ assertGlobalExpr("(function() { yield 42 })", genFunExpr(null, [], blockStmt([ex assertGlobalExpr("(let (x) x)", 20, { letExpression: function() 20 }); assertGlobalStmt("switch (x) { case y: }", switchStmt(ident("x"), [1]), { switchCase: function() 1 }); -assertGlobalStmt("try { } catch (e) { }", tryStmt(blockStmt([]), [2], null), { catchClause: function() 2 }); +assertGlobalStmt("try { } catch (e) { }", 2, { tryStatement: (function(b, g, u, f) u), catchClause: function() 2 }); +assertGlobalStmt("try { } catch (e if e instanceof A) { } catch (e if e instanceof B) { }", [2, 2], { tryStatement: (function(b, g, u, f) g), catchClause: function() 2 }); +assertGlobalStmt("try { } catch (e) { }", tryStmt(blockStmt([]), [], 2, null), { catchClause: function() 2 }); assertGlobalStmt("try { } catch (e if e instanceof A) { } catch (e if e instanceof B) { }", - tryStmt(blockStmt([]), [2, 2], null), + tryStmt(blockStmt([]), [2, 2], null, null), { catchClause: function() 2 }); assertGlobalExpr("[x for (y in z) for (x in y)]", compExpr(ident("x"), [3, 3], null), { comprehensionBlock: function() 3 });