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:
Anthony Van de Gejuchte
2017-02-24 01:49:19 +01:00
committed by Alex Lam S.L
parent 85c1cba760
commit 07734b000a
16 changed files with 1253 additions and 141 deletions

View File

@@ -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,