support destructuring of catch variable (#4412)
This commit is contained in:
10
lib/ast.js
10
lib/ast.js
@@ -786,7 +786,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
|
|||||||
var AST_Catch = DEFNODE("Catch", "argname", {
|
var AST_Catch = DEFNODE("Catch", "argname", {
|
||||||
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
argname: "[AST_SymbolCatch?] symbol for the exception, or null if not present",
|
argname: "[(AST_Destructured|AST_SymbolCatch)?] symbol for the exception, or null if not present",
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
@@ -796,9 +796,9 @@ var AST_Catch = DEFNODE("Catch", "argname", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (this.argname != null) {
|
if (this.argname != null) validate_destructured(this.argname, function(node) {
|
||||||
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
if (!(node instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
||||||
}
|
});
|
||||||
},
|
},
|
||||||
}, AST_Block);
|
}, AST_Block);
|
||||||
|
|
||||||
@@ -868,7 +868,7 @@ var AST_Var = DEFNODE("Var", null, {
|
|||||||
var AST_VarDef = DEFNODE("VarDef", "name value", {
|
var AST_VarDef = DEFNODE("VarDef", "name value", {
|
||||||
$documentation: "A variable declaration; only appears in a AST_Definitions node",
|
$documentation: "A variable declaration; only appears in a AST_Definitions node",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[AST_SymbolVar] name of the variable",
|
name: "[AST_Destructured|AST_SymbolVar] name of the variable",
|
||||||
value: "[AST_Node?] initializer, or null of there's no initializer"
|
value: "[AST_Node?] initializer, or null of there's no initializer"
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
|
|||||||
@@ -4949,11 +4949,13 @@ merge(Compressor.prototype, {
|
|||||||
walk_body(node, tw);
|
walk_body(node, tw);
|
||||||
pop();
|
pop();
|
||||||
if (node.bcatch) {
|
if (node.bcatch) {
|
||||||
if (node.bcatch.argname) {
|
if (node.bcatch.argname) node.bcatch.argname.mark_symbol(function(node) {
|
||||||
var def = node.bcatch.argname.definition();
|
if (node instanceof AST_SymbolCatch) {
|
||||||
references[def.id] = false;
|
var def = node.definition();
|
||||||
if (def = def.redefined()) references[def.id] = false;
|
references[def.id] = false;
|
||||||
}
|
if (def = def.redefined()) references[def.id] = false;
|
||||||
|
}
|
||||||
|
}, tw);
|
||||||
push();
|
push();
|
||||||
if (node.bfinally) segment.block = node.bcatch;
|
if (node.bfinally) segment.block = node.bcatch;
|
||||||
walk_body(node.bcatch, tw);
|
walk_body(node.bcatch, tw);
|
||||||
@@ -5317,6 +5319,34 @@ merge(Compressor.prototype, {
|
|||||||
var unused_fn_names = [];
|
var unused_fn_names = [];
|
||||||
var calls_to_drop_args = [];
|
var calls_to_drop_args = [];
|
||||||
var fns_with_marked_args = [];
|
var fns_with_marked_args = [];
|
||||||
|
var trimmer = new TreeTransformer(function(node) {
|
||||||
|
if (node instanceof AST_DestructuredArray) {
|
||||||
|
var trim = true;
|
||||||
|
for (var i = node.elements.length; --i >= 0;) {
|
||||||
|
var sym = node.elements[i];
|
||||||
|
if (!(sym instanceof AST_SymbolDeclaration)) {
|
||||||
|
node.elements[i] = sym.transform(trimmer);
|
||||||
|
trim = false;
|
||||||
|
} else if (sym.definition().id in in_use_ids) {
|
||||||
|
trim = false;
|
||||||
|
} else if (trim) {
|
||||||
|
node.elements.pop();
|
||||||
|
} else {
|
||||||
|
node.elements[i] = make_node(AST_Hole, sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_DestructuredKeyVal) {
|
||||||
|
if (!(node.value instanceof AST_SymbolDeclaration)) {
|
||||||
|
node.value = node.value.transform(trimmer);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (typeof node.key != "string") return node;
|
||||||
|
if (node.value.definition().id in in_use_ids) return node;
|
||||||
|
return List.skip;
|
||||||
|
}
|
||||||
|
});
|
||||||
var tt = new TreeTransformer(function(node, descend, in_list) {
|
var tt = new TreeTransformer(function(node, descend, in_list) {
|
||||||
var parent = tt.parent();
|
var parent = tt.parent();
|
||||||
if (drop_vars) {
|
if (drop_vars) {
|
||||||
@@ -5383,34 +5413,7 @@ merge(Compressor.prototype, {
|
|||||||
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
||||||
var sym = a[i];
|
var sym = a[i];
|
||||||
if (sym instanceof AST_Destructured) {
|
if (sym instanceof AST_Destructured) {
|
||||||
sym.transform(new TreeTransformer(function(node) {
|
sym.transform(trimmer);
|
||||||
if (node instanceof AST_DestructuredArray) {
|
|
||||||
var trim = true;
|
|
||||||
for (var i = node.elements.length; --i >= 0;) {
|
|
||||||
var sym = node.elements[i];
|
|
||||||
if (!(sym instanceof AST_SymbolFunarg)) {
|
|
||||||
node.elements[i] = sym.transform(this);
|
|
||||||
trim = false;
|
|
||||||
} else if (sym.definition().id in in_use_ids) {
|
|
||||||
trim = false;
|
|
||||||
} else if (trim) {
|
|
||||||
node.elements.pop();
|
|
||||||
} else {
|
|
||||||
node.elements[i] = make_node(AST_Hole, sym);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_DestructuredKeyVal) {
|
|
||||||
if (!(node.value instanceof AST_SymbolFunarg)) {
|
|
||||||
node.value = node.value.transform(this);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
if (typeof node.key != "string") return node;
|
|
||||||
if (node.value.definition().id in in_use_ids) return node;
|
|
||||||
return List.skip;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
trim = false;
|
trim = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -5429,6 +5432,9 @@ merge(Compressor.prototype, {
|
|||||||
fns_with_marked_args.push(node);
|
fns_with_marked_args.push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Catch && node.argname instanceof AST_Destructured) {
|
||||||
|
node.argname.transform(trimmer);
|
||||||
|
}
|
||||||
if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) {
|
if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) {
|
||||||
// place uninitialized names at the start
|
// place uninitialized names at the start
|
||||||
var body = [], head = [], tail = [];
|
var body = [], head = [], tail = [];
|
||||||
@@ -7263,7 +7269,9 @@ merge(Compressor.prototype, {
|
|||||||
self.body = tighten_body(self.body, compressor);
|
self.body = tighten_body(self.body, compressor);
|
||||||
if (compressor.option("dead_code")) {
|
if (compressor.option("dead_code")) {
|
||||||
if (has_declarations_only(self)
|
if (has_declarations_only(self)
|
||||||
&& !(self.bcatch && self.bcatch.argname && !can_drop_symbol(self.bcatch.argname))) {
|
&& !(self.bcatch && self.bcatch.argname && self.bcatch.argname.match_symbol(function(node) {
|
||||||
|
return node instanceof AST_SymbolCatch && !can_drop_symbol(node);
|
||||||
|
}, true))) {
|
||||||
var body = [];
|
var body = [];
|
||||||
if (self.bcatch) {
|
if (self.bcatch) {
|
||||||
extract_declarations_from_unreachable_code(compressor, self.bcatch, body);
|
extract_declarations_from_unreachable_code(compressor, self.bcatch, body);
|
||||||
|
|||||||
@@ -1216,7 +1216,7 @@ function parse($TEXT, options) {
|
|||||||
var name = null;
|
var name = null;
|
||||||
if (is("punc", "(")) {
|
if (is("punc", "(")) {
|
||||||
next();
|
next();
|
||||||
name = as_symbol(AST_SymbolCatch);
|
name = maybe_destructured(AST_SymbolCatch);
|
||||||
expect(")");
|
expect(")");
|
||||||
}
|
}
|
||||||
bcatch = new AST_Catch({
|
bcatch = new AST_Catch({
|
||||||
|
|||||||
@@ -750,6 +750,46 @@ simple_var: {
|
|||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drop_catch: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {} catch ({
|
||||||
|
[console.log("FAIL")]: e,
|
||||||
|
}) {} finally {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_catch_var: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw new Error("PASS");
|
||||||
|
} catch ({ name, message }) {
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw new Error("PASS");
|
||||||
|
} catch ({ message }) {
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
collapse_vars_1: {
|
collapse_vars_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
|||||||
@@ -858,22 +858,44 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
if (n !== 1) {
|
if (n !== 1) {
|
||||||
// the catch var should only be accessible in the catch clause...
|
// the catch var should only be accessible in the catch clause...
|
||||||
// we have to do go through some trouble here to prevent leaking it
|
// we have to do go through some trouble here to prevent leaking it
|
||||||
var nameLenBefore = VAR_NAMES.length;
|
|
||||||
mayCreateBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
mayCreateBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
if (SUPPORT.catch_omit_var && rng(20) == 0) {
|
var block_len = block_vars.length;
|
||||||
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
|
var unique_len = unique_vars.length;
|
||||||
|
var offset = SUPPORT.catch_omit_var ? 0 : SUPPORT.destructuring ? 1 : 2;
|
||||||
|
switch (offset + rng(20 - offset)) {
|
||||||
|
case 0:
|
||||||
s += " catch { ";
|
s += " catch { ";
|
||||||
} else {
|
break;
|
||||||
var catchName = createVarName(MANDATORY);
|
case 1:
|
||||||
if (!catch_redef) unique_vars.push(catchName);
|
var name = createVarName(MANDATORY);
|
||||||
s += " catch (" + catchName + ") { ";
|
block_vars.push(name);
|
||||||
|
var message = createVarName(MANDATORY);
|
||||||
|
block_vars.push(message);
|
||||||
|
if (SUPPORT.computed_key && rng(10) == 0) {
|
||||||
|
s += " catch ({ message: " + message + ", ";
|
||||||
|
addAvoidVars([ name ]);
|
||||||
|
s += "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]: " + name;
|
||||||
|
removeAvoidVars([ name ]);
|
||||||
|
s += " }) { ";
|
||||||
|
} else {
|
||||||
|
s += " catch ({ name: " + name + ", message: " + message + " }) { ";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
var name = createVarName(MANDATORY);
|
||||||
|
if (!catch_redef) unique_vars.push(name);
|
||||||
|
s += " catch (" + name + ") { ";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
|
var catches = VAR_NAMES.length - nameLenBefore;
|
||||||
s += defns() + "\n";
|
s += defns() + "\n";
|
||||||
s += _createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
s += _createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
||||||
s += " }";
|
s += " }";
|
||||||
// remove catch name
|
// remove catch variables
|
||||||
if (!catch_redef) unique_vars.pop();
|
block_vars.length = block_len;
|
||||||
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1);
|
if (catches > 0) VAR_NAMES.splice(nameLenBefore, catches);
|
||||||
|
unique_vars.length = unique_len;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (n !== 0) s += " finally { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
|
if (n !== 0) s += " finally { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
|
||||||
|
|||||||
Reference in New Issue
Block a user