support rest parameters (#4515)

This commit is contained in:
Alex Lam S.L
2021-01-07 02:04:09 +00:00
committed by GitHub
parent 68497d0258
commit c3d358a5b8
12 changed files with 819 additions and 135 deletions

View File

@@ -1039,11 +1039,18 @@ function parse($TEXT, options) {
}
function to_funarg(node) {
if (node instanceof AST_Array) return new AST_DestructuredArray({
start: node.start,
elements: node.elements.map(to_funarg),
end: node.end,
});
if (node instanceof AST_Array) {
var rest = null;
if (node.elements[node.elements.length - 1] instanceof AST_Spread) {
rest = to_funarg(node.elements.pop().expression);
}
return new AST_DestructuredArray({
start: node.start,
elements: node.elements.map(to_funarg),
rest: rest,
end: node.end,
});
}
if (node instanceof AST_Assign) return new AST_DefaultValue({
start: node.start,
name: to_funarg(node.left),
@@ -1056,28 +1063,37 @@ function parse($TEXT, options) {
}
if (node instanceof AST_DestructuredArray) {
node.elements = node.elements.map(to_funarg);
if (node.rest) node.rest = to_funarg(node.rest);
return node;
}
if (node instanceof AST_DestructuredObject) {
node.properties.forEach(function(prop) {
prop.value = to_funarg(prop.value);
});
if (node.rest) node.rest = to_funarg(node.rest);
return node;
}
if (node instanceof AST_Hole) return node;
if (node instanceof AST_Object) return new AST_DestructuredObject({
start: node.start,
properties: node.properties.map(function(prop) {
if (!(prop instanceof AST_ObjectKeyVal)) token_error(prop.start, "Invalid destructuring assignment");
return new AST_DestructuredKeyVal({
start: prop.start,
key: prop.key,
value: to_funarg(prop.value),
end: prop.end,
});
}),
end: node.end,
});
if (node instanceof AST_Object) {
var rest = null;
if (node.properties[node.properties.length - 1] instanceof AST_Spread) {
rest = to_funarg(node.properties.pop().expression);
}
return new AST_DestructuredObject({
start: node.start,
properties: node.properties.map(function(prop) {
if (!(prop instanceof AST_ObjectKeyVal)) token_error(prop.start, "Invalid destructuring assignment");
return new AST_DestructuredKeyVal({
start: prop.start,
key: prop.key,
value: to_funarg(prop.value),
end: prop.end,
});
}),
rest: rest,
end: node.end,
});
}
if (node instanceof AST_SymbolRef) return new AST_SymbolFunarg(node);
token_error(node.start, "Invalid arrow parameter");
}
@@ -1116,6 +1132,7 @@ function parse($TEXT, options) {
return new AST_Arrow({
start: start,
argnames: argnames,
rest: exprs.rest || null,
body: body,
value: value,
end: prev(),
@@ -1155,6 +1172,7 @@ function parse($TEXT, options) {
if (S.input.has_directive("use strict")) {
if (name) strict_verify_symbol(name);
argnames.forEach(strict_verify_symbol);
if (argnames.rest) strict_verify_symbol(argnames.rest);
}
S.input.pop_directives_stack();
--S.in_function;
@@ -1164,6 +1182,7 @@ function parse($TEXT, options) {
return new ctor({
name: name,
argnames: argnames,
rest: argnames.rest || null,
body: body
});
};
@@ -1445,17 +1464,22 @@ function parse($TEXT, options) {
if (allow_trailing_comma && is("punc", closing)) break;
if (allow_empty && is("punc", ",")) {
a.push(new AST_Hole({ start: S.token, end: S.token }));
} else if (parser === maybe_assign && is("operator", "...")) {
} else if (!is("operator", "...")) {
a.push(parser());
} else if (parser === maybe_assign) {
a.push(new AST_Spread({
start: S.token,
expression: (next(), parser()),
end: prev(),
}));
} else {
a.push(parser());
next();
a.rest = parser();
if (a.rest instanceof AST_DefaultValue) token_error(a.rest.start, "Invalid rest parameter");
break;
}
}
next();
expect(closing);
return a;
}
@@ -1634,17 +1658,19 @@ function parse($TEXT, options) {
var start = S.token;
if (is("punc", "[")) {
next();
var elements = expr_list("]", !options.strict, true, function() {
return maybe_default(type);
});
return new AST_DestructuredArray({
start: start,
elements: expr_list("]", !options.strict, true, function() {
return maybe_default(type);
}),
elements: elements,
rest: elements.rest || null,
end: prev(),
});
}
if (is("punc", "{")) {
next();
var first = true, a = [];
var first = true, a = [], rest = null;
while (!is("punc", "}")) {
if (first) first = false; else expect(",");
// allow trailing comma
@@ -1661,6 +1687,11 @@ function parse($TEXT, options) {
}));
continue;
}
if (is("operator", "...")) {
next();
rest = maybe_destructured(type);
break;
}
var name = as_symbol(type);
if (is("operator", "=")) {
next();
@@ -1678,10 +1709,11 @@ function parse($TEXT, options) {
end: prev(),
}));
}
next();
expect("}");
return new AST_DestructuredObject({
start: start,
properties: a,
rest: rest,
end: prev(),
});
}
@@ -1845,6 +1877,11 @@ function parse($TEXT, options) {
function to_destructured(node) {
if (node instanceof AST_Array) {
var rest = null;
if (node.elements[node.elements.length - 1] instanceof AST_Spread) {
rest = to_destructured(node.elements.pop().expression);
if (!(rest instanceof AST_Destructured || is_assignable(rest))) return node;
}
var elements = node.elements.map(to_destructured);
return all(elements, function(node) {
return node instanceof AST_DefaultValue
@@ -1854,6 +1891,7 @@ function parse($TEXT, options) {
}) ? new AST_DestructuredArray({
start: node.start,
elements: elements,
rest: rest,
end: node.end,
}) : node;
}
@@ -1867,6 +1905,11 @@ function parse($TEXT, options) {
}) : node;
}
if (!(node instanceof AST_Object)) return node;
var rest = null;
if (node.properties[node.properties.length - 1] instanceof AST_Spread) {
rest = to_destructured(node.properties.pop().expression);
if (!(rest instanceof AST_Destructured || is_assignable(rest))) return node;
}
var props = [];
for (var i = 0; i < node.properties.length; i++) {
var prop = node.properties[i];
@@ -1885,6 +1928,7 @@ function parse($TEXT, options) {
return new AST_DestructuredObject({
start: node.start,
properties: props,
rest: rest,
end: node.end,
});
}
@@ -1912,15 +1956,20 @@ function parse($TEXT, options) {
var start = S.token;
var exprs = [];
while (true) {
if (maybe_arrow && is("operator", "...")) {
next();
exprs.rest = maybe_destructured(AST_SymbolFunarg);
break;
}
exprs.push(maybe_assign(no_in));
if (!is("punc", ",")) break;
next();
if (maybe_arrow && is("punc", ")") && is_token(peek(), "punc", "=>")) break;
}
return exprs.length == 1 ? exprs[0] : new AST_Sequence({
start : start,
expressions : exprs,
end : prev()
return exprs.length == 1 && !exprs.rest ? exprs[0] : new AST_Sequence({
start: start,
expressions: exprs,
end: prev(),
});
}