Destructuring consistency fixes (#1417)
- Use AST_Destructuring for lhf assignment patterns - Use AST_DefaultAssign for default assignments - Add more checks for lhs expressions - Add lots of testing - Cleanup ast (e.g. remove default property) - Fix #1402 based on a patch from @kzc - Refine spread allowance in array destructring pattern - Add destructuring AST tree checker
This commit is contained in:
committed by
Alex Lam S.L
parent
85c1cba760
commit
07734b000a
175
lib/parse.js
175
lib/parse.js
@@ -1106,11 +1106,9 @@ function parse($TEXT, options) {
|
||||
|
||||
case "export":
|
||||
return export_();
|
||||
|
||||
default:
|
||||
unexpected();
|
||||
}
|
||||
}
|
||||
unexpected();
|
||||
});
|
||||
|
||||
function labeled_statement() {
|
||||
@@ -1384,7 +1382,13 @@ function parse($TEXT, options) {
|
||||
if (is("operator", "=") && expand === false) {
|
||||
used_parameters.mark_default_assignment(S.token);
|
||||
next();
|
||||
param.default = expression(false);
|
||||
param = new AST_DefaultAssign({
|
||||
start: param.start,
|
||||
left: param,
|
||||
operator: "=",
|
||||
right: expression(false),
|
||||
end: S.token
|
||||
});
|
||||
}
|
||||
|
||||
if (expand !== false) {
|
||||
@@ -1458,7 +1462,13 @@ function parse($TEXT, options) {
|
||||
if (is("operator", "=") && is_expand === false) {
|
||||
used_parameters.mark_default_assignment(S.token);
|
||||
next();
|
||||
elements[elements.length - 1].default = expression(false);
|
||||
elements[elements.length - 1] = new AST_DefaultAssign({
|
||||
start: elements[elements.length - 1].start,
|
||||
left: elements[elements.length - 1],
|
||||
operator: "=",
|
||||
right: expression(false),
|
||||
end: S.token
|
||||
});
|
||||
}
|
||||
if (is_expand) {
|
||||
if (!is("punc", "]")) {
|
||||
@@ -1489,10 +1499,15 @@ function parse($TEXT, options) {
|
||||
}
|
||||
if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].indexOf(peek().value) !== -1) {
|
||||
used_parameters.add_parameter(S.token);
|
||||
elements.push(new symbol_type({
|
||||
start: S.token,
|
||||
name: S.token.value,
|
||||
end: S.token
|
||||
elements.push(new AST_ObjectKeyVal({
|
||||
start: prev(),
|
||||
key: S.token.value,
|
||||
value: new symbol_type({
|
||||
start: S.token,
|
||||
name: S.token.value,
|
||||
end: S.token
|
||||
}),
|
||||
end: prev()
|
||||
}));
|
||||
next();
|
||||
} else if (is("punc", "}")) {
|
||||
@@ -1503,9 +1518,14 @@ function parse($TEXT, options) {
|
||||
if (property === null) {
|
||||
unexpected(prev());
|
||||
} else if (prev().type === "name" && !is("punc", ":")) {
|
||||
elements.push(new AST_SymbolFunarg({
|
||||
elements.push(new AST_ObjectKeyVal({
|
||||
start: prev(),
|
||||
name: property_token,
|
||||
key: property,
|
||||
value: new symbol_type({
|
||||
start: prev(),
|
||||
name: property,
|
||||
end: prev()
|
||||
}),
|
||||
end: prev()
|
||||
}));
|
||||
} else {
|
||||
@@ -1513,16 +1533,22 @@ function parse($TEXT, options) {
|
||||
elements.push(new AST_ObjectKeyVal({
|
||||
start: property_token,
|
||||
quote: property_token.quote,
|
||||
end: prev(),
|
||||
key: property,
|
||||
value: binding_element(used_parameters, symbol_type)
|
||||
value: binding_element(used_parameters, symbol_type),
|
||||
end: prev()
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (is("operator", "=")) {
|
||||
used_parameters.mark_default_assignment(S.token);
|
||||
next();
|
||||
elements[elements.length - 1].default = expression(false);
|
||||
elements[elements.length - 1].value = new AST_DefaultAssign({
|
||||
start: elements[elements.length - 1].value.start,
|
||||
left: elements[elements.length - 1].value,
|
||||
operator: "=",
|
||||
right: expression(false),
|
||||
end: S.token
|
||||
});
|
||||
}
|
||||
}
|
||||
expect("}");
|
||||
@@ -1558,7 +1584,7 @@ function parse($TEXT, options) {
|
||||
next();
|
||||
a.push(new AST_Expansion({
|
||||
start: prev(),
|
||||
expression: binding_element(undefined, AST_SymbolFunarg),
|
||||
expression: expression(false),
|
||||
end: S.token,
|
||||
}));
|
||||
if (!is("punc", ")")) {
|
||||
@@ -1943,7 +1969,7 @@ function parse($TEXT, options) {
|
||||
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||
} else if (is("expand", "...")) {
|
||||
next();
|
||||
a.push(new AST_Expansion({start: S.token, expression: expression(),end: S.token}));
|
||||
a.push(new AST_Expansion({start: prev(), expression: expression(),end: S.token}));
|
||||
} else {
|
||||
a.push(expression(false));
|
||||
}
|
||||
@@ -1970,63 +1996,51 @@ function parse($TEXT, options) {
|
||||
start = S.token;
|
||||
var type = start.type;
|
||||
var name = as_property_name();
|
||||
var value;
|
||||
|
||||
// Check property and fetch value
|
||||
if (!is("punc", ":")) {
|
||||
var concise = concise_method_or_getset(name, start);
|
||||
if (concise) {
|
||||
a.push(concise);
|
||||
continue;
|
||||
}
|
||||
if (!(start.type !== name)) {
|
||||
unexpected(S.token);
|
||||
}
|
||||
|
||||
value = new AST_SymbolRef({
|
||||
start: prev(),
|
||||
name: name,
|
||||
end: prev()
|
||||
});
|
||||
} else if (name === null) {
|
||||
unexpected(prev());
|
||||
} else {
|
||||
next(); // `:` - see first condition
|
||||
value = expression(false);
|
||||
}
|
||||
|
||||
if (type == "punc" && start.value == "[") {
|
||||
expect(":");
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
key: name,
|
||||
value: expression(false),
|
||||
end: prev()
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for default value and alter value accordingly if necessary
|
||||
if (is("operator", "=")) {
|
||||
next();
|
||||
a.push(new AST_Assign({
|
||||
value = new AST_Assign({
|
||||
start: start,
|
||||
// Symbol class doesn't matter. This is only meant to carry the symbol name into .as_params() since this is not normally valid.
|
||||
left: new AST_SymbolRef({
|
||||
start: start,
|
||||
end: start,
|
||||
name: name
|
||||
}),
|
||||
left: value,
|
||||
operator: "=",
|
||||
right: expression(false),
|
||||
end: prev()
|
||||
}));
|
||||
} else if (!is("punc", ":")) {
|
||||
// It's one of those object destructurings, the value is its own name
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
key: name,
|
||||
value: new AST_SymbolRef({
|
||||
start: start,
|
||||
end: prev(),
|
||||
name: name
|
||||
}),
|
||||
end: start,
|
||||
}));
|
||||
} else {
|
||||
expect(":");
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start : start,
|
||||
quote : start.quote,
|
||||
key : name,
|
||||
value : expression(false),
|
||||
end : prev()
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
// Create property
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
quote: start.quote,
|
||||
key: name,
|
||||
value: value,
|
||||
end: prev()
|
||||
}));
|
||||
}
|
||||
next();
|
||||
return new AST_Object({ properties: a })
|
||||
@@ -2493,6 +2507,55 @@ function parse($TEXT, options) {
|
||||
|
||||
if (is("operator") && ASSIGNMENT(val)) {
|
||||
if (is_assignable(left)) {
|
||||
|
||||
var walk = function(node) {
|
||||
var newNode;
|
||||
if (node instanceof AST_Object) {
|
||||
newNode = new AST_Destructuring({
|
||||
start: node.start,
|
||||
names: node.properties.map(walk),
|
||||
is_array: false,
|
||||
end: node.end
|
||||
});
|
||||
node = newNode;
|
||||
} else if (node instanceof AST_Array) {
|
||||
var names = [];
|
||||
|
||||
for (var i = 0; i < node.elements.length; i++) {
|
||||
// Only allow expansion as last element
|
||||
if (node.elements[i] instanceof AST_Expansion) {
|
||||
if (i + 1 !== node.elements.length) {
|
||||
token_error(node.elements[i].start, "SyntaxError: Spread must the be last element in destructuring array");
|
||||
}
|
||||
node.elements[i].expression = walk(node.elements[i].expression);
|
||||
}
|
||||
|
||||
names.push(walk(node.elements[i]));
|
||||
}
|
||||
|
||||
newNode = new AST_Destructuring({
|
||||
start: node.start,
|
||||
names: names,
|
||||
is_array: true,
|
||||
end: node.end
|
||||
});
|
||||
node = newNode;
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
node.value = walk(node.value);
|
||||
} else if (node instanceof AST_Assign) {
|
||||
node = new AST_DefaultAssign({
|
||||
start: node.start,
|
||||
left: node.left,
|
||||
operator: "=",
|
||||
right: node.right,
|
||||
end: node.end
|
||||
});
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
left = walk(left);
|
||||
|
||||
next();
|
||||
return new AST_Assign({
|
||||
start : start,
|
||||
|
||||
Reference in New Issue
Block a user