summaryrefslogtreecommitdiffstats
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.cpp3145
1 files changed, 1911 insertions, 1234 deletions
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 3b7a0e612..0c279591f 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -19,6 +19,8 @@
#include "frontend/Parser.h"
+#include "mozilla/Sprintf.h"
+
#include <new>
#include "jsapi.h"
@@ -62,19 +64,33 @@ using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
using BindingIter = ParseContext::Scope::BindingIter;
using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
-/* Read a token. Report an error and return null() if that token isn't of type tt. */
-#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \
+// Read a token. Report an error and return null() if that token doesn't match
+// to the condition. Do not use MUST_MATCH_TOKEN_INTERNAL directly.
+#define MUST_MATCH_TOKEN_INTERNAL(cond, modifier, errorReport) \
JS_BEGIN_MACRO \
TokenKind token; \
if (!tokenStream.getToken(&token, modifier)) \
return null(); \
- if (token != tt) { \
- error(errorNumber); \
+ if (!(cond)) { \
+ errorReport; \
return null(); \
} \
JS_END_MACRO
-#define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errno)
+#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \
+ MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, error(errorNumber))
+
+#define MUST_MATCH_TOKEN(tt, errorNumber) \
+ MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errorNumber)
+
+#define MUST_MATCH_TOKEN_FUNC_MOD(func, modifier, errorNumber) \
+ MUST_MATCH_TOKEN_INTERNAL((func)(token), modifier, error(errorNumber))
+
+#define MUST_MATCH_TOKEN_FUNC(func, errorNumber) \
+ MUST_MATCH_TOKEN_FUNC_MOD(func, TokenStream::None, errorNumber)
+
+#define MUST_MATCH_TOKEN_MOD_WITH_REPORT(tt, modifier, errorReport) \
+ MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, errorReport)
template <class T, class U>
static inline void
@@ -106,6 +122,7 @@ DeclarationKindString(DeclarationKind kind)
case DeclarationKind::Import:
return "import";
case DeclarationKind::BodyLevelFunction:
+ case DeclarationKind::ModuleBodyLevelFunction:
case DeclarationKind::LexicalFunction:
return "function";
case DeclarationKind::VarForAnnexBLexicalFunction:
@@ -127,7 +144,8 @@ StatementKindIsBraced(StatementKind kind)
kind == StatementKind::Switch ||
kind == StatementKind::Try ||
kind == StatementKind::Catch ||
- kind == StatementKind::Finally;
+ kind == StatementKind::Finally ||
+ kind == StatementKind::Class;
}
void
@@ -189,11 +207,12 @@ ParseContext::Scope::addCatchParameters(ParseContext* pc, Scope& catchParamScope
for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) {
DeclarationKind kind = r.front().value()->kind();
+ uint32_t pos = r.front().value()->pos();
MOZ_ASSERT(DeclarationKindIsCatchParameter(kind));
JSAtom* name = r.front().key();
AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name);
MOZ_ASSERT(!p);
- if (!addDeclaredName(pc, p, name, kind))
+ if (!addDeclaredName(pc, p, name, kind, pos))
return false;
}
@@ -332,7 +351,8 @@ ParseContext::init()
namedLambdaScope_->lookupDeclaredNameForAdd(fun->explicitName());
MOZ_ASSERT(!p);
if (!namedLambdaScope_->addDeclaredName(this, p, fun->explicitName(),
- DeclarationKind::Const))
+ DeclarationKind::Const,
+ DeclaredNameInfo::npos))
{
return false;
}
@@ -441,7 +461,7 @@ UsedNameTracker::rewind(RewindToken token)
}
FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead,
- JSFunction* fun, uint32_t preludeStart,
+ JSFunction* fun, uint32_t toStringStart,
Directives directives, bool extraWarnings,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
: ObjectBox(fun, traceListHead),
@@ -455,7 +475,8 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
bufEnd(0),
startLine(1),
startColumn(0),
- preludeStart(preludeStart),
+ toStringStart(toStringStart),
+ toStringEnd(0),
length(0),
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
asyncKindBits_(AsyncKindAsBits(asyncKind)),
@@ -474,6 +495,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
usesThis(false),
usesReturn(false),
hasRest_(false),
+ isExprBody_(false),
funCxFlags()
{
// Functions created at parse time may be set singleton after parsing and
@@ -525,10 +547,16 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
allowNewTarget_ = true;
allowSuperProperty_ = fun->allowSuperProperty();
- if (kind == DerivedClassConstructor) {
- setDerivedClassConstructor();
- allowSuperCall_ = true;
- needsThisTDZChecks_ = true;
+ if (kind == ClassConstructor || kind == DerivedClassConstructor) {
+ auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
+ MOZ_ASSERT(stmt);
+ stmt->constructorBox = this;
+
+ if (kind == DerivedClassConstructor) {
+ setDerivedClassConstructor();
+ allowSuperCall_ = true;
+ needsThisTDZChecks_ = true;
+ }
}
if (isGenexpLambda)
@@ -570,97 +598,136 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
computeInWith(enclosingScope);
}
-template <typename ParseHandler>
void
-Parser<ParseHandler>::error(unsigned errorNumber, ...)
+ParserBase::error(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
#ifdef DEBUG
bool result =
#endif
- tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_ERROR, errorNumber, args);
+ tokenStream.reportCompileErrorNumberVA(nullptr, pos().begin, JSREPORT_ERROR,
+ errorNumber, args);
MOZ_ASSERT(!result, "reporting an error returned true?");
va_end(args);
}
-template <typename ParseHandler>
void
-Parser<ParseHandler>::errorAt(uint32_t offset, unsigned errorNumber, ...)
+ParserBase::errorWithNotes(UniquePtr<JSErrorNotes> notes, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
#ifdef DEBUG
bool result =
#endif
- tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args);
+ tokenStream.reportCompileErrorNumberVA(Move(notes), pos().begin, JSREPORT_ERROR,
+ errorNumber, args);
+ MOZ_ASSERT(!result, "reporting an error returned true?");
+ va_end(args);
+}
+
+void
+ParserBase::errorAt(uint32_t offset, unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+#ifdef DEBUG
+ bool result =
+#endif
+ tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR, errorNumber, args);
+ MOZ_ASSERT(!result, "reporting an error returned true?");
+ va_end(args);
+}
+
+void
+ParserBase::errorWithNotesAt(UniquePtr<JSErrorNotes> notes, uint32_t offset,
+ unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+#ifdef DEBUG
+ bool result =
+#endif
+ tokenStream.reportCompileErrorNumberVA(Move(notes), offset, JSREPORT_ERROR,
+ errorNumber, args);
MOZ_ASSERT(!result, "reporting an error returned true?");
va_end(args);
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::warning(unsigned errorNumber, ...)
+ParserBase::warning(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
bool result =
- tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_WARNING, errorNumber, args);
+ tokenStream.reportCompileErrorNumberVA(nullptr, pos().begin, JSREPORT_WARNING,
+ errorNumber, args);
va_end(args);
return result;
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::warningAt(uint32_t offset, unsigned errorNumber, ...)
+ParserBase::warningAt(uint32_t offset, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
bool result =
- tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args);
+ tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_WARNING,
+ errorNumber, args);
va_end(args);
return result;
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::extraWarning(unsigned errorNumber, ...)
+ParserBase::extraWarning(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
- bool result = tokenStream.reportExtraWarningErrorNumberVA(pos().begin, errorNumber, args);
+ bool result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, pos().begin,
+ errorNumber, args);
va_end(args);
return result;
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::strictModeError(unsigned errorNumber, ...)
+ParserBase::extraWarningAt(uint32_t offset, unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+
+ bool result =
+ tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, args);
+
+ va_end(args);
+ return result;
+}
+
+bool
+ParserBase::strictModeError(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
bool res =
- tokenStream.reportStrictModeErrorNumberVA(pos().begin, pc->sc()->strict(),
+ tokenStream.reportStrictModeErrorNumberVA(nullptr, pos().begin, pc->sc()->strict(),
errorNumber, args);
va_end(args);
return res;
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
+ParserBase::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
bool res =
- tokenStream.reportStrictModeErrorNumberVA(offset, pc->sc()->strict(), errorNumber, args);
+ tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, pc->sc()->strict(),
+ errorNumber, args);
va_end(args);
return res;
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
+ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
@@ -668,17 +735,21 @@ Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned
uint32_t offset = TokenStream::NoOffset;
switch (kind) {
case ParseError:
- result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args);
+ result = tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR,
+ errorNumber, args);
break;
case ParseWarning:
result =
- tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args);
+ tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_WARNING,
+ errorNumber, args);
break;
case ParseExtraWarning:
- result = tokenStream.reportExtraWarningErrorNumberVA(offset, errorNumber, args);
+ result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset,
+ errorNumber, args);
break;
case ParseStrictError:
- result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args);
+ result = tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, strict,
+ errorNumber, args);
break;
}
va_end(args);
@@ -686,7 +757,7 @@ Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned
}
template <>
-bool
+inline bool
Parser<FullParseHandler>::abortIfSyntaxParser()
{
handler.disableSyntaxParser();
@@ -694,23 +765,21 @@ Parser<FullParseHandler>::abortIfSyntaxParser()
}
template <>
-bool
+inline bool
Parser<SyntaxParseHandler>::abortIfSyntaxParser()
{
abortedSyntaxParse = true;
return false;
}
-template <typename ParseHandler>
-Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc,
- const ReadOnlyCompileOptions& options,
- const char16_t* chars, size_t length,
- bool foldConstants,
- UsedNameTracker& usedNames,
- Parser<SyntaxParseHandler>* syntaxParser,
- LazyScript* lazyOuterFunction)
- : AutoGCRooter(cx, PARSER),
- context(cx),
+ParserBase::ParserBase(ExclusiveContext* cx, LifoAlloc& alloc,
+ const ReadOnlyCompileOptions& options,
+ const char16_t* chars, size_t length,
+ bool foldConstants,
+ UsedNameTracker& usedNames,
+ Parser<SyntaxParseHandler>* syntaxParser,
+ LazyScript* lazyOuterFunction)
+ : context(cx),
alloc(alloc),
tokenStream(cx, options, chars, length, thisForCtor()),
traceListHead(nullptr),
@@ -725,17 +794,44 @@ Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc,
#endif
abortedSyntaxParse(false),
isUnexpectedEOF_(false),
- handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction)
+ awaitIsKeyword_(false)
{
cx->perThreadData->frontendCollectionPool.addActiveCompilation();
+ tempPoolMark = alloc.mark();
+}
+
+ParserBase::~ParserBase()
+{
+ alloc.release(tempPoolMark);
+
+ /*
+ * The parser can allocate enormous amounts of memory for large functions.
+ * Eagerly free the memory now (which otherwise won't be freed until the
+ * next GC) to avoid unnecessary OOMs.
+ */
+ alloc.freeAllIfHugeAndUnused();
+
+ context->perThreadData->frontendCollectionPool.removeActiveCompilation();
+}
+template <typename ParseHandler>
+Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc,
+ const ReadOnlyCompileOptions& options,
+ const char16_t* chars, size_t length,
+ bool foldConstants,
+ UsedNameTracker& usedNames,
+ Parser<SyntaxParseHandler>* syntaxParser,
+ LazyScript* lazyOuterFunction)
+ : ParserBase(cx, alloc, options, chars, length, foldConstants, usedNames, syntaxParser,
+ lazyOuterFunction),
+ AutoGCRooter(cx, PARSER),
+ handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction)
+{
// The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings
// which are not generated if functions are parsed lazily. Note that the
// standard "use strict" does not inhibit lazy parsing.
if (options.extraWarningsOption)
handler.disableSyntaxParser();
-
- tempPoolMark = alloc.mark();
}
template<typename ParseHandler>
@@ -746,26 +842,29 @@ Parser<ParseHandler>::checkOptions()
checkOptionsCalled = true;
#endif
- if (!tokenStream.checkOptions())
- return false;
-
- return true;
+ return tokenStream.checkOptions();
}
template <typename ParseHandler>
Parser<ParseHandler>::~Parser()
{
MOZ_ASSERT(checkOptionsCalled);
- alloc.release(tempPoolMark);
+}
- /*
- * The parser can allocate enormous amounts of memory for large functions.
- * Eagerly free the memory now (which otherwise won't be freed until the
- * next GC) to avoid unnecessary OOMs.
- */
- alloc.freeAllIfHugeAndUnused();
+template <>
+void
+Parser<SyntaxParseHandler>::setAwaitIsKeyword(bool isKeyword)
+{
+ awaitIsKeyword_ = isKeyword;
+}
- context->perThreadData->frontendCollectionPool.removeActiveCompilation();
+template <>
+void
+Parser<FullParseHandler>::setAwaitIsKeyword(bool isKeyword)
+{
+ awaitIsKeyword_ = isKeyword;
+ if (Parser<SyntaxParseHandler>* parser = handler.syntaxParser)
+ parser->setAwaitIsKeyword(isKeyword);
}
template <typename ParseHandler>
@@ -795,7 +894,7 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj)
template <typename ParseHandler>
FunctionBox*
-Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart,
+Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart,
Directives inheritedDirectives,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB)
@@ -811,7 +910,7 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeS
* function.
*/
FunctionBox* funbox =
- alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, preludeStart,
+ alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, toStringStart,
inheritedDirectives, options().extraWarningsOption,
generatorKind, asyncKind);
if (!funbox) {
@@ -894,38 +993,17 @@ Parser<ParseHandler>::parse()
/*
* Strict mode forbids introducing new definitions for 'eval', 'arguments', or
- * for any strict mode reserved keyword.
+ * for any strict mode reserved word.
*/
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::isValidStrictBinding(PropertyName* name)
+ParserBase::isValidStrictBinding(PropertyName* name)
{
return name != context->names().eval &&
name != context->names().arguments &&
name != context->names().let &&
name != context->names().static_ &&
- !(IsKeyword(name) && name != context->names().await);
-}
-
-/*
- * Check that it is permitted to introduce a binding for |name|. Use |pos| for
- * reporting error locations.
- */
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkStrictBinding(PropertyName* name, TokenPos pos)
-{
- if (!pc->sc()->needStrictChecks())
- return true;
-
- if (!isValidStrictBinding(name)) {
- JSAutoByteString bytes;
- if (!AtomToPrintableString(context, name, &bytes))
- return false;
- return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, bytes.ptr());
- }
-
- return true;
+ name != context->names().yield &&
+ !IsStrictReservedWord(name);
}
/*
@@ -952,13 +1030,71 @@ Parser<ParseHandler>::hasValidSimpleStrictParameterNames()
template <typename ParseHandler>
void
-Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKind kind,
- TokenPos pos)
+Parser<ParseHandler>::reportMissingClosing(unsigned errorNumber, unsigned noteNumber,
+ uint32_t openedPos)
+{
+ auto notes = MakeUnique<JSErrorNotes>();
+ if (!notes)
+ return;
+
+ uint32_t line, column;
+ tokenStream.srcCoords.lineNumAndColumnIndex(openedPos, &line, &column);
+
+ const size_t MaxWidth = sizeof("4294967295");
+ char columnNumber[MaxWidth];
+ SprintfLiteral(columnNumber, "%" PRIu32, column);
+ char lineNumber[MaxWidth];
+ SprintfLiteral(lineNumber, "%" PRIu32, line);
+
+ if (!notes->addNoteASCII(pc->sc()->context,
+ getFilename(), line, column,
+ GetErrorMessage, nullptr,
+ noteNumber, lineNumber, columnNumber))
+ {
+ return;
+ }
+
+ errorWithNotes(Move(notes), errorNumber);
+}
+
+template <typename ParseHandler>
+void
+Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind,
+ TokenPos pos, uint32_t prevPos)
{
JSAutoByteString bytes;
if (!AtomToPrintableString(context, name, &bytes))
return;
- errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(kind), bytes.ptr());
+
+ if (prevPos == DeclaredNameInfo::npos) {
+ errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(prevKind), bytes.ptr());
+ return;
+ }
+
+ auto notes = MakeUnique<JSErrorNotes>();
+ if (!notes)
+ return;
+
+ uint32_t line, column;
+ tokenStream.srcCoords.lineNumAndColumnIndex(prevPos, &line, &column);
+
+ const size_t MaxWidth = sizeof("4294967295");
+ char columnNumber[MaxWidth];
+ SprintfLiteral(columnNumber, "%" PRIu32, column);
+ char lineNumber[MaxWidth];
+ SprintfLiteral(lineNumber, "%" PRIu32, line);
+
+ if (!notes->addNoteASCII(pc->sc()->context,
+ getFilename(), line, column,
+ GetErrorMessage, nullptr,
+ JSMSG_REDECLARED_PREV,
+ lineNumber, columnNumber))
+ {
+ return;
+ }
+
+ errorWithNotesAt(Move(notes), pos.begin, JSMSG_REDECLARED_VAR,
+ DeclarationKindString(prevKind), bytes.ptr());
}
// notePositionalFormalParameter is called for both the arguments of a regular
@@ -973,6 +1109,7 @@ Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKi
template <typename ParseHandler>
bool
Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName name,
+ uint32_t beginPos,
bool disallowDuplicateParams,
bool* duplicatedParam)
{
@@ -997,7 +1134,7 @@ Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName
*duplicatedParam = true;
} else {
DeclarationKind kind = DeclarationKind::PositionalFormalParameter;
- if (!pc->functionScope().addDeclaredName(pc, p, name, kind))
+ if (!pc->functionScope().addDeclaredName(pc, p, name, kind, beginPos))
return false;
}
@@ -1010,9 +1147,6 @@ Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName
if (!paramNode)
return false;
- if (!checkStrictBinding(name, pos()))
- return false;
-
handler.addFunctionFormalParameter(fn, paramNode);
return true;
}
@@ -1104,8 +1238,8 @@ DeclarationKindIsParameter(DeclarationKind kind)
template <typename ParseHandler>
bool
-Parser<ParseHandler>::tryDeclareVar(HandlePropertyName name, DeclarationKind kind,
- Maybe<DeclarationKind>* redeclaredKind)
+Parser<ParseHandler>::tryDeclareVar(HandlePropertyName name, DeclarationKind kind, uint32_t beginPos,
+ Maybe<DeclarationKind>* redeclaredKind, uint32_t* prevPos)
{
MOZ_ASSERT(DeclarationKindIsVar(kind));
@@ -1178,17 +1312,29 @@ Parser<ParseHandler>::tryDeclareVar(HandlePropertyName name, DeclarationKind kin
if (!annexB35Allowance && !annexB33Allowance) {
*redeclaredKind = Some(declaredKind);
+ *prevPos = p->value()->pos();
return true;
}
+ } else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) {
+ MOZ_ASSERT(DeclarationKindIsParameter(declaredKind));
+
+ // Annex B.3.3.1 disallows redeclaring parameter names.
+ // We don't need to set *prevPos here since this case is not
+ // an error.
+ *redeclaredKind = Some(declaredKind);
+ return true;
}
} else {
- if (!scope->addDeclaredName(pc, p, name, kind))
+ if (!scope->addDeclaredName(pc, p, name, kind, beginPos))
return false;
}
}
- if (!pc->sc()->strict() && pc->sc()->isEvalContext())
+ if (!pc->sc()->strict() && pc->sc()->isEvalContext()) {
*redeclaredKind = isVarRedeclaredInEval(name, kind);
+ // We don't have position information at runtime.
+ *prevPos = DeclaredNameInfo::npos;
+ }
return true;
}
@@ -1196,11 +1342,34 @@ Parser<ParseHandler>::tryDeclareVar(HandlePropertyName name, DeclarationKind kin
template <typename ParseHandler>
bool
Parser<ParseHandler>::tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name,
- bool* tryAnnexB)
+ uint32_t beginPos, bool* tryAnnexB)
{
Maybe<DeclarationKind> redeclaredKind;
- if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, &redeclaredKind))
+ uint32_t unused;
+ if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, beginPos,
+ &redeclaredKind, &unused))
+ {
return false;
+ }
+
+ if (!redeclaredKind && pc->isFunctionBox()) {
+ ParseContext::Scope& funScope = pc->functionScope();
+ ParseContext::Scope& varScope = pc->varScope();
+ if (&funScope != &varScope) {
+ // Annex B.3.3.1 disallows redeclaring parameter names. In the
+ // presence of parameter expressions, parameter names are on the
+ // function scope, which encloses the var scope. This means
+ // tryDeclareVar call above would not catch this case, so test it
+ // manually.
+ if (AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(name)) {
+ DeclarationKind declaredKind = p->value()->kind();
+ if (DeclarationKindIsParameter(declaredKind))
+ redeclaredKind = Some(declaredKind);
+ else
+ MOZ_ASSERT(FunctionScope::isSpecialName(context, name));
+ }
+ }
+ }
if (redeclaredKind) {
// If an early error would have occurred, undo all the
@@ -1248,25 +1417,41 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
if (pc->useAsmOrInsideUseAsm())
return true;
- if (!checkStrictBinding(name, pos))
- return false;
-
switch (kind) {
case DeclarationKind::Var:
case DeclarationKind::BodyLevelFunction:
case DeclarationKind::ForOfVar: {
Maybe<DeclarationKind> redeclaredKind;
- if (!tryDeclareVar(name, kind, &redeclaredKind))
+ uint32_t prevPos;
+ if (!tryDeclareVar(name, kind, pos.begin, &redeclaredKind, &prevPos))
return false;
if (redeclaredKind) {
- reportRedeclaration(name, *redeclaredKind, pos);
+ reportRedeclaration(name, *redeclaredKind, pos, prevPos);
return false;
}
break;
}
+ case DeclarationKind::ModuleBodyLevelFunction: {
+ MOZ_ASSERT(pc->atModuleLevel());
+
+ AddDeclaredNamePtr p = pc->varScope().lookupDeclaredNameForAdd(name);
+ if (p) {
+ reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
+ return false;
+ }
+
+ if (!pc->varScope().addDeclaredName(pc, p, name, kind, pos.begin))
+ return false;
+
+ // Body-level functions in modules are always closed over.
+ pc->varScope().lookupDeclaredName(name)->value()->setClosedOver();
+
+ break;
+ }
+
case DeclarationKind::FormalParameter: {
// It is an early error if any non-positional formal parameter name
// (e.g., destructuring formal parameter) is duplicated.
@@ -1277,7 +1462,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
return false;
}
- if (!pc->functionScope().addDeclaredName(pc, p, name, kind))
+ if (!pc->functionScope().addDeclaredName(pc, p, name, kind, pos.begin))
return false;
break;
@@ -1300,7 +1485,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
(p->value()->kind() != DeclarationKind::LexicalFunction &&
p->value()->kind() != DeclarationKind::VarForAnnexBLexicalFunction))
{
- reportRedeclaration(name, p->value()->kind(), pos);
+ reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
return false;
}
@@ -1308,7 +1493,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
// declaration that shadows the VarForAnnexBLexicalFunction.
p->value()->alterKind(kind);
} else {
- if (!scope->addDeclaredName(pc, p, name, kind))
+ if (!scope->addDeclaredName(pc, p, name, kind, pos.begin))
return false;
}
@@ -1348,7 +1533,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
if (pc->isFunctionExtraBodyVarScopeInnermost()) {
DeclaredNamePtr p = pc->functionScope().lookupDeclaredName(name);
if (p && DeclarationKindIsParameter(p->value()->kind())) {
- reportRedeclaration(name, p->value()->kind(), pos);
+ reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
return false;
}
}
@@ -1365,12 +1550,12 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
p = scope->lookupDeclaredNameForAdd(name);
MOZ_ASSERT(!p);
} else {
- reportRedeclaration(name, p->value()->kind(), pos);
+ reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
return false;
}
}
- if (!p && !scope->addDeclaredName(pc, p, name, kind))
+ if (!p && !scope->addDeclaredName(pc, p, name, kind, pos.begin))
return false;
break;
@@ -1742,11 +1927,8 @@ Parser<FullParseHandler>::newFunctionScopeData(ParseContext::Scope& scope, bool
case BindingKind::Var:
// The only vars in the function scope when there are parameter
// exprs, which induces a separate var environment, should be the
- // special internal bindings.
- MOZ_ASSERT_IF(hasParameterExprs,
- bi.name() == context->names().arguments ||
- bi.name() == context->names().dotThis ||
- bi.name() == context->names().dotGenerator);
+ // special bindings.
+ MOZ_ASSERT_IF(hasParameterExprs, FunctionScope::isSpecialName(context, bi.name()));
if (!vars.append(binding))
return Nothing();
break;
@@ -2031,7 +2213,7 @@ Parser<FullParseHandler>::moduleBody(ModuleSharedContext* modulesc)
if (!mn)
return null();
- AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, true);
+ AutoAwaitIsKeyword<FullParseHandler> awaitIsKeyword(this, true);
ParseNode* pn = statementList(YieldIsKeyword);
if (!pn)
return null();
@@ -2123,8 +2305,11 @@ Parser<ParseHandler>::declareFunctionThis()
ParseContext::Scope& funScope = pc->functionScope();
AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis);
MOZ_ASSERT(!p);
- if (!funScope.addDeclaredName(pc, p, dotThis, DeclarationKind::Var))
+ if (!funScope.addDeclaredName(pc, p, dotThis, DeclarationKind::Var,
+ DeclaredNameInfo::npos))
+ {
return false;
+ }
funbox->setHasThisBinding();
}
@@ -2166,14 +2351,17 @@ Parser<ParseHandler>::declareDotGeneratorName()
ParseContext::Scope& funScope = pc->functionScope();
HandlePropertyName dotGenerator = context->names().dotGenerator;
AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator);
- if (!p && !funScope.addDeclaredName(pc, p, dotGenerator, DeclarationKind::Var))
+ if (!p && !funScope.addDeclaredName(pc, p, dotGenerator, DeclarationKind::Var,
+ DeclaredNameInfo::npos))
+ {
return false;
+ }
return true;
}
template <typename ParseHandler>
bool
-Parser<ParseHandler>::finishFunctionScopes()
+Parser<ParseHandler>::finishFunctionScopes(bool isStandaloneFunction)
{
FunctionBox* funbox = pc->functionBox();
@@ -2182,7 +2370,7 @@ Parser<ParseHandler>::finishFunctionScopes()
return false;
}
- if (funbox->function()->isNamedLambda()) {
+ if (funbox->function()->isNamedLambda() && !isStandaloneFunction) {
if (!propagateFreeNamesAndMarkClosedOverBindings(pc->namedLambdaScope()))
return false;
}
@@ -2192,9 +2380,9 @@ Parser<ParseHandler>::finishFunctionScopes()
template <>
bool
-Parser<FullParseHandler>::finishFunction()
+Parser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */)
{
- if (!finishFunctionScopes())
+ if (!finishFunctionScopes(isStandaloneFunction))
return false;
FunctionBox* funbox = pc->functionBox();
@@ -2215,7 +2403,7 @@ Parser<FullParseHandler>::finishFunction()
funbox->functionScopeBindings().set(*bindings);
}
- if (funbox->function()->isNamedLambda()) {
+ if (funbox->function()->isNamedLambda() && !isStandaloneFunction) {
Maybe<LexicalScope::Data*> bindings = newLexicalScopeData(pc->namedLambdaScope());
if (!bindings)
return false;
@@ -2227,14 +2415,14 @@ Parser<FullParseHandler>::finishFunction()
template <>
bool
-Parser<SyntaxParseHandler>::finishFunction()
+Parser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false */)
{
// The LazyScript for a lazily parsed function needs to know its set of
// free variables and inner functions so that when it is fully parsed, we
// can skip over any already syntax parsed inner functions and still
// retain correct scope information.
- if (!finishFunctionScopes())
+ if (!finishFunctionScopes(isStandaloneFunction))
return false;
// There are too many bindings or inner functions to be saved into the
@@ -2251,7 +2439,7 @@ Parser<SyntaxParseHandler>::finishFunction()
LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(),
pc->innerFunctionsForLazy, versionNumber(),
funbox->bufStart, funbox->bufEnd,
- funbox->preludeStart,
+ funbox->toStringStart,
funbox->startLine, funbox->startColumn);
if (!lazy)
return false;
@@ -2264,6 +2452,8 @@ Parser<SyntaxParseHandler>::finishFunction()
lazy->setAsyncKind(funbox->asyncKind());
if (funbox->hasRest())
lazy->setHasRest();
+ if (funbox->isExprBody())
+ lazy->setIsExprBody();
if (funbox->isLikelyConstructorWrapper())
lazy->setLikelyConstructorWrapper();
if (funbox->isDerivedClassConstructor())
@@ -2340,7 +2530,7 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
return null();
fn->pn_body = argsbody;
- FunctionBox* funbox = newFunctionBox(fn, fun, /* preludeStart = */ 0, inheritedDirectives,
+ FunctionBox* funbox = newFunctionBox(fn, fun, /* toStringStart = */ 0, inheritedDirectives,
generatorKind, asyncKind, /* tryAnnexB = */ false);
if (!funbox)
return null();
@@ -2352,9 +2542,9 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
funpc.setIsStandaloneFunctionBody();
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
- AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
+ AutoAwaitIsKeyword<FullParseHandler> awaitIsKeyword(this, asyncKind == AsyncFunction);
if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement,
- parameterListEnd))
+ parameterListEnd, /* isStandaloneFunction = */ true))
{
return null();
}
@@ -2414,8 +2604,11 @@ Parser<ParseHandler>::declareFunctionArgumentsObject()
if (tryDeclareArguments) {
AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName);
if (!p) {
- if (!funScope.addDeclaredName(pc, p, argumentsName, DeclarationKind::Var))
+ if (!funScope.addDeclaredName(pc, p, argumentsName, DeclarationKind::Var,
+ DeclaredNameInfo::npos))
+ {
return false;
+ }
funbox->declaredArguments = true;
funbox->usesArguments = true;
} else if (hasExtraBodyVarScope) {
@@ -2631,39 +2824,59 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
/*
* WARNING: Do not call this function directly.
- * Call either MatchOrInsertSemicolonAfterExpression or
- * MatchOrInsertSemicolonAfterNonExpression instead, depending on context.
+ * Call either matchOrInsertSemicolonAfterExpression or
+ * matchOrInsertSemicolonAfterNonExpression instead, depending on context.
*/
-static bool
-MatchOrInsertSemicolonHelper(TokenStream& ts, TokenStream::Modifier modifier)
+template <typename ParseHandler>
+bool
+Parser<ParseHandler>::matchOrInsertSemicolonHelper(TokenStream::Modifier modifier)
{
TokenKind tt = TOK_EOF;
- if (!ts.peekTokenSameLine(&tt, modifier))
+ if (!tokenStream.peekTokenSameLine(&tt, modifier))
return false;
if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
+ /*
+ * When current token is `await` and it's outside of async function,
+ * it's possibly intended to be an await expression.
+ *
+ * await f();
+ * ^
+ * |
+ * tried to insert semicolon here
+ *
+ * Detect this situation and throw an understandable error. Otherwise
+ * we'd throw a confusing "missing ; before statement" error.
+ */
+ if (!pc->isAsync() && tokenStream.currentToken().type == TOK_AWAIT) {
+ error(JSMSG_AWAIT_OUTSIDE_ASYNC);
+ return false;
+ }
+
/* Advance the scanner for proper error location reporting. */
- ts.consumeKnownToken(tt, modifier);
- ts.reportError(JSMSG_SEMI_BEFORE_STMNT);
+ tokenStream.consumeKnownToken(tt, modifier);
+ error(JSMSG_SEMI_BEFORE_STMNT);
return false;
}
bool matched;
- if (!ts.matchToken(&matched, TOK_SEMI, modifier))
+ if (!tokenStream.matchToken(&matched, TOK_SEMI, modifier))
return false;
if (!matched && modifier == TokenStream::None)
- ts.addModifierException(TokenStream::OperandIsNone);
+ tokenStream.addModifierException(TokenStream::OperandIsNone);
return true;
}
-static bool
-MatchOrInsertSemicolonAfterExpression(TokenStream& ts)
+template <typename ParseHandler>
+bool
+Parser<ParseHandler>::matchOrInsertSemicolonAfterExpression()
{
- return MatchOrInsertSemicolonHelper(ts, TokenStream::None);
+ return matchOrInsertSemicolonHelper(TokenStream::None);
}
-static bool
-MatchOrInsertSemicolonAfterNonExpression(TokenStream& ts)
+template <typename ParseHandler>
+bool
+Parser<ParseHandler>::matchOrInsertSemicolonAfterNonExpression()
{
- return MatchOrInsertSemicolonHelper(ts, TokenStream::Operand);
+ return matchOrInsertSemicolonHelper(TokenStream::Operand);
}
template <typename ParseHandler>
@@ -2757,7 +2970,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
firstTokenModifier = funbox->isAsync() ? TokenStream::None : TokenStream::Operand;
if (!tokenStream.peekToken(&tt, firstTokenModifier))
return false;
- if (tt == TOK_NAME || tt == TOK_YIELD) {
+ if (TokenKindIsPossibleIdentifier(tt)) {
parenFreeArrow = true;
argModifier = firstTokenModifier;
}
@@ -2813,7 +3026,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
if (!tokenStream.getToken(&tt, argModifier))
return false;
argModifier = TokenStream::Operand;
- MOZ_ASSERT_IF(parenFreeArrow, tt == TOK_NAME || tt == TOK_YIELD);
+ MOZ_ASSERT_IF(parenFreeArrow, TokenKindIsPossibleIdentifier(tt));
if (tt == TOK_TRIPLEDOT) {
if (IsSetterKind(kind)) {
@@ -2834,7 +3047,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
if (!tokenStream.getToken(&tt))
return false;
- if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) {
+ if (!TokenKindIsPossibleIdentifier(tt) && tt != TOK_LB && tt != TOK_LC) {
error(JSMSG_NO_REST_NAME);
return false;
}
@@ -2864,26 +3077,21 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
break;
}
- case TOK_NAME:
- case TOK_YIELD: {
- if (parenFreeArrow)
- funbox->setStart(tokenStream);
-
- if (funbox->isAsync() && tokenStream.currentName() == context->names().await) {
- // `await` is already gotten as TOK_NAME for the following
- // case:
- //
- // async await => 1
- error(JSMSG_RESERVED_ID, "await");
+ default: {
+ if (!TokenKindIsPossibleIdentifier(tt)) {
+ error(JSMSG_MISSING_FORMAL);
return false;
}
+ if (parenFreeArrow)
+ funbox->setStart(tokenStream);
+
RootedPropertyName name(context, bindingIdentifier(yieldHandling));
if (!name)
return false;
- if (!notePositionalFormalParameter(funcpn, name, disallowDuplicateParams,
- &duplicatedParam))
+ if (!notePositionalFormalParameter(funcpn, name, pos().begin,
+ disallowDuplicateParams, &duplicatedParam))
{
return false;
}
@@ -2892,10 +3100,6 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
break;
}
-
- default:
- error(JSMSG_MISSING_FORMAL);
- return false;
}
if (positionalFormals.length() >= ARGNO_LIMIT) {
@@ -2989,7 +3193,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
template <>
bool
-Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart,
+Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t toStringStart,
FunctionSyntaxKind kind, bool tryAnnexB)
{
// When a lazily-parsed function is called, we only fully parse (and emit)
@@ -2999,7 +3203,7 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS
RootedFunction fun(context, handler.nextLazyInnerFunction());
MOZ_ASSERT(!fun->isLegacyGenerator());
- FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, Directives(/* strict = */ false),
+ FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, Directives(/* strict = */ false),
fun->generatorKind(), fun->asyncKind(), tryAnnexB);
if (!funbox)
return false;
@@ -3007,6 +3211,8 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS
LazyScript* lazy = fun->lazyScript();
if (lazy->needsHomeObject())
funbox->setNeedsHomeObject();
+ if (lazy->isExprBody())
+ funbox->setIsExprBody();
PropagateTransitiveParseFlags(lazy, pc->sc());
@@ -3019,17 +3225,22 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS
if (!tokenStream.advance(fun->lazyScript()->end() - userbufBase))
return false;
- if (kind == Statement && fun->isExprBody()) {
- if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
+#if JS_HAS_EXPR_CLOSURES
+ // Only expression closure can be Statement kind.
+ // If we remove expression closure, we can remove isExprBody flag from
+ // LazyScript and JSScript.
+ if (kind == Statement && funbox->isExprBody()) {
+ if (!matchOrInsertSemicolonAfterExpression())
return false;
}
+#endif
return true;
}
template <>
bool
-Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t preludeStart,
+Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t toStringStart,
FunctionSyntaxKind kind, bool tryAnnexB)
{
MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
@@ -3082,7 +3293,7 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
{
- Node pn = noSubstitutionTemplate();
+ Node pn = noSubstitutionUntaggedTemplate();
if (!pn)
return null();
@@ -3095,7 +3306,7 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt))
return null();
- pn = noSubstitutionTemplate();
+ pn = noSubstitutionUntaggedTemplate();
if (!pn)
return null();
@@ -3106,7 +3317,7 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling,
+Parser<ParseHandler>::functionDefinition(uint32_t toStringStart, Node pn, InHandling inHandling,
YieldHandling yieldHandling,
HandleAtom funName, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
@@ -3119,7 +3330,7 @@ Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, Node pn, InHandl
// functions, which are also lazy. Instead, their free variables and
// source extents are recorded and may be skipped.
if (handler.canSkipLazyInnerFunctions()) {
- if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB))
+ if (!skipLazyInnerFunction(pn, toStringStart, kind, tryAnnexB))
return null();
return pn;
}
@@ -3152,7 +3363,7 @@ Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, Node pn, InHandl
// reparse a function due to failed syntax parsing and encountering new
// "use foo" directives.
while (true) {
- if (trySyntaxParseInnerFunction(pn, fun, preludeStart, inHandling, yieldHandling, kind,
+ if (trySyntaxParseInnerFunction(pn, fun, toStringStart, inHandling, yieldHandling, kind,
generatorKind, asyncKind, tryAnnexB, directives,
&newDirectives))
{
@@ -3181,7 +3392,7 @@ Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, Node pn, InHandl
template <>
bool
Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun,
- uint32_t preludeStart,
+ uint32_t toStringStart,
InHandling inHandling,
YieldHandling yieldHandling,
FunctionSyntaxKind kind,
@@ -3215,13 +3426,13 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
// Make a FunctionBox before we enter the syntax parser, because |pn|
// still expects a FunctionBox to be attached to it during BCE, and
// the syntax parser cannot attach one to it.
- FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives,
+ FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, inheritedDirectives,
generatorKind, asyncKind, tryAnnexB);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(pc, kind);
- if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, preludeStart,
+ if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, toStringStart,
inHandling, yieldHandling, kind,
inheritedDirectives, newDirectives))
{
@@ -3249,14 +3460,14 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
} while (false);
// We failed to do a syntax parse above, so do the full parse.
- return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind,
+ return innerFunction(pn, pc, fun, toStringStart, inHandling, yieldHandling, kind,
generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
}
template <>
bool
Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction fun,
- uint32_t preludeStart,
+ uint32_t toStringStart,
InHandling inHandling,
YieldHandling yieldHandling,
FunctionSyntaxKind kind,
@@ -3267,14 +3478,14 @@ Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction
Directives* newDirectives)
{
// This is already a syntax parser, so just parse the inner function.
- return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind,
+ return innerFunction(pn, pc, fun, toStringStart, inHandling, yieldHandling, kind,
generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox,
- uint32_t preludeStart,
+ uint32_t toStringStart,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, Directives inheritedDirectives,
Directives* newDirectives)
@@ -3298,7 +3509,7 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox*
template <typename ParseHandler>
bool
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
- uint32_t preludeStart,
+ uint32_t toStringStart,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
@@ -3310,13 +3521,13 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti
// parser. In that case, outerpc is a ParseContext from the full parser
// instead of the current top of the stack of the syntax parser.
- FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives,
+ FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, inheritedDirectives,
generatorKind, asyncKind, tryAnnexB);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(outerpc, kind);
- return innerFunction(pn, outerpc, funbox, preludeStart, inHandling, yieldHandling, kind,
+ return innerFunction(pn, outerpc, funbox, toStringStart, inHandling, yieldHandling, kind,
inheritedDirectives, newDirectives);
}
@@ -3324,7 +3535,7 @@ template <typename ParseHandler>
bool
Parser<ParseHandler>::appendToCallSiteObj(Node callSiteObj)
{
- Node cookedNode = noSubstitutionTemplate();
+ Node cookedNode = noSubstitutionTaggedTemplate();
if (!cookedNode)
return false;
@@ -3352,7 +3563,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
return null();
Directives directives(strict);
- FunctionBox* funbox = newFunctionBox(pn, fun, /* preludeStart = */ 0, directives,
+ FunctionBox* funbox = newFunctionBox(pn, fun, /* toStringStart = */ 0, directives,
generatorKind, asyncKind, /* tryAnnexB = */ false);
if (!funbox)
return null();
@@ -3402,7 +3613,8 @@ bool
Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
YieldHandling yieldHandling,
Node pn, FunctionSyntaxKind kind,
- Maybe<uint32_t> parameterListEnd /* = Nothing() */)
+ Maybe<uint32_t> parameterListEnd /* = Nothing() */,
+ bool isStandaloneFunction /* = false */)
{
// Given a properly initialized parse context, try to parse an actual
// function without concern for conversion to strict mode, use of lazy
@@ -3411,9 +3623,14 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
FunctionBox* funbox = pc->functionBox();
RootedFunction fun(context, funbox->function());
- AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, funbox->isAsync());
- if (!functionArguments(yieldHandling, kind, pn))
- return false;
+ // See below for an explanation why arrow function parameters and arrow
+ // function bodies are parsed with different yield/await settings.
+ {
+ bool asyncOrArrowInAsync = funbox->isAsync() || (kind == Arrow && awaitIsKeyword());
+ AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, asyncOrArrowInAsync);
+ if (!functionArguments(yieldHandling, kind, pn))
+ return false;
+ }
Maybe<ParseContext::VarScope> varScope;
if (funbox->hasParameterExprs) {
@@ -3446,6 +3663,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return false;
+ uint32_t openedPos = 0;
if (tt != TOK_LC) {
if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method ||
kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure ||
@@ -3466,9 +3684,9 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
tokenStream.ungetToken();
bodyType = ExpressionBody;
-#if JS_HAS_EXPR_CLOSURES
- fun->setIsExprBody();
-#endif
+ funbox->setIsExprBody();
+ } else {
+ openedPos = pos().begin;
}
// Arrow function parameters inherit yieldHandling from the enclosing
@@ -3476,41 +3694,59 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
// |yield| in the parameters is either a name or keyword, depending on
// whether the arrow function is enclosed in a generator function or not.
// Whereas the |yield| in the function body is always parsed as a name.
+ // The same goes when parsing |await| in arrow functions.
YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind(), pc->asyncKind());
- Node body = functionBody(inHandling, bodyYieldHandling, kind, bodyType);
- if (!body)
- return false;
+ Node body;
+ {
+ AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, funbox->isAsync());
+ body = functionBody(inHandling, bodyYieldHandling, kind, bodyType);
+ if (!body)
+ return false;
+ }
- if ((kind != Method && !IsConstructorKind(kind)) && fun->explicitName()) {
+ if ((kind == Statement || kind == Expression) && fun->explicitName()) {
RootedPropertyName propertyName(context, fun->explicitName()->asPropertyName());
- if (!checkStrictBinding(propertyName, handler.getPosition(pn)))
+ YieldHandling nameYieldHandling;
+ if (kind == Expression) {
+ // Named lambda has binding inside it.
+ nameYieldHandling = bodyYieldHandling;
+ } else {
+ // Otherwise YieldHandling cannot be checked at this point
+ // because of different context.
+ // It should already be checked before this point.
+ nameYieldHandling = YieldIsName;
+ }
+
+ // We already use the correct await-handling at this point, therefore
+ // we don't need call AutoAwaitIsKeyword here.
+
+ if (!checkBindingIdentifier(propertyName, handler.getPosition(pn).begin,
+ nameYieldHandling))
+ {
return false;
+ }
}
if (bodyType == StatementListBody) {
- bool matched;
- if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand))
- return false;
- if (!matched) {
- error(JSMSG_CURLY_AFTER_BODY);
- return false;
- }
- funbox->bufEnd = pos().end;
+ MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
+ reportMissingClosing(JSMSG_CURLY_AFTER_BODY,
+ JSMSG_CURLY_OPENED, openedPos));
+ funbox->setEnd(pos().end);
} else {
#if !JS_HAS_EXPR_CLOSURES
MOZ_ASSERT(kind == Arrow);
#endif
if (tokenStream.hadError())
return false;
- funbox->bufEnd = pos().end;
- if (kind == Statement && !MatchOrInsertSemicolonAfterExpression(tokenStream))
+ funbox->setEnd(pos().end);
+ if (kind == Statement && !matchOrInsertSemicolonAfterExpression())
return false;
}
if (IsMethodDefinitionKind(kind) && pc->superScopeNeedsHomeObject())
funbox->setNeedsHomeObject();
- if (!finishFunction())
+ if (!finishFunction(isStandaloneFunction))
return false;
handler.setEndPosition(body, pos().begin);
@@ -3522,26 +3758,11 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling,
+Parser<ParseHandler>::functionStmt(uint32_t toStringStart, YieldHandling yieldHandling,
DefaultHandling defaultHandling, FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
- // Annex B.3.4 says we can parse function declarations unbraced under if
- // or else as if it were braced. That is, |if (x) function f() {}| is
- // parsed as |if (x) { function f() {} }|.
- Maybe<ParseContext::Statement> synthesizedStmtForAnnexB;
- Maybe<ParseContext::Scope> synthesizedScopeForAnnexB;
- if (!pc->sc()->strict()) {
- ParseContext::Statement* stmt = pc->innermostStatement();
- if (stmt && stmt->kind() == StatementKind::If) {
- synthesizedStmtForAnnexB.emplace(pc, StatementKind::Block);
- synthesizedScopeForAnnexB.emplace(this);
- if (!synthesizedScopeForAnnexB->init(pc))
- return null();
- }
- }
-
// In sloppy mode, Annex B.3.2 allows labelled function declarations.
// Otherwise it's a parse error.
ParseContext::Statement* declaredInStmt = pc->innermostStatement();
@@ -3577,7 +3798,7 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan
}
RootedPropertyName name(context);
- if (tt == TOK_NAME || tt == TOK_YIELD) {
+ if (TokenKindIsPossibleIdentifier(tt)) {
name = bindingIdentifier(yieldHandling);
if (!name)
return null();
@@ -3602,19 +3823,18 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan
// early error, do so. This 'var' binding would be assigned
// the function object when its declaration is reached, not at
// the start of the block.
- if (!tryDeclareVarForAnnexBLexicalFunction(name, &tryAnnexB))
+ if (!tryDeclareVarForAnnexBLexicalFunction(name, pos().begin, &tryAnnexB))
return null();
}
if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos()))
return null();
} else {
- if (!noteDeclaredName(name, DeclarationKind::BodyLevelFunction, pos()))
+ DeclarationKind kind = pc->atModuleLevel()
+ ? DeclarationKind::ModuleBodyLevelFunction
+ : DeclarationKind::BodyLevelFunction;
+ if (!noteDeclaredName(name, kind, pos()))
return null();
-
- // Body-level functions in modules are always closed over.
- if (pc->atModuleLevel())
- pc->varScope().lookupDeclaredName(name)->value()->setClosedOver();
}
Node pn = handler.newFunctionStatement();
@@ -3622,30 +3842,18 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan
return null();
YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
- Node fun = functionDefinition(preludeStart, pn, InAllowed, newYieldHandling,
+ return functionDefinition(toStringStart, pn, InAllowed, newYieldHandling,
name, Statement, generatorKind, asyncKind, tryAnnexB);
- if (!fun)
- return null();
-
- if (synthesizedStmtForAnnexB) {
- Node synthesizedStmtList = handler.newStatementList(handler.getPosition(fun));
- if (!synthesizedStmtList)
- return null();
- handler.addStatementToList(synthesizedStmtList, fun);
- return finishLexicalScope(*synthesizedScopeForAnnexB, synthesizedStmtList);
- }
-
- return fun;
}
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invoked,
+Parser<ParseHandler>::functionExpr(uint32_t toStringStart, InvokedPrediction invoked,
FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
- AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
+ AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, asyncKind == AsyncFunction);
GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
TokenKind tt;
if (!tokenStream.getToken(&tt))
@@ -3664,7 +3872,7 @@ Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invo
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
RootedPropertyName name(context);
- if (tt == TOK_NAME || tt == TOK_YIELD) {
+ if (TokenKindIsPossibleIdentifier(tt)) {
name = bindingIdentifier(yieldHandling);
if (!name)
return null();
@@ -3679,7 +3887,7 @@ Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invo
if (invoked)
pn = handler.setLikelyIIFE(pn);
- return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, name, Expression,
+ return functionDefinition(toStringStart, pn, InAllowed, yieldHandling, name, Expression,
generatorKind, asyncKind);
}
@@ -3701,18 +3909,6 @@ IsEscapeFreeStringLiteral(const TokenPos& pos, JSAtom* str)
return pos.begin + str->length() + 2 == pos.end;
}
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkUnescapedName()
-{
- const Token& token = tokenStream.currentToken();
- if (!token.nameContainsEscape())
- return true;
-
- errorAt(token.pos.begin, JSMSG_ESCAPED_KEYWORD);
- return false;
-}
-
template <>
bool
Parser<SyntaxParseHandler>::asmJS(Node list)
@@ -3931,7 +4127,7 @@ Parser<ParseHandler>::matchLabel(YieldHandling yieldHandling, MutableHandle<Prop
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
return false;
- if (tt == TOK_NAME || tt == TOK_YIELD) {
+ if (TokenKindIsPossibleIdentifier(tt)) {
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
label.set(labelIdentifier(yieldHandling));
@@ -3954,8 +4150,17 @@ Parser<ParseHandler>::PossibleError::error(ErrorKind kind)
{
if (kind == ErrorKind::Expression)
return exprError_;
- MOZ_ASSERT(kind == ErrorKind::Destructuring);
- return destructuringError_;
+ if (kind == ErrorKind::Destructuring)
+ return destructuringError_;
+ MOZ_ASSERT(kind == ErrorKind::DestructuringWarning);
+ return destructuringWarning_;
+}
+
+template <typename ParseHandler>
+bool
+Parser<ParseHandler>::PossibleError::hasPendingDestructuringError()
+{
+ return hasError(ErrorKind::Destructuring);
}
template <typename ParseHandler>
@@ -3999,6 +4204,14 @@ Parser<ParseHandler>::PossibleError::setPendingDestructuringErrorAt(const TokenP
template <typename ParseHandler>
void
+Parser<ParseHandler>::PossibleError::setPendingDestructuringWarningAt(const TokenPos& pos,
+ unsigned errorNumber)
+{
+ setPending(ErrorKind::DestructuringWarning, pos, errorNumber);
+}
+
+template <typename ParseHandler>
+void
Parser<ParseHandler>::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos,
unsigned errorNumber)
{
@@ -4019,23 +4232,36 @@ Parser<ParseHandler>::PossibleError::checkForError(ErrorKind kind)
template <typename ParseHandler>
bool
-Parser<ParseHandler>::PossibleError::checkForDestructuringError()
+Parser<ParseHandler>::PossibleError::checkForWarning(ErrorKind kind)
+{
+ if (!hasError(kind))
+ return true;
+
+ Error& err = error(kind);
+ return parser_.extraWarningAt(err.offset_, err.errorNumber_);
+}
+
+template <typename ParseHandler>
+bool
+Parser<ParseHandler>::PossibleError::checkForDestructuringErrorOrWarning()
{
// Clear pending expression error, because we're definitely not in an
// expression context.
setResolved(ErrorKind::Expression);
- // Report any pending destructuring error.
- return checkForError(ErrorKind::Destructuring);
+ // Report any pending destructuring error or warning.
+ return checkForError(ErrorKind::Destructuring) &&
+ checkForWarning(ErrorKind::DestructuringWarning);
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::PossibleError::checkForExpressionError()
{
- // Clear pending destructuring error, because we're definitely not in a
- // destructuring context.
+ // Clear pending destructuring error or warning, because we're definitely
+ // not in a destructuring context.
setResolved(ErrorKind::Destructuring);
+ setResolved(ErrorKind::DestructuringWarning);
// Report any pending expression error.
return checkForError(ErrorKind::Expression);
@@ -4067,191 +4293,272 @@ Parser<ParseHandler>::PossibleError::transferErrorsTo(PossibleError* other)
transferErrorTo(ErrorKind::Expression, other);
}
-template <>
-bool
-Parser<FullParseHandler>::checkDestructuringName(ParseNode* expr, Maybe<DeclarationKind> maybeDecl)
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::bindingInitializer(Node lhs, DeclarationKind kind,
+ YieldHandling yieldHandling)
{
- MOZ_ASSERT(!handler.isUnparenthesizedDestructuringPattern(expr));
-
- // Parentheses are forbidden around destructuring *patterns* (but allowed
- // around names). Use our nicer error message for parenthesized, nested
- // patterns.
- if (handler.isParenthesizedDestructuringPattern(expr)) {
- errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_PARENS);
- return false;
- }
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN));
- // This expression might be in a variable-binding pattern where only plain,
- // unparenthesized names are permitted.
- if (maybeDecl) {
- // Destructuring patterns in declarations must only contain
- // unparenthesized names.
- if (!handler.isUnparenthesizedName(expr)) {
- errorAt(expr->pn_pos.begin, JSMSG_NO_VARIABLE_NAME);
- return false;
- }
+ if (kind == DeclarationKind::FormalParameter)
+ pc->functionBox()->hasParameterExprs = true;
- RootedPropertyName name(context, expr->name());
- return noteDeclaredName(name, *maybeDecl, expr->pn_pos);
- }
+ Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
+ if (!rhs)
+ return null();
- // Otherwise this is an expression in destructuring outside a declaration.
- if (handler.isNameAnyParentheses(expr)) {
- if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(expr, context)) {
- if (!strictModeErrorAt(expr->pn_pos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
- return false;
- }
+ handler.checkAndSetIsDirectRHSAnonFunction(rhs);
- return true;
- }
+ Node assign = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP);
+ if (!assign)
+ return null();
- if (handler.isPropertyAccess(expr))
- return true;
+ if (foldConstants && !FoldConstants(context, &assign, this))
+ return null();
- errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_TARGET);
- return false;
+ return assign;
}
-template <>
-bool
-Parser<FullParseHandler>::checkDestructuringPattern(ParseNode* pattern,
- Maybe<DeclarationKind> maybeDecl,
- PossibleError* possibleError /* = nullptr */);
-
-template <>
-bool
-Parser<FullParseHandler>::checkDestructuringObject(ParseNode* objectPattern,
- Maybe<DeclarationKind> maybeDecl)
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling)
{
- MOZ_ASSERT(objectPattern->isKind(PNK_OBJECT));
+ RootedPropertyName name(context, bindingIdentifier(yieldHandling));
+ if (!name)
+ return null();
- for (ParseNode* member = objectPattern->pn_head; member; member = member->pn_next) {
- ParseNode* target;
- if (member->isKind(PNK_MUTATEPROTO)) {
- target = member->pn_kid;
- } else {
- MOZ_ASSERT(member->isKind(PNK_COLON) || member->isKind(PNK_SHORTHAND));
- MOZ_ASSERT_IF(member->isKind(PNK_SHORTHAND),
- member->pn_left->isKind(PNK_OBJECT_PROPERTY_NAME) &&
- member->pn_right->isKind(PNK_NAME) &&
- member->pn_left->pn_atom == member->pn_right->pn_atom);
+ Node binding = newName(name);
+ if (!binding || !noteDeclaredName(name, kind, pos()))
+ return null();
- target = member->pn_right;
- }
- if (handler.isUnparenthesizedAssignment(target))
- target = target->pn_left;
+ return binding;
+}
- if (handler.isUnparenthesizedDestructuringPattern(target)) {
- if (!checkDestructuringPattern(target, maybeDecl))
- return false;
- } else {
- if (!checkDestructuringName(target, maybeDecl))
- return false;
- }
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::bindingIdentifierOrPattern(DeclarationKind kind, YieldHandling yieldHandling,
+ TokenKind tt)
+{
+ if (tt == TOK_LB)
+ return arrayBindingPattern(kind, yieldHandling);
+
+ if (tt == TOK_LC)
+ return objectBindingPattern(kind, yieldHandling);
+
+ if (!TokenKindIsPossibleIdentifierName(tt)) {
+ error(JSMSG_NO_VARIABLE_NAME);
+ return null();
}
- return true;
+ return bindingIdentifier(kind, yieldHandling);
}
-template <>
-bool
-Parser<FullParseHandler>::checkDestructuringArray(ParseNode* arrayPattern,
- Maybe<DeclarationKind> maybeDecl)
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling)
{
- MOZ_ASSERT(arrayPattern->isKind(PNK_ARRAY));
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
- for (ParseNode* element = arrayPattern->pn_head; element; element = element->pn_next) {
- if (element->isKind(PNK_ELISION))
- continue;
+ JS_CHECK_RECURSION(context, return null());
- ParseNode* target;
- if (element->isKind(PNK_SPREAD)) {
- if (element->pn_next) {
- errorAt(element->pn_next->pn_pos.begin, JSMSG_PARAMETER_AFTER_REST);
- return false;
- }
- target = element->pn_kid;
- } else if (handler.isUnparenthesizedAssignment(element)) {
- target = element->pn_left;
+ uint32_t begin = pos().begin;
+ Node literal = handler.newObjectLiteral(begin);
+ if (!literal)
+ return null();
+
+ Maybe<DeclarationKind> declKind = Some(kind);
+ RootedAtom propAtom(context);
+ for (;;) {
+ TokenKind tt;
+ if (!tokenStream.peekToken(&tt))
+ return null();
+ if (tt == TOK_RC)
+ break;
+
+ if (tt == TOK_TRIPLEDOT) {
+ // rest-binding property
+ tokenStream.consumeKnownToken(TOK_TRIPLEDOT);
+ uint32_t begin = pos().begin;
+
+ TokenKind tt;
+ if (!tokenStream.getToken(&tt))
+ return null();
+
+ Node inner = bindingIdentifierOrPattern(kind, yieldHandling, tt);
+ if (!inner)
+ return null();
+
+ if (!handler.addSpreadProperty(literal, begin, inner))
+ return null();
} else {
- target = element;
+ TokenPos namePos = tokenStream.nextToken().pos;
+
+ PropertyType propType;
+ Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
+ if (!propName)
+ return null();
+ if (propType == PropertyType::Normal) {
+ // Handle e.g., |var {p: x} = o| and |var {p: x=0} = o|.
+
+ if (!tokenStream.getToken(&tt, TokenStream::Operand))
+ return null();
+
+ Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt);
+ if (!binding)
+ return null();
+
+ bool hasInitializer;
+ if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN))
+ return null();
+
+ Node bindingExpr = hasInitializer
+ ? bindingInitializer(binding, kind, yieldHandling)
+ : binding;
+ if (!bindingExpr)
+ return null();
+
+ if (!handler.addPropertyDefinition(literal, propName, bindingExpr))
+ return null();
+ } else if (propType == PropertyType::Shorthand) {
+ // Handle e.g., |var {x, y} = o| as destructuring shorthand
+ // for |var {x: x, y: y} = o|.
+ MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
+
+ Node binding = bindingIdentifier(kind, yieldHandling);
+ if (!binding)
+ return null();
+
+ if (!handler.addShorthand(literal, propName, binding))
+ return null();
+ } else if (propType == PropertyType::CoverInitializedName) {
+ // Handle e.g., |var {x=1, y=2} = o| as destructuring
+ // shorthand with default values.
+ MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
+
+ Node binding = bindingIdentifier(kind, yieldHandling);
+ if (!binding)
+ return null();
+
+ tokenStream.consumeKnownToken(TOK_ASSIGN);
+
+ Node bindingExpr = bindingInitializer(binding, kind, yieldHandling);
+ if (!bindingExpr)
+ return null();
+
+ if (!handler.addPropertyDefinition(literal, propName, bindingExpr))
+ return null();
+ } else {
+ errorAt(namePos.begin, JSMSG_NO_VARIABLE_NAME);
+ return null();
+
+ }
}
- if (handler.isUnparenthesizedDestructuringPattern(target)) {
- if (!checkDestructuringPattern(target, maybeDecl))
- return false;
- } else {
- if (!checkDestructuringName(target, maybeDecl))
- return false;
+ bool matched;
+ if (!tokenStream.matchToken(&matched, TOK_COMMA))
+ return null();
+ if (!matched)
+ break;
+ if (tt == TOK_TRIPLEDOT) {
+ error(JSMSG_REST_WITH_COMMA);
+ return null();
}
}
- return true;
+ MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None,
+ reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
+ JSMSG_CURLY_OPENED, begin));
+
+ handler.setEndPosition(literal, pos().end);
+ return literal;
}
-/*
- * Destructuring patterns can appear in two kinds of contexts:
- *
- * - assignment-like: assignment expressions and |for| loop heads. In
- * these cases, the patterns' property value positions can be
- * arbitrary lvalue expressions; the destructuring is just a fancy
- * assignment.
- *
- * - binding-like: |var| and |let| declarations, functions' formal
- * parameter lists, |catch| clauses, and comprehension tails. In
- * these cases, the patterns' property value positions must be
- * simple names; the destructuring defines them as new variables.
- *
- * In both cases, other code parses the pattern as an arbitrary
- * primaryExpr, and then, here in checkDestructuringPattern, verify
- * that the tree is a valid AssignmentPattern or BindingPattern.
- *
- * In assignment-like contexts, we parse the pattern with
- * pc->inDestructuringDecl clear, so the lvalue expressions in the
- * pattern are parsed normally. primaryExpr links variable references
- * into the appropriate use chains; creates placeholder definitions;
- * and so on. checkDestructuringPattern won't bind any new names and
- * we specialize lvalues as appropriate.
- *
- * In declaration-like contexts, the normal variable reference
- * processing would just be an obstruction, because we're going to
- * define the names that appear in the property value positions as new
- * variables anyway. In this case, we parse the pattern with
- * pc->inDestructuringDecl set, which directs primaryExpr to leave
- * whatever name nodes it creates unconnected. Then, here in
- * checkDestructuringPattern, we require the pattern's property value
- * positions to be simple names, and define them as appropriate to the
- * context.
- */
-template <>
-bool
-Parser<FullParseHandler>::checkDestructuringPattern(ParseNode* pattern,
- Maybe<DeclarationKind> maybeDecl,
- PossibleError* possibleError /* = nullptr */)
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling)
{
- if (pattern->isKind(PNK_ARRAYCOMP)) {
- errorAt(pattern->pn_pos.begin, JSMSG_ARRAY_COMP_LEFTSIDE);
- return false;
- }
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LB));
- bool isDestructuring = pattern->isKind(PNK_ARRAY)
- ? checkDestructuringArray(pattern, maybeDecl)
- : checkDestructuringObject(pattern, maybeDecl);
+ JS_CHECK_RECURSION(context, return null());
- // Report any pending destructuring error.
- if (isDestructuring && possibleError && !possibleError->checkForDestructuringError())
- return false;
+ uint32_t begin = pos().begin;
+ Node literal = handler.newArrayLiteral(begin);
+ if (!literal)
+ return null();
- return isDestructuring;
-}
+ uint32_t index = 0;
+ TokenStream::Modifier modifier = TokenStream::Operand;
+ for (; ; index++) {
+ if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
+ error(JSMSG_ARRAY_INIT_TOO_BIG);
+ return null();
+ }
+
+ TokenKind tt;
+ if (!tokenStream.getToken(&tt, TokenStream::Operand))
+ return null();
+
+ if (tt == TOK_RB) {
+ tokenStream.ungetToken();
+ break;
+ }
+
+ if (tt == TOK_COMMA) {
+ if (!handler.addElision(literal, pos()))
+ return null();
+ } else if (tt == TOK_TRIPLEDOT) {
+ uint32_t begin = pos().begin;
+
+ TokenKind tt;
+ if (!tokenStream.getToken(&tt, TokenStream::Operand))
+ return null();
+
+ Node inner = bindingIdentifierOrPattern(kind, yieldHandling, tt);
+ if (!inner)
+ return null();
+
+ if (!handler.addSpreadElement(literal, begin, inner))
+ return null();
+ } else {
+ Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt);
+ if (!binding)
+ return null();
+
+ bool hasInitializer;
+ if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN))
+ return null();
+
+ Node element = hasInitializer
+ ? bindingInitializer(binding, kind, yieldHandling)
+ : binding;
+ if (!element)
+ return null();
+
+ handler.addArrayElement(literal, element);
+ }
+
+ if (tt != TOK_COMMA) {
+ // If we didn't already match TOK_COMMA in above case.
+ bool matched;
+ if (!tokenStream.matchToken(&matched, TOK_COMMA))
+ return null();
+ if (!matched) {
+ modifier = TokenStream::None;
+ break;
+ }
+ if (tt == TOK_TRIPLEDOT) {
+ error(JSMSG_REST_WITH_COMMA);
+ return null();
+ }
+ }
+ }
+
+ MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RB, modifier,
+ reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
+ JSMSG_BRACKET_OPENED, begin));
-template <>
-bool
-Parser<SyntaxParseHandler>::checkDestructuringPattern(Node pattern,
- Maybe<DeclarationKind> maybeDecl,
- PossibleError* possibleError /* = nullptr */)
-{
- return abortIfSyntaxParser();
+ handler.setEndPosition(literal, pos().end);
+ return literal;
}
template <typename ParseHandler>
@@ -4262,18 +4569,9 @@ Parser<ParseHandler>::destructuringDeclaration(DeclarationKind kind, YieldHandli
MOZ_ASSERT(tokenStream.isCurrentTokenType(tt));
MOZ_ASSERT(tt == TOK_LB || tt == TOK_LC);
- PossibleError possibleError(*this);
- Node pattern;
- {
- pc->inDestructuringDecl = Some(kind);
- pattern = primaryExpr(yieldHandling, TripledotProhibited, tt, &possibleError);
- pc->inDestructuringDecl = Nothing();
- }
-
- if (!pattern || !checkDestructuringPattern(pattern, Some(kind), &possibleError))
- return null();
-
- return pattern;
+ return tt == TOK_LB
+ ? arrayBindingPattern(kind, yieldHandling)
+ : objectBindingPattern(kind, yieldHandling);
}
template <typename ParseHandler>
@@ -4303,6 +4601,7 @@ typename ParseHandler::Node
Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned errorNumber)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
+ uint32_t openedPos = pos().begin;
ParseContext::Statement stmt(pc, StatementKind::Block);
ParseContext::Scope scope(this);
@@ -4313,7 +4612,9 @@ Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned error
if (!list)
return null();
- MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, errorNumber);
+ MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
+ reportMissingClosing(errorNumber, JSMSG_CURLY_OPENED,
+ openedPos));
return finishLexicalScope(scope, list);
}
@@ -4384,6 +4685,12 @@ Parser<ParseHandler>::declarationPattern(Node decl, DeclarationKind declKind, To
// binary operator (examined with modifier None) terminated |init|.
// For all other declarations, through ASI's infinite majesty, a next
// token on a new line would begin an expression.
+ // Similar to the case in initializerInNameDeclaration(), we need to
+ // peek at the next token when assignExpr() is a lazily parsed arrow
+ // function.
+ TokenKind ignored;
+ if (!tokenStream.peekToken(&ignored))
+ return null();
tokenStream.addModifierException(TokenStream::OperandIsNone);
}
@@ -4484,7 +4791,8 @@ Parser<ParseHandler>::declarationName(Node decl, DeclarationKind declKind, Token
ParseNodeKind* forHeadKind, Node* forInOrOfExpression)
{
// Anything other than TOK_YIELD or TOK_NAME is an error.
- if (tt != TOK_NAME && tt != TOK_YIELD) {
+ // Anything other than possible identifier is an error.
+ if (!TokenKindIsPossibleIdentifier(tt)) {
error(JSMSG_NO_VARIABLE_NAME);
return null();
}
@@ -4625,8 +4933,10 @@ Parser<ParseHandler>::declarationList(YieldHandling yieldHandling,
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, bool isConst)
+Parser<ParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind)
{
+ MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let);
+
/*
* Parse body-level lets without a new block object. ES6 specs
* that an execution environment's initial lexical environment
@@ -4638,8 +4948,9 @@ Parser<ParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, bool isCon
*
* See 8.1.1.1.6 and the note in 13.2.1.
*/
- Node decl = declarationList(yieldHandling, isConst ? PNK_CONST : PNK_LET);
- if (!decl || !MatchOrInsertSemicolonAfterExpression(tokenStream))
+ Node decl = declarationList(yieldHandling,
+ kind == DeclarationKind::Const ? PNK_CONST : PNK_LET);
+ if (!decl || !matchOrInsertSemicolonAfterExpression())
return null();
return decl;
@@ -4650,41 +4961,34 @@ bool
Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet)
{
if (tt == TOK_LC) {
- TokenStream::Modifier modifier = TokenStream::KeywordIsName;
while (true) {
// Handle the forms |import {} from 'a'| and
// |import { ..., } from 'a'| (where ... is non empty), by
// escaping the loop early if the next token is }.
- if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName))
+ if (!tokenStream.getToken(&tt))
return false;
if (tt == TOK_RC)
break;
- // If the next token is a keyword, the previous call to
- // peekToken matched it as a TOK_NAME, and put it in the
- // lookahead buffer, so this call will match keywords as well.
- MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_IMPORT_NAME);
+ if (!TokenKindIsPossibleIdentifierName(tt)) {
+ error(JSMSG_NO_IMPORT_NAME);
+ return false;
+ }
+
Rooted<PropertyName*> importName(context, tokenStream.currentName());
TokenPos importNamePos = pos();
- TokenKind maybeAs;
- if (!tokenStream.peekToken(&maybeAs))
+ bool matched;
+ if (!tokenStream.matchToken(&matched, TOK_AS))
return null();
- if (maybeAs == TOK_NAME &&
- tokenStream.nextName() == context->names().as)
- {
- tokenStream.consumeKnownToken(TOK_NAME);
-
- if (!checkUnescapedName())
- return false;
-
+ if (matched) {
TokenKind afterAs;
if (!tokenStream.getToken(&afterAs))
return false;
- if (afterAs != TOK_NAME && afterAs != TOK_YIELD) {
+ if (!TokenKindIsPossibleIdentifierName(afterAs)) {
error(JSMSG_NO_BINDING_NAME);
return false;
}
@@ -4694,10 +4998,7 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor
// by the keyword 'as'.
// See the ImportSpecifier production in ES6 section 15.2.2.
if (IsKeyword(importName)) {
- JSAutoByteString bytes;
- if (!AtomToPrintableString(context, importName, &bytes))
- return false;
- error(JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr());
+ error(JSMSG_AS_AFTER_RESERVED_WORD, ReservedWordToCharZ(importName));
return false;
}
}
@@ -4722,31 +5023,24 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor
handler.addList(importSpecSet, importSpec);
- bool matched;
- if (!tokenStream.matchToken(&matched, TOK_COMMA))
+ TokenKind next;
+ if (!tokenStream.getToken(&next))
return false;
- if (!matched) {
- modifier = TokenStream::None;
+ if (next == TOK_RC)
break;
+
+ if (next != TOK_COMMA) {
+ error(JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
+ return false;
}
}
-
- MUST_MATCH_TOKEN_MOD(TOK_RC, modifier, JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
} else {
MOZ_ASSERT(tt == TOK_MUL);
- if (!tokenStream.getToken(&tt))
- return false;
- if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) {
- error(JSMSG_AS_AFTER_IMPORT_STAR);
- return false;
- }
-
- if (!checkUnescapedName())
- return false;
+ MUST_MATCH_TOKEN(TOK_AS, JSMSG_AS_AFTER_IMPORT_STAR);
- MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_BINDING_NAME);
+ MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_BINDING_NAME);
Node importName = newName(context->names().star);
if (!importName)
@@ -4780,14 +5074,6 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor
}
template<>
-bool
-Parser<SyntaxParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet)
-{
- MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
- return false;
-}
-
-template<>
ParseNode*
Parser<FullParseHandler>::importDeclaration()
{
@@ -4807,8 +5093,15 @@ Parser<FullParseHandler>::importDeclaration()
if (!importSpecSet)
return null();
- if (tt == TOK_NAME || tt == TOK_LC || tt == TOK_MUL) {
- if (tt == TOK_NAME) {
+ if (tt == TOK_STRING) {
+ // Handle the form |import 'a'| by leaving the list empty. This is
+ // equivalent to |import {} from 'a'|.
+ importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin;
+ } else {
+ if (tt == TOK_LC || tt == TOK_MUL) {
+ if (!namedImportsOrNamespaceImport(tt, importSpecSet))
+ return null();
+ } else if (TokenKindIsPossibleIdentifierName(tt)) {
// Handle the form |import a from 'b'|, by adding a single import
// specifier to the list, with 'default' as the import name and
// 'a' as the binding name. This is equivalent to
@@ -4851,36 +5144,20 @@ Parser<FullParseHandler>::importDeclaration()
return null();
}
} else {
- if (!namedImportsOrNamespaceImport(tt, importSpecSet))
- return null();
- }
-
- if (!tokenStream.getToken(&tt))
- return null();
-
- if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) {
- error(JSMSG_FROM_AFTER_IMPORT_CLAUSE);
+ error(JSMSG_DECLARATION_AFTER_IMPORT);
return null();
}
- if (!checkUnescapedName())
- return null();
+ MUST_MATCH_TOKEN(TOK_FROM, JSMSG_FROM_AFTER_IMPORT_CLAUSE);
MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
- } else if (tt == TOK_STRING) {
- // Handle the form |import 'a'| by leaving the list empty. This is
- // equivalent to |import {} from 'a'|.
- importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin;
- } else {
- error(JSMSG_DECLARATION_AFTER_IMPORT);
- return null();
}
Node moduleSpec = stringLiteral();
if (!moduleSpec)
return null();
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterNonExpression())
return null();
ParseNode* node =
@@ -4947,284 +5224,539 @@ Parser<SyntaxParseHandler>::checkExportedNamesForDeclaration(Node node)
}
template<>
-ParseNode*
-Parser<FullParseHandler>::exportDeclaration()
+bool
+Parser<FullParseHandler>::checkExportedNameForClause(ParseNode* node)
{
- MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT);
+ return checkExportedName(node->pn_atom);
+}
- if (!pc->atModuleLevel()) {
- error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL);
+template<>
+bool
+Parser<SyntaxParseHandler>::checkExportedNameForClause(Node node)
+{
+ MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
+ return false;
+}
+
+template<>
+bool
+Parser<FullParseHandler>::checkExportedNameForFunction(ParseNode* node)
+{
+ return checkExportedName(node->pn_funbox->function()->explicitName());
+}
+
+template<>
+bool
+Parser<SyntaxParseHandler>::checkExportedNameForFunction(Node node)
+{
+ MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
+ return false;
+}
+
+template<>
+bool
+Parser<FullParseHandler>::checkExportedNameForClass(ParseNode* node)
+{
+ const ClassNode& cls = node->as<ClassNode>();
+ MOZ_ASSERT(cls.names());
+ return checkExportedName(cls.names()->innerBinding()->pn_atom);
+}
+
+template<>
+bool
+Parser<SyntaxParseHandler>::checkExportedNameForClass(Node node)
+{
+ MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
+ return false;
+}
+
+template<>
+bool
+Parser<FullParseHandler>::processExport(ParseNode* node)
+{
+ return pc->sc()->asModuleContext()->builder.processExport(node);
+}
+
+template<>
+bool
+Parser<SyntaxParseHandler>::processExport(Node node)
+{
+ MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
+ return false;
+}
+
+template<>
+bool
+Parser<FullParseHandler>::processExportFrom(ParseNode* node)
+{
+ return pc->sc()->asModuleContext()->builder.processExportFrom(node);
+}
+
+template<>
+bool
+Parser<SyntaxParseHandler>::processExportFrom(Node node)
+{
+ MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
+ return false;
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportFrom(uint32_t begin, Node specList)
+{
+ if (!abortIfSyntaxParser())
return null();
- }
- uint32_t begin = pos().begin;
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FROM));
- Node kid;
- TokenKind tt;
- if (!tokenStream.getToken(&tt))
+ if (!abortIfSyntaxParser())
return null();
- switch (tt) {
- case TOK_LC: {
- kid = handler.newList(PNK_EXPORT_SPEC_LIST);
- if (!kid)
- return null();
- while (true) {
- // Handle the forms |export {}| and |export { ..., }| (where ...
- // is non empty), by escaping the loop early if the next token
- // is }.
- if (!tokenStream.peekToken(&tt))
- return null();
- if (tt == TOK_RC)
- break;
+ MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
- MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_BINDING_NAME);
- Node bindingName = newName(tokenStream.currentName());
- if (!bindingName)
- return null();
+ Node moduleSpec = stringLiteral();
+ if (!moduleSpec)
+ return null();
- bool foundAs;
- if (!tokenStream.matchContextualKeyword(&foundAs, context->names().as))
- return null();
- if (foundAs)
- MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_EXPORT_NAME);
+ if (!matchOrInsertSemicolonAfterNonExpression())
+ return null();
- Node exportName = newName(tokenStream.currentName());
- if (!exportName)
- return null();
+ Node node = handler.newExportFromDeclaration(begin, specList, moduleSpec);
+ if (!node)
+ return null();
- if (!checkExportedName(exportName->pn_atom))
- return null();
+ if (!processExportFrom(node))
+ return null();
- Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName);
- if (!exportSpec)
- return null();
+ return node;
+}
- handler.addList(kid, exportSpec);
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportBatch(uint32_t begin)
+{
+ if (!abortIfSyntaxParser())
+ return null();
- bool matched;
- if (!tokenStream.matchToken(&matched, TOK_COMMA))
- return null();
- if (!matched)
- break;
- }
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_MUL));
- MUST_MATCH_TOKEN(TOK_RC, JSMSG_RC_AFTER_EXPORT_SPEC_LIST);
+ Node kid = handler.newList(PNK_EXPORT_SPEC_LIST);
+ if (!kid)
+ return null();
- // Careful! If |from| follows, even on a new line, it must start a
- // FromClause:
- //
- // export { x }
- // from "foo"; // a single ExportDeclaration
- //
- // But if it doesn't, we might have an ASI opportunity in Operand
- // context, so simply matching a contextual keyword won't work:
- //
- // export { x } // ExportDeclaration, terminated by ASI
- // fro\u006D // ExpressionStatement, the name "from"
- //
- // In that case let MatchOrInsertSemicolonAfterNonExpression sort out
- // ASI or any necessary error.
- TokenKind tt;
- if (!tokenStream.getToken(&tt, TokenStream::Operand))
- return null();
+ // Handle the form |export *| by adding a special export batch
+ // specifier to the list.
+ Node exportSpec = handler.newNullary(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos());
+ if (!exportSpec)
+ return null();
- if (tt == TOK_NAME &&
- tokenStream.currentToken().name() == context->names().from &&
- !tokenStream.currentToken().nameContainsEscape())
- {
- MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
+ handler.addList(kid, exportSpec);
- Node moduleSpec = stringLiteral();
- if (!moduleSpec)
- return null();
+ MUST_MATCH_TOKEN(TOK_FROM, JSMSG_FROM_AFTER_EXPORT_STAR);
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
- return null();
+ return exportFrom(begin, kid);
+}
- ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec);
- if (!node || !pc->sc()->asModuleContext()->builder.processExportFrom(node))
- return null();
+template<>
+bool
+Parser<FullParseHandler>::checkLocalExportNames(ParseNode* node)
+{
+ // ES 2017 draft 15.2.3.1.
+ for (ParseNode* next = node->pn_head; next; next = next->pn_next) {
+ ParseNode* name = next->pn_left;
+ MOZ_ASSERT(name->isKind(PNK_NAME));
- return node;
- }
+ RootedPropertyName ident(context, name->pn_atom->asPropertyName());
+ if (!checkLocalExportName(ident, name->pn_pos.begin))
+ return false;
+ }
- tokenStream.ungetToken();
+ return true;
+}
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
- return null();
- break;
- }
+template<>
+bool
+Parser<SyntaxParseHandler>::checkLocalExportNames(Node node)
+{
+ MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
+ return false;
+}
- case TOK_MUL: {
- kid = handler.newList(PNK_EXPORT_SPEC_LIST);
- if (!kid)
- return null();
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportClause(uint32_t begin)
+{
+ if (!abortIfSyntaxParser())
+ return null();
- // Handle the form |export *| by adding a special export batch
- // specifier to the list.
- Node exportSpec = handler.newNullary(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos());
- if (!exportSpec)
- return null();
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
- handler.addList(kid, exportSpec);
+ Node kid = handler.newList(PNK_EXPORT_SPEC_LIST);
+ if (!kid)
+ return null();
+ TokenKind tt;
+ while (true) {
+ // Handle the forms |export {}| and |export { ..., }| (where ... is non
+ // empty), by escaping the loop early if the next token is }.
if (!tokenStream.getToken(&tt))
return null();
- if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) {
- error(JSMSG_FROM_AFTER_EXPORT_STAR);
+
+ if (tt == TOK_RC)
+ break;
+
+ if (!TokenKindIsPossibleIdentifierName(tt)) {
+ error(JSMSG_NO_BINDING_NAME);
return null();
}
- if (!checkUnescapedName())
+ Node bindingName = newName(tokenStream.currentName());
+ if (!bindingName)
return null();
- MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
-
- Node moduleSpec = stringLiteral();
- if (!moduleSpec)
+ bool foundAs;
+ if (!tokenStream.matchToken(&foundAs, TOK_AS))
return null();
+ if (foundAs)
+ MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_EXPORT_NAME);
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
+ Node exportName = newName(tokenStream.currentName());
+ if (!exportName)
return null();
- ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec);
- if (!node || !pc->sc()->asModuleContext()->builder.processExportFrom(node))
+ if (!checkExportedNameForClause(exportName))
return null();
- return node;
+ Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName);
+ if (!exportSpec)
+ return null();
- }
+ handler.addList(kid, exportSpec);
- case TOK_FUNCTION:
- kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired);
- if (!kid)
+ TokenKind next;
+ if (!tokenStream.getToken(&next))
return null();
- if (!checkExportedName(kid->pn_funbox->function()->explicitName()))
- return null();
- break;
+ if (next == TOK_RC)
+ break;
- case TOK_CLASS: {
- kid = classDefinition(YieldIsKeyword, ClassStatement, NameRequired);
- if (!kid)
+ if (next != TOK_COMMA) {
+ error(JSMSG_RC_AFTER_EXPORT_SPEC_LIST);
return null();
+ }
+ }
- const ClassNode& cls = kid->as<ClassNode>();
- MOZ_ASSERT(cls.names());
- if (!checkExportedName(cls.names()->innerBinding()->pn_atom))
- return null();
- break;
- }
+ // Careful! If |from| follows, even on a new line, it must start a
+ // FromClause:
+ //
+ // export { x }
+ // from "foo"; // a single ExportDeclaration
+ //
+ // But if it doesn't, we might have an ASI opportunity in Operand context:
+ //
+ // export { x } // ExportDeclaration, terminated by ASI
+ // fro\u006D // ExpressionStatement, the name "from"
+ //
+ // In that case let matchOrInsertSemicolonAfterNonExpression sort out ASI
+ // or any necessary error.
+ bool matched;
+ if (!tokenStream.matchToken(&matched, TOK_FROM, TokenStream::Operand))
+ return null();
- case TOK_VAR:
- kid = declarationList(YieldIsName, PNK_VAR);
- if (!kid)
- return null();
- if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
- return null();
- if (!checkExportedNamesForDeclaration(kid))
- return null();
- break;
+ if (matched)
+ return exportFrom(begin, kid);
- case TOK_DEFAULT: {
- if (!tokenStream.getToken(&tt, TokenStream::Operand))
- return null();
+ if (!matchOrInsertSemicolonAfterNonExpression())
+ return null();
- if (!checkExportedName(context->names().default_))
- return null();
+ if (!checkLocalExportNames(kid))
+ return null();
- ParseNode* nameNode = nullptr;
- switch (tt) {
- case TOK_FUNCTION:
- kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName);
- if (!kid)
- return null();
- break;
- case TOK_CLASS:
- kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName);
- if (!kid)
- return null();
- break;
- default: {
- if (tt == TOK_NAME && tokenStream.currentName() == context->names().async) {
- TokenKind nextSameLine = TOK_EOF;
- if (!tokenStream.peekTokenSameLine(&nextSameLine))
- return null();
+ Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
+ if (!node)
+ return null();
- if (nextSameLine == TOK_FUNCTION) {
- tokenStream.consumeKnownToken(nextSameLine);
- kid = functionStmt(pos().begin, YieldIsName, AllowDefaultName, AsyncFunction);
- if (!kid)
- return null();
- break;
- }
- }
+ if (!processExport(node))
+ return null();
- tokenStream.ungetToken();
- RootedPropertyName name(context, context->names().starDefaultStar);
- nameNode = newName(name);
- if (!nameNode)
- return null();
- if (!noteDeclaredName(name, DeclarationKind::Const, pos()))
- return null();
- kid = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited);
- if (!kid)
- return null();
- if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
- return null();
- break;
- }
- }
+ return node;
+}
- ParseNode* node = handler.newExportDefaultDeclaration(kid, nameNode,
- TokenPos(begin, pos().end));
- if (!node || !pc->sc()->asModuleContext()->builder.processExport(node))
- return null();
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportVariableStatement(uint32_t begin)
+{
+ if (!abortIfSyntaxParser())
+ return null();
- return node;
- }
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_VAR));
- case TOK_CONST:
- kid = lexicalDeclaration(YieldIsName, /* isConst = */ true);
- if (!kid)
- return null();
- if (!checkExportedNamesForDeclaration(kid))
- return null();
- break;
+ Node kid = declarationList(YieldIsName, PNK_VAR);
+ if (!kid)
+ return null();
+ if (!matchOrInsertSemicolonAfterExpression())
+ return null();
+ if (!checkExportedNamesForDeclaration(kid))
+ return null();
- case TOK_NAME:
- if (tokenStream.currentName() == context->names().let) {
- if (!checkUnescapedName())
- return null();
+ Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
+ if (!node)
+ return null();
- kid = lexicalDeclaration(YieldIsName, /* isConst = */ false);
- if (!kid)
- return null();
- if (!checkExportedNamesForDeclaration(kid))
- return null();
- break;
- }
- MOZ_FALLTHROUGH;
+ if (!processExport(node))
+ return null();
- default:
- error(JSMSG_DECLARATION_AFTER_EXPORT);
+ return node;
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin)
+{
+ if (!abortIfSyntaxParser())
+ return null();
+
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
+
+ Node kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired);
+ if (!kid)
+ return null();
+
+ if (!checkExportedNameForFunction(kid))
return null();
- }
- ParseNode* node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
- if (!node || !pc->sc()->asModuleContext()->builder.processExport(node))
+ Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
+ if (!node)
+ return null();
+
+ if (!processExport(node))
return null();
return node;
}
-template<>
-SyntaxParseHandler::Node
-Parser<SyntaxParseHandler>::exportDeclaration()
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportClassDeclaration(uint32_t begin)
{
- JS_ALWAYS_FALSE(abortIfSyntaxParser());
- return SyntaxParseHandler::NodeFailure;
+ if (!abortIfSyntaxParser())
+ return null();
+
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS));
+
+ Node kid = classDefinition(YieldIsKeyword, ClassStatement, NameRequired);
+ if (!kid)
+ return null();
+
+ if (!checkExportedNameForClass(kid))
+ return null();
+
+ Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
+ if (!node)
+ return null();
+
+ if (!processExport(node))
+ return null();
+
+ return node;
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportLexicalDeclaration(uint32_t begin, DeclarationKind kind)
+{
+ if (!abortIfSyntaxParser())
+ return null();
+
+ MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let);
+ MOZ_ASSERT_IF(kind == DeclarationKind::Const, tokenStream.isCurrentTokenType(TOK_CONST));
+ MOZ_ASSERT_IF(kind == DeclarationKind::Let, tokenStream.isCurrentTokenType(TOK_LET));
+
+ Node kid = lexicalDeclaration(YieldIsName, kind);
+ if (!kid)
+ return null();
+ if (!checkExportedNamesForDeclaration(kid))
+ return null();
+
+ Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
+ if (!node)
+ return null();
+
+ if (!processExport(node))
+ return null();
+
+ return node;
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportDefaultFunctionDeclaration(uint32_t begin,
+ FunctionAsyncKind asyncKind
+ /* = SyncFunction */)
+{
+ if (!abortIfSyntaxParser())
+ return null();
+
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
+
+ Node kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName, asyncKind);
+ if (!kid)
+ return null();
+
+ Node node = handler.newExportDefaultDeclaration(kid, null(), TokenPos(begin, pos().end));
+ if (!node)
+ return null();
+
+ if (!processExport(node))
+ return null();
+
+ return node;
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportDefaultClassDeclaration(uint32_t begin)
+{
+ if (!abortIfSyntaxParser())
+ return null();
+
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS));
+
+ Node kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName);
+ if (!kid)
+ return null();
+
+ Node node = handler.newExportDefaultDeclaration(kid, null(), TokenPos(begin, pos().end));
+ if (!node)
+ return null();
+
+ if (!processExport(node))
+ return null();
+
+ return node;
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportDefaultAssignExpr(uint32_t begin)
+{
+ if (!abortIfSyntaxParser())
+ return null();
+
+ RootedPropertyName name(context, context->names().starDefaultStar);
+ Node nameNode = newName(name);
+ if (!nameNode)
+ return null();
+ if (!noteDeclaredName(name, DeclarationKind::Const, pos()))
+ return null();
+
+ Node kid = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited);
+ if (!kid)
+ return null();
+ if (!matchOrInsertSemicolonAfterExpression())
+ return null();
+
+ Node node = handler.newExportDefaultDeclaration(kid, nameNode, TokenPos(begin, pos().end));
+ if (!node)
+ return null();
+
+ if (!processExport(node))
+ return null();
+
+ return node;
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportDefault(uint32_t begin)
+{
+ if (!abortIfSyntaxParser())
+ return null();
+
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_DEFAULT));
+
+ TokenKind tt;
+ if (!tokenStream.getToken(&tt, TokenStream::Operand))
+ return null();
+
+ if (!checkExportedName(context->names().default_))
+ return null();
+
+ switch (tt) {
+ case TOK_FUNCTION:
+ return exportDefaultFunctionDeclaration(begin);
+
+ case TOK_ASYNC: {
+ TokenKind nextSameLine = TOK_EOF;
+ if (!tokenStream.peekTokenSameLine(&nextSameLine))
+ return null();
+
+ if (nextSameLine == TOK_FUNCTION) {
+ tokenStream.consumeKnownToken(TOK_FUNCTION);
+ return exportDefaultFunctionDeclaration(begin, AsyncFunction);
+ }
+
+ tokenStream.ungetToken();
+ return exportDefaultAssignExpr(begin);
+ }
+
+ case TOK_CLASS:
+ return exportDefaultClassDeclaration(begin);
+
+ default:
+ tokenStream.ungetToken();
+ return exportDefaultAssignExpr(begin);
+ }
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportDeclaration()
+{
+ if (!abortIfSyntaxParser())
+ return null();
+
+ MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT);
+
+ if (!pc->atModuleLevel()) {
+ error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL);
+ return null();
+ }
+
+ uint32_t begin = pos().begin;
+
+ TokenKind tt;
+ if (!tokenStream.getToken(&tt))
+ return null();
+ switch (tt) {
+ case TOK_MUL:
+ return exportBatch(begin);
+
+ case TOK_LC:
+ return exportClause(begin);
+
+ case TOK_VAR:
+ return exportVariableStatement(begin);
+
+ case TOK_FUNCTION:
+ return exportFunctionDeclaration(begin);
+
+ case TOK_CLASS:
+ return exportClassDeclaration(begin);
+
+ case TOK_CONST:
+ return exportLexicalDeclaration(begin, DeclarationKind::Const);
+
+ case TOK_LET:
+ return exportLexicalDeclaration(begin, DeclarationKind::Let);
+
+ case TOK_DEFAULT:
+ return exportDefault(begin);
+
+ default:
+ error(JSMSG_DECLARATION_AFTER_EXPORT);
+ return null();
+ }
}
template <typename ParseHandler>
@@ -5236,7 +5768,7 @@ Parser<ParseHandler>::expressionStatement(YieldHandling yieldHandling, InvokedPr
/* possibleError = */ nullptr, invoked);
if (!pnexpr)
return null();
- if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterExpression())
return null();
return handler.newExprStatement(pnexpr, pos().end);
}
@@ -5249,14 +5781,71 @@ Parser<ParseHandler>::consequentOrAlternative(YieldHandling yieldHandling)
if (!tokenStream.peekToken(&next, TokenStream::Operand))
return null();
- if (next == TOK_FUNCTION) {
- // Apply Annex B.3.4 in non-strict code to allow FunctionDeclaration as
- // the consequent/alternative of an |if| or |else|. Parser::statement
- // will report the strict mode error.
- if (!pc->sc()->strict()) {
- tokenStream.consumeKnownToken(next, TokenStream::Operand);
- return functionStmt(pos().begin, yieldHandling, NameRequired);
+ // Annex B.3.4 says that unbraced FunctionDeclarations under if/else in
+ // non-strict code act as if they were braced: |if (x) function f() {}|
+ // parses as |if (x) { function f() {} }|.
+ //
+ // Careful! FunctionDeclaration doesn't include generators or async
+ // functions.
+ if (next == TOK_ASYNC) {
+ tokenStream.consumeKnownToken(next, TokenStream::Operand);
+
+ // Peek only on the same line: ExpressionStatement's lookahead
+ // restriction is phrased as
+ //
+ // [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]
+ //
+ // meaning that code like this is valid:
+ //
+ // if (true)
+ // async // ASI opportunity
+ // function clownshoes() {}
+ TokenKind maybeFunction;
+ if (!tokenStream.peekTokenSameLine(&maybeFunction))
+ return null();
+
+ if (maybeFunction == TOK_FUNCTION) {
+ error(JSMSG_FORBIDDEN_AS_STATEMENT, "async function declarations");
+ return null();
}
+
+ // Otherwise this |async| begins an ExpressionStatement.
+ tokenStream.ungetToken();
+ } else if (next == TOK_FUNCTION) {
+ tokenStream.consumeKnownToken(next, TokenStream::Operand);
+
+ // Parser::statement would handle this, but as this function handles
+ // every other error case, it seems best to handle this.
+ if (pc->sc()->strict()) {
+ error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
+ return null();
+ }
+
+ TokenKind maybeStar;
+ if (!tokenStream.peekToken(&maybeStar))
+ return null();
+
+ if (maybeStar == TOK_MUL) {
+ error(JSMSG_FORBIDDEN_AS_STATEMENT, "generator declarations");
+ return null();
+ }
+
+ ParseContext::Statement stmt(pc, StatementKind::Block);
+ ParseContext::Scope scope(this);
+ if (!scope.init(pc))
+ return null();
+
+ TokenPos funcPos = pos();
+ Node fun = functionStmt(pos().begin, yieldHandling, NameRequired);
+ if (!fun)
+ return null();
+
+ Node block = handler.newStatementList(funcPos);
+ if (!block)
+ return null();
+
+ handler.addStatementToList(block, fun);
+ return finishLexicalScope(scope, block);
}
return statement(yieldHandling);
@@ -5371,13 +5960,9 @@ Parser<ParseHandler>::matchInOrOf(bool* isForInp, bool* isForOfp)
return false;
*isForInp = tt == TOK_IN;
- *isForOfp = tt == TOK_NAME && tokenStream.currentToken().name() == context->names().of;
- if (!*isForInp && !*isForOfp) {
+ *isForOfp = tt == TOK_OF;
+ if (!*isForInp && !*isForOfp)
tokenStream.ungetToken();
- } else {
- if (tt == TOK_NAME && !checkUnescapedName())
- return false;
- }
MOZ_ASSERT_IF(*isForInp || *isForOfp, *isForInp != *isForOfp);
return true;
@@ -5427,15 +6012,12 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
if (tt == TOK_CONST) {
parsingLexicalDeclaration = true;
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
- } else if (tt == TOK_NAME &&
- tokenStream.nextName() == context->names().let &&
- !tokenStream.nextNameContainsEscape())
- {
+ } else if (tt == TOK_LET) {
// We could have a {For,Lexical}Declaration, or we could have a
// LeftHandSideExpression with lookahead restrictions so it's not
// ambiguous with the former. Check for a continuation of the former
// to decide which we have.
- tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand);
+ tokenStream.consumeKnownToken(TOK_LET, TokenStream::Operand);
TokenKind next;
if (!tokenStream.peekToken(&next))
@@ -5512,7 +6094,7 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
// Verify the left-hand side expression doesn't have a forbidden form.
if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) {
- if (!checkDestructuringPattern(*forInitialPart, Nothing(), &possibleError))
+ if (!possibleError.checkForDestructuringErrorOrWarning())
return false;
} else if (handler.isNameAnyParentheses(*forInitialPart)) {
const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context);
@@ -5556,7 +6138,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
if (allowsForEachIn()) {
bool matched;
- if (!tokenStream.matchContextualKeyword(&matched, context->names().each))
+ if (!tokenStream.matchToken(&matched, TOK_EACH))
return null();
if (matched) {
iflags = JSITER_FOREACH;
@@ -5867,7 +6449,7 @@ Parser<ParseHandler>::continueStatement(YieldHandling yieldHandling)
return null();
}
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterNonExpression())
return null();
return handler.newContinueStatement(label, TokenPos(begin, pos().end));
@@ -5907,7 +6489,7 @@ Parser<ParseHandler>::breakStatement(YieldHandling yieldHandling)
}
}
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterNonExpression())
return null();
return handler.newBreakStatement(label, TokenPos(begin, pos().end));
@@ -5947,10 +6529,10 @@ Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
}
if (exprNode) {
- if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterExpression())
return null();
} else {
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterNonExpression())
return null();
}
@@ -6070,7 +6652,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
if (pc->funHasReturnExpr
#if JS_HAS_EXPR_CLOSURES
- || pc->functionBox()->function()->isExprBody()
+ || pc->functionBox()->isExprBody()
#endif
)
{
@@ -6247,7 +6829,7 @@ Parser<ParseHandler>::throwStatement(YieldHandling yieldHandling)
if (!throwExpr)
return null();
- if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterExpression())
return null();
return handler.newThrowStatement(throwExpr, TokenPos(begin, pos().end));
@@ -6267,12 +6849,12 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
* kid3 is the finally statement
*
* catch nodes are ternary.
- * kid1 is the lvalue (TOK_NAME, TOK_LB, or TOK_LC)
+ * kid1 is the lvalue (possible identifier, TOK_LB, or TOK_LC)
* kid2 is the catch guard or null if no guard
* kid3 is the catch block
*
* catch lvalue nodes are either:
- * TOK_NAME for a single identifier
+ * a single identifier
* TOK_RB or TOK_RC for a destructuring left-hand side
*
* finally nodes are TOK_LC statement lists.
@@ -6282,6 +6864,8 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
{
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
+ uint32_t openedPos = pos().begin;
+
ParseContext::Statement stmt(pc, StatementKind::Try);
ParseContext::Scope scope(this);
if (!scope.init(pc))
@@ -6295,7 +6879,9 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!innerBlock)
return null();
- MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_TRY);
+ MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
+ reportMissingClosing(JSMSG_CURLY_AFTER_TRY,
+ JSMSG_CURLY_OPENED, openedPos));
}
bool hasUnconditionalCatch = false;
@@ -6347,22 +6933,18 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
return null();
break;
- case TOK_NAME:
- case TOK_YIELD: {
- RootedPropertyName param(context, bindingIdentifier(yieldHandling));
- if (!param)
+ default: {
+ if (!TokenKindIsPossibleIdentifierName(tt)) {
+ error(JSMSG_CATCH_IDENTIFIER);
return null();
- catchName = newName(param);
+ }
+
+ catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter,
+ yieldHandling);
if (!catchName)
return null();
- if (!noteDeclaredName(param, DeclarationKind::SimpleCatchParameter, pos()))
- return null();
break;
}
-
- default:
- error(JSMSG_CATCH_IDENTIFIER);
- return null();
}
Node catchGuard = null();
@@ -6411,6 +6993,8 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (tt == TOK_FINALLY) {
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
+ uint32_t openedPos = pos().begin;
+
ParseContext::Statement stmt(pc, StatementKind::Finally);
ParseContext::Scope scope(this);
if (!scope.init(pc))
@@ -6424,7 +7008,9 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!finallyBlock)
return null();
- MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_FINALLY);
+ MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
+ reportMissingClosing(JSMSG_CURLY_AFTER_FINALLY,
+ JSMSG_CURLY_OPENED, openedPos));
} else {
tokenStream.ungetToken();
}
@@ -6441,6 +7027,8 @@ typename ParseHandler::Node
Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
ParseContext::Scope& catchParamScope)
{
+ uint32_t openedPos = pos().begin;
+
ParseContext::Statement stmt(pc, StatementKind::Block);
// ES 13.15.7 CatchClauseEvaluation
@@ -6460,7 +7048,9 @@ Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
if (!list)
return null();
- MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_CATCH);
+ MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
+ reportMissingClosing(JSMSG_CURLY_AFTER_CATCH,
+ JSMSG_CURLY_OPENED, openedPos));
// The catch parameter names are not bound in the body scope, so remove
// them before generating bindings.
@@ -6474,7 +7064,7 @@ Parser<ParseHandler>::debuggerStatement()
{
TokenPos p;
p.begin = pos().begin;
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterNonExpression())
return null();
p.end = pos().end;
@@ -6514,6 +7104,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS));
+ uint32_t classStartOffset = pos().begin;
bool savedStrictness = setLocalStrictMode(true);
TokenKind tt;
@@ -6521,7 +7112,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
return null();
RootedPropertyName name(context);
- if (tt == TOK_NAME || tt == TOK_YIELD) {
+ if (TokenKindIsPossibleIdentifier(tt)) {
name = bindingIdentifier(yieldHandling);
if (!name)
return null();
@@ -6539,16 +7130,20 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
tokenStream.ungetToken();
}
+ // Push a ParseContext::ClassStatement to keep track of the constructor
+ // funbox.
+ ParseContext::ClassStatement classStmt(pc);
+
RootedAtom propAtom(context);
// A named class creates a new lexical scope with a const binding of the
- // class name.
- Maybe<ParseContext::Statement> classStmt;
- Maybe<ParseContext::Scope> classScope;
+ // class name for the "inner name".
+ Maybe<ParseContext::Statement> innerScopeStmt;
+ Maybe<ParseContext::Scope> innerScope;
if (name) {
- classStmt.emplace(pc, StatementKind::Block);
- classScope.emplace(this);
- if (!classScope->init(pc))
+ innerScopeStmt.emplace(pc, StatementKind::Block);
+ innerScope.emplace(this);
+ if (!innerScope->init(pc))
return null();
}
@@ -6575,10 +7170,10 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!classMethods)
return null();
- bool seenConstructor = false;
+ Maybe<DeclarationKind> declKind = Nothing();
for (;;) {
TokenKind tt;
- if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName))
+ if (!tokenStream.getToken(&tt))
return null();
if (tt == TOK_RC)
break;
@@ -6587,22 +7182,18 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
continue;
bool isStatic = false;
- if (tt == TOK_NAME && tokenStream.currentName() == context->names().static_) {
- if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName))
+ if (tt == TOK_STATIC) {
+ if (!tokenStream.peekToken(&tt))
return null();
if (tt == TOK_RC) {
- tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName);
+ tokenStream.consumeKnownToken(tt);
error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt));
return null();
}
if (tt != TOK_LP) {
- if (!checkUnescapedName())
- return null();
-
isStatic = true;
} else {
- tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName);
tokenStream.ungetToken();
}
} else {
@@ -6614,7 +7205,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
return null();
PropertyType propType;
- Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom);
+ Node propName = propertyName(yieldHandling, declKind, classMethods, &propType, &propAtom);
if (!propName)
return null();
@@ -6631,16 +7222,17 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
propType = PropertyType::GetterNoExpressionClosure;
if (propType == PropertyType::Setter)
propType = PropertyType::SetterNoExpressionClosure;
- if (!isStatic && propAtom == context->names().constructor) {
+
+ bool isConstructor = !isStatic && propAtom == context->names().constructor;
+ if (isConstructor) {
if (propType != PropertyType::Method) {
errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
return null();
}
- if (seenConstructor) {
+ if (classStmt.constructorBox) {
errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor");
return null();
}
- seenConstructor = true;
propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor;
} else if (isStatic && propAtom == context->names().prototype) {
errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
@@ -6665,7 +7257,12 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!tokenStream.isCurrentTokenType(TOK_RB))
funName = propAtom;
}
- Node fn = methodDefinition(nameOffset, propType, funName);
+
+ // Calling toString on constructors need to return the source text for
+ // the entire class. The end offset is unknown at this point in
+ // parsing and will be amended when class parsing finishes below.
+ Node fn = methodDefinition(isConstructor ? classStartOffset : nameOffset,
+ propType, funName);
if (!fn)
return null();
@@ -6676,6 +7273,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
return null();
}
+ // Amend the toStringEnd offset for the constructor now that we've
+ // finished parsing the class.
+ uint32_t classEndOffset = pos().end;
+ if (FunctionBox* ctorbox = classStmt.constructorBox) {
+ if (ctorbox->function()->isInterpretedLazy())
+ ctorbox->function()->lazyScript()->setToStringEnd(classEndOffset);
+ ctorbox->toStringEnd = classEndOffset;
+ }
+
Node nameNode = null();
Node methodsOrBlock = classMethods;
if (name) {
@@ -6687,15 +7293,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!innerName)
return null();
- Node classBlock = finishLexicalScope(*classScope, classMethods);
+ Node classBlock = finishLexicalScope(*innerScope, classMethods);
if (!classBlock)
return null();
methodsOrBlock = classBlock;
// Pop the inner scope.
- classScope.reset();
- classStmt.reset();
+ innerScope.reset();
+ innerScopeStmt.reset();
Node outerName = null();
if (classContext == ClassStatement) {
@@ -6715,16 +7321,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
- return handler.newClass(nameNode, classHeritage, methodsOrBlock);
+ return handler.newClass(nameNode, classHeritage, methodsOrBlock,
+ TokenPos(classStartOffset, classEndOffset));
}
template <class ParseHandler>
bool
Parser<ParseHandler>::nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling)
{
- MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
- MOZ_ASSERT(tokenStream.currentName() == context->names().let);
- MOZ_ASSERT(!tokenStream.currentToken().nameContainsEscape());
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LET));
#ifdef DEBUG
TokenKind verify;
@@ -6736,18 +7341,19 @@ Parser<ParseHandler>::nextTokenContinuesLetDeclaration(TokenKind next, YieldHand
if (next == TOK_LB || next == TOK_LC)
return true;
- // Otherwise a let declaration must have a name.
- if (next == TOK_NAME) {
- if (tokenStream.nextName() == context->names().yield) {
- MOZ_ASSERT(tokenStream.nextNameContainsEscape(),
- "token stream should interpret unescaped 'yield' as TOK_YIELD");
-
- // Same as |next == TOK_YIELD|.
- return yieldHandling == YieldIsName;
- }
+ // If we have the name "yield", the grammar parameter exactly states
+ // whether this is okay. (This wasn't true for SpiderMonkey's ancient
+ // legacy generator syntax, but that's dead now.) If YieldIsName,
+ // declaration-parsing code will (if necessary) enforce a strict mode
+ // restriction on defining "yield". If YieldIsKeyword, consider this the
+ // end of the declaration, in case ASI induces a semicolon that makes the
+ // "yield" valid.
+ if (next == TOK_YIELD)
+ return yieldHandling == YieldIsName;
- // One non-"yield" TOK_NAME edge case deserves special comment.
- // Consider this:
+ // Otherwise a let declaration must have a name.
+ if (TokenKindIsPossibleIdentifier(next)) {
+ // A "let" edge case deserves special comment. Consider this:
//
// let // not an ASI opportunity
// let;
@@ -6760,16 +7366,6 @@ Parser<ParseHandler>::nextTokenContinuesLetDeclaration(TokenKind next, YieldHand
return true;
}
- // If we have the name "yield", the grammar parameter exactly states
- // whether this is okay. (This wasn't true for SpiderMonkey's ancient
- // legacy generator syntax, but that's dead now.) If YieldIsName,
- // declaration-parsing code will (if necessary) enforce a strict mode
- // restriction on defining "yield". If YieldIsKeyword, consider this the
- // end of the declaration, in case ASI induces a semicolon that makes the
- // "yield" valid.
- if (next == TOK_YIELD)
- return yieldHandling == YieldIsName;
-
// Otherwise not a let declaration.
return false;
}
@@ -6781,7 +7377,7 @@ Parser<ParseHandler>::variableStatement(YieldHandling yieldHandling)
Node vars = declarationList(yieldHandling, PNK_VAR);
if (!vars)
return null();
- if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterExpression())
return null();
return vars;
}
@@ -6832,16 +7428,21 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
return expressionStatement(yieldHandling);
}
- case TOK_NAME: {
+ default: {
+ // Avoid getting next token with None.
+ if (tt == TOK_AWAIT && pc->isAsync())
+ return expressionStatement(yieldHandling);
+
+ if (!TokenKindIsPossibleIdentifier(tt))
+ return expressionStatement(yieldHandling);
+
TokenKind next;
if (!tokenStream.peekToken(&next))
return null();
// |let| here can only be an Identifier, not a declaration. Give nicer
// errors for declaration-looking typos.
- if (!tokenStream.currentToken().nameContainsEscape() &&
- tokenStream.currentName() == context->names().let)
- {
+ if (tt == TOK_LET) {
bool forbiddenLetDeclaration = false;
if (pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) {
@@ -6851,7 +7452,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
} else if (next == TOK_LB) {
// Enforce ExpressionStatement's 'let [' lookahead restriction.
forbiddenLetDeclaration = true;
- } else if (next == TOK_LC || next == TOK_NAME) {
+ } else if (next == TOK_LC || TokenKindIsPossibleIdentifier(next)) {
// 'let {' and 'let foo' aren't completely forbidden, if ASI
// causes 'let' to be the entire Statement. But if they're
// same-line, we can aggressively give a better error message.
@@ -6862,7 +7463,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
- MOZ_ASSERT(nextSameLine == TOK_NAME ||
+ MOZ_ASSERT(TokenKindIsPossibleIdentifier(nextSameLine) ||
nextSameLine == TOK_LC ||
nextSameLine == TOK_EOL);
@@ -6886,9 +7487,6 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
case TOK_NEW:
return expressionStatement(yieldHandling, PredictInvoked);
- default:
- return expressionStatement(yieldHandling);
-
// IfStatement[?Yield, ?Return]
case TOK_IF:
return ifStatement(yieldHandling);
@@ -6934,7 +7532,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
return withStatement(yieldHandling);
// LabelledStatement[?Yield, ?Return]
- // This is really handled by TOK_NAME and TOK_YIELD cases above.
+ // This is really handled by default and TOK_YIELD cases above.
// ThrowStatement[?Yield]
case TOK_THROW:
@@ -7040,26 +7638,29 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
return expressionStatement(yieldHandling);
}
- case TOK_NAME: {
+ default: {
+ // Avoid getting next token with None.
+ if (tt == TOK_AWAIT && pc->isAsync())
+ return expressionStatement(yieldHandling);
+
+ if (!TokenKindIsPossibleIdentifier(tt))
+ return expressionStatement(yieldHandling);
+
TokenKind next;
if (!tokenStream.peekToken(&next))
return null();
- if (!tokenStream.currentToken().nameContainsEscape() &&
- tokenStream.currentName() == context->names().let &&
- nextTokenContinuesLetDeclaration(next, yieldHandling))
- {
- return lexicalDeclaration(yieldHandling, /* isConst = */ false);
- }
+ if (tt == TOK_LET && nextTokenContinuesLetDeclaration(next, yieldHandling))
+ return lexicalDeclaration(yieldHandling, DeclarationKind::Let);
- if (tokenStream.currentName() == context->names().async) {
+ if (tt == TOK_ASYNC) {
TokenKind nextSameLine = TOK_EOF;
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
if (nextSameLine == TOK_FUNCTION) {
- uint32_t preludeStart = pos().begin;
+ uint32_t toStringStart = pos().begin;
tokenStream.consumeKnownToken(TOK_FUNCTION);
- return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction);
+ return functionStmt(toStringStart, yieldHandling, NameRequired, AsyncFunction);
}
}
@@ -7072,9 +7673,6 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
case TOK_NEW:
return expressionStatement(yieldHandling, PredictInvoked);
- default:
- return expressionStatement(yieldHandling);
-
// IfStatement[?Yield, ?Return]
case TOK_IF:
return ifStatement(yieldHandling);
@@ -7120,7 +7718,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
return withStatement(yieldHandling);
// LabelledStatement[?Yield, ?Return]
- // This is really handled by TOK_NAME and TOK_YIELD cases above.
+ // This is really handled by default and TOK_YIELD cases above.
// ThrowStatement[?Yield]
case TOK_THROW:
@@ -7149,7 +7747,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
case TOK_CONST:
// [In] is the default behavior, because for-loops specially parse
// their heads to handle |in| in this situation.
- return lexicalDeclaration(yieldHandling, /* isConst = */ true);
+ return lexicalDeclaration(yieldHandling, DeclarationKind::Const);
// ImportDeclaration (only inside modules)
case TOK_IMPORT:
@@ -7438,26 +8036,6 @@ Parser<ParseHandler>::condExpr1(InHandling inHandling, YieldHandling yieldHandli
return handler.newConditional(condition, thenExpr, elseExpr);
}
-class AutoClearInDestructuringDecl
-{
- ParseContext* pc_;
- Maybe<DeclarationKind> saved_;
-
- public:
- explicit AutoClearInDestructuringDecl(ParseContext* pc)
- : pc_(pc),
- saved_(pc->inDestructuringDecl)
- {
- pc->inDestructuringDecl = Nothing();
- if (saved_ && *saved_ == DeclarationKind::FormalParameter)
- pc->functionBox()->hasParameterExprs = true;
- }
-
- ~AutoClearInDestructuringDecl() {
- pc_->inDestructuringDecl = saved_;
- }
-};
-
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandling,
@@ -7482,10 +8060,13 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
- uint32_t exprOffset = pos().begin;
+ TokenPos exprPos = pos();
bool endsExpr;
+ // This only handles identifiers that *never* have special meaning anywhere
+ // in the language. Contextual keywords, reserved words in strict mode,
+ // and other hard cases are handled outside this fast path.
if (tt == TOK_NAME) {
if (!tokenStream.nextTokenEndsExpr(&endsExpr))
return null();
@@ -7516,12 +8097,12 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
return yieldExpression(inHandling);
bool maybeAsyncArrow = false;
- if (tt == TOK_NAME && tokenStream.currentName() == context->names().async) {
+ if (tt == TOK_ASYNC) {
TokenKind nextSameLine = TOK_EOF;
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
- if (nextSameLine == TOK_NAME || nextSameLine == TOK_YIELD)
+ if (TokenKindIsPossibleIdentifier(nextSameLine))
maybeAsyncArrow = true;
}
@@ -7535,13 +8116,12 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
PossibleError possibleErrorInner(*this);
Node lhs;
if (maybeAsyncArrow) {
- tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand);
- MOZ_ASSERT(tokenStream.currentName() == context->names().async);
+ tokenStream.consumeKnownToken(TOK_ASYNC, TokenStream::Operand);
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null();
- MOZ_ASSERT(tt == TOK_NAME || tt == TOK_YIELD);
+ MOZ_ASSERT(TokenKindIsPossibleIdentifier(tt));
// Check yield validity here.
RootedPropertyName name(context, bindingIdentifier(yieldHandling));
@@ -7604,28 +8184,24 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (!tokenStream.getToken(&next, TokenStream::Operand))
return null();
- uint32_t preludeStart = pos().begin;
+ uint32_t toStringStart = pos().begin;
tokenStream.ungetToken();
GeneratorKind generatorKind = NotGenerator;
FunctionAsyncKind asyncKind = SyncFunction;
- if (next == TOK_NAME) {
+ if (next == TOK_ASYNC) {
tokenStream.consumeKnownToken(next, TokenStream::Operand);
- if (tokenStream.currentName() == context->names().async) {
- TokenKind nextSameLine = TOK_EOF;
- if (!tokenStream.peekTokenSameLine(&nextSameLine))
- return null();
+ TokenKind nextSameLine = TOK_EOF;
+ if (!tokenStream.peekTokenSameLine(&nextSameLine))
+ return null();
- if (nextSameLine == TOK_ARROW) {
- tokenStream.ungetToken();
- } else {
- generatorKind = StarGenerator;
- asyncKind = AsyncFunction;
- }
- } else {
+ if (nextSameLine == TOK_ARROW) {
tokenStream.ungetToken();
+ } else {
+ generatorKind = StarGenerator;
+ asyncKind = AsyncFunction;
}
}
@@ -7633,7 +8209,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (!pn)
return null();
- Node arrowFunc = functionDefinition(preludeStart, pn, inHandling, yieldHandling, nullptr,
+ Node arrowFunc = functionDefinition(toStringStart, pn, inHandling, yieldHandling, nullptr,
Arrow, generatorKind, asyncKind);
if (!arrowFunc)
return null();
@@ -7690,12 +8266,12 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
return null();
}
- if (!checkDestructuringPattern(lhs, Nothing(), &possibleErrorInner))
+ if (!possibleErrorInner.checkForDestructuringErrorOrWarning())
return null();
} else if (handler.isNameAnyParentheses(lhs)) {
if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
// |chars| is "arguments" or "eval" here.
- if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars))
+ if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
return null();
}
@@ -7703,23 +8279,22 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
} else if (handler.isPropertyAccess(lhs)) {
// Permitted: no additional testing/fixup needed.
} else if (handler.isFunctionCall(lhs)) {
- if (!strictModeErrorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS))
+ if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS))
return null();
+
+ if (possibleError)
+ possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
} else {
- errorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS);
+ errorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS);
return null();
}
if (!possibleErrorInner.checkForExpressionError())
return null();
- Node rhs;
- {
- AutoClearInDestructuringDecl autoClear(pc);
- rhs = assignExpr(inHandling, yieldHandling, TripledotProhibited);
- if (!rhs)
- return null();
- }
+ Node rhs = assignExpr(inHandling, yieldHandling, TripledotProhibited);
+ if (!rhs)
+ return null();
if (kind == PNK_ASSIGN)
handler.checkAndSetIsDirectRHSAnonFunction(rhs);
@@ -7874,20 +8449,17 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
}
case TOK_AWAIT: {
- if (!pc->isAsync()) {
- // TOK_AWAIT can be returned in module, even if it's not inside
- // async function.
- error(JSMSG_RESERVED_ID, "await");
- return null();
+ if (pc->isAsync()) {
+ Node kid = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked);
+ if (!kid)
+ return null();
+ pc->lastAwaitOffset = begin;
+ return newAwaitExpression(begin, kid);
}
-
- Node kid = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked);
- if (!kid)
- return null();
- pc->lastAwaitOffset = begin;
- return newAwaitExpression(begin, kid);
}
+ MOZ_FALLTHROUGH;
+
default: {
Node expr = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true,
possibleError, invoked);
@@ -7949,7 +8521,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
// Create box for fun->object early to root it.
Directives directives(/* strict = */ outerpc->sc()->strict());
- FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* preludeStart = */ 0, directives,
+ FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* toStringStart = */ 0, directives,
StarGenerator, SyncFunction, /* tryAnnexB = */ false);
if (!genFunbox)
return null();
@@ -7985,7 +8557,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
uint32_t end = pos().end;
handler.setBeginPosition(comp, begin);
handler.setEndPosition(comp, end);
- genFunbox->bufEnd = end;
+ genFunbox->setEnd(end);
handler.addStatementToList(body, comp);
handler.setEndPosition(body, end);
handler.setBeginPosition(genfn, begin);
@@ -8025,8 +8597,10 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
// FIXME: Destructuring binding (bug 980828).
- MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME);
- RootedPropertyName name(context, tokenStream.currentName());
+ MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifier, JSMSG_NO_VARIABLE_NAME);
+ RootedPropertyName name(context, bindingIdentifier(YieldIsKeyword));
+ if (!name)
+ return null();
if (name == context->names().let) {
error(JSMSG_LET_COMP_BINDING);
return null();
@@ -8036,7 +8610,7 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
if (!lhs)
return null();
bool matched;
- if (!tokenStream.matchContextualKeyword(&matched, context->names().of))
+ if (!tokenStream.matchToken(&matched, TOK_OF))
return null();
if (!matched) {
error(JSMSG_OF_AFTER_FOR_NAME);
@@ -8371,9 +8945,9 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
Node nextMember;
if (tt == TOK_DOT) {
- if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName))
+ if (!tokenStream.getToken(&tt))
return null();
- if (tt == TOK_NAME) {
+ if (TokenKindIsPossibleIdentifierName(tt)) {
PropertyName* field = tokenStream.currentName();
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
error(JSMSG_BAD_SUPERPROP, "property");
@@ -8448,8 +9022,27 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
JSOp op = JSOP_CALL;
bool maybeAsyncArrow = false;
- if (tt == TOK_LP && handler.isNameAnyParentheses(lhs)) {
- if (handler.nameIsEvalAnyParentheses(lhs, context)) {
+ if (PropertyName* prop = handler.maybeDottedProperty(lhs)) {
+ // Use the JSOP_FUN{APPLY,CALL} optimizations given the
+ // right syntax.
+ if (prop == context->names().apply) {
+ op = JSOP_FUNAPPLY;
+ if (pc->isFunctionBox()) {
+ pc->functionBox()->usesApply = true;
+ }
+ } else if (prop == context->names().call) {
+ op = JSOP_FUNCALL;
+ }
+ } else if (tt == TOK_LP) {
+ if (handler.isAsyncKeyword(lhs, context)) {
+ // |async (| can be the start of an async arrow
+ // function, so we need to defer reporting possible
+ // errors from destructuring syntax. To give better
+ // error messages, we only allow the AsyncArrowHead
+ // part of the CoverCallExpressionAndAsyncArrowHead
+ // syntax when the initial name is "async".
+ maybeAsyncArrow = true;
+ } else if (handler.isEvalAnyParentheses(lhs, context)) {
// Select the right EVAL op and flag pc as having a
// direct eval.
op = pc->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
@@ -8466,24 +9059,6 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
// it. (If we're not in a method, that's fine, so
// ignore the return value.)
checkAndMarkSuperScope();
- } else if (handler.nameIsUnparenthesizedAsync(lhs, context)) {
- // |async (| can be the start of an async arrow
- // function, so we need to defer reporting possible
- // errors from destructuring syntax. To give better
- // error messages, we only allow the AsyncArrowHead
- // part of the CoverCallExpressionAndAsyncArrowHead
- // syntax when the initial name is "async".
- maybeAsyncArrow = true;
- }
- } else if (PropertyName* prop = handler.maybeDottedProperty(lhs)) {
- // Use the JSOP_FUN{APPLY,CALL} optimizations given the
- // right syntax.
- if (prop == context->names().apply) {
- op = JSOP_FUNAPPLY;
- if (pc->isFunctionBox())
- pc->functionBox()->usesApply = true;
- } else if (prop == context->names().call) {
- op = JSOP_FUNCALL;
}
}
@@ -8542,106 +9117,117 @@ Parser<ParseHandler>::newName(PropertyName* name, TokenPos pos)
}
template <typename ParseHandler>
-PropertyName*
-Parser<ParseHandler>::labelOrIdentifierReference(YieldHandling yieldHandling,
- bool yieldTokenizedAsName)
-{
- PropertyName* ident;
- bool isYield;
- const Token& tok = tokenStream.currentToken();
- if (tok.type == TOK_NAME) {
- MOZ_ASSERT(tok.name() != context->names().yield ||
- tok.nameContainsEscape() ||
- yieldTokenizedAsName,
- "tokenizer should have treated unescaped 'yield' as TOK_YIELD");
- MOZ_ASSERT_IF(yieldTokenizedAsName, tok.name() == context->names().yield);
-
- ident = tok.name();
- isYield = ident == context->names().yield;
- } else {
- MOZ_ASSERT(tok.type == TOK_YIELD && !yieldTokenizedAsName);
+bool
+Parser<ParseHandler>::checkLabelOrIdentifierReference(HandlePropertyName ident,
+ uint32_t offset,
+ YieldHandling yieldHandling)
+{
+ if (ident == context->names().yield) {
+ if (yieldHandling == YieldIsKeyword ||
+ versionNumber() >= JSVERSION_1_7)
+ {
+ errorAt(offset, JSMSG_RESERVED_ID, "yield");
+ return false;
+ }
+ if (pc->sc()->needStrictChecks()) {
+ if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "yield"))
+ return false;
+ }
- ident = context->names().yield;
- isYield = true;
+ return true;
}
- if (!isYield) {
- if (pc->sc()->strict()) {
- const char* badName = ident == context->names().let
- ? "let"
- : ident == context->names().static_
- ? "static"
- : nullptr;
- if (badName) {
- error(JSMSG_RESERVED_ID, badName);
- return nullptr;
- }
+ if (ident == context->names().await) {
+ if (awaitIsKeyword()) {
+ errorAt(offset, JSMSG_RESERVED_ID, "await");
+ return false;
}
- } else {
- if (yieldHandling == YieldIsKeyword ||
- pc->sc()->strict() ||
- versionNumber() >= JSVERSION_1_7)
- {
- error(JSMSG_RESERVED_ID, "yield");
- return nullptr;
+ return true;
+ }
+
+ if (IsKeyword(ident) || IsReservedWordLiteral(ident)) {
+ errorAt(offset, JSMSG_INVALID_ID, ReservedWordToCharZ(ident));
+ return false;
+ }
+
+ if (IsFutureReservedWord(ident)) {
+ errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident));
+ return false;
+ }
+
+ if (pc->sc()->needStrictChecks()) {
+ if (IsStrictReservedWord(ident)) {
+ if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident)))
+ return false;
+ return true;
+ }
+
+ if (ident == context->names().let) {
+ if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "let"))
+ return false;
+ return true;
+ }
+
+ if (ident == context->names().static_) {
+ if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "static"))
+ return false;
+ return true;
}
}
- return ident;
+ return true;
}
template <typename ParseHandler>
-PropertyName*
-Parser<ParseHandler>::bindingIdentifier(YieldHandling yieldHandling)
+bool
+Parser<ParseHandler>::checkBindingIdentifier(HandlePropertyName ident,
+ uint32_t offset,
+ YieldHandling yieldHandling)
{
- PropertyName* ident;
- bool isYield;
- const Token& tok = tokenStream.currentToken();
- if (tok.type == TOK_NAME) {
- MOZ_ASSERT(tok.name() != context->names().yield || tok.nameContainsEscape(),
- "tokenizer should have treated unescaped 'yield' as TOK_YIELD");
+ if (!checkLabelOrIdentifierReference(ident, offset, yieldHandling))
+ return false;
- ident = tok.name();
- isYield = ident == context->names().yield;
- } else {
- MOZ_ASSERT(tok.type == TOK_YIELD);
+ if (pc->sc()->needStrictChecks()) {
+ if (ident == context->names().arguments) {
+ if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "arguments"))
+ return false;
+ return true;
+ }
- ident = context->names().yield;
- isYield = true;
+ if (ident == context->names().eval) {
+ if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "eval"))
+ return false;
+ return true;
+ }
}
- if (!isYield) {
- if (pc->sc()->strict()) {
- const char* badName = ident == context->names().arguments
- ? "arguments"
- : ident == context->names().eval
- ? "eval"
- : nullptr;
- if (badName) {
- error(JSMSG_BAD_STRICT_ASSIGN, badName);
- return nullptr;
- }
+ return true;
+}
- badName = ident == context->names().let
- ? "let"
- : ident == context->names().static_
- ? "static"
- : nullptr;
- if (badName) {
- error(JSMSG_RESERVED_ID, badName);
- return nullptr;
- }
- }
- } else {
- if (yieldHandling == YieldIsKeyword ||
- pc->sc()->strict() ||
- versionNumber() >= JSVERSION_1_7)
- {
- error(JSMSG_RESERVED_ID, "yield");
- return nullptr;
- }
- }
+template <typename ParseHandler>
+PropertyName*
+Parser<ParseHandler>::labelOrIdentifierReference(YieldHandling yieldHandling)
+{
+ // ES 2017 draft 12.1.1.
+ // StringValue of IdentifierName normalizes any Unicode escape sequences
+ // in IdentifierName hence such escapes cannot be used to write an
+ // Identifier whose code point sequence is the same as a ReservedWord.
+ //
+ // Use PropertyName* instead of TokenKind to reflect the normalization.
+ RootedPropertyName ident(context, tokenStream.currentName());
+ if (!checkLabelOrIdentifierReference(ident, pos().begin, yieldHandling))
+ return nullptr;
+ return ident;
+}
+
+template <typename ParseHandler>
+PropertyName*
+Parser<ParseHandler>::bindingIdentifier(YieldHandling yieldHandling)
+{
+ RootedPropertyName ident(context, tokenStream.currentName());
+ if (!checkBindingIdentifier(ident, pos().begin, yieldHandling))
+ return nullptr;
return ident;
}
@@ -8653,7 +9239,7 @@ Parser<ParseHandler>::identifierReference(Handle<PropertyName*> name)
if (!pn)
return null();
- if (!pc->inDestructuringDecl && !noteUsedName(name))
+ if (!noteUsedName(name))
return null();
return pn;
@@ -8668,8 +9254,23 @@ Parser<ParseHandler>::stringLiteral()
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::noSubstitutionTemplate()
+Parser<ParseHandler>::noSubstitutionTaggedTemplate()
+{
+ if (tokenStream.hasInvalidTemplateEscape()) {
+ tokenStream.clearInvalidTemplateEscape();
+ return handler.newRawUndefinedLiteral(pos());
+ }
+
+ return handler.newTemplateStringLiteral(stopStringCompression(), pos());
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::noSubstitutionUntaggedTemplate()
{
+ if (!tokenStream.checkForInvalidTemplateEscapeError())
+ return null();
+
return handler.newTemplateStringLiteral(stopStringCompression(), pos());
}
@@ -8705,6 +9306,74 @@ Parser<ParseHandler>::newRegExp()
}
template <typename ParseHandler>
+void
+Parser<ParseHandler>::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
+ PossibleError* possibleError)
+{
+ // Return early if a pending destructuring error is already present.
+ if (possibleError->hasPendingDestructuringError())
+ return;
+
+ if (pc->sc()->needStrictChecks()) {
+ if (handler.isArgumentsAnyParentheses(expr, context)) {
+ if (pc->sc()->strict()) {
+ possibleError->setPendingDestructuringErrorAt(exprPos,
+ JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
+ } else {
+ possibleError->setPendingDestructuringWarningAt(exprPos,
+ JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
+ }
+ return;
+ }
+
+ if (handler.isEvalAnyParentheses(expr, context)) {
+ if (pc->sc()->strict()) {
+ possibleError->setPendingDestructuringErrorAt(exprPos,
+ JSMSG_BAD_STRICT_ASSIGN_EVAL);
+ } else {
+ possibleError->setPendingDestructuringWarningAt(exprPos,
+ JSMSG_BAD_STRICT_ASSIGN_EVAL);
+ }
+ return;
+ }
+ }
+
+ // The expression must be either a simple assignment target, i.e. a name
+ // or a property accessor, or a nested destructuring pattern.
+ if (!handler.isUnparenthesizedDestructuringPattern(expr) &&
+ !handler.isNameAnyParentheses(expr) &&
+ !handler.isPropertyAccess(expr))
+ {
+ // Parentheses are forbidden around destructuring *patterns* (but
+ // allowed around names). Use our nicer error message for
+ // parenthesized, nested patterns.
+ if (handler.isParenthesizedDestructuringPattern(expr))
+ possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_PARENS);
+ else
+ possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
+ }
+}
+
+template <typename ParseHandler>
+void
+Parser<ParseHandler>::checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
+ PossibleError* possibleError)
+{
+ // ES2018 draft rev 0719f44aab93215ed9a626b2f45bd34f36916834
+ // 12.15.5 Destructuring Assignment
+ //
+ // AssignmentElement[Yield, Await]:
+ // DestructuringAssignmentTarget[?Yield, ?Await]
+ // DestructuringAssignmentTarget[?Yield, ?Await] Initializer[+In, ?Yield, ?Await]
+
+ // If |expr| is an assignment element with an initializer expression, its
+ // destructuring assignment target was already validated in assignExpr().
+ // Otherwise we need to check that |expr| is a valid destructuring target.
+ if (!handler.isUnparenthesizedAssignment(expr))
+ checkDestructuringAssignmentTarget(expr, exprPos, possibleError);
+}
+
+template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError)
{
@@ -8753,17 +9422,29 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro
} else if (tt == TOK_TRIPLEDOT) {
tokenStream.consumeKnownToken(TOK_TRIPLEDOT, TokenStream::Operand);
uint32_t begin = pos().begin;
+
+ TokenPos innerPos;
+ if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand))
+ return null();
+
Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
possibleError);
if (!inner)
return null();
+ if (possibleError)
+ checkDestructuringAssignmentTarget(inner, innerPos, possibleError);
if (!handler.addSpreadElement(literal, begin, inner))
return null();
} else {
+ TokenPos elementPos;
+ if (!tokenStream.peekTokenPos(&elementPos, TokenStream::Operand))
+ return null();
Node element = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
possibleError);
if (!element)
return null();
+ if (possibleError)
+ checkDestructuringAssignmentElement(element, elementPos, possibleError);
if (foldConstants && !FoldConstants(context, &element, this))
return null();
handler.addArrayElement(literal, element);
@@ -8783,7 +9464,9 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro
}
}
- MUST_MATCH_TOKEN_MOD(TOK_RB, modifier, JSMSG_BRACKET_AFTER_LIST);
+ MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RB, modifier,
+ reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
+ JSMSG_BRACKET_OPENED, begin));
}
handler.setEndPosition(literal, pos().end);
return literal;
@@ -8799,11 +9482,12 @@ DoubleToAtom(ExclusiveContext* cx, double value)
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
+Parser<ParseHandler>::propertyName(YieldHandling yieldHandling,
+ const Maybe<DeclarationKind>& maybeDecl, Node propList,
PropertyType* propType, MutableHandleAtom propAtom)
{
TokenKind ltok;
- if (!tokenStream.getToken(&ltok, TokenStream::KeywordIsName))
+ if (!tokenStream.getToken(&ltok))
return null();
MOZ_ASSERT(ltok != TOK_RC, "caller should have handled TOK_RC");
@@ -8812,11 +9496,11 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
bool isAsync = false;
if (ltok == TOK_MUL) {
isGenerator = true;
- if (!tokenStream.getToken(&ltok, TokenStream::KeywordIsName))
+ if (!tokenStream.getToken(&ltok))
return null();
}
- if (ltok == TOK_NAME && tokenStream.currentName() == context->names().async) {
+ if (ltok == TOK_ASYNC) {
// AsyncMethod[Yield, Await]:
// async [no LineTerminator here] PropertyName[?Yield, ?Await] ...
//
@@ -8832,16 +9516,13 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
// ComputedPropertyName[Yield, Await]:
// [ ...
TokenKind tt = TOK_EOF;
- if (!tokenStream.peekTokenSameLine(&tt, TokenStream::KeywordIsName))
+ if (!tokenStream.getToken(&tt))
return null();
- if (tt == TOK_STRING || tt == TOK_NUMBER || tt == TOK_LB ||
- tt == TOK_NAME || tt == TOK_YIELD)
- {
+ if (tt != TOK_LP && tt != TOK_COLON && tt != TOK_RC && tt != TOK_ASSIGN) {
isAsync = true;
- tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName);
ltok = tt;
} else {
- tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName);
+ tokenStream.ungetToken();
}
}
@@ -8863,46 +9544,41 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
break;
case TOK_LB:
- propName = computedPropertyName(yieldHandling, propList);
+ propName = computedPropertyName(yieldHandling, maybeDecl, propList);
if (!propName)
return null();
break;
- case TOK_NAME: {
+ default: {
+ if (!TokenKindIsPossibleIdentifierName(ltok)) {
+ error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(ltok));
+ return null();
+ }
+
propAtom.set(tokenStream.currentName());
// Do not look for accessor syntax on generators
- if (isGenerator || isAsync ||
- !(propAtom.get() == context->names().get ||
- propAtom.get() == context->names().set))
- {
+ if (isGenerator || isAsync || !(ltok == TOK_GET || ltok == TOK_SET)) {
propName = handler.newObjectLiteralPropertyName(propAtom, pos());
if (!propName)
return null();
break;
}
- *propType = propAtom.get() == context->names().get ? PropertyType::Getter
- : PropertyType::Setter;
+ *propType = ltok == TOK_GET ? PropertyType::Getter : PropertyType::Setter;
// We have parsed |get| or |set|. Look for an accessor property
// name next.
TokenKind tt;
- if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName))
+ if (!tokenStream.peekToken(&tt))
return null();
- if (tt == TOK_NAME) {
- if (!checkUnescapedName())
- return null();
-
- tokenStream.consumeKnownToken(TOK_NAME, TokenStream::KeywordIsName);
+ if (TokenKindIsPossibleIdentifierName(tt)) {
+ tokenStream.consumeKnownToken(tt);
propAtom.set(tokenStream.currentName());
return handler.newObjectLiteralPropertyName(propAtom, pos());
}
if (tt == TOK_STRING) {
- if (!checkUnescapedName())
- return null();
-
- tokenStream.consumeKnownToken(TOK_STRING, TokenStream::KeywordIsName);
+ tokenStream.consumeKnownToken(TOK_STRING);
propAtom.set(tokenStream.currentToken().atom());
@@ -8916,10 +9592,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
return stringLiteral();
}
if (tt == TOK_NUMBER) {
- if (!checkUnescapedName())
- return null();
-
- tokenStream.consumeKnownToken(TOK_NUMBER, TokenStream::KeywordIsName);
+ tokenStream.consumeKnownToken(TOK_NUMBER);
propAtom.set(DoubleToAtom(context, tokenStream.currentToken().number()));
if (!propAtom.get())
@@ -8927,19 +9600,15 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
return newNumber(tokenStream.currentToken());
}
if (tt == TOK_LB) {
- if (!checkUnescapedName())
- return null();
+ tokenStream.consumeKnownToken(TOK_LB);
- tokenStream.consumeKnownToken(TOK_LB, TokenStream::KeywordIsName);
-
- return computedPropertyName(yieldHandling, propList);
+ return computedPropertyName(yieldHandling, maybeDecl, propList);
}
// Not an accessor property after all.
propName = handler.newObjectLiteralPropertyName(propAtom.get(), pos());
if (!propName)
return null();
- tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName);
break;
}
@@ -8957,10 +9626,6 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
return null();
break;
}
-
- default:
- error(JSMSG_BAD_PROP_ID);
- return null();
}
TokenKind tt;
@@ -8976,7 +9641,9 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
return propName;
}
- if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) {
+ if (TokenKindIsPossibleIdentifierName(ltok) &&
+ (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN))
+ {
if (isGenerator) {
error(JSMSG_BAD_PROP_ID);
return null();
@@ -9005,28 +9672,25 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::computedPropertyName(YieldHandling yieldHandling, Node literal)
+Parser<ParseHandler>::computedPropertyName(YieldHandling yieldHandling,
+ const Maybe<DeclarationKind>& maybeDecl,
+ Node literal)
{
uint32_t begin = pos().begin;
- Node assignNode;
- {
- // Turn off the inDestructuringDecl flag when parsing computed property
- // names. In short, when parsing 'let {[x + y]: z} = obj;', noteUsedName()
- // should be called on x and y, but not on z. See the comment on
- // Parser<>::checkDestructuringPattern() for details.
- AutoClearInDestructuringDecl autoClear(pc);
- assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
- if (!assignNode)
- return null();
+ if (maybeDecl) {
+ if (*maybeDecl == DeclarationKind::FormalParameter)
+ pc->functionBox()->hasParameterExprs = true;
+ } else {
+ handler.setListFlag(literal, PNX_NONCONST);
}
- MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR);
- Node propname = handler.newComputedName(assignNode, begin, pos().end);
- if (!propname)
+ Node assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
+ if (!assignNode)
return null();
- handler.setListFlag(literal, PNX_NONCONST);
- return propname;
+
+ MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR);
+ return handler.newComputedName(assignNode, begin, pos().end);
}
template <typename ParseHandler>
@@ -9035,200 +9699,219 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
+ uint32_t openedPos = pos().begin;
+
Node literal = handler.newObjectLiteral(pos().begin);
if (!literal)
return null();
bool seenPrototypeMutation = false;
bool seenCoverInitializedName = false;
+ Maybe<DeclarationKind> declKind = Nothing();
RootedAtom propAtom(context);
for (;;) {
TokenKind tt;
- if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName))
+ if (!tokenStream.peekToken(&tt))
return null();
if (tt == TOK_RC)
break;
- TokenPos namePos = pos();
-
- tokenStream.ungetToken();
-
- PropertyType propType;
- Node propName = propertyName(yieldHandling, literal, &propType, &propAtom);
- if (!propName)
- return null();
+ if (tt == TOK_TRIPLEDOT) {
+ // object spread
+ tokenStream.consumeKnownToken(TOK_TRIPLEDOT);
+ uint32_t begin = pos().begin;
- if (propType == PropertyType::Normal) {
- Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
- possibleError);
- if (!propExpr)
+ TokenPos innerPos;
+ if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand))
return null();
- handler.checkAndSetIsDirectRHSAnonFunction(propExpr);
-
- if (foldConstants && !FoldConstants(context, &propExpr, this))
+ Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
+ possibleError);
+ if (!inner)
+ return null();
+ if (possibleError)
+ checkDestructuringAssignmentTarget(inner, innerPos, possibleError);
+ if (!handler.addSpreadProperty(literal, begin, inner))
return null();
+ } else {
+ TokenPos namePos = tokenStream.nextToken().pos;
- if (propAtom == context->names().proto) {
- if (seenPrototypeMutation) {
- // Directly report the error when we're not in a
- // destructuring context.
- if (!possibleError) {
- errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY);
- return null();
- }
+ PropertyType propType;
+ Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
+ if (!propName)
- // Otherwise delay error reporting until we've determined
- // whether or not we're destructuring.
- possibleError->setPendingExpressionErrorAt(namePos,
- JSMSG_DUPLICATE_PROTO_PROPERTY);
- }
- seenPrototypeMutation = true;
+ return null();
- // Note: this occurs *only* if we observe TOK_COLON! Only
- // __proto__: v mutates [[Prototype]]. Getters, setters,
- // method/generator definitions, computed property name
- // versions of all of these, and shorthands do not.
- if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr))
+ if (propType == PropertyType::Normal) {
+ TokenPos exprPos;
+ if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand))
return null();
- } else {
- if (!handler.isConstant(propExpr))
- handler.setListFlag(literal, PNX_NONCONST);
- if (!handler.addPropertyDefinition(literal, propName, propExpr))
+ Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
+ possibleError);
+ if (!propExpr)
return null();
- }
- } else if (propType == PropertyType::Shorthand) {
- /*
- * Support, e.g., |var {x, y} = o| as destructuring shorthand
- * for |var {x: x, y: y} = o|, and |var o = {x, y}| as initializer
- * shorthand for |var o = {x: x, y: y}|.
- */
- TokenKind propToken = TOK_NAME;
- if (!tokenStream.checkForKeyword(propAtom, &propToken))
- return null();
- if (propToken != TOK_NAME && propToken != TOK_YIELD) {
- error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken));
- return null();
- }
+ handler.checkAndSetIsDirectRHSAnonFunction(propExpr);
- Rooted<PropertyName*> name(context,
- identifierReference(yieldHandling, propToken == TOK_YIELD));
- if (!name)
- return null();
+ if (possibleError)
+ checkDestructuringAssignmentElement(propExpr, exprPos, possibleError);
- Node nameExpr = identifierReference(name);
- if (!nameExpr)
- return null();
+ if (foldConstants && !FoldConstants(context, &propExpr, this))
+ return null();
- if (!handler.addShorthand(literal, propName, nameExpr))
- return null();
- } else if (propType == PropertyType::CoverInitializedName) {
- /*
- * Support, e.g., |var {x=1, y=2} = o| as destructuring shorthand
- * with default values, as per ES6 12.14.5
- */
- TokenKind propToken = TOK_NAME;
- if (!tokenStream.checkForKeyword(propAtom, &propToken))
- return null();
+ if (propAtom == context->names().proto) {
+ if (seenPrototypeMutation) {
+ // Directly report the error when we're not in a
+ // destructuring context.
+ if (!possibleError) {
+ errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY);
+ return null();
+ }
- if (propToken != TOK_NAME && propToken != TOK_YIELD) {
- error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken));
- return null();
- }
+ // Otherwise delay error reporting until we've
+ // determined whether or not we're destructuring.
+ possibleError->setPendingExpressionErrorAt(namePos,
+ JSMSG_DUPLICATE_PROTO_PROPERTY);
+ }
+ seenPrototypeMutation = true;
- Rooted<PropertyName*> name(context,
- identifierReference(yieldHandling, propToken == TOK_YIELD));
- if (!name)
- return null();
+ // Note: this occurs *only* if we observe TOK_COLON! Only
+ // __proto__: v mutates [[Prototype]]. Getters, setters,
+ // method/generator definitions, computed property name
+ // versions of all of these, and shorthands do not.
+ if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr))
+ return null();
+ } else {
+ if (!handler.isConstant(propExpr))
+ handler.setListFlag(literal, PNX_NONCONST);
- Node lhs = identifierReference(name);
- if (!lhs)
- return null();
+ if (!handler.addPropertyDefinition(literal, propName, propExpr))
+ return null();
+ }
+ } else if (propType == PropertyType::Shorthand) {
+ /*
+ * Support, e.g., |({x, y} = o)| as destructuring shorthand
+ * for |({x: x, y: y} = o)|, and |var o = {x, y}| as
+ * initializer shorthand for |var o = {x: x, y: y}|.
+ */
+ Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
+ if (!name)
+ return null();
- tokenStream.consumeKnownToken(TOK_ASSIGN);
+ Node nameExpr = identifierReference(name);
+ if (!nameExpr)
+ return null();
- if (!seenCoverInitializedName) {
- // "shorthand default" or "CoverInitializedName" syntax is only
- // valid in the case of destructuring.
- seenCoverInitializedName = true;
+ if (possibleError)
+ checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError);
- if (!possibleError) {
- // Destructuring defaults are definitely not allowed in this object literal,
- // because of something the caller knows about the preceding code.
- // For example, maybe the preceding token is an operator: `x + {y=z}`.
- error(JSMSG_COLON_AFTER_ID);
+ if (!handler.addShorthand(literal, propName, nameExpr))
return null();
+ } else if (propType == PropertyType::CoverInitializedName) {
+ /*
+ * Support, e.g., |({x=1, y=2} = o)| as destructuring
+ * shorthand with default values, as per ES6 12.14.5
+ */
+ Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
+ if (!name)
+ return null();
+
+ Node lhs = identifierReference(name);
+ if (!lhs)
+ return null();
+
+ tokenStream.consumeKnownToken(TOK_ASSIGN);
+
+ if (!seenCoverInitializedName) {
+ // "shorthand default" or "CoverInitializedName" syntax is
+ // only valid in the case of destructuring.
+ seenCoverInitializedName = true;
+
+ if (!possibleError) {
+ // Destructuring defaults are definitely not allowed
+ // in this object literal, because of something the
+ // caller knows about the preceding code. For example,
+ // maybe the preceding token is an operator:
+ // |x + {y=z}|.
+ error(JSMSG_COLON_AFTER_ID);
+ return null();
+ }
+
+ // Here we set a pending error so that later in the parse,
+ // once we've determined whether or not we're
+ // destructuring, the error can be reported or ignored
+ // appropriately.
+ possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID);
}
- // Here we set a pending error so that later in the parse, once we've
- // determined whether or not we're destructuring, the error can be
- // reported or ignored appropriately.
- possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID);
- }
+ if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
+ // |chars| is "arguments" or "eval" here.
+ if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
+ return null();
+ }
- Node rhs;
- {
- // Clearing `inDestructuringDecl` allows name use to be noted
- // in Parser::identifierReference. See bug 1255167.
- AutoClearInDestructuringDecl autoClear(pc);
- rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
+ Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (!rhs)
return null();
- }
- handler.checkAndSetIsDirectRHSAnonFunction(rhs);
+ handler.checkAndSetIsDirectRHSAnonFunction(rhs);
- Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP);
- if (!propExpr)
- return null();
-
- if (!handler.addPropertyDefinition(literal, propName, propExpr))
- return null();
+ Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP);
+ if (!propExpr)
+ return null();
- if (!abortIfSyntaxParser())
- return null();
- } else {
- RootedAtom funName(context);
- if (!tokenStream.isCurrentTokenType(TOK_RB)) {
- funName = propAtom;
+ if (!handler.addPropertyDefinition(literal, propName, propExpr))
+ return null();
+ } else {
+ RootedAtom funName(context);
+ if (!tokenStream.isCurrentTokenType(TOK_RB)) {
+ funName = propAtom;
- if (propType == PropertyType::Getter || propType == PropertyType::Setter) {
- funName = prefixAccessorName(propType, propAtom);
- if (!funName)
- return null();
+ if (propType == PropertyType::Getter || propType == PropertyType::Setter) {
+ funName = prefixAccessorName(propType, propAtom);
+ if (!funName)
+ return null();
+ }
}
- }
- Node fn = methodDefinition(namePos.begin, propType, funName);
- if (!fn)
- return null();
+ Node fn = methodDefinition(namePos.begin, propType, funName);
+ if (!fn)
+ return null();
- handler.checkAndSetIsDirectRHSAnonFunction(fn);
+ handler.checkAndSetIsDirectRHSAnonFunction(fn);
- JSOp op = JSOpFromPropertyType(propType);
- if (!handler.addObjectMethodDefinition(literal, propName, fn, op))
- return null();
+ JSOp op = JSOpFromPropertyType(propType);
+ if (!handler.addObjectMethodDefinition(literal, propName, fn, op))
+ return null();
+
+ if (possibleError) {
+ possibleError->setPendingDestructuringErrorAt(namePos,
+ JSMSG_BAD_DESTRUCT_TARGET);
+ }
+ }
}
- if (!tokenStream.getToken(&tt))
+ bool matched;
+ if (!tokenStream.matchToken(&matched, TOK_COMMA))
return null();
- if (tt == TOK_RC)
+ if (!matched)
break;
- if (tt != TOK_COMMA) {
- error(JSMSG_CURLY_AFTER_LIST);
- return null();
- }
+ if (tt == TOK_TRIPLEDOT && possibleError)
+ possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA);
}
+ MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None,
+ reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
+ JSMSG_CURLY_OPENED, openedPos));
+
handler.setEndPosition(literal, pos().end);
return literal;
}
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propType,
+Parser<ParseHandler>::methodDefinition(uint32_t toStringStart, PropertyType propType,
HandleAtom funName)
{
FunctionSyntaxKind kind;
@@ -9282,7 +9965,7 @@ Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propT
if (!pn)
return null();
- return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, funName,
+ return functionDefinition(toStringStart, pn, InAllowed, yieldHandling, funName,
kind, generatorKind, asyncKind);
}
@@ -9312,14 +9995,11 @@ Parser<ParseHandler>::tryNewTarget(Node &newTarget)
if (!tokenStream.getToken(&next))
return false;
- if (next != TOK_NAME || tokenStream.currentName() != context->names().target) {
+ if (next != TOK_TARGET) {
error(JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next));
return false;
}
- if (!checkUnescapedName())
- return false;
-
if (!pc->sc()->allowNewTarget()) {
errorAt(begin, JSMSG_BAD_NEWTARGET);
return false;
@@ -9389,7 +10069,6 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
if (!expr)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
- handler.setEndPosition(expr, pos().end);
return handler.parenthesize(expr);
}
@@ -9397,22 +10076,26 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
return templateLiteral(yieldHandling);
case TOK_NO_SUBS_TEMPLATE:
- return noSubstitutionTemplate();
+ return noSubstitutionUntaggedTemplate();
case TOK_STRING:
return stringLiteral();
- case TOK_YIELD:
- case TOK_NAME: {
- if (tokenStream.currentName() == context->names().async) {
+ default: {
+ if (!TokenKindIsPossibleIdentifier(tt)) {
+ error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
+ return null();
+ }
+
+ if (tt == TOK_ASYNC) {
TokenKind nextSameLine = TOK_EOF;
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
if (nextSameLine == TOK_FUNCTION) {
- uint32_t preludeStart = pos().begin;
+ uint32_t toStringStart = pos().begin;
tokenStream.consumeKnownToken(TOK_FUNCTION);
- return functionExpr(preludeStart, PredictUninvoked, AsyncFunction);
+ return functionExpr(toStringStart, PredictUninvoked, AsyncFunction);
}
}
@@ -9476,7 +10159,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
// the enclosing code is strict mode code, any of "let", "yield",
// or "arguments" should be prohibited. Argument-parsing code
// handles that.
- if (next != TOK_NAME && next != TOK_YIELD) {
+ if (!TokenKindIsPossibleIdentifier(next)) {
error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next));
return null();
}
@@ -9503,10 +10186,6 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
// Return an arbitrary expression node. See case TOK_RP above.
return handler.newNullLiteral(pos());
}
-
- default:
- error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
- return null();
}
}
@@ -9520,9 +10199,8 @@ Parser<ParseHandler>::exprInParens(InHandling inHandling, YieldHandling yieldHan
return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked);
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::warnOnceAboutExprClosure()
+ParserBase::warnOnceAboutExprClosure()
{
#ifndef RELEASE_OR_BETA
JSContext* cx = context->maybeJSContext();
@@ -9538,9 +10216,8 @@ Parser<ParseHandler>::warnOnceAboutExprClosure()
return true;
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::warnOnceAboutForEach()
+ParserBase::warnOnceAboutForEach()
{
JSContext* cx = context->maybeJSContext();
if (!cx)