diff options
Diffstat (limited to 'js/src/frontend/Parser.cpp')
-rw-r--r-- | js/src/frontend/Parser.cpp | 110 |
1 files changed, 81 insertions, 29 deletions
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5202b7154..a66183b4a 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -18,6 +18,7 @@ #include "frontend/Parser.h" +#include "mozilla/ArrayUtils.h" // mozilla::ArrayLength #include "mozilla/Sprintf.h" #include <new> @@ -46,6 +47,7 @@ using namespace js; using namespace js::gc; +using mozilla::ArrayLength; using mozilla::Maybe; using mozilla::Move; using mozilla::Nothing; @@ -7842,7 +7844,13 @@ Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling, return seq; } +/* These must be in the same order in several places: + * - the precedence table in Parser.cpp + * - the binary operators in ParseNode.h and TokenKind.h + * - the first and last binary operator markers in ParseNode.h + */ static const JSOp ParseNodeKindToJSOp[] = { + JSOP_COALESCE, JSOP_OR, JSOP_AND, JSOP_BITOR, @@ -7874,6 +7882,11 @@ BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk) { MOZ_ASSERT(pnk >= PNK_BINOP_FIRST); MOZ_ASSERT(pnk <= PNK_BINOP_LAST); +#ifdef DEBUG + int jsopArraySize = ArrayLength(ParseNodeKindToJSOp); + int parseNodeKindListSize = PNK_BINOP_LAST - PNK_BINOP_FIRST + 1; + MOZ_ASSERT(jsopArraySize == parseNodeKindListSize); +#endif return ParseNodeKindToJSOp[pnk - PNK_BINOP_FIRST]; } @@ -7884,34 +7897,39 @@ BinaryOpTokenKindToParseNodeKind(TokenKind tok) return ParseNodeKind(PNK_BINOP_FIRST + (tok - TOK_BINOP_FIRST)); } +/* These must be in the same order in several places: + * - the JSOp code list in Parser.cpp + * - the binary operators in ParseNode.h and TokenKind.h + */ static const int PrecedenceTable[] = { - 1, /* PNK_OR */ - 2, /* PNK_AND */ - 3, /* PNK_BITOR */ - 4, /* PNK_BITXOR */ - 5, /* PNK_BITAND */ - 6, /* PNK_STRICTEQ */ - 6, /* PNK_EQ */ - 6, /* PNK_STRICTNE */ - 6, /* PNK_NE */ - 7, /* PNK_LT */ - 7, /* PNK_LE */ - 7, /* PNK_GT */ - 7, /* PNK_GE */ - 7, /* PNK_INSTANCEOF */ - 7, /* PNK_IN */ - 8, /* PNK_LSH */ - 8, /* PNK_RSH */ - 8, /* PNK_URSH */ - 9, /* PNK_ADD */ - 9, /* PNK_SUB */ - 10, /* PNK_STAR */ - 10, /* PNK_DIV */ - 10, /* PNK_MOD */ - 11 /* PNK_POW */ + 1, /* PNK_COALESCE */ + 2, /* PNK_OR */ + 3, /* PNK_AND */ + 4, /* PNK_BITOR */ + 5, /* PNK_BITXOR */ + 6, /* PNK_BITAND */ + 7, /* PNK_STRICTEQ */ + 7, /* PNK_EQ */ + 7, /* PNK_STRICTNE */ + 7, /* PNK_NE */ + 8, /* PNK_LT */ + 8, /* PNK_LE */ + 8, /* PNK_GT */ + 8, /* PNK_GE */ + 8, /* PNK_INSTANCEOF */ + 8, /* PNK_IN */ + 9, /* PNK_LSH */ + 9, /* PNK_RSH */ + 9, /* PNK_URSH */ + 10, /* PNK_ADD */ + 10, /* PNK_SUB */ + 11, /* PNK_STAR */ + 11, /* PNK_DIV */ + 11, /* PNK_MOD */ + 12 /* PNK_POW */ }; -static const int PRECEDENCE_CLASSES = 11; +static const int PRECEDENCE_CLASSES = 12; static int Precedence(ParseNodeKind pnk) { @@ -7926,6 +7944,8 @@ Precedence(ParseNodeKind pnk) { return PrecedenceTable[pnk - PNK_BINOP_FIRST]; } +enum class EnforcedParentheses : uint8_t { CoalesceExpr, AndOrExpr, None }; + template <typename ParseHandler> MOZ_ALWAYS_INLINE typename ParseHandler::Node Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling, @@ -7942,6 +7962,7 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling ParseNodeKind kindStack[PRECEDENCE_CLASSES]; int depth = 0; Node pn; + EnforcedParentheses unparenthesizedExpression = EnforcedParentheses::None; for (;;) { pn = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked); if (!pn) @@ -7959,11 +7980,42 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling // pending expression error now. if (possibleError && !possibleError->checkForExpressionError()) return null(); - // Report an error for unary expressions on the LHS of **. - if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) { - error(JSMSG_BAD_POW_LEFTSIDE); - return null(); + + switch (tok) { + // Report an error for unary expressions on the LHS of **. + case TOK_POW: + if (handler.isUnparenthesizedUnaryExpression(pn)) { + error(JSMSG_BAD_POW_LEFTSIDE); + return null(); + } + break; + case TOK_OR: + case TOK_AND: + // Report an error if ?? is on the LHS of the expression. + // Mixing other logical operators with the nullish coalescing + // operator is disallowed unless one expression is parenthesized. + if (unparenthesizedExpression == EnforcedParentheses::CoalesceExpr) { + error(JSMSG_BAD_COALESCE_MIXING); + return null(); + } + // If we have not detected a mixing error at this point, record that + // we have an unparenthesized expression, in case we have one later. + unparenthesizedExpression = EnforcedParentheses::AndOrExpr; + break; + case TOK_COALESCE: + if (unparenthesizedExpression == EnforcedParentheses::AndOrExpr) { + error(JSMSG_BAD_COALESCE_MIXING); + return null(); + } + // If we have not detected a mixing error at this point, record that + // we have an unparenthesized expression, in case we have one later. + unparenthesizedExpression = EnforcedParentheses::CoalesceExpr; + break; + default: + // Do nothing in other cases. + break; } + pnk = BinaryOpTokenKindToParseNodeKind(tok); } else { tok = TOK_EOF; |