summaryrefslogtreecommitdiff
path: root/js/src/frontend/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/Parser.cpp')
-rw-r--r--js/src/frontend/Parser.cpp110
1 files changed, 81 insertions, 29 deletions
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 5202b71545..a66183b4a8 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;