mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-27 20:25:44 +00:00
Bug 1446811 - Support exporting array and object binding patterns r=jorendorff a=abillings
This commit is contained in:
parent
524a6c226d
commit
1747f82987
@ -1382,14 +1382,25 @@ ModuleBuilder::processExport(frontend::ParseNode* pn)
|
||||
case ParseNodeKind::Const:
|
||||
case ParseNodeKind::Let: {
|
||||
MOZ_ASSERT(kid->isArity(PN_LIST));
|
||||
for (ParseNode* var = kid->pn_head; var; var = var->pn_next) {
|
||||
if (var->isKind(ParseNodeKind::Assign))
|
||||
var = var->pn_left;
|
||||
MOZ_ASSERT(var->isKind(ParseNodeKind::Name));
|
||||
RootedAtom localName(cx_, var->pn_atom);
|
||||
RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
|
||||
if (!appendExportEntry(exportName, localName))
|
||||
return false;
|
||||
for (ParseNode* binding = kid->pn_head; binding; binding = binding->pn_next) {
|
||||
if (binding->isKind(ParseNodeKind::Assign))
|
||||
binding = binding->pn_left;
|
||||
else
|
||||
MOZ_ASSERT(binding->isKind(ParseNodeKind::Name));
|
||||
|
||||
if (binding->isKind(ParseNodeKind::Name)) {
|
||||
RootedAtom localName(cx_, binding->pn_atom);
|
||||
RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
|
||||
if (!appendExportEntry(exportName, localName))
|
||||
return false;
|
||||
} else if (binding->isKind(ParseNodeKind::Array)) {
|
||||
if (!processExportArrayBinding(binding))
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(binding->isKind(ParseNodeKind::Object));
|
||||
if (!processExportObjectBinding(binding))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1412,6 +1423,68 @@ ModuleBuilder::processExport(frontend::ParseNode* pn)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleBuilder::processExportBinding(frontend::ParseNode* binding)
|
||||
{
|
||||
if (binding->isKind(ParseNodeKind::Name)) {
|
||||
RootedAtom name(cx_, binding->pn_atom);
|
||||
return appendExportEntry(name, name);
|
||||
}
|
||||
|
||||
if (binding->isKind(ParseNodeKind::Array))
|
||||
return processExportArrayBinding(binding);
|
||||
|
||||
MOZ_ASSERT(binding->isKind(ParseNodeKind::Object));
|
||||
return processExportObjectBinding(binding);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleBuilder::processExportArrayBinding(frontend::ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(ParseNodeKind::Array));
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
|
||||
for (ParseNode* node = pn->pn_head; node; node = node->pn_next) {
|
||||
if (node->isKind(ParseNodeKind::Elision))
|
||||
continue;
|
||||
|
||||
if (node->isKind(ParseNodeKind::Spread))
|
||||
node = node->pn_kid;
|
||||
else if (node->isKind(ParseNodeKind::Assign))
|
||||
node = node->pn_left;
|
||||
|
||||
if (!processExportBinding(node))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleBuilder::processExportObjectBinding(frontend::ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(ParseNodeKind::Object));
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
|
||||
for (ParseNode* node = pn->pn_head; node; node = node->pn_next) {
|
||||
MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) ||
|
||||
node->isKind(ParseNodeKind::Colon) ||
|
||||
node->isKind(ParseNodeKind::Shorthand));
|
||||
|
||||
ParseNode* target = node->isKind(ParseNodeKind::MutateProto)
|
||||
? node->pn_kid
|
||||
: node->pn_right;
|
||||
|
||||
if (target->isKind(ParseNodeKind::Assign))
|
||||
target = target->pn_left;
|
||||
|
||||
if (!processExportBinding(target))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleBuilder::processExportFrom(frontend::ParseNode* pn)
|
||||
{
|
||||
|
@ -392,6 +392,10 @@ class MOZ_STACK_CLASS ModuleBuilder
|
||||
|
||||
ImportEntryObject* importEntryFor(JSAtom* localName) const;
|
||||
|
||||
bool processExportBinding(frontend::ParseNode* pn);
|
||||
bool processExportArrayBinding(frontend::ParseNode* pn);
|
||||
bool processExportObjectBinding(frontend::ParseNode* pn);
|
||||
|
||||
bool appendExportEntry(HandleAtom exportName, HandleAtom localName,
|
||||
frontend::ParseNode* node = nullptr);
|
||||
bool appendExportFromEntry(HandleAtom exportName, HandleAtom moduleRequest,
|
||||
|
@ -5316,16 +5316,101 @@ GeneralParser<ParseHandler, CharT>::checkExportedName(JSAtom* exportName)
|
||||
return asFinalParser()->checkExportedName(exportName);
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
bool
|
||||
Parser<FullParseHandler, CharT>::checkExportedNamesForArrayBinding(ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(ParseNodeKind::Array));
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
|
||||
for (ParseNode* node = pn->pn_head; node; node = node->pn_next) {
|
||||
if (node->isKind(ParseNodeKind::Elision))
|
||||
continue;
|
||||
|
||||
ParseNode* binding;
|
||||
if (node->isKind(ParseNodeKind::Spread))
|
||||
binding = node->pn_kid;
|
||||
else if (node->isKind(ParseNodeKind::Assign))
|
||||
binding = node->pn_left;
|
||||
else
|
||||
binding = node;
|
||||
|
||||
if (!checkExportedNamesForDeclaration(binding))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
inline bool
|
||||
Parser<SyntaxParseHandler, CharT>::checkExportedNamesForArrayBinding(Node node)
|
||||
{
|
||||
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class ParseHandler, typename CharT>
|
||||
inline bool
|
||||
GeneralParser<ParseHandler, CharT>::checkExportedNamesForArrayBinding(Node node)
|
||||
{
|
||||
return asFinalParser()->checkExportedNamesForArrayBinding(node);
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
bool
|
||||
Parser<FullParseHandler, CharT>::checkExportedNamesForObjectBinding(ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(ParseNodeKind::Object));
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
|
||||
for (ParseNode* node = pn->pn_head; node; node = node->pn_next) {
|
||||
MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) ||
|
||||
node->isKind(ParseNodeKind::Colon) ||
|
||||
node->isKind(ParseNodeKind::Shorthand));
|
||||
|
||||
ParseNode* target = node->isKind(ParseNodeKind::MutateProto)
|
||||
? node->pn_kid
|
||||
: node->pn_right;
|
||||
|
||||
if (target->isKind(ParseNodeKind::Assign))
|
||||
target = target->pn_left;
|
||||
|
||||
if (!checkExportedNamesForDeclaration(target))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
inline bool
|
||||
Parser<SyntaxParseHandler, CharT>::checkExportedNamesForObjectBinding(Node node)
|
||||
{
|
||||
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class ParseHandler, typename CharT>
|
||||
inline bool
|
||||
GeneralParser<ParseHandler, CharT>::checkExportedNamesForObjectBinding(Node node)
|
||||
{
|
||||
return asFinalParser()->checkExportedNamesForObjectBinding(node);
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
bool
|
||||
Parser<FullParseHandler, CharT>::checkExportedNamesForDeclaration(ParseNode* node)
|
||||
{
|
||||
MOZ_ASSERT(node->isArity(PN_LIST));
|
||||
for (ParseNode* binding = node->pn_head; binding; binding = binding->pn_next) {
|
||||
if (binding->isKind(ParseNodeKind::Assign))
|
||||
binding = binding->pn_left;
|
||||
MOZ_ASSERT(binding->isKind(ParseNodeKind::Name));
|
||||
if (!checkExportedName(binding->pn_atom))
|
||||
if (node->isKind(ParseNodeKind::Name)) {
|
||||
if (!checkExportedName(node->pn_atom))
|
||||
return false;
|
||||
} else if (node->isKind(ParseNodeKind::Array)) {
|
||||
if (!checkExportedNamesForArrayBinding(node))
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(node->isKind(ParseNodeKind::Object));
|
||||
if (!checkExportedNamesForObjectBinding(node))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5347,6 +5432,39 @@ GeneralParser<ParseHandler, CharT>::checkExportedNamesForDeclaration(Node node)
|
||||
return asFinalParser()->checkExportedNamesForDeclaration(node);
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
bool
|
||||
Parser<FullParseHandler, CharT>::checkExportedNamesForDeclarationList(ParseNode* node)
|
||||
{
|
||||
MOZ_ASSERT(node->isArity(PN_LIST));
|
||||
for (ParseNode* binding = node->pn_head; binding; binding = binding->pn_next) {
|
||||
if (binding->isKind(ParseNodeKind::Assign))
|
||||
binding = binding->pn_left;
|
||||
else
|
||||
MOZ_ASSERT(binding->isKind(ParseNodeKind::Name));
|
||||
|
||||
if (!checkExportedNamesForDeclaration(binding))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
inline bool
|
||||
Parser<SyntaxParseHandler, CharT>::checkExportedNamesForDeclarationList(Node node)
|
||||
{
|
||||
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class ParseHandler, typename CharT>
|
||||
inline bool
|
||||
GeneralParser<ParseHandler, CharT>::checkExportedNamesForDeclarationList(Node node)
|
||||
{
|
||||
return asFinalParser()->checkExportedNamesForDeclarationList(node);
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
inline bool
|
||||
Parser<FullParseHandler, CharT>::checkExportedNameForClause(ParseNode* node)
|
||||
@ -5648,7 +5766,7 @@ GeneralParser<ParseHandler, CharT>::exportVariableStatement(uint32_t begin)
|
||||
return null();
|
||||
if (!matchOrInsertSemicolon())
|
||||
return null();
|
||||
if (!checkExportedNamesForDeclaration(kid))
|
||||
if (!checkExportedNamesForDeclarationList(kid))
|
||||
return null();
|
||||
|
||||
Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
|
||||
@ -5729,7 +5847,7 @@ GeneralParser<ParseHandler, CharT>::exportLexicalDeclaration(uint32_t begin, Dec
|
||||
Node kid = lexicalDeclaration(YieldIsName, kind);
|
||||
if (!kid)
|
||||
return null();
|
||||
if (!checkExportedNamesForDeclaration(kid))
|
||||
if (!checkExportedNamesForDeclarationList(kid))
|
||||
return null();
|
||||
|
||||
Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
|
||||
|
@ -1152,7 +1152,10 @@ class GeneralParser
|
||||
TokenKind tt);
|
||||
|
||||
inline bool checkExportedName(JSAtom* exportName);
|
||||
inline bool checkExportedNamesForArrayBinding(Node node);
|
||||
inline bool checkExportedNamesForObjectBinding(Node node);
|
||||
inline bool checkExportedNamesForDeclaration(Node node);
|
||||
inline bool checkExportedNamesForDeclarationList(Node node);
|
||||
inline bool checkExportedNameForFunction(Node node);
|
||||
inline bool checkExportedNameForClass(Node node);
|
||||
inline bool checkExportedNameForClause(Node node);
|
||||
@ -1346,7 +1349,10 @@ class Parser<SyntaxParseHandler, CharT> final
|
||||
inline Node importDeclaration();
|
||||
inline bool checkLocalExportNames(Node node);
|
||||
inline bool checkExportedName(JSAtom* exportName);
|
||||
inline bool checkExportedNamesForArrayBinding(Node node);
|
||||
inline bool checkExportedNamesForObjectBinding(Node node);
|
||||
inline bool checkExportedNamesForDeclaration(Node node);
|
||||
inline bool checkExportedNamesForDeclarationList(Node node);
|
||||
inline bool checkExportedNameForFunction(Node node);
|
||||
inline bool checkExportedNameForClass(Node node);
|
||||
inline bool checkExportedNameForClause(Node node);
|
||||
@ -1461,7 +1467,10 @@ class Parser<FullParseHandler, CharT> final
|
||||
Node importDeclaration();
|
||||
bool checkLocalExportNames(Node node);
|
||||
bool checkExportedName(JSAtom* exportName);
|
||||
bool checkExportedNamesForArrayBinding(Node node);
|
||||
bool checkExportedNamesForObjectBinding(Node node);
|
||||
bool checkExportedNamesForDeclaration(Node node);
|
||||
bool checkExportedNamesForDeclarationList(Node node);
|
||||
bool checkExportedNameForFunction(Node node);
|
||||
bool checkExportedNameForClass(Node node);
|
||||
inline bool checkExportedNameForClause(Node node);
|
||||
|
106
js/src/jit-test/tests/modules/export-destructuring.js
Normal file
106
js/src/jit-test/tests/modules/export-destructuring.js
Normal file
@ -0,0 +1,106 @@
|
||||
load(libdir + "dummyModuleResolveHook.js");
|
||||
|
||||
function assertArrayEq(value, expected)
|
||||
{
|
||||
assertEq(value instanceof Array, true);
|
||||
assertEq(value.length, expected.length);
|
||||
for (let i = 0; i < value.length; i++)
|
||||
assertEq(value[i], expected[i]);
|
||||
}
|
||||
|
||||
moduleRepo['a'] = parseModule(`
|
||||
export const [] = [];
|
||||
export const [a=0] = [];
|
||||
export const [b] = [1];
|
||||
export const [c, d, e] = [2, 3, 4];
|
||||
export const [, f, g] = [5, 6, 7];
|
||||
export const [h,, i] = [8, 9, 10];
|
||||
export const [,, j] = [11, 12, 13];
|
||||
export const [...k] = [14, 15, 16];
|
||||
export const [l, ...m] = [17, 18, 19];
|
||||
export const [,, ...n] = [20, 21, 22];
|
||||
`);
|
||||
|
||||
m = parseModule(`
|
||||
import * as a from 'a';
|
||||
|
||||
assertEq(a.a, 0);
|
||||
assertEq(a.b, 1);
|
||||
assertEq(a.c, 2);
|
||||
assertEq(a.d, 3);
|
||||
assertEq(a.e, 4);
|
||||
assertEq(a.f, 6);
|
||||
assertEq(a.g, 7);
|
||||
assertEq(a.h, 8);
|
||||
assertEq(a.i, 10);
|
||||
assertEq(a.j, 13);
|
||||
assertArrayEq(a.k, [14, 15, 16]);
|
||||
assertEq(a.l, 17);
|
||||
assertArrayEq(a.m, [18, 19]);
|
||||
assertArrayEq(a.n, [22]);
|
||||
`);
|
||||
|
||||
m.declarationInstantiation();
|
||||
m.evaluation();
|
||||
|
||||
moduleRepo['o'] = parseModule(`
|
||||
export const {} = {};
|
||||
export const {x: a=0} = {};
|
||||
export const {x: b=0} = {x: 1};
|
||||
export const {c, d, e} = {c: 2, d: 3, e: 4};
|
||||
export const {x: f} = {x: 5};
|
||||
export const {g} = {};
|
||||
export const {h=6} = {};
|
||||
`);
|
||||
|
||||
m = parseModule(`
|
||||
import * as o from 'o';
|
||||
|
||||
assertEq(o.a, 0);
|
||||
assertEq(o.b, 1);
|
||||
assertEq(o.c, 2);
|
||||
assertEq(o.d, 3);
|
||||
assertEq(o.e, 4);
|
||||
assertEq(o.f, 5);
|
||||
assertEq(o.g, undefined);
|
||||
assertEq(o.h, 6);
|
||||
`);
|
||||
|
||||
m.declarationInstantiation();
|
||||
m.evaluation();
|
||||
|
||||
moduleRepo['ao'] = parseModule(`
|
||||
export const [{x: a}, {x: b}] = [{x: 1}, {x: 2}];
|
||||
export const [{c}, {d}] = [{c: 3}, {d: 4}];
|
||||
export const [,, {e}, ...f] = [5, 6, {e: 7}, 8, 9];
|
||||
|
||||
export const {x: [g, h, i]} = {x: [10, 11, 12]};
|
||||
|
||||
export const [[], [...j], [, k, l]] = [[], [13, 14], [15, 16, 17]];
|
||||
|
||||
export const {x: {m, n, o=20}, y: {z: p}} = {x: {m: 18, n: 19}, y: {z: 21}};
|
||||
`);
|
||||
|
||||
m = parseModule(`
|
||||
import * as ao from 'ao';
|
||||
|
||||
assertEq(ao.a, 1);
|
||||
assertEq(ao.b, 2);
|
||||
assertEq(ao.c, 3);
|
||||
assertEq(ao.d, 4);
|
||||
assertEq(ao.e, 7);
|
||||
assertArrayEq(ao.f, [8, 9]);
|
||||
assertEq(ao.g, 10);
|
||||
assertEq(ao.h, 11);
|
||||
assertEq(ao.i, 12);
|
||||
assertArrayEq(ao.j, [13, 14]);
|
||||
assertEq(ao.k, 16);
|
||||
assertEq(ao.l, 17);
|
||||
assertEq(ao.m, 18);
|
||||
assertEq(ao.n, 19);
|
||||
assertEq(ao.o, 20);
|
||||
assertEq(ao.p, 21);
|
||||
`);
|
||||
|
||||
m.declarationInstantiation();
|
||||
m.evaluation();
|
Loading…
Reference in New Issue
Block a user