Improve binding patterns for arrow functions

This commit is contained in:
Anthony Van de Gejuchte
2016-09-07 01:00:07 +02:00
committed by Richard van Velzen
parent 947b8750e8
commit 32c2cc33bb
12 changed files with 243 additions and 54 deletions

View File

@@ -394,8 +394,6 @@ var AST_ArrowParametersOrSeq = DEFNODE("ArrowParametersOrSeq", "expressions", {
var root = this;
return this.expressions.map(function to_fun_args(ex, _, __, default_seen_above) {
if (ex instanceof AST_Object) {
if (ex.properties.length == 0)
croak("Invalid destructuring function parameter", ex.start.line, ex.start.col);
return new AST_Destructuring({
start: ex.start,
end: ex.end,
@@ -403,12 +401,16 @@ var AST_ArrowParametersOrSeq = DEFNODE("ArrowParametersOrSeq", "expressions", {
default: default_seen_above,
names: ex.properties.map(to_fun_args)
});
} else if (ex instanceof AST_ObjectKeyVal && ex.shorthand) {
return new AST_SymbolFunarg({
name: ex.key,
start: ex.start,
end: ex.end
});
} else if (ex instanceof AST_ObjectKeyVal ||
ex instanceof AST_ObjectComputedKeyVal
) {
if (ex.key instanceof AST_SymbolRef) {
ex.key = to_fun_args(ex.key, 0, [ex.key], ex.default);
}
ex.value = to_fun_args(ex.value, 0, [ex.key], ex.default);
return ex;
} else if (ex instanceof AST_Hole) {
return ex;
} else if (ex instanceof AST_Destructuring) {
if (ex.names.length == 0)
croak("Invalid destructuring function parameter", ex.start.line, ex.start.col);
@@ -424,8 +426,6 @@ var AST_ArrowParametersOrSeq = DEFNODE("ArrowParametersOrSeq", "expressions", {
} else if (ex instanceof AST_Expansion) {
return ex;
} else if (ex instanceof AST_Array) {
if (ex.elements.length === 0)
croak("Invalid destructuring function parameter", ex.start.line, ex.start.col);
return new AST_Destructuring({
start: ex.start,
end: ex.end,
@@ -494,6 +494,11 @@ var AST_Defun = DEFNODE("Defun", null, {
/* -----[ DESTRUCTURING ]----- */
var AST_Destructuring = DEFNODE("Destructuring", "names is_array default", {
$documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names",
$propdoc: {
"names": "[AST_Destructuring|AST_Expansion|AST_Hole|AST_ObjectKeyVal|AST_Symbol] Array of properties or elements",
"is_array": "[Boolean] Whether the destructuring represents an object or array",
"default": "[AST_Node?] Default assign value"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.names.forEach(function(name){
@@ -1001,11 +1006,11 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
}
});
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote shorthand", {
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote default", {
$documentation: "A key: value object property",
$propdoc: {
quote: "[string] the original quote character",
shorthand: "[boolean] whether this is a shorthand key:value pair, expressed as just the key."
default: "[AST_Expression] The default parameter value, only used when nested inside a binding pattern"
}
}, AST_ObjectProperty);
@@ -1068,13 +1073,19 @@ var AST_ClassExpression = DEFNODE("ClassExpression", null, {
$documentation: "A class expression."
}, AST_Class);
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
var AST_Symbol = DEFNODE("Symbol", "scope name thedef default", {
$propdoc: {
name: "[string] name of this symbol",
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
thedef: "[SymbolDef/S] the definition of this symbol"
thedef: "[SymbolDef/S] the definition of this symbol",
default: "[AST_Expression] The default parameter value, only used when nested inside a binding pattern"
},
$documentation: "Base class for all symbols",
_walk: function (visitor) {
return visitor._visit(this, function() {
if (this.default) this.default._walk(visitor);
});
}
});
var AST_NewTarget = DEFNODE("NewTarget", null, {
@@ -1085,17 +1096,11 @@ var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
$documentation: "The name of a property accessor (setter/getter function)"
}, AST_Symbol);
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init default", {
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
$documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
$propdoc: {
init: "[AST_Node*/S] array of initializers for this declaration.",
default: "[AST_Expression] The default for this parameter. For example, `= 6`"
init: "[AST_Node*/S] array of initializers for this declaration."
},
_walk: function (visitor) {
return visitor._visit(this, function() {
if (this.default) this.default._walk(visitor);
});
}
}, AST_Symbol);
var AST_SymbolVar = DEFNODE("SymbolVar", null, {

View File

@@ -69,11 +69,16 @@ function OutputStream(options) {
preamble : null,
quote_style : 0,
keep_quoted_props: false,
shorthand : undefined,
ecma : 5,
}, true);
if (typeof options.ascii_identifiers === 'undefined')
options.ascii_identifiers = options.ascii_only;
if (options.shorthand === undefined)
options.shorthand = options.ecma > 5;
var indentation = 0;
var current_col = 0;
var current_line = 1;
@@ -728,9 +733,15 @@ function OutputStream(options) {
DEFPRINT(AST_Destructuring, function (self, output) {
output.print(self.is_array ? "[" : "{");
var first = true;
self.names.forEach(function (name) {
var len = self.names.length;
self.names.forEach(function (name, i) {
if (first) first = false; else { output.comma(); output.space(); }
name.print(output);
// If the final element is a hole, we need to make sure it
// doesn't look like a trailing comma, by inserting an actual
// trailing comma.
if (i === len - 1 && name instanceof AST_Hole)
output.comma();
})
output.print(self.is_array ? "]" : "}");
if (self.default) {
@@ -739,7 +750,7 @@ function OutputStream(options) {
output.space();
self.default.print(output)
}
})
});
DEFPRINT(AST_Debugger, function(self, output){
output.print("debugger");
@@ -1444,17 +1455,21 @@ function OutputStream(options) {
}
});
DEFPRINT(AST_ObjectKeyVal, function(self, output){
var print_as_shorthand = self.shorthand &&
self.value instanceof AST_Symbol &&
self.key == self.value.print_to_string();
if (print_as_shorthand) {
output.print_name(self.key);
return;
function get_name(self) {
var def = self.value.definition();
return def ? def.mangled_name || def.name : self.value.name;
}
if (output.option("shorthand") &&
self.value instanceof AST_Symbol &&
is_identifier_string(self.key) &&
get_name(self) === self.key
) {
self.print_property_name(self.key, self.quote, output);
} else {
self.print_property_name(self.key, self.quote, output);
output.colon();
self.value.print(output);
}
self.print_property_name(self.key, self.quote, output);
output.colon();
self.value.print(output);
if (self.default) {
output.space();
output.print('=');

View File

@@ -1232,6 +1232,10 @@ function parse($TEXT, options) {
};
var arrow_function = function(args) {
if (S.token.nlb) {
croak("SyntaxError: Unexpected newline before arrow (=>)");
}
expect_token("arrow", "=>");
var argnames;
@@ -1425,12 +1429,13 @@ function parse($TEXT, options) {
if (is("punc")) {
switch (S.token.value) {
case ",":
case "]": // Last element
elements.push(new AST_Hole({
start: S.token,
end: S.token
}));
continue;
case "]": // Trailing comma after last element
break;
case "[":
case "{":
elements.push(binding_element(used_parameters, symbol_type));
@@ -1560,7 +1565,7 @@ function parse($TEXT, options) {
next();
a.push(new AST_Expansion({
start: prev(),
expression: as_symbol(AST_SymbolFunarg),
expression: binding_element(undefined, AST_SymbolFunarg),
end: S.token,
}));
if (!is("punc", ")")) {
@@ -2011,15 +2016,13 @@ function parse($TEXT, options) {
// It's one of those object destructurings, the value is its own name
a.push(new AST_ObjectKeyVal({
start: start,
quote: start.quote,
end: start,
key: name,
value: new AST_SymbolRef({
start: start,
end: start,
end: prev(),
name: name
}),
shorthand: true,
end: start,
}));
} else {
expect(":");

View File

@@ -567,10 +567,12 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
else if (node instanceof AST_With)
base54.consider("with");
else if (node instanceof AST_ObjectSetter)
base54.consider("set" + node.key);
base54.consider("set" + (typeof node.key === "string" ? node.key : ""));
else if (node instanceof AST_ObjectGetter)
base54.consider("get" + node.key);
else if (node instanceof AST_ObjectKeyVal)
base54.consider("get" + (typeof node.key === "string" ? node.key : ""));
else if (node instanceof AST_ObjectKeyVal && typeof node.key === "string")
base54.consider(node.key);
else if (node instanceof AST_ConciseMethod && typeof node.key === "string")
base54.consider(node.key);
else if (node instanceof AST_New)
base54.consider("new");