diff options
author | wolfbeast <mcwerewolf@wolfbeast.com> | 2020-02-27 20:09:26 +0100 |
---|---|---|
committer | wolfbeast <mcwerewolf@wolfbeast.com> | 2020-02-27 20:09:26 +0100 |
commit | ae8eb4d4c42d96c264d5036e1c50e8c1d0d55425 (patch) | |
tree | 061997488fc462caeae817e6547d3a30351c8a8d /js/src/frontend | |
parent | 793da7dd6238ce156e29c71304e24b2c05edc11d (diff) | |
download | UXP-ae8eb4d4c42d96c264d5036e1c50e8c1d0d55425.tar UXP-ae8eb4d4c42d96c264d5036e1c50e8c1d0d55425.tar.gz UXP-ae8eb4d4c42d96c264d5036e1c50e8c1d0d55425.tar.lz UXP-ae8eb4d4c42d96c264d5036e1c50e8c1d0d55425.tar.xz UXP-ae8eb4d4c42d96c264d5036e1c50e8c1d0d55425.zip |
Issue #1465 - Implement optional catch binding.
Diffstat (limited to 'js/src/frontend')
-rw-r--r-- | js/src/frontend/BytecodeEmitter.cpp | 57 | ||||
-rw-r--r-- | js/src/frontend/FoldConstants.cpp | 7 | ||||
-rw-r--r-- | js/src/frontend/NameFunctions.cpp | 6 | ||||
-rw-r--r-- | js/src/frontend/ParseNode.cpp | 11 | ||||
-rw-r--r-- | js/src/frontend/Parser.cpp | 88 |
5 files changed, 97 insertions, 72 deletions
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 8cd06feac..18cc7d954 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3459,10 +3459,12 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_CATCH: MOZ_ASSERT(pn->isArity(PN_TERNARY)); - if (!checkSideEffects(pn->pn_kid1, answer)) - return false; - if (*answer) - return true; + if (ParseNode* name = pn->pn_kid1) { + if (!checkSideEffects(name, answer)) + return false; + if (*answer) + return true; + } if (ParseNode* cond = pn->pn_kid2) { if (!checkSideEffects(cond, answer)) return false; @@ -6638,24 +6640,31 @@ BytecodeEmitter::emitCatch(ParseNode* pn) return false; ParseNode* pn2 = pn->pn_kid1; - switch (pn2->getKind()) { - case PNK_ARRAY: - case PNK_OBJECT: - if (!emitDestructuringOps(pn2, DestructuringDeclaration)) - return false; - if (!emit1(JSOP_POP)) - return false; - break; - - case PNK_NAME: - if (!emitLexicalInitialization(pn2)) - return false; - if (!emit1(JSOP_POP)) - return false; - break; - - default: - MOZ_ASSERT(0); + if (!pn2) { + // See ES2019 13.15.7 Runtime Semantics: CatchClauseEvaluation + // Catch variable was omitted: discard the exception. + if (!emit1(JSOP_POP)) + return false; + } else { + switch (pn2->getKind()) { + case PNK_ARRAY: + case PNK_OBJECT: + if (!emitDestructuringOps(pn2, DestructuringDeclaration)) + return false; + if (!emit1(JSOP_POP)) + return false; + break; + + case PNK_NAME: + if (!emitLexicalInitialization(pn2)) + return false; + if (!emit1(JSOP_POP)) + return false; + break; + + default: + MOZ_ASSERT(0); + } } // If there is a guard expression, emit it and arrange to jump to the next @@ -6899,7 +6908,9 @@ BytecodeEmitter::emitLexicalScope(ParseNode* pn) EmitterScope emitterScope(this); ScopeKind kind; if (body->isKind(PNK_CATCH)) - kind = body->pn_kid1->isKind(PNK_NAME) ? ScopeKind::SimpleCatch : ScopeKind::Catch; + kind = (!body->pn_kid1 || body->pn_kid1->isKind(PNK_NAME)) ? + ScopeKind::SimpleCatch : + ScopeKind::Catch; else kind = ScopeKind::Lexical; diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 16294c4a8..b460b92b6 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -1260,9 +1260,10 @@ FoldCatch(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parse MOZ_ASSERT(node->isKind(PNK_CATCH)); MOZ_ASSERT(node->isArity(PN_TERNARY)); - ParseNode*& declPattern = node->pn_kid1; - if (!Fold(cx, &declPattern, parser, inGenexpLambda)) - return false; + if (ParseNode*& declPattern = node->pn_kid1) { + if (!Fold(cx, &declPattern, parser, inGenexpLambda)) + return false; + } if (ParseNode*& cond = node->pn_kid2) { if (!FoldCondition(cx, &cond, parser, inGenexpLambda)) diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index 376be7624..db70bb5b4 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -651,8 +651,10 @@ class NameResolver // contain arbitrary expressions. case PNK_CATCH: MOZ_ASSERT(cur->isArity(PN_TERNARY)); - if (!resolve(cur->pn_kid1, prefix)) - return false; + if (cur->pn_kid1) { + if (!resolve(cur->pn_kid1, prefix)) + return false; + } if (cur->pn_kid2) { if (!resolve(cur->pn_kid2, prefix)) return false; diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 42ae9451a..e01a41067 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -409,13 +409,14 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) return PushResult::Recyclable; } - // A catch node has first kid as catch-variable pattern, the second kid - // as catch condition (which, if non-null, records the |<cond>| in - // SpiderMonkey's |catch (e if <cond>)| extension), and third kid as the - // statements in the catch block. + // A catch node has an (optional) first kid as catch-variable pattern, + // the second kid as (optional) catch condition (which, records the + // |<cond>| in SpiderMonkey's |catch (e if <cond>)| extension), and + // third kid as the statements in the catch block. case PNK_CATCH: { MOZ_ASSERT(pn->isArity(PN_TERNARY)); - stack->push(pn->pn_kid1); + if (pn->pn_kid1) + stack->push(pn->pn_kid1); if (pn->pn_kid2) stack->push(pn->pn_kid2); stack->push(pn->pn_kid3); diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index cf9f1e27c..810d589be 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6901,57 +6901,67 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling) /* * Legal catch forms are: * catch (lhs) - * catch (lhs if <boolean_expression>) + * catch (lhs if <boolean_expression>) ** non-standard ** + * catch ** ES2019 ** * where lhs is a name or a destructuring left-hand side. - * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD) + * The second is legal only #ifdef JS_HAS_CATCH_GUARD */ - MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH); - - if (!tokenStream.getToken(&tt)) + bool omittedBinding; + if (!tokenStream.matchToken(&omittedBinding, TOK_LC)) return null(); + Node catchName; - switch (tt) { - case TOK_LB: - case TOK_LC: - catchName = destructuringDeclaration(DeclarationKind::CatchParameter, - yieldHandling, tt); - if (!catchName) - return null(); - break; + Node catchGuard = null(); - default: { - if (!TokenKindIsPossibleIdentifierName(tt)) { - error(JSMSG_CATCH_IDENTIFIER); - return null(); - } + if (omittedBinding) { + catchName = null(); + } else { + MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH); - catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter, - yieldHandling); - if (!catchName) + if (!tokenStream.getToken(&tt)) return null(); - break; - } - } + switch (tt) { + case TOK_LB: + case TOK_LC: + catchName = destructuringDeclaration(DeclarationKind::CatchParameter, + yieldHandling, tt); + if (!catchName) + return null(); + break; + + default: { + if (!TokenKindIsPossibleIdentifierName(tt)) { + error(JSMSG_CATCH_IDENTIFIER); + return null(); + } + + catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter, + yieldHandling); + if (!catchName) + return null(); + break; + } + } - Node catchGuard = null(); #if JS_HAS_CATCH_GUARD - /* - * We use 'catch (x if x === 5)' (not 'catch (x : x === 5)') - * to avoid conflicting with the JS2/ECMAv4 type annotation - * catchguard syntax. - */ - bool matched; - if (!tokenStream.matchToken(&matched, TOK_IF)) - return null(); - if (matched) { - catchGuard = expr(InAllowed, yieldHandling, TripledotProhibited); - if (!catchGuard) + /* + * We use 'catch (x if x === 5)' (not 'catch (x : x === 5)') + * to avoid conflicting with the JS2/ECMAv4 type annotation + * catchguard syntax. + */ + bool matched; + if (!tokenStream.matchToken(&matched, TOK_IF)) return null(); - } + if (matched) { + catchGuard = expr(InAllowed, yieldHandling, TripledotProhibited); + if (!catchGuard) + return null(); + } #endif - MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH); + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH); - MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH); + MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH); + } Node catchBody = catchBlockStatement(yieldHandling, scope); if (!catchBody) |