#include "frontend/Parser.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
#include "mozilla/Range.h"
#include "mozilla/Sprintf.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/Unused.h"
#include "mozilla/Utf8.h"
#include "mozilla/Variant.h"
#include <memory>
#include <new>
#include "jsnum.h"
#include "jstypes.h"
#include "builtin/ModuleObject.h"
#include "builtin/SelfHostingDefines.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/FoldConstants.h"
#include "frontend/ModuleSharedContext.h"
#include "frontend/ParseNode.h"
#include "frontend/TokenStream.h"
#include "irregexp/RegExpParser.h"
#include "vm/BytecodeUtil.h"
#include "vm/JSAtom.h"
#include "vm/JSContext.h"
#include "vm/JSFunction.h"
#include "vm/JSScript.h"
#include "vm/RegExpObject.h"
#include "vm/StringType.h"
#include "wasm/AsmJS.h"
#include "frontend/ParseContext-inl.h"
#include "frontend/SharedContext-inl.h"
#include "vm/EnvironmentObject-inl.h"
using namespace js;
using mozilla::AssertedCast;
using mozilla::AsVariant;
using mozilla::Maybe;
using mozilla::Nothing;
using mozilla::PodCopy;
using mozilla::PodZero;
using mozilla::PointerRangeSize;
using mozilla::Some;
using mozilla::Unused;
using mozilla::Utf8Unit;
using JS::AutoGCRooter;
using JS::ReadOnlyCompileOptions;
namespace js {
namespace frontend {
using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
using BindingIter = ParseContext::Scope::BindingIter;
using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
using BindingNameVector = Vector<BindingName, 6>;
template <class T, class U>
static inline void PropagateTransitiveParseFlags(const T* inner, U* outer) {
if (inner->bindingsAccessedDynamically()) {
outer->setBindingsAccessedDynamically();
}
if (inner->hasDebuggerStatement()) {
outer->setHasDebuggerStatement();
}
if (inner->hasDirectEval()) {
outer->setHasDirectEval();
}
}
static bool StatementKindIsBraced(StatementKind kind) {
return kind == StatementKind::Block || kind == StatementKind::Switch ||
kind == StatementKind::Try || kind == StatementKind::Catch ||
kind == StatementKind::Finally || kind == StatementKind::Class;
}
template <class ParseHandler, typename Unit>
inline typename GeneralParser<ParseHandler, Unit>::FinalParser*
GeneralParser<ParseHandler, Unit>::asFinalParser() {
static_assert(
mozilla::IsBaseOf<GeneralParser<ParseHandler, Unit>, FinalParser>::value,
"inheritance relationship required by the static_cast<> below");
return static_cast<FinalParser*>(this);
}
template <class ParseHandler, typename Unit>
inline const typename GeneralParser<ParseHandler, Unit>::FinalParser*
GeneralParser<ParseHandler, Unit>::asFinalParser() const {
static_assert(
mozilla::IsBaseOf<GeneralParser<ParseHandler, Unit>, FinalParser>::value,
"inheritance relationship required by the static_cast<> below");
return static_cast<const FinalParser*>(this);
}
template <class ParseHandler, typename Unit>
template <typename ConditionT, typename ErrorReportT>
bool GeneralParser<ParseHandler, Unit>::mustMatchTokenInternal(
ConditionT condition, Modifier modifier, ErrorReportT errorReport) {
TokenKind actual;
if (!tokenStream.getToken(&actual, modifier)) {
return false;
}
if (!condition(actual)) {
errorReport(actual);
return false;
}
return true;
}
ParserSharedBase::ParserSharedBase(JSContext* cx, LifoAlloc& alloc,
UsedNameTracker& usedNames,
ScriptSourceObject* sourceObject, Kind kind)
: JS::AutoGCRooter(
cx,
#ifdef JS_BUILD_BINAST
kind == Kind::Parser ? JS::AutoGCRooter::Tag::Parser
: JS::AutoGCRooter::Tag::BinASTParser
#else
JS::AutoGCRooter::Tag::Parser
#endif
),
cx_(cx),
alloc_(alloc),
traceListHead_(nullptr),
pc_(nullptr),
usedNames_(usedNames),
sourceObject_(cx, sourceObject),
keepAtoms_(cx) {
cx->frontendCollectionPool().addActiveCompilation();
tempPoolMark_ = alloc_.mark();
}
ParserSharedBase::~ParserSharedBase() {
alloc_.release(tempPoolMark_);
alloc_.freeAllIfHugeAndUnused();
cx_->frontendCollectionPool().removeActiveCompilation();
}
ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc,
const ReadOnlyCompileOptions& options,
bool foldConstants, UsedNameTracker& usedNames,
ScriptSourceObject* sourceObject, ParseGoal parseGoal)
: ParserSharedBase(cx, alloc, usedNames, sourceObject,
ParserSharedBase::Kind::Parser),
anyChars(cx, options, thisForCtor()),
ss(nullptr),
foldConstants_(foldConstants),
#ifdef DEBUG
checkOptionsCalled_(false),
#endif
isUnexpectedEOF_(false),
awaitHandling_(AwaitIsName),
inParametersOfAsyncFunction_(false),
parseGoal_(uint8_t(parseGoal)) {
}
bool ParserBase::checkOptions() {
#ifdef DEBUG
checkOptionsCalled_ = true;
#endif
return anyChars.checkOptions();
}
ParserBase::~ParserBase() { MOZ_ASSERT(checkOptionsCalled_); }
template <class ParseHandler>
PerHandlerParser<ParseHandler>::PerHandlerParser(
JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
bool foldConstants, UsedNameTracker& usedNames,
LazyScript* lazyOuterFunction, ScriptSourceObject* sourceObject,
ParseGoal parseGoal, void* internalSyntaxParser)
: ParserBase(cx, alloc, options, foldConstants, usedNames, sourceObject,
parseGoal),
handler_(cx, alloc, lazyOuterFunction),
internalSyntaxParser_(internalSyntaxParser) {}
template <class ParseHandler, typename Unit>
GeneralParser<ParseHandler, Unit>::GeneralParser(
JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
const Unit* units, size_t length, bool foldConstants,
UsedNameTracker& usedNames, SyntaxParser* syntaxParser,
LazyScript* lazyOuterFunction, ScriptSourceObject* sourceObject,
ParseGoal parseGoal)
: Base(cx, alloc, options, foldConstants, usedNames, syntaxParser,
lazyOuterFunction, sourceObject, parseGoal),
tokenStream(cx, options, units, length) {}
template <typename Unit>
void Parser<SyntaxParseHandler, Unit>::setAwaitHandling(
AwaitHandling awaitHandling) {
this->awaitHandling_ = awaitHandling;
}
template <typename Unit>
void Parser<FullParseHandler, Unit>::setAwaitHandling(
AwaitHandling awaitHandling) {
this->awaitHandling_ = awaitHandling;
if (SyntaxParser* syntaxParser = getSyntaxParser()) {
syntaxParser->setAwaitHandling(awaitHandling);
}
}
template <class ParseHandler, typename Unit>
inline void GeneralParser<ParseHandler, Unit>::setAwaitHandling(
AwaitHandling awaitHandling) {
asFinalParser()->setAwaitHandling(awaitHandling);
}
template <typename Unit>
void Parser<SyntaxParseHandler, Unit>::setInParametersOfAsyncFunction(
bool inParameters) {
this->inParametersOfAsyncFunction_ = inParameters;
}
template <typename Unit>
void Parser<FullParseHandler, Unit>::setInParametersOfAsyncFunction(
bool inParameters) {
this->inParametersOfAsyncFunction_ = inParameters;
if (SyntaxParser* syntaxParser = getSyntaxParser()) {
syntaxParser->setInParametersOfAsyncFunction(inParameters);
}
}
template <class ParseHandler, typename Unit>
inline void GeneralParser<ParseHandler, Unit>::setInParametersOfAsyncFunction(
bool inParameters) {
asFinalParser()->setInParametersOfAsyncFunction(inParameters);
}
template <typename BoxT, typename ArgT>
BoxT* ParserSharedBase::newTraceListNode(ArgT* arg) {
MOZ_ASSERT(arg);
BoxT* box = alloc_.template new_<BoxT>(arg, traceListHead_);
if (!box) {
ReportOutOfMemory(cx_);
return nullptr;
}
traceListHead_ = box;
return box;
}
ObjectBox* ParserSharedBase::newObjectBox(JSObject* obj) {
return newTraceListNode<ObjectBox, JSObject>(obj);
}
BigIntBox* ParserSharedBase::newBigIntBox(BigInt* val) {
return newTraceListNode<BigIntBox, BigInt>(val);
}
template <class ParseHandler>
FunctionBox* PerHandlerParser<ParseHandler>::newFunctionBox(
FunctionNodeType funNode, JSFunction* fun, uint32_t toStringStart,
Directives inheritedDirectives, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind) {
MOZ_ASSERT(fun);
FunctionBox* funbox = alloc_.new_<FunctionBox>(
cx_, traceListHead_, fun, toStringStart, inheritedDirectives,
options().extraWarningsOption, generatorKind, asyncKind);
if (!funbox) {
ReportOutOfMemory(cx_);
return nullptr;
}
traceListHead_ = funbox;
if (funNode) {
handler_.setFunctionBox(funNode, funbox);
}
return funbox;
}
void ParserBase::trace(JSTracer* trc) {
TraceListNode::TraceList(trc, traceListHead_);
}
void TraceParser(JSTracer* trc, AutoGCRooter* parser) {
static_cast<ParserBase*>(parser)->trace(trc);
}
bool ParserBase::setSourceMapInfo() {
if (!ss) {
return true;
}
if (anyChars.hasDisplayURL()) {
if (!ss->setDisplayURL(cx_, anyChars.displayURL())) {
return false;
}
}
if (anyChars.hasSourceMapURL()) {
MOZ_ASSERT(!ss->hasSourceMapURL());
if (!ss->setSourceMapURL(cx_, anyChars.sourceMapURL())) {
return false;
}
}
if (options().sourceMapURL()) {
if (ss->hasSourceMapURL()) {
if (!warningNoOffset(JSMSG_ALREADY_HAS_PRAGMA, ss->filename(),
"//# sourceMappingURL")) {
return false;
}
}
if (!ss->setSourceMapURL(cx_, options().sourceMapURL())) {
return false;
}
}
return true;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType GeneralParser<ParseHandler, Unit>::parse() {
MOZ_ASSERT(checkOptionsCalled_);
Directives directives(options().strictOption);
GlobalSharedContext globalsc(cx_, ScopeKind::Global, directives,
options().extraWarningsOption);
SourceParseContext globalpc(this, &globalsc, nullptr);
if (!globalpc.init()) {
return null();
}
ParseContext::VarScope varScope(this);
if (!varScope.init(pc_)) {
return null();
}
ListNodeType stmtList = statementList(YieldIsName);
if (!stmtList) {
return null();
}
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt != TokenKind::Eof) {
error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt));
return null();
}
if (foldConstants_) {
Node node = stmtList;
if (!pc_->useAsmOrInsideUseAsm()) {
if (!FoldConstants(cx_, &node, &handler_)) {
return null();
}
}
stmtList = handler_.asList(node);
}
return stmtList;
}
bool ParserBase::isValidStrictBinding(PropertyName* name) {
TokenKind tt = ReservedWordTokenKind(name);
if (tt == TokenKind::Name) {
return name != cx_->names().eval && name != cx_->names().arguments;
}
return tt != TokenKind::Let && tt != TokenKind::Static &&
tt != TokenKind::Yield && !TokenKindIsStrictReservedWord(tt);
}
bool ParserBase::hasValidSimpleStrictParameterNames() {
MOZ_ASSERT(pc_->isFunctionBox() &&
pc_->functionBox()->hasSimpleParameterList());
if (pc_->functionBox()->hasDuplicateParameters) {
return false;
}
for (auto* name : pc_->positionalFormalParameterNames()) {
MOZ_ASSERT(name);
if (!isValidStrictBinding(name->asPropertyName())) {
return false;
}
}
return true;
}
template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::reportMissingClosing(
unsigned errorNumber, unsigned noteNumber, uint32_t openedPos) {
auto notes = MakeUnique<JSErrorNotes>();
if (!notes) {
ReportOutOfMemory(pc_->sc()->cx_);
return;
}
uint32_t line, column;
tokenStream.computeLineAndColumn(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()->cx_, getFilename(), 0, line, column,
GetErrorMessage, nullptr, noteNumber, lineNumber,
columnNumber)) {
return;
}
errorWithNotes(std::move(notes), errorNumber);
}
template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::reportRedeclaration(
HandlePropertyName name, DeclarationKind prevKind, TokenPos pos,
uint32_t prevPos) {
UniqueChars bytes = AtomToPrintableString(cx_, name);
if (!bytes) {
return;
}
if (prevPos == DeclaredNameInfo::npos) {
errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(prevKind),
bytes.get());
return;
}
auto notes = MakeUnique<JSErrorNotes>();
if (!notes) {
ReportOutOfMemory(pc_->sc()->cx_);
return;
}
uint32_t line, column;
tokenStream.computeLineAndColumn(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()->cx_, getFilename(), 0, line, column,
GetErrorMessage, nullptr, JSMSG_REDECLARED_PREV,
lineNumber, columnNumber)) {
return;
}
errorWithNotesAt(std::move(notes), pos.begin, JSMSG_REDECLARED_VAR,
DeclarationKindString(prevKind), bytes.get());
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::notePositionalFormalParameter(
FunctionNodeType funNode, HandlePropertyName name, uint32_t beginPos,
bool disallowDuplicateParams, bool* duplicatedParam) {
if (AddDeclaredNamePtr p =
pc_->functionScope().lookupDeclaredNameForAdd(name)) {
if (disallowDuplicateParams) {
error(JSMSG_BAD_DUP_ARGS);
return false;
}
if (pc_->sc()->needStrictChecks()) {
UniqueChars bytes = AtomToPrintableString(cx_, name);
if (!bytes) {
return false;
}
if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.get())) {
return false;
}
}
*duplicatedParam = true;
} else {
DeclarationKind kind = DeclarationKind::PositionalFormalParameter;
if (!pc_->functionScope().addDeclaredName(pc_, p, name, kind, beginPos)) {
return false;
}
}
if (!pc_->positionalFormalParameterNames().append(name)) {
ReportOutOfMemory(cx_);
return false;
}
NameNodeType paramNode = newName(name);
if (!paramNode) {
return false;
}
handler_.addFunctionFormalParameter(funNode, paramNode);
return true;
}
template <class ParseHandler>
bool PerHandlerParser<ParseHandler>::noteDestructuredPositionalFormalParameter(
FunctionNodeType funNode, Node destruct) {
if (!pc_->positionalFormalParameterNames().append(nullptr)) {
ReportOutOfMemory(cx_);
return false;
}
handler_.addFunctionFormalParameter(funNode, destruct);
return true;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::
checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt,
DeclarationKind kind,
TokenPos pos) {
MOZ_ASSERT(DeclarationKindIsLexical(kind));
if (!StatementKindIsBraced(stmt.kind()) &&
stmt.kind() != StatementKind::ForLoopLexicalHead) {
errorAt(pos.begin,
stmt.kind() == StatementKind::Label
? JSMSG_LEXICAL_DECL_LABEL
: JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
DeclarationKindString(kind));
return false;
}
return true;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::noteDeclaredName(
HandlePropertyName name, DeclarationKind kind, TokenPos pos) {
if (pc_->useAsmOrInsideUseAsm()) {
return true;
}
switch (kind) {
case DeclarationKind::Var:
case DeclarationKind::BodyLevelFunction: {
Maybe<DeclarationKind> redeclaredKind;
uint32_t prevPos;
if (!pc_->tryDeclareVar(name, kind, pos.begin, &redeclaredKind,
&prevPos)) {
return false;
}
if (redeclaredKind) {
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;
}
pc_->varScope().lookupDeclaredName(name)->value()->setClosedOver();
break;
}
case DeclarationKind::FormalParameter: {
AddDeclaredNamePtr p =
pc_->functionScope().lookupDeclaredNameForAdd(name);
if (p) {
error(JSMSG_BAD_DUP_ARGS);
return false;
}
if (!pc_->functionScope().addDeclaredName(pc_, p, name, kind,
pos.begin)) {
return false;
}
break;
}
case DeclarationKind::LexicalFunction: {
ParseContext::Scope* scope = pc_->innermostScope();
AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name);
if (p) {
reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
return false;
}
if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin)) {
return false;
}
break;
}
case DeclarationKind::SloppyLexicalFunction: {
ParseContext::Scope* scope = pc_->innermostScope();
if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
if (p->value()->kind() != DeclarationKind::SloppyLexicalFunction) {
reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
return false;
}
} else {
if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin)) {
return false;
}
}
break;
}
case DeclarationKind::Let:
case DeclarationKind::Const:
case DeclarationKind::Class:
if (name == cx_->names().let) {
errorAt(pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET);
return false;
}
MOZ_FALLTHROUGH;
case DeclarationKind::Import:
MOZ_ASSERT(name != cx_->names().let);
MOZ_FALLTHROUGH;
case DeclarationKind::SimpleCatchParameter:
case DeclarationKind::CatchParameter: {
if (ParseContext::Statement* stmt = pc_->innermostStatement()) {
if (!checkLexicalDeclarationDirectlyWithinBlock(*stmt, kind, pos)) {
return false;
}
}
ParseContext::Scope* scope = pc_->innermostScope();
if (pc_->isFunctionExtraBodyVarScopeInnermost()) {
DeclaredNamePtr p = pc_->functionScope().lookupDeclaredName(name);
if (p && DeclarationKindIsParameter(p->value()->kind())) {
reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
return false;
}
}
AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name);
if (p) {
reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
return false;
}
if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin)) {
return false;
}
break;
}
case DeclarationKind::CoverArrowParameter:
break;
case DeclarationKind::PositionalFormalParameter:
MOZ_CRASH(
"Positional formal parameter names should use "
"notePositionalFormalParameter");
break;
case DeclarationKind::VarForAnnexBLexicalFunction:
MOZ_CRASH(
"Synthesized Annex B vars should go through "
"tryDeclareVarForAnnexBLexicalFunction");
break;
}
return true;
}
bool ParserBase::noteUsedNameInternal(HandlePropertyName name) {
if (pc_->useAsmOrInsideUseAsm()) {
return true;
}
ParseContext::Scope* scope = pc_->innermostScope();
if (pc_->sc()->isGlobalContext() && scope == &pc_->varScope()) {
return true;
}
return usedNames_.noteUse(cx_, name, pc_->scriptId(), scope->id());
}
template <class ParseHandler>
bool PerHandlerParser<ParseHandler>::
propagateFreeNamesAndMarkClosedOverBindings(ParseContext::Scope& scope) {
if (!scope.propagateAndMarkAnnexBFunctionBoxes(pc_)) {
return false;
}
if (handler_.canSkipLazyClosedOverBindings()) {
while (JSAtom* name = handler_.nextLazyClosedOverBinding()) {
scope.lookupDeclaredName(name)->value()->setClosedOver();
}
return true;
}
bool isSyntaxParser =
mozilla::IsSame<ParseHandler, SyntaxParseHandler>::value;
uint32_t scriptId = pc_->scriptId();
uint32_t scopeId = scope.id();
for (BindingIter bi = scope.bindings(pc_); bi; bi++) {
if (UsedNamePtr p = usedNames_.lookup(bi.name())) {
bool closedOver;
p->value().noteBoundInScope(scriptId, scopeId, &closedOver);
if (closedOver) {
bi.setClosedOver();
if (isSyntaxParser &&
!pc_->closedOverBindingsForLazy().append(bi.name())) {
ReportOutOfMemory(cx_);
return false;
}
}
}
}
if (isSyntaxParser && !pc_->closedOverBindingsForLazy().append(nullptr)) {
ReportOutOfMemory(cx_);
return false;
}
return true;
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::checkStatementsEOF() {
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
return false;
}
if (tt != TokenKind::Eof) {
error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
return false;
}
return true;
}
template <typename Scope>
typename Scope::Data* NewEmptyBindingData(JSContext* cx, LifoAlloc& alloc,
uint32_t numBindings) {
using Data = typename Scope::Data;
size_t allocSize = SizeOfData<typename Scope::Data>(numBindings);
auto* bindings = alloc.newWithSize<Data>(allocSize, numBindings);
if (!bindings) {
ReportOutOfMemory(cx);
}
return bindings;
}
namespace detail {
template <class Data>
static MOZ_ALWAYS_INLINE BindingName* InitializeIndexedBindings(
Data* data, BindingName* start, BindingName* cursor) {
return cursor;
}
template <class Data, typename UnsignedInteger, typename... Step>
static MOZ_ALWAYS_INLINE BindingName* InitializeIndexedBindings(
Data* data, BindingName* start, BindingName* cursor,
UnsignedInteger Data::*field, const BindingNameVector& bindings,
Step&&... step) {
data->*field = AssertedCast<UnsignedInteger>(PointerRangeSize(start, cursor));
BindingName* newCursor =
std::uninitialized_copy(bindings.begin(), bindings.end(), cursor);
return InitializeIndexedBindings(data, start, newCursor,
std::forward<Step>(step)...);
}
}
template <class Data, typename... Step>
static MOZ_ALWAYS_INLINE void InitializeBindingData(
Data* data, uint32_t count, const BindingNameVector& firstBindings,
Step&&... step) {
MOZ_ASSERT(data->length == 0, "data shouldn't be filled yet");
BindingName* start = data->trailingNames.start();
BindingName* cursor = std::uninitialized_copy(firstBindings.begin(),
firstBindings.end(), start);
#ifdef DEBUG
BindingName* end =
#endif
detail::InitializeIndexedBindings(data, start, cursor,
std::forward<Step>(step)...);
MOZ_ASSERT(PointerRangeSize(start, end) == count);
data->length = count;
}
Maybe<GlobalScope::Data*> NewGlobalScopeData(JSContext* cx,
ParseContext::Scope& scope,
LifoAlloc& alloc,
ParseContext* pc) {
BindingNameVector vars(cx);
BindingNameVector lets(cx);
BindingNameVector consts(cx);
bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
bool closedOver = allBindingsClosedOver || bi.closedOver();
switch (bi.kind()) {
case BindingKind::Var: {
bool isTopLevelFunction =
bi.declarationKind() == DeclarationKind::BodyLevelFunction;
BindingName binding(bi.name(), closedOver, isTopLevelFunction);
if (!vars.append(binding)) {
return Nothing();
}
break;
}
case BindingKind::Let: {
BindingName binding(bi.name(), closedOver);
if (!lets.append(binding)) {
return Nothing();
}
break;
}
case BindingKind::Const: {
BindingName binding(bi.name(), closedOver);
if (!consts.append(binding)) {
return Nothing();
}
break;
}
default:
MOZ_CRASH("Bad global scope BindingKind");
}
}
GlobalScope::Data* bindings = nullptr;
uint32_t numBindings = vars.length() + lets.length() + consts.length();
if (numBindings > 0) {
bindings = NewEmptyBindingData<GlobalScope>(cx, alloc, numBindings);
if (!bindings) {
return Nothing();
}
InitializeBindingData(bindings, numBindings, vars,
&GlobalScope::Data::letStart, lets,
&GlobalScope::Data::constStart, consts);
}
return Some(bindings);
}
Maybe<GlobalScope::Data*> ParserBase::newGlobalScopeData(
ParseContext::Scope& scope) {
return NewGlobalScopeData(cx_, scope, alloc_, pc_);
}
Maybe<ModuleScope::Data*> NewModuleScopeData(JSContext* cx,
ParseContext::Scope& scope,
LifoAlloc& alloc,
ParseContext* pc) {
BindingNameVector imports(cx);
BindingNameVector vars(cx);
BindingNameVector lets(cx);
BindingNameVector consts(cx);
bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
BindingName binding(bi.name(), (allBindingsClosedOver || bi.closedOver()) &&
bi.kind() != BindingKind::Import);
switch (bi.kind()) {
case BindingKind::Import:
if (!imports.append(binding)) {
return Nothing();
}
break;
case BindingKind::Var:
if (!vars.append(binding)) {
return Nothing();
}
break;
case BindingKind::Let:
if (!lets.append(binding)) {
return Nothing();
}
break;
case BindingKind::Const:
if (!consts.append(binding)) {
return Nothing();
}
break;
default:
MOZ_CRASH("Bad module scope BindingKind");
}
}
ModuleScope::Data* bindings = nullptr;
uint32_t numBindings =
imports.length() + vars.length() + lets.length() + consts.length();
if (numBindings > 0) {
bindings = NewEmptyBindingData<ModuleScope>(cx, alloc, numBindings);
if (!bindings) {
return Nothing();
}
InitializeBindingData(bindings, numBindings, imports,
&ModuleScope::Data::varStart, vars,
&ModuleScope::Data::letStart, lets,
&ModuleScope::Data::constStart, consts);
}
return Some(bindings);
}
Maybe<ModuleScope::Data*> ParserBase::newModuleScopeData(
ParseContext::Scope& scope) {
return NewModuleScopeData(cx_, scope, alloc_, pc_);
}
Maybe<EvalScope::Data*> NewEvalScopeData(JSContext* cx,
ParseContext::Scope& scope,
LifoAlloc& alloc, ParseContext* pc) {
BindingNameVector vars(cx);
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
MOZ_ASSERT(bi.kind() == BindingKind::Var);
bool isTopLevelFunction =
bi.declarationKind() == DeclarationKind::BodyLevelFunction;
BindingName binding(bi.name(), true, isTopLevelFunction);
if (!vars.append(binding)) {
return Nothing();
}
}
EvalScope::Data* bindings = nullptr;
uint32_t numBindings = vars.length();
if (numBindings > 0) {
bindings = NewEmptyBindingData<EvalScope>(cx, alloc, numBindings);
if (!bindings) {
return Nothing();
}
InitializeBindingData(bindings, numBindings, vars);
}
return Some(bindings);
}
Maybe<EvalScope::Data*> ParserBase::newEvalScopeData(
ParseContext::Scope& scope) {
return NewEvalScopeData(cx_, scope, alloc_, pc_);
}
Maybe<FunctionScope::Data*> NewFunctionScopeData(JSContext* cx,
ParseContext::Scope& scope,
bool hasParameterExprs,
LifoAlloc& alloc,
ParseContext* pc) {
BindingNameVector positionalFormals(cx);
BindingNameVector formals(cx);
BindingNameVector vars(cx);
bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
bool hasDuplicateParams = pc->functionBox()->hasDuplicateParameters;
for (size_t i = 0; i < pc->positionalFormalParameterNames().length(); i++) {
JSAtom* name = pc->positionalFormalParameterNames()[i];
BindingName bindName;
if (name) {
DeclaredNamePtr p = scope.lookupDeclaredName(name);
bool closedOver =
allBindingsClosedOver || (p && p->value()->closedOver());
if (hasDuplicateParams) {
for (size_t j = pc->positionalFormalParameterNames().length() - 1;
j > i; j--) {
if (pc->positionalFormalParameterNames()[j] == name) {
closedOver = false;
break;
}
}
}
bindName = BindingName(name, closedOver);
}
if (!positionalFormals.append(bindName)) {
return Nothing();
}
}
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
BindingName binding(bi.name(), allBindingsClosedOver || bi.closedOver());
switch (bi.kind()) {
case BindingKind::FormalParameter:
if (bi.declarationKind() == DeclarationKind::FormalParameter) {
if (!formals.append(binding)) {
return Nothing();
}
}
break;
case BindingKind::Var:
MOZ_ASSERT_IF(hasParameterExprs,
FunctionScope::isSpecialName(cx, bi.name()));
if (!vars.append(binding)) {
return Nothing();
}
break;
default:
break;
}
}
FunctionScope::Data* bindings = nullptr;
uint32_t numBindings =
positionalFormals.length() + formals.length() + vars.length();
if (numBindings > 0) {
bindings = NewEmptyBindingData<FunctionScope>(cx, alloc, numBindings);
if (!bindings) {
return Nothing();
}
InitializeBindingData(bindings, numBindings, positionalFormals,
&FunctionScope::Data::nonPositionalFormalStart,
formals, &FunctionScope::Data::varStart, vars);
}
return Some(bindings);
}
Maybe<FunctionScope::Data*> ParserBase::newFunctionScopeData(
ParseContext::Scope& scope, bool hasParameterExprs) {
return NewFunctionScopeData(cx_, scope, hasParameterExprs, alloc_, pc_);
}
Maybe<VarScope::Data*> NewVarScopeData(JSContext* cx,
ParseContext::Scope& scope,
LifoAlloc& alloc, ParseContext* pc) {
BindingNameVector vars(cx);
bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
if (bi.kind() == BindingKind::Var) {
BindingName binding(bi.name(), allBindingsClosedOver || bi.closedOver());
if (!vars.append(binding)) {
return Nothing();
}
}
}
VarScope::Data* bindings = nullptr;
uint32_t numBindings = vars.length();
if (numBindings > 0) {
bindings = NewEmptyBindingData<VarScope>(cx, alloc, numBindings);
if (!bindings) {
return Nothing();
}
InitializeBindingData(bindings, numBindings, vars);
}
return Some(bindings);
}
Maybe<VarScope::Data*> ParserBase::newVarScopeData(ParseContext::Scope& scope) {
return NewVarScopeData(cx_, scope, alloc_, pc_);
}
Maybe<LexicalScope::Data*> NewLexicalScopeData(JSContext* cx,
ParseContext::Scope& scope,
LifoAlloc& alloc,
ParseContext* pc) {
BindingNameVector lets(cx);
BindingNameVector consts(cx);
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
BindingName binding(bi.name(), bi.closedOver());
switch (bi.kind()) {
case BindingKind::Let:
if (!lets.append(binding)) {
return Nothing();
}
break;
case BindingKind::Const:
if (!consts.append(binding)) {
return Nothing();
}
break;
default:
break;
}
}
LexicalScope::Data* bindings = nullptr;
uint32_t numBindings = lets.length() + consts.length();
if (numBindings > 0) {
bindings = NewEmptyBindingData<LexicalScope>(cx, alloc, numBindings);
if (!bindings) {
return Nothing();
}
InitializeBindingData(bindings, numBindings, lets,
&LexicalScope::Data::constStart, consts);
}
return Some(bindings);
}
Maybe<LexicalScope::Data*> ParserBase::newLexicalScopeData(
ParseContext::Scope& scope) {
return NewLexicalScopeData(cx_, scope, alloc_, pc_);
}
template <>
SyntaxParseHandler::LexicalScopeNodeType
PerHandlerParser<SyntaxParseHandler>::finishLexicalScope(
ParseContext::Scope& scope, Node body) {
if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
return null();
}
return handler_.newLexicalScope(body);
}
template <>
LexicalScopeNode* PerHandlerParser<FullParseHandler>::finishLexicalScope(
ParseContext::Scope& scope, ParseNode* body) {
if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
return nullptr;
}
Maybe<LexicalScope::Data*> bindings = newLexicalScopeData(scope);
if (!bindings) {
return nullptr;
}
return handler_.newLexicalScope(*bindings, body);
}
template <typename Unit>
LexicalScopeNode* Parser<FullParseHandler, Unit>::evalBody(
EvalSharedContext* evalsc) {
SourceParseContext evalpc(this, evalsc, nullptr);
if (!evalpc.init()) {
return nullptr;
}
ParseContext::VarScope varScope(this);
if (!varScope.init(pc_)) {
return nullptr;
}
LexicalScopeNode* body;
{
ParseContext::Scope lexicalScope(this);
if (!lexicalScope.init(pc_)) {
return nullptr;
}
ParseNode* list = statementList(YieldIsName);
if (!list) {
return nullptr;
}
if (!checkStatementsEOF()) {
return nullptr;
}
body = finishLexicalScope(lexicalScope, list);
if (!body) {
return nullptr;
}
}
#ifdef DEBUG
if (evalpc.superScopeNeedsHomeObject() &&
evalsc->compilationEnclosingScope()) {
ScopeIter si(evalsc->compilationEnclosingScope());
for (; si; si++) {
if (si.kind() == ScopeKind::Function) {
JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
if (fun->isArrow()) {
continue;
}
MOZ_ASSERT(fun->allowSuperProperty());
MOZ_ASSERT(fun->nonLazyScript()->needsHomeObject());
break;
}
}
MOZ_ASSERT(!si.done(),
"Eval must have found an enclosing function box scope that "
"allows super.property");
}
#endif
ParseNode* node = body;
if (!pc_->useAsmOrInsideUseAsm()) {
if (!FoldConstants(cx_, &node, &handler_)) {
return null();
}
}
body = handler_.asLexicalScope(node);
if (!this->setSourceMapInfo()) {
return nullptr;
}
if (!varScope.propagateAndMarkAnnexBFunctionBoxes(pc_)) {
return nullptr;
}
Maybe<EvalScope::Data*> bindings = newEvalScopeData(pc_->varScope());
if (!bindings) {
return nullptr;
}
evalsc->bindings = *bindings;
return body;
}
template <typename Unit>
ListNode* Parser<FullParseHandler, Unit>::globalBody(
GlobalSharedContext* globalsc) {
SourceParseContext globalpc(this, globalsc, nullptr);
if (!globalpc.init()) {
return nullptr;
}
ParseContext::VarScope varScope(this);
if (!varScope.init(pc_)) {
return nullptr;
}
ListNode* body = statementList(YieldIsName);
if (!body) {
return nullptr;
}
if (!checkStatementsEOF()) {
return nullptr;
}
ParseNode* node = body;
if (!pc_->useAsmOrInsideUseAsm()) {
if (!FoldConstants(cx_, &node, &handler_)) {
return null();
}
}
body = &node->as<ListNode>();
if (!this->setSourceMapInfo()) {
return nullptr;
}
if (!varScope.propagateAndMarkAnnexBFunctionBoxes(pc_)) {
return nullptr;
}
Maybe<GlobalScope::Data*> bindings = newGlobalScopeData(pc_->varScope());
if (!bindings) {
return nullptr;
}
globalsc->bindings = *bindings;
return body;
}
template <typename Unit>
ModuleNode* Parser<FullParseHandler, Unit>::moduleBody(
ModuleSharedContext* modulesc) {
MOZ_ASSERT(checkOptionsCalled_);
SourceParseContext modulepc(this, modulesc, nullptr);
if (!modulepc.init()) {
return null();
}
ParseContext::VarScope varScope(this);
if (!varScope.init(pc_)) {
return nullptr;
}
ModuleNodeType moduleNode = handler_.newModule(pos());
if (!moduleNode) {
return null();
}
AutoAwaitIsKeyword<FullParseHandler, Unit> awaitIsKeyword(
this, AwaitIsModuleKeyword);
ListNode* stmtList = statementList(YieldIsName);
if (!stmtList) {
return null();
}
MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
moduleNode->setBody(&stmtList->as<ListNode>());
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt != TokenKind::Eof) {
error(JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt));
return null();
}
if (!modulesc->builder.buildTables()) {
return null();
}
for (auto entry : modulesc->builder.localExportEntries()) {
JSAtom* name = entry->localName();
MOZ_ASSERT(name);
DeclaredNamePtr p = modulepc.varScope().lookupDeclaredName(name);
if (!p) {
UniqueChars str = AtomToPrintableString(cx_, name);
if (!str) {
return null();
}
errorNoOffset(JSMSG_MISSING_EXPORT, str.get());
return null();
}
p->value()->setClosedOver();
}
ParseNode* node = stmtList;
if (!pc_->useAsmOrInsideUseAsm()) {
if (!FoldConstants(cx_, &node, &handler_)) {
return null();
}
}
stmtList = &node->as<ListNode>();
if (!this->setSourceMapInfo()) {
return null();
}
if (!propagateFreeNamesAndMarkClosedOverBindings(modulepc.varScope())) {
return null();
}
Maybe<ModuleScope::Data*> bindings = newModuleScopeData(modulepc.varScope());
if (!bindings) {
return nullptr;
}
modulesc->bindings = *bindings;
return moduleNode;
}
template <typename Unit>
SyntaxParseHandler::ModuleNodeType Parser<SyntaxParseHandler, Unit>::moduleBody(
ModuleSharedContext* modulesc) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return SyntaxParseHandler::NodeFailure;
}
template <class ParseHandler>
typename ParseHandler::NameNodeType
PerHandlerParser<ParseHandler>::newInternalDotName(HandlePropertyName name) {
NameNodeType nameNode = newName(name);
if (!nameNode) {
return null();
}
if (!noteUsedName(name)) {
return null();
}
return nameNode;
}
template <class ParseHandler>
typename ParseHandler::NameNodeType
PerHandlerParser<ParseHandler>::newThisName() {
return newInternalDotName(cx_->names().dotThis);
}
template <class ParseHandler>
typename ParseHandler::NameNodeType
PerHandlerParser<ParseHandler>::newDotGeneratorName() {
return newInternalDotName(cx_->names().dotGenerator);
}
template <class ParseHandler>
bool PerHandlerParser<ParseHandler>::finishFunctionScopes(
bool isStandaloneFunction) {
FunctionBox* funbox = pc_->functionBox();
if (funbox->hasParameterExprs) {
if (!propagateFreeNamesAndMarkClosedOverBindings(pc_->functionScope())) {
return false;
}
}
if (funbox->function()->isNamedLambda() && !isStandaloneFunction) {
if (!propagateFreeNamesAndMarkClosedOverBindings(pc_->namedLambdaScope())) {
return false;
}
}
return true;
}
template <>
bool PerHandlerParser<FullParseHandler>::finishFunction(
bool isStandaloneFunction ) {
if (!finishFunctionScopes(isStandaloneFunction)) {
return false;
}
FunctionBox* funbox = pc_->functionBox();
bool hasParameterExprs = funbox->hasParameterExprs;
if (hasParameterExprs) {
Maybe<VarScope::Data*> bindings = newVarScopeData(pc_->varScope());
if (!bindings) {
return false;
}
funbox->extraVarScopeBindings().set(*bindings);
}
{
Maybe<FunctionScope::Data*> bindings =
newFunctionScopeData(pc_->functionScope(), hasParameterExprs);
if (!bindings) {
return false;
}
funbox->functionScopeBindings().set(*bindings);
}
if (funbox->function()->isNamedLambda() && !isStandaloneFunction) {
Maybe<LexicalScope::Data*> bindings =
newLexicalScopeData(pc_->namedLambdaScope());
if (!bindings) {
return false;
}
funbox->namedLambdaBindings().set(*bindings);
}
return true;
}
template <>
bool PerHandlerParser<SyntaxParseHandler>::finishFunction(
bool isStandaloneFunction ) {
if (!finishFunctionScopes(isStandaloneFunction)) {
return false;
}
if (pc_->closedOverBindingsForLazy().length() >=
LazyScript::NumClosedOverBindingsLimit ||
pc_->innerFunctionsForLazy.length() >=
LazyScript::NumInnerFunctionsLimit) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
FunctionBox* funbox = pc_->functionBox();
RootedFunction fun(cx_, funbox->function());
LazyScript* lazy = LazyScript::Create(
cx_, fun, sourceObject_, pc_->closedOverBindingsForLazy(),
pc_->innerFunctionsForLazy, funbox->bufStart, funbox->bufEnd,
funbox->toStringStart, funbox->startLine, funbox->startColumn,
parseGoal());
if (!lazy) {
return false;
}
if (pc_->sc()->strict()) {
lazy->setStrict();
}
lazy->setGeneratorKind(funbox->generatorKind());
lazy->setAsyncKind(funbox->asyncKind());
if (funbox->hasRest()) {
lazy->setHasRest();
}
if (funbox->isLikelyConstructorWrapper()) {
lazy->setLikelyConstructorWrapper();
}
if (funbox->isDerivedClassConstructor()) {
lazy->setIsDerivedClassConstructor();
}
if (funbox->needsHomeObject()) {
lazy->setNeedsHomeObject();
}
if (funbox->declaredArguments) {
lazy->setShouldDeclareArguments();
}
if (funbox->hasThisBinding()) {
lazy->setHasThisBinding();
}
PropagateTransitiveParseFlags(funbox, lazy);
fun->initLazyScript(lazy);
return true;
}
static YieldHandling GetYieldHandling(GeneratorKind generatorKind) {
if (generatorKind == GeneratorKind::NotGenerator) {
return YieldIsName;
}
return YieldIsKeyword;
}
static AwaitHandling GetAwaitHandling(FunctionAsyncKind asyncKind) {
if (asyncKind == FunctionAsyncKind::SyncFunction) {
return AwaitIsName;
}
return AwaitIsKeyword;
}
template <typename Unit>
FunctionNode* Parser<FullParseHandler, Unit>::standaloneFunction(
HandleFunction fun, HandleScope enclosingScope,
const Maybe<uint32_t>& parameterListEnd, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind, Directives inheritedDirectives,
Directives* newDirectives) {
MOZ_ASSERT(checkOptionsCalled_);
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
if (asyncKind == FunctionAsyncKind::AsyncFunction) {
MOZ_ASSERT(tt == TokenKind::Async);
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
}
MOZ_ASSERT(tt == TokenKind::Function);
if (!tokenStream.getToken(&tt)) {
return null();
}
if (generatorKind == GeneratorKind::Generator) {
MOZ_ASSERT(tt == TokenKind::Mul);
if (!tokenStream.getToken(&tt)) {
return null();
}
}
if (TokenKindIsPossibleIdentifierName(tt)) {
MOZ_ASSERT(anyChars.currentName() == fun->explicitName());
} else {
MOZ_ASSERT(fun->explicitName() == nullptr);
anyChars.ungetToken();
}
FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Statement;
FunctionNodeType funNode = handler_.newFunction(syntaxKind, pos());
if (!funNode) {
return null();
}
ListNodeType argsbody = handler_.newList(ParseNodeKind::ParamsBody, pos());
if (!argsbody) {
return null();
}
funNode->setBody(argsbody);
FunctionBox* funbox =
newFunctionBox(funNode, fun, 0, inheritedDirectives,
generatorKind, asyncKind);
if (!funbox) {
return null();
}
funbox->initStandaloneFunction(enclosingScope);
SourceParseContext funpc(this, funbox, newDirectives);
if (!funpc.init()) {
return null();
}
funpc.setIsStandaloneFunctionBody();
YieldHandling yieldHandling = GetYieldHandling(generatorKind);
AwaitHandling awaitHandling = GetAwaitHandling(asyncKind);
AutoAwaitIsKeyword<FullParseHandler, Unit> awaitIsKeyword(this,
awaitHandling);
if (!functionFormalParametersAndBody(InAllowed, yieldHandling, &funNode,
syntaxKind, parameterListEnd,
true)) {
return null();
}
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt != TokenKind::Eof) {
error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt));
return null();
}
ParseNode* node = funNode;
if (!pc_->useAsmOrInsideUseAsm()) {
if (!FoldConstants(cx_, &node, &handler_)) {
return null();
}
}
funNode = &node->as<FunctionNode>();
if (!this->setSourceMapInfo()) {
return null();
}
return funNode;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::LexicalScopeNodeType
GeneralParser<ParseHandler, Unit>::functionBody(InHandling inHandling,
YieldHandling yieldHandling,
FunctionSyntaxKind kind,
FunctionBodyType type) {
MOZ_ASSERT(pc_->isFunctionBox());
#ifdef DEBUG
uint32_t startYieldOffset = pc_->lastYieldOffset;
#endif
Node body;
if (type == StatementListBody) {
bool inheritedStrict = pc_->sc()->strict();
body = statementList(yieldHandling);
if (!body) {
return null();
}
if (!inheritedStrict && pc_->sc()->strict()) {
MOZ_ASSERT(pc_->sc()->hasExplicitUseStrict(),
"strict mode should only change when a 'use strict' directive "
"is present");
if (!hasValidSimpleStrictParameterNames()) {
pc_->newDirectives->setStrict();
return null();
}
}
} else {
MOZ_ASSERT(type == ExpressionBody);
ListNodeType stmtList = null();
if (pc_->isAsync()) {
stmtList = handler_.newStatementList(pos());
if (!stmtList) {
return null();
}
}
Node kid = assignExpr(inHandling, yieldHandling, TripledotProhibited);
if (!kid) {
return null();
}
body = handler_.newExpressionBody(kid);
if (!body) {
return null();
}
if (pc_->isAsync()) {
handler_.addStatementToList(stmtList, body);
body = stmtList;
}
}
MOZ_ASSERT_IF(!pc_->isGenerator() && !pc_->isAsync(),
pc_->lastYieldOffset == startYieldOffset);
MOZ_ASSERT_IF(pc_->isGenerator(), kind != FunctionSyntaxKind::Arrow);
MOZ_ASSERT_IF(pc_->isGenerator(), type == StatementListBody);
if (pc_->needsDotGeneratorName()) {
MOZ_ASSERT_IF(!pc_->isAsync(), type == StatementListBody);
if (!pc_->declareDotGeneratorName()) {
return null();
}
if (pc_->isGenerator()) {
NameNodeType generator = newDotGeneratorName();
if (!generator) {
return null();
}
if (!handler_.prependInitialYield(handler_.asList(body), generator)) {
return null();
}
}
}
if (kind != FunctionSyntaxKind::Arrow) {
bool canSkipLazyClosedOverBindings =
handler_.canSkipLazyClosedOverBindings();
if (!pc_->declareFunctionArgumentsObject(usedNames_,
canSkipLazyClosedOverBindings)) {
return null();
}
if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
return null();
}
}
return finishLexicalScope(pc_->varScope(), body);
}
JSFunction* AllocNewFunction(JSContext* cx, HandleAtom atom,
FunctionSyntaxKind kind,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind, HandleObject proto,
bool isSelfHosting ,
bool inFunctionBox ) {
MOZ_ASSERT_IF(kind == FunctionSyntaxKind::Statement, atom != nullptr);
RootedFunction fun(cx);
gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
JSFunction::Flags flags;
#ifdef DEBUG
bool isGlobalSelfHostedBuiltin = false;
#endif
switch (kind) {
case FunctionSyntaxKind::Expression:
flags = (generatorKind == GeneratorKind::NotGenerator &&
asyncKind == FunctionAsyncKind::SyncFunction
? JSFunction::INTERPRETED_LAMBDA
: JSFunction::INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC);
break;
case FunctionSyntaxKind::Arrow:
flags = JSFunction::INTERPRETED_LAMBDA_ARROW;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case FunctionSyntaxKind::Method:
flags = JSFunction::INTERPRETED_METHOD;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case FunctionSyntaxKind::ClassConstructor:
case FunctionSyntaxKind::DerivedClassConstructor:
flags = JSFunction::INTERPRETED_CLASS_CONSTRUCTOR;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case FunctionSyntaxKind::Getter:
flags = JSFunction::INTERPRETED_GETTER;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case FunctionSyntaxKind::Setter:
flags = JSFunction::INTERPRETED_SETTER;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
default:
MOZ_ASSERT(kind == FunctionSyntaxKind::Statement);
#ifdef DEBUG
if (isSelfHosting && !inFunctionBox) {
isGlobalSelfHostedBuiltin = true;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
}
#endif
flags = (generatorKind == GeneratorKind::NotGenerator &&
asyncKind == FunctionAsyncKind::SyncFunction
? JSFunction::INTERPRETED_NORMAL
: JSFunction::INTERPRETED_GENERATOR_OR_ASYNC);
}
fun = NewFunctionWithProto(cx, nullptr, 0, flags, nullptr, atom, proto,
allocKind, TenuredObject);
if (!fun) {
return nullptr;
}
if (isSelfHosting) {
fun->setIsSelfHostedBuiltin();
#ifdef DEBUG
if (isGlobalSelfHostedBuiltin) {
fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT,
BooleanValue(false));
}
#endif
}
return fun;
}
JSFunction* ParserBase::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
HandleObject proto ) {
return AllocNewFunction(cx_, atom, kind, generatorKind, asyncKind, proto,
options().selfHostingMode, pc_->isFunctionBox());
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::matchOrInsertSemicolon() {
TokenKind tt = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) {
return false;
}
if (tt != TokenKind::Eof && tt != TokenKind::Eol && tt != TokenKind::Semi &&
tt != TokenKind::RightCurly) {
if (!pc_->isAsync() && anyChars.currentToken().type == TokenKind::Await) {
error(JSMSG_AWAIT_OUTSIDE_ASYNC);
return false;
}
if (!yieldExpressionsSupported() &&
anyChars.currentToken().type == TokenKind::Yield) {
error(JSMSG_YIELD_OUTSIDE_GENERATOR);
return false;
}
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
error(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, TokenKindToDesc(tt));
return false;
}
bool matched;
return tokenStream.matchToken(&matched, TokenKind::Semi,
TokenStream::Operand);
}
bool ParserBase::leaveInnerFunction(ParseContext* outerpc) {
MOZ_ASSERT(pc_ != outerpc);
if (pc_->superScopeNeedsHomeObject()) {
if (!pc_->isArrowFunction()) {
MOZ_ASSERT(pc_->functionBox()->needsHomeObject());
} else {
outerpc->setSuperScopeNeedsHomeObject();
}
}
if (!outerpc->innerFunctionsForLazy.append(pc_->functionBox()->function())) {
return false;
}
PropagateTransitiveParseFlags(pc_->functionBox(), outerpc->sc());
return true;
}
JSAtom* ParserBase::prefixAccessorName(PropertyType propType,
HandleAtom propAtom) {
RootedAtom prefix(cx_);
if (propType == PropertyType::Setter) {
prefix = cx_->names().setPrefix;
} else {
MOZ_ASSERT(propType == PropertyType::Getter);
prefix = cx_->names().getPrefix;
}
RootedString str(cx_, ConcatStrings<CanGC>(cx_, prefix, propAtom));
if (!str) {
return nullptr;
}
return AtomizeString(cx_, str);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::functionArguments(
YieldHandling yieldHandling, FunctionSyntaxKind kind,
FunctionNodeType funNode) {
FunctionBox* funbox = pc_->functionBox();
bool parenFreeArrow = false;
Modifier firstTokenModifier = TokenStream::None;
Modifier argModifier = TokenStream::Operand;
if (kind == FunctionSyntaxKind::Arrow) {
TokenKind tt;
firstTokenModifier =
funbox->isAsync() ? TokenStream::None : TokenStream::Operand;
if (!tokenStream.peekToken(&tt, firstTokenModifier)) {
return false;
}
if (TokenKindIsPossibleIdentifier(tt)) {
parenFreeArrow = true;
argModifier = firstTokenModifier;
}
}
TokenPos firstTokenPos;
if (!parenFreeArrow) {
TokenKind tt;
if (!tokenStream.getToken(&tt, firstTokenModifier)) {
return false;
}
if (tt != TokenKind::LeftParen) {
error(kind == FunctionSyntaxKind::Arrow ? JSMSG_BAD_ARROW_ARGS
: JSMSG_PAREN_BEFORE_FORMAL);
return false;
}
firstTokenPos = pos();
tokenStream.setFunctionStart(funbox);
} else {
if (!tokenStream.peekTokenPos(&firstTokenPos, firstTokenModifier)) {
return false;
}
}
ListNodeType argsbody =
handler_.newList(ParseNodeKind::ParamsBody, firstTokenPos);
if (!argsbody) {
return false;
}
handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
bool hasArguments = false;
if (parenFreeArrow) {
hasArguments = true;
} else {
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::RightParen,
TokenStream::Operand)) {
return false;
}
if (!matched) {
hasArguments = true;
}
}
if (hasArguments) {
bool hasRest = false;
bool hasDefault = false;
bool duplicatedParam = false;
bool disallowDuplicateParams = kind == FunctionSyntaxKind::Arrow ||
kind == FunctionSyntaxKind::Method ||
kind == FunctionSyntaxKind::ClassConstructor;
AtomVector& positionalFormals = pc_->positionalFormalParameterNames();
if (kind == FunctionSyntaxKind::Getter) {
error(JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
return false;
}
while (true) {
if (hasRest) {
error(JSMSG_PARAMETER_AFTER_REST);
return false;
}
TokenKind tt;
if (!tokenStream.getToken(&tt, argModifier)) {
return false;
}
argModifier = TokenStream::Operand;
MOZ_ASSERT_IF(parenFreeArrow, TokenKindIsPossibleIdentifier(tt));
if (tt == TokenKind::TripleDot) {
if (kind == FunctionSyntaxKind::Setter) {
error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
}
disallowDuplicateParams = true;
if (duplicatedParam) {
error(JSMSG_BAD_DUP_ARGS);
return false;
}
hasRest = true;
funbox->setHasRest();
if (!tokenStream.getToken(&tt)) {
return false;
}
if (!TokenKindIsPossibleIdentifier(tt) &&
tt != TokenKind::LeftBracket && tt != TokenKind::LeftCurly) {
error(JSMSG_NO_REST_NAME);
return false;
}
}
switch (tt) {
case TokenKind::LeftBracket:
case TokenKind::LeftCurly: {
disallowDuplicateParams = true;
if (duplicatedParam) {
error(JSMSG_BAD_DUP_ARGS);
return false;
}
funbox->hasDestructuringArgs = true;
Node destruct = destructuringDeclarationWithoutYieldOrAwait(
DeclarationKind::FormalParameter, yieldHandling, tt);
if (!destruct) {
return false;
}
if (!noteDestructuredPositionalFormalParameter(funNode, destruct)) {
return false;
}
break;
}
default: {
if (!TokenKindIsPossibleIdentifier(tt)) {
error(JSMSG_MISSING_FORMAL);
return false;
}
if (parenFreeArrow) {
tokenStream.setFunctionStart(funbox);
}
RootedPropertyName name(cx_, bindingIdentifier(yieldHandling));
if (!name) {
return false;
}
if (!notePositionalFormalParameter(funNode, name, pos().begin,
disallowDuplicateParams,
&duplicatedParam)) {
return false;
}
if (duplicatedParam) {
funbox->hasDuplicateParameters = true;
}
break;
}
}
if (positionalFormals.length() >= ARGNO_LIMIT) {
error(JSMSG_TOO_MANY_FUN_ARGS);
return false;
}
if (parenFreeArrow) {
break;
}
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Assign,
TokenStream::Operand)) {
return false;
}
if (matched) {
MOZ_ASSERT(!parenFreeArrow);
if (hasRest) {
error(JSMSG_REST_WITH_DEFAULT);
return false;
}
disallowDuplicateParams = true;
if (duplicatedParam) {
error(JSMSG_BAD_DUP_ARGS);
return false;
}
if (!hasDefault) {
hasDefault = true;
funbox->length = positionalFormals.length() - 1;
}
funbox->hasParameterExprs = true;
Node def_expr = assignExprWithoutYieldOrAwait(yieldHandling);
if (!def_expr) {
return false;
}
if (!handler_.setLastFunctionFormalParameterDefault(funNode,
def_expr)) {
return false;
}
}
if (kind == FunctionSyntaxKind::Setter) {
break;
}
if (!tokenStream.matchToken(&matched, TokenKind::Comma,
TokenStream::Operand)) {
return false;
}
if (!matched) {
break;
}
if (!hasRest) {
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
return false;
}
if (tt == TokenKind::RightParen) {
break;
}
}
}
if (!parenFreeArrow) {
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return false;
}
if (tt != TokenKind::RightParen) {
if (kind == FunctionSyntaxKind::Setter) {
error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
}
error(JSMSG_PAREN_AFTER_FORMAL);
return false;
}
}
if (!hasDefault) {
funbox->length = positionalFormals.length() - hasRest;
}
if (funbox->hasParameterExprs && funbox->hasDirectEval()) {
funbox->hasDirectEvalInParameterExpr = true;
}
funbox->function()->setArgCount(positionalFormals.length());
} else if (kind == FunctionSyntaxKind::Setter) {
error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
}
return true;
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::skipLazyInnerFunction(
FunctionNode* funNode, uint32_t toStringStart, FunctionSyntaxKind kind,
bool tryAnnexB) {
RootedFunction fun(cx_, handler_.nextLazyInnerFunction());
FunctionBox* funbox = newFunctionBox(funNode, fun, toStringStart,
Directives( false),
fun->generatorKind(), fun->asyncKind());
if (!funbox) {
return false;
}
LazyScript* lazy = fun->lazyScript();
if (lazy->needsHomeObject()) {
funbox->setNeedsHomeObject();
}
PropagateTransitiveParseFlags(lazy, pc_->sc());
if (!tokenStream.advance(fun->lazyScript()->sourceEnd())) {
return false;
}
if (tryAnnexB &&
!pc_->innermostScope()->addPossibleAnnexBFunctionBox(pc_, funbox)) {
return false;
}
return true;
}
template <typename Unit>
bool Parser<SyntaxParseHandler, Unit>::skipLazyInnerFunction(
FunctionNodeType funNode, uint32_t toStringStart, FunctionSyntaxKind kind,
bool tryAnnexB) {
MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::skipLazyInnerFunction(
FunctionNodeType funNode, uint32_t toStringStart, FunctionSyntaxKind kind,
bool tryAnnexB) {
return asFinalParser()->skipLazyInnerFunction(funNode, toStringStart, kind,
tryAnnexB);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::addExprAndGetNextTemplStrToken(
YieldHandling yieldHandling, ListNodeType nodeList, TokenKind* ttp) {
Node pn = expr(InAllowed, yieldHandling, TripledotProhibited);
if (!pn) {
return false;
}
handler_.addList(nodeList, pn);
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return false;
}
if (tt != TokenKind::RightCurly) {
error(JSMSG_TEMPLSTR_UNTERM_EXPR);
return false;
}
return tokenStream.getToken(ttp, TokenStream::TemplateTail);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::taggedTemplate(
YieldHandling yieldHandling, ListNodeType tagArgsList, TokenKind tt) {
CallSiteNodeType callSiteObjNode = handler_.newCallSiteObject(pos().begin);
if (!callSiteObjNode) {
return false;
}
handler_.addList(tagArgsList, callSiteObjNode);
while (true) {
if (!appendToCallSiteObj(callSiteObjNode)) {
return false;
}
if (tt != TokenKind::TemplateHead) {
break;
}
if (!addExprAndGetNextTemplStrToken(yieldHandling, tagArgsList, &tt)) {
return false;
}
}
handler_.setEndPosition(tagArgsList, callSiteObjNode);
return true;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::templateLiteral(
YieldHandling yieldHandling) {
NameNodeType literal = noSubstitutionUntaggedTemplate();
if (!literal) {
return null();
}
ListNodeType nodeList =
handler_.newList(ParseNodeKind::TemplateStringListExpr, literal);
if (!nodeList) {
return null();
}
TokenKind tt;
do {
if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt)) {
return null();
}
literal = noSubstitutionUntaggedTemplate();
if (!literal) {
return null();
}
handler_.addList(nodeList, literal);
} while (tt == TokenKind::TemplateHead);
return nodeList;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::FunctionNodeType
GeneralParser<ParseHandler, Unit>::functionDefinition(
FunctionNodeType funNode, uint32_t toStringStart, InHandling inHandling,
YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB ) {
MOZ_ASSERT_IF(kind == FunctionSyntaxKind::Statement, funName);
if (handler_.canSkipLazyInnerFunctions()) {
if (!skipLazyInnerFunction(funNode, toStringStart, kind, tryAnnexB)) {
return null();
}
return funNode;
}
RootedObject proto(cx_);
if (!GetFunctionPrototype(cx_, generatorKind, asyncKind, &proto)) {
return null();
}
RootedFunction fun(
cx_, newFunction(funName, kind, generatorKind, asyncKind, proto));
if (!fun) {
return null();
}
Directives directives(pc_);
Directives newDirectives = directives;
Position start(keepAtoms_, tokenStream);
while (true) {
if (trySyntaxParseInnerFunction(
&funNode, fun, toStringStart, inHandling, yieldHandling, kind,
generatorKind, asyncKind, tryAnnexB, directives, &newDirectives)) {
break;
}
if (anyChars.hadError() || directives == newDirectives) {
return null();
}
MOZ_ASSERT_IF(directives.strict(), newDirectives.strict());
MOZ_ASSERT_IF(directives.asmJS(), newDirectives.asmJS());
directives = newDirectives;
tokenStream.seek(start);
handler_.setFunctionFormalParametersAndBody(funNode, null());
}
return funNode;
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::trySyntaxParseInnerFunction(
FunctionNode** funNode, HandleFunction fun, uint32_t toStringStart,
InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives) {
do {
if ((*funNode)->isLikelyIIFE() &&
generatorKind == GeneratorKind::NotGenerator &&
asyncKind == FunctionAsyncKind::SyncFunction) {
break;
}
SyntaxParser* syntaxParser = getSyntaxParser();
if (!syntaxParser) {
break;
}
UsedNameTracker::RewindToken token = usedNames_.getRewindToken();
Position currentPosition(keepAtoms_, tokenStream);
if (!syntaxParser->tokenStream.seek(currentPosition, anyChars)) {
return false;
}
FunctionBox* funbox =
newFunctionBox(*funNode, fun, toStringStart, inheritedDirectives,
generatorKind, asyncKind);
if (!funbox) {
return false;
}
funbox->initWithEnclosingParseContext(pc_, kind);
SyntaxParseHandler::Node syntaxNode =
syntaxParser->innerFunctionForFunctionBox(
SyntaxParseHandler::NodeGeneric, pc_, funbox, inHandling,
yieldHandling, kind, newDirectives);
if (!syntaxNode) {
if (syntaxParser->hadAbortedSyntaxParse()) {
syntaxParser->clearAbortedSyntaxParse();
usedNames_.rewind(token);
MOZ_ASSERT_IF(!syntaxParser->cx_->helperThread(),
!syntaxParser->cx_->isExceptionPending());
break;
}
return false;
}
Position currentSyntaxPosition(keepAtoms_, syntaxParser->tokenStream);
if (!tokenStream.seek(currentSyntaxPosition, syntaxParser->anyChars)) {
return false;
}
(*funNode)->pn_pos.end = anyChars.currentToken().pos.end;
if (tryAnnexB) {
if (!pc_->innermostScope()->addPossibleAnnexBFunctionBox(pc_, funbox)) {
return false;
}
}
return true;
} while (false);
FunctionNodeType innerFunc = innerFunction(
*funNode, pc_, fun, toStringStart, inHandling, yieldHandling, kind,
generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
if (!innerFunc) {
return false;
}
*funNode = innerFunc;
return true;
}
template <typename Unit>
bool Parser<SyntaxParseHandler, Unit>::trySyntaxParseInnerFunction(
FunctionNodeType* funNode, HandleFunction fun, uint32_t toStringStart,
InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives) {
FunctionNodeType innerFunc = innerFunction(
*funNode, pc_, fun, toStringStart, inHandling, yieldHandling, kind,
generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
if (!innerFunc) {
return false;
}
*funNode = innerFunc;
return true;
}
template <class ParseHandler, typename Unit>
inline bool GeneralParser<ParseHandler, Unit>::trySyntaxParseInnerFunction(
FunctionNodeType* funNode, HandleFunction fun, uint32_t toStringStart,
InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives) {
return asFinalParser()->trySyntaxParseInnerFunction(
funNode, fun, toStringStart, inHandling, yieldHandling, kind,
generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::FunctionNodeType
GeneralParser<ParseHandler, Unit>::innerFunctionForFunctionBox(
FunctionNodeType funNode, ParseContext* outerpc, FunctionBox* funbox,
InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
Directives* newDirectives) {
SourceParseContext funpc(this, funbox, newDirectives);
if (!funpc.init()) {
return null();
}
if (!functionFormalParametersAndBody(inHandling, yieldHandling, &funNode,
kind)) {
return null();
}
if (!leaveInnerFunction(outerpc)) {
return null();
}
return funNode;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::FunctionNodeType
GeneralParser<ParseHandler, Unit>::innerFunction(
FunctionNodeType funNode, ParseContext* outerpc, HandleFunction fun,
uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives,
Directives* newDirectives) {
FunctionBox* funbox =
newFunctionBox(funNode, fun, toStringStart, inheritedDirectives,
generatorKind, asyncKind);
if (!funbox) {
return null();
}
funbox->initWithEnclosingParseContext(outerpc, kind);
FunctionNodeType innerFunc = innerFunctionForFunctionBox(
funNode, outerpc, funbox, inHandling, yieldHandling, kind, newDirectives);
if (!innerFunc) {
return null();
}
if (tryAnnexB) {
if (!pc_->innermostScope()->addPossibleAnnexBFunctionBox(pc_, funbox)) {
return null();
}
}
return innerFunc;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::appendToCallSiteObj(
CallSiteNodeType callSiteObj) {
Node cookedNode = noSubstitutionTaggedTemplate();
if (!cookedNode) {
return false;
}
JSAtom* atom = tokenStream.getRawTemplateStringAtom();
if (!atom) {
return false;
}
NameNodeType rawNode = handler_.newTemplateStringLiteral(atom, pos());
if (!rawNode) {
return false;
}
handler_.addToCallSiteObject(callSiteObj, rawNode, cookedNode);
return true;
}
template <typename Unit>
FunctionNode* Parser<FullParseHandler, Unit>::standaloneLazyFunction(
HandleFunction fun, uint32_t toStringStart, bool strict,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind) {
MOZ_ASSERT(checkOptionsCalled_);
FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Statement;
if (fun->isClassConstructor()) {
syntaxKind = FunctionSyntaxKind::ClassConstructor;
} else if (fun->isMethod()) {
syntaxKind = FunctionSyntaxKind::Method;
} else if (fun->isGetter()) {
syntaxKind = FunctionSyntaxKind::Getter;
} else if (fun->isSetter()) {
syntaxKind = FunctionSyntaxKind::Setter;
} else if (fun->isArrow()) {
syntaxKind = FunctionSyntaxKind::Arrow;
}
FunctionNodeType funNode = handler_.newFunction(syntaxKind, pos());
if (!funNode) {
return null();
}
Directives directives(strict);
FunctionBox* funbox = newFunctionBox(funNode, fun, toStringStart, directives,
generatorKind, asyncKind);
if (!funbox) {
return null();
}
funbox->initFromLazyFunction();
Directives newDirectives = directives;
SourceParseContext funpc(this, funbox, &newDirectives);
if (!funpc.init()) {
return null();
}
Modifier modifier =
(fun->isArrow() && asyncKind == FunctionAsyncKind::SyncFunction)
? TokenStream::Operand
: TokenStream::None;
if (!tokenStream.peekTokenPos(&funNode->pn_pos, modifier)) {
return null();
}
YieldHandling yieldHandling = GetYieldHandling(generatorKind);
if (!functionFormalParametersAndBody(InAllowed, yieldHandling, &funNode,
syntaxKind)) {
MOZ_ASSERT(directives == newDirectives);
return null();
}
ParseNode* node = funNode;
if (!pc_->useAsmOrInsideUseAsm()) {
if (!FoldConstants(cx_, &node, &handler_)) {
return null();
}
}
funNode = &node->as<FunctionNode>();
return funNode;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::functionFormalParametersAndBody(
InHandling inHandling, YieldHandling yieldHandling,
FunctionNodeType* funNode, FunctionSyntaxKind kind,
const Maybe<uint32_t>& parameterListEnd ,
bool isStandaloneFunction ) {
FunctionBox* funbox = pc_->functionBox();
RootedFunction fun(cx_, funbox->function());
{
AwaitHandling awaitHandling =
(funbox->isAsync() ||
(kind == FunctionSyntaxKind::Arrow && awaitIsKeyword()))
? AwaitIsKeyword
: AwaitIsName;
AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(this, awaitHandling);
AutoInParametersOfAsyncFunction<ParseHandler, Unit> inParameters(
this, funbox->isAsync());
if (!functionArguments(yieldHandling, kind, *funNode)) {
return false;
}
}
Maybe<ParseContext::VarScope> varScope;
if (funbox->hasParameterExprs) {
varScope.emplace(this);
if (!varScope->init(pc_)) {
return false;
}
} else {
pc_->functionScope().useAsVarScope(pc_);
}
if (kind == FunctionSyntaxKind::Arrow) {
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Arrow)) {
return false;
}
if (!matched) {
error(JSMSG_BAD_ARROW_ARGS);
return false;
}
}
if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) {
error(JSMSG_UNEXPECTED_PARAMLIST_END);
return false;
}
FunctionBodyType bodyType = StatementListBody;
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return false;
}
uint32_t openedPos = 0;
if (tt != TokenKind::LeftCurly) {
if (kind != FunctionSyntaxKind::Arrow) {
error(JSMSG_CURLY_BEFORE_BODY);
return false;
}
anyChars.ungetToken();
bodyType = ExpressionBody;
funbox->setHasExprBody();
} else {
openedPos = pos().begin;
}
YieldHandling bodyYieldHandling = GetYieldHandling(pc_->generatorKind());
AwaitHandling bodyAwaitHandling = GetAwaitHandling(pc_->asyncKind());
bool inheritedStrict = pc_->sc()->strict();
LexicalScopeNodeType body;
{
AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(this,
bodyAwaitHandling);
AutoInParametersOfAsyncFunction<ParseHandler, Unit> inParameters(this,
false);
body = functionBody(inHandling, bodyYieldHandling, kind, bodyType);
if (!body) {
return false;
}
}
if ((kind == FunctionSyntaxKind::Statement ||
kind == FunctionSyntaxKind::Expression) &&
fun->explicitName() && !inheritedStrict && pc_->sc()->strict()) {
MOZ_ASSERT(pc_->sc()->hasExplicitUseStrict(),
"strict mode should only change when a 'use strict' directive "
"is present");
PropertyName* propertyName = fun->explicitName()->asPropertyName();
YieldHandling nameYieldHandling;
if (kind == FunctionSyntaxKind::Expression) {
nameYieldHandling = bodyYieldHandling;
} else {
nameYieldHandling = YieldIsName;
}
uint32_t nameOffset = handler_.getFunctionNameOffset(*funNode, anyChars);
if (!checkBindingIdentifier(propertyName, nameOffset, nameYieldHandling)) {
return false;
}
}
if (bodyType == StatementListBody) {
TokenKind actual;
if (!tokenStream.getToken(&actual, TokenStream::Operand)) {
return false;
}
if (actual != TokenKind::RightCurly) {
reportMissingClosing(JSMSG_CURLY_AFTER_BODY, JSMSG_CURLY_OPENED,
openedPos);
return false;
}
funbox->setEnd(anyChars);
} else {
MOZ_ASSERT(kind == FunctionSyntaxKind::Arrow);
if (anyChars.hadError()) {
return false;
}
funbox->setEnd(anyChars);
if (kind == FunctionSyntaxKind::Statement) {
if (!matchOrInsertSemicolon()) {
return false;
}
}
}
if (IsMethodDefinitionKind(kind) && pc_->superScopeNeedsHomeObject()) {
funbox->setNeedsHomeObject();
}
if (!finishFunction(isStandaloneFunction)) {
return false;
}
handler_.setEndPosition(body, pos().begin);
handler_.setEndPosition(*funNode, pos().end);
handler_.setFunctionBody(*funNode, body);
return true;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::FunctionNodeType
GeneralParser<ParseHandler, Unit>::functionStmt(uint32_t toStringStart,
YieldHandling yieldHandling,
DefaultHandling defaultHandling,
FunctionAsyncKind asyncKind) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
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");
while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
declaredInStmt = declaredInStmt->enclosing();
}
if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) {
error(JSMSG_SLOPPY_FUNCTION_LABEL);
return null();
}
}
TokenKind tt;
if (!tokenStream.getToken(&tt)) {
return null();
}
GeneratorKind generatorKind = GeneratorKind::NotGenerator;
if (tt == TokenKind::Mul) {
generatorKind = GeneratorKind::Generator;
if (!tokenStream.getToken(&tt)) {
return null();
}
}
RootedPropertyName name(cx_);
if (TokenKindIsPossibleIdentifier(tt)) {
name = bindingIdentifier(yieldHandling);
if (!name) {
return null();
}
} else if (defaultHandling == AllowDefaultName) {
name = cx_->names().default_;
anyChars.ungetToken();
} else {
error(JSMSG_UNNAMED_FUNCTION_STMT);
return null();
}
DeclarationKind kind;
if (declaredInStmt) {
MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
kind =
(!pc_->sc()->strict() && generatorKind == GeneratorKind::NotGenerator &&
asyncKind == FunctionAsyncKind::SyncFunction)
? DeclarationKind::SloppyLexicalFunction
: DeclarationKind::LexicalFunction;
} else {
kind = pc_->atModuleLevel() ? DeclarationKind::ModuleBodyLevelFunction
: DeclarationKind::BodyLevelFunction;
}
if (!noteDeclaredName(name, kind, pos())) {
return null();
}
FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Statement;
FunctionNodeType funNode = handler_.newFunction(syntaxKind, pos());
if (!funNode) {
return null();
}
bool tryAnnexB = kind == DeclarationKind::SloppyLexicalFunction;
YieldHandling newYieldHandling = GetYieldHandling(generatorKind);
return functionDefinition(funNode, toStringStart, InAllowed, newYieldHandling,
name, syntaxKind, generatorKind, asyncKind,
tryAnnexB);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::FunctionNodeType
GeneralParser<ParseHandler, Unit>::functionExpr(uint32_t toStringStart,
InvokedPrediction invoked,
FunctionAsyncKind asyncKind) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(
this, GetAwaitHandling(asyncKind));
GeneratorKind generatorKind = GeneratorKind::NotGenerator;
TokenKind tt;
if (!tokenStream.getToken(&tt)) {
return null();
}
if (tt == TokenKind::Mul) {
generatorKind = GeneratorKind::Generator;
if (!tokenStream.getToken(&tt)) {
return null();
}
}
YieldHandling yieldHandling = GetYieldHandling(generatorKind);
RootedPropertyName name(cx_);
if (TokenKindIsPossibleIdentifier(tt)) {
name = bindingIdentifier(yieldHandling);
if (!name) {
return null();
}
} else {
anyChars.ungetToken();
}
FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Expression;
FunctionNodeType funNode = handler_.newFunction(syntaxKind, pos());
if (!funNode) {
return null();
}
if (invoked) {
funNode = handler_.setLikelyIIFE(funNode);
}
return functionDefinition(funNode, toStringStart, InAllowed, yieldHandling,
name, syntaxKind, generatorKind, asyncKind);
}
static inline bool IsEscapeFreeStringLiteral(const TokenPos& pos, JSAtom* str) {
return pos.begin + str->length() + 2 == pos.end;
}
template <typename Unit>
bool Parser<SyntaxParseHandler, Unit>::asmJS(ListNodeType list) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
if (ss) {
ss->setContainsAsmJS();
}
return false;
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::asmJS(ListNodeType list) {
disableSyntaxParser();
if (!pc_->newDirectives || pc_->newDirectives->asmJS()) {
return true;
}
if (ss == nullptr) {
return true;
}
ss->setContainsAsmJS();
pc_->functionBox()->useAsm = true;
bool validated;
if (!CompileAsmJS(cx_, *this, list, &validated)) {
return false;
}
if (!validated) {
pc_->newDirectives->setAsmJS();
return false;
}
return true;
}
template <class ParseHandler, typename Unit>
inline bool GeneralParser<ParseHandler, Unit>::asmJS(ListNodeType list) {
return asFinalParser()->asmJS(list);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::maybeParseDirective(
ListNodeType list, Node possibleDirective, bool* cont) {
TokenPos directivePos;
JSAtom* directive =
handler_.isStringExprStatement(possibleDirective, &directivePos);
*cont = !!directive;
if (!*cont) {
return true;
}
if (IsEscapeFreeStringLiteral(directivePos, directive)) {
handler_.setInDirectivePrologue(handler_.asUnary(possibleDirective));
if (directive == cx_->names().useStrict) {
if (pc_->isFunctionBox()) {
FunctionBox* funbox = pc_->functionBox();
if (!funbox->hasSimpleParameterList()) {
const char* parameterKind =
funbox->hasDestructuringArgs
? "destructuring"
: funbox->hasParameterExprs ? "default" : "rest";
errorAt(directivePos.begin, JSMSG_STRICT_NON_SIMPLE_PARAMS,
parameterKind);
return false;
}
}
pc_->sc()->setExplicitUseStrict();
if (!pc_->sc()->strict()) {
if (anyChars.sawOctalEscape()) {
error(JSMSG_DEPRECATED_OCTAL);
return false;
}
pc_->sc()->strictScript = true;
}
} else if (directive == cx_->names().useAsm) {
if (pc_->isFunctionBox()) {
return asmJS(list);
}
return warningAt(directivePos.begin, JSMSG_USE_ASM_DIRECTIVE_FAIL);
}
}
return true;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::statementList(YieldHandling yieldHandling) {
if (!CheckRecursionLimit(cx_)) {
return null();
}
ListNodeType stmtList = handler_.newStatementList(pos());
if (!stmtList) {
return null();
}
bool canHaveDirectives = pc_->atBodyLevel();
if (canHaveDirectives) {
anyChars.clearSawOctalEscape();
}
bool canHaveHashbangComment = pc_->atTopLevel();
if (canHaveHashbangComment) {
tokenStream.consumeOptionalHashbangComment();
}
bool afterReturn = false;
bool warnedAboutStatementsAfterReturn = false;
uint32_t statementBegin = 0;
for (;;) {
TokenKind tt = TokenKind::Eof;
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
if (anyChars.isEOF()) {
isUnexpectedEOF_ = true;
}
return null();
}
if (tt == TokenKind::Eof || tt == TokenKind::RightCurly) {
TokenPos pos;
if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand)) {
return null();
}
handler_.setListEndPosition(stmtList, pos);
break;
}
if (afterReturn) {
if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand)) {
return null();
}
}
Node next = statementListItem(yieldHandling, canHaveDirectives);
if (!next) {
if (anyChars.isEOF()) {
isUnexpectedEOF_ = true;
}
return null();
}
if (!warnedAboutStatementsAfterReturn) {
if (afterReturn) {
if (!handler_.isStatementPermittedAfterReturnStatement(next)) {
if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) {
return null();
}
warnedAboutStatementsAfterReturn = true;
}
} else if (handler_.isReturnStatement(next)) {
afterReturn = true;
}
}
if (canHaveDirectives) {
if (!maybeParseDirective(stmtList, next, &canHaveDirectives)) {
return null();
}
}
handler_.addStatementToList(stmtList, next);
}
return stmtList;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::condition(
InHandling inHandling, YieldHandling yieldHandling) {
if (!mustMatchToken(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_COND)) {
return null();
}
Node pn = exprInParens(inHandling, yieldHandling, TripledotProhibited);
if (!pn) {
return null();
}
if (!mustMatchToken(TokenKind::RightParen, TokenStream::Operand,
JSMSG_PAREN_AFTER_COND)) {
return null();
}
if (handler_.isUnparenthesizedAssignment(pn)) {
if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN)) {
return null();
}
}
return pn;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::matchLabel(
YieldHandling yieldHandling, MutableHandle<PropertyName*> label) {
TokenKind tt = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) {
return false;
}
if (TokenKindIsPossibleIdentifier(tt)) {
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
label.set(labelIdentifier(yieldHandling));
if (!label) {
return false;
}
} else {
label.set(nullptr);
}
return true;
}
template <class ParseHandler, typename Unit>
GeneralParser<ParseHandler, Unit>::PossibleError::PossibleError(
GeneralParser<ParseHandler, Unit>& parser)
: parser_(parser) {}
template <class ParseHandler, typename Unit>
typename GeneralParser<ParseHandler, Unit>::PossibleError::Error&
GeneralParser<ParseHandler, Unit>::PossibleError::error(ErrorKind kind) {
if (kind == ErrorKind::Expression) {
return exprError_;
}
if (kind == ErrorKind::Destructuring) {
return destructuringError_;
}
MOZ_ASSERT(kind == ErrorKind::DestructuringWarning);
return destructuringWarning_;
}
template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::PossibleError::setResolved(
ErrorKind kind) {
error(kind).state_ = ErrorState::None;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::PossibleError::hasError(
ErrorKind kind) {
return error(kind).state_ == ErrorState::Pending;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler,
Unit>::PossibleError::hasPendingDestructuringError() {
return hasError(ErrorKind::Destructuring);
}
template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::PossibleError::setPending(
ErrorKind kind, const TokenPos& pos, unsigned errorNumber) {
if (hasError(kind)) {
return;
}
Error& err = error(kind);
err.offset_ = pos.begin;
err.errorNumber_ = errorNumber;
err.state_ = ErrorState::Pending;
}
template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::PossibleError::
setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber) {
setPending(ErrorKind::Destructuring, pos, errorNumber);
}
template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::PossibleError::
setPendingDestructuringWarningAt(const TokenPos& pos,
unsigned errorNumber) {
setPending(ErrorKind::DestructuringWarning, pos, errorNumber);
}
template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::PossibleError::
setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber) {
setPending(ErrorKind::Expression, pos, errorNumber);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::PossibleError::checkForError(
ErrorKind kind) {
if (!hasError(kind)) {
return true;
}
Error& err = error(kind);
parser_.errorAt(err.offset_, err.errorNumber_);
return false;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::PossibleError::checkForWarning(
ErrorKind kind) {
if (!hasError(kind)) {
return true;
}
Error& err = error(kind);
return parser_.extraWarningAt(err.offset_, err.errorNumber_);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler,
Unit>::PossibleError::checkForDestructuringErrorOrWarning() {
setResolved(ErrorKind::Expression);
return checkForError(ErrorKind::Destructuring) &&
checkForWarning(ErrorKind::DestructuringWarning);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler,
Unit>::PossibleError::checkForExpressionError() {
setResolved(ErrorKind::Destructuring);
setResolved(ErrorKind::DestructuringWarning);
return checkForError(ErrorKind::Expression);
}
template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::PossibleError::transferErrorTo(
ErrorKind kind, PossibleError* other) {
if (hasError(kind) && !other->hasError(kind)) {
Error& err = error(kind);
Error& otherErr = other->error(kind);
otherErr.offset_ = err.offset_;
otherErr.errorNumber_ = err.errorNumber_;
otherErr.state_ = err.state_;
}
}
template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::PossibleError::transferErrorsTo(
PossibleError* other) {
MOZ_ASSERT(other);
MOZ_ASSERT(this != other);
MOZ_ASSERT(&parser_ == &other->parser_,
"Can't transfer fields to an instance which belongs to a "
"different parser");
transferErrorTo(ErrorKind::Destructuring, other);
transferErrorTo(ErrorKind::Expression, other);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::bindingInitializer(
Node lhs, DeclarationKind kind, YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Assign));
if (kind == DeclarationKind::FormalParameter) {
pc_->functionBox()->hasParameterExprs = true;
}
Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (!rhs) {
return null();
}
BinaryNodeType assign =
handler_.newAssignment(ParseNodeKind::AssignExpr, lhs, rhs);
if (!assign) {
return null();
}
return assign;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::NameNodeType
GeneralParser<ParseHandler, Unit>::bindingIdentifier(
DeclarationKind kind, YieldHandling yieldHandling) {
RootedPropertyName name(cx_, bindingIdentifier(yieldHandling));
if (!name) {
return null();
}
NameNodeType binding = newName(name);
if (!binding || !noteDeclaredName(name, kind, pos())) {
return null();
}
return binding;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::bindingIdentifierOrPattern(
DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt) {
if (tt == TokenKind::LeftBracket) {
return arrayBindingPattern(kind, yieldHandling);
}
if (tt == TokenKind::LeftCurly) {
return objectBindingPattern(kind, yieldHandling);
}
if (!TokenKindIsPossibleIdentifierName(tt)) {
error(JSMSG_NO_VARIABLE_NAME);
return null();
}
return bindingIdentifier(kind, yieldHandling);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::objectBindingPattern(
DeclarationKind kind, YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
if (!CheckRecursionLimit(cx_)) {
return null();
}
uint32_t begin = pos().begin;
ListNodeType literal = handler_.newObjectLiteral(begin);
if (!literal) {
return null();
}
Maybe<DeclarationKind> declKind = Some(kind);
RootedAtom propAtom(cx_);
for (;;) {
TokenKind tt;
if (!tokenStream.peekToken(&tt)) {
return null();
}
if (tt == TokenKind::RightCurly) {
anyChars.addModifierException(TokenStream::OperandIsNone);
break;
}
if (tt == TokenKind::TripleDot) {
tokenStream.consumeKnownToken(TokenKind::TripleDot);
uint32_t begin = pos().begin;
TokenKind tt;
if (!tokenStream.getToken(&tt)) {
return null();
}
if (!TokenKindIsPossibleIdentifierName(tt)) {
error(JSMSG_NO_VARIABLE_NAME);
return null();
}
NameNodeType inner = bindingIdentifier(kind, yieldHandling);
if (!inner) {
return null();
}
if (!handler_.addSpreadProperty(literal, begin, inner)) {
return null();
}
} else {
TokenPos namePos = anyChars.nextToken().pos;
PropertyType propType;
Node propName = propertyName(yieldHandling, PropertyNameInPattern,
declKind, literal, &propType, &propAtom);
if (!propName) {
return null();
}
if (propType == PropertyType::Normal) {
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt);
if (!binding) {
return null();
}
bool hasInitializer;
if (!tokenStream.matchToken(&hasInitializer, TokenKind::Assign,
TokenStream::Operand)) {
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) {
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
NameNodeType binding = bindingIdentifier(kind, yieldHandling);
if (!binding) {
return null();
}
if (!handler_.addShorthand(literal, handler_.asName(propName),
binding)) {
return null();
}
} else if (propType == PropertyType::CoverInitializedName) {
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
NameNodeType binding = bindingIdentifier(kind, yieldHandling);
if (!binding) {
return null();
}
tokenStream.consumeKnownToken(TokenKind::Assign);
BinaryNodeType 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();
}
}
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Comma,
TokenStream::Operand)) {
return null();
}
if (!matched) {
break;
}
if (tt == TokenKind::TripleDot) {
error(JSMSG_REST_WITH_COMMA);
return null();
}
}
if (!mustMatchToken(TokenKind::RightCurly, TokenStream::Operand,
[this, begin](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
JSMSG_CURLY_OPENED, begin);
})) {
return null();
}
handler_.setEndPosition(literal, pos().end);
return literal;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::arrayBindingPattern(
DeclarationKind kind, YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
if (!CheckRecursionLimit(cx_)) {
return null();
}
uint32_t begin = pos().begin;
ListNodeType literal = handler_.newArrayLiteral(begin);
if (!literal) {
return null();
}
uint32_t index = 0;
for (;; index++) {
if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
error(JSMSG_ARRAY_INIT_TOO_BIG);
return null();
}
TokenKind tt;
if (!tokenStream.getToken(&tt)) {
return null();
}
if (tt == TokenKind::RightBracket) {
anyChars.ungetToken();
anyChars.addModifierException(TokenStream::OperandIsNone);
break;
}
if (tt == TokenKind::Comma) {
if (!handler_.addElision(literal, pos())) {
return null();
}
} else if (tt == TokenKind::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_.addSpreadElement(literal, begin, inner)) {
return null();
}
} else {
Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt);
if (!binding) {
return null();
}
bool hasInitializer;
if (!tokenStream.matchToken(&hasInitializer, TokenKind::Assign,
TokenStream::Operand)) {
return null();
}
Node element = hasInitializer
? bindingInitializer(binding, kind, yieldHandling)
: binding;
if (!element) {
return null();
}
handler_.addArrayElement(literal, element);
}
if (tt != TokenKind::Comma) {
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Comma,
TokenStream::Operand)) {
return null();
}
if (!matched) {
break;
}
if (tt == TokenKind::TripleDot) {
error(JSMSG_REST_WITH_COMMA);
return null();
}
}
}
if (!mustMatchToken(TokenKind::RightBracket, TokenStream::Operand,
[this, begin](TokenKind actual) {
this->reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
JSMSG_BRACKET_OPENED, begin);
})) {
return null();
}
handler_.setEndPosition(literal, pos().end);
return literal;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::destructuringDeclaration(
DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt) {
MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
MOZ_ASSERT(tt == TokenKind::LeftBracket || tt == TokenKind::LeftCurly);
return tt == TokenKind::LeftBracket
? arrayBindingPattern(kind, yieldHandling)
: objectBindingPattern(kind, yieldHandling);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::destructuringDeclarationWithoutYieldOrAwait(
DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt) {
uint32_t startYieldOffset = pc_->lastYieldOffset;
uint32_t startAwaitOffset = pc_->lastAwaitOffset;
Node res = destructuringDeclaration(kind, yieldHandling, tt);
if (res) {
if (pc_->lastYieldOffset != startYieldOffset) {
errorAt(pc_->lastYieldOffset, JSMSG_YIELD_IN_PARAMETER);
return null();
}
if (pc_->lastAwaitOffset != startAwaitOffset) {
errorAt(pc_->lastAwaitOffset, JSMSG_AWAIT_IN_PARAMETER);
return null();
}
}
return res;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::LexicalScopeNodeType
GeneralParser<ParseHandler, Unit>::blockStatement(YieldHandling yieldHandling,
unsigned errorNumber) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
uint32_t openedPos = pos().begin;
ParseContext::Statement stmt(pc_, StatementKind::Block);
ParseContext::Scope scope(this);
if (!scope.init(pc_)) {
return null();
}
ListNodeType list = statementList(yieldHandling);
if (!list) {
return null();
}
if (!mustMatchToken(TokenKind::RightCurly, TokenStream::Operand,
[this, errorNumber, openedPos](TokenKind actual) {
this->reportMissingClosing(
errorNumber, JSMSG_CURLY_OPENED, openedPos);
})) {
return null();
}
return finishLexicalScope(scope, list);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::expressionAfterForInOrOf(
ParseNodeKind forHeadKind, YieldHandling yieldHandling) {
MOZ_ASSERT(forHeadKind == ParseNodeKind::ForIn ||
forHeadKind == ParseNodeKind::ForOf);
Node pn = forHeadKind == ParseNodeKind::ForOf
? assignExpr(InAllowed, yieldHandling, TripledotProhibited)
: expr(InAllowed, yieldHandling, TripledotProhibited);
return pn;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::declarationPattern(
DeclarationKind declKind, TokenKind tt, bool initialDeclaration,
YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
Node* forInOrOfExpression) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket) ||
anyChars.isCurrentTokenType(TokenKind::LeftCurly));
Node pattern = destructuringDeclaration(declKind, yieldHandling, tt);
if (!pattern) {
return null();
}
if (initialDeclaration && forHeadKind) {
bool isForIn, isForOf;
if (!matchInOrOf(&isForIn, &isForOf)) {
return null();
}
if (isForIn) {
*forHeadKind = ParseNodeKind::ForIn;
} else if (isForOf) {
*forHeadKind = ParseNodeKind::ForOf;
} else {
*forHeadKind = ParseNodeKind::ForHead;
}
if (*forHeadKind != ParseNodeKind::ForHead) {
*forInOrOfExpression =
expressionAfterForInOrOf(*forHeadKind, yieldHandling);
if (!*forInOrOfExpression) {
return null();
}
return pattern;
}
}
if (!mustMatchToken(TokenKind::Assign, TokenStream::Operand,
JSMSG_BAD_DESTRUCT_DECL)) {
return null();
}
Node init = assignExpr(forHeadKind ? InProhibited : InAllowed, yieldHandling,
TripledotProhibited);
if (!init) {
return null();
}
return handler_.newAssignment(ParseNodeKind::AssignExpr, pattern, init);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
NameNodeType binding, DeclarationKind declKind, bool initialDeclaration,
YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
Node* forInOrOfExpression) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Assign));
uint32_t initializerOffset;
if (!tokenStream.peekOffset(&initializerOffset, TokenStream::Operand)) {
return null();
}
Node initializer = assignExpr(forHeadKind ? InProhibited : InAllowed,
yieldHandling, TripledotProhibited);
if (!initializer) {
return null();
}
if (forHeadKind && initialDeclaration) {
bool isForIn, isForOf;
if (!matchInOrOf(&isForIn, &isForOf)) {
return null();
}
if (isForOf) {
errorAt(initializerOffset, JSMSG_OF_AFTER_FOR_LOOP_DECL);
return null();
}
if (isForIn) {
if (DeclarationKindIsLexical(declKind)) {
errorAt(initializerOffset, JSMSG_IN_AFTER_LEXICAL_FOR_DECL);
return null();
}
*forHeadKind = ParseNodeKind::ForIn;
if (!strictModeErrorAt(initializerOffset,
JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) {
return null();
}
*forInOrOfExpression =
expressionAfterForInOrOf(ParseNodeKind::ForIn, yieldHandling);
if (!*forInOrOfExpression) {
return null();
}
} else {
*forHeadKind = ParseNodeKind::ForHead;
}
}
return handler_.finishInitializerAssignment(binding, initializer);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::declarationName(
DeclarationKind declKind, TokenKind tt, bool initialDeclaration,
YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
Node* forInOrOfExpression) {
if (!TokenKindIsPossibleIdentifier(tt)) {
error(JSMSG_NO_VARIABLE_NAME);
return null();
}
RootedPropertyName name(cx_, bindingIdentifier(yieldHandling));
if (!name) {
return null();
}
NameNodeType binding = newName(name);
if (!binding) {
return null();
}
TokenPos namePos = pos();
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Assign,
TokenStream::Operand)) {
return null();
}
Node declaration;
if (matched) {
declaration = initializerInNameDeclaration(
binding, declKind, initialDeclaration, yieldHandling, forHeadKind,
forInOrOfExpression);
if (!declaration) {
return null();
}
} else {
declaration = binding;
if (initialDeclaration && forHeadKind) {
bool isForIn, isForOf;
if (!matchInOrOf(&isForIn, &isForOf)) {
return null();
}
if (isForIn) {
*forHeadKind = ParseNodeKind::ForIn;
} else if (isForOf) {
*forHeadKind = ParseNodeKind::ForOf;
} else {
*forHeadKind = ParseNodeKind::ForHead;
}
}
if (forHeadKind && *forHeadKind != ParseNodeKind::ForHead) {
*forInOrOfExpression =
expressionAfterForInOrOf(*forHeadKind, yieldHandling);
if (!*forInOrOfExpression) {
return null();
}
} else {
if (declKind == DeclarationKind::Const) {
errorAt(namePos.begin, JSMSG_BAD_CONST_DECL);
return null();
}
}
}
if (!noteDeclaredName(name, declKind, namePos)) {
return null();
}
return declaration;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::declarationList(
YieldHandling yieldHandling, ParseNodeKind kind,
ParseNodeKind* forHeadKind ,
Node* forInOrOfExpression ) {
MOZ_ASSERT(kind == ParseNodeKind::VarStmt || kind == ParseNodeKind::LetDecl ||
kind == ParseNodeKind::ConstDecl);
DeclarationKind declKind;
switch (kind) {
case ParseNodeKind::VarStmt:
declKind = DeclarationKind::Var;
break;
case ParseNodeKind::ConstDecl:
declKind = DeclarationKind::Const;
break;
case ParseNodeKind::LetDecl:
declKind = DeclarationKind::Let;
break;
default:
MOZ_CRASH("Unknown declaration kind");
}
ListNodeType decl = handler_.newDeclarationList(kind, pos());
if (!decl) {
return null();
}
bool moreDeclarations;
bool initialDeclaration = true;
do {
MOZ_ASSERT_IF(!initialDeclaration && forHeadKind,
*forHeadKind == ParseNodeKind::ForHead);
TokenKind tt;
if (!tokenStream.getToken(&tt)) {
return null();
}
Node binding =
(tt == TokenKind::LeftBracket || tt == TokenKind::LeftCurly)
? declarationPattern(declKind, tt, initialDeclaration,
yieldHandling, forHeadKind,
forInOrOfExpression)
: declarationName(declKind, tt, initialDeclaration, yieldHandling,
forHeadKind, forInOrOfExpression);
if (!binding) {
return null();
}
handler_.addList(decl, binding);
if (forHeadKind && *forHeadKind != ParseNodeKind::ForHead) {
break;
}
initialDeclaration = false;
if (!tokenStream.matchToken(&moreDeclarations, TokenKind::Comma,
TokenStream::Operand)) {
return null();
}
} while (moreDeclarations);
return decl;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::lexicalDeclaration(
YieldHandling yieldHandling, DeclarationKind kind) {
MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let);
ListNodeType decl = declarationList(
yieldHandling, kind == DeclarationKind::Const ? ParseNodeKind::ConstDecl
: ParseNodeKind::LetDecl);
if (!decl || !matchOrInsertSemicolon()) {
return null();
}
return decl;
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::namedImportsOrNamespaceImport(
TokenKind tt, ListNodeType importSpecSet) {
if (tt == TokenKind::LeftCurly) {
while (true) {
if (!tokenStream.getToken(&tt)) {
return false;
}
if (tt == TokenKind::RightCurly) {
break;
}
if (!TokenKindIsPossibleIdentifierName(tt)) {
error(JSMSG_NO_IMPORT_NAME);
return false;
}
Rooted<PropertyName*> importName(cx_, anyChars.currentName());
TokenPos importNamePos = pos();
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::As)) {
return false;
}
if (matched) {
TokenKind afterAs;
if (!tokenStream.getToken(&afterAs)) {
return false;
}
if (!TokenKindIsPossibleIdentifierName(afterAs)) {
error(JSMSG_NO_BINDING_NAME);
return false;
}
} else {
if (IsKeyword(importName)) {
error(JSMSG_AS_AFTER_RESERVED_WORD, ReservedWordToCharZ(importName));
return false;
}
}
RootedPropertyName bindingAtom(cx_, importedBinding());
if (!bindingAtom) {
return false;
}
NameNodeType bindingName = newName(bindingAtom);
if (!bindingName) {
return false;
}
if (!noteDeclaredName(bindingAtom, DeclarationKind::Import, pos())) {
return false;
}
NameNodeType importNameNode = newName(importName, importNamePos);
if (!importNameNode) {
return false;
}
BinaryNodeType importSpec =
handler_.newImportSpec(importNameNode, bindingName);
if (!importSpec) {
return false;
}
handler_.addList(importSpecSet, importSpec);
TokenKind next;
if (!tokenStream.getToken(&next)) {
return false;
}
if (next == TokenKind::RightCurly) {
break;
}
if (next != TokenKind::Comma) {
error(JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
return false;
}
}
} else {
MOZ_ASSERT(tt == TokenKind::Mul);
if (!mustMatchToken(TokenKind::As, JSMSG_AS_AFTER_IMPORT_STAR)) {
return false;
}
if (!mustMatchToken(TokenKindIsPossibleIdentifierName,
JSMSG_NO_BINDING_NAME)) {
return false;
}
NameNodeType importName = newName(cx_->names().star);
if (!importName) {
return false;
}
RootedPropertyName bindingName(cx_, importedBinding());
if (!bindingName) {
return false;
}
NameNodeType bindingNameNode = newName(bindingName);
if (!bindingNameNode) {
return false;
}
if (!noteDeclaredName(bindingName, DeclarationKind::Const, pos())) {
return false;
}
pc_->varScope().lookupDeclaredName(bindingName)->value()->setClosedOver();
BinaryNodeType importSpec =
handler_.newImportSpec(importName, bindingNameNode);
if (!importSpec) {
return false;
}
handler_.addList(importSpecSet, importSpec);
}
return true;
}
template <typename Unit>
BinaryNode* Parser<FullParseHandler, Unit>::importDeclaration() {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
if (!pc_->atModuleLevel()) {
error(JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
return null();
}
uint32_t begin = pos().begin;
TokenKind tt;
if (!tokenStream.getToken(&tt)) {
return null();
}
ListNodeType importSpecSet =
handler_.newList(ParseNodeKind::ImportSpecList, pos());
if (!importSpecSet) {
return null();
}
if (tt == TokenKind::String) {
importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin;
} else {
if (tt == TokenKind::LeftCurly || tt == TokenKind::Mul) {
if (!namedImportsOrNamespaceImport(tt, importSpecSet)) {
return null();
}
} else if (TokenKindIsPossibleIdentifierName(tt)) {
Node importName = newName(cx_->names().default_);
if (!importName) {
return null();
}
RootedPropertyName bindingAtom(cx_, importedBinding());
if (!bindingAtom) {
return null();
}
Node bindingName = newName(bindingAtom);
if (!bindingName) {
return null();
}
if (!noteDeclaredName(bindingAtom, DeclarationKind::Import, pos())) {
return null();
}
BinaryNodeType importSpec =
handler_.newImportSpec(importName, bindingName);
if (!importSpec) {
return null();
}
handler_.addList(importSpecSet, importSpec);
if (!tokenStream.peekToken(&tt)) {
return null();
}
if (tt == TokenKind::Comma) {
tokenStream.consumeKnownToken(tt);
if (!tokenStream.getToken(&tt)) {
return null();
}
if (tt != TokenKind::LeftCurly && tt != TokenKind::Mul) {
error(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT);
return null();
}
if (!namedImportsOrNamespaceImport(tt, importSpecSet)) {
return null();
}
}
} else {
error(JSMSG_DECLARATION_AFTER_IMPORT);
return null();
}
if (!mustMatchToken(TokenKind::From, JSMSG_FROM_AFTER_IMPORT_CLAUSE)) {
return null();
}
if (!mustMatchToken(TokenKind::String, JSMSG_MODULE_SPEC_AFTER_FROM)) {
return null();
}
}
NameNodeType moduleSpec = stringLiteral();
if (!moduleSpec) {
return null();
}
if (!matchOrInsertSemicolon()) {
return null();
}
BinaryNode* node = handler_.newImportDeclaration(importSpecSet, moduleSpec,
TokenPos(begin, pos().end));
if (!node || !pc_->sc()->asModuleContext()->builder.processImport(node)) {
return null();
}
return node;
}
template <typename Unit>
inline SyntaxParseHandler::BinaryNodeType
Parser<SyntaxParseHandler, Unit>::importDeclaration() {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return SyntaxParseHandler::NodeFailure;
}
template <class ParseHandler, typename Unit>
inline typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::importDeclaration() {
return asFinalParser()->importDeclaration();
}
template <class ParseHandler, typename Unit>
inline typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::importDeclarationOrImportExpr(
YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
TokenKind tt;
if (!tokenStream.peekToken(&tt)) {
return null();
}
if (tt == TokenKind::Dot || tt == TokenKind::LeftParen) {
return expressionStatement(yieldHandling);
}
return importDeclaration();
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::checkExportedName(JSAtom* exportName) {
if (!pc_->sc()->asModuleContext()->builder.hasExportedName(exportName)) {
return true;
}
UniqueChars str = AtomToPrintableString(cx_, exportName);
if (!str) {
return false;
}
error(JSMSG_DUPLICATE_EXPORT_NAME, str.get());
return false;
}
template <typename Unit>
inline bool Parser<SyntaxParseHandler, Unit>::checkExportedName(
JSAtom* exportName) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <class ParseHandler, typename Unit>
inline bool GeneralParser<ParseHandler, Unit>::checkExportedName(
JSAtom* exportName) {
return asFinalParser()->checkExportedName(exportName);
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::checkExportedNamesForArrayBinding(
ListNode* array) {
MOZ_ASSERT(array->isKind(ParseNodeKind::ArrayExpr));
for (ParseNode* node : array->contents()) {
if (node->isKind(ParseNodeKind::Elision)) {
continue;
}
ParseNode* binding;
if (node->isKind(ParseNodeKind::Spread)) {
binding = node->as<UnaryNode>().kid();
} else if (node->isKind(ParseNodeKind::AssignExpr)) {
binding = node->as<AssignmentNode>().left();
} else {
binding = node;
}
if (!checkExportedNamesForDeclaration(binding)) {
return false;
}
}
return true;
}
template <typename Unit>
inline bool Parser<SyntaxParseHandler, Unit>::checkExportedNamesForArrayBinding(
ListNodeType array) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <class ParseHandler, typename Unit>
inline bool
GeneralParser<ParseHandler, Unit>::checkExportedNamesForArrayBinding(
ListNodeType array) {
return asFinalParser()->checkExportedNamesForArrayBinding(array);
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::checkExportedNamesForObjectBinding(
ListNode* obj) {
MOZ_ASSERT(obj->isKind(ParseNodeKind::ObjectExpr));
for (ParseNode* node : obj->contents()) {
MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) ||
node->isKind(ParseNodeKind::Colon) ||
node->isKind(ParseNodeKind::Shorthand) ||
node->isKind(ParseNodeKind::Spread));
ParseNode* target;
if (node->isKind(ParseNodeKind::Spread)) {
target = node->as<UnaryNode>().kid();
} else {
if (node->isKind(ParseNodeKind::MutateProto)) {
target = node->as<UnaryNode>().kid();
} else {
target = node->as<BinaryNode>().right();
}
if (target->isKind(ParseNodeKind::AssignExpr)) {
target = target->as<AssignmentNode>().left();
}
}
if (!checkExportedNamesForDeclaration(target)) {
return false;
}
}
return true;
}
template <typename Unit>
inline bool Parser<SyntaxParseHandler,
Unit>::checkExportedNamesForObjectBinding(ListNodeType obj) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <class ParseHandler, typename Unit>
inline bool
GeneralParser<ParseHandler, Unit>::checkExportedNamesForObjectBinding(
ListNodeType obj) {
return asFinalParser()->checkExportedNamesForObjectBinding(obj);
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::checkExportedNamesForDeclaration(
ParseNode* node) {
if (node->isKind(ParseNodeKind::Name)) {
if (!checkExportedName(node->as<NameNode>().atom())) {
return false;
}
} else if (node->isKind(ParseNodeKind::ArrayExpr)) {
if (!checkExportedNamesForArrayBinding(&node->as<ListNode>())) {
return false;
}
} else {
MOZ_ASSERT(node->isKind(ParseNodeKind::ObjectExpr));
if (!checkExportedNamesForObjectBinding(&node->as<ListNode>())) {
return false;
}
}
return true;
}
template <typename Unit>
inline bool Parser<SyntaxParseHandler, Unit>::checkExportedNamesForDeclaration(
Node node) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <class ParseHandler, typename Unit>
inline bool GeneralParser<ParseHandler, Unit>::checkExportedNamesForDeclaration(
Node node) {
return asFinalParser()->checkExportedNamesForDeclaration(node);
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::checkExportedNamesForDeclarationList(
ListNode* node) {
for (ParseNode* binding : node->contents()) {
if (binding->isKind(ParseNodeKind::AssignExpr)) {
binding = binding->as<AssignmentNode>().left();
} else {
MOZ_ASSERT(binding->isKind(ParseNodeKind::Name));
}
if (!checkExportedNamesForDeclaration(binding)) {
return false;
}
}
return true;
}
template <typename Unit>
inline bool
Parser<SyntaxParseHandler, Unit>::checkExportedNamesForDeclarationList(
ListNodeType node) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <class ParseHandler, typename Unit>
inline bool
GeneralParser<ParseHandler, Unit>::checkExportedNamesForDeclarationList(
ListNodeType node) {
return asFinalParser()->checkExportedNamesForDeclarationList(node);
}
template <typename Unit>
inline bool Parser<FullParseHandler, Unit>::checkExportedNameForClause(
NameNode* nameNode) {
return checkExportedName(nameNode->atom());
}
template <typename Unit>
inline bool Parser<SyntaxParseHandler, Unit>::checkExportedNameForClause(
NameNodeType nameNode) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <class ParseHandler, typename Unit>
inline bool GeneralParser<ParseHandler, Unit>::checkExportedNameForClause(
NameNodeType nameNode) {
return asFinalParser()->checkExportedNameForClause(nameNode);
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::checkExportedNameForFunction(
FunctionNode* funNode) {
return checkExportedName(funNode->funbox()->function()->explicitName());
}
template <typename Unit>
inline bool Parser<SyntaxParseHandler, Unit>::checkExportedNameForFunction(
FunctionNodeType funNode) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <class ParseHandler, typename Unit>
inline bool GeneralParser<ParseHandler, Unit>::checkExportedNameForFunction(
FunctionNodeType funNode) {
return asFinalParser()->checkExportedNameForFunction(funNode);
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::checkExportedNameForClass(
ClassNode* classNode) {
MOZ_ASSERT(classNode->names());
return checkExportedName(classNode->names()->innerBinding()->atom());
}
template <typename Unit>
inline bool Parser<SyntaxParseHandler, Unit>::checkExportedNameForClass(
ClassNodeType classNode) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <class ParseHandler, typename Unit>
inline bool GeneralParser<ParseHandler, Unit>::checkExportedNameForClass(
ClassNodeType classNode) {
return asFinalParser()->checkExportedNameForClass(classNode);
}
template <>
inline bool PerHandlerParser<FullParseHandler>::processExport(ParseNode* node) {
return pc_->sc()->asModuleContext()->builder.processExport(node);
}
template <>
inline bool PerHandlerParser<SyntaxParseHandler>::processExport(Node node) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <>
inline bool PerHandlerParser<FullParseHandler>::processExportFrom(
BinaryNodeType node) {
return pc_->sc()->asModuleContext()->builder.processExportFrom(node);
}
template <>
inline bool PerHandlerParser<SyntaxParseHandler>::processExportFrom(
BinaryNodeType node) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::exportFrom(uint32_t begin, Node specList) {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::From));
if (!abortIfSyntaxParser()) {
return null();
}
if (!mustMatchToken(TokenKind::String, JSMSG_MODULE_SPEC_AFTER_FROM)) {
return null();
}
NameNodeType moduleSpec = stringLiteral();
if (!moduleSpec) {
return null();
}
if (!matchOrInsertSemicolon()) {
return null();
}
BinaryNodeType node =
handler_.newExportFromDeclaration(begin, specList, moduleSpec);
if (!node) {
return null();
}
if (!processExportFrom(node)) {
return null();
}
return node;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::exportBatch(uint32_t begin) {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Mul));
ListNodeType kid = handler_.newList(ParseNodeKind::ExportSpecList, pos());
if (!kid) {
return null();
}
NullaryNodeType exportSpec = handler_.newExportBatchSpec(pos());
if (!exportSpec) {
return null();
}
handler_.addList(kid, exportSpec);
if (!mustMatchToken(TokenKind::From, JSMSG_FROM_AFTER_EXPORT_STAR)) {
return null();
}
return exportFrom(begin, kid);
}
template <typename Unit>
bool Parser<FullParseHandler, Unit>::checkLocalExportNames(ListNode* node) {
for (ParseNode* next : node->contents()) {
ParseNode* name = next->as<BinaryNode>().left();
MOZ_ASSERT(name->isKind(ParseNodeKind::Name));
RootedPropertyName ident(cx_,
name->as<NameNode>().atom()->asPropertyName());
if (!checkLocalExportName(ident, name->pn_pos.begin)) {
return false;
}
}
return true;
}
template <typename Unit>
bool Parser<SyntaxParseHandler, Unit>::checkLocalExportNames(
ListNodeType node) {
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return false;
}
template <class ParseHandler, typename Unit>
inline bool GeneralParser<ParseHandler, Unit>::checkLocalExportNames(
ListNodeType node) {
return asFinalParser()->checkLocalExportNames(node);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::exportClause(
uint32_t begin) {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
ListNodeType kid = handler_.newList(ParseNodeKind::ExportSpecList, pos());
if (!kid) {
return null();
}
TokenKind tt;
while (true) {
if (!tokenStream.getToken(&tt)) {
return null();
}
if (tt == TokenKind::RightCurly) {
break;
}
if (!TokenKindIsPossibleIdentifierName(tt)) {
error(JSMSG_NO_BINDING_NAME);
return null();
}
NameNodeType bindingName = newName(anyChars.currentName());
if (!bindingName) {
return null();
}
bool foundAs;
if (!tokenStream.matchToken(&foundAs, TokenKind::As)) {
return null();
}
if (foundAs) {
if (!mustMatchToken(TokenKindIsPossibleIdentifierName,
JSMSG_NO_EXPORT_NAME)) {
return null();
}
}
NameNodeType exportName = newName(anyChars.currentName());
if (!exportName) {
return null();
}
if (!checkExportedNameForClause(exportName)) {
return null();
}
BinaryNodeType exportSpec = handler_.newExportSpec(bindingName, exportName);
if (!exportSpec) {
return null();
}
handler_.addList(kid, exportSpec);
TokenKind next;
if (!tokenStream.getToken(&next)) {
return null();
}
if (next == TokenKind::RightCurly) {
break;
}
if (next != TokenKind::Comma) {
error(JSMSG_RC_AFTER_EXPORT_SPEC_LIST);
return null();
}
}
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::From,
TokenStream::Operand)) {
return null();
}
if (matched) {
return exportFrom(begin, kid);
}
if (!matchOrInsertSemicolon()) {
return null();
}
if (!checkLocalExportNames(kid)) {
return null();
}
UnaryNodeType node =
handler_.newExportDeclaration(kid, TokenPos(begin, pos().end));
if (!node) {
return null();
}
if (!processExport(node)) {
return null();
}
return node;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::UnaryNodeType
GeneralParser<ParseHandler, Unit>::exportVariableStatement(uint32_t begin) {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Var));
ListNodeType kid = declarationList(YieldIsName, ParseNodeKind::VarStmt);
if (!kid) {
return null();
}
if (!matchOrInsertSemicolon()) {
return null();
}
if (!checkExportedNamesForDeclarationList(kid)) {
return null();
}
UnaryNodeType node =
handler_.newExportDeclaration(kid, TokenPos(begin, pos().end));
if (!node) {
return null();
}
if (!processExport(node)) {
return null();
}
return node;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::UnaryNodeType
GeneralParser<ParseHandler, Unit>::exportFunctionDeclaration(
uint32_t begin, uint32_t toStringStart,
FunctionAsyncKind asyncKind ) {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
Node kid = functionStmt(toStringStart, YieldIsName, NameRequired, asyncKind);
if (!kid) {
return null();
}
if (!checkExportedNameForFunction(handler_.asFunction(kid))) {
return null();
}
UnaryNodeType node =
handler_.newExportDeclaration(kid, TokenPos(begin, pos().end));
if (!node) {
return null();
}
if (!processExport(node)) {
return null();
}
return node;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::UnaryNodeType
GeneralParser<ParseHandler, Unit>::exportClassDeclaration(uint32_t begin) {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Class));
ClassNodeType kid =
classDefinition(YieldIsName, ClassStatement, NameRequired);
if (!kid) {
return null();
}
if (!checkExportedNameForClass(kid)) {
return null();
}
UnaryNodeType node =
handler_.newExportDeclaration(kid, TokenPos(begin, pos().end));
if (!node) {
return null();
}
if (!processExport(node)) {
return null();
}
return node;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::UnaryNodeType
GeneralParser<ParseHandler, Unit>::exportLexicalDeclaration(
uint32_t begin, DeclarationKind kind) {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let);
MOZ_ASSERT_IF(kind == DeclarationKind::Const,
anyChars.isCurrentTokenType(TokenKind::Const));
MOZ_ASSERT_IF(kind == DeclarationKind::Let,
anyChars.isCurrentTokenType(TokenKind::Let));
ListNodeType kid = lexicalDeclaration(YieldIsName, kind);
if (!kid) {
return null();
}
if (!checkExportedNamesForDeclarationList(kid)) {
return null();
}
UnaryNodeType node =
handler_.newExportDeclaration(kid, TokenPos(begin, pos().end));
if (!node) {
return null();
}
if (!processExport(node)) {
return null();
}
return node;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::exportDefaultFunctionDeclaration(
uint32_t begin, uint32_t toStringStart,
FunctionAsyncKind asyncKind ) {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
Node kid =
functionStmt(toStringStart, YieldIsName, AllowDefaultName, asyncKind);
if (!kid) {
return null();
}
BinaryNodeType node = handler_.newExportDefaultDeclaration(
kid, null(), TokenPos(begin, pos().end));
if (!node) {
return null();
}
if (!processExport(node)) {
return null();
}
return node;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::exportDefaultClassDeclaration(
uint32_t begin) {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Class));
ClassNodeType kid =
classDefinition(YieldIsName, ClassStatement, AllowDefaultName);
if (!kid) {
return null();
}
BinaryNodeType node = handler_.newExportDefaultDeclaration(
kid, null(), TokenPos(begin, pos().end));
if (!node) {
return null();
}
if (!processExport(node)) {
return null();
}
return node;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::exportDefaultAssignExpr(uint32_t begin) {
if (!abortIfSyntaxParser()) {
return null();
}
HandlePropertyName name = cx_->names().default_;
NameNodeType nameNode = newName(name);
if (!nameNode) {
return null();
}
if (!noteDeclaredName(name, DeclarationKind::Const, pos())) {
return null();
}
Node kid = assignExpr(InAllowed, YieldIsName, TripledotProhibited);
if (!kid) {
return null();
}
if (!matchOrInsertSemicolon()) {
return null();
}
BinaryNodeType node = handler_.newExportDefaultDeclaration(
kid, nameNode, TokenPos(begin, pos().end));
if (!node) {
return null();
}
if (!processExport(node)) {
return null();
}
return node;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::exportDefault(uint32_t begin) {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Default));
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
if (!checkExportedName(cx_->names().default_)) {
return null();
}
switch (tt) {
case TokenKind::Function:
return exportDefaultFunctionDeclaration(begin, pos().begin);
case TokenKind::Async: {
TokenKind nextSameLine = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
return null();
}
if (nextSameLine == TokenKind::Function) {
uint32_t toStringStart = pos().begin;
tokenStream.consumeKnownToken(TokenKind::Function);
return exportDefaultFunctionDeclaration(
begin, toStringStart, FunctionAsyncKind::AsyncFunction);
}
anyChars.ungetToken();
return exportDefaultAssignExpr(begin);
}
case TokenKind::Class:
return exportDefaultClassDeclaration(begin);
default:
anyChars.ungetToken();
return exportDefaultAssignExpr(begin);
}
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::exportDeclaration() {
if (!abortIfSyntaxParser()) {
return null();
}
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::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 TokenKind::Mul:
return exportBatch(begin);
case TokenKind::LeftCurly:
return exportClause(begin);
case TokenKind::Var:
return exportVariableStatement(begin);
case TokenKind::Function:
return exportFunctionDeclaration(begin, pos().begin);
case TokenKind::Async: {
TokenKind nextSameLine = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
return null();
}
if (nextSameLine == TokenKind::Function) {
uint32_t toStringStart = pos().begin;
tokenStream.consumeKnownToken(TokenKind::Function);
return exportFunctionDeclaration(begin, toStringStart,
FunctionAsyncKind::AsyncFunction);
}
error(JSMSG_DECLARATION_AFTER_EXPORT);
return null();
}
case TokenKind::Class:
return exportClassDeclaration(begin);
case TokenKind::Const:
return exportLexicalDeclaration(begin, DeclarationKind::Const);
case TokenKind::Let:
return exportLexicalDeclaration(begin, DeclarationKind::Let);
case TokenKind::Default:
return exportDefault(begin);
default:
error(JSMSG_DECLARATION_AFTER_EXPORT);
return null();
}
}
template <class ParseHandler, typename Unit>
typename ParseHandler::UnaryNodeType
GeneralParser<ParseHandler, Unit>::expressionStatement(
YieldHandling yieldHandling, InvokedPrediction invoked) {
anyChars.ungetToken();
Node pnexpr = expr(InAllowed, yieldHandling, TripledotProhibited,
nullptr, invoked);
if (!pnexpr) {
return null();
}
if (!matchOrInsertSemicolon()) {
return null();
}
return handler_.newExprStatement(pnexpr, pos().end);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::consequentOrAlternative(
YieldHandling yieldHandling) {
TokenKind next;
if (!tokenStream.peekToken(&next, TokenStream::Operand)) {
return null();
}
if (next == TokenKind::Function) {
tokenStream.consumeKnownToken(next, TokenStream::Operand);
if (pc_->sc()->strict()) {
error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
return null();
}
TokenKind maybeStar;
if (!tokenStream.peekToken(&maybeStar)) {
return null();
}
if (maybeStar == TokenKind::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();
}
ListNodeType block = handler_.newStatementList(funcPos);
if (!block) {
return null();
}
handler_.addStatementToList(block, fun);
return finishLexicalScope(scope, block);
}
return statement(yieldHandling);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::TernaryNodeType
GeneralParser<ParseHandler, Unit>::ifStatement(YieldHandling yieldHandling) {
Vector<Node, 4> condList(cx_), thenList(cx_);
Vector<uint32_t, 4> posList(cx_);
Node elseBranch;
ParseContext::Statement stmt(pc_, StatementKind::If);
while (true) {
uint32_t begin = pos().begin;
Node cond = condition(InAllowed, yieldHandling);
if (!cond) {
return null();
}
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt == TokenKind::Semi) {
if (!extraWarning(JSMSG_EMPTY_CONSEQUENT)) {
return null();
}
}
Node thenBranch = consequentOrAlternative(yieldHandling);
if (!thenBranch) {
return null();
}
if (!condList.append(cond) || !thenList.append(thenBranch) ||
!posList.append(begin)) {
return null();
}
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Else,
TokenStream::Operand)) {
return null();
}
if (matched) {
if (!tokenStream.matchToken(&matched, TokenKind::If,
TokenStream::Operand)) {
return null();
}
if (matched) {
continue;
}
elseBranch = consequentOrAlternative(yieldHandling);
if (!elseBranch) {
return null();
}
} else {
elseBranch = null();
}
break;
}
TernaryNodeType ifNode;
for (int i = condList.length() - 1; i >= 0; i--) {
ifNode = handler_.newIfStatement(posList[i], condList[i], thenList[i],
elseBranch);
if (!ifNode) {
return null();
}
elseBranch = ifNode;
}
return ifNode;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::doWhileStatement(
YieldHandling yieldHandling) {
uint32_t begin = pos().begin;
ParseContext::Statement stmt(pc_, StatementKind::DoLoop);
Node body = statement(yieldHandling);
if (!body) {
return null();
}
if (!mustMatchToken(TokenKind::While, TokenStream::Operand,
JSMSG_WHILE_AFTER_DO)) {
return null();
}
Node cond = condition(InAllowed, yieldHandling);
if (!cond) {
return null();
}
bool ignored;
if (!tokenStream.matchToken(&ignored, TokenKind::Semi,
TokenStream::Operand)) {
return null();
}
return handler_.newDoWhileStatement(body, cond, TokenPos(begin, pos().end));
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::whileStatement(YieldHandling yieldHandling) {
uint32_t begin = pos().begin;
ParseContext::Statement stmt(pc_, StatementKind::WhileLoop);
Node cond = condition(InAllowed, yieldHandling);
if (!cond) {
return null();
}
Node body = statement(yieldHandling);
if (!body) {
return null();
}
return handler_.newWhileStatement(begin, cond, body);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::matchInOrOf(bool* isForInp,
bool* isForOfp) {
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return false;
}
*isForInp = tt == TokenKind::In;
*isForOfp = tt == TokenKind::Of;
if (!*isForInp && !*isForOfp) {
anyChars.ungetToken();
}
MOZ_ASSERT_IF(*isForInp || *isForOfp, *isForInp != *isForOfp);
return true;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::forHeadStart(
YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
Node* forInitialPart, Maybe<ParseContext::Scope>& forLoopLexicalScope,
Node* forInOrOfExpression) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftParen));
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
return false;
}
if (tt == TokenKind::Semi) {
*forInitialPart = null();
*forHeadKind = ParseNodeKind::ForHead;
return true;
}
if (tt == TokenKind::Var) {
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
*forInitialPart = declarationList(yieldHandling, ParseNodeKind::VarStmt,
forHeadKind, forInOrOfExpression);
return *forInitialPart != null();
}
bool parsingLexicalDeclaration = false;
bool letIsIdentifier = false;
if (tt == TokenKind::Const) {
parsingLexicalDeclaration = true;
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
} else if (tt == TokenKind::Let) {
tokenStream.consumeKnownToken(TokenKind::Let, TokenStream::Operand);
TokenKind next;
if (!tokenStream.peekToken(&next)) {
return false;
}
parsingLexicalDeclaration = nextTokenContinuesLetDeclaration(next);
if (!parsingLexicalDeclaration) {
anyChars.ungetToken();
letIsIdentifier = true;
}
}
if (parsingLexicalDeclaration) {
forLoopLexicalScope.emplace(this);
if (!forLoopLexicalScope->init(pc_)) {
return false;
}
ParseContext::Statement forHeadStmt(pc_, StatementKind::ForLoopLexicalHead);
*forInitialPart =
declarationList(yieldHandling,
tt == TokenKind::Const ? ParseNodeKind::ConstDecl
: ParseNodeKind::LetDecl,
forHeadKind, forInOrOfExpression);
return *forInitialPart != null();
}
uint32_t exprOffset;
if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand)) {
return false;
}
PossibleError possibleError(*this);
*forInitialPart =
expr(InProhibited, yieldHandling, TripledotProhibited, &possibleError);
if (!*forInitialPart) {
return false;
}
bool isForIn, isForOf;
if (!matchInOrOf(&isForIn, &isForOf)) {
return false;
}
if (!isForIn && !isForOf) {
if (!possibleError.checkForExpressionError()) {
return false;
}
*forHeadKind = ParseNodeKind::ForHead;
return true;
}
MOZ_ASSERT(isForIn != isForOf);
if (isForOf && letIsIdentifier) {
errorAt(exprOffset, JSMSG_LET_STARTING_FOROF_LHS);
return false;
}
*forHeadKind = isForIn ? ParseNodeKind::ForIn : ParseNodeKind::ForOf;
if (handler_.isUnparenthesizedDestructuringPattern(*forInitialPart)) {
if (!possibleError.checkForDestructuringErrorOrWarning()) {
return false;
}
} else if (handler_.isName(*forInitialPart)) {
if (const char* chars = nameIsArgumentsOrEval(*forInitialPart)) {
if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) {
return false;
}
}
handler_.adjustGetToSet(*forInitialPart);
} else if (handler_.isPropertyAccess(*forInitialPart)) {
} 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;
}
*forInOrOfExpression = expressionAfterForInOrOf(*forHeadKind, yieldHandling);
return *forInOrOfExpression != null();
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::forStatement(
YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::For));
uint32_t begin = pos().begin;
ParseContext::Statement stmt(pc_, StatementKind::ForLoop);
IteratorKind iterKind = IteratorKind::Sync;
unsigned iflags = 0;
if (pc_->isAsync()) {
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Await)) {
return null();
}
if (matched) {
iflags |= JSITER_FORAWAITOF;
iterKind = IteratorKind::Async;
}
}
if (!mustMatchToken(TokenKind::LeftParen, [this](TokenKind actual) {
this->error((actual == TokenKind::Await && !this->pc_->isAsync())
? JSMSG_FOR_AWAIT_OUTSIDE_ASYNC
: JSMSG_PAREN_AFTER_FOR);
})) {
return null();
}
ParseNodeKind headKind;
Node startNode;
Maybe<ParseContext::Scope> forLoopLexicalScope;
Node iteratedExpr;
if (!forHeadStart(yieldHandling, &headKind, &startNode, forLoopLexicalScope,
&iteratedExpr)) {
return null();
}
MOZ_ASSERT(headKind == ParseNodeKind::ForIn ||
headKind == ParseNodeKind::ForOf ||
headKind == ParseNodeKind::ForHead);
if (iterKind == IteratorKind::Async && headKind != ParseNodeKind::ForOf) {
errorAt(begin, JSMSG_FOR_AWAIT_NOT_OF);
return null();
}
TernaryNodeType forHead;
if (headKind == ParseNodeKind::ForHead) {
Node init = startNode;
if (!mustMatchToken(TokenKind::Semi, TokenStream::Operand,
JSMSG_SEMI_AFTER_FOR_INIT)) {
return null();
}
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
return null();
}
Node test;
if (tt == TokenKind::Semi) {
test = null();
} else {
test = expr(InAllowed, yieldHandling, TripledotProhibited);
if (!test) {
return null();
}
}
if (!mustMatchToken(TokenKind::Semi, TokenStream::Operand,
JSMSG_SEMI_AFTER_FOR_COND)) {
return null();
}
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
return null();
}
Node update;
if (tt == TokenKind::RightParen) {
update = null();
} else {
update = expr(InAllowed, yieldHandling, TripledotProhibited);
if (!update) {
return null();
}
}
if (!mustMatchToken(TokenKind::RightParen, TokenStream::Operand,
JSMSG_PAREN_AFTER_FOR_CTRL)) {
return null();
}
TokenPos headPos(begin, pos().end);
forHead = handler_.newForHead(init, test, update, headPos);
if (!forHead) {
return null();
}
} else {
MOZ_ASSERT(headKind == ParseNodeKind::ForIn ||
headKind == ParseNodeKind::ForOf);
Node target = startNode;
if (headKind == ParseNodeKind::ForIn) {
stmt.refineForKind(StatementKind::ForInLoop);
} else {
stmt.refineForKind(StatementKind::ForOfLoop);
}
if (!mustMatchToken(TokenKind::RightParen, TokenStream::Operand,
JSMSG_PAREN_AFTER_FOR_CTRL)) {
return null();
}
TokenPos headPos(begin, pos().end);
forHead =
handler_.newForInOrOfHead(headKind, target, iteratedExpr, headPos);
if (!forHead) {
return null();
}
}
Node body = statement(yieldHandling);
if (!body) {
return null();
}
ForNodeType forLoop = handler_.newForStatement(begin, forHead, body, iflags);
if (!forLoop) {
return null();
}
if (forLoopLexicalScope) {
return finishLexicalScope(*forLoopLexicalScope, forLoop);
}
return forLoop;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::SwitchStatementType
GeneralParser<ParseHandler, Unit>::switchStatement(
YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Switch));
uint32_t begin = pos().begin;
if (!mustMatchToken(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_SWITCH)) {
return null();
}
Node discriminant =
exprInParens(InAllowed, yieldHandling, TripledotProhibited);
if (!discriminant) {
return null();
}
if (!mustMatchToken(TokenKind::RightParen, TokenStream::Operand,
JSMSG_PAREN_AFTER_SWITCH)) {
return null();
}
if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_SWITCH)) {
return null();
}
ParseContext::Statement stmt(pc_, StatementKind::Switch);
ParseContext::Scope scope(this);
if (!scope.init(pc_)) {
return null();
}
ListNodeType caseList = handler_.newStatementList(pos());
if (!caseList) {
return null();
}
bool seenDefault = false;
TokenKind tt;
while (true) {
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt == TokenKind::RightCurly) {
break;
}
uint32_t caseBegin = pos().begin;
Node caseExpr;
switch (tt) {
case TokenKind::Default:
if (seenDefault) {
error(JSMSG_TOO_MANY_DEFAULTS);
return null();
}
seenDefault = true;
caseExpr = null(); break;
case TokenKind::Case:
caseExpr = expr(InAllowed, yieldHandling, TripledotProhibited);
if (!caseExpr) {
return null();
}
break;
default:
error(JSMSG_BAD_SWITCH);
return null();
}
if (!mustMatchToken(TokenKind::Colon, TokenStream::Operand,
JSMSG_COLON_AFTER_CASE)) {
return null();
}
ListNodeType body = handler_.newStatementList(pos());
if (!body) {
return null();
}
bool afterReturn = false;
bool warnedAboutStatementsAfterReturn = false;
uint32_t statementBegin = 0;
while (true) {
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt == TokenKind::RightCurly || tt == TokenKind::Case ||
tt == TokenKind::Default) {
break;
}
if (afterReturn) {
if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand)) {
return null();
}
}
Node stmt = statementListItem(yieldHandling);
if (!stmt) {
return null();
}
if (!warnedAboutStatementsAfterReturn) {
if (afterReturn) {
if (!handler_.isStatementPermittedAfterReturnStatement(stmt)) {
if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) {
return null();
}
warnedAboutStatementsAfterReturn = true;
}
} else if (handler_.isReturnStatement(stmt)) {
afterReturn = true;
}
}
handler_.addStatementToList(body, stmt);
}
CaseClauseType caseClause =
handler_.newCaseOrDefault(caseBegin, caseExpr, body);
if (!caseClause) {
return null();
}
handler_.addCaseStatementToList(caseList, caseClause);
}
LexicalScopeNodeType lexicalForCaseList = finishLexicalScope(scope, caseList);
if (!lexicalForCaseList) {
return null();
}
handler_.setEndPosition(lexicalForCaseList, pos().end);
return handler_.newSwitchStatement(begin, discriminant, lexicalForCaseList,
seenDefault);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ContinueStatementType
GeneralParser<ParseHandler, Unit>::continueStatement(
YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Continue));
uint32_t begin = pos().begin;
RootedPropertyName label(cx_);
if (!matchLabel(yieldHandling, &label)) {
return null();
}
auto validity = pc_->checkContinueStatement(label);
if (validity.isErr()) {
switch (validity.unwrapErr()) {
case ParseContext::ContinueStatementError::NotInALoop:
errorAt(begin, JSMSG_BAD_CONTINUE);
break;
case ParseContext::ContinueStatementError::LabelNotFound:
error(JSMSG_LABEL_NOT_FOUND);
break;
}
return null();
}
if (!matchOrInsertSemicolon()) {
return null();
}
return handler_.newContinueStatement(label, TokenPos(begin, pos().end));
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BreakStatementType
GeneralParser<ParseHandler, Unit>::breakStatement(YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Break));
uint32_t begin = pos().begin;
RootedPropertyName label(cx_);
if (!matchLabel(yieldHandling, &label)) {
return null();
}
auto validity = pc_->checkBreakStatement(label);
if (validity.isErr()) {
switch (validity.unwrapErr()) {
case ParseContext::BreakStatementError::ToughBreak:
errorAt(begin, JSMSG_TOUGH_BREAK);
return null();
case ParseContext::BreakStatementError::LabelNotFound:
error(JSMSG_LABEL_NOT_FOUND);
return null();
}
}
if (!matchOrInsertSemicolon()) {
return null();
}
return handler_.newBreakStatement(label, TokenPos(begin, pos().end));
}
template <class ParseHandler, typename Unit>
typename ParseHandler::UnaryNodeType
GeneralParser<ParseHandler, Unit>::returnStatement(
YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Return));
uint32_t begin = pos().begin;
MOZ_ASSERT(pc_->isFunctionBox());
pc_->functionBox()->usesReturn = true;
Node exprNode;
TokenKind tt = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) {
return null();
}
switch (tt) {
case TokenKind::Eol:
case TokenKind::Eof:
case TokenKind::Semi:
case TokenKind::RightCurly:
exprNode = null();
break;
default: {
exprNode = expr(InAllowed, yieldHandling, TripledotProhibited);
if (!exprNode) {
return null();
}
}
}
if (!matchOrInsertSemicolon()) {
return null();
}
return handler_.newReturnStatement(exprNode, TokenPos(begin, pos().end));
}
template <class ParseHandler, typename Unit>
typename ParseHandler::UnaryNodeType
GeneralParser<ParseHandler, Unit>::yieldExpression(InHandling inHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Yield));
uint32_t begin = pos().begin;
MOZ_ASSERT(pc_->isGenerator());
MOZ_ASSERT(pc_->isFunctionBox());
pc_->lastYieldOffset = begin;
Node exprNode;
ParseNodeKind kind = ParseNodeKind::YieldExpr;
TokenKind tt = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) {
return null();
}
switch (tt) {
case TokenKind::Eol:
case TokenKind::Eof:
case TokenKind::Semi:
case TokenKind::RightCurly:
case TokenKind::RightBracket:
case TokenKind::RightParen:
case TokenKind::Colon:
case TokenKind::Comma:
case TokenKind::In:
exprNode = null();
anyChars.addModifierException(TokenStream::NoneIsOperand);
break;
case TokenKind::Mul:
kind = ParseNodeKind::YieldStarExpr;
tokenStream.consumeKnownToken(TokenKind::Mul, TokenStream::Operand);
MOZ_FALLTHROUGH;
default:
exprNode = assignExpr(inHandling, YieldIsKeyword, TripledotProhibited);
if (!exprNode) {
return null();
}
}
if (kind == ParseNodeKind::YieldStarExpr) {
return handler_.newYieldStarExpression(begin, exprNode);
}
return handler_.newYieldExpression(begin, exprNode);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::withStatement(YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::With));
uint32_t begin = pos().begin;
if (pc_->sc()->strict()) {
if (!strictModeError(JSMSG_STRICT_CODE_WITH)) {
return null();
}
}
if (!mustMatchToken(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_WITH)) {
return null();
}
Node objectExpr = exprInParens(InAllowed, yieldHandling, TripledotProhibited);
if (!objectExpr) {
return null();
}
if (!mustMatchToken(TokenKind::RightParen, TokenStream::Operand,
JSMSG_PAREN_AFTER_WITH)) {
return null();
}
Node innerBlock;
{
ParseContext::Statement stmt(pc_, StatementKind::With);
innerBlock = statement(yieldHandling);
if (!innerBlock) {
return null();
}
}
pc_->sc()->setBindingsAccessedDynamically();
return handler_.newWithStatement(begin, objectExpr, innerBlock);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::labeledItem(
YieldHandling yieldHandling) {
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt == TokenKind::Function) {
TokenKind next;
if (!tokenStream.peekToken(&next)) {
return null();
}
if (next == TokenKind::Mul) {
error(JSMSG_GENERATOR_LABEL);
return null();
}
if (pc_->sc()->strict()) {
error(JSMSG_FUNCTION_LABEL);
return null();
}
return functionStmt(pos().begin, yieldHandling, NameRequired);
}
anyChars.ungetToken();
return statement(yieldHandling);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::LabeledStatementType
GeneralParser<ParseHandler, Unit>::labeledStatement(
YieldHandling yieldHandling) {
RootedPropertyName label(cx_, labelIdentifier(yieldHandling));
if (!label) {
return null();
}
auto hasSameLabel = [&label](ParseContext::LabelStatement* stmt) {
return stmt->label() == label;
};
uint32_t begin = pos().begin;
if (pc_->template findInnermostStatement<ParseContext::LabelStatement>(
hasSameLabel)) {
errorAt(begin, JSMSG_DUPLICATE_LABEL);
return null();
}
tokenStream.consumeKnownToken(TokenKind::Colon);
ParseContext::LabelStatement stmt(pc_, label);
Node pn = labeledItem(yieldHandling);
if (!pn) {
return null();
}
return handler_.newLabeledStatement(label, pn, begin);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::UnaryNodeType
GeneralParser<ParseHandler, Unit>::throwStatement(YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Throw));
uint32_t begin = pos().begin;
TokenKind tt = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) {
return null();
}
if (tt == TokenKind::Eof || tt == TokenKind::Semi ||
tt == TokenKind::RightCurly) {
error(JSMSG_MISSING_EXPR_AFTER_THROW);
return null();
}
if (tt == TokenKind::Eol) {
error(JSMSG_LINE_BREAK_AFTER_THROW);
return null();
}
Node throwExpr = expr(InAllowed, yieldHandling, TripledotProhibited);
if (!throwExpr) {
return null();
}
if (!matchOrInsertSemicolon()) {
return null();
}
return handler_.newThrowStatement(throwExpr, TokenPos(begin, pos().end));
}
template <class ParseHandler, typename Unit>
typename ParseHandler::TernaryNodeType
GeneralParser<ParseHandler, Unit>::tryStatement(YieldHandling yieldHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Try));
uint32_t begin = pos().begin;
Node innerBlock;
{
if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_TRY)) {
return null();
}
uint32_t openedPos = pos().begin;
ParseContext::Statement stmt(pc_, StatementKind::Try);
ParseContext::Scope scope(this);
if (!scope.init(pc_)) {
return null();
}
innerBlock = statementList(yieldHandling);
if (!innerBlock) {
return null();
}
innerBlock = finishLexicalScope(scope, innerBlock);
if (!innerBlock) {
return null();
}
if (!mustMatchToken(TokenKind::RightCurly, TokenStream::Operand,
[this, openedPos](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_TRY,
JSMSG_CURLY_OPENED,
openedPos);
})) {
return null();
}
}
LexicalScopeNodeType catchScope = null();
TokenKind tt;
if (!tokenStream.getToken(&tt)) {
return null();
}
if (tt == TokenKind::Catch) {
ParseContext::Statement stmt(pc_, StatementKind::Catch);
ParseContext::Scope scope(this);
if (!scope.init(pc_)) {
return null();
}
bool omittedBinding;
if (!tokenStream.matchToken(&omittedBinding, TokenKind::LeftCurly)) {
return null();
}
Node catchName;
if (omittedBinding) {
catchName = null();
} else {
if (!mustMatchToken(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_CATCH)) {
return null();
}
if (!tokenStream.getToken(&tt)) {
return null();
}
switch (tt) {
case TokenKind::LeftBracket:
case TokenKind::LeftCurly:
catchName = destructuringDeclaration(DeclarationKind::CatchParameter,
yieldHandling, tt);
if (!catchName) {
return null();
}
break;
default: {
if (!TokenKindIsPossibleIdentifierName(tt)) {
error(JSMSG_CATCH_IDENTIFIER);
return null();
}
catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter,
yieldHandling);
if (!catchName) {
return null();
}
break;
}
}
if (!mustMatchToken(TokenKind::RightParen, TokenStream::Operand,
JSMSG_PAREN_AFTER_CATCH)) {
return null();
}
if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_CATCH)) {
return null();
}
}
LexicalScopeNodeType catchBody = catchBlockStatement(yieldHandling, scope);
if (!catchBody) {
return null();
}
catchScope = finishLexicalScope(scope, catchBody);
if (!catchScope) {
return null();
}
if (!handler_.setupCatchScope(catchScope, catchName, catchBody)) {
return null();
}
handler_.setEndPosition(catchScope, pos().end);
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
}
Node finallyBlock = null();
if (tt == TokenKind::Finally) {
if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_FINALLY)) {
return null();
}
uint32_t openedPos = pos().begin;
ParseContext::Statement stmt(pc_, StatementKind::Finally);
ParseContext::Scope scope(this);
if (!scope.init(pc_)) {
return null();
}
finallyBlock = statementList(yieldHandling);
if (!finallyBlock) {
return null();
}
finallyBlock = finishLexicalScope(scope, finallyBlock);
if (!finallyBlock) {
return null();
}
if (!mustMatchToken(TokenKind::RightCurly, TokenStream::Operand,
[this, openedPos](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_FINALLY,
JSMSG_CURLY_OPENED,
openedPos);
})) {
return null();
}
} else {
anyChars.ungetToken();
}
if (!catchScope && !finallyBlock) {
error(JSMSG_CATCH_OR_FINALLY);
return null();
}
return handler_.newTryStatement(begin, innerBlock, catchScope, finallyBlock);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::LexicalScopeNodeType
GeneralParser<ParseHandler, Unit>::catchBlockStatement(
YieldHandling yieldHandling, ParseContext::Scope& catchParamScope) {
uint32_t openedPos = pos().begin;
ParseContext::Statement stmt(pc_, StatementKind::Block);
ParseContext::Scope scope(this);
if (!scope.init(pc_)) {
return null();
}
if (!scope.addCatchParameters(pc_, catchParamScope)) {
return null();
}
ListNodeType list = statementList(yieldHandling);
if (!list) {
return null();
}
if (!mustMatchToken(TokenKind::RightCurly, TokenStream::Operand,
[this, openedPos](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_CATCH,
JSMSG_CURLY_OPENED,
openedPos);
})) {
return null();
}
scope.removeCatchParameters(pc_, catchParamScope);
return finishLexicalScope(scope, list);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::DebuggerStatementType
GeneralParser<ParseHandler, Unit>::debuggerStatement() {
TokenPos p;
p.begin = pos().begin;
if (!matchOrInsertSemicolon()) {
return null();
}
p.end = pos().end;
pc_->sc()->setBindingsAccessedDynamically();
pc_->sc()->setHasDebuggerStatement();
return handler_.newDebuggerStatement(p);
}
static AccessorType ToAccessorType(PropertyType propType) {
switch (propType) {
case PropertyType::Getter:
return AccessorType::Getter;
case PropertyType::Setter:
return AccessorType::Setter;
case PropertyType::Normal:
case PropertyType::Method:
case PropertyType::GeneratorMethod:
case PropertyType::AsyncMethod:
case PropertyType::AsyncGeneratorMethod:
case PropertyType::Constructor:
case PropertyType::DerivedConstructor:
return AccessorType::None;
default:
MOZ_CRASH("unexpected property type");
}
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::classMember(
YieldHandling yieldHandling, DefaultHandling defaultHandling,
const ParseContext::ClassStatement& classStmt, HandlePropertyName className,
uint32_t classStartOffset, bool hasHeritage,
size_t& numFieldsWithInitializers, ListNodeType& classMembers, bool* done) {
*done = false;
TokenKind tt;
if (!tokenStream.getToken(&tt)) {
return false;
}
if (tt == TokenKind::RightCurly) {
*done = true;
return true;
}
if (tt == TokenKind::Semi) {
return true;
}
bool isStatic = false;
if (tt == TokenKind::Static) {
if (!tokenStream.peekToken(&tt)) {
return false;
}
if (tt == TokenKind::RightCurly) {
tokenStream.consumeKnownToken(tt);
error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt));
return false;
}
if (tt != TokenKind::LeftParen) {
isStatic = true;
} else {
anyChars.ungetToken();
}
} else {
anyChars.ungetToken();
}
uint32_t propNameOffset;
if (!tokenStream.peekOffset(&propNameOffset)) {
return false;
}
RootedAtom propAtom(cx_);
PropertyType propType;
Node propName = propertyName(yieldHandling, PropertyNameInClass,
Nothing(), classMembers,
&propType, &propAtom);
if (!propName) {
return false;
}
if (propType == PropertyType::Field) {
if (!options().fieldsEnabledOption) {
errorAt(propNameOffset, JSMSG_FIELDS_NOT_SUPPORTED);
return false;
}
if (isStatic) {
errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
return false;
}
if (!tokenStream.getToken(&tt)) {
return false;
}
FunctionNodeType initializer = null();
if (tt == TokenKind::Assign) {
initializer = fieldInitializer(yieldHandling, propAtom);
if (!initializer) {
return false;
}
numFieldsWithInitializers++;
if (!tokenStream.getToken(&tt)) {
return false;
}
}
if (tt != TokenKind::Semi) {
error(JSMSG_MISSING_SEMI_FIELD);
return false;
}
return handler_.addClassFieldDefinition(classMembers, propName,
initializer);
}
if (propType != PropertyType::Getter && propType != PropertyType::Setter &&
propType != PropertyType::Method &&
propType != PropertyType::GeneratorMethod &&
propType != PropertyType::AsyncMethod &&
propType != PropertyType::AsyncGeneratorMethod) {
errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
return false;
}
bool isConstructor = !isStatic && propAtom == cx_->names().constructor;
if (isConstructor) {
if (propType != PropertyType::Method) {
errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
return false;
}
if (classStmt.constructorBox) {
errorAt(propNameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor");
return false;
}
propType = hasHeritage ? PropertyType::DerivedConstructor
: PropertyType::Constructor;
} else if (isStatic && propAtom == cx_->names().prototype) {
errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
return false;
}
RootedAtom funName(cx_);
switch (propType) {
case PropertyType::Getter:
case PropertyType::Setter:
if (!anyChars.isCurrentTokenType(TokenKind::RightBracket)) {
funName = prefixAccessorName(propType, propAtom);
if (!funName) {
return false;
}
}
break;
case PropertyType::Constructor:
case PropertyType::DerivedConstructor:
funName = className;
break;
default:
if (!anyChars.isCurrentTokenType(TokenKind::RightBracket)) {
funName = propAtom;
}
}
FunctionNodeType funNode = methodDefinition(
isConstructor ? classStartOffset : propNameOffset, propType, funName);
if (!funNode) {
return false;
}
AccessorType atype = ToAccessorType(propType);
return handler_.addClassMethodDefinition(classMembers, propName, funNode,
atype, isStatic);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::finishClassConstructor(
const ParseContext::ClassStatement& classStmt, HandlePropertyName className,
uint32_t classStartOffset, uint32_t classEndOffset,
size_t numFieldsWithInitializers, ListNodeType& classMembers) {
if (classStmt.constructorBox == nullptr && numFieldsWithInitializers > 0) {
FunctionNodeType synthesizedCtor =
synthesizeConstructor(className, classStartOffset);
if (!synthesizedCtor) {
return false;
}
MOZ_ASSERT(classStmt.constructorBox != nullptr);
Node constructorNameNode =
handler_.newObjectLiteralPropertyName(cx_->names().constructor, pos());
if (!constructorNameNode) {
return false;
}
if (!handler_.addClassMethodDefinition(classMembers, constructorNameNode,
synthesizedCtor, AccessorType::None,
false)) {
return false;
}
}
if (FunctionBox* ctorbox = classStmt.constructorBox) {
ctorbox->toStringEnd = classEndOffset;
if (numFieldsWithInitializers > 0) {
ctorbox->setHasThisBinding();
}
if (ctorbox->function()->isInterpretedLazy()) {
ctorbox->function()->lazyScript()->setToStringEnd(classEndOffset);
if (numFieldsWithInitializers > 0) {
ctorbox->function()->lazyScript()->setHasThisBinding();
}
FieldInitializers fieldInfo(numFieldsWithInitializers);
ctorbox->function()->lazyScript()->setFieldInitializers(fieldInfo);
}
}
return true;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ClassNodeType
GeneralParser<ParseHandler, Unit>::classDefinition(
YieldHandling yieldHandling, ClassContext classContext,
DefaultHandling defaultHandling) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Class));
uint32_t classStartOffset = pos().begin;
bool savedStrictness = setLocalStrictMode(true);
TokenKind tt;
if (!tokenStream.getToken(&tt)) {
return null();
}
RootedPropertyName className(cx_);
if (TokenKindIsPossibleIdentifier(tt)) {
className = bindingIdentifier(yieldHandling);
if (!className) {
return null();
}
} else if (classContext == ClassStatement) {
if (defaultHandling == AllowDefaultName) {
className = cx_->names().default_;
anyChars.ungetToken();
} else {
error(JSMSG_UNNAMED_CLASS_STMT);
return null();
}
} else {
anyChars.ungetToken();
}
TokenPos namePos = pos();
ParseContext::ClassStatement classStmt(pc_);
NameNodeType innerName;
Node nameNode = null();
Node classHeritage = null();
Node classBlock = null();
uint32_t classEndOffset;
{
ParseContext::Statement innerScopeStmt(pc_, StatementKind::Block);
ParseContext::Scope innerScope(this);
if (!innerScope.init(pc_)) {
return null();
}
bool hasHeritage;
if (!tokenStream.matchToken(&hasHeritage, TokenKind::Extends)) {
return null();
}
if (hasHeritage) {
if (!tokenStream.getToken(&tt)) {
return null();
}
classHeritage = memberExpr(yieldHandling, TripledotProhibited, tt);
if (!classHeritage) {
return null();
}
}
if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_CLASS)) {
return null();
}
ListNodeType classMembers = handler_.newClassMemberList(pos().begin);
if (!classMembers) {
return null();
}
size_t numFieldsWithInitializers = 0;
for (;;) {
bool done;
if (!classMember(yieldHandling, defaultHandling, classStmt, className,
classStartOffset, hasHeritage, numFieldsWithInitializers,
classMembers, &done)) {
return null();
}
if (done) {
break;
}
}
if (numFieldsWithInitializers > 0) {
if (!usedNames_.markAsAlwaysClosedOver(cx_, cx_->names().dotInitializers,
pc_->scriptId(),
pc_->innermostScope()->id())) {
return null();
}
if (!noteDeclaredName(cx_->names().dotInitializers,
DeclarationKind::Const, namePos)) {
return null();
}
}
classEndOffset = pos().end;
if (!finishClassConstructor(classStmt, className, classStartOffset,
classEndOffset, numFieldsWithInitializers,
classMembers)) {
return null();
}
if (className) {
if (!noteDeclaredName(className, DeclarationKind::Const, namePos)) {
return null();
}
innerName = newName(className, namePos);
if (!innerName) {
return null();
}
}
classBlock = finishLexicalScope(innerScope, classMembers);
if (!classBlock) {
return null();
}
}
if (className) {
NameNodeType outerName = null();
if (classContext == ClassStatement) {
if (!noteDeclaredName(className, DeclarationKind::Class, namePos)) {
return null();
}
outerName = newName(className, namePos);
if (!outerName) {
return null();
}
}
nameNode = handler_.newClassNames(outerName, innerName, namePos);
if (!nameNode) {
return null();
}
}
MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
return handler_.newClass(nameNode, classHeritage, classBlock,
TokenPos(classStartOffset, classEndOffset));
}
template <class ParseHandler, typename Unit>
typename ParseHandler::FunctionNodeType
GeneralParser<ParseHandler, Unit>::synthesizeConstructor(
HandleAtom className, uint32_t classNameOffset) {
FunctionSyntaxKind functionSyntaxKind = FunctionSyntaxKind::ClassConstructor;
RootedFunction fun(cx_, newFunction(className, functionSyntaxKind,
GeneratorKind::NotGenerator,
FunctionAsyncKind::SyncFunction));
if (!fun) {
return null();
}
FunctionNodeType funNode = handler_.newFunction(functionSyntaxKind, pos());
if (!funNode) {
return null();
}
Directives directives(true);
FunctionBox* funbox = newFunctionBox(funNode, fun, classNameOffset,
directives, GeneratorKind::NotGenerator,
FunctionAsyncKind::SyncFunction);
if (!funbox) {
return null();
}
funbox->initWithEnclosingParseContext(pc_, functionSyntaxKind);
handler_.setFunctionBox(funNode, funbox);
funbox->setEnd(anyChars);
SourceParseContext funpc(this, funbox, nullptr);
if (!funpc.init()) {
return null();
}
TokenPos synthesizedBodyPos = TokenPos(classNameOffset, classNameOffset + 1);
ListNodeType argsbody =
handler_.newList(ParseNodeKind::ParamsBody, synthesizedBodyPos);
if (!argsbody) {
return null();
}
handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
funbox->function()->setArgCount(0);
tokenStream.setFunctionStart(funbox);
ParseContext::Scope lexicalScope(this);
if (!lexicalScope.init(pc_)) {
return null();
}
auto stmtList = handler_.newStatementList(synthesizedBodyPos);
if (!stmtList) {
return null();
}
if (!noteUsedName(cx_->names().dotThis)) {
return null();
}
bool canSkipLazyClosedOverBindings = handler_.canSkipLazyClosedOverBindings();
if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
return null();
}
auto initializerBody = finishLexicalScope(lexicalScope, stmtList);
if (!initializerBody) {
return null();
}
handler_.setBeginPosition(initializerBody, stmtList);
handler_.setEndPosition(initializerBody, stmtList);
handler_.setFunctionBody(funNode, initializerBody);
if (!finishFunction()) {
return null();
}
return funNode;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::FunctionNodeType
GeneralParser<ParseHandler, Unit>::fieldInitializer(YieldHandling yieldHandling,
HandleAtom propAtom) {
TokenPos firstTokenPos = pos();
RootedFunction fun(cx_, newFunction(propAtom, FunctionSyntaxKind::Expression,
GeneratorKind::NotGenerator,
FunctionAsyncKind::SyncFunction));
if (!fun) {
return null();
}
FunctionNodeType funNode =
handler_.newFunction(FunctionSyntaxKind::Expression, firstTokenPos);
if (!funNode) {
return null();
}
Directives directives(true);
FunctionBox* funbox = newFunctionBox(funNode, fun, firstTokenPos.begin,
directives, GeneratorKind::NotGenerator,
FunctionAsyncKind::SyncFunction);
if (!funbox) {
return null();
}
funbox->initWithEnclosingParseContext(pc_, FunctionSyntaxKind::Expression);
handler_.setFunctionBox(funNode, funbox);
tokenStream.setFunctionStart(funbox);
SourceParseContext funpc(this, funbox, nullptr);
if (!funpc.init()) {
return null();
}
ParseContext::VarScope varScope(this);
if (!varScope.init(pc_)) {
return null();
}
ParseContext::Scope lexicalScope(this);
if (!lexicalScope.init(pc_)) {
return null();
}
Node initializerExpr =
assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (!initializerExpr) {
return null();
}
TokenPos wholeInitializerPos = pos();
wholeInitializerPos.begin = firstTokenPos.begin;
handler_.setEndPosition(funNode, wholeInitializerPos.end);
funbox->setEnd(anyChars);
ListNodeType argsbody =
handler_.newList(ParseNodeKind::ParamsBody, wholeInitializerPos);
if (!argsbody) {
return null();
}
handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
funbox->function()->setArgCount(0);
funbox->usesThis = true;
NameNodeType thisName = newThisName();
if (!thisName) {
return null();
}
ThisLiteralType propAssignThis =
handler_.newThisLiteral(wholeInitializerPos, thisName);
if (!propAssignThis) {
return null();
}
NameNodeType propAssignName =
handler_.newPropertyName(propAtom->asPropertyName(), wholeInitializerPos);
if (!propAssignName) {
return null();
}
PropertyAccessType propAssignFieldAccess =
handler_.newPropertyAccess(propAssignThis, propAssignName);
if (!propAssignFieldAccess) {
return null();
}
AssignmentNodeType initializerAssignment = handler_.newAssignment(
ParseNodeKind::AssignExpr, propAssignFieldAccess, initializerExpr);
if (!initializerAssignment) {
return null();
}
bool canSkipLazyClosedOverBindings = handler_.canSkipLazyClosedOverBindings();
if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
return null();
}
UnaryNodeType exprStatement =
handler_.newExprStatement(initializerAssignment, pos().end);
if (!exprStatement) {
return null();
}
ListNodeType statementList = handler_.newStatementList(wholeInitializerPos);
if (!argsbody) {
return null();
}
handler_.addStatementToList(statementList, exprStatement);
LexicalScopeNodeType initializerBody =
finishLexicalScope(lexicalScope, statementList);
if (!initializerBody) {
return null();
}
handler_.setFunctionBody(funNode, initializerBody);
if (!finishFunction()) {
return null();
}
return funNode;
}
bool ParserBase::nextTokenContinuesLetDeclaration(TokenKind next) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Let));
MOZ_ASSERT(anyChars.nextToken().type == next);
TokenStreamShared::verifyConsistentModifier(TokenStreamShared::None,
anyChars.nextToken());
if (next == TokenKind::LeftBracket || next == TokenKind::LeftCurly) {
return true;
}
return TokenKindIsPossibleIdentifier(next);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::variableStatement(
YieldHandling yieldHandling) {
ListNodeType vars = declarationList(yieldHandling, ParseNodeKind::VarStmt);
if (!vars) {
return null();
}
if (!matchOrInsertSemicolon()) {
return null();
}
return vars;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::statement(
YieldHandling yieldHandling) {
MOZ_ASSERT(checkOptionsCalled_);
if (!CheckRecursionLimit(cx_)) {
return null();
}
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
switch (tt) {
case TokenKind::LeftCurly:
return blockStatement(yieldHandling);
case TokenKind::Var:
return variableStatement(yieldHandling);
case TokenKind::Semi:
return handler_.newEmptyStatement(pos());
case TokenKind::Yield: {
Modifier modifier;
if (yieldExpressionsSupported()) {
modifier = TokenStream::Operand;
} else {
modifier = TokenStream::None;
}
TokenKind next;
if (!tokenStream.peekToken(&next, modifier)) {
return null();
}
if (next == TokenKind::Colon) {
return labeledStatement(yieldHandling);
}
return expressionStatement(yieldHandling);
}
default: {
if (tt == TokenKind::Await && pc_->isAsync()) {
return expressionStatement(yieldHandling);
}
if (!TokenKindIsPossibleIdentifier(tt)) {
return expressionStatement(yieldHandling);
}
TokenKind next;
if (!tokenStream.peekToken(&next)) {
return null();
}
if (tt == TokenKind::Let) {
bool forbiddenLetDeclaration = false;
if (next == TokenKind::LeftBracket) {
forbiddenLetDeclaration = true;
} else if (next == TokenKind::LeftCurly ||
TokenKindIsPossibleIdentifier(next)) {
TokenKind nextSameLine;
if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
return null();
}
MOZ_ASSERT(TokenKindIsPossibleIdentifier(nextSameLine) ||
nextSameLine == TokenKind::LeftCurly ||
nextSameLine == TokenKind::Eol);
forbiddenLetDeclaration = nextSameLine != TokenKind::Eol;
}
if (forbiddenLetDeclaration) {
error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations");
return null();
}
} else if (tt == TokenKind::Async) {
TokenKind maybeFunction;
if (!tokenStream.peekTokenSameLine(&maybeFunction)) {
return null();
}
if (maybeFunction == TokenKind::Function) {
error(JSMSG_FORBIDDEN_AS_STATEMENT, "async function declarations");
return null();
}
}
if (next == TokenKind::Colon) {
return labeledStatement(yieldHandling);
}
return expressionStatement(yieldHandling);
}
case TokenKind::New:
return expressionStatement(yieldHandling, PredictInvoked);
case TokenKind::If:
return ifStatement(yieldHandling);
case TokenKind::Do:
return doWhileStatement(yieldHandling);
case TokenKind::While:
return whileStatement(yieldHandling);
case TokenKind::For:
return forStatement(yieldHandling);
case TokenKind::Switch:
return switchStatement(yieldHandling);
case TokenKind::Continue:
return continueStatement(yieldHandling);
case TokenKind::Break:
return breakStatement(yieldHandling);
case TokenKind::Return:
if (!pc_->isFunctionBox()) {
error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
return null();
}
return returnStatement(yieldHandling);
case TokenKind::With:
return withStatement(yieldHandling);
case TokenKind::Throw:
return throwStatement(yieldHandling);
case TokenKind::Try:
return tryStatement(yieldHandling);
case TokenKind::Debugger:
return debuggerStatement();
case TokenKind::Function:
error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
return null();
case TokenKind::Class:
error(JSMSG_FORBIDDEN_AS_STATEMENT, "classes");
return null();
case TokenKind::Import:
return importDeclarationOrImportExpr(yieldHandling);
case TokenKind::Export:
return exportDeclaration();
case TokenKind::Catch:
error(JSMSG_CATCH_WITHOUT_TRY);
return null();
case TokenKind::Finally:
error(JSMSG_FINALLY_WITHOUT_TRY);
return null();
}
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::statementListItem(
YieldHandling yieldHandling, bool canHaveDirectives ) {
MOZ_ASSERT(checkOptionsCalled_);
if (!CheckRecursionLimit(cx_)) {
return null();
}
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
switch (tt) {
case TokenKind::LeftCurly:
return blockStatement(yieldHandling);
case TokenKind::Var:
return variableStatement(yieldHandling);
case TokenKind::Semi:
return handler_.newEmptyStatement(pos());
case TokenKind::String:
if (!canHaveDirectives &&
anyChars.currentToken().atom() == cx_->names().useAsm) {
if (!abortIfSyntaxParser()) {
return null();
}
if (!warning(JSMSG_USE_ASM_DIRECTIVE_FAIL)) {
return null();
}
}
return expressionStatement(yieldHandling);
case TokenKind::Yield: {
Modifier modifier;
if (yieldExpressionsSupported()) {
modifier = TokenStream::Operand;
} else {
modifier = TokenStream::None;
}
TokenKind next;
if (!tokenStream.peekToken(&next, modifier)) {
return null();
}
if (next == TokenKind::Colon) {
return labeledStatement(yieldHandling);
}
return expressionStatement(yieldHandling);
}
default: {
if (tt == TokenKind::Await && pc_->isAsync()) {
return expressionStatement(yieldHandling);
}
if (!TokenKindIsPossibleIdentifier(tt)) {
return expressionStatement(yieldHandling);
}
TokenKind next;
if (!tokenStream.peekToken(&next)) {
return null();
}
if (tt == TokenKind::Let && nextTokenContinuesLetDeclaration(next)) {
return lexicalDeclaration(yieldHandling, DeclarationKind::Let);
}
if (tt == TokenKind::Async) {
TokenKind nextSameLine = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
return null();
}
if (nextSameLine == TokenKind::Function) {
uint32_t toStringStart = pos().begin;
tokenStream.consumeKnownToken(TokenKind::Function);
return functionStmt(toStringStart, yieldHandling, NameRequired,
FunctionAsyncKind::AsyncFunction);
}
}
if (next == TokenKind::Colon) {
return labeledStatement(yieldHandling);
}
return expressionStatement(yieldHandling);
}
case TokenKind::New:
return expressionStatement(yieldHandling, PredictInvoked);
case TokenKind::If:
return ifStatement(yieldHandling);
case TokenKind::Do:
return doWhileStatement(yieldHandling);
case TokenKind::While:
return whileStatement(yieldHandling);
case TokenKind::For:
return forStatement(yieldHandling);
case TokenKind::Switch:
return switchStatement(yieldHandling);
case TokenKind::Continue:
return continueStatement(yieldHandling);
case TokenKind::Break:
return breakStatement(yieldHandling);
case TokenKind::Return:
if (!pc_->isFunctionBox()) {
error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
return null();
}
return returnStatement(yieldHandling);
case TokenKind::With:
return withStatement(yieldHandling);
case TokenKind::Throw:
return throwStatement(yieldHandling);
case TokenKind::Try:
return tryStatement(yieldHandling);
case TokenKind::Debugger:
return debuggerStatement();
case TokenKind::Function:
return functionStmt(pos().begin, yieldHandling, NameRequired);
case TokenKind::Class:
return classDefinition(yieldHandling, ClassStatement, NameRequired);
case TokenKind::Const:
return lexicalDeclaration(yieldHandling, DeclarationKind::Const);
case TokenKind::Import:
return importDeclarationOrImportExpr(yieldHandling);
case TokenKind::Export:
return exportDeclaration();
case TokenKind::Catch:
error(JSMSG_CATCH_WITHOUT_TRY);
return null();
case TokenKind::Finally:
error(JSMSG_FINALLY_WITHOUT_TRY);
return null();
}
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::expr(
InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
PossibleError* possibleError ,
InvokedPrediction invoked ) {
Node pn = assignExpr(inHandling, yieldHandling, tripledotHandling,
possibleError, invoked);
if (!pn) {
return null();
}
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Comma,
TokenStream::Operand)) {
return null();
}
if (!matched) {
return pn;
}
ListNodeType seq = handler_.newCommaExpressionList(pn);
if (!seq) {
return null();
}
while (true) {
if (tripledotHandling == TripledotAllowed) {
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt == TokenKind::RightParen) {
tokenStream.consumeKnownToken(TokenKind::RightParen,
TokenStream::Operand);
if (!tokenStream.peekToken(&tt)) {
return null();
}
if (tt != TokenKind::Arrow) {
error(JSMSG_UNEXPECTED_TOKEN, "expression",
TokenKindToDesc(TokenKind::RightParen));
return null();
}
anyChars.ungetToken(); break;
}
}
PossibleError possibleErrorInner(*this);
pn = assignExpr(inHandling, yieldHandling, tripledotHandling,
&possibleErrorInner);
if (!pn) {
return null();
}
if (!possibleError) {
if (!possibleErrorInner.checkForExpressionError()) {
return null();
}
} else {
possibleErrorInner.transferErrorsTo(possibleError);
}
handler_.addList(seq, pn);
if (!tokenStream.matchToken(&matched, TokenKind::Comma,
TokenStream::Operand)) {
return null();
}
if (!matched) {
break;
}
}
return seq;
}
static ParseNodeKind BinaryOpTokenKindToParseNodeKind(TokenKind tok) {
MOZ_ASSERT(TokenKindIsBinaryOp(tok));
return ParseNodeKind(size_t(ParseNodeKind::BinOpFirst) +
(size_t(tok) - size_t(TokenKind::BinOpFirst)));
}
static const int PrecedenceTable[] = {
1,
2,
3,
4,
5,
6,
7,
7,
7,
7,
8,
8,
8,
8,
8,
8,
9,
9,
9,
10,
10,
11,
11,
11,
12
};
static const int PRECEDENCE_CLASSES = 12;
static int Precedence(ParseNodeKind pnk) {
if (pnk == ParseNodeKind::Limit) {
return 0;
}
MOZ_ASSERT(pnk >= ParseNodeKind::BinOpFirst);
MOZ_ASSERT(pnk <= ParseNodeKind::BinOpLast);
return PrecedenceTable[size_t(pnk) - size_t(ParseNodeKind::BinOpFirst)];
}
template <class ParseHandler, typename Unit>
MOZ_ALWAYS_INLINE typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::orExpr(
InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling, PossibleError* possibleError,
InvokedPrediction invoked ) {
Node nodeStack[PRECEDENCE_CLASSES];
ParseNodeKind kindStack[PRECEDENCE_CLASSES];
int depth = 0;
Node pn;
for (;;) {
pn = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked);
if (!pn) {
return null();
}
TokenKind tok;
if (!tokenStream.getToken(&tok)) {
return null();
}
ParseNodeKind pnk;
if (tok == TokenKind::In ? inHandling == InAllowed
: TokenKindIsBinaryOp(tok)) {
if (possibleError && !possibleError->checkForExpressionError()) {
return null();
}
if (tok == TokenKind::Pow &&
handler_.isUnparenthesizedUnaryExpression(pn)) {
error(JSMSG_BAD_POW_LEFTSIDE);
return null();
}
pnk = BinaryOpTokenKindToParseNodeKind(tok);
} else {
tok = TokenKind::Eof;
pnk = ParseNodeKind::Limit;
}
possibleError = nullptr;
while (depth > 0 && Precedence(kindStack[depth - 1]) >= Precedence(pnk)) {
depth--;
ParseNodeKind combiningPnk = kindStack[depth];
pn = handler_.appendOrCreateList(combiningPnk, nodeStack[depth], pn, pc_);
if (!pn) {
return null();
}
}
if (pnk == ParseNodeKind::Limit) {
break;
}
nodeStack[depth] = pn;
kindStack[depth] = pnk;
depth++;
MOZ_ASSERT(depth <= PRECEDENCE_CLASSES);
}
anyChars.ungetToken();
anyChars.addModifierException(TokenStream::OperandIsNone);
MOZ_ASSERT(depth == 0);
return pn;
}
template <class ParseHandler, typename Unit>
MOZ_ALWAYS_INLINE typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::condExpr(
InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling, PossibleError* possibleError,
InvokedPrediction invoked ) {
Node condition = orExpr(inHandling, yieldHandling, tripledotHandling,
possibleError, invoked);
if (!condition) {
return null();
}
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Hook)) {
return null();
}
if (!matched) {
return condition;
}
Node thenExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (!thenExpr) {
return null();
}
if (!mustMatchToken(TokenKind::Colon, TokenStream::Operand,
JSMSG_COLON_IN_COND)) {
return null();
}
Node elseExpr = assignExpr(inHandling, yieldHandling, TripledotProhibited);
if (!elseExpr) {
return null();
}
return handler_.newConditional(condition, thenExpr, elseExpr);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::assignExpr(
InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
PossibleError* possibleError ,
InvokedPrediction invoked ) {
if (!CheckRecursionLimit(cx_)) {
return null();
}
TokenKind firstToken;
if (!tokenStream.getToken(&firstToken, TokenStream::Operand)) {
return null();
}
TokenPos exprPos = pos();
bool endsExpr;
if (firstToken == TokenKind::Name) {
if (!tokenStream.nextTokenEndsExpr(&endsExpr)) {
return null();
}
if (endsExpr) {
Rooted<PropertyName*> name(cx_, identifierReference(yieldHandling));
if (!name) {
return null();
}
return identifierReference(name);
}
}
if (firstToken == TokenKind::Number) {
if (!tokenStream.nextTokenEndsExpr(&endsExpr)) {
return null();
}
if (endsExpr) {
return newNumber(anyChars.currentToken());
}
}
if (firstToken == TokenKind::String) {
if (!tokenStream.nextTokenEndsExpr(&endsExpr)) {
return null();
}
if (endsExpr) {
return stringLiteral();
}
}
if (firstToken == TokenKind::Yield && yieldExpressionsSupported()) {
return yieldExpression(inHandling);
}
bool maybeAsyncArrow = false;
if (firstToken == TokenKind::Async) {
TokenKind nextSameLine = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
return null();
}
if (TokenKindIsPossibleIdentifier(nextSameLine)) {
maybeAsyncArrow = true;
}
}
anyChars.ungetToken();
Position start(keepAtoms_, tokenStream);
PossibleError possibleErrorInner(*this);
Node lhs;
TokenKind tokenAfterLHS;
bool isArrow;
if (maybeAsyncArrow) {
tokenStream.consumeKnownToken(TokenKind::Async, TokenStream::Operand);
TokenKind tokenAfterAsync;
if (!tokenStream.getToken(&tokenAfterAsync)) {
return null();
}
MOZ_ASSERT(TokenKindIsPossibleIdentifier(tokenAfterAsync));
RootedPropertyName name(cx_, bindingIdentifier(yieldHandling));
if (!name) {
return null();
}
if (!tokenStream.peekTokenSameLine(&tokenAfterLHS)) {
return null();
}
if (tokenAfterLHS != TokenKind::Arrow) {
error(JSMSG_UNEXPECTED_TOKEN,
"'=>' on the same line after an argument list",
TokenKindToDesc(tokenAfterLHS));
return null();
}
isArrow = true;
} else {
lhs = condExpr(inHandling, yieldHandling, tripledotHandling,
&possibleErrorInner, invoked);
if (!lhs) {
return null();
}
if (!tokenStream.peekTokenSameLine(&tokenAfterLHS, TokenStream::Operand)) {
return null();
}
isArrow = tokenAfterLHS == TokenKind::Arrow;
}
if (isArrow) {
tokenStream.seek(start);
TokenKind next;
if (!tokenStream.getToken(&next, TokenStream::Operand)) {
return null();
}
TokenPos startPos = pos();
uint32_t toStringStart = startPos.begin;
anyChars.ungetToken();
FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction;
if (next == TokenKind::Async) {
tokenStream.consumeKnownToken(next, TokenStream::Operand);
TokenKind nextSameLine = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
return null();
}
if (TokenKindIsPossibleIdentifier(nextSameLine) ||
nextSameLine == TokenKind::LeftParen) {
asyncKind = FunctionAsyncKind::AsyncFunction;
} else {
anyChars.ungetToken();
}
}
FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Arrow;
FunctionNodeType funNode = handler_.newFunction(syntaxKind, startPos);
if (!funNode) {
return null();
}
return functionDefinition(funNode, toStringStart, inHandling, yieldHandling,
nullptr, syntaxKind, GeneratorKind::NotGenerator,
asyncKind);
}
MOZ_ALWAYS_TRUE(tokenStream.getToken(&tokenAfterLHS, TokenStream::Operand));
ParseNodeKind kind;
switch (tokenAfterLHS) {
case TokenKind::Assign:
kind = ParseNodeKind::AssignExpr;
break;
case TokenKind::AddAssign:
kind = ParseNodeKind::AddAssignExpr;
break;
case TokenKind::SubAssign:
kind = ParseNodeKind::SubAssignExpr;
break;
case TokenKind::BitOrAssign:
kind = ParseNodeKind::BitOrAssignExpr;
break;
case TokenKind::BitXorAssign:
kind = ParseNodeKind::BitXorAssignExpr;
break;
case TokenKind::BitAndAssign:
kind = ParseNodeKind::BitAndAssignExpr;
break;
case TokenKind::LshAssign:
kind = ParseNodeKind::LshAssignExpr;
break;
case TokenKind::RshAssign:
kind = ParseNodeKind::RshAssignExpr;
break;
case TokenKind::UrshAssign:
kind = ParseNodeKind::UrshAssignExpr;
break;
case TokenKind::MulAssign:
kind = ParseNodeKind::MulAssignExpr;
break;
case TokenKind::DivAssign:
kind = ParseNodeKind::DivAssignExpr;
break;
case TokenKind::ModAssign:
kind = ParseNodeKind::ModAssignExpr;
break;
case TokenKind::PowAssign:
kind = ParseNodeKind::PowAssignExpr;
break;
default:
MOZ_ASSERT(!anyChars.isCurrentTokenAssignment());
if (!possibleError) {
if (!possibleErrorInner.checkForExpressionError()) {
return null();
}
} else {
possibleErrorInner.transferErrorsTo(possibleError);
}
anyChars.ungetToken();
return lhs;
}
if (handler_.isUnparenthesizedDestructuringPattern(lhs)) {
if (kind != ParseNodeKind::AssignExpr) {
error(JSMSG_BAD_DESTRUCT_ASS);
return null();
}
if (!possibleErrorInner.checkForDestructuringErrorOrWarning()) {
return null();
}
} else if (handler_.isName(lhs)) {
if (const char* chars = nameIsArgumentsOrEval(lhs)) {
if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) {
return null();
}
}
handler_.adjustGetToSet(lhs);
} else if (handler_.isPropertyAccess(lhs)) {
} 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 = assignExpr(inHandling, yieldHandling, TripledotProhibited);
if (!rhs) {
return null();
}
return handler_.newAssignment(kind, lhs, rhs);
}
template <class ParseHandler>
bool PerHandlerParser<ParseHandler>::isValidSimpleAssignmentTarget(
Node node,
FunctionCallBehavior behavior ) {
if (handler_.isName(node)) {
if (!pc_->sc()->strict()) {
return true;
}
return !nameIsArgumentsOrEval(node);
}
if (handler_.isPropertyAccess(node)) {
return true;
}
if (behavior == PermitAssignmentToFunctionCalls) {
if (handler_.isFunctionCall(node)) {
return true;
}
}
return false;
}
template <class ParseHandler>
const char* PerHandlerParser<ParseHandler>::nameIsArgumentsOrEval(Node node) {
MOZ_ASSERT(handler_.isName(node),
"must only call this function on known names");
if (handler_.isEvalName(node, cx_)) {
return js_eval_str;
}
if (handler_.isArgumentsName(node, cx_)) {
return js_arguments_str;
}
return nullptr;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::checkIncDecOperand(
Node operand, uint32_t operandOffset) {
if (handler_.isName(operand)) {
if (const char* chars = nameIsArgumentsOrEval(operand)) {
if (!strictModeErrorAt(operandOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) {
return false;
}
}
} else if (handler_.isPropertyAccess(operand)) {
} else if (handler_.isFunctionCall(operand)) {
if (!strictModeErrorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND)) {
return false;
}
} else {
errorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND);
return false;
}
MOZ_ASSERT(
isValidSimpleAssignmentTarget(operand, PermitAssignmentToFunctionCalls),
"inconsistent increment/decrement operand validation");
return true;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::UnaryNodeType
GeneralParser<ParseHandler, Unit>::unaryOpExpr(YieldHandling yieldHandling,
ParseNodeKind kind,
uint32_t begin) {
Node kid = unaryExpr(yieldHandling, TripledotProhibited);
if (!kid) {
return null();
}
return handler_.newUnary(kind, begin, kid);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::unaryExpr(
YieldHandling yieldHandling, TripledotHandling tripledotHandling,
PossibleError* possibleError ,
InvokedPrediction invoked ) {
if (!CheckRecursionLimit(cx_)) {
return null();
}
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
uint32_t begin = pos().begin;
switch (tt) {
case TokenKind::Void:
return unaryOpExpr(yieldHandling, ParseNodeKind::VoidExpr, begin);
case TokenKind::Not:
return unaryOpExpr(yieldHandling, ParseNodeKind::NotExpr, begin);
case TokenKind::BitNot:
return unaryOpExpr(yieldHandling, ParseNodeKind::BitNotExpr, begin);
case TokenKind::Add:
return unaryOpExpr(yieldHandling, ParseNodeKind::PosExpr, begin);
case TokenKind::Sub:
return unaryOpExpr(yieldHandling, ParseNodeKind::NegExpr, begin);
case TokenKind::TypeOf: {
Node kid = unaryExpr(yieldHandling, TripledotProhibited);
if (!kid) {
return null();
}
return handler_.newTypeof(begin, kid);
}
case TokenKind::Inc:
case TokenKind::Dec: {
TokenKind tt2;
if (!tokenStream.getToken(&tt2, TokenStream::Operand)) {
return null();
}
uint32_t operandOffset = pos().begin;
Node operand = memberExpr(yieldHandling, TripledotProhibited, tt2);
if (!operand || !checkIncDecOperand(operand, operandOffset)) {
return null();
}
ParseNodeKind pnk = (tt == TokenKind::Inc)
? ParseNodeKind::PreIncrementExpr
: ParseNodeKind::PreDecrementExpr;
return handler_.newUpdate(pnk, begin, operand);
}
case TokenKind::Delete: {
uint32_t exprOffset;
if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand)) {
return null();
}
Node expr = unaryExpr(yieldHandling, TripledotProhibited);
if (!expr) {
return null();
}
if (handler_.isName(expr)) {
if (!strictModeErrorAt(exprOffset, JSMSG_DEPRECATED_DELETE_OPERAND)) {
return null();
}
pc_->sc()->setBindingsAccessedDynamically();
}
return handler_.newDelete(begin, expr);
}
case TokenKind::Await: {
if (pc_->isAsync()) {
if (inParametersOfAsyncFunction()) {
error(JSMSG_AWAIT_IN_PARAMETER);
return null();
}
Node kid =
unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked);
if (!kid) {
return null();
}
pc_->lastAwaitOffset = begin;
return handler_.newAwaitExpression(begin, kid);
}
}
MOZ_FALLTHROUGH;
default: {
Node expr =
memberExpr(yieldHandling, tripledotHandling, tt,
true, possibleError, invoked);
if (!expr) {
return null();
}
if (!tokenStream.peekTokenSameLine(&tt)) {
return null();
}
if (tt != TokenKind::Inc && tt != TokenKind::Dec) {
return expr;
}
tokenStream.consumeKnownToken(tt);
if (!checkIncDecOperand(expr, begin)) {
return null();
}
ParseNodeKind pnk = (tt == TokenKind::Inc)
? ParseNodeKind::PostIncrementExpr
: ParseNodeKind::PostDecrementExpr;
return handler_.newUpdate(pnk, begin, expr);
}
}
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::assignExprWithoutYieldOrAwait(
YieldHandling yieldHandling) {
uint32_t startYieldOffset = pc_->lastYieldOffset;
uint32_t startAwaitOffset = pc_->lastAwaitOffset;
Node res = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (res) {
if (pc_->lastYieldOffset != startYieldOffset) {
errorAt(pc_->lastYieldOffset, JSMSG_YIELD_IN_PARAMETER);
return null();
}
if (pc_->lastAwaitOffset != startAwaitOffset) {
errorAt(pc_->lastAwaitOffset, JSMSG_AWAIT_IN_PARAMETER);
return null();
}
}
return res;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::argumentList(
YieldHandling yieldHandling, bool* isSpread,
PossibleError* possibleError ) {
ListNodeType argsList = handler_.newArguments(pos());
if (!argsList) {
return null();
}
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::RightParen,
TokenStream::Operand)) {
return null();
}
if (matched) {
handler_.setEndPosition(argsList, pos().end);
return argsList;
}
while (true) {
bool spread = false;
uint32_t begin = 0;
if (!tokenStream.matchToken(&matched, TokenKind::TripleDot,
TokenStream::Operand)) {
return null();
}
if (matched) {
spread = true;
begin = pos().begin;
*isSpread = true;
}
Node argNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
possibleError);
if (!argNode) {
return null();
}
if (spread) {
argNode = handler_.newSpread(begin, argNode);
if (!argNode) {
return null();
}
}
handler_.addList(argsList, argNode);
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Comma,
TokenStream::Operand)) {
return null();
}
if (!matched) {
break;
}
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt == TokenKind::RightParen) {
break;
}
}
if (!mustMatchToken(TokenKind::RightParen, TokenStream::Operand,
JSMSG_PAREN_AFTER_ARGS)) {
return null();
}
handler_.setEndPosition(argsList, pos().end);
return argsList;
}
bool ParserBase::checkAndMarkSuperScope() {
if (!pc_->sc()->allowSuperProperty()) {
return false;
}
pc_->setSuperScopeNeedsHomeObject();
return true;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::computeErrorMetadata(
ErrorMetadata* err, const ErrorReportMixin::ErrorOffset& offset) {
if (offset.is<ErrorReportMixin::Current>()) {
return tokenStream.computeErrorMetadata(err, AsVariant(pos().begin));
}
return tokenStream.computeErrorMetadata(err, offset);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::memberExpr(
YieldHandling yieldHandling, TripledotHandling tripledotHandling,
TokenKind tt, bool allowCallSyntax ,
PossibleError* possibleError ,
InvokedPrediction invoked ) {
MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
Node lhs;
if (!CheckRecursionLimit(cx_)) {
return null();
}
if (tt == TokenKind::New) {
uint32_t newBegin = pos().begin;
BinaryNodeType newTarget;
if (!tryNewTarget(&newTarget)) {
return null();
}
if (newTarget) {
lhs = newTarget;
} else {
tt = anyChars.currentToken().type;
Node ctorExpr = memberExpr(yieldHandling, TripledotProhibited, tt,
false,
nullptr, PredictInvoked);
if (!ctorExpr) {
return null();
}
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::LeftParen)) {
return null();
}
bool isSpread = false;
Node args;
if (matched) {
args = argumentList(yieldHandling, &isSpread);
} else {
args = handler_.newArguments(pos());
}
if (!args) {
return null();
}
lhs = handler_.newNewExpression(newBegin, ctorExpr, args);
if (!lhs) {
return null();
}
if (isSpread) {
handler_.setOp(lhs, JSOP_SPREADNEW);
}
}
} else if (tt == TokenKind::Super) {
NameNodeType thisName = newThisName();
if (!thisName) {
return null();
}
lhs = handler_.newSuperBase(thisName, pos());
if (!lhs) {
return null();
}
} else if (tt == TokenKind::Import) {
lhs = importExpr(yieldHandling, allowCallSyntax);
if (!lhs) {
return null();
}
} else {
lhs = primaryExpr(yieldHandling, tripledotHandling, tt, possibleError,
invoked);
if (!lhs) {
return null();
}
}
MOZ_ASSERT_IF(handler_.isSuperBase(lhs),
anyChars.isCurrentTokenType(TokenKind::Super));
while (true) {
if (!tokenStream.getToken(&tt)) {
return null();
}
if (tt == TokenKind::Eof) {
break;
}
Node nextMember;
if (tt == TokenKind::Dot) {
if (!tokenStream.getToken(&tt)) {
return null();
}
if (TokenKindIsPossibleIdentifierName(tt)) {
PropertyName* field = anyChars.currentName();
if (handler_.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
error(JSMSG_BAD_SUPERPROP, "property");
return null();
}
NameNodeType name = handler_.newPropertyName(field, pos());
if (!name) {
return null();
}
nextMember = handler_.newPropertyAccess(lhs, name);
if (!nextMember) {
return null();
}
} else {
error(JSMSG_NAME_AFTER_DOT);
return null();
}
} else if (tt == TokenKind::LeftBracket) {
Node propExpr = expr(InAllowed, yieldHandling, TripledotProhibited);
if (!propExpr) {
return null();
}
if (!mustMatchToken(TokenKind::RightBracket, TokenStream::Operand,
JSMSG_BRACKET_IN_INDEX)) {
return null();
}
if (handler_.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
error(JSMSG_BAD_SUPERPROP, "member");
return null();
}
nextMember = handler_.newPropertyByValue(lhs, propExpr, pos().end);
if (!nextMember) {
return null();
}
} else if ((allowCallSyntax && tt == TokenKind::LeftParen) ||
tt == TokenKind::TemplateHead ||
tt == TokenKind::NoSubsTemplate) {
if (handler_.isSuperBase(lhs)) {
if (!pc_->sc()->allowSuperCall()) {
error(JSMSG_BAD_SUPERCALL);
return null();
}
if (tt != TokenKind::LeftParen) {
error(JSMSG_BAD_SUPER);
return null();
}
bool isSpread = false;
Node args = argumentList(yieldHandling, &isSpread);
if (!args) {
return null();
}
nextMember = handler_.newSuperCall(lhs, args);
if (!nextMember) {
return null();
}
if (isSpread) {
handler_.setOp(nextMember, JSOP_SPREADSUPERCALL);
}
NameNodeType thisName = newThisName();
if (!thisName) {
return null();
}
nextMember = handler_.newSetThis(thisName, nextMember);
if (!nextMember) {
return null();
}
} else {
if (options().selfHostingMode && handler_.isPropertyAccess(lhs)) {
error(JSMSG_SELFHOSTED_METHOD_CALL);
return null();
}
JSOp op = JSOP_CALL;
bool maybeAsyncArrow = false;
if (PropertyName* prop = handler_.maybeDottedProperty(lhs)) {
if (prop == cx_->names().apply) {
op = JSOP_FUNAPPLY;
if (pc_->isFunctionBox()) {
pc_->functionBox()->usesApply = true;
}
} else if (prop == cx_->names().call) {
op = JSOP_FUNCALL;
}
} else if (tt == TokenKind::LeftParen) {
if (handler_.isAsyncKeyword(lhs, cx_)) {
maybeAsyncArrow = true;
} else if (handler_.isEvalName(lhs, cx_)) {
op = pc_->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
pc_->sc()->setBindingsAccessedDynamically();
pc_->sc()->setHasDirectEval();
if (pc_->isFunctionBox() && !pc_->sc()->strict()) {
pc_->functionBox()->setHasExtensibleScope();
}
checkAndMarkSuperScope();
}
}
if (tt == TokenKind::LeftParen) {
bool isSpread = false;
PossibleError* asyncPossibleError =
maybeAsyncArrow ? possibleError : nullptr;
Node args =
argumentList(yieldHandling, &isSpread, asyncPossibleError);
if (!args) {
return null();
}
if (isSpread) {
if (op == JSOP_EVAL) {
op = JSOP_SPREADEVAL;
} else if (op == JSOP_STRICTEVAL) {
op = JSOP_STRICTSPREADEVAL;
} else {
op = JSOP_SPREADCALL;
}
}
nextMember = handler_.newCall(lhs, args);
if (!nextMember) {
return null();
}
} else {
ListNodeType args = handler_.newArguments(pos());
if (!args) {
return null();
}
if (!taggedTemplate(yieldHandling, args, tt)) {
return null();
}
nextMember = handler_.newTaggedTemplate(lhs, args);
if (!nextMember) {
return null();
}
}
handler_.setOp(nextMember, op);
}
} else {
anyChars.ungetToken();
if (handler_.isSuperBase(lhs)) {
break;
}
return lhs;
}
lhs = nextMember;
}
if (handler_.isSuperBase(lhs)) {
error(JSMSG_BAD_SUPER);
return null();
}
return lhs;
}
template <class ParseHandler>
inline typename ParseHandler::NameNodeType
PerHandlerParser<ParseHandler>::newName(PropertyName* name) {
return newName(name, pos());
}
template <class ParseHandler>
inline typename ParseHandler::NameNodeType
PerHandlerParser<ParseHandler>::newName(PropertyName* name, TokenPos pos) {
return handler_.newName(name, pos, cx_);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::checkLabelOrIdentifierReference(
PropertyName* ident, uint32_t offset, YieldHandling yieldHandling,
TokenKind hint ) {
TokenKind tt;
if (hint == TokenKind::Limit) {
tt = ReservedWordTokenKind(ident);
} else {
MOZ_ASSERT(hint == ReservedWordTokenKind(ident),
"hint doesn't match actual token kind");
tt = hint;
}
if (tt == TokenKind::Name || tt == TokenKind::PrivateName) {
return true;
}
if (TokenKindIsContextualKeyword(tt)) {
if (tt == TokenKind::Yield) {
if (yieldHandling == YieldIsKeyword) {
errorAt(offset, JSMSG_RESERVED_ID, "yield");
return false;
}
if (pc_->sc()->needStrictChecks()) {
if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "yield")) {
return false;
}
}
return true;
}
if (tt == TokenKind::Await) {
if (awaitIsKeyword()) {
errorAt(offset, JSMSG_RESERVED_ID, "await");
return false;
}
return true;
}
if (pc_->sc()->needStrictChecks()) {
if (tt == TokenKind::Let) {
if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "let")) {
return false;
}
return true;
}
if (tt == TokenKind::Static) {
if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "static")) {
return false;
}
return true;
}
}
return true;
}
if (TokenKindIsStrictReservedWord(tt)) {
if (pc_->sc()->needStrictChecks()) {
if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID,
ReservedWordToCharZ(tt))) {
return false;
}
}
return true;
}
if (TokenKindIsKeyword(tt) || TokenKindIsReservedWordLiteral(tt)) {
errorAt(offset, JSMSG_INVALID_ID, ReservedWordToCharZ(tt));
return false;
}
if (TokenKindIsFutureReservedWord(tt)) {
errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(tt));
return false;
}
MOZ_ASSERT_UNREACHABLE("Unexpected reserved word kind.");
return false;
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::checkBindingIdentifier(
PropertyName* ident, uint32_t offset, YieldHandling yieldHandling,
TokenKind hint ) {
if (pc_->sc()->needStrictChecks()) {
if (ident == cx_->names().arguments) {
if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "arguments")) {
return false;
}
return true;
}
if (ident == cx_->names().eval) {
if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "eval")) {
return false;
}
return true;
}
}
return checkLabelOrIdentifierReference(ident, offset, yieldHandling, hint);
}
template <class ParseHandler, typename Unit>
PropertyName* GeneralParser<ParseHandler, Unit>::labelOrIdentifierReference(
YieldHandling yieldHandling) {
TokenKind hint = !anyChars.currentNameHasEscapes()
? anyChars.currentToken().type
: TokenKind::Limit;
RootedPropertyName ident(cx_, anyChars.currentName());
if (!checkLabelOrIdentifierReference(ident, pos().begin, yieldHandling,
hint)) {
return nullptr;
}
return ident;
}
template <class ParseHandler, typename Unit>
PropertyName* GeneralParser<ParseHandler, Unit>::bindingIdentifier(
YieldHandling yieldHandling) {
TokenKind hint = !anyChars.currentNameHasEscapes()
? anyChars.currentToken().type
: TokenKind::Limit;
RootedPropertyName ident(cx_, anyChars.currentName());
if (!checkBindingIdentifier(ident, pos().begin, yieldHandling, hint)) {
return nullptr;
}
return ident;
}
template <class ParseHandler>
typename ParseHandler::NameNodeType
PerHandlerParser<ParseHandler>::identifierReference(
Handle<PropertyName*> name) {
NameNodeType id = newName(name);
if (!id) {
return null();
}
if (!noteUsedName(name)) {
return null();
}
return id;
}
template <class ParseHandler>
typename ParseHandler::NameNodeType
PerHandlerParser<ParseHandler>::stringLiteral() {
return handler_.newStringLiteral(anyChars.currentToken().atom(), pos());
}
template <class ParseHandler>
typename ParseHandler::Node
PerHandlerParser<ParseHandler>::noSubstitutionTaggedTemplate() {
if (anyChars.hasInvalidTemplateEscape()) {
anyChars.clearInvalidTemplateEscape();
return handler_.newRawUndefinedLiteral(pos());
}
return handler_.newTemplateStringLiteral(anyChars.currentToken().atom(),
pos());
}
template <class ParseHandler, typename Unit>
typename ParseHandler::NameNodeType
GeneralParser<ParseHandler, Unit>::noSubstitutionUntaggedTemplate() {
if (!tokenStream.checkForInvalidTemplateEscapeError()) {
return null();
}
return handler_.newTemplateStringLiteral(anyChars.currentToken().atom(),
pos());
}
template <typename Unit>
RegExpLiteral* Parser<FullParseHandler, Unit>::newRegExp() {
MOZ_ASSERT(!options().selfHostingMode);
const auto& chars = tokenStream.getCharBuffer();
RegExpFlag flags = anyChars.currentToken().regExpFlags();
Rooted<RegExpObject*> reobj(cx_);
reobj = RegExpObject::create(cx_, chars.begin(), chars.length(), flags,
anyChars, TenuredObject);
if (!reobj) {
return null();
}
return handler_.newRegExp(reobj, pos(), *this);
}
template <typename Unit>
SyntaxParseHandler::RegExpLiteralType
Parser<SyntaxParseHandler, Unit>::newRegExp() {
MOZ_ASSERT(!options().selfHostingMode);
const auto& chars = tokenStream.getCharBuffer();
RegExpFlag flags = anyChars.currentToken().regExpFlags();
mozilla::Range<const char16_t> source(chars.begin(), chars.length());
{
LifoAllocScope scopeAlloc(&alloc_);
if (!js::irregexp::ParsePatternSyntax(anyChars, scopeAlloc.alloc(), source,
flags & UnicodeFlag)) {
return null();
}
}
return handler_.newRegExp(SyntaxParseHandler::NodeGeneric, pos(), *this);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::RegExpLiteralType
GeneralParser<ParseHandler, Unit>::newRegExp() {
return asFinalParser()->newRegExp();
}
template <typename Unit>
BigIntLiteral* Parser<FullParseHandler, Unit>::newBigInt() {
const auto& chars = tokenStream.getCharBuffer();
mozilla::Range<const char16_t> source(chars.begin(), chars.length());
BigInt* b = js::ParseBigIntLiteral(cx_, source);
if (!b) {
return null();
}
return handler_.newBigInt(b, pos(), *this);
}
template <typename Unit>
SyntaxParseHandler::BigIntLiteralType
Parser<SyntaxParseHandler, Unit>::newBigInt() {
return handler_.newBigInt();
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BigIntLiteralType
GeneralParser<ParseHandler, Unit>::newBigInt() {
return asFinalParser()->newBigInt();
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::checkDestructuringAssignmentTarget(
Node expr, TokenPos exprPos, PossibleError* exprPossibleError,
PossibleError* possibleError, TargetBehavior behavior) {
if (!possibleError || handler_.isPropertyAccess(expr)) {
return exprPossibleError->checkForExpressionError();
}
exprPossibleError->transferErrorsTo(possibleError);
if (possibleError->hasPendingDestructuringError()) {
return true;
}
if (handler_.isName(expr)) {
checkDestructuringAssignmentName(handler_.asName(expr), exprPos,
possibleError);
return true;
}
if (handler_.isUnparenthesizedDestructuringPattern(expr)) {
if (behavior == TargetBehavior::ForbidAssignmentPattern) {
possibleError->setPendingDestructuringErrorAt(exprPos,
JSMSG_BAD_DESTRUCT_TARGET);
}
return true;
}
if (handler_.isParenthesizedDestructuringPattern(expr) &&
behavior != TargetBehavior::ForbidAssignmentPattern) {
possibleError->setPendingDestructuringErrorAt(exprPos,
JSMSG_BAD_DESTRUCT_PARENS);
} else {
possibleError->setPendingDestructuringErrorAt(exprPos,
JSMSG_BAD_DESTRUCT_TARGET);
}
return true;
}
template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::checkDestructuringAssignmentName(
NameNodeType name, TokenPos namePos, PossibleError* possibleError) {
#ifdef DEBUG
bool isName = handler_.isName(name);
MOZ_ASSERT(isName);
#endif
if (possibleError->hasPendingDestructuringError()) {
return;
}
if (pc_->sc()->needStrictChecks()) {
if (handler_.isArgumentsName(name, cx_)) {
if (pc_->sc()->strict()) {
possibleError->setPendingDestructuringErrorAt(
namePos, JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
} else {
possibleError->setPendingDestructuringWarningAt(
namePos, JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
}
return;
}
if (handler_.isEvalName(name, cx_)) {
if (pc_->sc()->strict()) {
possibleError->setPendingDestructuringErrorAt(
namePos, JSMSG_BAD_STRICT_ASSIGN_EVAL);
} else {
possibleError->setPendingDestructuringWarningAt(
namePos, JSMSG_BAD_STRICT_ASSIGN_EVAL);
}
return;
}
}
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::checkDestructuringAssignmentElement(
Node expr, TokenPos exprPos, PossibleError* exprPossibleError,
PossibleError* possibleError) {
if (handler_.isUnparenthesizedAssignment(expr)) {
if (!possibleError) {
return exprPossibleError->checkForExpressionError();
}
exprPossibleError->transferErrorsTo(possibleError);
return true;
}
return checkDestructuringAssignmentTarget(expr, exprPos, exprPossibleError,
possibleError);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::arrayInitializer(
YieldHandling yieldHandling, PossibleError* possibleError) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
uint32_t begin = pos().begin;
ListNodeType literal = handler_.newArrayLiteral(begin);
if (!literal) {
return null();
}
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt == TokenKind::RightBracket) {
handler_.setListHasNonConstInitializer(literal);
} else {
anyChars.ungetToken();
for (uint32_t index = 0;; index++) {
if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
error(JSMSG_ARRAY_INIT_TOO_BIG);
return null();
}
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
return null();
}
if (tt == TokenKind::RightBracket) {
break;
}
if (tt == TokenKind::Comma) {
tokenStream.consumeKnownToken(TokenKind::Comma, TokenStream::Operand);
if (!handler_.addElision(literal, pos())) {
return null();
}
continue;
}
if (tt == TokenKind::TripleDot) {
tokenStream.consumeKnownToken(TokenKind::TripleDot,
TokenStream::Operand);
uint32_t begin = pos().begin;
TokenPos innerPos;
if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand)) {
return null();
}
PossibleError possibleErrorInner(*this);
Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
&possibleErrorInner);
if (!inner) {
return null();
}
if (!checkDestructuringAssignmentTarget(
inner, innerPos, &possibleErrorInner, possibleError)) {
return null();
}
if (!handler_.addSpreadElement(literal, begin, inner)) {
return null();
}
} else {
TokenPos elementPos;
if (!tokenStream.peekTokenPos(&elementPos, TokenStream::Operand)) {
return null();
}
PossibleError possibleErrorInner(*this);
Node element = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
&possibleErrorInner);
if (!element) {
return null();
}
if (!checkDestructuringAssignmentElement(
element, elementPos, &possibleErrorInner, possibleError)) {
return null();
}
handler_.addArrayElement(literal, element);
}
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Comma,
TokenStream::Operand)) {
return null();
}
if (!matched) {
break;
}
if (tt == TokenKind::TripleDot && possibleError) {
possibleError->setPendingDestructuringErrorAt(pos(),
JSMSG_REST_WITH_COMMA);
}
}
if (!mustMatchToken(TokenKind::RightBracket, TokenStream::Operand,
[this, begin](TokenKind actual) {
this->reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
JSMSG_BRACKET_OPENED,
begin);
})) {
return null();
}
}
handler_.setEndPosition(literal, pos().end);
return literal;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::propertyName(
YieldHandling yieldHandling, PropertyNameContext propertyNameContext,
const Maybe<DeclarationKind>& maybeDecl, ListNodeType propList,
PropertyType* propType, MutableHandleAtom propAtom) {
TokenKind ltok;
if (!tokenStream.getToken(<ok)) {
return null();
}
MOZ_ASSERT(ltok != TokenKind::RightCurly,
"caller should have handled TokenKind::RightCurly");
bool isGenerator = false;
bool isAsync = false;
if (ltok == TokenKind::Async) {
TokenKind tt = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&tt)) {
return null();
}
if (tt == TokenKind::String || tt == TokenKind::Number ||
tt == TokenKind::LeftBracket || TokenKindIsPossibleIdentifierName(tt) ||
tt == TokenKind::Mul) {
isAsync = true;
tokenStream.consumeKnownToken(tt);
ltok = tt;
}
}
if (ltok == TokenKind::Mul) {
isGenerator = true;
if (!tokenStream.getToken(<ok)) {
return null();
}
}
propAtom.set(nullptr);
Node propName;
switch (ltok) {
case TokenKind::Number:
propAtom.set(NumberToAtom(cx_, anyChars.currentToken().number()));
if (!propAtom.get()) {
return null();
}
propName = newNumber(anyChars.currentToken());
if (!propName) {
return null();
}
break;
case TokenKind::String: {
propAtom.set(anyChars.currentToken().atom());
uint32_t index;
if (propAtom->isIndex(&index)) {
propName = handler_.newNumber(index, NoDecimal, pos());
if (!propName) {
return null();
}
break;
}
propName = stringLiteral();
if (!propName) {
return null();
}
break;
}
case TokenKind::LeftBracket:
propName = computedPropertyName(yieldHandling, maybeDecl,
propertyNameContext, propList);
if (!propName) {
return null();
}
break;
default: {
if (!TokenKindIsPossibleIdentifierName(ltok)) {
error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(ltok));
return null();
}
propAtom.set(anyChars.currentName());
if (isGenerator || isAsync ||
!(ltok == TokenKind::Get || ltok == TokenKind::Set)) {
propName = handler_.newObjectLiteralPropertyName(propAtom, pos());
if (!propName) {
return null();
}
break;
}
*propType =
ltok == TokenKind::Get ? PropertyType::Getter : PropertyType::Setter;
TokenKind tt;
if (!tokenStream.peekToken(&tt)) {
return null();
}
if (TokenKindIsPossibleIdentifierName(tt)) {
tokenStream.consumeKnownToken(tt);
propAtom.set(anyChars.currentName());
return handler_.newObjectLiteralPropertyName(propAtom, pos());
}
if (tt == TokenKind::String) {
tokenStream.consumeKnownToken(TokenKind::String);
propAtom.set(anyChars.currentToken().atom());
uint32_t index;
if (propAtom->isIndex(&index)) {
propAtom.set(NumberToAtom(cx_, index));
if (!propAtom.get()) {
return null();
}
return handler_.newNumber(index, NoDecimal, pos());
}
return stringLiteral();
}
if (tt == TokenKind::Number) {
tokenStream.consumeKnownToken(TokenKind::Number);
propAtom.set(NumberToAtom(cx_, anyChars.currentToken().number()));
if (!propAtom.get()) {
return null();
}
return newNumber(anyChars.currentToken());
}
if (tt == TokenKind::LeftBracket) {
tokenStream.consumeKnownToken(TokenKind::LeftBracket);
return computedPropertyName(yieldHandling, maybeDecl,
propertyNameContext, propList);
}
propName = handler_.newObjectLiteralPropertyName(propAtom.get(), pos());
if (!propName) {
return null();
}
break;
}
}
TokenKind tt;
if (!tokenStream.getToken(&tt)) {
return null();
}
if (tt == TokenKind::Colon) {
if (isGenerator || isAsync) {
error(JSMSG_BAD_PROP_ID);
return null();
}
*propType = PropertyType::Normal;
return propName;
}
if (propertyNameContext == PropertyNameInClass &&
(tt == TokenKind::Semi || tt == TokenKind::Assign)) {
if (isGenerator || isAsync) {
error(JSMSG_BAD_PROP_ID);
return null();
}
anyChars.ungetToken();
*propType = PropertyType::Field;
return propName;
}
if (TokenKindIsPossibleIdentifierName(ltok) &&
(tt == TokenKind::Comma || tt == TokenKind::RightCurly ||
tt == TokenKind::Assign)) {
if (isGenerator || isAsync) {
error(JSMSG_BAD_PROP_ID);
return null();
}
anyChars.ungetToken();
anyChars.addModifierException(TokenStream::OperandIsNone);
*propType = tt == TokenKind::Assign ? PropertyType::CoverInitializedName
: PropertyType::Shorthand;
return propName;
}
if (tt == TokenKind::LeftParen) {
anyChars.ungetToken();
if (isGenerator && isAsync) {
*propType = PropertyType::AsyncGeneratorMethod;
} else if (isGenerator) {
*propType = PropertyType::GeneratorMethod;
} else if (isAsync) {
*propType = PropertyType::AsyncMethod;
} else {
*propType = PropertyType::Method;
}
return propName;
}
error(JSMSG_COLON_AFTER_ID);
return null();
}
template <class ParseHandler, typename Unit>
typename ParseHandler::UnaryNodeType
GeneralParser<ParseHandler, Unit>::computedPropertyName(
YieldHandling yieldHandling, const Maybe<DeclarationKind>& maybeDecl,
PropertyNameContext propertyNameContext, ListNodeType literal) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
uint32_t begin = pos().begin;
if (maybeDecl) {
if (*maybeDecl == DeclarationKind::FormalParameter) {
pc_->functionBox()->hasParameterExprs = true;
}
} else if (propertyNameContext ==
PropertyNameContext::PropertyNameInLiteral) {
handler_.setListHasNonConstInitializer(literal);
}
Node assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (!assignNode) {
return null();
}
if (!mustMatchToken(TokenKind::RightBracket, TokenStream::Operand,
JSMSG_COMP_PROP_UNTERM_EXPR)) {
return null();
}
return handler_.newComputedName(assignNode, begin, pos().end);
}
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::objectLiteral(YieldHandling yieldHandling,
PossibleError* possibleError) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
uint32_t openedPos = pos().begin;
ListNodeType literal = handler_.newObjectLiteral(pos().begin);
if (!literal) {
return null();
}
bool seenPrototypeMutation = false;
bool seenCoverInitializedName = false;
Maybe<DeclarationKind> declKind = Nothing();
RootedAtom propAtom(cx_);
for (;;) {
TokenKind tt;
if (!tokenStream.peekToken(&tt)) {
return null();
}
if (tt == TokenKind::RightCurly) {
anyChars.addModifierException(TokenStream::OperandIsNone);
break;
}
if (tt == TokenKind::TripleDot) {
tokenStream.consumeKnownToken(TokenKind::TripleDot);
uint32_t begin = pos().begin;
TokenPos innerPos;
if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand)) {
return null();
}
PossibleError possibleErrorInner(*this);
Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
&possibleErrorInner);
if (!inner) {
return null();
}
if (!checkDestructuringAssignmentTarget(
inner, innerPos, &possibleErrorInner, possibleError,
TargetBehavior::ForbidAssignmentPattern)) {
return null();
}
if (!handler_.addSpreadProperty(literal, begin, inner)) {
return null();
}
} else {
TokenPos namePos = anyChars.nextToken().pos;
PropertyType propType;
Node propName = propertyName(yieldHandling, PropertyNameInLiteral,
declKind, literal, &propType, &propAtom);
if (!propName) {
return null();
}
if (propType == PropertyType::Normal) {
TokenPos exprPos;
if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand)) {
return null();
}
PossibleError possibleErrorInner(*this);
Node propExpr = assignExpr(InAllowed, yieldHandling,
TripledotProhibited, &possibleErrorInner);
if (!propExpr) {
return null();
}
if (!checkDestructuringAssignmentElement(
propExpr, exprPos, &possibleErrorInner, possibleError)) {
return null();
}
if (propAtom == cx_->names().proto) {
if (seenPrototypeMutation) {
if (!possibleError) {
errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY);
return null();
}
possibleError->setPendingExpressionErrorAt(
namePos, JSMSG_DUPLICATE_PROTO_PROPERTY);
}
seenPrototypeMutation = true;
if (!handler_.addPrototypeMutation(literal, namePos.begin,
propExpr)) {
return null();
}
} else {
BinaryNodeType propDef =
handler_.newPropertyDefinition(propName, propExpr);
if (!propDef) {
return null();
}
handler_.addPropertyDefinition(literal, propDef);
}
} else if (propType == PropertyType::Shorthand) {
Rooted<PropertyName*> name(cx_, identifierReference(yieldHandling));
if (!name) {
return null();
}
NameNodeType nameExpr = identifierReference(name);
if (!nameExpr) {
return null();
}
if (possibleError) {
checkDestructuringAssignmentName(nameExpr, namePos, possibleError);
}
if (!handler_.addShorthand(literal, handler_.asName(propName),
nameExpr)) {
return null();
}
} else if (propType == PropertyType::CoverInitializedName) {
Rooted<PropertyName*> name(cx_, identifierReference(yieldHandling));
if (!name) {
return null();
}
Node lhs = identifierReference(name);
if (!lhs) {
return null();
}
tokenStream.consumeKnownToken(TokenKind::Assign);
if (!seenCoverInitializedName) {
seenCoverInitializedName = true;
if (!possibleError) {
error(JSMSG_COLON_AFTER_ID);
return null();
}
possibleError->setPendingExpressionErrorAt(pos(),
JSMSG_COLON_AFTER_ID);
}
if (const char* chars = nameIsArgumentsOrEval(lhs)) {
if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN,
chars)) {
return null();
}
}
Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (!rhs) {
return null();
}
BinaryNodeType propExpr =
handler_.newAssignment(ParseNodeKind::AssignExpr, lhs, rhs);
if (!propExpr) {
return null();
}
if (!handler_.addPropertyDefinition(literal, propName, propExpr)) {
return null();
}
} else {
RootedAtom funName(cx_);
if (!anyChars.isCurrentTokenType(TokenKind::RightBracket)) {
funName = propAtom;
if (propType == PropertyType::Getter ||
propType == PropertyType::Setter) {
funName = prefixAccessorName(propType, propAtom);
if (!funName) {
return null();
}
}
}
FunctionNodeType funNode =
methodDefinition(namePos.begin, propType, funName);
if (!funNode) {
return null();
}
AccessorType atype = ToAccessorType(propType);
if (!handler_.addObjectMethodDefinition(literal, propName, funNode,
atype)) {
return null();
}
if (possibleError) {
possibleError->setPendingDestructuringErrorAt(
namePos, JSMSG_BAD_DESTRUCT_TARGET);
}
}
}
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Comma,
TokenStream::Operand)) {
return null();
}
if (!matched) {
break;
}
if (tt == TokenKind::TripleDot && possibleError) {
possibleError->setPendingDestructuringErrorAt(pos(),
JSMSG_REST_WITH_COMMA);
}
}
if (!mustMatchToken(TokenKind::RightCurly, TokenStream::Operand,
[this, openedPos](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
JSMSG_CURLY_OPENED,
openedPos);
})) {
return null();
}
handler_.setEndPosition(literal, pos().end);
return literal;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::FunctionNodeType
GeneralParser<ParseHandler, Unit>::methodDefinition(uint32_t toStringStart,
PropertyType propType,
HandleAtom funName) {
FunctionSyntaxKind syntaxKind;
switch (propType) {
case PropertyType::Getter:
syntaxKind = FunctionSyntaxKind::Getter;
break;
case PropertyType::Setter:
syntaxKind = FunctionSyntaxKind::Setter;
break;
case PropertyType::Method:
case PropertyType::GeneratorMethod:
case PropertyType::AsyncMethod:
case PropertyType::AsyncGeneratorMethod:
syntaxKind = FunctionSyntaxKind::Method;
break;
case PropertyType::Constructor:
syntaxKind = FunctionSyntaxKind::ClassConstructor;
break;
case PropertyType::DerivedConstructor:
syntaxKind = FunctionSyntaxKind::DerivedClassConstructor;
break;
default:
MOZ_CRASH("unexpected property type");
}
GeneratorKind generatorKind = (propType == PropertyType::GeneratorMethod ||
propType == PropertyType::AsyncGeneratorMethod)
? GeneratorKind::Generator
: GeneratorKind::NotGenerator;
FunctionAsyncKind asyncKind = (propType == PropertyType::AsyncMethod ||
propType == PropertyType::AsyncGeneratorMethod)
? FunctionAsyncKind::AsyncFunction
: FunctionAsyncKind::SyncFunction;
YieldHandling yieldHandling = GetYieldHandling(generatorKind);
FunctionNodeType funNode = handler_.newFunction(syntaxKind, pos());
if (!funNode) {
return null();
}
return functionDefinition(funNode, toStringStart, InAllowed, yieldHandling,
funName, syntaxKind, generatorKind, asyncKind);
}
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::tryNewTarget(
BinaryNodeType* newTarget) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::New));
*newTarget = null();
NullaryNodeType newHolder = handler_.newPosHolder(pos());
if (!newHolder) {
return false;
}
uint32_t begin = pos().begin;
TokenKind next;
if (!tokenStream.getToken(&next, TokenStream::Operand)) {
return false;
}
if (next != TokenKind::Dot) {
return true;
}
if (!tokenStream.getToken(&next)) {
return false;
}
if (next != TokenKind::Target) {
error(JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next));
return false;
}
if (!pc_->sc()->allowNewTarget()) {
errorAt(begin, JSMSG_BAD_NEWTARGET);
return false;
}
NullaryNodeType targetHolder = handler_.newPosHolder(pos());
if (!targetHolder) {
return false;
}
*newTarget = handler_.newNewTarget(newHolder, targetHolder);
return !!*newTarget;
}
template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::importExpr(YieldHandling yieldHandling,
bool allowCallSyntax) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
NullaryNodeType importHolder = handler_.newPosHolder(pos());
if (!importHolder) {
return null();
}
TokenKind next;
if (!tokenStream.getToken(&next)) {
return null();
}
if (next == TokenKind::Dot) {
if (!tokenStream.getToken(&next)) {
return null();
}
if (next != TokenKind::Meta) {
error(JSMSG_UNEXPECTED_TOKEN, "meta", TokenKindToDesc(next));
return null();
}
if (parseGoal() != ParseGoal::Module) {
errorAt(pos().begin, JSMSG_IMPORT_META_OUTSIDE_MODULE);
return null();
}
NullaryNodeType metaHolder = handler_.newPosHolder(pos());
if (!metaHolder) {
return null();
}
return handler_.newImportMeta(importHolder, metaHolder);
} else if (next == TokenKind::LeftParen && allowCallSyntax) {
Node arg = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (!arg) {
return null();
}
if (!mustMatchToken(TokenKind::RightParen, TokenStream::Operand,
JSMSG_PAREN_AFTER_ARGS)) {
return null();
}
if (!cx_->runtime()->moduleDynamicImportHook) {
error(JSMSG_NO_DYNAMIC_IMPORT);
return null();
}
return handler_.newCallImport(importHolder, arg);
} else {
error(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, TokenKindToDesc(next));
return null();
}
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::primaryExpr(
YieldHandling yieldHandling, TripledotHandling tripledotHandling,
TokenKind tt, PossibleError* possibleError,
InvokedPrediction invoked ) {
MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
if (!CheckRecursionLimit(cx_)) {
return null();
}
switch (tt) {
case TokenKind::Function:
return functionExpr(pos().begin, invoked,
FunctionAsyncKind::SyncFunction);
case TokenKind::Class:
return classDefinition(yieldHandling, ClassExpression, NameRequired);
case TokenKind::LeftBracket:
return arrayInitializer(yieldHandling, possibleError);
case TokenKind::LeftCurly:
return objectLiteral(yieldHandling, possibleError);
case TokenKind::LeftParen: {
TokenKind next;
if (!tokenStream.peekToken(&next, TokenStream::Operand)) {
return null();
}
if (next == TokenKind::RightParen) {
tokenStream.consumeKnownToken(TokenKind::RightParen,
TokenStream::Operand);
if (!tokenStream.peekToken(&next)) {
return null();
}
if (next != TokenKind::Arrow) {
error(JSMSG_UNEXPECTED_TOKEN, "expression",
TokenKindToDesc(TokenKind::RightParen));
return null();
}
return handler_.newNullLiteral(pos());
}
Node expr = exprInParens(InAllowed, yieldHandling, TripledotAllowed,
possibleError);
if (!expr) {
return null();
}
if (!mustMatchToken(TokenKind::RightParen, TokenStream::Operand,
JSMSG_PAREN_IN_PAREN)) {
return null();
}
return handler_.parenthesize(expr);
}
case TokenKind::TemplateHead:
return templateLiteral(yieldHandling);
case TokenKind::NoSubsTemplate:
return noSubstitutionUntaggedTemplate();
case TokenKind::String:
return stringLiteral();
default: {
if (!TokenKindIsPossibleIdentifier(tt)) {
error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
return null();
}
if (tt == TokenKind::Async) {
TokenKind nextSameLine = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
return null();
}
if (nextSameLine == TokenKind::Function) {
uint32_t toStringStart = pos().begin;
tokenStream.consumeKnownToken(TokenKind::Function);
return functionExpr(toStringStart, PredictUninvoked,
FunctionAsyncKind::AsyncFunction);
}
}
Rooted<PropertyName*> name(cx_, identifierReference(yieldHandling));
if (!name) {
return null();
}
return identifierReference(name);
}
case TokenKind::RegExp:
return newRegExp();
case TokenKind::Number:
return newNumber(anyChars.currentToken());
case TokenKind::BigInt:
return newBigInt();
case TokenKind::True:
return handler_.newBooleanLiteral(true, pos());
case TokenKind::False:
return handler_.newBooleanLiteral(false, pos());
case TokenKind::This: {
if (pc_->isFunctionBox()) {
pc_->functionBox()->usesThis = true;
}
NameNodeType thisName = null();
if (pc_->sc()->thisBinding() == ThisBinding::Function) {
thisName = newThisName();
if (!thisName) {
return null();
}
}
return handler_.newThisLiteral(pos(), thisName);
}
case TokenKind::Null:
return handler_.newNullLiteral(pos());
case TokenKind::TripleDot: {
if (tripledotHandling != TripledotAllowed) {
error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
return null();
}
TokenKind next;
if (!tokenStream.getToken(&next)) {
return null();
}
if (next == TokenKind::LeftBracket || next == TokenKind::LeftCurly) {
if (!destructuringDeclaration(DeclarationKind::CoverArrowParameter,
yieldHandling, next)) {
return null();
}
} else {
if (!TokenKindIsPossibleIdentifier(next)) {
error(JSMSG_UNEXPECTED_TOKEN, "rest argument name",
TokenKindToDesc(next));
return null();
}
}
if (!tokenStream.getToken(&next)) {
return null();
}
if (next != TokenKind::RightParen) {
error(JSMSG_UNEXPECTED_TOKEN, "closing parenthesis",
TokenKindToDesc(next));
return null();
}
if (!tokenStream.peekToken(&next)) {
return null();
}
if (next != TokenKind::Arrow) {
tokenStream.consumeKnownToken(next);
error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list",
TokenKindToDesc(next));
return null();
}
anyChars.ungetToken();
return handler_.newNullLiteral(pos());
}
}
}
template <class ParseHandler, typename Unit>
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::exprInParens(
InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
PossibleError* possibleError ) {
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftParen));
return expr(inHandling, yieldHandling, tripledotHandling, possibleError,
PredictInvoked);
}
template class PerHandlerParser<FullParseHandler>;
template class PerHandlerParser<SyntaxParseHandler>;
template class GeneralParser<FullParseHandler, Utf8Unit>;
template class GeneralParser<SyntaxParseHandler, Utf8Unit>;
template class GeneralParser<FullParseHandler, char16_t>;
template class GeneralParser<SyntaxParseHandler, char16_t>;
template class Parser<FullParseHandler, Utf8Unit>;
template class Parser<SyntaxParseHandler, Utf8Unit>;
template class Parser<FullParseHandler, char16_t>;
template class Parser<SyntaxParseHandler, char16_t>;
}
}