Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / Parser.cpp
blob290c4ab51d298fe1058a445713c2eda3fdb4cf7e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * JS parser.
10 * This is a recursive-descent parser for the JavaScript language specified by
11 * "The ECMAScript Language Specification" (Standard ECMA-262). It uses
12 * lexical and semantic feedback to disambiguate non-LL(1) structures. It
13 * generates trees of nodes induced by the recursive parsing (not precise
14 * syntax trees, see Parser.h). After tree construction, it rewrites trees to
15 * fold constants and evaluate compile-time expressions.
17 * This parser attempts no error recovery.
20 #include "frontend/Parser.h"
22 #include "mozilla/ArrayUtils.h"
23 #include "mozilla/Assertions.h"
24 #include "mozilla/Casting.h"
25 #include "mozilla/Range.h"
26 #include "mozilla/Sprintf.h"
27 #include "mozilla/Try.h" // MOZ_TRY*
28 #include "mozilla/Utf8.h"
29 #include "mozilla/Variant.h"
31 #include <memory>
32 #include <new>
33 #include <type_traits>
35 #include "jsnum.h"
36 #include "jstypes.h"
38 #include "frontend/FoldConstants.h"
39 #include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
40 #include "frontend/ModuleSharedContext.h"
41 #include "frontend/ParseNode.h"
42 #include "frontend/ParseNodeVerify.h"
43 #include "frontend/Parser-macros.h" // MOZ_TRY_VAR_OR_RETURN
44 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex, ParserAtomsTable, ParserAtom
45 #include "frontend/ScriptIndex.h" // ScriptIndex
46 #include "frontend/TokenStream.h" // IsKeyword, ReservedWordTokenKind, ReservedWordToCharZ, DeprecatedContent, *TokenStream*, CharBuffer, TokenKindToDesc
47 #include "irregexp/RegExpAPI.h"
48 #include "js/ColumnNumber.h" // JS::LimitedColumnNumberOneOrigin, JS::ColumnNumberOneOrigin
49 #include "js/ErrorReport.h" // JSErrorBase
50 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
51 #include "js/HashTable.h"
52 #include "js/RegExpFlags.h" // JS::RegExpFlags
53 #include "js/Stack.h" // JS::NativeStackLimit
54 #include "util/StringBuffer.h" // StringBuffer
55 #include "vm/BytecodeUtil.h"
56 #include "vm/FunctionFlags.h" // js::FunctionFlags
57 #include "vm/GeneratorAndAsyncKind.h" // js::GeneratorKind, js::FunctionAsyncKind
58 #include "vm/JSContext.h"
59 #include "vm/JSScript.h"
60 #include "vm/ModuleBuilder.h" // js::ModuleBuilder
61 #include "vm/Scope.h" // GetScopeDataTrailingNames
62 #include "wasm/AsmJS.h"
64 #include "frontend/ParseContext-inl.h"
65 #include "frontend/SharedContext-inl.h"
67 using namespace js;
69 using mozilla::AssertedCast;
70 using mozilla::AsVariant;
71 using mozilla::Maybe;
72 using mozilla::Nothing;
73 using mozilla::PointerRangeSize;
74 using mozilla::Some;
75 using mozilla::Utf8Unit;
77 using JS::ReadOnlyCompileOptions;
78 using JS::RegExpFlags;
80 namespace js::frontend {
82 using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
83 using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
84 using BindingIter = ParseContext::Scope::BindingIter;
85 using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
87 using ParserBindingNameVector = Vector<ParserBindingName, 6>;
89 static inline void PropagateTransitiveParseFlags(const FunctionBox* inner,
90 SharedContext* outer) {
91 if (inner->bindingsAccessedDynamically()) {
92 outer->setBindingsAccessedDynamically();
94 if (inner->hasDirectEval()) {
95 outer->setHasDirectEval();
99 static bool StatementKindIsBraced(StatementKind kind) {
100 return kind == StatementKind::Block || kind == StatementKind::Switch ||
101 kind == StatementKind::Try || kind == StatementKind::Catch ||
102 kind == StatementKind::Finally;
105 template <class ParseHandler, typename Unit>
106 inline typename GeneralParser<ParseHandler, Unit>::FinalParser*
107 GeneralParser<ParseHandler, Unit>::asFinalParser() {
108 static_assert(
109 std::is_base_of_v<GeneralParser<ParseHandler, Unit>, FinalParser>,
110 "inheritance relationship required by the static_cast<> below");
112 return static_cast<FinalParser*>(this);
115 template <class ParseHandler, typename Unit>
116 inline const typename GeneralParser<ParseHandler, Unit>::FinalParser*
117 GeneralParser<ParseHandler, Unit>::asFinalParser() const {
118 static_assert(
119 std::is_base_of_v<GeneralParser<ParseHandler, Unit>, FinalParser>,
120 "inheritance relationship required by the static_cast<> below");
122 return static_cast<const FinalParser*>(this);
125 template <class ParseHandler, typename Unit>
126 template <typename ConditionT, typename ErrorReportT>
127 bool GeneralParser<ParseHandler, Unit>::mustMatchTokenInternal(
128 ConditionT condition, ErrorReportT errorReport) {
129 MOZ_ASSERT(condition(TokenKind::Div) == false);
130 MOZ_ASSERT(condition(TokenKind::DivAssign) == false);
131 MOZ_ASSERT(condition(TokenKind::RegExp) == false);
133 TokenKind actual;
134 if (!tokenStream.getToken(&actual, TokenStream::SlashIsInvalid)) {
135 return false;
137 if (!condition(actual)) {
138 errorReport(actual);
139 return false;
141 return true;
144 ParserSharedBase::ParserSharedBase(FrontendContext* fc,
145 CompilationState& compilationState,
146 Kind kind)
147 : fc_(fc),
148 alloc_(compilationState.parserAllocScope.alloc()),
149 compilationState_(compilationState),
150 pc_(nullptr),
151 usedNames_(compilationState.usedNames) {
152 fc_->nameCollectionPool().addActiveCompilation();
155 ParserSharedBase::~ParserSharedBase() {
156 fc_->nameCollectionPool().removeActiveCompilation();
159 #if defined(DEBUG) || defined(JS_JITSPEW)
160 void ParserSharedBase::dumpAtom(TaggedParserAtomIndex index) const {
161 parserAtoms().dump(index);
163 #endif
165 ParserBase::ParserBase(FrontendContext* fc,
166 const ReadOnlyCompileOptions& options,
167 bool foldConstants, CompilationState& compilationState)
168 : ParserSharedBase(fc, compilationState, ParserSharedBase::Kind::Parser),
169 anyChars(fc, options, this),
170 ss(nullptr),
171 foldConstants_(foldConstants),
172 #ifdef DEBUG
173 checkOptionsCalled_(false),
174 #endif
175 isUnexpectedEOF_(false),
176 awaitHandling_(AwaitIsName),
177 inParametersOfAsyncFunction_(false) {
180 bool ParserBase::checkOptions() {
181 #ifdef DEBUG
182 checkOptionsCalled_ = true;
183 #endif
185 return anyChars.checkOptions();
188 ParserBase::~ParserBase() { MOZ_ASSERT(checkOptionsCalled_); }
190 JSAtom* ParserBase::liftParserAtomToJSAtom(TaggedParserAtomIndex index) {
191 JSContext* cx = fc_->maybeCurrentJSContext();
192 MOZ_ASSERT(cx);
193 return parserAtoms().toJSAtom(cx, fc_, index,
194 compilationState_.input.atomCache);
197 template <class ParseHandler>
198 PerHandlerParser<ParseHandler>::PerHandlerParser(
199 FrontendContext* fc, const ReadOnlyCompileOptions& options,
200 bool foldConstants, CompilationState& compilationState,
201 void* internalSyntaxParser)
202 : ParserBase(fc, options, foldConstants, compilationState),
203 handler_(fc, compilationState),
204 internalSyntaxParser_(internalSyntaxParser) {
205 MOZ_ASSERT(compilationState.isInitialStencil() ==
206 compilationState.input.isInitialStencil());
209 template <class ParseHandler, typename Unit>
210 GeneralParser<ParseHandler, Unit>::GeneralParser(
211 FrontendContext* fc, const ReadOnlyCompileOptions& options,
212 const Unit* units, size_t length, bool foldConstants,
213 CompilationState& compilationState, SyntaxParser* syntaxParser)
214 : Base(fc, options, foldConstants, compilationState, syntaxParser),
215 tokenStream(fc, &compilationState.parserAtoms, options, units, length) {}
217 template <typename Unit>
218 void Parser<SyntaxParseHandler, Unit>::setAwaitHandling(
219 AwaitHandling awaitHandling) {
220 this->awaitHandling_ = awaitHandling;
223 template <typename Unit>
224 void Parser<FullParseHandler, Unit>::setAwaitHandling(
225 AwaitHandling awaitHandling) {
226 this->awaitHandling_ = awaitHandling;
227 if (SyntaxParser* syntaxParser = getSyntaxParser()) {
228 syntaxParser->setAwaitHandling(awaitHandling);
232 template <class ParseHandler, typename Unit>
233 inline void GeneralParser<ParseHandler, Unit>::setAwaitHandling(
234 AwaitHandling awaitHandling) {
235 asFinalParser()->setAwaitHandling(awaitHandling);
238 template <typename Unit>
239 void Parser<SyntaxParseHandler, Unit>::setInParametersOfAsyncFunction(
240 bool inParameters) {
241 this->inParametersOfAsyncFunction_ = inParameters;
244 template <typename Unit>
245 void Parser<FullParseHandler, Unit>::setInParametersOfAsyncFunction(
246 bool inParameters) {
247 this->inParametersOfAsyncFunction_ = inParameters;
248 if (SyntaxParser* syntaxParser = getSyntaxParser()) {
249 syntaxParser->setInParametersOfAsyncFunction(inParameters);
253 template <class ParseHandler, typename Unit>
254 inline void GeneralParser<ParseHandler, Unit>::setInParametersOfAsyncFunction(
255 bool inParameters) {
256 asFinalParser()->setInParametersOfAsyncFunction(inParameters);
259 template <class ParseHandler>
260 FunctionBox* PerHandlerParser<ParseHandler>::newFunctionBox(
261 FunctionNodeType funNode, TaggedParserAtomIndex explicitName,
262 FunctionFlags flags, uint32_t toStringStart, Directives inheritedDirectives,
263 GeneratorKind generatorKind, FunctionAsyncKind asyncKind) {
264 MOZ_ASSERT(funNode);
266 ScriptIndex index = ScriptIndex(compilationState_.scriptData.length());
267 if (uint32_t(index) >= TaggedScriptThingIndex::IndexLimit) {
268 ReportAllocationOverflow(fc_);
269 return nullptr;
271 if (!compilationState_.appendScriptStencilAndData(fc_)) {
272 return nullptr;
275 bool isInitialStencil = compilationState_.isInitialStencil();
277 // This source extent will be further filled in during the remainder of parse.
278 SourceExtent extent;
279 extent.toStringStart = toStringStart;
281 FunctionBox* funbox = alloc_.new_<FunctionBox>(
282 fc_, extent, compilationState_, inheritedDirectives, generatorKind,
283 asyncKind, isInitialStencil, explicitName, flags, index);
284 if (!funbox) {
285 ReportOutOfMemory(fc_);
286 return nullptr;
289 handler_.setFunctionBox(funNode, funbox);
291 return funbox;
294 template <class ParseHandler>
295 FunctionBox* PerHandlerParser<ParseHandler>::newFunctionBox(
296 FunctionNodeType funNode, const ScriptStencil& cachedScriptData,
297 const ScriptStencilExtra& cachedScriptExtra) {
298 MOZ_ASSERT(funNode);
300 ScriptIndex index = ScriptIndex(compilationState_.scriptData.length());
301 if (uint32_t(index) >= TaggedScriptThingIndex::IndexLimit) {
302 ReportAllocationOverflow(fc_);
303 return nullptr;
305 if (!compilationState_.appendScriptStencilAndData(fc_)) {
306 return nullptr;
309 FunctionBox* funbox = alloc_.new_<FunctionBox>(
310 fc_, cachedScriptExtra.extent, compilationState_,
311 Directives(/* strict = */ false), cachedScriptExtra.generatorKind(),
312 cachedScriptExtra.asyncKind(), compilationState_.isInitialStencil(),
313 cachedScriptData.functionAtom, cachedScriptData.functionFlags, index);
314 if (!funbox) {
315 ReportOutOfMemory(fc_);
316 return nullptr;
319 handler_.setFunctionBox(funNode, funbox);
320 funbox->initFromScriptStencilExtra(cachedScriptExtra);
322 return funbox;
325 bool ParserBase::setSourceMapInfo() {
326 // If support for source pragmas have been fully disabled, we can skip
327 // processing of all of these values.
328 if (!options().sourcePragmas()) {
329 return true;
332 // Not all clients initialize ss. Can't update info to an object that isn't
333 // there.
334 if (!ss) {
335 return true;
338 if (anyChars.hasDisplayURL()) {
339 if (!ss->setDisplayURL(fc_, anyChars.displayURL())) {
340 return false;
344 if (anyChars.hasSourceMapURL()) {
345 MOZ_ASSERT(!ss->hasSourceMapURL());
346 if (!ss->setSourceMapURL(fc_, anyChars.sourceMapURL())) {
347 return false;
352 * Source map URLs passed as a compile option (usually via a HTTP source map
353 * header) override any source map urls passed as comment pragmas.
355 if (options().sourceMapURL()) {
356 // Warn about the replacement, but use the new one.
357 if (ss->hasSourceMapURL()) {
358 if (!warningNoOffset(JSMSG_ALREADY_HAS_PRAGMA, ss->filename(),
359 "//# sourceMappingURL")) {
360 return false;
364 if (!ss->setSourceMapURL(fc_, options().sourceMapURL())) {
365 return false;
369 return true;
373 * Parse a top-level JS script.
375 template <class ParseHandler, typename Unit>
376 typename ParseHandler::ListNodeResult
377 GeneralParser<ParseHandler, Unit>::parse() {
378 MOZ_ASSERT(checkOptionsCalled_);
380 SourceExtent extent = SourceExtent::makeGlobalExtent(
381 /* len = */ 0, options().lineno,
382 JS::LimitedColumnNumberOneOrigin::fromUnlimited(
383 JS::ColumnNumberOneOrigin(options().column)));
384 Directives directives(options().forceStrictMode());
385 GlobalSharedContext globalsc(this->fc_, ScopeKind::Global, options(),
386 directives, extent);
387 SourceParseContext globalpc(this, &globalsc, /* newDirectives = */ nullptr);
388 if (!globalpc.init()) {
389 return errorResult();
392 ParseContext::VarScope varScope(this);
393 if (!varScope.init(pc_)) {
394 return errorResult();
397 ListNodeType stmtList;
398 MOZ_TRY_VAR(stmtList, statementList(YieldIsName));
400 TokenKind tt;
401 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
402 return errorResult();
404 if (tt != TokenKind::Eof) {
405 error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt));
406 return errorResult();
409 if (!CheckParseTree(this->fc_, alloc_, stmtList)) {
410 return errorResult();
413 if (foldConstants_) {
414 Node node = stmtList;
415 // Don't constant-fold inside "use asm" code, as this could create a parse
416 // tree that doesn't type-check as asm.js.
417 if (!pc_->useAsmOrInsideUseAsm()) {
418 if (!FoldConstants(this->fc_, this->parserAtoms(), &node, &handler_)) {
419 return errorResult();
422 stmtList = handler_.asListNode(node);
425 return stmtList;
429 * Strict mode forbids introducing new definitions for 'eval', 'arguments',
430 * 'let', 'static', 'yield', or for any strict mode reserved word.
432 bool ParserBase::isValidStrictBinding(TaggedParserAtomIndex name) {
433 TokenKind tt = ReservedWordTokenKind(name);
434 if (tt == TokenKind::Limit) {
435 return name != TaggedParserAtomIndex::WellKnown::eval() &&
436 name != TaggedParserAtomIndex::WellKnown::arguments();
438 return tt != TokenKind::Let && tt != TokenKind::Static &&
439 tt != TokenKind::Yield && !TokenKindIsStrictReservedWord(tt);
443 * Returns true if all parameter names are valid strict mode binding names and
444 * no duplicate parameter names are present.
446 bool ParserBase::hasValidSimpleStrictParameterNames() {
447 MOZ_ASSERT(pc_->isFunctionBox() &&
448 pc_->functionBox()->hasSimpleParameterList());
450 if (pc_->functionBox()->hasDuplicateParameters) {
451 return false;
454 for (auto name : pc_->positionalFormalParameterNames()) {
455 MOZ_ASSERT(name);
456 if (!isValidStrictBinding(name)) {
457 return false;
460 return true;
463 template <class ParseHandler, typename Unit>
464 void GeneralParser<ParseHandler, Unit>::reportMissingClosing(
465 unsigned errorNumber, unsigned noteNumber, uint32_t openedPos) {
466 auto notes = MakeUnique<JSErrorNotes>();
467 if (!notes) {
468 ReportOutOfMemory(this->fc_);
469 return;
472 uint32_t line;
473 JS::LimitedColumnNumberOneOrigin column;
474 tokenStream.computeLineAndColumn(openedPos, &line, &column);
476 const size_t MaxWidth = sizeof("4294967295");
477 char columnNumber[MaxWidth];
478 SprintfLiteral(columnNumber, "%" PRIu32, column.oneOriginValue());
479 char lineNumber[MaxWidth];
480 SprintfLiteral(lineNumber, "%" PRIu32, line);
482 if (!notes->addNoteASCII(this->fc_, getFilename().c_str(), 0, line,
483 JS::ColumnNumberOneOrigin(column), GetErrorMessage,
484 nullptr, noteNumber, lineNumber, columnNumber)) {
485 return;
488 errorWithNotes(std::move(notes), errorNumber);
491 template <class ParseHandler, typename Unit>
492 void GeneralParser<ParseHandler, Unit>::reportRedeclarationHelper(
493 TaggedParserAtomIndex& name, DeclarationKind& prevKind, TokenPos& pos,
494 uint32_t& prevPos, const unsigned& errorNumber,
495 const unsigned& noteErrorNumber) {
496 UniqueChars bytes = this->parserAtoms().toPrintableString(name);
497 if (!bytes) {
498 ReportOutOfMemory(this->fc_);
499 return;
502 if (prevPos == DeclaredNameInfo::npos) {
503 errorAt(pos.begin, errorNumber, DeclarationKindString(prevKind),
504 bytes.get());
505 return;
508 auto notes = MakeUnique<JSErrorNotes>();
509 if (!notes) {
510 ReportOutOfMemory(this->fc_);
511 return;
514 uint32_t line;
515 JS::LimitedColumnNumberOneOrigin column;
516 tokenStream.computeLineAndColumn(prevPos, &line, &column);
518 const size_t MaxWidth = sizeof("4294967295");
519 char columnNumber[MaxWidth];
520 SprintfLiteral(columnNumber, "%" PRIu32, column.oneOriginValue());
521 char lineNumber[MaxWidth];
522 SprintfLiteral(lineNumber, "%" PRIu32, line);
524 if (!notes->addNoteASCII(this->fc_, getFilename().c_str(), 0, line,
525 JS::ColumnNumberOneOrigin(column), GetErrorMessage,
526 nullptr, noteErrorNumber, lineNumber,
527 columnNumber)) {
528 return;
531 errorWithNotesAt(std::move(notes), pos.begin, errorNumber,
532 DeclarationKindString(prevKind), bytes.get());
535 template <class ParseHandler, typename Unit>
536 void GeneralParser<ParseHandler, Unit>::reportRedeclaration(
537 TaggedParserAtomIndex name, DeclarationKind prevKind, TokenPos pos,
538 uint32_t prevPos) {
539 reportRedeclarationHelper(name, prevKind, pos, prevPos, JSMSG_REDECLARED_VAR,
540 JSMSG_PREV_DECLARATION);
543 template <class ParseHandler, typename Unit>
544 void GeneralParser<ParseHandler, Unit>::reportMismatchedPlacement(
545 TaggedParserAtomIndex name, DeclarationKind prevKind, TokenPos pos,
546 uint32_t prevPos) {
547 reportRedeclarationHelper(name, prevKind, pos, prevPos,
548 JSMSG_MISMATCHED_PLACEMENT, JSMSG_PREV_DECLARATION);
551 // notePositionalFormalParameter is called for both the arguments of a regular
552 // function definition and the arguments specified by the Function
553 // constructor.
555 // The 'disallowDuplicateParams' bool indicates whether the use of another
556 // feature (destructuring or default arguments) disables duplicate arguments.
557 // (ECMA-262 requires us to support duplicate parameter names, but, for newer
558 // features, we consider the code to have "opted in" to higher standards and
559 // forbid duplicates.)
560 template <class ParseHandler, typename Unit>
561 bool GeneralParser<ParseHandler, Unit>::notePositionalFormalParameter(
562 FunctionNodeType funNode, TaggedParserAtomIndex name, uint32_t beginPos,
563 bool disallowDuplicateParams, bool* duplicatedParam) {
564 if (AddDeclaredNamePtr p =
565 pc_->functionScope().lookupDeclaredNameForAdd(name)) {
566 if (disallowDuplicateParams) {
567 error(JSMSG_BAD_DUP_ARGS);
568 return false;
571 // Strict-mode disallows duplicate args. We may not know whether we are
572 // in strict mode or not (since the function body hasn't been parsed).
573 // In such cases, report will queue up the potential error and return
574 // 'true'.
575 if (pc_->sc()->strict()) {
576 UniqueChars bytes = this->parserAtoms().toPrintableString(name);
577 if (!bytes) {
578 ReportOutOfMemory(this->fc_);
579 return false;
581 if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.get())) {
582 return false;
586 *duplicatedParam = true;
587 } else {
588 DeclarationKind kind = DeclarationKind::PositionalFormalParameter;
589 if (!pc_->functionScope().addDeclaredName(pc_, p, name, kind, beginPos)) {
590 return false;
594 if (!pc_->positionalFormalParameterNames().append(
595 TrivialTaggedParserAtomIndex::from(name))) {
596 ReportOutOfMemory(this->fc_);
597 return false;
600 NameNodeType paramNode;
601 MOZ_TRY_VAR_OR_RETURN(paramNode, newName(name), false);
603 handler_.addFunctionFormalParameter(funNode, paramNode);
604 return true;
607 template <class ParseHandler>
608 bool PerHandlerParser<ParseHandler>::noteDestructuredPositionalFormalParameter(
609 FunctionNodeType funNode, Node destruct) {
610 // Append an empty name to the positional formals vector to keep track of
611 // argument slots when making FunctionScope::ParserData.
612 if (!pc_->positionalFormalParameterNames().append(
613 TrivialTaggedParserAtomIndex::null())) {
614 ReportOutOfMemory(fc_);
615 return false;
618 handler_.addFunctionFormalParameter(funNode, destruct);
619 return true;
622 template <class ParseHandler, typename Unit>
623 bool GeneralParser<ParseHandler, Unit>::noteDeclaredName(
624 TaggedParserAtomIndex name, DeclarationKind kind, TokenPos pos,
625 ClosedOver isClosedOver) {
626 // The asm.js validator does all its own symbol-table management so, as an
627 // optimization, avoid doing any work here.
628 if (pc_->useAsmOrInsideUseAsm()) {
629 return true;
632 switch (kind) {
633 case DeclarationKind::Var:
634 case DeclarationKind::BodyLevelFunction: {
635 Maybe<DeclarationKind> redeclaredKind;
636 uint32_t prevPos;
637 if (!pc_->tryDeclareVar(name, this, kind, pos.begin, &redeclaredKind,
638 &prevPos)) {
639 return false;
642 if (redeclaredKind) {
643 reportRedeclaration(name, *redeclaredKind, pos, prevPos);
644 return false;
647 break;
650 case DeclarationKind::ModuleBodyLevelFunction: {
651 MOZ_ASSERT(pc_->atModuleLevel());
653 AddDeclaredNamePtr p = pc_->varScope().lookupDeclaredNameForAdd(name);
654 if (p) {
655 reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
656 return false;
659 if (!pc_->varScope().addDeclaredName(pc_, p, name, kind, pos.begin,
660 isClosedOver)) {
661 return false;
664 // Body-level functions in modules are always closed over.
665 pc_->varScope().lookupDeclaredName(name)->value()->setClosedOver();
667 break;
670 case DeclarationKind::FormalParameter: {
671 // It is an early error if any non-positional formal parameter name
672 // (e.g., destructuring formal parameter) is duplicated.
674 AddDeclaredNamePtr p =
675 pc_->functionScope().lookupDeclaredNameForAdd(name);
676 if (p) {
677 error(JSMSG_BAD_DUP_ARGS);
678 return false;
681 if (!pc_->functionScope().addDeclaredName(pc_, p, name, kind, pos.begin,
682 isClosedOver)) {
683 return false;
686 break;
689 case DeclarationKind::LexicalFunction:
690 case DeclarationKind::PrivateName:
691 case DeclarationKind::Synthetic:
692 case DeclarationKind::PrivateMethod: {
693 ParseContext::Scope* scope = pc_->innermostScope();
694 AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name);
695 if (p) {
696 reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
697 return false;
700 if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin,
701 isClosedOver)) {
702 return false;
705 break;
708 case DeclarationKind::SloppyLexicalFunction: {
709 // Functions in block have complex allowances in sloppy mode for being
710 // labelled that other lexical declarations do not have. Those checks
711 // are done in functionStmt.
713 ParseContext::Scope* scope = pc_->innermostScope();
714 if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
715 // It is usually an early error if there is another declaration
716 // with the same name in the same scope.
718 // Sloppy lexical functions may redeclare other sloppy lexical
719 // functions for web compatibility reasons.
720 if (p->value()->kind() != DeclarationKind::SloppyLexicalFunction) {
721 reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
722 return false;
724 } else {
725 if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin,
726 isClosedOver)) {
727 return false;
731 break;
734 case DeclarationKind::Let:
735 case DeclarationKind::Const:
736 case DeclarationKind::Class:
737 // The BoundNames of LexicalDeclaration and ForDeclaration must not
738 // contain 'let'. (CatchParameter is the only lexical binding form
739 // without this restriction.)
740 if (name == TaggedParserAtomIndex::WellKnown::let()) {
741 errorAt(pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET);
742 return false;
745 // For body-level lexically declared names in a function, it is an
746 // early error if there is a formal parameter of the same name. This
747 // needs a special check if there is an extra var scope due to
748 // parameter expressions.
749 if (pc_->isFunctionExtraBodyVarScopeInnermost()) {
750 DeclaredNamePtr p = pc_->functionScope().lookupDeclaredName(name);
751 if (p && DeclarationKindIsParameter(p->value()->kind())) {
752 reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
753 return false;
757 [[fallthrough]];
759 case DeclarationKind::Import:
760 // Module code is always strict, so 'let' is always a keyword and never a
761 // name.
762 MOZ_ASSERT(name != TaggedParserAtomIndex::WellKnown::let());
763 [[fallthrough]];
765 case DeclarationKind::SimpleCatchParameter:
766 case DeclarationKind::CatchParameter: {
767 ParseContext::Scope* scope = pc_->innermostScope();
769 // It is an early error if there is another declaration with the same
770 // name in the same scope.
771 AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name);
772 if (p) {
773 reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
774 return false;
777 if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin,
778 isClosedOver)) {
779 return false;
782 break;
785 case DeclarationKind::CoverArrowParameter:
786 // CoverArrowParameter is only used as a placeholder declaration kind.
787 break;
789 case DeclarationKind::PositionalFormalParameter:
790 MOZ_CRASH(
791 "Positional formal parameter names should use "
792 "notePositionalFormalParameter");
793 break;
795 case DeclarationKind::VarForAnnexBLexicalFunction:
796 MOZ_CRASH(
797 "Synthesized Annex B vars should go through "
798 "addPossibleAnnexBFunctionBox, and "
799 "propagateAndMarkAnnexBFunctionBoxes");
800 break;
803 return true;
806 template <class ParseHandler, typename Unit>
807 bool GeneralParser<ParseHandler, Unit>::noteDeclaredPrivateName(
808 Node nameNode, TaggedParserAtomIndex name, PropertyType propType,
809 FieldPlacement placement, TokenPos pos) {
810 ParseContext::Scope* scope = pc_->innermostScope();
811 AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name);
813 DeclarationKind declKind = DeclarationKind::PrivateName;
814 ClosedOver closedOver = ClosedOver::No;
815 PrivateNameKind kind;
816 switch (propType) {
817 case PropertyType::Field:
818 kind = PrivateNameKind::Field;
819 break;
820 case PropertyType::FieldWithAccessor:
821 // In this case, we create a new private field for the underlying storage,
822 // and use the current name for the getter and setter.
823 kind = PrivateNameKind::GetterSetter;
824 break;
825 case PropertyType::Method:
826 case PropertyType::GeneratorMethod:
827 case PropertyType::AsyncMethod:
828 case PropertyType::AsyncGeneratorMethod:
829 if (placement == FieldPlacement::Instance) {
830 // Optimized private method. Non-optimized paths still get
831 // DeclarationKind::Synthetic.
832 declKind = DeclarationKind::PrivateMethod;
835 // Methods must be marked closed-over so that
836 // EmitterScope::lookupPrivate() works even if the method is used, but not
837 // within any method (from a computed property name, or debugger frame)
838 closedOver = ClosedOver::Yes;
839 kind = PrivateNameKind::Method;
840 break;
841 case PropertyType::Getter:
842 kind = PrivateNameKind::Getter;
843 break;
844 case PropertyType::Setter:
845 kind = PrivateNameKind::Setter;
846 break;
847 default:
848 kind = PrivateNameKind::None;
851 if (p) {
852 PrivateNameKind prevKind = p->value()->privateNameKind();
853 if ((prevKind == PrivateNameKind::Getter &&
854 kind == PrivateNameKind::Setter) ||
855 (prevKind == PrivateNameKind::Setter &&
856 kind == PrivateNameKind::Getter)) {
857 // Private methods demands that
859 // class A {
860 // static set #x(_) {}
861 // get #x() { }
862 // }
864 // Report a SyntaxError.
865 if (placement == p->value()->placement()) {
866 p->value()->setPrivateNameKind(PrivateNameKind::GetterSetter);
867 handler_.setPrivateNameKind(nameNode, PrivateNameKind::GetterSetter);
868 return true;
872 reportMismatchedPlacement(name, p->value()->kind(), pos, p->value()->pos());
873 return false;
876 if (!scope->addDeclaredName(pc_, p, name, declKind, pos.begin, closedOver)) {
877 return false;
880 DeclaredNamePtr declared = scope->lookupDeclaredName(name);
881 declared->value()->setPrivateNameKind(kind);
882 declared->value()->setFieldPlacement(placement);
883 handler_.setPrivateNameKind(nameNode, kind);
885 return true;
888 bool ParserBase::noteUsedNameInternal(TaggedParserAtomIndex name,
889 NameVisibility visibility,
890 mozilla::Maybe<TokenPos> tokenPosition) {
891 // The asm.js validator does all its own symbol-table management so, as an
892 // optimization, avoid doing any work here.
893 if (pc_->useAsmOrInsideUseAsm()) {
894 return true;
897 // Global bindings are properties and not actual bindings; we don't need
898 // to know if they are closed over. So no need to track used name at the
899 // global scope. It is not incorrect to track them, this is an
900 // optimization.
902 // Exceptions:
903 // (a) Track private name references, as the used names tracker is used to
904 // provide early errors for undeclared private name references
905 // (b) If the script has extra bindings, track all references to detect
906 // references to extra bindings
907 ParseContext::Scope* scope = pc_->innermostScope();
908 if (pc_->sc()->isGlobalContext() && scope == &pc_->varScope() &&
909 visibility == NameVisibility::Public &&
910 !this->compilationState_.input.hasExtraBindings()) {
911 return true;
914 return usedNames_.noteUse(fc_, name, visibility, pc_->scriptId(), scope->id(),
915 tokenPosition);
918 template <class ParseHandler>
919 bool PerHandlerParser<ParseHandler>::
920 propagateFreeNamesAndMarkClosedOverBindings(ParseContext::Scope& scope) {
921 // Now that we have all the declared names in the scope, check which
922 // functions should exhibit Annex B semantics.
923 if (!scope.propagateAndMarkAnnexBFunctionBoxes(pc_, this)) {
924 return false;
927 if (handler_.reuseClosedOverBindings()) {
928 MOZ_ASSERT(pc_->isOutermostOfCurrentCompile());
930 // Closed over bindings for all scopes are stored in a contiguous array, in
931 // the same order as the order in which scopes are visited, and seprated by
932 // TaggedParserAtomIndex::null().
933 uint32_t slotCount = scope.declaredCount();
934 while (auto parserAtom = handler_.nextLazyClosedOverBinding()) {
935 scope.lookupDeclaredName(parserAtom)->value()->setClosedOver();
936 MOZ_ASSERT(slotCount > 0);
937 slotCount--;
940 if (pc_->isGeneratorOrAsync()) {
941 scope.setOwnStackSlotCount(slotCount);
943 return true;
946 constexpr bool isSyntaxParser =
947 std::is_same_v<ParseHandler, SyntaxParseHandler>;
948 uint32_t scriptId = pc_->scriptId();
949 uint32_t scopeId = scope.id();
951 uint32_t slotCount = 0;
952 for (BindingIter bi = scope.bindings(pc_); bi; bi++) {
953 bool closedOver = false;
954 if (UsedNamePtr p = usedNames_.lookup(bi.name())) {
955 p->value().noteBoundInScope(scriptId, scopeId, &closedOver);
956 if (closedOver) {
957 bi.setClosedOver();
959 if constexpr (isSyntaxParser) {
960 if (!pc_->closedOverBindingsForLazy().append(
961 TrivialTaggedParserAtomIndex::from(bi.name()))) {
962 ReportOutOfMemory(fc_);
963 return false;
969 if constexpr (!isSyntaxParser) {
970 if (!closedOver) {
971 slotCount++;
975 if constexpr (!isSyntaxParser) {
976 if (pc_->isGeneratorOrAsync()) {
977 scope.setOwnStackSlotCount(slotCount);
981 // Append a nullptr to denote end-of-scope.
982 if constexpr (isSyntaxParser) {
983 if (!pc_->closedOverBindingsForLazy().append(
984 TrivialTaggedParserAtomIndex::null())) {
985 ReportOutOfMemory(fc_);
986 return false;
990 return true;
993 template <typename Unit>
994 bool Parser<FullParseHandler, Unit>::checkStatementsEOF() {
995 // This is designed to be paired with parsing a statement list at the top
996 // level.
998 // The statementList() call breaks on TokenKind::RightCurly, so make sure
999 // we've reached EOF here.
1000 TokenKind tt;
1001 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
1002 return false;
1004 if (tt != TokenKind::Eof) {
1005 error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
1006 return false;
1008 return true;
1011 template <typename ScopeT>
1012 typename ScopeT::ParserData* NewEmptyBindingData(FrontendContext* fc,
1013 LifoAlloc& alloc,
1014 uint32_t numBindings) {
1015 using Data = typename ScopeT::ParserData;
1016 size_t allocSize = SizeOfScopeData<Data>(numBindings);
1017 auto* bindings = alloc.newWithSize<Data>(allocSize, numBindings);
1018 if (!bindings) {
1019 ReportOutOfMemory(fc);
1021 return bindings;
1024 GlobalScope::ParserData* NewEmptyGlobalScopeData(FrontendContext* fc,
1025 LifoAlloc& alloc,
1026 uint32_t numBindings) {
1027 return NewEmptyBindingData<GlobalScope>(fc, alloc, numBindings);
1030 LexicalScope::ParserData* NewEmptyLexicalScopeData(FrontendContext* fc,
1031 LifoAlloc& alloc,
1032 uint32_t numBindings) {
1033 return NewEmptyBindingData<LexicalScope>(fc, alloc, numBindings);
1036 FunctionScope::ParserData* NewEmptyFunctionScopeData(FrontendContext* fc,
1037 LifoAlloc& alloc,
1038 uint32_t numBindings) {
1039 return NewEmptyBindingData<FunctionScope>(fc, alloc, numBindings);
1042 namespace detail {
1044 template <class SlotInfo>
1045 static MOZ_ALWAYS_INLINE ParserBindingName* InitializeIndexedBindings(
1046 SlotInfo& slotInfo, ParserBindingName* start, ParserBindingName* cursor) {
1047 return cursor;
1050 template <class SlotInfo, typename UnsignedInteger, typename... Step>
1051 static MOZ_ALWAYS_INLINE ParserBindingName* InitializeIndexedBindings(
1052 SlotInfo& slotInfo, ParserBindingName* start, ParserBindingName* cursor,
1053 UnsignedInteger SlotInfo::*field, const ParserBindingNameVector& bindings,
1054 Step&&... step) {
1055 slotInfo.*field =
1056 AssertedCast<UnsignedInteger>(PointerRangeSize(start, cursor));
1058 ParserBindingName* newCursor =
1059 std::uninitialized_copy(bindings.begin(), bindings.end(), cursor);
1061 return InitializeIndexedBindings(slotInfo, start, newCursor,
1062 std::forward<Step>(step)...);
1065 } // namespace detail
1067 // Initialize the trailing name bindings of |data|, then set |data->length| to
1068 // the count of bindings added (which must equal |count|).
1070 // First, |firstBindings| are added to the trailing names. Then any
1071 // "steps" present are performed first to last. Each step is 1) a pointer to a
1072 // member of |data| to be set to the current number of bindings added, and 2) a
1073 // vector of |ParserBindingName|s to then copy into |data->trailingNames|.
1074 // (Thus each |data| member field indicates where the corresponding vector's
1075 // names start.)
1076 template <class Data, typename... Step>
1077 static MOZ_ALWAYS_INLINE void InitializeBindingData(
1078 Data* data, uint32_t count, const ParserBindingNameVector& firstBindings,
1079 Step&&... step) {
1080 MOZ_ASSERT(data->length == 0, "data shouldn't be filled yet");
1082 ParserBindingName* start = GetScopeDataTrailingNamesPointer(data);
1083 ParserBindingName* cursor = std::uninitialized_copy(
1084 firstBindings.begin(), firstBindings.end(), start);
1086 #ifdef DEBUG
1087 ParserBindingName* end =
1088 #endif
1089 detail::InitializeIndexedBindings(data->slotInfo, start, cursor,
1090 std::forward<Step>(step)...);
1092 MOZ_ASSERT(PointerRangeSize(start, end) == count);
1093 data->length = count;
1096 static Maybe<GlobalScope::ParserData*> NewGlobalScopeData(
1097 FrontendContext* fc, ParseContext::Scope& scope, LifoAlloc& alloc,
1098 ParseContext* pc) {
1099 ParserBindingNameVector vars(fc);
1100 ParserBindingNameVector lets(fc);
1101 ParserBindingNameVector consts(fc);
1103 bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
1104 for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1105 bool closedOver = allBindingsClosedOver || bi.closedOver();
1107 switch (bi.kind()) {
1108 case BindingKind::Var: {
1109 bool isTopLevelFunction =
1110 bi.declarationKind() == DeclarationKind::BodyLevelFunction;
1112 ParserBindingName binding(bi.name(), closedOver, isTopLevelFunction);
1113 if (!vars.append(binding)) {
1114 return Nothing();
1116 break;
1118 case BindingKind::Let: {
1119 ParserBindingName binding(bi.name(), closedOver);
1120 if (!lets.append(binding)) {
1121 return Nothing();
1123 break;
1125 case BindingKind::Const: {
1126 ParserBindingName binding(bi.name(), closedOver);
1127 if (!consts.append(binding)) {
1128 return Nothing();
1130 break;
1132 default:
1133 MOZ_CRASH("Bad global scope BindingKind");
1137 GlobalScope::ParserData* bindings = nullptr;
1138 uint32_t numBindings = vars.length() + lets.length() + consts.length();
1140 if (numBindings > 0) {
1141 bindings = NewEmptyBindingData<GlobalScope>(fc, alloc, numBindings);
1142 if (!bindings) {
1143 return Nothing();
1146 // The ordering here is important. See comments in GlobalScope.
1147 InitializeBindingData(bindings, numBindings, vars,
1148 &ParserGlobalScopeSlotInfo::letStart, lets,
1149 &ParserGlobalScopeSlotInfo::constStart, consts);
1152 return Some(bindings);
1155 Maybe<GlobalScope::ParserData*> ParserBase::newGlobalScopeData(
1156 ParseContext::Scope& scope) {
1157 return NewGlobalScopeData(fc_, scope, stencilAlloc(), pc_);
1160 static Maybe<ModuleScope::ParserData*> NewModuleScopeData(
1161 FrontendContext* fc, ParseContext::Scope& scope, LifoAlloc& alloc,
1162 ParseContext* pc) {
1163 ParserBindingNameVector imports(fc);
1164 ParserBindingNameVector vars(fc);
1165 ParserBindingNameVector lets(fc);
1166 ParserBindingNameVector consts(fc);
1168 bool allBindingsClosedOver =
1169 pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();
1171 for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1172 // Imports are indirect bindings and must not be given known slots.
1173 ParserBindingName binding(bi.name(),
1174 (allBindingsClosedOver || bi.closedOver()) &&
1175 bi.kind() != BindingKind::Import);
1176 switch (bi.kind()) {
1177 case BindingKind::Import:
1178 if (!imports.append(binding)) {
1179 return Nothing();
1181 break;
1182 case BindingKind::Var:
1183 if (!vars.append(binding)) {
1184 return Nothing();
1186 break;
1187 case BindingKind::Let:
1188 if (!lets.append(binding)) {
1189 return Nothing();
1191 break;
1192 case BindingKind::Const:
1193 if (!consts.append(binding)) {
1194 return Nothing();
1196 break;
1197 default:
1198 MOZ_CRASH("Bad module scope BindingKind");
1202 ModuleScope::ParserData* bindings = nullptr;
1203 uint32_t numBindings =
1204 imports.length() + vars.length() + lets.length() + consts.length();
1206 if (numBindings > 0) {
1207 bindings = NewEmptyBindingData<ModuleScope>(fc, alloc, numBindings);
1208 if (!bindings) {
1209 return Nothing();
1212 // The ordering here is important. See comments in ModuleScope.
1213 InitializeBindingData(bindings, numBindings, imports,
1214 &ParserModuleScopeSlotInfo::varStart, vars,
1215 &ParserModuleScopeSlotInfo::letStart, lets,
1216 &ParserModuleScopeSlotInfo::constStart, consts);
1219 return Some(bindings);
1222 Maybe<ModuleScope::ParserData*> ParserBase::newModuleScopeData(
1223 ParseContext::Scope& scope) {
1224 return NewModuleScopeData(fc_, scope, stencilAlloc(), pc_);
1227 static Maybe<EvalScope::ParserData*> NewEvalScopeData(
1228 FrontendContext* fc, ParseContext::Scope& scope, LifoAlloc& alloc,
1229 ParseContext* pc) {
1230 ParserBindingNameVector vars(fc);
1232 // Treat all bindings as closed over in non-strict eval.
1233 bool allBindingsClosedOver =
1234 !pc->sc()->strict() || pc->sc()->allBindingsClosedOver();
1235 for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1236 // Eval scopes only contain 'var' bindings.
1237 MOZ_ASSERT(bi.kind() == BindingKind::Var);
1238 bool isTopLevelFunction =
1239 bi.declarationKind() == DeclarationKind::BodyLevelFunction;
1240 bool closedOver = allBindingsClosedOver || bi.closedOver();
1242 ParserBindingName binding(bi.name(), closedOver, isTopLevelFunction);
1243 if (!vars.append(binding)) {
1244 return Nothing();
1248 EvalScope::ParserData* bindings = nullptr;
1249 uint32_t numBindings = vars.length();
1251 if (numBindings > 0) {
1252 bindings = NewEmptyBindingData<EvalScope>(fc, alloc, numBindings);
1253 if (!bindings) {
1254 return Nothing();
1257 InitializeBindingData(bindings, numBindings, vars);
1260 return Some(bindings);
1263 Maybe<EvalScope::ParserData*> ParserBase::newEvalScopeData(
1264 ParseContext::Scope& scope) {
1265 return NewEvalScopeData(fc_, scope, stencilAlloc(), pc_);
1268 static Maybe<FunctionScope::ParserData*> NewFunctionScopeData(
1269 FrontendContext* fc, ParseContext::Scope& scope, bool hasParameterExprs,
1270 LifoAlloc& alloc, ParseContext* pc) {
1271 ParserBindingNameVector positionalFormals(fc);
1272 ParserBindingNameVector formals(fc);
1273 ParserBindingNameVector vars(fc);
1275 bool allBindingsClosedOver =
1276 pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();
1277 bool argumentBindingsClosedOver =
1278 allBindingsClosedOver || pc->isGeneratorOrAsync();
1279 bool hasDuplicateParams = pc->functionBox()->hasDuplicateParameters;
1281 // Positional parameter names must be added in order of appearance as they are
1282 // referenced using argument slots.
1283 for (size_t i = 0; i < pc->positionalFormalParameterNames().length(); i++) {
1284 TaggedParserAtomIndex name = pc->positionalFormalParameterNames()[i];
1286 ParserBindingName bindName;
1287 if (name) {
1288 DeclaredNamePtr p = scope.lookupDeclaredName(name);
1290 // Do not consider any positional formal parameters closed over if
1291 // there are parameter defaults. It is the binding in the defaults
1292 // scope that is closed over instead.
1293 bool closedOver =
1294 argumentBindingsClosedOver || (p && p->value()->closedOver());
1296 // If the parameter name has duplicates, only the final parameter
1297 // name should be on the environment, as otherwise the environment
1298 // object would have multiple, same-named properties.
1299 if (hasDuplicateParams) {
1300 for (size_t j = pc->positionalFormalParameterNames().length() - 1;
1301 j > i; j--) {
1302 if (TaggedParserAtomIndex(pc->positionalFormalParameterNames()[j]) ==
1303 name) {
1304 closedOver = false;
1305 break;
1310 bindName = ParserBindingName(name, closedOver);
1313 if (!positionalFormals.append(bindName)) {
1314 return Nothing();
1318 for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1319 ParserBindingName binding(bi.name(),
1320 allBindingsClosedOver || bi.closedOver());
1321 switch (bi.kind()) {
1322 case BindingKind::FormalParameter:
1323 // Positional parameter names are already handled above.
1324 if (bi.declarationKind() == DeclarationKind::FormalParameter) {
1325 if (!formals.append(binding)) {
1326 return Nothing();
1329 break;
1330 case BindingKind::Var:
1331 // The only vars in the function scope when there are parameter
1332 // exprs, which induces a separate var environment, should be the
1333 // special bindings.
1334 MOZ_ASSERT_IF(hasParameterExprs,
1335 FunctionScope::isSpecialName(bi.name()));
1336 if (!vars.append(binding)) {
1337 return Nothing();
1339 break;
1340 case BindingKind::Let:
1341 case BindingKind::Const:
1342 break;
1343 default:
1344 MOZ_CRASH("bad function scope BindingKind");
1345 break;
1349 FunctionScope::ParserData* bindings = nullptr;
1350 uint32_t numBindings =
1351 positionalFormals.length() + formals.length() + vars.length();
1353 if (numBindings > 0) {
1354 bindings = NewEmptyBindingData<FunctionScope>(fc, alloc, numBindings);
1355 if (!bindings) {
1356 return Nothing();
1359 // The ordering here is important. See comments in FunctionScope.
1360 InitializeBindingData(
1361 bindings, numBindings, positionalFormals,
1362 &ParserFunctionScopeSlotInfo::nonPositionalFormalStart, formals,
1363 &ParserFunctionScopeSlotInfo::varStart, vars);
1366 return Some(bindings);
1369 // Compute if `NewFunctionScopeData` would return any binding list with any
1370 // entry marked as closed-over. This is done without the need to allocate the
1371 // binding list. If true, an EnvironmentObject will be needed at runtime.
1372 bool FunctionScopeHasClosedOverBindings(ParseContext* pc) {
1373 bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver() ||
1374 pc->functionScope().tooBigToOptimize();
1376 for (BindingIter bi = pc->functionScope().bindings(pc); bi; bi++) {
1377 switch (bi.kind()) {
1378 case BindingKind::FormalParameter:
1379 case BindingKind::Var:
1380 if (allBindingsClosedOver || bi.closedOver()) {
1381 return true;
1383 break;
1385 default:
1386 break;
1390 return false;
1393 Maybe<FunctionScope::ParserData*> ParserBase::newFunctionScopeData(
1394 ParseContext::Scope& scope, bool hasParameterExprs) {
1395 return NewFunctionScopeData(fc_, scope, hasParameterExprs, stencilAlloc(),
1396 pc_);
1399 VarScope::ParserData* NewEmptyVarScopeData(FrontendContext* fc,
1400 LifoAlloc& alloc,
1401 uint32_t numBindings) {
1402 return NewEmptyBindingData<VarScope>(fc, alloc, numBindings);
1405 static Maybe<VarScope::ParserData*> NewVarScopeData(FrontendContext* fc,
1406 ParseContext::Scope& scope,
1407 LifoAlloc& alloc,
1408 ParseContext* pc) {
1409 ParserBindingNameVector vars(fc);
1411 bool allBindingsClosedOver =
1412 pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();
1414 for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1415 if (bi.kind() == BindingKind::Var) {
1416 ParserBindingName binding(bi.name(),
1417 allBindingsClosedOver || bi.closedOver());
1418 if (!vars.append(binding)) {
1419 return Nothing();
1421 } else {
1422 MOZ_ASSERT(
1423 bi.kind() == BindingKind::Let || bi.kind() == BindingKind::Const,
1424 "bad var scope BindingKind");
1428 VarScope::ParserData* bindings = nullptr;
1429 uint32_t numBindings = vars.length();
1431 if (numBindings > 0) {
1432 bindings = NewEmptyBindingData<VarScope>(fc, alloc, numBindings);
1433 if (!bindings) {
1434 return Nothing();
1437 InitializeBindingData(bindings, numBindings, vars);
1440 return Some(bindings);
1443 // Compute if `NewVarScopeData` would return any binding list. This is done
1444 // without allocate the binding list.
1445 static bool VarScopeHasBindings(ParseContext* pc) {
1446 for (BindingIter bi = pc->varScope().bindings(pc); bi; bi++) {
1447 if (bi.kind() == BindingKind::Var) {
1448 return true;
1452 return false;
1455 Maybe<VarScope::ParserData*> ParserBase::newVarScopeData(
1456 ParseContext::Scope& scope) {
1457 return NewVarScopeData(fc_, scope, stencilAlloc(), pc_);
1460 static Maybe<LexicalScope::ParserData*> NewLexicalScopeData(
1461 FrontendContext* fc, ParseContext::Scope& scope, LifoAlloc& alloc,
1462 ParseContext* pc) {
1463 ParserBindingNameVector lets(fc);
1464 ParserBindingNameVector consts(fc);
1466 bool allBindingsClosedOver =
1467 pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();
1469 for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1470 ParserBindingName binding(bi.name(),
1471 allBindingsClosedOver || bi.closedOver());
1472 switch (bi.kind()) {
1473 case BindingKind::Let:
1474 if (!lets.append(binding)) {
1475 return Nothing();
1477 break;
1478 case BindingKind::Const:
1479 if (!consts.append(binding)) {
1480 return Nothing();
1482 break;
1483 case BindingKind::Var:
1484 case BindingKind::FormalParameter:
1485 break;
1486 default:
1487 MOZ_CRASH("Bad lexical scope BindingKind");
1488 break;
1492 LexicalScope::ParserData* bindings = nullptr;
1493 uint32_t numBindings = lets.length() + consts.length();
1495 if (numBindings > 0) {
1496 bindings = NewEmptyBindingData<LexicalScope>(fc, alloc, numBindings);
1497 if (!bindings) {
1498 return Nothing();
1501 // The ordering here is important. See comments in LexicalScope.
1502 InitializeBindingData(bindings, numBindings, lets,
1503 &ParserLexicalScopeSlotInfo::constStart, consts);
1506 return Some(bindings);
1509 // Compute if `NewLexicalScopeData` would return any binding list with any entry
1510 // marked as closed-over. This is done without the need to allocate the binding
1511 // list. If true, an EnvironmentObject will be needed at runtime.
1512 bool LexicalScopeHasClosedOverBindings(ParseContext* pc,
1513 ParseContext::Scope& scope) {
1514 bool allBindingsClosedOver =
1515 pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();
1517 for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1518 switch (bi.kind()) {
1519 case BindingKind::Let:
1520 case BindingKind::Const:
1521 if (allBindingsClosedOver || bi.closedOver()) {
1522 return true;
1524 break;
1526 default:
1527 break;
1531 return false;
1534 Maybe<LexicalScope::ParserData*> ParserBase::newLexicalScopeData(
1535 ParseContext::Scope& scope) {
1536 return NewLexicalScopeData(fc_, scope, stencilAlloc(), pc_);
1539 static Maybe<ClassBodyScope::ParserData*> NewClassBodyScopeData(
1540 FrontendContext* fc, ParseContext::Scope& scope, LifoAlloc& alloc,
1541 ParseContext* pc) {
1542 ParserBindingNameVector privateBrand(fc);
1543 ParserBindingNameVector synthetics(fc);
1544 ParserBindingNameVector privateMethods(fc);
1546 bool allBindingsClosedOver =
1547 pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();
1549 for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1550 ParserBindingName binding(bi.name(),
1551 allBindingsClosedOver || bi.closedOver());
1552 switch (bi.kind()) {
1553 case BindingKind::Synthetic:
1554 if (bi.name() ==
1555 TaggedParserAtomIndex::WellKnown::dot_privateBrand_()) {
1556 MOZ_ASSERT(privateBrand.empty());
1557 if (!privateBrand.append(binding)) {
1558 return Nothing();
1560 } else {
1561 if (!synthetics.append(binding)) {
1562 return Nothing();
1565 break;
1567 case BindingKind::PrivateMethod:
1568 if (!privateMethods.append(binding)) {
1569 return Nothing();
1571 break;
1573 default:
1574 MOZ_CRASH("bad class body scope BindingKind");
1575 break;
1579 // We should have zero or one private brands.
1580 MOZ_ASSERT(privateBrand.length() == 0 || privateBrand.length() == 1);
1582 ClassBodyScope::ParserData* bindings = nullptr;
1583 uint32_t numBindings =
1584 privateBrand.length() + synthetics.length() + privateMethods.length();
1586 if (numBindings > 0) {
1587 bindings = NewEmptyBindingData<ClassBodyScope>(fc, alloc, numBindings);
1588 if (!bindings) {
1589 return Nothing();
1591 // To simplify initialization of the bindings, we concatenate the
1592 // synthetics+privateBrand vector such that the private brand is always the
1593 // first element, as ordering is important. See comments in ClassBodyScope.
1594 ParserBindingNameVector brandAndSynthetics(fc);
1595 if (!brandAndSynthetics.appendAll(privateBrand)) {
1596 return Nothing();
1598 if (!brandAndSynthetics.appendAll(synthetics)) {
1599 return Nothing();
1602 // The ordering here is important. See comments in ClassBodyScope.
1603 InitializeBindingData(bindings, numBindings, brandAndSynthetics,
1604 &ParserClassBodyScopeSlotInfo::privateMethodStart,
1605 privateMethods);
1608 // `EmitterScope::lookupPrivate()` requires `.privateBrand` to be stored in a
1609 // predictable slot: the first slot available in the environment object,
1610 // `ClassBodyLexicalEnvironmentObject::privateBrandSlot()`. We assume that
1611 // if `.privateBrand` is first in the scope, it will be stored there.
1612 MOZ_ASSERT_IF(!privateBrand.empty(),
1613 GetScopeDataTrailingNames(bindings)[0].name() ==
1614 TaggedParserAtomIndex::WellKnown::dot_privateBrand_());
1616 return Some(bindings);
1619 Maybe<ClassBodyScope::ParserData*> ParserBase::newClassBodyScopeData(
1620 ParseContext::Scope& scope) {
1621 return NewClassBodyScopeData(fc_, scope, stencilAlloc(), pc_);
1624 template <>
1625 SyntaxParseHandler::LexicalScopeNodeResult
1626 PerHandlerParser<SyntaxParseHandler>::finishLexicalScope(
1627 ParseContext::Scope& scope, Node body, ScopeKind kind) {
1628 if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
1629 return errorResult();
1632 return handler_.newLexicalScope(body);
1635 template <>
1636 FullParseHandler::LexicalScopeNodeResult
1637 PerHandlerParser<FullParseHandler>::finishLexicalScope(
1638 ParseContext::Scope& scope, ParseNode* body, ScopeKind kind) {
1639 if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
1640 return errorResult();
1643 Maybe<LexicalScope::ParserData*> bindings = newLexicalScopeData(scope);
1644 if (!bindings) {
1645 return errorResult();
1648 return handler_.newLexicalScope(*bindings, body, kind);
1651 template <>
1652 SyntaxParseHandler::ClassBodyScopeNodeResult
1653 PerHandlerParser<SyntaxParseHandler>::finishClassBodyScope(
1654 ParseContext::Scope& scope, ListNodeType body) {
1655 if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
1656 return errorResult();
1659 return handler_.newClassBodyScope(body);
1662 template <>
1663 FullParseHandler::ClassBodyScopeNodeResult
1664 PerHandlerParser<FullParseHandler>::finishClassBodyScope(
1665 ParseContext::Scope& scope, ListNode* body) {
1666 if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
1667 return errorResult();
1670 Maybe<ClassBodyScope::ParserData*> bindings = newClassBodyScopeData(scope);
1671 if (!bindings) {
1672 return errorResult();
1675 return handler_.newClassBodyScope(*bindings, body);
1678 template <class ParseHandler>
1679 bool PerHandlerParser<ParseHandler>::checkForUndefinedPrivateFields(
1680 EvalSharedContext* evalSc) {
1681 if (!this->compilationState_.isInitialStencil()) {
1682 // We're delazifying -- so we already checked private names during first
1683 // parse.
1684 return true;
1687 Vector<UnboundPrivateName, 8> unboundPrivateNames(fc_);
1688 if (!usedNames_.getUnboundPrivateNames(unboundPrivateNames)) {
1689 return false;
1692 // No unbound names, let's get out of here!
1693 if (unboundPrivateNames.empty()) {
1694 return true;
1697 // It is an early error if there's private name references unbound,
1698 // unless it's an eval, in which case we need to check the scope
1699 // chain.
1700 if (!evalSc) {
1701 // The unbound private names are sorted, so just grab the first one.
1702 UnboundPrivateName minimum = unboundPrivateNames[0];
1703 UniqueChars str = this->parserAtoms().toPrintableString(minimum.atom);
1704 if (!str) {
1705 ReportOutOfMemory(this->fc_);
1706 return false;
1709 errorAt(minimum.position.begin, JSMSG_MISSING_PRIVATE_DECL, str.get());
1710 return false;
1713 // It's important that the unbound private names are sorted, as we
1714 // want our errors to always be issued to the first textually.
1715 for (UnboundPrivateName unboundName : unboundPrivateNames) {
1716 // If the enclosingScope is non-syntactic, then we are in a
1717 // Debugger.Frame.prototype.eval call. In order to find the declared private
1718 // names, we must use the effective scope that was determined when creating
1719 // the scopeContext.
1720 if (!this->compilationState_.scopeContext
1721 .effectiveScopePrivateFieldCacheHas(unboundName.atom)) {
1722 UniqueChars str = this->parserAtoms().toPrintableString(unboundName.atom);
1723 if (!str) {
1724 ReportOutOfMemory(this->fc_);
1725 return false;
1727 errorAt(unboundName.position.begin, JSMSG_MISSING_PRIVATE_DECL,
1728 str.get());
1729 return false;
1733 return true;
1736 template <typename Unit>
1737 FullParseHandler::LexicalScopeNodeResult
1738 Parser<FullParseHandler, Unit>::evalBody(EvalSharedContext* evalsc) {
1739 SourceParseContext evalpc(this, evalsc, /* newDirectives = */ nullptr);
1740 if (!evalpc.init()) {
1741 return errorResult();
1744 ParseContext::VarScope varScope(this);
1745 if (!varScope.init(pc_)) {
1746 return errorResult();
1749 LexicalScopeNode* body;
1751 // All evals have an implicit non-extensible lexical scope.
1752 ParseContext::Scope lexicalScope(this);
1753 if (!lexicalScope.init(pc_)) {
1754 return errorResult();
1757 ListNode* list;
1758 MOZ_TRY_VAR(list, statementList(YieldIsName));
1760 if (!checkStatementsEOF()) {
1761 return errorResult();
1764 // Private names not lexically defined must trigger a syntax error.
1765 if (!checkForUndefinedPrivateFields(evalsc)) {
1766 return errorResult();
1769 MOZ_TRY_VAR(body, finishLexicalScope(lexicalScope, list));
1772 #ifdef DEBUG
1773 if (evalpc.superScopeNeedsHomeObject() &&
1774 !this->compilationState_.input.enclosingScope.isNull()) {
1775 // If superScopeNeedsHomeObject_ is set and we are an entry-point
1776 // ParseContext, then we must be emitting an eval script, and the
1777 // outer function must already be marked as needing a home object
1778 // since it contains an eval.
1779 MOZ_ASSERT(
1780 this->compilationState_.scopeContext.hasFunctionNeedsHomeObjectOnChain,
1781 "Eval must have found an enclosing function box scope that "
1782 "allows super.property");
1784 #endif
1786 if (!CheckParseTree(this->fc_, alloc_, body)) {
1787 return errorResult();
1790 ParseNode* node = body;
1791 // Don't constant-fold inside "use asm" code, as this could create a parse
1792 // tree that doesn't type-check as asm.js.
1793 if (!pc_->useAsmOrInsideUseAsm()) {
1794 if (!FoldConstants(this->fc_, this->parserAtoms(), &node, &handler_)) {
1795 return errorResult();
1798 body = handler_.asLexicalScopeNode(node);
1800 if (!this->setSourceMapInfo()) {
1801 return errorResult();
1804 if (pc_->sc()->strict()) {
1805 if (!propagateFreeNamesAndMarkClosedOverBindings(varScope)) {
1806 return errorResult();
1808 } else {
1809 // For non-strict eval scripts, since all bindings are automatically
1810 // considered closed over, we don't need to call propagateFreeNames-
1811 // AndMarkClosedOverBindings. However, Annex B.3.3 functions still need to
1812 // be marked.
1813 if (!varScope.propagateAndMarkAnnexBFunctionBoxes(pc_, this)) {
1814 return errorResult();
1818 Maybe<EvalScope::ParserData*> bindings = newEvalScopeData(pc_->varScope());
1819 if (!bindings) {
1820 return errorResult();
1822 evalsc->bindings = *bindings;
1824 return body;
1827 template <typename Unit>
1828 FullParseHandler::ListNodeResult Parser<FullParseHandler, Unit>::globalBody(
1829 GlobalSharedContext* globalsc) {
1830 SourceParseContext globalpc(this, globalsc, /* newDirectives = */ nullptr);
1831 if (!globalpc.init()) {
1832 return errorResult();
1835 ParseContext::VarScope varScope(this);
1836 if (!varScope.init(pc_)) {
1837 return errorResult();
1840 ListNode* body;
1841 MOZ_TRY_VAR(body, statementList(YieldIsName));
1843 if (!checkStatementsEOF()) {
1844 return errorResult();
1847 if (!CheckParseTree(this->fc_, alloc_, body)) {
1848 return errorResult();
1851 if (!checkForUndefinedPrivateFields()) {
1852 return errorResult();
1855 ParseNode* node = body;
1856 // Don't constant-fold inside "use asm" code, as this could create a parse
1857 // tree that doesn't type-check as asm.js.
1858 if (!pc_->useAsmOrInsideUseAsm()) {
1859 if (!FoldConstants(this->fc_, this->parserAtoms(), &node, &handler_)) {
1860 return errorResult();
1863 body = &node->as<ListNode>();
1865 if (!this->setSourceMapInfo()) {
1866 return errorResult();
1869 // For global scripts, whether bindings are closed over or not doesn't
1870 // matter, so no need to call propagateFreeNamesAndMarkClosedOver-
1871 // Bindings. However, Annex B.3.3 functions still need to be marked.
1872 if (!varScope.propagateAndMarkAnnexBFunctionBoxes(pc_, this)) {
1873 return errorResult();
1876 Maybe<GlobalScope::ParserData*> bindings =
1877 newGlobalScopeData(pc_->varScope());
1878 if (!bindings) {
1879 return errorResult();
1881 globalsc->bindings = *bindings;
1883 return body;
1886 template <typename Unit>
1887 FullParseHandler::ModuleNodeResult Parser<FullParseHandler, Unit>::moduleBody(
1888 ModuleSharedContext* modulesc) {
1889 MOZ_ASSERT(checkOptionsCalled_);
1891 this->compilationState_.moduleMetadata =
1892 fc_->getAllocator()->template new_<StencilModuleMetadata>();
1893 if (!this->compilationState_.moduleMetadata) {
1894 return errorResult();
1897 SourceParseContext modulepc(this, modulesc, nullptr);
1898 if (!modulepc.init()) {
1899 return errorResult();
1902 ParseContext::VarScope varScope(this);
1903 if (!varScope.init(pc_)) {
1904 return errorResult();
1907 ModuleNodeType moduleNode;
1908 MOZ_TRY_VAR(moduleNode, handler_.newModule(pos()));
1910 AutoAwaitIsKeyword<FullParseHandler, Unit> awaitIsKeyword(
1911 this, AwaitIsModuleKeyword);
1912 ListNode* stmtList;
1913 MOZ_TRY_VAR(stmtList, statementList(YieldIsName));
1915 MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
1916 moduleNode->setBody(&stmtList->template as<ListNode>());
1918 if (pc_->isAsync()) {
1919 if (!noteUsedName(TaggedParserAtomIndex::WellKnown::dot_generator_())) {
1920 return errorResult();
1923 if (!pc_->declareTopLevelDotGeneratorName()) {
1924 return errorResult();
1928 TokenKind tt;
1929 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
1930 return errorResult();
1932 if (tt != TokenKind::Eof) {
1933 error(JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt));
1934 return errorResult();
1937 // Set the module to async if an await keyword was found at the top level.
1938 if (pc_->isAsync()) {
1939 pc_->sc()->asModuleContext()->builder.noteAsync(
1940 *this->compilationState_.moduleMetadata);
1943 // Generate the Import/Export tables and store in CompilationState.
1944 if (!modulesc->builder.buildTables(*this->compilationState_.moduleMetadata)) {
1945 return errorResult();
1948 // Check exported local bindings exist and mark them as closed over.
1949 StencilModuleMetadata& moduleMetadata =
1950 *this->compilationState_.moduleMetadata;
1951 for (auto entry : moduleMetadata.localExportEntries) {
1952 DeclaredNamePtr p = modulepc.varScope().lookupDeclaredName(entry.localName);
1953 if (!p) {
1954 UniqueChars str = this->parserAtoms().toPrintableString(entry.localName);
1955 if (!str) {
1956 ReportOutOfMemory(this->fc_);
1957 return errorResult();
1960 errorNoOffset(JSMSG_MISSING_EXPORT, str.get());
1961 return errorResult();
1964 p->value()->setClosedOver();
1967 // Reserve an environment slot for a "*namespace*" psuedo-binding and mark as
1968 // closed-over. We do not know until module linking if this will be used.
1969 if (!noteDeclaredName(
1970 TaggedParserAtomIndex::WellKnown::star_namespace_star_(),
1971 DeclarationKind::Const, pos())) {
1972 return errorResult();
1974 modulepc.varScope()
1975 .lookupDeclaredName(
1976 TaggedParserAtomIndex::WellKnown::star_namespace_star_())
1977 ->value()
1978 ->setClosedOver();
1980 if (options().deoptimizeModuleGlobalVars) {
1981 for (BindingIter bi = modulepc.varScope().bindings(pc_); bi; bi++) {
1982 bi.setClosedOver();
1986 if (!CheckParseTree(this->fc_, alloc_, stmtList)) {
1987 return errorResult();
1990 ParseNode* node = stmtList;
1991 // Don't constant-fold inside "use asm" code, as this could create a parse
1992 // tree that doesn't type-check as asm.js.
1993 if (!pc_->useAsmOrInsideUseAsm()) {
1994 if (!FoldConstants(this->fc_, this->parserAtoms(), &node, &handler_)) {
1995 return errorResult();
1998 stmtList = &node->as<ListNode>();
2000 if (!this->setSourceMapInfo()) {
2001 return errorResult();
2004 // Private names not lexically defined must trigger a syntax error.
2005 if (!checkForUndefinedPrivateFields()) {
2006 return errorResult();
2009 if (!propagateFreeNamesAndMarkClosedOverBindings(modulepc.varScope())) {
2010 return errorResult();
2013 Maybe<ModuleScope::ParserData*> bindings =
2014 newModuleScopeData(modulepc.varScope());
2015 if (!bindings) {
2016 return errorResult();
2019 modulesc->bindings = *bindings;
2020 return moduleNode;
2023 template <typename Unit>
2024 SyntaxParseHandler::ModuleNodeResult
2025 Parser<SyntaxParseHandler, Unit>::moduleBody(ModuleSharedContext* modulesc) {
2026 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
2027 return errorResult();
2030 template <class ParseHandler>
2031 typename ParseHandler::NameNodeResult
2032 PerHandlerParser<ParseHandler>::newInternalDotName(TaggedParserAtomIndex name) {
2033 NameNodeType nameNode;
2034 MOZ_TRY_VAR(nameNode, newName(name));
2035 if (!noteUsedName(name)) {
2036 return errorResult();
2038 return nameNode;
2041 template <class ParseHandler>
2042 typename ParseHandler::NameNodeResult
2043 PerHandlerParser<ParseHandler>::newThisName() {
2044 return newInternalDotName(TaggedParserAtomIndex::WellKnown::dot_this_());
2047 template <class ParseHandler>
2048 typename ParseHandler::NameNodeResult
2049 PerHandlerParser<ParseHandler>::newNewTargetName() {
2050 return newInternalDotName(TaggedParserAtomIndex::WellKnown::dot_newTarget_());
2053 template <class ParseHandler>
2054 typename ParseHandler::NameNodeResult
2055 PerHandlerParser<ParseHandler>::newDotGeneratorName() {
2056 return newInternalDotName(TaggedParserAtomIndex::WellKnown::dot_generator_());
2059 template <class ParseHandler>
2060 bool PerHandlerParser<ParseHandler>::finishFunctionScopes(
2061 bool isStandaloneFunction) {
2062 FunctionBox* funbox = pc_->functionBox();
2064 if (funbox->hasParameterExprs) {
2065 if (!propagateFreeNamesAndMarkClosedOverBindings(pc_->functionScope())) {
2066 return false;
2069 // Functions with parameter expressions utilize the FunctionScope for vars
2070 // generated by sloppy-direct-evals, as well as arguments (which are
2071 // lexicals bindings). If the function body has var bindings (or has a
2072 // sloppy-direct-eval that might), then an extra VarScope must be created
2073 // for them.
2074 if (VarScopeHasBindings(pc_) ||
2075 funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings()) {
2076 funbox->setFunctionHasExtraBodyVarScope();
2080 // See: JSFunction::needsCallObject()
2081 if (FunctionScopeHasClosedOverBindings(pc_) ||
2082 funbox->needsCallObjectRegardlessOfBindings()) {
2083 funbox->setNeedsFunctionEnvironmentObjects();
2086 if (funbox->isNamedLambda() && !isStandaloneFunction) {
2087 if (!propagateFreeNamesAndMarkClosedOverBindings(pc_->namedLambdaScope())) {
2088 return false;
2091 // See: JSFunction::needsNamedLambdaEnvironment()
2092 if (LexicalScopeHasClosedOverBindings(pc_, pc_->namedLambdaScope())) {
2093 funbox->setNeedsFunctionEnvironmentObjects();
2097 return true;
2100 template <>
2101 bool PerHandlerParser<FullParseHandler>::finishFunction(
2102 bool isStandaloneFunction /* = false */) {
2103 if (!finishFunctionScopes(isStandaloneFunction)) {
2104 return false;
2107 FunctionBox* funbox = pc_->functionBox();
2108 ScriptStencil& script = funbox->functionStencil();
2110 if (funbox->isInterpreted()) {
2111 // BCE will need to generate bytecode for this.
2112 funbox->emitBytecode = true;
2113 this->compilationState_.nonLazyFunctionCount++;
2116 bool hasParameterExprs = funbox->hasParameterExprs;
2118 if (hasParameterExprs) {
2119 Maybe<VarScope::ParserData*> bindings = newVarScopeData(pc_->varScope());
2120 if (!bindings) {
2121 return false;
2123 funbox->setExtraVarScopeBindings(*bindings);
2125 MOZ_ASSERT(bool(*bindings) == VarScopeHasBindings(pc_));
2126 MOZ_ASSERT_IF(!funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings(),
2127 bool(*bindings) == funbox->functionHasExtraBodyVarScope());
2131 Maybe<FunctionScope::ParserData*> bindings =
2132 newFunctionScopeData(pc_->functionScope(), hasParameterExprs);
2133 if (!bindings) {
2134 return false;
2136 funbox->setFunctionScopeBindings(*bindings);
2139 if (funbox->isNamedLambda() && !isStandaloneFunction) {
2140 Maybe<LexicalScope::ParserData*> bindings =
2141 newLexicalScopeData(pc_->namedLambdaScope());
2142 if (!bindings) {
2143 return false;
2145 funbox->setNamedLambdaBindings(*bindings);
2148 funbox->finishScriptFlags();
2149 funbox->copyFunctionFields(script);
2151 if (this->compilationState_.isInitialStencil()) {
2152 ScriptStencilExtra& scriptExtra = funbox->functionExtraStencil();
2153 funbox->copyFunctionExtraFields(scriptExtra);
2154 funbox->copyScriptExtraFields(scriptExtra);
2157 return true;
2160 template <>
2161 bool PerHandlerParser<SyntaxParseHandler>::finishFunction(
2162 bool isStandaloneFunction /* = false */) {
2163 // The BaseScript for a lazily parsed function needs to know its set of
2164 // free variables and inner functions so that when it is fully parsed, we
2165 // can skip over any already syntax parsed inner functions and still
2166 // retain correct scope information.
2168 if (!finishFunctionScopes(isStandaloneFunction)) {
2169 return false;
2172 FunctionBox* funbox = pc_->functionBox();
2173 ScriptStencil& script = funbox->functionStencil();
2175 funbox->finishScriptFlags();
2176 funbox->copyFunctionFields(script);
2178 ScriptStencilExtra& scriptExtra = funbox->functionExtraStencil();
2179 funbox->copyFunctionExtraFields(scriptExtra);
2180 funbox->copyScriptExtraFields(scriptExtra);
2182 // Elide nullptr sentinels from end of binding list. These are inserted for
2183 // each scope regardless of if any bindings are actually closed over.
2185 AtomVector& closedOver = pc_->closedOverBindingsForLazy();
2186 while (!closedOver.empty() && !closedOver.back()) {
2187 closedOver.popBack();
2191 // Check if we will overflow the `ngcthings` field later.
2192 mozilla::CheckedUint32 ngcthings =
2193 mozilla::CheckedUint32(pc_->innerFunctionIndexesForLazy.length()) +
2194 mozilla::CheckedUint32(pc_->closedOverBindingsForLazy().length());
2195 if (!ngcthings.isValid()) {
2196 ReportAllocationOverflow(fc_);
2197 return false;
2200 // If there are no script-things, we can return early without allocating.
2201 if (ngcthings.value() == 0) {
2202 MOZ_ASSERT(!script.hasGCThings());
2203 return true;
2206 TaggedScriptThingIndex* cursor = nullptr;
2207 if (!this->compilationState_.allocateGCThingsUninitialized(
2208 fc_, funbox->index(), ngcthings.value(), &cursor)) {
2209 return false;
2212 // Copy inner-function and closed-over-binding info for the stencil. The order
2213 // is important here. We emit functions first, followed by the bindings info.
2214 // The bindings list uses nullptr as delimiter to separates the bindings per
2215 // scope.
2217 // See: FullParseHandler::nextLazyInnerFunction(),
2218 // FullParseHandler::nextLazyClosedOverBinding()
2219 for (const ScriptIndex& index : pc_->innerFunctionIndexesForLazy) {
2220 void* raw = &(*cursor++);
2221 new (raw) TaggedScriptThingIndex(index);
2223 for (auto binding : pc_->closedOverBindingsForLazy()) {
2224 void* raw = &(*cursor++);
2225 if (binding) {
2226 this->parserAtoms().markUsedByStencil(binding, ParserAtom::Atomize::Yes);
2227 new (raw) TaggedScriptThingIndex(binding);
2228 } else {
2229 new (raw) TaggedScriptThingIndex();
2233 return true;
2236 static YieldHandling GetYieldHandling(GeneratorKind generatorKind) {
2237 if (generatorKind == GeneratorKind::NotGenerator) {
2238 return YieldIsName;
2240 return YieldIsKeyword;
2243 static AwaitHandling GetAwaitHandling(FunctionAsyncKind asyncKind) {
2244 if (asyncKind == FunctionAsyncKind::SyncFunction) {
2245 return AwaitIsName;
2247 return AwaitIsKeyword;
2250 static FunctionFlags InitialFunctionFlags(FunctionSyntaxKind kind,
2251 GeneratorKind generatorKind,
2252 FunctionAsyncKind asyncKind,
2253 bool isSelfHosting) {
2254 FunctionFlags flags = {};
2256 switch (kind) {
2257 case FunctionSyntaxKind::Expression:
2258 flags = (generatorKind == GeneratorKind::NotGenerator &&
2259 asyncKind == FunctionAsyncKind::SyncFunction
2260 ? FunctionFlags::INTERPRETED_LAMBDA
2261 : FunctionFlags::INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC);
2262 break;
2263 case FunctionSyntaxKind::Arrow:
2264 flags = FunctionFlags::INTERPRETED_LAMBDA_ARROW;
2265 break;
2266 case FunctionSyntaxKind::Method:
2267 case FunctionSyntaxKind::FieldInitializer:
2268 case FunctionSyntaxKind::StaticClassBlock:
2269 flags = FunctionFlags::INTERPRETED_METHOD;
2270 break;
2271 case FunctionSyntaxKind::ClassConstructor:
2272 case FunctionSyntaxKind::DerivedClassConstructor:
2273 flags = FunctionFlags::INTERPRETED_CLASS_CTOR;
2274 break;
2275 case FunctionSyntaxKind::Getter:
2276 flags = FunctionFlags::INTERPRETED_GETTER;
2277 break;
2278 case FunctionSyntaxKind::Setter:
2279 flags = FunctionFlags::INTERPRETED_SETTER;
2280 break;
2281 default:
2282 MOZ_ASSERT(kind == FunctionSyntaxKind::Statement);
2283 flags = (generatorKind == GeneratorKind::NotGenerator &&
2284 asyncKind == FunctionAsyncKind::SyncFunction
2285 ? FunctionFlags::INTERPRETED_NORMAL
2286 : FunctionFlags::INTERPRETED_GENERATOR_OR_ASYNC);
2289 if (isSelfHosting) {
2290 flags.setIsSelfHostedBuiltin();
2293 return flags;
2296 template <typename Unit>
2297 FullParseHandler::FunctionNodeResult
2298 Parser<FullParseHandler, Unit>::standaloneFunction(
2299 const Maybe<uint32_t>& parameterListEnd, FunctionSyntaxKind syntaxKind,
2300 GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
2301 Directives inheritedDirectives, Directives* newDirectives) {
2302 MOZ_ASSERT(checkOptionsCalled_);
2303 // Skip prelude.
2304 TokenKind tt;
2305 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
2306 return errorResult();
2308 if (asyncKind == FunctionAsyncKind::AsyncFunction) {
2309 MOZ_ASSERT(tt == TokenKind::Async);
2310 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
2311 return errorResult();
2314 MOZ_ASSERT(tt == TokenKind::Function);
2316 if (!tokenStream.getToken(&tt)) {
2317 return errorResult();
2319 if (generatorKind == GeneratorKind::Generator) {
2320 MOZ_ASSERT(tt == TokenKind::Mul);
2321 if (!tokenStream.getToken(&tt)) {
2322 return errorResult();
2326 // Skip function name, if present.
2327 TaggedParserAtomIndex explicitName;
2328 if (TokenKindIsPossibleIdentifierName(tt)) {
2329 explicitName = anyChars.currentName();
2330 } else {
2331 anyChars.ungetToken();
2334 FunctionNodeType funNode;
2335 MOZ_TRY_VAR(funNode, handler_.newFunction(syntaxKind, pos()));
2337 ParamsBodyNodeType argsbody;
2338 MOZ_TRY_VAR(argsbody, handler_.newParamsBody(pos()));
2339 funNode->setBody(argsbody);
2341 bool isSelfHosting = options().selfHostingMode;
2342 FunctionFlags flags =
2343 InitialFunctionFlags(syntaxKind, generatorKind, asyncKind, isSelfHosting);
2344 FunctionBox* funbox =
2345 newFunctionBox(funNode, explicitName, flags, /* toStringStart = */ 0,
2346 inheritedDirectives, generatorKind, asyncKind);
2347 if (!funbox) {
2348 return errorResult();
2351 // Function is not syntactically part of another script.
2352 MOZ_ASSERT(funbox->index() == CompilationStencil::TopLevelIndex);
2354 funbox->initStandalone(this->compilationState_.scopeContext, syntaxKind);
2356 SourceParseContext funpc(this, funbox, newDirectives);
2357 if (!funpc.init()) {
2358 return errorResult();
2361 YieldHandling yieldHandling = GetYieldHandling(generatorKind);
2362 AwaitHandling awaitHandling = GetAwaitHandling(asyncKind);
2363 AutoAwaitIsKeyword<FullParseHandler, Unit> awaitIsKeyword(this,
2364 awaitHandling);
2365 if (!functionFormalParametersAndBody(InAllowed, yieldHandling, &funNode,
2366 syntaxKind, parameterListEnd,
2367 /* isStandaloneFunction = */ true)) {
2368 return errorResult();
2371 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
2372 return errorResult();
2374 if (tt != TokenKind::Eof) {
2375 error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt));
2376 return errorResult();
2379 if (!CheckParseTree(this->fc_, alloc_, funNode)) {
2380 return errorResult();
2383 ParseNode* node = funNode;
2384 // Don't constant-fold inside "use asm" code, as this could create a parse
2385 // tree that doesn't type-check as asm.js.
2386 if (!pc_->useAsmOrInsideUseAsm()) {
2387 if (!FoldConstants(this->fc_, this->parserAtoms(), &node, &handler_)) {
2388 return errorResult();
2391 funNode = &node->as<FunctionNode>();
2393 if (!checkForUndefinedPrivateFields(nullptr)) {
2394 return errorResult();
2397 if (!this->setSourceMapInfo()) {
2398 return errorResult();
2401 return funNode;
2404 template <class ParseHandler, typename Unit>
2405 typename ParseHandler::LexicalScopeNodeResult
2406 GeneralParser<ParseHandler, Unit>::functionBody(InHandling inHandling,
2407 YieldHandling yieldHandling,
2408 FunctionSyntaxKind kind,
2409 FunctionBodyType type) {
2410 MOZ_ASSERT(pc_->isFunctionBox());
2412 #ifdef DEBUG
2413 uint32_t startYieldOffset = pc_->lastYieldOffset;
2414 #endif
2416 Node body;
2417 if (type == StatementListBody) {
2418 bool inheritedStrict = pc_->sc()->strict();
2419 MOZ_TRY_VAR(body, statementList(yieldHandling));
2421 // When we transitioned from non-strict to strict mode, we need to
2422 // validate that all parameter names are valid strict mode names.
2423 if (!inheritedStrict && pc_->sc()->strict()) {
2424 MOZ_ASSERT(pc_->sc()->hasExplicitUseStrict(),
2425 "strict mode should only change when a 'use strict' directive "
2426 "is present");
2427 if (!hasValidSimpleStrictParameterNames()) {
2428 // Request that this function be reparsed as strict to report
2429 // the invalid parameter name at the correct source location.
2430 pc_->newDirectives->setStrict();
2431 return errorResult();
2434 } else {
2435 MOZ_ASSERT(type == ExpressionBody);
2437 // Async functions are implemented as generators, and generators are
2438 // assumed to be statement lists, to prepend initial `yield`.
2439 ListNodeType stmtList = null();
2440 if (pc_->isAsync()) {
2441 MOZ_TRY_VAR(stmtList, handler_.newStatementList(pos()));
2444 Node kid;
2445 MOZ_TRY_VAR(kid,
2446 assignExpr(inHandling, yieldHandling, TripledotProhibited));
2448 MOZ_TRY_VAR(body, handler_.newExpressionBody(kid));
2450 if (pc_->isAsync()) {
2451 handler_.addStatementToList(stmtList, body);
2452 body = stmtList;
2456 MOZ_ASSERT_IF(!pc_->isGenerator() && !pc_->isAsync(),
2457 pc_->lastYieldOffset == startYieldOffset);
2458 MOZ_ASSERT_IF(pc_->isGenerator(), kind != FunctionSyntaxKind::Arrow);
2459 MOZ_ASSERT_IF(pc_->isGenerator(), type == StatementListBody);
2461 if (pc_->needsDotGeneratorName()) {
2462 MOZ_ASSERT_IF(!pc_->isAsync(), type == StatementListBody);
2463 if (!pc_->declareDotGeneratorName()) {
2464 return errorResult();
2466 if (pc_->isGenerator()) {
2467 NameNodeType generator;
2468 MOZ_TRY_VAR(generator, newDotGeneratorName());
2469 if (!handler_.prependInitialYield(handler_.asListNode(body), generator)) {
2470 return errorResult();
2475 // Declare the 'arguments', 'this', and 'new.target' bindings if necessary
2476 // before finishing up the scope so these special bindings get marked as
2477 // closed over if necessary. Arrow functions don't have these bindings.
2478 if (kind != FunctionSyntaxKind::Arrow) {
2479 bool canSkipLazyClosedOverBindings = handler_.reuseClosedOverBindings();
2480 if (!pc_->declareFunctionArgumentsObject(usedNames_,
2481 canSkipLazyClosedOverBindings)) {
2482 return errorResult();
2484 if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
2485 return errorResult();
2487 if (!pc_->declareNewTarget(usedNames_, canSkipLazyClosedOverBindings)) {
2488 return errorResult();
2492 return finishLexicalScope(pc_->varScope(), body, ScopeKind::FunctionLexical);
2495 template <class ParseHandler, typename Unit>
2496 bool GeneralParser<ParseHandler, Unit>::matchOrInsertSemicolon(
2497 Modifier modifier /* = TokenStream::SlashIsRegExp */) {
2498 TokenKind tt = TokenKind::Eof;
2499 if (!tokenStream.peekTokenSameLine(&tt, modifier)) {
2500 return false;
2502 if (tt != TokenKind::Eof && tt != TokenKind::Eol && tt != TokenKind::Semi &&
2503 tt != TokenKind::RightCurly) {
2505 * When current token is `await` and it's outside of async function,
2506 * it's possibly intended to be an await expression.
2508 * await f();
2511 * tried to insert semicolon here
2513 * Detect this situation and throw an understandable error. Otherwise
2514 * we'd throw a confusing "unexpected token: (unexpected token)" error.
2516 if (!pc_->isAsync() && anyChars.currentToken().type == TokenKind::Await) {
2517 error(JSMSG_AWAIT_OUTSIDE_ASYNC_OR_MODULE);
2518 return false;
2520 if (!yieldExpressionsSupported() &&
2521 anyChars.currentToken().type == TokenKind::Yield) {
2522 error(JSMSG_YIELD_OUTSIDE_GENERATOR);
2523 return false;
2526 /* Advance the scanner for proper error location reporting. */
2527 tokenStream.consumeKnownToken(tt, modifier);
2528 error(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, TokenKindToDesc(tt));
2529 return false;
2531 bool matched;
2532 return tokenStream.matchToken(&matched, TokenKind::Semi, modifier);
2535 bool ParserBase::leaveInnerFunction(ParseContext* outerpc) {
2536 MOZ_ASSERT(pc_ != outerpc);
2538 MOZ_ASSERT_IF(outerpc->isFunctionBox(),
2539 outerpc->functionBox()->index() < pc_->functionBox()->index());
2541 // If the current function allows super.property but cannot have a home
2542 // object, i.e., it is an arrow function, we need to propagate the flag to
2543 // the outer ParseContext.
2544 if (pc_->superScopeNeedsHomeObject()) {
2545 if (!pc_->isArrowFunction()) {
2546 MOZ_ASSERT(pc_->functionBox()->needsHomeObject());
2547 } else {
2548 outerpc->setSuperScopeNeedsHomeObject();
2552 // Lazy functions inner to another lazy function need to be remembered by
2553 // the inner function so that if the outer function is eventually parsed
2554 // we do not need any further parsing or processing of the inner function.
2556 // Append the inner function index here unconditionally; the vector is only
2557 // used if the Parser using outerpc is a syntax parsing. See
2558 // GeneralParser<SyntaxParseHandler>::finishFunction.
2559 if (!outerpc->innerFunctionIndexesForLazy.append(
2560 pc_->functionBox()->index())) {
2561 return false;
2564 PropagateTransitiveParseFlags(pc_->functionBox(), outerpc->sc());
2566 return true;
2569 TaggedParserAtomIndex ParserBase::prefixAccessorName(
2570 PropertyType propType, TaggedParserAtomIndex propAtom) {
2571 StringBuffer prefixed(fc_);
2572 if (propType == PropertyType::Setter) {
2573 if (!prefixed.append("set ")) {
2574 return TaggedParserAtomIndex::null();
2576 } else {
2577 if (!prefixed.append("get ")) {
2578 return TaggedParserAtomIndex::null();
2581 if (!prefixed.append(this->parserAtoms(), propAtom)) {
2582 return TaggedParserAtomIndex::null();
2584 return prefixed.finishParserAtom(this->parserAtoms(), fc_);
2587 template <class ParseHandler, typename Unit>
2588 void GeneralParser<ParseHandler, Unit>::setFunctionStartAtPosition(
2589 FunctionBox* funbox, TokenPos pos) const {
2590 uint32_t startLine;
2591 JS::LimitedColumnNumberOneOrigin startColumn;
2592 tokenStream.computeLineAndColumn(pos.begin, &startLine, &startColumn);
2594 // NOTE: `Debugger::CallData::findScripts` relies on sourceStart and
2595 // lineno/column referring to the same location.
2596 funbox->setStart(pos.begin, startLine, startColumn);
2599 template <class ParseHandler, typename Unit>
2600 void GeneralParser<ParseHandler, Unit>::setFunctionStartAtCurrentToken(
2601 FunctionBox* funbox) const {
2602 setFunctionStartAtPosition(funbox, anyChars.currentToken().pos);
2605 template <class ParseHandler, typename Unit>
2606 bool GeneralParser<ParseHandler, Unit>::functionArguments(
2607 YieldHandling yieldHandling, FunctionSyntaxKind kind,
2608 FunctionNodeType funNode) {
2609 FunctionBox* funbox = pc_->functionBox();
2611 // Modifier for the following tokens.
2612 // TokenStream::SlashIsDiv for the following cases:
2613 // async a => 1
2614 // ^
2616 // (a) => 1
2617 // ^
2619 // async (a) => 1
2620 // ^
2622 // function f(a) {}
2623 // ^
2625 // TokenStream::SlashIsRegExp for the following case:
2626 // a => 1
2627 // ^
2628 Modifier firstTokenModifier =
2629 kind != FunctionSyntaxKind::Arrow || funbox->isAsync()
2630 ? TokenStream::SlashIsDiv
2631 : TokenStream::SlashIsRegExp;
2632 TokenKind tt;
2633 if (!tokenStream.getToken(&tt, firstTokenModifier)) {
2634 return false;
2637 if (kind == FunctionSyntaxKind::Arrow && TokenKindIsPossibleIdentifier(tt)) {
2638 // Record the start of function source (for FunctionToString).
2639 setFunctionStartAtCurrentToken(funbox);
2641 ParamsBodyNodeType argsbody;
2642 MOZ_TRY_VAR_OR_RETURN(argsbody, handler_.newParamsBody(pos()), false);
2643 handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
2645 TaggedParserAtomIndex name = bindingIdentifier(yieldHandling);
2646 if (!name) {
2647 return false;
2650 constexpr bool disallowDuplicateParams = true;
2651 bool duplicatedParam = false;
2652 if (!notePositionalFormalParameter(funNode, name, pos().begin,
2653 disallowDuplicateParams,
2654 &duplicatedParam)) {
2655 return false;
2657 MOZ_ASSERT(!duplicatedParam);
2658 MOZ_ASSERT(pc_->positionalFormalParameterNames().length() == 1);
2660 funbox->setLength(1);
2661 funbox->setArgCount(1);
2662 return true;
2665 if (tt != TokenKind::LeftParen) {
2666 error(kind == FunctionSyntaxKind::Arrow ? JSMSG_BAD_ARROW_ARGS
2667 : JSMSG_PAREN_BEFORE_FORMAL);
2668 return false;
2671 // Record the start of function source (for FunctionToString).
2672 setFunctionStartAtCurrentToken(funbox);
2674 ParamsBodyNodeType argsbody;
2675 MOZ_TRY_VAR_OR_RETURN(argsbody, handler_.newParamsBody(pos()), false);
2676 handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
2678 bool matched;
2679 if (!tokenStream.matchToken(&matched, TokenKind::RightParen,
2680 TokenStream::SlashIsRegExp)) {
2681 return false;
2683 if (!matched) {
2684 bool hasRest = false;
2685 bool hasDefault = false;
2686 bool duplicatedParam = false;
2687 bool disallowDuplicateParams =
2688 kind == FunctionSyntaxKind::Arrow ||
2689 kind == FunctionSyntaxKind::Method ||
2690 kind == FunctionSyntaxKind::FieldInitializer ||
2691 kind == FunctionSyntaxKind::ClassConstructor;
2692 AtomVector& positionalFormals = pc_->positionalFormalParameterNames();
2694 if (kind == FunctionSyntaxKind::Getter) {
2695 error(JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
2696 return false;
2699 while (true) {
2700 if (hasRest) {
2701 error(JSMSG_PARAMETER_AFTER_REST);
2702 return false;
2705 TokenKind tt;
2706 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
2707 return false;
2710 if (tt == TokenKind::TripleDot) {
2711 if (kind == FunctionSyntaxKind::Setter) {
2712 error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
2713 return false;
2716 disallowDuplicateParams = true;
2717 if (duplicatedParam) {
2718 // Has duplicated args before the rest parameter.
2719 error(JSMSG_BAD_DUP_ARGS);
2720 return false;
2723 hasRest = true;
2724 funbox->setHasRest();
2726 if (!tokenStream.getToken(&tt)) {
2727 return false;
2730 if (!TokenKindIsPossibleIdentifier(tt) &&
2731 tt != TokenKind::LeftBracket && tt != TokenKind::LeftCurly) {
2732 error(JSMSG_NO_REST_NAME);
2733 return false;
2737 switch (tt) {
2738 case TokenKind::LeftBracket:
2739 case TokenKind::LeftCurly: {
2740 disallowDuplicateParams = true;
2741 if (duplicatedParam) {
2742 // Has duplicated args before the destructuring parameter.
2743 error(JSMSG_BAD_DUP_ARGS);
2744 return false;
2747 funbox->hasDestructuringArgs = true;
2749 Node destruct;
2750 MOZ_TRY_VAR_OR_RETURN(
2751 destruct,
2752 destructuringDeclarationWithoutYieldOrAwait(
2753 DeclarationKind::FormalParameter, yieldHandling, tt),
2754 false);
2756 if (!noteDestructuredPositionalFormalParameter(funNode, destruct)) {
2757 return false;
2760 break;
2763 default: {
2764 if (!TokenKindIsPossibleIdentifier(tt)) {
2765 error(JSMSG_MISSING_FORMAL);
2766 return false;
2769 TaggedParserAtomIndex name = bindingIdentifier(yieldHandling);
2770 if (!name) {
2771 return false;
2774 if (!notePositionalFormalParameter(funNode, name, pos().begin,
2775 disallowDuplicateParams,
2776 &duplicatedParam)) {
2777 return false;
2779 if (duplicatedParam) {
2780 funbox->hasDuplicateParameters = true;
2783 break;
2787 if (positionalFormals.length() >= ARGNO_LIMIT) {
2788 error(JSMSG_TOO_MANY_FUN_ARGS);
2789 return false;
2792 bool matched;
2793 if (!tokenStream.matchToken(&matched, TokenKind::Assign,
2794 TokenStream::SlashIsRegExp)) {
2795 return false;
2797 if (matched) {
2798 if (hasRest) {
2799 error(JSMSG_REST_WITH_DEFAULT);
2800 return false;
2802 disallowDuplicateParams = true;
2803 if (duplicatedParam) {
2804 error(JSMSG_BAD_DUP_ARGS);
2805 return false;
2808 if (!hasDefault) {
2809 hasDefault = true;
2811 // The Function.length property is the number of formals
2812 // before the first default argument.
2813 funbox->setLength(positionalFormals.length() - 1);
2815 funbox->hasParameterExprs = true;
2817 Node def_expr;
2818 MOZ_TRY_VAR_OR_RETURN(
2819 def_expr, assignExprWithoutYieldOrAwait(yieldHandling), false);
2820 if (!handler_.setLastFunctionFormalParameterDefault(funNode,
2821 def_expr)) {
2822 return false;
2826 // Setter syntax uniquely requires exactly one argument.
2827 if (kind == FunctionSyntaxKind::Setter) {
2828 break;
2831 if (!tokenStream.matchToken(&matched, TokenKind::Comma,
2832 TokenStream::SlashIsRegExp)) {
2833 return false;
2835 if (!matched) {
2836 break;
2839 if (!hasRest) {
2840 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
2841 return false;
2843 if (tt == TokenKind::RightParen) {
2844 break;
2849 TokenKind tt;
2850 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
2851 return false;
2853 if (tt != TokenKind::RightParen) {
2854 if (kind == FunctionSyntaxKind::Setter) {
2855 error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
2856 return false;
2859 error(JSMSG_PAREN_AFTER_FORMAL);
2860 return false;
2863 if (!hasDefault) {
2864 funbox->setLength(positionalFormals.length() - hasRest);
2867 funbox->setArgCount(positionalFormals.length());
2868 } else if (kind == FunctionSyntaxKind::Setter) {
2869 error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
2870 return false;
2873 return true;
2876 template <typename Unit>
2877 bool Parser<FullParseHandler, Unit>::skipLazyInnerFunction(
2878 FunctionNode* funNode, uint32_t toStringStart, bool tryAnnexB) {
2879 // When a lazily-parsed function is called, we only fully parse (and emit)
2880 // that function, not any of its nested children. The initial syntax-only
2881 // parse recorded the free variables of nested functions and their extents,
2882 // so we can skip over them after accounting for their free variables.
2884 MOZ_ASSERT(pc_->isOutermostOfCurrentCompile());
2885 handler_.nextLazyInnerFunction();
2886 const ScriptStencil& cachedData = handler_.cachedScriptData();
2887 const ScriptStencilExtra& cachedExtra = handler_.cachedScriptExtra();
2888 MOZ_ASSERT(toStringStart == cachedExtra.extent.toStringStart);
2890 FunctionBox* funbox = newFunctionBox(funNode, cachedData, cachedExtra);
2891 if (!funbox) {
2892 return false;
2895 ScriptStencil& script = funbox->functionStencil();
2896 funbox->copyFunctionFields(script);
2898 // If the inner lazy function is class constructor, connect it to the class
2899 // statement/expression we are parsing.
2900 if (funbox->isClassConstructor()) {
2901 auto classStmt =
2902 pc_->template findInnermostStatement<ParseContext::ClassStatement>();
2903 MOZ_ASSERT(!classStmt->constructorBox);
2904 classStmt->constructorBox = funbox;
2907 MOZ_ASSERT_IF(pc_->isFunctionBox(),
2908 pc_->functionBox()->index() < funbox->index());
2910 PropagateTransitiveParseFlags(funbox, pc_->sc());
2912 if (!tokenStream.advance(funbox->extent().sourceEnd)) {
2913 return false;
2916 // Append possible Annex B function box only upon successfully parsing.
2917 if (tryAnnexB &&
2918 !pc_->innermostScope()->addPossibleAnnexBFunctionBox(pc_, funbox)) {
2919 return false;
2922 return true;
2925 template <typename Unit>
2926 bool Parser<SyntaxParseHandler, Unit>::skipLazyInnerFunction(
2927 FunctionNodeType funNode, uint32_t toStringStart, bool tryAnnexB) {
2928 MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
2931 template <class ParseHandler, typename Unit>
2932 bool GeneralParser<ParseHandler, Unit>::skipLazyInnerFunction(
2933 FunctionNodeType funNode, uint32_t toStringStart, bool tryAnnexB) {
2934 return asFinalParser()->skipLazyInnerFunction(funNode, toStringStart,
2935 tryAnnexB);
2938 template <class ParseHandler, typename Unit>
2939 bool GeneralParser<ParseHandler, Unit>::addExprAndGetNextTemplStrToken(
2940 YieldHandling yieldHandling, ListNodeType nodeList, TokenKind* ttp) {
2941 Node pn;
2942 MOZ_TRY_VAR_OR_RETURN(pn, expr(InAllowed, yieldHandling, TripledotProhibited),
2943 false);
2944 handler_.addList(nodeList, pn);
2946 TokenKind tt;
2947 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
2948 return false;
2950 if (tt != TokenKind::RightCurly) {
2951 error(JSMSG_TEMPLSTR_UNTERM_EXPR);
2952 return false;
2955 return tokenStream.getTemplateToken(ttp);
2958 template <class ParseHandler, typename Unit>
2959 bool GeneralParser<ParseHandler, Unit>::taggedTemplate(
2960 YieldHandling yieldHandling, ListNodeType tagArgsList, TokenKind tt) {
2961 CallSiteNodeType callSiteObjNode;
2962 MOZ_TRY_VAR_OR_RETURN(callSiteObjNode,
2963 handler_.newCallSiteObject(pos().begin), false);
2964 handler_.addList(tagArgsList, callSiteObjNode);
2966 pc_->sc()->setHasCallSiteObj();
2968 while (true) {
2969 if (!appendToCallSiteObj(callSiteObjNode)) {
2970 return false;
2972 if (tt != TokenKind::TemplateHead) {
2973 break;
2976 if (!addExprAndGetNextTemplStrToken(yieldHandling, tagArgsList, &tt)) {
2977 return false;
2980 handler_.setEndPosition(tagArgsList, callSiteObjNode);
2981 return true;
2984 template <class ParseHandler, typename Unit>
2985 typename ParseHandler::ListNodeResult
2986 GeneralParser<ParseHandler, Unit>::templateLiteral(
2987 YieldHandling yieldHandling) {
2988 NameNodeType literal;
2989 MOZ_TRY_VAR(literal, noSubstitutionUntaggedTemplate());
2991 ListNodeType nodeList;
2992 MOZ_TRY_VAR(nodeList,
2993 handler_.newList(ParseNodeKind::TemplateStringListExpr, literal));
2995 TokenKind tt;
2996 do {
2997 if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt)) {
2998 return errorResult();
3001 MOZ_TRY_VAR(literal, noSubstitutionUntaggedTemplate());
3003 handler_.addList(nodeList, literal);
3004 } while (tt == TokenKind::TemplateHead);
3005 return nodeList;
3008 template <class ParseHandler, typename Unit>
3009 typename ParseHandler::FunctionNodeResult
3010 GeneralParser<ParseHandler, Unit>::functionDefinition(
3011 FunctionNodeType funNode, uint32_t toStringStart, InHandling inHandling,
3012 YieldHandling yieldHandling, TaggedParserAtomIndex funName,
3013 FunctionSyntaxKind kind, GeneratorKind generatorKind,
3014 FunctionAsyncKind asyncKind, bool tryAnnexB /* = false */) {
3015 MOZ_ASSERT_IF(kind == FunctionSyntaxKind::Statement, funName);
3017 // If we see any inner function, note it on our current context. The bytecode
3018 // emitter may eliminate the function later, but we use a conservative
3019 // definition for consistency between lazy and full parsing.
3020 pc_->sc()->setHasInnerFunctions();
3022 // When fully parsing a lazy script, we do not fully reparse its inner
3023 // functions, which are also lazy. Instead, their free variables and source
3024 // extents are recorded and may be skipped.
3025 if (handler_.reuseLazyInnerFunctions()) {
3026 if (!skipLazyInnerFunction(funNode, toStringStart, tryAnnexB)) {
3027 return errorResult();
3030 return funNode;
3033 bool isSelfHosting = options().selfHostingMode;
3034 FunctionFlags flags =
3035 InitialFunctionFlags(kind, generatorKind, asyncKind, isSelfHosting);
3037 // Self-hosted functions with special function names require extended slots
3038 // for various purposes.
3039 bool forceExtended =
3040 isSelfHosting && funName &&
3041 this->parserAtoms().isExtendedUnclonedSelfHostedFunctionName(funName);
3042 if (forceExtended) {
3043 flags.setIsExtended();
3046 // Speculatively parse using the directives of the parent parsing context.
3047 // If a directive is encountered (e.g., "use strict") that changes how the
3048 // function should have been parsed, we backup and reparse with the new set
3049 // of directives.
3050 Directives directives(pc_);
3051 Directives newDirectives = directives;
3053 Position start(tokenStream);
3054 auto startObj = this->compilationState_.getPosition();
3056 // Parse the inner function. The following is a loop as we may attempt to
3057 // reparse a function due to failed syntax parsing and encountering new
3058 // "use foo" directives.
3059 while (true) {
3060 if (trySyntaxParseInnerFunction(&funNode, funName, flags, toStringStart,
3061 inHandling, yieldHandling, kind,
3062 generatorKind, asyncKind, tryAnnexB,
3063 directives, &newDirectives)) {
3064 break;
3067 // Return on error.
3068 if (anyChars.hadError() || directives == newDirectives) {
3069 return errorResult();
3072 // Assignment must be monotonic to prevent infinitely attempting to
3073 // reparse.
3074 MOZ_ASSERT_IF(directives.strict(), newDirectives.strict());
3075 MOZ_ASSERT_IF(directives.asmJS(), newDirectives.asmJS());
3076 directives = newDirectives;
3078 // Rewind to retry parsing with new directives applied.
3079 tokenStream.rewind(start);
3080 this->compilationState_.rewind(startObj);
3082 // functionFormalParametersAndBody may have already set body before failing.
3083 handler_.setFunctionFormalParametersAndBody(funNode, null());
3086 return funNode;
3089 template <typename Unit>
3090 bool Parser<FullParseHandler, Unit>::advancePastSyntaxParsedFunction(
3091 SyntaxParser* syntaxParser) {
3092 MOZ_ASSERT(getSyntaxParser() == syntaxParser);
3094 // Advance this parser over tokens processed by the syntax parser.
3095 Position currentSyntaxPosition(syntaxParser->tokenStream);
3096 if (!tokenStream.fastForward(currentSyntaxPosition, syntaxParser->anyChars)) {
3097 return false;
3100 anyChars.adoptState(syntaxParser->anyChars);
3101 tokenStream.adoptState(syntaxParser->tokenStream);
3102 return true;
3105 template <typename Unit>
3106 bool Parser<FullParseHandler, Unit>::trySyntaxParseInnerFunction(
3107 FunctionNode** funNode, TaggedParserAtomIndex explicitName,
3108 FunctionFlags flags, uint32_t toStringStart, InHandling inHandling,
3109 YieldHandling yieldHandling, FunctionSyntaxKind kind,
3110 GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
3111 Directives inheritedDirectives, Directives* newDirectives) {
3112 // Try a syntax parse for this inner function.
3113 do {
3114 // If we're assuming this function is an IIFE, always perform a full
3115 // parse to avoid the overhead of a lazy syntax-only parse. Although
3116 // the prediction may be incorrect, IIFEs are common enough that it
3117 // pays off for lots of code.
3118 if ((*funNode)->isLikelyIIFE() &&
3119 generatorKind == GeneratorKind::NotGenerator &&
3120 asyncKind == FunctionAsyncKind::SyncFunction) {
3121 break;
3124 SyntaxParser* syntaxParser = getSyntaxParser();
3125 if (!syntaxParser) {
3126 break;
3129 UsedNameTracker::RewindToken token = usedNames_.getRewindToken();
3130 auto statePosition = this->compilationState_.getPosition();
3132 // Move the syntax parser to the current position in the stream. In the
3133 // common case this seeks forward, but it'll also seek backward *at least*
3134 // when arrow functions appear inside arrow function argument defaults
3135 // (because we rewind to reparse arrow functions once we're certain they're
3136 // arrow functions):
3138 // var x = (y = z => 2) => q;
3139 // // ^ we first seek to here to syntax-parse this function
3140 // // ^ then we seek back to here to syntax-parse the outer function
3141 Position currentPosition(tokenStream);
3142 if (!syntaxParser->tokenStream.seekTo(currentPosition, anyChars)) {
3143 return false;
3146 // Make a FunctionBox before we enter the syntax parser, because |pn|
3147 // still expects a FunctionBox to be attached to it during BCE, and
3148 // the syntax parser cannot attach one to it.
3149 FunctionBox* funbox =
3150 newFunctionBox(*funNode, explicitName, flags, toStringStart,
3151 inheritedDirectives, generatorKind, asyncKind);
3152 if (!funbox) {
3153 return false;
3155 funbox->initWithEnclosingParseContext(pc_, kind);
3157 auto syntaxNodeResult = syntaxParser->innerFunctionForFunctionBox(
3158 SyntaxParseHandler::Node::NodeGeneric, pc_, funbox, inHandling,
3159 yieldHandling, kind, newDirectives);
3160 if (syntaxNodeResult.isErr()) {
3161 if (syntaxParser->hadAbortedSyntaxParse()) {
3162 // Try again with a full parse. UsedNameTracker needs to be
3163 // rewound to just before we tried the syntax parse for
3164 // correctness.
3165 syntaxParser->clearAbortedSyntaxParse();
3166 usedNames_.rewind(token);
3167 this->compilationState_.rewind(statePosition);
3168 MOZ_ASSERT(!fc_->hadErrors());
3169 break;
3171 return false;
3174 if (!advancePastSyntaxParsedFunction(syntaxParser)) {
3175 return false;
3178 // Update the end position of the parse node.
3179 (*funNode)->pn_pos.end = anyChars.currentToken().pos.end;
3181 // Append possible Annex B function box only upon successfully parsing.
3182 if (tryAnnexB) {
3183 if (!pc_->innermostScope()->addPossibleAnnexBFunctionBox(pc_, funbox)) {
3184 return false;
3188 return true;
3189 } while (false);
3191 // We failed to do a syntax parse above, so do the full parse.
3192 FunctionNodeType innerFunc;
3193 MOZ_TRY_VAR_OR_RETURN(
3194 innerFunc,
3195 innerFunction(*funNode, pc_, explicitName, flags, toStringStart,
3196 inHandling, yieldHandling, kind, generatorKind, asyncKind,
3197 tryAnnexB, inheritedDirectives, newDirectives),
3198 false);
3200 *funNode = innerFunc;
3201 return true;
3204 template <typename Unit>
3205 bool Parser<SyntaxParseHandler, Unit>::trySyntaxParseInnerFunction(
3206 FunctionNodeType* funNode, TaggedParserAtomIndex explicitName,
3207 FunctionFlags flags, uint32_t toStringStart, InHandling inHandling,
3208 YieldHandling yieldHandling, FunctionSyntaxKind kind,
3209 GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
3210 Directives inheritedDirectives, Directives* newDirectives) {
3211 // This is already a syntax parser, so just parse the inner function.
3212 FunctionNodeType innerFunc;
3213 MOZ_TRY_VAR_OR_RETURN(
3214 innerFunc,
3215 innerFunction(*funNode, pc_, explicitName, flags, toStringStart,
3216 inHandling, yieldHandling, kind, generatorKind, asyncKind,
3217 tryAnnexB, inheritedDirectives, newDirectives),
3218 false);
3220 *funNode = innerFunc;
3221 return true;
3224 template <class ParseHandler, typename Unit>
3225 inline bool GeneralParser<ParseHandler, Unit>::trySyntaxParseInnerFunction(
3226 FunctionNodeType* funNode, TaggedParserAtomIndex explicitName,
3227 FunctionFlags flags, uint32_t toStringStart, InHandling inHandling,
3228 YieldHandling yieldHandling, FunctionSyntaxKind kind,
3229 GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
3230 Directives inheritedDirectives, Directives* newDirectives) {
3231 return asFinalParser()->trySyntaxParseInnerFunction(
3232 funNode, explicitName, flags, toStringStart, inHandling, yieldHandling,
3233 kind, generatorKind, asyncKind, tryAnnexB, inheritedDirectives,
3234 newDirectives);
3237 template <class ParseHandler, typename Unit>
3238 typename ParseHandler::FunctionNodeResult
3239 GeneralParser<ParseHandler, Unit>::innerFunctionForFunctionBox(
3240 FunctionNodeType funNode, ParseContext* outerpc, FunctionBox* funbox,
3241 InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
3242 Directives* newDirectives) {
3243 // Note that it is possible for outerpc != this->pc_, as we may be
3244 // attempting to syntax parse an inner function from an outer full
3245 // parser. In that case, outerpc is a SourceParseContext from the full parser
3246 // instead of the current top of the stack of the syntax parser.
3248 // Push a new ParseContext.
3249 SourceParseContext funpc(this, funbox, newDirectives);
3250 if (!funpc.init()) {
3251 return errorResult();
3254 if (!functionFormalParametersAndBody(inHandling, yieldHandling, &funNode,
3255 kind)) {
3256 return errorResult();
3259 if (!leaveInnerFunction(outerpc)) {
3260 return errorResult();
3263 return funNode;
3266 template <class ParseHandler, typename Unit>
3267 typename ParseHandler::FunctionNodeResult
3268 GeneralParser<ParseHandler, Unit>::innerFunction(
3269 FunctionNodeType funNode, ParseContext* outerpc,
3270 TaggedParserAtomIndex explicitName, FunctionFlags flags,
3271 uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling,
3272 FunctionSyntaxKind kind, GeneratorKind generatorKind,
3273 FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives,
3274 Directives* newDirectives) {
3275 // Note that it is possible for outerpc != this->pc_, as we may be
3276 // attempting to syntax parse an inner function from an outer full
3277 // parser. In that case, outerpc is a SourceParseContext from the full parser
3278 // instead of the current top of the stack of the syntax parser.
3280 FunctionBox* funbox =
3281 newFunctionBox(funNode, explicitName, flags, toStringStart,
3282 inheritedDirectives, generatorKind, asyncKind);
3283 if (!funbox) {
3284 return errorResult();
3286 funbox->initWithEnclosingParseContext(outerpc, kind);
3288 FunctionNodeType innerFunc;
3289 MOZ_TRY_VAR(innerFunc,
3290 innerFunctionForFunctionBox(funNode, outerpc, funbox, inHandling,
3291 yieldHandling, kind, newDirectives));
3293 // Append possible Annex B function box only upon successfully parsing.
3294 if (tryAnnexB) {
3295 if (!pc_->innermostScope()->addPossibleAnnexBFunctionBox(pc_, funbox)) {
3296 return errorResult();
3300 return innerFunc;
3303 template <class ParseHandler, typename Unit>
3304 bool GeneralParser<ParseHandler, Unit>::appendToCallSiteObj(
3305 CallSiteNodeType callSiteObj) {
3306 Node cookedNode;
3307 MOZ_TRY_VAR_OR_RETURN(cookedNode, noSubstitutionTaggedTemplate(), false);
3309 auto atom = tokenStream.getRawTemplateStringAtom();
3310 if (!atom) {
3311 return false;
3313 NameNodeType rawNode;
3314 MOZ_TRY_VAR_OR_RETURN(rawNode, handler_.newTemplateStringLiteral(atom, pos()),
3315 false);
3317 handler_.addToCallSiteObject(callSiteObj, rawNode, cookedNode);
3318 return true;
3321 template <typename Unit>
3322 FullParseHandler::FunctionNodeResult
3323 Parser<FullParseHandler, Unit>::standaloneLazyFunction(
3324 CompilationInput& input, uint32_t toStringStart, bool strict,
3325 GeneratorKind generatorKind, FunctionAsyncKind asyncKind) {
3326 MOZ_ASSERT(checkOptionsCalled_);
3328 FunctionSyntaxKind syntaxKind = input.functionSyntaxKind();
3329 FunctionNodeType funNode;
3330 MOZ_TRY_VAR(funNode, handler_.newFunction(syntaxKind, pos()));
3332 TaggedParserAtomIndex displayAtom =
3333 this->getCompilationState().previousParseCache.displayAtom();
3335 Directives directives(strict);
3336 FunctionBox* funbox =
3337 newFunctionBox(funNode, displayAtom, input.functionFlags(), toStringStart,
3338 directives, generatorKind, asyncKind);
3339 if (!funbox) {
3340 return errorResult();
3342 const ScriptStencilExtra& funExtra =
3343 this->getCompilationState().previousParseCache.funExtra();
3344 funbox->initFromLazyFunction(
3345 funExtra, this->getCompilationState().scopeContext, syntaxKind);
3346 if (funbox->useMemberInitializers()) {
3347 funbox->setMemberInitializers(funExtra.memberInitializers());
3350 Directives newDirectives = directives;
3351 SourceParseContext funpc(this, funbox, &newDirectives);
3352 if (!funpc.init()) {
3353 return errorResult();
3356 // Our tokenStream has no current token, so funNode's position is garbage.
3357 // Substitute the position of the first token in our source. If the
3358 // function is a not-async arrow, use TokenStream::SlashIsRegExp to keep
3359 // verifyConsistentModifier from complaining (we will use
3360 // TokenStream::SlashIsRegExp in functionArguments).
3361 Modifier modifier = (input.functionFlags().isArrow() &&
3362 asyncKind == FunctionAsyncKind::SyncFunction)
3363 ? TokenStream::SlashIsRegExp
3364 : TokenStream::SlashIsDiv;
3365 if (!tokenStream.peekTokenPos(&funNode->pn_pos, modifier)) {
3366 return errorResult();
3369 YieldHandling yieldHandling = GetYieldHandling(generatorKind);
3371 if (funbox->isSyntheticFunction()) {
3372 // Currently default class constructors are the only synthetic function that
3373 // supports delazification.
3374 MOZ_ASSERT(funbox->isClassConstructor());
3375 MOZ_ASSERT(funbox->extent().toStringStart == funbox->extent().sourceStart);
3377 HasHeritage hasHeritage = funbox->isDerivedClassConstructor()
3378 ? HasHeritage::Yes
3379 : HasHeritage::No;
3380 TokenPos synthesizedBodyPos(funbox->extent().toStringStart,
3381 funbox->extent().toStringEnd);
3383 // Reset pos() to the `class` keyword for predictable results.
3384 tokenStream.consumeKnownToken(TokenKind::Class);
3386 if (!this->synthesizeConstructorBody(synthesizedBodyPos, hasHeritage,
3387 funNode, funbox)) {
3388 return errorResult();
3390 } else {
3391 if (!functionFormalParametersAndBody(InAllowed, yieldHandling, &funNode,
3392 syntaxKind)) {
3393 MOZ_ASSERT(directives == newDirectives);
3394 return errorResult();
3398 if (!CheckParseTree(this->fc_, alloc_, funNode)) {
3399 return errorResult();
3402 ParseNode* node = funNode;
3403 // Don't constant-fold inside "use asm" code, as this could create a parse
3404 // tree that doesn't type-check as asm.js.
3405 if (!pc_->useAsmOrInsideUseAsm()) {
3406 if (!FoldConstants(this->fc_, this->parserAtoms(), &node, &handler_)) {
3407 return errorResult();
3410 funNode = &node->as<FunctionNode>();
3412 return funNode;
3415 void ParserBase::setFunctionEndFromCurrentToken(FunctionBox* funbox) const {
3416 if (compilationState_.isInitialStencil()) {
3417 MOZ_ASSERT(anyChars.currentToken().type != TokenKind::Eof);
3418 MOZ_ASSERT(anyChars.currentToken().type < TokenKind::Limit);
3419 funbox->setEnd(anyChars.currentToken().pos.end);
3420 } else {
3421 // If we're delazifying an arrow function with expression body and
3422 // the expression is also a function, we arrive here immediately after
3423 // skipping the function by Parser::skipLazyInnerFunction.
3425 // a => b => c
3426 // ^
3427 // |
3428 // we're here
3430 // In that case, the current token's type field is either Limit or
3431 // poisoned.
3432 // We shouldn't read the value if it's poisoned.
3433 // See TokenStreamSpecific<Unit, AnyCharsAccess>::advance and
3434 // mfbt/MemoryChecking.h for more details.
3436 // Also, in delazification, the FunctionBox should already have the
3437 // correct extent, and we shouldn't overwrite it here.
3438 // See ScriptStencil variant of PerHandlerParser::newFunctionBox.
3439 #if !defined(MOZ_ASAN) && !defined(MOZ_MSAN) && !defined(MOZ_VALGRIND)
3440 MOZ_ASSERT(anyChars.currentToken().type != TokenKind::Eof);
3441 #endif
3442 MOZ_ASSERT(funbox->extent().sourceEnd == anyChars.currentToken().pos.end);
3446 template <class ParseHandler, typename Unit>
3447 bool GeneralParser<ParseHandler, Unit>::functionFormalParametersAndBody(
3448 InHandling inHandling, YieldHandling yieldHandling,
3449 FunctionNodeType* funNode, FunctionSyntaxKind kind,
3450 const Maybe<uint32_t>& parameterListEnd /* = Nothing() */,
3451 bool isStandaloneFunction /* = false */) {
3452 // Given a properly initialized parse context, try to parse an actual
3453 // function without concern for conversion to strict mode, use of lazy
3454 // parsing and such.
3456 FunctionBox* funbox = pc_->functionBox();
3458 if (kind == FunctionSyntaxKind::ClassConstructor ||
3459 kind == FunctionSyntaxKind::DerivedClassConstructor) {
3460 if (!noteUsedName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
3461 return false;
3465 // See below for an explanation why arrow function parameters and arrow
3466 // function bodies are parsed with different yield/await settings.
3468 AwaitHandling awaitHandling =
3469 kind == FunctionSyntaxKind::StaticClassBlock ? AwaitIsDisallowed
3470 : (funbox->isAsync() ||
3471 (kind == FunctionSyntaxKind::Arrow && awaitIsKeyword()))
3472 ? AwaitIsKeyword
3473 : AwaitIsName;
3474 AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(this, awaitHandling);
3475 AutoInParametersOfAsyncFunction<ParseHandler, Unit> inParameters(
3476 this, funbox->isAsync());
3477 if (!functionArguments(yieldHandling, kind, *funNode)) {
3478 return false;
3482 Maybe<ParseContext::VarScope> varScope;
3483 if (funbox->hasParameterExprs) {
3484 varScope.emplace(this);
3485 if (!varScope->init(pc_)) {
3486 return false;
3488 } else {
3489 pc_->functionScope().useAsVarScope(pc_);
3492 if (kind == FunctionSyntaxKind::Arrow) {
3493 TokenKind tt;
3494 if (!tokenStream.peekTokenSameLine(&tt)) {
3495 return false;
3498 if (tt == TokenKind::Eol) {
3499 error(JSMSG_UNEXPECTED_TOKEN,
3500 "'=>' on the same line after an argument list",
3501 TokenKindToDesc(tt));
3502 return false;
3504 if (tt != TokenKind::Arrow) {
3505 error(JSMSG_BAD_ARROW_ARGS);
3506 return false;
3508 tokenStream.consumeKnownToken(TokenKind::Arrow);
3511 // When parsing something for new Function() we have to make sure to
3512 // only treat a certain part of the source as a parameter list.
3513 if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) {
3514 error(JSMSG_UNEXPECTED_PARAMLIST_END);
3515 return false;
3518 // Parse the function body.
3519 FunctionBodyType bodyType = StatementListBody;
3520 TokenKind tt;
3521 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
3522 return false;
3524 uint32_t openedPos = 0;
3525 if (tt != TokenKind::LeftCurly) {
3526 if (kind != FunctionSyntaxKind::Arrow) {
3527 error(JSMSG_CURLY_BEFORE_BODY);
3528 return false;
3531 anyChars.ungetToken();
3532 bodyType = ExpressionBody;
3533 funbox->setHasExprBody();
3534 } else {
3535 openedPos = pos().begin;
3538 // Arrow function parameters inherit yieldHandling from the enclosing
3539 // context, but the arrow body doesn't. E.g. in |(a = yield) => yield|,
3540 // |yield| in the parameters is either a name or keyword, depending on
3541 // whether the arrow function is enclosed in a generator function or not.
3542 // Whereas the |yield| in the function body is always parsed as a name.
3543 // The same goes when parsing |await| in arrow functions.
3544 YieldHandling bodyYieldHandling = GetYieldHandling(pc_->generatorKind());
3545 AwaitHandling bodyAwaitHandling = GetAwaitHandling(pc_->asyncKind());
3546 bool inheritedStrict = pc_->sc()->strict();
3547 LexicalScopeNodeType body;
3549 AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(this,
3550 bodyAwaitHandling);
3551 AutoInParametersOfAsyncFunction<ParseHandler, Unit> inParameters(this,
3552 false);
3553 MOZ_TRY_VAR_OR_RETURN(
3554 body, functionBody(inHandling, bodyYieldHandling, kind, bodyType),
3555 false);
3558 // Revalidate the function name when we transitioned to strict mode.
3559 if ((kind == FunctionSyntaxKind::Statement ||
3560 kind == FunctionSyntaxKind::Expression) &&
3561 funbox->explicitName() && !inheritedStrict && pc_->sc()->strict()) {
3562 MOZ_ASSERT(pc_->sc()->hasExplicitUseStrict(),
3563 "strict mode should only change when a 'use strict' directive "
3564 "is present");
3566 auto propertyName = funbox->explicitName();
3567 YieldHandling nameYieldHandling;
3568 if (kind == FunctionSyntaxKind::Expression) {
3569 // Named lambda has binding inside it.
3570 nameYieldHandling = bodyYieldHandling;
3571 } else {
3572 // Otherwise YieldHandling cannot be checked at this point
3573 // because of different context.
3574 // It should already be checked before this point.
3575 nameYieldHandling = YieldIsName;
3578 // We already use the correct await-handling at this point, therefore
3579 // we don't need call AutoAwaitIsKeyword here.
3581 uint32_t nameOffset = handler_.getFunctionNameOffset(*funNode, anyChars);
3582 if (!checkBindingIdentifier(propertyName, nameOffset, nameYieldHandling)) {
3583 return false;
3587 if (bodyType == StatementListBody) {
3588 // Cannot use mustMatchToken here because of internal compiler error on
3589 // gcc 6.4.0, with linux 64 SM hazard build.
3590 TokenKind actual;
3591 if (!tokenStream.getToken(&actual, TokenStream::SlashIsRegExp)) {
3592 return false;
3594 if (actual != TokenKind::RightCurly) {
3595 reportMissingClosing(JSMSG_CURLY_AFTER_BODY, JSMSG_CURLY_OPENED,
3596 openedPos);
3597 return false;
3600 setFunctionEndFromCurrentToken(funbox);
3601 } else {
3602 MOZ_ASSERT(kind == FunctionSyntaxKind::Arrow);
3604 if (anyChars.hadError()) {
3605 return false;
3608 setFunctionEndFromCurrentToken(funbox);
3610 if (kind == FunctionSyntaxKind::Statement) {
3611 if (!matchOrInsertSemicolon()) {
3612 return false;
3617 if (IsMethodDefinitionKind(kind) && pc_->superScopeNeedsHomeObject()) {
3618 funbox->setNeedsHomeObject();
3621 if (!finishFunction(isStandaloneFunction)) {
3622 return false;
3625 handler_.setEndPosition(body, pos().begin);
3626 handler_.setEndPosition(*funNode, pos().end);
3627 handler_.setFunctionBody(*funNode, body);
3629 return true;
3632 template <class ParseHandler, typename Unit>
3633 typename ParseHandler::FunctionNodeResult
3634 GeneralParser<ParseHandler, Unit>::functionStmt(uint32_t toStringStart,
3635 YieldHandling yieldHandling,
3636 DefaultHandling defaultHandling,
3637 FunctionAsyncKind asyncKind) {
3638 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
3640 // In sloppy mode, Annex B.3.2 allows labelled function declarations.
3641 // Otherwise it's a parse error.
3642 ParseContext::Statement* declaredInStmt = pc_->innermostStatement();
3643 if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
3644 MOZ_ASSERT(!pc_->sc()->strict(),
3645 "labeled functions shouldn't be parsed in strict mode");
3647 // Find the innermost non-label statement. Report an error if it's
3648 // unbraced: functions can't appear in it. Otherwise the statement
3649 // (or its absence) determines the scope the function's bound in.
3650 while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
3651 declaredInStmt = declaredInStmt->enclosing();
3654 if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) {
3655 error(JSMSG_SLOPPY_FUNCTION_LABEL);
3656 return errorResult();
3660 TokenKind tt;
3661 if (!tokenStream.getToken(&tt)) {
3662 return errorResult();
3665 GeneratorKind generatorKind = GeneratorKind::NotGenerator;
3666 if (tt == TokenKind::Mul) {
3667 generatorKind = GeneratorKind::Generator;
3668 if (!tokenStream.getToken(&tt)) {
3669 return errorResult();
3673 TaggedParserAtomIndex name;
3674 if (TokenKindIsPossibleIdentifier(tt)) {
3675 name = bindingIdentifier(yieldHandling);
3676 if (!name) {
3677 return errorResult();
3679 } else if (defaultHandling == AllowDefaultName) {
3680 name = TaggedParserAtomIndex::WellKnown::default_();
3681 anyChars.ungetToken();
3682 } else {
3683 /* Unnamed function expressions are forbidden in statement context. */
3684 error(JSMSG_UNNAMED_FUNCTION_STMT);
3685 return errorResult();
3688 // Note the declared name and check for early errors.
3689 DeclarationKind kind;
3690 if (declaredInStmt) {
3691 MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
3692 MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
3694 kind =
3695 (!pc_->sc()->strict() && generatorKind == GeneratorKind::NotGenerator &&
3696 asyncKind == FunctionAsyncKind::SyncFunction)
3697 ? DeclarationKind::SloppyLexicalFunction
3698 : DeclarationKind::LexicalFunction;
3699 } else {
3700 kind = pc_->atModuleLevel() ? DeclarationKind::ModuleBodyLevelFunction
3701 : DeclarationKind::BodyLevelFunction;
3704 if (!noteDeclaredName(name, kind, pos())) {
3705 return errorResult();
3708 FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Statement;
3709 FunctionNodeType funNode;
3710 MOZ_TRY_VAR(funNode, handler_.newFunction(syntaxKind, pos()));
3712 // Under sloppy mode, try Annex B.3.3 semantics. If making an additional
3713 // 'var' binding of the same name does not throw an early error, do so.
3714 // This 'var' binding would be assigned the function object when its
3715 // declaration is reached, not at the start of the block.
3717 // This semantics is implemented upon Scope exit in
3718 // Scope::propagateAndMarkAnnexBFunctionBoxes.
3719 bool tryAnnexB = kind == DeclarationKind::SloppyLexicalFunction;
3721 YieldHandling newYieldHandling = GetYieldHandling(generatorKind);
3722 return functionDefinition(funNode, toStringStart, InAllowed, newYieldHandling,
3723 name, syntaxKind, generatorKind, asyncKind,
3724 tryAnnexB);
3727 template <class ParseHandler, typename Unit>
3728 typename ParseHandler::FunctionNodeResult
3729 GeneralParser<ParseHandler, Unit>::functionExpr(uint32_t toStringStart,
3730 InvokedPrediction invoked,
3731 FunctionAsyncKind asyncKind) {
3732 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
3734 AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(
3735 this, GetAwaitHandling(asyncKind));
3736 GeneratorKind generatorKind = GeneratorKind::NotGenerator;
3737 TokenKind tt;
3738 if (!tokenStream.getToken(&tt)) {
3739 return errorResult();
3742 if (tt == TokenKind::Mul) {
3743 generatorKind = GeneratorKind::Generator;
3744 if (!tokenStream.getToken(&tt)) {
3745 return errorResult();
3749 YieldHandling yieldHandling = GetYieldHandling(generatorKind);
3751 TaggedParserAtomIndex name;
3752 if (TokenKindIsPossibleIdentifier(tt)) {
3753 name = bindingIdentifier(yieldHandling);
3754 if (!name) {
3755 return errorResult();
3757 } else {
3758 anyChars.ungetToken();
3761 FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Expression;
3762 FunctionNodeType funNode;
3763 MOZ_TRY_VAR(funNode, handler_.newFunction(syntaxKind, pos()));
3765 if (invoked) {
3766 funNode = handler_.setLikelyIIFE(funNode);
3769 return functionDefinition(funNode, toStringStart, InAllowed, yieldHandling,
3770 name, syntaxKind, generatorKind, asyncKind);
3774 * Return true if this node, known to be an unparenthesized string literal
3775 * that never contain escape sequences, could be the string of a directive in a
3776 * Directive Prologue. Directive strings never contain escape sequences or line
3777 * continuations.
3779 static inline bool IsUseStrictDirective(const TokenPos& pos,
3780 TaggedParserAtomIndex atom) {
3781 // the length of "use strict", including quotation.
3782 static constexpr size_t useStrictLength = 12;
3783 return atom == TaggedParserAtomIndex::WellKnown::use_strict_() &&
3784 pos.begin + useStrictLength == pos.end;
3786 static inline bool IsUseAsmDirective(const TokenPos& pos,
3787 TaggedParserAtomIndex atom) {
3788 // the length of "use asm", including quotation.
3789 static constexpr size_t useAsmLength = 9;
3790 return atom == TaggedParserAtomIndex::WellKnown::use_asm_() &&
3791 pos.begin + useAsmLength == pos.end;
3794 template <typename Unit>
3795 bool Parser<SyntaxParseHandler, Unit>::asmJS(ListNodeType list) {
3796 // While asm.js could technically be validated and compiled during syntax
3797 // parsing, we have no guarantee that some later JS wouldn't abort the
3798 // syntax parse and cause us to re-parse (and re-compile) the asm.js module.
3799 // For simplicity, unconditionally abort the syntax parse when "use asm" is
3800 // encountered so that asm.js is always validated/compiled exactly once
3801 // during a full parse.
3802 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
3803 return false;
3806 template <typename Unit>
3807 bool Parser<FullParseHandler, Unit>::asmJS(ListNodeType list) {
3808 // Disable syntax parsing in anything nested inside the asm.js module.
3809 disableSyntaxParser();
3811 // We should be encountering the "use asm" directive for the first time; if
3812 // the directive is already, we must have failed asm.js validation and we're
3813 // reparsing. In that case, don't try to validate again. A non-null
3814 // newDirectives means we're not in a normal function.
3815 if (!pc_->newDirectives || pc_->newDirectives->asmJS()) {
3816 return true;
3819 // If there is no ScriptSource, then we are doing a non-compiling parse and
3820 // so we shouldn't (and can't, without a ScriptSource) compile.
3821 if (ss == nullptr) {
3822 return true;
3825 pc_->functionBox()->useAsm = true;
3827 // Attempt to validate and compile this asm.js module. On success, the
3828 // tokenStream has been advanced to the closing }. On failure, the
3829 // tokenStream is in an indeterminate state and we must reparse the
3830 // function from the beginning. Reparsing is triggered by marking that a
3831 // new directive has been encountered and returning 'false'.
3832 bool validated;
3833 if (!CompileAsmJS(this->fc_, this->parserAtoms(), *this, list, &validated)) {
3834 return false;
3836 if (!validated) {
3837 pc_->newDirectives->setAsmJS();
3838 return false;
3841 return true;
3844 template <class ParseHandler, typename Unit>
3845 inline bool GeneralParser<ParseHandler, Unit>::asmJS(ListNodeType list) {
3846 return asFinalParser()->asmJS(list);
3850 * Recognize Directive Prologue members and directives. Assuming |pn| is a
3851 * candidate for membership in a directive prologue, recognize directives and
3852 * set |pc_|'s flags accordingly. If |pn| is indeed part of a prologue, set its
3853 * |prologue| flag.
3855 * Note that the following is a strict mode function:
3857 * function foo() {
3858 * "blah" // inserted semi colon
3859 * "blurgh"
3860 * "use\x20loose"
3861 * "use strict"
3864 * That is, even though "use\x20loose" can never be a directive, now or in the
3865 * future (because of the hex escape), the Directive Prologue extends through it
3866 * to the "use strict" statement, which is indeed a directive.
3868 template <class ParseHandler, typename Unit>
3869 bool GeneralParser<ParseHandler, Unit>::maybeParseDirective(
3870 ListNodeType list, Node possibleDirective, bool* cont) {
3871 TokenPos directivePos;
3872 TaggedParserAtomIndex directive =
3873 handler_.isStringExprStatement(possibleDirective, &directivePos);
3875 *cont = !!directive;
3876 if (!*cont) {
3877 return true;
3880 if (IsUseStrictDirective(directivePos, directive)) {
3881 // Functions with non-simple parameter lists (destructuring,
3882 // default or rest parameters) must not contain a "use strict"
3883 // directive.
3884 if (pc_->isFunctionBox()) {
3885 FunctionBox* funbox = pc_->functionBox();
3886 if (!funbox->hasSimpleParameterList()) {
3887 const char* parameterKind = funbox->hasDestructuringArgs
3888 ? "destructuring"
3889 : funbox->hasParameterExprs ? "default"
3890 : "rest";
3891 errorAt(directivePos.begin, JSMSG_STRICT_NON_SIMPLE_PARAMS,
3892 parameterKind);
3893 return false;
3897 // We're going to be in strict mode. Note that this scope explicitly
3898 // had "use strict";
3899 pc_->sc()->setExplicitUseStrict();
3900 if (!pc_->sc()->strict()) {
3901 // Some strict mode violations can appear before a Use Strict Directive
3902 // is applied. (See the |DeprecatedContent| enum initializers.) These
3903 // violations can manifest in two ways.
3905 // First, the violation can appear *before* the Use Strict Directive.
3906 // Numeric literals (and therefore octal literals) can only precede a
3907 // Use Strict Directive if this function's parameter list is not simple,
3908 // but we reported an error for non-simple parameter lists above, so
3909 // octal literals present no issue. But octal escapes and \8 and \9 can
3910 // appear in the directive prologue before a Use Strict Directive:
3912 // function f()
3913 // {
3914 // "hell\157 world"; // octal escape
3915 // "\8"; "\9"; // NonOctalDecimalEscape
3916 // "use strict"; // retroactively makes all the above errors
3917 // }
3919 // Second, the violation can appear *after* the Use Strict Directive but
3920 // *before* the directive is recognized as terminated. This only
3921 // happens when a directive is terminated by ASI, and the next token
3922 // contains a violation:
3924 // function a()
3925 // {
3926 // "use strict" // ASI
3927 // 0755;
3928 // }
3929 // function b()
3930 // {
3931 // "use strict" // ASI
3932 // "hell\157 world";
3933 // }
3934 // function c()
3935 // {
3936 // "use strict" // ASI
3937 // "\8";
3938 // }
3940 // We note such violations when tokenizing. Then, if a violation has
3941 // been observed at the time a "use strict" is applied, we report the
3942 // error.
3943 switch (anyChars.sawDeprecatedContent()) {
3944 case DeprecatedContent::None:
3945 break;
3946 case DeprecatedContent::OctalLiteral:
3947 error(JSMSG_DEPRECATED_OCTAL_LITERAL);
3948 return false;
3949 case DeprecatedContent::OctalEscape:
3950 error(JSMSG_DEPRECATED_OCTAL_ESCAPE);
3951 return false;
3952 case DeprecatedContent::EightOrNineEscape:
3953 error(JSMSG_DEPRECATED_EIGHT_OR_NINE_ESCAPE);
3954 return false;
3957 pc_->sc()->setStrictScript();
3959 } else if (IsUseAsmDirective(directivePos, directive)) {
3960 if (pc_->isFunctionBox()) {
3961 return asmJS(list);
3963 return warningAt(directivePos.begin, JSMSG_USE_ASM_DIRECTIVE_FAIL);
3965 return true;
3968 template <class ParseHandler, typename Unit>
3969 typename ParseHandler::ListNodeResult
3970 GeneralParser<ParseHandler, Unit>::statementList(YieldHandling yieldHandling) {
3971 AutoCheckRecursionLimit recursion(this->fc_);
3972 if (!recursion.check(this->fc_)) {
3973 return errorResult();
3976 ListNodeType stmtList;
3977 MOZ_TRY_VAR(stmtList, handler_.newStatementList(pos()));
3979 bool canHaveDirectives = pc_->atBodyLevel();
3980 if (canHaveDirectives) {
3981 // Clear flags for deprecated content that might have been seen in an
3982 // enclosing context.
3983 anyChars.clearSawDeprecatedContent();
3986 bool canHaveHashbangComment = pc_->atTopLevel();
3987 if (canHaveHashbangComment) {
3988 tokenStream.consumeOptionalHashbangComment();
3991 bool afterReturn = false;
3992 bool warnedAboutStatementsAfterReturn = false;
3993 uint32_t statementBegin = 0;
3994 for (;;) {
3995 TokenKind tt = TokenKind::Eof;
3996 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
3997 if (anyChars.isEOF()) {
3998 isUnexpectedEOF_ = true;
4000 return errorResult();
4002 if (tt == TokenKind::Eof || tt == TokenKind::RightCurly) {
4003 TokenPos pos;
4004 if (!tokenStream.peekTokenPos(&pos, TokenStream::SlashIsRegExp)) {
4005 return errorResult();
4007 handler_.setListEndPosition(stmtList, pos);
4008 break;
4010 if (afterReturn) {
4011 if (!tokenStream.peekOffset(&statementBegin,
4012 TokenStream::SlashIsRegExp)) {
4013 return errorResult();
4016 auto nextResult = statementListItem(yieldHandling, canHaveDirectives);
4017 if (nextResult.isErr()) {
4018 if (anyChars.isEOF()) {
4019 isUnexpectedEOF_ = true;
4021 return errorResult();
4023 Node next = nextResult.unwrap();
4024 if (!warnedAboutStatementsAfterReturn) {
4025 if (afterReturn) {
4026 if (!handler_.isStatementPermittedAfterReturnStatement(next)) {
4027 if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) {
4028 return errorResult();
4031 warnedAboutStatementsAfterReturn = true;
4033 } else if (handler_.isReturnStatement(next)) {
4034 afterReturn = true;
4038 if (canHaveDirectives) {
4039 if (!maybeParseDirective(stmtList, next, &canHaveDirectives)) {
4040 return errorResult();
4044 handler_.addStatementToList(stmtList, next);
4047 return stmtList;
4050 template <class ParseHandler, typename Unit>
4051 typename ParseHandler::NodeResult GeneralParser<ParseHandler, Unit>::condition(
4052 InHandling inHandling, YieldHandling yieldHandling) {
4053 if (!mustMatchToken(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_COND)) {
4054 return errorResult();
4057 Node pn;
4058 MOZ_TRY_VAR(pn, exprInParens(inHandling, yieldHandling, TripledotProhibited));
4060 if (!mustMatchToken(TokenKind::RightParen, JSMSG_PAREN_AFTER_COND)) {
4061 return errorResult();
4064 return pn;
4067 template <class ParseHandler, typename Unit>
4068 bool GeneralParser<ParseHandler, Unit>::matchLabel(
4069 YieldHandling yieldHandling, TaggedParserAtomIndex* labelOut) {
4070 MOZ_ASSERT(labelOut != nullptr);
4071 TokenKind tt = TokenKind::Eof;
4072 if (!tokenStream.peekTokenSameLine(&tt, TokenStream::SlashIsRegExp)) {
4073 return false;
4076 if (TokenKindIsPossibleIdentifier(tt)) {
4077 tokenStream.consumeKnownToken(tt, TokenStream::SlashIsRegExp);
4079 *labelOut = labelIdentifier(yieldHandling);
4080 if (!*labelOut) {
4081 return false;
4083 } else {
4084 *labelOut = TaggedParserAtomIndex::null();
4086 return true;
4089 template <class ParseHandler, typename Unit>
4090 GeneralParser<ParseHandler, Unit>::PossibleError::PossibleError(
4091 GeneralParser<ParseHandler, Unit>& parser)
4092 : parser_(parser) {}
4094 template <class ParseHandler, typename Unit>
4095 typename GeneralParser<ParseHandler, Unit>::PossibleError::Error&
4096 GeneralParser<ParseHandler, Unit>::PossibleError::error(ErrorKind kind) {
4097 if (kind == ErrorKind::Expression) {
4098 return exprError_;
4100 if (kind == ErrorKind::Destructuring) {
4101 return destructuringError_;
4103 MOZ_ASSERT(kind == ErrorKind::DestructuringWarning);
4104 return destructuringWarning_;
4107 template <class ParseHandler, typename Unit>
4108 void GeneralParser<ParseHandler, Unit>::PossibleError::setResolved(
4109 ErrorKind kind) {
4110 error(kind).state_ = ErrorState::None;
4113 template <class ParseHandler, typename Unit>
4114 bool GeneralParser<ParseHandler, Unit>::PossibleError::hasError(
4115 ErrorKind kind) {
4116 return error(kind).state_ == ErrorState::Pending;
4119 template <class ParseHandler, typename Unit>
4120 bool GeneralParser<ParseHandler,
4121 Unit>::PossibleError::hasPendingDestructuringError() {
4122 return hasError(ErrorKind::Destructuring);
4125 template <class ParseHandler, typename Unit>
4126 void GeneralParser<ParseHandler, Unit>::PossibleError::setPending(
4127 ErrorKind kind, const TokenPos& pos, unsigned errorNumber) {
4128 // Don't overwrite a previously recorded error.
4129 if (hasError(kind)) {
4130 return;
4133 // If we report an error later, we'll do it from the position where we set
4134 // the state to pending.
4135 Error& err = error(kind);
4136 err.offset_ = pos.begin;
4137 err.errorNumber_ = errorNumber;
4138 err.state_ = ErrorState::Pending;
4141 template <class ParseHandler, typename Unit>
4142 void GeneralParser<ParseHandler, Unit>::PossibleError::
4143 setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber) {
4144 setPending(ErrorKind::Destructuring, pos, errorNumber);
4147 template <class ParseHandler, typename Unit>
4148 void GeneralParser<ParseHandler, Unit>::PossibleError::
4149 setPendingDestructuringWarningAt(const TokenPos& pos,
4150 unsigned errorNumber) {
4151 setPending(ErrorKind::DestructuringWarning, pos, errorNumber);
4154 template <class ParseHandler, typename Unit>
4155 void GeneralParser<ParseHandler, Unit>::PossibleError::
4156 setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber) {
4157 setPending(ErrorKind::Expression, pos, errorNumber);
4160 template <class ParseHandler, typename Unit>
4161 bool GeneralParser<ParseHandler, Unit>::PossibleError::checkForError(
4162 ErrorKind kind) {
4163 if (!hasError(kind)) {
4164 return true;
4167 Error& err = error(kind);
4168 parser_.errorAt(err.offset_, err.errorNumber_);
4169 return false;
4172 template <class ParseHandler, typename Unit>
4173 bool GeneralParser<ParseHandler,
4174 Unit>::PossibleError::checkForDestructuringErrorOrWarning() {
4175 // Clear pending expression error, because we're definitely not in an
4176 // expression context.
4177 setResolved(ErrorKind::Expression);
4179 // Report any pending destructuring error.
4180 return checkForError(ErrorKind::Destructuring);
4183 template <class ParseHandler, typename Unit>
4184 bool GeneralParser<ParseHandler,
4185 Unit>::PossibleError::checkForExpressionError() {
4186 // Clear pending destructuring error, because we're definitely not
4187 // in a destructuring context.
4188 setResolved(ErrorKind::Destructuring);
4189 setResolved(ErrorKind::DestructuringWarning);
4191 // Report any pending expression error.
4192 return checkForError(ErrorKind::Expression);
4195 template <class ParseHandler, typename Unit>
4196 void GeneralParser<ParseHandler, Unit>::PossibleError::transferErrorTo(
4197 ErrorKind kind, PossibleError* other) {
4198 if (hasError(kind) && !other->hasError(kind)) {
4199 Error& err = error(kind);
4200 Error& otherErr = other->error(kind);
4201 otherErr.offset_ = err.offset_;
4202 otherErr.errorNumber_ = err.errorNumber_;
4203 otherErr.state_ = err.state_;
4207 template <class ParseHandler, typename Unit>
4208 void GeneralParser<ParseHandler, Unit>::PossibleError::transferErrorsTo(
4209 PossibleError* other) {
4210 MOZ_ASSERT(other);
4211 MOZ_ASSERT(this != other);
4212 MOZ_ASSERT(&parser_ == &other->parser_,
4213 "Can't transfer fields to an instance which belongs to a "
4214 "different parser");
4216 transferErrorTo(ErrorKind::Destructuring, other);
4217 transferErrorTo(ErrorKind::Expression, other);
4220 template <class ParseHandler, typename Unit>
4221 typename ParseHandler::BinaryNodeResult
4222 GeneralParser<ParseHandler, Unit>::bindingInitializer(
4223 Node lhs, DeclarationKind kind, YieldHandling yieldHandling) {
4224 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Assign));
4226 if (kind == DeclarationKind::FormalParameter) {
4227 pc_->functionBox()->hasParameterExprs = true;
4230 Node rhs;
4231 MOZ_TRY_VAR(rhs, assignExpr(InAllowed, yieldHandling, TripledotProhibited));
4233 BinaryNodeType assign;
4234 MOZ_TRY_VAR(assign,
4235 handler_.newAssignment(ParseNodeKind::AssignExpr, lhs, rhs));
4237 return assign;
4240 template <class ParseHandler, typename Unit>
4241 typename ParseHandler::NameNodeResult
4242 GeneralParser<ParseHandler, Unit>::bindingIdentifier(
4243 DeclarationKind kind, YieldHandling yieldHandling) {
4244 TaggedParserAtomIndex name = bindingIdentifier(yieldHandling);
4245 if (!name) {
4246 return errorResult();
4249 NameNodeType binding;
4250 MOZ_TRY_VAR(binding, newName(name));
4251 if (!noteDeclaredName(name, kind, pos())) {
4252 return errorResult();
4255 return binding;
4258 template <class ParseHandler, typename Unit>
4259 typename ParseHandler::NodeResult
4260 GeneralParser<ParseHandler, Unit>::bindingIdentifierOrPattern(
4261 DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt) {
4262 if (tt == TokenKind::LeftBracket) {
4263 return arrayBindingPattern(kind, yieldHandling);
4266 if (tt == TokenKind::LeftCurly) {
4267 return objectBindingPattern(kind, yieldHandling);
4270 if (!TokenKindIsPossibleIdentifierName(tt)) {
4271 error(JSMSG_NO_VARIABLE_NAME);
4272 return errorResult();
4275 return bindingIdentifier(kind, yieldHandling);
4278 template <class ParseHandler, typename Unit>
4279 typename ParseHandler::ListNodeResult
4280 GeneralParser<ParseHandler, Unit>::objectBindingPattern(
4281 DeclarationKind kind, YieldHandling yieldHandling) {
4282 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
4284 AutoCheckRecursionLimit recursion(this->fc_);
4285 if (!recursion.check(this->fc_)) {
4286 return errorResult();
4289 uint32_t begin = pos().begin;
4290 ListNodeType literal;
4291 MOZ_TRY_VAR(literal, handler_.newObjectLiteral(begin));
4293 Maybe<DeclarationKind> declKind = Some(kind);
4294 TaggedParserAtomIndex propAtom;
4295 for (;;) {
4296 TokenKind tt;
4297 if (!tokenStream.peekToken(&tt)) {
4298 return errorResult();
4300 if (tt == TokenKind::RightCurly) {
4301 break;
4304 if (tt == TokenKind::TripleDot) {
4305 tokenStream.consumeKnownToken(TokenKind::TripleDot);
4306 uint32_t begin = pos().begin;
4308 TokenKind tt;
4309 if (!tokenStream.getToken(&tt)) {
4310 return errorResult();
4313 if (!TokenKindIsPossibleIdentifierName(tt)) {
4314 error(JSMSG_NO_VARIABLE_NAME);
4315 return errorResult();
4318 NameNodeType inner;
4319 MOZ_TRY_VAR(inner, bindingIdentifier(kind, yieldHandling));
4321 if (!handler_.addSpreadProperty(literal, begin, inner)) {
4322 return errorResult();
4324 } else {
4325 TokenPos namePos = anyChars.nextToken().pos;
4327 PropertyType propType;
4328 Node propName;
4329 MOZ_TRY_VAR(propName, propertyOrMethodName(
4330 yieldHandling, PropertyNameInPattern, declKind,
4331 literal, &propType, &propAtom));
4333 if (propType == PropertyType::Normal) {
4334 // Handle e.g., |var {p: x} = o| and |var {p: x=0} = o|.
4336 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
4337 return errorResult();
4340 Node binding;
4341 MOZ_TRY_VAR(binding,
4342 bindingIdentifierOrPattern(kind, yieldHandling, tt));
4344 bool hasInitializer;
4345 if (!tokenStream.matchToken(&hasInitializer, TokenKind::Assign,
4346 TokenStream::SlashIsRegExp)) {
4347 return errorResult();
4350 Node bindingExpr;
4351 if (hasInitializer) {
4352 MOZ_TRY_VAR(bindingExpr,
4353 bindingInitializer(binding, kind, yieldHandling));
4354 } else {
4355 bindingExpr = binding;
4358 if (!handler_.addPropertyDefinition(literal, propName, bindingExpr)) {
4359 return errorResult();
4361 } else if (propType == PropertyType::Shorthand) {
4362 // Handle e.g., |var {x, y} = o| as destructuring shorthand
4363 // for |var {x: x, y: y} = o|.
4364 MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
4366 NameNodeType binding;
4367 MOZ_TRY_VAR(binding, bindingIdentifier(kind, yieldHandling));
4369 if (!handler_.addShorthand(literal, handler_.asNameNode(propName),
4370 binding)) {
4371 return errorResult();
4373 } else if (propType == PropertyType::CoverInitializedName) {
4374 // Handle e.g., |var {x=1, y=2} = o| as destructuring
4375 // shorthand with default values.
4376 MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
4378 NameNodeType binding;
4379 MOZ_TRY_VAR(binding, bindingIdentifier(kind, yieldHandling));
4381 tokenStream.consumeKnownToken(TokenKind::Assign);
4383 BinaryNodeType bindingExpr;
4384 MOZ_TRY_VAR(bindingExpr,
4385 bindingInitializer(binding, kind, yieldHandling));
4387 if (!handler_.addPropertyDefinition(literal, propName, bindingExpr)) {
4388 return errorResult();
4390 } else {
4391 errorAt(namePos.begin, JSMSG_NO_VARIABLE_NAME);
4392 return errorResult();
4396 bool matched;
4397 if (!tokenStream.matchToken(&matched, TokenKind::Comma,
4398 TokenStream::SlashIsInvalid)) {
4399 return errorResult();
4401 if (!matched) {
4402 break;
4404 if (tt == TokenKind::TripleDot) {
4405 error(JSMSG_REST_WITH_COMMA);
4406 return errorResult();
4410 if (!mustMatchToken(TokenKind::RightCurly, [this, begin](TokenKind actual) {
4411 this->reportMissingClosing(JSMSG_CURLY_AFTER_LIST, JSMSG_CURLY_OPENED,
4412 begin);
4413 })) {
4414 return errorResult();
4417 handler_.setEndPosition(literal, pos().end);
4418 return literal;
4421 template <class ParseHandler, typename Unit>
4422 typename ParseHandler::ListNodeResult
4423 GeneralParser<ParseHandler, Unit>::arrayBindingPattern(
4424 DeclarationKind kind, YieldHandling yieldHandling) {
4425 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
4427 AutoCheckRecursionLimit recursion(this->fc_);
4428 if (!recursion.check(this->fc_)) {
4429 return errorResult();
4432 uint32_t begin = pos().begin;
4433 ListNodeType literal;
4434 MOZ_TRY_VAR(literal, handler_.newArrayLiteral(begin));
4436 uint32_t index = 0;
4437 for (;; index++) {
4438 if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
4439 error(JSMSG_ARRAY_INIT_TOO_BIG);
4440 return errorResult();
4443 TokenKind tt;
4444 if (!tokenStream.getToken(&tt)) {
4445 return errorResult();
4448 if (tt == TokenKind::RightBracket) {
4449 anyChars.ungetToken();
4450 break;
4453 if (tt == TokenKind::Comma) {
4454 if (!handler_.addElision(literal, pos())) {
4455 return errorResult();
4457 } else if (tt == TokenKind::TripleDot) {
4458 uint32_t begin = pos().begin;
4460 TokenKind tt;
4461 if (!tokenStream.getToken(&tt)) {
4462 return errorResult();
4465 Node inner;
4466 MOZ_TRY_VAR(inner, bindingIdentifierOrPattern(kind, yieldHandling, tt));
4468 if (!handler_.addSpreadElement(literal, begin, inner)) {
4469 return errorResult();
4471 } else {
4472 Node binding;
4473 MOZ_TRY_VAR(binding, bindingIdentifierOrPattern(kind, yieldHandling, tt));
4475 bool hasInitializer;
4476 if (!tokenStream.matchToken(&hasInitializer, TokenKind::Assign,
4477 TokenStream::SlashIsRegExp)) {
4478 return errorResult();
4481 Node element;
4482 if (hasInitializer) {
4483 MOZ_TRY_VAR(element, bindingInitializer(binding, kind, yieldHandling));
4484 } else {
4485 element = binding;
4488 handler_.addArrayElement(literal, element);
4491 if (tt != TokenKind::Comma) {
4492 // If we didn't already match TokenKind::Comma in above case.
4493 bool matched;
4494 if (!tokenStream.matchToken(&matched, TokenKind::Comma,
4495 TokenStream::SlashIsRegExp)) {
4496 return errorResult();
4498 if (!matched) {
4499 break;
4502 if (tt == TokenKind::TripleDot) {
4503 error(JSMSG_REST_WITH_COMMA);
4504 return errorResult();
4509 if (!mustMatchToken(TokenKind::RightBracket, [this, begin](TokenKind actual) {
4510 this->reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
4511 JSMSG_BRACKET_OPENED, begin);
4512 })) {
4513 return errorResult();
4516 handler_.setEndPosition(literal, pos().end);
4517 return literal;
4520 template <class ParseHandler, typename Unit>
4521 typename ParseHandler::NodeResult
4522 GeneralParser<ParseHandler, Unit>::destructuringDeclaration(
4523 DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt) {
4524 MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
4525 MOZ_ASSERT(tt == TokenKind::LeftBracket || tt == TokenKind::LeftCurly);
4527 if (tt == TokenKind::LeftBracket) {
4528 return arrayBindingPattern(kind, yieldHandling);
4530 return objectBindingPattern(kind, yieldHandling);
4533 template <class ParseHandler, typename Unit>
4534 typename ParseHandler::NodeResult
4535 GeneralParser<ParseHandler, Unit>::destructuringDeclarationWithoutYieldOrAwait(
4536 DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt) {
4537 uint32_t startYieldOffset = pc_->lastYieldOffset;
4538 uint32_t startAwaitOffset = pc_->lastAwaitOffset;
4540 Node res;
4541 MOZ_TRY_VAR(res, destructuringDeclaration(kind, yieldHandling, tt));
4543 if (pc_->lastYieldOffset != startYieldOffset) {
4544 errorAt(pc_->lastYieldOffset, JSMSG_YIELD_IN_PARAMETER);
4545 return errorResult();
4547 if (pc_->lastAwaitOffset != startAwaitOffset) {
4548 errorAt(pc_->lastAwaitOffset, JSMSG_AWAIT_IN_PARAMETER);
4549 return errorResult();
4551 return res;
4554 template <class ParseHandler, typename Unit>
4555 typename ParseHandler::LexicalScopeNodeResult
4556 GeneralParser<ParseHandler, Unit>::blockStatement(YieldHandling yieldHandling,
4557 unsigned errorNumber) {
4558 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
4559 uint32_t openedPos = pos().begin;
4561 ParseContext::Statement stmt(pc_, StatementKind::Block);
4562 ParseContext::Scope scope(this);
4563 if (!scope.init(pc_)) {
4564 return errorResult();
4567 ListNodeType list;
4568 MOZ_TRY_VAR(list, statementList(yieldHandling));
4570 if (!mustMatchToken(TokenKind::RightCurly, [this, errorNumber,
4571 openedPos](TokenKind actual) {
4572 this->reportMissingClosing(errorNumber, JSMSG_CURLY_OPENED, openedPos);
4573 })) {
4574 return errorResult();
4577 return finishLexicalScope(scope, list);
4580 template <class ParseHandler, typename Unit>
4581 typename ParseHandler::NodeResult
4582 GeneralParser<ParseHandler, Unit>::expressionAfterForInOrOf(
4583 ParseNodeKind forHeadKind, YieldHandling yieldHandling) {
4584 MOZ_ASSERT(forHeadKind == ParseNodeKind::ForIn ||
4585 forHeadKind == ParseNodeKind::ForOf);
4586 if (forHeadKind == ParseNodeKind::ForOf) {
4587 return assignExpr(InAllowed, yieldHandling, TripledotProhibited);
4590 return expr(InAllowed, yieldHandling, TripledotProhibited);
4593 template <class ParseHandler, typename Unit>
4594 typename ParseHandler::NodeResult
4595 GeneralParser<ParseHandler, Unit>::declarationPattern(
4596 DeclarationKind declKind, TokenKind tt, bool initialDeclaration,
4597 YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
4598 Node* forInOrOfExpression) {
4599 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket) ||
4600 anyChars.isCurrentTokenType(TokenKind::LeftCurly));
4602 Node pattern;
4603 MOZ_TRY_VAR(pattern, destructuringDeclaration(declKind, yieldHandling, tt));
4605 if (initialDeclaration && forHeadKind) {
4606 bool isForIn, isForOf;
4607 if (!matchInOrOf(&isForIn, &isForOf)) {
4608 return errorResult();
4611 if (isForIn) {
4612 *forHeadKind = ParseNodeKind::ForIn;
4613 } else if (isForOf) {
4614 *forHeadKind = ParseNodeKind::ForOf;
4615 } else {
4616 *forHeadKind = ParseNodeKind::ForHead;
4619 if (*forHeadKind != ParseNodeKind::ForHead) {
4620 MOZ_TRY_VAR(*forInOrOfExpression,
4621 expressionAfterForInOrOf(*forHeadKind, yieldHandling));
4623 return pattern;
4627 if (!mustMatchToken(TokenKind::Assign, JSMSG_BAD_DESTRUCT_DECL)) {
4628 return errorResult();
4631 Node init;
4632 MOZ_TRY_VAR(init, assignExpr(forHeadKind ? InProhibited : InAllowed,
4633 yieldHandling, TripledotProhibited));
4635 return handler_.newAssignment(ParseNodeKind::AssignExpr, pattern, init);
4638 template <class ParseHandler, typename Unit>
4639 typename ParseHandler::AssignmentNodeResult
4640 GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
4641 NameNodeType binding, DeclarationKind declKind, bool initialDeclaration,
4642 YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
4643 Node* forInOrOfExpression) {
4644 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Assign));
4646 uint32_t initializerOffset;
4647 if (!tokenStream.peekOffset(&initializerOffset, TokenStream::SlashIsRegExp)) {
4648 return errorResult();
4651 Node initializer;
4652 MOZ_TRY_VAR(initializer, assignExpr(forHeadKind ? InProhibited : InAllowed,
4653 yieldHandling, TripledotProhibited));
4655 if (forHeadKind && initialDeclaration) {
4656 bool isForIn, isForOf;
4657 if (!matchInOrOf(&isForIn, &isForOf)) {
4658 return errorResult();
4661 // An initialized declaration can't appear in a for-of:
4663 // for (var/let/const x = ... of ...); // BAD
4664 if (isForOf) {
4665 errorAt(initializerOffset, JSMSG_OF_AFTER_FOR_LOOP_DECL);
4666 return errorResult();
4669 if (isForIn) {
4670 // Lexical declarations in for-in loops can't be initialized:
4672 // for (let/const x = ... in ...); // BAD
4673 if (DeclarationKindIsLexical(declKind)) {
4674 errorAt(initializerOffset, JSMSG_IN_AFTER_LEXICAL_FOR_DECL);
4675 return errorResult();
4678 // This leaves only initialized for-in |var| declarations. ES6
4679 // forbids these; later ES un-forbids in non-strict mode code.
4680 *forHeadKind = ParseNodeKind::ForIn;
4681 if (!strictModeErrorAt(initializerOffset,
4682 JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) {
4683 return errorResult();
4686 MOZ_TRY_VAR(
4687 *forInOrOfExpression,
4688 expressionAfterForInOrOf(ParseNodeKind::ForIn, yieldHandling));
4689 } else {
4690 *forHeadKind = ParseNodeKind::ForHead;
4694 return handler_.finishInitializerAssignment(binding, initializer);
4697 template <class ParseHandler, typename Unit>
4698 typename ParseHandler::NodeResult
4699 GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind,
4700 TokenKind tt,
4701 bool initialDeclaration,
4702 YieldHandling yieldHandling,
4703 ParseNodeKind* forHeadKind,
4704 Node* forInOrOfExpression) {
4705 // Anything other than possible identifier is an error.
4706 if (!TokenKindIsPossibleIdentifier(tt)) {
4707 error(JSMSG_NO_VARIABLE_NAME);
4708 return errorResult();
4711 TaggedParserAtomIndex name = bindingIdentifier(yieldHandling);
4712 if (!name) {
4713 return errorResult();
4716 NameNodeType binding;
4717 MOZ_TRY_VAR(binding, newName(name));
4719 TokenPos namePos = pos();
4721 // The '=' context after a variable name in a declaration is an opportunity
4722 // for ASI, and thus for the next token to start an ExpressionStatement:
4724 // var foo // VariableDeclaration
4725 // /bar/g; // ExpressionStatement
4727 // Therefore get the token here with SlashIsRegExp.
4728 bool matched;
4729 if (!tokenStream.matchToken(&matched, TokenKind::Assign,
4730 TokenStream::SlashIsRegExp)) {
4731 return errorResult();
4734 Node declaration;
4735 if (matched) {
4736 MOZ_TRY_VAR(declaration,
4737 initializerInNameDeclaration(binding, declKind,
4738 initialDeclaration, yieldHandling,
4739 forHeadKind, forInOrOfExpression));
4740 } else {
4741 declaration = binding;
4743 if (initialDeclaration && forHeadKind) {
4744 bool isForIn, isForOf;
4745 if (!matchInOrOf(&isForIn, &isForOf)) {
4746 return errorResult();
4749 if (isForIn) {
4750 *forHeadKind = ParseNodeKind::ForIn;
4751 } else if (isForOf) {
4752 *forHeadKind = ParseNodeKind::ForOf;
4753 } else {
4754 *forHeadKind = ParseNodeKind::ForHead;
4758 if (forHeadKind && *forHeadKind != ParseNodeKind::ForHead) {
4759 MOZ_TRY_VAR(*forInOrOfExpression,
4760 expressionAfterForInOrOf(*forHeadKind, yieldHandling));
4761 } else {
4762 // Normal const declarations, and const declarations in for(;;)
4763 // heads, must be initialized.
4764 if (declKind == DeclarationKind::Const) {
4765 errorAt(namePos.begin, JSMSG_BAD_CONST_DECL);
4766 return errorResult();
4771 // Note the declared name after knowing whether or not we are in a for-of
4772 // loop, due to special early error semantics in Annex B.3.5.
4773 if (!noteDeclaredName(name, declKind, namePos)) {
4774 return errorResult();
4777 return declaration;
4780 template <class ParseHandler, typename Unit>
4781 typename ParseHandler::DeclarationListNodeResult
4782 GeneralParser<ParseHandler, Unit>::declarationList(
4783 YieldHandling yieldHandling, ParseNodeKind kind,
4784 ParseNodeKind* forHeadKind /* = nullptr */,
4785 Node* forInOrOfExpression /* = nullptr */) {
4786 MOZ_ASSERT(kind == ParseNodeKind::VarStmt || kind == ParseNodeKind::LetDecl ||
4787 kind == ParseNodeKind::ConstDecl);
4789 DeclarationKind declKind;
4790 switch (kind) {
4791 case ParseNodeKind::VarStmt:
4792 declKind = DeclarationKind::Var;
4793 break;
4794 case ParseNodeKind::ConstDecl:
4795 declKind = DeclarationKind::Const;
4796 break;
4797 case ParseNodeKind::LetDecl:
4798 declKind = DeclarationKind::Let;
4799 break;
4800 default:
4801 MOZ_CRASH("Unknown declaration kind");
4804 DeclarationListNodeType decl;
4805 MOZ_TRY_VAR(decl, handler_.newDeclarationList(kind, pos()));
4807 bool moreDeclarations;
4808 bool initialDeclaration = true;
4809 do {
4810 MOZ_ASSERT_IF(!initialDeclaration && forHeadKind,
4811 *forHeadKind == ParseNodeKind::ForHead);
4813 TokenKind tt;
4814 if (!tokenStream.getToken(&tt)) {
4815 return errorResult();
4818 Node binding;
4819 if (tt == TokenKind::LeftBracket || tt == TokenKind::LeftCurly) {
4820 MOZ_TRY_VAR(binding, declarationPattern(declKind, tt, initialDeclaration,
4821 yieldHandling, forHeadKind,
4822 forInOrOfExpression));
4823 } else {
4824 MOZ_TRY_VAR(binding, declarationName(declKind, tt, initialDeclaration,
4825 yieldHandling, forHeadKind,
4826 forInOrOfExpression));
4829 handler_.addList(decl, binding);
4831 // If we have a for-in/of loop, the above call matches the entirety
4832 // of the loop head (up to the closing parenthesis).
4833 if (forHeadKind && *forHeadKind != ParseNodeKind::ForHead) {
4834 break;
4837 initialDeclaration = false;
4839 if (!tokenStream.matchToken(&moreDeclarations, TokenKind::Comma,
4840 TokenStream::SlashIsRegExp)) {
4841 return errorResult();
4843 } while (moreDeclarations);
4845 return decl;
4848 template <class ParseHandler, typename Unit>
4849 typename ParseHandler::DeclarationListNodeResult
4850 GeneralParser<ParseHandler, Unit>::lexicalDeclaration(
4851 YieldHandling yieldHandling, DeclarationKind kind) {
4852 MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let);
4854 if (options().selfHostingMode) {
4855 error(JSMSG_SELFHOSTED_LEXICAL);
4856 return errorResult();
4860 * Parse body-level lets without a new block object. ES6 specs
4861 * that an execution environment's initial lexical environment
4862 * is the VariableEnvironment, i.e., body-level lets are in
4863 * the same environment record as vars.
4865 * However, they cannot be parsed exactly as vars, as ES6
4866 * requires that uninitialized lets throw ReferenceError on use.
4868 * See 8.1.1.1.6 and the note in 13.2.1.
4870 DeclarationListNodeType decl;
4871 MOZ_TRY_VAR(decl,
4872 declarationList(yieldHandling, kind == DeclarationKind::Const
4873 ? ParseNodeKind::ConstDecl
4874 : ParseNodeKind::LetDecl));
4875 if (!matchOrInsertSemicolon()) {
4876 return errorResult();
4879 return decl;
4882 template <class ParseHandler, typename Unit>
4883 typename ParseHandler::NameNodeResult
4884 GeneralParser<ParseHandler, Unit>::moduleExportName() {
4885 MOZ_ASSERT(anyChars.currentToken().type == TokenKind::String);
4886 TaggedParserAtomIndex name = anyChars.currentToken().atom();
4887 if (!this->parserAtoms().isModuleExportName(name)) {
4888 error(JSMSG_UNPAIRED_SURROGATE_EXPORT);
4889 return errorResult();
4891 return handler_.newStringLiteral(name, pos());
4894 template <class ParseHandler, typename Unit>
4895 bool GeneralParser<ParseHandler, Unit>::assertClause(
4896 ListNodeType assertionsSet) {
4897 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Assert));
4899 if (!options().importAssertions()) {
4900 error(JSMSG_IMPORT_ASSERTIONS_NOT_SUPPORTED);
4901 return false;
4904 if (!abortIfSyntaxParser()) {
4905 return false;
4908 if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_AFTER_ASSERT)) {
4909 return false;
4912 // Handle the form |... assert {}|
4913 TokenKind token;
4914 if (!tokenStream.getToken(&token)) {
4915 return false;
4917 if (token == TokenKind::RightCurly) {
4918 return true;
4921 js::HashSet<TaggedParserAtomIndex, TaggedParserAtomIndexHasher,
4922 js::SystemAllocPolicy>
4923 usedAssertionKeys;
4925 for (;;) {
4926 TaggedParserAtomIndex keyName;
4927 if (TokenKindIsPossibleIdentifierName(token)) {
4928 keyName = anyChars.currentName();
4929 } else if (token == TokenKind::String) {
4930 keyName = anyChars.currentToken().atom();
4931 } else {
4932 error(JSMSG_ASSERT_KEY_EXPECTED);
4933 return false;
4936 auto p = usedAssertionKeys.lookupForAdd(keyName);
4937 if (p) {
4938 UniqueChars str = this->parserAtoms().toPrintableString(keyName);
4939 if (!str) {
4940 ReportOutOfMemory(this->fc_);
4941 return false;
4943 error(JSMSG_DUPLICATE_ASSERT_KEY, str.get());
4944 return false;
4946 if (!usedAssertionKeys.add(p, keyName)) {
4947 ReportOutOfMemory(this->fc_);
4948 return false;
4951 NameNodeType keyNode;
4952 MOZ_TRY_VAR_OR_RETURN(keyNode, newName(keyName), false);
4954 if (!mustMatchToken(TokenKind::Colon, JSMSG_COLON_AFTER_ASSERT_KEY)) {
4955 return false;
4957 if (!mustMatchToken(TokenKind::String, JSMSG_ASSERT_STRING_LITERAL)) {
4958 return false;
4961 NameNodeType valueNode;
4962 MOZ_TRY_VAR_OR_RETURN(valueNode, stringLiteral(), false);
4964 BinaryNodeType importAssertionNode;
4965 MOZ_TRY_VAR_OR_RETURN(importAssertionNode,
4966 handler_.newImportAssertion(keyNode, valueNode),
4967 false);
4969 handler_.addList(assertionsSet, importAssertionNode);
4971 if (!tokenStream.getToken(&token)) {
4972 return false;
4974 if (token == TokenKind::Comma) {
4975 if (!tokenStream.getToken(&token)) {
4976 return false;
4979 if (token == TokenKind::RightCurly) {
4980 break;
4984 return true;
4987 template <class ParseHandler, typename Unit>
4988 bool GeneralParser<ParseHandler, Unit>::namedImports(
4989 ListNodeType importSpecSet) {
4990 if (!abortIfSyntaxParser()) {
4991 return false;
4994 while (true) {
4995 // Handle the forms |import {} from 'a'| and
4996 // |import { ..., } from 'a'| (where ... is non empty), by
4997 // escaping the loop early if the next token is }.
4998 TokenKind tt;
4999 if (!tokenStream.getToken(&tt)) {
5000 return false;
5003 if (tt == TokenKind::RightCurly) {
5004 break;
5007 TaggedParserAtomIndex importName;
5008 NameNodeType importNameNode = null();
5009 if (TokenKindIsPossibleIdentifierName(tt)) {
5010 importName = anyChars.currentName();
5011 MOZ_TRY_VAR_OR_RETURN(importNameNode, newName(importName), false);
5012 } else if (tt == TokenKind::String) {
5013 MOZ_TRY_VAR_OR_RETURN(importNameNode, moduleExportName(), false);
5014 } else {
5015 error(JSMSG_NO_IMPORT_NAME);
5016 return false;
5019 bool matched;
5020 if (!tokenStream.matchToken(&matched, TokenKind::As)) {
5021 return false;
5024 if (matched) {
5025 TokenKind afterAs;
5026 if (!tokenStream.getToken(&afterAs)) {
5027 return false;
5030 if (!TokenKindIsPossibleIdentifierName(afterAs)) {
5031 error(JSMSG_NO_BINDING_NAME);
5032 return false;
5034 } else {
5035 // String export names can't refer to local bindings.
5036 if (tt == TokenKind::String) {
5037 error(JSMSG_AS_AFTER_STRING);
5038 return false;
5041 // Keywords cannot be bound to themselves, so an import name
5042 // that is a keyword is a syntax error if it is not followed
5043 // by the keyword 'as'.
5044 // See the ImportSpecifier production in ES6 section 15.2.2.
5045 MOZ_ASSERT(importName);
5046 if (IsKeyword(importName)) {
5047 error(JSMSG_AS_AFTER_RESERVED_WORD, ReservedWordToCharZ(importName));
5048 return false;
5052 TaggedParserAtomIndex bindingAtom = importedBinding();
5053 if (!bindingAtom) {
5054 return false;
5057 NameNodeType bindingName;
5058 MOZ_TRY_VAR_OR_RETURN(bindingName, newName(bindingAtom), false);
5059 if (!noteDeclaredName(bindingAtom, DeclarationKind::Import, pos())) {
5060 return false;
5063 BinaryNodeType importSpec;
5064 MOZ_TRY_VAR_OR_RETURN(
5065 importSpec, handler_.newImportSpec(importNameNode, bindingName), false);
5067 handler_.addList(importSpecSet, importSpec);
5069 TokenKind next;
5070 if (!tokenStream.getToken(&next)) {
5071 return false;
5074 if (next == TokenKind::RightCurly) {
5075 break;
5078 if (next != TokenKind::Comma) {
5079 error(JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
5080 return false;
5084 return true;
5087 template <class ParseHandler, typename Unit>
5088 bool GeneralParser<ParseHandler, Unit>::namespaceImport(
5089 ListNodeType importSpecSet) {
5090 if (!abortIfSyntaxParser()) {
5091 return false;
5094 if (!mustMatchToken(TokenKind::As, JSMSG_AS_AFTER_IMPORT_STAR)) {
5095 return false;
5097 uint32_t begin = pos().begin;
5099 if (!mustMatchToken(TokenKindIsPossibleIdentifierName,
5100 JSMSG_NO_BINDING_NAME)) {
5101 return false;
5104 // Namespace imports are not indirect bindings but lexical
5105 // definitions that hold a module namespace object. They are treated
5106 // as const variables which are initialized during the
5107 // ModuleInstantiate step.
5108 TaggedParserAtomIndex bindingName = importedBinding();
5109 if (!bindingName) {
5110 return false;
5112 NameNodeType bindingNameNode;
5113 MOZ_TRY_VAR_OR_RETURN(bindingNameNode, newName(bindingName), false);
5114 if (!noteDeclaredName(bindingName, DeclarationKind::Const, pos())) {
5115 return false;
5118 // The namespace import name is currently required to live on the
5119 // environment.
5120 pc_->varScope().lookupDeclaredName(bindingName)->value()->setClosedOver();
5122 UnaryNodeType importSpec;
5123 MOZ_TRY_VAR_OR_RETURN(importSpec,
5124 handler_.newImportNamespaceSpec(begin, bindingNameNode),
5125 false);
5127 handler_.addList(importSpecSet, importSpec);
5129 return true;
5132 template <class ParseHandler, typename Unit>
5133 typename ParseHandler::BinaryNodeResult
5134 GeneralParser<ParseHandler, Unit>::importDeclaration() {
5135 if (!abortIfSyntaxParser()) {
5136 return errorResult();
5139 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
5141 if (!pc_->atModuleLevel()) {
5142 error(JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
5143 return errorResult();
5146 uint32_t begin = pos().begin;
5147 TokenKind tt;
5148 if (!tokenStream.getToken(&tt)) {
5149 return errorResult();
5152 ListNodeType importSpecSet;
5153 MOZ_TRY_VAR(importSpecSet,
5154 handler_.newList(ParseNodeKind::ImportSpecList, pos()));
5156 if (tt == TokenKind::String) {
5157 // Handle the form |import 'a'| by leaving the list empty. This is
5158 // equivalent to |import {} from 'a'|.
5159 handler_.setEndPosition(importSpecSet, pos().begin);
5160 } else {
5161 if (tt == TokenKind::LeftCurly) {
5162 if (!namedImports(importSpecSet)) {
5163 return errorResult();
5165 } else if (tt == TokenKind::Mul) {
5166 if (!namespaceImport(importSpecSet)) {
5167 return errorResult();
5169 } else if (TokenKindIsPossibleIdentifierName(tt)) {
5170 // Handle the form |import a from 'b'|, by adding a single import
5171 // specifier to the list, with 'default' as the import name and
5172 // 'a' as the binding name. This is equivalent to
5173 // |import { default as a } from 'b'|.
5174 NameNodeType importName;
5175 MOZ_TRY_VAR(importName,
5176 newName(TaggedParserAtomIndex::WellKnown::default_()));
5178 TaggedParserAtomIndex bindingAtom = importedBinding();
5179 if (!bindingAtom) {
5180 return errorResult();
5183 NameNodeType bindingName;
5184 MOZ_TRY_VAR(bindingName, newName(bindingAtom));
5186 if (!noteDeclaredName(bindingAtom, DeclarationKind::Import, pos())) {
5187 return errorResult();
5190 BinaryNodeType importSpec;
5191 MOZ_TRY_VAR(importSpec, handler_.newImportSpec(importName, bindingName));
5193 handler_.addList(importSpecSet, importSpec);
5195 if (!tokenStream.peekToken(&tt)) {
5196 return errorResult();
5199 if (tt == TokenKind::Comma) {
5200 tokenStream.consumeKnownToken(tt);
5201 if (!tokenStream.getToken(&tt)) {
5202 return errorResult();
5205 if (tt == TokenKind::LeftCurly) {
5206 if (!namedImports(importSpecSet)) {
5207 return errorResult();
5209 } else if (tt == TokenKind::Mul) {
5210 if (!namespaceImport(importSpecSet)) {
5211 return errorResult();
5213 } else {
5214 error(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT);
5215 return errorResult();
5218 } else {
5219 error(JSMSG_DECLARATION_AFTER_IMPORT);
5220 return errorResult();
5223 if (!mustMatchToken(TokenKind::From, JSMSG_FROM_AFTER_IMPORT_CLAUSE)) {
5224 return errorResult();
5227 if (!mustMatchToken(TokenKind::String, JSMSG_MODULE_SPEC_AFTER_FROM)) {
5228 return errorResult();
5232 NameNodeType moduleSpec;
5233 MOZ_TRY_VAR(moduleSpec, stringLiteral());
5235 if (!tokenStream.peekTokenSameLine(&tt, TokenStream::SlashIsRegExp)) {
5236 return errorResult();
5239 ListNodeType importAssertionList;
5240 MOZ_TRY_VAR(importAssertionList,
5241 handler_.newList(ParseNodeKind::ImportAssertionList, pos()));
5243 if (tt == TokenKind::Assert) {
5244 tokenStream.consumeKnownToken(TokenKind::Assert,
5245 TokenStream::SlashIsRegExp);
5247 if (!assertClause(importAssertionList)) {
5248 return errorResult();
5252 if (!matchOrInsertSemicolon(TokenStream::SlashIsRegExp)) {
5253 return errorResult();
5256 BinaryNodeType moduleRequest;
5257 MOZ_TRY_VAR(moduleRequest,
5258 handler_.newModuleRequest(moduleSpec, importAssertionList,
5259 TokenPos(begin, pos().end)));
5261 BinaryNodeType node;
5262 MOZ_TRY_VAR(node, handler_.newImportDeclaration(importSpecSet, moduleRequest,
5263 TokenPos(begin, pos().end)));
5264 if (!processImport(node)) {
5265 return errorResult();
5268 return node;
5271 template <class ParseHandler, typename Unit>
5272 inline typename ParseHandler::NodeResult
5273 GeneralParser<ParseHandler, Unit>::importDeclarationOrImportExpr(
5274 YieldHandling yieldHandling) {
5275 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
5277 TokenKind tt;
5278 if (!tokenStream.peekToken(&tt)) {
5279 return errorResult();
5282 if (tt == TokenKind::Dot || tt == TokenKind::LeftParen) {
5283 return expressionStatement(yieldHandling);
5286 return importDeclaration();
5289 template <typename Unit>
5290 bool Parser<FullParseHandler, Unit>::checkExportedName(
5291 TaggedParserAtomIndex exportName) {
5292 if (!pc_->sc()->asModuleContext()->builder.hasExportedName(exportName)) {
5293 return true;
5296 UniqueChars str = this->parserAtoms().toPrintableString(exportName);
5297 if (!str) {
5298 ReportOutOfMemory(this->fc_);
5299 return false;
5302 error(JSMSG_DUPLICATE_EXPORT_NAME, str.get());
5303 return false;
5306 template <typename Unit>
5307 inline bool Parser<SyntaxParseHandler, Unit>::checkExportedName(
5308 TaggedParserAtomIndex exportName) {
5309 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5310 return false;
5313 template <class ParseHandler, typename Unit>
5314 inline bool GeneralParser<ParseHandler, Unit>::checkExportedName(
5315 TaggedParserAtomIndex exportName) {
5316 return asFinalParser()->checkExportedName(exportName);
5319 template <typename Unit>
5320 bool Parser<FullParseHandler, Unit>::checkExportedNamesForArrayBinding(
5321 ListNode* array) {
5322 MOZ_ASSERT(array->isKind(ParseNodeKind::ArrayExpr));
5324 for (ParseNode* node : array->contents()) {
5325 if (node->isKind(ParseNodeKind::Elision)) {
5326 continue;
5329 ParseNode* binding;
5330 if (node->isKind(ParseNodeKind::Spread)) {
5331 binding = node->as<UnaryNode>().kid();
5332 } else if (node->isKind(ParseNodeKind::AssignExpr)) {
5333 binding = node->as<AssignmentNode>().left();
5334 } else {
5335 binding = node;
5338 if (!checkExportedNamesForDeclaration(binding)) {
5339 return false;
5343 return true;
5346 template <typename Unit>
5347 inline bool Parser<SyntaxParseHandler, Unit>::checkExportedNamesForArrayBinding(
5348 ListNodeType array) {
5349 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5350 return false;
5353 template <class ParseHandler, typename Unit>
5354 inline bool
5355 GeneralParser<ParseHandler, Unit>::checkExportedNamesForArrayBinding(
5356 ListNodeType array) {
5357 return asFinalParser()->checkExportedNamesForArrayBinding(array);
5360 template <typename Unit>
5361 bool Parser<FullParseHandler, Unit>::checkExportedNamesForObjectBinding(
5362 ListNode* obj) {
5363 MOZ_ASSERT(obj->isKind(ParseNodeKind::ObjectExpr));
5365 for (ParseNode* node : obj->contents()) {
5366 MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) ||
5367 node->isKind(ParseNodeKind::PropertyDefinition) ||
5368 node->isKind(ParseNodeKind::Shorthand) ||
5369 node->isKind(ParseNodeKind::Spread));
5371 ParseNode* target;
5372 if (node->isKind(ParseNodeKind::Spread)) {
5373 target = node->as<UnaryNode>().kid();
5374 } else {
5375 if (node->isKind(ParseNodeKind::MutateProto)) {
5376 target = node->as<UnaryNode>().kid();
5377 } else {
5378 target = node->as<BinaryNode>().right();
5381 if (target->isKind(ParseNodeKind::AssignExpr)) {
5382 target = target->as<AssignmentNode>().left();
5386 if (!checkExportedNamesForDeclaration(target)) {
5387 return false;
5391 return true;
5394 template <typename Unit>
5395 inline bool Parser<SyntaxParseHandler,
5396 Unit>::checkExportedNamesForObjectBinding(ListNodeType obj) {
5397 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5398 return false;
5401 template <class ParseHandler, typename Unit>
5402 inline bool
5403 GeneralParser<ParseHandler, Unit>::checkExportedNamesForObjectBinding(
5404 ListNodeType obj) {
5405 return asFinalParser()->checkExportedNamesForObjectBinding(obj);
5408 template <typename Unit>
5409 bool Parser<FullParseHandler, Unit>::checkExportedNamesForDeclaration(
5410 ParseNode* node) {
5411 if (node->isKind(ParseNodeKind::Name)) {
5412 if (!checkExportedName(node->as<NameNode>().atom())) {
5413 return false;
5415 } else if (node->isKind(ParseNodeKind::ArrayExpr)) {
5416 if (!checkExportedNamesForArrayBinding(&node->as<ListNode>())) {
5417 return false;
5419 } else {
5420 MOZ_ASSERT(node->isKind(ParseNodeKind::ObjectExpr));
5421 if (!checkExportedNamesForObjectBinding(&node->as<ListNode>())) {
5422 return false;
5426 return true;
5429 template <typename Unit>
5430 inline bool Parser<SyntaxParseHandler, Unit>::checkExportedNamesForDeclaration(
5431 Node node) {
5432 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5433 return false;
5436 template <class ParseHandler, typename Unit>
5437 inline bool GeneralParser<ParseHandler, Unit>::checkExportedNamesForDeclaration(
5438 Node node) {
5439 return asFinalParser()->checkExportedNamesForDeclaration(node);
5442 template <typename Unit>
5443 bool Parser<FullParseHandler, Unit>::checkExportedNamesForDeclarationList(
5444 DeclarationListNodeType node) {
5445 for (ParseNode* binding : node->contents()) {
5446 if (binding->isKind(ParseNodeKind::AssignExpr)) {
5447 binding = binding->as<AssignmentNode>().left();
5448 } else {
5449 MOZ_ASSERT(binding->isKind(ParseNodeKind::Name));
5452 if (!checkExportedNamesForDeclaration(binding)) {
5453 return false;
5457 return true;
5460 template <typename Unit>
5461 inline bool
5462 Parser<SyntaxParseHandler, Unit>::checkExportedNamesForDeclarationList(
5463 DeclarationListNodeType node) {
5464 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5465 return false;
5468 template <class ParseHandler, typename Unit>
5469 inline bool
5470 GeneralParser<ParseHandler, Unit>::checkExportedNamesForDeclarationList(
5471 DeclarationListNodeType node) {
5472 return asFinalParser()->checkExportedNamesForDeclarationList(node);
5475 template <typename Unit>
5476 inline bool Parser<FullParseHandler, Unit>::checkExportedNameForClause(
5477 NameNode* nameNode) {
5478 return checkExportedName(nameNode->atom());
5481 template <typename Unit>
5482 inline bool Parser<SyntaxParseHandler, Unit>::checkExportedNameForClause(
5483 NameNodeType nameNode) {
5484 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5485 return false;
5488 template <class ParseHandler, typename Unit>
5489 inline bool GeneralParser<ParseHandler, Unit>::checkExportedNameForClause(
5490 NameNodeType nameNode) {
5491 return asFinalParser()->checkExportedNameForClause(nameNode);
5494 template <typename Unit>
5495 bool Parser<FullParseHandler, Unit>::checkExportedNameForFunction(
5496 FunctionNode* funNode) {
5497 return checkExportedName(funNode->funbox()->explicitName());
5500 template <typename Unit>
5501 inline bool Parser<SyntaxParseHandler, Unit>::checkExportedNameForFunction(
5502 FunctionNodeType funNode) {
5503 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5504 return false;
5507 template <class ParseHandler, typename Unit>
5508 inline bool GeneralParser<ParseHandler, Unit>::checkExportedNameForFunction(
5509 FunctionNodeType funNode) {
5510 return asFinalParser()->checkExportedNameForFunction(funNode);
5513 template <typename Unit>
5514 bool Parser<FullParseHandler, Unit>::checkExportedNameForClass(
5515 ClassNode* classNode) {
5516 MOZ_ASSERT(classNode->names());
5517 return checkExportedName(classNode->names()->innerBinding()->atom());
5520 template <typename Unit>
5521 inline bool Parser<SyntaxParseHandler, Unit>::checkExportedNameForClass(
5522 ClassNodeType classNode) {
5523 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5524 return false;
5527 template <class ParseHandler, typename Unit>
5528 inline bool GeneralParser<ParseHandler, Unit>::checkExportedNameForClass(
5529 ClassNodeType classNode) {
5530 return asFinalParser()->checkExportedNameForClass(classNode);
5533 template <>
5534 inline bool PerHandlerParser<FullParseHandler>::processExport(ParseNode* node) {
5535 return pc_->sc()->asModuleContext()->builder.processExport(node);
5538 template <>
5539 inline bool PerHandlerParser<SyntaxParseHandler>::processExport(Node node) {
5540 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5541 return false;
5544 template <>
5545 inline bool PerHandlerParser<FullParseHandler>::processExportFrom(
5546 BinaryNodeType node) {
5547 return pc_->sc()->asModuleContext()->builder.processExportFrom(node);
5550 template <>
5551 inline bool PerHandlerParser<SyntaxParseHandler>::processExportFrom(
5552 BinaryNodeType node) {
5553 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5554 return false;
5557 template <>
5558 inline bool PerHandlerParser<FullParseHandler>::processImport(
5559 BinaryNodeType node) {
5560 return pc_->sc()->asModuleContext()->builder.processImport(node);
5563 template <>
5564 inline bool PerHandlerParser<SyntaxParseHandler>::processImport(
5565 BinaryNodeType node) {
5566 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5567 return false;
5570 template <class ParseHandler, typename Unit>
5571 typename ParseHandler::BinaryNodeResult
5572 GeneralParser<ParseHandler, Unit>::exportFrom(uint32_t begin, Node specList) {
5573 if (!abortIfSyntaxParser()) {
5574 return errorResult();
5577 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::From));
5579 if (!mustMatchToken(TokenKind::String, JSMSG_MODULE_SPEC_AFTER_FROM)) {
5580 return errorResult();
5583 NameNodeType moduleSpec;
5584 MOZ_TRY_VAR(moduleSpec, stringLiteral());
5586 TokenKind tt;
5587 if (!tokenStream.peekTokenSameLine(&tt, TokenStream::SlashIsRegExp)) {
5588 return errorResult();
5590 uint32_t moduleSpecPos = pos().begin;
5592 ListNodeType importAssertionList;
5593 MOZ_TRY_VAR(importAssertionList,
5594 handler_.newList(ParseNodeKind::ImportAssertionList, pos()));
5595 if (tt == TokenKind::Assert) {
5596 tokenStream.consumeKnownToken(TokenKind::Assert,
5597 TokenStream::SlashIsRegExp);
5599 if (!assertClause(importAssertionList)) {
5600 return errorResult();
5604 if (!matchOrInsertSemicolon(TokenStream::SlashIsRegExp)) {
5605 return errorResult();
5608 BinaryNodeType moduleRequest;
5609 MOZ_TRY_VAR(moduleRequest,
5610 handler_.newModuleRequest(moduleSpec, importAssertionList,
5611 TokenPos(moduleSpecPos, pos().end)));
5613 BinaryNodeType node;
5614 MOZ_TRY_VAR(
5615 node, handler_.newExportFromDeclaration(begin, specList, moduleRequest));
5617 if (!processExportFrom(node)) {
5618 return errorResult();
5621 return node;
5624 template <class ParseHandler, typename Unit>
5625 typename ParseHandler::BinaryNodeResult
5626 GeneralParser<ParseHandler, Unit>::exportBatch(uint32_t begin) {
5627 if (!abortIfSyntaxParser()) {
5628 return errorResult();
5631 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Mul));
5632 uint32_t beginExportSpec = pos().begin;
5634 ListNodeType kid;
5635 MOZ_TRY_VAR(kid, handler_.newList(ParseNodeKind::ExportSpecList, pos()));
5637 bool foundAs;
5638 if (!tokenStream.matchToken(&foundAs, TokenKind::As)) {
5639 return errorResult();
5642 if (foundAs) {
5643 TokenKind tt;
5644 if (!tokenStream.getToken(&tt)) {
5645 return errorResult();
5648 NameNodeType exportName = null();
5649 if (TokenKindIsPossibleIdentifierName(tt)) {
5650 MOZ_TRY_VAR(exportName, newName(anyChars.currentName()));
5651 } else if (tt == TokenKind::String) {
5652 MOZ_TRY_VAR(exportName, moduleExportName());
5653 } else {
5654 error(JSMSG_NO_EXPORT_NAME);
5655 return errorResult();
5658 if (!checkExportedNameForClause(exportName)) {
5659 return errorResult();
5662 UnaryNodeType exportSpec;
5663 MOZ_TRY_VAR(exportSpec,
5664 handler_.newExportNamespaceSpec(beginExportSpec, exportName));
5666 handler_.addList(kid, exportSpec);
5667 } else {
5668 // Handle the form |export *| by adding a special export batch
5669 // specifier to the list.
5670 NullaryNodeType exportSpec;
5671 MOZ_TRY_VAR(exportSpec, handler_.newExportBatchSpec(pos()));
5673 handler_.addList(kid, exportSpec);
5676 if (!mustMatchToken(TokenKind::From, JSMSG_FROM_AFTER_EXPORT_STAR)) {
5677 return errorResult();
5680 return exportFrom(begin, kid);
5683 template <typename Unit>
5684 bool Parser<FullParseHandler, Unit>::checkLocalExportNames(ListNode* node) {
5685 // ES 2017 draft 15.2.3.1.
5686 for (ParseNode* next : node->contents()) {
5687 ParseNode* name = next->as<BinaryNode>().left();
5689 if (name->isKind(ParseNodeKind::StringExpr)) {
5690 errorAt(name->pn_pos.begin, JSMSG_BAD_LOCAL_STRING_EXPORT);
5691 return false;
5694 MOZ_ASSERT(name->isKind(ParseNodeKind::Name));
5696 TaggedParserAtomIndex ident = name->as<NameNode>().atom();
5697 if (!checkLocalExportName(ident, name->pn_pos.begin)) {
5698 return false;
5702 return true;
5705 template <typename Unit>
5706 bool Parser<SyntaxParseHandler, Unit>::checkLocalExportNames(
5707 ListNodeType node) {
5708 MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
5709 return false;
5712 template <class ParseHandler, typename Unit>
5713 inline bool GeneralParser<ParseHandler, Unit>::checkLocalExportNames(
5714 ListNodeType node) {
5715 return asFinalParser()->checkLocalExportNames(node);
5718 template <class ParseHandler, typename Unit>
5719 typename ParseHandler::NodeResult
5720 GeneralParser<ParseHandler, Unit>::exportClause(uint32_t begin) {
5721 if (!abortIfSyntaxParser()) {
5722 return errorResult();
5725 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
5727 ListNodeType kid;
5728 MOZ_TRY_VAR(kid, handler_.newList(ParseNodeKind::ExportSpecList, pos()));
5730 TokenKind tt;
5731 while (true) {
5732 // Handle the forms |export {}| and |export { ..., }| (where ... is non
5733 // empty), by escaping the loop early if the next token is }.
5734 if (!tokenStream.getToken(&tt)) {
5735 return errorResult();
5738 if (tt == TokenKind::RightCurly) {
5739 break;
5742 NameNodeType bindingName = null();
5743 if (TokenKindIsPossibleIdentifierName(tt)) {
5744 MOZ_TRY_VAR(bindingName, newName(anyChars.currentName()));
5745 } else if (tt == TokenKind::String) {
5746 MOZ_TRY_VAR(bindingName, moduleExportName());
5747 } else {
5748 error(JSMSG_NO_BINDING_NAME);
5749 return errorResult();
5752 bool foundAs;
5753 if (!tokenStream.matchToken(&foundAs, TokenKind::As)) {
5754 return errorResult();
5757 NameNodeType exportName = null();
5758 if (foundAs) {
5759 TokenKind tt;
5760 if (!tokenStream.getToken(&tt)) {
5761 return errorResult();
5764 if (TokenKindIsPossibleIdentifierName(tt)) {
5765 MOZ_TRY_VAR(exportName, newName(anyChars.currentName()));
5766 } else if (tt == TokenKind::String) {
5767 MOZ_TRY_VAR(exportName, moduleExportName());
5768 } else {
5769 error(JSMSG_NO_EXPORT_NAME);
5770 return errorResult();
5772 } else {
5773 if (tt != TokenKind::String) {
5774 MOZ_TRY_VAR(exportName, newName(anyChars.currentName()));
5775 } else {
5776 MOZ_TRY_VAR(exportName, moduleExportName());
5780 if (!checkExportedNameForClause(exportName)) {
5781 return errorResult();
5784 BinaryNodeType exportSpec;
5785 MOZ_TRY_VAR(exportSpec, handler_.newExportSpec(bindingName, exportName));
5787 handler_.addList(kid, exportSpec);
5789 TokenKind next;
5790 if (!tokenStream.getToken(&next)) {
5791 return errorResult();
5794 if (next == TokenKind::RightCurly) {
5795 break;
5798 if (next != TokenKind::Comma) {
5799 error(JSMSG_RC_AFTER_EXPORT_SPEC_LIST);
5800 return errorResult();
5804 // Careful! If |from| follows, even on a new line, it must start a
5805 // FromClause:
5807 // export { x }
5808 // from "foo"; // a single ExportDeclaration
5810 // But if it doesn't, we might have an ASI opportunity in SlashIsRegExp
5811 // context:
5813 // export { x } // ExportDeclaration, terminated by ASI
5814 // fro\u006D // ExpressionStatement, the name "from"
5816 // In that case let matchOrInsertSemicolon sort out ASI or any necessary
5817 // error.
5818 bool matched;
5819 if (!tokenStream.matchToken(&matched, TokenKind::From,
5820 TokenStream::SlashIsRegExp)) {
5821 return errorResult();
5824 if (matched) {
5825 return exportFrom(begin, kid);
5828 if (!matchOrInsertSemicolon()) {
5829 return errorResult();
5832 if (!checkLocalExportNames(kid)) {
5833 return errorResult();
5836 UnaryNodeType node;
5837 MOZ_TRY_VAR(node,
5838 handler_.newExportDeclaration(kid, TokenPos(begin, pos().end)));
5840 if (!processExport(node)) {
5841 return errorResult();
5844 return node;
5847 template <class ParseHandler, typename Unit>
5848 typename ParseHandler::UnaryNodeResult
5849 GeneralParser<ParseHandler, Unit>::exportVariableStatement(uint32_t begin) {
5850 if (!abortIfSyntaxParser()) {
5851 return errorResult();
5854 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Var));
5856 DeclarationListNodeType kid;
5857 MOZ_TRY_VAR(kid, declarationList(YieldIsName, ParseNodeKind::VarStmt));
5858 if (!matchOrInsertSemicolon()) {
5859 return errorResult();
5861 if (!checkExportedNamesForDeclarationList(kid)) {
5862 return errorResult();
5865 UnaryNodeType node;
5866 MOZ_TRY_VAR(node,
5867 handler_.newExportDeclaration(kid, TokenPos(begin, pos().end)));
5869 if (!processExport(node)) {
5870 return errorResult();
5873 return node;
5876 template <class ParseHandler, typename Unit>
5877 typename ParseHandler::UnaryNodeResult
5878 GeneralParser<ParseHandler, Unit>::exportFunctionDeclaration(
5879 uint32_t begin, uint32_t toStringStart,
5880 FunctionAsyncKind asyncKind /* = SyncFunction */) {
5881 if (!abortIfSyntaxParser()) {
5882 return errorResult();
5885 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
5887 Node kid;
5888 MOZ_TRY_VAR(
5889 kid, functionStmt(toStringStart, YieldIsName, NameRequired, asyncKind));
5891 if (!checkExportedNameForFunction(handler_.asFunctionNode(kid))) {
5892 return errorResult();
5895 UnaryNodeType node;
5896 MOZ_TRY_VAR(node,
5897 handler_.newExportDeclaration(kid, TokenPos(begin, pos().end)));
5899 if (!processExport(node)) {
5900 return errorResult();
5903 return node;
5906 template <class ParseHandler, typename Unit>
5907 typename ParseHandler::UnaryNodeResult
5908 GeneralParser<ParseHandler, Unit>::exportClassDeclaration(uint32_t begin) {
5909 if (!abortIfSyntaxParser()) {
5910 return errorResult();
5913 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Class));
5915 ClassNodeType kid;
5916 MOZ_TRY_VAR(kid, classDefinition(YieldIsName, ClassStatement, NameRequired));
5918 if (!checkExportedNameForClass(kid)) {
5919 return errorResult();
5922 UnaryNodeType node;
5923 MOZ_TRY_VAR(node,
5924 handler_.newExportDeclaration(kid, TokenPos(begin, pos().end)));
5926 if (!processExport(node)) {
5927 return errorResult();
5930 return node;
5933 template <class ParseHandler, typename Unit>
5934 typename ParseHandler::UnaryNodeResult
5935 GeneralParser<ParseHandler, Unit>::exportLexicalDeclaration(
5936 uint32_t begin, DeclarationKind kind) {
5937 if (!abortIfSyntaxParser()) {
5938 return errorResult();
5941 MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let);
5942 MOZ_ASSERT_IF(kind == DeclarationKind::Const,
5943 anyChars.isCurrentTokenType(TokenKind::Const));
5944 MOZ_ASSERT_IF(kind == DeclarationKind::Let,
5945 anyChars.isCurrentTokenType(TokenKind::Let));
5947 DeclarationListNodeType kid;
5948 MOZ_TRY_VAR(kid, lexicalDeclaration(YieldIsName, kind));
5949 if (!checkExportedNamesForDeclarationList(kid)) {
5950 return errorResult();
5953 UnaryNodeType node;
5954 MOZ_TRY_VAR(node,
5955 handler_.newExportDeclaration(kid, TokenPos(begin, pos().end)));
5957 if (!processExport(node)) {
5958 return errorResult();
5961 return node;
5964 template <class ParseHandler, typename Unit>
5965 typename ParseHandler::BinaryNodeResult
5966 GeneralParser<ParseHandler, Unit>::exportDefaultFunctionDeclaration(
5967 uint32_t begin, uint32_t toStringStart,
5968 FunctionAsyncKind asyncKind /* = SyncFunction */) {
5969 if (!abortIfSyntaxParser()) {
5970 return errorResult();
5973 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
5975 Node kid;
5976 MOZ_TRY_VAR(kid, functionStmt(toStringStart, YieldIsName, AllowDefaultName,
5977 asyncKind));
5979 BinaryNodeType node;
5980 MOZ_TRY_VAR(node, handler_.newExportDefaultDeclaration(
5981 kid, null(), TokenPos(begin, pos().end)));
5983 if (!processExport(node)) {
5984 return errorResult();
5987 return node;
5990 template <class ParseHandler, typename Unit>
5991 typename ParseHandler::BinaryNodeResult
5992 GeneralParser<ParseHandler, Unit>::exportDefaultClassDeclaration(
5993 uint32_t begin) {
5994 if (!abortIfSyntaxParser()) {
5995 return errorResult();
5998 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Class));
6000 ClassNodeType kid;
6001 MOZ_TRY_VAR(kid,
6002 classDefinition(YieldIsName, ClassStatement, AllowDefaultName));
6004 BinaryNodeType node;
6005 MOZ_TRY_VAR(node, handler_.newExportDefaultDeclaration(
6006 kid, null(), TokenPos(begin, pos().end)));
6008 if (!processExport(node)) {
6009 return errorResult();
6012 return node;
6015 template <class ParseHandler, typename Unit>
6016 typename ParseHandler::BinaryNodeResult
6017 GeneralParser<ParseHandler, Unit>::exportDefaultAssignExpr(uint32_t begin) {
6018 if (!abortIfSyntaxParser()) {
6019 return errorResult();
6022 TaggedParserAtomIndex name = TaggedParserAtomIndex::WellKnown::default_();
6023 NameNodeType nameNode;
6024 MOZ_TRY_VAR(nameNode, newName(name));
6025 if (!noteDeclaredName(name, DeclarationKind::Const, pos())) {
6026 return errorResult();
6029 Node kid;
6030 MOZ_TRY_VAR(kid, assignExpr(InAllowed, YieldIsName, TripledotProhibited));
6032 if (!matchOrInsertSemicolon()) {
6033 return errorResult();
6036 BinaryNodeType node;
6037 MOZ_TRY_VAR(node, handler_.newExportDefaultDeclaration(
6038 kid, nameNode, TokenPos(begin, pos().end)));
6040 if (!processExport(node)) {
6041 return errorResult();
6044 return node;
6047 template <class ParseHandler, typename Unit>
6048 typename ParseHandler::BinaryNodeResult
6049 GeneralParser<ParseHandler, Unit>::exportDefault(uint32_t begin) {
6050 if (!abortIfSyntaxParser()) {
6051 return errorResult();
6054 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Default));
6056 TokenKind tt;
6057 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
6058 return errorResult();
6061 if (!checkExportedName(TaggedParserAtomIndex::WellKnown::default_())) {
6062 return errorResult();
6065 switch (tt) {
6066 case TokenKind::Function:
6067 return exportDefaultFunctionDeclaration(begin, pos().begin);
6069 case TokenKind::Async: {
6070 TokenKind nextSameLine = TokenKind::Eof;
6071 if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
6072 return errorResult();
6075 if (nextSameLine == TokenKind::Function) {
6076 uint32_t toStringStart = pos().begin;
6077 tokenStream.consumeKnownToken(TokenKind::Function);
6078 return exportDefaultFunctionDeclaration(
6079 begin, toStringStart, FunctionAsyncKind::AsyncFunction);
6082 anyChars.ungetToken();
6083 return exportDefaultAssignExpr(begin);
6086 case TokenKind::Class:
6087 return exportDefaultClassDeclaration(begin);
6089 default:
6090 anyChars.ungetToken();
6091 return exportDefaultAssignExpr(begin);
6095 template <class ParseHandler, typename Unit>
6096 typename ParseHandler::NodeResult
6097 GeneralParser<ParseHandler, Unit>::exportDeclaration() {
6098 if (!abortIfSyntaxParser()) {
6099 return errorResult();
6102 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Export));
6104 if (!pc_->atModuleLevel()) {
6105 error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL);
6106 return errorResult();
6109 uint32_t begin = pos().begin;
6111 TokenKind tt;
6112 if (!tokenStream.getToken(&tt)) {
6113 return errorResult();
6115 switch (tt) {
6116 case TokenKind::Mul:
6117 return exportBatch(begin);
6119 case TokenKind::LeftCurly:
6120 return exportClause(begin);
6122 case TokenKind::Var:
6123 return exportVariableStatement(begin);
6125 case TokenKind::Function:
6126 return exportFunctionDeclaration(begin, pos().begin);
6128 case TokenKind::Async: {
6129 TokenKind nextSameLine = TokenKind::Eof;
6130 if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
6131 return errorResult();
6134 if (nextSameLine == TokenKind::Function) {
6135 uint32_t toStringStart = pos().begin;
6136 tokenStream.consumeKnownToken(TokenKind::Function);
6137 return exportFunctionDeclaration(begin, toStringStart,
6138 FunctionAsyncKind::AsyncFunction);
6141 error(JSMSG_DECLARATION_AFTER_EXPORT);
6142 return errorResult();
6145 case TokenKind::Class:
6146 return exportClassDeclaration(begin);
6148 case TokenKind::Const:
6149 return exportLexicalDeclaration(begin, DeclarationKind::Const);
6151 case TokenKind::Let:
6152 return exportLexicalDeclaration(begin, DeclarationKind::Let);
6154 case TokenKind::Default:
6155 return exportDefault(begin);
6157 default:
6158 error(JSMSG_DECLARATION_AFTER_EXPORT);
6159 return errorResult();
6163 template <class ParseHandler, typename Unit>
6164 typename ParseHandler::UnaryNodeResult
6165 GeneralParser<ParseHandler, Unit>::expressionStatement(
6166 YieldHandling yieldHandling, InvokedPrediction invoked) {
6167 anyChars.ungetToken();
6168 Node pnexpr;
6169 MOZ_TRY_VAR(pnexpr, expr(InAllowed, yieldHandling, TripledotProhibited,
6170 /* possibleError = */ nullptr, invoked));
6171 if (!matchOrInsertSemicolon()) {
6172 return errorResult();
6174 return handler_.newExprStatement(pnexpr, pos().end);
6177 template <class ParseHandler, typename Unit>
6178 typename ParseHandler::NodeResult
6179 GeneralParser<ParseHandler, Unit>::consequentOrAlternative(
6180 YieldHandling yieldHandling) {
6181 TokenKind next;
6182 if (!tokenStream.peekToken(&next, TokenStream::SlashIsRegExp)) {
6183 return errorResult();
6186 // Annex B.3.4 says that unbraced FunctionDeclarations under if/else in
6187 // non-strict code act as if they were braced: |if (x) function f() {}|
6188 // parses as |if (x) { function f() {} }|.
6190 // Careful! FunctionDeclaration doesn't include generators or async
6191 // functions.
6192 if (next == TokenKind::Function) {
6193 tokenStream.consumeKnownToken(next, TokenStream::SlashIsRegExp);
6195 // Parser::statement would handle this, but as this function handles
6196 // every other error case, it seems best to handle this.
6197 if (pc_->sc()->strict()) {
6198 error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
6199 return errorResult();
6202 TokenKind maybeStar;
6203 if (!tokenStream.peekToken(&maybeStar)) {
6204 return errorResult();
6207 if (maybeStar == TokenKind::Mul) {
6208 error(JSMSG_FORBIDDEN_AS_STATEMENT, "generator declarations");
6209 return errorResult();
6212 ParseContext::Statement stmt(pc_, StatementKind::Block);
6213 ParseContext::Scope scope(this);
6214 if (!scope.init(pc_)) {
6215 return errorResult();
6218 TokenPos funcPos = pos();
6219 Node fun;
6220 MOZ_TRY_VAR(fun, functionStmt(pos().begin, yieldHandling, NameRequired));
6222 ListNodeType block;
6223 MOZ_TRY_VAR(block, handler_.newStatementList(funcPos));
6225 handler_.addStatementToList(block, fun);
6226 return finishLexicalScope(scope, block);
6229 return statement(yieldHandling);
6232 template <class ParseHandler, typename Unit>
6233 typename ParseHandler::TernaryNodeResult
6234 GeneralParser<ParseHandler, Unit>::ifStatement(YieldHandling yieldHandling) {
6235 Vector<Node, 4> condList(fc_), thenList(fc_);
6236 Vector<uint32_t, 4> posList(fc_);
6237 Node elseBranch;
6239 ParseContext::Statement stmt(pc_, StatementKind::If);
6241 while (true) {
6242 uint32_t begin = pos().begin;
6244 /* An IF node has three kids: condition, then, and optional else. */
6245 Node cond;
6246 MOZ_TRY_VAR(cond, condition(InAllowed, yieldHandling));
6248 TokenKind tt;
6249 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
6250 return errorResult();
6253 Node thenBranch;
6254 MOZ_TRY_VAR(thenBranch, consequentOrAlternative(yieldHandling));
6256 if (!condList.append(cond) || !thenList.append(thenBranch) ||
6257 !posList.append(begin)) {
6258 return errorResult();
6261 bool matched;
6262 if (!tokenStream.matchToken(&matched, TokenKind::Else,
6263 TokenStream::SlashIsRegExp)) {
6264 return errorResult();
6266 if (matched) {
6267 if (!tokenStream.matchToken(&matched, TokenKind::If,
6268 TokenStream::SlashIsRegExp)) {
6269 return errorResult();
6271 if (matched) {
6272 continue;
6274 MOZ_TRY_VAR(elseBranch, consequentOrAlternative(yieldHandling));
6275 } else {
6276 elseBranch = null();
6278 break;
6281 TernaryNodeType ifNode;
6282 for (int i = condList.length() - 1; i >= 0; i--) {
6283 MOZ_TRY_VAR(ifNode, handler_.newIfStatement(posList[i], condList[i],
6284 thenList[i], elseBranch));
6285 elseBranch = ifNode;
6288 return ifNode;
6291 template <class ParseHandler, typename Unit>
6292 typename ParseHandler::BinaryNodeResult
6293 GeneralParser<ParseHandler, Unit>::doWhileStatement(
6294 YieldHandling yieldHandling) {
6295 uint32_t begin = pos().begin;
6296 ParseContext::Statement stmt(pc_, StatementKind::DoLoop);
6297 Node body;
6298 MOZ_TRY_VAR(body, statement(yieldHandling));
6299 if (!mustMatchToken(TokenKind::While, JSMSG_WHILE_AFTER_DO)) {
6300 return errorResult();
6302 Node cond;
6303 MOZ_TRY_VAR(cond, condition(InAllowed, yieldHandling));
6305 // The semicolon after do-while is even more optional than most
6306 // semicolons in JS. Web compat required this by 2004:
6307 // http://bugzilla.mozilla.org/show_bug.cgi?id=238945
6308 // ES3 and ES5 disagreed, but ES6 conforms to Web reality:
6309 // https://bugs.ecmascript.org/show_bug.cgi?id=157
6310 // To parse |do {} while (true) false| correctly, use SlashIsRegExp.
6311 bool ignored;
6312 if (!tokenStream.matchToken(&ignored, TokenKind::Semi,
6313 TokenStream::SlashIsRegExp)) {
6314 return errorResult();
6316 return handler_.newDoWhileStatement(body, cond, TokenPos(begin, pos().end));
6319 template <class ParseHandler, typename Unit>
6320 typename ParseHandler::BinaryNodeResult
6321 GeneralParser<ParseHandler, Unit>::whileStatement(YieldHandling yieldHandling) {
6322 uint32_t begin = pos().begin;
6323 ParseContext::Statement stmt(pc_, StatementKind::WhileLoop);
6324 Node cond;
6325 MOZ_TRY_VAR(cond, condition(InAllowed, yieldHandling));
6326 Node body;
6327 MOZ_TRY_VAR(body, statement(yieldHandling));
6328 return handler_.newWhileStatement(begin, cond, body);
6331 template <class ParseHandler, typename Unit>
6332 bool GeneralParser<ParseHandler, Unit>::matchInOrOf(bool* isForInp,
6333 bool* isForOfp) {
6334 TokenKind tt;
6335 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
6336 return false;
6339 *isForInp = tt == TokenKind::In;
6340 *isForOfp = tt == TokenKind::Of;
6341 if (!*isForInp && !*isForOfp) {
6342 anyChars.ungetToken();
6345 MOZ_ASSERT_IF(*isForInp || *isForOfp, *isForInp != *isForOfp);
6346 return true;
6349 template <class ParseHandler, typename Unit>
6350 bool GeneralParser<ParseHandler, Unit>::forHeadStart(
6351 YieldHandling yieldHandling, IteratorKind iterKind,
6352 ParseNodeKind* forHeadKind, Node* forInitialPart,
6353 Maybe<ParseContext::Scope>& forLoopLexicalScope,
6354 Node* forInOrOfExpression) {
6355 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftParen));
6357 TokenKind tt;
6358 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
6359 return false;
6362 // Super-duper easy case: |for (;| is a C-style for-loop with no init
6363 // component.
6364 if (tt == TokenKind::Semi) {
6365 *forInitialPart = null();
6366 *forHeadKind = ParseNodeKind::ForHead;
6367 return true;
6370 // Parsing after |for (var| is also relatively simple (from this method's
6371 // point of view). No block-related work complicates matters, so delegate
6372 // to Parser::declaration.
6373 if (tt == TokenKind::Var) {
6374 tokenStream.consumeKnownToken(tt, TokenStream::SlashIsRegExp);
6376 // Pass null for block object because |var| declarations don't use one.
6377 MOZ_TRY_VAR_OR_RETURN(*forInitialPart,
6378 declarationList(yieldHandling, ParseNodeKind::VarStmt,
6379 forHeadKind, forInOrOfExpression),
6380 false);
6381 return true;
6384 // Otherwise we have a lexical declaration or an expression.
6386 // For-in loop backwards compatibility requires that |let| starting a
6387 // for-loop that's not a (new to ES6) for-of loop, in non-strict mode code,
6388 // parse as an identifier. (|let| in for-of is always a declaration.)
6390 // For-of loops can't start with the token sequence "async of", because that
6391 // leads to a shift-reduce conflict when parsing |for (async of => {};;)| or
6392 // |for (async of [])|.
6393 bool parsingLexicalDeclaration = false;
6394 bool letIsIdentifier = false;
6395 bool startsWithForOf = false;
6396 if (tt == TokenKind::Const) {
6397 parsingLexicalDeclaration = true;
6398 tokenStream.consumeKnownToken(tt, TokenStream::SlashIsRegExp);
6399 } else if (tt == TokenKind::Let) {
6400 // We could have a {For,Lexical}Declaration, or we could have a
6401 // LeftHandSideExpression with lookahead restrictions so it's not
6402 // ambiguous with the former. Check for a continuation of the former
6403 // to decide which we have.
6404 tokenStream.consumeKnownToken(TokenKind::Let, TokenStream::SlashIsRegExp);
6406 TokenKind next;
6407 if (!tokenStream.peekToken(&next)) {
6408 return false;
6411 parsingLexicalDeclaration = nextTokenContinuesLetDeclaration(next);
6412 if (!parsingLexicalDeclaration) {
6413 anyChars.ungetToken();
6414 letIsIdentifier = true;
6416 } else if (tt == TokenKind::Async && iterKind == IteratorKind::Sync) {
6417 tokenStream.consumeKnownToken(TokenKind::Async, TokenStream::SlashIsRegExp);
6419 TokenKind next;
6420 if (!tokenStream.peekToken(&next)) {
6421 return false;
6424 if (next == TokenKind::Of) {
6425 startsWithForOf = true;
6427 anyChars.ungetToken();
6430 if (parsingLexicalDeclaration) {
6431 if (options().selfHostingMode) {
6432 error(JSMSG_SELFHOSTED_LEXICAL);
6433 return false;
6436 forLoopLexicalScope.emplace(this);
6437 if (!forLoopLexicalScope->init(pc_)) {
6438 return false;
6441 // Push a temporary ForLoopLexicalHead Statement that allows for
6442 // lexical declarations, as they are usually allowed only in braced
6443 // statements.
6444 ParseContext::Statement forHeadStmt(pc_, StatementKind::ForLoopLexicalHead);
6446 MOZ_TRY_VAR_OR_RETURN(
6447 *forInitialPart,
6448 declarationList(yieldHandling,
6449 tt == TokenKind::Const ? ParseNodeKind::ConstDecl
6450 : ParseNodeKind::LetDecl,
6451 forHeadKind, forInOrOfExpression),
6452 false);
6453 return true;
6456 uint32_t exprOffset;
6457 if (!tokenStream.peekOffset(&exprOffset, TokenStream::SlashIsRegExp)) {
6458 return false;
6461 // Finally, handle for-loops that start with expressions. Pass
6462 // |InProhibited| so that |in| isn't parsed in a RelationalExpression as a
6463 // binary operator. |in| makes it a for-in loop, *not* an |in| expression.
6464 PossibleError possibleError(*this);
6465 MOZ_TRY_VAR_OR_RETURN(
6466 *forInitialPart,
6467 expr(InProhibited, yieldHandling, TripledotProhibited, &possibleError),
6468 false);
6470 bool isForIn, isForOf;
6471 if (!matchInOrOf(&isForIn, &isForOf)) {
6472 return false;
6475 // If we don't encounter 'in'/'of', we have a for(;;) loop. We've handled
6476 // the init expression; the caller handles the rest.
6477 if (!isForIn && !isForOf) {
6478 if (!possibleError.checkForExpressionError()) {
6479 return false;
6482 *forHeadKind = ParseNodeKind::ForHead;
6483 return true;
6486 MOZ_ASSERT(isForIn != isForOf);
6488 // In a for-of loop, 'let' that starts the loop head is a |let| keyword,
6489 // per the [lookahead ≠ let] restriction on the LeftHandSideExpression
6490 // variant of such loops. Expressions that start with |let| can't be used
6491 // here.
6493 // var let = {};
6494 // for (let.prop of [1]) // BAD
6495 // break;
6497 // See ES6 13.7.
6498 if (isForOf && letIsIdentifier) {
6499 errorAt(exprOffset, JSMSG_BAD_STARTING_FOROF_LHS, "let");
6500 return false;
6503 // In a for-of loop, the LeftHandSideExpression isn't allowed to be an
6504 // identifier named "async" per the [lookahead ≠ async of] restriction.
6505 if (isForOf && startsWithForOf) {
6506 errorAt(exprOffset, JSMSG_BAD_STARTING_FOROF_LHS, "async of");
6507 return false;
6510 *forHeadKind = isForIn ? ParseNodeKind::ForIn : ParseNodeKind::ForOf;
6512 // Verify the left-hand side expression doesn't have a forbidden form.
6513 if (handler_.isUnparenthesizedDestructuringPattern(*forInitialPart)) {
6514 if (!possibleError.checkForDestructuringErrorOrWarning()) {
6515 return false;
6517 } else if (handler_.isName(*forInitialPart)) {
6518 if (const char* chars = nameIsArgumentsOrEval(*forInitialPart)) {
6519 // |chars| is "arguments" or "eval" here.
6520 if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) {
6521 return false;
6524 } else if (handler_.isPropertyOrPrivateMemberAccess(*forInitialPart)) {
6525 // Permitted: no additional testing/fixup needed.
6526 } else if (handler_.isFunctionCall(*forInitialPart)) {
6527 if (!strictModeErrorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE)) {
6528 return false;
6530 } else {
6531 errorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE);
6532 return false;
6535 if (!possibleError.checkForExpressionError()) {
6536 return false;
6539 // Finally, parse the iterated expression, making the for-loop's closing
6540 // ')' the next token.
6541 MOZ_TRY_VAR_OR_RETURN(*forInOrOfExpression,
6542 expressionAfterForInOrOf(*forHeadKind, yieldHandling),
6543 false);
6544 return true;
6547 template <class ParseHandler, typename Unit>
6548 typename ParseHandler::NodeResult
6549 GeneralParser<ParseHandler, Unit>::forStatement(YieldHandling yieldHandling) {
6550 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::For));
6552 uint32_t begin = pos().begin;
6554 ParseContext::Statement stmt(pc_, StatementKind::ForLoop);
6556 IteratorKind iterKind = IteratorKind::Sync;
6557 unsigned iflags = 0;
6559 if (pc_->isAsync() || pc_->sc()->isModuleContext()) {
6560 bool matched;
6561 if (!tokenStream.matchToken(&matched, TokenKind::Await)) {
6562 return errorResult();
6565 // If we come across a top level await here, mark the module as async.
6566 if (matched && pc_->sc()->isModuleContext() && !pc_->isAsync()) {
6567 if (!options().topLevelAwait) {
6568 error(JSMSG_TOP_LEVEL_AWAIT_NOT_SUPPORTED);
6569 return errorResult();
6571 pc_->sc()->asModuleContext()->setIsAsync();
6572 MOZ_ASSERT(pc_->isAsync());
6575 if (matched) {
6576 iflags |= JSITER_FORAWAITOF;
6577 iterKind = IteratorKind::Async;
6581 if (!mustMatchToken(TokenKind::LeftParen, [this](TokenKind actual) {
6582 this->error((actual == TokenKind::Await && !this->pc_->isAsync())
6583 ? JSMSG_FOR_AWAIT_OUTSIDE_ASYNC
6584 : JSMSG_PAREN_AFTER_FOR);
6585 })) {
6586 return errorResult();
6589 // ParseNodeKind::ForHead, ParseNodeKind::ForIn, or
6590 // ParseNodeKind::ForOf depending on the loop type.
6591 ParseNodeKind headKind;
6593 // |x| in either |for (x; ...; ...)| or |for (x in/of ...)|.
6594 Node startNode;
6596 // The next two variables are used to implement `for (let/const ...)`.
6598 // We generate an implicit block, wrapping the whole loop, to store loop
6599 // variables declared this way. Note that if the loop uses `for (var...)`
6600 // instead, those variables go on some existing enclosing scope, so no
6601 // implicit block scope is created.
6603 // Both variables remain null/none if the loop is any other form.
6605 // The static block scope for the implicit block scope.
6606 Maybe<ParseContext::Scope> forLoopLexicalScope;
6608 // The expression being iterated over, for for-in/of loops only. Unused
6609 // for for(;;) loops.
6610 Node iteratedExpr;
6612 // Parse the entirety of the loop-head for a for-in/of loop (so the next
6613 // token is the closing ')'):
6615 // for (... in/of ...) ...
6616 // ^next token
6618 // ...OR, parse up to the first ';' in a C-style for-loop:
6620 // for (...; ...; ...) ...
6621 // ^next token
6623 // In either case the subsequent token can be consistently accessed using
6624 // TokenStream::SlashIsDiv semantics.
6625 if (!forHeadStart(yieldHandling, iterKind, &headKind, &startNode,
6626 forLoopLexicalScope, &iteratedExpr)) {
6627 return errorResult();
6630 MOZ_ASSERT(headKind == ParseNodeKind::ForIn ||
6631 headKind == ParseNodeKind::ForOf ||
6632 headKind == ParseNodeKind::ForHead);
6634 if (iterKind == IteratorKind::Async && headKind != ParseNodeKind::ForOf) {
6635 errorAt(begin, JSMSG_FOR_AWAIT_NOT_OF);
6636 return errorResult();
6639 TernaryNodeType forHead;
6640 if (headKind == ParseNodeKind::ForHead) {
6641 Node init = startNode;
6643 // Look for an operand: |for (;| means we might have already examined
6644 // this semicolon with that modifier.
6645 if (!mustMatchToken(TokenKind::Semi, JSMSG_SEMI_AFTER_FOR_INIT)) {
6646 return errorResult();
6649 TokenKind tt;
6650 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
6651 return errorResult();
6654 Node test;
6655 if (tt == TokenKind::Semi) {
6656 test = null();
6657 } else {
6658 MOZ_TRY_VAR(test, expr(InAllowed, yieldHandling, TripledotProhibited));
6661 if (!mustMatchToken(TokenKind::Semi, JSMSG_SEMI_AFTER_FOR_COND)) {
6662 return errorResult();
6665 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
6666 return errorResult();
6669 Node update;
6670 if (tt == TokenKind::RightParen) {
6671 update = null();
6672 } else {
6673 MOZ_TRY_VAR(update, expr(InAllowed, yieldHandling, TripledotProhibited));
6676 if (!mustMatchToken(TokenKind::RightParen, JSMSG_PAREN_AFTER_FOR_CTRL)) {
6677 return errorResult();
6680 TokenPos headPos(begin, pos().end);
6681 MOZ_TRY_VAR(forHead, handler_.newForHead(init, test, update, headPos));
6682 } else {
6683 MOZ_ASSERT(headKind == ParseNodeKind::ForIn ||
6684 headKind == ParseNodeKind::ForOf);
6686 // |target| is the LeftHandSideExpression or declaration to which the
6687 // per-iteration value (an arbitrary value exposed by the iteration
6688 // protocol, or a string naming a property) is assigned.
6689 Node target = startNode;
6691 // Parse the rest of the for-in/of head.
6692 if (headKind == ParseNodeKind::ForIn) {
6693 stmt.refineForKind(StatementKind::ForInLoop);
6694 } else {
6695 stmt.refineForKind(StatementKind::ForOfLoop);
6698 // Parser::declaration consumed everything up to the closing ')'. That
6699 // token follows an {Assignment,}Expression and so must be interpreted
6700 // as an operand to be consistent with normal expression tokenizing.
6701 if (!mustMatchToken(TokenKind::RightParen, JSMSG_PAREN_AFTER_FOR_CTRL)) {
6702 return errorResult();
6705 TokenPos headPos(begin, pos().end);
6706 MOZ_TRY_VAR(forHead, handler_.newForInOrOfHead(headKind, target,
6707 iteratedExpr, headPos));
6710 Node body;
6711 MOZ_TRY_VAR(body, statement(yieldHandling));
6713 ForNodeType forLoop;
6714 MOZ_TRY_VAR(forLoop, handler_.newForStatement(begin, forHead, body, iflags));
6716 if (forLoopLexicalScope) {
6717 return finishLexicalScope(*forLoopLexicalScope, forLoop);
6720 return forLoop;
6723 template <class ParseHandler, typename Unit>
6724 typename ParseHandler::SwitchStatementResult
6725 GeneralParser<ParseHandler, Unit>::switchStatement(
6726 YieldHandling yieldHandling) {
6727 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Switch));
6728 uint32_t begin = pos().begin;
6730 if (!mustMatchToken(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_SWITCH)) {
6731 return errorResult();
6734 Node discriminant;
6735 MOZ_TRY_VAR(discriminant,
6736 exprInParens(InAllowed, yieldHandling, TripledotProhibited));
6738 if (!mustMatchToken(TokenKind::RightParen, JSMSG_PAREN_AFTER_SWITCH)) {
6739 return errorResult();
6741 if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_SWITCH)) {
6742 return errorResult();
6745 ParseContext::Statement stmt(pc_, StatementKind::Switch);
6746 ParseContext::Scope scope(this);
6747 if (!scope.init(pc_)) {
6748 return errorResult();
6751 ListNodeType caseList;
6752 MOZ_TRY_VAR(caseList, handler_.newStatementList(pos()));
6754 bool seenDefault = false;
6755 TokenKind tt;
6756 while (true) {
6757 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
6758 return errorResult();
6760 if (tt == TokenKind::RightCurly) {
6761 break;
6763 uint32_t caseBegin = pos().begin;
6765 Node caseExpr;
6766 switch (tt) {
6767 case TokenKind::Default:
6768 if (seenDefault) {
6769 error(JSMSG_TOO_MANY_DEFAULTS);
6770 return errorResult();
6772 seenDefault = true;
6773 caseExpr = null(); // The default case has pn_left == nullptr.
6774 break;
6776 case TokenKind::Case:
6777 MOZ_TRY_VAR(caseExpr,
6778 expr(InAllowed, yieldHandling, TripledotProhibited));
6779 break;
6781 default:
6782 error(JSMSG_BAD_SWITCH);
6783 return errorResult();
6786 if (!mustMatchToken(TokenKind::Colon, JSMSG_COLON_AFTER_CASE)) {
6787 return errorResult();
6790 ListNodeType body;
6791 MOZ_TRY_VAR(body, handler_.newStatementList(pos()));
6793 bool afterReturn = false;
6794 bool warnedAboutStatementsAfterReturn = false;
6795 uint32_t statementBegin = 0;
6796 while (true) {
6797 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
6798 return errorResult();
6800 if (tt == TokenKind::RightCurly || tt == TokenKind::Case ||
6801 tt == TokenKind::Default) {
6802 break;
6804 if (afterReturn) {
6805 if (!tokenStream.peekOffset(&statementBegin,
6806 TokenStream::SlashIsRegExp)) {
6807 return errorResult();
6810 Node stmt;
6811 MOZ_TRY_VAR(stmt, statementListItem(yieldHandling));
6812 if (!warnedAboutStatementsAfterReturn) {
6813 if (afterReturn) {
6814 if (!handler_.isStatementPermittedAfterReturnStatement(stmt)) {
6815 if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) {
6816 return errorResult();
6819 warnedAboutStatementsAfterReturn = true;
6821 } else if (handler_.isReturnStatement(stmt)) {
6822 afterReturn = true;
6825 handler_.addStatementToList(body, stmt);
6828 CaseClauseType caseClause;
6829 MOZ_TRY_VAR(caseClause,
6830 handler_.newCaseOrDefault(caseBegin, caseExpr, body));
6831 handler_.addCaseStatementToList(caseList, caseClause);
6834 LexicalScopeNodeType lexicalForCaseList;
6835 MOZ_TRY_VAR(lexicalForCaseList, finishLexicalScope(scope, caseList));
6837 handler_.setEndPosition(lexicalForCaseList, pos().end);
6839 return handler_.newSwitchStatement(begin, discriminant, lexicalForCaseList,
6840 seenDefault);
6843 template <class ParseHandler, typename Unit>
6844 typename ParseHandler::ContinueStatementResult
6845 GeneralParser<ParseHandler, Unit>::continueStatement(
6846 YieldHandling yieldHandling) {
6847 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Continue));
6848 uint32_t begin = pos().begin;
6850 TaggedParserAtomIndex label;
6851 if (!matchLabel(yieldHandling, &label)) {
6852 return errorResult();
6855 auto validity = pc_->checkContinueStatement(label);
6856 if (validity.isErr()) {
6857 switch (validity.unwrapErr()) {
6858 case ParseContext::ContinueStatementError::NotInALoop:
6859 errorAt(begin, JSMSG_BAD_CONTINUE);
6860 break;
6861 case ParseContext::ContinueStatementError::LabelNotFound:
6862 error(JSMSG_LABEL_NOT_FOUND);
6863 break;
6865 return errorResult();
6868 if (!matchOrInsertSemicolon()) {
6869 return errorResult();
6872 return handler_.newContinueStatement(label, TokenPos(begin, pos().end));
6875 template <class ParseHandler, typename Unit>
6876 typename ParseHandler::BreakStatementResult
6877 GeneralParser<ParseHandler, Unit>::breakStatement(YieldHandling yieldHandling) {
6878 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Break));
6879 uint32_t begin = pos().begin;
6881 TaggedParserAtomIndex label;
6882 if (!matchLabel(yieldHandling, &label)) {
6883 return errorResult();
6886 auto validity = pc_->checkBreakStatement(label);
6887 if (validity.isErr()) {
6888 switch (validity.unwrapErr()) {
6889 case ParseContext::BreakStatementError::ToughBreak:
6890 errorAt(begin, JSMSG_TOUGH_BREAK);
6891 return errorResult();
6892 case ParseContext::BreakStatementError::LabelNotFound:
6893 error(JSMSG_LABEL_NOT_FOUND);
6894 return errorResult();
6898 if (!matchOrInsertSemicolon()) {
6899 return errorResult();
6902 return handler_.newBreakStatement(label, TokenPos(begin, pos().end));
6905 template <class ParseHandler, typename Unit>
6906 typename ParseHandler::UnaryNodeResult
6907 GeneralParser<ParseHandler, Unit>::returnStatement(
6908 YieldHandling yieldHandling) {
6909 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Return));
6910 uint32_t begin = pos().begin;
6912 MOZ_ASSERT(pc_->isFunctionBox());
6914 // Parse an optional operand.
6916 // This is ugly, but we don't want to require a semicolon.
6917 Node exprNode;
6918 TokenKind tt = TokenKind::Eof;
6919 if (!tokenStream.peekTokenSameLine(&tt, TokenStream::SlashIsRegExp)) {
6920 return errorResult();
6922 switch (tt) {
6923 case TokenKind::Eol:
6924 case TokenKind::Eof:
6925 case TokenKind::Semi:
6926 case TokenKind::RightCurly:
6927 exprNode = null();
6928 break;
6929 default: {
6930 MOZ_TRY_VAR(exprNode,
6931 expr(InAllowed, yieldHandling, TripledotProhibited));
6935 if (!matchOrInsertSemicolon()) {
6936 return errorResult();
6939 return handler_.newReturnStatement(exprNode, TokenPos(begin, pos().end));
6942 template <class ParseHandler, typename Unit>
6943 typename ParseHandler::UnaryNodeResult
6944 GeneralParser<ParseHandler, Unit>::yieldExpression(InHandling inHandling) {
6945 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Yield));
6946 uint32_t begin = pos().begin;
6948 MOZ_ASSERT(pc_->isGenerator());
6949 MOZ_ASSERT(pc_->isFunctionBox());
6951 pc_->lastYieldOffset = begin;
6953 Node exprNode;
6954 ParseNodeKind kind = ParseNodeKind::YieldExpr;
6955 TokenKind tt = TokenKind::Eof;
6956 if (!tokenStream.peekTokenSameLine(&tt, TokenStream::SlashIsRegExp)) {
6957 return errorResult();
6959 switch (tt) {
6960 // TokenKind::Eol is special; it implements the [no LineTerminator here]
6961 // quirk in the grammar.
6962 case TokenKind::Eol:
6963 // The rest of these make up the complete set of tokens that can
6964 // appear after any of the places where AssignmentExpression is used
6965 // throughout the grammar. Conveniently, none of them can also be the
6966 // start an expression.
6967 case TokenKind::Eof:
6968 case TokenKind::Semi:
6969 case TokenKind::RightCurly:
6970 case TokenKind::RightBracket:
6971 case TokenKind::RightParen:
6972 case TokenKind::Colon:
6973 case TokenKind::Comma:
6974 case TokenKind::In: // Annex B.3.6 `for (x = yield in y) ;`
6975 // No value.
6976 exprNode = null();
6977 break;
6978 case TokenKind::Mul:
6979 kind = ParseNodeKind::YieldStarExpr;
6980 tokenStream.consumeKnownToken(TokenKind::Mul, TokenStream::SlashIsRegExp);
6981 [[fallthrough]];
6982 default:
6983 MOZ_TRY_VAR(exprNode,
6984 assignExpr(inHandling, YieldIsKeyword, TripledotProhibited));
6986 if (kind == ParseNodeKind::YieldStarExpr) {
6987 return handler_.newYieldStarExpression(begin, exprNode);
6989 return handler_.newYieldExpression(begin, exprNode);
6992 template <class ParseHandler, typename Unit>
6993 typename ParseHandler::BinaryNodeResult
6994 GeneralParser<ParseHandler, Unit>::withStatement(YieldHandling yieldHandling) {
6995 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::With));
6996 uint32_t begin = pos().begin;
6998 if (pc_->sc()->strict()) {
6999 if (!strictModeError(JSMSG_STRICT_CODE_WITH)) {
7000 return errorResult();
7004 if (!mustMatchToken(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_WITH)) {
7005 return errorResult();
7008 Node objectExpr;
7009 MOZ_TRY_VAR(objectExpr,
7010 exprInParens(InAllowed, yieldHandling, TripledotProhibited));
7012 if (!mustMatchToken(TokenKind::RightParen, JSMSG_PAREN_AFTER_WITH)) {
7013 return errorResult();
7016 Node innerBlock;
7018 ParseContext::Statement stmt(pc_, StatementKind::With);
7019 MOZ_TRY_VAR(innerBlock, statement(yieldHandling));
7022 pc_->sc()->setBindingsAccessedDynamically();
7024 return handler_.newWithStatement(begin, objectExpr, innerBlock);
7027 template <class ParseHandler, typename Unit>
7028 typename ParseHandler::NodeResult
7029 GeneralParser<ParseHandler, Unit>::labeledItem(YieldHandling yieldHandling) {
7030 TokenKind tt;
7031 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
7032 return errorResult();
7035 if (tt == TokenKind::Function) {
7036 TokenKind next;
7037 if (!tokenStream.peekToken(&next)) {
7038 return errorResult();
7041 // GeneratorDeclaration is only matched by HoistableDeclaration in
7042 // StatementListItem, so generators can't be inside labels.
7043 if (next == TokenKind::Mul) {
7044 error(JSMSG_GENERATOR_LABEL);
7045 return errorResult();
7048 // Per 13.13.1 it's a syntax error if LabelledItem: FunctionDeclaration
7049 // is ever matched. Per Annex B.3.2 that modifies this text, this
7050 // applies only to strict mode code.
7051 if (pc_->sc()->strict()) {
7052 error(JSMSG_FUNCTION_LABEL);
7053 return errorResult();
7056 return functionStmt(pos().begin, yieldHandling, NameRequired);
7059 anyChars.ungetToken();
7060 return statement(yieldHandling);
7063 template <class ParseHandler, typename Unit>
7064 typename ParseHandler::LabeledStatementResult
7065 GeneralParser<ParseHandler, Unit>::labeledStatement(
7066 YieldHandling yieldHandling) {
7067 TaggedParserAtomIndex label = labelIdentifier(yieldHandling);
7068 if (!label) {
7069 return errorResult();
7072 auto hasSameLabel = [&label](ParseContext::LabelStatement* stmt) {
7073 return stmt->label() == label;
7076 uint32_t begin = pos().begin;
7078 if (pc_->template findInnermostStatement<ParseContext::LabelStatement>(
7079 hasSameLabel)) {
7080 errorAt(begin, JSMSG_DUPLICATE_LABEL);
7081 return errorResult();
7084 tokenStream.consumeKnownToken(TokenKind::Colon);
7086 /* Push a label struct and parse the statement. */
7087 ParseContext::LabelStatement stmt(pc_, label);
7088 Node pn;
7089 MOZ_TRY_VAR(pn, labeledItem(yieldHandling));
7091 return handler_.newLabeledStatement(label, pn, begin);
7094 template <class ParseHandler, typename Unit>
7095 typename ParseHandler::UnaryNodeResult
7096 GeneralParser<ParseHandler, Unit>::throwStatement(YieldHandling yieldHandling) {
7097 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Throw));
7098 uint32_t begin = pos().begin;
7100 /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */
7101 TokenKind tt = TokenKind::Eof;
7102 if (!tokenStream.peekTokenSameLine(&tt, TokenStream::SlashIsRegExp)) {
7103 return errorResult();
7105 if (tt == TokenKind::Eof || tt == TokenKind::Semi ||
7106 tt == TokenKind::RightCurly) {
7107 error(JSMSG_MISSING_EXPR_AFTER_THROW);
7108 return errorResult();
7110 if (tt == TokenKind::Eol) {
7111 error(JSMSG_LINE_BREAK_AFTER_THROW);
7112 return errorResult();
7115 Node throwExpr;
7116 MOZ_TRY_VAR(throwExpr, expr(InAllowed, yieldHandling, TripledotProhibited));
7118 if (!matchOrInsertSemicolon()) {
7119 return errorResult();
7122 return handler_.newThrowStatement(throwExpr, TokenPos(begin, pos().end));
7125 template <class ParseHandler, typename Unit>
7126 typename ParseHandler::TernaryNodeResult
7127 GeneralParser<ParseHandler, Unit>::tryStatement(YieldHandling yieldHandling) {
7128 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Try));
7129 uint32_t begin = pos().begin;
7132 * try nodes are ternary.
7133 * kid1 is the try statement
7134 * kid2 is the catch node list or null
7135 * kid3 is the finally statement
7137 * catch nodes are binary.
7138 * left is the catch-name/pattern or null
7139 * right is the catch block
7141 * catch lvalue nodes are either:
7142 * a single identifier
7143 * TokenKind::RightBracket for a destructuring left-hand side
7144 * TokenKind::RightCurly for a destructuring left-hand side
7146 * finally nodes are TokenKind::LeftCurly statement lists.
7149 Node innerBlock;
7151 if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_TRY)) {
7152 return errorResult();
7155 uint32_t openedPos = pos().begin;
7157 ParseContext::Statement stmt(pc_, StatementKind::Try);
7158 ParseContext::Scope scope(this);
7159 if (!scope.init(pc_)) {
7160 return errorResult();
7163 MOZ_TRY_VAR(innerBlock, statementList(yieldHandling));
7165 MOZ_TRY_VAR(innerBlock, finishLexicalScope(scope, innerBlock));
7167 if (!mustMatchToken(
7168 TokenKind::RightCurly, [this, openedPos](TokenKind actual) {
7169 this->reportMissingClosing(JSMSG_CURLY_AFTER_TRY,
7170 JSMSG_CURLY_OPENED, openedPos);
7171 })) {
7172 return errorResult();
7176 LexicalScopeNodeType catchScope = null();
7177 TokenKind tt;
7178 if (!tokenStream.getToken(&tt)) {
7179 return errorResult();
7181 if (tt == TokenKind::Catch) {
7183 * Create a lexical scope node around the whole catch clause,
7184 * including the head.
7186 ParseContext::Statement stmt(pc_, StatementKind::Catch);
7187 ParseContext::Scope scope(this);
7188 if (!scope.init(pc_)) {
7189 return errorResult();
7193 * Legal catch forms are:
7194 * catch (lhs) {
7195 * catch {
7196 * where lhs is a name or a destructuring left-hand side.
7198 bool omittedBinding;
7199 if (!tokenStream.matchToken(&omittedBinding, TokenKind::LeftCurly)) {
7200 return errorResult();
7203 Node catchName;
7204 if (omittedBinding) {
7205 catchName = null();
7206 } else {
7207 if (!mustMatchToken(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_CATCH)) {
7208 return errorResult();
7211 if (!tokenStream.getToken(&tt)) {
7212 return errorResult();
7214 switch (tt) {
7215 case TokenKind::LeftBracket:
7216 case TokenKind::LeftCurly:
7217 MOZ_TRY_VAR(catchName,
7218 destructuringDeclaration(DeclarationKind::CatchParameter,
7219 yieldHandling, tt));
7220 break;
7222 default: {
7223 if (!TokenKindIsPossibleIdentifierName(tt)) {
7224 error(JSMSG_CATCH_IDENTIFIER);
7225 return errorResult();
7228 MOZ_TRY_VAR(catchName,
7229 bindingIdentifier(DeclarationKind::SimpleCatchParameter,
7230 yieldHandling));
7231 break;
7235 if (!mustMatchToken(TokenKind::RightParen, JSMSG_PAREN_AFTER_CATCH)) {
7236 return errorResult();
7239 if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_CATCH)) {
7240 return errorResult();
7244 LexicalScopeNodeType catchBody;
7245 MOZ_TRY_VAR(catchBody, catchBlockStatement(yieldHandling, scope));
7247 MOZ_TRY_VAR(catchScope, finishLexicalScope(scope, catchBody));
7249 if (!handler_.setupCatchScope(catchScope, catchName, catchBody)) {
7250 return errorResult();
7252 handler_.setEndPosition(catchScope, pos().end);
7254 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
7255 return errorResult();
7259 Node finallyBlock = null();
7261 if (tt == TokenKind::Finally) {
7262 if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_FINALLY)) {
7263 return errorResult();
7266 uint32_t openedPos = pos().begin;
7268 ParseContext::Statement stmt(pc_, StatementKind::Finally);
7269 ParseContext::Scope scope(this);
7270 if (!scope.init(pc_)) {
7271 return errorResult();
7274 MOZ_TRY_VAR(finallyBlock, statementList(yieldHandling));
7276 MOZ_TRY_VAR(finallyBlock, finishLexicalScope(scope, finallyBlock));
7278 if (!mustMatchToken(
7279 TokenKind::RightCurly, [this, openedPos](TokenKind actual) {
7280 this->reportMissingClosing(JSMSG_CURLY_AFTER_FINALLY,
7281 JSMSG_CURLY_OPENED, openedPos);
7282 })) {
7283 return errorResult();
7285 } else {
7286 anyChars.ungetToken();
7288 if (!catchScope && !finallyBlock) {
7289 error(JSMSG_CATCH_OR_FINALLY);
7290 return errorResult();
7293 return handler_.newTryStatement(begin, innerBlock, catchScope, finallyBlock);
7296 template <class ParseHandler, typename Unit>
7297 typename ParseHandler::LexicalScopeNodeResult
7298 GeneralParser<ParseHandler, Unit>::catchBlockStatement(
7299 YieldHandling yieldHandling, ParseContext::Scope& catchParamScope) {
7300 uint32_t openedPos = pos().begin;
7302 ParseContext::Statement stmt(pc_, StatementKind::Block);
7304 // ES 13.15.7 CatchClauseEvaluation
7306 // Step 8 means that the body of a catch block always has an additional
7307 // lexical scope.
7308 ParseContext::Scope scope(this);
7309 if (!scope.init(pc_)) {
7310 return errorResult();
7313 // The catch parameter names cannot be redeclared inside the catch
7314 // block, so declare the name in the inner scope.
7315 if (!scope.addCatchParameters(pc_, catchParamScope)) {
7316 return errorResult();
7319 ListNodeType list;
7320 MOZ_TRY_VAR(list, statementList(yieldHandling));
7322 if (!mustMatchToken(
7323 TokenKind::RightCurly, [this, openedPos](TokenKind actual) {
7324 this->reportMissingClosing(JSMSG_CURLY_AFTER_CATCH,
7325 JSMSG_CURLY_OPENED, openedPos);
7326 })) {
7327 return errorResult();
7330 // The catch parameter names are not bound in the body scope, so remove
7331 // them before generating bindings.
7332 scope.removeCatchParameters(pc_, catchParamScope);
7333 return finishLexicalScope(scope, list);
7336 template <class ParseHandler, typename Unit>
7337 typename ParseHandler::DebuggerStatementResult
7338 GeneralParser<ParseHandler, Unit>::debuggerStatement() {
7339 TokenPos p;
7340 p.begin = pos().begin;
7341 if (!matchOrInsertSemicolon()) {
7342 return errorResult();
7344 p.end = pos().end;
7346 return handler_.newDebuggerStatement(p);
7349 static AccessorType ToAccessorType(PropertyType propType) {
7350 switch (propType) {
7351 case PropertyType::Getter:
7352 return AccessorType::Getter;
7353 case PropertyType::Setter:
7354 return AccessorType::Setter;
7355 case PropertyType::Normal:
7356 case PropertyType::Method:
7357 case PropertyType::GeneratorMethod:
7358 case PropertyType::AsyncMethod:
7359 case PropertyType::AsyncGeneratorMethod:
7360 case PropertyType::Constructor:
7361 case PropertyType::DerivedConstructor:
7362 return AccessorType::None;
7363 default:
7364 MOZ_CRASH("unexpected property type");
7368 #ifdef ENABLE_DECORATORS
7369 template <class ParseHandler, typename Unit>
7370 typename ParseHandler::ListNodeResult
7371 GeneralParser<ParseHandler, Unit>::decoratorList(YieldHandling yieldHandling) {
7372 ListNodeType decorators;
7373 MOZ_TRY_VAR(decorators,
7374 handler_.newList(ParseNodeKind::DecoratorList, pos()));
7376 // Build a decorator list element. At each entry point to this loop we have
7377 // already consumed the |@| token
7378 TokenKind tt;
7379 for (;;) {
7380 if (!tokenStream.getToken(&tt, TokenStream::SlashIsInvalid)) {
7381 return errorResult();
7384 Node decorator;
7385 MOZ_TRY_VAR(decorator, decoratorExpr(yieldHandling, tt));
7387 handler_.addList(decorators, decorator);
7389 if (!tokenStream.getToken(&tt)) {
7390 return errorResult();
7392 if (tt != TokenKind::At) {
7393 anyChars.ungetToken();
7394 break;
7397 return decorators;
7399 #endif
7401 template <class ParseHandler, typename Unit>
7402 bool GeneralParser<ParseHandler, Unit>::classMember(
7403 YieldHandling yieldHandling, const ParseContext::ClassStatement& classStmt,
7404 TaggedParserAtomIndex className, uint32_t classStartOffset,
7405 HasHeritage hasHeritage, ClassInitializedMembers& classInitializedMembers,
7406 ListNodeType& classMembers, bool* done) {
7407 *done = false;
7409 TokenKind tt;
7410 if (!tokenStream.getToken(&tt, TokenStream::SlashIsInvalid)) {
7411 return false;
7413 if (tt == TokenKind::RightCurly) {
7414 *done = true;
7415 return true;
7418 if (tt == TokenKind::Semi) {
7419 return true;
7422 #ifdef ENABLE_DECORATORS
7423 ListNodeType decorators = null();
7424 if (tt == TokenKind::At) {
7425 MOZ_TRY_VAR_OR_RETURN(decorators, decoratorList(yieldHandling), false);
7427 if (!tokenStream.getToken(&tt, TokenStream::SlashIsInvalid)) {
7428 return false;
7431 #endif
7433 bool isStatic = false;
7434 if (tt == TokenKind::Static) {
7435 if (!tokenStream.peekToken(&tt)) {
7436 return false;
7439 if (tt == TokenKind::LeftCurly) {
7440 /* Parsing static class block: static { ... } */
7441 FunctionNodeType staticBlockBody;
7442 MOZ_TRY_VAR_OR_RETURN(staticBlockBody,
7443 staticClassBlock(classInitializedMembers), false);
7445 StaticClassBlockType classBlock;
7446 MOZ_TRY_VAR_OR_RETURN(
7447 classBlock, handler_.newStaticClassBlock(staticBlockBody), false);
7449 return handler_.addClassMemberDefinition(classMembers, classBlock);
7452 if (tt != TokenKind::LeftParen && tt != TokenKind::Assign &&
7453 tt != TokenKind::Semi && tt != TokenKind::RightCurly) {
7454 isStatic = true;
7455 } else {
7456 anyChars.ungetToken();
7458 } else {
7459 anyChars.ungetToken();
7462 uint32_t propNameOffset;
7463 if (!tokenStream.peekOffset(&propNameOffset, TokenStream::SlashIsInvalid)) {
7464 return false;
7467 TaggedParserAtomIndex propAtom;
7468 PropertyType propType;
7469 Node propName;
7470 MOZ_TRY_VAR_OR_RETURN(
7471 propName,
7472 propertyOrMethodName(yieldHandling, PropertyNameInClass,
7473 /* maybeDecl = */ Nothing(), classMembers, &propType,
7474 &propAtom),
7475 false);
7477 if (propType == PropertyType::Field ||
7478 propType == PropertyType::FieldWithAccessor) {
7479 if (isStatic) {
7480 if (propAtom == TaggedParserAtomIndex::WellKnown::prototype()) {
7481 errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
7482 return false;
7486 if (propAtom == TaggedParserAtomIndex::WellKnown::constructor()) {
7487 errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
7488 return false;
7491 if (handler_.isPrivateName(propName)) {
7492 if (propAtom == TaggedParserAtomIndex::WellKnown::hash_constructor_()) {
7493 errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
7494 return false;
7497 auto privateName = propAtom;
7498 if (!noteDeclaredPrivateName(
7499 propName, privateName, propType,
7500 isStatic ? FieldPlacement::Static : FieldPlacement::Instance,
7501 pos())) {
7502 return false;
7506 #ifdef ENABLE_DECORATORS
7507 ClassMethodType accessorGetterNode = null();
7508 ClassMethodType accessorSetterNode = null();
7509 if (propType == PropertyType::FieldWithAccessor) {
7510 // Decorators Proposal
7511 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-runtime-semantics-classfielddefinitionevaluation
7513 // FieldDefinition : accessor ClassElementName Initializeropt
7515 // Step 1. Let name be the result of evaluating ClassElementName.
7516 // ...
7517 // Step 3. Let privateStateDesc be the string-concatenation of name
7518 // and " accessor storage".
7519 StringBuffer privateStateDesc(fc_);
7520 if (!privateStateDesc.append(this->parserAtoms(), propAtom)) {
7521 return false;
7523 if (!privateStateDesc.append(" accessor storage")) {
7524 return false;
7526 // Step 4. Let privateStateName be a new Private Name whose
7527 // [[Description]] value is privateStateDesc.
7528 TokenPos propNamePos(propNameOffset, pos().end);
7529 auto privateStateName =
7530 privateStateDesc.finishParserAtom(this->parserAtoms(), fc_);
7531 if (!noteDeclaredPrivateName(
7532 propName, privateStateName, propType,
7533 isStatic ? FieldPlacement::Static : FieldPlacement::Instance,
7534 propNamePos)) {
7535 return false;
7538 // Step 5. Let getter be MakeAutoAccessorGetter(homeObject, name,
7539 // privateStateName).
7540 MOZ_TRY_VAR_OR_RETURN(
7541 accessorGetterNode,
7542 synthesizeAccessor(propName, propNamePos, propAtom, privateStateName,
7543 isStatic, FunctionSyntaxKind::Getter,
7544 classInitializedMembers),
7545 false);
7547 // If the accessor is not decorated or is a non-static private field,
7548 // add it to the class here. Otherwise, we'll handle this when the
7549 // decorators are called. We don't need to keep a reference to the node
7550 // after this except for non-static private accessors. Please see the
7551 // comment in the definition of ClassField for details.
7552 bool addAccessorImmediately =
7553 !decorators || (!isStatic && handler_.isPrivateName(propName));
7554 if (addAccessorImmediately) {
7555 if (!handler_.addClassMemberDefinition(classMembers,
7556 accessorGetterNode)) {
7557 return false;
7559 if (!handler_.isPrivateName(propName)) {
7560 accessorGetterNode = null();
7564 // Step 6. Let setter be MakeAutoAccessorSetter(homeObject, name,
7565 // privateStateName).
7566 MOZ_TRY_VAR_OR_RETURN(
7567 accessorSetterNode,
7568 synthesizeAccessor(propName, propNamePos, propAtom, privateStateName,
7569 isStatic, FunctionSyntaxKind::Setter,
7570 classInitializedMembers),
7571 false);
7573 if (addAccessorImmediately) {
7574 if (!handler_.addClassMemberDefinition(classMembers,
7575 accessorSetterNode)) {
7576 return false;
7578 if (!handler_.isPrivateName(propName)) {
7579 accessorSetterNode = null();
7583 // Step 10. Return ClassElementDefinition Record { [[Key]]: name,
7584 // [[Kind]]: accessor, [[Get]]: getter, [[Set]]: setter,
7585 // [[BackingStorageKey]]: privateStateName, [[Initializers]]:
7586 // initializers, [[Decorators]]: empty }.
7587 MOZ_TRY_VAR_OR_RETURN(
7588 propName, handler_.newPrivateName(privateStateName, pos()), false);
7589 propAtom = privateStateName;
7590 // We maintain `decorators` here to perform this step at the same time:
7591 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-static-semantics-classelementevaluation
7592 // 4. Set fieldDefinition.[[Decorators]] to decorators.
7594 #endif
7595 if (isStatic) {
7596 classInitializedMembers.staticFields++;
7597 } else {
7598 classInitializedMembers.instanceFields++;
7601 TokenPos propNamePos(propNameOffset, pos().end);
7602 FunctionNodeType initializer;
7603 MOZ_TRY_VAR_OR_RETURN(
7604 initializer,
7605 fieldInitializerOpt(propNamePos, propName, propAtom,
7606 classInitializedMembers, isStatic, hasHeritage),
7607 false);
7609 if (!matchOrInsertSemicolon(TokenStream::SlashIsInvalid)) {
7610 return false;
7613 ClassFieldType field;
7614 MOZ_TRY_VAR_OR_RETURN(field,
7615 handler_.newClassFieldDefinition(
7616 propName, initializer, isStatic
7617 #ifdef ENABLE_DECORATORS
7619 decorators, accessorGetterNode, accessorSetterNode
7620 #endif
7622 false);
7624 return handler_.addClassMemberDefinition(classMembers, field);
7627 if (propType != PropertyType::Getter && propType != PropertyType::Setter &&
7628 propType != PropertyType::Method &&
7629 propType != PropertyType::GeneratorMethod &&
7630 propType != PropertyType::AsyncMethod &&
7631 propType != PropertyType::AsyncGeneratorMethod) {
7632 errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
7633 return false;
7636 bool isConstructor =
7637 !isStatic && propAtom == TaggedParserAtomIndex::WellKnown::constructor();
7638 if (isConstructor) {
7639 if (propType != PropertyType::Method) {
7640 errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
7641 return false;
7643 if (classStmt.constructorBox) {
7644 errorAt(propNameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor");
7645 return false;
7647 propType = hasHeritage == HasHeritage::Yes
7648 ? PropertyType::DerivedConstructor
7649 : PropertyType::Constructor;
7650 } else if (isStatic &&
7651 propAtom == TaggedParserAtomIndex::WellKnown::prototype()) {
7652 errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
7653 return false;
7656 TaggedParserAtomIndex funName;
7657 switch (propType) {
7658 case PropertyType::Getter:
7659 case PropertyType::Setter: {
7660 bool hasStaticName =
7661 !anyChars.isCurrentTokenType(TokenKind::RightBracket) && propAtom;
7662 if (hasStaticName) {
7663 funName = prefixAccessorName(propType, propAtom);
7664 if (!funName) {
7665 return false;
7668 break;
7670 case PropertyType::Constructor:
7671 case PropertyType::DerivedConstructor:
7672 funName = className;
7673 break;
7674 default:
7675 if (!anyChars.isCurrentTokenType(TokenKind::RightBracket)) {
7676 funName = propAtom;
7680 // When |super()| is invoked, we search for the nearest scope containing
7681 // |.initializers| to initialize the class fields. This set-up precludes
7682 // declaring |.initializers| in the class scope, because in some syntactic
7683 // contexts |super()| can appear nested in a class, while actually belonging
7684 // to an outer class definition.
7686 // Example:
7687 // class Outer extends Base {
7688 // field = 1;
7689 // constructor() {
7690 // class Inner {
7691 // field = 2;
7693 // // The super() call in the computed property name mustn't access
7694 // // Inner's |.initializers| array, but instead Outer's.
7695 // [super()]() {}
7696 // }
7697 // }
7698 // }
7699 Maybe<ParseContext::Scope> dotInitializersScope;
7700 if (isConstructor && !options().selfHostingMode) {
7701 dotInitializersScope.emplace(this);
7702 if (!dotInitializersScope->init(pc_)) {
7703 return false;
7706 if (!noteDeclaredName(TaggedParserAtomIndex::WellKnown::dot_initializers_(),
7707 DeclarationKind::Let, pos())) {
7708 return false;
7712 // Calling toString on constructors need to return the source text for
7713 // the entire class. The end offset is unknown at this point in
7714 // parsing and will be amended when class parsing finishes below.
7715 FunctionNodeType funNode;
7716 MOZ_TRY_VAR_OR_RETURN(
7717 funNode,
7718 methodDefinition(isConstructor ? classStartOffset : propNameOffset,
7719 propType, funName),
7720 false);
7722 AccessorType atype = ToAccessorType(propType);
7724 Maybe<FunctionNodeType> initializerIfPrivate = Nothing();
7725 if (handler_.isPrivateName(propName)) {
7726 if (propAtom == TaggedParserAtomIndex::WellKnown::hash_constructor_()) {
7727 // #constructor is an invalid private name.
7728 errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
7729 return false;
7732 TaggedParserAtomIndex privateName = propAtom;
7733 if (!noteDeclaredPrivateName(
7734 propName, privateName, propType,
7735 isStatic ? FieldPlacement::Static : FieldPlacement::Instance,
7736 pos())) {
7737 return false;
7740 // Private non-static methods are stored in the class body environment.
7741 // Private non-static accessors are stamped onto every instance using
7742 // initializers. Private static methods are stamped onto the constructor
7743 // during class evaluation; see BytecodeEmitter::emitPropertyList.
7744 if (!isStatic) {
7745 if (atype == AccessorType::Getter || atype == AccessorType::Setter) {
7746 classInitializedMembers.privateAccessors++;
7747 TokenPos propNamePos(propNameOffset, pos().end);
7748 FunctionNodeType initializerNode;
7749 MOZ_TRY_VAR_OR_RETURN(
7750 initializerNode,
7751 synthesizePrivateMethodInitializer(propAtom, atype, propNamePos),
7752 false);
7753 initializerIfPrivate = Some(initializerNode);
7754 } else {
7755 MOZ_ASSERT(atype == AccessorType::None);
7756 classInitializedMembers.privateMethods++;
7761 Node method;
7762 MOZ_TRY_VAR_OR_RETURN(
7763 method,
7764 handler_.newClassMethodDefinition(propName, funNode, atype, isStatic,
7765 initializerIfPrivate
7766 #ifdef ENABLE_DECORATORS
7768 decorators
7769 #endif
7771 false);
7773 if (dotInitializersScope.isSome()) {
7774 MOZ_TRY_VAR_OR_RETURN(
7775 method, finishLexicalScope(*dotInitializersScope, method), false);
7776 dotInitializersScope.reset();
7779 return handler_.addClassMemberDefinition(classMembers, method);
7782 template <class ParseHandler, typename Unit>
7783 bool GeneralParser<ParseHandler, Unit>::finishClassConstructor(
7784 const ParseContext::ClassStatement& classStmt,
7785 TaggedParserAtomIndex className, HasHeritage hasHeritage,
7786 uint32_t classStartOffset, uint32_t classEndOffset,
7787 const ClassInitializedMembers& classInitializedMembers,
7788 ListNodeType& classMembers) {
7789 if (classStmt.constructorBox == nullptr) {
7790 MOZ_ASSERT(!options().selfHostingMode);
7791 // Unconditionally create the scope here, because it's always the
7792 // constructor.
7793 ParseContext::Scope dotInitializersScope(this);
7794 if (!dotInitializersScope.init(pc_)) {
7795 return false;
7798 if (!noteDeclaredName(TaggedParserAtomIndex::WellKnown::dot_initializers_(),
7799 DeclarationKind::Let, pos())) {
7800 return false;
7803 // synthesizeConstructor assigns to classStmt.constructorBox
7804 TokenPos synthesizedBodyPos(classStartOffset, classEndOffset);
7805 FunctionNodeType synthesizedCtor;
7806 MOZ_TRY_VAR_OR_RETURN(
7807 synthesizedCtor,
7808 synthesizeConstructor(className, synthesizedBodyPos, hasHeritage),
7809 false);
7811 // Note: the *function* has the name of the class, but the *property*
7812 // containing the function has the name "constructor"
7813 Node constructorNameNode;
7814 MOZ_TRY_VAR_OR_RETURN(
7815 constructorNameNode,
7816 handler_.newObjectLiteralPropertyName(
7817 TaggedParserAtomIndex::WellKnown::constructor(), pos()),
7818 false);
7819 ClassMethodType method;
7820 MOZ_TRY_VAR_OR_RETURN(method,
7821 handler_.newDefaultClassConstructor(
7822 constructorNameNode, synthesizedCtor),
7823 false);
7824 LexicalScopeNodeType scope;
7825 MOZ_TRY_VAR_OR_RETURN(
7826 scope, finishLexicalScope(dotInitializersScope, method), false);
7827 if (!handler_.addClassMemberDefinition(classMembers, scope)) {
7828 return false;
7832 MOZ_ASSERT(classStmt.constructorBox);
7833 FunctionBox* ctorbox = classStmt.constructorBox;
7835 // Amend the toStringEnd offset for the constructor now that we've
7836 // finished parsing the class.
7837 ctorbox->setCtorToStringEnd(classEndOffset);
7839 size_t numMemberInitializers = classInitializedMembers.privateAccessors +
7840 classInitializedMembers.instanceFields;
7841 bool hasPrivateBrand = classInitializedMembers.hasPrivateBrand();
7842 if (hasPrivateBrand || numMemberInitializers > 0) {
7843 // Now that we have full set of initializers, update the constructor.
7844 MemberInitializers initializers(hasPrivateBrand, numMemberInitializers);
7845 ctorbox->setMemberInitializers(initializers);
7847 // Field initialization need access to `this`.
7848 ctorbox->setCtorFunctionHasThisBinding();
7851 return true;
7854 template <class ParseHandler, typename Unit>
7855 typename ParseHandler::ClassNodeResult
7856 GeneralParser<ParseHandler, Unit>::classDefinition(
7857 YieldHandling yieldHandling, ClassContext classContext,
7858 DefaultHandling defaultHandling) {
7859 #ifdef ENABLE_DECORATORS
7860 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::At) ||
7861 anyChars.isCurrentTokenType(TokenKind::Class));
7863 ListNodeType decorators = null();
7864 if (anyChars.isCurrentTokenType(TokenKind::At)) {
7865 MOZ_TRY_VAR(decorators, decoratorList(yieldHandling));
7866 TokenKind next;
7867 if (!tokenStream.getToken(&next)) {
7868 return errorResult();
7870 if (next != TokenKind::Class) {
7871 error(JSMSG_CLASS_EXPECTED);
7872 return errorResult();
7875 #else
7876 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Class));
7877 #endif
7879 uint32_t classStartOffset = pos().begin;
7880 bool savedStrictness = setLocalStrictMode(true);
7882 // Classes are quite broken in self-hosted code.
7883 if (options().selfHostingMode) {
7884 error(JSMSG_SELFHOSTED_CLASS);
7885 return errorResult();
7888 TokenKind tt;
7889 if (!tokenStream.getToken(&tt)) {
7890 return errorResult();
7893 TaggedParserAtomIndex className;
7894 if (TokenKindIsPossibleIdentifier(tt)) {
7895 className = bindingIdentifier(yieldHandling);
7896 if (!className) {
7897 return errorResult();
7899 } else if (classContext == ClassStatement) {
7900 if (defaultHandling == AllowDefaultName) {
7901 className = TaggedParserAtomIndex::WellKnown::default_();
7902 anyChars.ungetToken();
7903 } else {
7904 // Class statements must have a bound name
7905 error(JSMSG_UNNAMED_CLASS_STMT);
7906 return errorResult();
7908 } else {
7909 // Make sure to put it back, whatever it was
7910 anyChars.ungetToken();
7913 // Because the binding definitions keep track of their blockId, we need to
7914 // create at least the inner binding later. Keep track of the name's
7915 // position in order to provide it for the nodes created later.
7916 TokenPos namePos = pos();
7918 bool isInClass = pc_->sc()->inClass();
7920 // Push a ParseContext::ClassStatement to keep track of the constructor
7921 // funbox.
7922 ParseContext::ClassStatement classStmt(pc_);
7924 NameNodeType innerName;
7925 Node nameNode = null();
7926 Node classHeritage = null();
7927 LexicalScopeNodeType classBlock = null();
7928 ClassBodyScopeNodeType classBodyBlock = null();
7929 uint32_t classEndOffset;
7931 // A named class creates a new lexical scope with a const binding of the
7932 // class name for the "inner name".
7933 ParseContext::Statement innerScopeStmt(pc_, StatementKind::Block);
7934 ParseContext::Scope innerScope(this);
7935 if (!innerScope.init(pc_)) {
7936 return errorResult();
7939 bool hasHeritageBool;
7940 if (!tokenStream.matchToken(&hasHeritageBool, TokenKind::Extends)) {
7941 return errorResult();
7943 HasHeritage hasHeritage =
7944 hasHeritageBool ? HasHeritage::Yes : HasHeritage::No;
7945 if (hasHeritage == HasHeritage::Yes) {
7946 if (!tokenStream.getToken(&tt)) {
7947 return errorResult();
7949 MOZ_TRY_VAR(classHeritage,
7950 optionalExpr(yieldHandling, TripledotProhibited, tt));
7953 if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_CLASS)) {
7954 return errorResult();
7958 ParseContext::Statement bodyScopeStmt(pc_, StatementKind::Block);
7959 ParseContext::Scope bodyScope(this);
7960 if (!bodyScope.init(pc_)) {
7961 return errorResult();
7964 ListNodeType classMembers;
7965 MOZ_TRY_VAR(classMembers, handler_.newClassMemberList(pos().begin));
7967 ClassInitializedMembers classInitializedMembers{};
7968 for (;;) {
7969 bool done;
7970 if (!classMember(yieldHandling, classStmt, className, classStartOffset,
7971 hasHeritage, classInitializedMembers, classMembers,
7972 &done)) {
7973 return errorResult();
7975 if (done) {
7976 break;
7980 if (classInitializedMembers.privateMethods +
7981 classInitializedMembers.privateAccessors >
7982 0) {
7983 // We declare `.privateBrand` as ClosedOver because the constructor
7984 // always uses it, even a default constructor. We could equivalently
7985 // `noteUsedName` when parsing the constructor, except that at that
7986 // time, we don't necessarily know if the class has a private brand.
7987 if (!noteDeclaredName(
7988 TaggedParserAtomIndex::WellKnown::dot_privateBrand_(),
7989 DeclarationKind::Synthetic, namePos, ClosedOver::Yes)) {
7990 return errorResult();
7994 if (classInitializedMembers.instanceFieldKeys > 0) {
7995 if (!noteDeclaredName(
7996 TaggedParserAtomIndex::WellKnown::dot_fieldKeys_(),
7997 DeclarationKind::Synthetic, namePos)) {
7998 return errorResult();
8002 if (classInitializedMembers.staticFields > 0) {
8003 if (!noteDeclaredName(
8004 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_(),
8005 DeclarationKind::Synthetic, namePos)) {
8006 return errorResult();
8010 if (classInitializedMembers.staticFieldKeys > 0) {
8011 if (!noteDeclaredName(
8012 TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_(),
8013 DeclarationKind::Synthetic, namePos)) {
8014 return errorResult();
8018 classEndOffset = pos().end;
8019 if (!finishClassConstructor(classStmt, className, hasHeritage,
8020 classStartOffset, classEndOffset,
8021 classInitializedMembers, classMembers)) {
8022 return errorResult();
8025 MOZ_TRY_VAR(classBodyBlock,
8026 finishClassBodyScope(bodyScope, classMembers));
8028 // Pop the class body scope
8031 if (className) {
8032 // The inner name is immutable.
8033 if (!noteDeclaredName(className, DeclarationKind::Const, namePos)) {
8034 return errorResult();
8037 MOZ_TRY_VAR(innerName, newName(className, namePos));
8040 MOZ_TRY_VAR(classBlock, finishLexicalScope(innerScope, classBodyBlock));
8042 // Pop the inner scope.
8045 if (className) {
8046 NameNodeType outerName = null();
8047 if (classContext == ClassStatement) {
8048 // The outer name is mutable.
8049 if (!noteDeclaredName(className, DeclarationKind::Class, namePos)) {
8050 return errorResult();
8053 MOZ_TRY_VAR(outerName, newName(className, namePos));
8056 MOZ_TRY_VAR(nameNode,
8057 handler_.newClassNames(outerName, innerName, namePos));
8059 MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
8060 // We're leaving a class definition that was not itself nested within a class
8061 if (!isInClass) {
8062 mozilla::Maybe<UnboundPrivateName> maybeUnboundName;
8063 if (!usedNames_.hasUnboundPrivateNames(fc_, maybeUnboundName)) {
8064 return errorResult();
8066 if (maybeUnboundName) {
8067 UniqueChars str =
8068 this->parserAtoms().toPrintableString(maybeUnboundName->atom);
8069 if (!str) {
8070 ReportOutOfMemory(this->fc_);
8071 return errorResult();
8074 errorAt(maybeUnboundName->position.begin, JSMSG_MISSING_PRIVATE_DECL,
8075 str.get());
8076 return errorResult();
8080 return handler_.newClass(nameNode, classHeritage, classBlock,
8081 #ifdef ENABLE_DECORATORS
8082 decorators,
8083 #endif
8084 TokenPos(classStartOffset, classEndOffset));
8087 template <class ParseHandler, typename Unit>
8088 typename ParseHandler::FunctionNodeResult
8089 GeneralParser<ParseHandler, Unit>::synthesizeConstructor(
8090 TaggedParserAtomIndex className, TokenPos synthesizedBodyPos,
8091 HasHeritage hasHeritage) {
8092 FunctionSyntaxKind functionSyntaxKind =
8093 hasHeritage == HasHeritage::Yes
8094 ? FunctionSyntaxKind::DerivedClassConstructor
8095 : FunctionSyntaxKind::ClassConstructor;
8097 bool isSelfHosting = options().selfHostingMode;
8098 FunctionFlags flags =
8099 InitialFunctionFlags(functionSyntaxKind, GeneratorKind::NotGenerator,
8100 FunctionAsyncKind::SyncFunction, isSelfHosting);
8102 // Create the top-level field initializer node.
8103 FunctionNodeType funNode;
8104 MOZ_TRY_VAR(funNode,
8105 handler_.newFunction(functionSyntaxKind, synthesizedBodyPos));
8107 // If we see any inner function, note it on our current context. The bytecode
8108 // emitter may eliminate the function later, but we use a conservative
8109 // definition for consistency between lazy and full parsing.
8110 pc_->sc()->setHasInnerFunctions();
8112 // When fully parsing a lazy script, we do not fully reparse its inner
8113 // functions, which are also lazy. Instead, their free variables and source
8114 // extents are recorded and may be skipped.
8115 if (handler_.reuseLazyInnerFunctions()) {
8116 if (!skipLazyInnerFunction(funNode, synthesizedBodyPos.begin,
8117 /* tryAnnexB = */ false)) {
8118 return errorResult();
8121 return funNode;
8124 // Create the FunctionBox and link it to the function object.
8125 Directives directives(true);
8126 FunctionBox* funbox = newFunctionBox(
8127 funNode, className, flags, synthesizedBodyPos.begin, directives,
8128 GeneratorKind::NotGenerator, FunctionAsyncKind::SyncFunction);
8129 if (!funbox) {
8130 return errorResult();
8132 funbox->initWithEnclosingParseContext(pc_, functionSyntaxKind);
8133 setFunctionEndFromCurrentToken(funbox);
8135 // Mark this function as being synthesized by the parser. This means special
8136 // handling in delazification will be used since we don't have typical
8137 // function syntax.
8138 funbox->setSyntheticFunction();
8140 // Push a SourceParseContext on to the stack.
8141 ParseContext* outerpc = pc_;
8142 SourceParseContext funpc(this, funbox, /* newDirectives = */ nullptr);
8143 if (!funpc.init()) {
8144 return errorResult();
8147 if (!synthesizeConstructorBody(synthesizedBodyPos, hasHeritage, funNode,
8148 funbox)) {
8149 return errorResult();
8152 if (!leaveInnerFunction(outerpc)) {
8153 return errorResult();
8156 return funNode;
8159 template <class ParseHandler, typename Unit>
8160 bool GeneralParser<ParseHandler, Unit>::synthesizeConstructorBody(
8161 TokenPos synthesizedBodyPos, HasHeritage hasHeritage,
8162 FunctionNodeType funNode, FunctionBox* funbox) {
8163 MOZ_ASSERT(funbox->isClassConstructor());
8165 // Create a ParamsBodyNode for the parameters + body (there are no
8166 // parameters).
8167 ParamsBodyNodeType argsbody;
8168 MOZ_TRY_VAR_OR_RETURN(argsbody, handler_.newParamsBody(synthesizedBodyPos),
8169 false);
8170 handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
8171 setFunctionStartAtPosition(funbox, synthesizedBodyPos);
8173 if (hasHeritage == HasHeritage::Yes) {
8174 // Synthesize the equivalent to `function f(...args)`
8175 funbox->setHasRest();
8176 if (!notePositionalFormalParameter(
8177 funNode, TaggedParserAtomIndex::WellKnown::dot_args_(),
8178 synthesizedBodyPos.begin,
8179 /* disallowDuplicateParams = */ false,
8180 /* duplicatedParam = */ nullptr)) {
8181 return false;
8183 funbox->setArgCount(1);
8184 } else {
8185 funbox->setArgCount(0);
8188 pc_->functionScope().useAsVarScope(pc_);
8190 ListNodeType stmtList;
8191 MOZ_TRY_VAR_OR_RETURN(stmtList, handler_.newStatementList(synthesizedBodyPos),
8192 false);
8194 if (!noteUsedName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
8195 return false;
8198 if (!noteUsedName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
8199 return false;
8202 if (hasHeritage == HasHeritage::Yes) {
8203 // |super()| implicitly reads |new.target|.
8204 if (!noteUsedName(TaggedParserAtomIndex::WellKnown::dot_newTarget_())) {
8205 return false;
8208 NameNodeType thisName;
8209 MOZ_TRY_VAR_OR_RETURN(thisName, newThisName(), false);
8211 UnaryNodeType superBase;
8212 MOZ_TRY_VAR_OR_RETURN(
8213 superBase, handler_.newSuperBase(thisName, synthesizedBodyPos), false);
8215 ListNodeType arguments;
8216 MOZ_TRY_VAR_OR_RETURN(arguments, handler_.newArguments(synthesizedBodyPos),
8217 false);
8219 NameNodeType argsNameNode;
8220 MOZ_TRY_VAR_OR_RETURN(argsNameNode,
8221 newName(TaggedParserAtomIndex::WellKnown::dot_args_(),
8222 synthesizedBodyPos),
8223 false);
8224 if (!noteUsedName(TaggedParserAtomIndex::WellKnown::dot_args_())) {
8225 return false;
8228 UnaryNodeType spreadArgs;
8229 MOZ_TRY_VAR_OR_RETURN(
8230 spreadArgs, handler_.newSpread(synthesizedBodyPos.begin, argsNameNode),
8231 false);
8232 handler_.addList(arguments, spreadArgs);
8234 CallNodeType superCall;
8235 MOZ_TRY_VAR_OR_RETURN(
8236 superCall,
8237 handler_.newSuperCall(superBase, arguments, /* isSpread = */ true),
8238 false);
8240 BinaryNodeType setThis;
8241 MOZ_TRY_VAR_OR_RETURN(setThis, handler_.newSetThis(thisName, superCall),
8242 false);
8244 UnaryNodeType exprStatement;
8245 MOZ_TRY_VAR_OR_RETURN(
8246 exprStatement,
8247 handler_.newExprStatement(setThis, synthesizedBodyPos.end), false);
8249 handler_.addStatementToList(stmtList, exprStatement);
8252 bool canSkipLazyClosedOverBindings = handler_.reuseClosedOverBindings();
8253 if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
8254 return false;
8256 if (!pc_->declareNewTarget(usedNames_, canSkipLazyClosedOverBindings)) {
8257 return false;
8260 LexicalScopeNodeType initializerBody;
8261 MOZ_TRY_VAR_OR_RETURN(
8262 initializerBody,
8263 finishLexicalScope(pc_->varScope(), stmtList, ScopeKind::FunctionLexical),
8264 false);
8265 handler_.setBeginPosition(initializerBody, stmtList);
8266 handler_.setEndPosition(initializerBody, stmtList);
8268 handler_.setFunctionBody(funNode, initializerBody);
8270 return finishFunction();
8273 template <class ParseHandler, typename Unit>
8274 typename ParseHandler::FunctionNodeResult
8275 GeneralParser<ParseHandler, Unit>::privateMethodInitializer(
8276 TokenPos propNamePos, TaggedParserAtomIndex propAtom,
8277 TaggedParserAtomIndex storedMethodAtom) {
8278 if (!abortIfSyntaxParser()) {
8279 return errorResult();
8282 // Synthesize an initializer function that the constructor can use to stamp a
8283 // private method onto an instance object.
8284 FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::FieldInitializer;
8285 FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction;
8286 GeneratorKind generatorKind = GeneratorKind::NotGenerator;
8287 bool isSelfHosting = options().selfHostingMode;
8288 FunctionFlags flags =
8289 InitialFunctionFlags(syntaxKind, generatorKind, asyncKind, isSelfHosting);
8291 FunctionNodeType funNode;
8292 MOZ_TRY_VAR(funNode, handler_.newFunction(syntaxKind, propNamePos));
8294 Directives directives(true);
8295 FunctionBox* funbox =
8296 newFunctionBox(funNode, TaggedParserAtomIndex::null(), flags,
8297 propNamePos.begin, directives, generatorKind, asyncKind);
8298 if (!funbox) {
8299 return errorResult();
8301 funbox->initWithEnclosingParseContext(pc_, syntaxKind);
8303 // Push a SourceParseContext on to the stack.
8304 ParseContext* outerpc = pc_;
8305 SourceParseContext funpc(this, funbox, /* newDirectives = */ nullptr);
8306 if (!funpc.init()) {
8307 return errorResult();
8309 pc_->functionScope().useAsVarScope(pc_);
8311 // Add empty parameter list.
8312 ParamsBodyNodeType argsbody;
8313 MOZ_TRY_VAR(argsbody, handler_.newParamsBody(propNamePos));
8314 handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
8315 setFunctionStartAtCurrentToken(funbox);
8316 funbox->setArgCount(0);
8318 // Note both the stored private method body and it's private name as being
8319 // used in the initializer. They will be emitted into the method body in the
8320 // BCE.
8321 if (!noteUsedName(storedMethodAtom)) {
8322 return errorResult();
8324 MOZ_TRY(privateNameReference(propAtom));
8326 // Unlike field initializers, private method initializers are not created with
8327 // a body of synthesized AST nodes. Instead, the body is left empty and the
8328 // initializer is synthesized at the bytecode level.
8329 // See BytecodeEmitter::emitPrivateMethodInitializer.
8330 ListNodeType stmtList;
8331 MOZ_TRY_VAR(stmtList, handler_.newStatementList(propNamePos));
8333 bool canSkipLazyClosedOverBindings = handler_.reuseClosedOverBindings();
8334 if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
8335 return errorResult();
8337 if (!pc_->declareNewTarget(usedNames_, canSkipLazyClosedOverBindings)) {
8338 return errorResult();
8341 LexicalScopeNodeType initializerBody;
8342 MOZ_TRY_VAR(initializerBody, finishLexicalScope(pc_->varScope(), stmtList,
8343 ScopeKind::FunctionLexical));
8344 handler_.setBeginPosition(initializerBody, stmtList);
8345 handler_.setEndPosition(initializerBody, stmtList);
8346 handler_.setFunctionBody(funNode, initializerBody);
8348 // Set field-initializer lambda boundary to start at property name and end
8349 // after method body.
8350 setFunctionStartAtPosition(funbox, propNamePos);
8351 setFunctionEndFromCurrentToken(funbox);
8353 if (!finishFunction()) {
8354 return errorResult();
8357 if (!leaveInnerFunction(outerpc)) {
8358 return errorResult();
8361 return funNode;
8364 template <class ParseHandler, typename Unit>
8365 typename ParseHandler::FunctionNodeResult
8366 GeneralParser<ParseHandler, Unit>::staticClassBlock(
8367 ClassInitializedMembers& classInitializedMembers) {
8368 // Both for getting-this-done, and because this will invariably be executed,
8369 // syntax parsing should be aborted.
8370 if (!abortIfSyntaxParser()) {
8371 return errorResult();
8374 FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::StaticClassBlock;
8375 FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction;
8376 GeneratorKind generatorKind = GeneratorKind::NotGenerator;
8377 bool isSelfHosting = options().selfHostingMode;
8378 FunctionFlags flags =
8379 InitialFunctionFlags(syntaxKind, generatorKind, asyncKind, isSelfHosting);
8381 AutoAwaitIsKeyword awaitIsKeyword(this, AwaitHandling::AwaitIsDisallowed);
8383 // Create the function node for the static class body.
8384 FunctionNodeType funNode;
8385 MOZ_TRY_VAR(funNode, handler_.newFunction(syntaxKind, pos()));
8387 // Create the FunctionBox and link it to the function object.
8388 Directives directives(true);
8389 FunctionBox* funbox =
8390 newFunctionBox(funNode, TaggedParserAtomIndex::null(), flags, pos().begin,
8391 directives, generatorKind, asyncKind);
8392 if (!funbox) {
8393 return errorResult();
8395 funbox->initWithEnclosingParseContext(pc_, syntaxKind);
8396 MOZ_ASSERT(funbox->isSyntheticFunction());
8397 MOZ_ASSERT(!funbox->allowSuperCall());
8398 MOZ_ASSERT(!funbox->allowArguments());
8399 MOZ_ASSERT(!funbox->allowReturn());
8401 // Set start at `static` token.
8402 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Static));
8403 setFunctionStartAtCurrentToken(funbox);
8405 // Push a SourceParseContext on to the stack.
8406 ParseContext* outerpc = pc_;
8407 SourceParseContext funpc(this, funbox, /* newDirectives = */ nullptr);
8408 if (!funpc.init()) {
8409 return errorResult();
8412 pc_->functionScope().useAsVarScope(pc_);
8414 uint32_t start = pos().begin;
8416 tokenStream.consumeKnownToken(TokenKind::LeftCurly);
8418 // Static class blocks are code-generated as if they were static field
8419 // initializers, so we bump the staticFields count here, which ensures
8420 // .staticInitializers is noted as used.
8421 classInitializedMembers.staticFields++;
8423 LexicalScopeNodeType body;
8424 MOZ_TRY_VAR(body,
8425 functionBody(InHandling::InAllowed, YieldHandling::YieldIsKeyword,
8426 syntaxKind, FunctionBodyType::StatementListBody));
8428 if (anyChars.isEOF()) {
8429 error(JSMSG_UNTERMINATED_STATIC_CLASS_BLOCK);
8430 return errorResult();
8433 tokenStream.consumeKnownToken(TokenKind::RightCurly,
8434 TokenStream::Modifier::SlashIsRegExp);
8436 TokenPos wholeBodyPos(start, pos().end);
8438 handler_.setEndPosition(funNode, wholeBodyPos.end);
8439 setFunctionEndFromCurrentToken(funbox);
8441 // Create a ParamsBodyNode for the parameters + body (there are no
8442 // parameters).
8443 ParamsBodyNodeType argsbody;
8444 MOZ_TRY_VAR(argsbody, handler_.newParamsBody(wholeBodyPos));
8446 handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
8447 funbox->setArgCount(0);
8449 if (pc_->superScopeNeedsHomeObject()) {
8450 funbox->setNeedsHomeObject();
8453 handler_.setEndPosition(body, pos().begin);
8454 handler_.setEndPosition(funNode, pos().end);
8455 handler_.setFunctionBody(funNode, body);
8457 if (!finishFunction()) {
8458 return errorResult();
8461 if (!leaveInnerFunction(outerpc)) {
8462 return errorResult();
8465 return funNode;
8468 template <class ParseHandler, typename Unit>
8469 typename ParseHandler::FunctionNodeResult
8470 GeneralParser<ParseHandler, Unit>::fieldInitializerOpt(
8471 TokenPos propNamePos, Node propName, TaggedParserAtomIndex propAtom,
8472 ClassInitializedMembers& classInitializedMembers, bool isStatic,
8473 HasHeritage hasHeritage) {
8474 if (!abortIfSyntaxParser()) {
8475 return errorResult();
8478 bool hasInitializer = false;
8479 if (!tokenStream.matchToken(&hasInitializer, TokenKind::Assign,
8480 TokenStream::SlashIsDiv)) {
8481 return errorResult();
8484 FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::FieldInitializer;
8485 FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction;
8486 GeneratorKind generatorKind = GeneratorKind::NotGenerator;
8487 bool isSelfHosting = options().selfHostingMode;
8488 FunctionFlags flags =
8489 InitialFunctionFlags(syntaxKind, generatorKind, asyncKind, isSelfHosting);
8491 // Create the top-level field initializer node.
8492 FunctionNodeType funNode;
8493 MOZ_TRY_VAR(funNode, handler_.newFunction(syntaxKind, propNamePos));
8495 // Create the FunctionBox and link it to the function object.
8496 Directives directives(true);
8497 FunctionBox* funbox =
8498 newFunctionBox(funNode, TaggedParserAtomIndex::null(), flags,
8499 propNamePos.begin, directives, generatorKind, asyncKind);
8500 if (!funbox) {
8501 return errorResult();
8503 funbox->initWithEnclosingParseContext(pc_, syntaxKind);
8504 MOZ_ASSERT(funbox->isSyntheticFunction());
8506 // We can't use setFunctionStartAtCurrentToken because that uses pos().begin,
8507 // which is incorrect for fields without initializers (pos() points to the
8508 // field identifier)
8509 setFunctionStartAtPosition(funbox, propNamePos);
8511 // Push a SourceParseContext on to the stack.
8512 ParseContext* outerpc = pc_;
8513 SourceParseContext funpc(this, funbox, /* newDirectives = */ nullptr);
8514 if (!funpc.init()) {
8515 return errorResult();
8518 pc_->functionScope().useAsVarScope(pc_);
8520 Node initializerExpr;
8521 if (hasInitializer) {
8522 // Parse the expression for the field initializer.
8524 AutoAwaitIsKeyword awaitHandling(this, AwaitIsName);
8525 MOZ_TRY_VAR(initializerExpr,
8526 assignExpr(InAllowed, YieldIsName, TripledotProhibited));
8529 handler_.checkAndSetIsDirectRHSAnonFunction(initializerExpr);
8530 } else {
8531 MOZ_TRY_VAR(initializerExpr, handler_.newRawUndefinedLiteral(propNamePos));
8534 TokenPos wholeInitializerPos(propNamePos.begin, pos().end);
8536 // Update the end position of the parse node.
8537 handler_.setEndPosition(funNode, wholeInitializerPos.end);
8538 setFunctionEndFromCurrentToken(funbox);
8540 // Create a ParamsBodyNode for the parameters + body (there are no
8541 // parameters).
8542 ParamsBodyNodeType argsbody;
8543 MOZ_TRY_VAR(argsbody, handler_.newParamsBody(wholeInitializerPos));
8544 handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
8545 funbox->setArgCount(0);
8547 NameNodeType thisName;
8548 MOZ_TRY_VAR(thisName, newThisName());
8550 // Build `this.field` expression.
8551 ThisLiteralType propAssignThis;
8552 MOZ_TRY_VAR(propAssignThis,
8553 handler_.newThisLiteral(wholeInitializerPos, thisName));
8555 Node propAssignFieldAccess;
8556 uint32_t indexValue;
8557 if (!propAtom) {
8558 // See BytecodeEmitter::emitCreateFieldKeys for an explanation of what
8559 // .fieldKeys means and its purpose.
8560 NameNodeType fieldKeysName;
8561 if (isStatic) {
8562 MOZ_TRY_VAR(
8563 fieldKeysName,
8564 newInternalDotName(
8565 TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_()));
8566 } else {
8567 MOZ_TRY_VAR(fieldKeysName,
8568 newInternalDotName(
8569 TaggedParserAtomIndex::WellKnown::dot_fieldKeys_()));
8571 if (!fieldKeysName) {
8572 return errorResult();
8575 double fieldKeyIndex;
8576 if (isStatic) {
8577 fieldKeyIndex = classInitializedMembers.staticFieldKeys++;
8578 } else {
8579 fieldKeyIndex = classInitializedMembers.instanceFieldKeys++;
8581 Node fieldKeyIndexNode;
8582 MOZ_TRY_VAR(fieldKeyIndexNode,
8583 handler_.newNumber(fieldKeyIndex, DecimalPoint::NoDecimal,
8584 wholeInitializerPos));
8586 Node fieldKeyValue;
8587 MOZ_TRY_VAR(fieldKeyValue,
8588 handler_.newPropertyByValue(fieldKeysName, fieldKeyIndexNode,
8589 wholeInitializerPos.end));
8591 MOZ_TRY_VAR(propAssignFieldAccess,
8592 handler_.newPropertyByValue(propAssignThis, fieldKeyValue,
8593 wholeInitializerPos.end));
8594 } else if (handler_.isPrivateName(propName)) {
8595 // It would be nice if we could tweak this here such that only if
8596 // HasHeritage::Yes we end up emitting CheckPrivateField, but otherwise we
8597 // emit InitElem -- this is an optimization to minimize HasOwn checks
8598 // in InitElem for classes without heritage.
8600 // Further tweaking would be to ultimately only do CheckPrivateField for the
8601 // -first- field in a derived class, which would suffice to match the
8602 // semantic check.
8604 NameNodeType privateNameNode;
8605 MOZ_TRY_VAR(privateNameNode, privateNameReference(propAtom));
8607 MOZ_TRY_VAR(propAssignFieldAccess,
8608 handler_.newPrivateMemberAccess(propAssignThis, privateNameNode,
8609 wholeInitializerPos.end));
8610 } else if (this->parserAtoms().isIndex(propAtom, &indexValue)) {
8611 MOZ_TRY_VAR(propAssignFieldAccess,
8612 handler_.newPropertyByValue(propAssignThis, propName,
8613 wholeInitializerPos.end));
8614 } else {
8615 NameNodeType propAssignName;
8616 MOZ_TRY_VAR(propAssignName,
8617 handler_.newPropertyName(propAtom, wholeInitializerPos));
8619 MOZ_TRY_VAR(propAssignFieldAccess,
8620 handler_.newPropertyAccess(propAssignThis, propAssignName));
8623 // Synthesize an property init.
8624 BinaryNodeType initializerPropInit;
8625 MOZ_TRY_VAR(initializerPropInit,
8626 handler_.newInitExpr(propAssignFieldAccess, initializerExpr));
8628 UnaryNodeType exprStatement;
8629 MOZ_TRY_VAR(exprStatement, handler_.newExprStatement(
8630 initializerPropInit, wholeInitializerPos.end));
8632 ListNodeType statementList;
8633 MOZ_TRY_VAR(statementList, handler_.newStatementList(wholeInitializerPos));
8634 handler_.addStatementToList(statementList, exprStatement);
8636 bool canSkipLazyClosedOverBindings = handler_.reuseClosedOverBindings();
8637 if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
8638 return errorResult();
8640 if (!pc_->declareNewTarget(usedNames_, canSkipLazyClosedOverBindings)) {
8641 return errorResult();
8644 // Set the function's body to the field assignment.
8645 LexicalScopeNodeType initializerBody;
8646 MOZ_TRY_VAR(initializerBody,
8647 finishLexicalScope(pc_->varScope(), statementList,
8648 ScopeKind::FunctionLexical));
8650 handler_.setFunctionBody(funNode, initializerBody);
8652 if (pc_->superScopeNeedsHomeObject()) {
8653 funbox->setNeedsHomeObject();
8656 if (!finishFunction()) {
8657 return errorResult();
8660 if (!leaveInnerFunction(outerpc)) {
8661 return errorResult();
8664 return funNode;
8667 template <class ParseHandler, typename Unit>
8668 typename ParseHandler::FunctionNodeResult
8669 GeneralParser<ParseHandler, Unit>::synthesizePrivateMethodInitializer(
8670 TaggedParserAtomIndex propAtom, AccessorType accessorType,
8671 TokenPos propNamePos) {
8672 if (!abortIfSyntaxParser()) {
8673 return errorResult();
8676 // Synthesize a name for the lexical variable that will store the
8677 // accessor body.
8678 StringBuffer storedMethodName(fc_);
8679 if (!storedMethodName.append(this->parserAtoms(), propAtom)) {
8680 return errorResult();
8682 if (!storedMethodName.append(
8683 accessorType == AccessorType::Getter ? ".getter" : ".setter")) {
8684 return errorResult();
8686 auto storedMethodProp =
8687 storedMethodName.finishParserAtom(this->parserAtoms(), fc_);
8688 if (!storedMethodProp) {
8689 return errorResult();
8691 if (!noteDeclaredName(storedMethodProp, DeclarationKind::Synthetic, pos())) {
8692 return errorResult();
8695 return privateMethodInitializer(propNamePos, propAtom, storedMethodProp);
8698 #ifdef ENABLE_DECORATORS
8700 template <class ParseHandler, typename Unit>
8701 typename ParseHandler::ClassMethodResult
8702 GeneralParser<ParseHandler, Unit>::synthesizeAccessor(
8703 Node propName, TokenPos propNamePos, TaggedParserAtomIndex propAtom,
8704 TaggedParserAtomIndex privateStateNameAtom, bool isStatic,
8705 FunctionSyntaxKind syntaxKind,
8706 ClassInitializedMembers& classInitializedMembers) {
8707 // Decorators Proposal
8708 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-makeautoaccessorgetter
8709 // The abstract operation MakeAutoAccessorGetter takes arguments homeObject
8710 // (an Object), name (a property key or Private Name), and privateStateName (a
8711 // Private Name) and returns a function object.
8713 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-makeautoaccessorsetter
8714 // The abstract operation MakeAutoAccessorSetter takes arguments homeObject
8715 // (an Object), name (a property key or Private Name), and privateStateName (a
8716 // Private Name) and returns a function object.
8717 if (!abortIfSyntaxParser()) {
8718 return errorResult();
8721 AccessorType accessorType = syntaxKind == FunctionSyntaxKind::Getter
8722 ? AccessorType::Getter
8723 : AccessorType::Setter;
8725 mozilla::Maybe<FunctionNodeType> initializerIfPrivate = Nothing();
8726 if (!isStatic && handler_.isPrivateName(propName)) {
8727 classInitializedMembers.privateAccessors++;
8728 FunctionNodeType initializerNode;
8729 MOZ_TRY_VAR(initializerNode, synthesizePrivateMethodInitializer(
8730 propAtom, accessorType, propNamePos));
8731 initializerIfPrivate = Some(initializerNode);
8732 handler_.setPrivateNameKind(propName, PrivateNameKind::GetterSetter);
8735 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-makeautoaccessorgetter
8736 // 2. Let getter be CreateBuiltinFunction(getterClosure, 0, "get", « »).
8738 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-makeautoaccessorsetter
8739 // 2. Let setter be CreateBuiltinFunction(setterClosure, 1, "set", « »).
8740 StringBuffer storedMethodName(fc_);
8741 if (!storedMethodName.append(accessorType == AccessorType::Getter ? "get"
8742 : "set")) {
8743 return errorResult();
8745 TaggedParserAtomIndex funNameAtom =
8746 storedMethodName.finishParserAtom(this->parserAtoms(), fc_);
8748 FunctionNodeType funNode;
8749 MOZ_TRY_VAR(funNode,
8750 synthesizeAccessorBody(funNameAtom, propNamePos,
8751 privateStateNameAtom, syntaxKind));
8753 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-makeautoaccessorgetter
8754 // 3. Perform MakeMethod(getter, homeObject).
8755 // 4. Return getter.
8757 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-makeautoaccessorsetter
8758 // 3. Perform MakeMethod(setter, homeObject).
8759 // 4. Return setter.
8760 return handler_.newClassMethodDefinition(
8761 propName, funNode, accessorType, isStatic, initializerIfPrivate, null());
8764 template <class ParseHandler, typename Unit>
8765 typename ParseHandler::FunctionNodeResult
8766 GeneralParser<ParseHandler, Unit>::synthesizeAccessorBody(
8767 TaggedParserAtomIndex funNameAtom, TokenPos propNamePos,
8768 TaggedParserAtomIndex propNameAtom, FunctionSyntaxKind syntaxKind) {
8769 if (!abortIfSyntaxParser()) {
8770 return errorResult();
8773 FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction;
8774 GeneratorKind generatorKind = GeneratorKind::NotGenerator;
8775 bool isSelfHosting = options().selfHostingMode;
8776 FunctionFlags flags =
8777 InitialFunctionFlags(syntaxKind, generatorKind, asyncKind, isSelfHosting);
8779 // Create the top-level function node.
8780 FunctionNodeType funNode;
8781 MOZ_TRY_VAR(funNode, handler_.newFunction(syntaxKind, propNamePos));
8783 // Create the FunctionBox and link it to the function object.
8784 Directives directives(true);
8785 FunctionBox* funbox =
8786 newFunctionBox(funNode, funNameAtom, flags, propNamePos.begin, directives,
8787 generatorKind, asyncKind);
8788 if (!funbox) {
8789 return errorResult();
8791 funbox->initWithEnclosingParseContext(pc_, syntaxKind);
8792 funbox->setSyntheticFunction();
8794 // Push a SourceParseContext on to the stack.
8795 ParseContext* outerpc = pc_;
8796 SourceParseContext funpc(this, funbox, /* newDirectives = */ nullptr);
8797 if (!funpc.init()) {
8798 return errorResult();
8801 pc_->functionScope().useAsVarScope(pc_);
8803 // The function we synthesize is located at the field with the
8804 // accessor.
8805 setFunctionStartAtCurrentToken(funbox);
8806 setFunctionEndFromCurrentToken(funbox);
8808 // Create a ListNode for the parameters + body
8809 ParamsBodyNodeType paramsbody;
8810 MOZ_TRY_VAR(paramsbody, handler_.newParamsBody(propNamePos));
8811 handler_.setFunctionFormalParametersAndBody(funNode, paramsbody);
8813 if (syntaxKind == FunctionSyntaxKind::Getter) {
8814 funbox->setArgCount(0);
8815 } else {
8816 funbox->setArgCount(1);
8819 // Build `this` expression to access the privateStateName for use in the
8820 // operations to create the getter and setter below.
8821 NameNodeType thisName;
8822 MOZ_TRY_VAR(thisName, newThisName());
8824 ThisLiteralType propThis;
8825 MOZ_TRY_VAR(propThis, handler_.newThisLiteral(propNamePos, thisName));
8827 NameNodeType privateNameNode;
8828 MOZ_TRY_VAR(privateNameNode, privateNameReference(propNameAtom));
8830 Node propFieldAccess;
8831 MOZ_TRY_VAR(propFieldAccess, handler_.newPrivateMemberAccess(
8832 propThis, privateNameNode, propNamePos.end));
8834 Node accessorBody;
8835 if (syntaxKind == FunctionSyntaxKind::Getter) {
8836 // Decorators Proposal
8837 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-makeautoaccessorgetter
8838 // 1. Let getterClosure be a new Abstract Closure with no parameters that
8839 // captures privateStateName and performs the following steps when called:
8840 // 1.a. Let o be the this value.
8841 // 1.b. Return ? PrivateGet(privateStateName, o).
8842 MOZ_TRY_VAR(accessorBody,
8843 handler_.newReturnStatement(propFieldAccess, propNamePos));
8844 } else {
8845 // Decorators Proposal
8846 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-makeautoaccessorsetter
8847 // The abstract operation MakeAutoAccessorSetter takes arguments homeObject
8848 // (an Object), name (a property key or Private Name), and privateStateName
8849 // (a Private Name) and returns a function object.
8850 // 1. Let setterClosure be a new Abstract Closure with parameters (value)
8851 // that captures privateStateName and performs the following steps when
8852 // called:
8853 // 1.a. Let o be the this value.
8854 notePositionalFormalParameter(funNode,
8855 TaggedParserAtomIndex::WellKnown::value(),
8856 /* pos = */ 0, false,
8857 /* duplicatedParam = */ nullptr);
8859 Node initializerExpr;
8860 MOZ_TRY_VAR(initializerExpr,
8861 handler_.newName(TaggedParserAtomIndex::WellKnown::value(),
8862 propNamePos));
8864 // 1.b. Perform ? PrivateSet(privateStateName, o, value).
8865 Node assignment;
8866 MOZ_TRY_VAR(assignment,
8867 handler_.newAssignment(ParseNodeKind::AssignExpr,
8868 propFieldAccess, initializerExpr));
8870 MOZ_TRY_VAR(accessorBody,
8871 handler_.newExprStatement(assignment, propNamePos.end));
8873 // 1.c. Return undefined.
8876 ListNodeType statementList;
8877 MOZ_TRY_VAR(statementList, handler_.newStatementList(propNamePos));
8878 handler_.addStatementToList(statementList, accessorBody);
8880 bool canSkipLazyClosedOverBindings = handler_.reuseClosedOverBindings();
8881 if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
8882 return errorResult();
8884 if (!pc_->declareNewTarget(usedNames_, canSkipLazyClosedOverBindings)) {
8885 return errorResult();
8888 LexicalScopeNodeType initializerBody;
8889 MOZ_TRY_VAR(initializerBody,
8890 finishLexicalScope(pc_->varScope(), statementList,
8891 ScopeKind::FunctionLexical));
8893 handler_.setFunctionBody(funNode, initializerBody);
8895 if (pc_->superScopeNeedsHomeObject()) {
8896 funbox->setNeedsHomeObject();
8899 if (!finishFunction()) {
8900 return errorResult();
8903 if (!leaveInnerFunction(outerpc)) {
8904 return errorResult();
8907 return funNode;
8910 #endif
8912 bool ParserBase::nextTokenContinuesLetDeclaration(TokenKind next) {
8913 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Let));
8914 MOZ_ASSERT(anyChars.nextToken().type == next);
8916 TokenStreamShared::verifyConsistentModifier(TokenStreamShared::SlashIsDiv,
8917 anyChars.nextToken());
8919 // Destructuring continues a let declaration.
8920 if (next == TokenKind::LeftBracket || next == TokenKind::LeftCurly) {
8921 return true;
8924 // A "let" edge case deserves special comment. Consider this:
8926 // let // not an ASI opportunity
8927 // let;
8929 // Static semantics in §13.3.1.1 turn a LexicalDeclaration that binds
8930 // "let" into an early error. Does this retroactively permit ASI so
8931 // that we should parse this as two ExpressionStatements? No. ASI
8932 // resolves during parsing. Static semantics only apply to the full
8933 // parse tree with ASI applied. No backsies!
8935 // Otherwise a let declaration must have a name.
8936 return TokenKindIsPossibleIdentifier(next);
8939 template <class ParseHandler, typename Unit>
8940 typename ParseHandler::DeclarationListNodeResult
8941 GeneralParser<ParseHandler, Unit>::variableStatement(
8942 YieldHandling yieldHandling) {
8943 DeclarationListNodeType vars;
8944 MOZ_TRY_VAR(vars, declarationList(yieldHandling, ParseNodeKind::VarStmt));
8945 if (!matchOrInsertSemicolon()) {
8946 return errorResult();
8948 return vars;
8951 template <class ParseHandler, typename Unit>
8952 typename ParseHandler::NodeResult GeneralParser<ParseHandler, Unit>::statement(
8953 YieldHandling yieldHandling) {
8954 MOZ_ASSERT(checkOptionsCalled_);
8956 AutoCheckRecursionLimit recursion(this->fc_);
8957 if (!recursion.check(this->fc_)) {
8958 return errorResult();
8961 TokenKind tt;
8962 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
8963 return errorResult();
8966 switch (tt) {
8967 // BlockStatement[?Yield, ?Return]
8968 case TokenKind::LeftCurly:
8969 return blockStatement(yieldHandling);
8971 // VariableStatement[?Yield]
8972 case TokenKind::Var:
8973 return variableStatement(yieldHandling);
8975 // EmptyStatement
8976 case TokenKind::Semi:
8977 return handler_.newEmptyStatement(pos());
8979 // ExpressionStatement[?Yield].
8981 case TokenKind::Yield: {
8982 // Don't use a ternary operator here due to obscure linker issues
8983 // around using static consts in the arms of a ternary.
8984 Modifier modifier;
8985 if (yieldExpressionsSupported()) {
8986 modifier = TokenStream::SlashIsRegExp;
8987 } else {
8988 modifier = TokenStream::SlashIsDiv;
8991 TokenKind next;
8992 if (!tokenStream.peekToken(&next, modifier)) {
8993 return errorResult();
8996 if (next == TokenKind::Colon) {
8997 return labeledStatement(yieldHandling);
9000 return expressionStatement(yieldHandling);
9003 default: {
9004 // If we encounter an await in a module, and the module is not marked
9005 // as async, mark the module as async.
9006 if (tt == TokenKind::Await && !pc_->isAsync()) {
9007 if (pc_->atModuleTopLevel()) {
9008 if (!options().topLevelAwait) {
9009 error(JSMSG_TOP_LEVEL_AWAIT_NOT_SUPPORTED);
9010 return errorResult();
9012 pc_->sc()->asModuleContext()->setIsAsync();
9013 MOZ_ASSERT(pc_->isAsync());
9017 // Avoid getting next token with SlashIsDiv.
9018 if (tt == TokenKind::Await && pc_->isAsync()) {
9019 return expressionStatement(yieldHandling);
9022 if (!TokenKindIsPossibleIdentifier(tt)) {
9023 return expressionStatement(yieldHandling);
9026 TokenKind next;
9027 if (!tokenStream.peekToken(&next)) {
9028 return errorResult();
9031 // |let| here can only be an Identifier, not a declaration. Give nicer
9032 // errors for declaration-looking typos.
9033 if (tt == TokenKind::Let) {
9034 bool forbiddenLetDeclaration = false;
9036 if (next == TokenKind::LeftBracket) {
9037 // Enforce ExpressionStatement's 'let [' lookahead restriction.
9038 forbiddenLetDeclaration = true;
9039 } else if (next == TokenKind::LeftCurly ||
9040 TokenKindIsPossibleIdentifier(next)) {
9041 // 'let {' and 'let foo' aren't completely forbidden, if ASI
9042 // causes 'let' to be the entire Statement. But if they're
9043 // same-line, we can aggressively give a better error message.
9045 // Note that this ignores 'yield' as TokenKind::Yield: we'll handle it
9046 // correctly but with a worse error message.
9047 TokenKind nextSameLine;
9048 if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
9049 return errorResult();
9052 MOZ_ASSERT(TokenKindIsPossibleIdentifier(nextSameLine) ||
9053 nextSameLine == TokenKind::LeftCurly ||
9054 nextSameLine == TokenKind::Eol);
9056 forbiddenLetDeclaration = nextSameLine != TokenKind::Eol;
9059 if (forbiddenLetDeclaration) {
9060 error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations");
9061 return errorResult();
9063 } else if (tt == TokenKind::Async) {
9064 // Peek only on the same line: ExpressionStatement's lookahead
9065 // restriction is phrased as
9067 // [lookahead ∉ { '{',
9068 // function,
9069 // async [no LineTerminator here] function,
9070 // class,
9071 // let '[' }]
9073 // meaning that code like this is valid:
9075 // if (true)
9076 // async // ASI opportunity
9077 // function clownshoes() {}
9078 TokenKind maybeFunction;
9079 if (!tokenStream.peekTokenSameLine(&maybeFunction)) {
9080 return errorResult();
9083 if (maybeFunction == TokenKind::Function) {
9084 error(JSMSG_FORBIDDEN_AS_STATEMENT, "async function declarations");
9085 return errorResult();
9088 // Otherwise this |async| begins an ExpressionStatement or is a
9089 // label name.
9092 // NOTE: It's unfortunately allowed to have a label named 'let' in
9093 // non-strict code. 💯
9094 if (next == TokenKind::Colon) {
9095 return labeledStatement(yieldHandling);
9098 return expressionStatement(yieldHandling);
9101 case TokenKind::New:
9102 return expressionStatement(yieldHandling, PredictInvoked);
9104 // IfStatement[?Yield, ?Return]
9105 case TokenKind::If:
9106 return ifStatement(yieldHandling);
9108 // BreakableStatement[?Yield, ?Return]
9110 // BreakableStatement[Yield, Return]:
9111 // IterationStatement[?Yield, ?Return]
9112 // SwitchStatement[?Yield, ?Return]
9113 case TokenKind::Do:
9114 return doWhileStatement(yieldHandling);
9116 case TokenKind::While:
9117 return whileStatement(yieldHandling);
9119 case TokenKind::For:
9120 return forStatement(yieldHandling);
9122 case TokenKind::Switch:
9123 return switchStatement(yieldHandling);
9125 // ContinueStatement[?Yield]
9126 case TokenKind::Continue:
9127 return continueStatement(yieldHandling);
9129 // BreakStatement[?Yield]
9130 case TokenKind::Break:
9131 return breakStatement(yieldHandling);
9133 // [+Return] ReturnStatement[?Yield]
9134 case TokenKind::Return:
9135 // The Return parameter is only used here, and the effect is easily
9136 // detected this way, so don't bother passing around an extra parameter
9137 // everywhere.
9138 if (!pc_->allowReturn()) {
9139 error(JSMSG_BAD_RETURN_OR_YIELD, "return");
9140 return errorResult();
9142 return returnStatement(yieldHandling);
9144 // WithStatement[?Yield, ?Return]
9145 case TokenKind::With:
9146 return withStatement(yieldHandling);
9148 // LabelledStatement[?Yield, ?Return]
9149 // This is really handled by default and TokenKind::Yield cases above.
9151 // ThrowStatement[?Yield]
9152 case TokenKind::Throw:
9153 return throwStatement(yieldHandling);
9155 // TryStatement[?Yield, ?Return]
9156 case TokenKind::Try:
9157 return tryStatement(yieldHandling);
9159 // DebuggerStatement
9160 case TokenKind::Debugger:
9161 return debuggerStatement();
9163 // |function| is forbidden by lookahead restriction (unless as child
9164 // statement of |if| or |else|, but Parser::consequentOrAlternative
9165 // handles that).
9166 case TokenKind::Function:
9167 error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
9168 return errorResult();
9170 // |class| is also forbidden by lookahead restriction.
9171 case TokenKind::Class:
9172 error(JSMSG_FORBIDDEN_AS_STATEMENT, "classes");
9173 return errorResult();
9175 // ImportDeclaration (only inside modules)
9176 case TokenKind::Import:
9177 return importDeclarationOrImportExpr(yieldHandling);
9179 // ExportDeclaration (only inside modules)
9180 case TokenKind::Export:
9181 return exportDeclaration();
9183 // Miscellaneous error cases arguably better caught here than elsewhere.
9185 case TokenKind::Catch:
9186 error(JSMSG_CATCH_WITHOUT_TRY);
9187 return errorResult();
9189 case TokenKind::Finally:
9190 error(JSMSG_FINALLY_WITHOUT_TRY);
9191 return errorResult();
9193 // NOTE: default case handled in the ExpressionStatement section.
9197 template <class ParseHandler, typename Unit>
9198 typename ParseHandler::NodeResult
9199 GeneralParser<ParseHandler, Unit>::statementListItem(
9200 YieldHandling yieldHandling, bool canHaveDirectives /* = false */) {
9201 MOZ_ASSERT(checkOptionsCalled_);
9203 AutoCheckRecursionLimit recursion(this->fc_);
9204 if (!recursion.check(this->fc_)) {
9205 return errorResult();
9208 TokenKind tt;
9209 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
9210 return errorResult();
9213 switch (tt) {
9214 // BlockStatement[?Yield, ?Return]
9215 case TokenKind::LeftCurly:
9216 return blockStatement(yieldHandling);
9218 // VariableStatement[?Yield]
9219 case TokenKind::Var:
9220 return variableStatement(yieldHandling);
9222 // EmptyStatement
9223 case TokenKind::Semi:
9224 return handler_.newEmptyStatement(pos());
9226 // ExpressionStatement[?Yield].
9228 // These should probably be handled by a single ExpressionStatement
9229 // function in a default, not split up this way.
9230 case TokenKind::String:
9231 if (!canHaveDirectives &&
9232 anyChars.currentToken().atom() ==
9233 TaggedParserAtomIndex::WellKnown::use_asm_()) {
9234 if (!warning(JSMSG_USE_ASM_DIRECTIVE_FAIL)) {
9235 return errorResult();
9238 return expressionStatement(yieldHandling);
9240 case TokenKind::Yield: {
9241 // Don't use a ternary operator here due to obscure linker issues
9242 // around using static consts in the arms of a ternary.
9243 Modifier modifier;
9244 if (yieldExpressionsSupported()) {
9245 modifier = TokenStream::SlashIsRegExp;
9246 } else {
9247 modifier = TokenStream::SlashIsDiv;
9250 TokenKind next;
9251 if (!tokenStream.peekToken(&next, modifier)) {
9252 return errorResult();
9255 if (next == TokenKind::Colon) {
9256 return labeledStatement(yieldHandling);
9259 return expressionStatement(yieldHandling);
9262 default: {
9263 // If we encounter an await in a module, and the module is not marked
9264 // as async, mark the module as async.
9265 if (tt == TokenKind::Await && !pc_->isAsync()) {
9266 if (pc_->atModuleTopLevel()) {
9267 if (!options().topLevelAwait) {
9268 error(JSMSG_TOP_LEVEL_AWAIT_NOT_SUPPORTED);
9269 return errorResult();
9271 pc_->sc()->asModuleContext()->setIsAsync();
9272 MOZ_ASSERT(pc_->isAsync());
9276 // Avoid getting next token with SlashIsDiv.
9277 if (tt == TokenKind::Await && pc_->isAsync()) {
9278 return expressionStatement(yieldHandling);
9281 if (!TokenKindIsPossibleIdentifier(tt)) {
9282 return expressionStatement(yieldHandling);
9285 TokenKind next;
9286 if (!tokenStream.peekToken(&next)) {
9287 return errorResult();
9290 if (tt == TokenKind::Let && nextTokenContinuesLetDeclaration(next)) {
9291 return lexicalDeclaration(yieldHandling, DeclarationKind::Let);
9294 if (tt == TokenKind::Async) {
9295 TokenKind nextSameLine = TokenKind::Eof;
9296 if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
9297 return errorResult();
9299 if (nextSameLine == TokenKind::Function) {
9300 uint32_t toStringStart = pos().begin;
9301 tokenStream.consumeKnownToken(TokenKind::Function);
9302 return functionStmt(toStringStart, yieldHandling, NameRequired,
9303 FunctionAsyncKind::AsyncFunction);
9307 if (next == TokenKind::Colon) {
9308 return labeledStatement(yieldHandling);
9311 return expressionStatement(yieldHandling);
9314 case TokenKind::New:
9315 return expressionStatement(yieldHandling, PredictInvoked);
9317 // IfStatement[?Yield, ?Return]
9318 case TokenKind::If:
9319 return ifStatement(yieldHandling);
9321 // BreakableStatement[?Yield, ?Return]
9323 // BreakableStatement[Yield, Return]:
9324 // IterationStatement[?Yield, ?Return]
9325 // SwitchStatement[?Yield, ?Return]
9326 case TokenKind::Do:
9327 return doWhileStatement(yieldHandling);
9329 case TokenKind::While:
9330 return whileStatement(yieldHandling);
9332 case TokenKind::For:
9333 return forStatement(yieldHandling);
9335 case TokenKind::Switch:
9336 return switchStatement(yieldHandling);
9338 // ContinueStatement[?Yield]
9339 case TokenKind::Continue:
9340 return continueStatement(yieldHandling);
9342 // BreakStatement[?Yield]
9343 case TokenKind::Break:
9344 return breakStatement(yieldHandling);
9346 // [+Return] ReturnStatement[?Yield]
9347 case TokenKind::Return:
9348 // The Return parameter is only used here, and the effect is easily
9349 // detected this way, so don't bother passing around an extra parameter
9350 // everywhere.
9351 if (!pc_->allowReturn()) {
9352 error(JSMSG_BAD_RETURN_OR_YIELD, "return");
9353 return errorResult();
9355 return returnStatement(yieldHandling);
9357 // WithStatement[?Yield, ?Return]
9358 case TokenKind::With:
9359 return withStatement(yieldHandling);
9361 // LabelledStatement[?Yield, ?Return]
9362 // This is really handled by default and TokenKind::Yield cases above.
9364 // ThrowStatement[?Yield]
9365 case TokenKind::Throw:
9366 return throwStatement(yieldHandling);
9368 // TryStatement[?Yield, ?Return]
9369 case TokenKind::Try:
9370 return tryStatement(yieldHandling);
9372 // DebuggerStatement
9373 case TokenKind::Debugger:
9374 return debuggerStatement();
9376 // Declaration[Yield]:
9378 // HoistableDeclaration[?Yield, ~Default]
9379 case TokenKind::Function:
9380 return functionStmt(pos().begin, yieldHandling, NameRequired);
9382 // DecoratorList[?Yield, ?Await] opt ClassDeclaration[?Yield, ~Default]
9383 #ifdef ENABLE_DECORATORS
9384 case TokenKind::At:
9385 return classDefinition(yieldHandling, ClassStatement, NameRequired);
9386 #endif
9388 case TokenKind::Class:
9389 return classDefinition(yieldHandling, ClassStatement, NameRequired);
9391 // LexicalDeclaration[In, ?Yield]
9392 // LetOrConst BindingList[?In, ?Yield]
9393 case TokenKind::Const:
9394 // [In] is the default behavior, because for-loops specially parse
9395 // their heads to handle |in| in this situation.
9396 return lexicalDeclaration(yieldHandling, DeclarationKind::Const);
9398 // ImportDeclaration (only inside modules)
9399 case TokenKind::Import:
9400 return importDeclarationOrImportExpr(yieldHandling);
9402 // ExportDeclaration (only inside modules)
9403 case TokenKind::Export:
9404 return exportDeclaration();
9406 // Miscellaneous error cases arguably better caught here than elsewhere.
9408 case TokenKind::Catch:
9409 error(JSMSG_CATCH_WITHOUT_TRY);
9410 return errorResult();
9412 case TokenKind::Finally:
9413 error(JSMSG_FINALLY_WITHOUT_TRY);
9414 return errorResult();
9416 // NOTE: default case handled in the ExpressionStatement section.
9420 template <class ParseHandler, typename Unit>
9421 typename ParseHandler::NodeResult GeneralParser<ParseHandler, Unit>::expr(
9422 InHandling inHandling, YieldHandling yieldHandling,
9423 TripledotHandling tripledotHandling,
9424 PossibleError* possibleError /* = nullptr */,
9425 InvokedPrediction invoked /* = PredictUninvoked */) {
9426 Node pn;
9427 MOZ_TRY_VAR(pn, assignExpr(inHandling, yieldHandling, tripledotHandling,
9428 possibleError, invoked));
9430 bool matched;
9431 if (!tokenStream.matchToken(&matched, TokenKind::Comma,
9432 TokenStream::SlashIsRegExp)) {
9433 return errorResult();
9435 if (!matched) {
9436 return pn;
9439 ListNodeType seq;
9440 MOZ_TRY_VAR(seq, handler_.newCommaExpressionList(pn));
9441 while (true) {
9442 // Trailing comma before the closing parenthesis is valid in an arrow
9443 // function parameters list: `(a, b, ) => body`. Check if we are
9444 // directly under CoverParenthesizedExpressionAndArrowParameterList,
9445 // and the next two tokens are closing parenthesis and arrow. If all
9446 // are present allow the trailing comma.
9447 if (tripledotHandling == TripledotAllowed) {
9448 TokenKind tt;
9449 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
9450 return errorResult();
9453 if (tt == TokenKind::RightParen) {
9454 tokenStream.consumeKnownToken(TokenKind::RightParen,
9455 TokenStream::SlashIsRegExp);
9457 if (!tokenStream.peekToken(&tt)) {
9458 return errorResult();
9460 if (tt != TokenKind::Arrow) {
9461 error(JSMSG_UNEXPECTED_TOKEN, "expression",
9462 TokenKindToDesc(TokenKind::RightParen));
9463 return errorResult();
9466 anyChars.ungetToken(); // put back right paren
9467 break;
9471 // Additional calls to assignExpr should not reuse the possibleError
9472 // which had been passed into the function. Otherwise we would lose
9473 // information needed to determine whether or not we're dealing with
9474 // a non-recoverable situation.
9475 PossibleError possibleErrorInner(*this);
9476 MOZ_TRY_VAR(pn, assignExpr(inHandling, yieldHandling, tripledotHandling,
9477 &possibleErrorInner));
9479 if (!possibleError) {
9480 // Report any pending expression error.
9481 if (!possibleErrorInner.checkForExpressionError()) {
9482 return errorResult();
9484 } else {
9485 possibleErrorInner.transferErrorsTo(possibleError);
9488 handler_.addList(seq, pn);
9490 if (!tokenStream.matchToken(&matched, TokenKind::Comma,
9491 TokenStream::SlashIsRegExp)) {
9492 return errorResult();
9494 if (!matched) {
9495 break;
9498 return seq;
9501 static ParseNodeKind BinaryOpTokenKindToParseNodeKind(TokenKind tok) {
9502 MOZ_ASSERT(TokenKindIsBinaryOp(tok));
9503 return ParseNodeKind(size_t(ParseNodeKind::BinOpFirst) +
9504 (size_t(tok) - size_t(TokenKind::BinOpFirst)));
9507 // This list must be kept in the same order in several places:
9508 // - The binary operators in ParseNode.h ,
9509 // - the binary operators in TokenKind.h
9510 // - the JSOp code list in BytecodeEmitter.cpp
9511 static const int PrecedenceTable[] = {
9512 1, /* ParseNodeKind::Coalesce */
9513 2, /* ParseNodeKind::Or */
9514 3, /* ParseNodeKind::And */
9515 4, /* ParseNodeKind::BitOr */
9516 5, /* ParseNodeKind::BitXor */
9517 6, /* ParseNodeKind::BitAnd */
9518 7, /* ParseNodeKind::StrictEq */
9519 7, /* ParseNodeKind::Eq */
9520 7, /* ParseNodeKind::StrictNe */
9521 7, /* ParseNodeKind::Ne */
9522 8, /* ParseNodeKind::Lt */
9523 8, /* ParseNodeKind::Le */
9524 8, /* ParseNodeKind::Gt */
9525 8, /* ParseNodeKind::Ge */
9526 8, /* ParseNodeKind::InstanceOf */
9527 8, /* ParseNodeKind::In */
9528 8, /* ParseNodeKind::PrivateIn */
9529 9, /* ParseNodeKind::Lsh */
9530 9, /* ParseNodeKind::Rsh */
9531 9, /* ParseNodeKind::Ursh */
9532 10, /* ParseNodeKind::Add */
9533 10, /* ParseNodeKind::Sub */
9534 11, /* ParseNodeKind::Star */
9535 11, /* ParseNodeKind::Div */
9536 11, /* ParseNodeKind::Mod */
9537 12 /* ParseNodeKind::Pow */
9540 static const int PRECEDENCE_CLASSES = 12;
9542 static int Precedence(ParseNodeKind pnk) {
9543 // Everything binds tighter than ParseNodeKind::Limit, because we want
9544 // to reduce all nodes to a single node when we reach a token that is not
9545 // another binary operator.
9546 if (pnk == ParseNodeKind::Limit) {
9547 return 0;
9550 MOZ_ASSERT(pnk >= ParseNodeKind::BinOpFirst);
9551 MOZ_ASSERT(pnk <= ParseNodeKind::BinOpLast);
9552 return PrecedenceTable[size_t(pnk) - size_t(ParseNodeKind::BinOpFirst)];
9555 enum class EnforcedParentheses : uint8_t { CoalesceExpr, AndOrExpr, None };
9557 template <class ParseHandler, typename Unit>
9558 MOZ_ALWAYS_INLINE typename ParseHandler::NodeResult
9559 GeneralParser<ParseHandler, Unit>::orExpr(InHandling inHandling,
9560 YieldHandling yieldHandling,
9561 TripledotHandling tripledotHandling,
9562 PossibleError* possibleError,
9563 InvokedPrediction invoked) {
9564 // Shift-reduce parser for the binary operator part of the JS expression
9565 // syntax.
9567 // Conceptually there's just one stack, a stack of pairs (lhs, op).
9568 // It's implemented using two separate arrays, though.
9569 Node nodeStack[PRECEDENCE_CLASSES];
9570 ParseNodeKind kindStack[PRECEDENCE_CLASSES];
9571 int depth = 0;
9572 Node pn;
9573 EnforcedParentheses unparenthesizedExpression = EnforcedParentheses::None;
9574 for (;;) {
9575 MOZ_TRY_VAR(
9576 pn, unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked,
9577 PrivateNameHandling::PrivateNameAllowed));
9579 // If a binary operator follows, consume it and compute the
9580 // corresponding operator.
9581 TokenKind tok;
9582 if (!tokenStream.getToken(&tok)) {
9583 return errorResult();
9586 // Ensure that if we have a private name lhs we are legally constructing a
9587 // `#x in obj` expessions:
9588 if (handler_.isPrivateName(pn)) {
9589 if (tok != TokenKind::In || inHandling != InAllowed) {
9590 error(JSMSG_ILLEGAL_PRIVATE_NAME);
9591 return errorResult();
9595 ParseNodeKind pnk;
9596 if (tok == TokenKind::In ? inHandling == InAllowed
9597 : TokenKindIsBinaryOp(tok)) {
9598 // We're definitely not in a destructuring context, so report any
9599 // pending expression error now.
9600 if (possibleError && !possibleError->checkForExpressionError()) {
9601 return errorResult();
9604 bool isErgonomicBrandCheck = false;
9605 switch (tok) {
9606 // Report an error for unary expressions on the LHS of **.
9607 case TokenKind::Pow:
9608 if (handler_.isUnparenthesizedUnaryExpression(pn)) {
9609 error(JSMSG_BAD_POW_LEFTSIDE);
9610 return errorResult();
9612 break;
9614 case TokenKind::Or:
9615 case TokenKind::And:
9616 // In the case that the `??` is on the left hand side of the
9617 // expression: Disallow Mixing of ?? and other logical operators (||
9618 // and &&) unless one expression is parenthesized
9619 if (unparenthesizedExpression == EnforcedParentheses::CoalesceExpr) {
9620 error(JSMSG_BAD_COALESCE_MIXING);
9621 return errorResult();
9623 // If we have not detected a mixing error at this point, record that
9624 // we have an unparenthesized expression, in case we have one later.
9625 unparenthesizedExpression = EnforcedParentheses::AndOrExpr;
9626 break;
9628 case TokenKind::Coalesce:
9629 if (unparenthesizedExpression == EnforcedParentheses::AndOrExpr) {
9630 error(JSMSG_BAD_COALESCE_MIXING);
9631 return errorResult();
9633 // If we have not detected a mixing error at this point, record that
9634 // we have an unparenthesized expression, in case we have one later.
9635 unparenthesizedExpression = EnforcedParentheses::CoalesceExpr;
9636 break;
9638 case TokenKind::In:
9639 // if the LHS is a private name, and the operator is In,
9640 // ensure we're construcing an ergonomic brand check of
9641 // '#x in y', rather than having a higher precedence operator
9642 // like + cause a different reduction, such as
9643 // 1 + #x in y.
9644 if (handler_.isPrivateName(pn)) {
9645 if (depth > 0 && Precedence(kindStack[depth - 1]) >=
9646 Precedence(ParseNodeKind::InExpr)) {
9647 error(JSMSG_INVALID_PRIVATE_NAME_PRECEDENCE);
9648 return errorResult();
9651 isErgonomicBrandCheck = true;
9653 break;
9655 default:
9656 // do nothing in other cases
9657 break;
9660 if (isErgonomicBrandCheck) {
9661 pnk = ParseNodeKind::PrivateInExpr;
9662 } else {
9663 pnk = BinaryOpTokenKindToParseNodeKind(tok);
9666 } else {
9667 tok = TokenKind::Eof;
9668 pnk = ParseNodeKind::Limit;
9671 // From this point on, destructuring defaults are definitely an error.
9672 possibleError = nullptr;
9674 // If pnk has precedence less than or equal to another operator on the
9675 // stack, reduce. This combines nodes on the stack until we form the
9676 // actual lhs of pnk.
9678 // The >= in this condition works because it is appendOrCreateList's
9679 // job to decide if the operator in question is left- or
9680 // right-associative, and build the corresponding tree.
9681 while (depth > 0 && Precedence(kindStack[depth - 1]) >= Precedence(pnk)) {
9682 depth--;
9683 ParseNodeKind combiningPnk = kindStack[depth];
9684 MOZ_TRY_VAR(pn, handler_.appendOrCreateList(combiningPnk,
9685 nodeStack[depth], pn, pc_));
9688 if (pnk == ParseNodeKind::Limit) {
9689 break;
9692 nodeStack[depth] = pn;
9693 kindStack[depth] = pnk;
9694 depth++;
9695 MOZ_ASSERT(depth <= PRECEDENCE_CLASSES);
9698 anyChars.ungetToken();
9700 // Had the next token been a Div, we would have consumed it. So there's no
9701 // ambiguity if we later (after ASI) re-get this token with SlashIsRegExp.
9702 anyChars.allowGettingNextTokenWithSlashIsRegExp();
9704 MOZ_ASSERT(depth == 0);
9705 return pn;
9708 template <class ParseHandler, typename Unit>
9709 MOZ_ALWAYS_INLINE typename ParseHandler::NodeResult
9710 GeneralParser<ParseHandler, Unit>::condExpr(InHandling inHandling,
9711 YieldHandling yieldHandling,
9712 TripledotHandling tripledotHandling,
9713 PossibleError* possibleError,
9714 InvokedPrediction invoked) {
9715 Node condition;
9716 MOZ_TRY_VAR(condition, orExpr(inHandling, yieldHandling, tripledotHandling,
9717 possibleError, invoked));
9719 bool matched;
9720 if (!tokenStream.matchToken(&matched, TokenKind::Hook,
9721 TokenStream::SlashIsInvalid)) {
9722 return errorResult();
9724 if (!matched) {
9725 return condition;
9728 Node thenExpr;
9729 MOZ_TRY_VAR(thenExpr,
9730 assignExpr(InAllowed, yieldHandling, TripledotProhibited));
9732 if (!mustMatchToken(TokenKind::Colon, JSMSG_COLON_IN_COND)) {
9733 return errorResult();
9736 Node elseExpr;
9737 MOZ_TRY_VAR(elseExpr,
9738 assignExpr(inHandling, yieldHandling, TripledotProhibited));
9740 return handler_.newConditional(condition, thenExpr, elseExpr);
9743 template <class ParseHandler, typename Unit>
9744 typename ParseHandler::NodeResult GeneralParser<ParseHandler, Unit>::assignExpr(
9745 InHandling inHandling, YieldHandling yieldHandling,
9746 TripledotHandling tripledotHandling,
9747 PossibleError* possibleError /* = nullptr */,
9748 InvokedPrediction invoked /* = PredictUninvoked */) {
9749 AutoCheckRecursionLimit recursion(this->fc_);
9750 if (!recursion.check(this->fc_)) {
9751 return errorResult();
9754 // It's very common at this point to have a "detectably simple" expression,
9755 // i.e. a name/number/string token followed by one of the following tokens
9756 // that obviously isn't part of an expression: , ; : ) ] }
9758 // (In Parsemark this happens 81.4% of the time; in code with large
9759 // numeric arrays, such as some Kraken benchmarks, it happens more often.)
9761 // In such cases, we can avoid the full expression parsing route through
9762 // assignExpr(), condExpr(), orExpr(), unaryExpr(), memberExpr(), and
9763 // primaryExpr().
9765 TokenKind firstToken;
9766 if (!tokenStream.getToken(&firstToken, TokenStream::SlashIsRegExp)) {
9767 return errorResult();
9770 TokenPos exprPos = pos();
9772 bool endsExpr;
9774 // This only handles identifiers that *never* have special meaning anywhere
9775 // in the language. Contextual keywords, reserved words in strict mode,
9776 // and other hard cases are handled outside this fast path.
9777 if (firstToken == TokenKind::Name) {
9778 if (!tokenStream.nextTokenEndsExpr(&endsExpr)) {
9779 return errorResult();
9781 if (endsExpr) {
9782 TaggedParserAtomIndex name = identifierReference(yieldHandling);
9783 if (!name) {
9784 return errorResult();
9787 return identifierReference(name);
9791 if (firstToken == TokenKind::Number) {
9792 if (!tokenStream.nextTokenEndsExpr(&endsExpr)) {
9793 return errorResult();
9795 if (endsExpr) {
9796 return newNumber(anyChars.currentToken());
9800 if (firstToken == TokenKind::String) {
9801 if (!tokenStream.nextTokenEndsExpr(&endsExpr)) {
9802 return errorResult();
9804 if (endsExpr) {
9805 return stringLiteral();
9809 if (firstToken == TokenKind::Yield && yieldExpressionsSupported()) {
9810 return yieldExpression(inHandling);
9813 bool maybeAsyncArrow = false;
9814 if (firstToken == TokenKind::Async) {
9815 TokenKind nextSameLine = TokenKind::Eof;
9816 if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
9817 return errorResult();
9820 if (TokenKindIsPossibleIdentifier(nextSameLine)) {
9821 maybeAsyncArrow = true;
9825 anyChars.ungetToken();
9827 // Save the tokenizer state in case we find an arrow function and have to
9828 // rewind.
9829 Position start(tokenStream);
9830 auto ghostToken = this->compilationState_.getPosition();
9832 PossibleError possibleErrorInner(*this);
9833 Node lhs;
9834 TokenKind tokenAfterLHS;
9835 bool isArrow;
9836 if (maybeAsyncArrow) {
9837 tokenStream.consumeKnownToken(TokenKind::Async, TokenStream::SlashIsRegExp);
9839 TokenKind tokenAfterAsync;
9840 if (!tokenStream.getToken(&tokenAfterAsync)) {
9841 return errorResult();
9843 MOZ_ASSERT(TokenKindIsPossibleIdentifier(tokenAfterAsync));
9845 // Check yield validity here.
9846 TaggedParserAtomIndex name = bindingIdentifier(yieldHandling);
9847 if (!name) {
9848 return errorResult();
9851 if (!tokenStream.peekToken(&tokenAfterLHS, TokenStream::SlashIsRegExp)) {
9852 return errorResult();
9855 isArrow = tokenAfterLHS == TokenKind::Arrow;
9857 // |async [no LineTerminator] of| without being followed by => is only
9858 // possible in for-await-of loops, e.g. |for await (async of [])|. Pretend
9859 // the |async| token was parsed an identifier reference and then proceed
9860 // with the rest of this function.
9861 if (!isArrow) {
9862 anyChars.ungetToken(); // unget the binding identifier
9864 // The next token is guaranteed to never be a Div (, because it's an
9865 // identifier), so it's okay to re-get the token with SlashIsRegExp.
9866 anyChars.allowGettingNextTokenWithSlashIsRegExp();
9868 TaggedParserAtomIndex asyncName = identifierReference(yieldHandling);
9869 if (!asyncName) {
9870 return errorResult();
9873 MOZ_TRY_VAR(lhs, identifierReference(asyncName));
9875 } else {
9876 MOZ_TRY_VAR(lhs, condExpr(inHandling, yieldHandling, tripledotHandling,
9877 &possibleErrorInner, invoked));
9879 // Use SlashIsRegExp here because the ConditionalExpression parsed above
9880 // could be the entirety of this AssignmentExpression, and then ASI
9881 // permits this token to be a regular expression.
9882 if (!tokenStream.peekToken(&tokenAfterLHS, TokenStream::SlashIsRegExp)) {
9883 return errorResult();
9886 isArrow = tokenAfterLHS == TokenKind::Arrow;
9889 if (isArrow) {
9890 // Rewind to reparse as an arrow function.
9892 // Note: We do not call CompilationState::rewind here because parsing
9893 // during delazification will see the same rewind and need the same sequence
9894 // of inner functions to skip over.
9895 // Instead, we mark inner functions as "ghost".
9897 // See GHOST_FUNCTION in FunctionFlags.h for more details.
9898 tokenStream.rewind(start);
9899 this->compilationState_.markGhost(ghostToken);
9901 TokenKind next;
9902 if (!tokenStream.getToken(&next, TokenStream::SlashIsRegExp)) {
9903 return errorResult();
9905 TokenPos startPos = pos();
9906 uint32_t toStringStart = startPos.begin;
9907 anyChars.ungetToken();
9909 FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction;
9911 if (next == TokenKind::Async) {
9912 tokenStream.consumeKnownToken(next, TokenStream::SlashIsRegExp);
9914 TokenKind nextSameLine = TokenKind::Eof;
9915 if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
9916 return errorResult();
9919 // The AsyncArrowFunction production are
9920 // async [no LineTerminator here] AsyncArrowBindingIdentifier ...
9921 // async [no LineTerminator here] ArrowFormalParameters ...
9922 if (TokenKindIsPossibleIdentifier(nextSameLine) ||
9923 nextSameLine == TokenKind::LeftParen) {
9924 asyncKind = FunctionAsyncKind::AsyncFunction;
9925 } else {
9926 anyChars.ungetToken();
9930 FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Arrow;
9931 FunctionNodeType funNode;
9932 MOZ_TRY_VAR(funNode, handler_.newFunction(syntaxKind, startPos));
9934 return functionDefinition(funNode, toStringStart, inHandling, yieldHandling,
9935 TaggedParserAtomIndex::null(), syntaxKind,
9936 GeneratorKind::NotGenerator, asyncKind);
9939 MOZ_ALWAYS_TRUE(
9940 tokenStream.getToken(&tokenAfterLHS, TokenStream::SlashIsRegExp));
9942 ParseNodeKind kind;
9943 switch (tokenAfterLHS) {
9944 case TokenKind::Assign:
9945 kind = ParseNodeKind::AssignExpr;
9946 break;
9947 case TokenKind::AddAssign:
9948 kind = ParseNodeKind::AddAssignExpr;
9949 break;
9950 case TokenKind::SubAssign:
9951 kind = ParseNodeKind::SubAssignExpr;
9952 break;
9953 case TokenKind::CoalesceAssign:
9954 kind = ParseNodeKind::CoalesceAssignExpr;
9955 break;
9956 case TokenKind::OrAssign:
9957 kind = ParseNodeKind::OrAssignExpr;
9958 break;
9959 case TokenKind::AndAssign:
9960 kind = ParseNodeKind::AndAssignExpr;
9961 break;
9962 case TokenKind::BitOrAssign:
9963 kind = ParseNodeKind::BitOrAssignExpr;
9964 break;
9965 case TokenKind::BitXorAssign:
9966 kind = ParseNodeKind::BitXorAssignExpr;
9967 break;
9968 case TokenKind::BitAndAssign:
9969 kind = ParseNodeKind::BitAndAssignExpr;
9970 break;
9971 case TokenKind::LshAssign:
9972 kind = ParseNodeKind::LshAssignExpr;
9973 break;
9974 case TokenKind::RshAssign:
9975 kind = ParseNodeKind::RshAssignExpr;
9976 break;
9977 case TokenKind::UrshAssign:
9978 kind = ParseNodeKind::UrshAssignExpr;
9979 break;
9980 case TokenKind::MulAssign:
9981 kind = ParseNodeKind::MulAssignExpr;
9982 break;
9983 case TokenKind::DivAssign:
9984 kind = ParseNodeKind::DivAssignExpr;
9985 break;
9986 case TokenKind::ModAssign:
9987 kind = ParseNodeKind::ModAssignExpr;
9988 break;
9989 case TokenKind::PowAssign:
9990 kind = ParseNodeKind::PowAssignExpr;
9991 break;
9993 default:
9994 MOZ_ASSERT(!anyChars.isCurrentTokenAssignment());
9995 if (!possibleError) {
9996 if (!possibleErrorInner.checkForExpressionError()) {
9997 return errorResult();
9999 } else {
10000 possibleErrorInner.transferErrorsTo(possibleError);
10003 anyChars.ungetToken();
10004 return lhs;
10007 // Verify the left-hand side expression doesn't have a forbidden form.
10008 if (handler_.isUnparenthesizedDestructuringPattern(lhs)) {
10009 if (kind != ParseNodeKind::AssignExpr) {
10010 error(JSMSG_BAD_DESTRUCT_ASS);
10011 return errorResult();
10014 if (!possibleErrorInner.checkForDestructuringErrorOrWarning()) {
10015 return errorResult();
10017 } else if (handler_.isName(lhs)) {
10018 if (const char* chars = nameIsArgumentsOrEval(lhs)) {
10019 // |chars| is "arguments" or "eval" here.
10020 if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) {
10021 return errorResult();
10024 } else if (handler_.isPropertyOrPrivateMemberAccess(lhs)) {
10025 // Permitted: no additional testing/fixup needed.
10026 } else if (handler_.isFunctionCall(lhs)) {
10027 // We don't have to worry about backward compatibility issues with the new
10028 // compound assignment operators, so we always throw here. Also that way we
10029 // don't have to worry if |f() &&= expr| should always throw an error or
10030 // only if |f()| returns true.
10031 if (kind == ParseNodeKind::CoalesceAssignExpr ||
10032 kind == ParseNodeKind::OrAssignExpr ||
10033 kind == ParseNodeKind::AndAssignExpr) {
10034 errorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS);
10035 return errorResult();
10038 if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS)) {
10039 return errorResult();
10042 if (possibleError) {
10043 possibleError->setPendingDestructuringErrorAt(exprPos,
10044 JSMSG_BAD_DESTRUCT_TARGET);
10046 } else {
10047 errorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS);
10048 return errorResult();
10051 if (!possibleErrorInner.checkForExpressionError()) {
10052 return errorResult();
10055 Node rhs;
10056 MOZ_TRY_VAR(rhs, assignExpr(inHandling, yieldHandling, TripledotProhibited));
10058 return handler_.newAssignment(kind, lhs, rhs);
10061 template <class ParseHandler>
10062 const char* PerHandlerParser<ParseHandler>::nameIsArgumentsOrEval(Node node) {
10063 MOZ_ASSERT(handler_.isName(node),
10064 "must only call this function on known names");
10066 if (handler_.isEvalName(node)) {
10067 return "eval";
10069 if (handler_.isArgumentsName(node)) {
10070 return "arguments";
10072 return nullptr;
10075 template <class ParseHandler, typename Unit>
10076 bool GeneralParser<ParseHandler, Unit>::checkIncDecOperand(
10077 Node operand, uint32_t operandOffset) {
10078 if (handler_.isName(operand)) {
10079 if (const char* chars = nameIsArgumentsOrEval(operand)) {
10080 if (!strictModeErrorAt(operandOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) {
10081 return false;
10084 } else if (handler_.isPropertyOrPrivateMemberAccess(operand)) {
10085 // Permitted: no additional testing/fixup needed.
10086 } else if (handler_.isFunctionCall(operand)) {
10087 // Assignment to function calls is forbidden in ES6. We're still
10088 // somewhat concerned about sites using this in dead code, so forbid it
10089 // only in strict mode code.
10090 if (!strictModeErrorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND)) {
10091 return false;
10093 } else {
10094 errorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND);
10095 return false;
10097 return true;
10100 template <class ParseHandler, typename Unit>
10101 typename ParseHandler::UnaryNodeResult
10102 GeneralParser<ParseHandler, Unit>::unaryOpExpr(YieldHandling yieldHandling,
10103 ParseNodeKind kind,
10104 uint32_t begin) {
10105 Node kid;
10106 MOZ_TRY_VAR(kid, unaryExpr(yieldHandling, TripledotProhibited));
10107 return handler_.newUnary(kind, begin, kid);
10110 template <class ParseHandler, typename Unit>
10111 typename ParseHandler::NodeResult
10112 GeneralParser<ParseHandler, Unit>::optionalExpr(
10113 YieldHandling yieldHandling, TripledotHandling tripledotHandling,
10114 TokenKind tt, PossibleError* possibleError /* = nullptr */,
10115 InvokedPrediction invoked /* = PredictUninvoked */) {
10116 AutoCheckRecursionLimit recursion(this->fc_);
10117 if (!recursion.check(this->fc_)) {
10118 return errorResult();
10121 uint32_t begin = pos().begin;
10123 Node lhs;
10124 MOZ_TRY_VAR(lhs,
10125 memberExpr(yieldHandling, tripledotHandling, tt,
10126 /* allowCallSyntax = */ true, possibleError, invoked));
10128 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsDiv)) {
10129 return errorResult();
10132 if (tt != TokenKind::OptionalChain) {
10133 return lhs;
10136 while (true) {
10137 if (!tokenStream.getToken(&tt)) {
10138 return errorResult();
10141 if (tt == TokenKind::Eof) {
10142 anyChars.ungetToken();
10143 break;
10146 Node nextMember;
10147 if (tt == TokenKind::OptionalChain) {
10148 if (!tokenStream.getToken(&tt)) {
10149 return errorResult();
10151 if (TokenKindIsPossibleIdentifierName(tt)) {
10152 MOZ_TRY_VAR(nextMember,
10153 memberPropertyAccess(lhs, OptionalKind::Optional));
10154 } else if (tt == TokenKind::PrivateName) {
10155 MOZ_TRY_VAR(nextMember,
10156 memberPrivateAccess(lhs, OptionalKind::Optional));
10157 } else if (tt == TokenKind::LeftBracket) {
10158 MOZ_TRY_VAR(nextMember, memberElemAccess(lhs, yieldHandling,
10159 OptionalKind::Optional));
10160 } else if (tt == TokenKind::LeftParen) {
10161 MOZ_TRY_VAR(nextMember,
10162 memberCall(tt, lhs, yieldHandling, possibleError,
10163 OptionalKind::Optional));
10164 } else {
10165 error(JSMSG_NAME_AFTER_DOT);
10166 return errorResult();
10168 } else if (tt == TokenKind::Dot) {
10169 if (!tokenStream.getToken(&tt)) {
10170 return errorResult();
10172 if (TokenKindIsPossibleIdentifierName(tt)) {
10173 MOZ_TRY_VAR(nextMember, memberPropertyAccess(lhs));
10174 } else if (tt == TokenKind::PrivateName) {
10175 MOZ_TRY_VAR(nextMember, memberPrivateAccess(lhs));
10176 } else {
10177 error(JSMSG_NAME_AFTER_DOT);
10178 return errorResult();
10180 } else if (tt == TokenKind::LeftBracket) {
10181 MOZ_TRY_VAR(nextMember, memberElemAccess(lhs, yieldHandling));
10182 } else if (tt == TokenKind::LeftParen) {
10183 MOZ_TRY_VAR(nextMember,
10184 memberCall(tt, lhs, yieldHandling, possibleError));
10185 } else if (tt == TokenKind::TemplateHead ||
10186 tt == TokenKind::NoSubsTemplate) {
10187 error(JSMSG_BAD_OPTIONAL_TEMPLATE);
10188 return errorResult();
10189 } else {
10190 anyChars.ungetToken();
10191 break;
10194 MOZ_ASSERT(nextMember);
10195 lhs = nextMember;
10198 return handler_.newOptionalChain(begin, lhs);
10201 template <class ParseHandler, typename Unit>
10202 typename ParseHandler::NodeResult GeneralParser<ParseHandler, Unit>::unaryExpr(
10203 YieldHandling yieldHandling, TripledotHandling tripledotHandling,
10204 PossibleError* possibleError /* = nullptr */,
10205 InvokedPrediction invoked /* = PredictUninvoked */,
10206 PrivateNameHandling privateNameHandling /* = PrivateNameProhibited */) {
10207 AutoCheckRecursionLimit recursion(this->fc_);
10208 if (!recursion.check(this->fc_)) {
10209 return errorResult();
10212 TokenKind tt;
10213 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
10214 return errorResult();
10216 uint32_t begin = pos().begin;
10217 switch (tt) {
10218 case TokenKind::Void:
10219 return unaryOpExpr(yieldHandling, ParseNodeKind::VoidExpr, begin);
10220 case TokenKind::Not:
10221 return unaryOpExpr(yieldHandling, ParseNodeKind::NotExpr, begin);
10222 case TokenKind::BitNot:
10223 return unaryOpExpr(yieldHandling, ParseNodeKind::BitNotExpr, begin);
10224 case TokenKind::Add:
10225 return unaryOpExpr(yieldHandling, ParseNodeKind::PosExpr, begin);
10226 case TokenKind::Sub:
10227 return unaryOpExpr(yieldHandling, ParseNodeKind::NegExpr, begin);
10229 case TokenKind::TypeOf: {
10230 // The |typeof| operator is specially parsed to distinguish its
10231 // application to a name, from its application to a non-name
10232 // expression:
10234 // // Looks up the name, doesn't find it and so evaluates to
10235 // // "undefined".
10236 // assertEq(typeof nonExistentName, "undefined");
10238 // // Evaluates expression, triggering a runtime ReferenceError for
10239 // // the undefined name.
10240 // typeof (1, nonExistentName);
10241 Node kid;
10242 MOZ_TRY_VAR(kid, unaryExpr(yieldHandling, TripledotProhibited));
10244 return handler_.newTypeof(begin, kid);
10247 case TokenKind::Inc:
10248 case TokenKind::Dec: {
10249 TokenKind tt2;
10250 if (!tokenStream.getToken(&tt2, TokenStream::SlashIsRegExp)) {
10251 return errorResult();
10254 uint32_t operandOffset = pos().begin;
10255 Node operand;
10256 MOZ_TRY_VAR(operand,
10257 optionalExpr(yieldHandling, TripledotProhibited, tt2));
10258 if (!checkIncDecOperand(operand, operandOffset)) {
10259 return errorResult();
10261 ParseNodeKind pnk = (tt == TokenKind::Inc)
10262 ? ParseNodeKind::PreIncrementExpr
10263 : ParseNodeKind::PreDecrementExpr;
10264 return handler_.newUpdate(pnk, begin, operand);
10266 case TokenKind::PrivateName: {
10267 if (privateNameHandling == PrivateNameHandling::PrivateNameAllowed) {
10268 TaggedParserAtomIndex field = anyChars.currentName();
10269 return privateNameReference(field);
10271 error(JSMSG_INVALID_PRIVATE_NAME_IN_UNARY_EXPR);
10272 return errorResult();
10275 case TokenKind::Delete: {
10276 uint32_t exprOffset;
10277 if (!tokenStream.peekOffset(&exprOffset, TokenStream::SlashIsRegExp)) {
10278 return errorResult();
10281 Node expr;
10282 MOZ_TRY_VAR(expr, unaryExpr(yieldHandling, TripledotProhibited));
10284 // Per spec, deleting most unary expressions is valid -- it simply
10285 // returns true -- except for two cases:
10286 // 1. `var x; ...; delete x` is a syntax error in strict mode.
10287 // 2. Private fields cannot be deleted.
10288 if (handler_.isName(expr)) {
10289 if (!strictModeErrorAt(exprOffset, JSMSG_DEPRECATED_DELETE_OPERAND)) {
10290 return errorResult();
10293 pc_->sc()->setBindingsAccessedDynamically();
10296 if (handler_.isPrivateMemberAccess(expr)) {
10297 errorAt(exprOffset, JSMSG_PRIVATE_DELETE);
10298 return errorResult();
10301 return handler_.newDelete(begin, expr);
10303 case TokenKind::Await: {
10304 // If we encounter an await in a module, mark it as async.
10305 if (!pc_->isAsync() && pc_->sc()->isModule()) {
10306 if (!options().topLevelAwait) {
10307 error(JSMSG_TOP_LEVEL_AWAIT_NOT_SUPPORTED);
10308 return errorResult();
10310 pc_->sc()->asModuleContext()->setIsAsync();
10311 MOZ_ASSERT(pc_->isAsync());
10314 if (pc_->isAsync()) {
10315 if (inParametersOfAsyncFunction()) {
10316 error(JSMSG_AWAIT_IN_PARAMETER);
10317 return errorResult();
10319 Node kid;
10320 MOZ_TRY_VAR(kid, unaryExpr(yieldHandling, tripledotHandling,
10321 possibleError, invoked));
10322 pc_->lastAwaitOffset = begin;
10323 return handler_.newAwaitExpression(begin, kid);
10327 [[fallthrough]];
10329 default: {
10330 Node expr;
10331 MOZ_TRY_VAR(expr, optionalExpr(yieldHandling, tripledotHandling, tt,
10332 possibleError, invoked));
10334 /* Don't look across a newline boundary for a postfix incop. */
10335 if (!tokenStream.peekTokenSameLine(&tt)) {
10336 return errorResult();
10339 if (tt != TokenKind::Inc && tt != TokenKind::Dec) {
10340 return expr;
10343 tokenStream.consumeKnownToken(tt);
10344 if (!checkIncDecOperand(expr, begin)) {
10345 return errorResult();
10348 ParseNodeKind pnk = (tt == TokenKind::Inc)
10349 ? ParseNodeKind::PostIncrementExpr
10350 : ParseNodeKind::PostDecrementExpr;
10351 return handler_.newUpdate(pnk, begin, expr);
10356 template <class ParseHandler, typename Unit>
10357 typename ParseHandler::NodeResult
10358 GeneralParser<ParseHandler, Unit>::assignExprWithoutYieldOrAwait(
10359 YieldHandling yieldHandling) {
10360 uint32_t startYieldOffset = pc_->lastYieldOffset;
10361 uint32_t startAwaitOffset = pc_->lastAwaitOffset;
10363 Node res;
10364 MOZ_TRY_VAR(res, assignExpr(InAllowed, yieldHandling, TripledotProhibited));
10366 if (pc_->lastYieldOffset != startYieldOffset) {
10367 errorAt(pc_->lastYieldOffset, JSMSG_YIELD_IN_PARAMETER);
10368 return errorResult();
10370 if (pc_->lastAwaitOffset != startAwaitOffset) {
10371 errorAt(pc_->lastAwaitOffset, JSMSG_AWAIT_IN_PARAMETER);
10372 return errorResult();
10374 return res;
10377 template <class ParseHandler, typename Unit>
10378 typename ParseHandler::ListNodeResult
10379 GeneralParser<ParseHandler, Unit>::argumentList(
10380 YieldHandling yieldHandling, bool* isSpread,
10381 PossibleError* possibleError /* = nullptr */) {
10382 ListNodeType argsList;
10383 MOZ_TRY_VAR(argsList, handler_.newArguments(pos()));
10385 bool matched;
10386 if (!tokenStream.matchToken(&matched, TokenKind::RightParen,
10387 TokenStream::SlashIsRegExp)) {
10388 return errorResult();
10390 if (matched) {
10391 handler_.setEndPosition(argsList, pos().end);
10392 return argsList;
10395 while (true) {
10396 bool spread = false;
10397 uint32_t begin = 0;
10398 if (!tokenStream.matchToken(&matched, TokenKind::TripleDot,
10399 TokenStream::SlashIsRegExp)) {
10400 return errorResult();
10402 if (matched) {
10403 spread = true;
10404 begin = pos().begin;
10405 *isSpread = true;
10408 Node argNode;
10409 MOZ_TRY_VAR(argNode, assignExpr(InAllowed, yieldHandling,
10410 TripledotProhibited, possibleError));
10411 if (spread) {
10412 MOZ_TRY_VAR(argNode, handler_.newSpread(begin, argNode));
10415 handler_.addList(argsList, argNode);
10417 bool matched;
10418 if (!tokenStream.matchToken(&matched, TokenKind::Comma,
10419 TokenStream::SlashIsRegExp)) {
10420 return errorResult();
10422 if (!matched) {
10423 break;
10426 TokenKind tt;
10427 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
10428 return errorResult();
10430 if (tt == TokenKind::RightParen) {
10431 break;
10435 if (!mustMatchToken(TokenKind::RightParen, JSMSG_PAREN_AFTER_ARGS)) {
10436 return errorResult();
10439 handler_.setEndPosition(argsList, pos().end);
10440 return argsList;
10443 bool ParserBase::checkAndMarkSuperScope() {
10444 if (!pc_->sc()->allowSuperProperty()) {
10445 return false;
10448 pc_->setSuperScopeNeedsHomeObject();
10449 return true;
10452 template <class ParseHandler, typename Unit>
10453 bool GeneralParser<ParseHandler, Unit>::computeErrorMetadata(
10454 ErrorMetadata* err, const ErrorReportMixin::ErrorOffset& offset) const {
10455 if (offset.is<ErrorReportMixin::Current>()) {
10456 return tokenStream.computeErrorMetadata(err, AsVariant(pos().begin));
10458 return tokenStream.computeErrorMetadata(err, offset);
10461 template <class ParseHandler, typename Unit>
10462 typename ParseHandler::NodeResult GeneralParser<ParseHandler, Unit>::memberExpr(
10463 YieldHandling yieldHandling, TripledotHandling tripledotHandling,
10464 TokenKind tt, bool allowCallSyntax, PossibleError* possibleError,
10465 InvokedPrediction invoked) {
10466 MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
10468 Node lhs;
10470 AutoCheckRecursionLimit recursion(this->fc_);
10471 if (!recursion.check(this->fc_)) {
10472 return errorResult();
10475 /* Check for new expression first. */
10476 if (tt == TokenKind::New) {
10477 uint32_t newBegin = pos().begin;
10478 // Make sure this wasn't a |new.target| in disguise.
10479 NewTargetNodeType newTarget;
10480 if (!tryNewTarget(&newTarget)) {
10481 return errorResult();
10483 if (newTarget) {
10484 lhs = newTarget;
10485 } else {
10486 // Gotten by tryNewTarget
10487 tt = anyChars.currentToken().type;
10488 Node ctorExpr;
10489 MOZ_TRY_VAR(ctorExpr,
10490 memberExpr(yieldHandling, TripledotProhibited, tt,
10491 /* allowCallSyntax = */ false,
10492 /* possibleError = */ nullptr, PredictInvoked));
10494 // If we have encountered an optional chain, in the form of `new
10495 // ClassName?.()` then we need to throw, as this is disallowed by the
10496 // spec.
10497 bool optionalToken;
10498 if (!tokenStream.matchToken(&optionalToken, TokenKind::OptionalChain)) {
10499 return errorResult();
10501 if (optionalToken) {
10502 errorAt(newBegin, JSMSG_BAD_NEW_OPTIONAL);
10503 return errorResult();
10506 bool matched;
10507 if (!tokenStream.matchToken(&matched, TokenKind::LeftParen)) {
10508 return errorResult();
10511 bool isSpread = false;
10512 ListNodeType args;
10513 if (matched) {
10514 MOZ_TRY_VAR(args, argumentList(yieldHandling, &isSpread));
10515 } else {
10516 MOZ_TRY_VAR(args, handler_.newArguments(pos()));
10519 if (!args) {
10520 return errorResult();
10523 MOZ_TRY_VAR(
10524 lhs, handler_.newNewExpression(newBegin, ctorExpr, args, isSpread));
10526 } else if (tt == TokenKind::Super) {
10527 NameNodeType thisName;
10528 MOZ_TRY_VAR(thisName, newThisName());
10529 MOZ_TRY_VAR(lhs, handler_.newSuperBase(thisName, pos()));
10530 } else if (tt == TokenKind::Import) {
10531 MOZ_TRY_VAR(lhs, importExpr(yieldHandling, allowCallSyntax));
10532 } else {
10533 MOZ_TRY_VAR(lhs, primaryExpr(yieldHandling, tripledotHandling, tt,
10534 possibleError, invoked));
10537 MOZ_ASSERT_IF(handler_.isSuperBase(lhs),
10538 anyChars.isCurrentTokenType(TokenKind::Super));
10540 while (true) {
10541 if (!tokenStream.getToken(&tt)) {
10542 return errorResult();
10544 if (tt == TokenKind::Eof) {
10545 anyChars.ungetToken();
10546 break;
10549 Node nextMember;
10550 if (tt == TokenKind::Dot) {
10551 if (!tokenStream.getToken(&tt)) {
10552 return errorResult();
10555 if (TokenKindIsPossibleIdentifierName(tt)) {
10556 MOZ_TRY_VAR(nextMember, memberPropertyAccess(lhs));
10557 } else if (tt == TokenKind::PrivateName) {
10558 MOZ_TRY_VAR(nextMember, memberPrivateAccess(lhs));
10559 } else {
10560 error(JSMSG_NAME_AFTER_DOT);
10561 return errorResult();
10563 } else if (tt == TokenKind::LeftBracket) {
10564 MOZ_TRY_VAR(nextMember, memberElemAccess(lhs, yieldHandling));
10565 } else if ((allowCallSyntax && tt == TokenKind::LeftParen) ||
10566 tt == TokenKind::TemplateHead ||
10567 tt == TokenKind::NoSubsTemplate) {
10568 if (handler_.isSuperBase(lhs)) {
10569 if (!pc_->sc()->allowSuperCall()) {
10570 error(JSMSG_BAD_SUPERCALL);
10571 return errorResult();
10574 if (tt != TokenKind::LeftParen) {
10575 error(JSMSG_BAD_SUPER);
10576 return errorResult();
10579 MOZ_TRY_VAR(nextMember, memberSuperCall(lhs, yieldHandling));
10581 if (!noteUsedName(
10582 TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
10583 return errorResult();
10585 } else {
10586 MOZ_TRY_VAR(nextMember,
10587 memberCall(tt, lhs, yieldHandling, possibleError));
10589 } else {
10590 anyChars.ungetToken();
10591 if (handler_.isSuperBase(lhs)) {
10592 break;
10594 return lhs;
10597 lhs = nextMember;
10600 if (handler_.isSuperBase(lhs)) {
10601 error(JSMSG_BAD_SUPER);
10602 return errorResult();
10605 return lhs;
10608 template <class ParseHandler, typename Unit>
10609 typename ParseHandler::NodeResult
10610 GeneralParser<ParseHandler, Unit>::decoratorExpr(YieldHandling yieldHandling,
10611 TokenKind tt) {
10612 MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
10614 AutoCheckRecursionLimit recursion(this->fc_);
10615 if (!recursion.check(this->fc_)) {
10616 return errorResult();
10619 if (tt == TokenKind::LeftParen) {
10620 // DecoratorParenthesizedExpression
10621 Node expr;
10622 MOZ_TRY_VAR(expr, exprInParens(InAllowed, yieldHandling, TripledotAllowed,
10623 /* possibleError*/ nullptr));
10624 if (!mustMatchToken(TokenKind::RightParen, JSMSG_PAREN_AFTER_DECORATOR)) {
10625 return errorResult();
10628 return handler_.parenthesize(expr);
10631 if (!TokenKindIsPossibleIdentifier(tt)) {
10632 error(JSMSG_DECORATOR_NAME_EXPECTED);
10633 return errorResult();
10636 TaggedParserAtomIndex name = identifierReference(yieldHandling);
10637 if (!name) {
10638 return errorResult();
10641 Node lhs;
10642 MOZ_TRY_VAR(lhs, identifierReference(name));
10644 while (true) {
10645 if (!tokenStream.getToken(&tt)) {
10646 return errorResult();
10648 if (tt == TokenKind::Eof) {
10649 anyChars.ungetToken();
10650 break;
10653 Node nextMember;
10654 if (tt == TokenKind::Dot) {
10655 if (!tokenStream.getToken(&tt)) {
10656 return errorResult();
10659 if (TokenKindIsPossibleIdentifierName(tt)) {
10660 MOZ_TRY_VAR(nextMember, memberPropertyAccess(lhs));
10661 } else if (tt == TokenKind::PrivateName) {
10662 MOZ_TRY_VAR(nextMember, memberPrivateAccess(lhs));
10663 } else {
10664 error(JSMSG_NAME_AFTER_DOT);
10665 return errorResult();
10667 } else if (tt == TokenKind::LeftParen) {
10668 MOZ_TRY_VAR(nextMember, memberCall(tt, lhs, yieldHandling,
10669 /* possibleError */ nullptr));
10670 lhs = nextMember;
10671 // This is a `DecoratorCallExpression` and it's defined at the top level
10672 // of `Decorator`, no other `DecoratorMemberExpression` is allowed to
10673 // follow after the arguments.
10674 break;
10675 } else {
10676 anyChars.ungetToken();
10677 break;
10680 lhs = nextMember;
10683 return lhs;
10686 template <class ParseHandler>
10687 inline typename ParseHandler::NameNodeResult
10688 PerHandlerParser<ParseHandler>::newName(TaggedParserAtomIndex name) {
10689 return newName(name, pos());
10692 template <class ParseHandler>
10693 inline typename ParseHandler::NameNodeResult
10694 PerHandlerParser<ParseHandler>::newName(TaggedParserAtomIndex name,
10695 TokenPos pos) {
10696 return handler_.newName(name, pos);
10699 template <class ParseHandler>
10700 inline typename ParseHandler::NameNodeResult
10701 PerHandlerParser<ParseHandler>::newPrivateName(TaggedParserAtomIndex name) {
10702 return handler_.newPrivateName(name, pos());
10705 template <class ParseHandler, typename Unit>
10706 typename ParseHandler::NodeResult
10707 GeneralParser<ParseHandler, Unit>::memberPropertyAccess(
10708 Node lhs, OptionalKind optionalKind /* = OptionalKind::NonOptional */) {
10709 MOZ_ASSERT(TokenKindIsPossibleIdentifierName(anyChars.currentToken().type) ||
10710 anyChars.currentToken().type == TokenKind::PrivateName);
10711 TaggedParserAtomIndex field = anyChars.currentName();
10712 if (handler_.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
10713 error(JSMSG_BAD_SUPERPROP, "property");
10714 return errorResult();
10717 NameNodeType name;
10718 MOZ_TRY_VAR(name, handler_.newPropertyName(field, pos()));
10720 if (optionalKind == OptionalKind::Optional) {
10721 MOZ_ASSERT(!handler_.isSuperBase(lhs));
10722 return handler_.newOptionalPropertyAccess(lhs, name);
10724 return handler_.newPropertyAccess(lhs, name);
10727 template <class ParseHandler, typename Unit>
10728 typename ParseHandler::NodeResult
10729 GeneralParser<ParseHandler, Unit>::memberPrivateAccess(
10730 Node lhs, OptionalKind optionalKind /* = OptionalKind::NonOptional */) {
10731 MOZ_ASSERT(anyChars.currentToken().type == TokenKind::PrivateName);
10733 TaggedParserAtomIndex field = anyChars.currentName();
10734 // Cannot access private fields on super.
10735 if (handler_.isSuperBase(lhs)) {
10736 error(JSMSG_BAD_SUPERPRIVATE);
10737 return errorResult();
10740 NameNodeType privateName;
10741 MOZ_TRY_VAR(privateName, privateNameReference(field));
10743 if (optionalKind == OptionalKind::Optional) {
10744 MOZ_ASSERT(!handler_.isSuperBase(lhs));
10745 return handler_.newOptionalPrivateMemberAccess(lhs, privateName, pos().end);
10747 return handler_.newPrivateMemberAccess(lhs, privateName, pos().end);
10750 template <class ParseHandler, typename Unit>
10751 typename ParseHandler::NodeResult
10752 GeneralParser<ParseHandler, Unit>::memberElemAccess(
10753 Node lhs, YieldHandling yieldHandling,
10754 OptionalKind optionalKind /* = OptionalKind::NonOptional */) {
10755 MOZ_ASSERT(anyChars.currentToken().type == TokenKind::LeftBracket);
10756 Node propExpr;
10757 MOZ_TRY_VAR(propExpr, expr(InAllowed, yieldHandling, TripledotProhibited));
10759 if (!mustMatchToken(TokenKind::RightBracket, JSMSG_BRACKET_IN_INDEX)) {
10760 return errorResult();
10763 if (handler_.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
10764 error(JSMSG_BAD_SUPERPROP, "member");
10765 return errorResult();
10767 if (optionalKind == OptionalKind::Optional) {
10768 MOZ_ASSERT(!handler_.isSuperBase(lhs));
10769 return handler_.newOptionalPropertyByValue(lhs, propExpr, pos().end);
10771 return handler_.newPropertyByValue(lhs, propExpr, pos().end);
10774 template <class ParseHandler, typename Unit>
10775 typename ParseHandler::NodeResult
10776 GeneralParser<ParseHandler, Unit>::memberSuperCall(
10777 Node lhs, YieldHandling yieldHandling) {
10778 MOZ_ASSERT(anyChars.currentToken().type == TokenKind::LeftParen);
10779 // Despite the fact that it's impossible to have |super()| in a
10780 // generator, we still inherit the yieldHandling of the
10781 // memberExpression, per spec. Curious.
10782 bool isSpread = false;
10783 ListNodeType args;
10784 MOZ_TRY_VAR(args, argumentList(yieldHandling, &isSpread));
10786 CallNodeType superCall;
10787 MOZ_TRY_VAR(superCall, handler_.newSuperCall(lhs, args, isSpread));
10789 // |super()| implicitly reads |new.target|.
10790 if (!noteUsedName(TaggedParserAtomIndex::WellKnown::dot_newTarget_())) {
10791 return errorResult();
10794 NameNodeType thisName;
10795 MOZ_TRY_VAR(thisName, newThisName());
10797 return handler_.newSetThis(thisName, superCall);
10800 template <class ParseHandler, typename Unit>
10801 typename ParseHandler::NodeResult GeneralParser<ParseHandler, Unit>::memberCall(
10802 TokenKind tt, Node lhs, YieldHandling yieldHandling,
10803 PossibleError* possibleError /* = nullptr */,
10804 OptionalKind optionalKind /* = OptionalKind::NonOptional */) {
10805 if (options().selfHostingMode &&
10806 (handler_.isPropertyOrPrivateMemberAccess(lhs) ||
10807 handler_.isOptionalPropertyOrPrivateMemberAccess(lhs))) {
10808 error(JSMSG_SELFHOSTED_METHOD_CALL);
10809 return errorResult();
10812 MOZ_ASSERT(tt == TokenKind::LeftParen || tt == TokenKind::TemplateHead ||
10813 tt == TokenKind::NoSubsTemplate,
10814 "Unexpected token kind for member call");
10816 JSOp op = JSOp::Call;
10817 bool maybeAsyncArrow = false;
10818 if (tt == TokenKind::LeftParen && optionalKind == OptionalKind::NonOptional) {
10819 if (handler_.isAsyncKeyword(lhs)) {
10820 // |async (| can be the start of an async arrow
10821 // function, so we need to defer reporting possible
10822 // errors from destructuring syntax. To give better
10823 // error messages, we only allow the AsyncArrowHead
10824 // part of the CoverCallExpressionAndAsyncArrowHead
10825 // syntax when the initial name is "async".
10826 maybeAsyncArrow = true;
10827 } else if (handler_.isEvalName(lhs)) {
10828 // Select the right Eval op and flag pc_ as having a
10829 // direct eval.
10830 op = pc_->sc()->strict() ? JSOp::StrictEval : JSOp::Eval;
10831 pc_->sc()->setBindingsAccessedDynamically();
10832 pc_->sc()->setHasDirectEval();
10834 // In non-strict mode code, direct calls to eval can
10835 // add variables to the call object.
10836 if (pc_->isFunctionBox() && !pc_->sc()->strict()) {
10837 pc_->functionBox()->setFunHasExtensibleScope();
10840 // If we're in a method, mark the method as requiring
10841 // support for 'super', since direct eval code can use
10842 // it. (If we're not in a method, that's fine, so
10843 // ignore the return value.)
10844 checkAndMarkSuperScope();
10848 if (tt == TokenKind::LeftParen) {
10849 bool isSpread = false;
10850 PossibleError* asyncPossibleError =
10851 maybeAsyncArrow ? possibleError : nullptr;
10852 ListNodeType args;
10853 MOZ_TRY_VAR(args,
10854 argumentList(yieldHandling, &isSpread, asyncPossibleError));
10855 if (isSpread) {
10856 if (op == JSOp::Eval) {
10857 op = JSOp::SpreadEval;
10858 } else if (op == JSOp::StrictEval) {
10859 op = JSOp::StrictSpreadEval;
10860 } else {
10861 op = JSOp::SpreadCall;
10865 if (optionalKind == OptionalKind::Optional) {
10866 return handler_.newOptionalCall(lhs, args, op);
10868 return handler_.newCall(lhs, args, op);
10871 ListNodeType args;
10872 MOZ_TRY_VAR(args, handler_.newArguments(pos()));
10874 if (!taggedTemplate(yieldHandling, args, tt)) {
10875 return errorResult();
10878 if (optionalKind == OptionalKind::Optional) {
10879 error(JSMSG_BAD_OPTIONAL_TEMPLATE);
10880 return errorResult();
10883 return handler_.newTaggedTemplate(lhs, args, op);
10886 template <class ParseHandler, typename Unit>
10887 bool GeneralParser<ParseHandler, Unit>::checkLabelOrIdentifierReference(
10888 TaggedParserAtomIndex ident, uint32_t offset, YieldHandling yieldHandling,
10889 TokenKind hint /* = TokenKind::Limit */) {
10890 TokenKind tt;
10891 if (hint == TokenKind::Limit) {
10892 tt = ReservedWordTokenKind(ident);
10893 } else {
10894 // All non-reserved word kinds are folded into TokenKind::Limit in
10895 // ReservedWordTokenKind and the following code.
10896 if (hint == TokenKind::Name || hint == TokenKind::PrivateName) {
10897 hint = TokenKind::Limit;
10899 MOZ_ASSERT(hint == ReservedWordTokenKind(ident),
10900 "hint doesn't match actual token kind");
10901 tt = hint;
10904 if (!pc_->sc()->allowArguments() &&
10905 ident == TaggedParserAtomIndex::WellKnown::arguments()) {
10906 error(JSMSG_BAD_ARGUMENTS);
10907 return false;
10910 if (tt == TokenKind::Limit) {
10911 // Either TokenKind::Name or TokenKind::PrivateName
10912 return true;
10914 if (TokenKindIsContextualKeyword(tt)) {
10915 if (tt == TokenKind::Yield) {
10916 if (yieldHandling == YieldIsKeyword) {
10917 errorAt(offset, JSMSG_RESERVED_ID, "yield");
10918 return false;
10920 if (pc_->sc()->strict()) {
10921 if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "yield")) {
10922 return false;
10925 return true;
10927 if (tt == TokenKind::Await) {
10928 if (awaitIsKeyword() || awaitIsDisallowed()) {
10929 errorAt(offset, JSMSG_RESERVED_ID, "await");
10930 return false;
10932 return true;
10934 if (pc_->sc()->strict()) {
10935 if (tt == TokenKind::Let) {
10936 if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "let")) {
10937 return false;
10939 return true;
10941 if (tt == TokenKind::Static) {
10942 if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "static")) {
10943 return false;
10945 return true;
10948 return true;
10950 if (TokenKindIsStrictReservedWord(tt)) {
10951 if (pc_->sc()->strict()) {
10952 if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID,
10953 ReservedWordToCharZ(tt))) {
10954 return false;
10957 return true;
10959 if (TokenKindIsKeyword(tt) || TokenKindIsReservedWordLiteral(tt)) {
10960 errorAt(offset, JSMSG_INVALID_ID, ReservedWordToCharZ(tt));
10961 return false;
10963 if (TokenKindIsFutureReservedWord(tt)) {
10964 errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(tt));
10965 return false;
10967 MOZ_ASSERT_UNREACHABLE("Unexpected reserved word kind.");
10968 return false;
10971 template <class ParseHandler, typename Unit>
10972 bool GeneralParser<ParseHandler, Unit>::checkBindingIdentifier(
10973 TaggedParserAtomIndex ident, uint32_t offset, YieldHandling yieldHandling,
10974 TokenKind hint /* = TokenKind::Limit */) {
10975 if (pc_->sc()->strict()) {
10976 if (ident == TaggedParserAtomIndex::WellKnown::arguments()) {
10977 if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "arguments")) {
10978 return false;
10980 return true;
10983 if (ident == TaggedParserAtomIndex::WellKnown::eval()) {
10984 if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "eval")) {
10985 return false;
10987 return true;
10991 return checkLabelOrIdentifierReference(ident, offset, yieldHandling, hint);
10994 template <class ParseHandler, typename Unit>
10995 TaggedParserAtomIndex
10996 GeneralParser<ParseHandler, Unit>::labelOrIdentifierReference(
10997 YieldHandling yieldHandling) {
10998 // ES 2017 draft 12.1.1.
10999 // StringValue of IdentifierName normalizes any Unicode escape sequences
11000 // in IdentifierName hence such escapes cannot be used to write an
11001 // Identifier whose code point sequence is the same as a ReservedWord.
11003 // Use const ParserName* instead of TokenKind to reflect the normalization.
11005 // Unless the name contains escapes, we can reuse the current TokenKind
11006 // to determine if the name is a restricted identifier.
11007 TokenKind hint = !anyChars.currentNameHasEscapes(this->parserAtoms())
11008 ? anyChars.currentToken().type
11009 : TokenKind::Limit;
11010 TaggedParserAtomIndex ident = anyChars.currentName();
11011 if (!checkLabelOrIdentifierReference(ident, pos().begin, yieldHandling,
11012 hint)) {
11013 return TaggedParserAtomIndex::null();
11015 return ident;
11018 template <class ParseHandler, typename Unit>
11019 TaggedParserAtomIndex GeneralParser<ParseHandler, Unit>::bindingIdentifier(
11020 YieldHandling yieldHandling) {
11021 TokenKind hint = !anyChars.currentNameHasEscapes(this->parserAtoms())
11022 ? anyChars.currentToken().type
11023 : TokenKind::Limit;
11024 TaggedParserAtomIndex ident = anyChars.currentName();
11025 if (!checkBindingIdentifier(ident, pos().begin, yieldHandling, hint)) {
11026 return TaggedParserAtomIndex::null();
11028 return ident;
11031 template <class ParseHandler>
11032 typename ParseHandler::NameNodeResult
11033 PerHandlerParser<ParseHandler>::identifierReference(
11034 TaggedParserAtomIndex name) {
11035 NameNodeType id;
11036 MOZ_TRY_VAR(id, newName(name));
11038 if (!noteUsedName(name)) {
11039 return errorResult();
11042 return id;
11045 template <class ParseHandler>
11046 typename ParseHandler::NameNodeResult
11047 PerHandlerParser<ParseHandler>::privateNameReference(
11048 TaggedParserAtomIndex name) {
11049 NameNodeType id;
11050 MOZ_TRY_VAR(id, newPrivateName(name));
11052 if (!noteUsedName(name, NameVisibility::Private, Some(pos()))) {
11053 return errorResult();
11056 return id;
11059 template <class ParseHandler>
11060 typename ParseHandler::NameNodeResult
11061 PerHandlerParser<ParseHandler>::stringLiteral() {
11062 return handler_.newStringLiteral(anyChars.currentToken().atom(), pos());
11065 template <class ParseHandler>
11066 typename ParseHandler::NodeResult
11067 PerHandlerParser<ParseHandler>::noSubstitutionTaggedTemplate() {
11068 if (anyChars.hasInvalidTemplateEscape()) {
11069 anyChars.clearInvalidTemplateEscape();
11070 return handler_.newRawUndefinedLiteral(pos());
11073 return handler_.newTemplateStringLiteral(anyChars.currentToken().atom(),
11074 pos());
11077 template <class ParseHandler, typename Unit>
11078 typename ParseHandler::NameNodeResult
11079 GeneralParser<ParseHandler, Unit>::noSubstitutionUntaggedTemplate() {
11080 if (!tokenStream.checkForInvalidTemplateEscapeError()) {
11081 return errorResult();
11084 return handler_.newTemplateStringLiteral(anyChars.currentToken().atom(),
11085 pos());
11088 template <typename Unit>
11089 FullParseHandler::RegExpLiteralResult
11090 Parser<FullParseHandler, Unit>::newRegExp() {
11091 MOZ_ASSERT(!options().selfHostingMode);
11093 // Create the regexp and check its syntax.
11094 const auto& chars = tokenStream.getCharBuffer();
11095 mozilla::Range<const char16_t> range(chars.begin(), chars.length());
11096 RegExpFlags flags = anyChars.currentToken().regExpFlags();
11098 uint32_t offset = anyChars.currentToken().pos.begin;
11099 uint32_t line;
11100 JS::LimitedColumnNumberOneOrigin column;
11101 tokenStream.computeLineAndColumn(offset, &line, &column);
11103 if (!handler_.reuseRegexpSyntaxParse()) {
11104 // Verify that the Regexp will syntax parse when the time comes to
11105 // instantiate it. If we have already done a syntax parse, we can
11106 // skip this.
11107 if (!irregexp::CheckPatternSyntax(
11108 this->alloc_, this->fc_->stackLimit(), anyChars, range, flags,
11109 Some(line), Some(JS::ColumnNumberOneOrigin(column)))) {
11110 return errorResult();
11114 auto atom =
11115 this->parserAtoms().internChar16(fc_, chars.begin(), chars.length());
11116 if (!atom) {
11117 return errorResult();
11119 // RegExp patterm must be atomized.
11120 this->parserAtoms().markUsedByStencil(atom, ParserAtom::Atomize::Yes);
11122 RegExpIndex index(this->compilationState_.regExpData.length());
11123 if (uint32_t(index) >= TaggedScriptThingIndex::IndexLimit) {
11124 ReportAllocationOverflow(fc_);
11125 return errorResult();
11127 if (!this->compilationState_.regExpData.emplaceBack(atom, flags)) {
11128 js::ReportOutOfMemory(this->fc_);
11129 return errorResult();
11132 return handler_.newRegExp(index, pos());
11135 template <typename Unit>
11136 SyntaxParseHandler::RegExpLiteralResult
11137 Parser<SyntaxParseHandler, Unit>::newRegExp() {
11138 MOZ_ASSERT(!options().selfHostingMode);
11140 // Only check the regexp's syntax, but don't create a regexp object.
11141 const auto& chars = tokenStream.getCharBuffer();
11142 RegExpFlags flags = anyChars.currentToken().regExpFlags();
11144 uint32_t offset = anyChars.currentToken().pos.begin;
11145 uint32_t line;
11146 JS::LimitedColumnNumberOneOrigin column;
11147 tokenStream.computeLineAndColumn(offset, &line, &column);
11149 mozilla::Range<const char16_t> source(chars.begin(), chars.length());
11150 if (!irregexp::CheckPatternSyntax(this->alloc_, this->fc_->stackLimit(),
11151 anyChars, source, flags, Some(line),
11152 Some(JS::ColumnNumberOneOrigin(column)))) {
11153 return errorResult();
11156 return handler_.newRegExp(SyntaxParseHandler::Node::NodeGeneric, pos());
11159 template <class ParseHandler, typename Unit>
11160 typename ParseHandler::RegExpLiteralResult
11161 GeneralParser<ParseHandler, Unit>::newRegExp() {
11162 return asFinalParser()->newRegExp();
11165 template <typename Unit>
11166 FullParseHandler::BigIntLiteralResult
11167 Parser<FullParseHandler, Unit>::newBigInt() {
11168 // The token's charBuffer contains the DecimalIntegerLiteral or
11169 // NonDecimalIntegerLiteral production, and as such does not include the
11170 // BigIntLiteralSuffix (the trailing "n"). Note that NonDecimalIntegerLiteral
11171 // productions start with 0[bBoOxX], indicating binary/octal/hex.
11172 const auto& chars = tokenStream.getCharBuffer();
11173 if (chars.length() > UINT32_MAX) {
11174 ReportAllocationOverflow(fc_);
11175 return errorResult();
11178 BigIntIndex index(this->compilationState_.bigIntData.length());
11179 if (uint32_t(index) >= TaggedScriptThingIndex::IndexLimit) {
11180 ReportAllocationOverflow(fc_);
11181 return errorResult();
11183 if (!this->compilationState_.bigIntData.emplaceBack()) {
11184 js::ReportOutOfMemory(this->fc_);
11185 return errorResult();
11188 if (!this->compilationState_.bigIntData[index].init(
11189 this->fc_, this->stencilAlloc(), chars)) {
11190 return errorResult();
11193 bool isZero = this->compilationState_.bigIntData[index].isZero();
11195 // Should the operations below fail, the buffer held by data will
11196 // be cleaned up by the CompilationState destructor.
11197 return handler_.newBigInt(index, isZero, pos());
11200 template <typename Unit>
11201 SyntaxParseHandler::BigIntLiteralResult
11202 Parser<SyntaxParseHandler, Unit>::newBigInt() {
11203 // The tokenizer has already checked the syntax of the bigint.
11205 return handler_.newBigInt();
11208 template <class ParseHandler, typename Unit>
11209 typename ParseHandler::BigIntLiteralResult
11210 GeneralParser<ParseHandler, Unit>::newBigInt() {
11211 return asFinalParser()->newBigInt();
11214 // |exprPossibleError| is the PossibleError state within |expr|,
11215 // |possibleError| is the surrounding PossibleError state.
11216 template <class ParseHandler, typename Unit>
11217 bool GeneralParser<ParseHandler, Unit>::checkDestructuringAssignmentTarget(
11218 Node expr, TokenPos exprPos, PossibleError* exprPossibleError,
11219 PossibleError* possibleError, TargetBehavior behavior) {
11220 // Report any pending expression error if we're definitely not in a
11221 // destructuring context or the possible destructuring target is a
11222 // property accessor.
11223 if (!possibleError || handler_.isPropertyOrPrivateMemberAccess(expr)) {
11224 return exprPossibleError->checkForExpressionError();
11227 // |expr| may end up as a destructuring assignment target, so we need to
11228 // validate it's either a name or can be parsed as a nested destructuring
11229 // pattern. Property accessors are also valid assignment targets, but
11230 // those are already handled above.
11232 exprPossibleError->transferErrorsTo(possibleError);
11234 // Return early if a pending destructuring error is already present.
11235 if (possibleError->hasPendingDestructuringError()) {
11236 return true;
11239 if (handler_.isName(expr)) {
11240 checkDestructuringAssignmentName(handler_.asNameNode(expr), exprPos,
11241 possibleError);
11242 return true;
11245 if (handler_.isUnparenthesizedDestructuringPattern(expr)) {
11246 if (behavior == TargetBehavior::ForbidAssignmentPattern) {
11247 possibleError->setPendingDestructuringErrorAt(exprPos,
11248 JSMSG_BAD_DESTRUCT_TARGET);
11250 return true;
11253 // Parentheses are forbidden around destructuring *patterns* (but allowed
11254 // around names). Use our nicer error message for parenthesized, nested
11255 // patterns if nested destructuring patterns are allowed.
11256 if (handler_.isParenthesizedDestructuringPattern(expr) &&
11257 behavior != TargetBehavior::ForbidAssignmentPattern) {
11258 possibleError->setPendingDestructuringErrorAt(exprPos,
11259 JSMSG_BAD_DESTRUCT_PARENS);
11260 } else {
11261 possibleError->setPendingDestructuringErrorAt(exprPos,
11262 JSMSG_BAD_DESTRUCT_TARGET);
11265 return true;
11268 template <class ParseHandler, typename Unit>
11269 void GeneralParser<ParseHandler, Unit>::checkDestructuringAssignmentName(
11270 NameNodeType name, TokenPos namePos, PossibleError* possibleError) {
11271 #ifdef DEBUG
11272 // GCC 8.0.1 crashes if this is a one-liner.
11273 bool isName = handler_.isName(name);
11274 MOZ_ASSERT(isName);
11275 #endif
11277 // Return early if a pending destructuring error is already present.
11278 if (possibleError->hasPendingDestructuringError()) {
11279 return;
11282 if (pc_->sc()->strict()) {
11283 if (handler_.isArgumentsName(name)) {
11284 if (pc_->sc()->strict()) {
11285 possibleError->setPendingDestructuringErrorAt(
11286 namePos, JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
11287 } else {
11288 possibleError->setPendingDestructuringWarningAt(
11289 namePos, JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
11291 return;
11294 if (handler_.isEvalName(name)) {
11295 if (pc_->sc()->strict()) {
11296 possibleError->setPendingDestructuringErrorAt(
11297 namePos, JSMSG_BAD_STRICT_ASSIGN_EVAL);
11298 } else {
11299 possibleError->setPendingDestructuringWarningAt(
11300 namePos, JSMSG_BAD_STRICT_ASSIGN_EVAL);
11302 return;
11307 template <class ParseHandler, typename Unit>
11308 bool GeneralParser<ParseHandler, Unit>::checkDestructuringAssignmentElement(
11309 Node expr, TokenPos exprPos, PossibleError* exprPossibleError,
11310 PossibleError* possibleError) {
11311 // ES2018 draft rev 0719f44aab93215ed9a626b2f45bd34f36916834
11312 // 12.15.5 Destructuring Assignment
11314 // AssignmentElement[Yield, Await]:
11315 // DestructuringAssignmentTarget[?Yield, ?Await]
11316 // DestructuringAssignmentTarget[?Yield, ?Await] Initializer[+In,
11317 // ?Yield,
11318 // ?Await]
11320 // If |expr| is an assignment element with an initializer expression, its
11321 // destructuring assignment target was already validated in assignExpr().
11322 // Otherwise we need to check that |expr| is a valid destructuring target.
11323 if (handler_.isUnparenthesizedAssignment(expr)) {
11324 // Report any pending expression error if we're definitely not in a
11325 // destructuring context.
11326 if (!possibleError) {
11327 return exprPossibleError->checkForExpressionError();
11330 exprPossibleError->transferErrorsTo(possibleError);
11331 return true;
11333 return checkDestructuringAssignmentTarget(expr, exprPos, exprPossibleError,
11334 possibleError);
11337 template <class ParseHandler, typename Unit>
11338 typename ParseHandler::ListNodeResult
11339 GeneralParser<ParseHandler, Unit>::arrayInitializer(
11340 YieldHandling yieldHandling, PossibleError* possibleError) {
11341 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
11343 uint32_t begin = pos().begin;
11344 ListNodeType literal;
11345 MOZ_TRY_VAR(literal, handler_.newArrayLiteral(begin));
11347 TokenKind tt;
11348 if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
11349 return errorResult();
11352 if (tt == TokenKind::RightBracket) {
11354 * Mark empty arrays as non-constant, since we cannot easily
11355 * determine their type.
11357 handler_.setListHasNonConstInitializer(literal);
11358 } else {
11359 anyChars.ungetToken();
11361 for (uint32_t index = 0;; index++) {
11362 if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
11363 error(JSMSG_ARRAY_INIT_TOO_BIG);
11364 return errorResult();
11367 TokenKind tt;
11368 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
11369 return errorResult();
11371 if (tt == TokenKind::RightBracket) {
11372 break;
11375 if (tt == TokenKind::Comma) {
11376 tokenStream.consumeKnownToken(TokenKind::Comma,
11377 TokenStream::SlashIsRegExp);
11378 if (!handler_.addElision(literal, pos())) {
11379 return errorResult();
11381 continue;
11384 if (tt == TokenKind::TripleDot) {
11385 tokenStream.consumeKnownToken(TokenKind::TripleDot,
11386 TokenStream::SlashIsRegExp);
11387 uint32_t begin = pos().begin;
11389 TokenPos innerPos;
11390 if (!tokenStream.peekTokenPos(&innerPos, TokenStream::SlashIsRegExp)) {
11391 return errorResult();
11394 PossibleError possibleErrorInner(*this);
11395 Node inner;
11396 MOZ_TRY_VAR(inner,
11397 assignExpr(InAllowed, yieldHandling, TripledotProhibited,
11398 &possibleErrorInner));
11399 if (!checkDestructuringAssignmentTarget(
11400 inner, innerPos, &possibleErrorInner, possibleError)) {
11401 return errorResult();
11404 if (!handler_.addSpreadElement(literal, begin, inner)) {
11405 return errorResult();
11407 } else {
11408 TokenPos elementPos;
11409 if (!tokenStream.peekTokenPos(&elementPos,
11410 TokenStream::SlashIsRegExp)) {
11411 return errorResult();
11414 PossibleError possibleErrorInner(*this);
11415 Node element;
11416 MOZ_TRY_VAR(element,
11417 assignExpr(InAllowed, yieldHandling, TripledotProhibited,
11418 &possibleErrorInner));
11419 if (!checkDestructuringAssignmentElement(
11420 element, elementPos, &possibleErrorInner, possibleError)) {
11421 return errorResult();
11423 handler_.addArrayElement(literal, element);
11426 bool matched;
11427 if (!tokenStream.matchToken(&matched, TokenKind::Comma,
11428 TokenStream::SlashIsRegExp)) {
11429 return errorResult();
11431 if (!matched) {
11432 break;
11435 if (tt == TokenKind::TripleDot && possibleError) {
11436 possibleError->setPendingDestructuringErrorAt(pos(),
11437 JSMSG_REST_WITH_COMMA);
11441 if (!mustMatchToken(
11442 TokenKind::RightBracket, [this, begin](TokenKind actual) {
11443 this->reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
11444 JSMSG_BRACKET_OPENED, begin);
11445 })) {
11446 return errorResult();
11450 handler_.setEndPosition(literal, pos().end);
11451 return literal;
11454 template <class ParseHandler, typename Unit>
11455 typename ParseHandler::NodeResult
11456 GeneralParser<ParseHandler, Unit>::propertyName(
11457 YieldHandling yieldHandling, PropertyNameContext propertyNameContext,
11458 const Maybe<DeclarationKind>& maybeDecl, ListNodeType propList,
11459 TaggedParserAtomIndex* propAtomOut) {
11460 // PropertyName[Yield, Await]:
11461 // LiteralPropertyName
11462 // ComputedPropertyName[?Yield, ?Await]
11464 // LiteralPropertyName:
11465 // IdentifierName
11466 // StringLiteral
11467 // NumericLiteral
11468 TokenKind ltok = anyChars.currentToken().type;
11470 *propAtomOut = TaggedParserAtomIndex::null();
11471 switch (ltok) {
11472 case TokenKind::Number: {
11473 auto numAtom = NumberToParserAtom(fc_, this->parserAtoms(),
11474 anyChars.currentToken().number());
11475 if (!numAtom) {
11476 return errorResult();
11478 *propAtomOut = numAtom;
11479 return newNumber(anyChars.currentToken());
11482 case TokenKind::BigInt: {
11483 Node biNode;
11484 MOZ_TRY_VAR(biNode, newBigInt());
11485 return handler_.newSyntheticComputedName(biNode, pos().begin, pos().end);
11487 case TokenKind::String: {
11488 auto str = anyChars.currentToken().atom();
11489 *propAtomOut = str;
11490 uint32_t index;
11491 if (this->parserAtoms().isIndex(str, &index)) {
11492 return handler_.newNumber(index, NoDecimal, pos());
11494 return stringLiteral();
11497 case TokenKind::LeftBracket:
11498 return computedPropertyName(yieldHandling, maybeDecl, propertyNameContext,
11499 propList);
11501 case TokenKind::PrivateName: {
11502 if (propertyNameContext != PropertyNameContext::PropertyNameInClass) {
11503 error(JSMSG_ILLEGAL_PRIVATE_FIELD);
11504 return errorResult();
11507 TaggedParserAtomIndex propName = anyChars.currentName();
11508 *propAtomOut = propName;
11509 return privateNameReference(propName);
11512 default: {
11513 if (!TokenKindIsPossibleIdentifierName(ltok)) {
11514 error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(ltok));
11515 return errorResult();
11518 TaggedParserAtomIndex name = anyChars.currentName();
11519 *propAtomOut = name;
11520 return handler_.newObjectLiteralPropertyName(name, pos());
11525 // True if `kind` can be the first token of a PropertyName.
11526 static bool TokenKindCanStartPropertyName(TokenKind tt) {
11527 return TokenKindIsPossibleIdentifierName(tt) || tt == TokenKind::String ||
11528 tt == TokenKind::Number || tt == TokenKind::LeftBracket ||
11529 tt == TokenKind::Mul || tt == TokenKind::BigInt ||
11530 tt == TokenKind::PrivateName;
11533 template <class ParseHandler, typename Unit>
11534 typename ParseHandler::NodeResult
11535 GeneralParser<ParseHandler, Unit>::propertyOrMethodName(
11536 YieldHandling yieldHandling, PropertyNameContext propertyNameContext,
11537 const Maybe<DeclarationKind>& maybeDecl, ListNodeType propList,
11538 PropertyType* propType, TaggedParserAtomIndex* propAtomOut) {
11539 // We're parsing an object literal, class, or destructuring pattern;
11540 // propertyNameContext tells which one. This method parses any of the
11541 // following, storing the corresponding PropertyType in `*propType` to tell
11542 // the caller what we parsed:
11544 // async [no LineTerminator here] PropertyName
11545 // ==> PropertyType::AsyncMethod
11546 // async [no LineTerminator here] * PropertyName
11547 // ==> PropertyType::AsyncGeneratorMethod
11548 // * PropertyName ==> PropertyType::GeneratorMethod
11549 // get PropertyName ==> PropertyType::Getter
11550 // set PropertyName ==> PropertyType::Setter
11551 // accessor PropertyName ==> PropertyType::FieldWithAccessor
11552 // PropertyName : ==> PropertyType::Normal
11553 // PropertyName ==> see below
11555 // In the last case, where there's not a `:` token to consume, we peek at
11556 // (but don't consume) the next token to decide how to set `*propType`.
11558 // `,` or `}` ==> PropertyType::Shorthand
11559 // `(` ==> PropertyType::Method
11560 // `=`, not in a class ==> PropertyType::CoverInitializedName
11561 // '=', in a class ==> PropertyType::Field
11562 // any token, in a class ==> PropertyType::Field (ASI)
11564 // The caller must check `*propType` and throw if whatever we parsed isn't
11565 // allowed here (for example, a getter in a destructuring pattern).
11567 // This method does *not* match `static` (allowed in classes) or `...`
11568 // (allowed in object literals and patterns). The caller must take care of
11569 // those before calling this method.
11571 TokenKind ltok;
11572 if (!tokenStream.getToken(&ltok, TokenStream::SlashIsInvalid)) {
11573 return errorResult();
11576 MOZ_ASSERT(ltok != TokenKind::RightCurly,
11577 "caller should have handled TokenKind::RightCurly");
11579 // Accept `async` and/or `*`, indicating an async or generator method;
11580 // or `get` or `set` or `accessor`, indicating an accessor.
11581 bool isGenerator = false;
11582 bool isAsync = false;
11583 bool isGetter = false;
11584 bool isSetter = false;
11585 #ifdef ENABLE_DECORATORS
11586 bool hasAccessor = false;
11587 #endif
11589 if (ltok == TokenKind::Async) {
11590 // `async` is also a PropertyName by itself (it's a conditional keyword),
11591 // so peek at the next token to see if we're really looking at a method.
11592 TokenKind tt = TokenKind::Eof;
11593 if (!tokenStream.peekTokenSameLine(&tt)) {
11594 return errorResult();
11596 if (TokenKindCanStartPropertyName(tt)) {
11597 isAsync = true;
11598 tokenStream.consumeKnownToken(tt);
11599 ltok = tt;
11603 if (ltok == TokenKind::Mul) {
11604 isGenerator = true;
11605 if (!tokenStream.getToken(&ltok)) {
11606 return errorResult();
11610 if (!isAsync && !isGenerator &&
11611 (ltok == TokenKind::Get || ltok == TokenKind::Set)) {
11612 // We have parsed |get| or |set|. Look for an accessor property
11613 // name next.
11614 TokenKind tt;
11615 if (!tokenStream.peekToken(&tt)) {
11616 return errorResult();
11618 if (TokenKindCanStartPropertyName(tt)) {
11619 tokenStream.consumeKnownToken(tt);
11620 isGetter = (ltok == TokenKind::Get);
11621 isSetter = (ltok == TokenKind::Set);
11625 #ifdef ENABLE_DECORATORS
11626 if (!isGenerator && !isAsync && propertyNameContext == PropertyNameInClass &&
11627 ltok == TokenKind::Accessor) {
11628 MOZ_ASSERT(!isGetter && !isSetter);
11629 TokenKind tt;
11630 if (!tokenStream.peekTokenSameLine(&tt)) {
11631 return errorResult();
11634 // The target rule is `accessor [no LineTerminator here]
11635 // ClassElementName[?Yield, ?Await] Initializer[+In, ?Yield, ?Await]opt`
11636 if (TokenKindCanStartPropertyName(tt)) {
11637 tokenStream.consumeKnownToken(tt);
11638 hasAccessor = true;
11641 #endif
11643 Node propName;
11644 MOZ_TRY_VAR(propName, propertyName(yieldHandling, propertyNameContext,
11645 maybeDecl, propList, propAtomOut));
11647 // Grab the next token following the property/method name.
11648 // (If this isn't a colon, we're going to either put it back or throw.)
11649 TokenKind tt;
11650 if (!tokenStream.getToken(&tt)) {
11651 return errorResult();
11654 if (tt == TokenKind::Colon) {
11655 if (isGenerator || isAsync || isGetter || isSetter
11656 #ifdef ENABLE_DECORATORS
11657 || hasAccessor
11658 #endif
11660 error(JSMSG_BAD_PROP_ID);
11661 return errorResult();
11663 *propType = PropertyType::Normal;
11664 return propName;
11667 if (propertyNameContext != PropertyNameInClass &&
11668 TokenKindIsPossibleIdentifierName(ltok) &&
11669 (tt == TokenKind::Comma || tt == TokenKind::RightCurly ||
11670 tt == TokenKind::Assign)) {
11671 #ifdef ENABLE_DECORATORS
11672 MOZ_ASSERT(!hasAccessor);
11673 #endif
11674 if (isGenerator || isAsync || isGetter || isSetter) {
11675 error(JSMSG_BAD_PROP_ID);
11676 return errorResult();
11679 anyChars.ungetToken();
11680 *propType = tt == TokenKind::Assign ? PropertyType::CoverInitializedName
11681 : PropertyType::Shorthand;
11682 return propName;
11685 if (tt == TokenKind::LeftParen) {
11686 anyChars.ungetToken();
11688 #ifdef ENABLE_RECORD_TUPLE
11689 if (propertyNameContext == PropertyNameInRecord) {
11690 // Record & Tuple proposal, section 7.1.1:
11691 // RecordPropertyDefinition doesn't cover methods
11692 error(JSMSG_BAD_PROP_ID);
11693 return errorResult();
11695 #endif
11697 #ifdef ENABLE_DECORATORS
11698 if (hasAccessor) {
11699 error(JSMSG_BAD_PROP_ID);
11700 return errorResult();
11702 #endif
11704 if (isGenerator && isAsync) {
11705 *propType = PropertyType::AsyncGeneratorMethod;
11706 } else if (isGenerator) {
11707 *propType = PropertyType::GeneratorMethod;
11708 } else if (isAsync) {
11709 *propType = PropertyType::AsyncMethod;
11710 } else if (isGetter) {
11711 *propType = PropertyType::Getter;
11712 } else if (isSetter) {
11713 *propType = PropertyType::Setter;
11714 } else {
11715 *propType = PropertyType::Method;
11717 return propName;
11720 if (propertyNameContext == PropertyNameInClass) {
11721 if (isGenerator || isAsync || isGetter || isSetter) {
11722 error(JSMSG_BAD_PROP_ID);
11723 return errorResult();
11725 anyChars.ungetToken();
11726 #ifdef ENABLE_DECORATORS
11727 if (!hasAccessor) {
11728 *propType = PropertyType::Field;
11729 } else {
11730 *propType = PropertyType::FieldWithAccessor;
11732 #else
11733 *propType = PropertyType::Field;
11734 #endif
11735 return propName;
11738 error(JSMSG_COLON_AFTER_ID);
11739 return errorResult();
11742 template <class ParseHandler, typename Unit>
11743 typename ParseHandler::UnaryNodeResult
11744 GeneralParser<ParseHandler, Unit>::computedPropertyName(
11745 YieldHandling yieldHandling, const Maybe<DeclarationKind>& maybeDecl,
11746 PropertyNameContext propertyNameContext, ListNodeType literal) {
11747 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
11749 uint32_t begin = pos().begin;
11751 if (maybeDecl) {
11752 if (*maybeDecl == DeclarationKind::FormalParameter) {
11753 pc_->functionBox()->hasParameterExprs = true;
11755 } else if (propertyNameContext ==
11756 PropertyNameContext::PropertyNameInLiteral) {
11757 handler_.setListHasNonConstInitializer(literal);
11760 Node assignNode;
11761 MOZ_TRY_VAR(assignNode,
11762 assignExpr(InAllowed, yieldHandling, TripledotProhibited));
11764 if (!mustMatchToken(TokenKind::RightBracket, JSMSG_COMP_PROP_UNTERM_EXPR)) {
11765 return errorResult();
11767 return handler_.newComputedName(assignNode, begin, pos().end);
11770 template <class ParseHandler, typename Unit>
11771 typename ParseHandler::ListNodeResult
11772 GeneralParser<ParseHandler, Unit>::objectLiteral(YieldHandling yieldHandling,
11773 PossibleError* possibleError) {
11774 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
11776 uint32_t openedPos = pos().begin;
11778 ListNodeType literal;
11779 MOZ_TRY_VAR(literal, handler_.newObjectLiteral(pos().begin));
11781 bool seenPrototypeMutation = false;
11782 bool seenCoverInitializedName = false;
11783 Maybe<DeclarationKind> declKind = Nothing();
11784 TaggedParserAtomIndex propAtom;
11785 for (;;) {
11786 TokenKind tt;
11787 if (!tokenStream.peekToken(&tt)) {
11788 return errorResult();
11790 if (tt == TokenKind::RightCurly) {
11791 break;
11794 if (tt == TokenKind::TripleDot) {
11795 tokenStream.consumeKnownToken(TokenKind::TripleDot);
11796 uint32_t begin = pos().begin;
11798 TokenPos innerPos;
11799 if (!tokenStream.peekTokenPos(&innerPos, TokenStream::SlashIsRegExp)) {
11800 return errorResult();
11803 PossibleError possibleErrorInner(*this);
11804 Node inner;
11805 MOZ_TRY_VAR(inner, assignExpr(InAllowed, yieldHandling,
11806 TripledotProhibited, &possibleErrorInner));
11807 if (!checkDestructuringAssignmentTarget(
11808 inner, innerPos, &possibleErrorInner, possibleError,
11809 TargetBehavior::ForbidAssignmentPattern)) {
11810 return errorResult();
11812 if (!handler_.addSpreadProperty(literal, begin, inner)) {
11813 return errorResult();
11815 } else {
11816 TokenPos namePos = anyChars.nextToken().pos;
11818 PropertyType propType;
11819 Node propName;
11820 MOZ_TRY_VAR(propName, propertyOrMethodName(
11821 yieldHandling, PropertyNameInLiteral, declKind,
11822 literal, &propType, &propAtom));
11824 if (propType == PropertyType::Normal) {
11825 TokenPos exprPos;
11826 if (!tokenStream.peekTokenPos(&exprPos, TokenStream::SlashIsRegExp)) {
11827 return errorResult();
11830 PossibleError possibleErrorInner(*this);
11831 Node propExpr;
11832 MOZ_TRY_VAR(propExpr,
11833 assignExpr(InAllowed, yieldHandling, TripledotProhibited,
11834 &possibleErrorInner));
11836 if (!checkDestructuringAssignmentElement(
11837 propExpr, exprPos, &possibleErrorInner, possibleError)) {
11838 return errorResult();
11841 if (propAtom == TaggedParserAtomIndex::WellKnown::proto_()) {
11842 if (seenPrototypeMutation) {
11843 // Directly report the error when we're definitely not
11844 // in a destructuring context.
11845 if (!possibleError) {
11846 errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY);
11847 return errorResult();
11850 // Otherwise delay error reporting until we've
11851 // determined whether or not we're destructuring.
11852 possibleError->setPendingExpressionErrorAt(
11853 namePos, JSMSG_DUPLICATE_PROTO_PROPERTY);
11855 seenPrototypeMutation = true;
11857 // This occurs *only* if we observe PropertyType::Normal!
11858 // Only |__proto__: v| mutates [[Prototype]]. Getters,
11859 // setters, method/generator definitions, computed
11860 // property name versions of all of these, and shorthands
11861 // do not.
11862 if (!handler_.addPrototypeMutation(literal, namePos.begin,
11863 propExpr)) {
11864 return errorResult();
11866 } else {
11867 BinaryNodeType propDef;
11868 MOZ_TRY_VAR(propDef,
11869 handler_.newPropertyDefinition(propName, propExpr));
11871 handler_.addPropertyDefinition(literal, propDef);
11873 } else if (propType == PropertyType::Shorthand) {
11875 * Support, e.g., |({x, y} = o)| as destructuring shorthand
11876 * for |({x: x, y: y} = o)|, and |var o = {x, y}| as
11877 * initializer shorthand for |var o = {x: x, y: y}|.
11879 TaggedParserAtomIndex name = identifierReference(yieldHandling);
11880 if (!name) {
11881 return errorResult();
11884 NameNodeType nameExpr;
11885 MOZ_TRY_VAR(nameExpr, identifierReference(name));
11887 if (possibleError) {
11888 checkDestructuringAssignmentName(nameExpr, namePos, possibleError);
11891 if (!handler_.addShorthand(literal, handler_.asNameNode(propName),
11892 nameExpr)) {
11893 return errorResult();
11895 } else if (propType == PropertyType::CoverInitializedName) {
11897 * Support, e.g., |({x=1, y=2} = o)| as destructuring
11898 * shorthand with default values, as per ES6 12.14.5
11900 TaggedParserAtomIndex name = identifierReference(yieldHandling);
11901 if (!name) {
11902 return errorResult();
11905 Node lhs;
11906 MOZ_TRY_VAR(lhs, identifierReference(name));
11908 tokenStream.consumeKnownToken(TokenKind::Assign);
11910 if (!seenCoverInitializedName) {
11911 // "shorthand default" or "CoverInitializedName" syntax is
11912 // only valid in the case of destructuring.
11913 seenCoverInitializedName = true;
11915 if (!possibleError) {
11916 // Destructuring defaults are definitely not allowed
11917 // in this object literal, because of something the
11918 // caller knows about the preceding code. For example,
11919 // maybe the preceding token is an operator:
11920 // |x + {y=z}|.
11921 error(JSMSG_COLON_AFTER_ID);
11922 return errorResult();
11925 // Here we set a pending error so that later in the parse,
11926 // once we've determined whether or not we're
11927 // destructuring, the error can be reported or ignored
11928 // appropriately.
11929 possibleError->setPendingExpressionErrorAt(pos(),
11930 JSMSG_COLON_AFTER_ID);
11933 if (const char* chars = nameIsArgumentsOrEval(lhs)) {
11934 // |chars| is "arguments" or "eval" here.
11935 if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN,
11936 chars)) {
11937 return errorResult();
11941 Node rhs;
11942 MOZ_TRY_VAR(rhs,
11943 assignExpr(InAllowed, yieldHandling, TripledotProhibited));
11945 BinaryNodeType propExpr;
11946 MOZ_TRY_VAR(propExpr, handler_.newAssignment(ParseNodeKind::AssignExpr,
11947 lhs, rhs));
11949 if (!handler_.addPropertyDefinition(literal, propName, propExpr)) {
11950 return errorResult();
11952 } else {
11953 TaggedParserAtomIndex funName;
11954 bool hasStaticName =
11955 !anyChars.isCurrentTokenType(TokenKind::RightBracket) && propAtom;
11956 if (hasStaticName) {
11957 funName = propAtom;
11959 if (propType == PropertyType::Getter ||
11960 propType == PropertyType::Setter) {
11961 funName = prefixAccessorName(propType, propAtom);
11962 if (!funName) {
11963 return errorResult();
11968 FunctionNodeType funNode;
11969 MOZ_TRY_VAR(funNode,
11970 methodDefinition(namePos.begin, propType, funName));
11972 AccessorType atype = ToAccessorType(propType);
11973 if (!handler_.addObjectMethodDefinition(literal, propName, funNode,
11974 atype)) {
11975 return errorResult();
11978 if (possibleError) {
11979 possibleError->setPendingDestructuringErrorAt(
11980 namePos, JSMSG_BAD_DESTRUCT_TARGET);
11985 bool matched;
11986 if (!tokenStream.matchToken(&matched, TokenKind::Comma,
11987 TokenStream::SlashIsInvalid)) {
11988 return errorResult();
11990 if (!matched) {
11991 break;
11993 if (tt == TokenKind::TripleDot && possibleError) {
11994 possibleError->setPendingDestructuringErrorAt(pos(),
11995 JSMSG_REST_WITH_COMMA);
11999 if (!mustMatchToken(
12000 TokenKind::RightCurly, [this, openedPos](TokenKind actual) {
12001 this->reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
12002 JSMSG_CURLY_OPENED, openedPos);
12003 })) {
12004 return errorResult();
12007 handler_.setEndPosition(literal, pos().end);
12008 return literal;
12011 #ifdef ENABLE_RECORD_TUPLE
12012 template <class ParseHandler, typename Unit>
12013 typename ParseHandler::ListNodeResult
12014 GeneralParser<ParseHandler, Unit>::recordLiteral(YieldHandling yieldHandling) {
12015 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::HashCurly));
12017 uint32_t openedPos = pos().begin;
12019 ListNodeType literal;
12020 MOZ_TRY_VAR(literal, handler_.newRecordLiteral(pos().begin));
12022 TaggedParserAtomIndex propAtom;
12023 for (;;) {
12024 TokenKind tt;
12025 if (!tokenStream.peekToken(&tt)) {
12026 return errorResult();
12028 if (tt == TokenKind::RightCurly) {
12029 break;
12032 if (tt == TokenKind::TripleDot) {
12033 tokenStream.consumeKnownToken(TokenKind::TripleDot);
12034 uint32_t begin = pos().begin;
12036 TokenPos innerPos;
12037 if (!tokenStream.peekTokenPos(&innerPos, TokenStream::SlashIsRegExp)) {
12038 return errorResult();
12041 Node inner;
12042 MOZ_TRY_VAR(inner,
12043 assignExpr(InAllowed, yieldHandling, TripledotProhibited));
12045 if (!handler_.addSpreadProperty(literal, begin, inner)) {
12046 return errorResult();
12048 } else {
12049 TokenPos namePos = anyChars.nextToken().pos;
12051 PropertyType propType;
12052 Node propName;
12053 MOZ_TRY_VAR(propName,
12054 propertyOrMethodName(yieldHandling, PropertyNameInRecord,
12055 /* maybeDecl */ Nothing(), literal,
12056 &propType, &propAtom));
12058 if (propType == PropertyType::Normal) {
12059 TokenPos exprPos;
12060 if (!tokenStream.peekTokenPos(&exprPos, TokenStream::SlashIsRegExp)) {
12061 return errorResult();
12064 Node propExpr;
12065 MOZ_TRY_VAR(propExpr,
12066 assignExpr(InAllowed, yieldHandling, TripledotProhibited));
12068 if (propAtom == TaggedParserAtomIndex::WellKnown::proto_()) {
12069 errorAt(namePos.begin, JSMSG_RECORD_NO_PROTO);
12070 return errorResult();
12073 BinaryNodeType propDef;
12074 MOZ_TRY_VAR(propDef,
12075 handler_.newPropertyDefinition(propName, propExpr));
12077 handler_.addPropertyDefinition(literal, propDef);
12078 } else if (propType == PropertyType::Shorthand) {
12080 * Support |var o = #{x, y}| as initializer shorthand for
12081 * |var o = #{x: x, y: y}|.
12083 TaggedParserAtomIndex name = identifierReference(yieldHandling);
12084 if (!name) {
12085 return errorResult();
12088 NameNodeType nameExpr;
12089 MOZ_TRY_VAR(nameExpr, identifierReference(name));
12091 if (!handler_.addShorthand(literal, handler_.asNameNode(propName),
12092 nameExpr)) {
12093 return errorResult();
12095 } else {
12096 error(JSMSG_BAD_PROP_ID);
12097 return errorResult();
12101 bool matched;
12102 if (!tokenStream.matchToken(&matched, TokenKind::Comma,
12103 TokenStream::SlashIsInvalid)) {
12104 return errorResult();
12106 if (!matched) {
12107 break;
12111 if (!mustMatchToken(
12112 TokenKind::RightCurly, [this, openedPos](TokenKind actual) {
12113 this->reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
12114 JSMSG_CURLY_OPENED, openedPos);
12115 })) {
12116 return errorResult();
12119 handler_.setEndPosition(literal, pos().end);
12120 return literal;
12123 template <class ParseHandler, typename Unit>
12124 typename ParseHandler::ListNodeResult
12125 GeneralParser<ParseHandler, Unit>::tupleLiteral(YieldHandling yieldHandling) {
12126 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::HashBracket));
12128 uint32_t begin = pos().begin;
12129 ListNodeType literal;
12130 MOZ_TRY_VAR(literal, handler_.newTupleLiteral(begin));
12132 for (uint32_t index = 0;; index++) {
12133 if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
12134 error(JSMSG_ARRAY_INIT_TOO_BIG);
12135 return errorResult();
12138 TokenKind tt;
12139 if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
12140 return errorResult();
12142 if (tt == TokenKind::RightBracket) {
12143 break;
12146 if (tt == TokenKind::TripleDot) {
12147 tokenStream.consumeKnownToken(TokenKind::TripleDot,
12148 TokenStream::SlashIsRegExp);
12149 uint32_t begin = pos().begin;
12151 TokenPos innerPos;
12152 if (!tokenStream.peekTokenPos(&innerPos, TokenStream::SlashIsRegExp)) {
12153 return errorResult();
12156 Node inner;
12157 MOZ_TRY_VAR(inner,
12158 assignExpr(InAllowed, yieldHandling, TripledotProhibited));
12160 if (!handler_.addSpreadElement(literal, begin, inner)) {
12161 return errorResult();
12163 } else {
12164 TokenPos elementPos;
12165 if (!tokenStream.peekTokenPos(&elementPos, TokenStream::SlashIsRegExp)) {
12166 return errorResult();
12169 Node element;
12170 MOZ_TRY_VAR(element,
12171 assignExpr(InAllowed, yieldHandling, TripledotProhibited));
12172 handler_.addArrayElement(literal, element);
12175 bool matched;
12176 if (!tokenStream.matchToken(&matched, TokenKind::Comma,
12177 TokenStream::SlashIsRegExp)) {
12178 return errorResult();
12180 if (!matched) {
12181 break;
12185 if (!mustMatchToken(TokenKind::RightBracket, [this, begin](TokenKind actual) {
12186 this->reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
12187 JSMSG_BRACKET_OPENED, begin);
12188 })) {
12189 return errorResult();
12192 handler_.setEndPosition(literal, pos().end);
12193 return literal;
12195 #endif
12197 template <class ParseHandler, typename Unit>
12198 typename ParseHandler::FunctionNodeResult
12199 GeneralParser<ParseHandler, Unit>::methodDefinition(
12200 uint32_t toStringStart, PropertyType propType,
12201 TaggedParserAtomIndex funName) {
12202 FunctionSyntaxKind syntaxKind;
12203 switch (propType) {
12204 case PropertyType::Getter:
12205 syntaxKind = FunctionSyntaxKind::Getter;
12206 break;
12208 case PropertyType::Setter:
12209 syntaxKind = FunctionSyntaxKind::Setter;
12210 break;
12212 case PropertyType::Method:
12213 case PropertyType::GeneratorMethod:
12214 case PropertyType::AsyncMethod:
12215 case PropertyType::AsyncGeneratorMethod:
12216 syntaxKind = FunctionSyntaxKind::Method;
12217 break;
12219 case PropertyType::Constructor:
12220 syntaxKind = FunctionSyntaxKind::ClassConstructor;
12221 break;
12223 case PropertyType::DerivedConstructor:
12224 syntaxKind = FunctionSyntaxKind::DerivedClassConstructor;
12225 break;
12227 default:
12228 MOZ_CRASH("unexpected property type");
12231 GeneratorKind generatorKind = (propType == PropertyType::GeneratorMethod ||
12232 propType == PropertyType::AsyncGeneratorMethod)
12233 ? GeneratorKind::Generator
12234 : GeneratorKind::NotGenerator;
12236 FunctionAsyncKind asyncKind = (propType == PropertyType::AsyncMethod ||
12237 propType == PropertyType::AsyncGeneratorMethod)
12238 ? FunctionAsyncKind::AsyncFunction
12239 : FunctionAsyncKind::SyncFunction;
12241 YieldHandling yieldHandling = GetYieldHandling(generatorKind);
12243 FunctionNodeType funNode;
12244 MOZ_TRY_VAR(funNode, handler_.newFunction(syntaxKind, pos()));
12246 return functionDefinition(funNode, toStringStart, InAllowed, yieldHandling,
12247 funName, syntaxKind, generatorKind, asyncKind);
12250 template <class ParseHandler, typename Unit>
12251 bool GeneralParser<ParseHandler, Unit>::tryNewTarget(
12252 NewTargetNodeType* newTarget) {
12253 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::New));
12255 *newTarget = null();
12257 NullaryNodeType newHolder;
12258 MOZ_TRY_VAR_OR_RETURN(newHolder, handler_.newPosHolder(pos()), false);
12260 uint32_t begin = pos().begin;
12262 // |new| expects to look for an operand, so we will honor that.
12263 TokenKind next;
12264 if (!tokenStream.getToken(&next, TokenStream::SlashIsRegExp)) {
12265 return false;
12268 // Don't unget the token, since lookahead cannot handle someone calling
12269 // getToken() with a different modifier. Callers should inspect
12270 // currentToken().
12271 if (next != TokenKind::Dot) {
12272 return true;
12275 if (!tokenStream.getToken(&next)) {
12276 return false;
12278 if (next != TokenKind::Target) {
12279 error(JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next));
12280 return false;
12283 if (!pc_->sc()->allowNewTarget()) {
12284 errorAt(begin, JSMSG_BAD_NEWTARGET);
12285 return false;
12288 NullaryNodeType targetHolder;
12289 MOZ_TRY_VAR_OR_RETURN(targetHolder, handler_.newPosHolder(pos()), false);
12291 NameNodeType newTargetName;
12292 MOZ_TRY_VAR_OR_RETURN(newTargetName, newNewTargetName(), false);
12294 MOZ_TRY_VAR_OR_RETURN(
12295 *newTarget, handler_.newNewTarget(newHolder, targetHolder, newTargetName),
12296 false);
12298 return true;
12301 template <class ParseHandler, typename Unit>
12302 typename ParseHandler::BinaryNodeResult
12303 GeneralParser<ParseHandler, Unit>::importExpr(YieldHandling yieldHandling,
12304 bool allowCallSyntax) {
12305 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
12307 NullaryNodeType importHolder;
12308 MOZ_TRY_VAR(importHolder, handler_.newPosHolder(pos()));
12310 TokenKind next;
12311 if (!tokenStream.getToken(&next)) {
12312 return errorResult();
12315 if (next == TokenKind::Dot) {
12316 if (!tokenStream.getToken(&next)) {
12317 return errorResult();
12319 if (next != TokenKind::Meta) {
12320 error(JSMSG_UNEXPECTED_TOKEN, "meta", TokenKindToDesc(next));
12321 return errorResult();
12324 if (parseGoal() != ParseGoal::Module) {
12325 errorAt(pos().begin, JSMSG_IMPORT_META_OUTSIDE_MODULE);
12326 return errorResult();
12329 NullaryNodeType metaHolder;
12330 MOZ_TRY_VAR(metaHolder, handler_.newPosHolder(pos()));
12332 return handler_.newImportMeta(importHolder, metaHolder);
12335 if (next == TokenKind::LeftParen && allowCallSyntax) {
12336 Node arg;
12337 MOZ_TRY_VAR(arg, assignExpr(InAllowed, yieldHandling, TripledotProhibited));
12339 if (!tokenStream.peekToken(&next, TokenStream::SlashIsRegExp)) {
12340 return errorResult();
12343 Node optionalArg;
12344 if (options().importAssertions()) {
12345 if (next == TokenKind::Comma) {
12346 tokenStream.consumeKnownToken(TokenKind::Comma,
12347 TokenStream::SlashIsRegExp);
12349 if (!tokenStream.peekToken(&next, TokenStream::SlashIsRegExp)) {
12350 return errorResult();
12353 if (next != TokenKind::RightParen) {
12354 MOZ_TRY_VAR(optionalArg, assignExpr(InAllowed, yieldHandling,
12355 TripledotProhibited));
12357 if (!tokenStream.peekToken(&next, TokenStream::SlashIsRegExp)) {
12358 return errorResult();
12361 if (next == TokenKind::Comma) {
12362 tokenStream.consumeKnownToken(TokenKind::Comma,
12363 TokenStream::SlashIsRegExp);
12365 } else {
12366 MOZ_TRY_VAR(optionalArg,
12367 handler_.newPosHolder(TokenPos(pos().end, pos().end)));
12369 } else {
12370 MOZ_TRY_VAR(optionalArg,
12371 handler_.newPosHolder(TokenPos(pos().end, pos().end)));
12373 } else {
12374 MOZ_TRY_VAR(optionalArg,
12375 handler_.newPosHolder(TokenPos(pos().end, pos().end)));
12378 if (!mustMatchToken(TokenKind::RightParen, JSMSG_PAREN_AFTER_ARGS)) {
12379 return errorResult();
12382 Node spec;
12383 MOZ_TRY_VAR(spec, handler_.newCallImportSpec(arg, optionalArg));
12385 return handler_.newCallImport(importHolder, spec);
12388 error(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, TokenKindToDesc(next));
12389 return errorResult();
12392 template <class ParseHandler, typename Unit>
12393 typename ParseHandler::NodeResult
12394 GeneralParser<ParseHandler, Unit>::primaryExpr(
12395 YieldHandling yieldHandling, TripledotHandling tripledotHandling,
12396 TokenKind tt, PossibleError* possibleError, InvokedPrediction invoked) {
12397 MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
12398 AutoCheckRecursionLimit recursion(this->fc_);
12399 if (!recursion.check(this->fc_)) {
12400 return errorResult();
12403 switch (tt) {
12404 case TokenKind::Function:
12405 return functionExpr(pos().begin, invoked,
12406 FunctionAsyncKind::SyncFunction);
12408 case TokenKind::Class:
12409 return classDefinition(yieldHandling, ClassExpression, NameRequired);
12411 case TokenKind::LeftBracket:
12412 return arrayInitializer(yieldHandling, possibleError);
12414 case TokenKind::LeftCurly:
12415 return objectLiteral(yieldHandling, possibleError);
12417 #ifdef ENABLE_RECORD_TUPLE
12418 case TokenKind::HashCurly:
12419 return recordLiteral(yieldHandling);
12421 case TokenKind::HashBracket:
12422 return tupleLiteral(yieldHandling);
12423 #endif
12425 #ifdef ENABLE_DECORATORS
12426 case TokenKind::At:
12427 return classDefinition(yieldHandling, ClassExpression, NameRequired);
12428 #endif
12430 case TokenKind::LeftParen: {
12431 TokenKind next;
12432 if (!tokenStream.peekToken(&next, TokenStream::SlashIsRegExp)) {
12433 return errorResult();
12436 if (next == TokenKind::RightParen) {
12437 // Not valid expression syntax, but this is valid in an arrow function
12438 // with no params: `() => body`.
12439 tokenStream.consumeKnownToken(TokenKind::RightParen,
12440 TokenStream::SlashIsRegExp);
12442 if (!tokenStream.peekToken(&next)) {
12443 return errorResult();
12445 if (next != TokenKind::Arrow) {
12446 error(JSMSG_UNEXPECTED_TOKEN, "expression",
12447 TokenKindToDesc(TokenKind::RightParen));
12448 return errorResult();
12451 // Now just return something that will allow parsing to continue.
12452 // It doesn't matter what; when we reach the =>, we will rewind and
12453 // reparse the whole arrow function. See Parser::assignExpr.
12454 return handler_.newNullLiteral(pos());
12457 // Pass |possibleError| to support destructuring in arrow parameters.
12458 Node expr;
12459 MOZ_TRY_VAR(expr, exprInParens(InAllowed, yieldHandling, TripledotAllowed,
12460 possibleError));
12461 if (!mustMatchToken(TokenKind::RightParen, JSMSG_PAREN_IN_PAREN)) {
12462 return errorResult();
12464 return handler_.parenthesize(expr);
12467 case TokenKind::TemplateHead:
12468 return templateLiteral(yieldHandling);
12470 case TokenKind::NoSubsTemplate:
12471 return noSubstitutionUntaggedTemplate();
12473 case TokenKind::String:
12474 return stringLiteral();
12476 default: {
12477 if (!TokenKindIsPossibleIdentifier(tt)) {
12478 error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
12479 return errorResult();
12482 if (tt == TokenKind::Async) {
12483 TokenKind nextSameLine = TokenKind::Eof;
12484 if (!tokenStream.peekTokenSameLine(&nextSameLine)) {
12485 return errorResult();
12488 if (nextSameLine == TokenKind::Function) {
12489 uint32_t toStringStart = pos().begin;
12490 tokenStream.consumeKnownToken(TokenKind::Function);
12491 return functionExpr(toStringStart, PredictUninvoked,
12492 FunctionAsyncKind::AsyncFunction);
12496 TaggedParserAtomIndex name = identifierReference(yieldHandling);
12497 if (!name) {
12498 return errorResult();
12501 return identifierReference(name);
12504 case TokenKind::RegExp:
12505 return newRegExp();
12507 case TokenKind::Number:
12508 return newNumber(anyChars.currentToken());
12510 case TokenKind::BigInt:
12511 return newBigInt();
12513 case TokenKind::True:
12514 return handler_.newBooleanLiteral(true, pos());
12515 case TokenKind::False:
12516 return handler_.newBooleanLiteral(false, pos());
12517 case TokenKind::This: {
12518 NameNodeType thisName = null();
12519 if (pc_->sc()->hasFunctionThisBinding()) {
12520 MOZ_TRY_VAR(thisName, newThisName());
12522 return handler_.newThisLiteral(pos(), thisName);
12524 case TokenKind::Null:
12525 return handler_.newNullLiteral(pos());
12527 case TokenKind::TripleDot: {
12528 // This isn't valid expression syntax, but it's valid in an arrow
12529 // function as a trailing rest param: `(a, b, ...rest) => body`. Check
12530 // if it's directly under
12531 // CoverParenthesizedExpressionAndArrowParameterList, and check for a
12532 // name, closing parenthesis, and arrow, and allow it only if all are
12533 // present.
12534 if (tripledotHandling != TripledotAllowed) {
12535 error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
12536 return errorResult();
12539 TokenKind next;
12540 if (!tokenStream.getToken(&next)) {
12541 return errorResult();
12544 if (next == TokenKind::LeftBracket || next == TokenKind::LeftCurly) {
12545 // Validate, but don't store the pattern right now. The whole arrow
12546 // function is reparsed in functionFormalParametersAndBody().
12547 MOZ_TRY(destructuringDeclaration(DeclarationKind::CoverArrowParameter,
12548 yieldHandling, next));
12549 } else {
12550 // This doesn't check that the provided name is allowed, e.g. if
12551 // the enclosing code is strict mode code, any of "let", "yield",
12552 // or "arguments" should be prohibited. Argument-parsing code
12553 // handles that.
12554 if (!TokenKindIsPossibleIdentifier(next)) {
12555 error(JSMSG_UNEXPECTED_TOKEN, "rest argument name",
12556 TokenKindToDesc(next));
12557 return errorResult();
12561 if (!tokenStream.getToken(&next)) {
12562 return errorResult();
12564 if (next != TokenKind::RightParen) {
12565 error(JSMSG_UNEXPECTED_TOKEN, "closing parenthesis",
12566 TokenKindToDesc(next));
12567 return errorResult();
12570 if (!tokenStream.peekToken(&next)) {
12571 return errorResult();
12573 if (next != TokenKind::Arrow) {
12574 // Advance the scanner for proper error location reporting.
12575 tokenStream.consumeKnownToken(next);
12576 error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list",
12577 TokenKindToDesc(next));
12578 return errorResult();
12581 anyChars.ungetToken(); // put back right paren
12583 // Return an arbitrary expression node. See case TokenKind::RightParen
12584 // above.
12585 return handler_.newNullLiteral(pos());
12590 template <class ParseHandler, typename Unit>
12591 typename ParseHandler::NodeResult
12592 GeneralParser<ParseHandler, Unit>::exprInParens(
12593 InHandling inHandling, YieldHandling yieldHandling,
12594 TripledotHandling tripledotHandling,
12595 PossibleError* possibleError /* = nullptr */) {
12596 MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftParen));
12597 return expr(inHandling, yieldHandling, tripledotHandling, possibleError,
12598 PredictInvoked);
12601 template class PerHandlerParser<FullParseHandler>;
12602 template class PerHandlerParser<SyntaxParseHandler>;
12603 template class GeneralParser<FullParseHandler, Utf8Unit>;
12604 template class GeneralParser<SyntaxParseHandler, Utf8Unit>;
12605 template class GeneralParser<FullParseHandler, char16_t>;
12606 template class GeneralParser<SyntaxParseHandler, char16_t>;
12607 template class Parser<FullParseHandler, Utf8Unit>;
12608 template class Parser<SyntaxParseHandler, Utf8Unit>;
12609 template class Parser<FullParseHandler, char16_t>;
12610 template class Parser<SyntaxParseHandler, char16_t>;
12612 } // namespace js::frontend