Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e390e7e124 | ||
|
|
6fd5b5b371 | ||
|
|
fba27bfb71 | ||
|
|
41310e6404 | ||
|
|
91fc1c82b5 | ||
|
|
810cd40356 | ||
|
|
1cbd07e789 | ||
|
|
b82de04775 | ||
|
|
4bbeb09f7c | ||
|
|
c2f6fd5fde | ||
|
|
af4ea3ff69 | ||
|
|
e7643248a3 | ||
|
|
68091dbf69 | ||
|
|
cbf7269296 | ||
|
|
d8563caba7 | ||
|
|
2e0ad40fe6 | ||
|
|
5d12abc41b | ||
|
|
79e5c3f564 | ||
|
|
607f87c5cd | ||
|
|
b2775746a7 | ||
|
|
e478da24c7 | ||
|
|
c5df8355ba | ||
|
|
ff38d2471f | ||
|
|
8e86d05c32 | ||
|
|
9e40abeded | ||
|
|
23ca7d675f | ||
|
|
fd8c0212b8 | ||
|
|
256950c2c0 | ||
|
|
8ecaa40c6e | ||
|
|
96bf7fceab | ||
|
|
6c7226c10e | ||
|
|
dc575919e2 | ||
|
|
4298201938 | ||
|
|
4f833937fe | ||
|
|
3d71e97dd1 | ||
|
|
7f35d9cee0 | ||
|
|
9f8106e1d8 | ||
|
|
b7b8435721 | ||
|
|
c0c04c33bb | ||
|
|
0e234a25c5 | ||
|
|
3096f6fdad | ||
|
|
176c09c6a5 | ||
|
|
9272f662c0 | ||
|
|
4d33cb2f94 | ||
|
|
00d0eda85b | ||
|
|
1cdf810f0b | ||
|
|
b512726cf3 | ||
|
|
9b7a13c8c7 | ||
|
|
74ff6ce261 | ||
|
|
b1b8898e7c | ||
|
|
55451e7b78 |
@@ -784,6 +784,9 @@ to be `false` and all symbol names will be omitted.
|
|||||||
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple
|
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple
|
||||||
direct variable assignments do not count as references unless set to `"keep_assign"`)
|
direct variable assignments do not count as references unless set to `"keep_assign"`)
|
||||||
|
|
||||||
|
- `varify` (default: `true`) -- convert block-scoped declaractions into `var`
|
||||||
|
whenever safe to do so
|
||||||
|
|
||||||
## 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
|
||||||
|
|||||||
@@ -276,7 +276,9 @@ function convert_ast(fn) {
|
|||||||
function run() {
|
function run() {
|
||||||
var content = options.sourceMap && options.sourceMap.content;
|
var content = options.sourceMap && options.sourceMap.content;
|
||||||
if (content && content != "inline") {
|
if (content && content != "inline") {
|
||||||
UglifyJS.AST_Node.info("Using input source map: " + content);
|
UglifyJS.AST_Node.info("Using input source map: {content}", {
|
||||||
|
content : content,
|
||||||
|
});
|
||||||
options.sourceMap.content = read_file(content, content);
|
options.sourceMap.content = read_file(content, content);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
170
lib/ast.js
170
lib/ast.js
@@ -137,17 +137,17 @@ var AST_Node = DEFNODE("Node", "start end", {
|
|||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
(AST_Node.log_function = function(fn, verbose) {
|
(AST_Node.log_function = function(fn, verbose) {
|
||||||
var printed = Object.create(null);
|
if (!fn) {
|
||||||
if (fn) {
|
|
||||||
AST_Node.info = verbose ? function(text, props) {
|
|
||||||
log("INFO: " + string_template(text, props));
|
|
||||||
} : noop;
|
|
||||||
AST_Node.warn = function(text, props) {
|
|
||||||
log("WARN: " + string_template(text, props));
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
AST_Node.info = AST_Node.warn = noop;
|
AST_Node.info = AST_Node.warn = noop;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
var printed = Object.create(null);
|
||||||
|
AST_Node.info = verbose ? function(text, props) {
|
||||||
|
log("INFO: " + string_template(text, props));
|
||||||
|
} : noop;
|
||||||
|
AST_Node.warn = function(text, props) {
|
||||||
|
log("WARN: " + string_template(text, props));
|
||||||
|
};
|
||||||
|
|
||||||
function log(msg) {
|
function log(msg) {
|
||||||
if (printed[msg]) return;
|
if (printed[msg]) return;
|
||||||
@@ -203,6 +203,10 @@ var AST_Directive = DEFNODE("Directive", "value quote", {
|
|||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
|
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
|
||||||
|
$documentation: "The empty statement (empty block or simply a semicolon)"
|
||||||
|
}, AST_Statement);
|
||||||
|
|
||||||
function must_be_expression(node, prop) {
|
function must_be_expression(node, prop) {
|
||||||
if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
|
if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
|
||||||
if (node[prop] instanceof AST_Statement && !(node[prop] instanceof AST_Function)) {
|
if (node[prop] instanceof AST_Statement && !(node[prop] instanceof AST_Function)) {
|
||||||
@@ -226,6 +230,34 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
|||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
|
var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", {
|
||||||
|
$documentation: "Base class for all statements introducing a lexical scope",
|
||||||
|
$propdoc: {
|
||||||
|
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
||||||
|
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||||
|
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
||||||
|
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||||
|
},
|
||||||
|
clone: function(deep) {
|
||||||
|
var node = this._clone(deep);
|
||||||
|
if (this.enclosed) node.enclosed = this.enclosed.slice();
|
||||||
|
if (this.functions) node.functions = this.functions.clone();
|
||||||
|
if (this.variables) node.variables = this.variables.clone();
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
pinned: function() {
|
||||||
|
return this.resolve().pinned();
|
||||||
|
},
|
||||||
|
resolve: function() {
|
||||||
|
return this.parent_scope.resolve();
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.parent_scope == null) return;
|
||||||
|
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");
|
||||||
|
},
|
||||||
|
}, AST_Statement);
|
||||||
|
|
||||||
function walk_body(node, visitor) {
|
function walk_body(node, visitor) {
|
||||||
node.body.forEach(function(node) {
|
node.body.forEach(function(node) {
|
||||||
node.walk(visitor);
|
node.walk(visitor);
|
||||||
@@ -249,44 +281,11 @@ var AST_Block = DEFNODE("Block", "body", {
|
|||||||
if (node instanceof AST_Function) throw new Error("body cannot contain AST_Function");
|
if (node instanceof AST_Function) throw new Error("body cannot contain AST_Function");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_BlockScope);
|
||||||
|
|
||||||
var AST_BlockScope = DEFNODE("BlockScope", "cname enclosed functions make_def parent_scope variables", {
|
|
||||||
$documentation: "Base class for all statements introducing a lexical scope",
|
|
||||||
$propdoc: {
|
|
||||||
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
|
|
||||||
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
|
||||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
|
||||||
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
|
||||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
|
||||||
},
|
|
||||||
clone: function(deep) {
|
|
||||||
var node = this._clone(deep);
|
|
||||||
if (this.enclosed) node.enclosed = this.enclosed.slice();
|
|
||||||
if (this.functions) node.functions = this.functions.clone();
|
|
||||||
if (this.variables) node.variables = this.variables.clone();
|
|
||||||
return node;
|
|
||||||
},
|
|
||||||
pinned: function() {
|
|
||||||
return this.resolve().pinned();
|
|
||||||
},
|
|
||||||
resolve: function() {
|
|
||||||
return this.parent_scope.resolve();
|
|
||||||
},
|
|
||||||
_validate: function() {
|
|
||||||
if (this.parent_scope == null) return;
|
|
||||||
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");
|
|
||||||
},
|
|
||||||
}, AST_Block);
|
|
||||||
|
|
||||||
var AST_BlockStatement = DEFNODE("BlockStatement", null, {
|
var AST_BlockStatement = DEFNODE("BlockStatement", null, {
|
||||||
$documentation: "A block statement",
|
$documentation: "A block statement",
|
||||||
}, AST_BlockScope);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
|
|
||||||
$documentation: "The empty statement (empty block or simply a semicolon)"
|
|
||||||
}, AST_Statement);
|
|
||||||
|
|
||||||
var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
||||||
$documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
|
$documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
|
||||||
@@ -297,7 +296,7 @@ var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
|||||||
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 (this.body instanceof AST_Function) throw new Error("body cannot be AST_Function");
|
if (this.body instanceof AST_Function) throw new Error("body cannot be AST_Function");
|
||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_BlockScope);
|
||||||
|
|
||||||
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
||||||
$documentation: "Statement with a label",
|
$documentation: "Statement with a label",
|
||||||
@@ -451,7 +450,7 @@ 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,
|
||||||
}, AST_BlockScope);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||||
$documentation: "The toplevel scope",
|
$documentation: "The toplevel scope",
|
||||||
@@ -699,7 +698,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
|
|||||||
if (!(this.bfinally instanceof AST_Finally)) throw new Error("bfinally must be AST_Finally");
|
if (!(this.bfinally instanceof AST_Finally)) throw new Error("bfinally must be AST_Finally");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}, AST_BlockScope);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Catch = DEFNODE("Catch", "argname", {
|
var AST_Catch = DEFNODE("Catch", "argname", {
|
||||||
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
||||||
@@ -718,11 +717,11 @@ var AST_Catch = DEFNODE("Catch", "argname", {
|
|||||||
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}, AST_BlockScope);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Finally = DEFNODE("Finally", null, {
|
var AST_Finally = DEFNODE("Finally", null, {
|
||||||
$documentation: "A `finally` node; only makes sense as part of a `try` statement"
|
$documentation: "A `finally` node; only makes sense as part of a `try` statement"
|
||||||
}, AST_BlockScope);
|
}, AST_Block);
|
||||||
|
|
||||||
/* -----[ VAR ]----- */
|
/* -----[ VAR ]----- */
|
||||||
|
|
||||||
@@ -738,14 +737,41 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
|
|||||||
defn.walk(visitor);
|
defn.walk(visitor);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.definitions.length < 1) throw new Error("must have at least one definition");
|
||||||
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
|
var AST_Const = DEFNODE("Const", null, {
|
||||||
|
$documentation: "A `const` statement",
|
||||||
|
_validate: function() {
|
||||||
|
this.definitions.forEach(function(node) {
|
||||||
|
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||||
|
if (!(node.name instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
|
||||||
|
must_be_expression(node, "value");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, AST_Definitions);
|
||||||
|
|
||||||
|
var AST_Let = DEFNODE("Let", null, {
|
||||||
|
$documentation: "A `let` statement",
|
||||||
|
_validate: function() {
|
||||||
|
this.definitions.forEach(function(node) {
|
||||||
|
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||||
|
if (!(node.name instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
|
||||||
|
if (node.value != null) must_be_expression(node, "value");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, AST_Definitions);
|
||||||
|
|
||||||
var AST_Var = DEFNODE("Var", null, {
|
var AST_Var = DEFNODE("Var", null, {
|
||||||
$documentation: "A `var` statement",
|
$documentation: "A `var` statement",
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.definitions.forEach(function(node) {
|
this.definitions.forEach(function(node) {
|
||||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||||
|
if (!(node.name instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
||||||
|
if (node.value != null) must_be_expression(node, "value");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Definitions);
|
}, AST_Definitions);
|
||||||
@@ -763,10 +789,6 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
|
|||||||
if (node.value) node.value.walk(visitor);
|
if (node.value) node.value.walk(visitor);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
|
||||||
if (!(this.name instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
|
||||||
if (this.value != null) must_be_expression(this, "value");
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ OTHER ]----- */
|
/* -----[ OTHER ]----- */
|
||||||
@@ -993,24 +1015,28 @@ var AST_Object = DEFNODE("Object", "properties", {
|
|||||||
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
||||||
$documentation: "Base class for literal object properties",
|
$documentation: "Base class for literal object properties",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
key: "[string|AST_SymbolAccessor] property name. For ObjectKeyVal this is a string. For getters and setters this is an AST_SymbolAccessor.",
|
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
|
||||||
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
|
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor.",
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
visitor.visit(node, function() {
|
visitor.visit(node, function() {
|
||||||
|
if (node.key instanceof AST_Node) node.key.walk(visitor);
|
||||||
node.value.walk(visitor);
|
node.value.walk(visitor);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
|
||||||
$documentation: "A key: value object property",
|
|
||||||
$propdoc: {
|
|
||||||
quote: "[string] the original quote character"
|
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (typeof this.key != "string") throw new Error("key must be string");
|
if (typeof this.key != "string") {
|
||||||
|
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
|
||||||
|
must_be_expression(this, "key");
|
||||||
|
}
|
||||||
|
if (!(this.value instanceof AST_Node)) throw new Error("value must be AST_Node");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
|
||||||
|
$documentation: "A key: value object property",
|
||||||
|
_validate: function() {
|
||||||
must_be_expression(this, "value");
|
must_be_expression(this, "value");
|
||||||
},
|
},
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
@@ -1018,7 +1044,6 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
|||||||
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||||
$documentation: "An object setter property",
|
$documentation: "An object setter property",
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
|
|
||||||
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
||||||
},
|
},
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
@@ -1026,31 +1051,34 @@ var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
|||||||
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
|
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
|
||||||
$documentation: "An object getter property",
|
$documentation: "An object getter property",
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
|
|
||||||
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
||||||
},
|
},
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
|
|
||||||
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
||||||
|
$documentation: "Base class for all symbols",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[string] name of this symbol",
|
name: "[string] name of this symbol",
|
||||||
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
||||||
thedef: "[SymbolDef/S] the definition of this symbol"
|
thedef: "[SymbolDef/S] the definition of this symbol"
|
||||||
},
|
},
|
||||||
$documentation: "Base class for all symbols",
|
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (typeof this.name != "string") throw new Error("name must be string");
|
if (typeof this.name != "string") throw new Error("name must be string");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
|
|
||||||
$documentation: "The name of a property accessor (setter/getter function)"
|
|
||||||
}, AST_Symbol);
|
|
||||||
|
|
||||||
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
|
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
|
||||||
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
|
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|
||||||
|
var AST_SymbolConst = DEFNODE("SymbolConst", null, {
|
||||||
|
$documentation: "Symbol defining a constant",
|
||||||
|
}, AST_SymbolDeclaration);
|
||||||
|
|
||||||
|
var AST_SymbolLet = DEFNODE("SymbolLet", null, {
|
||||||
|
$documentation: "Symbol defining a lexical-scoped variable",
|
||||||
|
}, AST_SymbolDeclaration);
|
||||||
|
|
||||||
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
|
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
|
||||||
$documentation: "Symbol defining a variable",
|
$documentation: "Symbol defining a variable",
|
||||||
}, AST_SymbolDeclaration);
|
}, AST_SymbolDeclaration);
|
||||||
|
|||||||
754
lib/compress.js
754
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,9 @@ function read_source_map(name, toplevel) {
|
|||||||
return to_ascii(match[2]);
|
return to_ascii(match[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AST_Node.warn("inline source map not found: " + name);
|
AST_Node.warn("inline source map not found: {name}", {
|
||||||
|
name: name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function parse_source_map(content) {
|
function parse_source_map(content) {
|
||||||
@@ -258,6 +260,7 @@ function minify(files, options) {
|
|||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
return { error: ex };
|
return { error: ex };
|
||||||
} finally {
|
} finally {
|
||||||
|
AST_Node.log_function();
|
||||||
AST_Node.disable_validation();
|
AST_Node.disable_validation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,9 +115,6 @@
|
|||||||
value : from_moz(M.value)
|
value : from_moz(M.value)
|
||||||
};
|
};
|
||||||
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
||||||
args.key = new AST_SymbolAccessor({
|
|
||||||
name: args.key
|
|
||||||
});
|
|
||||||
args.value = new AST_Accessor(args.value);
|
args.value = new AST_Accessor(args.value);
|
||||||
if (M.kind == "get") return new AST_ObjectGetter(args);
|
if (M.kind == "get") return new AST_ObjectGetter(args);
|
||||||
if (M.kind == "set") return new AST_ObjectSetter(args);
|
if (M.kind == "set") return new AST_ObjectSetter(args);
|
||||||
@@ -385,7 +382,7 @@
|
|||||||
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
||||||
var key = {
|
var key = {
|
||||||
type: "Literal",
|
type: "Literal",
|
||||||
value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
|
value: M.key
|
||||||
};
|
};
|
||||||
var kind;
|
var kind;
|
||||||
if (M instanceof AST_ObjectKeyVal) {
|
if (M instanceof AST_ObjectKeyVal) {
|
||||||
|
|||||||
@@ -107,6 +107,9 @@ function OutputStream(options) {
|
|||||||
var OUTPUT = "";
|
var OUTPUT = "";
|
||||||
|
|
||||||
var to_utf8 = options.ascii_only ? function(str, identifier) {
|
var to_utf8 = options.ascii_only ? function(str, identifier) {
|
||||||
|
if (identifier) str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
|
||||||
|
return "\\u{" + (ch.charCodeAt(0) - 0xd7c0 << 10 | ch.charCodeAt(1) - 0xdc00).toString(16) + "}";
|
||||||
|
});
|
||||||
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
|
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
|
||||||
var code = ch.charCodeAt(0).toString(16);
|
var code = ch.charCodeAt(0).toString(16);
|
||||||
if (code.length <= 2 && !identifier) {
|
if (code.length <= 2 && !identifier) {
|
||||||
@@ -696,6 +699,7 @@ function OutputStream(options) {
|
|||||||
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||||
// ==> 20 (side effect, set a := 10 and b := 20)
|
// ==> 20 (side effect, set a := 10 and b := 20)
|
||||||
|| p instanceof AST_Conditional
|
|| p instanceof AST_Conditional
|
||||||
|
// { [(1, 2)]: 3 }[2] ==> 3
|
||||||
// { foo: (1, 2) }.foo ==> 2
|
// { foo: (1, 2) }.foo ==> 2
|
||||||
|| p instanceof AST_ObjectProperty
|
|| p instanceof AST_ObjectProperty
|
||||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||||
@@ -835,10 +839,6 @@ function OutputStream(options) {
|
|||||||
use_asm = was_asm;
|
use_asm = was_asm;
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
|
|
||||||
force_statement(this.body, output);
|
|
||||||
});
|
|
||||||
|
|
||||||
DEFPRINT(AST_Statement, function(output) {
|
DEFPRINT(AST_Statement, function(output) {
|
||||||
this.body.print(output);
|
this.body.print(output);
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
@@ -897,7 +897,7 @@ function OutputStream(options) {
|
|||||||
self.condition.print(output);
|
self.condition.print(output);
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
force_statement(self.body, output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_For, function(output) {
|
DEFPRINT(AST_For, function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -927,7 +927,7 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
force_statement(self.body, output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_ForIn, function(output) {
|
DEFPRINT(AST_ForIn, function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -941,7 +941,7 @@ function OutputStream(options) {
|
|||||||
self.object.print(output);
|
self.object.print(output);
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
force_statement(self.body, output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_With, function(output) {
|
DEFPRINT(AST_With, function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -951,7 +951,7 @@ function OutputStream(options) {
|
|||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
force_statement(self.body, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ functions ]----- */
|
/* -----[ functions ]----- */
|
||||||
@@ -994,7 +994,7 @@ function OutputStream(options) {
|
|||||||
/* -----[ if ]----- */
|
/* -----[ if ]----- */
|
||||||
function make_then(self, output) {
|
function make_then(self, output) {
|
||||||
var b = self.body;
|
var b = self.body;
|
||||||
if (output.option("braces")
|
if (output.option("braces") && !(b instanceof AST_Const || b instanceof AST_Let)
|
||||||
|| output.option("ie8") && b instanceof AST_Do)
|
|| output.option("ie8") && b instanceof AST_Do)
|
||||||
return make_block(b, output);
|
return make_block(b, output);
|
||||||
// The squeezer replaces "block"-s that contain only a single
|
// The squeezer replaces "block"-s that contain only a single
|
||||||
@@ -1036,7 +1036,7 @@ function OutputStream(options) {
|
|||||||
else
|
else
|
||||||
force_statement(self.alternative, output);
|
force_statement(self.alternative, output);
|
||||||
} else {
|
} else {
|
||||||
self._do_print_body(output);
|
force_statement(self.body, output);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1114,17 +1114,22 @@ function OutputStream(options) {
|
|||||||
print_braced(this, output);
|
print_braced(this, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFPRINT(AST_Var, function(output) {
|
function print_definitinos(type) {
|
||||||
var self = this;
|
return function(output) {
|
||||||
output.print("var");
|
var self = this;
|
||||||
output.space();
|
output.print(type);
|
||||||
self.definitions.forEach(function(def, i) {
|
output.space();
|
||||||
if (i) output.comma();
|
self.definitions.forEach(function(def, i) {
|
||||||
def.print(output);
|
if (i) output.comma();
|
||||||
});
|
def.print(output);
|
||||||
var p = output.parent();
|
});
|
||||||
if (p && p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon();
|
var p = output.parent();
|
||||||
});
|
if (p && p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
DEFPRINT(AST_Const, print_definitinos("const"));
|
||||||
|
DEFPRINT(AST_Let, print_definitinos("let"));
|
||||||
|
DEFPRINT(AST_Var, print_definitinos("var"));
|
||||||
|
|
||||||
function parenthesize_for_noin(node, output, noin) {
|
function parenthesize_for_noin(node, output, noin) {
|
||||||
var parens = false;
|
var parens = false;
|
||||||
@@ -1285,25 +1290,33 @@ function OutputStream(options) {
|
|||||||
else print_braced_empty(this, output);
|
else print_braced_empty(this, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
function print_property_name(key, quote, output) {
|
function print_property_key(self, output) {
|
||||||
if (output.option("quote_keys")) {
|
var key = self.key;
|
||||||
|
if (key instanceof AST_Node) {
|
||||||
|
output.with_square(function() {
|
||||||
|
key.print(output);
|
||||||
|
});
|
||||||
|
} else if (output.option("quote_keys")) {
|
||||||
output.print_string(key);
|
output.print_string(key);
|
||||||
} else if ("" + +key == key && key >= 0) {
|
} else if ("" + +key == key && key >= 0) {
|
||||||
output.print(make_num(key));
|
output.print(make_num(key));
|
||||||
} else if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
|
|
||||||
if (quote && output.option("keep_quoted_props")) {
|
|
||||||
output.print_string(key, quote);
|
|
||||||
} else {
|
|
||||||
output.print_name(key);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
output.print_string(key, quote);
|
var quote = self.start && self.start.quote;
|
||||||
|
if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
|
||||||
|
if (quote && output.option("keep_quoted_props")) {
|
||||||
|
output.print_string(key, quote);
|
||||||
|
} else {
|
||||||
|
output.print_name(key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output.print_string(key, quote);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFPRINT(AST_ObjectKeyVal, function(output) {
|
DEFPRINT(AST_ObjectKeyVal, function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
print_property_name(self.key, self.quote, output);
|
print_property_key(self, output);
|
||||||
output.colon();
|
output.colon();
|
||||||
self.value.print(output);
|
self.value.print(output);
|
||||||
});
|
});
|
||||||
@@ -1312,7 +1325,7 @@ function OutputStream(options) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
output.print(type);
|
output.print(type);
|
||||||
output.space();
|
output.space();
|
||||||
print_property_name(self.key.name, self.quote, output);
|
print_property_key(self, output);
|
||||||
self.value._codegen(output, true);
|
self.value._codegen(output, true);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1381,13 +1394,12 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function force_statement(stat, output) {
|
function force_statement(stat, output) {
|
||||||
if (output.option("braces")) {
|
if (output.option("braces") && !(stat instanceof AST_Const || stat instanceof AST_Let)) {
|
||||||
make_block(stat, output);
|
make_block(stat, output);
|
||||||
|
} else if (!stat || stat instanceof AST_EmptyStatement) {
|
||||||
|
output.force_semicolon();
|
||||||
} else {
|
} else {
|
||||||
if (!stat || stat instanceof AST_EmptyStatement)
|
stat.print(output);
|
||||||
output.force_semicolon();
|
|
||||||
else
|
|
||||||
stat.print(output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1485,14 +1497,7 @@ function OutputStream(options) {
|
|||||||
output.add_mapping(this.start);
|
output.add_mapping(this.start);
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFMAP([
|
|
||||||
AST_ObjectGetter,
|
|
||||||
AST_ObjectSetter,
|
|
||||||
], function(output) {
|
|
||||||
output.add_mapping(this.start, this.key.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
DEFMAP([ AST_ObjectProperty ], function(output) {
|
DEFMAP([ AST_ObjectProperty ], function(output) {
|
||||||
output.add_mapping(this.start, this.key);
|
if (typeof this.key == "string") output.add_mapping(this.start, this.key);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
275
lib/parse.js
275
lib/parse.js
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with";
|
var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof let new return switch throw try typeof var void while with";
|
||||||
var KEYWORDS_ATOM = "false null true";
|
var KEYWORDS_ATOM = "false null true";
|
||||||
var RESERVED_WORDS = [
|
var RESERVED_WORDS = [
|
||||||
"abstract boolean byte char class double enum export extends final float goto implements import int interface let long native package private protected public short static super synchronized this throws transient volatile yield",
|
"abstract boolean byte char class double enum export extends final float goto implements import int interface let long native package private protected public short static super synchronized this throws transient volatile yield",
|
||||||
@@ -58,8 +58,6 @@ RESERVED_WORDS = makePredicate(RESERVED_WORDS);
|
|||||||
KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
|
KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
|
||||||
KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
|
KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
|
||||||
|
|
||||||
var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
|
|
||||||
|
|
||||||
var RE_BIN_NUMBER = /^0b([01]+)$/i;
|
var RE_BIN_NUMBER = /^0b([01]+)$/i;
|
||||||
var RE_HEX_NUMBER = /^0x([0-9a-f]+)$/i;
|
var RE_HEX_NUMBER = /^0x([0-9a-f]+)$/i;
|
||||||
var RE_OCT_NUMBER = /^0o?([0-7]+)$/i;
|
var RE_OCT_NUMBER = /^0o?([0-7]+)$/i;
|
||||||
@@ -111,31 +109,21 @@ var OPERATORS = makePredicate([
|
|||||||
"||"
|
"||"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\uFEFF"));
|
var NEWLINE_CHARS = "\n\r\u2028\u2029";
|
||||||
|
var OPERATOR_CHARS = "+-*&%=<>!?|~^";
|
||||||
|
var PUNC_BEFORE_EXPRESSION = "[{(,;:";
|
||||||
|
var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + ")}]";
|
||||||
|
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 NEWLINE_CHARS = makePredicate(characters("\n\r\u2028\u2029"));
|
NEWLINE_CHARS = makePredicate(characters(NEWLINE_CHARS));
|
||||||
|
OPERATOR_CHARS = makePredicate(characters(OPERATOR_CHARS));
|
||||||
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,;:"));
|
PUNC_BEFORE_EXPRESSION = makePredicate(characters(PUNC_BEFORE_EXPRESSION));
|
||||||
|
PUNC_CHARS = makePredicate(characters(PUNC_CHARS));
|
||||||
var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
|
WHITESPACE_CHARS = makePredicate(characters(WHITESPACE_CHARS));
|
||||||
|
|
||||||
/* -----[ Tokenizer ]----- */
|
/* -----[ Tokenizer ]----- */
|
||||||
|
|
||||||
// regexps adapted from http://xregexp.com/plugins/#unicode
|
|
||||||
var UNICODE = {
|
|
||||||
letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0-\\u08B2\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA7AD\\uA7B0\\uA7B1\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB5F\\uAB64\\uAB65\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
|
|
||||||
digit: new RegExp("[\\u0030-\\u0039\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0DE6-\\u0DEF\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]"),
|
|
||||||
non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
|
|
||||||
space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
|
|
||||||
connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
|
|
||||||
};
|
|
||||||
|
|
||||||
function is_letter(code) {
|
|
||||||
return (code >= 97 && code <= 122)
|
|
||||||
|| (code >= 65 && code <= 90)
|
|
||||||
|| (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_surrogate_pair_head(code) {
|
function is_surrogate_pair_head(code) {
|
||||||
return code >= 0xd800 && code <= 0xdbff;
|
return code >= 0xd800 && code <= 0xdbff;
|
||||||
}
|
}
|
||||||
@@ -148,32 +136,8 @@ function is_digit(code) {
|
|||||||
return code >= 48 && code <= 57;
|
return code >= 48 && code <= 57;
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_unicode_digit(code) {
|
|
||||||
return UNICODE.digit.test(String.fromCharCode(code));
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_unicode_combining_mark(ch) {
|
|
||||||
return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_unicode_connector_punctuation(ch) {
|
|
||||||
return UNICODE.connector_punctuation.test(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_identifier_start(code) {
|
|
||||||
return code == 36 || code == 95 || is_letter(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_identifier_char(ch) {
|
function is_identifier_char(ch) {
|
||||||
var code = ch.charCodeAt(0);
|
return !NON_IDENTIFIER_CHARS[ch];
|
||||||
return is_identifier_start(code)
|
|
||||||
|| is_digit(code)
|
|
||||||
|| code == 8204 // \u200c: zero-width non-joiner <ZWNJ>
|
|
||||||
|| code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
|
|
||||||
|| is_unicode_combining_mark(ch)
|
|
||||||
|| is_unicode_connector_punctuation(ch)
|
|
||||||
|| is_unicode_digit(code)
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_identifier_string(str) {
|
function is_identifier_string(str) {
|
||||||
@@ -342,7 +306,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
case (after_e = false, 46): // .
|
case (after_e = false, 46): // .
|
||||||
return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
|
return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
|
||||||
}
|
}
|
||||||
return is_digit(code) || is_letter(code) || ch == "_";
|
return is_digit(code) || /[_0-9a-fo]/i.test(ch);
|
||||||
});
|
});
|
||||||
if (prefix) num = prefix + num;
|
if (prefix) num = prefix + num;
|
||||||
if (/^0[0-7_]+$/.test(num)) {
|
if (/^0[0-7_]+$/.test(num)) {
|
||||||
@@ -358,20 +322,30 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
function read_escaped_char(in_string) {
|
function read_escaped_char(in_string) {
|
||||||
var ch = next(true, in_string);
|
var ch = next(true, in_string);
|
||||||
switch (ch.charCodeAt(0)) {
|
switch (ch.charCodeAt(0)) {
|
||||||
case 110 : return "\n";
|
case 110: return "\n";
|
||||||
case 114 : return "\r";
|
case 114: return "\r";
|
||||||
case 116 : return "\t";
|
case 116: return "\t";
|
||||||
case 98 : return "\b";
|
case 98: return "\b";
|
||||||
case 118 : return "\u000b"; // \v
|
case 118: return "\u000b"; // \v
|
||||||
case 102 : return "\f";
|
case 102: return "\f";
|
||||||
case 120 : return String.fromCharCode(hex_bytes(2)); // \x
|
case 120: return String.fromCharCode(hex_bytes(2)); // \x
|
||||||
case 117 : return String.fromCharCode(hex_bytes(4)); // \u
|
case 117: // \u
|
||||||
case 10 : return ""; // newline
|
if (peek() != "{") return String.fromCharCode(hex_bytes(4));
|
||||||
case 13 : // \r
|
next();
|
||||||
if (peek() == "\n") { // DOS newline
|
var num = 0;
|
||||||
next(true, in_string);
|
do {
|
||||||
return "";
|
var digit = parseInt(next(true), 16);
|
||||||
}
|
if (isNaN(digit)) parse_error("Invalid hex-character pattern in string");
|
||||||
|
num = num * 16 + digit;
|
||||||
|
} while (peek() != "}");
|
||||||
|
next();
|
||||||
|
if (num < 0x10000) return String.fromCharCode(num);
|
||||||
|
if (num > 0x10ffff) parse_error("Invalid character code: " + num);
|
||||||
|
return String.fromCharCode((num >> 10) + 0xd7c0) + String.fromCharCode((num & 0x03ff) + 0xdc00);
|
||||||
|
case 13: // \r
|
||||||
|
// DOS newline
|
||||||
|
if (peek() == "\n") next(true, in_string);
|
||||||
|
case 10: return ""; // \n
|
||||||
}
|
}
|
||||||
if (ch >= "0" && ch <= "7")
|
if (ch >= "0" && ch <= "7")
|
||||||
return read_octal_escape_sequence(ch);
|
return read_octal_escape_sequence(ch);
|
||||||
@@ -448,7 +422,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
|
|
||||||
function read_name() {
|
function read_name() {
|
||||||
var backslash = false, name = "", ch, escaped = false, hex;
|
var backslash = false, name = "", ch, escaped = false, hex;
|
||||||
while ((ch = peek()) != null) {
|
while (ch = peek()) {
|
||||||
if (!backslash) {
|
if (!backslash) {
|
||||||
if (ch == "\\") escaped = backslash = true, next();
|
if (ch == "\\") escaped = backslash = true, next();
|
||||||
else if (is_identifier_char(ch)) name += next();
|
else if (is_identifier_char(ch)) name += next();
|
||||||
@@ -587,7 +561,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
if (is_digit(code)) return read_num();
|
if (is_digit(code)) return read_num();
|
||||||
if (PUNC_CHARS[ch]) return token("punc", next());
|
if (PUNC_CHARS[ch]) return token("punc", next());
|
||||||
if (OPERATOR_CHARS[ch]) return read_operator();
|
if (OPERATOR_CHARS[ch]) return read_operator();
|
||||||
if (code == 92 || is_identifier_start(code)) return read_word();
|
if (code == 92 || !NON_IDENTIFIER_CHARS[ch]) return read_word();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
parse_error("Unexpected character '" + ch + "'");
|
parse_error("Unexpected character '" + ch + "'");
|
||||||
@@ -779,7 +753,7 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var statement = embed_tokens(function(strict_defun) {
|
var statement = embed_tokens(function() {
|
||||||
handle_regexp();
|
handle_regexp();
|
||||||
switch (S.token.type) {
|
switch (S.token.type) {
|
||||||
case "string":
|
case "string":
|
||||||
@@ -832,6 +806,12 @@ function parse($TEXT, options) {
|
|||||||
next();
|
next();
|
||||||
return break_cont(AST_Break);
|
return break_cont(AST_Break);
|
||||||
|
|
||||||
|
case "const":
|
||||||
|
next();
|
||||||
|
var node = const_();
|
||||||
|
semicolon();
|
||||||
|
return node;
|
||||||
|
|
||||||
case "continue":
|
case "continue":
|
||||||
next();
|
next();
|
||||||
return break_cont(AST_Continue);
|
return break_cont(AST_Continue);
|
||||||
@@ -864,9 +844,6 @@ function parse($TEXT, options) {
|
|||||||
return for_();
|
return for_();
|
||||||
|
|
||||||
case "function":
|
case "function":
|
||||||
if (!strict_defun && S.input.has_directive("use strict")) {
|
|
||||||
croak("In strict mode code, functions can only be declared at top level or immediately within another function.");
|
|
||||||
}
|
|
||||||
next();
|
next();
|
||||||
return function_(AST_Defun);
|
return function_(AST_Defun);
|
||||||
|
|
||||||
@@ -874,6 +851,12 @@ function parse($TEXT, options) {
|
|||||||
next();
|
next();
|
||||||
return if_();
|
return if_();
|
||||||
|
|
||||||
|
case "let":
|
||||||
|
next();
|
||||||
|
var node = let_();
|
||||||
|
semicolon();
|
||||||
|
return node;
|
||||||
|
|
||||||
case "return":
|
case "return":
|
||||||
if (S.in_function == 0 && !options.bare_returns)
|
if (S.in_function == 0 && !options.bare_returns)
|
||||||
croak("'return' outside of function");
|
croak("'return' outside of function");
|
||||||
@@ -988,7 +971,9 @@ function parse($TEXT, options) {
|
|||||||
expect("(");
|
expect("(");
|
||||||
var init = null;
|
var init = null;
|
||||||
if (!is("punc", ";")) {
|
if (!is("punc", ";")) {
|
||||||
init = is("keyword", "var")
|
init = is("keyword", "const")
|
||||||
|
? (next(), const_(true))
|
||||||
|
: is("keyword", "var")
|
||||||
? (next(), var_(true))
|
? (next(), var_(true))
|
||||||
: expression(true, true);
|
: expression(true, true);
|
||||||
if (is("operator", "in")) {
|
if (is("operator", "in")) {
|
||||||
@@ -1050,7 +1035,7 @@ function parse($TEXT, options) {
|
|||||||
S.input.push_directives_stack();
|
S.input.push_directives_stack();
|
||||||
S.in_loop = 0;
|
S.in_loop = 0;
|
||||||
S.labels = [];
|
S.labels = [];
|
||||||
var body = block_(true);
|
var body = block_();
|
||||||
if (S.input.has_directive("use strict")) {
|
if (S.input.has_directive("use strict")) {
|
||||||
if (name) strict_verify_symbol(name);
|
if (name) strict_verify_symbol(name);
|
||||||
argnames.forEach(strict_verify_symbol);
|
argnames.forEach(strict_verify_symbol);
|
||||||
@@ -1079,12 +1064,12 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function block_(strict_defun) {
|
function block_() {
|
||||||
expect("{");
|
expect("{");
|
||||||
var a = [];
|
var a = [];
|
||||||
while (!is("punc", "}")) {
|
while (!is("punc", "}")) {
|
||||||
if (is("eof")) expect_token("punc", "}");
|
if (is("eof")) expect_token("punc", "}");
|
||||||
a.push(statement(strict_defun));
|
a.push(statement());
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return a;
|
return a;
|
||||||
@@ -1161,13 +1146,22 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function vardefs(no_in) {
|
function vardefs(type, no_in, must_init) {
|
||||||
var a = [];
|
var a = [];
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
var start = S.token;
|
||||||
|
var name = as_symbol(type);
|
||||||
|
var value = null;
|
||||||
|
if (is("operator", "=")) {
|
||||||
|
next();
|
||||||
|
value = expression(false, no_in);
|
||||||
|
} else if (must_init) {
|
||||||
|
croak("Missing initializer in declaration");
|
||||||
|
}
|
||||||
a.push(new AST_VarDef({
|
a.push(new AST_VarDef({
|
||||||
start : S.token,
|
start : start,
|
||||||
name : as_symbol(AST_SymbolVar),
|
name : name,
|
||||||
value : is("operator", "=") ? (next(), expression(false, no_in)) : null,
|
value : value,
|
||||||
end : prev()
|
end : prev()
|
||||||
}));
|
}));
|
||||||
if (!is("punc", ","))
|
if (!is("punc", ","))
|
||||||
@@ -1177,10 +1171,26 @@ function parse($TEXT, options) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var const_ = function(no_in) {
|
||||||
|
return new AST_Const({
|
||||||
|
start : prev(),
|
||||||
|
definitions : vardefs(AST_SymbolConst, no_in, true),
|
||||||
|
end : prev()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var let_ = function(no_in) {
|
||||||
|
return new AST_Let({
|
||||||
|
start : prev(),
|
||||||
|
definitions : vardefs(AST_SymbolLet, no_in),
|
||||||
|
end : prev()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
var var_ = function(no_in) {
|
var var_ = function(no_in) {
|
||||||
return new AST_Var({
|
return new AST_Var({
|
||||||
start : prev(),
|
start : prev(),
|
||||||
definitions : vardefs(no_in),
|
definitions : vardefs(AST_SymbolVar, no_in),
|
||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1209,7 +1219,7 @@ function parse($TEXT, options) {
|
|||||||
var tok = S.token, ret;
|
var tok = S.token, ret;
|
||||||
switch (tok.type) {
|
switch (tok.type) {
|
||||||
case "name":
|
case "name":
|
||||||
ret = _make_symbol(AST_SymbolRef);
|
ret = _make_symbol(AST_SymbolRef, tok);
|
||||||
break;
|
break;
|
||||||
case "num":
|
case "num":
|
||||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
||||||
@@ -1327,51 +1337,62 @@ function parse($TEXT, options) {
|
|||||||
var first = true, a = [];
|
var first = true, a = [];
|
||||||
while (!is("punc", "}")) {
|
while (!is("punc", "}")) {
|
||||||
if (first) first = false; else expect(",");
|
if (first) first = false; else expect(",");
|
||||||
if (!options.strict && is("punc", "}"))
|
// allow trailing comma
|
||||||
// allow trailing comma
|
if (!options.strict && is("punc", "}")) break;
|
||||||
break;
|
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var type = start.type;
|
var key = as_property_key();
|
||||||
var name = as_property_name();
|
if (is("punc", "(")) {
|
||||||
if (type == "name" && !is("punc", ":")) {
|
var func_start = S.token;
|
||||||
var key = new AST_SymbolAccessor({
|
var func = function_(AST_Function);
|
||||||
start: S.token,
|
func.start = func_start;
|
||||||
name: "" + as_property_name(),
|
func.end = prev();
|
||||||
end: prev()
|
a.push(new AST_ObjectKeyVal({
|
||||||
});
|
start: start,
|
||||||
if (name == "get") {
|
key: key,
|
||||||
a.push(new AST_ObjectGetter({
|
value: func,
|
||||||
start : start,
|
end: prev(),
|
||||||
key : key,
|
}));
|
||||||
value : create_accessor(),
|
continue;
|
||||||
end : prev()
|
}
|
||||||
}));
|
if (!is("punc", ":") && start.type == "name") switch (key) {
|
||||||
continue;
|
case "get":
|
||||||
}
|
a.push(new AST_ObjectGetter({
|
||||||
if (name == "set") {
|
start: start,
|
||||||
a.push(new AST_ObjectSetter({
|
key: as_property_key(),
|
||||||
start : start,
|
value: create_accessor(),
|
||||||
key : key,
|
end: prev(),
|
||||||
value : create_accessor(),
|
}));
|
||||||
end : prev()
|
continue;
|
||||||
}));
|
case "set":
|
||||||
continue;
|
a.push(new AST_ObjectSetter({
|
||||||
}
|
start: start,
|
||||||
|
key: as_property_key(),
|
||||||
|
value: create_accessor(),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start: start,
|
||||||
|
key: key,
|
||||||
|
value: _make_symbol(AST_SymbolRef, start),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
expect(":");
|
expect(":");
|
||||||
a.push(new AST_ObjectKeyVal({
|
a.push(new AST_ObjectKeyVal({
|
||||||
start : start,
|
start: start,
|
||||||
quote : start.quote,
|
key: key,
|
||||||
key : "" + name,
|
value: expression(false),
|
||||||
value : expression(false),
|
end: prev(),
|
||||||
end : prev()
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return new AST_Object({ properties: a });
|
return new AST_Object({ properties: a });
|
||||||
});
|
});
|
||||||
|
|
||||||
function as_property_name() {
|
function as_property_key() {
|
||||||
var tmp = S.token;
|
var tmp = S.token;
|
||||||
switch (tmp.type) {
|
switch (tmp.type) {
|
||||||
case "operator":
|
case "operator":
|
||||||
@@ -1382,7 +1403,13 @@ function parse($TEXT, options) {
|
|||||||
case "keyword":
|
case "keyword":
|
||||||
case "atom":
|
case "atom":
|
||||||
next();
|
next();
|
||||||
return tmp.value;
|
return "" + tmp.value;
|
||||||
|
case "punc":
|
||||||
|
if (tmp.value != "[") unexpected();
|
||||||
|
next();
|
||||||
|
var key = expression(false);
|
||||||
|
expect("]");
|
||||||
|
return key;
|
||||||
default:
|
default:
|
||||||
unexpected();
|
unexpected();
|
||||||
}
|
}
|
||||||
@@ -1395,12 +1422,12 @@ function parse($TEXT, options) {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _make_symbol(type) {
|
function _make_symbol(type, token) {
|
||||||
var name = S.token.value;
|
var name = token.value;
|
||||||
return new (name == "this" ? AST_This : type)({
|
return new (name === "this" ? AST_This : type)({
|
||||||
name : String(name),
|
name: "" + name,
|
||||||
start : S.token,
|
start: token,
|
||||||
end : S.token
|
end: token,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1414,7 +1441,7 @@ function parse($TEXT, options) {
|
|||||||
if (!noerror) croak("Name expected");
|
if (!noerror) croak("Name expected");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var sym = _make_symbol(type);
|
var sym = _make_symbol(type, S.token);
|
||||||
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
|
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
|
||||||
strict_verify_symbol(sym);
|
strict_verify_symbol(sym);
|
||||||
}
|
}
|
||||||
@@ -1603,7 +1630,7 @@ function parse($TEXT, options) {
|
|||||||
var body = [];
|
var body = [];
|
||||||
S.input.push_directives_stack();
|
S.input.push_directives_stack();
|
||||||
while (!is("eof"))
|
while (!is("eof"))
|
||||||
body.push(statement(true));
|
body.push(statement());
|
||||||
S.input.pop_directives_stack();
|
S.input.pop_directives_stack();
|
||||||
var end = prev();
|
var end = prev();
|
||||||
var toplevel = options.toplevel;
|
var toplevel = options.toplevel;
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ var builtins = function() {
|
|||||||
|
|
||||||
function reserve_quoted_keys(ast, reserved) {
|
function reserve_quoted_keys(ast, reserved) {
|
||||||
ast.walk(new TreeWalker(function(node) {
|
ast.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectProperty) {
|
||||||
if (node.quote) add(node.key);
|
if (node.start && node.start.quote) add(node.key);
|
||||||
} else if (node instanceof AST_Sub) {
|
} else if (node instanceof AST_Sub) {
|
||||||
addStrings(node.property, add);
|
addStrings(node.property, add);
|
||||||
}
|
}
|
||||||
@@ -165,11 +165,8 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
} else if (node instanceof AST_Dot) {
|
} else if (node instanceof AST_Dot) {
|
||||||
add(node.property);
|
add(node.property);
|
||||||
} else if (node instanceof AST_ObjectKeyVal) {
|
|
||||||
add(node.key);
|
|
||||||
} else if (node instanceof AST_ObjectProperty) {
|
} else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter, since KeyVal is handled above
|
if (typeof node.key == "string") add(node.key);
|
||||||
add(node.key.name);
|
|
||||||
} else if (node instanceof AST_Sub) {
|
} else if (node instanceof AST_Sub) {
|
||||||
addStrings(node.property, add);
|
addStrings(node.property, add);
|
||||||
}
|
}
|
||||||
@@ -198,11 +195,8 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
} else if (node instanceof AST_Dot) {
|
} else if (node instanceof AST_Dot) {
|
||||||
node.property = mangle(node.property);
|
node.property = mangle(node.property);
|
||||||
} else if (node instanceof AST_ObjectKeyVal) {
|
|
||||||
node.key = mangle(node.key);
|
|
||||||
} else if (node instanceof AST_ObjectProperty) {
|
} else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter
|
if (typeof node.key == "string") node.key = mangle(node.key);
|
||||||
node.key.name = mangle(node.key.name);
|
|
||||||
} else if (node instanceof AST_Sub) {
|
} else if (node instanceof AST_Sub) {
|
||||||
if (!options.keep_quoted) mangleStrings(node.property);
|
if (!options.keep_quoted) mangleStrings(node.property);
|
||||||
}
|
}
|
||||||
|
|||||||
73
lib/scope.js
73
lib/scope.js
@@ -68,8 +68,8 @@ SymbolDef.prototype = {
|
|||||||
if (this.global && cache && cache.has(this.name)) {
|
if (this.global && cache && cache.has(this.name)) {
|
||||||
this.mangled_name = cache.get(this.name);
|
this.mangled_name = cache.get(this.name);
|
||||||
} else if (!this.mangled_name && !this.unmangleable(options)) {
|
} else if (!this.mangled_name && !this.unmangleable(options)) {
|
||||||
var def;
|
var def = this.redefined();
|
||||||
if (def = this.redefined()) {
|
if (def) {
|
||||||
this.mangled_name = def.mangled_name || def.name;
|
this.mangled_name = def.mangled_name || def.name;
|
||||||
} else {
|
} else {
|
||||||
this.mangled_name = next_mangled_name(this.scope, options, this);
|
this.mangled_name = next_mangled_name(this.scope, options, this);
|
||||||
@@ -80,7 +80,15 @@ SymbolDef.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
redefined: function() {
|
redefined: function() {
|
||||||
return this.defun && this.defun.variables.get(this.name);
|
var scope = this.defun;
|
||||||
|
if (!scope) return;
|
||||||
|
var name = this.name;
|
||||||
|
var def = scope.variables.get(name)
|
||||||
|
|| scope instanceof AST_Toplevel && scope.globals.get(name)
|
||||||
|
|| this.orig[0] instanceof AST_SymbolConst && find_if(function(def) {
|
||||||
|
return def.name == name;
|
||||||
|
}, scope.enclosed);
|
||||||
|
if (def && def !== this) return def.redefined() || def;
|
||||||
},
|
},
|
||||||
unmangleable: function(options) {
|
unmangleable: function(options) {
|
||||||
return this.global && !options.toplevel
|
return this.global && !options.toplevel
|
||||||
@@ -114,6 +122,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_SwitchBranch) {
|
||||||
|
node.init_vars(scope);
|
||||||
|
descend();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_Try) {
|
if (node instanceof AST_Try) {
|
||||||
walk_scope(function() {
|
walk_scope(function() {
|
||||||
walk_body(node, tw);
|
walk_body(node, tw);
|
||||||
@@ -122,10 +135,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
if (node.bfinally) node.bfinally.walk(tw);
|
if (node.bfinally) node.bfinally.walk(tw);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_BlockScope) {
|
|
||||||
walk_scope(descend);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_With) {
|
if (node instanceof AST_With) {
|
||||||
var s = scope;
|
var s = scope;
|
||||||
do {
|
do {
|
||||||
@@ -133,7 +142,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
if (s.uses_with) break;
|
if (s.uses_with) break;
|
||||||
s.uses_with = true;
|
s.uses_with = true;
|
||||||
} while (s = s.parent_scope);
|
} while (s = s.parent_scope);
|
||||||
return;
|
walk_scope(descend);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_BlockScope) {
|
||||||
|
walk_scope(descend);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Symbol) {
|
if (node instanceof AST_Symbol) {
|
||||||
node.scope = scope;
|
node.scope = scope;
|
||||||
@@ -144,6 +158,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolCatch) {
|
if (node instanceof AST_SymbolCatch) {
|
||||||
scope.def_variable(node).defun = defun;
|
scope.def_variable(node).defun = defun;
|
||||||
|
} else if (node instanceof AST_SymbolConst) {
|
||||||
|
scope.def_variable(node).defun = defun;
|
||||||
} else if (node instanceof AST_SymbolDefun) {
|
} else if (node instanceof AST_SymbolDefun) {
|
||||||
defun.def_function(node, tw.parent());
|
defun.def_function(node, tw.parent());
|
||||||
entangle(defun, scope);
|
entangle(defun, scope);
|
||||||
@@ -153,6 +169,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
} else if (node instanceof AST_SymbolLambda) {
|
} else if (node instanceof AST_SymbolLambda) {
|
||||||
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
||||||
if (options.ie8) def.defun = defun.parent_scope.resolve();
|
if (options.ie8) def.defun = defun.parent_scope.resolve();
|
||||||
|
} else if (node instanceof AST_SymbolLet) {
|
||||||
|
scope.def_variable(node);
|
||||||
} else if (node instanceof AST_SymbolVar) {
|
} else if (node instanceof AST_SymbolVar) {
|
||||||
defun.def_variable(node, null);
|
defun.def_variable(node, null);
|
||||||
entangle(defun, scope);
|
entangle(defun, scope);
|
||||||
@@ -216,7 +234,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
node.reference(options);
|
node.reference(options);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// ensure mangling works if catch reuses a scope variable
|
// ensure mangling works if `catch` reuses a scope variable
|
||||||
if (node instanceof AST_SymbolCatch) {
|
if (node instanceof AST_SymbolCatch) {
|
||||||
var def = node.definition().redefined();
|
var def = node.definition().redefined();
|
||||||
if (def) for (var s = node.scope; s; s = s.parent_scope) {
|
if (def) for (var s = node.scope; s; s = s.parent_scope) {
|
||||||
@@ -225,6 +243,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// ensure compression works if `const` reuses a scope variable
|
||||||
|
if (node instanceof AST_SymbolConst) {
|
||||||
|
var redef = node.definition().redefined();
|
||||||
|
if (redef) redef.const_redefs = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
|
||||||
@@ -253,10 +277,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
function redefine(node, scope) {
|
function redefine(node, scope) {
|
||||||
var name = node.name;
|
var name = node.name;
|
||||||
var old_def = node.thedef;
|
var old_def = node.thedef;
|
||||||
|
if (!all(old_def.orig, function(sym) {
|
||||||
|
return !(sym instanceof AST_SymbolConst || sym instanceof AST_SymbolLet);
|
||||||
|
})) return;
|
||||||
var new_def = scope.find_variable(name);
|
var new_def = scope.find_variable(name);
|
||||||
if (new_def) {
|
if (new_def) {
|
||||||
var redef;
|
var redef = new_def.redefined();
|
||||||
while (redef = new_def.redefined()) new_def = redef;
|
if (redef) new_def = redef;
|
||||||
} else {
|
} else {
|
||||||
new_def = self.globals.get(name);
|
new_def = self.globals.get(name);
|
||||||
}
|
}
|
||||||
@@ -290,7 +317,6 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function init_block_vars(scope, parent) {
|
function init_block_vars(scope, parent) {
|
||||||
scope.cname = -1; // the current index for mangling functions/variables
|
|
||||||
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes
|
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||||
scope.parent_scope = parent; // the parent scope (null if this is the top level)
|
scope.parent_scope = parent; // the parent scope (null if this is the top level)
|
||||||
scope.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
scope.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||||
@@ -368,8 +394,9 @@ AST_BlockScope.DEFMETHOD("def_variable", function(symbol, init) {
|
|||||||
function names_in_use(scope, options) {
|
function names_in_use(scope, options) {
|
||||||
var names = scope.names_in_use;
|
var names = scope.names_in_use;
|
||||||
if (!names) {
|
if (!names) {
|
||||||
scope.names_in_use = names = Object.create(null);
|
scope.cname = -1;
|
||||||
scope.cname_holes = [];
|
scope.cname_holes = [];
|
||||||
|
scope.names_in_use = names = Object.create(null);
|
||||||
var cache = options.cache && options.cache.props;
|
var cache = options.cache && options.cache.props;
|
||||||
scope.enclosed.forEach(function(def) {
|
scope.enclosed.forEach(function(def) {
|
||||||
if (def.unmangleable(options)) names[def.name] = true;
|
if (def.unmangleable(options)) names[def.name] = true;
|
||||||
@@ -467,7 +494,11 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
lname = save_nesting;
|
lname = save_nesting;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_BlockScope) {
|
||||||
|
var to_mangle = [];
|
||||||
|
node.variables.each(function(def) {
|
||||||
|
if (!defer_redef(def)) to_mangle.push(def);
|
||||||
|
});
|
||||||
descend();
|
descend();
|
||||||
if (options.cache && node instanceof AST_Toplevel) {
|
if (options.cache && node instanceof AST_Toplevel) {
|
||||||
node.globals.each(mangle);
|
node.globals.each(mangle);
|
||||||
@@ -477,9 +508,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
sym.scope = node;
|
sym.scope = node;
|
||||||
sym.reference(options);
|
sym.reference(options);
|
||||||
}
|
}
|
||||||
node.variables.each(function(def) {
|
to_mangle.forEach(mangle);
|
||||||
if (!defer_redef(def)) mangle(def);
|
|
||||||
});
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Label) {
|
if (node instanceof AST_Label) {
|
||||||
@@ -490,13 +519,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
node.mangled_name = name;
|
node.mangled_name = name;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!options.ie8 && node instanceof AST_Catch && node.argname) {
|
|
||||||
var def = node.argname.definition();
|
|
||||||
var redef = defer_redef(def, node.argname);
|
|
||||||
descend();
|
|
||||||
if (!redef) mangle(def);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
this.walk(tw);
|
this.walk(tw);
|
||||||
redefined.forEach(mangle);
|
redefined.forEach(mangle);
|
||||||
@@ -511,7 +533,8 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
if (!redef) return false;
|
if (!redef) return false;
|
||||||
redefined.push(def);
|
redefined.push(def);
|
||||||
def.references.forEach(reference);
|
def.references.forEach(reference);
|
||||||
if (node) reference(node);
|
var node = def.orig[0];
|
||||||
|
if (node instanceof AST_SymbolCatch || node instanceof AST_SymbolConst) reference(node);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
function reference(sym) {
|
function reference(sym) {
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
self.properties = do_list(self.properties, tw);
|
self.properties = do_list(self.properties, tw);
|
||||||
});
|
});
|
||||||
DEF(AST_ObjectProperty, function(self, tw) {
|
DEF(AST_ObjectProperty, function(self, tw) {
|
||||||
|
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
|
||||||
self.value = self.value.transform(tw);
|
self.value = self.value.transform(tw);
|
||||||
});
|
});
|
||||||
})(function(node, descend) {
|
})(function(node, descend) {
|
||||||
|
|||||||
@@ -143,8 +143,9 @@ function push_uniq(array, el) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function string_template(text, props) {
|
function string_template(text, props) {
|
||||||
return text.replace(/\{(.+?)\}/g, function(str, p) {
|
return text.replace(/\{([^}]+)\}/g, function(str, p) {
|
||||||
return props && props[p];
|
var value = props[p];
|
||||||
|
return value instanceof AST_Node ? value.print_to_string() : value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.11.2",
|
"version": "3.11.6",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -315,6 +315,7 @@ function test_case(test) {
|
|||||||
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
|
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
|
||||||
}
|
}
|
||||||
var output_code = make_code(output, output_options);
|
var output_code = make_code(output, output_options);
|
||||||
|
U.AST_Node.log_function();
|
||||||
if (expect != output_code) {
|
if (expect != output_code) {
|
||||||
log([
|
log([
|
||||||
"!!! failed",
|
"!!! failed",
|
||||||
@@ -386,7 +387,7 @@ function test_case(test) {
|
|||||||
mangle: test.mangle
|
mangle: test.mangle
|
||||||
});
|
});
|
||||||
var actual = stdout[toplevel ? 1 : 0];
|
var actual = stdout[toplevel ? 1 : 0];
|
||||||
if (test.expect_stdout === true) {
|
if (test.expect_stdout === true || test.expect_stdout instanceof Error && test.expect_stdout.name === actual.name) {
|
||||||
test.expect_stdout = actual;
|
test.expect_stdout = actual;
|
||||||
}
|
}
|
||||||
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
||||||
|
|||||||
@@ -783,3 +783,27 @@ issue_3420_7: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "true"
|
expect_stdout: "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4200: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
get p() {
|
||||||
|
return arguments[0];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(o.p);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
get p() {
|
||||||
|
return arguments[0];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(o.p);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
ascii_only_true: {
|
|
||||||
options = {}
|
|
||||||
beautify = {
|
|
||||||
ascii_only : true,
|
|
||||||
ie8 : false,
|
|
||||||
beautify : false,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function f() {
|
|
||||||
return "\x000\x001\x007\x008\x00" +
|
|
||||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
|
||||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
|
||||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
|
|
||||||
}
|
|
||||||
|
|
||||||
ascii_only_false: {
|
|
||||||
options = {}
|
|
||||||
beautify = {
|
|
||||||
ascii_only : false,
|
|
||||||
ie8 : false,
|
|
||||||
beautify : false,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function f() {
|
|
||||||
return "\x000\x001\x007\x008\x00" +
|
|
||||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
|
||||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
|
||||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
|
|
||||||
}
|
|
||||||
@@ -76,9 +76,8 @@ asm_mixed: {
|
|||||||
start = start | 0;
|
start = start | 0;
|
||||||
end = end | 0;
|
end = end | 0;
|
||||||
var sum = 0.0, p = 0, q = 0;
|
var sum = 0.0, p = 0, q = 0;
|
||||||
for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0) {
|
for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0)
|
||||||
sum = sum + +log(values[p >> 3]);
|
sum = sum + +log(values[p >> 3]);
|
||||||
}
|
|
||||||
return +sum;
|
return +sum;
|
||||||
}
|
}
|
||||||
function geometricMean(start, end) {
|
function geometricMean(start, end) {
|
||||||
@@ -91,7 +90,8 @@ asm_mixed: {
|
|||||||
function no_asm_GeometricMean(stdlib, foreign, buffer) {
|
function no_asm_GeometricMean(stdlib, foreign, buffer) {
|
||||||
function logSum(start, end) {
|
function logSum(start, end) {
|
||||||
start |= 0, end |= 0;
|
start |= 0, end |= 0;
|
||||||
for (var sum = 0, p = 0, q = 0, p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0) sum += +log(values[p >> 3]);
|
for (var sum = 0, p = 0, q = 0, p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0)
|
||||||
|
sum += +log(values[p >> 3]);
|
||||||
return +sum;
|
return +sum;
|
||||||
}
|
}
|
||||||
function geometricMean(start, end) {
|
function geometricMean(start, end) {
|
||||||
|
|||||||
@@ -346,9 +346,8 @@ collapse_vars_if: {
|
|||||||
return "x" != "Bar" + x / 4 ? g9 : g5;
|
return "x" != "Bar" + x / 4 ? g9 : g5;
|
||||||
}
|
}
|
||||||
function f3(x) {
|
function f3(x) {
|
||||||
if (x) {
|
if (x)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4192,9 +4191,8 @@ issue_2436_11: {
|
|||||||
if (isCollection(arg1)) {
|
if (isCollection(arg1)) {
|
||||||
var size = arg1, max = arg2, min = 0, res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
|
var size = arg1, max = arg2, min = 0, res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
|
||||||
return size && true === size.isMatrix ? matrix(res) : res;
|
return size && true === size.isMatrix ? matrix(res) : res;
|
||||||
} else {
|
} else
|
||||||
return _randomInt(min = arg1, max = arg2);
|
return _randomInt(min = arg1, max = arg2);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4310,9 +4308,8 @@ issue_2497: {
|
|||||||
function sample() {
|
function sample() {
|
||||||
if (true)
|
if (true)
|
||||||
for (var i = 0; i < 1; ++i)
|
for (var i = 0; i < 1; ++i)
|
||||||
for (var k = 0; k < 1; ++k) {
|
for (var k = 0; k < 1; ++k)
|
||||||
value = (value = 1) ? value + 1 : 0;
|
value = (value = 1) ? value + 1 : 0;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
for (i = 0; i < 1; ++i)
|
for (i = 0; i < 1; ++i)
|
||||||
for (k = 0; k < 1; ++k)
|
for (k = 0; k < 1; ++k)
|
||||||
@@ -8559,3 +8556,49 @@ issue_4070: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "NaN"
|
expect_stdout: "NaN"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4242: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
if (console)
|
||||||
|
var a = function(){}, b = (!1 === console || a)();
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
console && (!1 === console || function(){})();
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4248: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
try {
|
||||||
|
a = 1;
|
||||||
|
b[1];
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
try {
|
||||||
|
a = 1;
|
||||||
|
b[1];
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,14 +55,15 @@ ifs_3_should_warn: {
|
|||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x, y;
|
var x, y;
|
||||||
if (x && !(x + "1") && y) { // 1
|
// 1
|
||||||
|
if (x && !(x + "1") && y) {
|
||||||
var qq;
|
var qq;
|
||||||
foo();
|
foo();
|
||||||
} else {
|
} else {
|
||||||
bar();
|
bar();
|
||||||
}
|
}
|
||||||
|
// 2
|
||||||
if (x || !!(x + "1") || y) { // 2
|
if (x || !!(x + "1") || y) {
|
||||||
foo();
|
foo();
|
||||||
} else {
|
} else {
|
||||||
var jj;
|
var jj;
|
||||||
@@ -71,9 +72,25 @@ ifs_3_should_warn: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x, y;
|
var x, y;
|
||||||
var qq; bar(); // 1
|
// 1
|
||||||
var jj; foo(); // 2
|
var qq; bar();
|
||||||
|
// 2
|
||||||
|
foo(); var jj;
|
||||||
}
|
}
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: + in boolean context always true [test/compress/conditionals.js:3,18]",
|
||||||
|
"WARN: Boolean && always false [test/compress/conditionals.js:3,12]",
|
||||||
|
"WARN: Condition left of && always false [test/compress/conditionals.js:3,12]",
|
||||||
|
"WARN: Condition always false [test/compress/conditionals.js:3,12]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/conditionals.js:3,34]",
|
||||||
|
"WARN: + in boolean context always true [test/compress/conditionals.js:10,19]",
|
||||||
|
"WARN: Boolean || always true [test/compress/conditionals.js:10,12]",
|
||||||
|
"WARN: Condition left of || always true [test/compress/conditionals.js:10,12]",
|
||||||
|
"WARN: Condition always true [test/compress/conditionals.js:10,12]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/conditionals.js:12,15]",
|
||||||
|
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:3,12]",
|
||||||
|
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:10,12]",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
ifs_4: {
|
ifs_4: {
|
||||||
|
|||||||
1227
test/compress/const.js
Normal file
1227
test/compress/const.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -59,6 +59,9 @@ dead_code_2_should_warn: {
|
|||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: Dropping unreachable code [test/compress/dead-code.js:8,12]",
|
||||||
|
]
|
||||||
node_version: "<=4"
|
node_version: "<=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,11 +92,21 @@ dead_code_constant_boolean_should_warn_more: {
|
|||||||
function bar() {}
|
function bar() {}
|
||||||
// nothing for the while
|
// nothing for the while
|
||||||
// as for the for, it should keep:
|
// as for the for, it should keep:
|
||||||
var moo;
|
|
||||||
var x = 10, y;
|
var x = 10, y;
|
||||||
|
var moo;
|
||||||
bar();
|
bar();
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: + in boolean context always true [test/compress/dead-code.js:1,33]",
|
||||||
|
"WARN: Boolean || always true [test/compress/dead-code.js:1,16]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/dead-code.js:1,45]",
|
||||||
|
"WARN: Boolean expression always true [test/compress/dead-code.js:6,47]",
|
||||||
|
"WARN: Boolean && always false [test/compress/dead-code.js:6,28]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/dead-code.js:6,63]",
|
||||||
|
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:1,15]",
|
||||||
|
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:6,28]",
|
||||||
|
]
|
||||||
node_version: "<=4"
|
node_version: "<=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3085,3 +3085,30 @@ issue_4184: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "42"
|
expect_stdout: "42"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4235: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
{
|
||||||
|
const f = 0;
|
||||||
|
}
|
||||||
|
(function f() {
|
||||||
|
var f = console.log(f);
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
f = console.log(f),
|
||||||
|
void 0;
|
||||||
|
var f;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|||||||
@@ -3014,3 +3014,63 @@ issue_4119_4: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4214: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
return function() {
|
||||||
|
try {
|
||||||
|
return a;
|
||||||
|
} finally {
|
||||||
|
var b = 0;
|
||||||
|
}
|
||||||
|
}(a++ && this());
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = function(a) {
|
||||||
|
return function() {
|
||||||
|
try {
|
||||||
|
return a;
|
||||||
|
} finally {}
|
||||||
|
}(a++ && this());
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "NaN"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4271: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
p: null,
|
||||||
|
q: (console.log("foo"), 42),
|
||||||
|
p: function() {}
|
||||||
|
})[console.log("bar"), "p"] && console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({
|
||||||
|
p: null,
|
||||||
|
q: (console.log("foo"), 42),
|
||||||
|
p: function() {}
|
||||||
|
})[console.log("bar"), "p"],
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -2081,7 +2081,7 @@ issue_3016_1: {
|
|||||||
var b = 1;
|
var b = 1;
|
||||||
do {
|
do {
|
||||||
3[b];
|
3[b];
|
||||||
} while(0);
|
} while (0);
|
||||||
console.log(b);
|
console.log(b);
|
||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
@@ -2112,7 +2112,7 @@ issue_3016_2: {
|
|||||||
do {
|
do {
|
||||||
a = 3,
|
a = 3,
|
||||||
a[b];
|
a[b];
|
||||||
} while(0);
|
} while (0);
|
||||||
var a;
|
var a;
|
||||||
console.log(b);
|
console.log(b);
|
||||||
}
|
}
|
||||||
@@ -2145,7 +2145,7 @@ issue_3016_2_ie8: {
|
|||||||
do {
|
do {
|
||||||
a = 3,
|
a = 3,
|
||||||
a[b];
|
a[b];
|
||||||
} while(0);
|
} while (0);
|
||||||
var a;
|
var a;
|
||||||
console.log(b);
|
console.log(b);
|
||||||
}
|
}
|
||||||
@@ -2175,7 +2175,7 @@ issue_3016_3: {
|
|||||||
var b = 1;
|
var b = 1;
|
||||||
do {
|
do {
|
||||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||||
} while(b--);
|
} while (b--);
|
||||||
var a;
|
var a;
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
@@ -2208,7 +2208,7 @@ issue_3016_3_ie8: {
|
|||||||
var b = 1;
|
var b = 1;
|
||||||
do {
|
do {
|
||||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||||
} while(b--);
|
} while (b--);
|
||||||
var a;
|
var a;
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
@@ -5076,3 +5076,141 @@ issue_4186: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "function"
|
expect_stdout: "function"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4233: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
try {
|
||||||
|
var a = function() {};
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
(function() {
|
||||||
|
console.log(typeof a);
|
||||||
|
})();
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
try {
|
||||||
|
var a = function() {};
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
(function() {
|
||||||
|
console.log(typeof a);
|
||||||
|
})();
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "number"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4259: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = function b() {
|
||||||
|
var c = b;
|
||||||
|
for (b in c);
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function a() {
|
||||||
|
for (a in a);
|
||||||
|
}
|
||||||
|
a();
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4261: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (e) {
|
||||||
|
(function() {
|
||||||
|
function f() {
|
||||||
|
e.p;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
while (f());
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
while (console.log(g()));
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (e) {
|
||||||
|
(function() {
|
||||||
|
function g() {
|
||||||
|
while (void e.p);
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
while (console.log(g()));
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4265: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
dead_code: true,
|
||||||
|
inline: true,
|
||||||
|
sequences: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
console;
|
||||||
|
if ([ function() {
|
||||||
|
return this + console.log(a);
|
||||||
|
a;
|
||||||
|
var a;
|
||||||
|
}() ]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
return console, function() {
|
||||||
|
return console.log(a);
|
||||||
|
var a;
|
||||||
|
}(), 0;
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|||||||
@@ -2859,3 +2859,48 @@ issue_4186: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "NaN"
|
expect_stdout: "NaN"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4235: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {} catch (e) {}
|
||||||
|
console.log(function e() {
|
||||||
|
var e = 0;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {} catch (e) {}
|
||||||
|
console.log(function e() {}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4250: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
loops: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {
|
||||||
|
(function() {
|
||||||
|
for (f in "f");
|
||||||
|
})();
|
||||||
|
return f;
|
||||||
|
var f;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f() {
|
||||||
|
(function() {
|
||||||
|
for (f in "f");
|
||||||
|
})();
|
||||||
|
return f;
|
||||||
|
var f;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ non_hoisted_function_after_return: {
|
|||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]"
|
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,19 +84,16 @@ non_hoisted_function_after_return_2a: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:4,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:7,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
|
||||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
|
||||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
||||||
"INFO: pass 0: last_count: Infinity, count: 36",
|
"INFO: pass 0: last_count: Infinity, count: 35",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||||
"INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
|
"INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
|
||||||
"INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
|
"INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
|
||||||
"INFO: pass 1: last_count: 36, count: 18",
|
"INFO: pass 1: last_count: 35, count: 18",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,10 +135,7 @@ non_hoisted_function_after_return_2b: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:8,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:6,16]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,12]",
|
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,12]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -242,19 +236,16 @@ non_hoisted_function_after_return_2a_strict: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "5 6"
|
expect_stdout: "5 6"
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:5,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:8,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
|
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
|
|
||||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
|
||||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
||||||
"INFO: pass 0: last_count: Infinity, count: 47",
|
"INFO: pass 0: last_count: Infinity, count: 46",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:10,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||||
"INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
|
"INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
|
||||||
"INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
|
"INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
|
||||||
"INFO: pass 1: last_count: 47, count: 29",
|
"INFO: pass 1: last_count: 46, count: 29",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,10 +292,7 @@ non_hoisted_function_after_return_2b_strict: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "5 6"
|
expect_stdout: "5 6"
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
1008
test/compress/let.js
Normal file
1008
test/compress/let.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -547,8 +547,8 @@ dead_code_condition: {
|
|||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var c;
|
|
||||||
var a = 0, b = 5;
|
var a = 0, b = 5;
|
||||||
|
var c;
|
||||||
a += 1, 0,
|
a += 1, 0,
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
@@ -1197,3 +1197,60 @@ issue_4182_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_continue: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
do {
|
||||||
|
continue;
|
||||||
|
} while ([ A ]);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
do {
|
||||||
|
continue;
|
||||||
|
} while ([ A ]);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4240: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
function f() {
|
||||||
|
var o = { PASS: 42 };
|
||||||
|
for (a in o);
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
if (f());
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
(function() {
|
||||||
|
if (function() {
|
||||||
|
for (a in { PASS: 42 });
|
||||||
|
}());
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -3011,3 +3011,175 @@ issue_4168_use_strict: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS true 42"
|
expect_stdout: "PASS true 42"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4237_1: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
do {
|
||||||
|
var b = a++;
|
||||||
|
if (b)
|
||||||
|
return "FAIL";
|
||||||
|
continue;
|
||||||
|
var c = 42;
|
||||||
|
} while ("undefined" != typeof c);
|
||||||
|
return "PASS";
|
||||||
|
}(0));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
do {
|
||||||
|
var b = a++;
|
||||||
|
if (b)
|
||||||
|
return "FAIL";
|
||||||
|
continue;
|
||||||
|
var c = 42;
|
||||||
|
} while ("undefined" != typeof c);
|
||||||
|
return "PASS";
|
||||||
|
}(0));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4237_2: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
|
loops: true,
|
||||||
|
merge_vars: true,
|
||||||
|
switches: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
do {
|
||||||
|
switch (0) {
|
||||||
|
case 0:
|
||||||
|
var b = a++;
|
||||||
|
default:
|
||||||
|
while (b)
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var c = 0;
|
||||||
|
} finally {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var d = 0;
|
||||||
|
} while ("undefined" != typeof d);
|
||||||
|
return "PASS";
|
||||||
|
}(0));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
do {
|
||||||
|
switch (0) {
|
||||||
|
case 0:
|
||||||
|
var b = a++;
|
||||||
|
if (b)
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var c = 0;
|
||||||
|
} finally {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var d = 0;
|
||||||
|
} while ("undefined" != typeof d);
|
||||||
|
return "PASS";
|
||||||
|
}(0));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4253: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
switch (0) {
|
||||||
|
default:
|
||||||
|
var a = "FAIL";
|
||||||
|
a = a && a;
|
||||||
|
try {
|
||||||
|
break;
|
||||||
|
} catch (e) {}
|
||||||
|
var b = 42;
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
switch (0) {
|
||||||
|
default:
|
||||||
|
var a = "FAIL";
|
||||||
|
a = a && a;
|
||||||
|
try {
|
||||||
|
break;
|
||||||
|
} catch (e) {}
|
||||||
|
var b = 42;
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4255: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
loops: true,
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
L: for (var a = 2; --a;)
|
||||||
|
for (var b = 0; console.log(b); --b)
|
||||||
|
break L;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
L: for (var a = 2; --a;) {
|
||||||
|
var b = 0;
|
||||||
|
if (console.log(b))
|
||||||
|
break L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4257: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
switch (--a) {
|
||||||
|
case 0:
|
||||||
|
var b = 0;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
var c = 1 + (0 | (b && A));
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
switch (--a) {
|
||||||
|
case 0:
|
||||||
|
var b = 0;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
var c = 1 + (0 | (b && A));
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -221,3 +221,142 @@ numeric_literal: {
|
|||||||
"8 7 8",
|
"8 7 8",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evaluate_computed_key: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
["foo" + "bar"]: "PASS",
|
||||||
|
}.foobar);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
foobar: "PASS",
|
||||||
|
}.foobar);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_computed_key: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
[console.log("PASS")]: 42,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4269_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
get 0() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
[0]: "PASS",
|
||||||
|
}[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
get 0() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
[0]: "PASS",
|
||||||
|
}[0]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4269_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
get [0]() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
0: "PASS",
|
||||||
|
}[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
get [0]() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
0: "PASS",
|
||||||
|
}[0]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4269_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
["foo"]: "bar",
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
42: "PASS",
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
["foo"]: "bar",
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
42: "PASS",
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4269_4: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
["foo"]: "bar",
|
||||||
|
42: "PASS",
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
["foo"]: "bar",
|
||||||
|
42: "PASS",
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -848,9 +848,8 @@ collapse_vars_1_true: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f(a, b) {
|
function f(a, b) {
|
||||||
for (;;) {
|
for (;;)
|
||||||
if (a.g() || b.p) break;
|
if (a.g() || b.p) break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1999,7 +1999,7 @@ issue_1606: {
|
|||||||
var a, b;
|
var a, b;
|
||||||
function g(){};
|
function g(){};
|
||||||
b = 2;
|
b = 2;
|
||||||
x(b);
|
x(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,37 @@
|
|||||||
|
ascii_only_false: {
|
||||||
|
options = {}
|
||||||
|
beautify = {
|
||||||
|
ascii_only: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(
|
||||||
|
"\x000\x001\x007\x008\x00",
|
||||||
|
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||||
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
|
||||||
|
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log("\\x000\\x001\\x007\\x008\\0","\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f","\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\');'
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ascii_only_true: {
|
||||||
|
options = {}
|
||||||
|
beautify = {
|
||||||
|
ascii_only: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(
|
||||||
|
"\x000\x001\x007\x008\x00",
|
||||||
|
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||||
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
|
||||||
|
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log("\\x000\\x001\\x007\\x008\\0","\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f","\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f",\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\');'
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
unicode_parse_variables: {
|
unicode_parse_variables: {
|
||||||
options = {}
|
options = {}
|
||||||
input: {
|
input: {
|
||||||
@@ -141,3 +175,35 @@ issue_2569: {
|
|||||||
}
|
}
|
||||||
expect_exact: 'new RegExp("[\\udc42-\\udcaa\\udd74-\\udd96\\ude45-\\ude4f\\udea3-\\udecc]");'
|
expect_exact: 'new RegExp("[\\udc42-\\udcaa\\udd74-\\udd96\\ude45-\\ude4f\\udea3-\\udecc]");'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
surrogate_pair: {
|
||||||
|
beautify = {
|
||||||
|
ascii_only: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var \u{2f800} = {
|
||||||
|
\u{2f801}: "\u{100000}",
|
||||||
|
};
|
||||||
|
\u{2f800}.\u{2f802} = "\u{100001}";
|
||||||
|
console.log(typeof \u{2f800}, \u{2f800}.\u{2f801}, \u{2f800}["\u{2f802}"]);
|
||||||
|
}
|
||||||
|
expect_exact: 'var \ud87e\udc00={"\ud87e\udc01":"\udbc0\udc00"};\ud87e\udc00.\ud87e\udc02="\udbc0\udc01";console.log(typeof \ud87e\udc00,\ud87e\udc00.\ud87e\udc01,\ud87e\udc00["\ud87e\udc02"]);'
|
||||||
|
expect_stdout: "object \udbc0\udc00 \udbc0\udc01"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
surrogate_pair_ascii: {
|
||||||
|
beautify = {
|
||||||
|
ascii_only: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var \u{2f800} = {
|
||||||
|
\u{2f801}: "\u{100000}",
|
||||||
|
};
|
||||||
|
\u{2f800}.\u{2f802} = "\u{100001}";
|
||||||
|
console.log(typeof \u{2f800}, \u{2f800}.\u{2f801}, \u{2f800}["\u{2f802}"]);
|
||||||
|
}
|
||||||
|
expect_exact: 'var \\u{2f800}={"\\ud87e\\udc01":"\\udbc0\\udc00"};\\u{2f800}.\\u{2f802}="\\udbc0\\udc01";console.log(typeof \\u{2f800},\\u{2f800}.\\u{2f801},\\u{2f800}["\\ud87e\\udc02"]);'
|
||||||
|
expect_stdout: "object \udbc0\udc00 \udbc0\udc01"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
236
test/compress/varify.js
Normal file
236
test/compress/varify.js
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
reduce_merge_const: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const a = console;
|
||||||
|
console.log(typeof a);
|
||||||
|
var b = typeof a;
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var b = console;
|
||||||
|
console.log(typeof b);
|
||||||
|
b = typeof b;
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"object",
|
||||||
|
"object",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_merge_let: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let a = console;
|
||||||
|
console.log(typeof a);
|
||||||
|
var b = typeof a;
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
var b = console;
|
||||||
|
console.log(typeof b);
|
||||||
|
b = typeof b;
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"object",
|
||||||
|
"object",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_block_const: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_block_let: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
{
|
||||||
|
let a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
var a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
hoist_props_const: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const o = {
|
||||||
|
p: "PASS",
|
||||||
|
};
|
||||||
|
console.log(o.p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o_p = "PASS";
|
||||||
|
console.log(o_p);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
hoist_props_let: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
{
|
||||||
|
let o = {
|
||||||
|
p: "PASS",
|
||||||
|
};
|
||||||
|
console.log(o.p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
var o_p = "PASS";
|
||||||
|
console.log(o_p);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
scope_adjustment_const: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (var k in [ 42 ])
|
||||||
|
console.log(function f() {
|
||||||
|
if (k) {
|
||||||
|
const a = 0;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var k in [ 42 ])
|
||||||
|
console.log(void (k && 0));
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
scope_adjustment_let: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
for (var k in [ 42 ])
|
||||||
|
console.log(function f() {
|
||||||
|
if (k) {
|
||||||
|
let a = 0;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
for (var k in [ 42 ])
|
||||||
|
console.log(void (k && 0));
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4191_const: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const a = function() {};
|
||||||
|
console.log(typeof a, a());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function a() {};
|
||||||
|
console.log(typeof a, a());
|
||||||
|
}
|
||||||
|
expect_stdout: "function undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4191_let: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let a = function() {};
|
||||||
|
console.log(typeof a, a());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
function a() {};
|
||||||
|
console.log(typeof a, a());
|
||||||
|
}
|
||||||
|
expect_stdout: "function undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
@@ -60,7 +60,7 @@ if (typeof phantom == "undefined") {
|
|||||||
var port = server.address().port;
|
var port = server.address().port;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
console.log("http://localhost:" + port + "/");
|
console.log("http://localhost:" + port + "/");
|
||||||
} else {
|
} else (function install() {
|
||||||
child_process.spawn(process.platform == "win32" ? "npm.cmd" : "npm", [
|
child_process.spawn(process.platform == "win32" ? "npm.cmd" : "npm", [
|
||||||
"install",
|
"install",
|
||||||
"phantomjs-prebuilt@2.1.14",
|
"phantomjs-prebuilt@2.1.14",
|
||||||
@@ -71,7 +71,10 @@ if (typeof phantom == "undefined") {
|
|||||||
], {
|
], {
|
||||||
stdio: [ "ignore", 1, 2 ]
|
stdio: [ "ignore", 1, 2 ]
|
||||||
}).on("exit", function(code) {
|
}).on("exit", function(code) {
|
||||||
if (code) throw new Error("npm install failed!");
|
if (code) {
|
||||||
|
console.log("npm install failed with code", code);
|
||||||
|
return install();
|
||||||
|
}
|
||||||
var program = require("phantomjs-prebuilt").exec(process.argv[1], port);
|
var program = require("phantomjs-prebuilt").exec(process.argv[1], port);
|
||||||
program.stdout.pipe(process.stdout);
|
program.stdout.pipe(process.stdout);
|
||||||
program.stderr.pipe(process.stderr);
|
program.stderr.pipe(process.stderr);
|
||||||
@@ -82,7 +85,7 @@ if (typeof phantom == "undefined") {
|
|||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
})();
|
||||||
});
|
});
|
||||||
server.timeout = 0;
|
server.timeout = 0;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,64 +1,58 @@
|
|||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
|
var run_code = require("../sandbox").run_code;
|
||||||
var UglifyJS = require("../node");
|
var UglifyJS = require("../node");
|
||||||
|
|
||||||
describe("String literals", function() {
|
describe("String literals", function() {
|
||||||
it("Should throw syntax error if a string literal contains a newline", function() {
|
it("Should throw syntax error if a string literal contains a newline", function() {
|
||||||
var inputs = [
|
[
|
||||||
"'\n'",
|
"'\n'",
|
||||||
"'\r'",
|
"'\r'",
|
||||||
'"\r\n"',
|
'"\r\n"',
|
||||||
"'\u2028'",
|
"'\u2028'",
|
||||||
'"\u2029"'
|
'"\u2029"',
|
||||||
];
|
].forEach(function(input) {
|
||||||
|
assert.throws(function() {
|
||||||
var test = function(input) {
|
|
||||||
return function() {
|
|
||||||
var ast = UglifyJS.parse(input);
|
var ast = UglifyJS.parse(input);
|
||||||
};
|
}, function(e) {
|
||||||
};
|
return e instanceof UglifyJS.JS_Parse_Error
|
||||||
|
&& e.message === "Unterminated string constant";
|
||||||
var error = function(e) {
|
});
|
||||||
return e instanceof UglifyJS.JS_Parse_Error
|
});
|
||||||
&& e.message === "Unterminated string constant";
|
});
|
||||||
};
|
it("Should handle line continuation correctly", function() {
|
||||||
|
[
|
||||||
for (var input in inputs) {
|
'"\\\r"',
|
||||||
assert.throws(test(inputs[input]), error);
|
'"\\\n"',
|
||||||
}
|
'"\\\r\n"',
|
||||||
|
].forEach(function(str) {
|
||||||
|
var code = "console.log(" + str + ");";
|
||||||
|
var result = UglifyJS.minify(code);
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(run_code(result.code), run_code(code));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should not throw syntax error if a string has a line continuation", function() {
|
it("Should not throw syntax error if a string has a line continuation", function() {
|
||||||
var output = UglifyJS.parse('var a = "a\\\nb";').print_to_string();
|
var ast = UglifyJS.parse('var a = "a\\\nb";');
|
||||||
assert.equal(output, 'var a="ab";');
|
assert.equal(ast.print_to_string(), 'var a="ab";');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should throw error in strict mode if string contains escaped octalIntegerLiteral", function() {
|
it("Should throw error in strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||||
var inputs = [
|
[
|
||||||
'"use strict";\n"\\76";',
|
'"use strict";\n"\\76";',
|
||||||
'"use strict";\nvar foo = "\\76";',
|
'"use strict";\nvar foo = "\\76";',
|
||||||
'"use strict";\n"\\1";',
|
'"use strict";\n"\\1";',
|
||||||
'"use strict";\n"\\07";',
|
'"use strict";\n"\\07";',
|
||||||
'"use strict";\n"\\011"'
|
'"use strict";\n"\\011"',
|
||||||
];
|
].forEach(function(input) {
|
||||||
|
assert.throws(function() {
|
||||||
var test = function(input) {
|
|
||||||
return function() {
|
|
||||||
var output = UglifyJS.parse(input);
|
var output = UglifyJS.parse(input);
|
||||||
}
|
}, function(e) {
|
||||||
};
|
return e instanceof UglifyJS.JS_Parse_Error
|
||||||
|
&& e.message === "Legacy octal escape sequences are not allowed in strict mode";
|
||||||
var error = function(e) {
|
});
|
||||||
return e instanceof UglifyJS.JS_Parse_Error
|
});
|
||||||
&& e.message === "Legacy octal escape sequences are not allowed in strict mode";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var input in inputs) {
|
|
||||||
assert.throws(test(inputs[input]), error);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
|
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||||
var tests = [
|
[
|
||||||
[ ';"\\76";', ';">";' ],
|
[ ';"\\76";', ';">";' ],
|
||||||
[ ';"\\0";', ';"\\0";' ],
|
[ ';"\\0";', ';"\\0";' ],
|
||||||
[ ';"\\08"', ';"\\x008";' ],
|
[ ';"\\08"', ';"\\x008";' ],
|
||||||
@@ -66,19 +60,15 @@ describe("String literals", function() {
|
|||||||
[ ';"\\0008"', ';"\\x008";' ],
|
[ ';"\\0008"', ';"\\x008";' ],
|
||||||
[ ';"use\\\n strict";\n"\\07";', ';"use strict";"\07";' ],
|
[ ';"use\\\n strict";\n"\\07";', ';"use strict";"\07";' ],
|
||||||
[ '"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";' ],
|
[ '"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";' ],
|
||||||
];
|
].forEach(function(test) {
|
||||||
|
var ast = UglifyJS.parse(test[0]);
|
||||||
for (var test in tests) {
|
assert.equal(ast.print_to_string(), test[1]);
|
||||||
var output = UglifyJS.parse(tests[test][0]).print_to_string();
|
});
|
||||||
assert.equal(output, tests[test][1]);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should not throw error when digit is 8 or 9", function() {
|
it("Should not throw error when digit is 8 or 9", function() {
|
||||||
assert.equal(UglifyJS.parse('"use strict";;"\\08"').print_to_string(), '"use strict";;"\\x008";');
|
assert.equal(UglifyJS.parse('"use strict";;"\\08"').print_to_string(), '"use strict";;"\\x008";');
|
||||||
assert.equal(UglifyJS.parse('"use strict";;"\\09"').print_to_string(), '"use strict";;"\\x009";');
|
assert.equal(UglifyJS.parse('"use strict";;"\\09"').print_to_string(), '"use strict";;"\\x009";');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should not unescape unpaired surrogates", function() {
|
it("Should not unescape unpaired surrogates", function() {
|
||||||
var code = [];
|
var code = [];
|
||||||
for (var i = 0; i <= 0xF; i++) {
|
for (var i = 0; i <= 0xF; i++) {
|
||||||
@@ -115,4 +105,33 @@ describe("String literals", function() {
|
|||||||
assert.ok(code.length > ascii.code.length);
|
assert.ok(code.length > ascii.code.length);
|
||||||
assert.strictEqual(eval(code), eval(ascii.code));
|
assert.strictEqual(eval(code), eval(ascii.code));
|
||||||
});
|
});
|
||||||
|
it("Should reject invalid Unicode escape sequence", function() {
|
||||||
|
[
|
||||||
|
'var foo = "\\u-111"',
|
||||||
|
'var bar = "\\u{-1}"',
|
||||||
|
'var baz = "\\ugggg"',
|
||||||
|
].forEach(function(test) {
|
||||||
|
assert.throws(function() {
|
||||||
|
UglifyJS.parse(test);
|
||||||
|
}, function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error
|
||||||
|
&& e.message === "Invalid hex-character pattern in string";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should reject invalid code points in Unicode escape sequence", function() {
|
||||||
|
[
|
||||||
|
// A bit over the valid range
|
||||||
|
'"\\u{110000}"',
|
||||||
|
// 32-bit overflow resulting in "a"
|
||||||
|
'"\\u{100000061}"',
|
||||||
|
].forEach(function(test) {
|
||||||
|
assert.throws(function() {
|
||||||
|
UglifyJS.parse(test);
|
||||||
|
}, function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error
|
||||||
|
&& /^Invalid character code: /.test(e.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ describe("tokens", function() {
|
|||||||
it("Should give correct positions for accessors", function() {
|
it("Should give correct positions for accessors", function() {
|
||||||
// location 0 1 2 3 4
|
// location 0 1 2 3 4
|
||||||
// 01234567890123456789012345678901234567890123456789
|
// 01234567890123456789012345678901234567890123456789
|
||||||
var ast = UglifyJS.parse("var obj = { get latest() { return undefined; } }");
|
var ast = UglifyJS.parse("var obj = { get [prop]() { return undefined; } }");
|
||||||
// test all AST_ObjectProperty tokens are set as expected
|
// test all AST_ObjectProperty tokens are set as expected
|
||||||
var found = false;
|
var found = false;
|
||||||
ast.walk(new UglifyJS.TreeWalker(function(node) {
|
ast.walk(new UglifyJS.TreeWalker(function(node) {
|
||||||
@@ -13,9 +13,9 @@ describe("tokens", function() {
|
|||||||
found = true;
|
found = true;
|
||||||
assert.equal(node.start.pos, 12);
|
assert.equal(node.start.pos, 12);
|
||||||
assert.equal(node.end.endpos, 46);
|
assert.equal(node.end.endpos, 46);
|
||||||
assert(node.key instanceof UglifyJS.AST_SymbolAccessor);
|
assert(node.key instanceof UglifyJS.AST_SymbolRef);
|
||||||
assert.equal(node.key.start.pos, 16);
|
assert.equal(node.key.start.pos, 17);
|
||||||
assert.equal(node.key.end.endpos, 22);
|
assert.equal(node.key.end.endpos, 21);
|
||||||
assert(node.value instanceof UglifyJS.AST_Accessor);
|
assert(node.value instanceof UglifyJS.AST_Accessor);
|
||||||
assert.equal(node.value.start.pos, 22);
|
assert.equal(node.value.start.pos, 22);
|
||||||
assert.equal(node.value.end.endpos, 46);
|
assert.equal(node.value.end.endpos, 46);
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// preserve for (var xxx; ...)
|
// preserve for (var xxx; ...)
|
||||||
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Var) return node;
|
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node;
|
||||||
// preserve for (xxx in ...)
|
// preserve for (xxx in ...)
|
||||||
if (parent instanceof U.AST_ForIn && parent.init === node) return node;
|
if (parent instanceof U.AST_ForIn && parent.init === node) return node;
|
||||||
|
|
||||||
@@ -145,7 +145,9 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
return permute < 2 ? expr : wrap_with_console_log(expr);
|
return permute < 2 ? expr : wrap_with_console_log(expr);
|
||||||
}
|
}
|
||||||
else if (node instanceof U.AST_BlockStatement) {
|
else if (node instanceof U.AST_BlockStatement) {
|
||||||
if (in_list) {
|
if (in_list && node.body.filter(function(node) {
|
||||||
|
return node instanceof U.AST_Const;
|
||||||
|
}).length == 0) {
|
||||||
node.start._permute++;
|
node.start._permute++;
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return List.splice(node.body);
|
return List.splice(node.body);
|
||||||
@@ -410,7 +412,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
start: {},
|
start: {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (node instanceof U.AST_Var) {
|
else if (node instanceof U.AST_Definitions) {
|
||||||
// remove empty var statement
|
// remove empty var statement
|
||||||
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
|
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
|
||||||
start: {},
|
start: {},
|
||||||
@@ -591,7 +593,7 @@ function is_error(result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function is_timed_out(result) {
|
function is_timed_out(result) {
|
||||||
return is_error(result) && /timed out/.test(result);
|
return is_error(result) && /timed out/.test(result.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_statement(node) {
|
function is_statement(node) {
|
||||||
|
|||||||
@@ -275,6 +275,8 @@ var CANNOT_RETURN = true;
|
|||||||
var NO_DEFUN = false;
|
var NO_DEFUN = false;
|
||||||
var DEFUN_OK = true;
|
var DEFUN_OK = true;
|
||||||
var DONT_STORE = true;
|
var DONT_STORE = true;
|
||||||
|
var NO_CONST = true;
|
||||||
|
var NO_DUPLICATE = true;
|
||||||
|
|
||||||
var VAR_NAMES = [
|
var VAR_NAMES = [
|
||||||
"a",
|
"a",
|
||||||
@@ -312,6 +314,7 @@ var TYPEOF_OUTCOMES = [
|
|||||||
"crap",
|
"crap",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
var block_vars = [];
|
||||||
var unique_vars = [];
|
var unique_vars = [];
|
||||||
var loops = 0;
|
var loops = 0;
|
||||||
var funcs = 0;
|
var funcs = 0;
|
||||||
@@ -329,6 +332,7 @@ function strictMode() {
|
|||||||
|
|
||||||
function createTopLevelCode() {
|
function createTopLevelCode() {
|
||||||
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
|
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
|
||||||
|
block_vars.length = 0;
|
||||||
unique_vars.length = 0;
|
unique_vars.length = 0;
|
||||||
loops = 0;
|
loops = 0;
|
||||||
funcs = 0;
|
funcs = 0;
|
||||||
@@ -353,11 +357,15 @@ function createFunctions(n, recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createParams() {
|
function createParams(noDuplicate) {
|
||||||
|
var len = unique_vars.length;
|
||||||
var params = [];
|
var params = [];
|
||||||
for (var n = rng(4); --n >= 0;) {
|
for (var n = rng(4); --n >= 0;) {
|
||||||
params.push(createVarName(MANDATORY));
|
var name = createVarName(MANDATORY);
|
||||||
|
if (noDuplicate) unique_vars.push(name);
|
||||||
|
params.push(name);
|
||||||
}
|
}
|
||||||
|
unique_vars.length = len;
|
||||||
return params.join(", ");
|
return params.join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,33 +382,77 @@ function filterDirective(s) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
||||||
|
var block_len = block_vars.length;
|
||||||
|
var var_len = VAR_NAMES.length;
|
||||||
|
var consts = [];
|
||||||
|
var lets = [];
|
||||||
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
|
while (!rng(block_vars.length > block_len ? 10 : 100)) {
|
||||||
|
var name = createVarName(MANDATORY, DONT_STORE);
|
||||||
|
if (rng(2)) {
|
||||||
|
consts.push(name);
|
||||||
|
} else {
|
||||||
|
lets.push(name);
|
||||||
|
}
|
||||||
|
block_vars.push(name);
|
||||||
|
}
|
||||||
|
unique_vars.length -= 6;
|
||||||
|
fn(function() {
|
||||||
|
if (rng(2)) {
|
||||||
|
return createDefinitions("const", consts) + "\n" + createDefinitions("let", lets) + "\n";
|
||||||
|
} else {
|
||||||
|
return createDefinitions("let", lets) + "\n" + createDefinitions("const", consts) + "\n";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
block_vars.length = block_len;
|
||||||
|
if (consts.length || lets.length) VAR_NAMES.splice(var_len, consts.length + lets.length);
|
||||||
|
|
||||||
|
function createDefinitions(type, names) {
|
||||||
|
if (!names.length) return "";
|
||||||
|
var save = VAR_NAMES;
|
||||||
|
VAR_NAMES = VAR_NAMES.filter(function(name) {
|
||||||
|
return names.indexOf(name) < 0;
|
||||||
|
});
|
||||||
|
var len = VAR_NAMES.length;
|
||||||
|
var s = type + " " + names.map(function(name) {
|
||||||
|
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||||
|
VAR_NAMES.push(name);
|
||||||
|
return name + " = " + value;
|
||||||
|
}).join(", ") + ";";
|
||||||
|
VAR_NAMES = save.concat(VAR_NAMES.slice(len));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||||
if (--recurmax < 0) { return ";"; }
|
if (--recurmax < 0) { return ";"; }
|
||||||
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
||||||
var namesLenBefore = VAR_NAMES.length;
|
var s = [];
|
||||||
var name;
|
var name;
|
||||||
if (allowDefun || rng(5) > 0) {
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
name = "f" + funcs++;
|
var namesLenBefore = VAR_NAMES.length;
|
||||||
} else {
|
if (allowDefun || rng(5) > 0) {
|
||||||
unique_vars.push("a", "b", "c");
|
name = "f" + funcs++;
|
||||||
name = createVarName(MANDATORY, !allowDefun);
|
} else {
|
||||||
unique_vars.length -= 3;
|
unique_vars.push("a", "b", "c");
|
||||||
}
|
name = createVarName(MANDATORY, !allowDefun);
|
||||||
var s = [
|
unique_vars.length -= 3;
|
||||||
"function " + name + "(" + createParams() + "){",
|
}
|
||||||
strictMode()
|
s.push("function " + name + "(" + createParams() + "){", strictMode());
|
||||||
];
|
s.push(defns());
|
||||||
if (rng(5) === 0) {
|
if (rng(5) === 0) {
|
||||||
// functions with functions. lower the recursion to prevent a mess.
|
// functions with functions. lower the recursion to prevent a mess.
|
||||||
s.push(createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), DEFUN_OK, canThrow, stmtDepth));
|
s.push(createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), DEFUN_OK, canThrow, stmtDepth));
|
||||||
} else {
|
} else {
|
||||||
// functions with statements
|
// functions with statements
|
||||||
s.push(createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
|
s.push(_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
|
||||||
}
|
}
|
||||||
s.push("}", "");
|
s.push("}", "");
|
||||||
s = filterDirective(s).join("\n");
|
s = filterDirective(s).join("\n");
|
||||||
|
|
||||||
VAR_NAMES.length = namesLenBefore;
|
VAR_NAMES.length = namesLenBefore;
|
||||||
|
});
|
||||||
|
|
||||||
if (!allowDefun) {
|
if (!allowDefun) {
|
||||||
// avoid "function statements" (decl inside statements)
|
// avoid "function statements" (decl inside statements)
|
||||||
@@ -414,7 +466,7 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
return s + ";";
|
return s + ";";
|
||||||
}
|
}
|
||||||
|
|
||||||
function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
function _createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
||||||
if (--recurmax < 0) { return ";"; }
|
if (--recurmax < 0) { return ";"; }
|
||||||
var s = "";
|
var s = "";
|
||||||
while (--n > 0) {
|
while (--n > 0) {
|
||||||
@@ -423,6 +475,15 @@ function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotRe
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
||||||
|
var s = "";
|
||||||
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
|
s += defns() + "\n";
|
||||||
|
s += _createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
||||||
|
});
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
function enableLoopControl(flag, defaultValue) {
|
function enableLoopControl(flag, defaultValue) {
|
||||||
return Array.isArray(flag) && flag.indexOf("") < 0 ? flag.concat("") : flag || defaultValue;
|
return Array.isArray(flag) && flag.indexOf("") < 0 ? flag.concat("") : flag || defaultValue;
|
||||||
}
|
}
|
||||||
@@ -496,7 +557,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
var label = createLabel(canBreak, canContinue);
|
var label = createLabel(canBreak, canContinue);
|
||||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||||
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
||||||
var key = rng(10) ? "key" + loop : getVarName();
|
var key = rng(10) ? "key" + loop : getVarName(NO_CONST);
|
||||||
return [
|
return [
|
||||||
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||||
label.target + " for (",
|
label.target + " for (",
|
||||||
@@ -571,13 +632,18 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
// the catch var should only be accessible in the catch clause...
|
// the catch var should only be accessible in the catch clause...
|
||||||
// we have to do go through some trouble here to prevent leaking it
|
// we have to do go through some trouble here to prevent leaking it
|
||||||
var nameLenBefore = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
var catchName = createVarName(MANDATORY);
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
|
var catchName = createVarName(MANDATORY);
|
||||||
if (!catch_redef) unique_vars.push(catchName);
|
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
|
||||||
s += " catch (" + catchName + ") { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
|
if (!catch_redef) unique_vars.push(catchName);
|
||||||
// remove catch name
|
s += " catch (" + catchName + ") { ";
|
||||||
if (!catch_redef) unique_vars.pop();
|
s += defns() + "\n";
|
||||||
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1);
|
s += _createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
||||||
|
s += " }";
|
||||||
|
// remove catch name
|
||||||
|
if (!catch_redef) unique_vars.pop();
|
||||||
|
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (n !== 0) s += " finally { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
|
if (n !== 0) s += " finally { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
|
||||||
return s;
|
return s;
|
||||||
@@ -597,7 +663,7 @@ function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotR
|
|||||||
if (hadDefault || rng(5) > 0) {
|
if (hadDefault || rng(5) > 0) {
|
||||||
s.push(
|
s.push(
|
||||||
"case " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ":",
|
"case " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ":",
|
||||||
createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
_createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||||
rng(10) > 0 ? " break;" : "/* fall-through */",
|
rng(10) > 0 ? " break;" : "/* fall-through */",
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
@@ -605,7 +671,7 @@ function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotR
|
|||||||
hadDefault = true;
|
hadDefault = true;
|
||||||
s.push(
|
s.push(
|
||||||
"default:",
|
"default:",
|
||||||
createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
_createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -653,7 +719,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
return getVarName();
|
return getVarName();
|
||||||
case p++:
|
case p++:
|
||||||
return getVarName() + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return getVarName(NO_CONST) + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
@@ -699,19 +765,22 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
var instantiate = rng(4) ? "new " : "";
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
s.push(
|
var instantiate = rng(4) ? "new " : "";
|
||||||
instantiate + "function " + name + "(){",
|
s.push(
|
||||||
strictMode()
|
instantiate + "function " + name + "(){",
|
||||||
);
|
strictMode(),
|
||||||
if (instantiate) for (var i = rng(4); --i >= 0;) {
|
defns()
|
||||||
if (rng(2)) s.push("this." + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
);
|
||||||
else s.push("this[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
if (instantiate) for (var i = rng(4); --i >= 0;) {
|
||||||
}
|
if (rng(2)) s.push("this." + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
||||||
s.push(
|
else s.push("this[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
||||||
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
}
|
||||||
rng(2) == 0 ? "}" : "}()"
|
s.push(
|
||||||
);
|
_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
|
rng(2) == 0 ? "}" : "}()"
|
||||||
|
);
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
VAR_NAMES.length = nameLenBefore;
|
VAR_NAMES.length = nameLenBefore;
|
||||||
@@ -844,31 +913,51 @@ function getDotKey(assign) {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAccessor(recurmax, stmtDepth, canThrow) {
|
function createObjectKey(recurmax, stmtDepth, canThrow) {
|
||||||
|
return rng(10) ? KEYS[rng(KEYS.length)] : "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
||||||
var namesLenBefore = VAR_NAMES.length;
|
var namesLenBefore = VAR_NAMES.length;
|
||||||
var s;
|
var s;
|
||||||
var prop1 = getDotKey();
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
if (rng(2) == 0) {
|
switch (rng(3)) {
|
||||||
s = [
|
case 0:
|
||||||
"get " + prop1 + "(){",
|
s = [
|
||||||
strictMode(),
|
"get " + createObjectKey(recurmax, stmtDepth, canThrow) + "(){",
|
||||||
createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
strictMode(),
|
||||||
createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC),
|
defns(),
|
||||||
"},"
|
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
];
|
createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC),
|
||||||
} else {
|
"},",
|
||||||
var prop2;
|
];
|
||||||
do {
|
break;
|
||||||
prop2 = getDotKey();
|
case 1:
|
||||||
} while (prop1 == prop2);
|
var prop1 = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
s = [
|
var prop2;
|
||||||
"set " + prop1 + "(" + createVarName(MANDATORY) + "){",
|
do {
|
||||||
strictMode(),
|
prop2 = getDotKey();
|
||||||
createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
} while (prop1 == prop2);
|
||||||
"this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
s = [
|
||||||
"},"
|
"set " + prop1 + "(" + createVarName(MANDATORY) + "){",
|
||||||
];
|
strictMode(),
|
||||||
}
|
defns(),
|
||||||
|
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
|
"this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
||||||
|
"},",
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = [
|
||||||
|
createObjectKey(recurmax, stmtDepth, canThrow) + "(" + createParams(NO_DUPLICATE) + "){",
|
||||||
|
strictMode(),
|
||||||
|
defns(),
|
||||||
|
_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
|
"},",
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
VAR_NAMES.length = namesLenBefore;
|
VAR_NAMES.length = namesLenBefore;
|
||||||
return filterDirective(s).join("\n");
|
return filterDirective(s).join("\n");
|
||||||
}
|
}
|
||||||
@@ -876,13 +965,16 @@ function createAccessor(recurmax, stmtDepth, canThrow) {
|
|||||||
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
|
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
|
||||||
recurmax--;
|
recurmax--;
|
||||||
var obj = ["({"];
|
var obj = ["({"];
|
||||||
for (var i = rng(6); --i >= 0;) {
|
for (var i = rng(6); --i >= 0;) switch (rng(30)) {
|
||||||
if (rng(20) == 0) {
|
case 0:
|
||||||
obj.push(createAccessor(recurmax, stmtDepth, canThrow));
|
obj.push(createObjectFunction(recurmax, stmtDepth, canThrow));
|
||||||
} else {
|
break;
|
||||||
var key = KEYS[rng(KEYS.length)];
|
case 1:
|
||||||
obj.push(key + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
|
obj.push(getVarName() + ",");
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
|
obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
obj.push("})");
|
obj.push("})");
|
||||||
return obj.join("\n");
|
return obj.join("\n");
|
||||||
@@ -906,7 +998,7 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case 1:
|
case 1:
|
||||||
return "(" + createUnarySafePrefix() + "(" + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + "))";
|
return "(" + createUnarySafePrefix() + "(" + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + "))";
|
||||||
case 2:
|
case 2:
|
||||||
assignee = getVarName();
|
assignee = getVarName(NO_CONST);
|
||||||
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||||
case 3:
|
case 3:
|
||||||
assignee = getVarName();
|
assignee = getVarName();
|
||||||
@@ -968,9 +1060,10 @@ function createUnaryPostfix() {
|
|||||||
return UNARY_POSTFIX[rng(UNARY_POSTFIX.length)];
|
return UNARY_POSTFIX[rng(UNARY_POSTFIX.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVarName() {
|
function getVarName(noConst) {
|
||||||
// try to get a generated name reachable from current scope. default to just `a`
|
// try to get a generated name reachable from current scope. default to just `a`
|
||||||
return VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)] || "a";
|
var name = VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)];
|
||||||
|
return !name || noConst && block_vars.indexOf(name) >= 0 ? "a" : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createVarName(maybe, dontStore) {
|
function createVarName(maybe, dontStore) {
|
||||||
@@ -980,7 +1073,7 @@ function createVarName(maybe, dontStore) {
|
|||||||
do {
|
do {
|
||||||
name = VAR_NAMES[rng(VAR_NAMES.length)];
|
name = VAR_NAMES[rng(VAR_NAMES.length)];
|
||||||
if (suffix) name += "_" + suffix;
|
if (suffix) name += "_" + suffix;
|
||||||
} while (unique_vars.indexOf(name) >= 0);
|
} while (unique_vars.indexOf(name) >= 0 || block_vars.indexOf(name) >= 0);
|
||||||
if (suffix && !dontStore) VAR_NAMES.push(name);
|
if (suffix && !dontStore) VAR_NAMES.push(name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -1258,10 +1351,6 @@ function patch_try_catch(orig, toplevel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fallback_options = [ JSON.stringify({
|
|
||||||
compress: false,
|
|
||||||
mangle: false
|
|
||||||
}) ];
|
|
||||||
var minify_options = require("./options.json").map(JSON.stringify);
|
var minify_options = require("./options.json").map(JSON.stringify);
|
||||||
var original_code, original_result, errored;
|
var original_code, original_result, errored;
|
||||||
var uglify_code, uglify_result, ok;
|
var uglify_code, uglify_result, ok;
|
||||||
@@ -1269,10 +1358,19 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
process.stdout.write(round + " of " + num_iterations + "\r");
|
process.stdout.write(round + " of " + num_iterations + "\r");
|
||||||
|
|
||||||
original_code = createTopLevelCode();
|
original_code = createTopLevelCode();
|
||||||
var orig_result = [ sandbox.run_code(original_code) ];
|
var orig_result = [ sandbox.run_code(original_code), sandbox.run_code(original_code, true) ];
|
||||||
errored = typeof orig_result[0] != "string";
|
errored = typeof orig_result[0] != "string";
|
||||||
if (!errored) orig_result.push(sandbox.run_code(original_code, true));
|
if (errored) {
|
||||||
(errored ? fallback_options : minify_options).forEach(function(options) {
|
println("//=============================================================");
|
||||||
|
println("// original code");
|
||||||
|
try_beautify(original_code, false, orig_result[0], println);
|
||||||
|
println();
|
||||||
|
println();
|
||||||
|
println("original result:");
|
||||||
|
println(orig_result[0]);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
minify_options.forEach(function(options) {
|
||||||
var o = JSON.parse(options);
|
var o = JSON.parse(options);
|
||||||
var toplevel = sandbox.has_toplevel(o);
|
var toplevel = sandbox.has_toplevel(o);
|
||||||
o.validate = true;
|
o.validate = true;
|
||||||
@@ -1287,13 +1385,20 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
ok = sandbox.same_stdout(sandbox.run_code(sort_globals(original_code)), sandbox.run_code(sort_globals(uglify_code)));
|
ok = sandbox.same_stdout(sandbox.run_code(sort_globals(original_code)), sandbox.run_code(sort_globals(uglify_code)));
|
||||||
}
|
}
|
||||||
// ignore numerical imprecision caused by `unsafe_math`
|
// ignore numerical imprecision caused by `unsafe_math`
|
||||||
if (!ok && typeof uglify_result == "string" && o.compress && o.compress.unsafe_math) {
|
if (!ok && o.compress && o.compress.unsafe_math && typeof original_result == "string" && typeof uglify_result == "string") {
|
||||||
ok = fuzzy_match(original_result, uglify_result);
|
ok = fuzzy_match(original_result, uglify_result);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
var fuzzy_result = sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"), toplevel);
|
var fuzzy_result = sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"), toplevel);
|
||||||
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ignore difference in error message caused by Temporal Dead Zone
|
||||||
|
if (!ok && errored && uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError") ok = true;
|
||||||
|
// ignore spurious time-outs
|
||||||
|
if (!ok && errored && /timed out/.test(original_result.message) && !/timed out/.test(uglify_result.message)) {
|
||||||
|
if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = sandbox.run_code(original_code, toplevel, 10000);
|
||||||
|
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
||||||
|
}
|
||||||
// ignore difference in error message caused by `in`
|
// ignore difference in error message caused by `in`
|
||||||
// ignore difference in depth of termination caused by infinite recursion
|
// ignore difference in depth of termination caused by infinite recursion
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@@ -1308,16 +1413,6 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
ok = errored && uglify_code.name == original_result.name;
|
ok = errored && uglify_code.name == original_result.name;
|
||||||
}
|
}
|
||||||
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
||||||
else if (errored) {
|
|
||||||
println("//=============================================================");
|
|
||||||
println("// original code");
|
|
||||||
try_beautify(original_code, toplevel, original_result, println);
|
|
||||||
println();
|
|
||||||
println();
|
|
||||||
println("original result:");
|
|
||||||
println(original_result);
|
|
||||||
println();
|
|
||||||
}
|
|
||||||
if (!ok && isFinite(num_iterations)) {
|
if (!ok && isFinite(num_iterations)) {
|
||||||
println();
|
println();
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
@@ -48,8 +48,10 @@ function run() {
|
|||||||
stderr = "";
|
stderr = "";
|
||||||
child.stderr.on("data", trap).pipe(process.stdout);
|
child.stderr.on("data", trap).pipe(process.stdout);
|
||||||
log = setInterval(function() {
|
log = setInterval(function() {
|
||||||
|
stdout = stdout.replace(/[^\r\n]+\r(?=[^\r\n]+\r)/g, "");
|
||||||
var end = stdout.lastIndexOf("\r");
|
var end = stdout.lastIndexOf("\r");
|
||||||
console.log(stdout.slice(stdout.lastIndexOf("\r", end - 1) + 1, end));
|
if (end < 0) return;
|
||||||
|
console.log(stdout.slice(0, end));
|
||||||
stdout = stdout.slice(end + 1);
|
stdout = stdout.slice(end + 1);
|
||||||
}, 5 * 60 * 1000);
|
}, 5 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user