[parser] Parser support for import assertions in dynamic import()
There's a bit more work to do to add support for import assertions for dynamic import(). This is the first of a series of changes to do that. This adds parser support for the form of import() that takes import assertions per https://tc39.es/proposal-import-assertions/#prod-ImportCall A future change will pass the assertions expression along to Runtime_DynamicImportCall where the assertions will be unpacked and filtered per Isolate::supported_import_assertions_. Bug: v8:10958 Change-Id: Ib1c80d15ac44923d97c5fdfcc4bd732cb9245cf9 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2612038 Reviewed-by: Adam Klein <adamk@chromium.org> Reviewed-by: Marja Hölttä <marja@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Commit-Queue: Dan Clark <daniec@microsoft.com> Cr-Commit-Position: refs/heads/master@{#71960}
This commit is contained in:
parent
34e7ae615d
commit
2893b9fbd6
@ -536,7 +536,10 @@ template <class Subclass>
|
||||
void AstTraversalVisitor<Subclass>::VisitImportCallExpression(
|
||||
ImportCallExpression* expr) {
|
||||
PROCESS_EXPRESSION(expr);
|
||||
RECURSE_EXPRESSION(Visit(expr->argument()));
|
||||
RECURSE_EXPRESSION(Visit(expr->specifier()));
|
||||
if (expr->import_assertions()) {
|
||||
RECURSE_EXPRESSION(Visit(expr->import_assertions()));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Subclass>
|
||||
|
@ -2543,16 +2543,26 @@ class SuperCallReference final : public Expression {
|
||||
// import(argument).
|
||||
class ImportCallExpression final : public Expression {
|
||||
public:
|
||||
Expression* argument() const { return argument_; }
|
||||
Expression* specifier() const { return specifier_; }
|
||||
Expression* import_assertions() const { return import_assertions_; }
|
||||
|
||||
private:
|
||||
friend class AstNodeFactory;
|
||||
friend Zone;
|
||||
|
||||
ImportCallExpression(Expression* argument, int pos)
|
||||
: Expression(pos, kImportCallExpression), argument_(argument) {}
|
||||
ImportCallExpression(Expression* specifier, int pos)
|
||||
: Expression(pos, kImportCallExpression),
|
||||
specifier_(specifier),
|
||||
import_assertions_(nullptr) {}
|
||||
|
||||
Expression* argument_;
|
||||
ImportCallExpression(Expression* specifier, Expression* import_assertions,
|
||||
int pos)
|
||||
: Expression(pos, kImportCallExpression),
|
||||
specifier_(specifier),
|
||||
import_assertions_(import_assertions) {}
|
||||
|
||||
Expression* specifier_;
|
||||
Expression* import_assertions_;
|
||||
};
|
||||
|
||||
// This class is produced when parsing the () in arrow functions without any
|
||||
@ -3227,8 +3237,15 @@ class AstNodeFactory final {
|
||||
return zone_->New<TemplateLiteral>(string_parts, substitutions, pos);
|
||||
}
|
||||
|
||||
ImportCallExpression* NewImportCallExpression(Expression* args, int pos) {
|
||||
return zone_->New<ImportCallExpression>(args, pos);
|
||||
ImportCallExpression* NewImportCallExpression(Expression* specifier,
|
||||
int pos) {
|
||||
return zone_->New<ImportCallExpression>(specifier, pos);
|
||||
}
|
||||
|
||||
ImportCallExpression* NewImportCallExpression(Expression* specifier,
|
||||
Expression* import_assertions,
|
||||
int pos) {
|
||||
return zone_->New<ImportCallExpression>(specifier, import_assertions, pos);
|
||||
}
|
||||
|
||||
InitializeClassMembersStatement* NewInitializeClassMembersStatement(
|
||||
|
@ -551,7 +551,10 @@ void CallPrinter::VisitTemplateLiteral(TemplateLiteral* node) {
|
||||
|
||||
void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) {
|
||||
Print("ImportCall(");
|
||||
Find(node->argument(), true);
|
||||
Find(node->specifier(), true);
|
||||
if (node->import_assertions()) {
|
||||
Find(node->import_assertions(), true);
|
||||
}
|
||||
Print(")");
|
||||
}
|
||||
|
||||
@ -1434,7 +1437,10 @@ void AstPrinter::VisitTemplateLiteral(TemplateLiteral* node) {
|
||||
|
||||
void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) {
|
||||
IndentedScope indent(this, "IMPORT-CALL", node->position());
|
||||
Visit(node->argument());
|
||||
Visit(node->specifier());
|
||||
if (node->import_assertions()) {
|
||||
Visit(node->import_assertions());
|
||||
}
|
||||
}
|
||||
|
||||
void AstPrinter::VisitThisExpression(ThisExpression* node) {
|
||||
|
@ -5621,7 +5621,7 @@ void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
|
||||
|
||||
void BytecodeGenerator::VisitImportCallExpression(ImportCallExpression* expr) {
|
||||
RegisterList args = register_allocator()->NewRegisterList(2);
|
||||
VisitForRegisterValue(expr->argument(), args[1]);
|
||||
VisitForRegisterValue(expr->specifier(), args[1]);
|
||||
builder()
|
||||
->MoveRegister(Register::function_closure(), args[0])
|
||||
.CallRuntime(Runtime::kDynamicImportCall, args);
|
||||
|
@ -3574,11 +3574,26 @@ ParserBase<Impl>::ParseImportExpressions() {
|
||||
MessageTemplate::kImportMissingSpecifier);
|
||||
return impl()->FailureExpression();
|
||||
}
|
||||
AcceptINScope scope(this, true);
|
||||
ExpressionT arg = ParseAssignmentExpressionCoverGrammar();
|
||||
Expect(Token::RPAREN);
|
||||
|
||||
return factory()->NewImportCallExpression(arg, pos);
|
||||
AcceptINScope scope(this, true);
|
||||
ExpressionT specifier = ParseAssignmentExpressionCoverGrammar();
|
||||
|
||||
if (FLAG_harmony_import_assertions && Check(Token::COMMA)) {
|
||||
if (Check(Token::RPAREN)) {
|
||||
// A trailing comma allowed after the specifier.
|
||||
return factory()->NewImportCallExpression(specifier, pos);
|
||||
} else {
|
||||
ExpressionT import_assertions = ParseAssignmentExpressionCoverGrammar();
|
||||
Check(Token::COMMA); // A trailing comma is allowed after the import
|
||||
// assertions.
|
||||
Expect(Token::RPAREN);
|
||||
return factory()->NewImportCallExpression(specifier, import_assertions,
|
||||
pos);
|
||||
}
|
||||
}
|
||||
|
||||
Expect(Token::RPAREN);
|
||||
return factory()->NewImportCallExpression(specifier, pos);
|
||||
}
|
||||
|
||||
template <typename Impl>
|
||||
|
@ -792,6 +792,12 @@ class PreParserFactory {
|
||||
return PreParserExpression::Default();
|
||||
}
|
||||
|
||||
PreParserExpression NewImportCallExpression(
|
||||
const PreParserExpression& specifier,
|
||||
const PreParserExpression& import_assertions, int pos) {
|
||||
return PreParserExpression::Default();
|
||||
}
|
||||
|
||||
private:
|
||||
// For creating VariableProxy objects to track unresolved variables.
|
||||
AstNodeFactory ast_node_factory_;
|
||||
|
@ -4854,6 +4854,35 @@ TEST(ImportExpressionSuccess) {
|
||||
RunModuleParserSyncTest(context_data, data, kSuccess);
|
||||
}
|
||||
|
||||
TEST(ImportExpressionWithImportAssertionSuccess) {
|
||||
i::FLAG_harmony_import_assertions = true;
|
||||
|
||||
// clang-format off
|
||||
const char* context_data[][2] = {
|
||||
{"", ""},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
const char* data[] = {
|
||||
"import(x,)",
|
||||
"import(x,1)",
|
||||
"import(x,y)",
|
||||
"import(x,y,)",
|
||||
"import(x, { 'a': 'b' })",
|
||||
"import(x, { a: 'b', 'c': 'd' },)",
|
||||
"import(x, { 'a': { b: 'c' }, 'd': 'e' },)",
|
||||
"import(x,import(y))",
|
||||
"import(x,y=z)",
|
||||
"import(x,[y, z])",
|
||||
"import(x,undefined)",
|
||||
nullptr
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
RunParserSyncTest(context_data, data, kSuccess);
|
||||
RunModuleParserSyncTest(context_data, data, kSuccess);
|
||||
}
|
||||
|
||||
TEST(ImportExpressionErrors) {
|
||||
{
|
||||
// clang-format off
|
||||
@ -4955,6 +4984,83 @@ TEST(ImportExpressionErrors) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ImportExpressionWithImportAssertionErrors) {
|
||||
{
|
||||
i::FLAG_harmony_import_assertions = true;
|
||||
|
||||
// clang-format off
|
||||
const char* context_data[][2] = {
|
||||
{"", ""},
|
||||
{"var ", ""},
|
||||
{"let ", ""},
|
||||
{"new ", ""},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
const char* data[] = {
|
||||
"import(x,,)",
|
||||
"import(x))",
|
||||
"import(x,))",
|
||||
"import(x,())",
|
||||
"import(x,y,,)",
|
||||
"import(x,y,z)",
|
||||
"import(x,y",
|
||||
"import(x,y,",
|
||||
"import(x,y(",
|
||||
nullptr
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
RunParserSyncTest(context_data, data, kError);
|
||||
RunModuleParserSyncTest(context_data, data, kError);
|
||||
}
|
||||
|
||||
{
|
||||
// clang-format off
|
||||
const char* context_data[][2] = {
|
||||
{"var ", ""},
|
||||
{"let ", ""},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
const char* data[] = {
|
||||
"import('x',y)",
|
||||
nullptr
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
RunParserSyncTest(context_data, data, kError);
|
||||
RunModuleParserSyncTest(context_data, data, kError);
|
||||
}
|
||||
|
||||
// Import statements as arrow function params and destructuring targets.
|
||||
{
|
||||
// clang-format off
|
||||
const char* context_data[][2] = {
|
||||
{"(", ") => {}"},
|
||||
{"(a, ", ") => {}"},
|
||||
{"(1, ", ") => {}"},
|
||||
{"let f = ", " => {}"},
|
||||
{"[", "] = [1];"},
|
||||
{"{", "} = {'a': 1};"},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
const char* data[] = {
|
||||
"import(foo,y)",
|
||||
"import(1,y)",
|
||||
"import(y=x,z)",
|
||||
"import(import(x),y)",
|
||||
"import(x,y).then()",
|
||||
nullptr
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
RunParserSyncTest(context_data, data, kError);
|
||||
RunModuleParserSyncTest(context_data, data, kError);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BasicImportAssertionParsing) {
|
||||
// clang-format off
|
||||
const char* kSources[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user