Bug 1670044 - Part 7: Add separate ImportNamespaceSpec and ExportNamespaceSpec parse nodes. r=yulia,tcampbell

The approach to use "*" for namespace imports/exports no longer works with
module export names. As an alternative add separate ImportNamespaceSpec and
ExportNamespaceSpec parse nodes. They're currently still implemented as binary
nodes, but the next part will change this.

Differential Revision: https://phabricator.services.mozilla.com/D101012
This commit is contained in:
André Bargull 2021-02-09 19:05:35 +00:00
parent 38e8e4ba47
commit 96e2220bd1
14 changed files with 212 additions and 30 deletions

View File

@ -1545,7 +1545,8 @@ bool ModuleBuilder::processImport(frontend::BinaryNode* importNode) {
for (ParseNode* item : specList->contents()) {
BinaryNode* spec = &item->as<BinaryNode>();
MOZ_ASSERT(spec->isKind(ParseNodeKind::ImportSpec));
MOZ_ASSERT(spec->isKind(ParseNodeKind::ImportSpec) ||
spec->isKind(ParseNodeKind::ImportNamespaceSpec));
NameNode* importNameNode = &spec->left()->as<NameNode>();
NameNode* localNameNode = &spec->right()->as<NameNode>();
@ -1561,8 +1562,16 @@ bool ModuleBuilder::processImport(frontend::BinaryNode* importNode) {
markUsedByStencil(module);
markUsedByStencil(localName);
markUsedByStencil(importName);
auto entry = frontend::StencilModuleEntry::importEntry(
module, localName, importName, line, column);
StencilModuleEntry entry;
if (spec->isKind(ParseNodeKind::ImportSpec)) {
entry = StencilModuleEntry::importEntry(module, localName, importName,
line, column);
} else {
entry = StencilModuleEntry::importNamespaceEntry(
module, localName, importName, line, column);
}
if (!importEntries_.put(localName, entry)) {
return false;
}
@ -1768,35 +1777,48 @@ bool ModuleBuilder::processExportFrom(frontend::BinaryNode* exportNode) {
eitherParser_.computeLineAndColumn(spec->pn_pos.begin, &line, &column);
StencilModuleEntry entry;
TaggedParserAtomIndex exportName;
if (spec->isKind(ParseNodeKind::ExportSpec)) {
auto* importNameNode = &spec->as<BinaryNode>().left()->as<NameNode>();
auto* exportNameNode = &spec->as<BinaryNode>().right()->as<NameNode>();
auto importName = importNameNode->atom();
auto exportName = exportNameNode->atom();
exportName = exportNameNode->atom();
markUsedByStencil(module);
markUsedByStencil(importName);
markUsedByStencil(exportName);
entry = StencilModuleEntry::exportFromEntry(module, importName,
exportName, line, column);
} else if (spec->isKind(ParseNodeKind::ExportNamespaceSpec)) {
auto* importNameNode = &spec->as<BinaryNode>().left()->as<NameNode>();
auto* exportNameNode = &spec->as<BinaryNode>().right()->as<NameNode>();
if (!exportNames_.put(exportName)) {
return false;
}
auto importName = importNameNode->atom();
exportName = exportNameNode->atom();
markUsedByStencil(module);
markUsedByStencil(importName);
markUsedByStencil(exportName);
entry = StencilModuleEntry::exportNamespaceFromEntry(
module, importName, exportName, line, column);
} else {
MOZ_ASSERT(spec->isKind(ParseNodeKind::ExportBatchSpecStmt));
auto importName = TaggedParserAtomIndex::WellKnown::star();
markUsedByStencil(module);
markUsedByStencil(importName);
entry = StencilModuleEntry::exportFromEntry(
module, importName, TaggedParserAtomIndex::null(), line, column);
entry = StencilModuleEntry::exportBatchFromEntry(module, importName, line,
column);
}
if (!exportEntries_.append(entry)) {
return false;
}
if (exportName && !exportNames_.put(exportName)) {
return false;
}
}
return true;

View File

@ -690,14 +690,14 @@ bool js::obj_toString(JSContext* cx, unsigned argc, Value* vp) {
if (!tag.isString()) {
if (!builtinTag) {
builtinTag = GetBuiltinTagFast(obj, clasp, cx);
#ifdef DEBUG
#ifdef DEBUG
// Assert this fast path is correct and matches BuiltinTagSlow.
JSString* builtinTagSlow = GetBuiltinTagSlow(cx, obj);
if (!builtinTagSlow) {
return false;
}
MOZ_ASSERT(builtinTagSlow == builtinTag);
#endif
#endif
}
args.rval().setString(builtinTag);

View File

@ -608,6 +608,11 @@ class NodeBuilder {
HandleValue bindingName, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool importNamespaceSpecifier(HandleValue importName,
HandleValue bindingName,
TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool exportDeclaration(HandleValue decl, NodeVector& elts,
HandleValue moduleSpec,
HandleValue isDefault, TokenPos* pos,
@ -617,6 +622,11 @@ class NodeBuilder {
HandleValue exportName, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool exportNamespaceSpecifier(HandleValue bindingName,
HandleValue exportName,
TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool classDefinition(bool expr, HandleValue name,
@ -1395,6 +1405,19 @@ bool NodeBuilder::importSpecifier(HandleValue importName,
dst);
}
bool NodeBuilder::importNamespaceSpecifier(HandleValue importName,
HandleValue bindingName,
TokenPos* pos,
MutableHandleValue dst) {
RootedValue cb(cx, callbacks[AST_IMPORT_NAMESPACE_SPEC]);
if (!cb.isNull()) {
return callback(cb, importName, bindingName, pos, dst);
}
return newNode(AST_IMPORT_NAMESPACE_SPEC, pos, "id", importName, "name",
bindingName, dst);
}
bool NodeBuilder::exportDeclaration(HandleValue decl, NodeVector& elts,
HandleValue moduleSpec,
HandleValue isDefault, TokenPos* pos,
@ -1426,6 +1449,19 @@ bool NodeBuilder::exportSpecifier(HandleValue bindingName,
dst);
}
bool NodeBuilder::exportNamespaceSpecifier(HandleValue bindingName,
HandleValue exportName,
TokenPos* pos,
MutableHandleValue dst) {
RootedValue cb(cx, callbacks[AST_EXPORT_NAMESPACE_SPEC]);
if (!cb.isNull()) {
return callback(cb, bindingName, exportName, pos, dst);
}
return newNode(AST_EXPORT_NAMESPACE_SPEC, pos, "id", bindingName, "name",
exportName, dst);
}
bool NodeBuilder::exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst) {
RootedValue cb(cx, callbacks[AST_EXPORT_BATCH_SPEC]);
if (!cb.isNull()) {
@ -1677,8 +1713,10 @@ class ASTSerializer {
bool variableDeclarator(ParseNode* pn, MutableHandleValue dst);
bool importDeclaration(BinaryNode* importNode, MutableHandleValue dst);
bool importSpecifier(BinaryNode* importSpec, MutableHandleValue dst);
bool importNamespaceSpecifier(BinaryNode* importSpec, MutableHandleValue dst);
bool exportDeclaration(ParseNode* exportNode, MutableHandleValue dst);
bool exportSpecifier(BinaryNode* exportSpec, MutableHandleValue dst);
bool exportNamespaceSpecifier(BinaryNode* exportSpec, MutableHandleValue dst);
bool classDefinition(ClassNode* pn, bool expr, MutableHandleValue dst);
bool optStatement(ParseNode* pn, MutableHandleValue dst) {
@ -2049,10 +2087,16 @@ bool ASTSerializer::importDeclaration(BinaryNode* importNode,
}
for (ParseNode* item : specList->contents()) {
BinaryNode* spec = &item->as<BinaryNode>();
auto* spec = &item->as<BinaryNode>();
RootedValue elt(cx);
if (!importSpecifier(spec, &elt)) {
return false;
if (spec->isKind(ParseNodeKind::ImportNamespaceSpec)) {
if (!importNamespaceSpecifier(spec, &elt)) {
return false;
}
} else {
if (!importSpecifier(spec, &elt)) {
return false;
}
}
elts.infallibleAppend(elt);
}
@ -2076,6 +2120,20 @@ bool ASTSerializer::importSpecifier(BinaryNode* importSpec,
dst);
}
bool ASTSerializer::importNamespaceSpecifier(BinaryNode* importSpec,
MutableHandleValue dst) {
MOZ_ASSERT(importSpec->isKind(ParseNodeKind::ImportNamespaceSpec));
NameNode* importNameNode = &importSpec->left()->as<NameNode>();
NameNode* bindingNameNode = &importSpec->right()->as<NameNode>();
RootedValue importName(cx);
RootedValue bindingName(cx);
return identifierOrLiteral(importNameNode, &importName) &&
identifier(bindingNameNode, &bindingName) &&
builder.importNamespaceSpecifier(importName, bindingName,
&importSpec->pn_pos, dst);
}
bool ASTSerializer::exportDeclaration(ParseNode* exportNode,
MutableHandleValue dst) {
MOZ_ASSERT(exportNode->isKind(ParseNodeKind::ExportStmt) ||
@ -2106,7 +2164,12 @@ bool ASTSerializer::exportDeclaration(ParseNode* exportNode,
if (!exportSpecifier(&spec->as<BinaryNode>(), &elt)) {
return false;
}
} else if (spec->isKind(ParseNodeKind::ExportNamespaceSpec)) {
if (!exportNamespaceSpecifier(&spec->as<BinaryNode>(), &elt)) {
return false;
}
} else {
MOZ_ASSERT(spec->isKind(ParseNodeKind::ExportBatchSpecStmt));
if (!builder.exportBatchSpecifier(&exportNode->pn_pos, &elt)) {
return false;
}
@ -2174,6 +2237,20 @@ bool ASTSerializer::exportSpecifier(BinaryNode* exportSpec,
dst);
}
bool ASTSerializer::exportNamespaceSpecifier(BinaryNode* exportSpec,
MutableHandleValue dst) {
MOZ_ASSERT(exportSpec->isKind(ParseNodeKind::ExportNamespaceSpec));
NameNode* bindingNameNode = &exportSpec->left()->as<NameNode>();
NameNode* exportNameNode = &exportSpec->right()->as<NameNode>();
RootedValue bindingName(cx);
RootedValue exportName(cx);
return identifierOrLiteral(bindingNameNode, &bindingName) &&
identifierOrLiteral(exportNameNode, &exportName) &&
builder.exportNamespaceSpecifier(bindingName, exportName,
&exportSpec->pn_pos, dst);
}
bool ASTSerializer::switchCase(CaseClause* caseClause, MutableHandleValue dst) {
MOZ_ASSERT_IF(
caseClause->caseExpression(),

View File

@ -1536,9 +1536,11 @@ restart:
case ParseNodeKind::ClassMemberList: // by ParseNodeKind::ClassDecl
case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
case ParseNodeKind::ImportSpec: // by ParseNodeKind::Import
case ParseNodeKind::ImportNamespaceSpec: // by ParseNodeKind::Import
case ParseNodeKind::ExportBatchSpecStmt: // by ParseNodeKind::Export
case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
case ParseNodeKind::ExportSpec: // by ParseNodeKind::Export
case ParseNodeKind::ExportNamespaceSpec: // by ParseNodeKind::Export
case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others

View File

@ -163,10 +163,12 @@ restart:
case ParseNodeKind::ImportDecl:
case ParseNodeKind::ImportSpecList:
case ParseNodeKind::ImportSpec:
case ParseNodeKind::ImportNamespaceSpec:
case ParseNodeKind::ExportFromStmt:
case ParseNodeKind::ExportDefaultStmt:
case ParseNodeKind::ExportSpecList:
case ParseNodeKind::ExportSpec:
case ParseNodeKind::ExportNamespaceSpec:
case ParseNodeKind::ExportStmt:
case ParseNodeKind::ExportBatchSpecStmt:
case ParseNodeKind::CallImportExpr:

View File

@ -649,6 +649,11 @@ class FullParseHandler {
return newBinary(ParseNodeKind::ImportSpec, importNameNode, bindingName);
}
BinaryNodeType newImportNamespaceSpec(Node importNameNode, Node bindingName) {
return newBinary(ParseNodeKind::ImportNamespaceSpec, importNameNode,
bindingName);
}
UnaryNodeType newExportDeclaration(Node kid, const TokenPos& pos) {
return new_<UnaryNode>(ParseNodeKind::ExportStmt, pos, kid);
}
@ -681,6 +686,11 @@ class FullParseHandler {
return newBinary(ParseNodeKind::ExportSpec, bindingName, exportName);
}
BinaryNodeType newExportNamespaceSpec(Node bindingName, Node exportName) {
return newBinary(ParseNodeKind::ExportNamespaceSpec, bindingName,
exportName);
}
NullaryNodeType newExportBatchSpec(const TokenPos& pos) {
return new_<NullaryNode>(ParseNodeKind::ExportBatchSpecStmt, pos);
}

View File

@ -421,9 +421,13 @@ class NameResolver : public ParseNodeVisitor<NameResolver> {
MOZ_ASSERT(item->is<NullaryNode>());
} else {
for (ParseNode* item : pn->contents()) {
BinaryNode* spec = &item->as<BinaryNode>();
MOZ_ASSERT(spec->isKind(isImport ? ParseNodeKind::ImportSpec
: ParseNodeKind::ExportSpec));
auto* spec = &item->as<BinaryNode>();
MOZ_ASSERT_IF(isImport,
spec->isKind(ParseNodeKind::ImportSpec) ||
spec->isKind(ParseNodeKind::ImportNamespaceSpec));
MOZ_ASSERT_IF(!isImport,
spec->isKind(ParseNodeKind::ExportSpec) ||
spec->isKind(ParseNodeKind::ExportNamespaceSpec));
MOZ_ASSERT(spec->left()->isKind(ParseNodeKind::Name) ||
spec->left()->isKind(ParseNodeKind::StringExpr));
MOZ_ASSERT(spec->right()->isKind(ParseNodeKind::Name) ||

View File

@ -145,11 +145,13 @@ class FunctionBox;
F(ImportDecl, BinaryNode) \
F(ImportSpecList, ListNode) \
F(ImportSpec, BinaryNode) \
F(ImportNamespaceSpec, BinaryNode) \
F(ExportStmt, UnaryNode) \
F(ExportFromStmt, BinaryNode) \
F(ExportDefaultStmt, BinaryNode) \
F(ExportSpecList, ListNode) \
F(ExportSpec, BinaryNode) \
F(ExportNamespaceSpec, BinaryNode) \
F(ExportBatchSpecStmt, NullaryNode) \
F(ForIn, TernaryNode) \
F(ForOf, TernaryNode) \
@ -401,6 +403,9 @@ inline bool IsTypeofKind(ParseNodeKind kind) {
* ImportSpec (BinaryNode)
* left: import name
* right: local binding name
* ImportNamespaceSpec (BinaryNode)
* left: import name
* right: local binding name
* ExportStmt (UnaryNode)
* kid: declaration expression
* ExportFromStmt (BinaryNode)
@ -412,6 +417,9 @@ inline bool IsTypeofKind(ParseNodeKind kind) {
* ExportSpec (BinaryNode)
* left: local binding name
* right: export name
* ExportNamespaceSpec (BinaryNode)
* left: local binding name
* right: export name
* ExportDefaultStmt (BinaryNode)
* left: export default declaration or expression
* right: Name node for assignment

View File

@ -4933,7 +4933,7 @@ bool GeneralParser<ParseHandler, Unit>::namespaceImport(
pc_->varScope().lookupDeclaredName(bindingName)->value()->setClosedOver();
BinaryNodeType importSpec =
handler_.newImportSpec(importName, bindingNameNode);
handler_.newImportNamespaceSpec(importName, bindingNameNode);
if (!importSpec) {
return false;
}
@ -5449,7 +5449,8 @@ GeneralParser<ParseHandler, Unit>::exportBatch(uint32_t begin) {
return null();
}
BinaryNodeType exportSpec = handler_.newExportSpec(importName, exportName);
BinaryNodeType exportSpec =
handler_.newExportNamespaceSpec(importName, exportName);
if (!exportSpec) {
return null();
}

View File

@ -476,12 +476,16 @@ using FunctionDeclarationVector =
// for readability.
class StencilModuleEntry {
public:
// | ModuleRequest | ImportEntry | ExportAs | ExportFrom |
// |-----------------------------------------------------|
// specifier | required | required | nullptr | required |
// localName | null | required | required | nullptr |
// importName | null | required | nullptr | required |
// exportName | null | null | required | optional |
// clang-format off
//
// | ModuleRequest | ImportEntry | ImportNamespaceEntry | ExportAs | ExportFrom | ExportNamespaceFrom | ExportBatchFrom |
// |--------------------------------------------------------------------------------------------------------------------|
// specifier | required | required | required | null | required | required | required |
// localName | null | required | required | required | null | null | null |
// importName | null | required | required | null | required | required | required |
// exportName | null | null | null | required | required | required | null |
//
// clang-format on
TaggedParserAtomIndex specifier;
TaggedParserAtomIndex localName;
TaggedParserAtomIndex importName;
@ -522,6 +526,17 @@ class StencilModuleEntry {
return entry;
}
static StencilModuleEntry importNamespaceEntry(
TaggedParserAtomIndex specifier, TaggedParserAtomIndex localName,
TaggedParserAtomIndex importName, uint32_t lineno, uint32_t column) {
MOZ_ASSERT(specifier && localName && importName);
StencilModuleEntry entry(lineno, column);
entry.specifier = specifier;
entry.localName = localName;
entry.importName = importName;
return entry;
}
static StencilModuleEntry exportAsEntry(TaggedParserAtomIndex localName,
TaggedParserAtomIndex exportName,
uint32_t lineno, uint32_t column) {
@ -536,14 +551,34 @@ class StencilModuleEntry {
TaggedParserAtomIndex importName,
TaggedParserAtomIndex exportName,
uint32_t lineno, uint32_t column) {
// NOTE: The `export * from "mod";` syntax generates nullptr exportName.
MOZ_ASSERT(specifier && importName);
MOZ_ASSERT(specifier && importName && exportName);
StencilModuleEntry entry(lineno, column);
entry.specifier = specifier;
entry.importName = importName;
entry.exportName = exportName;
return entry;
}
static StencilModuleEntry exportNamespaceFromEntry(
TaggedParserAtomIndex specifier, TaggedParserAtomIndex importName,
TaggedParserAtomIndex exportName, uint32_t lineno, uint32_t column) {
MOZ_ASSERT(specifier && importName && exportName);
StencilModuleEntry entry(lineno, column);
entry.specifier = specifier;
entry.importName = importName;
entry.exportName = exportName;
return entry;
}
static StencilModuleEntry exportBatchFromEntry(
TaggedParserAtomIndex specifier, TaggedParserAtomIndex importName,
uint32_t lineno, uint32_t column) {
MOZ_ASSERT(specifier && importName);
StencilModuleEntry entry(lineno, column);
entry.specifier = specifier;
entry.importName = importName;
return entry;
}
};
// Metadata generated by parsing module scripts, including import/export tables.

View File

@ -415,6 +415,9 @@ class SyntaxParseHandler {
BinaryNodeType newImportSpec(Node importNameNode, Node bindingName) {
return NodeGeneric;
}
BinaryNodeType newImportNamespaceSpec(Node importNameNode, Node bindingName) {
return NodeGeneric;
}
UnaryNodeType newExportDeclaration(Node kid, const TokenPos& pos) {
return NodeGeneric;
}
@ -429,6 +432,9 @@ class SyntaxParseHandler {
BinaryNodeType newExportSpec(Node bindingName, Node exportName) {
return NodeGeneric;
}
BinaryNodeType newExportNamespaceSpec(Node bindingName, Node exportName) {
return NodeGeneric;
}
NullaryNodeType newExportBatchSpec(const TokenPos& pos) {
return NodeGeneric;
}

View File

@ -17,6 +17,11 @@ importSpecifier = (id, name) => Pattern({
id: id,
name: name
});
importNamespaceSpecifier = (id, name) => Pattern({
type: "ImportNamespaceSpecifier",
id: id,
name: name
});
ident = (name) => Pattern({
type: "Identifier",
name: name
@ -46,7 +51,7 @@ program([
program([
importDeclaration(
[
importSpecifier(
importNamespaceSpecifier(
ident("*"),
ident("a")
)
@ -117,7 +122,7 @@ program([
ident("default"),
ident("a")
),
importSpecifier(
importNamespaceSpecifier(
ident("*"),
ident("b")
)

View File

@ -65,8 +65,10 @@ ASTDEF(AST_DEBUGGER_STMT, "DebuggerStatement", "debuggerSta
ASTDEF(AST_LET_STMT, "LetStatement", "letStatement")
ASTDEF(AST_IMPORT_DECL, "ImportDeclaration", "importDeclaration")
ASTDEF(AST_IMPORT_SPEC, "ImportSpecifier", "importSpecifier")
ASTDEF(AST_IMPORT_NAMESPACE_SPEC, "ImportNamespaceSpecifier", "importNamespaceSpecifier")
ASTDEF(AST_EXPORT_DECL, "ExportDeclaration", "exportDeclaration")
ASTDEF(AST_EXPORT_SPEC, "ExportSpecifier", "exportSpecifier")
ASTDEF(AST_EXPORT_NAMESPACE_SPEC, "ExportNamespaceSpecifier", "exportNamespaceSpecifier")
ASTDEF(AST_EXPORT_BATCH_SPEC, "ExportBatchSpecifier", "exportBatchSpecifier")
ASTDEF(AST_CASE, "SwitchCase", "switchCase")

View File

@ -34,6 +34,14 @@ function exportSpec(id, name) {
};
}
function exportNamespaceSpec(id, name) {
return {
type: "ExportNamespaceSpecifier",
id,
name,
};
}
function assertModule(src, patt) {
program(patt).assert(Reflect.parse(src, {target: "module"}));
}
@ -79,7 +87,7 @@ assertModule(`
assertModule(`
export * as "x" from "module";
`, [
exportDecl(null, [exportSpec(ident("*"), literal("x"))], literal("module"), false),
exportDecl(null, [exportNamespaceSpec(ident("*"), literal("x"))], literal("module"), false),
]);
if (typeof reportCompare === "function")