=> with destructuring arguments. Requires a lot of parser changes
This commit is contained in:
@@ -387,6 +387,11 @@ var AST_ArrowParametersOrSeq = DEFNODE("ArrowParametersOrSeq", "expressions", {
|
|||||||
start: ex.start,
|
start: ex.start,
|
||||||
end: ex.end
|
end: ex.end
|
||||||
});
|
});
|
||||||
|
} else if (ex instanceof AST_Destructuring) {
|
||||||
|
if (ex.names.length == 0)
|
||||||
|
croak("Invalid destructuring function parameter", ex.start.line, ex.start.col);
|
||||||
|
ex.names = ex.names.map(to_fun_args);
|
||||||
|
return ex;
|
||||||
} else if (ex instanceof AST_SymbolRef) {
|
} else if (ex instanceof AST_SymbolRef) {
|
||||||
return new AST_SymbolFunarg({
|
return new AST_SymbolFunarg({
|
||||||
name: ex.name,
|
name: ex.name,
|
||||||
|
|||||||
216
lib/parse.js
216
lib/parse.js
@@ -989,35 +989,17 @@ function parse($TEXT, options) {
|
|||||||
var arrow_function = function(args) {
|
var arrow_function = function(args) {
|
||||||
expect_token("arrow", "=>");
|
expect_token("arrow", "=>");
|
||||||
|
|
||||||
if (args instanceof AST_SymbolRef) {
|
var argnames = args.as_params(croak);
|
||||||
args = [args];
|
|
||||||
} else if (args instanceof AST_Seq) {
|
|
||||||
args = args.to_array();
|
|
||||||
} else if (args instanceof AST_Node) {
|
|
||||||
croak("Invalid syntax", args.start.line, args.start.col);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < args.length; i++) {
|
var body = is("punc", "{") ?
|
||||||
if (!(args[i] instanceof AST_SymbolRef)) {
|
_function_body(true) :
|
||||||
croak("Invalid parameter for an arrow function", args[i].start.line, args[i].start.col);
|
_function_body(false);
|
||||||
}
|
|
||||||
|
|
||||||
args[i] = new AST_SymbolFunarg({
|
|
||||||
name: args[i].name,
|
|
||||||
start: args[i].start,
|
|
||||||
end: args[i].end
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AST_Arrow({
|
return new AST_Arrow({
|
||||||
argnames: args,
|
start : args.start,
|
||||||
body: (function(){
|
end : body.end,
|
||||||
if (is("punc", "{")) {
|
argnames : argnames,
|
||||||
return _function_body();
|
body : body
|
||||||
} else {
|
|
||||||
return expression(true);
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1030,7 +1012,7 @@ function parse($TEXT, options) {
|
|||||||
unexpected();
|
unexpected();
|
||||||
|
|
||||||
var args = params_or_seq_().as_params(croak);
|
var args = params_or_seq_().as_params(croak);
|
||||||
var body = _function_body();
|
var body = _function_body(true);
|
||||||
return new ctor({
|
return new ctor({
|
||||||
start : args.start,
|
start : args.start,
|
||||||
end : body.end,
|
end : body.end,
|
||||||
@@ -1060,14 +1042,18 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function _function_body() {
|
function _function_body(block) {
|
||||||
var loop = S.in_loop;
|
var loop = S.in_loop;
|
||||||
var labels = S.labels;
|
var labels = S.labels;
|
||||||
++S.in_function;
|
++S.in_function;
|
||||||
S.in_directives = true;
|
if (block)
|
||||||
|
S.in_directives = true;
|
||||||
S.in_loop = 0;
|
S.in_loop = 0;
|
||||||
S.labels = [];
|
S.labels = [];
|
||||||
var a = block_();
|
if (block)
|
||||||
|
var a = block_();
|
||||||
|
else
|
||||||
|
var a = expression(false);
|
||||||
--S.in_function;
|
--S.in_function;
|
||||||
S.in_loop = loop;
|
S.in_loop = loop;
|
||||||
S.labels = labels;
|
S.labels = labels;
|
||||||
@@ -1263,16 +1249,17 @@ function parse($TEXT, options) {
|
|||||||
if (is("punc")) {
|
if (is("punc")) {
|
||||||
switch (start.value) {
|
switch (start.value) {
|
||||||
case "(":
|
case "(":
|
||||||
next();
|
var ex = params_or_seq_();
|
||||||
var ex = expression(true);
|
|
||||||
ex.start = start;
|
ex.start = start;
|
||||||
ex.end = S.token;
|
ex.end = S.token;
|
||||||
expect(")");
|
if (is("arrow", "=>")) {
|
||||||
return subscripts(ex, allow_calls);
|
return arrow_function(ex);
|
||||||
|
}
|
||||||
|
return subscripts(ex.as_expr(croak), allow_calls);
|
||||||
case "[":
|
case "[":
|
||||||
return subscripts(array_(), allow_calls);
|
return subscripts(array_(), allow_calls);
|
||||||
case "{":
|
case "{":
|
||||||
return subscripts(object_(), allow_calls);
|
return subscripts(object_or_object_destructuring_(), allow_calls);
|
||||||
}
|
}
|
||||||
unexpected();
|
unexpected();
|
||||||
}
|
}
|
||||||
@@ -1311,68 +1298,101 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var object_ = embed_tokens(function() {
|
var object_or_object_destructuring_ = embed_tokens(function() {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
expect("{");
|
expect("{");
|
||||||
var first = true, a = [];
|
function try_an_object() {
|
||||||
while (!is("punc", "}")) {
|
var first = true, a = [];
|
||||||
if (first) first = false; else expect(",");
|
while (!is("punc", "}")) {
|
||||||
if (!options.strict && is("punc", "}"))
|
if (first) first = false; else expect(",");
|
||||||
// allow trailing comma
|
if (!options.strict && is("punc", "}"))
|
||||||
break;
|
// allow trailing comma
|
||||||
var start = S.token;
|
break;
|
||||||
var type = start.type;
|
var start = S.token;
|
||||||
var name = as_property_name();
|
var type = start.type;
|
||||||
if (type == "name" && !is("punc", ":")) {
|
var name = as_property_name();
|
||||||
if (name == "get") {
|
if (type == "name" && !is("punc", ":")) {
|
||||||
a.push(new AST_ObjectGetter({
|
if (name == "get") {
|
||||||
start : start,
|
a.push(new AST_ObjectGetter({
|
||||||
key : as_atom_node(),
|
start : start,
|
||||||
value : function_(AST_Accessor),
|
key : as_atom_node(),
|
||||||
end : prev()
|
value : function_(AST_Accessor),
|
||||||
}));
|
end : prev()
|
||||||
continue;
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (name == "set") {
|
||||||
|
a.push(new AST_ObjectSetter({
|
||||||
|
start : start,
|
||||||
|
key : as_atom_node(),
|
||||||
|
value : function_(AST_Accessor),
|
||||||
|
end : prev()
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (name == "set") {
|
|
||||||
a.push(new AST_ObjectSetter({
|
|
||||||
start : start,
|
|
||||||
key : as_atom_node(),
|
|
||||||
value : function_(AST_Accessor),
|
|
||||||
end : prev()
|
|
||||||
}));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is("punc", ":")) {
|
if (!is("punc", ":")) {
|
||||||
// It's one of those object destructurings, the value is its own name
|
// It's one of those object destructurings, the value is its own name
|
||||||
if (!S.in_parameters) {
|
if (!S.in_parameters) {
|
||||||
croak("Invalid syntax", S.token.line, S.token.col);
|
croak("Invalid syntax", S.token.line, S.token.col);
|
||||||
}
|
}
|
||||||
a.push(new AST_ObjectSymbol({
|
a.push(new AST_ObjectSymbol({
|
||||||
start: start,
|
|
||||||
end: start,
|
|
||||||
symbol: new AST_SymbolRef({
|
|
||||||
start: start,
|
start: start,
|
||||||
end: start,
|
end: start,
|
||||||
name: name
|
symbol: new AST_SymbolRef({
|
||||||
})
|
start: start,
|
||||||
}));
|
end: start,
|
||||||
} else {
|
name: name
|
||||||
if (S.in_parameters) {
|
})
|
||||||
croak("Cannot destructure", S.token.line, S.token.col);
|
}));
|
||||||
|
} else {
|
||||||
|
if (S.in_parameters) {
|
||||||
|
croak("Cannot destructure", S.token.line, S.token.col);
|
||||||
|
}
|
||||||
|
expect(":");
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start : start,
|
||||||
|
key : name,
|
||||||
|
value : expression(false),
|
||||||
|
end : prev()
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
expect(":");
|
|
||||||
a.push(new AST_ObjectKeyVal({
|
|
||||||
start : start,
|
|
||||||
key : name,
|
|
||||||
value : expression(false),
|
|
||||||
end : prev()
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
next();
|
||||||
|
return new AST_Object({ properties: a })
|
||||||
}
|
}
|
||||||
next();
|
|
||||||
return new AST_Object({ properties: a });
|
var obj = try_an_object();
|
||||||
|
if (obj instanceof AST_Object) { return obj; }
|
||||||
|
|
||||||
|
if (!S.in_parameters) {
|
||||||
|
croak("Cannot destructure", S.token.line, S.token.col);
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstName = obj;
|
||||||
|
|
||||||
|
var namesInDestructuring = [];
|
||||||
|
|
||||||
|
namesInDestructuring.push( new AST_SymbolRef({
|
||||||
|
start : prev(),
|
||||||
|
end : prev(),
|
||||||
|
name : firstName
|
||||||
|
}));
|
||||||
|
|
||||||
|
while (!is("punc", "}")) {
|
||||||
|
expect(",");
|
||||||
|
namesInDestructuring.push(as_symbol(AST_SymbolRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
expect('}');
|
||||||
|
|
||||||
|
return new AST_Destructuring({
|
||||||
|
start : start,
|
||||||
|
end : S.token,
|
||||||
|
names : namesInDestructuring,
|
||||||
|
is_array : false
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
function as_property_name() {
|
function as_property_name() {
|
||||||
@@ -1530,16 +1550,13 @@ function parse($TEXT, options) {
|
|||||||
return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol);
|
return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// In ES6, AssignmentExpression can also be an ArrowFunction
|
||||||
var maybe_assign = function(no_in) {
|
var maybe_assign = function(no_in) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
|
|
||||||
if (start.value == "(" && peek().value == ")") {
|
var left = maybe_conditional(no_in);
|
||||||
next(); // (
|
var val = S.token.value;
|
||||||
next(); // )
|
|
||||||
return arrow_function([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var left = maybe_conditional(no_in), val = S.token.value;
|
|
||||||
if (is("operator") && ASSIGNMENT(val)) {
|
if (is("operator") && ASSIGNMENT(val)) {
|
||||||
if (is_assignable(left)) {
|
if (is_assignable(left)) {
|
||||||
next();
|
next();
|
||||||
@@ -1553,15 +1570,20 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
croak("Invalid assignment");
|
croak("Invalid assignment");
|
||||||
}
|
}
|
||||||
if (is("arrow")) {
|
|
||||||
return arrow_function(left)
|
|
||||||
}
|
|
||||||
return left;
|
return left;
|
||||||
};
|
};
|
||||||
|
|
||||||
var expression = function(commas, no_in) {
|
var expression = function(commas, no_in) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var expr = maybe_assign(no_in);
|
var expr = maybe_assign(no_in);
|
||||||
|
if (expr instanceof AST_SymbolRef && is("arrow", "=>")) {
|
||||||
|
expr = new AST_ArrowParametersOrSeq({
|
||||||
|
start: expr.start,
|
||||||
|
end: expr.end,
|
||||||
|
expressions: [expr]
|
||||||
|
});
|
||||||
|
return arrow_function(expr);
|
||||||
|
}
|
||||||
if (commas && is("punc", ",")) {
|
if (commas && is("punc", ",")) {
|
||||||
next();
|
next();
|
||||||
return new AST_Seq({
|
return new AST_Seq({
|
||||||
|
|||||||
@@ -35,3 +35,65 @@ regression_arrow_functions_and_hoist: {
|
|||||||
}
|
}
|
||||||
expect_exact: "a=>b;"
|
expect_exact: "a=>b;"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destructuring_arguments: {
|
||||||
|
input: {
|
||||||
|
(function ( a ) { });
|
||||||
|
(function ( [ a ] ) { });
|
||||||
|
(function ( [ a, b ] ) { });
|
||||||
|
(function ( [ [ a ] ] ) { });
|
||||||
|
(function ( [ [ a, b ] ] ) { });
|
||||||
|
(function ( [ a, [ b ] ] ) { });
|
||||||
|
(function ( [ [ b ], a ] ) { });
|
||||||
|
|
||||||
|
(function ( { a } ) { });
|
||||||
|
(function ( { a, b } ) { });
|
||||||
|
|
||||||
|
(function ( [ { a } ] ) { });
|
||||||
|
(function ( [ { a, b } ] ) { });
|
||||||
|
(function ( [ a, { b } ] ) { });
|
||||||
|
(function ( [ { b }, a ] ) { });
|
||||||
|
|
||||||
|
( [ a ] ) => { };
|
||||||
|
( [ a, b ] ) => { };
|
||||||
|
|
||||||
|
( { a } ) => { };
|
||||||
|
( { a, b, c, d, e } ) => { };
|
||||||
|
|
||||||
|
( [ a ] ) => b;
|
||||||
|
( [ a, b ] ) => c;
|
||||||
|
|
||||||
|
( { a } ) => b;
|
||||||
|
( { a, b } ) => c;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a){});
|
||||||
|
(function([a]){});
|
||||||
|
(function([a,b]){});
|
||||||
|
(function([[a]]){});
|
||||||
|
(function([[a,b]]){});
|
||||||
|
(function([a,[b]]){});
|
||||||
|
(function([[b],a]){});
|
||||||
|
|
||||||
|
(function({a}){});
|
||||||
|
(function({a,b}){});
|
||||||
|
|
||||||
|
(function([{a}]){});
|
||||||
|
(function([{a,b}]){});
|
||||||
|
(function([a,{b}]){});
|
||||||
|
(function([{b},a]){});
|
||||||
|
|
||||||
|
([a])=>{};
|
||||||
|
([a,b])=>{};
|
||||||
|
|
||||||
|
({a})=>{};
|
||||||
|
({a,b,c,d,e})=>{};
|
||||||
|
|
||||||
|
([a])=>b;
|
||||||
|
([a,b])=>c;
|
||||||
|
|
||||||
|
({a})=>b;
|
||||||
|
({a,b})=>c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ module.exports = function () {
|
|||||||
ok.equal(destr_fun1.argnames.length, 1);
|
ok.equal(destr_fun1.argnames.length, 1);
|
||||||
ok.equal(destr_fun2.argnames.length, 1);
|
ok.equal(destr_fun2.argnames.length, 1);
|
||||||
|
|
||||||
|
var destr_fun1 = UglifyJS.parse('({a, b}) => null').body[0].body;
|
||||||
|
var destr_fun2 = UglifyJS.parse('([a, [b]]) => null').body[0].body;
|
||||||
|
|
||||||
|
ok.equal(destr_fun1.argnames.length, 1);
|
||||||
|
ok.equal(destr_fun2.argnames.length, 1);
|
||||||
|
|
||||||
var destruct1 = destr_fun1.argnames[0];
|
var destruct1 = destr_fun1.argnames[0];
|
||||||
var destruct2 = destr_fun2.argnames[0];
|
var destruct2 = destr_fun2.argnames[0];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user