Commit bd16dc8f authored by Daniel Clark's avatar Daniel Clark Committed by Commit Bot

Implement parsing of AssertEntries in import assertion clause

Parse the AssertEntries in an import assertion clause, storing them in
a map.  Plumb them through the parser to the appropriate
SourceTextModuleDescriptor methods.

The next change will plumb them into the SourceTextModuleDescriptor's
ModuleRequestMap and through to SourceTextModuleInfo::New.

Bug: v8:10958
Change-Id: I19c31090520f14f94d014e760f5fe372bf773fc2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2482326Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Commit-Queue: Dan Clark <daniec@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#70622}
parent da1ea060
......@@ -31,8 +31,10 @@ bool SourceTextModuleDescriptor::AstRawStringComparer::operator()(
void SourceTextModuleDescriptor::AddImport(
const AstRawString* import_name, const AstRawString* local_name,
const AstRawString* module_request, const Scanner::Location loc,
const AstRawString* module_request,
const ImportAssertions* import_assertions, const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone) {
// TODO(v8:10958) Add import_assertions to the Entry.
Entry* entry = zone->New<Entry>(loc);
entry->local_name = local_name;
entry->import_name = import_name;
......@@ -42,8 +44,9 @@ void SourceTextModuleDescriptor::AddImport(
void SourceTextModuleDescriptor::AddStarImport(
const AstRawString* local_name, const AstRawString* module_request,
const Scanner::Location loc, const Scanner::Location specifier_loc,
Zone* zone) {
const ImportAssertions* import_assertions, const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone) {
// TODO(v8:10958) Add import_assertions to the Entry.
Entry* entry = zone->New<Entry>(loc);
entry->local_name = local_name;
entry->module_request = AddModuleRequest(module_request, specifier_loc);
......@@ -51,7 +54,10 @@ void SourceTextModuleDescriptor::AddStarImport(
}
void SourceTextModuleDescriptor::AddEmptyImport(
const AstRawString* module_request, const Scanner::Location specifier_loc) {
const AstRawString* module_request,
const ImportAssertions* import_assertions,
const Scanner::Location specifier_loc) {
// TODO(v8:10958) Add import_assertions to the Entry.
AddModuleRequest(module_request, specifier_loc);
}
......@@ -66,8 +72,10 @@ void SourceTextModuleDescriptor::AddExport(const AstRawString* local_name,
void SourceTextModuleDescriptor::AddExport(
const AstRawString* import_name, const AstRawString* export_name,
const AstRawString* module_request, const Scanner::Location loc,
const AstRawString* module_request,
const ImportAssertions* import_assertions, const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone) {
// TODO(v8:10958) Add import_assertions to the Entry.
DCHECK_NOT_NULL(import_name);
DCHECK_NOT_NULL(export_name);
Entry* entry = zone->New<Entry>(loc);
......@@ -78,8 +86,10 @@ void SourceTextModuleDescriptor::AddExport(
}
void SourceTextModuleDescriptor::AddStarExport(
const AstRawString* module_request, const Scanner::Location loc,
const AstRawString* module_request,
const ImportAssertions* import_assertions, const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone) {
// TODO(v8:10958) Add import_assertions to the Entry.
Entry* entry = zone->New<Entry>(loc);
entry->module_request = AddModuleRequest(module_request, specifier_loc);
AddSpecialExport(entry, zone);
......
......@@ -26,6 +26,10 @@ class SourceTextModuleDescriptor : public ZoneObject {
regular_exports_(zone),
regular_imports_(zone) {}
using ImportAssertions =
ZoneMap<const AstRawString*,
std::pair<const AstRawString*, Scanner::Location>>;
// The following Add* methods are high-level convenience functions for use by
// the parser.
......@@ -35,12 +39,14 @@ class SourceTextModuleDescriptor : public ZoneObject {
void AddImport(const AstRawString* import_name,
const AstRawString* local_name,
const AstRawString* module_request,
const ImportAssertions* import_assertions,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
// import * as x from "foo.js";
void AddStarImport(const AstRawString* local_name,
const AstRawString* module_request,
const ImportAssertions* import_assertions,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
......@@ -48,6 +54,7 @@ class SourceTextModuleDescriptor : public ZoneObject {
// import {} from "foo.js";
// export {} from "foo.js"; (sic!)
void AddEmptyImport(const AstRawString* module_request,
const ImportAssertions* import_assertions,
const Scanner::Location specifier_loc);
// export {x};
......@@ -64,11 +71,13 @@ class SourceTextModuleDescriptor : public ZoneObject {
void AddExport(const AstRawString* export_name,
const AstRawString* import_name,
const AstRawString* module_request,
const ImportAssertions* import_assertions,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
// export * from "foo.js";
void AddStarExport(const AstRawString* module_request,
const ImportAssertions* import_assertions,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
......
......@@ -92,6 +92,7 @@ namespace internal {
T(IllegalInvocation, "Illegal invocation") \
T(ImmutablePrototypeSet, \
"Immutable prototype object '%' cannot have their prototype set") \
T(ImportAssertionDuplicateKey, "Import assertion has duplicate key '%'") \
T(ImportCallNotNewExpression, "Cannot use new with import") \
T(ImportOutsideModule, "Cannot use import statement outside a module") \
T(ImportMetaOutsideModule, "Cannot use 'import.meta' outside a module") \
......
......@@ -1174,7 +1174,7 @@ ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports(int pos) {
return result;
}
void Parser::ParseImportAssertClause() {
Parser::ImportAssertions* Parser::ParseImportAssertClause() {
// AssertClause :
// assert '{' '}'
// assert '{' AssertEntries '}'
......@@ -1187,21 +1187,58 @@ void Parser::ParseImportAssertClause() {
// IdentifierName
// StringLiteral
auto import_assertions = zone()->New<ImportAssertions>(zone());
if (!FLAG_harmony_import_assertions) {
return;
return import_assertions;
}
// Assert clause is optional, and cannot be preceded by a LineTerminator.
if (scanner()->HasLineTerminatorBeforeNext() ||
!CheckContextualKeyword(ast_value_factory()->assert_string())) {
return;
return import_assertions;
}
Expect(Token::LBRACE);
// TODO(v8:10958) Parse the list of assertions and return the result.
while (peek() != Token::RBRACE) {
const AstRawString* attribute_key = nullptr;
if (Check(Token::STRING)) {
attribute_key = GetSymbol();
} else {
attribute_key = ParsePropertyName();
}
Scanner::Location location = scanner()->location();
Expect(Token::COLON);
Expect(Token::STRING);
const AstRawString* attribute_value = GetSymbol();
// Set the location to the whole "key: 'value'"" string, so that it makes
// sense both for errors due to the key and errors due to the value.
location.end_pos = scanner()->location().end_pos;
auto result = import_assertions->insert(std::make_pair(
attribute_key, std::make_pair(attribute_value, location)));
if (!result.second) {
// It is a syntax error if two AssertEntries have the same key.
ReportMessageAt(location, MessageTemplate::kImportAssertionDuplicateKey,
attribute_key);
break;
}
if (peek() == Token::RBRACE) break;
if (V8_UNLIKELY(!Check(Token::COMMA))) {
ReportUnexpectedToken(Next());
break;
}
}
Expect(Token::RBRACE);
return import_assertions;
}
void Parser::ParseImportDeclaration() {
......@@ -1231,9 +1268,10 @@ void Parser::ParseImportDeclaration() {
if (tok == Token::STRING) {
Scanner::Location specifier_loc = scanner()->peek_location();
const AstRawString* module_specifier = ParseModuleSpecifier();
ParseImportAssertClause();
const ImportAssertions* import_assertions = ParseImportAssertClause();
ExpectSemicolon();
module()->AddEmptyImport(module_specifier, specifier_loc);
module()->AddEmptyImport(module_specifier, import_assertions,
specifier_loc);
return;
}
......@@ -1276,7 +1314,7 @@ void Parser::ParseImportDeclaration() {
ExpectContextualKeyword(ast_value_factory()->from_string());
Scanner::Location specifier_loc = scanner()->peek_location();
const AstRawString* module_specifier = ParseModuleSpecifier();
ParseImportAssertClause();
const ImportAssertions* import_assertions = ParseImportAssertClause();
ExpectSemicolon();
// Now that we have all the information, we can make the appropriate
......@@ -1289,24 +1327,26 @@ void Parser::ParseImportDeclaration() {
if (module_namespace_binding != nullptr) {
module()->AddStarImport(module_namespace_binding, module_specifier,
module_namespace_binding_loc, specifier_loc,
zone());
import_assertions, module_namespace_binding_loc,
specifier_loc, zone());
}
if (import_default_binding != nullptr) {
module()->AddImport(ast_value_factory()->default_string(),
import_default_binding, module_specifier,
import_default_binding_loc, specifier_loc, zone());
import_assertions, import_default_binding_loc,
specifier_loc, zone());
}
if (named_imports != nullptr) {
if (named_imports->length() == 0) {
module()->AddEmptyImport(module_specifier, specifier_loc);
module()->AddEmptyImport(module_specifier, import_assertions,
specifier_loc);
} else {
for (const NamedImport* import : *named_imports) {
module()->AddImport(import->import_name, import->local_name,
module_specifier, import->location, specifier_loc,
zone());
module_specifier, import_assertions,
import->location, specifier_loc, zone());
}
}
}
......@@ -1396,9 +1436,10 @@ void Parser::ParseExportStar() {
ExpectContextualKeyword(ast_value_factory()->from_string());
Scanner::Location specifier_loc = scanner()->peek_location();
const AstRawString* module_specifier = ParseModuleSpecifier();
ParseImportAssertClause();
const ImportAssertions* import_assertions = ParseImportAssertClause();
ExpectSemicolon();
module()->AddStarExport(module_specifier, loc, specifier_loc, zone());
module()->AddStarExport(module_specifier, import_assertions, loc,
specifier_loc, zone());
return;
}
if (!FLAG_harmony_namespace_exports) return;
......@@ -1421,11 +1462,11 @@ void Parser::ParseExportStar() {
ExpectContextualKeyword(ast_value_factory()->from_string());
Scanner::Location specifier_loc = scanner()->peek_location();
const AstRawString* module_specifier = ParseModuleSpecifier();
ParseImportAssertClause();
const ImportAssertions* import_assertions = ParseImportAssertClause();
ExpectSemicolon();
module()->AddStarImport(local_name, module_specifier, local_name_loc,
specifier_loc, zone());
module()->AddStarImport(local_name, module_specifier, import_assertions,
local_name_loc, specifier_loc, zone());
module()->AddExport(local_name, export_name, export_name_loc, zone());
}
......@@ -1474,16 +1515,17 @@ Statement* Parser::ParseExportDeclaration() {
if (CheckContextualKeyword(ast_value_factory()->from_string())) {
Scanner::Location specifier_loc = scanner()->peek_location();
const AstRawString* module_specifier = ParseModuleSpecifier();
ParseImportAssertClause();
const ImportAssertions* import_assertions = ParseImportAssertClause();
ExpectSemicolon();
if (export_data->is_empty()) {
module()->AddEmptyImport(module_specifier, specifier_loc);
module()->AddEmptyImport(module_specifier, import_assertions,
specifier_loc);
} else {
for (const ExportClauseData& data : *export_data) {
module()->AddExport(data.local_name, data.export_name,
module_specifier, data.location, specifier_loc,
zone());
module_specifier, import_assertions,
data.location, specifier_loc, zone());
}
}
} else {
......
......@@ -281,7 +281,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
location(location) {}
};
ZonePtrList<const NamedImport>* ParseNamedImports(int pos);
void ParseImportAssertClause();
using ImportAssertions =
ZoneMap<const AstRawString*,
std::pair<const AstRawString*, Scanner::Location>>;
ImportAssertions* ParseImportAssertClause();
Statement* BuildInitializationBlock(DeclarationParsingResult* parsing_result);
Expression* RewriteReturn(Expression* return_value, int pos);
Statement* RewriteSwitchStatement(SwitchStatement* switch_statement,
......
......@@ -84,7 +84,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 48 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
/* 53 S> */ B(Wide), B(LdaSmi), I16(269),
/* 53 S> */ B(Wide), B(LdaSmi), I16(270),
B(Star), R(3),
B(LdaConstant), U8(0),
B(Star), R(4),
......@@ -115,7 +115,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 41 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
/* 46 S> */ B(Wide), B(LdaSmi), I16(268),
/* 46 S> */ B(Wide), B(LdaSmi), I16(269),
B(Star), R(3),
B(LdaConstant), U8(0),
B(Star), R(4),
......@@ -146,7 +146,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 48 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
/* 53 S> */ B(Wide), B(LdaSmi), I16(269),
/* 53 S> */ B(Wide), B(LdaSmi), I16(270),
B(Star), R(3),
B(LdaConstant), U8(0),
B(Star), R(4),
......@@ -177,7 +177,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 41 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
/* 46 S> */ B(Wide), B(LdaSmi), I16(268),
/* 46 S> */ B(Wide), B(LdaSmi), I16(269),
B(Star), R(4),
B(LdaConstant), U8(0),
B(Star), R(5),
......
......@@ -57,7 +57,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 44 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
/* 49 S> */ B(Wide), B(LdaSmi), I16(267),
/* 49 S> */ B(Wide), B(LdaSmi), I16(268),
B(Star), R(3),
B(LdaConstant), U8(0),
B(Star), R(4),
......@@ -89,7 +89,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 44 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
/* 49 S> */ B(Wide), B(LdaSmi), I16(267),
/* 49 S> */ B(Wide), B(LdaSmi), I16(268),
B(Star), R(3),
B(LdaConstant), U8(0),
B(Star), R(4),
......
......@@ -25,7 +25,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(1),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(265),
B(Wide), B(LdaSmi), I16(266),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
......@@ -56,7 +56,7 @@ frame size: 2
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 56 S> */ B(Wide), B(LdaSmi), I16(267),
/* 56 S> */ B(Wide), B(LdaSmi), I16(268),
B(Star), R(0),
B(LdaConstant), U8(0),
B(Star), R(1),
......@@ -83,7 +83,7 @@ frame size: 2
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 56 S> */ B(Wide), B(LdaSmi), I16(267),
/* 56 S> */ B(Wide), B(LdaSmi), I16(268),
B(Star), R(0),
B(LdaConstant), U8(0),
B(Star), R(1),
......@@ -122,7 +122,7 @@ bytecodes: [
/* 94 E> */ B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(265),
B(Wide), B(LdaSmi), I16(266),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
......@@ -144,7 +144,7 @@ bytecodes: [
/* 109 E> */ B(TestReferenceEqual), R(this),
B(Mov), R(this), R(1),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(266),
B(Wide), B(LdaSmi), I16(267),
B(Star), R(3),
B(LdaConstant), U8(0),
B(Star), R(4),
......@@ -159,7 +159,7 @@ bytecodes: [
/* 133 E> */ B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(265),
B(Wide), B(LdaSmi), I16(266),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
......@@ -189,7 +189,7 @@ frame size: 2
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 60 S> */ B(Wide), B(LdaSmi), I16(269),
/* 60 S> */ B(Wide), B(LdaSmi), I16(270),
B(Star), R(0),
B(LdaConstant), U8(0),
B(Star), R(1),
......@@ -215,7 +215,7 @@ frame size: 2
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 53 S> */ B(Wide), B(LdaSmi), I16(268),
/* 53 S> */ B(Wide), B(LdaSmi), I16(269),
B(Star), R(0),
B(LdaConstant), U8(0),
B(Star), R(1),
......@@ -241,7 +241,7 @@ frame size: 2
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 60 S> */ B(Wide), B(LdaSmi), I16(269),
/* 60 S> */ B(Wide), B(LdaSmi), I16(270),
B(Star), R(0),
B(LdaConstant), U8(0),
B(Star), R(1),
......@@ -267,7 +267,7 @@ frame size: 3
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 46 S> */ B(Wide), B(LdaSmi), I16(268),
/* 46 S> */ B(Wide), B(LdaSmi), I16(269),
B(Star), R(1),
B(LdaConstant), U8(0),
B(Star), R(2),
......
......@@ -5010,6 +5010,21 @@ TEST(BasicImportAssertionParsing) {
"export * from 'm.js' assert { };",
"import 'm.js' assert { };",
"import * as foo from 'bar.js' assert { };",
"import { a as b } from 'm.js' assert { a: 'b' };",
"import { a as b } from 'm.js' assert { c: 'd' };",
"import { a as b } from 'm.js' assert { 'c': 'd' };",
"import { a as b } from 'm.js' assert { a: 'b', 'c': 'd', e: 'f' };",
"import { a as b } from 'm.js' assert { 'c': 'd', };",
"import n from 'n.js' assert { 'c': 'd' };",
"export { a as b } from 'm.js' assert { 'c': 'd' };",
"export * from 'm.js' assert { 'c': 'd' };",
"import 'm.js' assert { 'c': 'd' };",
"import * as foo from 'bar.js' assert { 'c': 'd' };",
"import { a as b } from 'm.js' assert { \nc: 'd'};",
"import { a as b } from 'm.js' assert { c:\n 'd'};",
"import { a as b } from 'm.js' assert { c:'d'\n};",
};
// clang-format on
......@@ -5075,7 +5090,10 @@ TEST(ImportAssertionParsingErrors) {
"import { a } from 'm.js' assert { 1: 2 };",
"import { a } from 'm.js' assert { b: c };",
"import { a } from 'm.js' assert { 'b': c };",
"import { a } from 'm.js' assert { , b: c };",
"import { a } from 'm.js' assert { a: 'b', a: 'c' };",
"import { a } from 'm.js' assert { a: 'b', 'a': 'c' };",
};
// clang-format on
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment