diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 36659f4b0d2f..074076464220 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -33,12 +33,6 @@ using JS::AutoValueArray; using mozilla::DebugOnly; using mozilla::Forward; -enum class ParseTarget -{ - Script, - Module -}; - enum ASTType { AST_ERROR = -1, #define ASTDEF(ast, str, method) ast, @@ -2928,21 +2922,30 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) return classDefinition(pn, true, dst); case ParseNodeKind::NewTarget: + case ParseNodeKind::ImportMeta: { MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::PosHolder)); MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos)); MOZ_ASSERT(pn->pn_right->isKind(ParseNodeKind::PosHolder)); MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos)); - RootedValue newIdent(cx); - RootedValue targetIdent(cx); + RootedValue firstIdent(cx); + RootedValue secondIdent(cx); - RootedAtom newStr(cx, cx->names().new_); - RootedAtom targetStr(cx, cx->names().target); + RootedAtom firstStr(cx); + RootedAtom secondStr(cx); - return identifier(newStr, &pn->pn_left->pn_pos, &newIdent) && - identifier(targetStr, &pn->pn_right->pn_pos, &targetIdent) && - builder.metaProperty(newIdent, targetIdent, &pn->pn_pos, dst); + if (pn->getKind() == ParseNodeKind::NewTarget) { + firstStr = cx->names().new_; + secondStr = cx->names().target; + } else { + firstStr = cx->names().import; + secondStr = cx->names().meta; + } + + return identifier(firstStr, &pn->pn_left->pn_pos, &firstIdent) && + identifier(secondStr, &pn->pn_right->pn_pos, &secondIdent) && + builder.metaProperty(firstIdent, secondIdent, &pn->pn_pos, dst); } case ParseNodeKind::SetThis: @@ -3354,7 +3357,7 @@ reflect_parse(JSContext* cx, uint32_t argc, Value* vp) uint32_t lineno = 1; bool loc = true; RootedObject builder(cx); - ParseTarget target = ParseTarget::Script; + ParseGoal target = ParseGoal::Script; RootedValue arg(cx, args.get(1)); @@ -3442,9 +3445,9 @@ reflect_parse(JSContext* cx, uint32_t argc, Value* vp) return false; if (isScript) { - target = ParseTarget::Script; + target = ParseGoal::Script; } else if (isModule) { - target = ParseTarget::Module; + target = ParseGoal::Module; } else { JS_ReportErrorASCII(cx, "Bad target value, expected 'script' or 'module'"); return false; @@ -3467,7 +3470,7 @@ reflect_parse(JSContext* cx, uint32_t argc, Value* vp) CompileOptions options(cx); options.setFileAndLine(filename, lineno); options.setCanLazilyParse(false); - options.allowHTMLComments = target == ParseTarget::Script; + options.allowHTMLComments = target == ParseGoal::Script; mozilla::Range chars = linearChars.twoByteRange(); UsedNameTracker usedNames(cx); if (!usedNames.init()) @@ -3481,14 +3484,14 @@ reflect_parse(JSContext* cx, uint32_t argc, Value* vp) Parser parser(cx, cx->tempLifoAlloc(), options, chars.begin().get(), chars.length(), /* foldConstants = */ false, usedNames, nullptr, - nullptr, sourceObject); + nullptr, sourceObject, target); if (!parser.checkOptions()) return false; serialize.setParser(&parser); ParseNode* pn; - if (target == ParseTarget::Script) { + if (target == ParseGoal::Script) { pn = parser.parse(); if (!pn) return false; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 7e098daaadf7..793e585943d6 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -59,8 +59,9 @@ class MOZ_STACK_CLASS BytecodeCompiler bool checkLength(); bool createScriptSource(const Maybe& parameterListEnd); bool canLazilyParse(); - bool createParser(); - bool createSourceAndParser(const Maybe& parameterListEnd = Nothing()); + bool createParser(ParseGoal goal); + bool createSourceAndParser(ParseGoal goal, + const Maybe& parameterListEnd = Nothing()); // If toString{Start,End} are not explicitly passed, assume the script's // offsets in the source used to parse it are the same as what should be @@ -215,7 +216,7 @@ BytecodeCompiler::canLazilyParse() } bool -BytecodeCompiler::createParser() +BytecodeCompiler::createParser(ParseGoal goal) { usedNames.emplace(cx); if (!usedNames->init()) @@ -224,23 +225,24 @@ BytecodeCompiler::createParser() if (canLazilyParse()) { syntaxParser.emplace(cx, alloc, options, sourceBuffer.get(), sourceBuffer.length(), /* foldConstants = */ false, *usedNames, nullptr, nullptr, - sourceObject); + sourceObject, goal); if (!syntaxParser->checkOptions()) return false; } parser.emplace(cx, alloc, options, sourceBuffer.get(), sourceBuffer.length(), /* foldConstants = */ true, *usedNames, syntaxParser.ptrOr(nullptr), nullptr, - sourceObject); + sourceObject, goal); parser->ss = scriptSource; return parser->checkOptions(); } bool -BytecodeCompiler::createSourceAndParser(const Maybe& parameterListEnd /* = Nothing() */) +BytecodeCompiler::createSourceAndParser(ParseGoal goal, + const Maybe& parameterListEnd /* = Nothing() */) { return createScriptSource(parameterListEnd) && - createParser(); + createParser(goal); } bool @@ -314,7 +316,7 @@ BytecodeCompiler::deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObj JSScript* BytecodeCompiler::compileScript(HandleObject environment, SharedContext* sc) { - if (!createSourceAndParser()) + if (!createSourceAndParser(ParseGoal::Script)) return nullptr; TokenStreamPosition startPosition(keepAtoms, parser->tokenStream); @@ -390,7 +392,7 @@ BytecodeCompiler::compileEvalScript(HandleObject environment, HandleScope enclos ModuleObject* BytecodeCompiler::compileModule() { - if (!createSourceAndParser()) + if (!createSourceAndParser(ParseGoal::Module)) return nullptr; Rooted module(cx, ModuleObject::create(cx)); @@ -449,7 +451,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun, MOZ_ASSERT(fun); MOZ_ASSERT(fun->isTenured()); - if (!createSourceAndParser(parameterListEnd)) + if (!createSourceAndParser(ParseGoal::Script, parameterListEnd)) return false; TokenStreamPosition startPosition(keepAtoms, parser->tokenStream); @@ -780,7 +782,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha RootedScriptSourceObject sourceObject(cx, &lazy->sourceObject()); Parser parser(cx, cx->tempLifoAlloc(), options, chars, length, /* foldConstants = */ true, usedNames, nullptr, - lazy, sourceObject); + lazy, sourceObject, lazy->parseGoal()); if (!parser.checkOptions()) return false; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c0783004d3f9..2c2a7885d15c 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3303,6 +3303,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) // Trivial binary nodes with more token pos holders. case ParseNodeKind::NewTarget: + case ParseNodeKind::ImportMeta: MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::PosHolder)); MOZ_ASSERT(pn->pn_right->isKind(ParseNodeKind::PosHolder)); @@ -11146,6 +11147,10 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: return false; break; + case ParseNodeKind::ImportMeta: + MOZ_CRASH("NYI"); + break; + case ParseNodeKind::SetThis: if (!emitSetThis(pn)) return false; diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index a9f34ce78491..079194d5d607 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -375,6 +375,7 @@ ContainsHoistedDeclaration(JSContext* cx, ParseNode* node, bool* result) case ParseNodeKind::ClassMethodList: case ParseNodeKind::ClassNames: case ParseNodeKind::NewTarget: + case ParseNodeKind::ImportMeta: case ParseNodeKind::PosHolder: case ParseNodeKind::SuperCall: case ParseNodeKind::SuperBase: @@ -1725,6 +1726,7 @@ Fold(JSContext* cx, ParseNode** pnp, PerHandlerParser& parser) Fold(cx, &pn->pn_right, parser); case ParseNodeKind::NewTarget: + case ParseNodeKind::ImportMeta: MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::PosHolder)); MOZ_ASSERT(pn->pn_right->isKind(ParseNodeKind::PosHolder)); diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index a7af2cf391cf..48ee87009a02 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -560,6 +560,10 @@ class FullParseHandler return new_(ParseNodeKind::ExportBatchSpec, JSOP_NOP, pos); } + ParseNode* newImportMeta(ParseNode* importHolder, ParseNode* metaHolder) { + return new_(ParseNodeKind::ImportMeta, JSOP_NOP, importHolder, metaHolder); + } + ParseNode* newExprStatement(ParseNode* expr, uint32_t end) { MOZ_ASSERT(expr->pn_pos.end <= end); return new_(ParseNodeKind::ExpressionStatement, diff --git a/js/src/frontend/NameAnalysisTypes.h b/js/src/frontend/NameAnalysisTypes.h index b24799b8e363..d72d45cbc721 100644 --- a/js/src/frontend/NameAnalysisTypes.h +++ b/js/src/frontend/NameAnalysisTypes.h @@ -64,6 +64,12 @@ class EnvironmentCoordinate namespace frontend { +enum class ParseGoal : uint8_t +{ + Script, + Module +}; + // A detailed kind used for tracking declarations in the Parser. Used for // specific early error semantics and better error messages. enum class DeclarationKind : uint8_t diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index 9dd5b9a6d3db..0528ebcadac2 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -417,6 +417,7 @@ class NameResolver break; case ParseNodeKind::NewTarget: + case ParseNodeKind::ImportMeta: MOZ_ASSERT(cur->isArity(PN_BINARY)); MOZ_ASSERT(cur->pn_left->isKind(ParseNodeKind::PosHolder)); MOZ_ASSERT(cur->pn_right->isKind(ParseNodeKind::PosHolder)); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 136bb3727417..98c02a178a87 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -132,6 +132,7 @@ class ObjectBox; F(SuperBase) \ F(SuperCall) \ F(SetThis) \ + F(ImportMeta) \ \ /* Unary operators. */ \ F(TypeOfName) \ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a59ef26a8187..478e5a092452 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -800,7 +800,8 @@ ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, bool foldConstants, UsedNameTracker& usedNames, - ScriptSourceObject* sourceObject) + ScriptSourceObject* sourceObject, + ParseGoal parseGoal) : AutoGCRooter(cx, AutoGCRooter::Tag::Parser), context(cx), alloc(alloc), @@ -816,7 +817,8 @@ ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc, checkOptionsCalled(false), #endif isUnexpectedEOF_(false), - awaitHandling_(AwaitIsName) + awaitHandling_(AwaitIsName), + parseGoal_(uint8_t(parseGoal)) { cx->frontendCollectionPool().addActiveCompilation(); tempPoolMark = alloc.mark(); @@ -853,8 +855,9 @@ PerHandlerParser::PerHandlerParser(JSContext* cx, LifoAlloc& alloc const ReadOnlyCompileOptions& options, bool foldConstants, UsedNameTracker& usedNames, LazyScript* lazyOuterFunction, - ScriptSourceObject* sourceObject) - : ParserBase(cx, alloc, options, foldConstants, usedNames, sourceObject), + ScriptSourceObject* sourceObject, + ParseGoal parseGoal) + : ParserBase(cx, alloc, options, foldConstants, usedNames, sourceObject, parseGoal), handler(cx, alloc, lazyOuterFunction) { @@ -868,8 +871,9 @@ GeneralParser::GeneralParser(JSContext* cx, LifoAlloc& allo UsedNameTracker& usedNames, SyntaxParser* syntaxParser, LazyScript* lazyOuterFunction, - ScriptSourceObject* sourceObject) - : Base(cx, alloc, options, foldConstants, usedNames, lazyOuterFunction, sourceObject), + ScriptSourceObject* sourceObject, + ParseGoal parseGoal) + : Base(cx, alloc, options, foldConstants, usedNames, lazyOuterFunction, sourceObject, parseGoal), tokenStream(cx, options, chars, length) { // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings @@ -2551,7 +2555,8 @@ PerHandlerParser::finishFunction(bool isStandaloneFunction / pc->innerFunctionsForLazy, funbox->bufStart, funbox->bufEnd, funbox->toStringStart, - funbox->startLine, funbox->startColumn); + funbox->startLine, funbox->startColumn, + parseGoal()); if (!lazy) return false; @@ -5351,6 +5356,22 @@ GeneralParser::importDeclaration() return asFinalParser()->importDeclaration(); } +template +inline typename ParseHandler::Node +GeneralParser::importDeclarationOrImportMeta(YieldHandling yieldHandling) +{ + MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import)); + + TokenKind tt; + if (!tokenStream.peekToken(&tt)) + return null(); + + if (tt == TokenKind::Dot) + return expressionStatement(yieldHandling); + + return importDeclaration(); +} + template bool Parser::checkExportedName(JSAtom* exportName) @@ -7699,7 +7720,7 @@ GeneralParser::statement(YieldHandling yieldHandling) // ImportDeclaration (only inside modules) case TokenKind::Import: - return importDeclaration(); + return importDeclarationOrImportMeta(yieldHandling); // ExportDeclaration (only inside modules) case TokenKind::Export: @@ -7892,7 +7913,7 @@ GeneralParser::statementListItem(YieldHandling yieldHandlin // ImportDeclaration (only inside modules) case TokenKind::Import: - return importDeclaration(); + return importDeclarationOrImportMeta(yieldHandling); // ExportDeclaration (only inside modules) case TokenKind::Export: @@ -8714,6 +8735,10 @@ GeneralParser::memberExpr(YieldHandling yieldHandling, lhs = handler.newSuperBase(thisName, pos()); if (!lhs) return null(); + } else if (tt == TokenKind::Import) { + lhs = importMeta(); + if (!lhs) + return null(); } else { lhs = primaryExpr(yieldHandling, tripledotHandling, tt, possibleError, invoked); if (!lhs) @@ -9890,6 +9915,45 @@ GeneralParser::tryNewTarget(Node &newTarget) return !!newTarget; } +template +typename ParseHandler::Node +GeneralParser::importMeta() +{ + MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import)); + + uint32_t begin = pos().begin; + + if (parseGoal() != ParseGoal::Module) { + errorAt(begin, JSMSG_IMPORT_OUTSIDE_MODULE); + return null(); + } + + Node importHolder = handler.newPosHolder(pos()); + if (!importHolder) + return null(); + + TokenKind next; + if (!tokenStream.getToken(&next)) + return null(); + if (next != TokenKind::Dot) { + error(JSMSG_UNEXPECTED_TOKEN, "dot", TokenKindToDesc(next)); + return null(); + } + + if (!tokenStream.getToken(&next)) + return null(); + if (next != TokenKind::Meta) { + error(JSMSG_UNEXPECTED_TOKEN, "meta", TokenKindToDesc(next)); + return null(); + } + + Node metaHolder = handler.newPosHolder(pos()); + if (!metaHolder) + return null(); + + return handler.newImportMeta(importHolder, metaHolder); +} + template typename ParseHandler::Node GeneralParser::primaryExpr(YieldHandling yieldHandling, diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index a32c4963d2e4..5f567061576d 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -295,16 +295,22 @@ class MOZ_STACK_CLASS ParserBase /* AwaitHandling */ uint8_t awaitHandling_:2; + /* ParseGoal */ uint8_t parseGoal_:1; + public: bool awaitIsKeyword() const { return awaitHandling_ != AwaitIsName; } + ParseGoal parseGoal() const { + return ParseGoal(parseGoal_); + } + template friend class AutoAwaitIsKeyword; ParserBase(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, bool foldConstants, UsedNameTracker& usedNames, - ScriptSourceObject* sourceObject); + ScriptSourceObject* sourceObject, ParseGoal parseGoal); ~ParserBase(); bool checkOptions(); @@ -469,7 +475,8 @@ class MOZ_STACK_CLASS PerHandlerParser PerHandlerParser(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, bool foldConstants, UsedNameTracker& usedNames, LazyScript* lazyOuterFunction, - ScriptSourceObject* sourceObject); + ScriptSourceObject* sourceObject, + ParseGoal parseGoal); static Node null() { return ParseHandler::null(); } @@ -662,6 +669,7 @@ class MOZ_STACK_CLASS GeneralParser using Base::alloc; using Base::awaitIsKeyword; + using Base::parseGoal; #if DEBUG using Base::checkOptionsCalled; #endif @@ -872,7 +880,8 @@ class MOZ_STACK_CLASS GeneralParser const CharT* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames, SyntaxParser* syntaxParser, LazyScript* lazyOuterFunction, - ScriptSourceObject* sourceObject); + ScriptSourceObject* sourceObject, + ParseGoal parseGoal); inline void setAwaitHandling(AwaitHandling awaitHandling); @@ -1013,6 +1022,7 @@ class MOZ_STACK_CLASS GeneralParser Node lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind); inline Node importDeclaration(); + Node importDeclarationOrImportMeta(YieldHandling yieldHandling); Node exportFrom(uint32_t begin, Node specList); Node exportBatch(uint32_t begin); @@ -1112,6 +1122,8 @@ class MOZ_STACK_CLASS GeneralParser bool tryNewTarget(Node& newTarget); + Node importMeta(); + Node methodDefinition(uint32_t toStringStart, PropertyType propType, HandleAtom funName); /* diff --git a/js/src/frontend/ReservedWords.h b/js/src/frontend/ReservedWords.h index 04267c9d2361..5cc4e106ba0b 100644 --- a/js/src/frontend/ReservedWords.h +++ b/js/src/frontend/ReservedWords.h @@ -66,6 +66,7 @@ macro(from, from, TokenKind::From) \ macro(get, get, TokenKind::Get) \ macro(let, let, TokenKind::Let) \ + macro(meta, meta, TokenKind::Meta) \ macro(of, of, TokenKind::Of) \ macro(set, set, TokenKind::Set) \ macro(static, static_, TokenKind::Static) \ diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 8d1c07c92c96..eb393c698340 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -297,6 +297,9 @@ class SyntaxParseHandler Node newExportBatchSpec(const TokenPos& pos) { return NodeGeneric; } + Node newImportMeta(Node importHolder, Node metaHolder) { + return NodeGeneric; + } Node newSetThis(Node thisName, Node value) { return value; } diff --git a/js/src/frontend/TokenKind.h b/js/src/frontend/TokenKind.h index 9e529c7133e9..6060dd953ce7 100644 --- a/js/src/frontend/TokenKind.h +++ b/js/src/frontend/TokenKind.h @@ -127,6 +127,7 @@ macro(From, "'from'") \ macro(Get, "'get'") \ macro(Let, "'let'") \ + macro(Meta, "'meta'") \ macro(Of, "'of'") \ macro(Set, "'set'") \ macro(Static, "'static'") \ diff --git a/js/src/jit-test/tests/modules/import-meta-expression.js b/js/src/jit-test/tests/modules/import-meta-expression.js new file mode 100644 index 000000000000..bf2c9e0d0ac0 --- /dev/null +++ b/js/src/jit-test/tests/modules/import-meta-expression.js @@ -0,0 +1,97 @@ +load(libdir + "match.js"); +load(libdir + "asserts.js"); + +var { Pattern, MatchError } = Match; + +program = (elts) => Pattern({ + type: "Program", + body: elts +}); +expressionStatement = (expression) => Pattern({ + type: "ExpressionStatement", + expression: expression +}); +assignmentExpression = (left, operator, right) => Pattern({ + type: "AssignmentExpression", + operator: operator, + left: left, + right: right +}); +ident = (name) => Pattern({ + type: "Identifier", + name: name +}); +metaProperty = (meta, property) => Pattern({ + type: "MetaProperty", + meta: meta, + property: property +}); +memberExpression = (object, property) => Pattern({ + type: "MemberExpression", + object: object, + property: property +}); + +function parseAsModule(source) +{ + return Reflect.parse(source, {target: "module"}); +} + +program([ + expressionStatement( + metaProperty( + ident("import"), + ident("meta") + ) + ) +]).assert(parseAsModule("import.meta;")); + +program([ + expressionStatement( + assignmentExpression( + ident("x"), + "=", + metaProperty( + ident("import"), + ident("meta") + ) + ) + ) +]).assert(parseAsModule("x = import.meta;")); + +program([ + expressionStatement( + assignmentExpression( + memberExpression( + metaProperty( + ident("import"), + ident("meta") + ), + ident("foo") + ), + "=", + ident("x"), + ) + ) +]).assert(parseAsModule("import.meta.foo = x;")); + +function assertModuleParseThrowsSyntaxError(source) +{ + assertThrowsInstanceOf(() => parseAsModule(source), SyntaxError); +} + +function assertModuleParseThrowsReferenceError(source) +{ + assertThrowsInstanceOf(() => parseAsModule(source), ReferenceError); +} + +assertModuleParseThrowsSyntaxError("import"); +assertModuleParseThrowsSyntaxError("import."); +assertModuleParseThrowsSyntaxError("import.met"); +assertModuleParseThrowsSyntaxError("import.metaa"); +assertModuleParseThrowsSyntaxError("x = import"); +assertModuleParseThrowsSyntaxError("x = import."); +assertModuleParseThrowsSyntaxError("x = import.met"); +assertModuleParseThrowsSyntaxError("x = import.metaa"); + +assertModuleParseThrowsReferenceError("import.meta = x"); diff --git a/js/src/js.msg b/js/src/js.msg index 3ceeeae4b5dc..0f6cadd5dfd3 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -261,6 +261,7 @@ 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_BAD_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid escape sequence") MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character") +MSG_DEF(JSMSG_IMPORT_OUTSIDE_MODULE, 0, JSEXN_SYNTAXERR, "the import keyword may only appear in a module") 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") diff --git a/js/src/jsapi-tests/testBinASTReader.cpp b/js/src/jsapi-tests/testBinASTReader.cpp index 3d583cba27cb..d361f8442bef 100644 --- a/js/src/jsapi-tests/testBinASTReader.cpp +++ b/js/src/jsapi-tests/testBinASTReader.cpp @@ -177,7 +177,7 @@ runTestFromPath(JSContext* cx, const char* path) js::frontend::Parser txtParser( cx, allocScope.alloc(), txtOptions, txtSource.begin(), txtSource.length(), /* foldConstants = */ false, txtUsedNames, nullptr, - nullptr, sourceObject); + nullptr, sourceObject, frontend::ParseGoal::Script); if (!txtParser.checkOptions()) MOZ_CRASH("Bad options"); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 27a5e40fbb57..dbf4180db1d1 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4479,7 +4479,8 @@ JS_BufferIsCompilableUnit(JSContext* cx, HandleObject obj, const char* utf8, siz options, chars, length, /* foldConstants = */ true, usedNames, nullptr, nullptr, - sourceObject); + sourceObject, + frontend::ParseGoal::Script); JS::WarningReporter older = JS::SetWarningReporter(cx, nullptr); if (!parser.checkOptions() || !parser.parse()) { // We ran into an error. If it was because we ran out of source, we diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 8dde97184189..29708024d59f 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4518,7 +4518,7 @@ Parse(JSContext* cx, unsigned argc, Value* vp) Parser parser(cx, cx->tempLifoAlloc(), options, chars, length, /* foldConstants = */ false, usedNames, nullptr, - nullptr, sourceObject); + nullptr, sourceObject, ParseGoal::Script); if (!parser.checkOptions()) return false; @@ -4576,7 +4576,8 @@ SyntaxParse(JSContext* cx, unsigned argc, Value* vp) Parser parser(cx, cx->tempLifoAlloc(), options, chars, length, false, usedNames, nullptr, nullptr, - sourceObject); + sourceObject, + frontend::ParseGoal::Script); if (!parser.checkOptions()) return false; diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 504db9d56a4a..262fd1055aca 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -230,6 +230,7 @@ macro(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \ macro(maximumSignificantDigits, maximumSignificantDigits, "maximumSignificantDigits") \ macro(message, message, "message") \ + macro(meta, meta, "meta") \ macro(minDays, minDays, "minDays") \ macro(minimumFractionDigits, minimumFractionDigits, "minimumFractionDigits") \ macro(minimumIntegerDigits, minimumIntegerDigits, "minimumIntegerDigits") \ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index ae7dcf2f15e0..da774911fe00 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -5061,7 +5061,8 @@ Debugger::isCompilableUnit(JSContext* cx, unsigned argc, Value* vp) length, /* foldConstants = */ true, usedNames, nullptr, nullptr, - sourceObject); + sourceObject, + frontend::ParseGoal::Script); JS::WarningReporter older = JS::SetWarningReporter(cx, nullptr); if (!parser.checkOptions() || !parser.parse()) { // We ran into an error. If it was because we ran out of memory we report diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp index fcdb6c538972..9cee41113a0d 100644 --- a/js/src/vm/JSScript.cpp +++ b/js/src/vm/JSScript.cpp @@ -4302,7 +4302,8 @@ LazyScript::Create(JSContext* cx, HandleFunction fun, const frontend::AtomVector& closedOverBindings, Handle> innerFunctions, uint32_t sourceStart, uint32_t sourceEnd, - uint32_t toStringStart, uint32_t lineno, uint32_t column) + uint32_t toStringStart, uint32_t lineno, uint32_t column, + frontend::ParseGoal parseGoal) { union { PackedView p; @@ -4323,6 +4324,7 @@ LazyScript::Create(JSContext* cx, HandleFunction fun, p.isLikelyConstructorWrapper = false; p.isDerivedClassConstructor = false; p.needsHomeObject = false; + p.parseGoal = uint32_t(parseGoal); LazyScript* res = LazyScript::CreateRaw(cx, fun, sourceObject, packedFields, sourceStart, sourceEnd, diff --git a/js/src/vm/JSScript.h b/js/src/vm/JSScript.h index 2fdb9d7af45d..98921c997547 100644 --- a/js/src/vm/JSScript.h +++ b/js/src/vm/JSScript.h @@ -2187,6 +2187,7 @@ class LazyScript : public gc::TenuredCell uint32_t isDerivedClassConstructor : 1; uint32_t needsHomeObject : 1; uint32_t hasRest : 1; + uint32_t parseGoal : 1; }; union { @@ -2229,7 +2230,8 @@ class LazyScript : public gc::TenuredCell const frontend::AtomVector& closedOverBindings, Handle> innerFunctions, uint32_t begin, uint32_t end, - uint32_t toStringStart, uint32_t lineno, uint32_t column); + uint32_t toStringStart, uint32_t lineno, uint32_t column, + frontend::ParseGoal parseGoal); // Create a LazyScript and initialize the closedOverBindings and the // innerFunctions with dummy values to be replaced in a later initialization @@ -2326,6 +2328,10 @@ class LazyScript : public gc::TenuredCell p_.hasRest = true; } + frontend::ParseGoal parseGoal() const { + return frontend::ParseGoal(p_.parseGoal); + } + bool strict() const { return p_.strict; }