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.cpp4247
1 files changed, 2427 insertions, 1820 deletions
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 623379f61..0c279591f 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -19,6 +19,10 @@
#include "frontend/Parser.h"
+#include "mozilla/Sprintf.h"
+
+#include <new>
+
#include "jsapi.h"
#include "jsatom.h"
#include "jscntxt.h"
@@ -60,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, errno) \
+// 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) { \
- report(ParseError, false, null(), errno); \
+ 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
@@ -104,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:
@@ -125,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
@@ -187,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;
}
@@ -330,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;
}
@@ -439,7 +461,8 @@ UsedNameTracker::rewind(RewindToken token)
}
FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead,
- JSFunction* fun, Directives directives, bool extraWarnings,
+ JSFunction* fun, uint32_t toStringStart,
+ Directives directives, bool extraWarnings,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
: ObjectBox(fun, traceListHead),
SharedContext(cx, Kind::ObjectBox, directives, extraWarnings),
@@ -452,6 +475,8 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
bufEnd(0),
startLine(1),
startColumn(0),
+ toStringStart(toStringStart),
+ toStringEnd(0),
length(0),
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
asyncKindBits_(AsyncKindAsBits(asyncKind)),
@@ -470,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
@@ -521,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)
@@ -566,68 +598,166 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
computeInWith(enclosingScope);
}
-template <typename ParseHandler>
+void
+ParserBase::error(unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+#ifdef DEBUG
+ bool result =
+#endif
+ tokenStream.reportCompileErrorNumberVA(nullptr, pos().begin, JSREPORT_ERROR,
+ errorNumber, args);
+ MOZ_ASSERT(!result, "reporting an error returned true?");
+ va_end(args);
+}
+
+void
+ParserBase::errorWithNotes(UniquePtr<JSErrorNotes> notes, unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+#ifdef DEBUG
+ bool result =
+#endif
+ 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);
+}
+
bool
-Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
- unsigned errorNumber, va_list args)
+ParserBase::warning(unsigned errorNumber, ...)
{
- bool result = false;
- switch (kind) {
- case ParseError:
- result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args);
- break;
- case ParseWarning:
- result =
- tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args);
- break;
- case ParseExtraWarning:
- result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args);
- break;
- case ParseStrictError:
- result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args);
- break;
- }
+ va_list args;
+ va_start(args, errorNumber);
+ bool result =
+ tokenStream.reportCompileErrorNumberVA(nullptr, pos().begin, JSREPORT_WARNING,
+ errorNumber, args);
+ va_end(args);
return result;
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...)
+ParserBase::warningAt(uint32_t offset, unsigned errorNumber, ...)
{
- uint32_t offset = (pn ? handler.getPosition(pn) : pos()).begin;
+ va_list args;
+ va_start(args, errorNumber);
+ bool result =
+ tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_WARNING,
+ errorNumber, args);
+ va_end(args);
+ return result;
+}
+bool
+ParserBase::extraWarning(unsigned errorNumber, ...)
+{
va_list args;
va_start(args, errorNumber);
- bool result = reportHelper(kind, strict, offset, errorNumber, args);
+ bool result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, pos().begin,
+ errorNumber, args);
va_end(args);
return result;
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
+ParserBase::extraWarningAt(uint32_t offset, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
- bool result = reportHelper(kind, strict, TokenStream::NoOffset, errorNumber, args);
+
+ bool result =
+ tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, args);
+
va_end(args);
return result;
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset,
- unsigned errorNumber, ...)
+ParserBase::strictModeError(unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+ bool res =
+ tokenStream.reportStrictModeErrorNumberVA(nullptr, pos().begin, pc->sc()->strict(),
+ errorNumber, args);
+ va_end(args);
+ return res;
+}
+
+bool
+ParserBase::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+ bool res =
+ tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, pc->sc()->strict(),
+ errorNumber, args);
+ va_end(args);
+ return res;
+}
+
+bool
+ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
- bool result = reportHelper(kind, strict, offset, errorNumber, args);
+ bool result = false;
+ uint32_t offset = TokenStream::NoOffset;
+ switch (kind) {
+ case ParseError:
+ result = tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR,
+ errorNumber, args);
+ break;
+ case ParseWarning:
+ result =
+ tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_WARNING,
+ errorNumber, args);
+ break;
+ case ParseExtraWarning:
+ result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset,
+ errorNumber, args);
+ break;
+ case ParseStrictError:
+ result = tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, strict,
+ errorNumber, args);
+ break;
+ }
va_end(args);
return result;
}
template <>
-bool
+inline bool
Parser<FullParseHandler>::abortIfSyntaxParser()
{
handler.disableSyntaxParser();
@@ -635,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),
@@ -666,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>
@@ -687,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>
@@ -736,7 +894,8 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj)
template <typename ParseHandler>
FunctionBox*
-Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheritedDirectives,
+Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart,
+ Directives inheritedDirectives,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB)
{
@@ -751,8 +910,9 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheri
* function.
*/
FunctionBox* funbox =
- alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, inheritedDirectives,
- options().extraWarningsOption, generatorKind, asyncKind);
+ alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, toStringStart,
+ inheritedDirectives, options().extraWarningsOption,
+ generatorKind, asyncKind);
if (!funbox) {
ReportOutOfMemory(context);
return nullptr;
@@ -820,8 +980,7 @@ Parser<ParseHandler>::parse()
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
if (tt != TOK_EOF) {
- report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
- "script", TokenKindToDesc(tt));
+ error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt));
return null();
}
if (foldConstants) {
@@ -832,56 +991,19 @@ Parser<ParseHandler>::parse()
return pn;
}
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::reportBadReturn(Node pn, ParseReportKind kind,
- unsigned errnum, unsigned anonerrnum)
-{
- JSAutoByteString name;
- if (JSAtom* atom = pc->functionBox()->function()->explicitName()) {
- if (!AtomToPrintableString(context, atom, &name))
- return false;
- } else {
- errnum = anonerrnum;
- }
- return report(kind, pc->sc()->strict(), pn, errnum, name.ptr());
-}
-
/*
* 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 reportWithOffset(ParseStrictError, pc->sc()->strict(), pos.begin,
- JSMSG_BAD_BINDING, bytes.ptr());
- }
-
- return true;
+ name != context->names().yield &&
+ !IsStrictReservedWord(name);
}
/*
@@ -908,14 +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;
- reportWithOffset(ParseError, false, 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
@@ -930,12 +1109,13 @@ Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKi
template <typename ParseHandler>
bool
Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName name,
+ uint32_t beginPos,
bool disallowDuplicateParams,
bool* duplicatedParam)
{
if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) {
if (disallowDuplicateParams) {
- report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+ error(JSMSG_BAD_DUP_ARGS);
return false;
}
@@ -947,17 +1127,14 @@ Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName
JSAutoByteString bytes;
if (!AtomToPrintableString(context, name, &bytes))
return false;
- if (!report(ParseStrictError, pc->sc()->strict(), null(),
- JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
- {
+ if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
return false;
- }
}
*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;
}
@@ -970,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;
}
@@ -1064,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));
@@ -1138,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;
}
@@ -1156,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
@@ -1187,11 +1396,11 @@ Parser<ParseHandler>::checkLexicalDeclarationDirectlyWithinBlock(ParseContext::S
if (!StatementKindIsBraced(stmt.kind()) &&
stmt.kind() != StatementKind::ForLoopLexicalHead)
{
- reportWithOffset(ParseError, false, pos.begin,
- stmt.kind() == StatementKind::Label
- ? JSMSG_LEXICAL_DECL_LABEL
- : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
- DeclarationKindString(kind));
+ errorAt(pos.begin,
+ stmt.kind() == StatementKind::Label
+ ? JSMSG_LEXICAL_DECL_LABEL
+ : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
+ DeclarationKindString(kind));
return false;
}
@@ -1208,36 +1417,52 @@ 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.
AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name);
if (p) {
- report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+ error(JSMSG_BAD_DUP_ARGS);
return false;
}
- if (!pc->functionScope().addDeclaredName(pc, p, name, kind))
+ if (!pc->functionScope().addDeclaredName(pc, p, name, kind, pos.begin))
return false;
break;
@@ -1247,7 +1472,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
// Functions in block have complex allowances in sloppy mode for being
// labelled that other lexical declarations do not have. Those checks
// are more complex than calling checkLexicalDeclarationDirectlyWithin-
- // Block and are done in checkFunctionDefinition.
+ // Block and are done inline in callers.
ParseContext::Scope* scope = pc->innermostScope();
if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
@@ -1260,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;
}
@@ -1268,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;
}
@@ -1281,7 +1506,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
// contain 'let'. (CatchParameter is the only lexical binding form
// without this restriction.)
if (name == context->names().let) {
- reportWithOffset(ParseError, false, pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET);
+ errorAt(pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET);
return false;
}
@@ -1308,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;
}
}
@@ -1325,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;
@@ -1440,8 +1665,7 @@ Parser<FullParseHandler>::checkStatementsEOF()
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
return false;
if (tt != TOK_EOF) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "expression", TokenKindToDesc(tt));
+ error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
return false;
}
return true;
@@ -1451,16 +1675,26 @@ template <typename Scope>
static typename Scope::Data*
NewEmptyBindingData(ExclusiveContext* cx, LifoAlloc& alloc, uint32_t numBindings)
{
+ using Data = typename Scope::Data;
size_t allocSize = Scope::sizeOfData(numBindings);
- typename Scope::Data* bindings = static_cast<typename Scope::Data*>(alloc.alloc(allocSize));
- if (!bindings) {
+ auto* bindings = alloc.allocInSize<Data>(allocSize, numBindings);
+ if (!bindings)
ReportOutOfMemory(cx);
- return nullptr;
- }
- PodZero(bindings);
return bindings;
}
+/**
+ * Copy-construct |BindingName|s from |bindings| into |cursor|, then return
+ * the location one past the newly-constructed |BindingName|s.
+ */
+static MOZ_MUST_USE BindingName*
+FreshlyInitializeBindings(BindingName* cursor, const Vector<BindingName>& bindings)
+{
+ for (const BindingName& binding : bindings)
+ new (cursor++) BindingName(binding);
+ return cursor;
+}
+
template <>
Maybe<GlobalScope::Data*>
Parser<FullParseHandler>::newGlobalScopeData(ParseContext::Scope& scope)
@@ -1505,22 +1739,20 @@ Parser<FullParseHandler>::newGlobalScopeData(ParseContext::Scope& scope)
return Nothing();
// The ordering here is important. See comments in GlobalScope.
- BindingName* start = bindings->names;
+ BindingName* start = bindings->trailingNames.start();
BindingName* cursor = start;
- PodCopy(cursor, funs.begin(), funs.length());
- cursor += funs.length();
+ cursor = FreshlyInitializeBindings(cursor, funs);
bindings->varStart = cursor - start;
- PodCopy(cursor, vars.begin(), vars.length());
- cursor += vars.length();
+ cursor = FreshlyInitializeBindings(cursor, vars);
bindings->letStart = cursor - start;
- PodCopy(cursor, lets.begin(), lets.length());
- cursor += lets.length();
+ cursor = FreshlyInitializeBindings(cursor, lets);
bindings->constStart = cursor - start;
- PodCopy(cursor, consts.begin(), consts.length());
+ cursor = FreshlyInitializeBindings(cursor, consts);
+
bindings->length = numBindings;
}
@@ -1572,22 +1804,20 @@ Parser<FullParseHandler>::newModuleScopeData(ParseContext::Scope& scope)
return Nothing();
// The ordering here is important. See comments in ModuleScope.
- BindingName* start = bindings->names;
+ BindingName* start = bindings->trailingNames.start();
BindingName* cursor = start;
- PodCopy(cursor, imports.begin(), imports.length());
- cursor += imports.length();
+ cursor = FreshlyInitializeBindings(cursor, imports);
bindings->varStart = cursor - start;
- PodCopy(cursor, vars.begin(), vars.length());
- cursor += vars.length();
+ cursor = FreshlyInitializeBindings(cursor, vars);
bindings->letStart = cursor - start;
- PodCopy(cursor, lets.begin(), lets.length());
- cursor += lets.length();
+ cursor = FreshlyInitializeBindings(cursor, lets);
bindings->constStart = cursor - start;
- PodCopy(cursor, consts.begin(), consts.length());
+ cursor = FreshlyInitializeBindings(cursor, consts);
+
bindings->length = numBindings;
}
@@ -1623,16 +1853,16 @@ Parser<FullParseHandler>::newEvalScopeData(ParseContext::Scope& scope)
if (!bindings)
return Nothing();
- BindingName* start = bindings->names;
+ BindingName* start = bindings->trailingNames.start();
BindingName* cursor = start;
// Keep track of what vars are functions. This is only used in BCE to omit
// superfluous DEFVARs.
- PodCopy(cursor, funs.begin(), funs.length());
- cursor += funs.length();
+ cursor = FreshlyInitializeBindings(cursor, funs);
bindings->varStart = cursor - start;
- PodCopy(cursor, vars.begin(), vars.length());
+ cursor = FreshlyInitializeBindings(cursor, vars);
+
bindings->length = numBindings;
}
@@ -1697,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;
@@ -1719,18 +1946,17 @@ Parser<FullParseHandler>::newFunctionScopeData(ParseContext::Scope& scope, bool
return Nothing();
// The ordering here is important. See comments in FunctionScope.
- BindingName* start = bindings->names;
+ BindingName* start = bindings->trailingNames.start();
BindingName* cursor = start;
- PodCopy(cursor, positionalFormals.begin(), positionalFormals.length());
- cursor += positionalFormals.length();
+ cursor = FreshlyInitializeBindings(cursor, positionalFormals);
bindings->nonPositionalFormalStart = cursor - start;
- PodCopy(cursor, formals.begin(), formals.length());
- cursor += formals.length();
+ cursor = FreshlyInitializeBindings(cursor, formals);
bindings->varStart = cursor - start;
- PodCopy(cursor, vars.begin(), vars.length());
+ cursor = FreshlyInitializeBindings(cursor, vars);
+
bindings->length = numBindings;
}
@@ -1760,10 +1986,11 @@ Parser<FullParseHandler>::newVarScopeData(ParseContext::Scope& scope)
return Nothing();
// The ordering here is important. See comments in FunctionScope.
- BindingName* start = bindings->names;
+ BindingName* start = bindings->trailingNames.start();
BindingName* cursor = start;
- PodCopy(cursor, vars.begin(), vars.length());
+ cursor = FreshlyInitializeBindings(cursor, vars);
+
bindings->length = numBindings;
}
@@ -1808,14 +2035,14 @@ Parser<FullParseHandler>::newLexicalScopeData(ParseContext::Scope& scope)
return Nothing();
// The ordering here is important. See comments in LexicalScope.
- BindingName* cursor = bindings->names;
+ BindingName* cursor = bindings->trailingNames.start();
BindingName* start = cursor;
- PodCopy(cursor, lets.begin(), lets.length());
- cursor += lets.length();
+ cursor = FreshlyInitializeBindings(cursor, lets);
bindings->constStart = cursor - start;
- PodCopy(cursor, consts.begin(), consts.length());
+ cursor = FreshlyInitializeBindings(cursor, consts);
+
bindings->length = numBindings;
}
@@ -1900,7 +2127,7 @@ Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc)
// script.
if (hasUsedName(context->names().arguments)) {
if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) {
- report(ParseError, false, nullptr, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
+ error(JSMSG_BAD_GENEXP_BODY, js_arguments_str);
return nullptr;
}
}
@@ -1986,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();
@@ -1998,7 +2225,7 @@ Parser<FullParseHandler>::moduleBody(ModuleSharedContext* modulesc)
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
if (tt != TOK_EOF) {
- report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt));
+ error(JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt));
return null();
}
@@ -2078,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();
}
@@ -2121,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();
@@ -2137,7 +2370,7 @@ Parser<ParseHandler>::finishFunctionScopes()
return false;
}
- if (funbox->function()->isNamedLambda()) {
+ if (funbox->function()->isNamedLambda() && !isStandaloneFunction) {
if (!propagateFreeNamesAndMarkClosedOverBindings(pc->namedLambdaScope()))
return false;
}
@@ -2147,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();
@@ -2170,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;
@@ -2182,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
@@ -2206,6 +2439,7 @@ Parser<SyntaxParseHandler>::finishFunction()
LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(),
pc->innerFunctionsForLazy, versionNumber(),
funbox->bufStart, funbox->bufEnd,
+ funbox->toStringStart,
funbox->startLine, funbox->startColumn);
if (!lazy)
return false;
@@ -2218,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())
@@ -2259,7 +2495,33 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
{
MOZ_ASSERT(checkOptionsCalled);
- Node fn = handler.newFunctionDefinition();
+ // Skip prelude.
+ TokenKind tt;
+ if (!tokenStream.getToken(&tt))
+ return null();
+ if (asyncKind == AsyncFunction) {
+ if (!tokenStream.getToken(&tt))
+ return null();
+ }
+ MOZ_ASSERT(tt == TOK_FUNCTION);
+
+ if (!tokenStream.getToken(&tt))
+ return null();
+ if (generatorKind == StarGenerator && asyncKind == SyncFunction) {
+ MOZ_ASSERT(tt == TOK_MUL);
+ if (!tokenStream.getToken(&tt))
+ return null();
+ }
+
+ // Skip function name, if present.
+ if (tt == TOK_NAME || tt == TOK_YIELD) {
+ MOZ_ASSERT(tokenStream.currentName() == fun->explicitName());
+ } else {
+ MOZ_ASSERT(fun->explicitName() == nullptr);
+ tokenStream.ungetToken();
+ }
+
+ Node fn = handler.newFunctionStatement();
if (!fn)
return null();
@@ -2268,8 +2530,8 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
return null();
fn->pn_body = argsbody;
- FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind,
- asyncKind, /* tryAnnexB = */ false);
+ FunctionBox* funbox = newFunctionBox(fn, fun, /* toStringStart = */ 0, inheritedDirectives,
+ generatorKind, asyncKind, /* tryAnnexB = */ false);
if (!funbox)
return null();
funbox->initStandaloneFunction(enclosingScope);
@@ -2280,19 +2542,17 @@ 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();
}
- TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
if (tt != TOK_EOF) {
- report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
- "function body", TokenKindToDesc(tt));
+ error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt));
return null();
}
@@ -2344,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) {
@@ -2561,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>
@@ -2687,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;
}
@@ -2697,8 +2980,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
if (!tokenStream.getToken(&tt, firstTokenModifier))
return false;
if (tt != TOK_LP) {
- report(ParseError, false, null(),
- kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL);
+ error(kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL);
return false;
}
@@ -2730,13 +3012,13 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
AtomVector& positionalFormals = pc->positionalFormalParameterNames();
if (IsGetterKind(kind)) {
- report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
+ error(JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
return false;
}
while (true) {
if (hasRest) {
- report(ParseError, false, null(), JSMSG_PARAMETER_AFTER_REST);
+ error(JSMSG_PARAMETER_AFTER_REST);
return false;
}
@@ -2744,19 +3026,18 @@ 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)) {
- report(ParseError, false, null(),
- JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
+ error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
}
disallowDuplicateParams = true;
if (duplicatedParam) {
// Has duplicated args before the rest parameter.
- report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+ error(JSMSG_BAD_DUP_ARGS);
return false;
}
@@ -2766,8 +3047,8 @@ 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) {
- report(ParseError, false, null(), JSMSG_NO_REST_NAME);
+ if (!TokenKindIsPossibleIdentifier(tt) && tt != TOK_LB && tt != TOK_LC) {
+ error(JSMSG_NO_REST_NAME);
return false;
}
}
@@ -2778,7 +3059,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
disallowDuplicateParams = true;
if (duplicatedParam) {
// Has duplicated args before the destructuring parameter.
- report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+ error(JSMSG_BAD_DUP_ARGS);
return false;
}
@@ -2796,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
- report(ParseError, false, null(), 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;
}
@@ -2824,14 +3100,10 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
break;
}
-
- default:
- report(ParseError, false, null(), JSMSG_MISSING_FORMAL);
- return false;
}
if (positionalFormals.length() >= ARGNO_LIMIT) {
- report(ParseError, false, null(), JSMSG_TOO_MANY_FUN_ARGS);
+ error(JSMSG_TOO_MANY_FUN_ARGS);
return false;
}
@@ -2846,12 +3118,12 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
MOZ_ASSERT(!parenFreeArrow);
if (hasRest) {
- report(ParseError, false, null(), JSMSG_REST_WITH_DEFAULT);
+ error(JSMSG_REST_WITH_DEFAULT);
return false;
}
disallowDuplicateParams = true;
if (duplicatedParam) {
- report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+ error(JSMSG_BAD_DUP_ARGS);
return false;
}
@@ -2895,12 +3167,11 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
return false;
if (tt != TOK_RP) {
if (IsSetterKind(kind)) {
- report(ParseError, false, null(),
- JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
+ error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
}
- report(ParseError, false, null(), JSMSG_PAREN_AFTER_FORMAL);
+ error(JSMSG_PAREN_AFTER_FORMAL);
return false;
}
}
@@ -2913,78 +3184,17 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
funbox->function()->setArgCount(positionalFormals.length());
} else if (IsSetterKind(kind)) {
- report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
+ error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
}
return true;
}
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind,
- GeneratorKind generatorKind, bool* tryAnnexB)
-{
- if (kind == Statement) {
- TokenPos pos = handler.getPosition(pn);
- RootedPropertyName funName(context, funAtom->asPropertyName());
-
- // In sloppy mode, Annex B.3.2 allows labelled function
- // declarations. Otherwise it is a parse error.
- ParseContext::Statement* declaredInStmt = pc->innermostStatement();
- if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
- MOZ_ASSERT(!pc->sc()->strict(),
- "labeled functions shouldn't be parsed in strict mode");
-
- // Find the innermost non-label statement. Report an error if it's
- // unbraced: functions can't appear in it. Otherwise the statement
- // (or its absence) determines the scope the function's bound in.
- while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label)
- declaredInStmt = declaredInStmt->enclosing();
-
- if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) {
- reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL);
- return false;
- }
- }
-
- if (declaredInStmt) {
- MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
- MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
-
- if (!pc->sc()->strict() && generatorKind == NotGenerator) {
- // Under sloppy mode, try Annex B.3.3 semantics. If making an
- // additional 'var' binding of the same name does not throw an
- // 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(funName, tryAnnexB))
- return false;
- }
-
- if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos))
- return false;
- } else {
- if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos))
- return false;
-
- // Body-level functions in modules are always closed over.
- if (pc->atModuleLevel())
- pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver();
- }
- } else {
- // A function expression does not introduce any binding.
- handler.setOp(pn, kind == Arrow ? JSOP_LAMBDA_ARROW : JSOP_LAMBDA);
- }
-
- return true;
-}
-
template <>
bool
-Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKind kind,
- bool tryAnnexB)
+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)
// that function, not any of its nested children. The initial syntax-only
@@ -2993,7 +3203,7 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin
RootedFunction fun(context, handler.nextLazyInnerFunction());
MOZ_ASSERT(!fun->isLegacyGenerator());
- FunctionBox* funbox = newFunctionBox(pn, fun, Directives(/* strict = */ false),
+ FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, Directives(/* strict = */ false),
fun->generatorKind(), fun->asyncKind(), tryAnnexB);
if (!funbox)
return false;
@@ -3001,6 +3211,8 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin
LazyScript* lazy = fun->lazyScript();
if (lazy->needsHomeObject())
funbox->setNeedsHomeObject();
+ if (lazy->isExprBody())
+ funbox->setIsExprBody();
PropagateTransitiveParseFlags(lazy, pc->sc());
@@ -3013,18 +3225,23 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin
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, FunctionSyntaxKind kind,
- bool tryAnnexB)
+Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t toStringStart,
+ FunctionSyntaxKind kind, bool tryAnnexB)
{
MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
}
@@ -3043,7 +3260,7 @@ Parser<ParseHandler>::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling
if (!tokenStream.getToken(&tt))
return false;
if (tt != TOK_RC) {
- report(ParseError, false, null(), JSMSG_TEMPLSTR_UNTERM_EXPR);
+ error(JSMSG_TEMPLSTR_UNTERM_EXPR);
return false;
}
@@ -3076,7 +3293,7 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
{
- Node pn = noSubstitutionTemplate();
+ Node pn = noSubstitutionUntaggedTemplate();
if (!pn)
return null();
@@ -3089,7 +3306,7 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt))
return null();
- pn = noSubstitutionTemplate();
+ pn = noSubstitutionUntaggedTemplate();
if (!pn)
return null();
@@ -3100,31 +3317,20 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yieldHandling,
+Parser<ParseHandler>::functionDefinition(uint32_t toStringStart, Node pn, InHandling inHandling,
+ YieldHandling yieldHandling,
HandleAtom funName, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
- InvokedPrediction invoked)
+ bool tryAnnexB /* = false */)
{
MOZ_ASSERT_IF(kind == Statement, funName);
MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator);
- Node pn = handler.newFunctionDefinition();
- if (!pn)
- return null();
-
- if (invoked)
- pn = handler.setLikelyIIFE(pn);
-
- // Note the declared name and check for early errors.
- bool tryAnnexB = false;
- if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB))
- return null();
-
// When fully parsing a LazyScript, we do not fully reparse its inner
// functions, which are also lazy. Instead, their free variables and
// source extents are recorded and may be skipped.
if (handler.canSkipLazyInnerFunctions()) {
- if (!skipLazyInnerFunction(pn, kind, tryAnnexB))
+ if (!skipLazyInnerFunction(pn, toStringStart, kind, tryAnnexB))
return null();
return pn;
}
@@ -3157,8 +3363,9 @@ Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yi
// reparse a function due to failed syntax parsing and encountering new
// "use foo" directives.
while (true) {
- if (trySyntaxParseInnerFunction(pn, fun, inHandling, yieldHandling, kind, generatorKind,
- asyncKind, tryAnnexB, directives, &newDirectives))
+ if (trySyntaxParseInnerFunction(pn, fun, toStringStart, inHandling, yieldHandling, kind,
+ generatorKind, asyncKind, tryAnnexB, directives,
+ &newDirectives))
{
break;
}
@@ -3185,6 +3392,7 @@ Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yi
template <>
bool
Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun,
+ uint32_t toStringStart,
InHandling inHandling,
YieldHandling yieldHandling,
FunctionSyntaxKind kind,
@@ -3218,14 +3426,15 @@ 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, inheritedDirectives, generatorKind,
- asyncKind, tryAnnexB);
+ 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, inHandling,
- yieldHandling, kind, inheritedDirectives, newDirectives))
+ if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, toStringStart,
+ inHandling, yieldHandling, kind,
+ inheritedDirectives, newDirectives))
{
if (parser->hadAbortedSyntaxParse()) {
// Try again with a full parse. UsedNameTracker needs to be
@@ -3251,13 +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, inHandling, yieldHandling, kind, generatorKind, asyncKind,
- tryAnnexB, inheritedDirectives, newDirectives);
+ 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 toStringStart,
InHandling inHandling,
YieldHandling yieldHandling,
FunctionSyntaxKind kind,
@@ -3268,13 +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, inHandling, yieldHandling, kind, generatorKind, asyncKind,
- tryAnnexB, inheritedDirectives, newDirectives);
+ 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 toStringStart,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, Directives inheritedDirectives,
Directives* newDirectives)
@@ -3298,6 +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 toStringStart,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
@@ -3309,21 +3521,21 @@ 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, inheritedDirectives, generatorKind,
- asyncKind, tryAnnexB);
+ FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, inheritedDirectives,
+ generatorKind, asyncKind, tryAnnexB);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(outerpc, kind);
- return innerFunction(pn, outerpc, funbox, inHandling, yieldHandling, kind, inheritedDirectives,
- newDirectives);
+ return innerFunction(pn, outerpc, funbox, toStringStart, inHandling, yieldHandling, kind,
+ inheritedDirectives, newDirectives);
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::appendToCallSiteObj(Node callSiteObj)
{
- Node cookedNode = noSubstitutionTemplate();
+ Node cookedNode = noSubstitutionTaggedTemplate();
if (!cookedNode)
return false;
@@ -3346,13 +3558,13 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
{
MOZ_ASSERT(checkOptionsCalled);
- Node pn = handler.newFunctionDefinition();
+ Node pn = handler.newFunctionStatement();
if (!pn)
return null();
Directives directives(strict);
- FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind,
- /* tryAnnexB = */ false);
+ FunctionBox* funbox = newFunctionBox(pn, fun, /* toStringStart = */ 0, directives,
+ generatorKind, asyncKind, /* tryAnnexB = */ false);
if (!funbox)
return null();
funbox->initFromLazyFunction();
@@ -3401,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
@@ -3410,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) {
@@ -3428,7 +3646,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
if (!tokenStream.matchToken(&matched, TOK_ARROW))
return false;
if (!matched) {
- report(ParseError, false, null(), JSMSG_BAD_ARROW_ARGS);
+ error(JSMSG_BAD_ARROW_ARGS);
return false;
}
}
@@ -3436,7 +3654,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
// When parsing something for new Function() we have to make sure to
// only treat a certain part of the source as a parameter list.
if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_PARAMLIST_END);
+ error(JSMSG_UNEXPECTED_PARAMLIST_END);
return false;
}
@@ -3445,30 +3663,30 @@ 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 ||
IsConstructorKind(kind)) {
- report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY);
+ error(JSMSG_CURLY_BEFORE_BODY);
return false;
}
if (kind != Arrow) {
#if JS_HAS_EXPR_CLOSURES
- addTelemetry(JSCompartment::DeprecatedExpressionClosure);
if (!warnOnceAboutExprClosure())
return false;
#else
- report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY);
+ error(JSMSG_CURLY_BEFORE_BODY);
return false;
#endif
}
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) {
- report(ParseError, false, null(), 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,35 +3758,38 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling,
- FunctionAsyncKind asyncKind)
+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();
+ if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
+ MOZ_ASSERT(!pc->sc()->strict(),
+ "labeled functions shouldn't be parsed in strict mode");
+
+ // Find the innermost non-label statement. Report an error if it's
+ // unbraced: functions can't appear in it. Otherwise the statement
+ // (or its absence) determines the scope the function's bound in.
+ while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label)
+ declaredInStmt = declaredInStmt->enclosing();
+
+ if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) {
+ error(JSMSG_SLOPPY_FUNCTION_LABEL);
+ return null();
}
}
- RootedPropertyName name(context);
- GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null();
+ GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
if (tt == TOK_MUL) {
if (asyncKind != SyncFunction) {
- report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
+ error(JSMSG_ASYNC_GENERATOR);
return null();
}
generatorKind = StarGenerator;
@@ -3558,7 +3797,8 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
return null();
}
- if (tt == TOK_NAME || tt == TOK_YIELD) {
+ RootedPropertyName name(context);
+ if (TokenKindIsPossibleIdentifier(tt)) {
name = bindingIdentifier(yieldHandling);
if (!name)
return null();
@@ -3567,34 +3807,53 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
tokenStream.ungetToken();
} else {
/* Unnamed function expressions are forbidden in statement context. */
- report(ParseError, false, null(), JSMSG_UNNAMED_FUNCTION_STMT);
+ error(JSMSG_UNNAMED_FUNCTION_STMT);
return null();
}
- YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
- Node fun = functionDefinition(InAllowed, newYieldHandling, name, Statement, generatorKind,
- asyncKind, PredictUninvoked);
- if (!fun)
- return null();
+ // Note the declared name and check for early errors.
+ bool tryAnnexB = false;
+ if (declaredInStmt) {
+ MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
+ MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
+
+ if (!pc->sc()->strict() && generatorKind == NotGenerator) {
+ // In sloppy mode, try Annex B.3.3 semantics. If making an
+ // additional 'var' binding of the same name does not throw an
+ // 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, pos().begin, &tryAnnexB))
+ return null();
+ }
- if (synthesizedStmtForAnnexB) {
- Node synthesizedStmtList = handler.newStatementList(handler.getPosition(fun));
- if (!synthesizedStmtList)
+ if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos()))
+ return null();
+ } else {
+ DeclarationKind kind = pc->atModuleLevel()
+ ? DeclarationKind::ModuleBodyLevelFunction
+ : DeclarationKind::BodyLevelFunction;
+ if (!noteDeclaredName(name, kind, pos()))
return null();
- handler.addStatementToList(synthesizedStmtList, fun);
- return finishLexicalScope(*synthesizedScopeForAnnexB, synthesizedStmtList);
}
- return fun;
+ Node pn = handler.newFunctionStatement();
+ if (!pn)
+ return null();
+
+ YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
+ return functionDefinition(toStringStart, pn, InAllowed, newYieldHandling,
+ name, Statement, generatorKind, asyncKind, tryAnnexB);
}
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind)
+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))
@@ -3602,7 +3861,7 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind
if (tt == TOK_MUL) {
if (asyncKind != SyncFunction) {
- report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
+ error(JSMSG_ASYNC_GENERATOR);
return null();
}
generatorKind = StarGenerator;
@@ -3613,7 +3872,7 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind
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();
@@ -3621,8 +3880,15 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind
tokenStream.ungetToken();
}
- return functionDefinition(InAllowed, yieldHandling, name, Expression, generatorKind,
- asyncKind, invoked);
+ Node pn = handler.newFunctionExpression();
+ if (!pn)
+ return null();
+
+ if (invoked)
+ pn = handler.setLikelyIIFE(pn);
+
+ return functionDefinition(toStringStart, pn, InAllowed, yieldHandling, name, Expression,
+ generatorKind, asyncKind);
}
/*
@@ -3643,17 +3909,6 @@ IsEscapeFreeStringLiteral(const TokenPos& pos, JSAtom* str)
return pos.begin + str->length() + 2 == pos.end;
}
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkUnescapedName()
-{
- if (!tokenStream.currentToken().nameContainsEscape())
- return true;
-
- report(ParseError, false, null(), JSMSG_ESCAPED_KEYWORD);
- return false;
-}
-
template <>
bool
Parser<SyntaxParseHandler>::asmJS(Node list)
@@ -3726,10 +3981,10 @@ Parser<FullParseHandler>::asmJS(Node list)
*/
template <typename ParseHandler>
bool
-Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
+Parser<ParseHandler>::maybeParseDirective(Node list, Node possibleDirective, bool* cont)
{
TokenPos directivePos;
- JSAtom* directive = handler.isStringExprStatement(pn, &directivePos);
+ JSAtom* directive = handler.isStringExprStatement(possibleDirective, &directivePos);
*cont = !!directive;
if (!*cont)
@@ -3746,7 +4001,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
// directive in the future. We don't want to interfere with people
// taking advantage of directive-prologue-enabled features that appear
// in other browsers first.
- handler.setPrologue(pn);
+ handler.setInDirectivePrologue(possibleDirective);
if (directive == context->names().useStrict) {
// Functions with non-simple parameter lists (destructuring,
@@ -3760,8 +4015,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
: funbox->hasParameterExprs
? "default"
: "rest";
- reportWithOffset(ParseError, false, directivePos.begin,
- JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind);
+ errorAt(directivePos.begin, JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind);
return false;
}
}
@@ -3774,7 +4028,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
// occur in the directive prologue -- octal escapes -- and
// complain now.
if (tokenStream.sawOctalEscape()) {
- report(ParseError, false, null(), JSMSG_DEPRECATED_OCTAL);
+ error(JSMSG_DEPRECATED_OCTAL);
return false;
}
pc->sc()->strictScript = true;
@@ -3782,7 +4036,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
} else if (directive == context->names().useAsm) {
if (pc->isFunctionBox())
return asmJS(list);
- return report(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL);
+ return warningAt(directivePos.begin, JSMSG_USE_ASM_DIRECTIVE_FAIL);
}
}
return true;
@@ -3814,10 +4068,8 @@ Parser<ParseHandler>::statementList(YieldHandling yieldHandling)
if (tt == TOK_EOF || tt == TOK_RC)
break;
if (afterReturn) {
- TokenPos pos(0, 0);
- if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
+ if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand))
return null();
- statementBegin = pos.begin;
}
Node next = statementListItem(yieldHandling, canHaveDirectives);
if (!next) {
@@ -3828,11 +4080,9 @@ Parser<ParseHandler>::statementList(YieldHandling yieldHandling)
if (!warnedAboutStatementsAfterReturn) {
if (afterReturn) {
if (!handler.isStatementPermittedAfterReturnStatement(next)) {
- if (!reportWithOffset(ParseWarning, false, statementBegin,
- JSMSG_STMT_AFTER_RETURN))
- {
+ if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN))
return null();
- }
+
warnedAboutStatementsAfterReturn = true;
}
} else if (handler.isReturnStatement(next)) {
@@ -3863,7 +4113,7 @@ Parser<ParseHandler>::condition(InHandling inHandling, YieldHandling yieldHandli
/* Check for (a = b) and warn about possible (a == b) mistype. */
if (handler.isUnparenthesizedAssignment(pn)) {
- if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
+ if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN))
return null();
}
return pn;
@@ -3877,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));
@@ -3900,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>
@@ -3920,7 +4179,8 @@ Parser<ParseHandler>::PossibleError::hasError(ErrorKind kind)
template <typename ParseHandler>
void
-Parser<ParseHandler>::PossibleError::setPending(ErrorKind kind, Node pn, unsigned errorNumber)
+Parser<ParseHandler>::PossibleError::setPending(ErrorKind kind, const TokenPos& pos,
+ unsigned errorNumber)
{
// Don't overwrite a previously recorded error.
if (hasError(kind))
@@ -3929,23 +4189,33 @@ Parser<ParseHandler>::PossibleError::setPending(ErrorKind kind, Node pn, unsigne
// If we report an error later, we'll do it from the position where we set
// the state to pending.
Error& err = error(kind);
- err.offset_ = (pn ? parser_.handler.getPosition(pn) : parser_.pos()).begin;
+ err.offset_ = pos.begin;
err.errorNumber_ = errorNumber;
err.state_ = ErrorState::Pending;
}
template <typename ParseHandler>
void
-Parser<ParseHandler>::PossibleError::setPendingDestructuringError(Node pn, unsigned errorNumber)
+Parser<ParseHandler>::PossibleError::setPendingDestructuringErrorAt(const TokenPos& pos,
+ unsigned errorNumber)
+{
+ setPending(ErrorKind::Destructuring, pos, errorNumber);
+}
+
+template <typename ParseHandler>
+void
+Parser<ParseHandler>::PossibleError::setPendingDestructuringWarningAt(const TokenPos& pos,
+ unsigned errorNumber)
{
- setPending(ErrorKind::Destructuring, pn, errorNumber);
+ setPending(ErrorKind::DestructuringWarning, pos, errorNumber);
}
template <typename ParseHandler>
void
-Parser<ParseHandler>::PossibleError::setPendingExpressionError(Node pn, unsigned errorNumber)
+Parser<ParseHandler>::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos,
+ unsigned errorNumber)
{
- setPending(ErrorKind::Expression, pn, errorNumber);
+ setPending(ErrorKind::Expression, pos, errorNumber);
}
template <typename ParseHandler>
@@ -3956,29 +4226,42 @@ Parser<ParseHandler>::PossibleError::checkForError(ErrorKind kind)
return true;
Error& err = error(kind);
- parser_.reportWithOffset(ParseError, false, err.offset_, err.errorNumber_);
+ parser_.errorAt(err.offset_, err.errorNumber_);
return false;
}
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);
@@ -4011,205 +4294,271 @@ Parser<ParseHandler>::PossibleError::transferErrorsTo(PossibleError* other)
}
template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkAssignmentToCall(Node target, unsigned msg)
+typename ParseHandler::Node
+Parser<ParseHandler>::bindingInitializer(Node lhs, DeclarationKind kind,
+ YieldHandling yieldHandling)
{
- MOZ_ASSERT(handler.isFunctionCall(target));
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN));
+
+ if (kind == DeclarationKind::FormalParameter)
+ pc->functionBox()->hasParameterExprs = true;
- // Assignment to function calls is forbidden in ES6. We're still somewhat
- // concerned about sites using this in dead code, so forbid it only in
- // strict mode code (or if the werror option has been set), and otherwise
- // warn.
- return report(ParseStrictError, pc->sc()->strict(), target, msg);
+ Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
+ if (!rhs)
+ return null();
+
+ handler.checkAndSetIsDirectRHSAnonFunction(rhs);
+
+ Node assign = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP);
+ if (!assign)
+ return null();
+
+ if (foldConstants && !FoldConstants(context, &assign, this))
+ return null();
+
+ return assign;
}
-template <>
-bool
-Parser<FullParseHandler>::checkDestructuringName(ParseNode* expr, Maybe<DeclarationKind> maybeDecl)
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::bindingIdentifier(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)) {
- report(ParseError, false, expr, JSMSG_BAD_DESTRUCT_PARENS);
- return false;
- }
+ RootedPropertyName name(context, bindingIdentifier(yieldHandling));
+ if (!name)
+ return null();
- // 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)) {
- report(ParseError, false, expr, JSMSG_NO_VARIABLE_NAME);
- return false;
- }
+ Node binding = newName(name);
+ if (!binding || !noteDeclaredName(name, kind, pos()))
+ return null();
- RootedPropertyName name(context, expr->name());
- return noteDeclaredName(name, *maybeDecl, handler.getPosition(expr));
- }
+ return binding;
+}
- // Otherwise this is an expression in destructuring outside a declaration.
- if (!reportIfNotValidSimpleAssignmentTarget(expr, KeyedDestructuringAssignment))
- 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);
- MOZ_ASSERT(!handler.isFunctionCall(expr),
- "function calls shouldn't be considered valid targets in "
- "destructuring patterns");
+ if (tt == TOK_LC)
+ return objectBindingPattern(kind, yieldHandling);
- if (handler.isNameAnyParentheses(expr)) {
- // The arguments/eval identifiers are simple in non-strict mode code.
- // Warn to discourage their use nonetheless.
- return reportIfArgumentsEvalTarget(expr);
+ if (!TokenKindIsPossibleIdentifierName(tt)) {
+ error(JSMSG_NO_VARIABLE_NAME);
+ return null();
}
- // Nothing further to do for property accesses.
- MOZ_ASSERT(handler.isPropertyAccess(expr));
- return true;
+ return bindingIdentifier(kind, yieldHandling);
}
-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>::objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling)
{
- MOZ_ASSERT(objectPattern->isKind(PNK_OBJECT));
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
- 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);
+ JS_CHECK_RECURSION(context, return null());
- target = member->pn_right;
- }
- if (handler.isUnparenthesizedAssignment(target))
- target = target->pn_left;
+ uint32_t begin = pos().begin;
+ Node literal = handler.newObjectLiteral(begin);
+ if (!literal)
+ return null();
- if (handler.isUnparenthesizedDestructuringPattern(target)) {
- if (!checkDestructuringPattern(target, maybeDecl))
- return false;
+ 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 {
- if (!checkDestructuringName(target, maybeDecl))
- return false;
- }
- }
+ TokenPos namePos = tokenStream.nextToken().pos;
- return true;
-}
+ 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|.
-template <>
-bool
-Parser<FullParseHandler>::checkDestructuringArray(ParseNode* arrayPattern,
- Maybe<DeclarationKind> maybeDecl)
-{
- MOZ_ASSERT(arrayPattern->isKind(PNK_ARRAY));
+ if (!tokenStream.getToken(&tt, TokenStream::Operand))
+ return null();
- for (ParseNode* element = arrayPattern->pn_head; element; element = element->pn_next) {
- if (element->isKind(PNK_ELISION))
- continue;
+ 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();
- ParseNode* target;
- if (element->isKind(PNK_SPREAD)) {
- if (element->pn_next) {
- report(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST);
- return false;
}
- target = element->pn_kid;
- } else if (handler.isUnparenthesizedAssignment(element)) {
- target = element->pn_left;
- } else {
- target = element;
}
- 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)) {
- report(ParseError, false, pattern, 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>
@@ -4220,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>
@@ -4245,11 +4585,11 @@ Parser<ParseHandler>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKin
Node res = destructuringDeclaration(kind, yieldHandling, tt);
if (res) {
if (pc->lastYieldOffset != startYieldOffset) {
- reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT);
+ errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT);
return null();
}
if (pc->lastAwaitOffset != startAwaitOffset) {
- reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
+ errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
return null();
}
}
@@ -4261,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);
@@ -4271,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);
}
@@ -4327,14 +4670,7 @@ Parser<ParseHandler>::declarationPattern(Node decl, DeclarationKind declKind, To
}
}
- TokenKind token;
- if (!tokenStream.getToken(&token, TokenStream::None))
- return null();
-
- if (token != TOK_ASSIGN) {
- report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_DECL);
- return null();
- }
+ MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
Node init = assignExpr(forHeadKind ? InProhibited : InAllowed,
yieldHandling, TripledotProhibited);
@@ -4349,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);
}
@@ -4367,6 +4709,10 @@ Parser<ParseHandler>::initializerInNameDeclaration(Node decl, Node binding,
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN));
+ uint32_t initializerOffset;
+ if (!tokenStream.peekOffset(&initializerOffset, TokenStream::Operand))
+ return false;
+
Node initializer = assignExpr(forHeadKind ? InProhibited : InAllowed,
yieldHandling, TripledotProhibited);
if (!initializer)
@@ -4384,7 +4730,7 @@ Parser<ParseHandler>::initializerInNameDeclaration(Node decl, Node binding,
//
// for (var/let/const x = ... of ...); // BAD
if (isForOf) {
- report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE);
+ errorAt(initializerOffset, JSMSG_OF_AFTER_FOR_LOOP_DECL);
return false;
}
@@ -4393,18 +4739,15 @@ Parser<ParseHandler>::initializerInNameDeclaration(Node decl, Node binding,
//
// for (let/const x = ... in ...); // BAD
if (DeclarationKindIsLexical(declKind)) {
- report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE);
+ errorAt(initializerOffset, JSMSG_IN_AFTER_LEXICAL_FOR_DECL);
return false;
}
// This leaves only initialized for-in |var| declarations. ES6
// forbids these; later ES un-forbids in non-strict mode code.
*forHeadKind = PNK_FORIN;
- if (!report(ParseStrictError, pc->sc()->strict(), initializer,
- JSMSG_INVALID_FOR_IN_DECL_WITH_INIT))
- {
+ if (!strictModeErrorAt(initializerOffset, JSMSG_INVALID_FOR_IN_DECL_WITH_INIT))
return false;
- }
*forInOrOfExpression = expressionAfterForInOrOf(PNK_FORIN, yieldHandling);
if (!*forInOrOfExpression)
@@ -4448,8 +4791,9 @@ 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) {
- report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME);
+ // Anything other than possible identifier is an error.
+ if (!TokenKindIsPossibleIdentifier(tt)) {
+ error(JSMSG_NO_VARIABLE_NAME);
return null();
}
@@ -4509,7 +4853,7 @@ Parser<ParseHandler>::declarationName(Node decl, DeclarationKind declKind, Token
// Normal const declarations, and const declarations in for(;;)
// heads, must be initialized.
if (declKind == DeclarationKind::Const) {
- report(ParseError, false, binding, JSMSG_BAD_CONST_DECL);
+ errorAt(namePos.begin, JSMSG_BAD_CONST_DECL);
return null();
}
}
@@ -4589,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
@@ -4602,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;
@@ -4614,42 +4961,35 @@ 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) {
- report(ParseError, false, null(), JSMSG_NO_BINDING_NAME);
+ if (!TokenKindIsPossibleIdentifierName(afterAs)) {
+ error(JSMSG_NO_BINDING_NAME);
return false;
}
} else {
@@ -4658,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;
- report(ParseError, false, null(), JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr());
+ error(JSMSG_AS_AFTER_RESERVED_WORD, ReservedWordToCharZ(importName));
return false;
}
}
@@ -4686,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) {
- report(ParseError, false, null(), JSMSG_AS_AFTER_IMPORT_STAR);
- return false;
- }
+ MUST_MATCH_TOKEN(TOK_AS, JSMSG_AS_AFTER_IMPORT_STAR);
- if (!checkUnescapedName())
- return false;
-
- 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)
@@ -4744,21 +5074,13 @@ 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()
{
MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT);
if (!pc->atModuleLevel()) {
- report(ParseError, false, null(), JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
+ error(JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
return null();
}
@@ -4771,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
@@ -4807,7 +5136,7 @@ Parser<FullParseHandler>::importDeclaration()
return null();
if (tt != TOK_LC && tt != TOK_MUL) {
- report(ParseError, false, null(), JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT);
+ error(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT);
return null();
}
@@ -4815,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) {
- report(ParseError, false, null(), 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 {
- report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_IMPORT);
- return null();
}
Node moduleSpec = stringLiteral();
if (!moduleSpec)
return null();
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterNonExpression())
return null();
ParseNode* node =
@@ -4874,7 +5187,7 @@ Parser<FullParseHandler>::checkExportedName(JSAtom* exportName)
if (!AtomToPrintableString(context, exportName, &str))
return false;
- report(ParseError, false, null(), JSMSG_DUPLICATE_EXPORT_NAME, str.ptr());
+ error(JSMSG_DUPLICATE_EXPORT_NAME, str.ptr());
return false;
}
@@ -4911,290 +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()) {
- report(ParseError, false, null(), 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) {
- if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName))
- return null();
- if (tt != TOK_NAME) {
- report(ParseError, false, null(), JSMSG_NO_EXPORT_NAME);
- return null();
- }
- }
+ 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) {
- report(ParseError, false, null(), 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(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(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(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:
- report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_EXPORT);
+ return node;
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin)
+{
+ if (!abortIfSyntaxParser())
return null();
- }
- ParseNode* node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
- if (!node || !pc->sc()->asModuleContext()->builder.processExport(node))
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
+
+ Node kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired);
+ if (!kid)
+ return null();
+
+ if (!checkExportedNameForFunction(kid))
+ return null();
+
+ 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>
@@ -5206,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);
}
@@ -5219,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(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);
@@ -5254,7 +5873,7 @@ Parser<ParseHandler>::ifStatement(YieldHandling yieldHandling)
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
return null();
if (tt == TOK_SEMI) {
- if (!report(ParseExtraWarning, false, null(), JSMSG_EMPTY_CONSEQUENT))
+ if (!extraWarning(JSMSG_EMPTY_CONSEQUENT))
return null();
}
@@ -5341,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;
@@ -5355,37 +5970,6 @@ Parser<ParseHandler>::matchInOrOf(bool* isForInp, bool* isForOfp)
template <class ParseHandler>
bool
-Parser<ParseHandler>::validateForInOrOfLHSExpression(Node target, PossibleError* possibleError)
-{
- if (handler.isUnparenthesizedDestructuringPattern(target))
- return checkDestructuringPattern(target, Nothing(), possibleError);
-
- // All other permitted targets are simple.
- if (!reportIfNotValidSimpleAssignmentTarget(target, ForInOrOfTarget))
- return false;
-
- if (handler.isPropertyAccess(target))
- return true;
-
- if (handler.isNameAnyParentheses(target)) {
- // The arguments/eval identifiers are simple in non-strict mode code,
- // but warn to discourage use nonetheless.
- if (!reportIfArgumentsEvalTarget(target))
- return false;
-
- handler.adjustGetToSet(target);
- return true;
- }
-
- if (handler.isFunctionCall(target))
- return checkAssignmentToCall(target, JSMSG_BAD_FOR_LEFTSIDE);
-
- report(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE);
- return false;
-}
-
-template <class ParseHandler>
-bool
Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
ParseNodeKind* forHeadKind,
Node* forInitialPart,
@@ -5428,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))
@@ -5464,6 +6045,10 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
return *forInitialPart != null();
}
+ uint32_t exprOffset;
+ if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand))
+ return false;
+
// Finally, handle for-loops that start with expressions. Pass
// |InProhibited| so that |in| isn't parsed in a RelationalExpression as a
// binary operator. |in| makes it a for-in loop, *not* an |in| expression.
@@ -5501,14 +6086,35 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
//
// See ES6 13.7.
if (isForOf && letIsIdentifier) {
- report(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS);
+ errorAt(exprOffset, JSMSG_LET_STARTING_FOROF_LHS);
return false;
}
*forHeadKind = isForIn ? PNK_FORIN : PNK_FOROF;
- if (!validateForInOrOfLHSExpression(*forInitialPart, &possibleError))
+ // Verify the left-hand side expression doesn't have a forbidden form.
+ if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) {
+ if (!possibleError.checkForDestructuringErrorOrWarning())
+ return false;
+ } else if (handler.isNameAnyParentheses(*forInitialPart)) {
+ const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context);
+ if (chars) {
+ // |chars| is "arguments" or "eval" here.
+ if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars))
+ return false;
+ }
+
+ handler.adjustGetToSet(*forInitialPart);
+ } else if (handler.isPropertyAccess(*forInitialPart)) {
+ // Permitted: no additional testing/fixup needed.
+ } else if (handler.isFunctionCall(*forInitialPart)) {
+ if (!strictModeErrorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE))
+ return false;
+ } else {
+ errorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE);
return false;
+ }
+
if (!possibleError.checkForExpressionError())
return false;
@@ -5532,12 +6138,11 @@ 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;
isForEach = true;
- addTelemetry(JSCompartment::DeprecatedForEach);
if (!warnOnceAboutForEach())
return null();
}
@@ -5593,7 +6198,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
Node init = startNode;
if (isForEach) {
- reportWithOffset(ParseError, false, begin, JSMSG_BAD_FOR_EACH_LOOP);
+ errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP);
return null();
}
@@ -5653,19 +6258,13 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
iflags |= JSITER_ENUMERATE;
} else {
if (isForEach) {
- report(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP);
+ errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP);
return null();
}
stmt.refineForKind(StatementKind::ForOfLoop);
}
- if (!handler.isDeclarationList(target)) {
- MOZ_ASSERT(!forLoopLexicalScope);
- if (!checkAndMarkAsAssignmentLhs(target, PlainAssignment))
- return null();
- }
-
// Parser::declaration consumed everything up to the closing ')'. That
// token follows an {Assignment,}Expression, so the next token must be
// consumed as if an operator continued the expression, i.e. as None.
@@ -5729,7 +6328,7 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
switch (tt) {
case TOK_DEFAULT:
if (seenDefault) {
- report(ParseError, false, null(), JSMSG_TOO_MANY_DEFAULTS);
+ error(JSMSG_TOO_MANY_DEFAULTS);
return null();
}
seenDefault = true;
@@ -5743,7 +6342,7 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
break;
default:
- report(ParseError, false, null(), JSMSG_BAD_SWITCH);
+ error(JSMSG_BAD_SWITCH);
return null();
}
@@ -5762,10 +6361,8 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
if (tt == TOK_RC || tt == TOK_CASE || tt == TOK_DEFAULT)
break;
if (afterReturn) {
- TokenPos pos(0, 0);
- if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
+ if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand))
return null();
- statementBegin = pos.begin;
}
Node stmt = statementListItem(yieldHandling);
if (!stmt)
@@ -5773,11 +6370,9 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
if (!warnedAboutStatementsAfterReturn) {
if (afterReturn) {
if (!handler.isStatementPermittedAfterReturnStatement(stmt)) {
- if (!reportWithOffset(ParseWarning, false, statementBegin,
- JSMSG_STMT_AFTER_RETURN))
- {
+ if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN))
return null();
- }
+
warnedAboutStatementsAfterReturn = true;
}
} else if (handler.isReturnStatement(stmt)) {
@@ -5827,8 +6422,10 @@ Parser<ParseHandler>::continueStatement(YieldHandling yieldHandling)
for (;;) {
stmt = ParseContext::Statement::findNearest(stmt, isLoop);
if (!stmt) {
- report(ParseError, false, null(),
- foundLoop ? JSMSG_LABEL_NOT_FOUND : JSMSG_BAD_CONTINUE);
+ if (foundLoop)
+ error(JSMSG_LABEL_NOT_FOUND);
+ else
+ errorAt(begin, JSMSG_BAD_CONTINUE);
return null();
}
@@ -5848,11 +6445,11 @@ Parser<ParseHandler>::continueStatement(YieldHandling yieldHandling)
break;
}
} else if (!pc->findInnermostStatement(isLoop)) {
- report(ParseError, false, null(), JSMSG_BAD_CONTINUE);
+ error(JSMSG_BAD_CONTINUE);
return null();
}
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterNonExpression())
return null();
return handler.newContinueStatement(label, TokenPos(begin, pos().end));
@@ -5878,7 +6475,7 @@ Parser<ParseHandler>::breakStatement(YieldHandling yieldHandling)
};
if (!pc->findInnermostStatement<ParseContext::LabelStatement>(hasSameLabel)) {
- report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND);
+ error(JSMSG_LABEL_NOT_FOUND);
return null();
}
} else {
@@ -5887,12 +6484,12 @@ Parser<ParseHandler>::breakStatement(YieldHandling yieldHandling)
};
if (!pc->findInnermostStatement(isBreakTarget)) {
- report(ParseError, false, null(), JSMSG_TOUGH_BREAK);
+ errorAt(begin, JSMSG_TOUGH_BREAK);
return null();
}
}
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterNonExpression())
return null();
return handler.newBreakStatement(label, TokenPos(begin, pos().end));
@@ -5932,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();
}
@@ -5943,10 +6540,9 @@ Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
if (!pn)
return null();
+ /* Disallow "return v;" in legacy generators. */
if (pc->isLegacyGenerator() && exprNode) {
- /* Disallow "return v;" in legacy generators. */
- reportBadReturn(pn, ParseError, JSMSG_BAD_GENERATOR_RETURN,
- JSMSG_BAD_ANON_GENERATOR_RETURN);
+ errorAt(begin, JSMSG_BAD_GENERATOR_RETURN);
return null();
}
@@ -6037,13 +6633,12 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
return null();
if (!pc->isFunctionBox()) {
- report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
+ error(JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
return null();
}
if (pc->functionBox()->isArrow()) {
- reportWithOffset(ParseError, false, begin,
- JSMSG_YIELD_IN_ARROW, js_yield_str);
+ errorAt(begin, JSMSG_YIELD_IN_ARROW, js_yield_str);
return null();
}
@@ -6051,25 +6646,22 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
pc->functionBox()->function()->isGetter() ||
pc->functionBox()->function()->isSetter())
{
- reportWithOffset(ParseError, false, begin,
- JSMSG_YIELD_IN_METHOD, js_yield_str);
+ errorAt(begin, JSMSG_YIELD_IN_METHOD, js_yield_str);
return null();
}
if (pc->funHasReturnExpr
#if JS_HAS_EXPR_CLOSURES
- || pc->functionBox()->function()->isExprBody()
+ || pc->functionBox()->isExprBody()
#endif
)
{
/* As in Python (see PEP-255), disallow return v; in generators. */
- reportBadReturn(null(), ParseError, JSMSG_BAD_GENERATOR_RETURN,
- JSMSG_BAD_ANON_GENERATOR_RETURN);
+ errorAt(begin, JSMSG_BAD_GENERATOR_RETURN);
return null();
}
pc->functionBox()->setGeneratorKind(LegacyGenerator);
- addTelemetry(JSCompartment::DeprecatedLegacyGenerator);
MOZ_FALLTHROUGH;
@@ -6119,14 +6711,13 @@ Parser<ParseHandler>::withStatement(YieldHandling yieldHandling)
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_WITH));
uint32_t begin = pos().begin;
- // In most cases, we want the constructs forbidden in strict mode code to be
- // a subset of those that JSOPTION_EXTRA_WARNINGS warns about, and we should
- // use reportStrictModeError. However, 'with' is the sole instance of a
- // construct that is forbidden in strict mode code, but doesn't even merit a
- // warning under JSOPTION_EXTRA_WARNINGS. See
+ // Usually we want the constructs forbidden in strict mode code to be a
+ // subset of those that ContextOptions::extraWarnings() warns about, and we
+ // use strictModeError directly. But while 'with' is forbidden in strict
+ // mode code, it doesn't even merit a warning in non-strict code. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
if (pc->sc()->strict()) {
- if (!report(ParseStrictError, true, null(), JSMSG_STRICT_CODE_WITH))
+ if (!strictModeError(JSMSG_STRICT_CODE_WITH))
return null();
}
@@ -6165,7 +6756,7 @@ Parser<ParseHandler>::labeledItem(YieldHandling yieldHandling)
// GeneratorDeclaration is only matched by HoistableDeclaration in
// StatementListItem, so generators can't be inside labels.
if (next == TOK_MUL) {
- report(ParseError, false, null(), JSMSG_GENERATOR_LABEL);
+ error(JSMSG_GENERATOR_LABEL);
return null();
}
@@ -6173,11 +6764,11 @@ Parser<ParseHandler>::labeledItem(YieldHandling yieldHandling)
// is ever matched. Per Annex B.3.2 that modifies this text, this
// applies only to strict mode code.
if (pc->sc()->strict()) {
- report(ParseError, false, null(), JSMSG_FUNCTION_LABEL);
+ error(JSMSG_FUNCTION_LABEL);
return null();
}
- return functionStmt(yieldHandling, NameRequired);
+ return functionStmt(pos().begin, yieldHandling, NameRequired);
}
tokenStream.ungetToken();
@@ -6196,13 +6787,13 @@ Parser<ParseHandler>::labeledStatement(YieldHandling yieldHandling)
return stmt->label() == label;
};
+ uint32_t begin = pos().begin;
+
if (pc->findInnermostStatement<ParseContext::LabelStatement>(hasSameLabel)) {
- report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL);
+ errorAt(begin, JSMSG_DUPLICATE_LABEL);
return null();
}
- uint32_t begin = pos().begin;
-
tokenStream.consumeKnownToken(TOK_COLON);
/* Push a label struct and parse the statement. */
@@ -6226,11 +6817,11 @@ Parser<ParseHandler>::throwStatement(YieldHandling yieldHandling)
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
return null();
if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) {
- report(ParseError, false, null(), JSMSG_MISSING_EXPR_AFTER_THROW);
+ error(JSMSG_MISSING_EXPR_AFTER_THROW);
return null();
}
if (tt == TOK_EOL) {
- report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_THROW);
+ error(JSMSG_LINE_BREAK_AFTER_THROW);
return null();
}
@@ -6238,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));
@@ -6258,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.
@@ -6273,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))
@@ -6286,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;
@@ -6304,7 +6899,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
/* Check for another catch after unconditional catch. */
if (hasUnconditionalCatch) {
- report(ParseError, false, null(), JSMSG_CATCH_AFTER_GENERAL);
+ error(JSMSG_CATCH_AFTER_GENERAL);
return null();
}
@@ -6338,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:
- report(ParseError, false, null(), JSMSG_CATCH_IDENTIFIER);
- return null();
}
Node catchGuard = null();
@@ -6402,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))
@@ -6415,12 +7008,14 @@ 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();
}
if (!catchList && !finallyBlock) {
- report(ParseError, false, null(), JSMSG_CATCH_OR_FINALLY);
+ error(JSMSG_CATCH_OR_FINALLY);
return null();
}
@@ -6432,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
@@ -6451,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.
@@ -6465,7 +7064,7 @@ Parser<ParseHandler>::debuggerStatement()
{
TokenPos p;
p.begin = pos().begin;
- if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream))
+ if (!matchOrInsertSemicolonAfterNonExpression())
return null();
p.end = pos().end;
@@ -6497,49 +7096,6 @@ JSOpFromPropertyType(PropertyType propType)
}
}
-static FunctionSyntaxKind
-FunctionSyntaxKindFromPropertyType(PropertyType propType)
-{
- switch (propType) {
- case PropertyType::Getter:
- return Getter;
- case PropertyType::GetterNoExpressionClosure:
- return GetterNoExpressionClosure;
- case PropertyType::Setter:
- return Setter;
- case PropertyType::SetterNoExpressionClosure:
- return SetterNoExpressionClosure;
- case PropertyType::Method:
- case PropertyType::GeneratorMethod:
- case PropertyType::AsyncMethod:
- return Method;
- case PropertyType::Constructor:
- return ClassConstructor;
- case PropertyType::DerivedConstructor:
- return DerivedClassConstructor;
- default:
- MOZ_CRASH("unexpected property type");
- }
-}
-
-static GeneratorKind
-GeneratorKindFromPropertyType(PropertyType propType)
-{
- if (propType == PropertyType::GeneratorMethod)
- return StarGenerator;
- if (propType == PropertyType::AsyncMethod)
- return StarGenerator;
- return NotGenerator;
-}
-
-static FunctionAsyncKind
-AsyncKindFromPropertyType(PropertyType propType)
-{
- if (propType == PropertyType::AsyncMethod)
- return AsyncFunction;
- return SyncFunction;
-}
-
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
@@ -6548,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;
@@ -6555,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();
@@ -6565,7 +7122,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
tokenStream.ungetToken();
} else {
// Class statements must have a bound name
- report(ParseError, false, null(), JSMSG_UNNAMED_CLASS_STMT);
+ error(JSMSG_UNNAMED_CLASS_STMT);
return null();
}
} else {
@@ -6573,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();
}
@@ -6609,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;
@@ -6621,31 +7182,30 @@ 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);
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "property name", TokenKindToDesc(tt));
+ 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 {
tokenStream.ungetToken();
}
+ uint32_t nameOffset;
+ if (!tokenStream.peekOffset(&nameOffset))
+ return null();
+
PropertyType propType;
- Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom);
+ Node propName = propertyName(yieldHandling, declKind, classMethods, &propType, &propAtom);
if (!propName)
return null();
@@ -6654,7 +7214,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
propType != PropertyType::AsyncMethod &&
propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor)
{
- report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF);
+ errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
return null();
}
@@ -6662,19 +7222,20 @@ 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) {
- report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF);
+ errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
return null();
}
- if (seenConstructor) {
- report(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor");
+ 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) {
- report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF);
+ errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
return null();
}
@@ -6696,7 +7257,12 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!tokenStream.isCurrentTokenType(TOK_RB))
funName = propAtom;
}
- Node fn = methodDefinition(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();
@@ -6707,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) {
@@ -6718,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) {
@@ -6746,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;
@@ -6767,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;
@@ -6791,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;
}
@@ -6812,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;
}
@@ -6863,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) {
@@ -6882,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.
@@ -6893,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);
@@ -6901,8 +7471,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
}
if (forbiddenLetDeclaration) {
- report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT,
- "lexical declarations");
+ error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations");
return null();
}
}
@@ -6918,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);
@@ -6956,7 +7522,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
// detected this way, so don't bother passing around an extra parameter
// everywhere.
if (!pc->isFunctionBox()) {
- report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
+ error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
return null();
}
return returnStatement(yieldHandling);
@@ -6966,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:
@@ -6984,12 +7550,12 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
// statement of |if| or |else|, but Parser::consequentOrAlternative
// handles that).
case TOK_FUNCTION:
- report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
+ error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
return null();
// |class| is also forbidden by lookahead restriction.
case TOK_CLASS:
- report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "classes");
+ error(JSMSG_FORBIDDEN_AS_STATEMENT, "classes");
return null();
// ImportDeclaration (only inside modules)
@@ -7003,11 +7569,11 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
// Miscellaneous error cases arguably better caught here than elsewhere.
case TOK_CATCH:
- report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY);
+ error(JSMSG_CATCH_WITHOUT_TRY);
return null();
case TOK_FINALLY:
- report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY);
+ error(JSMSG_FINALLY_WITHOUT_TRY);
return null();
// NOTE: default case handled in the ExpressionStatement section.
@@ -7048,7 +7614,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) {
if (!abortIfSyntaxParser())
return null();
- if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL))
+ if (!warning(JSMSG_USE_ASM_DIRECTIVE_FAIL))
return null();
}
return expressionStatement(yieldHandling);
@@ -7072,25 +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 toStringStart = pos().begin;
tokenStream.consumeKnownToken(TOK_FUNCTION);
- return functionStmt(yieldHandling, NameRequired, AsyncFunction);
+ return functionStmt(toStringStart, yieldHandling, NameRequired, AsyncFunction);
}
}
@@ -7103,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);
@@ -7141,7 +7708,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
// detected this way, so don't bother passing around an extra parameter
// everywhere.
if (!pc->isFunctionBox()) {
- report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
+ error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
return null();
}
return returnStatement(yieldHandling);
@@ -7151,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:
@@ -7169,7 +7736,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
// HoistableDeclaration[?Yield, ~Default]
case TOK_FUNCTION:
- return functionStmt(yieldHandling, NameRequired);
+ return functionStmt(pos().begin, yieldHandling, NameRequired);
// ClassDeclaration[?Yield, ~Default]
case TOK_CLASS:
@@ -7180,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:
@@ -7193,11 +7760,11 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
// Miscellaneous error cases arguably better caught here than elsewhere.
case TOK_CATCH:
- report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY);
+ error(JSMSG_CATCH_WITHOUT_TRY);
return null();
case TOK_FINALLY:
- report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY);
+ error(JSMSG_FINALLY_WITHOUT_TRY);
return null();
// NOTE: default case handled in the ExpressionStatement section.
@@ -7242,8 +7809,7 @@ Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling,
if (!tokenStream.peekToken(&tt))
return null();
if (tt != TOK_ARROW) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "expression", TokenKindToDesc(TOK_RP));
+ error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP));
return null();
}
@@ -7400,7 +7966,7 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling
return null();
// Report an error for unary expressions on the LHS of **.
if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) {
- report(ParseError, false, null(), JSMSG_BAD_POW_LEFTSIDE);
+ error(JSMSG_BAD_POW_LEFTSIDE);
return null();
}
pnk = BinaryOpTokenKindToParseNodeKind(tok);
@@ -7471,65 +8037,6 @@ Parser<ParseHandler>::condExpr1(InHandling inHandling, YieldHandling yieldHandli
}
template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor flavor,
- PossibleError* possibleError)
-{
- MOZ_ASSERT(flavor != KeyedDestructuringAssignment,
- "destructuring must use special checking/marking code, not "
- "this method");
-
- if (handler.isUnparenthesizedDestructuringPattern(target)) {
- if (flavor == CompoundAssignment) {
- report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_ASS);
- return false;
- }
-
- return checkDestructuringPattern(target, Nothing(), possibleError);
- }
-
- // All other permitted targets are simple.
- if (!reportIfNotValidSimpleAssignmentTarget(target, flavor))
- return false;
-
- if (handler.isPropertyAccess(target))
- return true;
-
- if (handler.isNameAnyParentheses(target)) {
- // The arguments/eval identifiers are simple in non-strict mode code,
- // but warn to discourage use nonetheless.
- if (!reportIfArgumentsEvalTarget(target))
- return false;
-
- handler.adjustGetToSet(target);
- return true;
- }
-
- MOZ_ASSERT(handler.isFunctionCall(target));
- return checkAssignmentToCall(target, JSMSG_BAD_LEFTSIDE_OF_ASS);
-}
-
-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,
TripledotHandling tripledotHandling,
@@ -7553,8 +8060,13 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
+ 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();
@@ -7585,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;
}
@@ -7604,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));
@@ -7620,8 +8131,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (!tokenStream.getToken(&tt))
return null();
if (tt != TOK_ARROW) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "'=>' after argument list", TokenKindToDesc(tt));
+ error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt));
return null();
}
@@ -7659,7 +8169,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL);
if (next != TOK_ARROW) {
- report(ParseError, false, null(), JSMSG_LINE_BREAK_BEFORE_ARROW);
+ error(JSMSG_LINE_BREAK_BEFORE_ARROW);
return null();
}
tokenStream.consumeKnownToken(TOK_ARROW);
@@ -7672,32 +8182,34 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
tokenStream.seek(start);
- if (!tokenStream.peekToken(&next, TokenStream::Operand))
+ if (!tokenStream.getToken(&next, TokenStream::Operand))
return null();
+ 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;
}
}
- Node arrowFunc = functionDefinition(inHandling, yieldHandling, nullptr,
+ Node pn = handler.newArrowFunction();
+ if (!pn)
+ return null();
+
+ Node arrowFunc = functionDefinition(toStringStart, pn, inHandling, yieldHandling, nullptr,
Arrow, generatorKind, asyncKind);
if (!arrowFunc)
return null();
@@ -7747,19 +8259,42 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
return lhs;
}
- AssignmentFlavor flavor = kind == PNK_ASSIGN ? PlainAssignment : CompoundAssignment;
- if (!checkAndMarkAsAssignmentLhs(lhs, flavor, &possibleErrorInner))
+ // Verify the left-hand side expression doesn't have a forbidden form.
+ if (handler.isUnparenthesizedDestructuringPattern(lhs)) {
+ if (kind != PNK_ASSIGN) {
+ error(JSMSG_BAD_DESTRUCT_ASS);
+ return null();
+ }
+
+ 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(exprPos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
+ return null();
+ }
+
+ handler.adjustGetToSet(lhs);
+ } else if (handler.isPropertyAccess(lhs)) {
+ // Permitted: no additional testing/fixup needed.
+ } else if (handler.isFunctionCall(lhs)) {
+ if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS))
+ return null();
+
+ if (possibleError)
+ possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
+ } else {
+ 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);
@@ -7796,91 +8331,29 @@ Parser<ParseHandler>::isValidSimpleAssignmentTarget(Node node,
template <typename ParseHandler>
bool
-Parser<ParseHandler>::reportIfArgumentsEvalTarget(Node nameNode)
-{
- const char* chars = handler.nameIsArgumentsEvalAnyParentheses(nameNode, context);
- if (!chars)
- return true;
-
- if (!report(ParseStrictError, pc->sc()->strict(), nameNode, JSMSG_BAD_STRICT_ASSIGN, chars))
- return false;
-
- MOZ_ASSERT(!pc->sc()->strict(),
- "an error should have been reported if this was strict mode "
- "code");
- return true;
-}
-
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor)
+Parser<ParseHandler>::checkIncDecOperand(Node operand, uint32_t operandOffset)
{
- FunctionCallBehavior behavior = flavor == KeyedDestructuringAssignment
- ? ForbidAssignmentToFunctionCalls
- : PermitAssignmentToFunctionCalls;
- if (isValidSimpleAssignmentTarget(target, behavior))
- return true;
-
- if (handler.isNameAnyParentheses(target)) {
- // Use a special error if the target is arguments/eval. This ensures
- // targeting these names is consistently a SyntaxError (which error numbers
- // below don't guarantee) while giving us a nicer error message.
- if (!reportIfArgumentsEvalTarget(target))
+ if (handler.isNameAnyParentheses(operand)) {
+ if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(operand, context)) {
+ if (!strictModeErrorAt(operandOffset, JSMSG_BAD_STRICT_ASSIGN, chars))
+ return false;
+ }
+ } else if (handler.isPropertyAccess(operand)) {
+ // Permitted: no additional testing/fixup needed.
+ } else if (handler.isFunctionCall(operand)) {
+ // Assignment to function calls is forbidden in ES6. We're still
+ // somewhat concerned about sites using this in dead code, so forbid it
+ // only in strict mode code (or if the werror option has been set), and
+ // otherwise warn.
+ if (!strictModeErrorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND))
return false;
- }
-
- unsigned errnum = 0;
- const char* extra = nullptr;
-
- switch (flavor) {
- case IncrementAssignment:
- errnum = JSMSG_BAD_OPERAND;
- extra = "increment";
- break;
-
- case DecrementAssignment:
- errnum = JSMSG_BAD_OPERAND;
- extra = "decrement";
- break;
-
- case KeyedDestructuringAssignment:
- errnum = JSMSG_BAD_DESTRUCT_TARGET;
- break;
-
- case PlainAssignment:
- case CompoundAssignment:
- errnum = JSMSG_BAD_LEFTSIDE_OF_ASS;
- break;
-
- case ForInOrOfTarget:
- errnum = JSMSG_BAD_FOR_LEFTSIDE;
- break;
- }
-
- report(ParseError, pc->sc()->strict(), target, errnum, extra);
- return false;
-}
-
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkAndMarkAsIncOperand(Node target, AssignmentFlavor flavor)
-{
- MOZ_ASSERT(flavor == IncrementAssignment || flavor == DecrementAssignment);
-
- // Check.
- if (!reportIfNotValidSimpleAssignmentTarget(target, flavor))
+ } else {
+ errorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND);
return false;
-
- // Mark.
- if (handler.isNameAnyParentheses(target)) {
- // Assignment to arguments/eval is allowed outside strict mode code,
- // but it's dodgy. Report a strict warning (error, if werror was set).
- if (!reportIfArgumentsEvalTarget(target))
- return false;
- } else if (handler.isFunctionCall(target)) {
- if (!checkAssignmentToCall(target, JSMSG_BAD_INCOP_OPERAND))
- return false;
}
+
+ MOZ_ASSERT(isValidSimpleAssignmentTarget(operand, PermitAssignmentToFunctionCalls),
+ "inconsistent increment/decrement operand validation");
return true;
}
@@ -7944,18 +8417,21 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
TokenKind tt2;
if (!tokenStream.getToken(&tt2, TokenStream::Operand))
return null();
- Node pn2 = memberExpr(yieldHandling, TripledotProhibited, tt2);
- if (!pn2)
- return null();
- AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment;
- if (!checkAndMarkAsIncOperand(pn2, flavor))
+
+ uint32_t operandOffset = pos().begin;
+ Node operand = memberExpr(yieldHandling, TripledotProhibited, tt2);
+ if (!operand || !checkIncDecOperand(operand, operandOffset))
return null();
+
return handler.newUpdate((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT,
- begin,
- pn2);
+ begin, operand);
}
case TOK_DELETE: {
+ uint32_t exprOffset;
+ if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand))
+ return null();
+
Node expr = unaryExpr(yieldHandling, TripledotProhibited);
if (!expr)
return null();
@@ -7963,8 +8439,9 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
// Per spec, deleting any unary expression is valid -- it simply
// returns true -- except for one case that is illegal in strict mode.
if (handler.isNameAnyParentheses(expr)) {
- if (!report(ParseStrictError, pc->sc()->strict(), expr, JSMSG_DEPRECATED_DELETE_OPERAND))
+ if (!strictModeErrorAt(exprOffset, JSMSG_DEPRECATED_DELETE_OPERAND))
return null();
+
pc->sc()->setBindingsAccessedDynamically();
}
@@ -7972,39 +8449,35 @@ 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.
- report(ParseError, false, null(), 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 pn = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true,
+ Node expr = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true,
possibleError, invoked);
- if (!pn)
+ if (!expr)
return null();
/* Don't look across a newline boundary for a postfix incop. */
if (!tokenStream.peekTokenSameLine(&tt))
return null();
- if (tt == TOK_INC || tt == TOK_DEC) {
- tokenStream.consumeKnownToken(tt);
- AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment;
- if (!checkAndMarkAsIncOperand(pn, flavor))
- return null();
- return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT,
- begin,
- pn);
- }
- return pn;
+
+ if (tt != TOK_INC && tt != TOK_DEC)
+ return expr;
+
+ tokenStream.consumeKnownToken(tt);
+ if (!checkIncDecOperand(expr, begin))
+ return null();
+ return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT,
+ begin, expr);
}
}
}
@@ -8026,10 +8499,9 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
{
- Node genfn = handler.newFunctionDefinition();
+ Node genfn = handler.newFunctionExpression();
if (!genfn)
return null();
- handler.setOp(genfn, JSOP_LAMBDA);
ParseContext* outerpc = pc;
@@ -8049,8 +8521,8 @@ 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, directives, StarGenerator, SyncFunction,
- /* tryAnnexB = */ false);
+ FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* toStringStart = */ 0, directives,
+ StarGenerator, SyncFunction, /* tryAnnexB = */ false);
if (!genFunbox)
return null();
genFunbox->isGenexpLambda = true;
@@ -8082,12 +8554,14 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
+ uint32_t end = pos().end;
handler.setBeginPosition(comp, begin);
- handler.setEndPosition(comp, pos().end);
+ handler.setEndPosition(comp, end);
+ genFunbox->setEnd(end);
handler.addStatementToList(body, comp);
- handler.setEndPosition(body, pos().end);
+ handler.setEndPosition(body, end);
handler.setBeginPosition(genfn, begin);
- handler.setEndPosition(genfn, pos().end);
+ handler.setEndPosition(genfn, end);
Node generator = newDotGeneratorName();
if (!generator)
@@ -8123,10 +8597,12 @@ 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) {
- report(ParseError, false, null(), JSMSG_LET_COMP_BINDING);
+ error(JSMSG_LET_COMP_BINDING);
return null();
}
TokenPos namePos = pos();
@@ -8134,10 +8610,10 @@ 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) {
- report(ParseError, false, null(), JSMSG_OF_AFTER_FOR_NAME);
+ error(JSMSG_OF_AFTER_FOR_NAME);
return null();
}
@@ -8198,7 +8674,7 @@ Parser<ParseHandler>::comprehensionIf(GeneratorKind comprehensionKind)
/* Check for (a = b) and warn about possible (a == b) mistype. */
if (handler.isUnparenthesizedAssignment(cond)) {
- if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
+ if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN))
return null();
}
@@ -8259,8 +8735,7 @@ Parser<ParseHandler>::comprehension(GeneratorKind comprehensionKind)
return null();
if (comprehensionKind != NotGenerator && pc->lastYieldOffset != startYieldOffset) {
- reportWithOffset(ParseError, false, pc->lastYieldOffset,
- JSMSG_BAD_GENEXP_BODY, js_yield_str);
+ errorAt(pc->lastYieldOffset, JSMSG_BAD_GENEXP_BODY, js_yield_str);
return null();
}
@@ -8322,11 +8797,11 @@ Parser<ParseHandler>::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling)
Node res = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (res) {
if (pc->lastYieldOffset != startYieldOffset) {
- reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT);
+ errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT);
return null();
}
if (pc->lastAwaitOffset != startAwaitOffset) {
- reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
+ errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
return null();
}
}
@@ -8383,13 +8858,8 @@ Parser<ParseHandler>::argumentList(YieldHandling yieldHandling, Node listNode, b
}
}
- TokenKind tt;
- if (!tokenStream.getToken(&tt))
- return false;
- if (tt != TOK_RP) {
- report(ParseError, false, null(), JSMSG_PAREN_AFTER_ARGS);
- return false;
- }
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_ARGS);
+
handler.setEndPosition(listNode, pos().end);
return true;
}
@@ -8475,19 +8945,19 @@ 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()) {
- report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "property");
+ error(JSMSG_BAD_SUPERPROP, "property");
return null();
}
nextMember = handler.newPropertyAccess(lhs, field, pos().end);
if (!nextMember)
return null();
} else {
- report(ParseError, false, null(), JSMSG_NAME_AFTER_DOT);
+ error(JSMSG_NAME_AFTER_DOT);
return null();
}
} else if (tt == TOK_LB) {
@@ -8498,7 +8968,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
- report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "member");
+ error(JSMSG_BAD_SUPERPROP, "member");
return null();
}
nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end);
@@ -8510,12 +8980,12 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
{
if (handler.isSuperBase(lhs)) {
if (!pc->sc()->allowSuperCall()) {
- report(ParseError, false, null(), JSMSG_BAD_SUPERCALL);
+ error(JSMSG_BAD_SUPERCALL);
return null();
}
if (tt != TOK_LP) {
- report(ParseError, false, null(), JSMSG_BAD_SUPER);
+ error(JSMSG_BAD_SUPER);
return null();
}
@@ -8542,7 +9012,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
return null();
} else {
if (options().selfHostingMode && handler.isPropertyAccess(lhs)) {
- report(ParseError, false, null(), JSMSG_SELFHOSTED_METHOD_CALL);
+ error(JSMSG_SELFHOSTED_METHOD_CALL);
return null();
}
@@ -8552,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;
@@ -8570,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;
}
}
@@ -8624,7 +9095,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
}
if (handler.isSuperBase(lhs)) {
- report(ParseError, false, null(), JSMSG_BAD_SUPER);
+ error(JSMSG_BAD_SUPER);
return null();
}
@@ -8646,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) {
- report(ParseError, false, null(), 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)
- {
- report(ParseError, false, null(), 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) {
- report(ParseError, false, null(), JSMSG_BAD_STRICT_ASSIGN, badName);
- return nullptr;
- }
+ return true;
+}
- badName = ident == context->names().let
- ? "let"
- : ident == context->names().static_
- ? "static"
- : nullptr;
- if (badName) {
- report(ParseError, false, null(), JSMSG_RESERVED_ID, badName);
- return nullptr;
- }
- }
- } else {
- if (yieldHandling == YieldIsKeyword ||
- pc->sc()->strict() ||
- versionNumber() >= JSVERSION_1_7)
- {
- report(ParseError, false, null(), 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;
}
@@ -8757,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;
@@ -8772,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());
}
@@ -8809,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)
{
@@ -8840,7 +9405,7 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro
TokenStream::Modifier modifier = TokenStream::Operand;
for (; ; index++) {
if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
- report(ParseError, false, null(), JSMSG_ARRAY_INIT_TOO_BIG);
+ error(JSMSG_ARRAY_INIT_TOO_BIG);
return null();
}
@@ -8857,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);
@@ -8883,11 +9460,13 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro
break;
}
if (tt == TOK_TRIPLEDOT && possibleError)
- possibleError->setPendingDestructuringError(null(), JSMSG_REST_WITH_COMMA);
+ possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA);
}
}
- 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;
@@ -8903,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");
@@ -8916,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] ...
//
@@ -8936,21 +9516,18 @@ 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();
}
}
if (isAsync && isGenerator) {
- report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
+ error(JSMSG_ASYNC_GENERATOR);
return null();
}
@@ -8967,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());
@@ -9020,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())
@@ -9031,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::KeywordIsName);
+ tokenStream.consumeKnownToken(TOK_LB);
- 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;
}
@@ -9061,10 +9626,6 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
return null();
break;
}
-
- default:
- report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
- return null();
}
TokenKind tt;
@@ -9073,16 +9634,18 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
if (tt == TOK_COLON) {
if (isGenerator) {
- report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
+ error(JSMSG_BAD_PROP_ID);
return null();
}
*propType = PropertyType::Normal;
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) {
- report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
+ error(JSMSG_BAD_PROP_ID);
return null();
}
tokenStream.ungetToken();
@@ -9103,34 +9666,31 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
return propName;
}
- report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
+ error(JSMSG_COLON_AFTER_ID);
return null();
}
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>
@@ -9139,205 +9699,274 @@ 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;
- tokenStream.ungetToken();
+ if (tt == TOK_TRIPLEDOT) {
+ // object spread
+ tokenStream.consumeKnownToken(TOK_TRIPLEDOT);
+ uint32_t begin = pos().begin;
- PropertyType propType;
- Node propName = propertyName(yieldHandling, literal, &propType, &propAtom);
- if (!propName)
- return null();
+ TokenPos innerPos;
+ if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand))
+ return null();
- if (propType == PropertyType::Normal) {
- Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
- possibleError);
- if (!propExpr)
+ 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;
- handler.checkAndSetIsDirectRHSAnonFunction(propExpr);
+ PropertyType propType;
+ Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
+ if (!propName)
- if (foldConstants && !FoldConstants(context, &propExpr, this))
return null();
- if (propAtom == context->names().proto) {
- if (seenPrototypeMutation) {
- // Directly report the error when we're not in a
- // destructuring context.
- if (!possibleError) {
- report(ParseError, false, propName, JSMSG_DUPLICATE_PROTO_PROPERTY);
- return null();
- }
-
- // Otherwise delay error reporting until we've determined
- // whether or not we're destructuring.
- possibleError->setPendingExpressionError(propName,
- JSMSG_DUPLICATE_PROTO_PROPERTY);
- }
- seenPrototypeMutation = true;
-
- // 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.
- uint32_t begin = handler.getPosition(propName).begin;
- if (!handler.addPrototypeMutation(literal, 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) {
- report(ParseError, false, null(), 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) {
- report(ParseError, false, null(), 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();
+
+ Node nameExpr = identifierReference(name);
+ if (!nameExpr)
+ return null();
- tokenStream.consumeKnownToken(TOK_ASSIGN);
+ if (possibleError)
+ checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError);
- if (!seenCoverInitializedName) {
- // "shorthand default" or "CoverInitializedName" syntax is only
- // valid in the case of destructuring.
- seenCoverInitializedName = true;
+ 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();
- 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}`.
- report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
+ 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->setPendingExpressionError(null(), 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(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) {
- report(ParseError, false, null(), 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(PropertyType propType, HandleAtom funName)
+Parser<ParseHandler>::methodDefinition(uint32_t toStringStart, PropertyType propType,
+ HandleAtom funName)
{
- FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType);
- GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType);
- FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType);
+ FunctionSyntaxKind kind;
+ switch (propType) {
+ case PropertyType::Getter:
+ kind = Getter;
+ break;
+
+ case PropertyType::GetterNoExpressionClosure:
+ kind = GetterNoExpressionClosure;
+ break;
+
+ case PropertyType::Setter:
+ kind = Setter;
+ break;
+
+ case PropertyType::SetterNoExpressionClosure:
+ kind = SetterNoExpressionClosure;
+ break;
+
+ case PropertyType::Method:
+ case PropertyType::GeneratorMethod:
+ case PropertyType::AsyncMethod:
+ kind = Method;
+ break;
+
+ case PropertyType::Constructor:
+ kind = ClassConstructor;
+ break;
+
+ case PropertyType::DerivedConstructor:
+ kind = DerivedClassConstructor;
+ break;
+
+ default:
+ MOZ_CRASH("Parser: methodDefinition: unexpected property type");
+ }
+
+ GeneratorKind generatorKind = (propType == PropertyType::GeneratorMethod ||
+ propType == PropertyType::AsyncMethod)
+ ? StarGenerator
+ : NotGenerator;
+
+ FunctionAsyncKind asyncKind = (propType == PropertyType::AsyncMethod)
+ ? AsyncFunction
+ : SyncFunction;
+
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
- return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind);
+
+ Node pn = handler.newFunctionExpression();
+ if (!pn)
+ return null();
+
+ return functionDefinition(toStringStart, pn, InAllowed, yieldHandling, funName,
+ kind, generatorKind, asyncKind);
}
template <typename ParseHandler>
@@ -9366,17 +9995,13 @@ Parser<ParseHandler>::tryNewTarget(Node &newTarget)
if (!tokenStream.getToken(&next))
return false;
- if (next != TOK_NAME || tokenStream.currentName() != context->names().target) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "target", TokenKindToDesc(next));
+ if (next != TOK_TARGET) {
+ error(JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next));
return false;
}
- if (!checkUnescapedName())
- return false;
-
if (!pc->sc()->allowNewTarget()) {
- reportWithOffset(ParseError, false, begin, JSMSG_BAD_NEWTARGET);
+ errorAt(begin, JSMSG_BAD_NEWTARGET);
return false;
}
@@ -9399,7 +10024,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
switch (tt) {
case TOK_FUNCTION:
- return functionExpr(invoked);
+ return functionExpr(pos().begin, invoked);
case TOK_CLASS:
return classDefinition(yieldHandling, ClassExpression, NameRequired);
@@ -9423,8 +10048,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
if (!tokenStream.peekToken(&next))
return null();
if (next != TOK_ARROW) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "expression", TokenKindToDesc(TOK_RP));
+ error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP));
return null();
}
@@ -9445,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);
}
@@ -9453,21 +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 toStringStart = pos().begin;
tokenStream.consumeKnownToken(TOK_FUNCTION);
- return functionExpr(PredictUninvoked, AsyncFunction);
+ return functionExpr(toStringStart, PredictUninvoked, AsyncFunction);
}
}
@@ -9510,8 +10138,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
// name, closing parenthesis, and arrow, and allow it only if all are
// present.
if (tripledotHandling != TripledotAllowed) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "expression", TokenKindToDesc(tt));
+ error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
return null();
}
@@ -9532,9 +10159,8 @@ 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) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "rest argument name", TokenKindToDesc(next));
+ if (!TokenKindIsPossibleIdentifier(next)) {
+ error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next));
return null();
}
}
@@ -9542,8 +10168,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
if (!tokenStream.getToken(&next))
return null();
if (next != TOK_RP) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "closing parenthesis", TokenKindToDesc(next));
+ error(JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next));
return null();
}
@@ -9552,8 +10177,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
if (next != TOK_ARROW) {
// Advance the scanner for proper error location reporting.
tokenStream.consumeKnownToken(next);
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "'=>' after argument list", TokenKindToDesc(next));
+ error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next));
return null();
}
@@ -9562,11 +10186,6 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
// Return an arbitrary expression node. See case TOK_RP above.
return handler.newNullLiteral(pos());
}
-
- default:
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "expression", TokenKindToDesc(tt));
- return null();
}
}
@@ -9580,19 +10199,8 @@ Parser<ParseHandler>::exprInParens(InHandling inHandling, YieldHandling yieldHan
return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked);
}
-template <typename ParseHandler>
-void
-Parser<ParseHandler>::addTelemetry(JSCompartment::DeprecatedLanguageExtension e)
-{
- JSContext* cx = context->maybeJSContext();
- if (!cx)
- return;
- cx->compartment()->addTelemetry(getFilename(), e);
-}
-
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::warnOnceAboutExprClosure()
+ParserBase::warnOnceAboutExprClosure()
{
#ifndef RELEASE_OR_BETA
JSContext* cx = context->maybeJSContext();
@@ -9600,7 +10208,7 @@ Parser<ParseHandler>::warnOnceAboutExprClosure()
return true;
if (!cx->compartment()->warnedAboutExprClosure) {
- if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_EXPR_CLOSURE))
+ if (!warning(JSMSG_DEPRECATED_EXPR_CLOSURE))
return false;
cx->compartment()->warnedAboutExprClosure = true;
}
@@ -9608,9 +10216,8 @@ Parser<ParseHandler>::warnOnceAboutExprClosure()
return true;
}
-template <typename ParseHandler>
bool
-Parser<ParseHandler>::warnOnceAboutForEach()
+ParserBase::warnOnceAboutForEach()
{
JSContext* cx = context->maybeJSContext();
if (!cx)
@@ -9618,7 +10225,7 @@ Parser<ParseHandler>::warnOnceAboutForEach()
if (!cx->compartment()->warnedAboutForEach) {
// Disabled warning spew.
- // if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_FOR_EACH))
+ // if (!warning(JSMSG_DEPRECATED_FOR_EACH))
// return false;
cx->compartment()->warnedAboutForEach = true;
}