From e547de64c80b98d661999c0788c09210d9d4a37e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 12:47:28 +0100 Subject: Stage 1-1: Implement Function.prototype.toString revision proposal. Tag #960 --- js/src/frontend/BytecodeCompiler.cpp | 12 +-- js/src/frontend/BytecodeCompiler.h | 2 + js/src/frontend/BytecodeEmitter.cpp | 3 +- js/src/frontend/Parser.cpp | 167 +++++++++++++++++++++++------------ js/src/frontend/Parser.h | 28 +++--- js/src/frontend/SharedContext.h | 5 +- js/src/frontend/TokenStream.cpp | 6 ++ js/src/frontend/TokenStream.h | 7 ++ js/src/jsapi.cpp | 46 +++++++--- js/src/jsfun.cpp | 90 ++++++++++++------- js/src/jsscript.cpp | 47 +++++++--- js/src/jsscript.h | 49 +++++++--- js/src/wasm/AsmJS.cpp | 22 ++--- 13 files changed, 330 insertions(+), 154 deletions(-) diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 76afe80b1..b5be5f5ac 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -77,7 +77,7 @@ class MOZ_STACK_CLASS BytecodeCompiler bool canLazilyParse(); bool createParser(); bool createSourceAndParser(Maybe parameterListEnd = Nothing()); - bool createScript(); + bool createScript(uint32_t preludeStart = 0); bool emplaceEmitter(Maybe& emitter, SharedContext* sharedContext); bool handleParseFailure(const Directives& newDirectives); bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment); @@ -242,10 +242,11 @@ BytecodeCompiler::createSourceAndParser(Maybe parameterListEnd /* = No } bool -BytecodeCompiler::createScript() +BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */) { script = JSScript::Create(cx, options, - sourceObject, /* sourceStart = */ 0, sourceBuffer.length()); + sourceObject, /* sourceStart = */ 0, sourceBuffer.length(), + preludeStart); return script != nullptr; } @@ -456,7 +457,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun, if (fn->pn_funbox->function()->isInterpreted()) { MOZ_ASSERT(fun == fn->pn_funbox->function()); - if (!createScript()) + if (!createScript(fn->pn_funbox->preludeStart)) return false; Maybe emitter; @@ -650,7 +651,8 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha MOZ_ASSERT(sourceObject); Rooted script(cx, JSScript::Create(cx, options, sourceObject, - lazy->begin(), lazy->end())); + lazy->begin(), lazy->end(), + lazy->preludeStart())); if (!script) return false; diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index 72e967639..0bc1ab2ab 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -109,6 +109,8 @@ IsIdentifier(JSLinearString* str); * As above, but taking chars + length. */ bool +IsIdentifier(const char* chars, size_t length); +bool IsIdentifier(const char16_t* chars, size_t length); /* True if str is a keyword. Defined in TokenStream.cpp. */ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 4eb7bf880..c5e62ae34 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -7834,7 +7834,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) Rooted sourceObject(cx, script->sourceObject()); Rooted script(cx, JSScript::Create(cx, options, sourceObject, - funbox->bufStart, funbox->bufEnd)); + funbox->bufStart, funbox->bufEnd, + funbox->preludeStart)); if (!script) return false; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 209265a58..1ba725a82 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -441,7 +441,8 @@ UsedNameTracker::rewind(RewindToken token) } FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, - JSFunction* fun, Directives directives, bool extraWarnings, + JSFunction* fun, uint32_t preludeStart, + Directives directives, bool extraWarnings, GeneratorKind generatorKind, FunctionAsyncKind asyncKind) : ObjectBox(fun, traceListHead), SharedContext(cx, Kind::ObjectBox, directives, extraWarnings), @@ -454,6 +455,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac bufEnd(0), startLine(1), startColumn(0), + preludeStart(preludeStart), length(0), generatorKindBits_(GeneratorKindAsBits(generatorKind)), asyncKindBits_(AsyncKindAsBits(asyncKind)), @@ -738,7 +740,8 @@ Parser::newObjectBox(JSObject* obj) template FunctionBox* -Parser::newFunctionBox(Node fn, JSFunction* fun, Directives inheritedDirectives, +Parser::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart, + Directives inheritedDirectives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB) { @@ -753,8 +756,9 @@ Parser::newFunctionBox(Node fn, JSFunction* fun, Directives inheri * function. */ FunctionBox* funbox = - alloc.new_(context, alloc, traceListHead, fun, inheritedDirectives, - options().extraWarningsOption, generatorKind, asyncKind); + alloc.new_(context, alloc, traceListHead, fun, preludeStart, + inheritedDirectives, options().extraWarningsOption, + generatorKind, asyncKind); if (!funbox) { ReportOutOfMemory(context); return nullptr; @@ -2214,6 +2218,7 @@ Parser::finishFunction() LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(), pc->innerFunctionsForLazy, versionNumber(), funbox->bufStart, funbox->bufEnd, + funbox->preludeStart, funbox->startLine, funbox->startColumn); if (!lazy) return false; @@ -2267,6 +2272,33 @@ Parser::standaloneFunction(HandleFunction fun, { MOZ_ASSERT(checkOptionsCalled); + // Skip prelude. + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + if (asyncKind == AsyncFunction) { + MOZ_ASSERT(tt == TOK_ASYNC); + if (!tokenStream.getToken(&tt)) + return null(); + } + MOZ_ASSERT(tt == TOK_FUNCTION); + + if (!tokenStream.getToken(&tt)) + return null(); + if (generatorKind == StarGenerator && asyncKind == SyncFunction) { + MOZ_ASSERT(tt == TOK_MUL); + if (!tokenStream.getToken(&tt)) + return null(); + } + + // Skip function name, if present. + if (tt == TOK_NAME || tt == TOK_YIELD) { + MOZ_ASSERT(tokenStream.currentName() == fun->explicitName()); + } else { + MOZ_ASSERT(fun->explicitName() == nullptr); + tokenStream.ungetToken(); + } + Node fn = handler.newFunctionDefinition(); if (!fn) return null(); @@ -2276,8 +2308,8 @@ Parser::standaloneFunction(HandleFunction fun, return null(); fn->pn_body = argsbody; - FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind, - asyncKind, /* tryAnnexB = */ false); + FunctionBox* funbox = newFunctionBox(fn, fun, /* preludeStart = */ 0, inheritedDirectives, + generatorKind, asyncKind, /* tryAnnexB = */ false); if (!funbox) return null(); funbox->initStandaloneFunction(enclosingScope); @@ -2295,7 +2327,6 @@ Parser::standaloneFunction(HandleFunction fun, return null(); } - TokenKind tt; if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { @@ -2991,8 +3022,8 @@ Parser::checkFunctionDefinition(HandleAtom funAtom, Node pn, Funct template <> bool -Parser::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKind kind, - bool tryAnnexB) +Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart, + FunctionSyntaxKind kind, bool tryAnnexB) { // When a lazily-parsed function is called, we only fully parse (and emit) // that function, not any of its nested children. The initial syntax-only @@ -3001,7 +3032,7 @@ Parser::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin RootedFunction fun(context, handler.nextLazyInnerFunction()); MOZ_ASSERT(!fun->isLegacyGenerator()); - FunctionBox* funbox = newFunctionBox(pn, fun, Directives(/* strict = */ false), + FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, Directives(/* strict = */ false), fun->generatorKind(), fun->asyncKind(), tryAnnexB); if (!funbox) return false; @@ -3031,8 +3062,8 @@ Parser::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin template <> bool -Parser::skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, - bool tryAnnexB) +Parser::skipLazyInnerFunction(Node pn, uint32_t preludeStart, + FunctionSyntaxKind kind, bool tryAnnexB) { MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing"); } @@ -3108,7 +3139,8 @@ Parser::templateLiteral(YieldHandling yieldHandling) template typename ParseHandler::Node -Parser::functionDefinition(InHandling inHandling, YieldHandling yieldHandling, +Parser::functionDefinition(uint32_t preludeStart, InHandling inHandling, + YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, InvokedPrediction invoked) @@ -3132,7 +3164,7 @@ Parser::functionDefinition(InHandling inHandling, YieldHandling yi // functions, which are also lazy. Instead, their free variables and // source extents are recorded and may be skipped. if (handler.canSkipLazyInnerFunctions()) { - if (!skipLazyInnerFunction(pn, kind, tryAnnexB)) + if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB)) return null(); return pn; } @@ -3165,8 +3197,9 @@ Parser::functionDefinition(InHandling inHandling, YieldHandling yi // reparse a function due to failed syntax parsing and encountering new // "use foo" directives. while (true) { - if (trySyntaxParseInnerFunction(pn, fun, inHandling, yieldHandling, kind, generatorKind, - asyncKind, tryAnnexB, directives, &newDirectives)) + if (trySyntaxParseInnerFunction(pn, fun, preludeStart, inHandling, yieldHandling, kind, + generatorKind, asyncKind, tryAnnexB, directives, + &newDirectives)) { break; } @@ -3193,6 +3226,7 @@ Parser::functionDefinition(InHandling inHandling, YieldHandling yi template <> bool Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, @@ -3226,14 +3260,15 @@ Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct // Make a FunctionBox before we enter the syntax parser, because |pn| // still expects a FunctionBox to be attached to it during BCE, and // the syntax parser cannot attach one to it. - FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, - asyncKind, tryAnnexB); + FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives, + generatorKind, asyncKind, tryAnnexB); if (!funbox) return false; funbox->initWithEnclosingParseContext(pc, kind); - if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, inHandling, - yieldHandling, kind, inheritedDirectives, newDirectives)) + if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, preludeStart, + inHandling, yieldHandling, kind, + inheritedDirectives, newDirectives)) { if (parser->hadAbortedSyntaxParse()) { // Try again with a full parse. UsedNameTracker needs to be @@ -3259,13 +3294,14 @@ Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct } while (false); // We failed to do a syntax parse above, so do the full parse. - return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind, - tryAnnexB, inheritedDirectives, newDirectives); + return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind, + generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives); } template <> bool Parser::trySyntaxParseInnerFunction(Node pn, HandleFunction fun, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, @@ -3276,13 +3312,14 @@ Parser::trySyntaxParseInnerFunction(Node pn, HandleFunction Directives* newDirectives) { // This is already a syntax parser, so just parse the inner function. - return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind, - tryAnnexB, inheritedDirectives, newDirectives); + return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind, + generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives); } template bool Parser::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, Directives inheritedDirectives, Directives* newDirectives) @@ -3306,6 +3343,7 @@ Parser::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* template bool Parser::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, @@ -3317,14 +3355,14 @@ Parser::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti // parser. In that case, outerpc is a ParseContext from the full parser // instead of the current top of the stack of the syntax parser. - FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, - asyncKind, tryAnnexB); + FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives, + generatorKind, asyncKind, tryAnnexB); if (!funbox) return false; funbox->initWithEnclosingParseContext(outerpc, kind); - return innerFunction(pn, outerpc, funbox, inHandling, yieldHandling, kind, inheritedDirectives, - newDirectives); + return innerFunction(pn, outerpc, funbox, preludeStart, inHandling, yieldHandling, kind, + inheritedDirectives, newDirectives); } template @@ -3359,8 +3397,8 @@ Parser::standaloneLazyFunction(HandleFunction fun, bool strict return null(); Directives directives(strict); - FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind, - /* tryAnnexB = */ false); + FunctionBox* funbox = newFunctionBox(pn, fun, /* preludeStart = */ 0, directives, + generatorKind, asyncKind, /* tryAnnexB = */ false); if (!funbox) return null(); funbox->initFromLazyFunction(); @@ -3529,8 +3567,8 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, template typename ParseHandler::Node -Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling, - FunctionAsyncKind asyncKind) +Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling, + DefaultHandling defaultHandling, FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -3579,8 +3617,8 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling } YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node fun = functionDefinition(InAllowed, newYieldHandling, name, Statement, generatorKind, - asyncKind, PredictUninvoked); + Node fun = functionDefinition(preludeStart, InAllowed, newYieldHandling, name, Statement, + generatorKind, asyncKind, PredictUninvoked); if (!fun) return null(); @@ -3597,7 +3635,8 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling template typename ParseHandler::Node -Parser::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind) +Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invoked, + FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -3628,8 +3667,8 @@ Parser::functionExpr(InvokedPrediction invoked, FunctionAsyncKind tokenStream.ungetToken(); } - return functionDefinition(InAllowed, yieldHandling, name, Expression, generatorKind, - asyncKind, invoked); + return functionDefinition(preludeStart, InAllowed, yieldHandling, name, Expression, + generatorKind, asyncKind, invoked); } /* @@ -5074,7 +5113,7 @@ Parser::exportDeclaration() } case TOK_FUNCTION: - kid = functionStmt(YieldIsKeyword, NameRequired); + kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired); if (!kid) return null(); @@ -5114,7 +5153,7 @@ Parser::exportDeclaration() ParseNode* nameNode = nullptr; switch (tt) { case TOK_FUNCTION: - kid = functionStmt(YieldIsKeyword, AllowDefaultName); + kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName); if (!kid) return null(); break; @@ -5131,7 +5170,7 @@ Parser::exportDeclaration() if (nextSameLine == TOK_FUNCTION) { tokenStream.consumeKnownToken(nextSameLine); - kid = functionStmt(YieldIsName, AllowDefaultName, AsyncFunction); + kid = functionStmt(pos().begin, YieldIsName, AllowDefaultName, AsyncFunction); if (!kid) return null(); break; @@ -5232,7 +5271,7 @@ Parser::consequentOrAlternative(YieldHandling yieldHandling) // will report the strict mode error. if (!pc->sc()->strict()) { tokenStream.consumeKnownToken(next, TokenStream::Operand); - return functionStmt(yieldHandling, NameRequired); + return functionStmt(pos().begin, yieldHandling, NameRequired); } } @@ -6182,7 +6221,7 @@ Parser::labeledItem(YieldHandling yieldHandling) return null(); } - return functionStmt(yieldHandling, NameRequired); + return functionStmt(pos().begin, yieldHandling, NameRequired); } tokenStream.ungetToken(); @@ -6649,6 +6688,10 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } + uint32_t nameOffset; + if (!tokenStream.peekOffset(&nameOffset)) + return null(); + PropertyType propType; Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom); if (!propName) @@ -6701,7 +6744,7 @@ Parser::classDefinition(YieldHandling yieldHandling, if (!tokenStream.isCurrentTokenType(TOK_RB)) funName = propAtom; } - Node fn = methodDefinition(propType, funName); + Node fn = methodDefinition(nameOffset, propType, funName); if (!fn) return null(); @@ -7094,8 +7137,9 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); if (nextSameLine == TOK_FUNCTION) { + uint32_t preludeStart = pos().begin; tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionStmt(yieldHandling, NameRequired, AsyncFunction); + return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction); } } @@ -7174,7 +7218,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // HoistableDeclaration[?Yield, ~Default] case TOK_FUNCTION: - return functionStmt(yieldHandling, NameRequired); + return functionStmt(pos().begin, yieldHandling, NameRequired); // ClassDeclaration[?Yield, ~Default] case TOK_CLASS: @@ -7677,8 +7721,10 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl tokenStream.seek(start); - if (!tokenStream.peekToken(&next, TokenStream::Operand)) + if (!tokenStream.getToken(&next, TokenStream::Operand)) return null(); + uint32_t preludeStart = pos().begin; + tokenStream.ungetToken(); GeneratorKind generatorKind = NotGenerator; FunctionAsyncKind asyncKind = SyncFunction; @@ -7702,7 +7748,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl } } - Node arrowFunc = functionDefinition(inHandling, yieldHandling, nullptr, + Node arrowFunc = functionDefinition(preludeStart, inHandling, yieldHandling, nullptr, Arrow, generatorKind, asyncKind); if (!arrowFunc) return null(); @@ -8054,8 +8100,8 @@ Parser::generatorComprehensionLambda(unsigned begin) // Create box for fun->object early to root it. Directives directives(/* strict = */ outerpc->sc()->strict()); - FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator, SyncFunction, - /* tryAnnexB = */ false); + FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* preludeStart = */ 0, directives, + StarGenerator, SyncFunction, /* tryAnnexB = */ false); if (!genFunbox) return null(); genFunbox->isGenexpLambda = true; @@ -8087,12 +8133,14 @@ Parser::generatorComprehensionLambda(unsigned begin) MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN); + uint32_t end = pos().end; handler.setBeginPosition(comp, begin); - handler.setEndPosition(comp, pos().end); + handler.setEndPosition(comp, end); + genFunbox->bufEnd = end; handler.addStatementToList(body, comp); - handler.setEndPosition(body, pos().end); + handler.setEndPosition(body, end); handler.setBeginPosition(genfn, begin); - handler.setEndPosition(genfn, pos().end); + handler.setEndPosition(genfn, end); Node generator = newDotGeneratorName(); if (!generator) @@ -9158,6 +9206,8 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; + TokenPos namePos = pos(); + tokenStream.ungetToken(); PropertyType propType; @@ -9309,7 +9359,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* } } - Node fn = methodDefinition(propType, funName); + Node fn = methodDefinition(namePos.begin, propType, funName); if (!fn) return null(); @@ -9336,13 +9386,15 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* template typename ParseHandler::Node -Parser::methodDefinition(PropertyType propType, HandleAtom funName) +Parser::methodDefinition(uint32_t preludeStart, PropertyType propType, + HandleAtom funName) { FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind); + return functionDefinition(preludeStart, InAllowed, yieldHandling, funName, kind, + generatorKind, asyncKind); } template @@ -9404,7 +9456,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling switch (tt) { case TOK_FUNCTION: - return functionExpr(invoked); + return functionExpr(pos().begin, invoked); case TOK_CLASS: return classDefinition(yieldHandling, ClassExpression, NameRequired); @@ -9471,8 +9523,9 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling return null(); if (nextSameLine == TOK_FUNCTION) { + uint32_t preludeStart = pos().begin; tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionExpr(PredictUninvoked, AsyncFunction); + return functionExpr(preludeStart, PredictUninvoked, AsyncFunction); } } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 12642fad8..090931f5b 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -954,7 +954,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * cx->tempLifoAlloc. */ ObjectBox* newObjectBox(JSObject* obj); - FunctionBox* newFunctionBox(Node fn, JSFunction* fun, Directives directives, + FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart, + Directives directives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB); @@ -1034,8 +1035,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // Parse an inner function given an enclosing ParseContext and a // FunctionBox for the inner function. - bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, InHandling inHandling, - YieldHandling yieldHandling, FunctionSyntaxKind kind, + bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart, + InHandling inHandling, YieldHandling yieldHandling, + FunctionSyntaxKind kind, Directives inheritedDirectives, Directives* newDirectives); // Parse a function's formal parameters and its body assuming its function @@ -1088,9 +1090,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * Some parsers have two versions: an always-inlined version (with an 'i' * suffix) and a never-inlined version (with an 'n' suffix). */ - Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling, + Node functionStmt(uint32_t preludeStart, + YieldHandling yieldHandling, DefaultHandling defaultHandling, FunctionAsyncKind asyncKind = SyncFunction); - Node functionExpr(InvokedPrediction invoked = PredictUninvoked, + Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked, FunctionAsyncKind asyncKind = SyncFunction); Node statementList(YieldHandling yieldHandling); @@ -1222,7 +1225,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool tryNewTarget(Node& newTarget); bool checkAndMarkSuperScope(); - Node methodDefinition(PropertyType propType, HandleAtom funName); + Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName); /* * Additional JS parsers. @@ -1230,7 +1233,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, Node funcpn); - Node functionDefinition(InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, + Node functionDefinition(uint32_t preludeStart, + InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, InvokedPrediction invoked = PredictUninvoked); @@ -1321,14 +1325,16 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, GeneratorKind generatorKind, bool* tryAnnexB); - bool skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, bool tryAnnexB); - bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, + bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, + bool tryAnnexB); + bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); - bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling, - YieldHandling yieldHandling, FunctionSyntaxKind kind, + bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart, + InHandling inHandling, YieldHandling yieldHandling, + FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index a6ac542f6..b20417d5d 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -450,6 +450,7 @@ class FunctionBox : public ObjectBox, public SharedContext uint32_t bufEnd; uint32_t startLine; uint32_t startColumn; + uint32_t preludeStart; uint16_t length; uint8_t generatorKindBits_; /* The GeneratorKind of this function. */ @@ -476,8 +477,8 @@ class FunctionBox : public ObjectBox, public SharedContext FunctionContextFlags funCxFlags; FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun, - Directives directives, bool extraWarnings, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind); + uint32_t preludeStart, Directives directives, bool extraWarnings, + GeneratorKind generatorKind, FunctionAsyncKind asyncKind); MutableHandle namedLambdaBindings() { MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms()); diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 179a7c244..b040d2998 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -171,6 +171,12 @@ frontend::IsIdentifier(JSLinearString* str) : ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length()); } +bool +frontend::IsIdentifier(const char* chars, size_t length) +{ + return ::IsIdentifier(chars, length); +} + bool frontend::IsIdentifier(const char16_t* chars, size_t length) { diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 5d6b4b795..77eea3d81 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -570,6 +570,13 @@ class MOZ_STACK_CLASS TokenStream return true; } + MOZ_MUST_USE bool peekOffset(uint32_t* offset, Modifier modifier = None) { + TokenPos pos; + if (!peekTokenPos(&pos, modifier)) + return false; + *offset = pos.begin; + return true; + } // This is like peekToken(), with one exception: if there is an EOL // between the end of the current token and the start of the next token, it // return true and store TOK_EOL in |*ttp|. In that case, no token with diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 37d023bd4..9ee29ffe4 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4250,7 +4250,7 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun) */ static bool CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, - const char* name, + HandleAtom name, bool isInvalidName, SourceBufferHolder& srcBuf, uint32_t parameterListEnd, HandleObject enclosingEnv, HandleScope enclosingScope, MutableHandleFunction fun) @@ -4261,13 +4261,8 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, assertSameCompartment(cx, enclosingEnv); RootedAtom funAtom(cx); - if (name) { - funAtom = Atomize(cx, name, strlen(name)); - if (!funAtom) - return false; - } - - fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom, + fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, + isInvalidName ? nullptr : name, /* proto = */ nullptr, gc::AllocKind::FUNCTION, TenuredObject, enclosingEnv)); @@ -4285,11 +4280,17 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, return false; } + // When function name is not a valid identifier, the generated function + // source in srcBuf doesn't have a function name. Set it here. + if (isInvalidName) + fun->setAtom(name); + return true; } static MOZ_MUST_USE bool -BuildFunctionString(unsigned nargs, const char* const* argnames, +BuildFunctionString(const char* name, size_t nameLen, + unsigned nargs, const char* const* argnames, const SourceBufferHolder& srcBuf, StringBuffer* out, uint32_t* parameterListEnd) { @@ -4298,6 +4299,12 @@ BuildFunctionString(unsigned nargs, const char* const* argnames, if (!out->ensureTwoByteChars()) return false; + if (!out->append("function ")) + return false; + if (name) { + if (!out->append(name, nameLen)) + return false; + } if (!out->append("(")) return false; for (unsigned i = 0; i < nargs; i++) { @@ -4334,15 +4341,32 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain, if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope)) return false; + size_t nameLen = 0; + bool isInvalidName = false; + RootedAtom nameAtom(cx); + if (name) { + nameLen = strlen(name); + nameAtom = Atomize(cx, name, nameLen); + if (!nameAtom) + return false; + + // If name is not valid identifier + if (!js::frontend::IsIdentifier(name, nameLen)) + isInvalidName = true; + } + uint32_t parameterListEnd; StringBuffer funStr(cx); - if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, ¶meterListEnd)) + if (!BuildFunctionString(isInvalidName ? nullptr : name, nameLen, nargs, argnames, srcBuf, + &funStr, ¶meterListEnd)) { return false; + } size_t newLen = funStr.length(); SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership); - return CompileFunction(cx, options, name, newSrcBuf, parameterListEnd, env, scope, fun); + return CompileFunction(cx, options, nameAtom, isInvalidName, newSrcBuf, parameterListEnd, env, + scope, fun); } JS_PUBLIC_API(bool) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index bcb0da80b..4412362c2 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -815,8 +815,10 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) RootedFunction functionProto(cx, &functionProto_->as()); - const char* rawSource = "() {\n}"; + const char* rawSource = "function () {\n}"; size_t sourceLen = strlen(rawSource); + size_t begin = 9; + MOZ_ASSERT(rawSource[begin] == '('); mozilla::UniquePtr source(InflateString(cx, rawSource, &sourceLen)); if (!source) return nullptr; @@ -838,8 +840,9 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) RootedScript script(cx, JSScript::Create(cx, options, sourceObject, - 0, - ss->length())); + begin, + ss->length(), + 0)); if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto)) return nullptr; @@ -1019,53 +1022,62 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) } } - if (fun->isAsync()) { - if (!out.append("async ")) - return nullptr; - } - - bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() || - fun->isGetter() || fun->isSetter(); + bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow(); bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin(); - // If we're not in pretty mode, put parentheses around lambda functions and methods. - if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) { + // If we're not in pretty mode, put parentheses around lambda functions + // so that eval returns lambda, not function statement. + if (haveSource && !prettyPrint && funIsNonArrowLambda) { if (!out.append("(")) return nullptr; } - if (!fun->isArrow()) { - bool ok; - if (fun->isStarGenerator() && !fun->isAsync()) - ok = out.append("function* "); - else - ok = out.append("function "); - if (!ok) - return nullptr; - } - if (fun->explicitName()) { - if (!out.append(fun->explicitName())) - return nullptr; - } if (haveSource && !script->scriptSource()->hasSourceData() && !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) { return nullptr; } + + auto AppendPrelude = [&out, &fun]() { + if (fun->isAsync()) { + if (!out.append("async ")) + return false; + } + + if (!fun->isArrow()) { + if (!out.append("function")) + return false; + + if (fun->isStarGenerator()) { + if (!out.append('*')) + return false; + } + } + + if (fun->explicitName()) { + if (!out.append(' ')) + return false; + if (!out.append(fun->explicitName())) + return false; + } + return true; + }; + if (haveSource) { - Rooted src(cx, script->sourceData(cx)); + Rooted src(cx, script->sourceDataWithPrelude(cx)); if (!src) return nullptr; if (!out.append(src)) return nullptr; - if (!prettyPrint && funIsMethodOrNonArrowLambda) { + if (!prettyPrint && funIsNonArrowLambda) { if (!out.append(")")) return nullptr; } } else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) { - if (!out.append("() {\n ") || + if (!AppendPrelude() || + !out.append("() {\n ") || !out.append("[sourceless code]") || !out.append("\n}")) { @@ -1076,13 +1088,15 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) bool derived = fun->infallibleIsDefaultClassConstructor(cx); if (derived && fun->isDerivedClassConstructor()) { - if (!out.append("(...args) {\n ") || + if (!AppendPrelude() || + !out.append("(...args) {\n ") || !out.append("super(...args);\n}")) { return nullptr; } } else { - if (!out.append("() {\n ")) + if (!AppendPrelude() || + !out.append("() {\n ")) return nullptr; if (!derived) { @@ -1669,7 +1683,18 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator StringBuffer sb(cx); - if (!sb.append('(')) + if (isAsync) { + if (!sb.append("async ")) + return false; + } + if (!sb.append("function")) + return false; + if (isStarGenerator && !isAsync) { + if (!sb.append('*')) + return false; + } + + if (!sb.append(" anonymous(")) return false; if (args.length() > 1) { @@ -1696,6 +1721,9 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator } } + if (!sb.append('\n')) + return false; + // Remember the position of ")". Maybe parameterListEnd = Some(uint32_t(sb.length())); MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')'); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 9f914943e..33ae56d6f 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -235,6 +235,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri { uint32_t begin = script->sourceStart(); uint32_t end = script->sourceEnd(); + uint32_t preludeStart = script->preludeStart(); uint32_t lineno = script->lineno(); uint32_t column = script->column(); @@ -242,6 +243,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri packedFields = lazy->packedFields(); MOZ_ASSERT(begin == lazy->begin()); MOZ_ASSERT(end == lazy->end()); + MOZ_ASSERT(preludeStart == lazy->preludeStart()); MOZ_ASSERT(lineno == lazy->lineno()); MOZ_ASSERT(column == lazy->column()); // We can assert we have no inner functions because we don't @@ -255,7 +257,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri if (mode == XDR_DECODE) { lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, script, - packedFields, begin, end, lineno, column)); + packedFields, begin, end, preludeStart, lineno, column)); // As opposed to XDRLazyScript, we need to restore the runtime bits // of the script, as we are trying to match the fact this function @@ -517,7 +519,7 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip sourceObject = &enclosingScript->sourceObject()->as(); } - script = JSScript::Create(cx, options, sourceObject, 0, 0); + script = JSScript::Create(cx, options, sourceObject, 0, 0, 0); if (!script) return false; @@ -600,6 +602,8 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip return false; if (!xdr->codeUint32(&script->sourceEnd_)) return false; + if (!xdr->codeUint32(&script->preludeStart_)) + return false; if (!xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || @@ -930,6 +934,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript { uint32_t begin; uint32_t end; + uint32_t preludeStart; uint32_t lineno; uint32_t column; uint64_t packedFields; @@ -943,12 +948,14 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript begin = lazy->begin(); end = lazy->end(); + preludeStart = lazy->preludeStart(); lineno = lazy->lineno(); column = lazy->column(); packedFields = lazy->packedFields(); } if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) || + !xdr->codeUint32(&preludeStart) || !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || !xdr->codeUint64(&packedFields)) { @@ -957,7 +964,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript if (mode == XDR_DECODE) { lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript, - packedFields, begin, end, lineno, column)); + packedFields, begin, end, preludeStart, lineno, column)); if (!lazy) return false; fun->initLazyScript(lazy); @@ -1430,6 +1437,13 @@ JSScript::sourceData(JSContext* cx) return scriptSource()->substring(cx, sourceStart(), sourceEnd()); } +JSFlatString* +JSScript::sourceDataWithPrelude(JSContext* cx) +{ + MOZ_ASSERT(scriptSource()->hasSourceData()); + return scriptSource()->substring(cx, preludeStart(), sourceEnd()); +} + UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry() : cache_(nullptr), sourceChunk_() { @@ -2428,7 +2442,8 @@ JSScript::initCompartment(ExclusiveContext* cx) /* static */ JSScript* JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, - HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd) + HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd, + uint32_t preludeStart) { MOZ_ASSERT(bufStart <= bufEnd); @@ -2450,6 +2465,7 @@ JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, script->setSourceObject(sourceObject); script->sourceStart_ = bufStart; script->sourceEnd_ = bufEnd; + script->preludeStart_ = preludeStart; return script; } @@ -3382,7 +3398,8 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src) .setNoScriptRval(src->noScriptRval()) .setVersion(src->getVersion()); - return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd()); + return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd(), + src->preludeStart()); } JSScript* @@ -3932,7 +3949,8 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot) } LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) + uint32_t begin, uint32_t end, + uint32_t preludeStart, uint32_t lineno, uint32_t column) : script_(nullptr), function_(fun), enclosingScope_(nullptr), @@ -3941,6 +3959,7 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, packedFields_(packedFields), begin_(begin), end_(end), + preludeStart_(preludeStart), lineno_(lineno), column_(column) { @@ -3990,7 +4009,7 @@ LazyScript::maybeForwardedScriptSource() const /* static */ LazyScript* LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column) + uint32_t preludeStart, uint32_t lineno, uint32_t column) { union { PackedView p; @@ -4018,7 +4037,8 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, cx->compartment()->scheduleDelazificationForDebugger(); - return new (res) LazyScript(fun, table.forget(), packed, begin, end, lineno, column); + return new (res) LazyScript(fun, table.forget(), packed, begin, end, + preludeStart, lineno, column); } /* static */ LazyScript* @@ -4026,7 +4046,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, const frontend::AtomVector& closedOverBindings, Handle> innerFunctions, JSVersion version, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) + uint32_t begin, uint32_t end, + uint32_t preludeStart, uint32_t lineno, uint32_t column) { union { PackedView p; @@ -4049,7 +4070,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, p.isDerivedClassConstructor = false; p.needsHomeObject = false; - LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column); + LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart, + lineno, column); if (!res) return nullptr; @@ -4070,7 +4092,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, HandleScript script, HandleScope enclosingScope, HandleScript enclosingScript, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column) + uint32_t preludeStart, uint32_t lineno, uint32_t column) { // Dummy atom which is not a valid property name. RootedAtom dummyAtom(cx, cx->names().comma); @@ -4079,7 +4101,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, // holding this lazy script. HandleFunction dummyFun = fun; - LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column); + LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart, + lineno, column); if (!res) return nullptr; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 87da79901..bb8635581 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -575,10 +575,6 @@ class ScriptSource introductionOffset_ = offset; hasIntroductionOffset_ = true; } - - uint32_t parameterListEnd() const { - return parameterListEnd_; - } }; class ScriptSourceHolder @@ -857,9 +853,19 @@ class JSScript : public js::gc::TenuredCell uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */ - /* Range of characters in scriptSource which contains this script's source. */ + // Range of characters in scriptSource which contains this script's source. + // each field points the following location. + // + // function * f(a, b) { return a + b; } + // ^ ^ ^ + // | | | + // | sourceStart_ sourceEnd_ + // | + // preludeStart_ + // uint32_t sourceStart_; uint32_t sourceEnd_; + uint32_t preludeStart_; // Number of times the script has been called or has had backedges taken. // When running in ion, also increased for any inlined scripts. Reset if @@ -1020,7 +1026,7 @@ class JSScript : public js::gc::TenuredCell // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - // Currently no padding is needed. + uint32_t padding; #endif // @@ -1031,7 +1037,7 @@ class JSScript : public js::gc::TenuredCell static JSScript* Create(js::ExclusiveContext* cx, const JS::ReadOnlyCompileOptions& options, js::HandleObject sourceObject, uint32_t sourceStart, - uint32_t sourceEnd); + uint32_t sourceEnd, uint32_t preludeStart); void initCompartment(js::ExclusiveContext* cx); @@ -1178,6 +1184,10 @@ class JSScript : public js::gc::TenuredCell return sourceEnd_; } + size_t preludeStart() const { + return preludeStart_; + } + bool noScriptRval() const { return noScriptRval_; } @@ -1501,7 +1511,8 @@ class JSScript : public js::gc::TenuredCell bool mayReadFrameArgsDirectly(); JSFlatString* sourceData(JSContext* cx); - + JSFlatString* sourceDataWithPrelude(JSContext* cx); + static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked); void setSourceObject(JSObject* object); @@ -1920,7 +1931,8 @@ class LazyScript : public gc::TenuredCell // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - uint32_t padding; + // uint32_t padding; + // Currently no padding is needed. #endif private: @@ -1960,20 +1972,25 @@ class LazyScript : public gc::TenuredCell }; // Source location for the script. + // See the comment in JSScript for the details. uint32_t begin_; uint32_t end_; + uint32_t preludeStart_; + // Line and column of |begin_| position, that is the position where we + // start parsing. uint32_t lineno_; uint32_t column_; LazyScript(JSFunction* fun, void* table, uint64_t packedFields, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); + uint32_t begin, uint32_t end, uint32_t preludeStart, + uint32_t lineno, uint32_t column); // Create a LazyScript without initializing the closedOverBindings and the // innerFunctions. To be GC-safe, the caller must initialize both vectors // with valid atoms and functions. static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun, uint64_t packedData, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column); + uint32_t preludeStart, uint32_t lineno, uint32_t column); public: static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits; @@ -1985,7 +2002,7 @@ class LazyScript : public gc::TenuredCell const frontend::AtomVector& closedOverBindings, Handle> innerFunctions, JSVersion version, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column); + uint32_t preludeStart, uint32_t lineno, uint32_t column); // Create a LazyScript and initialize the closedOverBindings and the // innerFunctions with dummy values to be replaced in a later initialization @@ -2000,7 +2017,7 @@ class LazyScript : public gc::TenuredCell HandleScript script, HandleScope enclosingScope, HandleScript enclosingScript, uint64_t packedData, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column); + uint32_t preludeStart, uint32_t lineno, uint32_t column); void initRuntimeFields(uint64_t packedFields); @@ -2173,6 +2190,9 @@ class LazyScript : public gc::TenuredCell uint32_t end() const { return end_; } + uint32_t preludeStart() const { + return preludeStart_; + } uint32_t lineno() const { return lineno_; } @@ -2199,7 +2219,8 @@ class LazyScript : public gc::TenuredCell }; /* If this fails, add/remove padding within LazyScript. */ -JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0); +static_assert(sizeof(LazyScript) % js::gc::CellSize == 0, + "Size of LazyScript must be an integral multiple of js::gc::CellSize"); struct ScriptAndCounts { diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 2237d1d7f..2b6690363 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -318,6 +318,7 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod // Function constructor, this will be the first character in the function // source. Otherwise, it will be the opening parenthesis of the arguments // list. + uint32_t preludeStart; uint32_t srcStart; uint32_t srcBodyStart; bool strict; @@ -1758,6 +1759,7 @@ class MOZ_STACK_CLASS ModuleValidator if (!asmJSMetadata_) return false; + asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart; asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin; asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end; asmJSMetadata_->strict = parser_.pc->sc()->strict() && @@ -7049,6 +7051,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) TokenStream& tokenStream = m.tokenStream(); tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand); + uint32_t preludeStart = tokenStream.currentToken().pos.begin; *line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end); TokenKind tk; @@ -7071,7 +7074,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) ParseContext* outerpc = m.parser().pc; Directives directives(outerpc); - FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, directives, NotGenerator, + FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, preludeStart, directives, NotGenerator, SyncFunction, /* tryAnnexB = */ false); if (!funbox) return false; @@ -8054,7 +8057,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me return false; } - uint32_t begin = metadata.srcStart; + uint32_t begin = metadata.preludeStart; uint32_t end = metadata.srcEndAfterCurly(); Rooted src(cx, source->substringDontDeflate(cx, begin, end)); if (!src) @@ -8085,7 +8088,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller() ? SourceBufferHolder::GiveOwnership : SourceBufferHolder::NoOwnership; - SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership); + SourceBufferHolder srcBuf(chars, end - begin, ownership); if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing())) return false; @@ -8537,6 +8540,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded return true; // See AsmJSMetadata comment as well as ModuleValidator::init(). + asmJSMetadata->preludeStart = parser.pc->functionBox()->preludeStart; asmJSMetadata->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin; asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end; asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict(); @@ -8834,7 +8838,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda MOZ_ASSERT(IsAsmJSModule(fun)); const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS(); - uint32_t begin = metadata.srcStart; + uint32_t begin = metadata.preludeStart; uint32_t end = metadata.srcEndAfterCurly(); ScriptSource* source = metadata.scriptSource.get(); @@ -8843,17 +8847,15 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda if (addParenToLambda && fun->isLambda() && !out.append("(")) return nullptr; - if (!out.append("function ")) - return nullptr; - - if (fun->explicitName() && !out.append(fun->explicitName())) - return nullptr; - bool haveSource = source->hasSourceData(); if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) return nullptr; if (!haveSource) { + if (!out.append("function ")) + return nullptr; + if (fun->explicitName() && !out.append(fun->explicitName())) + return nullptr; if (!out.append("() {\n [sourceless code]\n}")) return nullptr; } else { -- cgit v1.2.3 From 4ee0411274b7ded730da8cb87f016d53dab56533 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 13:51:57 +0100 Subject: Stage 1-2: Remove a space after comma in parameter list for generated function source. --- js/src/jsfun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 4412362c2..be11bf436 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1715,7 +1715,7 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator if (i < args.length() - 2) { // Step 9.d.iii. - if (!sb.append(", ")) + if (!sb.append(",")) return false; } } -- cgit v1.2.3 From 90f6b2704658a554a12ed3c37545cb6474fbcf51 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 14:29:54 +0100 Subject: Stage 1-3: Generate better source in Object.prototype.toSource. Tag #960. --- js/src/builtin/Object.cpp | 280 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 193 insertions(+), 87 deletions(-) diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index cd4ac122c..389bb57db 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -9,11 +9,13 @@ #include "mozilla/ArrayUtils.h" #include "jscntxt.h" +#include "jsstr.h" #include "builtin/Eval.h" #include "frontend/BytecodeCompiler.h" #include "jit/InlinableNatives.h" #include "js/UniquePtr.h" +#include "vm/AsyncFunction.h" #include "vm/StringBuffer.h" #include "jsobjinlines.h" @@ -124,6 +126,27 @@ obj_toSource(JSContext* cx, unsigned argc, Value* vp) return true; } +template +static bool +Consume(const CharT*& s, const CharT* e, const char *chars) +{ + size_t len = strlen(chars); + if (s + len >= e) + return false; + if (!EqualChars(s, chars, len)) + return false; + s += len; + return true; +} + +template +static void +ConsumeSpaces(const CharT*& s, const CharT* e) +{ + while (*s == ' ' && s < e) + s++; +} + /* * Given a function source string, return the offset and length of the part * between '(function $name' and ')'. @@ -133,37 +156,53 @@ static bool ArgsAndBodySubstring(mozilla::Range chars, size_t* outOffset, size_t* outLen) { const CharT* const start = chars.begin().get(); - const CharT* const end = chars.end().get(); const CharT* s = start; + const CharT* e = chars.end().get(); - uint8_t parenChomp = 0; - if (s[0] == '(') { - s++; - parenChomp = 1; - } - - /* Try to jump "function" keyword. */ - s = js_strchr_limit(s, ' ', end); - if (!s) + if (s == e) return false; - /* - * Jump over the function's name: it can't be encoded as part - * of an ECMA getter or setter. - */ - s = js_strchr_limit(s, '(', end); - if (!s) - return false; + // Remove enclosing parentheses. + if (*s == '(' && *(e - 1) == ')') { + s++; + e--; + } - if (*s == ' ') + (void) Consume(s, e, "async"); + ConsumeSpaces(s, e); + (void) (Consume(s, e, "function") || Consume(s, e, "get") || Consume(s, e, "set")); + ConsumeSpaces(s, e); + (void) Consume(s, e, "*"); + ConsumeSpaces(s, e); + + // Jump over the function's name. + if (Consume(s, e, "[")) { + s = js_strchr_limit(s, ']', e); + if (!s) + return false; s++; + ConsumeSpaces(s, e); + if (*s != '(') + return false; + } else { + s = js_strchr_limit(s, '(', e); + if (!s) + return false; + } *outOffset = s - start; - *outLen = end - s - parenChomp; + *outLen = e - s; MOZ_ASSERT(*outOffset + *outLen <= chars.length()); return true; } +enum class PropertyKind { + Getter, + Setter, + Method, + Normal +}; + JSString* js::ObjectToSource(JSContext* cx, HandleObject obj) { @@ -182,59 +221,28 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) if (!buf.append('{')) return nullptr; - RootedValue v0(cx), v1(cx); - MutableHandleValue val[2] = {&v0, &v1}; - - RootedString str0(cx), str1(cx); - MutableHandleString gsop[2] = {&str0, &str1}; - AutoIdVector idv(cx); if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv)) return nullptr; bool comma = false; - for (size_t i = 0; i < idv.length(); ++i) { - RootedId id(cx, idv[i]); - Rooted desc(cx); - if (!GetOwnPropertyDescriptor(cx, obj, id, &desc)) - return nullptr; - - int valcnt = 0; - if (desc.object()) { - if (desc.isAccessorDescriptor()) { - if (desc.hasGetterObject() && desc.getterObject()) { - val[valcnt].setObject(*desc.getterObject()); - gsop[valcnt].set(cx->names().get); - valcnt++; - } - if (desc.hasSetterObject() && desc.setterObject()) { - val[valcnt].setObject(*desc.setterObject()); - gsop[valcnt].set(cx->names().set); - valcnt++; - } - } else { - valcnt = 1; - val[0].set(desc.value()); - gsop[0].set(nullptr); - } - } - + auto AddProperty = [cx, &comma, &buf](HandleId id, HandleValue val, PropertyKind kind) -> bool { /* Convert id to a string. */ RootedString idstr(cx); if (JSID_IS_SYMBOL(id)) { RootedValue v(cx, SymbolValue(JSID_TO_SYMBOL(id))); idstr = ValueToSource(cx, v); if (!idstr) - return nullptr; + return false; } else { RootedValue idv(cx, IdToValue(id)); idstr = ToString(cx, idv); if (!idstr) - return nullptr; + return false; /* - * If id is a string that's not an identifier, or if it's a negative - * integer, then it must be quoted. + * If id is a string that's not an identifier, or if it's a + * negative integer, then it must be quoted. */ if (JSID_IS_ATOM(id) ? !IsIdentifier(JSID_TO_ATOM(id)) @@ -242,28 +250,65 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) { idstr = QuoteString(cx, idstr, char16_t('\'')); if (!idstr) - return nullptr; + return false; } } - for (int j = 0; j < valcnt; j++) { - /* Convert val[j] to its canonical source form. */ - JSString* valsource = ValueToSource(cx, val[j]); - if (!valsource) - return nullptr; + RootedString valsource(cx, ValueToSource(cx, val)); + if (!valsource) + return false; - RootedLinearString valstr(cx, valsource->ensureLinear(cx)); - if (!valstr) - return nullptr; + RootedLinearString valstr(cx, valsource->ensureLinear(cx)); + if (!valstr) + return false; + + if (comma && !buf.append(", ")) + return false; + comma = true; + + size_t voffset, vlength; + + // Methods and accessors can return exact syntax of source, that fits + // into property without adding property name or "get"/"set" prefix. + // Use the exact syntax when the following conditions are met: + // + // * It's a function object + // (exclude proxies) + // * Function's kind and property's kind are same + // (this can be false for dynamically defined properties) + // * Function has explicit name + // (this can be false for computed property and dynamically defined + // properties) + // * Function's name and property's name are same + // (this can be false for dynamically defined properties) + if (kind == PropertyKind::Getter || kind == PropertyKind::Setter || + kind == PropertyKind::Method) + { + RootedFunction fun(cx); + if (val.toObject().is()) { + fun = &val.toObject().as(); + // Method's case should be checked on caller. + if (((fun->isGetter() && kind == PropertyKind::Getter) || + (fun->isSetter() && kind == PropertyKind::Setter) || + kind == PropertyKind::Method) && + fun->explicitName()) + { + bool result; + if (!EqualStrings(cx, fun->explicitName(), idstr, &result)) + return false; - size_t voffset = 0; - size_t vlength = valstr->length(); + if (result) { + if (!buf.append(valstr)) + return false; + return true; + } + } + } - /* - * Remove '(function ' from the beginning of valstr and ')' from the - * end so that we can put "get" in front of the function definition. - */ - if (gsop[j] && IsFunctionObject(val[j])) { + { + // When falling back try to generate a better string + // representation by skipping the prelude, and also removing + // the enclosing parentheses. bool success; JS::AutoCheckCannotGC nogc; if (valstr->hasLatin1Chars()) @@ -271,29 +316,90 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) else success = ArgsAndBodySubstring(valstr->twoByteRange(nogc), &voffset, &vlength); if (!success) - gsop[j].set(nullptr); + kind = PropertyKind::Normal; } - if (comma && !buf.append(", ")) - return nullptr; - comma = true; + if (kind == PropertyKind::Getter) { + if (!buf.append("get ")) + return false; + } else if (kind == PropertyKind::Setter) { + if (!buf.append("set ")) + return false; + } else if (kind == PropertyKind::Method && fun) { + if (IsWrappedAsyncFunction(fun)) { + if (!buf.append("async ")) + return false; + } - if (gsop[j]) { - if (!buf.append(gsop[j]) || !buf.append(' ')) - return nullptr; + if (fun->isStarGenerator()) { + if (!buf.append('*')) + return false; + } } - if (JSID_IS_SYMBOL(id) && !buf.append('[')) - return nullptr; - if (!buf.append(idstr)) - return nullptr; - if (JSID_IS_SYMBOL(id) && !buf.append(']')) - return nullptr; - if (!buf.append(gsop[j] ? ' ' : ':')) - return nullptr; + } + bool needsBracket = JSID_IS_SYMBOL(id); + if (needsBracket && !buf.append('[')) + return false; + if (!buf.append(idstr)) + return false; + if (needsBracket && !buf.append(']')) + return false; + + if (kind == PropertyKind::Getter || kind == PropertyKind::Setter || + kind == PropertyKind::Method) + { if (!buf.appendSubstring(valstr, voffset, vlength)) - return nullptr; + return false; + } else { + if (!buf.append(':')) + return false; + if (!buf.append(valstr)) + return false; + } + return true; + }; + + RootedId id(cx); + Rooted desc(cx); + RootedValue val(cx); + RootedFunction fun(cx); + for (size_t i = 0; i < idv.length(); ++i) { + id = idv[i]; + if (!GetOwnPropertyDescriptor(cx, obj, id, &desc)) + return nullptr; + + if (!desc.object()) + continue; + + if (desc.isAccessorDescriptor()) { + if (desc.hasGetterObject() && desc.getterObject()) { + val.setObject(*desc.getterObject()); + if (!AddProperty(id, val, PropertyKind::Getter)) + return nullptr; + } + if (desc.hasSetterObject() && desc.setterObject()) { + val.setObject(*desc.setterObject()); + if (!AddProperty(id, val, PropertyKind::Setter)) + return nullptr; + } + continue; } + + val.set(desc.value()); + if (IsFunctionObject(val, fun.address())) { + if (IsWrappedAsyncFunction(fun)) + fun = GetUnwrappedAsyncFunction(fun); + + if (fun->isMethod()) { + if (!AddProperty(id, val, PropertyKind::Method)) + return nullptr; + continue; + } + } + + if (!AddProperty(id, val, PropertyKind::Normal)) + return nullptr; } if (!buf.append('}')) -- cgit v1.2.3 From ae4af7b7e598b4fec037254a1fd03ac3495695a4 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sun, 3 Feb 2019 08:21:19 +0100 Subject: Stage 1-4: Update tests --- .../test/browser_webconsole_output_02.js | 4 +- devtools/server/tests/unit/test_listsources-04.js | 4 +- js/src/jit-test/tests/asm.js/testSource.js | 48 +-- .../tests/basic/function-tosource-bug779694.js | 2 +- .../tests/basic/function-tosource-constructor.js | 16 +- .../tests/basic/function-tosource-getset.js | 10 +- js/src/jit-test/tests/basic/testLet.js | 2 +- js/src/jit-test/tests/debug/Script-gc-02.js | 2 +- js/src/jit-test/tests/debug/Script-gc-03.js | 2 +- .../jit-test/tests/debug/Script-sourceStart-04.js | 4 +- js/src/jit-test/tests/debug/Source-text-02.js | 1 + js/src/jit-test/tests/latin1/assorted.js | 6 +- js/src/jit-test/tests/latin1/function.js | 4 +- js/src/tests/ecma_2017/Function/Object-toSource.js | 370 +++++++++++++++++++++ js/src/tests/ecma_2017/Function/browser.js | 0 js/src/tests/ecma_2017/Function/shell.js | 0 js/src/tests/ecma_6/Generators/runtime.js | 2 +- js/src/tests/js1_5/Scope/regress-185485.js | 2 +- js/src/tests/js1_7/extensions/regress-354945-01.js | 2 +- js/src/tests/js1_7/extensions/regress-354945-02.js | 2 +- js/src/tests/js1_8_5/regress/regress-584355.js | 2 +- .../webstorage/storage_string_conversion.html | 6 +- toolkit/modules/tests/xpcshell/test_Log.js | 6 +- 23 files changed, 434 insertions(+), 63 deletions(-) create mode 100644 js/src/tests/ecma_2017/Function/Object-toSource.js create mode 100644 js/src/tests/ecma_2017/Function/browser.js create mode 100644 js/src/tests/ecma_2017/Function/shell.js diff --git a/devtools/client/webconsole/test/browser_webconsole_output_02.js b/devtools/client/webconsole/test/browser_webconsole_output_02.js index 4c61cf041..837ec673c 100644 --- a/devtools/client/webconsole/test/browser_webconsole_output_02.js +++ b/devtools/client/webconsole/test/browser_webconsole_output_02.js @@ -24,7 +24,7 @@ var inputTests = [ { input: "(function() { return 42; })", output: "function ()", - printOutput: "function () { return 42; }", + printOutput: "function() { return 42; }", suppressClick: true }, @@ -40,7 +40,7 @@ var inputTests = [ { input: "testobj1.testfn2", output: "function testfn2()", - printOutput: "function () { return 42; }", + printOutput: "function() { return 42; }", suppressClick: true }, diff --git a/devtools/server/tests/unit/test_listsources-04.js b/devtools/server/tests/unit/test_listsources-04.js index 6da99a6ce..8e1a57bf0 100644 --- a/devtools/server/tests/unit/test_listsources-04.js +++ b/devtools/server/tests/unit/test_listsources-04.js @@ -29,12 +29,12 @@ function run_test_with_server(server, cb) { addSources(debuggee); threadClient.getSources(Task.async(function* (res) { - do_check_true(res.sources.length === 3, "3 sources exist"); + do_check_eq(res.sources.length, 3, "3 sources exist"); yield threadClient.reconfigure({ useSourceMaps: false }); threadClient.getSources(function(res) { - do_check_true(res.sources.length === 1, "1 source exist"); + do_check_eq(res.sources.length, 1, "1 source exist"); client.close().then(cb); }); })); diff --git a/js/src/jit-test/tests/asm.js/testSource.js b/js/src/jit-test/tests/asm.js/testSource.js index b44c52a6b..d7ad42864 100644 --- a/js/src/jit-test/tests/asm.js/testSource.js +++ b/js/src/jit-test/tests/asm.js/testSource.js @@ -32,7 +32,7 @@ var f0 = function() { } -funcBody1 = funcBody.replace('function f0','function '); +funcBody1 = funcBody.replace('function f0','function'); assertEq(f0.toString(), funcBody1); assertEq(f0.toSource(), '(' + funcBody1 + ')'); @@ -48,14 +48,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f0 = new Function(bodyOnly); -assertEq(f0.toString(), "function anonymous() {\n" + bodyOnly + "\n}"); -assertEq(f0.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})"); +assertEq(f0.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}"); +assertEq(f0.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function(bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous() {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})"); } })(); @@ -91,7 +91,7 @@ f1 = function(glob) { } -funcBody1 = funcBody.replace('function f1', 'function '); +funcBody1 = funcBody.replace('function f1', 'function'); assertEq(f1.toString(), funcBody1); assertEq(f1.toSource(), '(' + funcBody1 + ')'); @@ -107,14 +107,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f1 = new Function('glob', bodyOnly); -assertEq(f1.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}"); -assertEq(f1.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})"); +assertEq(f1.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}"); +assertEq(f1.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function('glob', bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})"); } })(); @@ -144,14 +144,14 @@ var funcBody = 'function f2(glob, ffi) {\n\ assertEq(f2.toString(), funcBody); assertEq(f2.toSource(), funcBody); -f2 = function (glob, ffi) { +f2 = function(glob, ffi) { "use asm"; function g() {} return g; } -funcBody1 = funcBody.replace('function f2', 'function '); +funcBody1 = funcBody.replace('function f2', 'function'); assertEq(f2.toString(), funcBody1); assertEq(f2.toSource(), '(' + funcBody1 + ')'); @@ -167,14 +167,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f2 = new Function('glob', 'ffi', bodyOnly); -assertEq(f2.toString(), "function anonymous(glob, ffi) {\n" + bodyOnly + "\n}"); -assertEq(f2.toSource(), "(function anonymous(glob, ffi) {\n" + bodyOnly + "\n})"); +assertEq(f2.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}"); +assertEq(f2.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function('glob', 'ffi', bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous(glob, ffi) {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous(glob, ffi) {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})"); } })(); @@ -204,14 +204,14 @@ var funcBody = 'function f3(glob, ffi, heap) {\n\ assertEq(f3.toString(), funcBody); assertEq(f3.toSource(), funcBody); -f3 = function (glob, ffi, heap) { +f3 = function(glob, ffi, heap) { "use asm"; function g() {} return g; } -funcBody1 = funcBody.replace('function f3', 'function '); +funcBody1 = funcBody.replace('function f3', 'function'); assertEq(f3.toString(), funcBody1); assertEq(f3.toSource(), '(' + funcBody1 + ')'); @@ -227,14 +227,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f3 = new Function('glob', 'ffi', 'heap', bodyOnly); -assertEq(f3.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}"); -assertEq(f3.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})"); +assertEq(f3.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}"); +assertEq(f3.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function('glob', 'ffi', 'heap', bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})"); } })(); @@ -243,7 +243,7 @@ if (isAsmJSCompilationAvailable() && isCachingEnabled()) { (function() { var funcSource = - `function (glob, ffi, heap) { + `function(glob, ffi, heap) { "use asm"; function g() {} return g; @@ -252,7 +252,7 @@ var funcSource = var f4 = eval("\"use strict\";\n(" + funcSource + ")"); var expectedToString = funcSource; -var expectedToSource = '(' + expectedToString + ')' +var expectedToSource = '(' + expectedToString + ')'; assertEq(f4.toString(), expectedToString); assertEq(f4.toSource(), expectedToSource); diff --git a/js/src/jit-test/tests/basic/function-tosource-bug779694.js b/js/src/jit-test/tests/basic/function-tosource-bug779694.js index 3893d3ff2..782b2594b 100644 --- a/js/src/jit-test/tests/basic/function-tosource-bug779694.js +++ b/js/src/jit-test/tests/basic/function-tosource-bug779694.js @@ -5,4 +5,4 @@ for (var i=0; i<400; ++i) { x += String.fromCharCode(i * 289); } var s = "'" + x + "'"; -assertEq(Function("evt", s).toString(), "function anonymous(evt) {\n" + s + "\n}"); +assertEq(Function("evt", s).toString(), "function anonymous(evt\n) {\n" + s + "\n}"); diff --git a/js/src/jit-test/tests/basic/function-tosource-constructor.js b/js/src/jit-test/tests/basic/function-tosource-constructor.js index e1d144364..9a8961fe2 100644 --- a/js/src/jit-test/tests/basic/function-tosource-constructor.js +++ b/js/src/jit-test/tests/basic/function-tosource-constructor.js @@ -1,14 +1,14 @@ var f = Function("a", "b", "return a + b;"); -assertEq(f.toString(), "function anonymous(a, b) {\nreturn a + b;\n}"); -assertEq(f.toSource(), "(function anonymous(a, b) {\nreturn a + b;\n})"); +assertEq(f.toString(), "function anonymous(a,b\n) {\nreturn a + b;\n}"); +assertEq(f.toSource(), "(function anonymous(a,b\n) {\nreturn a + b;\n})"); assertEq(decompileFunction(f), f.toString()); f = Function("a", "...rest", "return rest[42] + b;"); -assertEq(f.toString(), "function anonymous(a, ...rest) {\nreturn rest[42] + b;\n}"); -assertEq(f.toSource(), "(function anonymous(a, ...rest) {\nreturn rest[42] + b;\n})") +assertEq(f.toString(), "function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n}"); +assertEq(f.toSource(), "(function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n})") assertEq(decompileFunction(f), f.toString()); f = Function(""); -assertEq(f.toString(), "function anonymous() {\n\n}"); +assertEq(f.toString(), "function anonymous(\n) {\n\n}"); f = Function("", "(abc)"); -assertEq(f.toString(), "function anonymous() {\n(abc)\n}"); -f = Function("", "return function (a, b) a + b;")(); -assertEq(f.toString(), "function (a, b) a + b"); +assertEq(f.toString(), "function anonymous(\n) {\n(abc)\n}"); +f = Function("", "return function (a,b) a + b;")(); +assertEq(f.toString(), "function (a,b) a + b"); diff --git a/js/src/jit-test/tests/basic/function-tosource-getset.js b/js/src/jit-test/tests/basic/function-tosource-getset.js index 36c6d010e..1804d38f2 100644 --- a/js/src/jit-test/tests/basic/function-tosource-getset.js +++ b/js/src/jit-test/tests/basic/function-tosource-getset.js @@ -1,7 +1,7 @@ var o = {get prop() a + b, set prop(x) a + b}; var prop = Object.getOwnPropertyDescriptor(o, "prop"); -assertEq(prop.get.toString(), "function get prop() a + b"); -assertEq(prop.get.toSource(), "(function get prop() a + b)"); -assertEq(prop.set.toString(), "function set prop(x) a + b"); -assertEq(prop.set.toSource(), "(function set prop(x) a + b)"); -assertEq(o.toSource(), "({get prop () a + b, set prop (x) a + b})"); +assertEq(prop.get.toString(), "get prop() { a + b; }"); +assertEq(prop.get.toSource(), "get prop() { a + b; }"); +assertEq(prop.set.toString(), "set prop(x) { a + b; }"); +assertEq(prop.set.toSource(), "set prop(x) { a + b; }"); +assertEq(o.toSource(), "({get prop() { a + b; }, set prop(x) { a + b; }})"); diff --git a/js/src/jit-test/tests/basic/testLet.js b/js/src/jit-test/tests/basic/testLet.js index 263c3eb8a..9a2f39197 100644 --- a/js/src/jit-test/tests/basic/testLet.js +++ b/js/src/jit-test/tests/basic/testLet.js @@ -9,7 +9,7 @@ function test(str, arg, result) var fun = new Function('x', str); var got = fun.toSource(); - var expect = '(function anonymous(x) {\n' + str + '\n})'; + var expect = '(function anonymous(x\n) {\n' + str + '\n})'; if (got !== expect) { print("GOT: " + got); print("EXPECT: " + expect); diff --git a/js/src/jit-test/tests/debug/Script-gc-02.js b/js/src/jit-test/tests/debug/Script-gc-02.js index 04dd4b220..9689a6ebe 100644 --- a/js/src/jit-test/tests/debug/Script-gc-02.js +++ b/js/src/jit-test/tests/debug/Script-gc-02.js @@ -10,5 +10,5 @@ assertEq(arr.length, 10); gc(); for (var i = 0; i < arr.length; i++) - assertEq(arr[i].lineCount, 3); + assertEq(arr[i].lineCount, 4); diff --git a/js/src/jit-test/tests/debug/Script-gc-03.js b/js/src/jit-test/tests/debug/Script-gc-03.js index 30c3e8dbc..5ecb4556f 100644 --- a/js/src/jit-test/tests/debug/Script-gc-03.js +++ b/js/src/jit-test/tests/debug/Script-gc-03.js @@ -10,6 +10,6 @@ assertEq(arr.length, 100); gc(g); for (var i = 0; i < arr.length; i++) - assertEq(arr[i].lineCount, 3); + assertEq(arr[i].lineCount, 4); gc(); diff --git a/js/src/jit-test/tests/debug/Script-sourceStart-04.js b/js/src/jit-test/tests/debug/Script-sourceStart-04.js index 2aa382b7b..4546818e4 100644 --- a/js/src/jit-test/tests/debug/Script-sourceStart-04.js +++ b/js/src/jit-test/tests/debug/Script-sourceStart-04.js @@ -20,6 +20,6 @@ function test(string, range) { } test("eval('2 * 3')", [0, 5]); -test("new Function('2 * 3')", [0, 12]); -test("new Function('x', 'x * x')", [0, 13]); +test("new Function('2 * 3')", [0, 31]); +test("new Function('x', 'x * x')", [0, 32]); assertEq(count, 6); diff --git a/js/src/jit-test/tests/debug/Source-text-02.js b/js/src/jit-test/tests/debug/Source-text-02.js index 64cfce92a..46e76015e 100644 --- a/js/src/jit-test/tests/debug/Source-text-02.js +++ b/js/src/jit-test/tests/debug/Source-text-02.js @@ -3,6 +3,7 @@ let g = newGlobal(); let dbg = new Debugger(g); +var text; var count = 0; dbg.onNewScript = function (script) { ++count; diff --git a/js/src/jit-test/tests/latin1/assorted.js b/js/src/jit-test/tests/latin1/assorted.js index cef79cb96..1389a1ada 100644 --- a/js/src/jit-test/tests/latin1/assorted.js +++ b/js/src/jit-test/tests/latin1/assorted.js @@ -12,18 +12,18 @@ var o = {}; Object.defineProperty(o, "prop", {get: function() { return 1; }, set: function() { return 2; }, enumerable: true, configurable: true}); -assertEq(o.toSource(), "({get prop () { return 1; }, set prop () { return 2; }})"); +assertEq(o.toSource(), "({get prop() { return 1; }, set prop() { return 2; }})"); // obj.toSource TwoByte Object.defineProperty(o, "prop", {get: function() { return "\u1200"; }, set: function() { return "\u1200"; }, enumerable: true}); -assertEq(o.toSource(), '({get prop () { return "\\u1200"; }, set prop () { return "\\u1200"; }})'); +assertEq(o.toSource(), '({get prop() { return "\\u1200"; }, set prop() { return "\\u1200"; }})'); var ff = function() { return 10; }; ff.toSource = function() { return "((11))"; } Object.defineProperty(o, "prop", {get: ff, set: ff, enumerable: true}); -assertEq(o.toSource(), "({prop:((11)), prop:((11))})"); +assertEq(o.toSource(), "({get prop(11), set prop(11)})"); // XDR load(libdir + 'bytecode-cache.js'); diff --git a/js/src/jit-test/tests/latin1/function.js b/js/src/jit-test/tests/latin1/function.js index a0dedf251..07a76733a 100644 --- a/js/src/jit-test/tests/latin1/function.js +++ b/js/src/jit-test/tests/latin1/function.js @@ -6,11 +6,11 @@ function test() { var f = Function(arg1TwoByte, arg2Latin1, bodyLatin1); assertEq(f(10, 20), 60); - assertEq(f.toSource().includes("arg1\u1200, arg2"), true); + assertEq(f.toSource().includes("arg1\u1200,arg2"), true); var bodyTwoByte = "return arg1\u1200 + arg2;"; f = Function(arg1TwoByte, arg2Latin1, bodyTwoByte); assertEq(f(30, 40), 70); - assertEq(f.toSource().includes("arg1\u1200, arg2"), true); + assertEq(f.toSource().includes("arg1\u1200,arg2"), true); } test(); diff --git a/js/src/tests/ecma_2017/Function/Object-toSource.js b/js/src/tests/ecma_2017/Function/Object-toSource.js new file mode 100644 index 000000000..33b9e588e --- /dev/null +++ b/js/src/tests/ecma_2017/Function/Object-toSource.js @@ -0,0 +1,370 @@ +var BUGNUMBER = 1317400; +var summary = "Function string representation in Object.prototype.toSource"; + +print(BUGNUMBER + ": " + summary); + +// Methods. + +assertEq(({ foo(){} }).toSource(), + "({foo(){}})"); +assertEq(({ *foo(){} }).toSource(), + "({*foo(){}})"); +assertEq(({ async foo(){} }).toSource(), + "({async foo(){}})"); + +assertEq(({ 1(){} }).toSource(), + "({1(){}})"); + +// Methods with more spacing. +// Spacing is kept. + +assertEq(({ foo (){} }).toSource(), + "({foo (){}})"); +assertEq(({ foo () {} }).toSource(), + "({foo () {}})"); + +// Methods with computed name. +// Method syntax is composed. + +let name = "foo"; +assertEq(({ [name](){} }).toSource(), + "({foo(){}})"); +assertEq(({ *[name](){} }).toSource(), + "({*foo(){}})"); +assertEq(({ async [name](){} }).toSource(), + "({async foo(){}})"); + +assertEq(({ [ Symbol.iterator ](){} }).toSource(), + "({[Symbol.iterator](){}})"); + +// Accessors. + +assertEq(({ get foo(){} }).toSource(), + "({get foo(){}})"); +assertEq(({ set foo(v){} }).toSource(), + "({set foo(v){}})"); + +// Accessors with computed name. +// Method syntax is composed. + +assertEq(({ get [name](){} }).toSource(), + "({get foo(){}})"); +assertEq(({ set [name](v){} }).toSource(), + "({set foo(v){}})"); + +assertEq(({ get [ Symbol.iterator ](){} }).toSource(), + "({get [Symbol.iterator](){}})"); +assertEq(({ set [ Symbol.iterator ](v){} }).toSource(), + "({set [Symbol.iterator](v){}})"); + +// Getter and setter with same name. +// Getter always comes before setter. + +assertEq(({ get foo(){}, set foo(v){} }).toSource(), + "({get foo(){}, set foo(v){}})"); +assertEq(({ set foo(v){}, get foo(){} }).toSource(), + "({get foo(){}, set foo(v){}})"); + +// Normal properties. + +assertEq(({ foo: function(){} }).toSource(), + "({foo:(function(){})})"); +assertEq(({ foo: function bar(){} }).toSource(), + "({foo:(function bar(){})})"); +assertEq(({ foo: function*(){} }).toSource(), + "({foo:(function*(){})})"); +assertEq(({ foo: async function(){} }).toSource(), + "({foo:(async function(){})})"); + +// Normal properties with computed name. + +assertEq(({ [ Symbol.iterator ]: function(){} }).toSource(), + "({[Symbol.iterator]:(function(){})})"); + +// Dynamically defined properties with function expression. +// Never become a method syntax. + +let obj = {}; +obj.foo = function() {}; +assertEq(obj.toSource(), + "({foo:(function() {})})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function() {}}); +assertEq(obj.toSource(), + "({})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({foo:(function() {})})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true}); +assertEq(obj.toSource(), + "({foo:(function bar() {})})"); + +obj = {}; +Object.defineProperty(obj, Symbol.iterator, {value: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({[Symbol.iterator]:(function() {})})"); + +// Dynamically defined property with other object's method. +// Method syntax is composed. + +let method = ({foo() {}}).foo; + +obj = {}; +Object.defineProperty(obj, "foo", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "bar", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({bar() {}})"); + +method = ({*foo() {}}).foo; + +obj = {}; +Object.defineProperty(obj, "bar", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({*bar() {}})"); + +method = ({async foo() {}}).foo; + +obj = {}; +Object.defineProperty(obj, "bar", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({async bar() {}})"); + +// Dynamically defined accessors. +// Accessor syntax is composed. + +obj = {}; +Object.defineProperty(obj, "foo", {get: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +obj = {}; +Object.defineProperty(obj, Symbol.iterator, {get: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({get [Symbol.iterator]() {}})"); + +obj = {}; +Object.defineProperty(obj, Symbol.iterator, {set: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({set [Symbol.iterator]() {}})"); + +// Dynamically defined accessors with other object's accessors. +// Accessor syntax is composed. + +let accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +// Methods with proxy. +// Treated as normal property. + +method = ({foo() {}}).foo; +let handler = { + get(that, name) { + if (name == "toSource") { + return function() { + return that.toSource(); + }; + } + return that[name]; + } +}; +let proxy = new Proxy(method, handler); + +obj = {}; +Object.defineProperty(obj, "foo", {value: proxy, enumerable: true}); +assertEq(obj.toSource(), + "({foo:foo() {}})"); + +// Accessors with proxy. +// Accessor syntax is composed. + +accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get; +proxy = new Proxy(accessor, handler); + +obj = {}; +Object.defineProperty(obj, "foo", {get: proxy, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: proxy, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +// Methods from other global. +// Treated as normal property. + +let g = newGlobal(); + +method = g.eval("({ foo() {} }).foo"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({foo:foo() {}})"); + +// Accessors from other global. +// Accessor syntax is composed. + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +// **** Some weird cases **** + +// Accessors with generator or async. + +obj = {}; +Object.defineProperty(obj, "foo", {get: function*() {}, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: async function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +// Modified toSource. + +obj = { foo() {} }; +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({hello})"); + +obj = { foo() {} }; +obj.foo.toSource = () => "bar() {}"; +assertEq(obj.toSource(), + "({bar() {}})"); + +// Modified toSource with different method name. + +obj = {}; +Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true}); +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({foo:hello})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function* bar() {}, enumerable: true}); +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({foo:hello})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: async function bar() {}, enumerable: true}); +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({foo:hello})"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_2017/Function/browser.js b/js/src/tests/ecma_2017/Function/browser.js new file mode 100644 index 000000000..e69de29bb diff --git a/js/src/tests/ecma_2017/Function/shell.js b/js/src/tests/ecma_2017/Function/shell.js new file mode 100644 index 000000000..e69de29bb diff --git a/js/src/tests/ecma_6/Generators/runtime.js b/js/src/tests/ecma_6/Generators/runtime.js index c4d3bb6a6..7146eef9f 100644 --- a/js/src/tests/ecma_6/Generators/runtime.js +++ b/js/src/tests/ecma_6/Generators/runtime.js @@ -109,7 +109,7 @@ function TestGeneratorFunction() { // Doesn't matter particularly what string gets serialized, as long // as it contains "function*" and "yield 10". assertEq(GeneratorFunction('yield 10').toString(), - "function* anonymous() {\nyield 10\n}"); + "function* anonymous(\n) {\nyield 10\n}"); } TestGeneratorFunction(); diff --git a/js/src/tests/js1_5/Scope/regress-185485.js b/js/src/tests/js1_5/Scope/regress-185485.js index 19d190eea..a75bf885a 100644 --- a/js/src/tests/js1_5/Scope/regress-185485.js +++ b/js/src/tests/js1_5/Scope/regress-185485.js @@ -94,7 +94,7 @@ with (x) } status = inSection(5); actual = x.g.toString(); -expect = (function () {}).toString(); +expect = (function() {}).toString(); addThis(); diff --git a/js/src/tests/js1_7/extensions/regress-354945-01.js b/js/src/tests/js1_7/extensions/regress-354945-01.js index 76f1a3c82..1c57db0f7 100644 --- a/js/src/tests/js1_7/extensions/regress-354945-01.js +++ b/js/src/tests/js1_7/extensions/regress-354945-01.js @@ -6,7 +6,7 @@ //----------------------------------------------------------------------------- var BUGNUMBER = 354945; var summary = 'Do not crash with new Iterator'; -var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value'; +var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value'; var actual; diff --git a/js/src/tests/js1_7/extensions/regress-354945-02.js b/js/src/tests/js1_7/extensions/regress-354945-02.js index 261bf7de1..abef90f77 100644 --- a/js/src/tests/js1_7/extensions/regress-354945-02.js +++ b/js/src/tests/js1_7/extensions/regress-354945-02.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value'; + expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value'; var obj = {}; obj.__iterator__ = function(){ }; try diff --git a/js/src/tests/js1_8_5/regress/regress-584355.js b/js/src/tests/js1_8_5/regress/regress-584355.js index 4ddfe65d3..7d1b81a2e 100644 --- a/js/src/tests/js1_8_5/regress/regress-584355.js +++ b/js/src/tests/js1_8_5/regress/regress-584355.js @@ -1,5 +1,5 @@ var actual; -var expect = "function f() { ff (); }"; +var expect = "function f () { ff (); }"; function fun() { (new Function ("function ff () { actual = '' + ff. caller; } function f () { ff (); } f ();")) (); } diff --git a/testing/web-platform/tests/webstorage/storage_string_conversion.html b/testing/web-platform/tests/webstorage/storage_string_conversion.html index 518b27521..c76eddfec 100644 --- a/testing/web-platform/tests/webstorage/storage_string_conversion.html +++ b/testing/web-platform/tests/webstorage/storage_string_conversion.html @@ -22,21 +22,21 @@ storage.b = 0; assert_equals(storage.b, "0"); storage.c = function(){}; - assert_equals(storage.c, "function (){}"); + assert_equals(storage.c, "function(){}"); storage.setItem('d', null); assert_equals(storage.d, "null"); storage.setItem('e', 0); assert_equals(storage.e, "0"); storage.setItem('f', function(){}); - assert_equals(storage.f, "function (){}"); + assert_equals(storage.f, "function(){}"); storage['g'] = null; assert_equals(storage.g, "null"); storage['h'] = 0; assert_equals(storage.h, "0"); storage['i'] = function(){}; - assert_equals(storage.f, "function (){}"); + assert_equals(storage.f, "function(){}"); }, name + " only stores strings"); }); diff --git a/toolkit/modules/tests/xpcshell/test_Log.js b/toolkit/modules/tests/xpcshell/test_Log.js index 429bbcc50..6aee99c93 100644 --- a/toolkit/modules/tests/xpcshell/test_Log.js +++ b/toolkit/modules/tests/xpcshell/test_Log.js @@ -381,12 +381,12 @@ add_task(function* log_message_with_params() { ob = function() {}; ob.toJSON = function() {throw "oh noes JSON"}; do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}), - 'Fail is (function () {})'); + 'Fail is (function() {})'); // Fall back to .toString if both .toJSON and .toSource fail. ob.toSource = function() {throw "oh noes SOURCE"}; do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}), - 'Fail is function () {}'); + 'Fail is function() {}'); // Fall back to '[object]' if .toJSON, .toSource and .toString fail. ob.toString = function() {throw "oh noes STRING"}; @@ -450,7 +450,7 @@ add_task(function* log_message_with_params() { // doesn't cause the logger to fail. let vOf = {a: 1, valueOf: function() {throw "oh noes valueOf"}}; do_check_eq(formatMessage("Broken valueOf ${}", vOf), - 'Broken valueOf ({a:1, valueOf:(function () {throw "oh noes valueOf"})})'); + 'Broken valueOf ({a:1, valueOf:(function() {throw "oh noes valueOf"})})'); // Test edge cases of bad data to formatter: // If 'params' is not an object, format it as a basic type. -- cgit v1.2.3 From 8bbd0d556c0bf583b16076844b9e263a5f996495 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 20:54:29 +0200 Subject: Split Parser::report into Parser::zeport (a temporary name) that uses the current offset, and Parser::reportWithNode that derives it from a Node. --- js/src/frontend/BytecodeEmitter.cpp | 6 +- js/src/frontend/Parser.cpp | 387 +++++++++++++++++------------------- js/src/frontend/Parser.h | 13 +- js/src/frontend/TokenStream.h | 1 + 4 files changed, 198 insertions(+), 209 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c5e62ae34..71289e84a 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3559,9 +3559,11 @@ BytecodeEmitter::maybeSetSourceMap() if (parser->options().sourceMapURL()) { // Warn about the replacement, but use the new one. if (parser->ss->hasSourceMapURL()) { - if(!parser->report(ParseWarning, false, nullptr, JSMSG_ALREADY_HAS_PRAGMA, - parser->ss->filename(), "//# sourceMappingURL")) + if (!parser->reportNoOffset(ParseWarning, false, JSMSG_ALREADY_HAS_PRAGMA, + parser->ss->filename(), "//# sourceMappingURL")) + { return false; + } } if (!parser->ss->setSourceMapURL(cx, parser->options().sourceMapURL())) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 1ba725a82..26b3c2c25 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -69,7 +69,7 @@ using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; if (!tokenStream.getToken(&token, modifier)) \ return null(); \ if (token != tt) { \ - report(ParseError, false, null(), errno); \ + zeport(ParseError, false, errno); \ return null(); \ } \ JS_END_MACRO @@ -596,7 +596,18 @@ Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t o template bool -Parser::report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) +Parser::zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool result = reportHelper(kind, strict, pos().begin, errorNumber, args); + va_end(args); + return result; +} + +template +bool +Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) { uint32_t offset = (pn ? handler.getPosition(pn) : pos()).begin; @@ -826,8 +837,7 @@ Parser::parse() if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, - "script", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); return null(); } if (foldConstants) { @@ -850,7 +860,7 @@ Parser::reportBadReturn(Node pn, ParseReportKind kind, } else { errnum = anonerrnum; } - return report(kind, pc->sc()->strict(), pn, errnum, name.ptr()); + return reportWithNode(kind, pc->sc()->strict(), pn, errnum, name.ptr()); } /* @@ -941,7 +951,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName { if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) { if (disallowDuplicateParams) { - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -953,11 +963,8 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; - if (!report(ParseStrictError, pc->sc()->strict(), null(), - JSMSG_DUPLICATE_FORMAL, bytes.ptr())) - { + if (!zeport(ParseStrictError, pc->sc()->strict(), JSMSG_DUPLICATE_FORMAL, bytes.ptr())) return false; - } } *duplicatedParam = true; @@ -1239,7 +1246,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name); if (p) { - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -1446,8 +1453,7 @@ Parser::checkStatementsEOF() if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return false; if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return false; } return true; @@ -1912,7 +1918,7 @@ Parser::evalBody(EvalSharedContext* evalsc) // script. if (hasUsedName(context->names().arguments)) { if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) { - report(ParseError, false, nullptr, JSMSG_BAD_GENEXP_BODY, js_arguments_str); + zeport(ParseError, false, JSMSG_BAD_GENEXP_BODY, js_arguments_str); return nullptr; } } @@ -2010,7 +2016,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); return null(); } @@ -2330,8 +2336,7 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, - "function body", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); return null(); } @@ -2736,7 +2741,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, firstTokenModifier)) return false; if (tt != TOK_LP) { - report(ParseError, false, null(), + zeport(ParseError, false, kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); return false; } @@ -2769,13 +2774,13 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn AtomVector& positionalFormals = pc->positionalFormalParameterNames(); if (IsGetterKind(kind)) { - report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); return false; } while (true) { if (hasRest) { - report(ParseError, false, null(), JSMSG_PARAMETER_AFTER_REST); + zeport(ParseError, false, JSMSG_PARAMETER_AFTER_REST); return false; } @@ -2787,15 +2792,14 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { - report(ParseError, false, null(), - JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the rest parameter. - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -2806,7 +2810,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { - report(ParseError, false, null(), JSMSG_NO_REST_NAME); + zeport(ParseError, false, JSMSG_NO_REST_NAME); return false; } } @@ -2817,7 +2821,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the destructuring parameter. - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -2845,7 +2849,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // case: // // async await => 1 - report(ParseError, false, null(), JSMSG_RESERVED_ID, "await"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); return false; } @@ -2865,12 +2869,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn } default: - report(ParseError, false, null(), JSMSG_MISSING_FORMAL); + zeport(ParseError, false, JSMSG_MISSING_FORMAL); return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { - report(ParseError, false, null(), JSMSG_TOO_MANY_FUN_ARGS); + zeport(ParseError, false, JSMSG_TOO_MANY_FUN_ARGS); return false; } @@ -2885,12 +2889,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn MOZ_ASSERT(!parenFreeArrow); if (hasRest) { - report(ParseError, false, null(), JSMSG_REST_WITH_DEFAULT); + zeport(ParseError, false, JSMSG_REST_WITH_DEFAULT); return false; } disallowDuplicateParams = true; if (duplicatedParam) { - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -2934,12 +2938,11 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_RP) { if (IsSetterKind(kind)) { - report(ParseError, false, null(), - JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } - report(ParseError, false, null(), JSMSG_PAREN_AFTER_FORMAL); + zeport(ParseError, false, JSMSG_PAREN_AFTER_FORMAL); return false; } } @@ -2952,7 +2955,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn funbox->function()->setArgCount(positionalFormals.length()); } else if (IsSetterKind(kind)) { - report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } @@ -3082,7 +3085,7 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling if (!tokenStream.getToken(&tt)) return false; if (tt != TOK_RC) { - report(ParseError, false, null(), JSMSG_TEMPLSTR_UNTERM_EXPR); + zeport(ParseError, false, JSMSG_TEMPLSTR_UNTERM_EXPR); return false; } @@ -3474,7 +3477,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_ARROW)) return false; if (!matched) { - report(ParseError, false, null(), JSMSG_BAD_ARROW_ARGS); + zeport(ParseError, false, JSMSG_BAD_ARROW_ARGS); return false; } } @@ -3482,7 +3485,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // When parsing something for new Function() we have to make sure to // only treat a certain part of the source as a parameter list. if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_PARAMLIST_END); + zeport(ParseError, false, JSMSG_UNEXPECTED_PARAMLIST_END); return false; } @@ -3495,7 +3498,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || IsConstructorKind(kind)) { - report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY); + zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); return false; } @@ -3504,7 +3507,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!warnOnceAboutExprClosure()) return false; #else - report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY); + zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); return false; #endif } @@ -3537,7 +3540,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) return false; if (!matched) { - report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY); + zeport(ParseError, false, JSMSG_CURLY_AFTER_BODY); return false; } funbox->bufEnd = pos().end; @@ -3595,7 +3598,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3612,7 +3615,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan tokenStream.ungetToken(); } else { /* Unnamed function expressions are forbidden in statement context. */ - report(ParseError, false, null(), JSMSG_UNNAMED_FUNCTION_STMT); + zeport(ParseError, false, JSMSG_UNNAMED_FUNCTION_STMT); return null(); } @@ -3648,7 +3651,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3693,10 +3696,11 @@ template bool Parser::checkUnescapedName() { - if (!tokenStream.currentToken().nameContainsEscape()) + const Token& token = tokenStream.currentToken(); + if (!token.nameContainsEscape()) return true; - report(ParseError, false, null(), JSMSG_ESCAPED_KEYWORD); + reportWithOffset(ParseError, false, token.pos.begin, JSMSG_ESCAPED_KEYWORD); return false; } @@ -3820,7 +3824,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // occur in the directive prologue -- octal escapes -- and // complain now. if (tokenStream.sawOctalEscape()) { - report(ParseError, false, null(), JSMSG_DEPRECATED_OCTAL); + zeport(ParseError, false, JSMSG_DEPRECATED_OCTAL); return false; } pc->sc()->strictScript = true; @@ -3828,7 +3832,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) } else if (directive == context->names().useAsm) { if (pc->isFunctionBox()) return asmJS(list); - return report(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL); + return reportWithNode(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL); } } return true; @@ -3860,10 +3864,8 @@ Parser::statementList(YieldHandling yieldHandling) if (tt == TOK_EOF || tt == TOK_RC) break; if (afterReturn) { - TokenPos pos(0, 0); - if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand)) + if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand)) return null(); - statementBegin = pos.begin; } Node next = statementListItem(yieldHandling, canHaveDirectives); if (!next) { @@ -3909,7 +3911,7 @@ Parser::condition(InHandling inHandling, YieldHandling yieldHandli /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(pn)) { - if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN)) + if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) return null(); } return pn; @@ -3966,7 +3968,8 @@ Parser::PossibleError::hasError(ErrorKind kind) template void -Parser::PossibleError::setPending(ErrorKind kind, Node pn, unsigned errorNumber) +Parser::PossibleError::setPending(ErrorKind kind, const TokenPos& pos, + unsigned errorNumber) { // Don't overwrite a previously recorded error. if (hasError(kind)) @@ -3975,23 +3978,25 @@ Parser::PossibleError::setPending(ErrorKind kind, Node pn, unsigne // If we report an error later, we'll do it from the position where we set // the state to pending. Error& err = error(kind); - err.offset_ = (pn ? parser_.handler.getPosition(pn) : parser_.pos()).begin; + err.offset_ = pos.begin; err.errorNumber_ = errorNumber; err.state_ = ErrorState::Pending; } template void -Parser::PossibleError::setPendingDestructuringError(Node pn, unsigned errorNumber) +Parser::PossibleError::setPendingDestructuringErrorAt(const TokenPos& pos, + unsigned errorNumber) { - setPending(ErrorKind::Destructuring, pn, errorNumber); + setPending(ErrorKind::Destructuring, pos, errorNumber); } template void -Parser::PossibleError::setPendingExpressionError(Node pn, unsigned errorNumber) +Parser::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos, + unsigned errorNumber) { - setPending(ErrorKind::Expression, pn, errorNumber); + setPending(ErrorKind::Expression, pos, errorNumber); } template @@ -4066,7 +4071,7 @@ Parser::checkAssignmentToCall(Node target, unsigned msg) // concerned about sites using this in dead code, so forbid it only in // strict mode code (or if the werror option has been set), and otherwise // warn. - return report(ParseStrictError, pc->sc()->strict(), target, msg); + return reportWithNode(ParseStrictError, pc->sc()->strict(), target, msg); } template <> @@ -4079,7 +4084,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybe::checkDestructuringName(ParseNode* expr, Maybename()); - return noteDeclaredName(name, *maybeDecl, handler.getPosition(expr)); + return noteDeclaredName(name, *maybeDecl, expr->pn_pos); } // Otherwise this is an expression in destructuring outside a declaration. @@ -4171,7 +4176,7 @@ Parser::checkDestructuringArray(ParseNode* arrayPattern, ParseNode* target; if (element->isKind(PNK_SPREAD)) { if (element->pn_next) { - report(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST); + reportWithNode(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST); return false; } target = element->pn_kid; @@ -4234,7 +4239,7 @@ Parser::checkDestructuringPattern(ParseNode* pattern, PossibleError* possibleError /* = nullptr */) { if (pattern->isKind(PNK_ARRAYCOMP)) { - report(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE); + reportWithNode(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE); return false; } @@ -4373,14 +4378,7 @@ Parser::declarationPattern(Node decl, DeclarationKind declKind, To } } - TokenKind token; - if (!tokenStream.getToken(&token, TokenStream::None)) - return null(); - - if (token != TOK_ASSIGN) { - report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_DECL); - return null(); - } + MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL); Node init = assignExpr(forHeadKind ? InProhibited : InAllowed, yieldHandling, TripledotProhibited); @@ -4430,7 +4428,7 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (var/let/const x = ... of ...); // BAD if (isForOf) { - report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); return false; } @@ -4439,15 +4437,15 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (let/const x = ... in ...); // BAD if (DeclarationKindIsLexical(declKind)) { - report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); return false; } // This leaves only initialized for-in |var| declarations. ES6 // forbids these; later ES un-forbids in non-strict mode code. *forHeadKind = PNK_FORIN; - if (!report(ParseStrictError, pc->sc()->strict(), initializer, - JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) + if (!reportWithNode(ParseStrictError, pc->sc()->strict(), initializer, + JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) { return false; } @@ -4495,7 +4493,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token { // Anything other than TOK_YIELD or TOK_NAME is an error. if (tt != TOK_NAME && tt != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME); + zeport(ParseError, false, JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4555,7 +4553,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token // Normal const declarations, and const declarations in for(;;) // heads, must be initialized. if (declKind == DeclarationKind::Const) { - report(ParseError, false, binding, JSMSG_BAD_CONST_DECL); + reportWithNode(ParseError, false, binding, JSMSG_BAD_CONST_DECL); return null(); } } @@ -4695,7 +4693,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_NO_BINDING_NAME); + zeport(ParseError, false, JSMSG_NO_BINDING_NAME); return false; } } else { @@ -4707,7 +4705,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor JSAutoByteString bytes; if (!AtomToPrintableString(context, importName, &bytes)) return false; - report(ParseError, false, null(), JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + zeport(ParseError, false, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); return false; } } @@ -4749,7 +4747,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) { - report(ParseError, false, null(), JSMSG_AS_AFTER_IMPORT_STAR); + reportWithOffset(ParseError, false, pos().begin, JSMSG_AS_AFTER_IMPORT_STAR); return false; } @@ -4804,7 +4802,7 @@ Parser::importDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT); if (!pc->atModuleLevel()) { - report(ParseError, false, null(), JSMSG_IMPORT_DECL_AT_TOP_LEVEL); + zeport(ParseError, false, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4853,7 +4851,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_LC && tt != TOK_MUL) { - report(ParseError, false, null(), JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); + zeport(ParseError, false, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); return null(); } @@ -4869,7 +4867,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - report(ParseError, false, null(), JSMSG_FROM_AFTER_IMPORT_CLAUSE); + zeport(ParseError, false, JSMSG_FROM_AFTER_IMPORT_CLAUSE); return null(); } @@ -4882,7 +4880,7 @@ Parser::importDeclaration() // equivalent to |import {} from 'a'|. importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; } else { - report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_IMPORT); + zeport(ParseError, false, JSMSG_DECLARATION_AFTER_IMPORT); return null(); } @@ -4920,7 +4918,7 @@ Parser::checkExportedName(JSAtom* exportName) if (!AtomToPrintableString(context, exportName, &str)) return false; - report(ParseError, false, null(), JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); + zeport(ParseError, false, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); return false; } @@ -4963,7 +4961,7 @@ Parser::exportDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); if (!pc->atModuleLevel()) { - report(ParseError, false, null(), JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + zeport(ParseError, false, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4996,14 +4994,8 @@ Parser::exportDeclaration() bool foundAs; if (!tokenStream.matchContextualKeyword(&foundAs, context->names().as)) return null(); - if (foundAs) { - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) - return null(); - if (tt != TOK_NAME) { - report(ParseError, false, null(), JSMSG_NO_EXPORT_NAME); - return null(); - } - } + if (foundAs) + MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_EXPORT_NAME); Node exportName = newName(tokenStream.currentName()); if (!exportName) @@ -5088,7 +5080,7 @@ Parser::exportDeclaration() if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - report(ParseError, false, null(), JSMSG_FROM_AFTER_EXPORT_STAR); + zeport(ParseError, false, JSMSG_FROM_AFTER_EXPORT_STAR); return null(); } @@ -5224,7 +5216,7 @@ Parser::exportDeclaration() MOZ_FALLTHROUGH; default: - report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_EXPORT); + zeport(ParseError, false, JSMSG_DECLARATION_AFTER_EXPORT); return null(); } @@ -5300,7 +5292,7 @@ Parser::ifStatement(YieldHandling yieldHandling) if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return null(); if (tt == TOK_SEMI) { - if (!report(ParseExtraWarning, false, null(), JSMSG_EMPTY_CONSEQUENT)) + if (!zeport(ParseExtraWarning, false, JSMSG_EMPTY_CONSEQUENT)) return null(); } @@ -5426,7 +5418,7 @@ Parser::validateForInOrOfLHSExpression(Node target, PossibleError* if (handler.isFunctionCall(target)) return checkAssignmentToCall(target, JSMSG_BAD_FOR_LEFTSIDE); - report(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE); + reportWithNode(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE); return false; } @@ -5547,7 +5539,7 @@ Parser::forHeadStart(YieldHandling yieldHandling, // // See ES6 13.7. if (isForOf && letIsIdentifier) { - report(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS); + reportWithNode(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS); return false; } @@ -5698,7 +5690,7 @@ Parser::forStatement(YieldHandling yieldHandling) iflags |= JSITER_ENUMERATE; } else { if (isForEach) { - report(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP); + reportWithNode(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP); return null(); } @@ -5774,7 +5766,7 @@ Parser::switchStatement(YieldHandling yieldHandling) switch (tt) { case TOK_DEFAULT: if (seenDefault) { - report(ParseError, false, null(), JSMSG_TOO_MANY_DEFAULTS); + zeport(ParseError, false, JSMSG_TOO_MANY_DEFAULTS); return null(); } seenDefault = true; @@ -5788,7 +5780,7 @@ Parser::switchStatement(YieldHandling yieldHandling) break; default: - report(ParseError, false, null(), JSMSG_BAD_SWITCH); + zeport(ParseError, false, JSMSG_BAD_SWITCH); return null(); } @@ -5807,10 +5799,8 @@ Parser::switchStatement(YieldHandling yieldHandling) if (tt == TOK_RC || tt == TOK_CASE || tt == TOK_DEFAULT) break; if (afterReturn) { - TokenPos pos(0, 0); - if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand)) + if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand)) return null(); - statementBegin = pos.begin; } Node stmt = statementListItem(yieldHandling); if (!stmt) @@ -5872,8 +5862,10 @@ Parser::continueStatement(YieldHandling yieldHandling) for (;;) { stmt = ParseContext::Statement::findNearest(stmt, isLoop); if (!stmt) { - report(ParseError, false, null(), - foundLoop ? JSMSG_LABEL_NOT_FOUND : JSMSG_BAD_CONTINUE); + if (foundLoop) + zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); + else + reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); return null(); } @@ -5893,7 +5885,7 @@ Parser::continueStatement(YieldHandling yieldHandling) break; } } else if (!pc->findInnermostStatement(isLoop)) { - report(ParseError, false, null(), JSMSG_BAD_CONTINUE); + zeport(ParseError, false, JSMSG_BAD_CONTINUE); return null(); } @@ -5923,7 +5915,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(hasSameLabel)) { - report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND); + zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); return null(); } } else { @@ -5932,7 +5924,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(isBreakTarget)) { - report(ParseError, false, null(), JSMSG_TOUGH_BREAK); + reportWithOffset(ParseError, false, begin, JSMSG_TOUGH_BREAK); return null(); } } @@ -6082,7 +6074,7 @@ Parser::yieldExpression(InHandling inHandling) return null(); if (!pc->isFunctionBox()) { - report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); + zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return null(); } @@ -6170,7 +6162,7 @@ Parser::withStatement(YieldHandling yieldHandling) // warning under JSOPTION_EXTRA_WARNINGS. See // https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1. if (pc->sc()->strict()) { - if (!report(ParseStrictError, true, null(), JSMSG_STRICT_CODE_WITH)) + if (!zeport(ParseStrictError, true, JSMSG_STRICT_CODE_WITH)) return null(); } @@ -6209,7 +6201,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // GeneratorDeclaration is only matched by HoistableDeclaration in // StatementListItem, so generators can't be inside labels. if (next == TOK_MUL) { - report(ParseError, false, null(), JSMSG_GENERATOR_LABEL); + zeport(ParseError, false, JSMSG_GENERATOR_LABEL); return null(); } @@ -6217,7 +6209,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // is ever matched. Per Annex B.3.2 that modifies this text, this // applies only to strict mode code. if (pc->sc()->strict()) { - report(ParseError, false, null(), JSMSG_FUNCTION_LABEL); + zeport(ParseError, false, JSMSG_FUNCTION_LABEL); return null(); } @@ -6240,13 +6232,13 @@ Parser::labeledStatement(YieldHandling yieldHandling) return stmt->label() == label; }; + uint32_t begin = pos().begin; + if (pc->findInnermostStatement(hasSameLabel)) { - report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL); + reportWithOffset(ParseError, false, begin, JSMSG_DUPLICATE_LABEL); return null(); } - uint32_t begin = pos().begin; - tokenStream.consumeKnownToken(TOK_COLON); /* Push a label struct and parse the statement. */ @@ -6270,11 +6262,11 @@ Parser::throwStatement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { - report(ParseError, false, null(), JSMSG_MISSING_EXPR_AFTER_THROW); + zeport(ParseError, false, JSMSG_MISSING_EXPR_AFTER_THROW); return null(); } if (tt == TOK_EOL) { - report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_THROW); + zeport(ParseError, false, JSMSG_LINE_BREAK_AFTER_THROW); return null(); } @@ -6348,7 +6340,7 @@ Parser::tryStatement(YieldHandling yieldHandling) /* Check for another catch after unconditional catch. */ if (hasUnconditionalCatch) { - report(ParseError, false, null(), JSMSG_CATCH_AFTER_GENERAL); + zeport(ParseError, false, JSMSG_CATCH_AFTER_GENERAL); return null(); } @@ -6396,7 +6388,7 @@ Parser::tryStatement(YieldHandling yieldHandling) } default: - report(ParseError, false, null(), JSMSG_CATCH_IDENTIFIER); + zeport(ParseError, false, JSMSG_CATCH_IDENTIFIER); return null(); } @@ -6464,7 +6456,7 @@ Parser::tryStatement(YieldHandling yieldHandling) tokenStream.ungetToken(); } if (!catchList && !finallyBlock) { - report(ParseError, false, null(), JSMSG_CATCH_OR_FINALLY); + zeport(ParseError, false, JSMSG_CATCH_OR_FINALLY); return null(); } @@ -6609,7 +6601,7 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } else { // Class statements must have a bound name - report(ParseError, false, null(), JSMSG_UNNAMED_CLASS_STMT); + zeport(ParseError, false, JSMSG_UNNAMED_CLASS_STMT); return null(); } } else { @@ -6670,7 +6662,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); if (tt == TOK_RC) { tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } @@ -6702,7 +6694,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF); + zeport(ParseError, false, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6712,17 +6704,17 @@ Parser::classDefinition(YieldHandling yieldHandling, propType = PropertyType::SetterNoExpressionClosure; if (!isStatic && propAtom == context->names().constructor) { if (propType != PropertyType::Method) { - report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); return null(); } if (seenConstructor) { - report(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor"); + reportWithNode(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor"); return null(); } seenConstructor = true; propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor; } else if (isStatic && propAtom == context->names().prototype) { - report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6949,8 +6941,7 @@ Parser::statement(YieldHandling yieldHandling) } if (forbiddenLetDeclaration) { - report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, - "lexical declarations"); + zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); return null(); } } @@ -7004,7 +6995,7 @@ Parser::statement(YieldHandling yieldHandling) // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7032,12 +7023,12 @@ Parser::statement(YieldHandling yieldHandling) // statement of |if| or |else|, but Parser::consequentOrAlternative // handles that). case TOK_FUNCTION: - report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); return null(); // |class| is also forbidden by lookahead restriction. case TOK_CLASS: - report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); + zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); return null(); // ImportDeclaration (only inside modules) @@ -7051,11 +7042,11 @@ Parser::statement(YieldHandling yieldHandling) // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7096,7 +7087,7 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) { if (!abortIfSyntaxParser()) return null(); - if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL)) + if (!zeport(ParseWarning, false, JSMSG_USE_ASM_DIRECTIVE_FAIL)) return null(); } return expressionStatement(yieldHandling); @@ -7190,7 +7181,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7242,11 +7233,11 @@ Parser::statementListItem(YieldHandling yieldHandling, // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7291,8 +7282,8 @@ Parser::expr(InHandling inHandling, YieldHandling yieldHandling, if (!tokenStream.peekToken(&tt)) return null(); if (tt != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(TOK_RP)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -7449,7 +7440,7 @@ Parser::orExpr1(InHandling inHandling, YieldHandling yieldHandling return null(); // Report an error for unary expressions on the LHS of **. if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) { - report(ParseError, false, null(), JSMSG_BAD_POW_LEFTSIDE); + zeport(ParseError, false, JSMSG_BAD_POW_LEFTSIDE); return null(); } pnk = BinaryOpTokenKindToParseNodeKind(tok); @@ -7530,7 +7521,7 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor if (handler.isUnparenthesizedDestructuringPattern(target)) { if (flavor == CompoundAssignment) { - report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_ASS); + zeport(ParseError, false, JSMSG_BAD_DESTRUCT_ASS); return false; } @@ -7669,7 +7660,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt)); return null(); @@ -7708,7 +7699,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL); if (next != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_LINE_BREAK_BEFORE_ARROW); + zeport(ParseError, false, JSMSG_LINE_BREAK_BEFORE_ARROW); return null(); } tokenStream.consumeKnownToken(TOK_ARROW); @@ -7853,10 +7844,11 @@ Parser::reportIfArgumentsEvalTarget(Node nameNode) if (!chars) return true; - if (!report(ParseStrictError, pc->sc()->strict(), nameNode, JSMSG_BAD_STRICT_ASSIGN, chars)) + bool strict = pc->sc()->strict(); + if (!reportWithNode(ParseStrictError, strict, nameNode, JSMSG_BAD_STRICT_ASSIGN, chars)) return false; - MOZ_ASSERT(!pc->sc()->strict(), + MOZ_ASSERT(!strict, "an error should have been reported if this was strict mode " "code"); return true; @@ -7908,7 +7900,7 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign break; } - report(ParseError, pc->sc()->strict(), target, errnum, extra); + reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); return false; } @@ -8014,7 +8006,8 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t // Per spec, deleting any unary expression is valid -- it simply // returns true -- except for one case that is illegal in strict mode. if (handler.isNameAnyParentheses(expr)) { - if (!report(ParseStrictError, pc->sc()->strict(), expr, JSMSG_DEPRECATED_DELETE_OPERAND)) + bool strict = pc->sc()->strict(); + if (!reportWithNode(ParseStrictError, strict, expr, JSMSG_DEPRECATED_DELETE_OPERAND)) return null(); pc->sc()->setBindingsAccessedDynamically(); } @@ -8026,7 +8019,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t if (!pc->isAsync()) { // TOK_AWAIT can be returned in module, even if it's not inside // async function. - report(ParseError, false, null(), JSMSG_RESERVED_ID, "await"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); return null(); } @@ -8179,7 +8172,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, tokenStream.currentName()); if (name == context->names().let) { - report(ParseError, false, null(), JSMSG_LET_COMP_BINDING); + zeport(ParseError, false, JSMSG_LET_COMP_BINDING); return null(); } TokenPos namePos = pos(); @@ -8190,7 +8183,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) return null(); if (!matched) { - report(ParseError, false, null(), JSMSG_OF_AFTER_FOR_NAME); + zeport(ParseError, false, JSMSG_OF_AFTER_FOR_NAME); return null(); } @@ -8251,7 +8244,7 @@ Parser::comprehensionIf(GeneratorKind comprehensionKind) /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(cond)) { - if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN)) + if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) return null(); } @@ -8436,13 +8429,8 @@ Parser::argumentList(YieldHandling yieldHandling, Node listNode, b } } - TokenKind tt; - if (!tokenStream.getToken(&tt)) - return false; - if (tt != TOK_RP) { - report(ParseError, false, null(), JSMSG_PAREN_AFTER_ARGS); - return false; - } + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_ARGS); + handler.setEndPosition(listNode, pos().end); return true; } @@ -8533,14 +8521,14 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (tt == TOK_NAME) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "property"); + zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "property"); return null(); } nextMember = handler.newPropertyAccess(lhs, field, pos().end); if (!nextMember) return null(); } else { - report(ParseError, false, null(), JSMSG_NAME_AFTER_DOT); + zeport(ParseError, false, JSMSG_NAME_AFTER_DOT); return null(); } } else if (tt == TOK_LB) { @@ -8551,7 +8539,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "member"); + zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "member"); return null(); } nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end); @@ -8563,12 +8551,12 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling { if (handler.isSuperBase(lhs)) { if (!pc->sc()->allowSuperCall()) { - report(ParseError, false, null(), JSMSG_BAD_SUPERCALL); + zeport(ParseError, false, JSMSG_BAD_SUPERCALL); return null(); } if (tt != TOK_LP) { - report(ParseError, false, null(), JSMSG_BAD_SUPER); + zeport(ParseError, false, JSMSG_BAD_SUPER); return null(); } @@ -8595,7 +8583,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling return null(); } else { if (options().selfHostingMode && handler.isPropertyAccess(lhs)) { - report(ParseError, false, null(), JSMSG_SELFHOSTED_METHOD_CALL); + zeport(ParseError, false, JSMSG_SELFHOSTED_METHOD_CALL); return null(); } @@ -8677,7 +8665,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling } if (handler.isSuperBase(lhs)) { - report(ParseError, false, null(), JSMSG_BAD_SUPER); + zeport(ParseError, false, JSMSG_BAD_SUPER); return null(); } @@ -8730,7 +8718,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, ? "static" : nullptr; if (badName) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, badName); + zeport(ParseError, false, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8739,7 +8727,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8775,7 +8763,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "eval" : nullptr; if (badName) { - report(ParseError, false, null(), JSMSG_BAD_STRICT_ASSIGN, badName); + zeport(ParseError, false, JSMSG_BAD_STRICT_ASSIGN, badName); return nullptr; } @@ -8785,7 +8773,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "static" : nullptr; if (badName) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, badName); + zeport(ParseError, false, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8794,7 +8782,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8893,7 +8881,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro TokenStream::Modifier modifier = TokenStream::Operand; for (; ; index++) { if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { - report(ParseError, false, null(), JSMSG_ARRAY_INIT_TOO_BIG); + zeport(ParseError, false, JSMSG_ARRAY_INIT_TOO_BIG); return null(); } @@ -8936,7 +8924,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro break; } if (tt == TOK_TRIPLEDOT && possibleError) - possibleError->setPendingDestructuringError(null(), JSMSG_REST_WITH_COMMA); + possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA); } } @@ -9003,7 +8991,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } if (isAsync && isGenerator) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); return null(); } @@ -9116,7 +9104,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } default: - report(ParseError, false, null(), JSMSG_BAD_PROP_ID); + zeport(ParseError, false, JSMSG_BAD_PROP_ID); return null(); } @@ -9126,7 +9114,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_COLON) { if (isGenerator) { - report(ParseError, false, null(), JSMSG_BAD_PROP_ID); + zeport(ParseError, false, JSMSG_BAD_PROP_ID); return null(); } *propType = PropertyType::Normal; @@ -9135,7 +9123,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { if (isGenerator) { - report(ParseError, false, null(), JSMSG_BAD_PROP_ID); + zeport(ParseError, false, JSMSG_BAD_PROP_ID); return null(); } tokenStream.ungetToken(); @@ -9156,7 +9144,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - report(ParseError, false, null(), JSMSG_COLON_AFTER_ID); + zeport(ParseError, false, JSMSG_COLON_AFTER_ID); return null(); } @@ -9231,14 +9219,15 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Directly report the error when we're not in a // destructuring context. if (!possibleError) { - report(ParseError, false, propName, JSMSG_DUPLICATE_PROTO_PROPERTY); + reportWithOffset(ParseError, false, namePos.begin, + JSMSG_DUPLICATE_PROTO_PROPERTY); return null(); } // Otherwise delay error reporting until we've determined // whether or not we're destructuring. - possibleError->setPendingExpressionError(propName, - JSMSG_DUPLICATE_PROTO_PROPERTY); + possibleError->setPendingExpressionErrorAt(namePos, + JSMSG_DUPLICATE_PROTO_PROPERTY); } seenPrototypeMutation = true; @@ -9246,8 +9235,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // __proto__: v mutates [[Prototype]]. Getters, setters, // method/generator definitions, computed property name // versions of all of these, and shorthands do not. - uint32_t begin = handler.getPosition(propName).begin; - if (!handler.addPrototypeMutation(literal, begin, propExpr)) + if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr)) return null(); } else { if (!handler.isConstant(propExpr)) @@ -9267,7 +9255,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9292,7 +9280,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9316,14 +9304,14 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Destructuring defaults are definitely not allowed in this object literal, // because of something the caller knows about the preceding code. // For example, maybe the preceding token is an operator: `x + {y=z}`. - report(ParseError, false, null(), JSMSG_COLON_AFTER_ID); + zeport(ParseError, false, JSMSG_COLON_AFTER_ID); return null(); } // Here we set a pending error so that later in the parse, once we've // determined whether or not we're destructuring, the error can be // reported or ignored appropriately. - possibleError->setPendingExpressionError(null(), JSMSG_COLON_AFTER_ID); + possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID); } Node rhs; @@ -9375,7 +9363,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; if (tt != TOK_COMMA) { - report(ParseError, false, null(), JSMSG_CURLY_AFTER_LIST); + zeport(ParseError, false, JSMSG_CURLY_AFTER_LIST); return null(); } } @@ -9424,8 +9412,7 @@ Parser::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "target", TokenKindToDesc(next)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } @@ -9480,7 +9467,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.peekToken(&next)) return null(); if (next != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -9568,8 +9555,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // name, closing parenthesis, and arrow, and allow it only if all are // present. if (tripledotHandling != TripledotAllowed) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } @@ -9591,7 +9577,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // or "arguments" should be prohibited. Argument-parsing code // handles that. if (next != TOK_NAME && next != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next)); return null(); } @@ -9600,7 +9586,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.getToken(&next)) return null(); if (next != TOK_RP) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next)); return null(); } @@ -9610,7 +9596,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (next != TOK_ARROW) { // Advance the scanner for proper error location reporting. tokenStream.consumeKnownToken(next); - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next)); return null(); } @@ -9622,8 +9608,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling } default: - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } } @@ -9648,7 +9633,7 @@ Parser::warnOnceAboutExprClosure() return true; if (!cx->compartment()->warnedAboutExprClosure) { - if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_EXPR_CLOSURE)) + if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_EXPR_CLOSURE)) return false; cx->compartment()->warnedAboutExprClosure = true; } @@ -9666,7 +9651,7 @@ Parser::warnOnceAboutForEach() if (!cx->compartment()->warnedAboutForEach) { // Disabled warning spew. - // if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_FOR_EACH)) + // if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_FOR_EACH)) // return false; cx->compartment()->warnedAboutForEach = true; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 090931f5b..88d705108 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -769,13 +769,13 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * * Ex: * PossibleError possibleError(*this); - * possibleError.setPendingExpressionError(pn, JSMSG_BAD_PROP_ID); + * possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID); * // A JSMSG_BAD_PROP_ID ParseError is reported, returns false. * if (!possibleError.checkForExpressionError()) * return false; // we reach this point with a pending exception * * PossibleError possibleError(*this); - * possibleError.setPendingExpressionError(pn, JSMSG_BAD_PROP_ID); + * possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID); * // Returns true, no error is reported. * if (!possibleError.checkForDestructuringError()) * return false; // not reached, no pending exception @@ -815,7 +815,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // Set a pending error. Only a single error may be set per instance and // error kind. - void setPending(ErrorKind kind, Node pn, unsigned errorNumber); + void setPending(ErrorKind kind, const TokenPos& pos, unsigned errorNumber); // If there is a pending error, report it and return false, otherwise // return true. @@ -830,12 +830,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // Set a pending destructuring error. Only a single error may be set // per instance, i.e. subsequent calls to this method are ignored and // won't overwrite the existing pending error. - void setPendingDestructuringError(Node pn, unsigned errorNumber); + void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber); // Set a pending expression error. Only a single error may be set per // instance, i.e. subsequent calls to this method are ignored and won't // overwrite the existing pending error. - void setPendingExpressionError(Node pn, unsigned errorNumber); + void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber); // If there is a pending destructuring error, report it and return // false, otherwise return true. Clears any pending expression error. @@ -907,7 +907,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); + bool zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...); + bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, ...); diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 77eea3d81..03a580072 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -577,6 +577,7 @@ class MOZ_STACK_CLASS TokenStream *offset = pos.begin; return true; } + // This is like peekToken(), with one exception: if there is an EOL // between the end of the current token and the start of the next token, it // return true and store TOK_EOL in |*ttp|. In that case, no token with -- cgit v1.2.3 From 68c4eea34dc0ddf680036db62f1b9daeb131cfba Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:01:54 +0200 Subject: Remove the |bool strict| argument from the report-at-current-offset Parser function (zeport). zeport => qeport --- js/src/frontend/Parser.cpp | 256 +++++++++++++++++++++++---------------------- js/src/frontend/Parser.h | 9 +- 2 files changed, 140 insertions(+), 125 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 26b3c2c25..a29287850 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -69,7 +69,7 @@ using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; if (!tokenStream.getToken(&token, modifier)) \ return null(); \ if (token != tt) { \ - zeport(ParseError, false, errno); \ + qeport(ParseError, errno); \ return null(); \ } \ JS_END_MACRO @@ -596,15 +596,26 @@ Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t o template bool -Parser::zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...) +Parser::qeport(ParseReportKind kind, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(kind, strict, pos().begin, errorNumber, args); + bool result = reportHelper(kind, false, pos().begin, errorNumber, args); va_end(args); return result; } +template +bool +Parser::strictModeError(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool res = reportHelper(ParseStrictError, pc->sc()->strict(), pos().begin, errorNumber, args); + va_end(args); + return res; +} + template bool Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) @@ -837,7 +848,7 @@ Parser::parse() if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); return null(); } if (foldConstants) { @@ -951,7 +962,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName { if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) { if (disallowDuplicateParams) { - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -963,7 +974,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; - if (!zeport(ParseStrictError, pc->sc()->strict(), JSMSG_DUPLICATE_FORMAL, bytes.ptr())) + if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.ptr())) return false; } @@ -1246,7 +1257,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name); if (p) { - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -1453,7 +1464,7 @@ Parser::checkStatementsEOF() if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return false; if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return false; } return true; @@ -1918,7 +1929,7 @@ Parser::evalBody(EvalSharedContext* evalsc) // script. if (hasUsedName(context->names().arguments)) { if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) { - zeport(ParseError, false, JSMSG_BAD_GENEXP_BODY, js_arguments_str); + qeport(ParseError, JSMSG_BAD_GENEXP_BODY, js_arguments_str); return nullptr; } } @@ -2016,7 +2027,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); return null(); } @@ -2336,7 +2347,7 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); return null(); } @@ -2741,8 +2752,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, firstTokenModifier)) return false; if (tt != TOK_LP) { - zeport(ParseError, false, - kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); + qeport(ParseError, kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); return false; } @@ -2774,13 +2784,13 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn AtomVector& positionalFormals = pc->positionalFormalParameterNames(); if (IsGetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); return false; } while (true) { if (hasRest) { - zeport(ParseError, false, JSMSG_PARAMETER_AFTER_REST); + qeport(ParseError, JSMSG_PARAMETER_AFTER_REST); return false; } @@ -2792,14 +2802,14 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the rest parameter. - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -2810,7 +2820,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { - zeport(ParseError, false, JSMSG_NO_REST_NAME); + qeport(ParseError, JSMSG_NO_REST_NAME); return false; } } @@ -2821,7 +2831,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the destructuring parameter. - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -2849,7 +2859,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // case: // // async await => 1 - zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); + qeport(ParseError, JSMSG_RESERVED_ID, "await"); return false; } @@ -2869,12 +2879,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn } default: - zeport(ParseError, false, JSMSG_MISSING_FORMAL); + qeport(ParseError, JSMSG_MISSING_FORMAL); return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { - zeport(ParseError, false, JSMSG_TOO_MANY_FUN_ARGS); + qeport(ParseError, JSMSG_TOO_MANY_FUN_ARGS); return false; } @@ -2889,12 +2899,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn MOZ_ASSERT(!parenFreeArrow); if (hasRest) { - zeport(ParseError, false, JSMSG_REST_WITH_DEFAULT); + qeport(ParseError, JSMSG_REST_WITH_DEFAULT); return false; } disallowDuplicateParams = true; if (duplicatedParam) { - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -2938,11 +2948,11 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_RP) { if (IsSetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } - zeport(ParseError, false, JSMSG_PAREN_AFTER_FORMAL); + qeport(ParseError, JSMSG_PAREN_AFTER_FORMAL); return false; } } @@ -2955,7 +2965,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn funbox->function()->setArgCount(positionalFormals.length()); } else if (IsSetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } @@ -3085,7 +3095,7 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling if (!tokenStream.getToken(&tt)) return false; if (tt != TOK_RC) { - zeport(ParseError, false, JSMSG_TEMPLSTR_UNTERM_EXPR); + qeport(ParseError, JSMSG_TEMPLSTR_UNTERM_EXPR); return false; } @@ -3477,7 +3487,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_ARROW)) return false; if (!matched) { - zeport(ParseError, false, JSMSG_BAD_ARROW_ARGS); + qeport(ParseError, JSMSG_BAD_ARROW_ARGS); return false; } } @@ -3485,7 +3495,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // When parsing something for new Function() we have to make sure to // only treat a certain part of the source as a parameter list. if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) { - zeport(ParseError, false, JSMSG_UNEXPECTED_PARAMLIST_END); + qeport(ParseError, JSMSG_UNEXPECTED_PARAMLIST_END); return false; } @@ -3498,7 +3508,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || IsConstructorKind(kind)) { - zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); + qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); return false; } @@ -3507,7 +3517,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!warnOnceAboutExprClosure()) return false; #else - zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); + qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); return false; #endif } @@ -3540,7 +3550,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) return false; if (!matched) { - zeport(ParseError, false, JSMSG_CURLY_AFTER_BODY); + qeport(ParseError, JSMSG_CURLY_AFTER_BODY); return false; } funbox->bufEnd = pos().end; @@ -3598,7 +3608,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); + qeport(ParseError, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3615,7 +3625,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan tokenStream.ungetToken(); } else { /* Unnamed function expressions are forbidden in statement context. */ - zeport(ParseError, false, JSMSG_UNNAMED_FUNCTION_STMT); + qeport(ParseError, JSMSG_UNNAMED_FUNCTION_STMT); return null(); } @@ -3651,7 +3661,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); + qeport(ParseError, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3824,7 +3834,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // occur in the directive prologue -- octal escapes -- and // complain now. if (tokenStream.sawOctalEscape()) { - zeport(ParseError, false, JSMSG_DEPRECATED_OCTAL); + qeport(ParseError, JSMSG_DEPRECATED_OCTAL); return false; } pc->sc()->strictScript = true; @@ -3911,7 +3921,7 @@ Parser::condition(InHandling inHandling, YieldHandling yieldHandli /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(pn)) { - if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) + if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) return null(); } return pn; @@ -4493,7 +4503,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token { // Anything other than TOK_YIELD or TOK_NAME is an error. if (tt != TOK_NAME && tt != TOK_YIELD) { - zeport(ParseError, false, JSMSG_NO_VARIABLE_NAME); + qeport(ParseError, JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4693,7 +4703,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { - zeport(ParseError, false, JSMSG_NO_BINDING_NAME); + qeport(ParseError, JSMSG_NO_BINDING_NAME); return false; } } else { @@ -4705,7 +4715,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor JSAutoByteString bytes; if (!AtomToPrintableString(context, importName, &bytes)) return false; - zeport(ParseError, false, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + qeport(ParseError, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); return false; } } @@ -4802,7 +4812,7 @@ Parser::importDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT); if (!pc->atModuleLevel()) { - zeport(ParseError, false, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); + qeport(ParseError, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4851,7 +4861,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_LC && tt != TOK_MUL) { - zeport(ParseError, false, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); + qeport(ParseError, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); return null(); } @@ -4867,7 +4877,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - zeport(ParseError, false, JSMSG_FROM_AFTER_IMPORT_CLAUSE); + qeport(ParseError, JSMSG_FROM_AFTER_IMPORT_CLAUSE); return null(); } @@ -4880,7 +4890,7 @@ Parser::importDeclaration() // equivalent to |import {} from 'a'|. importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; } else { - zeport(ParseError, false, JSMSG_DECLARATION_AFTER_IMPORT); + qeport(ParseError, JSMSG_DECLARATION_AFTER_IMPORT); return null(); } @@ -4918,7 +4928,7 @@ Parser::checkExportedName(JSAtom* exportName) if (!AtomToPrintableString(context, exportName, &str)) return false; - zeport(ParseError, false, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); + qeport(ParseError, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); return false; } @@ -4961,7 +4971,7 @@ Parser::exportDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); if (!pc->atModuleLevel()) { - zeport(ParseError, false, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + qeport(ParseError, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -5080,7 +5090,7 @@ Parser::exportDeclaration() if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - zeport(ParseError, false, JSMSG_FROM_AFTER_EXPORT_STAR); + qeport(ParseError, JSMSG_FROM_AFTER_EXPORT_STAR); return null(); } @@ -5216,7 +5226,7 @@ Parser::exportDeclaration() MOZ_FALLTHROUGH; default: - zeport(ParseError, false, JSMSG_DECLARATION_AFTER_EXPORT); + qeport(ParseError, JSMSG_DECLARATION_AFTER_EXPORT); return null(); } @@ -5292,7 +5302,7 @@ Parser::ifStatement(YieldHandling yieldHandling) if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return null(); if (tt == TOK_SEMI) { - if (!zeport(ParseExtraWarning, false, JSMSG_EMPTY_CONSEQUENT)) + if (!qeport(ParseExtraWarning, JSMSG_EMPTY_CONSEQUENT)) return null(); } @@ -5766,7 +5776,7 @@ Parser::switchStatement(YieldHandling yieldHandling) switch (tt) { case TOK_DEFAULT: if (seenDefault) { - zeport(ParseError, false, JSMSG_TOO_MANY_DEFAULTS); + qeport(ParseError, JSMSG_TOO_MANY_DEFAULTS); return null(); } seenDefault = true; @@ -5780,7 +5790,7 @@ Parser::switchStatement(YieldHandling yieldHandling) break; default: - zeport(ParseError, false, JSMSG_BAD_SWITCH); + qeport(ParseError, JSMSG_BAD_SWITCH); return null(); } @@ -5863,7 +5873,7 @@ Parser::continueStatement(YieldHandling yieldHandling) stmt = ParseContext::Statement::findNearest(stmt, isLoop); if (!stmt) { if (foundLoop) - zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); + qeport(ParseError, JSMSG_LABEL_NOT_FOUND); else reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); return null(); @@ -5885,7 +5895,7 @@ Parser::continueStatement(YieldHandling yieldHandling) break; } } else if (!pc->findInnermostStatement(isLoop)) { - zeport(ParseError, false, JSMSG_BAD_CONTINUE); + qeport(ParseError, JSMSG_BAD_CONTINUE); return null(); } @@ -5915,7 +5925,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(hasSameLabel)) { - zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); + qeport(ParseError, JSMSG_LABEL_NOT_FOUND); return null(); } } else { @@ -6074,7 +6084,7 @@ Parser::yieldExpression(InHandling inHandling) return null(); if (!pc->isFunctionBox()) { - zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); + qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return null(); } @@ -6155,14 +6165,13 @@ Parser::withStatement(YieldHandling yieldHandling) MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_WITH)); uint32_t begin = pos().begin; - // In most cases, we want the constructs forbidden in strict mode code to be - // a subset of those that JSOPTION_EXTRA_WARNINGS warns about, and we should - // use reportStrictModeError. However, 'with' is the sole instance of a - // construct that is forbidden in strict mode code, but doesn't even merit a - // warning under JSOPTION_EXTRA_WARNINGS. See + // Usually we want the constructs forbidden in strict mode code to be a + // subset of those that ContextOptions::extraWarnings() warns about, and we + // use strictModeError directly. But while 'with' is forbidden in strict + // mode code, it doesn't even merit a warning in non-strict code. See // https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1. if (pc->sc()->strict()) { - if (!zeport(ParseStrictError, true, JSMSG_STRICT_CODE_WITH)) + if (!strictModeError(JSMSG_STRICT_CODE_WITH)) return null(); } @@ -6201,7 +6210,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // GeneratorDeclaration is only matched by HoistableDeclaration in // StatementListItem, so generators can't be inside labels. if (next == TOK_MUL) { - zeport(ParseError, false, JSMSG_GENERATOR_LABEL); + qeport(ParseError, JSMSG_GENERATOR_LABEL); return null(); } @@ -6209,7 +6218,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // is ever matched. Per Annex B.3.2 that modifies this text, this // applies only to strict mode code. if (pc->sc()->strict()) { - zeport(ParseError, false, JSMSG_FUNCTION_LABEL); + qeport(ParseError, JSMSG_FUNCTION_LABEL); return null(); } @@ -6262,11 +6271,11 @@ Parser::throwStatement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { - zeport(ParseError, false, JSMSG_MISSING_EXPR_AFTER_THROW); + qeport(ParseError, JSMSG_MISSING_EXPR_AFTER_THROW); return null(); } if (tt == TOK_EOL) { - zeport(ParseError, false, JSMSG_LINE_BREAK_AFTER_THROW); + qeport(ParseError, JSMSG_LINE_BREAK_AFTER_THROW); return null(); } @@ -6340,7 +6349,7 @@ Parser::tryStatement(YieldHandling yieldHandling) /* Check for another catch after unconditional catch. */ if (hasUnconditionalCatch) { - zeport(ParseError, false, JSMSG_CATCH_AFTER_GENERAL); + qeport(ParseError, JSMSG_CATCH_AFTER_GENERAL); return null(); } @@ -6388,7 +6397,7 @@ Parser::tryStatement(YieldHandling yieldHandling) } default: - zeport(ParseError, false, JSMSG_CATCH_IDENTIFIER); + qeport(ParseError, JSMSG_CATCH_IDENTIFIER); return null(); } @@ -6456,7 +6465,7 @@ Parser::tryStatement(YieldHandling yieldHandling) tokenStream.ungetToken(); } if (!catchList && !finallyBlock) { - zeport(ParseError, false, JSMSG_CATCH_OR_FINALLY); + qeport(ParseError, JSMSG_CATCH_OR_FINALLY); return null(); } @@ -6601,7 +6610,7 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } else { // Class statements must have a bound name - zeport(ParseError, false, JSMSG_UNNAMED_CLASS_STMT); + qeport(ParseError, JSMSG_UNNAMED_CLASS_STMT); return null(); } } else { @@ -6662,8 +6671,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); if (tt == TOK_RC) { tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, - "property name", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } @@ -6694,7 +6702,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - zeport(ParseError, false, JSMSG_BAD_METHOD_DEF); + qeport(ParseError, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6941,7 +6949,7 @@ Parser::statement(YieldHandling yieldHandling) } if (forbiddenLetDeclaration) { - zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); + qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); return null(); } } @@ -6995,7 +7003,7 @@ Parser::statement(YieldHandling yieldHandling) // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7023,12 +7031,12 @@ Parser::statement(YieldHandling yieldHandling) // statement of |if| or |else|, but Parser::consequentOrAlternative // handles that). case TOK_FUNCTION: - zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); return null(); // |class| is also forbidden by lookahead restriction. case TOK_CLASS: - zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); + qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); return null(); // ImportDeclaration (only inside modules) @@ -7042,11 +7050,11 @@ Parser::statement(YieldHandling yieldHandling) // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); + qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); + qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7087,7 +7095,7 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) { if (!abortIfSyntaxParser()) return null(); - if (!zeport(ParseWarning, false, JSMSG_USE_ASM_DIRECTIVE_FAIL)) + if (!qeport(ParseWarning, JSMSG_USE_ASM_DIRECTIVE_FAIL)) return null(); } return expressionStatement(yieldHandling); @@ -7181,7 +7189,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7233,11 +7241,11 @@ Parser::statementListItem(YieldHandling yieldHandling, // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); + qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); + qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7282,7 +7290,7 @@ Parser::expr(InHandling inHandling, YieldHandling yieldHandling, if (!tokenStream.peekToken(&tt)) return null(); if (tt != TOK_ARROW) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -7440,7 +7448,7 @@ Parser::orExpr1(InHandling inHandling, YieldHandling yieldHandling return null(); // Report an error for unary expressions on the LHS of **. if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) { - zeport(ParseError, false, JSMSG_BAD_POW_LEFTSIDE); + qeport(ParseError, JSMSG_BAD_POW_LEFTSIDE); return null(); } pnk = BinaryOpTokenKindToParseNodeKind(tok); @@ -7521,7 +7529,7 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor if (handler.isUnparenthesizedDestructuringPattern(target)) { if (flavor == CompoundAssignment) { - zeport(ParseError, false, JSMSG_BAD_DESTRUCT_ASS); + qeport(ParseError, JSMSG_BAD_DESTRUCT_ASS); return false; } @@ -7660,7 +7668,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_ARROW) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt)); return null(); @@ -7699,7 +7707,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL); if (next != TOK_ARROW) { - zeport(ParseError, false, JSMSG_LINE_BREAK_BEFORE_ARROW); + qeport(ParseError, JSMSG_LINE_BREAK_BEFORE_ARROW); return null(); } tokenStream.consumeKnownToken(TOK_ARROW); @@ -8019,7 +8027,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t if (!pc->isAsync()) { // TOK_AWAIT can be returned in module, even if it's not inside // async function. - zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); + qeport(ParseError, JSMSG_RESERVED_ID, "await"); return null(); } @@ -8172,7 +8180,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, tokenStream.currentName()); if (name == context->names().let) { - zeport(ParseError, false, JSMSG_LET_COMP_BINDING); + qeport(ParseError, JSMSG_LET_COMP_BINDING); return null(); } TokenPos namePos = pos(); @@ -8183,7 +8191,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) return null(); if (!matched) { - zeport(ParseError, false, JSMSG_OF_AFTER_FOR_NAME); + qeport(ParseError, JSMSG_OF_AFTER_FOR_NAME); return null(); } @@ -8244,7 +8252,7 @@ Parser::comprehensionIf(GeneratorKind comprehensionKind) /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(cond)) { - if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) + if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) return null(); } @@ -8521,14 +8529,14 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (tt == TOK_NAME) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "property"); + qeport(ParseError, JSMSG_BAD_SUPERPROP, "property"); return null(); } nextMember = handler.newPropertyAccess(lhs, field, pos().end); if (!nextMember) return null(); } else { - zeport(ParseError, false, JSMSG_NAME_AFTER_DOT); + qeport(ParseError, JSMSG_NAME_AFTER_DOT); return null(); } } else if (tt == TOK_LB) { @@ -8539,7 +8547,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "member"); + qeport(ParseError, JSMSG_BAD_SUPERPROP, "member"); return null(); } nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end); @@ -8551,12 +8559,12 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling { if (handler.isSuperBase(lhs)) { if (!pc->sc()->allowSuperCall()) { - zeport(ParseError, false, JSMSG_BAD_SUPERCALL); + qeport(ParseError, JSMSG_BAD_SUPERCALL); return null(); } if (tt != TOK_LP) { - zeport(ParseError, false, JSMSG_BAD_SUPER); + qeport(ParseError, JSMSG_BAD_SUPER); return null(); } @@ -8583,7 +8591,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling return null(); } else { if (options().selfHostingMode && handler.isPropertyAccess(lhs)) { - zeport(ParseError, false, JSMSG_SELFHOSTED_METHOD_CALL); + qeport(ParseError, JSMSG_SELFHOSTED_METHOD_CALL); return null(); } @@ -8665,7 +8673,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling } if (handler.isSuperBase(lhs)) { - zeport(ParseError, false, JSMSG_BAD_SUPER); + qeport(ParseError, JSMSG_BAD_SUPER); return null(); } @@ -8718,7 +8726,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, ? "static" : nullptr; if (badName) { - zeport(ParseError, false, JSMSG_RESERVED_ID, badName); + qeport(ParseError, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8727,7 +8735,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); + qeport(ParseError, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8763,7 +8771,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "eval" : nullptr; if (badName) { - zeport(ParseError, false, JSMSG_BAD_STRICT_ASSIGN, badName); + qeport(ParseError, JSMSG_BAD_STRICT_ASSIGN, badName); return nullptr; } @@ -8773,7 +8781,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "static" : nullptr; if (badName) { - zeport(ParseError, false, JSMSG_RESERVED_ID, badName); + qeport(ParseError, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8782,7 +8790,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); + qeport(ParseError, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8881,7 +8889,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro TokenStream::Modifier modifier = TokenStream::Operand; for (; ; index++) { if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { - zeport(ParseError, false, JSMSG_ARRAY_INIT_TOO_BIG); + qeport(ParseError, JSMSG_ARRAY_INIT_TOO_BIG); return null(); } @@ -8991,7 +8999,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } if (isAsync && isGenerator) { - zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); + qeport(ParseError, JSMSG_ASYNC_GENERATOR); return null(); } @@ -9104,7 +9112,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } default: - zeport(ParseError, false, JSMSG_BAD_PROP_ID); + qeport(ParseError, JSMSG_BAD_PROP_ID); return null(); } @@ -9114,7 +9122,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_COLON) { if (isGenerator) { - zeport(ParseError, false, JSMSG_BAD_PROP_ID); + qeport(ParseError, JSMSG_BAD_PROP_ID); return null(); } *propType = PropertyType::Normal; @@ -9123,7 +9131,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { if (isGenerator) { - zeport(ParseError, false, JSMSG_BAD_PROP_ID); + qeport(ParseError, JSMSG_BAD_PROP_ID); return null(); } tokenStream.ungetToken(); @@ -9144,7 +9152,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - zeport(ParseError, false, JSMSG_COLON_AFTER_ID); + qeport(ParseError, JSMSG_COLON_AFTER_ID); return null(); } @@ -9255,7 +9263,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9280,7 +9288,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9304,7 +9312,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Destructuring defaults are definitely not allowed in this object literal, // because of something the caller knows about the preceding code. // For example, maybe the preceding token is an operator: `x + {y=z}`. - zeport(ParseError, false, JSMSG_COLON_AFTER_ID); + qeport(ParseError, JSMSG_COLON_AFTER_ID); return null(); } @@ -9363,7 +9371,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; if (tt != TOK_COMMA) { - zeport(ParseError, false, JSMSG_CURLY_AFTER_LIST); + qeport(ParseError, JSMSG_CURLY_AFTER_LIST); return null(); } } @@ -9412,7 +9420,7 @@ Parser::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } @@ -9467,7 +9475,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.peekToken(&next)) return null(); if (next != TOK_ARROW) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -9555,7 +9563,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // name, closing parenthesis, and arrow, and allow it only if all are // present. if (tripledotHandling != TripledotAllowed) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } @@ -9577,8 +9585,8 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // or "arguments" should be prohibited. Argument-parsing code // handles that. if (next != TOK_NAME && next != TOK_YIELD) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, - "rest argument name", TokenKindToDesc(next)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, + "rest argument name", TokenKindToDesc(next)); return null(); } } @@ -9586,7 +9594,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.getToken(&next)) return null(); if (next != TOK_RP) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next)); return null(); } @@ -9596,7 +9604,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (next != TOK_ARROW) { // Advance the scanner for proper error location reporting. tokenStream.consumeKnownToken(next); - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next)); return null(); } @@ -9608,7 +9616,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling } default: - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } } @@ -9633,7 +9641,7 @@ Parser::warnOnceAboutExprClosure() return true; if (!cx->compartment()->warnedAboutExprClosure) { - if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_EXPR_CLOSURE)) + if (!qeport(ParseWarning, JSMSG_DEPRECATED_EXPR_CLOSURE)) return false; cx->compartment()->warnedAboutExprClosure = true; } @@ -9651,7 +9659,7 @@ Parser::warnOnceAboutForEach() if (!cx->compartment()->warnedAboutForEach) { // Disabled warning spew. - // if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_FOR_EACH)) + // if (!qeport(ParseWarning, JSMSG_DEPRECATED_FOR_EACH)) // return false; cx->compartment()->warnedAboutForEach = true; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 88d705108..402b977ba 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -907,12 +907,19 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...); + bool qeport(ParseReportKind kind, unsigned errorNumber, ...); bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, ...); + /* + * Handle a strict mode error at the current offset. Report an error if in + * strict mode code, or warn if not, using the given error number and + * arguments. + */ + MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames, Parser* syntaxParser, LazyScript* lazyOuterFunction); -- cgit v1.2.3 From 2950deb043a403377a589046acaa38cfe3dc9876 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:25:28 +0200 Subject: Change report at current offset to warning(), extraWarning() and error() --- js/src/frontend/Parser.cpp | 261 ++++++++++++++++++++++++--------------------- js/src/frontend/Parser.h | 13 ++- 2 files changed, 152 insertions(+), 122 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a29287850..8ad8813b5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -63,13 +63,13 @@ using BindingIter = ParseContext::Scope::BindingIter; using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; /* Read a token. Report an error and return null() if that token isn't of type tt. */ -#define MUST_MATCH_TOKEN_MOD(tt, modifier, errno) \ +#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \ JS_BEGIN_MACRO \ TokenKind token; \ if (!tokenStream.getToken(&token, modifier)) \ return null(); \ if (token != tt) { \ - qeport(ParseError, errno); \ + error(errorNumber); \ return null(); \ } \ JS_END_MACRO @@ -594,13 +594,38 @@ Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t o return result; } +template +void +Parser::error(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + reportHelper(ParseError, false, pos().begin, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + +template +bool +Parser::warning(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool result = reportHelper(ParseWarning, false, pos().begin, errorNumber, args); + va_end(args); + return result; +} + template bool -Parser::qeport(ParseReportKind kind, unsigned errorNumber, ...) +Parser::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(kind, false, pos().begin, errorNumber, args); + bool result = reportHelper(ParseExtraWarning, false, pos().begin, errorNumber, args); va_end(args); return result; } @@ -848,7 +873,7 @@ Parser::parse() if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); + error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); return null(); } if (foldConstants) { @@ -962,7 +987,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName { if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) { if (disallowDuplicateParams) { - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -1257,7 +1282,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name); if (p) { - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -1464,7 +1489,7 @@ Parser::checkStatementsEOF() if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return false; if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return false; } return true; @@ -1929,7 +1954,7 @@ Parser::evalBody(EvalSharedContext* evalsc) // script. if (hasUsedName(context->names().arguments)) { if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) { - qeport(ParseError, JSMSG_BAD_GENEXP_BODY, js_arguments_str); + error(JSMSG_BAD_GENEXP_BODY, js_arguments_str); return nullptr; } } @@ -2027,7 +2052,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); + error(JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); return null(); } @@ -2347,7 +2372,7 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); + error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); return null(); } @@ -2752,7 +2777,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, firstTokenModifier)) return false; if (tt != TOK_LP) { - qeport(ParseError, kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); + error(kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); return false; } @@ -2784,13 +2809,13 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn AtomVector& positionalFormals = pc->positionalFormalParameterNames(); if (IsGetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); + error(JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); return false; } while (true) { if (hasRest) { - qeport(ParseError, JSMSG_PARAMETER_AFTER_REST); + error(JSMSG_PARAMETER_AFTER_REST); return false; } @@ -2802,14 +2827,14 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the rest parameter. - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -2820,7 +2845,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { - qeport(ParseError, JSMSG_NO_REST_NAME); + error(JSMSG_NO_REST_NAME); return false; } } @@ -2831,7 +2856,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the destructuring parameter. - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -2859,7 +2884,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // case: // // async await => 1 - qeport(ParseError, JSMSG_RESERVED_ID, "await"); + error(JSMSG_RESERVED_ID, "await"); return false; } @@ -2879,12 +2904,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn } default: - qeport(ParseError, JSMSG_MISSING_FORMAL); + error(JSMSG_MISSING_FORMAL); return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { - qeport(ParseError, JSMSG_TOO_MANY_FUN_ARGS); + error(JSMSG_TOO_MANY_FUN_ARGS); return false; } @@ -2899,12 +2924,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn MOZ_ASSERT(!parenFreeArrow); if (hasRest) { - qeport(ParseError, JSMSG_REST_WITH_DEFAULT); + error(JSMSG_REST_WITH_DEFAULT); return false; } disallowDuplicateParams = true; if (duplicatedParam) { - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -2948,11 +2973,11 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_RP) { if (IsSetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } - qeport(ParseError, JSMSG_PAREN_AFTER_FORMAL); + error(JSMSG_PAREN_AFTER_FORMAL); return false; } } @@ -2965,7 +2990,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn funbox->function()->setArgCount(positionalFormals.length()); } else if (IsSetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } @@ -3095,7 +3120,7 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling if (!tokenStream.getToken(&tt)) return false; if (tt != TOK_RC) { - qeport(ParseError, JSMSG_TEMPLSTR_UNTERM_EXPR); + error(JSMSG_TEMPLSTR_UNTERM_EXPR); return false; } @@ -3487,7 +3512,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_ARROW)) return false; if (!matched) { - qeport(ParseError, JSMSG_BAD_ARROW_ARGS); + error(JSMSG_BAD_ARROW_ARGS); return false; } } @@ -3495,7 +3520,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // When parsing something for new Function() we have to make sure to // only treat a certain part of the source as a parameter list. if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) { - qeport(ParseError, JSMSG_UNEXPECTED_PARAMLIST_END); + error(JSMSG_UNEXPECTED_PARAMLIST_END); return false; } @@ -3508,7 +3533,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || IsConstructorKind(kind)) { - qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); + error(JSMSG_CURLY_BEFORE_BODY); return false; } @@ -3517,7 +3542,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!warnOnceAboutExprClosure()) return false; #else - qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); + error(JSMSG_CURLY_BEFORE_BODY); return false; #endif } @@ -3550,7 +3575,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) return false; if (!matched) { - qeport(ParseError, JSMSG_CURLY_AFTER_BODY); + error(JSMSG_CURLY_AFTER_BODY); return false; } funbox->bufEnd = pos().end; @@ -3608,7 +3633,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - qeport(ParseError, JSMSG_ASYNC_GENERATOR); + error(JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3625,7 +3650,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan tokenStream.ungetToken(); } else { /* Unnamed function expressions are forbidden in statement context. */ - qeport(ParseError, JSMSG_UNNAMED_FUNCTION_STMT); + error(JSMSG_UNNAMED_FUNCTION_STMT); return null(); } @@ -3661,7 +3686,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - qeport(ParseError, JSMSG_ASYNC_GENERATOR); + error(JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3834,7 +3859,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // occur in the directive prologue -- octal escapes -- and // complain now. if (tokenStream.sawOctalEscape()) { - qeport(ParseError, JSMSG_DEPRECATED_OCTAL); + error(JSMSG_DEPRECATED_OCTAL); return false; } pc->sc()->strictScript = true; @@ -3921,7 +3946,7 @@ Parser::condition(InHandling inHandling, YieldHandling yieldHandli /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(pn)) { - if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) + if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN)) return null(); } return pn; @@ -4503,7 +4528,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token { // Anything other than TOK_YIELD or TOK_NAME is an error. if (tt != TOK_NAME && tt != TOK_YIELD) { - qeport(ParseError, JSMSG_NO_VARIABLE_NAME); + error(JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4703,7 +4728,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { - qeport(ParseError, JSMSG_NO_BINDING_NAME); + error(JSMSG_NO_BINDING_NAME); return false; } } else { @@ -4715,7 +4740,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor JSAutoByteString bytes; if (!AtomToPrintableString(context, importName, &bytes)) return false; - qeport(ParseError, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + error(JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); return false; } } @@ -4812,7 +4837,7 @@ Parser::importDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT); if (!pc->atModuleLevel()) { - qeport(ParseError, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); + error(JSMSG_IMPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4861,7 +4886,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_LC && tt != TOK_MUL) { - qeport(ParseError, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); + error(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); return null(); } @@ -4877,7 +4902,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - qeport(ParseError, JSMSG_FROM_AFTER_IMPORT_CLAUSE); + error(JSMSG_FROM_AFTER_IMPORT_CLAUSE); return null(); } @@ -4890,7 +4915,7 @@ Parser::importDeclaration() // equivalent to |import {} from 'a'|. importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; } else { - qeport(ParseError, JSMSG_DECLARATION_AFTER_IMPORT); + error(JSMSG_DECLARATION_AFTER_IMPORT); return null(); } @@ -4928,7 +4953,7 @@ Parser::checkExportedName(JSAtom* exportName) if (!AtomToPrintableString(context, exportName, &str)) return false; - qeport(ParseError, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); + error(JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); return false; } @@ -4971,7 +4996,7 @@ Parser::exportDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); if (!pc->atModuleLevel()) { - qeport(ParseError, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -5090,7 +5115,7 @@ Parser::exportDeclaration() if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - qeport(ParseError, JSMSG_FROM_AFTER_EXPORT_STAR); + error(JSMSG_FROM_AFTER_EXPORT_STAR); return null(); } @@ -5226,7 +5251,7 @@ Parser::exportDeclaration() MOZ_FALLTHROUGH; default: - qeport(ParseError, JSMSG_DECLARATION_AFTER_EXPORT); + error(JSMSG_DECLARATION_AFTER_EXPORT); return null(); } @@ -5302,7 +5327,7 @@ Parser::ifStatement(YieldHandling yieldHandling) if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return null(); if (tt == TOK_SEMI) { - if (!qeport(ParseExtraWarning, JSMSG_EMPTY_CONSEQUENT)) + if (!extraWarning(JSMSG_EMPTY_CONSEQUENT)) return null(); } @@ -5776,7 +5801,7 @@ Parser::switchStatement(YieldHandling yieldHandling) switch (tt) { case TOK_DEFAULT: if (seenDefault) { - qeport(ParseError, JSMSG_TOO_MANY_DEFAULTS); + error(JSMSG_TOO_MANY_DEFAULTS); return null(); } seenDefault = true; @@ -5790,7 +5815,7 @@ Parser::switchStatement(YieldHandling yieldHandling) break; default: - qeport(ParseError, JSMSG_BAD_SWITCH); + error(JSMSG_BAD_SWITCH); return null(); } @@ -5873,7 +5898,7 @@ Parser::continueStatement(YieldHandling yieldHandling) stmt = ParseContext::Statement::findNearest(stmt, isLoop); if (!stmt) { if (foundLoop) - qeport(ParseError, JSMSG_LABEL_NOT_FOUND); + error(JSMSG_LABEL_NOT_FOUND); else reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); return null(); @@ -5895,7 +5920,7 @@ Parser::continueStatement(YieldHandling yieldHandling) break; } } else if (!pc->findInnermostStatement(isLoop)) { - qeport(ParseError, JSMSG_BAD_CONTINUE); + error(JSMSG_BAD_CONTINUE); return null(); } @@ -5925,7 +5950,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(hasSameLabel)) { - qeport(ParseError, JSMSG_LABEL_NOT_FOUND); + error(JSMSG_LABEL_NOT_FOUND); return null(); } } else { @@ -6084,7 +6109,7 @@ Parser::yieldExpression(InHandling inHandling) return null(); if (!pc->isFunctionBox()) { - qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); + error(JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return null(); } @@ -6210,7 +6235,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // GeneratorDeclaration is only matched by HoistableDeclaration in // StatementListItem, so generators can't be inside labels. if (next == TOK_MUL) { - qeport(ParseError, JSMSG_GENERATOR_LABEL); + error(JSMSG_GENERATOR_LABEL); return null(); } @@ -6218,7 +6243,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // is ever matched. Per Annex B.3.2 that modifies this text, this // applies only to strict mode code. if (pc->sc()->strict()) { - qeport(ParseError, JSMSG_FUNCTION_LABEL); + error(JSMSG_FUNCTION_LABEL); return null(); } @@ -6271,11 +6296,11 @@ Parser::throwStatement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { - qeport(ParseError, JSMSG_MISSING_EXPR_AFTER_THROW); + error(JSMSG_MISSING_EXPR_AFTER_THROW); return null(); } if (tt == TOK_EOL) { - qeport(ParseError, JSMSG_LINE_BREAK_AFTER_THROW); + error(JSMSG_LINE_BREAK_AFTER_THROW); return null(); } @@ -6349,7 +6374,7 @@ Parser::tryStatement(YieldHandling yieldHandling) /* Check for another catch after unconditional catch. */ if (hasUnconditionalCatch) { - qeport(ParseError, JSMSG_CATCH_AFTER_GENERAL); + error(JSMSG_CATCH_AFTER_GENERAL); return null(); } @@ -6397,7 +6422,7 @@ Parser::tryStatement(YieldHandling yieldHandling) } default: - qeport(ParseError, JSMSG_CATCH_IDENTIFIER); + error(JSMSG_CATCH_IDENTIFIER); return null(); } @@ -6465,7 +6490,7 @@ Parser::tryStatement(YieldHandling yieldHandling) tokenStream.ungetToken(); } if (!catchList && !finallyBlock) { - qeport(ParseError, JSMSG_CATCH_OR_FINALLY); + error(JSMSG_CATCH_OR_FINALLY); return null(); } @@ -6610,7 +6635,7 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } else { // Class statements must have a bound name - qeport(ParseError, JSMSG_UNNAMED_CLASS_STMT); + error(JSMSG_UNNAMED_CLASS_STMT); return null(); } } else { @@ -6671,7 +6696,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); if (tt == TOK_RC) { tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } @@ -6702,7 +6727,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - qeport(ParseError, JSMSG_BAD_METHOD_DEF); + error(JSMSG_BAD_METHOD_DEF); return null(); } @@ -6949,7 +6974,7 @@ Parser::statement(YieldHandling yieldHandling) } if (forbiddenLetDeclaration) { - qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); + error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); return null(); } } @@ -7003,7 +7028,7 @@ Parser::statement(YieldHandling yieldHandling) // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7031,12 +7056,12 @@ Parser::statement(YieldHandling yieldHandling) // statement of |if| or |else|, but Parser::consequentOrAlternative // handles that). case TOK_FUNCTION: - qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); return null(); // |class| is also forbidden by lookahead restriction. case TOK_CLASS: - qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); + error(JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); return null(); // ImportDeclaration (only inside modules) @@ -7050,11 +7075,11 @@ Parser::statement(YieldHandling yieldHandling) // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); + error(JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); + error(JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7095,7 +7120,7 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) { if (!abortIfSyntaxParser()) return null(); - if (!qeport(ParseWarning, JSMSG_USE_ASM_DIRECTIVE_FAIL)) + if (!warning(JSMSG_USE_ASM_DIRECTIVE_FAIL)) return null(); } return expressionStatement(yieldHandling); @@ -7189,7 +7214,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7241,11 +7266,11 @@ Parser::statementListItem(YieldHandling yieldHandling, // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); + error(JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); + error(JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7290,8 +7315,7 @@ Parser::expr(InHandling inHandling, YieldHandling yieldHandling, if (!tokenStream.peekToken(&tt)) return null(); if (tt != TOK_ARROW) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(TOK_RP)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -7448,7 +7472,7 @@ Parser::orExpr1(InHandling inHandling, YieldHandling yieldHandling return null(); // Report an error for unary expressions on the LHS of **. if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) { - qeport(ParseError, JSMSG_BAD_POW_LEFTSIDE); + error(JSMSG_BAD_POW_LEFTSIDE); return null(); } pnk = BinaryOpTokenKindToParseNodeKind(tok); @@ -7529,7 +7553,7 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor if (handler.isUnparenthesizedDestructuringPattern(target)) { if (flavor == CompoundAssignment) { - qeport(ParseError, JSMSG_BAD_DESTRUCT_ASS); + error(JSMSG_BAD_DESTRUCT_ASS); return false; } @@ -7668,8 +7692,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_ARROW) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "'=>' after argument list", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt)); return null(); } @@ -7707,7 +7730,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL); if (next != TOK_ARROW) { - qeport(ParseError, JSMSG_LINE_BREAK_BEFORE_ARROW); + error(JSMSG_LINE_BREAK_BEFORE_ARROW); return null(); } tokenStream.consumeKnownToken(TOK_ARROW); @@ -8027,7 +8050,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t if (!pc->isAsync()) { // TOK_AWAIT can be returned in module, even if it's not inside // async function. - qeport(ParseError, JSMSG_RESERVED_ID, "await"); + error(JSMSG_RESERVED_ID, "await"); return null(); } @@ -8180,7 +8203,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, tokenStream.currentName()); if (name == context->names().let) { - qeport(ParseError, JSMSG_LET_COMP_BINDING); + error(JSMSG_LET_COMP_BINDING); return null(); } TokenPos namePos = pos(); @@ -8191,7 +8214,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) return null(); if (!matched) { - qeport(ParseError, JSMSG_OF_AFTER_FOR_NAME); + error(JSMSG_OF_AFTER_FOR_NAME); return null(); } @@ -8252,7 +8275,7 @@ Parser::comprehensionIf(GeneratorKind comprehensionKind) /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(cond)) { - if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) + if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN)) return null(); } @@ -8529,14 +8552,14 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (tt == TOK_NAME) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - qeport(ParseError, JSMSG_BAD_SUPERPROP, "property"); + error(JSMSG_BAD_SUPERPROP, "property"); return null(); } nextMember = handler.newPropertyAccess(lhs, field, pos().end); if (!nextMember) return null(); } else { - qeport(ParseError, JSMSG_NAME_AFTER_DOT); + error(JSMSG_NAME_AFTER_DOT); return null(); } } else if (tt == TOK_LB) { @@ -8547,7 +8570,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - qeport(ParseError, JSMSG_BAD_SUPERPROP, "member"); + error(JSMSG_BAD_SUPERPROP, "member"); return null(); } nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end); @@ -8559,12 +8582,12 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling { if (handler.isSuperBase(lhs)) { if (!pc->sc()->allowSuperCall()) { - qeport(ParseError, JSMSG_BAD_SUPERCALL); + error(JSMSG_BAD_SUPERCALL); return null(); } if (tt != TOK_LP) { - qeport(ParseError, JSMSG_BAD_SUPER); + error(JSMSG_BAD_SUPER); return null(); } @@ -8591,7 +8614,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling return null(); } else { if (options().selfHostingMode && handler.isPropertyAccess(lhs)) { - qeport(ParseError, JSMSG_SELFHOSTED_METHOD_CALL); + error(JSMSG_SELFHOSTED_METHOD_CALL); return null(); } @@ -8673,7 +8696,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling } if (handler.isSuperBase(lhs)) { - qeport(ParseError, JSMSG_BAD_SUPER); + error(JSMSG_BAD_SUPER); return null(); } @@ -8726,7 +8749,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, ? "static" : nullptr; if (badName) { - qeport(ParseError, JSMSG_RESERVED_ID, badName); + error(JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8735,7 +8758,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - qeport(ParseError, JSMSG_RESERVED_ID, "yield"); + error(JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8771,7 +8794,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "eval" : nullptr; if (badName) { - qeport(ParseError, JSMSG_BAD_STRICT_ASSIGN, badName); + error(JSMSG_BAD_STRICT_ASSIGN, badName); return nullptr; } @@ -8781,7 +8804,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "static" : nullptr; if (badName) { - qeport(ParseError, JSMSG_RESERVED_ID, badName); + error(JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8790,7 +8813,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - qeport(ParseError, JSMSG_RESERVED_ID, "yield"); + error(JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8889,7 +8912,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro TokenStream::Modifier modifier = TokenStream::Operand; for (; ; index++) { if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { - qeport(ParseError, JSMSG_ARRAY_INIT_TOO_BIG); + error(JSMSG_ARRAY_INIT_TOO_BIG); return null(); } @@ -8999,7 +9022,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } if (isAsync && isGenerator) { - qeport(ParseError, JSMSG_ASYNC_GENERATOR); + error(JSMSG_ASYNC_GENERATOR); return null(); } @@ -9112,7 +9135,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } default: - qeport(ParseError, JSMSG_BAD_PROP_ID); + error(JSMSG_BAD_PROP_ID); return null(); } @@ -9122,7 +9145,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_COLON) { if (isGenerator) { - qeport(ParseError, JSMSG_BAD_PROP_ID); + error(JSMSG_BAD_PROP_ID); return null(); } *propType = PropertyType::Normal; @@ -9131,7 +9154,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { if (isGenerator) { - qeport(ParseError, JSMSG_BAD_PROP_ID); + error(JSMSG_BAD_PROP_ID); return null(); } tokenStream.ungetToken(); @@ -9152,7 +9175,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - qeport(ParseError, JSMSG_COLON_AFTER_ID); + error(JSMSG_COLON_AFTER_ID); return null(); } @@ -9263,7 +9286,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9288,7 +9311,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9312,7 +9335,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Destructuring defaults are definitely not allowed in this object literal, // because of something the caller knows about the preceding code. // For example, maybe the preceding token is an operator: `x + {y=z}`. - qeport(ParseError, JSMSG_COLON_AFTER_ID); + error(JSMSG_COLON_AFTER_ID); return null(); } @@ -9371,7 +9394,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; if (tt != TOK_COMMA) { - qeport(ParseError, JSMSG_CURLY_AFTER_LIST); + error(JSMSG_CURLY_AFTER_LIST); return null(); } } @@ -9420,7 +9443,7 @@ Parser::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } @@ -9475,8 +9498,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.peekToken(&next)) return null(); if (next != TOK_ARROW) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(TOK_RP)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -9563,7 +9585,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // name, closing parenthesis, and arrow, and allow it only if all are // present. if (tripledotHandling != TripledotAllowed) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } @@ -9585,8 +9607,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // or "arguments" should be prohibited. Argument-parsing code // handles that. if (next != TOK_NAME && next != TOK_YIELD) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "rest argument name", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next)); return null(); } } @@ -9594,8 +9615,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.getToken(&next)) return null(); if (next != TOK_RP) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "closing parenthesis", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next)); return null(); } @@ -9604,8 +9624,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (next != TOK_ARROW) { // Advance the scanner for proper error location reporting. tokenStream.consumeKnownToken(next); - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "'=>' after argument list", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next)); return null(); } @@ -9616,7 +9635,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling } default: - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } } @@ -9641,7 +9660,7 @@ Parser::warnOnceAboutExprClosure() return true; if (!cx->compartment()->warnedAboutExprClosure) { - if (!qeport(ParseWarning, JSMSG_DEPRECATED_EXPR_CLOSURE)) + if (!warning(JSMSG_DEPRECATED_EXPR_CLOSURE)) return false; cx->compartment()->warnedAboutExprClosure = true; } @@ -9659,7 +9678,7 @@ Parser::warnOnceAboutForEach() if (!cx->compartment()->warnedAboutForEach) { // Disabled warning spew. - // if (!qeport(ParseWarning, JSMSG_DEPRECATED_FOR_EACH)) + // if (!warning(JSMSG_DEPRECATED_FOR_EACH)) // return false; cx->compartment()->warnedAboutForEach = true; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 402b977ba..feead0e63 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -907,12 +907,14 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool qeport(ParseReportKind kind, unsigned errorNumber, ...); bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, ...); + /* Report the given error at the current offset. */ + void error(unsigned errorNumber, ...); + /* * Handle a strict mode error at the current offset. Report an error if in * strict mode code, or warn if not, using the given error number and @@ -920,6 +922,15 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter */ MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + /* Report the given warning at the current offset. */ + MOZ_MUST_USE bool warning(unsigned errorNumber, ...); + + /* + * If extra warnings are enabled, report the given warning at the current + * offset. + */ + MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...); + Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames, Parser* syntaxParser, LazyScript* lazyOuterFunction); -- cgit v1.2.3 From 1ee96e39db760004c33a235ea691ab06bac21375 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:30:52 +0200 Subject: Specify an explicit offset when warning about "use asm" found in the directive prologue of a script (rather than a function body). --- js/src/frontend/FullParseHandler.h | 2 +- js/src/frontend/Parser.cpp | 9 +++++---- js/src/frontend/SyntaxParseHandler.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 0fd137796..da068e5af 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -845,7 +845,7 @@ class FullParseHandler MOZ_MUST_USE ParseNode* setLikelyIIFE(ParseNode* pn) { return parenthesize(pn); } - void setPrologue(ParseNode* pn) { + void setInDirectivePrologue(ParseNode* pn) { pn->pn_prologue = true; } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 8ad8813b5..afbf4c4c9 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3811,10 +3811,10 @@ Parser::asmJS(Node list) */ template bool -Parser::maybeParseDirective(Node list, Node pn, bool* cont) +Parser::maybeParseDirective(Node list, Node possibleDirective, bool* cont) { TokenPos directivePos; - JSAtom* directive = handler.isStringExprStatement(pn, &directivePos); + JSAtom* directive = handler.isStringExprStatement(possibleDirective, &directivePos); *cont = !!directive; if (!*cont) @@ -3831,7 +3831,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // directive in the future. We don't want to interfere with people // taking advantage of directive-prologue-enabled features that appear // in other browsers first. - handler.setPrologue(pn); + handler.setInDirectivePrologue(possibleDirective); if (directive == context->names().useStrict) { // Functions with non-simple parameter lists (destructuring, @@ -3867,7 +3867,8 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) } else if (directive == context->names().useAsm) { if (pc->isFunctionBox()) return asmJS(list); - return reportWithNode(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL); + return reportWithOffset(ParseWarning, false, directivePos.begin, + JSMSG_USE_ASM_DIRECTIVE_FAIL); } } return true; diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index b7f00605b..85695ba9c 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -519,7 +519,7 @@ class SyntaxParseHandler MOZ_MUST_USE Node setLikelyIIFE(Node pn) { return pn; // Remain in syntax-parse mode. } - void setPrologue(Node pn) {} + void setInDirectivePrologue(Node pn) {} bool isConstant(Node pn) { return false; } -- cgit v1.2.3 From 11a1f58b9a0ebf83c17087a89e6b4ba83748374a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:32:55 +0200 Subject: Track strict mode errors in unary deletions correctly when syntax-parsing. --- js/src/frontend/Parser.cpp | 19 +++++++++++++++++-- js/src/frontend/Parser.h | 7 +++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index afbf4c4c9..f625595a2 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -641,6 +641,17 @@ Parser::strictModeError(unsigned errorNumber, ...) return res; } +template +bool +Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool res = reportHelper(ParseStrictError, pc->sc()->strict(), offset, errorNumber, args); + va_end(args); + return res; +} + template bool Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) @@ -8031,6 +8042,10 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t } case TOK_DELETE: { + uint32_t exprOffset; + if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand)) + return null(); + Node expr = unaryExpr(yieldHandling, TripledotProhibited); if (!expr) return null(); @@ -8038,9 +8053,9 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t // Per spec, deleting any unary expression is valid -- it simply // returns true -- except for one case that is illegal in strict mode. if (handler.isNameAnyParentheses(expr)) { - bool strict = pc->sc()->strict(); - if (!reportWithNode(ParseStrictError, strict, expr, JSMSG_DEPRECATED_DELETE_OPERAND)) + if (!strictModeErrorAt(exprOffset, JSMSG_DEPRECATED_DELETE_OPERAND)) return null(); + pc->sc()->setBindingsAccessedDynamically(); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index feead0e63..c8914a2d7 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -922,6 +922,13 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter */ MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + /* + * Handle a strict mode error at the given offset. Report an error if in + * strict mode code, or warn if not, using the given error number and + * arguments. + */ + MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...); + /* Report the given warning at the current offset. */ MOZ_MUST_USE bool warning(unsigned errorNumber, ...); -- cgit v1.2.3 From dcf64bd2ffd24d1c0d046af810c3270656081663 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:38:21 +0200 Subject: Track strict mode errors in for...in and for...of correctly when syntax-parsing. --- js/src/frontend/Parser.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index f625595a2..5981881d3 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4458,6 +4458,10 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN)); + uint32_t initializerOffset; + if (!tokenStream.peekOffset(&initializerOffset, TokenStream::Operand)) + return false; + Node initializer = assignExpr(forHeadKind ? InProhibited : InAllowed, yieldHandling, TripledotProhibited); if (!initializer) @@ -4491,11 +4495,8 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // This leaves only initialized for-in |var| declarations. ES6 // forbids these; later ES un-forbids in non-strict mode code. *forHeadKind = PNK_FORIN; - if (!reportWithNode(ParseStrictError, pc->sc()->strict(), initializer, - JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) - { + if (!strictModeErrorAt(initializerOffset, JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) return false; - } *forInOrOfExpression = expressionAfterForInOrOf(PNK_FORIN, yieldHandling); if (!*forInOrOfExpression) -- cgit v1.2.3 From 96899aa847ab7495e3b7baaa413cf50a5eaaffff Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 04:22:27 +0200 Subject: Move part of Parser::functionDefinition into callers. --- js/src/frontend/Parser.cpp | 46 +++++++++++++++++++++++++++++----------------- js/src/frontend/Parser.h | 5 ++--- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5981881d3..8466d7c1c 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3188,22 +3188,14 @@ Parser::templateLiteral(YieldHandling yieldHandling) template typename ParseHandler::Node -Parser::functionDefinition(uint32_t preludeStart, InHandling inHandling, +Parser::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind, - InvokedPrediction invoked) + GeneratorKind generatorKind, FunctionAsyncKind asyncKind) { MOZ_ASSERT_IF(kind == Statement, funName); MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator); - Node pn = handler.newFunctionDefinition(); - if (!pn) - return null(); - - if (invoked) - pn = handler.setLikelyIIFE(pn); - // Note the declared name and check for early errors. bool tryAnnexB = false; if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB)) @@ -3665,9 +3657,13 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node fun = functionDefinition(preludeStart, InAllowed, newYieldHandling, name, Statement, - generatorKind, asyncKind, PredictUninvoked); + Node fun = functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, + name, Statement, generatorKind, asyncKind); if (!fun) return null(); @@ -3716,8 +3712,15 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo tokenStream.ungetToken(); } - return functionDefinition(preludeStart, InAllowed, yieldHandling, name, Expression, - generatorKind, asyncKind, invoked); + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + + if (invoked) + pn = handler.setLikelyIIFE(pn); + + return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, name, Expression, + generatorKind, asyncKind); } /* @@ -7783,7 +7786,11 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl } } - Node arrowFunc = functionDefinition(preludeStart, inHandling, yieldHandling, nullptr, + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + + Node arrowFunc = functionDefinition(preludeStart, pn, inHandling, yieldHandling, nullptr, Arrow, generatorKind, asyncKind); if (!arrowFunc) return null(); @@ -9429,8 +9436,13 @@ Parser::methodDefinition(uint32_t preludeStart, PropertyType propT GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - return functionDefinition(preludeStart, InAllowed, yieldHandling, funName, kind, - generatorKind, asyncKind); + + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + + return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, funName, + kind, generatorKind, asyncKind); } template diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index c8914a2d7..3bfb4ae31 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1259,11 +1259,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, Node funcpn); - Node functionDefinition(uint32_t preludeStart, + Node functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind, - InvokedPrediction invoked = PredictUninvoked); + GeneratorKind generatorKind, FunctionAsyncKind asyncKind); // Parse a function body. Pass StatementListBody if the body is a list of // statements; pass ExpressionBody if the body is a single expression. -- cgit v1.2.3 From 7333618581b018ca73c3482e2d5547765f6c3a1d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:22:55 +0200 Subject: Move the Parser::checkFunctionDefinition call into its callers. --- js/src/frontend/FullParseHandler.h | 15 ++- js/src/frontend/ParseNode.h | 8 +- js/src/frontend/Parser.cpp | 176 ++++++++++++++++++----------------- js/src/frontend/Parser.h | 5 +- js/src/frontend/SyntaxParseHandler.h | 5 +- js/src/wasm/AsmJS.cpp | 2 +- 6 files changed, 116 insertions(+), 95 deletions(-) diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index da068e5af..b619cf24c 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -670,9 +670,18 @@ class FullParseHandler pn->setDirectRHSAnonFunction(true); } - ParseNode* newFunctionDefinition() { - return new_(PNK_FUNCTION, pos()); + ParseNode* newFunctionStatement() { + return new_(PNK_FUNCTION, JSOP_NOP, pos()); } + + ParseNode* newFunctionExpression() { + return new_(PNK_FUNCTION, JSOP_LAMBDA, pos()); + } + + ParseNode* newArrowFunction() { + return new_(PNK_FUNCTION, JSOP_LAMBDA_ARROW, pos()); + } + bool setComprehensionLambdaBody(ParseNode* pn, ParseNode* body) { MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST)); ParseNode* paramsBody = newList(PNK_PARAMSBODY, body); @@ -699,7 +708,7 @@ class FullParseHandler } ParseNode* newModule() { - return new_(PNK_MODULE, pos()); + return new_(PNK_MODULE, JSOP_NOP, pos()); } ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) { diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index c58dab431..c3523afe4 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -926,10 +926,14 @@ struct ListNode : public ParseNode struct CodeNode : public ParseNode { - CodeNode(ParseNodeKind kind, const TokenPos& pos) - : ParseNode(kind, JSOP_NOP, PN_CODE, pos) + CodeNode(ParseNodeKind kind, JSOp op, const TokenPos& pos) + : ParseNode(kind, op, PN_CODE, pos) { MOZ_ASSERT(kind == PNK_FUNCTION || kind == PNK_MODULE); + MOZ_ASSERT_IF(kind == PNK_MODULE, op == JSOP_NOP); + MOZ_ASSERT(op == JSOP_NOP || // statement, module + op == JSOP_LAMBDA_ARROW || // arrow function + op == JSOP_LAMBDA); // expression, method, comprehension, accessor, &c. MOZ_ASSERT(!pn_body); MOZ_ASSERT(!pn_objbox); } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 8466d7c1c..c34e4d563 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2352,7 +2352,7 @@ Parser::standaloneFunction(HandleFunction fun, tokenStream.ungetToken(); } - Node fn = handler.newFunctionDefinition(); + Node fn = handler.newFunctionStatement(); if (!fn) return null(); @@ -3010,60 +3010,54 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn template bool -Parser::checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, +Parser::checkFunctionDefinition(HandlePropertyName funName, Node pn, GeneratorKind generatorKind, bool* tryAnnexB) { - if (kind == Statement) { - TokenPos pos = handler.getPosition(pn); - RootedPropertyName funName(context, funAtom->asPropertyName()); - - // In sloppy mode, Annex B.3.2 allows labelled function - // declarations. Otherwise it is a parse error. - ParseContext::Statement* declaredInStmt = pc->innermostStatement(); - if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { - MOZ_ASSERT(!pc->sc()->strict(), - "labeled functions shouldn't be parsed in strict mode"); - - // Find the innermost non-label statement. Report an error if it's - // unbraced: functions can't appear in it. Otherwise the statement - // (or its absence) determines the scope the function's bound in. - while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) - declaredInStmt = declaredInStmt->enclosing(); - - if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { - reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL); - return false; - } - } + TokenPos pos = handler.getPosition(pn); - if (declaredInStmt) { - MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); - MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); + // In sloppy mode, Annex B.3.2 allows labelled function + // declarations. Otherwise it is a parse error. + ParseContext::Statement* declaredInStmt = pc->innermostStatement(); + if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { + MOZ_ASSERT(!pc->sc()->strict(), + "labeled functions shouldn't be parsed in strict mode"); - if (!pc->sc()->strict() && generatorKind == NotGenerator) { - // Under sloppy mode, try Annex B.3.3 semantics. If making an - // additional 'var' binding of the same name does not throw an - // early error, do so. This 'var' binding would be assigned - // the function object when its declaration is reached, not at - // the start of the block. + // Find the innermost non-label statement. Report an error if it's + // unbraced: functions can't appear in it. Otherwise the statement + // (or its absence) determines the scope the function's bound in. + while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) + declaredInStmt = declaredInStmt->enclosing(); - if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) - return false; - } + if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { + reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL); + return false; + } + } - if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos)) - return false; - } else { - if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos)) - return false; + if (declaredInStmt) { + MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); + MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); - // Body-level functions in modules are always closed over. - if (pc->atModuleLevel()) - pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver(); + if (!pc->sc()->strict() && generatorKind == NotGenerator) { + // In sloppy mode, try Annex B.3.3 semantics. If making an + // additional 'var' binding of the same name does not throw an + // early error, do so. This 'var' binding would be assigned + // the function object when its declaration is reached, not at + // the start of the block. + + if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) + return false; } + + if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos)) + return false; } else { - // A function expression does not introduce any binding. - handler.setOp(pn, kind == Arrow ? JSOP_LAMBDA_ARROW : JSOP_LAMBDA); + if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos)) + return false; + + // Body-level functions in modules are always closed over. + if (pc->atModuleLevel()) + pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver(); } return true; @@ -3191,16 +3185,12 @@ typename ParseHandler::Node Parser::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind) + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + bool tryAnnexB /* = false */) { MOZ_ASSERT_IF(kind == Statement, funName); MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator); - // Note the declared name and check for early errors. - bool tryAnnexB = false; - if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB)) - return null(); - // When fully parsing a LazyScript, we do not fully reparse its inner // functions, which are also lazy. Instead, their free variables and // source extents are recorded and may be skipped. @@ -3433,7 +3423,7 @@ Parser::standaloneLazyFunction(HandleFunction fun, bool strict { MOZ_ASSERT(checkOptionsCalled); - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionStatement(); if (!pn) return null(); @@ -3657,13 +3647,18 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionStatement(); if (!pn) return null(); + // Note the declared name and check for early errors. + bool tryAnnexB = false; + if (!checkFunctionDefinition(name, pn, generatorKind, &tryAnnexB)) + return null(); + YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); Node fun = functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, - name, Statement, generatorKind, asyncKind); + name, Statement, generatorKind, asyncKind, tryAnnexB); if (!fun) return null(); @@ -3712,7 +3707,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo tokenStream.ungetToken(); } - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionExpression(); if (!pn) return null(); @@ -6583,31 +6578,6 @@ JSOpFromPropertyType(PropertyType propType) } } -static FunctionSyntaxKind -FunctionSyntaxKindFromPropertyType(PropertyType propType) -{ - switch (propType) { - case PropertyType::Getter: - return Getter; - case PropertyType::GetterNoExpressionClosure: - return GetterNoExpressionClosure; - case PropertyType::Setter: - return Setter; - case PropertyType::SetterNoExpressionClosure: - return SetterNoExpressionClosure; - case PropertyType::Method: - case PropertyType::GeneratorMethod: - case PropertyType::AsyncMethod: - return Method; - case PropertyType::Constructor: - return ClassConstructor; - case PropertyType::DerivedConstructor: - return DerivedClassConstructor; - default: - MOZ_CRASH("unexpected property type"); - } -} - static GeneratorKind GeneratorKindFromPropertyType(PropertyType propType) { @@ -7786,7 +7756,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl } } - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newArrowFunction(); if (!pn) return null(); @@ -8125,10 +8095,9 @@ template typename ParseHandler::Node Parser::generatorComprehensionLambda(unsigned begin) { - Node genfn = handler.newFunctionDefinition(); + Node genfn = handler.newFunctionExpression(); if (!genfn) return null(); - handler.setOp(genfn, JSOP_LAMBDA); ParseContext* outerpc = pc; @@ -9432,12 +9401,47 @@ typename ParseHandler::Node Parser::methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName) { - FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); + FunctionSyntaxKind kind; + switch (propType) { + case PropertyType::Getter: + kind = Getter; + break; + + case PropertyType::GetterNoExpressionClosure: + kind = GetterNoExpressionClosure; + break; + + case PropertyType::Setter: + kind = Setter; + break; + + case PropertyType::SetterNoExpressionClosure: + kind = SetterNoExpressionClosure; + break; + + case PropertyType::Method: + case PropertyType::GeneratorMethod: + case PropertyType::AsyncMethod: + kind = Method; + break; + + case PropertyType::Constructor: + kind = ClassConstructor; + break; + + case PropertyType::DerivedConstructor: + kind = DerivedClassConstructor; + break; + + default: + MOZ_CRASH("Parser: methodDefinition: unexpected property type"); + } + GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionExpression(); if (!pn) return null(); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 3bfb4ae31..dc9c16adb 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1262,7 +1262,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind); + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + bool tryAnnexB = false); // Parse a function body. Pass StatementListBody if the body is a list of // statements; pass ExpressionBody if the body is a single expression. @@ -1348,7 +1349,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node newDotGeneratorName(); bool declareDotGeneratorName(); - bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, + bool checkFunctionDefinition(HandlePropertyName funName, Node pn, GeneratorKind generatorKind, bool* tryAnnexB); bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, bool tryAnnexB); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 85695ba9c..00ea9d35d 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -342,7 +342,10 @@ class SyntaxParseHandler void checkAndSetIsDirectRHSAnonFunction(Node pn) {} - Node newFunctionDefinition() { return NodeFunctionDefinition; } + Node newFunctionStatement() { return NodeFunctionDefinition; } + Node newFunctionExpression() { return NodeFunctionDefinition; } + Node newArrowFunction() { return NodeFunctionDefinition; } + bool setComprehensionLambdaBody(Node pn, Node body) { return true; } void setFunctionFormalParametersAndBody(Node pn, Node kid) {} void setFunctionBody(Node pn, Node kid) {} diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 2b6690363..a318d67a9 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -7064,7 +7064,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) if (!name) return false; - ParseNode* fn = m.parser().handler.newFunctionDefinition(); + ParseNode* fn = m.parser().handler.newFunctionStatement(); if (!fn) return false; -- cgit v1.2.3 From 239003468d0617ca34b5e78627f014207b4e63ee Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:26:49 +0200 Subject: Inline GeneratorKindFromPropertyType and AsyncKindFromPropertyType. Trivially inlines these into their sole caller. --- js/src/frontend/Parser.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c34e4d563..5a42b75b0 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6578,24 +6578,6 @@ JSOpFromPropertyType(PropertyType propType) } } -static GeneratorKind -GeneratorKindFromPropertyType(PropertyType propType) -{ - if (propType == PropertyType::GeneratorMethod) - return StarGenerator; - if (propType == PropertyType::AsyncMethod) - return StarGenerator; - return NotGenerator; -} - -static FunctionAsyncKind -AsyncKindFromPropertyType(PropertyType propType) -{ - if (propType == PropertyType::AsyncMethod) - return AsyncFunction; - return SyncFunction; -} - template typename ParseHandler::Node Parser::classDefinition(YieldHandling yieldHandling, @@ -9437,8 +9419,15 @@ Parser::methodDefinition(uint32_t preludeStart, PropertyType propT MOZ_CRASH("Parser: methodDefinition: unexpected property type"); } - GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); - FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); + GeneratorKind generatorKind = (propType == PropertyType::GeneratorMethod || + propType == PropertyType::AsyncMethod) + ? StarGenerator + : NotGenerator; + + FunctionAsyncKind asyncKind = (propType == PropertyType::AsyncMethod) + ? AsyncFunction + : SyncFunction; + YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); Node pn = handler.newFunctionExpression(); -- cgit v1.2.3 From 386cc5ee17b4e144fdffda1742031aa0cba7373a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:36:09 +0200 Subject: Inline Parser::checkFunctionDefinition into its sole caller. --- js/src/frontend/Parser.cpp | 112 ++++++++++++++++++++------------------------- js/src/frontend/Parser.h | 2 - 2 files changed, 49 insertions(+), 65 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5a42b75b0..34d87528f 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1307,7 +1307,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind // Functions in block have complex allowances in sloppy mode for being // labelled that other lexical declarations do not have. Those checks // are more complex than calling checkLexicalDeclarationDirectlyWithin- - // Block and are done in checkFunctionDefinition. + // Block and are done inline in callers. ParseContext::Scope* scope = pc->innermostScope(); if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) { @@ -3008,61 +3008,6 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return true; } -template -bool -Parser::checkFunctionDefinition(HandlePropertyName funName, Node pn, - GeneratorKind generatorKind, bool* tryAnnexB) -{ - TokenPos pos = handler.getPosition(pn); - - // In sloppy mode, Annex B.3.2 allows labelled function - // declarations. Otherwise it is a parse error. - ParseContext::Statement* declaredInStmt = pc->innermostStatement(); - if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { - MOZ_ASSERT(!pc->sc()->strict(), - "labeled functions shouldn't be parsed in strict mode"); - - // Find the innermost non-label statement. Report an error if it's - // unbraced: functions can't appear in it. Otherwise the statement - // (or its absence) determines the scope the function's bound in. - while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) - declaredInStmt = declaredInStmt->enclosing(); - - if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { - reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL); - return false; - } - } - - if (declaredInStmt) { - MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); - MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); - - if (!pc->sc()->strict() && generatorKind == NotGenerator) { - // In sloppy mode, try Annex B.3.3 semantics. If making an - // additional 'var' binding of the same name does not throw an - // early error, do so. This 'var' binding would be assigned - // the function object when its declaration is reached, not at - // the start of the block. - - if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) - return false; - } - - if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos)) - return false; - } else { - if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos)) - return false; - - // Body-level functions in modules are always closed over. - if (pc->atModuleLevel()) - pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver(); - } - - return true; -} - template <> bool Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart, @@ -3618,12 +3563,30 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan } } - RootedPropertyName name(context); - GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator; + // In sloppy mode, Annex B.3.2 allows labelled function declarations. + // Otherwise it's a parse error. + ParseContext::Statement* declaredInStmt = pc->innermostStatement(); + if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { + MOZ_ASSERT(!pc->sc()->strict(), + "labeled functions shouldn't be parsed in strict mode"); + + // Find the innermost non-label statement. Report an error if it's + // unbraced: functions can't appear in it. Otherwise the statement + // (or its absence) determines the scope the function's bound in. + while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) + declaredInStmt = declaredInStmt->enclosing(); + + if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { + error(JSMSG_SLOPPY_FUNCTION_LABEL); + return null(); + } + } + TokenKind tt; if (!tokenStream.getToken(&tt)) return null(); + GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator; if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { error(JSMSG_ASYNC_GENERATOR); @@ -3634,6 +3597,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } + RootedPropertyName name(context); if (tt == TOK_NAME || tt == TOK_YIELD) { name = bindingIdentifier(yieldHandling); if (!name) @@ -3647,13 +3611,35 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } - Node pn = handler.newFunctionStatement(); - if (!pn) - return null(); - // Note the declared name and check for early errors. bool tryAnnexB = false; - if (!checkFunctionDefinition(name, pn, generatorKind, &tryAnnexB)) + if (declaredInStmt) { + MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); + MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); + + if (!pc->sc()->strict() && generatorKind == NotGenerator) { + // In sloppy mode, try Annex B.3.3 semantics. If making an + // additional 'var' binding of the same name does not throw an + // early error, do so. This 'var' binding would be assigned + // the function object when its declaration is reached, not at + // the start of the block. + if (!tryDeclareVarForAnnexBLexicalFunction(name, &tryAnnexB)) + return null(); + } + + if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos())) + return null(); + } else { + if (!noteDeclaredName(name, DeclarationKind::BodyLevelFunction, pos())) + return null(); + + // Body-level functions in modules are always closed over. + if (pc->atModuleLevel()) + pc->varScope().lookupDeclaredName(name)->value()->setClosedOver(); + } + + Node pn = handler.newFunctionStatement(); + if (!pn) return null(); YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index dc9c16adb..13580846b 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1349,8 +1349,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node newDotGeneratorName(); bool declareDotGeneratorName(); - bool checkFunctionDefinition(HandlePropertyName funName, Node pn, - GeneratorKind generatorKind, bool* tryAnnexB); bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, bool tryAnnexB); bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart, -- cgit v1.2.3 From 7d56f431ccc11f3b5e2e6deec331bd9c7a06cf80 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:39:27 +0200 Subject: Introduce Parser::errorAt This reduces reporting an error at a particular offset to its bare essentials, simplifying calls. --- js/src/frontend/Parser.cpp | 71 +++++++++++++++++++++++++--------------------- js/src/frontend/Parser.h | 3 ++ 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 34d87528f..b494cc966 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -608,6 +608,20 @@ Parser::error(unsigned errorNumber, ...) va_end(args); } +template +void +Parser::errorAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + reportHelper(ParseError, false, offset, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + template bool Parser::warning(unsigned errorNumber, ...) @@ -940,8 +954,7 @@ Parser::checkStrictBinding(PropertyName* name, TokenPos pos) JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; - return reportWithOffset(ParseStrictError, pc->sc()->strict(), pos.begin, - JSMSG_BAD_BINDING, bytes.ptr()); + return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, bytes.ptr()); } return true; @@ -977,8 +990,7 @@ Parser::reportRedeclaration(HandlePropertyName name, DeclarationKi JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return; - reportWithOffset(ParseError, false, pos.begin, JSMSG_REDECLARED_VAR, - DeclarationKindString(kind), bytes.ptr()); + errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(kind), bytes.ptr()); } // notePositionalFormalParameter is called for both the arguments of a regular @@ -1247,11 +1259,11 @@ Parser::checkLexicalDeclarationDirectlyWithinBlock(ParseContext::S if (!StatementKindIsBraced(stmt.kind()) && stmt.kind() != StatementKind::ForLoopLexicalHead) { - reportWithOffset(ParseError, false, pos.begin, - stmt.kind() == StatementKind::Label - ? JSMSG_LEXICAL_DECL_LABEL - : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, - DeclarationKindString(kind)); + errorAt(pos.begin, + stmt.kind() == StatementKind::Label + ? JSMSG_LEXICAL_DECL_LABEL + : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, + DeclarationKindString(kind)); return false; } @@ -1341,7 +1353,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind // contain 'let'. (CatchParameter is the only lexical binding form // without this restriction.) if (name == context->names().let) { - reportWithOffset(ParseError, false, pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET); + errorAt(pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET); return false; } @@ -3730,7 +3742,7 @@ Parser::checkUnescapedName() if (!token.nameContainsEscape()) return true; - reportWithOffset(ParseError, false, token.pos.begin, JSMSG_ESCAPED_KEYWORD); + errorAt(token.pos.begin, JSMSG_ESCAPED_KEYWORD); return false; } @@ -3840,8 +3852,7 @@ Parser::maybeParseDirective(Node list, Node possibleDirective, boo : funbox->hasParameterExprs ? "default" : "rest"; - reportWithOffset(ParseError, false, directivePos.begin, - JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind); + errorAt(directivePos.begin, JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind); return false; } } @@ -4038,7 +4049,7 @@ Parser::PossibleError::checkForError(ErrorKind kind) return true; Error& err = error(kind); - parser_.reportWithOffset(ParseError, false, err.offset_, err.errorNumber_); + parser_.errorAt(err.offset_, err.errorNumber_); return false; } @@ -4327,11 +4338,11 @@ Parser::destructuringDeclarationWithoutYieldOrAwait(DeclarationKin Node res = destructuringDeclaration(kind, yieldHandling, tt); if (res) { if (pc->lastYieldOffset != startYieldOffset) { - reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); + errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); return null(); } if (pc->lastAwaitOffset != startAwaitOffset) { - reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); + errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); return null(); } } @@ -4779,7 +4790,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) { - reportWithOffset(ParseError, false, pos().begin, JSMSG_AS_AFTER_IMPORT_STAR); + error(JSMSG_AS_AFTER_IMPORT_STAR); return false; } @@ -5662,7 +5673,7 @@ Parser::forStatement(YieldHandling yieldHandling) Node init = startNode; if (isForEach) { - reportWithOffset(ParseError, false, begin, JSMSG_BAD_FOR_EACH_LOOP); + errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP); return null(); } @@ -5897,7 +5908,7 @@ Parser::continueStatement(YieldHandling yieldHandling) if (foundLoop) error(JSMSG_LABEL_NOT_FOUND); else - reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); + errorAt(begin, JSMSG_BAD_CONTINUE); return null(); } @@ -5956,7 +5967,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(isBreakTarget)) { - reportWithOffset(ParseError, false, begin, JSMSG_TOUGH_BREAK); + errorAt(begin, JSMSG_TOUGH_BREAK); return null(); } } @@ -6111,8 +6122,7 @@ Parser::yieldExpression(InHandling inHandling) } if (pc->functionBox()->isArrow()) { - reportWithOffset(ParseError, false, begin, - JSMSG_YIELD_IN_ARROW, js_yield_str); + errorAt(begin, JSMSG_YIELD_IN_ARROW, js_yield_str); return null(); } @@ -6120,8 +6130,7 @@ Parser::yieldExpression(InHandling inHandling) pc->functionBox()->function()->isGetter() || pc->functionBox()->function()->isSetter()) { - reportWithOffset(ParseError, false, begin, - JSMSG_YIELD_IN_METHOD, js_yield_str); + errorAt(begin, JSMSG_YIELD_IN_METHOD, js_yield_str); return null(); } @@ -6266,7 +6275,7 @@ Parser::labeledStatement(YieldHandling yieldHandling) uint32_t begin = pos().begin; if (pc->findInnermostStatement(hasSameLabel)) { - reportWithOffset(ParseError, false, begin, JSMSG_DUPLICATE_LABEL); + errorAt(begin, JSMSG_DUPLICATE_LABEL); return null(); } @@ -8297,8 +8306,7 @@ Parser::comprehension(GeneratorKind comprehensionKind) return null(); if (comprehensionKind != NotGenerator && pc->lastYieldOffset != startYieldOffset) { - reportWithOffset(ParseError, false, pc->lastYieldOffset, - JSMSG_BAD_GENEXP_BODY, js_yield_str); + errorAt(pc->lastYieldOffset, JSMSG_BAD_GENEXP_BODY, js_yield_str); return null(); } @@ -8360,11 +8368,11 @@ Parser::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling) Node res = assignExpr(InAllowed, yieldHandling, TripledotProhibited); if (res) { if (pc->lastYieldOffset != startYieldOffset) { - reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); + errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); return null(); } if (pc->lastAwaitOffset != startAwaitOffset) { - reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); + errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); return null(); } } @@ -9211,8 +9219,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Directly report the error when we're not in a // destructuring context. if (!possibleError) { - reportWithOffset(ParseError, false, namePos.begin, - JSMSG_DUPLICATE_PROTO_PROPERTY); + errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY); return null(); } @@ -9459,7 +9466,7 @@ Parser::tryNewTarget(Node &newTarget) return false; if (!pc->sc()->allowNewTarget()) { - reportWithOffset(ParseError, false, begin, JSMSG_BAD_NEWTARGET); + errorAt(begin, JSMSG_BAD_NEWTARGET); return false; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 13580846b..efbaebafd 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -915,6 +915,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter /* Report the given error at the current offset. */ void error(unsigned errorNumber, ...); + /* Report the given error at the given offset. */ + void errorAt(uint32_t offset, unsigned errorNumber, ...); + /* * Handle a strict mode error at the current offset. Report an error if in * strict mode code, or warn if not, using the given error number and -- cgit v1.2.3 From 4c4f8091e620a35d6d20a5b0ccc6c118e9b8e5e5 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:54:09 +0200 Subject: Remove Parser::reportBadReturn Report simpler errors that don't use the offset of a node as location. --- js/src/frontend/Parser.cpp | 23 +++-------------------- js/src/frontend/Parser.h | 2 -- js/src/js.msg | 4 ++-- js/src/tests/js1_7/geniter/regress-352197.js | 2 +- js/src/tests/js1_8/genexps/regress-683738.js | 8 ++++---- testing/xpcshell/selftest.py | 2 +- 6 files changed, 11 insertions(+), 30 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index b494cc966..0099ed19d 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -909,21 +909,6 @@ Parser::parse() return pn; } -template -bool -Parser::reportBadReturn(Node pn, ParseReportKind kind, - unsigned errnum, unsigned anonerrnum) -{ - JSAutoByteString name; - if (JSAtom* atom = pc->functionBox()->function()->explicitName()) { - if (!AtomToPrintableString(context, atom, &name)) - return false; - } else { - errnum = anonerrnum; - } - return reportWithNode(kind, pc->sc()->strict(), pn, errnum, name.ptr()); -} - /* * Strict mode forbids introducing new definitions for 'eval', 'arguments', or * for any strict mode reserved keyword. @@ -6023,10 +6008,9 @@ Parser::returnStatement(YieldHandling yieldHandling) if (!pn) return null(); + /* Disallow "return v;" in legacy generators. */ if (pc->isLegacyGenerator() && exprNode) { - /* Disallow "return v;" in legacy generators. */ - reportBadReturn(pn, ParseError, JSMSG_BAD_GENERATOR_RETURN, - JSMSG_BAD_ANON_GENERATOR_RETURN); + errorAt(begin, JSMSG_BAD_GENERATOR_RETURN); return null(); } @@ -6141,8 +6125,7 @@ Parser::yieldExpression(InHandling inHandling) ) { /* As in Python (see PEP-255), disallow return v; in generators. */ - reportBadReturn(null(), ParseError, JSMSG_BAD_GENERATOR_RETURN, - JSMSG_BAD_ANON_GENERATOR_RETURN); + errorAt(begin, JSMSG_BAD_GENERATOR_RETURN); return null(); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index efbaebafd..27a10458b 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1445,8 +1445,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter static Node null() { return ParseHandler::null(); } - bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum); - JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom); TokenPos pos() const { return tokenStream.currentToken().pos; } diff --git a/js/src/js.msg b/js/src/js.msg index a276dab94..42a48c3a5 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -186,7 +186,6 @@ MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'") MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async") MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression") -MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration") @@ -200,7 +199,8 @@ MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loo MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side") MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding") MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'") -MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value") +MSG_DEF(JSMSG_BAD_FUNCTION_YIELD, 0, JSEXN_TYPEERR, "can't use 'yield' in a function that can return a value") +MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "generator function can't return a value") MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression") MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") diff --git a/js/src/tests/js1_7/geniter/regress-352197.js b/js/src/tests/js1_7/geniter/regress-352197.js index 7982e12ee..495717af7 100644 --- a/js/src/tests/js1_7/geniter/regress-352197.js +++ b/js/src/tests/js1_7/geniter/regress-352197.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = /TypeError: anonymous generator function returns a value/; + expect = /TypeError: can't use 'yield' in a function that can return a value/; try { var gen = eval('(function() { { return 5; } yield 3; })'); diff --git a/js/src/tests/js1_8/genexps/regress-683738.js b/js/src/tests/js1_8/genexps/regress-683738.js index de563645d..b0309a90e 100644 --- a/js/src/tests/js1_8/genexps/regress-683738.js +++ b/js/src/tests/js1_8/genexps/regress-683738.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = "generator function foo returns a value"; + expect = "can't use 'yield' in a function that can return a value"; try { actual = 'No Error'; @@ -32,7 +32,7 @@ function test() } reportCompare(expect, actual, summary + ": 1"); - expect = "generator function foo returns a value"; + expect = "generator function can't return a value"; try { actual = 'No Error'; @@ -44,7 +44,7 @@ function test() } reportCompare(expect, actual, summary + ": 2"); - expect = "generator function foo returns a value"; + expect = "can't use 'yield' in a function that can return a value"; try { actual = 'No Error'; @@ -56,7 +56,7 @@ function test() } reportCompare(expect, actual, summary + ": 3"); - expect = "generator function foo returns a value"; + expect = "generator function can't return a value"; try { actual = 'No Error'; diff --git a/testing/xpcshell/selftest.py b/testing/xpcshell/selftest.py index 856f505fc..071ab5eda 100755 --- a/testing/xpcshell/selftest.py +++ b/testing/xpcshell/selftest.py @@ -1162,7 +1162,7 @@ add_test({ self.assertTestResult(False) self.assertInLog(TEST_FAIL_STRING) - self.assertInLog("TypeError: generator function run_test returns a value at") + self.assertInLog("TypeError: generator function can't return a value at") self.assertInLog("test_error.js:4") self.assertNotInLog(TEST_PASS_STRING) -- cgit v1.2.3 From f5c293d3e82581740558c79cf752bccc0420199c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 07:30:00 +0200 Subject: Report bad-class-member errors using a specified offset instead of a node's offset. --- js/src/frontend/Parser.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 0099ed19d..2702f3075 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6673,7 +6673,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - error(JSMSG_BAD_METHOD_DEF); + errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6683,17 +6683,17 @@ Parser::classDefinition(YieldHandling yieldHandling, propType = PropertyType::SetterNoExpressionClosure; if (!isStatic && propAtom == context->names().constructor) { if (propType != PropertyType::Method) { - reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } if (seenConstructor) { - reportWithNode(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor"); + errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor"); return null(); } seenConstructor = true; propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor; } else if (isStatic && propAtom == context->names().prototype) { - reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } -- cgit v1.2.3 From d7b76a5a5286475fcba1663028032a7ea834daed Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:31:01 +0200 Subject: Report for-loop-decl-with-initializer errors using a specified offset instead of a node's offset. --- js/src/frontend/Parser.cpp | 4 ++-- js/src/js.msg | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 2702f3075..a26520477 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4459,7 +4459,7 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (var/let/const x = ... of ...); // BAD if (isForOf) { - reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + errorAt(initializerOffset, JSMSG_OF_AFTER_FOR_LOOP_DECL); return false; } @@ -4468,7 +4468,7 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (let/const x = ... in ...); // BAD if (DeclarationKindIsLexical(declKind)) { - reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + errorAt(initializerOffset, JSMSG_IN_AFTER_LEXICAL_FOR_DECL); return false; } diff --git a/js/src/js.msg b/js/src/js.msg index 42a48c3a5..a19e3aa85 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -262,6 +262,8 @@ MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage a MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal") MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character") MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module") +MSG_DEF(JSMSG_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer") +MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer") MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers") MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable") -- cgit v1.2.3 From 940a6ceb9a5b3d8c7c2ed53da67f5c14cc84925c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:33:24 +0200 Subject: Introduce Parser::warningAt This reduces reporting an warning at a particular offset to its bare essentials, simplifying calls. --- js/src/frontend/Parser.cpp | 26 ++++++++++++++++---------- js/src/frontend/Parser.h | 5 +++-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a26520477..43f39dc23 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -633,6 +633,17 @@ Parser::warning(unsigned errorNumber, ...) return result; } +template +bool +Parser::warningAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool result = reportHelper(ParseWarning, false, offset, errorNumber, args); + va_end(args); + return result; +} + template bool Parser::extraWarning(unsigned errorNumber, ...) @@ -3858,8 +3869,7 @@ Parser::maybeParseDirective(Node list, Node possibleDirective, boo } else if (directive == context->names().useAsm) { if (pc->isFunctionBox()) return asmJS(list); - return reportWithOffset(ParseWarning, false, directivePos.begin, - JSMSG_USE_ASM_DIRECTIVE_FAIL); + return warningAt(directivePos.begin, JSMSG_USE_ASM_DIRECTIVE_FAIL); } } return true; @@ -3903,11 +3913,9 @@ Parser::statementList(YieldHandling yieldHandling) if (!warnedAboutStatementsAfterReturn) { if (afterReturn) { if (!handler.isStatementPermittedAfterReturnStatement(next)) { - if (!reportWithOffset(ParseWarning, false, statementBegin, - JSMSG_STMT_AFTER_RETURN)) - { + if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) return null(); - } + warnedAboutStatementsAfterReturn = true; } } else if (handler.isReturnStatement(next)) { @@ -5836,11 +5844,9 @@ Parser::switchStatement(YieldHandling yieldHandling) if (!warnedAboutStatementsAfterReturn) { if (afterReturn) { if (!handler.isStatementPermittedAfterReturnStatement(stmt)) { - if (!reportWithOffset(ParseWarning, false, statementBegin, - JSMSG_STMT_AFTER_RETURN)) - { + if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) return null(); - } + warnedAboutStatementsAfterReturn = true; } } else if (handler.isReturnStatement(stmt)) { diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 27a10458b..6bd7e586e 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -909,8 +909,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter public: bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); - bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, - ...); /* Report the given error at the current offset. */ void error(unsigned errorNumber, ...); @@ -935,6 +933,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter /* Report the given warning at the current offset. */ MOZ_MUST_USE bool warning(unsigned errorNumber, ...); + /* Report the given warning at the given offset. */ + MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...); + /* * If extra warnings are enabled, report the given warning at the current * offset. -- cgit v1.2.3 From 51e2758e02a6187228e35f58bfa0e1752870476b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:34:17 +0200 Subject: Remove Parser::reportWithOffset since it's no longer used. --- js/src/frontend/Parser.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 43f39dc23..9f9169950 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -701,18 +701,6 @@ Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned return result; } -template -bool -Parser::reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, - unsigned errorNumber, ...) -{ - va_list args; - va_start(args, errorNumber); - bool result = reportHelper(kind, strict, offset, errorNumber, args); - va_end(args); - return result; -} - template <> bool Parser::abortIfSyntaxParser() -- cgit v1.2.3 From d60cfce5e4b2e7ecf344b86c1bd4a712490a8c52 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:37:12 +0200 Subject: Report the error for uninitialized const-declaration in for(;;) loop head using an explicit offset. --- js/src/frontend/Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 9f9169950..fe30328de 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4577,7 +4577,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token // Normal const declarations, and const declarations in for(;;) // heads, must be initialized. if (declKind == DeclarationKind::Const) { - reportWithNode(ParseError, false, binding, JSMSG_BAD_CONST_DECL); + errorAt(namePos.begin, JSMSG_BAD_CONST_DECL); return null(); } } -- cgit v1.2.3 From 4a62cbec61620f54bfb3949d9165c4dd406c2444 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:41:42 +0200 Subject: Report some errors about invalid left-hand-sides in for-in/of loop heads using code with an explicitly computed offset. --- js/src/frontend/Parser.cpp | 62 +++++++++++++++++++--------------------------- js/src/frontend/Parser.h | 2 -- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index fe30328de..94573fce7 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5415,37 +5415,6 @@ Parser::matchInOrOf(bool* isForInp, bool* isForOfp) return true; } -template -bool -Parser::validateForInOrOfLHSExpression(Node target, PossibleError* possibleError) -{ - if (handler.isUnparenthesizedDestructuringPattern(target)) - return checkDestructuringPattern(target, Nothing(), possibleError); - - // All other permitted targets are simple. - if (!reportIfNotValidSimpleAssignmentTarget(target, ForInOrOfTarget)) - return false; - - if (handler.isPropertyAccess(target)) - return true; - - if (handler.isNameAnyParentheses(target)) { - // The arguments/eval identifiers are simple in non-strict mode code, - // but warn to discourage use nonetheless. - if (!reportIfArgumentsEvalTarget(target)) - return false; - - handler.adjustGetToSet(target); - return true; - } - - if (handler.isFunctionCall(target)) - return checkAssignmentToCall(target, JSMSG_BAD_FOR_LEFTSIDE); - - reportWithNode(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE); - return false; -} - template bool Parser::forHeadStart(YieldHandling yieldHandling, @@ -5526,6 +5495,10 @@ Parser::forHeadStart(YieldHandling yieldHandling, return *forInitialPart != null(); } + uint32_t exprOffset; + if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand)) + return false; + // Finally, handle for-loops that start with expressions. Pass // |InProhibited| so that |in| isn't parsed in a RelationalExpression as a // binary operator. |in| makes it a for-in loop, *not* an |in| expression. @@ -5569,8 +5542,29 @@ Parser::forHeadStart(YieldHandling yieldHandling, *forHeadKind = isForIn ? PNK_FORIN : PNK_FOROF; - if (!validateForInOrOfLHSExpression(*forInitialPart, &possibleError)) + // Verify the left-hand side expression doesn't have a forbidden form. + if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) { + if (!checkDestructuringPattern(*forInitialPart, Nothing(), &possibleError)) + return false; + } else if (handler.isNameAnyParentheses(*forInitialPart)) { + const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context); + if (chars) { + // |chars| is "arguments" or "eval" here. + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) + return false; + } + + handler.adjustGetToSet(*forInitialPart); + } else if (handler.isPropertyAccess(*forInitialPart)) { + // Permitted: no additional testing/fixup needed. + } else if (handler.isFunctionCall(*forInitialPart)) { + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE)) + return false; + } else { + errorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE); return false; + } + if (!possibleError.checkForExpressionError()) return false; @@ -7869,10 +7863,6 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign case CompoundAssignment: errnum = JSMSG_BAD_LEFTSIDE_OF_ASS; break; - - case ForInOrOfTarget: - errnum = JSMSG_BAD_FOR_LEFTSIDE; - break; } reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 6bd7e586e..e3827d953 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1139,7 +1139,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node* forInitialPart, mozilla::Maybe& forLetImpliedScope, Node* forInOrOfExpression); - bool validateForInOrOfLHSExpression(Node target, PossibleError* possibleError); Node expressionAfterForInOrOf(ParseNodeKind forHeadKind, YieldHandling yieldHandling); Node switchStatement(YieldHandling yieldHandling); @@ -1338,7 +1337,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter KeyedDestructuringAssignment, IncrementAssignment, DecrementAssignment, - ForInOrOfTarget }; bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor, -- cgit v1.2.3 From 8e8d0ed75c076b4b92e2971ff877b104dafeffca Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:44:48 +0200 Subject: Remove for-in/of loop parsing code that redundantly marks the loop target as assigned -- Parser::forHeadStart already does this. --- js/src/frontend/Parser.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 94573fce7..c979e38c3 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5715,12 +5715,6 @@ Parser::forStatement(YieldHandling yieldHandling) stmt.refineForKind(StatementKind::ForOfLoop); } - if (!handler.isDeclarationList(target)) { - MOZ_ASSERT(!forLoopLexicalScope); - if (!checkAndMarkAsAssignmentLhs(target, PlainAssignment)) - return null(); - } - // Parser::declaration consumed everything up to the closing ')'. That // token follows an {Assignment,}Expression, so the next token must be // consumed as if an operator continued the expression, i.e. as None. -- cgit v1.2.3 From b579e0567c887743d24c2745065b71bb06fea4f8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:46:15 +0200 Subject: Simplify checking of the left-hand side of assignment and compound assignment expressions. --- js/src/frontend/Parser.cpp | 74 ++++++++++++++++++---------------------------- js/src/frontend/Parser.h | 4 --- 2 files changed, 28 insertions(+), 50 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c979e38c3..3a5b5d6d7 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7470,45 +7470,6 @@ Parser::condExpr1(InHandling inHandling, YieldHandling yieldHandli return handler.newConditional(condition, thenExpr, elseExpr); } -template -bool -Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor flavor, - PossibleError* possibleError) -{ - MOZ_ASSERT(flavor != KeyedDestructuringAssignment, - "destructuring must use special checking/marking code, not " - "this method"); - - if (handler.isUnparenthesizedDestructuringPattern(target)) { - if (flavor == CompoundAssignment) { - error(JSMSG_BAD_DESTRUCT_ASS); - return false; - } - - return checkDestructuringPattern(target, Nothing(), possibleError); - } - - // All other permitted targets are simple. - if (!reportIfNotValidSimpleAssignmentTarget(target, flavor)) - return false; - - if (handler.isPropertyAccess(target)) - return true; - - if (handler.isNameAnyParentheses(target)) { - // The arguments/eval identifiers are simple in non-strict mode code, - // but warn to discourage use nonetheless. - if (!reportIfArgumentsEvalTarget(target)) - return false; - - handler.adjustGetToSet(target); - return true; - } - - MOZ_ASSERT(handler.isFunctionCall(target)); - return checkAssignmentToCall(target, JSMSG_BAD_LEFTSIDE_OF_ASS); -} - class AutoClearInDestructuringDecl { ParseContext* pc_; @@ -7553,6 +7514,8 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); + uint32_t exprOffset = pos().begin; + bool endsExpr; if (tt == TOK_NAME) { @@ -7752,9 +7715,33 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return lhs; } - AssignmentFlavor flavor = kind == PNK_ASSIGN ? PlainAssignment : CompoundAssignment; - if (!checkAndMarkAsAssignmentLhs(lhs, flavor, &possibleErrorInner)) + // Verify the left-hand side expression doesn't have a forbidden form. + if (handler.isUnparenthesizedDestructuringPattern(lhs)) { + if (kind != PNK_ASSIGN) { + error(JSMSG_BAD_DESTRUCT_ASS); + return null(); + } + + if (!checkDestructuringPattern(lhs, Nothing(), &possibleErrorInner)) + return null(); + } else if (handler.isNameAnyParentheses(lhs)) { + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) { + // |chars| is "arguments" or "eval" here. + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) + return null(); + } + + handler.adjustGetToSet(lhs); + } else if (handler.isPropertyAccess(lhs)) { + // Permitted: no additional testing/fixup needed. + } else if (handler.isFunctionCall(lhs)) { + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS)) + return null(); + } else { + errorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS); return null(); + } + if (!possibleErrorInner.checkForExpressionError()) return null(); @@ -7852,11 +7839,6 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign case KeyedDestructuringAssignment: errnum = JSMSG_BAD_DESTRUCT_TARGET; break; - - case PlainAssignment: - case CompoundAssignment: - errnum = JSMSG_BAD_LEFTSIDE_OF_ASS; - break; } reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index e3827d953..70d382501 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1332,15 +1332,11 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter } enum AssignmentFlavor { - PlainAssignment, - CompoundAssignment, KeyedDestructuringAssignment, IncrementAssignment, DecrementAssignment, }; - bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor, - PossibleError* possibleError=nullptr); bool matchInOrOf(bool* isForInp, bool* isForOfp); bool hasUsedFunctionSpecialName(HandlePropertyName name); -- cgit v1.2.3 From f4fec66e094281465ce1d143e00b0c9bda4863af Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:47:27 +0200 Subject: Specify an explicit offset when reporting an error for a for-of loop whose target is an expression that begins with 'let'. --- js/src/frontend/Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3a5b5d6d7..3f793ffcf 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5536,7 +5536,7 @@ Parser::forHeadStart(YieldHandling yieldHandling, // // See ES6 13.7. if (isForOf && letIsIdentifier) { - reportWithNode(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS); + errorAt(exprOffset, JSMSG_LET_STARTING_FOROF_LHS); return false; } -- cgit v1.2.3 From 194e6155211353738bb14ffd1ca9e9662a455b0e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:55:02 +0200 Subject: Inline Parser::checkAssignmentToCall into its sole caller. --- js/src/frontend/Parser.cpp | 19 +++++-------------- js/src/frontend/Parser.h | 2 -- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3f793ffcf..041c92fa7 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4084,19 +4084,6 @@ Parser::PossibleError::transferErrorsTo(PossibleError* other) transferErrorTo(ErrorKind::Expression, other); } -template -bool -Parser::checkAssignmentToCall(Node target, unsigned msg) -{ - MOZ_ASSERT(handler.isFunctionCall(target)); - - // Assignment to function calls is forbidden in ES6. We're still somewhat - // concerned about sites using this in dead code, so forbid it only in - // strict mode code (or if the werror option has been set), and otherwise - // warn. - return reportWithNode(ParseStrictError, pc->sc()->strict(), target, msg); -} - template <> bool Parser::checkDestructuringName(ParseNode* expr, Maybe maybeDecl) @@ -7862,7 +7849,11 @@ Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor fla if (!reportIfArgumentsEvalTarget(target)) return false; } else if (handler.isFunctionCall(target)) { - if (!checkAssignmentToCall(target, JSMSG_BAD_INCOP_OPERAND)) + // Assignment to function calls is forbidden in ES6. We're still + // somewhat concerned about sites using this in dead code, so forbid it + // only in strict mode code (or if the werror option has been set), and + // otherwise warn. + if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND)) return false; } return true; diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 70d382501..8bffafc42 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1432,8 +1432,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool checkDestructuringObject(Node objectPattern, mozilla::Maybe maybeDecl); bool checkDestructuringName(Node expr, mozilla::Maybe maybeDecl); - bool checkAssignmentToCall(Node node, unsigned errnum); - Node newNumber(const Token& tok) { return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos); } -- cgit v1.2.3 From 8580bf233e69da042e3d33cad56ca6f42ce441a4 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:56:39 +0200 Subject: Simplify increment/decrement operand checking. --- js/src/frontend/Parser.cpp | 34 ++++++++++++++++++---------------- js/src/frontend/Parser.h | 2 +- js/src/js.msg | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 041c92fa7..5c4d509dd 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7834,20 +7834,18 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign template bool -Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor flavor) +Parser::checkAndMarkAsIncOperand(Node target) { - MOZ_ASSERT(flavor == IncrementAssignment || flavor == DecrementAssignment); - - // Check. - if (!reportIfNotValidSimpleAssignmentTarget(target, flavor)) - return false; - - // Mark. if (handler.isNameAnyParentheses(target)) { - // Assignment to arguments/eval is allowed outside strict mode code, - // but it's dodgy. Report a strict warning (error, if werror was set). - if (!reportIfArgumentsEvalTarget(target)) - return false; + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(target, context)) { + if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, + JSMSG_BAD_STRICT_ASSIGN, chars)) + { + return false; + } + } + } else if (handler.isPropertyAccess(target)) { + // Permitted: no additional testing/fixup needed. } else if (handler.isFunctionCall(target)) { // Assignment to function calls is forbidden in ES6. We're still // somewhat concerned about sites using this in dead code, so forbid it @@ -7855,7 +7853,13 @@ Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor fla // otherwise warn. if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND)) return false; + } else { + reportWithNode(ParseError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND); + return false; } + + MOZ_ASSERT(isValidSimpleAssignmentTarget(target, PermitAssignmentToFunctionCalls), + "inconsistent increment/decrement operand validation"); return true; } @@ -7922,8 +7926,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t Node pn2 = memberExpr(yieldHandling, TripledotProhibited, tt2); if (!pn2) return null(); - AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment; - if (!checkAndMarkAsIncOperand(pn2, flavor)) + if (!checkAndMarkAsIncOperand(pn2)) return null(); return handler.newUpdate((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT, begin, @@ -7977,8 +7980,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t return null(); if (tt == TOK_INC || tt == TOK_DEC) { tokenStream.consumeKnownToken(tt); - AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment; - if (!checkAndMarkAsIncOperand(pn, flavor)) + if (!checkAndMarkAsIncOperand(pn)) return null(); return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, begin, diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 8bffafc42..c50f8e47d 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1377,7 +1377,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportIfArgumentsEvalTarget(Node nameNode); bool reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor); - bool checkAndMarkAsIncOperand(Node kid, AssignmentFlavor flavor); + bool checkAndMarkAsIncOperand(Node kid); bool checkStrictAssignment(Node lhs); bool checkStrictBinding(PropertyName* name, TokenPos pos); diff --git a/js/src/js.msg b/js/src/js.msg index a19e3aa85..2901b88cc 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -202,7 +202,7 @@ MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in ' MSG_DEF(JSMSG_BAD_FUNCTION_YIELD, 0, JSEXN_TYPEERR, "can't use 'yield' in a function that can return a value") MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "generator function can't return a value") MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression") -MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand") +MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") MSG_DEF(JSMSG_BAD_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand") -- cgit v1.2.3 From 74672745e6d1932a4aa7fa6a8cd6ab09fd9de4fe Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:05:22 +0200 Subject: Simplify checking of targets within destructuring patterns. --- js/src/frontend/Parser.cpp | 86 ++++++++-------------------------------------- js/src/frontend/Parser.h | 9 ----- js/src/js.msg | 1 - 3 files changed, 14 insertions(+), 82 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5c4d509dd..3e7c25c19 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4113,22 +4113,23 @@ Parser::checkDestructuringName(ParseNode* expr, Maybesc()->strict(), expr, + JSMSG_BAD_STRICT_ASSIGN, chars)) + { + return false; + } + } + + return true; } - // Nothing further to do for property accesses. - MOZ_ASSERT(handler.isPropertyAccess(expr)); - return true; + if (handler.isPropertyAccess(expr)) + return true; + + reportWithNode(ParseError, pc->sc()->strict(), expr, JSMSG_BAD_DESTRUCT_TARGET); + return false; } template <> @@ -7773,65 +7774,6 @@ Parser::isValidSimpleAssignmentTarget(Node node, return false; } -template -bool -Parser::reportIfArgumentsEvalTarget(Node nameNode) -{ - const char* chars = handler.nameIsArgumentsEvalAnyParentheses(nameNode, context); - if (!chars) - return true; - - bool strict = pc->sc()->strict(); - if (!reportWithNode(ParseStrictError, strict, nameNode, JSMSG_BAD_STRICT_ASSIGN, chars)) - return false; - - MOZ_ASSERT(!strict, - "an error should have been reported if this was strict mode " - "code"); - return true; -} - -template -bool -Parser::reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor) -{ - FunctionCallBehavior behavior = flavor == KeyedDestructuringAssignment - ? ForbidAssignmentToFunctionCalls - : PermitAssignmentToFunctionCalls; - if (isValidSimpleAssignmentTarget(target, behavior)) - return true; - - if (handler.isNameAnyParentheses(target)) { - // Use a special error if the target is arguments/eval. This ensures - // targeting these names is consistently a SyntaxError (which error numbers - // below don't guarantee) while giving us a nicer error message. - if (!reportIfArgumentsEvalTarget(target)) - return false; - } - - unsigned errnum = 0; - const char* extra = nullptr; - - switch (flavor) { - case IncrementAssignment: - errnum = JSMSG_BAD_OPERAND; - extra = "increment"; - break; - - case DecrementAssignment: - errnum = JSMSG_BAD_OPERAND; - extra = "decrement"; - break; - - case KeyedDestructuringAssignment: - errnum = JSMSG_BAD_DESTRUCT_TARGET; - break; - } - - reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); - return false; -} - template bool Parser::checkAndMarkAsIncOperand(Node target) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index c50f8e47d..0baaac3bc 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1331,12 +1331,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter #endif } - enum AssignmentFlavor { - KeyedDestructuringAssignment, - IncrementAssignment, - DecrementAssignment, - }; - bool matchInOrOf(bool* isForInp, bool* isForOfp); bool hasUsedFunctionSpecialName(HandlePropertyName name); @@ -1374,9 +1368,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls); private: - bool reportIfArgumentsEvalTarget(Node nameNode); - bool reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor); - bool checkAndMarkAsIncOperand(Node kid); bool checkStrictAssignment(Node lhs); bool checkStrictBinding(PropertyName* name, TokenPos pos); diff --git a/js/src/js.msg b/js/src/js.msg index 2901b88cc..4ded69a25 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -205,7 +205,6 @@ MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} i MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") -MSG_DEF(JSMSG_BAD_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand") MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'") MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id") MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function") -- cgit v1.2.3 From 7ea8efe0cb3199566b86a2b7ad4cb99df8620324 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:11:04 +0200 Subject: Report errors for bad increment/decrement operands using explicitly-specified offsets. --- js/src/frontend/Parser.cpp | 55 ++++++++++++++++++++++------------------------ js/src/frontend/Parser.h | 2 +- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3e7c25c19..3b1cadbff 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7776,31 +7776,28 @@ Parser::isValidSimpleAssignmentTarget(Node node, template bool -Parser::checkAndMarkAsIncOperand(Node target) +Parser::checkIncDecOperand(Node operand, uint32_t operandOffset) { - if (handler.isNameAnyParentheses(target)) { - if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(target, context)) { - if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, - JSMSG_BAD_STRICT_ASSIGN, chars)) - { + if (handler.isNameAnyParentheses(operand)) { + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(operand, context)) { + if (!strictModeErrorAt(operandOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) return false; - } } - } else if (handler.isPropertyAccess(target)) { + } else if (handler.isPropertyAccess(operand)) { // Permitted: no additional testing/fixup needed. - } else if (handler.isFunctionCall(target)) { + } else if (handler.isFunctionCall(operand)) { // Assignment to function calls is forbidden in ES6. We're still // somewhat concerned about sites using this in dead code, so forbid it // only in strict mode code (or if the werror option has been set), and // otherwise warn. - if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND)) + if (!strictModeErrorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND)) return false; } else { - reportWithNode(ParseError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND); + errorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND); return false; } - MOZ_ASSERT(isValidSimpleAssignmentTarget(target, PermitAssignmentToFunctionCalls), + MOZ_ASSERT(isValidSimpleAssignmentTarget(operand, PermitAssignmentToFunctionCalls), "inconsistent increment/decrement operand validation"); return true; } @@ -7865,14 +7862,14 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t TokenKind tt2; if (!tokenStream.getToken(&tt2, TokenStream::Operand)) return null(); - Node pn2 = memberExpr(yieldHandling, TripledotProhibited, tt2); - if (!pn2) - return null(); - if (!checkAndMarkAsIncOperand(pn2)) + + uint32_t operandOffset = pos().begin; + Node operand = memberExpr(yieldHandling, TripledotProhibited, tt2); + if (!operand || !checkIncDecOperand(operand, operandOffset)) return null(); + return handler.newUpdate((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT, - begin, - pn2); + begin, operand); } case TOK_DELETE: { @@ -7912,23 +7909,23 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t } default: { - Node pn = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true, + Node expr = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true, possibleError, invoked); - if (!pn) + if (!expr) return null(); /* Don't look across a newline boundary for a postfix incop. */ if (!tokenStream.peekTokenSameLine(&tt)) return null(); - if (tt == TOK_INC || tt == TOK_DEC) { - tokenStream.consumeKnownToken(tt); - if (!checkAndMarkAsIncOperand(pn)) - return null(); - return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, - begin, - pn); - } - return pn; + + if (tt != TOK_INC && tt != TOK_DEC) + return expr; + + tokenStream.consumeKnownToken(tt); + if (!checkIncDecOperand(expr, begin)) + return null(); + return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, + begin, expr); } } } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 0baaac3bc..a7e48c1a4 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1368,7 +1368,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls); private: - bool checkAndMarkAsIncOperand(Node kid); + bool checkIncDecOperand(Node operand, uint32_t operandOffset); bool checkStrictAssignment(Node lhs); bool checkStrictBinding(PropertyName* name, TokenPos pos); -- cgit v1.2.3 From 4f62fda966af85252f8345e51d694cd6d3a063c8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:18:36 +0200 Subject: Remove Parser::reportWithNode and its remaining callers. All of the callsites have a full ParseNode* at hand, of which the offset can be directly accessed. --- js/src/frontend/Parser.cpp | 30 +++++++----------------------- js/src/frontend/Parser.h | 1 - 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3b1cadbff..c08ba4889 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -677,19 +677,6 @@ Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, . return res; } -template -bool -Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) -{ - uint32_t offset = (pn ? handler.getPosition(pn) : pos()).begin; - - va_list args; - va_start(args, errorNumber); - bool result = reportHelper(kind, strict, offset, errorNumber, args); - va_end(args); - return result; -} - template bool Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...) @@ -4094,7 +4081,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybepn_pos.begin, JSMSG_BAD_DESTRUCT_PARENS); return false; } @@ -4104,7 +4091,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybepn_pos.begin, JSMSG_NO_VARIABLE_NAME); return false; } @@ -4115,11 +4102,8 @@ Parser::checkDestructuringName(ParseNode* expr, Maybesc()->strict(), expr, - JSMSG_BAD_STRICT_ASSIGN, chars)) - { + if (!strictModeErrorAt(expr->pn_pos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) return false; - } } return true; @@ -4128,7 +4112,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybesc()->strict(), expr, JSMSG_BAD_DESTRUCT_TARGET); + errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_TARGET); return false; } @@ -4187,7 +4171,7 @@ Parser::checkDestructuringArray(ParseNode* arrayPattern, ParseNode* target; if (element->isKind(PNK_SPREAD)) { if (element->pn_next) { - reportWithNode(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST); + errorAt(element->pn_next->pn_pos.begin, JSMSG_PARAMETER_AFTER_REST); return false; } target = element->pn_kid; @@ -4250,7 +4234,7 @@ Parser::checkDestructuringPattern(ParseNode* pattern, PossibleError* possibleError /* = nullptr */) { if (pattern->isKind(PNK_ARRAYCOMP)) { - reportWithNode(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE); + errorAt(pattern->pn_pos.begin, JSMSG_ARRAY_COMP_LEFTSIDE); return false; } @@ -5696,7 +5680,7 @@ Parser::forStatement(YieldHandling yieldHandling) iflags |= JSITER_ENUMERATE; } else { if (isForEach) { - reportWithNode(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP); + errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP); return null(); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index a7e48c1a4..196c71fa5 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -907,7 +907,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); /* Report the given error at the current offset. */ -- cgit v1.2.3 From f38ef66b7b9f1d1c85c5d8a7a5bbaa5f6c3c9948 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:20:43 +0200 Subject: Inline Parser::reportHelper into its callers. --- js/src/frontend/Parser.cpp | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c08ba4889..30a627a65 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -603,7 +603,7 @@ Parser::error(unsigned errorNumber, ...) #ifdef DEBUG bool result = #endif - reportHelper(ParseError, false, pos().begin, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_ERROR, errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } @@ -617,7 +617,7 @@ Parser::errorAt(uint32_t offset, unsigned errorNumber, ...) #ifdef DEBUG bool result = #endif - reportHelper(ParseError, false, offset, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } @@ -628,7 +628,8 @@ Parser::warning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(ParseWarning, false, pos().begin, errorNumber, args); + bool result = + tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_WARNING, errorNumber, args); va_end(args); return result; } @@ -639,7 +640,8 @@ Parser::warningAt(uint32_t offset, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(ParseWarning, false, offset, errorNumber, args); + bool result = + tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); va_end(args); return result; } @@ -650,7 +652,7 @@ Parser::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(ParseExtraWarning, false, pos().begin, errorNumber, args); + bool result = tokenStream.reportStrictWarningErrorNumberVA(pos().begin, errorNumber, args); va_end(args); return result; } @@ -661,7 +663,9 @@ Parser::strictModeError(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool res = reportHelper(ParseStrictError, pc->sc()->strict(), pos().begin, errorNumber, args); + bool res = + tokenStream.reportStrictModeErrorNumberVA(pos().begin, pc->sc()->strict(), + errorNumber, args); va_end(args); return res; } @@ -672,7 +676,8 @@ Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, . { va_list args; va_start(args, errorNumber); - bool res = reportHelper(ParseStrictError, pc->sc()->strict(), offset, errorNumber, args); + bool res = + tokenStream.reportStrictModeErrorNumberVA(offset, pc->sc()->strict(), errorNumber, args); va_end(args); return res; } @@ -683,7 +688,23 @@ Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned { va_list args; va_start(args, errorNumber); - bool result = reportHelper(kind, strict, TokenStream::NoOffset, errorNumber, args); + bool result = false; + uint32_t offset = TokenStream::NoOffset; + switch (kind) { + case ParseError: + result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); + break; + case ParseWarning: + result = + tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); + break; + case ParseExtraWarning: + result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args); + break; + case ParseStrictError: + result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); + break; + } va_end(args); return result; } -- cgit v1.2.3 From e88f15157f90cb2115d30dd7fc61704637536cd5 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:22:00 +0200 Subject: Remove Parser::reportHelper since it's no longer used. --- js/src/frontend/Parser.cpp | 24 ------------------------ js/src/frontend/Parser.h | 3 --- 2 files changed, 27 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 30a627a65..189f27bc4 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -570,30 +570,6 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope) computeInWith(enclosingScope); } -template -bool -Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t offset, - unsigned errorNumber, va_list args) -{ - bool result = false; - switch (kind) { - case ParseError: - result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); - break; - case ParseWarning: - result = - tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); - break; - case ParseExtraWarning: - result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args); - break; - case ParseStrictError: - result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); - break; - } - return result; -} - template void Parser::error(unsigned errorNumber, ...) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 196c71fa5..156a1c1b0 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -903,9 +903,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter void prepareNodeForMutation(Node node) { handler.prepareNodeForMutation(node); } void freeTree(Node node) { handler.freeTree(node); } - private: - bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, - unsigned errorNumber, va_list args); public: bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); -- cgit v1.2.3 From a5d22aa6106fbd3c8cec12333b14d4c65cd98647 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:26:49 +0200 Subject: Rename TokenStream::reportStrictWarningErrorNumberVA to TokenStream::reportExtraWarningErrorNumberVA for clarity. Emit Extra Warnings instead of Strict Warnings from the BCE where it makes sense. --- js/src/frontend/BytecodeEmitter.cpp | 8 ++++---- js/src/frontend/BytecodeEmitter.h | 2 +- js/src/frontend/Parser.cpp | 4 ++-- js/src/frontend/TokenStream.cpp | 2 +- js/src/frontend/TokenStream.h | 3 +-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 71289e84a..b3dd6d777 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3608,13 +3608,13 @@ BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) } bool -BytecodeEmitter::reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...) +BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...) { TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos; va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportStrictWarningErrorNumberVA(pos.begin, errorNumber, args); + bool result = tokenStream()->reportExtraWarningErrorNumberVA(pos.begin, errorNumber, args); va_end(args); return result; } @@ -8707,13 +8707,13 @@ BytecodeEmitter::emitStatement(ParseNode* pn) } if (directive) { - if (!reportStrictWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive)) + if (!reportExtraWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive)) return false; } } else { current->currentLine = parser->tokenStream.srcCoords.lineNum(pn2->pn_pos.begin); current->lastColumn = 0; - if (!reportStrictWarning(pn2, JSMSG_USELESS_EXPR)) + if (!reportExtraWarning(pn2, JSMSG_USELESS_EXPR)) return false; } } diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 04307c8c1..32668a34c 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -388,7 +388,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter } bool reportError(ParseNode* pn, unsigned errorNumber, ...); - bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...); + bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...); bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...); // If pn contains a useful expression, return true with *answer set to true. diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 189f27bc4..daacbb50b 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -628,7 +628,7 @@ Parser::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = tokenStream.reportStrictWarningErrorNumberVA(pos().begin, errorNumber, args); + bool result = tokenStream.reportExtraWarningErrorNumberVA(pos().begin, errorNumber, args); va_end(args); return result; } @@ -675,7 +675,7 @@ Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); break; case ParseExtraWarning: - result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args); + result = tokenStream.reportExtraWarningErrorNumberVA(offset, errorNumber, args); break; case ParseStrictError: result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index b040d2998..8438ff7c5 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -786,7 +786,7 @@ TokenStream::reportWarning(unsigned errorNumber, ...) } bool -TokenStream::reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args) +TokenStream::reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args) { if (!options().extraWarningsOption) return true; diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 03a580072..6ba9fba5a 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -375,8 +375,7 @@ class MOZ_STACK_CLASS TokenStream va_list args); bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber, va_list args); - bool reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, - va_list args); + bool reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args); // asm.js reporter void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...); -- cgit v1.2.3