support generator functions (#4620)
This commit is contained in:
@@ -811,6 +811,8 @@ to be `false` and all symbol names will be omitted.
|
|||||||
- `varify` (default: `true`) -- convert block-scoped declaractions into `var`
|
- `varify` (default: `true`) -- convert block-scoped declaractions into `var`
|
||||||
whenever safe to do so
|
whenever safe to do so
|
||||||
|
|
||||||
|
- `yields` (default: `true`) -- apply optimizations to `yield` expressions
|
||||||
|
|
||||||
## Mangle options
|
## Mangle options
|
||||||
|
|
||||||
- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
|
- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
|
||||||
|
|||||||
198
lib/ast.js
198
lib/ast.js
@@ -113,7 +113,9 @@ var AST_Node = DEFNODE("Node", "start end", {
|
|||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
visitor.visit(this);
|
visitor.visit(this);
|
||||||
},
|
},
|
||||||
_validate: noop,
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Node") throw new Error("should not instantiate AST_Node");
|
||||||
|
},
|
||||||
validate: function() {
|
validate: function() {
|
||||||
var ctor = this.CTOR;
|
var ctor = this.CTOR;
|
||||||
do {
|
do {
|
||||||
@@ -187,6 +189,9 @@ AST_Node.disable_validation = function() {
|
|||||||
|
|
||||||
var AST_Statement = DEFNODE("Statement", null, {
|
var AST_Statement = DEFNODE("Statement", null, {
|
||||||
$documentation: "Base class of all statements",
|
$documentation: "Base class of all statements",
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Statement") throw new Error("should not instantiate AST_Statement");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var AST_Debugger = DEFNODE("Debugger", null, {
|
var AST_Debugger = DEFNODE("Debugger", null, {
|
||||||
@@ -215,7 +220,7 @@ function validate_expression(value, prop, multiple, allow_spread, allow_hole) {
|
|||||||
if (value instanceof AST_Destructured) throw new Error(prop + " cannot " + multiple + " AST_Destructured");
|
if (value instanceof AST_Destructured) throw new Error(prop + " cannot " + multiple + " AST_Destructured");
|
||||||
if (value instanceof AST_Hole && !allow_hole) throw new Error(prop + " cannot " + multiple + " AST_Hole");
|
if (value instanceof AST_Hole && !allow_hole) throw new Error(prop + " cannot " + multiple + " AST_Hole");
|
||||||
if (value instanceof AST_Spread && !allow_spread) throw new Error(prop + " cannot " + multiple + " AST_Spread");
|
if (value instanceof AST_Spread && !allow_spread) throw new Error(prop + " cannot " + multiple + " AST_Spread");
|
||||||
if (value instanceof AST_Statement && !is_function(value)) {
|
if (value instanceof AST_Statement && !(value instanceof AST_LambdaExpression)) {
|
||||||
throw new Error(prop + " cannot " + multiple + " AST_Statement");
|
throw new Error(prop + " cannot " + multiple + " AST_Statement");
|
||||||
}
|
}
|
||||||
if (value instanceof AST_SymbolDeclaration) {
|
if (value instanceof AST_SymbolDeclaration) {
|
||||||
@@ -265,6 +270,7 @@ var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_s
|
|||||||
return this.parent_scope.resolve();
|
return this.parent_scope.resolve();
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "BlockScope") throw new Error("should not instantiate AST_BlockScope");
|
||||||
if (this.parent_scope == null) return;
|
if (this.parent_scope == null) return;
|
||||||
if (!(this.parent_scope instanceof AST_BlockScope)) throw new Error("parent_scope must be AST_BlockScope");
|
if (!(this.parent_scope instanceof AST_BlockScope)) throw new Error("parent_scope must be AST_BlockScope");
|
||||||
if (!(this.resolve() instanceof AST_Scope)) throw new Error("must be contained within AST_Scope");
|
if (!(this.resolve() instanceof AST_Scope)) throw new Error("must be contained within AST_Scope");
|
||||||
@@ -289,9 +295,10 @@ var AST_Block = DEFNODE("Block", "body", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Block") throw new Error("should not instantiate AST_Block");
|
||||||
this.body.forEach(function(node) {
|
this.body.forEach(function(node) {
|
||||||
if (!(node instanceof AST_Statement)) throw new Error("body must be AST_Statement[]");
|
if (!(node instanceof AST_Statement)) throw new Error("body must be AST_Statement[]");
|
||||||
if (is_function(node)) throw new Error("body cannot contain AST_Function");
|
if (node instanceof AST_LambdaExpression) throw new Error("body cannot contain AST_LambdaExpression");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_BlockScope);
|
}, AST_BlockScope);
|
||||||
@@ -306,8 +313,9 @@ var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
|||||||
body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
|
body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "StatementWithBody") throw new Error("should not instantiate AST_StatementWithBody");
|
||||||
if (!(this.body instanceof AST_Statement)) throw new Error("body must be AST_Statement");
|
if (!(this.body instanceof AST_Statement)) throw new Error("body must be AST_Statement");
|
||||||
if (is_function(this.body)) throw new Error("body cannot be AST_Function");
|
if (this.body instanceof AST_LambdaExpression) throw new Error("body cannot be AST_LambdaExpression");
|
||||||
},
|
},
|
||||||
}, AST_BlockScope);
|
}, AST_BlockScope);
|
||||||
|
|
||||||
@@ -346,7 +354,10 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
|||||||
}, AST_StatementWithBody);
|
}, AST_StatementWithBody);
|
||||||
|
|
||||||
var AST_IterationStatement = DEFNODE("IterationStatement", null, {
|
var AST_IterationStatement = DEFNODE("IterationStatement", null, {
|
||||||
$documentation: "Internal class. All loops inherit from it."
|
$documentation: "Internal class. All loops inherit from it.",
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "IterationStatement") throw new Error("should not instantiate AST_IterationStatement");
|
||||||
|
},
|
||||||
}, AST_StatementWithBody);
|
}, AST_StatementWithBody);
|
||||||
|
|
||||||
var AST_DWLoop = DEFNODE("DWLoop", "condition", {
|
var AST_DWLoop = DEFNODE("DWLoop", "condition", {
|
||||||
@@ -355,6 +366,7 @@ var AST_DWLoop = DEFNODE("DWLoop", "condition", {
|
|||||||
condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
|
condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "DWLoop") throw new Error("should not instantiate AST_DWLoop");
|
||||||
must_be_expression(this, "condition");
|
must_be_expression(this, "condition");
|
||||||
},
|
},
|
||||||
}, AST_IterationStatement);
|
}, AST_IterationStatement);
|
||||||
@@ -401,7 +413,7 @@ var AST_For = DEFNODE("For", "init condition step", {
|
|||||||
if (this.init != null) {
|
if (this.init != null) {
|
||||||
if (!(this.init instanceof AST_Node)) throw new Error("init must be AST_Node");
|
if (!(this.init instanceof AST_Node)) throw new Error("init must be AST_Node");
|
||||||
if (this.init instanceof AST_Statement
|
if (this.init instanceof AST_Statement
|
||||||
&& !(this.init instanceof AST_Definitions || is_function(this.init))) {
|
&& !(this.init instanceof AST_Definitions || this.init instanceof AST_LambdaExpression)) {
|
||||||
throw new Error("init cannot be AST_Statement");
|
throw new Error("init cannot be AST_Statement");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -467,6 +479,9 @@ var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", {
|
|||||||
return this.uses_eval || this.uses_with;
|
return this.uses_eval || this.uses_with;
|
||||||
},
|
},
|
||||||
resolve: return_this,
|
resolve: return_this,
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Scope") throw new Error("should not instantiate AST_Scope");
|
||||||
|
},
|
||||||
}, AST_Block);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||||
@@ -517,8 +532,9 @@ var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest uses_arguments", {
|
|||||||
$documentation: "Base class for functions",
|
$documentation: "Base class for functions",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
argnames: "[(AST_DefaultValue|AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
|
argnames: "[(AST_DefaultValue|AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
|
||||||
|
length_read: "[boolean/S] whether length property of this function is accessed",
|
||||||
rest: "[(AST_Destructured|AST_SymbolFunarg)?] rest parameter, or null if absent",
|
rest: "[(AST_Destructured|AST_SymbolFunarg)?] rest parameter, or null if absent",
|
||||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
|
uses_arguments: "[boolean/S] whether this function accesses the arguments array",
|
||||||
},
|
},
|
||||||
each_argname: function(visit) {
|
each_argname: function(visit) {
|
||||||
var tw = new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
@@ -549,6 +565,7 @@ var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest uses_arguments", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Lambda") throw new Error("should not instantiate AST_Lambda");
|
||||||
this.argnames.forEach(function(node) {
|
this.argnames.forEach(function(node) {
|
||||||
validate_destructured(node, function(node) {
|
validate_destructured(node, function(node) {
|
||||||
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
||||||
@@ -567,12 +584,33 @@ var AST_Accessor = DEFNODE("Accessor", null, {
|
|||||||
},
|
},
|
||||||
}, AST_Lambda);
|
}, AST_Lambda);
|
||||||
|
|
||||||
|
var AST_LambdaExpression = DEFNODE("LambdaExpression", "inlined", {
|
||||||
|
$documentation: "Base class for function expressions",
|
||||||
|
$propdoc: {
|
||||||
|
inlined: "[boolean/S] whether this function has been inlined",
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "LambdaExpression") throw new Error("should not instantiate AST_LambdaExpression");
|
||||||
|
},
|
||||||
|
}, AST_Lambda);
|
||||||
|
|
||||||
function is_arrow(node) {
|
function is_arrow(node) {
|
||||||
return node instanceof AST_AsyncArrow || node instanceof AST_Arrow;
|
return node instanceof AST_Arrow || node instanceof AST_AsyncArrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_function(node) {
|
function is_async(node) {
|
||||||
return is_arrow(node) || node instanceof AST_AsyncFunction || node instanceof AST_Function;
|
return node instanceof AST_AsyncArrow
|
||||||
|
|| node instanceof AST_AsyncDefun
|
||||||
|
|| node instanceof AST_AsyncFunction
|
||||||
|
|| node instanceof AST_AsyncGeneratorDefun
|
||||||
|
|| node instanceof AST_AsyncGeneratorFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_generator(node) {
|
||||||
|
return node instanceof AST_AsyncGeneratorDefun
|
||||||
|
|| node instanceof AST_AsyncGeneratorFunction
|
||||||
|
|| node instanceof AST_GeneratorDefun
|
||||||
|
|| node instanceof AST_GeneratorFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
function walk_lambda(node, tw) {
|
function walk_lambda(node, tw) {
|
||||||
@@ -583,7 +621,7 @@ function walk_lambda(node, tw) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var AST_Arrow = DEFNODE("Arrow", "inlined value", {
|
var AST_Arrow = DEFNODE("Arrow", "value", {
|
||||||
$documentation: "An arrow function expression",
|
$documentation: "An arrow function expression",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
value: "[AST_Node?] simple return expression, or null if using function body.",
|
value: "[AST_Node?] simple return expression, or null if using function body.",
|
||||||
@@ -610,13 +648,9 @@ var AST_Arrow = DEFNODE("Arrow", "inlined value", {
|
|||||||
if (this.body.length) throw new Error("body must be empty if value exists");
|
if (this.body.length) throw new Error("body must be empty if value exists");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}, AST_Lambda);
|
}, AST_LambdaExpression);
|
||||||
|
|
||||||
function is_async(node) {
|
var AST_AsyncArrow = DEFNODE("AsyncArrow", "value", {
|
||||||
return node instanceof AST_AsyncArrow || node instanceof AST_AsyncDefun || node instanceof AST_AsyncFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
var AST_AsyncArrow = DEFNODE("AsyncArrow", "inlined value", {
|
|
||||||
$documentation: "An asynchronous arrow function expression",
|
$documentation: "An asynchronous arrow function expression",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
value: "[AST_Node?] simple return expression, or null if using function body.",
|
value: "[AST_Node?] simple return expression, or null if using function body.",
|
||||||
@@ -643,9 +677,9 @@ var AST_AsyncArrow = DEFNODE("AsyncArrow", "inlined value", {
|
|||||||
if (this.body.length) throw new Error("body must be empty if value exists");
|
if (this.body.length) throw new Error("body must be empty if value exists");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}, AST_Lambda);
|
}, AST_LambdaExpression);
|
||||||
|
|
||||||
var AST_AsyncFunction = DEFNODE("AsyncFunction", "inlined name", {
|
var AST_AsyncFunction = DEFNODE("AsyncFunction", "name", {
|
||||||
$documentation: "An asynchronous function expression",
|
$documentation: "An asynchronous function expression",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[AST_SymbolLambda?] the name of this function",
|
name: "[AST_SymbolLambda?] the name of this function",
|
||||||
@@ -655,9 +689,21 @@ var AST_AsyncFunction = DEFNODE("AsyncFunction", "inlined name", {
|
|||||||
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
|
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}, AST_Lambda);
|
}, AST_LambdaExpression);
|
||||||
|
|
||||||
var AST_Function = DEFNODE("Function", "inlined name", {
|
var AST_AsyncGeneratorFunction = DEFNODE("AsyncGeneratorFunction", "name", {
|
||||||
|
$documentation: "An asynchronous generator function expression",
|
||||||
|
$propdoc: {
|
||||||
|
name: "[AST_SymbolLambda?] the name of this function",
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.name != null) {
|
||||||
|
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, AST_LambdaExpression);
|
||||||
|
|
||||||
|
var AST_Function = DEFNODE("Function", "name", {
|
||||||
$documentation: "A function expression",
|
$documentation: "A function expression",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[AST_SymbolLambda?] the name of this function",
|
name: "[AST_SymbolLambda?] the name of this function",
|
||||||
@@ -667,36 +713,55 @@ var AST_Function = DEFNODE("Function", "inlined name", {
|
|||||||
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
|
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
}, AST_LambdaExpression);
|
||||||
|
|
||||||
|
var AST_GeneratorFunction = DEFNODE("GeneratorFunction", "name", {
|
||||||
|
$documentation: "A generator function expression",
|
||||||
|
$propdoc: {
|
||||||
|
name: "[AST_SymbolLambda?] the name of this function",
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.name != null) {
|
||||||
|
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, AST_LambdaExpression);
|
||||||
|
|
||||||
|
var AST_LambdaDefinition = DEFNODE("LambdaDefinition", "inlined name", {
|
||||||
|
$documentation: "Base class for function definitions",
|
||||||
|
$propdoc: {
|
||||||
|
inlined: "[boolean/S] whether this function has been inlined",
|
||||||
|
name: "[AST_SymbolDefun] the name of this function",
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "LambdaDefinition") throw new Error("should not instantiate AST_LambdaDefinition");
|
||||||
|
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");
|
||||||
|
},
|
||||||
}, AST_Lambda);
|
}, AST_Lambda);
|
||||||
|
|
||||||
function is_defun(node) {
|
var AST_AsyncDefun = DEFNODE("AsyncDefun", null, {
|
||||||
return node instanceof AST_AsyncDefun || node instanceof AST_Defun;
|
|
||||||
}
|
|
||||||
|
|
||||||
var AST_AsyncDefun = DEFNODE("AsyncDefun", "inlined name", {
|
|
||||||
$documentation: "An asynchronous function definition",
|
$documentation: "An asynchronous function definition",
|
||||||
$propdoc: {
|
}, AST_LambdaDefinition);
|
||||||
name: "[AST_SymbolDefun] the name of this function",
|
|
||||||
},
|
|
||||||
_validate: function() {
|
|
||||||
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");
|
|
||||||
},
|
|
||||||
}, AST_Lambda);
|
|
||||||
|
|
||||||
var AST_Defun = DEFNODE("Defun", "inlined name", {
|
var AST_AsyncGeneratorDefun = DEFNODE("AsyncGeneratorDefun", null, {
|
||||||
|
$documentation: "An asynchronous generator function definition",
|
||||||
|
}, AST_LambdaDefinition);
|
||||||
|
|
||||||
|
var AST_Defun = DEFNODE("Defun", null, {
|
||||||
$documentation: "A function definition",
|
$documentation: "A function definition",
|
||||||
$propdoc: {
|
}, AST_LambdaDefinition);
|
||||||
name: "[AST_SymbolDefun] the name of this function",
|
|
||||||
},
|
var AST_GeneratorDefun = DEFNODE("GeneratorDefun", null, {
|
||||||
_validate: function() {
|
$documentation: "A generator function definition",
|
||||||
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");
|
}, AST_LambdaDefinition);
|
||||||
},
|
|
||||||
}, AST_Lambda);
|
|
||||||
|
|
||||||
/* -----[ JUMPS ]----- */
|
/* -----[ JUMPS ]----- */
|
||||||
|
|
||||||
var AST_Jump = DEFNODE("Jump", null, {
|
var AST_Jump = DEFNODE("Jump", null, {
|
||||||
$documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
|
$documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)",
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Jump") throw new Error("should not instantiate AST_Jump");
|
||||||
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
var AST_Exit = DEFNODE("Exit", "value", {
|
var AST_Exit = DEFNODE("Exit", "value", {
|
||||||
@@ -709,7 +774,10 @@ var AST_Exit = DEFNODE("Exit", "value", {
|
|||||||
visitor.visit(node, function() {
|
visitor.visit(node, function() {
|
||||||
if (node.value) node.value.walk(visitor);
|
if (node.value) node.value.walk(visitor);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Exit") throw new Error("should not instantiate AST_Exit");
|
||||||
|
},
|
||||||
}, AST_Jump);
|
}, AST_Jump);
|
||||||
|
|
||||||
var AST_Return = DEFNODE("Return", null, {
|
var AST_Return = DEFNODE("Return", null, {
|
||||||
@@ -738,6 +806,7 @@ var AST_LoopControl = DEFNODE("LoopControl", "label", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "LoopControl") throw new Error("should not instantiate AST_LoopControl");
|
||||||
if (this.label != null) {
|
if (this.label != null) {
|
||||||
if (!(this.label instanceof AST_LabelRef)) throw new Error("label must be AST_LabelRef");
|
if (!(this.label instanceof AST_LabelRef)) throw new Error("label must be AST_LabelRef");
|
||||||
}
|
}
|
||||||
@@ -772,7 +841,7 @@ var AST_If = DEFNODE("If", "condition alternative", {
|
|||||||
must_be_expression(this, "condition");
|
must_be_expression(this, "condition");
|
||||||
if (this.alternative != null) {
|
if (this.alternative != null) {
|
||||||
if (!(this.alternative instanceof AST_Statement)) throw new Error("alternative must be AST_Statement");
|
if (!(this.alternative instanceof AST_Statement)) throw new Error("alternative must be AST_Statement");
|
||||||
if (is_function(this.alternative)) throw new error("alternative cannot be AST_Function");
|
if (this.alternative instanceof AST_LambdaExpression) throw new error("alternative cannot be AST_LambdaExpression");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}, AST_StatementWithBody);
|
}, AST_StatementWithBody);
|
||||||
@@ -801,6 +870,9 @@ var AST_Switch = DEFNODE("Switch", "expression", {
|
|||||||
|
|
||||||
var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
|
var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
|
||||||
$documentation: "Base class for `switch` branches",
|
$documentation: "Base class for `switch` branches",
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "SwitchBranch") throw new Error("should not instantiate AST_SwitchBranch");
|
||||||
|
},
|
||||||
}, AST_Block);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Default = DEFNODE("Default", null, {
|
var AST_Default = DEFNODE("Default", null, {
|
||||||
@@ -889,6 +961,7 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Definitions") throw new Error("should not instantiate AST_Definitions");
|
||||||
if (this.definitions.length < 1) throw new Error("must have at least one definition");
|
if (this.definitions.length < 1) throw new Error("must have at least one definition");
|
||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
@@ -1036,6 +1109,7 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
|
|||||||
return p;
|
return p;
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "PropAccess") throw new Error("should not instantiate AST_PropAccess");
|
||||||
must_be_expression(this, "expression");
|
must_be_expression(this, "expression");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1096,6 +1170,7 @@ var AST_Unary = DEFNODE("Unary", "operator expression", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Unary") throw new Error("should not instantiate AST_Unary");
|
||||||
if (typeof this.operator != "string") throw new Error("operator must be string");
|
if (typeof this.operator != "string") throw new Error("operator must be string");
|
||||||
must_be_expression(this, "expression");
|
must_be_expression(this, "expression");
|
||||||
},
|
},
|
||||||
@@ -1183,6 +1258,27 @@ var AST_Await = DEFNODE("Await", "expression", {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var AST_Yield = DEFNODE("Yield", "expression nested", {
|
||||||
|
$documentation: "A yield expression",
|
||||||
|
$propdoc: {
|
||||||
|
expression: "[AST_Node?] return value for iterator, or null if undefined",
|
||||||
|
nested: "[boolean] whether to iterate over expression as generator",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
if (node.expression) node.expression.walk(visitor);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.expression != null) {
|
||||||
|
must_be_expression(this, "expression");
|
||||||
|
} else if (this.nested) {
|
||||||
|
throw new Error("yield* must contain expression");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
/* -----[ LITERALS ]----- */
|
/* -----[ LITERALS ]----- */
|
||||||
|
|
||||||
var AST_Array = DEFNODE("Array", "elements", {
|
var AST_Array = DEFNODE("Array", "elements", {
|
||||||
@@ -1208,6 +1304,9 @@ var AST_Destructured = DEFNODE("Destructured", "rest", {
|
|||||||
$propdoc: {
|
$propdoc: {
|
||||||
rest: "[(AST_Destructured|AST_SymbolDeclaration|AST_SymbolRef)?] rest parameter, or null if absent",
|
rest: "[(AST_Destructured|AST_SymbolDeclaration|AST_SymbolRef)?] rest parameter, or null if absent",
|
||||||
},
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Destructured") throw new Error("should not instantiate AST_Destructured");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function validate_destructured(node, check, allow_default) {
|
function validate_destructured(node, check, allow_default) {
|
||||||
@@ -1319,6 +1418,7 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "ObjectProperty") throw new Error("should not instantiate AST_ObjectProperty");
|
||||||
if (typeof this.key != "string") {
|
if (typeof this.key != "string") {
|
||||||
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
|
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
|
||||||
must_be_expression(this, "key");
|
must_be_expression(this, "key");
|
||||||
@@ -1356,6 +1456,7 @@ var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
|||||||
thedef: "[SymbolDef/S] the definition of this symbol"
|
thedef: "[SymbolDef/S] the definition of this symbol"
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Symbol") throw new Error("should not instantiate AST_Symbol");
|
||||||
if (typeof this.name != "string") throw new Error("name must be string");
|
if (typeof this.name != "string") throw new Error("name must be string");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1448,6 +1549,9 @@ var AST_Template = DEFNODE("Template", "expressions strings tag", {
|
|||||||
|
|
||||||
var AST_Constant = DEFNODE("Constant", null, {
|
var AST_Constant = DEFNODE("Constant", null, {
|
||||||
$documentation: "Base class for all constants",
|
$documentation: "Base class for all constants",
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Constant") throw new Error("should not instantiate AST_Constant");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var AST_String = DEFNODE("String", "value quote", {
|
var AST_String = DEFNODE("String", "value quote", {
|
||||||
@@ -1496,6 +1600,9 @@ var AST_RegExp = DEFNODE("RegExp", "value", {
|
|||||||
|
|
||||||
var AST_Atom = DEFNODE("Atom", null, {
|
var AST_Atom = DEFNODE("Atom", null, {
|
||||||
$documentation: "Base class for atoms",
|
$documentation: "Base class for atoms",
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Atom") throw new Error("should not instantiate AST_Atom");
|
||||||
|
},
|
||||||
}, AST_Constant);
|
}, AST_Constant);
|
||||||
|
|
||||||
var AST_Null = DEFNODE("Null", null, {
|
var AST_Null = DEFNODE("Null", null, {
|
||||||
@@ -1525,6 +1632,9 @@ var AST_Infinity = DEFNODE("Infinity", null, {
|
|||||||
|
|
||||||
var AST_Boolean = DEFNODE("Boolean", null, {
|
var AST_Boolean = DEFNODE("Boolean", null, {
|
||||||
$documentation: "Base class for booleans",
|
$documentation: "Base class for booleans",
|
||||||
|
_validate: function() {
|
||||||
|
if (this.TYPE == "Boolean") throw new Error("should not instantiate AST_Boolean");
|
||||||
|
},
|
||||||
}, AST_Atom);
|
}, AST_Atom);
|
||||||
|
|
||||||
var AST_False = DEFNODE("False", null, {
|
var AST_False = DEFNODE("False", null, {
|
||||||
|
|||||||
174
lib/compress.js
174
lib/compress.js
@@ -104,6 +104,7 @@ function Compressor(options, false_by_default) {
|
|||||||
unsafe_undefined: false,
|
unsafe_undefined: false,
|
||||||
unused : !false_by_default,
|
unused : !false_by_default,
|
||||||
varify : !false_by_default,
|
varify : !false_by_default,
|
||||||
|
yields : !false_by_default,
|
||||||
}, true);
|
}, true);
|
||||||
var evaluate = this.options["evaluate"];
|
var evaluate = this.options["evaluate"];
|
||||||
this.eval_threshold = /eager/.test(evaluate) ? 1 / 0 : +evaluate;
|
this.eval_threshold = /eager/.test(evaluate) ? 1 / 0 : +evaluate;
|
||||||
@@ -344,7 +345,7 @@ merge(Compressor.prototype, {
|
|||||||
return !immutable
|
return !immutable
|
||||||
&& parent.expression === node
|
&& parent.expression === node
|
||||||
&& !parent.is_expr_pure(compressor)
|
&& !parent.is_expr_pure(compressor)
|
||||||
&& (!is_function(value) || !(parent instanceof AST_New) && value.contains_this());
|
&& (!(value instanceof AST_LambdaExpression) || !(parent instanceof AST_New) && value.contains_this());
|
||||||
}
|
}
|
||||||
if (parent instanceof AST_ForIn) return parent.init === node;
|
if (parent instanceof AST_ForIn) return parent.init === node;
|
||||||
if (parent instanceof AST_ObjectKeyVal) {
|
if (parent instanceof AST_ObjectKeyVal) {
|
||||||
@@ -396,13 +397,13 @@ merge(Compressor.prototype, {
|
|||||||
def.fixed = !def.const_redefs
|
def.fixed = !def.const_redefs
|
||||||
&& !def.scope.pinned()
|
&& !def.scope.pinned()
|
||||||
&& !compressor.exposed(def)
|
&& !compressor.exposed(def)
|
||||||
&& !(is_function(def.init) && def.init !== def.scope)
|
&& !(def.init instanceof AST_LambdaExpression && def.init !== def.scope)
|
||||||
&& def.init;
|
&& def.init;
|
||||||
if (is_defun(def.fixed) && !all(def.references, function(ref) {
|
if (def.fixed instanceof AST_LambdaDefinition && !all(def.references, function(ref) {
|
||||||
var scope = ref.scope.resolve();
|
var scope = ref.scope.resolve();
|
||||||
do {
|
do {
|
||||||
if (def.scope === scope) return true;
|
if (def.scope === scope) return true;
|
||||||
} while (is_function(scope) && (scope = scope.parent_scope.resolve()));
|
} while (scope instanceof AST_LambdaExpression && (scope = scope.parent_scope.resolve()));
|
||||||
})) {
|
})) {
|
||||||
tw.defun_ids[def.id] = false;
|
tw.defun_ids[def.id] = false;
|
||||||
}
|
}
|
||||||
@@ -427,7 +428,7 @@ merge(Compressor.prototype, {
|
|||||||
scope.may_call_this = noop;
|
scope.may_call_this = noop;
|
||||||
if (!scope.contains_this()) return;
|
if (!scope.contains_this()) return;
|
||||||
scope.functions.each(function(def) {
|
scope.functions.each(function(def) {
|
||||||
if (is_defun(def.init) && !(def.id in tw.defun_ids)) {
|
if (def.init instanceof AST_LambdaDefinition && !(def.id in tw.defun_ids)) {
|
||||||
tw.defun_ids[def.id] = false;
|
tw.defun_ids[def.id] = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -467,7 +468,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function walk_defuns(tw, scope) {
|
function walk_defuns(tw, scope) {
|
||||||
scope.functions.each(function(def) {
|
scope.functions.each(function(def) {
|
||||||
if (is_defun(def.init) && !tw.defun_visited[def.id]) {
|
if (def.init instanceof AST_LambdaDefinition && !tw.defun_visited[def.id]) {
|
||||||
tw.defun_ids[def.id] = tw.safe_ids;
|
tw.defun_ids[def.id] = tw.safe_ids;
|
||||||
def.init.walk(tw);
|
def.init.walk(tw);
|
||||||
}
|
}
|
||||||
@@ -505,7 +506,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return !safe.assign || safe.assign === tw.safe_ids;
|
return !safe.assign || safe.assign === tw.safe_ids;
|
||||||
}
|
}
|
||||||
return is_defun(def.fixed);
|
return def.fixed instanceof AST_LambdaDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
function safe_to_assign(tw, def, declare) {
|
function safe_to_assign(tw, def, declare) {
|
||||||
@@ -702,25 +703,11 @@ merge(Compressor.prototype, {
|
|||||||
lhs.walk(scanner);
|
lhs.walk(scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reduce_defun(tw, descend, compressor) {
|
|
||||||
var id = this.name.definition().id;
|
|
||||||
if (tw.defun_visited[id]) return true;
|
|
||||||
if (tw.defun_ids[id] !== tw.safe_ids) return true;
|
|
||||||
tw.defun_visited[id] = true;
|
|
||||||
this.inlined = false;
|
|
||||||
push(tw);
|
|
||||||
reset_variables(tw, compressor, this);
|
|
||||||
descend();
|
|
||||||
pop(tw);
|
|
||||||
walk_defuns(tw, this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function reduce_iife(tw, descend, compressor) {
|
function reduce_iife(tw, descend, compressor) {
|
||||||
var fn = this;
|
var fn = this;
|
||||||
fn.inlined = false;
|
fn.inlined = false;
|
||||||
var iife = tw.parent();
|
var iife = tw.parent();
|
||||||
var hit = is_async(fn);
|
var hit = is_async(fn) || is_generator(fn);
|
||||||
var aborts = false;
|
var aborts = false;
|
||||||
fn.walk(new TreeWalker(function(node) {
|
fn.walk(new TreeWalker(function(node) {
|
||||||
if (hit) return aborts = true;
|
if (hit) return aborts = true;
|
||||||
@@ -848,7 +835,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
def(AST_AsyncDefun, reduce_defun);
|
|
||||||
def(AST_Binary, function(tw) {
|
def(AST_Binary, function(tw) {
|
||||||
if (!lazy_op[this.operator]) return;
|
if (!lazy_op[this.operator]) return;
|
||||||
this.left.walk(tw);
|
this.left.walk(tw);
|
||||||
@@ -865,7 +851,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Call, function(tw, descend) {
|
def(AST_Call, function(tw, descend) {
|
||||||
tw.find_parent(AST_Scope).may_call_this();
|
tw.find_parent(AST_Scope).may_call_this();
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
if (is_function(exp)) {
|
if (exp instanceof AST_LambdaExpression) {
|
||||||
var iife = !exp.name;
|
var iife = !exp.name;
|
||||||
this.args.forEach(function(arg) {
|
this.args.forEach(function(arg) {
|
||||||
arg.walk(tw);
|
arg.walk(tw);
|
||||||
@@ -878,7 +864,7 @@ merge(Compressor.prototype, {
|
|||||||
} else if (exp instanceof AST_SymbolRef) {
|
} else if (exp instanceof AST_SymbolRef) {
|
||||||
var def = exp.definition();
|
var def = exp.definition();
|
||||||
if (this.TYPE == "Call" && tw.in_boolean_context()) def.bool_fn++;
|
if (this.TYPE == "Call" && tw.in_boolean_context()) def.bool_fn++;
|
||||||
if (!is_defun(def.fixed)) return;
|
if (!(def.fixed instanceof AST_LambdaDefinition)) return;
|
||||||
var defun = mark_defun(tw, def);
|
var defun = mark_defun(tw, def);
|
||||||
if (!defun) return;
|
if (!defun) return;
|
||||||
descend();
|
descend();
|
||||||
@@ -909,7 +895,6 @@ merge(Compressor.prototype, {
|
|||||||
pop(tw);
|
pop(tw);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Defun, reduce_defun);
|
|
||||||
def(AST_Do, function(tw) {
|
def(AST_Do, function(tw) {
|
||||||
var saved_loop = tw.in_loop;
|
var saved_loop = tw.in_loop;
|
||||||
tw.in_loop = this;
|
tw.in_loop = this;
|
||||||
@@ -1008,6 +993,19 @@ merge(Compressor.prototype, {
|
|||||||
walk_defuns(tw, fn);
|
walk_defuns(tw, fn);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
def(AST_LambdaDefinition, function(tw, descend, compressor) {
|
||||||
|
var id = this.name.definition().id;
|
||||||
|
if (tw.defun_visited[id]) return true;
|
||||||
|
if (tw.defun_ids[id] !== tw.safe_ids) return true;
|
||||||
|
tw.defun_visited[id] = true;
|
||||||
|
this.inlined = false;
|
||||||
|
push(tw);
|
||||||
|
reset_variables(tw, compressor, this);
|
||||||
|
descend();
|
||||||
|
pop(tw);
|
||||||
|
walk_defuns(tw, this);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
def(AST_Switch, function(tw, descend, compressor) {
|
def(AST_Switch, function(tw, descend, compressor) {
|
||||||
this.variables.each(function(def) {
|
this.variables.each(function(def) {
|
||||||
reset_def(tw, compressor, def);
|
reset_def(tw, compressor, def);
|
||||||
@@ -1079,7 +1077,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (!this.fixed) this.fixed = d.fixed;
|
if (!this.fixed) this.fixed = d.fixed;
|
||||||
var parent;
|
var parent;
|
||||||
if (is_defun(d.fixed) && !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
|
if (d.fixed instanceof AST_LambdaDefinition
|
||||||
|
&& !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
|
||||||
var defun = mark_defun(tw, d);
|
var defun = mark_defun(tw, d);
|
||||||
if (defun) defun.walk(tw);
|
if (defun) defun.walk(tw);
|
||||||
}
|
}
|
||||||
@@ -1455,8 +1454,10 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function is_iife_call(node) {
|
function is_iife_call(node) {
|
||||||
if (node.TYPE != "Call") return false;
|
if (node.TYPE != "Call") return false;
|
||||||
var exp = node.expression;
|
do {
|
||||||
return exp instanceof AST_AsyncFunction || exp instanceof AST_Function || is_iife_call(exp);
|
node = node.expression;
|
||||||
|
} while (node instanceof AST_PropAccess);
|
||||||
|
return node instanceof AST_LambdaExpression ? !is_arrow(node) : is_iife_call(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_undeclared_ref(node) {
|
function is_undeclared_ref(node) {
|
||||||
@@ -1843,7 +1844,7 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_Call) {
|
if (node instanceof AST_Call) {
|
||||||
if (!(lhs instanceof AST_PropAccess)) return false;
|
if (!(lhs instanceof AST_PropAccess)) return false;
|
||||||
if (!lhs.equivalent_to(node.expression)) return false;
|
if (!lhs.equivalent_to(node.expression)) return false;
|
||||||
return !(is_function(rvalue) && !rvalue.contains_this());
|
return !(rvalue instanceof AST_LambdaExpression && !rvalue.contains_this());
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Debugger) return true;
|
if (node instanceof AST_Debugger) return true;
|
||||||
if (node instanceof AST_Defun) return funarg && lhs.name === node.name.name;
|
if (node instanceof AST_Defun) return funarg && lhs.name === node.name.name;
|
||||||
@@ -1951,6 +1952,7 @@ merge(Compressor.prototype, {
|
|||||||
&& (lvalues.has(node.name) || side_effects && may_modify(node));
|
&& (lvalues.has(node.name) || side_effects && may_modify(node));
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Yield) return true;
|
||||||
var sym = is_lhs(node.left, node);
|
var sym = is_lhs(node.left, node);
|
||||||
if (!sym) return false;
|
if (!sym) return false;
|
||||||
if (sym instanceof AST_PropAccess) return true;
|
if (sym instanceof AST_PropAccess) return true;
|
||||||
@@ -1988,7 +1990,8 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function extract_args() {
|
function extract_args() {
|
||||||
var iife, fn = compressor.self();
|
var iife, fn = compressor.self();
|
||||||
if (is_function(fn)
|
if (fn instanceof AST_LambdaExpression
|
||||||
|
&& !is_generator(fn)
|
||||||
&& !fn.name
|
&& !fn.name
|
||||||
&& !fn.uses_arguments
|
&& !fn.uses_arguments
|
||||||
&& !fn.pinned()
|
&& !fn.pinned()
|
||||||
@@ -2482,7 +2485,7 @@ merge(Compressor.prototype, {
|
|||||||
if (modify_toplevel) return;
|
if (modify_toplevel) return;
|
||||||
var exp = node.expression;
|
var exp = node.expression;
|
||||||
if (exp instanceof AST_PropAccess) return;
|
if (exp instanceof AST_PropAccess) return;
|
||||||
if (is_function(exp) && !exp.contains_this()) return;
|
if (exp instanceof AST_LambdaExpression && !exp.contains_this()) return;
|
||||||
modify_toplevel = true;
|
modify_toplevel = true;
|
||||||
} else if (node instanceof AST_PropAccess && may_be_global(node.expression)) {
|
} else if (node instanceof AST_PropAccess && may_be_global(node.expression)) {
|
||||||
if (node === lhs && !(expr instanceof AST_Unary)) {
|
if (node === lhs && !(expr instanceof AST_Unary)) {
|
||||||
@@ -3249,7 +3252,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
||||||
if (!(stat instanceof AST_Definitions || is_defun(stat))) {
|
if (!(stat instanceof AST_Definitions || stat instanceof AST_LambdaDefinition)) {
|
||||||
AST_Node.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
AST_Node.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
||||||
}
|
}
|
||||||
var block;
|
var block;
|
||||||
@@ -3265,7 +3268,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (is_defun(node)) {
|
if (node instanceof AST_LambdaDefinition) {
|
||||||
push(node);
|
push(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -5114,7 +5117,7 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_Call) {
|
if (node instanceof AST_Call) {
|
||||||
var exp = node.expression;
|
var exp = node.expression;
|
||||||
var tail = exp.tail_node();
|
var tail = exp.tail_node();
|
||||||
if (!is_function(tail)) return;
|
if (!(tail instanceof AST_LambdaExpression)) return;
|
||||||
if (exp !== tail) exp.expressions.slice(0, -1).forEach(function(node) {
|
if (exp !== tail) exp.expressions.slice(0, -1).forEach(function(node) {
|
||||||
node.walk(tw);
|
node.walk(tw);
|
||||||
});
|
});
|
||||||
@@ -5534,7 +5537,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node === self) return;
|
if (node === self) return;
|
||||||
if (scope === self) {
|
if (scope === self) {
|
||||||
if (is_defun(node)) {
|
if (node instanceof AST_LambdaDefinition) {
|
||||||
var def = node.name.definition();
|
var def = node.name.definition();
|
||||||
if (!drop_funcs && !(def.id in in_use_ids)) {
|
if (!drop_funcs && !(def.id in in_use_ids)) {
|
||||||
in_use_ids[def.id] = true;
|
in_use_ids[def.id] = true;
|
||||||
@@ -5735,7 +5738,7 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_Call) calls_to_drop_args.push(node);
|
if (node instanceof AST_Call) calls_to_drop_args.push(node);
|
||||||
if (scope !== self) return;
|
if (scope !== self) return;
|
||||||
if (node instanceof AST_Lambda) {
|
if (node instanceof AST_Lambda) {
|
||||||
if (drop_funcs && node !== self && is_defun(node)) {
|
if (drop_funcs && node !== self && node instanceof AST_LambdaDefinition) {
|
||||||
var def = node.name.definition();
|
var def = node.name.definition();
|
||||||
if (!(def.id in in_use_ids)) {
|
if (!(def.id in in_use_ids)) {
|
||||||
log(node.name, "Dropping unused function {name}");
|
log(node.name, "Dropping unused function {name}");
|
||||||
@@ -5743,7 +5746,7 @@ merge(Compressor.prototype, {
|
|||||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_function(node) && node.name && drop_fn_name(node.name.definition())) {
|
if (node instanceof AST_LambdaExpression && node.name && drop_fn_name(node.name.definition())) {
|
||||||
unused_fn_names.push(node);
|
unused_fn_names.push(node);
|
||||||
}
|
}
|
||||||
if (!(node instanceof AST_Accessor)) {
|
if (!(node instanceof AST_Accessor)) {
|
||||||
@@ -5853,12 +5856,28 @@ merge(Compressor.prototype, {
|
|||||||
&& node instanceof AST_Var
|
&& node instanceof AST_Var
|
||||||
&& var_defs[sym.id] == 1
|
&& var_defs[sym.id] == 1
|
||||||
&& sym.assignments == 0
|
&& sym.assignments == 0
|
||||||
&& (value instanceof AST_AsyncFunction || value instanceof AST_Function)
|
&& value instanceof AST_LambdaExpression
|
||||||
|
&& !is_arrow(value)
|
||||||
&& assigned_once(value, sym.references)
|
&& assigned_once(value, sym.references)
|
||||||
&& can_declare_defun()
|
&& can_declare_defun()
|
||||||
&& can_rename(value, def.name.name)) {
|
&& can_rename(value, def.name.name)) {
|
||||||
AST_Node.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name));
|
AST_Node.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name));
|
||||||
var defun = make_node(value instanceof AST_Function ? AST_Defun : AST_AsyncDefun, def, value);
|
var ctor;
|
||||||
|
switch (value.CTOR) {
|
||||||
|
case AST_AsyncFunction:
|
||||||
|
ctor = AST_AsyncDefun;
|
||||||
|
break;
|
||||||
|
case AST_AsyncGeneratorFunction:
|
||||||
|
ctor = AST_AsyncGeneratorDefun;
|
||||||
|
break;
|
||||||
|
case AST_Function:
|
||||||
|
ctor = AST_Defun;
|
||||||
|
break;
|
||||||
|
case AST_GeneratorFunction:
|
||||||
|
ctor = AST_GeneratorDefun;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var defun = make_node(ctor, def, value);
|
||||||
defun.name = make_node(AST_SymbolDefun, def.name, def.name);
|
defun.name = make_node(AST_SymbolDefun, def.name, def.name);
|
||||||
var name_def = def.name.scope.resolve().def_function(defun.name);
|
var name_def = def.name.scope.resolve().def_function(defun.name);
|
||||||
if (old_def) old_def.forEach(function(node) {
|
if (old_def) old_def.forEach(function(node) {
|
||||||
@@ -5916,6 +5935,7 @@ merge(Compressor.prototype, {
|
|||||||
if (old_def.assignments > 0) return false;
|
if (old_def.assignments > 0) return false;
|
||||||
if (old_def.name == name) return true;
|
if (old_def.name == name) return true;
|
||||||
if (name == "await" && is_async(fn)) return false;
|
if (name == "await" && is_async(fn)) return false;
|
||||||
|
if (name == "yield" && is_generator(fn)) return false;
|
||||||
return all(old_def.references, function(ref) {
|
return all(old_def.references, function(ref) {
|
||||||
return ref.scope.find_variable(name) === sym;
|
return ref.scope.find_variable(name) === sym;
|
||||||
});
|
});
|
||||||
@@ -6838,7 +6858,6 @@ merge(Compressor.prototype, {
|
|||||||
})) return this;
|
})) return this;
|
||||||
return make_sequence(this, values.map(convert_spread));
|
return make_sequence(this, values.map(convert_spread));
|
||||||
});
|
});
|
||||||
def(AST_Arrow, return_null);
|
|
||||||
def(AST_Assign, function(compressor) {
|
def(AST_Assign, function(compressor) {
|
||||||
var left = this.left;
|
var left = this.left;
|
||||||
if (left instanceof AST_PropAccess) {
|
if (left instanceof AST_PropAccess) {
|
||||||
@@ -6855,8 +6874,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_AsyncArrow, return_null);
|
|
||||||
def(AST_AsyncFunction, return_null);
|
|
||||||
def(AST_Await, function(compressor) {
|
def(AST_Await, function(compressor) {
|
||||||
if (!compressor.option("awaits")) return this;
|
if (!compressor.option("awaits")) return this;
|
||||||
var exp = this.expression.drop_side_effect_free(compressor);
|
var exp = this.expression.drop_side_effect_free(compressor);
|
||||||
@@ -6991,6 +7008,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Function, function(compressor) {
|
def(AST_Function, function(compressor) {
|
||||||
return fn_name_unused(this, compressor) ? null : this;
|
return fn_name_unused(this, compressor) ? null : this;
|
||||||
});
|
});
|
||||||
|
def(AST_LambdaExpression, return_null);
|
||||||
def(AST_Object, function(compressor, first_in_statement) {
|
def(AST_Object, function(compressor, first_in_statement) {
|
||||||
var exprs = [];
|
var exprs = [];
|
||||||
this.properties.forEach(function(prop) {
|
this.properties.forEach(function(prop) {
|
||||||
@@ -7553,7 +7571,7 @@ merge(Compressor.prototype, {
|
|||||||
var exprs = [];
|
var exprs = [];
|
||||||
for (var i = 0; i < stat.body.length; i++) {
|
for (var i = 0; i < stat.body.length; i++) {
|
||||||
var line = stat.body[i];
|
var line = stat.body[i];
|
||||||
if (is_defun(line)) {
|
if (line instanceof AST_LambdaDefinition) {
|
||||||
defuns.push(line);
|
defuns.push(line);
|
||||||
} else if (line instanceof AST_EmptyStatement) {
|
} else if (line instanceof AST_EmptyStatement) {
|
||||||
continue;
|
continue;
|
||||||
@@ -7570,7 +7588,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return exprs;
|
return exprs;
|
||||||
}
|
}
|
||||||
if (is_defun(stat)) {
|
if (stat instanceof AST_LambdaDefinition) {
|
||||||
defuns.push(stat);
|
defuns.push(stat);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -8274,8 +8292,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
||||||
var is_func = fn instanceof AST_Lambda && (!is_async(fn)
|
var parent = compressor.parent(), current = compressor.self();
|
||||||
|| compressor.option("awaits") && compressor.parent() instanceof AST_Await);
|
var is_func = fn instanceof AST_Lambda
|
||||||
|
&& (!is_async(fn) || compressor.option("awaits") && parent instanceof AST_Await)
|
||||||
|
&& (!is_generator(fn) || compressor.option("yields") && current instanceof AST_Yield && current.nested);
|
||||||
var stat = is_func && fn.first_statement();
|
var stat = is_func && fn.first_statement();
|
||||||
var has_default = 0, has_destructured = false;
|
var has_default = 0, has_destructured = false;
|
||||||
var has_spread = !all(self.args, function(arg) {
|
var has_spread = !all(self.args, function(arg) {
|
||||||
@@ -8308,7 +8328,7 @@ merge(Compressor.prototype, {
|
|||||||
if (can_inline
|
if (can_inline
|
||||||
&& !fn.uses_arguments
|
&& !fn.uses_arguments
|
||||||
&& !fn.pinned()
|
&& !fn.pinned()
|
||||||
&& !(fn.name && is_function(fn))
|
&& !(fn.name && fn instanceof AST_LambdaExpression)
|
||||||
&& (exp === fn || !recursive_ref(compressor, def = exp.definition())
|
&& (exp === fn || !recursive_ref(compressor, def = exp.definition())
|
||||||
&& fn.is_constant_expression(find_scope(compressor)))
|
&& fn.is_constant_expression(find_scope(compressor)))
|
||||||
&& !has_spread
|
&& !has_spread
|
||||||
@@ -8339,7 +8359,7 @@ merge(Compressor.prototype, {
|
|||||||
return arg;
|
return arg;
|
||||||
})).optimize(compressor);
|
})).optimize(compressor);
|
||||||
fn.inlined = save_inlined;
|
fn.inlined = save_inlined;
|
||||||
node = maintain_this_binding(compressor, compressor.parent(), compressor.self(), node);
|
node = maintain_this_binding(compressor, parent, current, node);
|
||||||
if (replacing || best_of_expression(node, self) === node) {
|
if (replacing || best_of_expression(node, self) === node) {
|
||||||
refs.forEach(function(ref) {
|
refs.forEach(function(ref) {
|
||||||
var def = ref.definition();
|
var def = ref.definition();
|
||||||
@@ -8358,7 +8378,7 @@ merge(Compressor.prototype, {
|
|||||||
fn._squeezed = true;
|
fn._squeezed = true;
|
||||||
if (exp !== fn) fn.parent_scope = exp.scope;
|
if (exp !== fn) fn.parent_scope = exp.scope;
|
||||||
var node = make_sequence(self, flatten_fn()).optimize(compressor);
|
var node = make_sequence(self, flatten_fn()).optimize(compressor);
|
||||||
return maintain_this_binding(compressor, compressor.parent(), compressor.self(), node);
|
return maintain_this_binding(compressor, parent, current, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("side_effects")
|
if (compressor.option("side_effects")
|
||||||
@@ -8380,9 +8400,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("negate_iife")
|
if (compressor.option("negate_iife") && parent instanceof AST_SimpleStatement && is_iife_call(current)) {
|
||||||
&& compressor.parent() instanceof AST_SimpleStatement
|
|
||||||
&& is_iife_call(self)) {
|
|
||||||
return self.negate(compressor, true);
|
return self.negate(compressor, true);
|
||||||
}
|
}
|
||||||
return try_evaluate(compressor, self);
|
return try_evaluate(compressor, self);
|
||||||
@@ -8480,7 +8498,7 @@ merge(Compressor.prototype, {
|
|||||||
if (node === fn) return;
|
if (node === fn) return;
|
||||||
if (is_arrow(node)) {
|
if (is_arrow(node)) {
|
||||||
for (var i = 0; safe && i < node.argnames.length; i++) node.argnames[i].walk(tw);
|
for (var i = 0; safe && i < node.argnames.length; i++) node.argnames[i].walk(tw);
|
||||||
} else if (is_defun(node) && node.name.name == "await") {
|
} else if (node instanceof AST_LambdaDefinition && node.name.name == "await") {
|
||||||
safe = false;
|
safe = false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -8566,7 +8584,7 @@ merge(Compressor.prototype, {
|
|||||||
in_order = null;
|
in_order = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (is_defun(def.init)) return abort = true;
|
if (def.init instanceof AST_LambdaDefinition) return abort = true;
|
||||||
if (is_lhs(node, this.parent())) return abort = true;
|
if (is_lhs(node, this.parent())) return abort = true;
|
||||||
var index = resolve_index(def);
|
var index = resolve_index(def);
|
||||||
if (!(begin < index)) begin = index;
|
if (!(begin < index)) begin = index;
|
||||||
@@ -8619,7 +8637,7 @@ merge(Compressor.prototype, {
|
|||||||
function can_inject_vars(defined, used, safe_to_inject) {
|
function can_inject_vars(defined, used, safe_to_inject) {
|
||||||
for (var i = 0; i < fn.body.length; i++) {
|
for (var i = 0; i < fn.body.length; i++) {
|
||||||
var stat = fn.body[i];
|
var stat = fn.body[i];
|
||||||
if (is_defun(stat)) {
|
if (stat instanceof AST_LambdaDefinition) {
|
||||||
if (!safe_to_inject || var_exists(used, stat.name.name)) return false;
|
if (!safe_to_inject || var_exists(used, stat.name.name)) return false;
|
||||||
if (!all(stat.enclosed, function(def) {
|
if (!all(stat.enclosed, function(def) {
|
||||||
return def.scope === stat || !defined[def.name];
|
return def.scope === stat || !defined[def.name];
|
||||||
@@ -8640,7 +8658,7 @@ merge(Compressor.prototype, {
|
|||||||
function can_inject_symbols() {
|
function can_inject_symbols() {
|
||||||
var defined = Object.create(null);
|
var defined = Object.create(null);
|
||||||
var level = 0, child;
|
var level = 0, child;
|
||||||
scope = compressor.self();
|
scope = current;
|
||||||
do {
|
do {
|
||||||
if (scope.variables) scope.variables.each(function(def) {
|
if (scope.variables) scope.variables.each(function(def) {
|
||||||
defined[def.name] = true;
|
defined[def.name] = true;
|
||||||
@@ -8806,7 +8824,7 @@ merge(Compressor.prototype, {
|
|||||||
flatten_vars(decls, expressions);
|
flatten_vars(decls, expressions);
|
||||||
expressions.push(value);
|
expressions.push(value);
|
||||||
var args = fn.body.filter(function(stat) {
|
var args = fn.body.filter(function(stat) {
|
||||||
if (is_defun(stat)) {
|
if (stat instanceof AST_LambdaDefinition) {
|
||||||
var def = stat.name.definition();
|
var def = stat.name.definition();
|
||||||
scope.functions.set(def.name, def);
|
scope.functions.set(def.name, def);
|
||||||
scope.variables.set(def.name, def);
|
scope.variables.set(def.name, def);
|
||||||
@@ -9040,6 +9058,20 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
OPT(AST_Yield, function(self, compressor) {
|
||||||
|
if (!compressor.option("yields")) return self;
|
||||||
|
if (compressor.option("sequences")) {
|
||||||
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
|
}
|
||||||
|
var exp = self.expression;
|
||||||
|
if (self.nested && exp.TYPE == "Call") {
|
||||||
|
var inlined = exp.clone().optimize(compressor);
|
||||||
|
if (inlined.TYPE != "Call") return inlined;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
});
|
||||||
|
|
||||||
AST_Binary.DEFMETHOD("lift_sequences", function(compressor) {
|
AST_Binary.DEFMETHOD("lift_sequences", function(compressor) {
|
||||||
if (this.left instanceof AST_PropAccess) {
|
if (this.left instanceof AST_PropAccess) {
|
||||||
if (!(this.left.expression instanceof AST_Sequence)) return this;
|
if (!(this.left.expression instanceof AST_Sequence)) return this;
|
||||||
@@ -9802,7 +9834,9 @@ merge(Compressor.prototype, {
|
|||||||
if (single_use == "f") {
|
if (single_use == "f") {
|
||||||
var scope = self.scope;
|
var scope = self.scope;
|
||||||
do {
|
do {
|
||||||
if (is_defun(scope) || is_function(scope)) scope.inlined = true;
|
if (scope instanceof AST_LambdaDefinition || scope instanceof AST_LambdaExpression) {
|
||||||
|
scope.inlined = true;
|
||||||
|
}
|
||||||
} while (scope = scope.parent_scope);
|
} while (scope = scope.parent_scope);
|
||||||
}
|
}
|
||||||
} else if (fixed.name && fixed.name.name == "await" && is_async(fixed)) {
|
} else if (fixed.name && fixed.name.name == "await" && is_async(fixed)) {
|
||||||
@@ -9817,11 +9851,23 @@ merge(Compressor.prototype, {
|
|||||||
def.single_use = false;
|
def.single_use = false;
|
||||||
fixed._squeezed = true;
|
fixed._squeezed = true;
|
||||||
fixed.single_use = true;
|
fixed.single_use = true;
|
||||||
if (fixed instanceof AST_AsyncDefun) {
|
if (fixed instanceof AST_LambdaDefinition) {
|
||||||
fixed = make_node(AST_AsyncFunction, fixed, fixed);
|
var ctor;
|
||||||
fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
|
switch (fixed.CTOR) {
|
||||||
} else if (fixed instanceof AST_Defun) {
|
case AST_AsyncDefun:
|
||||||
fixed = make_node(AST_Function, fixed, fixed);
|
ctor = AST_AsyncFunction;
|
||||||
|
break;
|
||||||
|
case AST_AsyncGeneratorDefun:
|
||||||
|
ctor = AST_AsyncGeneratorFunction;
|
||||||
|
break;
|
||||||
|
case AST_Defun:
|
||||||
|
ctor = AST_Function;
|
||||||
|
break;
|
||||||
|
case AST_GeneratorDefun:
|
||||||
|
ctor = AST_GeneratorFunction;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fixed = make_node(ctor, fixed, fixed);
|
||||||
fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
|
fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
|
||||||
}
|
}
|
||||||
if (fixed instanceof AST_Lambda) {
|
if (fixed instanceof AST_Lambda) {
|
||||||
|
|||||||
@@ -673,7 +673,9 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
PARENS(AST_AsyncFunction, needs_parens_function);
|
PARENS(AST_AsyncFunction, needs_parens_function);
|
||||||
|
PARENS(AST_AsyncGeneratorFunction, needs_parens_function);
|
||||||
PARENS(AST_Function, needs_parens_function);
|
PARENS(AST_Function, needs_parens_function);
|
||||||
|
PARENS(AST_GeneratorFunction, needs_parens_function);
|
||||||
|
|
||||||
// same goes for an object literal, because otherwise it would be
|
// same goes for an object literal, because otherwise it would be
|
||||||
// interpreted as a block of code.
|
// interpreted as a block of code.
|
||||||
@@ -682,14 +684,19 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
PARENS(AST_Object, needs_parens_obj);
|
PARENS(AST_Object, needs_parens_obj);
|
||||||
|
|
||||||
PARENS(AST_Unary, function(output) {
|
function needs_parens_unary(output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
// (-x) ** y
|
// (-x) ** y
|
||||||
if (p instanceof AST_Binary) return p.operator == "**" && p.left === this;
|
if (p instanceof AST_Binary) return p.operator == "**" && p.left === this;
|
||||||
// (x++).toString(3)
|
// (await x)(y)
|
||||||
// (typeof x).length
|
// new (await x)
|
||||||
return (p instanceof AST_Call || p instanceof AST_PropAccess) && p.expression === this;
|
if (p instanceof AST_Call) return p.expression === this;
|
||||||
});
|
// (x++)[y]
|
||||||
|
// (typeof x).y
|
||||||
|
if (p instanceof AST_PropAccess) return p.expression === this;
|
||||||
|
}
|
||||||
|
PARENS(AST_Await, needs_parens_unary);
|
||||||
|
PARENS(AST_Unary, needs_parens_unary);
|
||||||
|
|
||||||
PARENS(AST_Sequence, function(output) {
|
PARENS(AST_Sequence, function(output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
@@ -719,7 +726,9 @@ function OutputStream(options) {
|
|||||||
// !(foo, bar, baz)
|
// !(foo, bar, baz)
|
||||||
|| p instanceof AST_Unary
|
|| p instanceof AST_Unary
|
||||||
// var a = (1, 2), b = a + a; ---> b == 4
|
// var a = (1, 2), b = a + a; ---> b == 4
|
||||||
|| p instanceof AST_VarDef;
|
|| p instanceof AST_VarDef
|
||||||
|
// yield (foo, bar)
|
||||||
|
|| p instanceof AST_Yield;
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Binary, function(output) {
|
PARENS(AST_Binary, function(output) {
|
||||||
@@ -826,17 +835,8 @@ function OutputStream(options) {
|
|||||||
PARENS(AST_Conditional, function(output) {
|
PARENS(AST_Conditional, function(output) {
|
||||||
return needs_parens_assign_cond(this, output);
|
return needs_parens_assign_cond(this, output);
|
||||||
});
|
});
|
||||||
|
PARENS(AST_Yield, function(output) {
|
||||||
PARENS(AST_Await, function(output) {
|
return needs_parens_assign_cond(this, output);
|
||||||
var p = output.parent();
|
|
||||||
// (await x) ** y
|
|
||||||
if (p instanceof AST_Binary) return p.operator == "**" && p.left === this;
|
|
||||||
// new (await foo)
|
|
||||||
// (await foo)(bar)
|
|
||||||
if (p instanceof AST_Call) return p.expression === this;
|
|
||||||
// (await foo).prop
|
|
||||||
// (await foo)["prop"]
|
|
||||||
if (p instanceof AST_PropAccess) return p.expression === this;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ PRINTERS ]----- */
|
/* -----[ PRINTERS ]----- */
|
||||||
@@ -1061,6 +1061,20 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
DEFPRINT(AST_AsyncDefun, print_async);
|
DEFPRINT(AST_AsyncDefun, print_async);
|
||||||
DEFPRINT(AST_AsyncFunction, print_async);
|
DEFPRINT(AST_AsyncFunction, print_async);
|
||||||
|
function print_async_generator(output) {
|
||||||
|
output.print("async");
|
||||||
|
output.space();
|
||||||
|
output.print("function*");
|
||||||
|
print_lambda(this, output);
|
||||||
|
}
|
||||||
|
DEFPRINT(AST_AsyncGeneratorDefun, print_async_generator);
|
||||||
|
DEFPRINT(AST_AsyncGeneratorFunction, print_async_generator);
|
||||||
|
function print_generator(output) {
|
||||||
|
output.print("function*");
|
||||||
|
print_lambda(this, output);
|
||||||
|
}
|
||||||
|
DEFPRINT(AST_GeneratorDefun, print_generator);
|
||||||
|
DEFPRINT(AST_GeneratorFunction, print_generator);
|
||||||
|
|
||||||
/* -----[ jumps ]----- */
|
/* -----[ jumps ]----- */
|
||||||
function print_jump(kind, prop) {
|
function print_jump(kind, prop) {
|
||||||
@@ -1360,6 +1374,13 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
this.expression.print(output);
|
this.expression.print(output);
|
||||||
});
|
});
|
||||||
|
DEFPRINT(AST_Yield, function(output) {
|
||||||
|
output.print(this.nested ? "yield*" : "yield");
|
||||||
|
if (this.expression) {
|
||||||
|
output.space();
|
||||||
|
this.expression.print(output);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/* -----[ literals ]----- */
|
/* -----[ literals ]----- */
|
||||||
DEFPRINT(AST_Array, function(output) {
|
DEFPRINT(AST_Array, function(output) {
|
||||||
|
|||||||
120
lib/parse.js
120
lib/parse.js
@@ -112,13 +112,18 @@ var OPERATORS = makePredicate([
|
|||||||
|
|
||||||
var NEWLINE_CHARS = "\n\r\u2028\u2029";
|
var NEWLINE_CHARS = "\n\r\u2028\u2029";
|
||||||
var OPERATOR_CHARS = "+-*&%=<>!?|~^";
|
var OPERATOR_CHARS = "+-*&%=<>!?|~^";
|
||||||
var PUNC_BEFORE_EXPRESSION = "[{(,;:";
|
var PUNC_OPENERS = "[{(";
|
||||||
var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + "`)}]";
|
var PUNC_SEPARATORS = ",;:";
|
||||||
|
var PUNC_CLOSERS = ")}]";
|
||||||
|
var PUNC_AFTER_EXPRESSION = PUNC_SEPARATORS + PUNC_CLOSERS;
|
||||||
|
var PUNC_BEFORE_EXPRESSION = PUNC_OPENERS + PUNC_SEPARATORS;
|
||||||
|
var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + "`" + PUNC_CLOSERS;
|
||||||
var WHITESPACE_CHARS = NEWLINE_CHARS + " \u00a0\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF";
|
var WHITESPACE_CHARS = NEWLINE_CHARS + " \u00a0\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF";
|
||||||
var NON_IDENTIFIER_CHARS = makePredicate(characters("./'\"" + OPERATOR_CHARS + PUNC_CHARS + WHITESPACE_CHARS));
|
var NON_IDENTIFIER_CHARS = makePredicate(characters("./'\"" + OPERATOR_CHARS + PUNC_CHARS + WHITESPACE_CHARS));
|
||||||
|
|
||||||
NEWLINE_CHARS = makePredicate(characters(NEWLINE_CHARS));
|
NEWLINE_CHARS = makePredicate(characters(NEWLINE_CHARS));
|
||||||
OPERATOR_CHARS = makePredicate(characters(OPERATOR_CHARS));
|
OPERATOR_CHARS = makePredicate(characters(OPERATOR_CHARS));
|
||||||
|
PUNC_AFTER_EXPRESSION = makePredicate(characters(PUNC_AFTER_EXPRESSION));
|
||||||
PUNC_BEFORE_EXPRESSION = makePredicate(characters(PUNC_BEFORE_EXPRESSION));
|
PUNC_BEFORE_EXPRESSION = makePredicate(characters(PUNC_BEFORE_EXPRESSION));
|
||||||
PUNC_CHARS = makePredicate(characters(PUNC_CHARS));
|
PUNC_CHARS = makePredicate(characters(PUNC_CHARS));
|
||||||
WHITESPACE_CHARS = makePredicate(characters(WHITESPACE_CHARS));
|
WHITESPACE_CHARS = makePredicate(characters(WHITESPACE_CHARS));
|
||||||
@@ -692,6 +697,7 @@ function parse($TEXT, options) {
|
|||||||
in_directives : true,
|
in_directives : true,
|
||||||
in_funarg : -1,
|
in_funarg : -1,
|
||||||
in_function : 0,
|
in_function : 0,
|
||||||
|
in_generator : false,
|
||||||
in_loop : 0,
|
in_loop : 0,
|
||||||
labels : [],
|
labels : [],
|
||||||
peeked : null,
|
peeked : null,
|
||||||
@@ -829,12 +835,17 @@ function parse($TEXT, options) {
|
|||||||
if (is_token(peek(), "keyword", "function")) {
|
if (is_token(peek(), "keyword", "function")) {
|
||||||
next();
|
next();
|
||||||
next();
|
next();
|
||||||
return function_(AST_AsyncDefun);
|
if (!is("operator", "*")) return function_(AST_AsyncDefun);
|
||||||
|
next();
|
||||||
|
return function_(AST_AsyncGeneratorDefun);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "await":
|
case "await":
|
||||||
if (S.in_async) return simple_statement();
|
if (S.in_async) return simple_statement();
|
||||||
break;
|
break;
|
||||||
|
case "yield":
|
||||||
|
if (S.in_generator) return simple_statement();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return is_token(peek(), "punc", ":")
|
return is_token(peek(), "punc", ":")
|
||||||
? labeled_statement()
|
? labeled_statement()
|
||||||
@@ -905,7 +916,9 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
case "function":
|
case "function":
|
||||||
next();
|
next();
|
||||||
return function_(AST_Defun);
|
if (!is("operator", "*")) return function_(AST_Defun);
|
||||||
|
next();
|
||||||
|
return function_(AST_GeneratorDefun);
|
||||||
|
|
||||||
case "if":
|
case "if":
|
||||||
next();
|
next();
|
||||||
@@ -1181,15 +1194,15 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
var function_ = function(ctor) {
|
var function_ = function(ctor) {
|
||||||
var was_async = S.in_async;
|
var was_async = S.in_async;
|
||||||
|
var was_gen = S.in_generator;
|
||||||
var name;
|
var name;
|
||||||
if (ctor === AST_AsyncDefun) {
|
if (/Defun$/.test(ctor.TYPE)) {
|
||||||
name = as_symbol(AST_SymbolDefun);
|
name = as_symbol(AST_SymbolDefun);
|
||||||
S.in_async = true;
|
S.in_async = /^Async/.test(ctor.TYPE);
|
||||||
} else if (ctor === AST_Defun) {
|
S.in_generator = /Generator/.test(ctor.TYPE);
|
||||||
name = as_symbol(AST_SymbolDefun);
|
|
||||||
S.in_async = false;
|
|
||||||
} else {
|
} else {
|
||||||
S.in_async = ctor === AST_AsyncFunction;
|
S.in_async = /^Async/.test(ctor.TYPE);
|
||||||
|
S.in_generator = /Generator/.test(ctor.TYPE);
|
||||||
name = as_symbol(AST_SymbolLambda, true);
|
name = as_symbol(AST_SymbolLambda, true);
|
||||||
}
|
}
|
||||||
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
||||||
@@ -1218,6 +1231,7 @@ function parse($TEXT, options) {
|
|||||||
--S.in_function;
|
--S.in_function;
|
||||||
S.in_loop = loop;
|
S.in_loop = loop;
|
||||||
S.labels = labels;
|
S.labels = labels;
|
||||||
|
S.in_generator = was_gen;
|
||||||
S.in_async = was_async;
|
S.in_async = was_async;
|
||||||
return new ctor({
|
return new ctor({
|
||||||
name: name,
|
name: name,
|
||||||
@@ -1481,7 +1495,13 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
if (is("keyword", "function")) {
|
if (is("keyword", "function")) {
|
||||||
next();
|
next();
|
||||||
var func = function_(AST_Function);
|
var func;
|
||||||
|
if (is("operator", "*")) {
|
||||||
|
next();
|
||||||
|
func = function_(AST_GeneratorFunction);
|
||||||
|
} else {
|
||||||
|
func = function_(AST_Function);
|
||||||
|
}
|
||||||
func.start = start;
|
func.start = start;
|
||||||
func.end = prev();
|
func.end = prev();
|
||||||
return subscripts(func, allow_calls);
|
return subscripts(func, allow_calls);
|
||||||
@@ -1492,7 +1512,13 @@ function parse($TEXT, options) {
|
|||||||
if (sym.name == "async") {
|
if (sym.name == "async") {
|
||||||
if (is("keyword", "function")) {
|
if (is("keyword", "function")) {
|
||||||
next();
|
next();
|
||||||
var func = function_(AST_AsyncFunction);
|
var func;
|
||||||
|
if (is("operator", "*")) {
|
||||||
|
next();
|
||||||
|
func = function_(AST_AsyncGeneratorFunction);
|
||||||
|
} else {
|
||||||
|
func = function_(AST_AsyncFunction);
|
||||||
|
}
|
||||||
func.start = start;
|
func.start = start;
|
||||||
func.end = prev();
|
func.end = prev();
|
||||||
return subscripts(func, allow_calls);
|
return subscripts(func, allow_calls);
|
||||||
@@ -1567,6 +1593,21 @@ function parse($TEXT, options) {
|
|||||||
// allow trailing comma
|
// allow trailing comma
|
||||||
if (!options.strict && is("punc", "}")) break;
|
if (!options.strict && is("punc", "}")) break;
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
|
if (is("operator", "*")) {
|
||||||
|
next();
|
||||||
|
var key = as_property_key();
|
||||||
|
var gen_start = S.token;
|
||||||
|
var gen = function_(AST_GeneratorFunction);
|
||||||
|
gen.start = gen_start;
|
||||||
|
gen.end = prev();
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start: start,
|
||||||
|
key: key,
|
||||||
|
value: gen,
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (is("operator", "...")) {
|
if (is("operator", "...")) {
|
||||||
next();
|
next();
|
||||||
a.push(new AST_Spread({
|
a.push(new AST_Spread({
|
||||||
@@ -1628,9 +1669,10 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
if (start.type == "name") switch (key) {
|
if (start.type == "name") switch (key) {
|
||||||
case "async":
|
case "async":
|
||||||
|
var is_gen = is("operator", "*") && next();
|
||||||
key = as_property_key();
|
key = as_property_key();
|
||||||
var func_start = S.token;
|
var func_start = S.token;
|
||||||
var func = function_(AST_AsyncFunction);
|
var func = function_(is_gen ? AST_AsyncGeneratorFunction : AST_AsyncFunction);
|
||||||
func.start = func_start;
|
func.start = func_start;
|
||||||
func.end = prev();
|
func.end = prev();
|
||||||
a.push(new AST_ObjectKeyVal({
|
a.push(new AST_ObjectKeyVal({
|
||||||
@@ -1694,6 +1736,7 @@ function parse($TEXT, options) {
|
|||||||
function _make_symbol(type, token) {
|
function _make_symbol(type, token) {
|
||||||
var name = token.value;
|
var name = token.value;
|
||||||
if (name === "await" && S.in_async) unexpected(token);
|
if (name === "await" && S.in_async) unexpected(token);
|
||||||
|
if (name === "yield" && S.in_generator) unexpected(token);
|
||||||
return new (name === "this" ? AST_This : type)({
|
return new (name === "this" ? AST_This : type)({
|
||||||
name: "" + name,
|
name: "" + name,
|
||||||
start: token,
|
start: token,
|
||||||
@@ -1870,12 +1913,42 @@ function parse($TEXT, options) {
|
|||||||
return expr;
|
return expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
function maybe_unary() {
|
function maybe_unary(no_in) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
|
if (S.in_async && is("name", "await")) {
|
||||||
|
if (S.in_funarg === S.in_function) croak("Invalid use of await in function argument");
|
||||||
|
S.input.context().regex_allowed = true;
|
||||||
|
next();
|
||||||
|
return new AST_Await({
|
||||||
|
start: start,
|
||||||
|
expression: maybe_unary(no_in),
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (S.in_generator && is("name", "yield")) {
|
||||||
|
if (S.in_funarg === S.in_function) croak("Invalid use of yield in function argument");
|
||||||
|
S.input.context().regex_allowed = true;
|
||||||
|
next();
|
||||||
|
var exp = null;
|
||||||
|
var nested = false;
|
||||||
|
if (is("operator", "*")) {
|
||||||
|
next();
|
||||||
|
exp = maybe_assign(no_in);
|
||||||
|
nested = true;
|
||||||
|
} else if (is("punc") ? !PUNC_AFTER_EXPRESSION[S.token.value] : !can_insert_semicolon()) {
|
||||||
|
exp = maybe_assign(no_in);
|
||||||
|
}
|
||||||
|
return new AST_Yield({
|
||||||
|
start: start,
|
||||||
|
expression: exp,
|
||||||
|
nested: nested,
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
}
|
||||||
if (is("operator") && UNARY_PREFIX[start.value]) {
|
if (is("operator") && UNARY_PREFIX[start.value]) {
|
||||||
next();
|
next();
|
||||||
handle_regexp();
|
handle_regexp();
|
||||||
var ex = make_unary(AST_UnaryPrefix, start, maybe_await());
|
var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(no_in));
|
||||||
ex.start = start;
|
ex.start = start;
|
||||||
ex.end = prev();
|
ex.end = prev();
|
||||||
return ex;
|
return ex;
|
||||||
@@ -1906,26 +1979,13 @@ function parse($TEXT, options) {
|
|||||||
return new ctor({ operator: op, expression: expr });
|
return new ctor({ operator: op, expression: expr });
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybe_await() {
|
|
||||||
var start = S.token;
|
|
||||||
if (!(S.in_async && is("name", "await"))) return maybe_unary();
|
|
||||||
if (S.in_funarg === S.in_function) croak("Invalid use of await in function argument");
|
|
||||||
S.input.context().regex_allowed = true;
|
|
||||||
next();
|
|
||||||
return new AST_Await({
|
|
||||||
start: start,
|
|
||||||
expression: maybe_await(),
|
|
||||||
end: prev(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var expr_op = function(left, min_prec, no_in) {
|
var expr_op = function(left, min_prec, no_in) {
|
||||||
var op = is("operator") ? S.token.value : null;
|
var op = is("operator") ? S.token.value : null;
|
||||||
if (op == "in" && no_in) op = null;
|
if (op == "in" && no_in) op = null;
|
||||||
var prec = op != null ? PRECEDENCE[op] : null;
|
var prec = op != null ? PRECEDENCE[op] : null;
|
||||||
if (prec != null && prec > min_prec) {
|
if (prec != null && prec > min_prec) {
|
||||||
next();
|
next();
|
||||||
var right = expr_op(maybe_await(), op == "**" ? prec - 1 : prec, no_in);
|
var right = expr_op(maybe_unary(no_in), op == "**" ? prec - 1 : prec, no_in);
|
||||||
return expr_op(new AST_Binary({
|
return expr_op(new AST_Binary({
|
||||||
start : left.start,
|
start : left.start,
|
||||||
left : left,
|
left : left,
|
||||||
@@ -1938,7 +1998,7 @@ function parse($TEXT, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function expr_ops(no_in) {
|
function expr_ops(no_in) {
|
||||||
return expr_op(maybe_await(), 0, no_in);
|
return expr_op(maybe_unary(no_in), 0, no_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
var maybe_conditional = function(no_in) {
|
var maybe_conditional = function(no_in) {
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
var next_def_id = 0;
|
var next_def_id = 0;
|
||||||
var scope = self.parent_scope = null;
|
var scope = self.parent_scope = null;
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
if (is_defun(node)) {
|
if (node instanceof AST_LambdaDefinition) {
|
||||||
node.name.walk(tw);
|
node.name.walk(tw);
|
||||||
walk_scope(function() {
|
walk_scope(function() {
|
||||||
node.argnames.forEach(function(argname) {
|
node.argnames.forEach(function(argname) {
|
||||||
@@ -439,7 +439,7 @@ AST_BlockScope.DEFMETHOD("find_variable", function(name) {
|
|||||||
|
|
||||||
AST_BlockScope.DEFMETHOD("def_function", function(symbol, init) {
|
AST_BlockScope.DEFMETHOD("def_function", function(symbol, init) {
|
||||||
var def = this.def_variable(symbol, init);
|
var def = this.def_variable(symbol, init);
|
||||||
if (!def.init || is_defun(def.init)) def.init = init;
|
if (!def.init || def.init instanceof AST_LambdaDefinition) def.init = init;
|
||||||
this.functions.set(symbol.name, def);
|
this.functions.set(symbol.name, def);
|
||||||
return def;
|
return def;
|
||||||
});
|
});
|
||||||
@@ -448,7 +448,7 @@ AST_BlockScope.DEFMETHOD("def_variable", function(symbol, init) {
|
|||||||
var def = this.variables.get(symbol.name);
|
var def = this.variables.get(symbol.name);
|
||||||
if (def) {
|
if (def) {
|
||||||
def.orig.push(symbol);
|
def.orig.push(symbol);
|
||||||
if (is_function(def.init)) def.init = init;
|
if (def.init instanceof AST_LambdaExpression) def.init = init;
|
||||||
} else {
|
} else {
|
||||||
def = this.make_def(symbol, init);
|
def = this.make_def(symbol, init);
|
||||||
this.variables.set(symbol.name, def);
|
this.variables.set(symbol.name, def);
|
||||||
|
|||||||
@@ -157,6 +157,9 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
DEF(AST_Await, function(self, tw) {
|
DEF(AST_Await, function(self, tw) {
|
||||||
self.expression = self.expression.transform(tw);
|
self.expression = self.expression.transform(tw);
|
||||||
});
|
});
|
||||||
|
DEF(AST_Yield, function(self, tw) {
|
||||||
|
if (self.expression) self.expression = self.expression.transform(tw);
|
||||||
|
});
|
||||||
DEF(AST_Dot, function(self, tw) {
|
DEF(AST_Dot, function(self, tw) {
|
||||||
self.expression = self.expression.transform(tw);
|
self.expression = self.expression.transform(tw);
|
||||||
});
|
});
|
||||||
|
|||||||
589
test/compress/yields.js
Normal file
589
test/compress/yields.js
Normal file
@@ -0,0 +1,589 @@
|
|||||||
|
binary: {
|
||||||
|
input: {
|
||||||
|
var a = function*() {
|
||||||
|
console.log(6 * (yield "PA" + "SS"));
|
||||||
|
}();
|
||||||
|
console.log(a.next("FAIL").value);
|
||||||
|
console.log(a.next(7).done);
|
||||||
|
}
|
||||||
|
expect_exact: 'var a=function*(){console.log(6*(yield"PA"+"SS"))}();console.log(a.next("FAIL").value);console.log(a.next(7).done);'
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"42",
|
||||||
|
"true",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
empty_yield: {
|
||||||
|
input: {
|
||||||
|
var a = function*() {
|
||||||
|
yield;
|
||||||
|
console.log(yield);
|
||||||
|
yield
|
||||||
|
"FAIL 1";
|
||||||
|
}();
|
||||||
|
console.log(a.next("FAIL 2").value);
|
||||||
|
console.log(a.next("FAIL 3").value);
|
||||||
|
console.log(a.next("PASS").value);
|
||||||
|
console.log(a.next("FAIL 4").done);
|
||||||
|
}
|
||||||
|
expect_exact: 'var a=function*(){yield;console.log(yield);yield;"FAIL 1"}();console.log(a.next("FAIL 2").value);console.log(a.next("FAIL 3").value);console.log(a.next("PASS").value);console.log(a.next("FAIL 4").done);'
|
||||||
|
expect_stdout: [
|
||||||
|
"undefined",
|
||||||
|
"undefined",
|
||||||
|
"PASS",
|
||||||
|
"undefined",
|
||||||
|
"true",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
empty_yield_conditional: {
|
||||||
|
input: {
|
||||||
|
var a = function*() {
|
||||||
|
console.log((yield) ? yield : yield);
|
||||||
|
}();
|
||||||
|
console.log(a.next("FAIL 1").value);
|
||||||
|
console.log(a.next("FAIL 2").value);
|
||||||
|
console.log(a.next("PASS").value);
|
||||||
|
console.log(a.next("FAIL 3").done);
|
||||||
|
}
|
||||||
|
expect_exact: 'var a=function*(){console.log((yield)?yield:yield)}();console.log(a.next("FAIL 1").value);console.log(a.next("FAIL 2").value);console.log(a.next("PASS").value);console.log(a.next("FAIL 3").done);'
|
||||||
|
expect_stdout: [
|
||||||
|
"undefined",
|
||||||
|
"undefined",
|
||||||
|
"PASS",
|
||||||
|
"undefined",
|
||||||
|
"true",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
nested_yield: {
|
||||||
|
input: {
|
||||||
|
console.log(function*() {
|
||||||
|
(yield*
|
||||||
|
f())
|
||||||
|
function* f() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
yield*
|
||||||
|
f();
|
||||||
|
yield *f();
|
||||||
|
}().next().value || "PASS");
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log(function*(){yield*f();function*f(){return"FAIL"}yield*f();yield*f()}().next().value||"PASS");'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
pause_resume: {
|
||||||
|
input: {
|
||||||
|
function* f() {
|
||||||
|
console.log(yield "PASS");
|
||||||
|
}
|
||||||
|
var a = f();
|
||||||
|
console.log(a.next("FAIL").value);
|
||||||
|
console.log(a.next(42).done);
|
||||||
|
}
|
||||||
|
expect_exact: 'function*f(){console.log(yield"PASS")}var a=f();console.log(a.next("FAIL").value);console.log(a.next(42).done);'
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"42",
|
||||||
|
"true",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(function*() {
|
||||||
|
a = "PASS";
|
||||||
|
yield 42;
|
||||||
|
return "PASS";
|
||||||
|
})().next();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(function*() {
|
||||||
|
a = "PASS";
|
||||||
|
yield 42;
|
||||||
|
return "PASS";
|
||||||
|
})().next();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(function*() {
|
||||||
|
yield (a = "PASS");
|
||||||
|
return "PASS";
|
||||||
|
})().next();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(function*() {
|
||||||
|
yield (a = "PASS");
|
||||||
|
return "PASS";
|
||||||
|
})().next();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(function*() {
|
||||||
|
yield (a = "PASS", 42);
|
||||||
|
return "PASS";
|
||||||
|
})().next();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(function*() {
|
||||||
|
yield (a = "PASS", 42);
|
||||||
|
return "PASS";
|
||||||
|
})().next();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_4: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
var b = function*(c) {
|
||||||
|
return c;
|
||||||
|
}(a = "PASS");
|
||||||
|
console.log(a, b.next().done);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
var b = function*(c) {
|
||||||
|
return c;
|
||||||
|
}(a = "PASS");
|
||||||
|
console.log(a, b.next().done);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS true"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_property_lambda: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function* f() {
|
||||||
|
f.g = () => 42;
|
||||||
|
return f.g();
|
||||||
|
}().next().value);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function* f() {
|
||||||
|
return (f.g = () => 42)();
|
||||||
|
}().next().value);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluate: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = function*() {}();
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = function*() {}();
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
functions: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function*() {
|
||||||
|
var a = function* a() {
|
||||||
|
return a && "a";
|
||||||
|
};
|
||||||
|
var b = function* x() {
|
||||||
|
return !!x;
|
||||||
|
};
|
||||||
|
var c = function*(c) {
|
||||||
|
return c;
|
||||||
|
};
|
||||||
|
if (yield* c(yield* b(yield* a()))) {
|
||||||
|
var d = function*() {};
|
||||||
|
var e = function* y() {
|
||||||
|
return typeof y;
|
||||||
|
};
|
||||||
|
var f = function*(f) {
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
console.log(yield* a(yield* d()), yield* b(yield* e()), yield* c(yield* f(42)), typeof d, yield* e(), typeof f);
|
||||||
|
}
|
||||||
|
}().next();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function*() {
|
||||||
|
function* a() {
|
||||||
|
return a && "a";
|
||||||
|
}
|
||||||
|
function* b() {
|
||||||
|
return !!b;
|
||||||
|
}
|
||||||
|
var c = function*(c) {
|
||||||
|
return c;
|
||||||
|
};
|
||||||
|
if (yield* c(yield* b(yield* a()))) {
|
||||||
|
function* d() {}
|
||||||
|
function* e() {
|
||||||
|
return typeof e;
|
||||||
|
}
|
||||||
|
var f = function*(f) {
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
console.log(yield* a(yield* d()), yield* b(yield* e()), yield* c(yield* f(42)), typeof d, yield* e(), typeof f);
|
||||||
|
}
|
||||||
|
}().next();
|
||||||
|
}
|
||||||
|
expect_stdout: "a true 42 function function function"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
functions_use_strict: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
!function*() {
|
||||||
|
var a = function* a() {
|
||||||
|
return a && "a";
|
||||||
|
};
|
||||||
|
var b = function* x() {
|
||||||
|
return !!x;
|
||||||
|
};
|
||||||
|
var c = function*(c) {
|
||||||
|
return c;
|
||||||
|
};
|
||||||
|
if (yield* c(yield* b(yield* a()))) {
|
||||||
|
var d = function*() {};
|
||||||
|
var e = function* y() {
|
||||||
|
return typeof y;
|
||||||
|
};
|
||||||
|
var f = function*(f) {
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
console.log(yield* a(yield* d()), yield* b(yield* e()), yield* c(yield* f(42)), typeof d, yield* e(), typeof f);
|
||||||
|
}
|
||||||
|
}().next();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
!function*() {
|
||||||
|
function* a() {
|
||||||
|
return a && "a";
|
||||||
|
}
|
||||||
|
function* b() {
|
||||||
|
return !!b;
|
||||||
|
}
|
||||||
|
var c = function*(c) {
|
||||||
|
return c;
|
||||||
|
};
|
||||||
|
if (yield* c(yield* b(yield* a()))) {
|
||||||
|
var d = function*() {};
|
||||||
|
var e = function* y() {
|
||||||
|
return typeof y;
|
||||||
|
};
|
||||||
|
var f = function*(f) {
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
console.log(yield* a(yield* d()), yield* b(yield* e()), yield* c(yield* f(42)), typeof d, yield* e(), typeof f);
|
||||||
|
}
|
||||||
|
}().next();
|
||||||
|
}
|
||||||
|
expect_stdout: "a true 42 function function function"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
negate_iife: {
|
||||||
|
options = {
|
||||||
|
negate_iife: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function*(a) {
|
||||||
|
console.log(a);
|
||||||
|
})("PASS").next();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function*(a) {
|
||||||
|
console.log(a);
|
||||||
|
}("PASS").next();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function*(a) {
|
||||||
|
yield a;
|
||||||
|
}(42).next().value);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function*(a) {
|
||||||
|
yield 42;
|
||||||
|
}().next().value);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS";
|
||||||
|
(function*() {
|
||||||
|
a = "FAIL";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS";
|
||||||
|
(function*() {
|
||||||
|
a = "FAIL";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_single_use_defun: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function* f(a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
f("PASS").next();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function*(a) {
|
||||||
|
console.log(a);
|
||||||
|
})("PASS").next();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_tagged: {
|
||||||
|
options = {
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function* f() {
|
||||||
|
function g() {
|
||||||
|
h`foo`;
|
||||||
|
}
|
||||||
|
g();
|
||||||
|
function h(s) {
|
||||||
|
console.log(s[0]);
|
||||||
|
}
|
||||||
|
h([ "bar" ]);
|
||||||
|
}
|
||||||
|
f().next();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function* f() {
|
||||||
|
(function() {
|
||||||
|
h`foo`;
|
||||||
|
})();
|
||||||
|
function h(s) {
|
||||||
|
console.log(s[0]);
|
||||||
|
}
|
||||||
|
h([ "bar" ]);
|
||||||
|
}
|
||||||
|
f().next();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_tagged_async: {
|
||||||
|
options = {
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
async function* f() {
|
||||||
|
function g() {
|
||||||
|
h`foo`;
|
||||||
|
}
|
||||||
|
g();
|
||||||
|
function h(s) {
|
||||||
|
console.log(s[0]);
|
||||||
|
}
|
||||||
|
h([ "bar" ]);
|
||||||
|
}
|
||||||
|
f().next();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
async function* f() {
|
||||||
|
(function() {
|
||||||
|
h`foo`;
|
||||||
|
})();
|
||||||
|
function h(s) {
|
||||||
|
console.log(s[0]);
|
||||||
|
}
|
||||||
|
h([ "bar" ]);
|
||||||
|
}
|
||||||
|
f().next();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
node_version: ">=10"
|
||||||
|
}
|
||||||
|
|
||||||
|
lift_sequence: {
|
||||||
|
options = {
|
||||||
|
sequences: true,
|
||||||
|
yields: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function*() {
|
||||||
|
yield (console, "PASS");
|
||||||
|
}().next().value);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function*() {
|
||||||
|
console, yield "PASS";
|
||||||
|
}().next().value);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_nested_yield: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
sequences: true,
|
||||||
|
yields: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = function*() {
|
||||||
|
yield* function*() {
|
||||||
|
yield "foo";
|
||||||
|
return "FAIL";
|
||||||
|
}();
|
||||||
|
}(), b;
|
||||||
|
do {
|
||||||
|
b = a.next();
|
||||||
|
console.log(b.value);
|
||||||
|
} while (!b.done);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = function*() {
|
||||||
|
yield "foo",
|
||||||
|
"FAIL";
|
||||||
|
}(), b;
|
||||||
|
do {
|
||||||
|
b = a.next(),
|
||||||
|
console.log(b.value);
|
||||||
|
} while (!b.done);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"undefined",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4618: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(typeof function() {
|
||||||
|
var yield = function* f() {
|
||||||
|
console || f();
|
||||||
|
};
|
||||||
|
console.log;
|
||||||
|
return yield;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof function() {
|
||||||
|
var yield = function* f() {
|
||||||
|
console || f();
|
||||||
|
};
|
||||||
|
console.log;
|
||||||
|
return yield;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
82
test/mocha/yields.js
Normal file
82
test/mocha/yields.js
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var UglifyJS = require("../node");
|
||||||
|
|
||||||
|
describe("generator", function() {
|
||||||
|
it("Should reject `yield` as symbol name within generator functions only", function() {
|
||||||
|
[
|
||||||
|
"function yield() {}",
|
||||||
|
"function(yield) {}",
|
||||||
|
"function() { yield:{} }",
|
||||||
|
"function() { var yield; }",
|
||||||
|
"function() { function yield() {} }",
|
||||||
|
"function() { try {} catch (yield) {} }",
|
||||||
|
].forEach(function(code) {
|
||||||
|
var ast = UglifyJS.parse("(" + code + ")();");
|
||||||
|
assert.strictEqual(ast.TYPE, "Toplevel");
|
||||||
|
assert.strictEqual(ast.body.length, 1);
|
||||||
|
assert.strictEqual(ast.body[0].TYPE, "SimpleStatement");
|
||||||
|
assert.strictEqual(ast.body[0].body.TYPE, "Call");
|
||||||
|
assert.strictEqual(ast.body[0].body.expression.TYPE, "Function");
|
||||||
|
assert.throws(function() {
|
||||||
|
UglifyJS.parse("(" + code.replace(/^function/, "function*") + ")();");
|
||||||
|
}, function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error;
|
||||||
|
}, code);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should reject `yield` expression outside of generator functions", function() {
|
||||||
|
[
|
||||||
|
"yield 42;",
|
||||||
|
"function f() { yield 42; }",
|
||||||
|
"function* f() { function g() { yield 42; } }",
|
||||||
|
].forEach(function(code) {
|
||||||
|
assert.throws(function() {
|
||||||
|
UglifyJS.parse(code);
|
||||||
|
}, function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error;
|
||||||
|
}, code);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should reject `yield` expression directly on computed key of function argument", function() {
|
||||||
|
[
|
||||||
|
"function f({ [yield 42]: a }) {}",
|
||||||
|
"function* f({ [yield 42]: a }) {}",
|
||||||
|
].forEach(function(code) {
|
||||||
|
assert.throws(function() {
|
||||||
|
UglifyJS.parse(code);
|
||||||
|
}, function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error;
|
||||||
|
}, code);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should accept `yield` expression nested within computed key of function argument", function() {
|
||||||
|
[
|
||||||
|
"function f({ [function*() { yield 42; }()]: a }) {}",
|
||||||
|
"function* f({ [function*() { yield 42; }()]: a }) {}",
|
||||||
|
].forEach(function(code) {
|
||||||
|
var ast = UglifyJS.parse(code);
|
||||||
|
assert.strictEqual(ast.TYPE, "Toplevel");
|
||||||
|
assert.strictEqual(ast.body.length, 1);
|
||||||
|
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||||
|
assert.strictEqual(ast.body[0].argnames[0].TYPE, "DestructuredObject");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should reject `yield*` without an expression", function() {
|
||||||
|
[
|
||||||
|
"yield*",
|
||||||
|
"yield*;",
|
||||||
|
"yield*,",
|
||||||
|
"(yield*)",
|
||||||
|
"[ yield* ]",
|
||||||
|
"42[yield*]",
|
||||||
|
"yield* && 42",
|
||||||
|
].forEach(function(code) {
|
||||||
|
code = "function* f() { " + code + " }";
|
||||||
|
assert.throws(function() {
|
||||||
|
UglifyJS.parse(code);
|
||||||
|
}, function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error;
|
||||||
|
}, code);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -666,11 +666,7 @@ function is_timed_out(result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function is_statement(node) {
|
function is_statement(node) {
|
||||||
return node instanceof U.AST_Statement
|
return node instanceof U.AST_Statement && !(node instanceof U.AST_LambdaExpression);
|
||||||
&& !(node instanceof U.AST_Arrow
|
|
||||||
|| node instanceof U.AST_AsyncArrow
|
|
||||||
|| node instanceof U.AST_AsyncFunction
|
|
||||||
|| node instanceof U.AST_Function);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function merge_sequence(array, node) {
|
function merge_sequence(array, node) {
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ var SUPPORT = function(matrix) {
|
|||||||
}({
|
}({
|
||||||
arrow: "a => 0;",
|
arrow: "a => 0;",
|
||||||
async: "async function f(){}",
|
async: "async function f(){}",
|
||||||
|
async_generator: "async function* f(){}",
|
||||||
bigint: "42n",
|
bigint: "42n",
|
||||||
catch_omit_var: "try {} catch {}",
|
catch_omit_var: "try {} catch {}",
|
||||||
computed_key: "({[0]: 0});",
|
computed_key: "({[0]: 0});",
|
||||||
@@ -141,6 +142,7 @@ var SUPPORT = function(matrix) {
|
|||||||
default_value: "[ a = 0 ] = [];",
|
default_value: "[ a = 0 ] = [];",
|
||||||
destructuring: "[] = [];",
|
destructuring: "[] = [];",
|
||||||
exponentiation: "0 ** 0",
|
exponentiation: "0 ** 0",
|
||||||
|
generator: "function* f(){}",
|
||||||
let: "let a;",
|
let: "let a;",
|
||||||
rest: "var [...a] = [];",
|
rest: "var [...a] = [];",
|
||||||
rest_object: "var {...a} = {};",
|
rest_object: "var {...a} = {};",
|
||||||
@@ -349,6 +351,7 @@ var avoid_vars = [];
|
|||||||
var block_vars = [];
|
var block_vars = [];
|
||||||
var unique_vars = [];
|
var unique_vars = [];
|
||||||
var async = false;
|
var async = false;
|
||||||
|
var generator = false;
|
||||||
var loops = 0;
|
var loops = 0;
|
||||||
var funcs = 0;
|
var funcs = 0;
|
||||||
var called = Object.create(null);
|
var called = Object.create(null);
|
||||||
@@ -368,6 +371,7 @@ function createTopLevelCode() {
|
|||||||
block_vars.length = 0;
|
block_vars.length = 0;
|
||||||
unique_vars.length = 0;
|
unique_vars.length = 0;
|
||||||
async = false;
|
async = false;
|
||||||
|
generator = false;
|
||||||
loops = 0;
|
loops = 0;
|
||||||
funcs = 0;
|
funcs = 0;
|
||||||
called = Object.create(null);
|
called = Object.create(null);
|
||||||
@@ -395,9 +399,11 @@ function addTrailingComma(list) {
|
|||||||
return SUPPORT.trailing_comma && list && rng(20) == 0 ? list + "," : list;
|
return SUPPORT.trailing_comma && list && rng(20) == 0 ? list + "," : list;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createParams(was_async, noDuplicate) {
|
function createParams(was_async, was_generator, noDuplicate) {
|
||||||
var save_async = async;
|
var save_async = async;
|
||||||
if (was_async) async = true;
|
if (was_async) async = true;
|
||||||
|
var save_generator = generator;
|
||||||
|
if (was_generator) generator = true;
|
||||||
var len = unique_vars.length;
|
var len = unique_vars.length;
|
||||||
var params = [];
|
var params = [];
|
||||||
for (var n = rng(4); --n >= 0;) {
|
for (var n = rng(4); --n >= 0;) {
|
||||||
@@ -406,6 +412,7 @@ function createParams(was_async, noDuplicate) {
|
|||||||
params.push(name);
|
params.push(name);
|
||||||
}
|
}
|
||||||
unique_vars.length = len;
|
unique_vars.length = len;
|
||||||
|
generator = save_generator;
|
||||||
async = save_async;
|
async = save_async;
|
||||||
return addTrailingComma(params.join(", "));
|
return addTrailingComma(params.join(", "));
|
||||||
}
|
}
|
||||||
@@ -434,7 +441,7 @@ function createArgs(recurmax, stmtDepth, canThrow, noTemplate) {
|
|||||||
return "(" + addTrailingComma(args.join(", ")) + ")";
|
return "(" + addTrailingComma(args.join(", ")) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was_async) {
|
function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was_async, was_generator) {
|
||||||
var avoid = [];
|
var avoid = [];
|
||||||
var len = unique_vars.length;
|
var len = unique_vars.length;
|
||||||
var pairs = createPairs(recurmax, !nameLenBefore);
|
var pairs = createPairs(recurmax, !nameLenBefore);
|
||||||
@@ -476,9 +483,18 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
|||||||
async = false;
|
async = false;
|
||||||
if (save_async || was_async) addAvoidVar("await");
|
if (save_async || was_async) addAvoidVar("await");
|
||||||
}
|
}
|
||||||
|
var save_generator = generator;
|
||||||
|
if (was_generator != null) {
|
||||||
|
generator = false;
|
||||||
|
if (save_generator || was_generator) addAvoidVar("yield");
|
||||||
|
}
|
||||||
avoid.forEach(addAvoidVar);
|
avoid.forEach(addAvoidVar);
|
||||||
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
|
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
|
||||||
if (nameFn) nameFn();
|
if (nameFn) nameFn();
|
||||||
|
if (was_generator != null) {
|
||||||
|
generator = was_generator;
|
||||||
|
if (save_generator || was_generator) removeAvoidVar("yield");
|
||||||
|
}
|
||||||
if (was_async != null) {
|
if (was_async != null) {
|
||||||
async = was_async;
|
async = was_async;
|
||||||
if (save_async || was_async) removeAvoidVar("await");
|
if (save_async || was_async) removeAvoidVar("await");
|
||||||
@@ -486,6 +502,7 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
|||||||
if (valueFn) valueFn();
|
if (valueFn) valueFn();
|
||||||
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
|
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
|
||||||
avoid.forEach(removeAvoidVar);
|
avoid.forEach(removeAvoidVar);
|
||||||
|
generator = save_generator;
|
||||||
async = save_async;
|
async = save_async;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,7 +526,10 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
|||||||
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
var save_async = async;
|
var save_async = async;
|
||||||
if (was_async) async = true;
|
if (was_async) async = true;
|
||||||
|
var save_generator = generator;
|
||||||
|
if (was_generator) generator = true;
|
||||||
var name = createVarName(MANDATORY);
|
var name = createVarName(MANDATORY);
|
||||||
|
generator = save_generator;
|
||||||
async = save_async;
|
async = save_async;
|
||||||
unique_vars.length -= 6;
|
unique_vars.length -= 6;
|
||||||
avoid.push(name);
|
avoid.push(name);
|
||||||
@@ -707,7 +727,25 @@ function mayCreateBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function makeFunction(name) {
|
function makeFunction(name) {
|
||||||
return (async ? "async function " : "function ") + name;
|
if (generator) {
|
||||||
|
name = "function* " + name;
|
||||||
|
} else {
|
||||||
|
name = "function " + name;
|
||||||
|
}
|
||||||
|
if (async) name = "async " + name;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function invokeGenerator(was_generator) {
|
||||||
|
if (generator && !was_generator) switch (rng(4)) {
|
||||||
|
case 0:
|
||||||
|
return ".next()";
|
||||||
|
case 1:
|
||||||
|
return ".next().done";
|
||||||
|
case 2:
|
||||||
|
return ".next().value";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||||
@@ -718,6 +756,15 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
var nameLenBefore = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
var save_async = async;
|
var save_async = async;
|
||||||
async = SUPPORT.async && rng(50) == 0;
|
async = SUPPORT.async && rng(50) == 0;
|
||||||
|
var save_generator = generator;
|
||||||
|
generator = SUPPORT.generator && rng(50) == 0;
|
||||||
|
if (async && generator && !SUPPORT.async_generator) {
|
||||||
|
if (rng(2)) {
|
||||||
|
async = false;
|
||||||
|
} else {
|
||||||
|
generator = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
if (allowDefun || rng(5) > 0) {
|
if (allowDefun || rng(5) > 0) {
|
||||||
name = "f" + funcs++;
|
name = "f" + funcs++;
|
||||||
@@ -729,12 +776,12 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
var params;
|
var params;
|
||||||
if (SUPPORT.destructuring && (!allowDefun || !(name in called)) && rng(2)) {
|
if (SUPPORT.destructuring && (!allowDefun || !(name in called)) && rng(2)) {
|
||||||
called[name] = false;
|
called[name] = false;
|
||||||
var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, save_async);
|
var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, save_async, save_generator);
|
||||||
params = pairs.names.join(", ");
|
params = pairs.names.join(", ");
|
||||||
if (!pairs.has_rest) params = addTrailingComma(params);
|
if (!pairs.has_rest) params = addTrailingComma(params);
|
||||||
args = "(" + addTrailingComma(pairs.values.join(", ")) + ")";
|
args = "(" + addTrailingComma(pairs.values.join(", ")) + ")";
|
||||||
} else {
|
} else {
|
||||||
params = createParams(save_async);
|
params = createParams(save_async, save_generator);
|
||||||
}
|
}
|
||||||
s.push(makeFunction(name) + "(" + params + "){", strictMode());
|
s.push(makeFunction(name) + "(" + params + "){", strictMode());
|
||||||
s.push(defns());
|
s.push(defns());
|
||||||
@@ -748,6 +795,8 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
s.push("}", "");
|
s.push("}", "");
|
||||||
s = filterDirective(s).join("\n");
|
s = filterDirective(s).join("\n");
|
||||||
});
|
});
|
||||||
|
var call_next = invokeGenerator(save_generator);
|
||||||
|
generator = save_generator;
|
||||||
async = save_async;
|
async = save_async;
|
||||||
VAR_NAMES.length = nameLenBefore;
|
VAR_NAMES.length = nameLenBefore;
|
||||||
|
|
||||||
@@ -755,9 +804,11 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
// avoid "function statements" (decl inside statements)
|
// avoid "function statements" (decl inside statements)
|
||||||
s = "var " + createVarName(MANDATORY) + " = " + s;
|
s = "var " + createVarName(MANDATORY) + " = " + s;
|
||||||
s += args || createArgs(recurmax, stmtDepth, canThrow);
|
s += args || createArgs(recurmax, stmtDepth, canThrow);
|
||||||
|
s += call_next;
|
||||||
} else if (!(name in called) || args || rng(3)) {
|
} else if (!(name in called) || args || rng(3)) {
|
||||||
s += "var " + createVarName(MANDATORY) + " = " + name;
|
s += "var " + createVarName(MANDATORY) + " = " + name;
|
||||||
s += args || createArgs(recurmax, stmtDepth, canThrow);
|
s += args || createArgs(recurmax, stmtDepth, canThrow);
|
||||||
|
s += call_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return s + ";";
|
return s + ";";
|
||||||
@@ -1019,7 +1070,9 @@ function createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
return "((c = c + 1) + (" + _createExpression(recurmax, noComma, stmtDepth, canThrow) + "))"; // c only gets incremented
|
return "((c = c + 1) + (" + _createExpression(recurmax, noComma, stmtDepth, canThrow) + "))"; // c only gets incremented
|
||||||
default:
|
default:
|
||||||
var expr = "(" + _createExpression(recurmax, noComma, stmtDepth, canThrow) + ")";
|
var expr = "(" + _createExpression(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||||
return async && rng(50) == 0 ? "(await" + expr + ")" : expr;
|
if (async && rng(50) == 0) return "(await" + expr + ")";
|
||||||
|
if (generator && rng(50) == 0) return "(yield" + (canThrow && rng(20) == 0 ? "*" : "") + expr + ")";
|
||||||
|
return expr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,6 +1080,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
var p = 0;
|
var p = 0;
|
||||||
switch (rng(_createExpression.N)) {
|
switch (rng(_createExpression.N)) {
|
||||||
case p++:
|
case p++:
|
||||||
|
if (generator && rng(50) == 0) return "yield";
|
||||||
case p++:
|
case p++:
|
||||||
return createUnaryPrefix() + (rng(2) ? "a" : "b");
|
return createUnaryPrefix() + (rng(2) ? "a" : "b");
|
||||||
case p++:
|
case p++:
|
||||||
@@ -1082,25 +1136,34 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
var nameLenBefore = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
var save_async = async;
|
var save_async = async;
|
||||||
async = SUPPORT.async && rng(50) == 0;
|
async = SUPPORT.async && rng(50) == 0;
|
||||||
|
var save_generator = generator;
|
||||||
|
generator = SUPPORT.generator && rng(50) == 0;
|
||||||
|
if (async && generator && !SUPPORT.async_generator) {
|
||||||
|
if (rng(2)) {
|
||||||
|
async = false;
|
||||||
|
} else {
|
||||||
|
generator = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
unique_vars.push("c");
|
unique_vars.push("c");
|
||||||
var name = createVarName(MAYBE); // note: this name is only accessible from _within_ the function. and immutable at that.
|
var name = createVarName(MAYBE); // note: this name is only accessible from _within_ the function. and immutable at that.
|
||||||
unique_vars.pop();
|
unique_vars.pop();
|
||||||
var s = [];
|
var s = [];
|
||||||
switch (rng(5)) {
|
switch (rng(5)) {
|
||||||
case 0:
|
case 0:
|
||||||
if (SUPPORT.arrow && !name && rng(2)) {
|
if (SUPPORT.arrow && !name && !generator && rng(2)) {
|
||||||
var args, suffix;
|
var args, suffix;
|
||||||
(rng(2) ? createBlockVariables : function() {
|
(rng(2) ? createBlockVariables : function() {
|
||||||
arguments[3]();
|
arguments[3]();
|
||||||
})(recurmax, stmtDepth, canThrow, function(defns) {
|
})(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
var params;
|
var params;
|
||||||
if (SUPPORT.destructuring && rng(2)) {
|
if (SUPPORT.destructuring && rng(2)) {
|
||||||
var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, save_async);
|
var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, save_async, save_generator);
|
||||||
params = pairs.names.join(", ");
|
params = pairs.names.join(", ");
|
||||||
if (!pairs.has_rest) params = addTrailingComma(params);
|
if (!pairs.has_rest) params = addTrailingComma(params);
|
||||||
args = "(" + addTrailingComma(pairs.values.join(", ")) + ")";
|
args = "(" + addTrailingComma(pairs.values.join(", ")) + ")";
|
||||||
} else {
|
} else {
|
||||||
params = createParams(save_async, NO_DUPLICATE);
|
params = createParams(save_async, save_generator, NO_DUPLICATE);
|
||||||
}
|
}
|
||||||
params = (async ? "async (" : "(") + params + ") => ";
|
params = (async ? "async (" : "(") + params + ") => ";
|
||||||
if (defns) {
|
if (defns) {
|
||||||
@@ -1127,6 +1190,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
suffix = ")";
|
suffix = ")";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
generator = save_generator;
|
||||||
async = save_async;
|
async = save_async;
|
||||||
VAR_NAMES.length = nameLenBefore;
|
VAR_NAMES.length = nameLenBefore;
|
||||||
if (!args && rng(2)) args = createArgs(recurmax, stmtDepth, canThrow);
|
if (!args && rng(2)) args = createArgs(recurmax, stmtDepth, canThrow);
|
||||||
@@ -1137,7 +1201,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
"(" + makeFunction(name) + "(){",
|
"(" + makeFunction(name) + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
rng(2) ? "})" : "})()"
|
rng(2) ? "})" : "})()" + invokeGenerator(save_generator)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1146,7 +1210,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
"+" + makeFunction(name) + "(){",
|
"+" + makeFunction(name) + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
"}()"
|
"}()" + invokeGenerator(save_generator)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
@@ -1154,7 +1218,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
"!" + makeFunction(name) + "(){",
|
"!" + makeFunction(name) + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
"}()"
|
"}()" + invokeGenerator(save_generator)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
@@ -1162,15 +1226,16 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
"void " + makeFunction(name) + "(){",
|
"void " + makeFunction(name) + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
"}()"
|
"}()" + invokeGenerator(save_generator)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
async = false;
|
async = false;
|
||||||
|
generator = false;
|
||||||
var instantiate = rng(4) ? "new " : "";
|
var instantiate = rng(4) ? "new " : "";
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
s.push(
|
s.push(
|
||||||
instantiate + "function " + name + "(" + createParams(save_async) + "){",
|
instantiate + "function " + name + "(" + createParams(save_async, save_generator) + "){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
defns()
|
defns()
|
||||||
);
|
);
|
||||||
@@ -1180,11 +1245,13 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
}
|
}
|
||||||
s.push(_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
|
s.push(_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
|
||||||
});
|
});
|
||||||
|
generator = save_generator;
|
||||||
async = save_async;
|
async = save_async;
|
||||||
VAR_NAMES.length = nameLenBefore;
|
VAR_NAMES.length = nameLenBefore;
|
||||||
s.push(rng(2) ? "}" : "}" + createArgs(recurmax, stmtDepth, canThrow, instantiate));
|
s.push(rng(2) ? "}" : "}" + createArgs(recurmax, stmtDepth, canThrow, instantiate));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
generator = save_generator;
|
||||||
async = save_async;
|
async = save_async;
|
||||||
VAR_NAMES.length = nameLenBefore;
|
VAR_NAMES.length = nameLenBefore;
|
||||||
return filterDirective(s).join("\n");
|
return filterDirective(s).join("\n");
|
||||||
@@ -1328,8 +1395,6 @@ function createTemplateLiteral(recurmax, stmtDepth, canThrow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var SAFE_KEYS = [
|
var SAFE_KEYS = [
|
||||||
"length",
|
|
||||||
"foo",
|
|
||||||
"a",
|
"a",
|
||||||
"b",
|
"b",
|
||||||
"c",
|
"c",
|
||||||
@@ -1337,7 +1402,13 @@ var SAFE_KEYS = [
|
|||||||
"null",
|
"null",
|
||||||
"NaN",
|
"NaN",
|
||||||
"Infinity",
|
"Infinity",
|
||||||
|
"done",
|
||||||
|
"foo",
|
||||||
"in",
|
"in",
|
||||||
|
"length",
|
||||||
|
"next",
|
||||||
|
"then",
|
||||||
|
"value",
|
||||||
"var",
|
"var",
|
||||||
];
|
];
|
||||||
var KEYS = [
|
var KEYS = [
|
||||||
@@ -1367,12 +1438,14 @@ function createObjectKey(recurmax, stmtDepth, canThrow) {
|
|||||||
function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
||||||
var nameLenBefore = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
var save_async = async;
|
var save_async = async;
|
||||||
|
var save_generator = generator;
|
||||||
var s;
|
var s;
|
||||||
var name = createObjectKey(recurmax, stmtDepth, canThrow);
|
var name = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
var fn;
|
var fn;
|
||||||
switch (rng(SUPPORT.computed_key ? 3 : 2)) {
|
switch (rng(SUPPORT.computed_key ? 3 : 2)) {
|
||||||
case 0:
|
case 0:
|
||||||
async = false;
|
async = false;
|
||||||
|
generator = false;
|
||||||
fn = function(defns) {
|
fn = function(defns) {
|
||||||
s = [
|
s = [
|
||||||
"get " + name + "(){",
|
"get " + name + "(){",
|
||||||
@@ -1390,6 +1463,7 @@ function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
|||||||
prop = getDotKey();
|
prop = getDotKey();
|
||||||
} while (name == prop);
|
} while (name == prop);
|
||||||
async = false;
|
async = false;
|
||||||
|
generator = false;
|
||||||
fn = function(defns) {
|
fn = function(defns) {
|
||||||
s = [
|
s = [
|
||||||
"set " + name + "(" + createVarName(MANDATORY) + "){",
|
"set " + name + "(" + createVarName(MANDATORY) + "){",
|
||||||
@@ -1403,9 +1477,19 @@ function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
async = SUPPORT.async && rng(50) == 0;
|
async = SUPPORT.async && rng(50) == 0;
|
||||||
|
generator = SUPPORT.generator && rng(50) == 0;
|
||||||
|
if (async && generator && !SUPPORT.async_generator) {
|
||||||
|
if (rng(2)) {
|
||||||
|
async = false;
|
||||||
|
} else {
|
||||||
|
generator = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
fn = function(defns) {
|
fn = function(defns) {
|
||||||
|
if (generator) name = "*" + name;
|
||||||
|
if (async) name = "async "+ name;
|
||||||
s = [
|
s = [
|
||||||
(async ? "async " : "") + name + "(" + createParams(save_async, NO_DUPLICATE) + "){",
|
name + "(" + createParams(save_async, save_generator, NO_DUPLICATE) + "){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
defns(),
|
defns(),
|
||||||
_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
@@ -1415,6 +1499,7 @@ function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, fn);
|
createBlockVariables(recurmax, stmtDepth, canThrow, fn);
|
||||||
|
generator = save_generator;
|
||||||
async = save_async;
|
async = save_async;
|
||||||
VAR_NAMES.length = nameLenBefore;
|
VAR_NAMES.length = nameLenBefore;
|
||||||
return filterDirective(s).join("\n");
|
return filterDirective(s).join("\n");
|
||||||
@@ -1563,8 +1648,11 @@ function createTypeofExpr(recurmax, stmtDepth, canThrow) {
|
|||||||
|
|
||||||
function createVar() {
|
function createVar() {
|
||||||
var save_async = async;
|
var save_async = async;
|
||||||
|
var save_generator = generator;
|
||||||
if (!async && avoid_vars.indexOf("await") >= 0) async = true;
|
if (!async && avoid_vars.indexOf("await") >= 0) async = true;
|
||||||
|
if (!generator && avoid_vars.indexOf("yield") >= 0) generator = true;
|
||||||
var name = createVarName(MANDATORY, DONT_STORE);
|
var name = createVarName(MANDATORY, DONT_STORE);
|
||||||
|
generator = save_generator;
|
||||||
async = save_async;
|
async = save_async;
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -1613,7 +1701,11 @@ function getVarName(noConst) {
|
|||||||
do {
|
do {
|
||||||
if (--tries < 0) return "a";
|
if (--tries < 0) return "a";
|
||||||
name = VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)];
|
name = VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)];
|
||||||
} while (!name || avoid_vars.indexOf(name) >= 0 || noConst && block_vars.indexOf(name) >= 0 || async && name == "await");
|
} while (!name
|
||||||
|
|| avoid_vars.indexOf(name) >= 0
|
||||||
|
|| noConst && block_vars.indexOf(name) >= 0
|
||||||
|
|| async && name == "await"
|
||||||
|
|| generator && name == "yield");
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1625,7 +1717,10 @@ function createVarName(maybe, dontStore) {
|
|||||||
name = VAR_NAMES[rng(VAR_NAMES.length)];
|
name = VAR_NAMES[rng(VAR_NAMES.length)];
|
||||||
if (--tries < 0) suffix++;
|
if (--tries < 0) suffix++;
|
||||||
if (suffix) name += "_" + suffix;
|
if (suffix) name += "_" + suffix;
|
||||||
} while (unique_vars.indexOf(name) >= 0 || block_vars.indexOf(name) >= 0 || async && name == "await");
|
} while (unique_vars.indexOf(name) >= 0
|
||||||
|
|| block_vars.indexOf(name) >= 0
|
||||||
|
|| async && name == "await"
|
||||||
|
|| generator && name == "yield");
|
||||||
if (!dontStore) VAR_NAMES.push(name);
|
if (!dontStore) VAR_NAMES.push(name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user