Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e390e7e124 | ||
|
|
6fd5b5b371 | ||
|
|
fba27bfb71 | ||
|
|
41310e6404 | ||
|
|
91fc1c82b5 | ||
|
|
810cd40356 | ||
|
|
1cbd07e789 | ||
|
|
b82de04775 | ||
|
|
4bbeb09f7c | ||
|
|
c2f6fd5fde |
30
lib/ast.js
30
lib/ast.js
@@ -1015,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);
|
||||||
@@ -1040,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);
|
||||||
@@ -1048,7 +1051,6 @@ 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);
|
||||||
@@ -1065,10 +1067,6 @@ var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
119
lib/compress.js
119
lib/compress.js
@@ -1166,7 +1166,9 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function as_statement_array(thing) {
|
function as_statement_array(thing) {
|
||||||
if (thing === null) return [];
|
if (thing === null) return [];
|
||||||
if (thing instanceof AST_BlockStatement) return thing.body;
|
if (thing instanceof AST_BlockStatement) return all(thing.body, function(stat) {
|
||||||
|
return !(stat instanceof AST_Const || stat instanceof AST_Let);
|
||||||
|
}) ? thing.body : [ thing ];
|
||||||
if (thing instanceof AST_EmptyStatement) return [];
|
if (thing instanceof AST_EmptyStatement) return [];
|
||||||
if (thing instanceof AST_Statement) return [ thing ];
|
if (thing instanceof AST_Statement) return [ thing ];
|
||||||
throw new Error("Can't convert thing to statement array");
|
throw new Error("Can't convert thing to statement array");
|
||||||
@@ -1424,8 +1426,9 @@ merge(Compressor.prototype, {
|
|||||||
if (!--replaced) abort = true;
|
if (!--replaced) abort = true;
|
||||||
if (is_lhs(node, multi_replacer.parent())) return node;
|
if (is_lhs(node, multi_replacer.parent())) return node;
|
||||||
def.replaced++;
|
def.replaced++;
|
||||||
value_def.replaced--;
|
var ref = rvalue.clone();
|
||||||
return rvalue.clone();
|
value_def.references.push(ref);
|
||||||
|
return ref;
|
||||||
}
|
}
|
||||||
// Skip (non-executed) functions and (leading) default case in switch statements
|
// Skip (non-executed) functions and (leading) default case in switch statements
|
||||||
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
|
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
|
||||||
@@ -1748,11 +1751,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
} else if (expr instanceof AST_Object) {
|
} else if (expr instanceof AST_Object) {
|
||||||
expr.properties.forEach(function(prop) {
|
expr.properties.forEach(function(prop) {
|
||||||
if (prop instanceof AST_ObjectKeyVal) {
|
|
||||||
hit_stack.push(prop);
|
hit_stack.push(prop);
|
||||||
extract_candidates(prop.value);
|
if (prop.key instanceof AST_Node) extract_candidates(prop.key);
|
||||||
|
if (prop instanceof AST_ObjectKeyVal) extract_candidates(prop.value);
|
||||||
hit_stack.pop();
|
hit_stack.pop();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} else if (expr instanceof AST_Sequence) {
|
} else if (expr instanceof AST_Sequence) {
|
||||||
expr.expressions.forEach(extract_candidates);
|
expr.expressions.forEach(extract_candidates);
|
||||||
@@ -1798,7 +1800,7 @@ merge(Compressor.prototype, {
|
|||||||
if (parent instanceof AST_Exit) return node;
|
if (parent instanceof AST_Exit) return node;
|
||||||
if (parent instanceof AST_If) return node;
|
if (parent instanceof AST_If) return node;
|
||||||
if (parent instanceof AST_IterationStatement) return node;
|
if (parent instanceof AST_IterationStatement) return node;
|
||||||
if (parent instanceof AST_ObjectKeyVal) return node;
|
if (parent instanceof AST_ObjectProperty) return node;
|
||||||
if (parent instanceof AST_PropAccess) return node;
|
if (parent instanceof AST_PropAccess) return node;
|
||||||
if (parent instanceof AST_Sequence) {
|
if (parent instanceof AST_Sequence) {
|
||||||
return (parent.tail_node() === node ? find_stop : find_stop_unused)(parent, level + 1);
|
return (parent.tail_node() === node ? find_stop : find_stop_unused)(parent, level + 1);
|
||||||
@@ -1856,7 +1858,7 @@ merge(Compressor.prototype, {
|
|||||||
if (parent.condition !== node) return node;
|
if (parent.condition !== node) return node;
|
||||||
return find_stop_value(parent, level + 1);
|
return find_stop_value(parent, level + 1);
|
||||||
}
|
}
|
||||||
if (parent instanceof AST_ObjectKeyVal) {
|
if (parent instanceof AST_ObjectProperty) {
|
||||||
var obj = scanner.parent(level + 1);
|
var obj = scanner.parent(level + 1);
|
||||||
return all(obj.properties, function(prop) {
|
return all(obj.properties, function(prop) {
|
||||||
return prop instanceof AST_ObjectKeyVal;
|
return prop instanceof AST_ObjectKeyVal;
|
||||||
@@ -1904,7 +1906,7 @@ merge(Compressor.prototype, {
|
|||||||
if (parent instanceof AST_Exit) return find_stop_unused(parent, level + 1);
|
if (parent instanceof AST_Exit) return find_stop_unused(parent, level + 1);
|
||||||
if (parent instanceof AST_If) return find_stop_unused(parent, level + 1);
|
if (parent instanceof AST_If) return find_stop_unused(parent, level + 1);
|
||||||
if (parent instanceof AST_IterationStatement) return node;
|
if (parent instanceof AST_IterationStatement) return node;
|
||||||
if (parent instanceof AST_ObjectKeyVal) {
|
if (parent instanceof AST_ObjectProperty) {
|
||||||
var obj = scanner.parent(level + 1);
|
var obj = scanner.parent(level + 1);
|
||||||
return all(obj.properties, function(prop) {
|
return all(obj.properties, function(prop) {
|
||||||
return prop instanceof AST_ObjectKeyVal;
|
return prop instanceof AST_ObjectKeyVal;
|
||||||
@@ -2698,9 +2700,12 @@ merge(Compressor.prototype, {
|
|||||||
if (prop instanceof AST_Node) break;
|
if (prop instanceof AST_Node) break;
|
||||||
prop = "" + prop;
|
prop = "" + prop;
|
||||||
var diff = prop == "__proto__" || compressor.has_directive("use strict") ? function(node) {
|
var diff = prop == "__proto__" || compressor.has_directive("use strict") ? function(node) {
|
||||||
return node.key != prop && node.key.name != prop;
|
return typeof node.key == "string" && node.key != prop;
|
||||||
} : function(node) {
|
} : function(node) {
|
||||||
return node.key.name != prop;
|
if (node instanceof AST_ObjectGetter || node instanceof AST_ObjectSetter) {
|
||||||
|
return typeof node.key == "string" && node.key != prop;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
if (!all(value.properties, diff)) break;
|
if (!all(value.properties, diff)) break;
|
||||||
value.properties.push(make_node(AST_ObjectKeyVal, node, {
|
value.properties.push(make_node(AST_ObjectKeyVal, node, {
|
||||||
@@ -2985,10 +2990,9 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Lambda, return_false);
|
def(AST_Lambda, return_false);
|
||||||
def(AST_Null, return_true);
|
def(AST_Null, return_true);
|
||||||
def(AST_Object, function(compressor) {
|
def(AST_Object, function(compressor) {
|
||||||
if (!is_strict(compressor)) return false;
|
return is_strict(compressor) && !all(this.properties, function(prop) {
|
||||||
for (var i = this.properties.length; --i >=0;)
|
return prop instanceof AST_ObjectKeyVal;
|
||||||
if (this.properties[i].value instanceof AST_Accessor) return true;
|
});
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
def(AST_Sequence, function(compressor) {
|
def(AST_Sequence, function(compressor) {
|
||||||
return this.tail_node()._dot_throw(compressor);
|
return this.tail_node()._dot_throw(compressor);
|
||||||
@@ -3584,12 +3588,13 @@ merge(Compressor.prototype, {
|
|||||||
var val = {};
|
var val = {};
|
||||||
for (var i = 0; i < this.properties.length; i++) {
|
for (var i = 0; i < this.properties.length; i++) {
|
||||||
var prop = this.properties[i];
|
var prop = this.properties[i];
|
||||||
|
if (!(prop instanceof AST_ObjectKeyVal)) return this;
|
||||||
var key = prop.key;
|
var key = prop.key;
|
||||||
if (key instanceof AST_Symbol) key = key.name;
|
if (key instanceof AST_Node) {
|
||||||
if (prop.value instanceof AST_Function) {
|
key = key._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (typeof Object.prototype[key] == "function") return this;
|
if (key === prop.key) return this;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
if (prop.value instanceof AST_Function && typeof Object.prototype[key] == "function") return this;
|
||||||
val[key] = prop.value._eval(compressor, ignore_side_effects, cached, depth);
|
val[key] = prop.value._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (val[key] === prop.value) return this;
|
if (val[key] === prop.value) return this;
|
||||||
}
|
}
|
||||||
@@ -4107,7 +4112,8 @@ merge(Compressor.prototype, {
|
|||||||
return any(this.properties, compressor);
|
return any(this.properties, compressor);
|
||||||
});
|
});
|
||||||
def(AST_ObjectProperty, function(compressor) {
|
def(AST_ObjectProperty, function(compressor) {
|
||||||
return this.value.has_side_effects(compressor);
|
return this.key instanceof AST_Node && this.key.has_side_effects(compressor)
|
||||||
|
|| this.value.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Sub, function(compressor) {
|
def(AST_Sub, function(compressor) {
|
||||||
return this.expression.may_throw_on_access(compressor)
|
return this.expression.may_throw_on_access(compressor)
|
||||||
@@ -4219,7 +4225,8 @@ merge(Compressor.prototype, {
|
|||||||
return any(this.properties, compressor);
|
return any(this.properties, compressor);
|
||||||
});
|
});
|
||||||
def(AST_ObjectProperty, function(compressor) {
|
def(AST_ObjectProperty, function(compressor) {
|
||||||
return this.value.may_throw(compressor);
|
return this.key instanceof AST_Node && this.key.may_throw(compressor)
|
||||||
|
|| this.value.may_throw(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Return, function(compressor) {
|
def(AST_Return, function(compressor) {
|
||||||
return this.value && this.value.may_throw(compressor);
|
return this.value && this.value.may_throw(compressor);
|
||||||
@@ -4315,7 +4322,7 @@ merge(Compressor.prototype, {
|
|||||||
return all(this.properties);
|
return all(this.properties);
|
||||||
});
|
});
|
||||||
def(AST_ObjectProperty, function() {
|
def(AST_ObjectProperty, function() {
|
||||||
return this.value.is_constant_expression();
|
return typeof this.key == "string" && this.value.is_constant_expression();
|
||||||
});
|
});
|
||||||
def(AST_Unary, function() {
|
def(AST_Unary, function() {
|
||||||
return this.expression.is_constant_expression();
|
return this.expression.is_constant_expression();
|
||||||
@@ -5433,7 +5440,7 @@ merge(Compressor.prototype, {
|
|||||||
vars.set(def.name.name, def);
|
vars.set(def.name.name, def);
|
||||||
++vars_found;
|
++vars_found;
|
||||||
});
|
});
|
||||||
var seq = node.to_assignments(compressor);
|
var seq = node.to_assignments();
|
||||||
var p = tt.parent();
|
var p = tt.parent();
|
||||||
if (p instanceof AST_ForIn && p.init === node) {
|
if (p instanceof AST_ForIn && p.init === node) {
|
||||||
if (seq) return seq;
|
if (seq) return seq;
|
||||||
@@ -5741,7 +5748,7 @@ merge(Compressor.prototype, {
|
|||||||
return right instanceof AST_Object
|
return right instanceof AST_Object
|
||||||
&& right.properties.length > 0
|
&& right.properties.length > 0
|
||||||
&& all(right.properties, function(prop) {
|
&& all(right.properties, function(prop) {
|
||||||
return prop instanceof AST_ObjectKeyVal;
|
return prop instanceof AST_ObjectKeyVal && typeof prop.key == "string";
|
||||||
})
|
})
|
||||||
&& all(def.references, function(ref) {
|
&& all(def.references, function(ref) {
|
||||||
return ref.fixed_value() === right;
|
return ref.fixed_value() === right;
|
||||||
@@ -5931,11 +5938,13 @@ merge(Compressor.prototype, {
|
|||||||
return safe_to_drop(this, compressor) ? null : this;
|
return safe_to_drop(this, compressor) ? null : this;
|
||||||
});
|
});
|
||||||
def(AST_Object, function(compressor, first_in_statement) {
|
def(AST_Object, function(compressor, first_in_statement) {
|
||||||
var values = trim(this.properties, compressor, first_in_statement);
|
var exprs = [];
|
||||||
return values && make_sequence(this, values);
|
this.properties.forEach(function(prop) {
|
||||||
|
if (prop.key instanceof AST_Node) exprs.push(prop.key);
|
||||||
|
exprs.push(prop.value);
|
||||||
});
|
});
|
||||||
def(AST_ObjectProperty, function(compressor, first_in_statement) {
|
var values = trim(exprs, compressor, first_in_statement);
|
||||||
return this.value.drop_side_effect_free(compressor, first_in_statement);
|
return values && make_sequence(this, values);
|
||||||
});
|
});
|
||||||
def(AST_Sequence, function(compressor, first_in_statement) {
|
def(AST_Sequence, function(compressor, first_in_statement) {
|
||||||
var expressions = trim(this.expressions, compressor, first_in_statement);
|
var expressions = trim(this.expressions, compressor, first_in_statement);
|
||||||
@@ -6716,21 +6725,19 @@ merge(Compressor.prototype, {
|
|||||||
AST_Let.DEFMETHOD("remove_initializers", remove_initializers);
|
AST_Let.DEFMETHOD("remove_initializers", remove_initializers);
|
||||||
AST_Var.DEFMETHOD("remove_initializers", remove_initializers);
|
AST_Var.DEFMETHOD("remove_initializers", remove_initializers);
|
||||||
|
|
||||||
AST_Definitions.DEFMETHOD("to_assignments", function(compressor) {
|
AST_Definitions.DEFMETHOD("to_assignments", function() {
|
||||||
var reduce_vars = compressor.option("reduce_vars");
|
var assignments = this.definitions.reduce(function(a, defn) {
|
||||||
var assignments = this.definitions.reduce(function(a, def) {
|
var def = defn.name.definition();
|
||||||
if (def.value) {
|
if (defn.value) {
|
||||||
var name = make_node(AST_SymbolRef, def.name, def.name);
|
var name = make_node(AST_SymbolRef, defn.name, defn.name);
|
||||||
a.push(make_node(AST_Assign, def, {
|
a.push(make_node(AST_Assign, defn, {
|
||||||
operator : "=",
|
operator : "=",
|
||||||
left : name,
|
left : name,
|
||||||
right : def.value
|
right : defn.value
|
||||||
}));
|
}));
|
||||||
if (reduce_vars) name.definition().fixed = false;
|
def.references.push(name);
|
||||||
}
|
}
|
||||||
def = def.name.definition();
|
|
||||||
def.eliminated++;
|
def.eliminated++;
|
||||||
def.replaced--;
|
|
||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
if (assignments.length == 0) return null;
|
if (assignments.length == 0) return null;
|
||||||
@@ -7167,7 +7174,7 @@ merge(Compressor.prototype, {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var child, in_loop, scope;
|
var insert, in_loop, scope;
|
||||||
if (replacing && can_inject_symbols()) {
|
if (replacing && can_inject_symbols()) {
|
||||||
fn._squeezed = true;
|
fn._squeezed = true;
|
||||||
if (exp !== fn) fn.parent_scope = exp.scope;
|
if (exp !== fn) fn.parent_scope = exp.scope;
|
||||||
@@ -7337,7 +7344,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function can_inject_symbols() {
|
function can_inject_symbols() {
|
||||||
var defined = Object.create(null);
|
var defined = Object.create(null);
|
||||||
var level = 0;
|
var level = 0, child;
|
||||||
scope = compressor.self();
|
scope = compressor.self();
|
||||||
while (!(scope instanceof AST_Scope)) {
|
while (!(scope instanceof AST_Scope)) {
|
||||||
if (scope.variables) scope.variables.each(function(def) {
|
if (scope.variables) scope.variables.each(function(def) {
|
||||||
@@ -7358,6 +7365,8 @@ merge(Compressor.prototype, {
|
|||||||
if (scope.fixed_value() instanceof AST_Scope) return false;
|
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
insert = scope.body.indexOf(child) + 1;
|
||||||
|
if (!insert) return false;
|
||||||
var safe_to_inject = (!(scope instanceof AST_Toplevel) || compressor.toplevel.vars)
|
var safe_to_inject = (!(scope instanceof AST_Toplevel) || compressor.toplevel.vars)
|
||||||
&& (exp !== fn || fn.parent_scope.resolve() === compressor.find_parent(AST_Scope));
|
&& (exp !== fn || fn.parent_scope.resolve() === compressor.find_parent(AST_Scope));
|
||||||
var inline = compressor.option("inline");
|
var inline = compressor.option("inline");
|
||||||
@@ -7460,7 +7469,7 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
args.unshift(scope.body.indexOf(child) + 1, 0);
|
args.unshift(insert, 0);
|
||||||
if (decls.length) args.push(make_node(AST_Var, fn, {
|
if (decls.length) args.push(make_node(AST_Var, fn, {
|
||||||
definitions: decls
|
definitions: decls
|
||||||
}));
|
}));
|
||||||
@@ -8430,7 +8439,7 @@ merge(Compressor.prototype, {
|
|||||||
fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
|
fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
|
||||||
}
|
}
|
||||||
if (fixed instanceof AST_Lambda) {
|
if (fixed instanceof AST_Lambda) {
|
||||||
var scope = self.scope;
|
var scope = self.scope.resolve();
|
||||||
fixed.enclosed.forEach(function(def) {
|
fixed.enclosed.forEach(function(def) {
|
||||||
if (fixed.variables.has(def.name)) return;
|
if (fixed.variables.has(def.name)) return;
|
||||||
if (scope.var_names()[def.name]) return;
|
if (scope.var_names()[def.name]) return;
|
||||||
@@ -9316,9 +9325,9 @@ merge(Compressor.prototype, {
|
|||||||
var props = expr.properties;
|
var props = expr.properties;
|
||||||
for (var i = props.length; --i >= 0;) {
|
for (var i = props.length; --i >= 0;) {
|
||||||
var prop = props[i];
|
var prop = props[i];
|
||||||
if ("" + prop.key == key) {
|
if (prop.key != key) continue;
|
||||||
if (!all(props, function(prop) {
|
if (!all(props, function(prop) {
|
||||||
return prop instanceof AST_ObjectKeyVal;
|
return prop instanceof AST_ObjectKeyVal && typeof prop.key == "string";
|
||||||
})) break;
|
})) break;
|
||||||
if (!safe_to_flatten(prop.value, compressor)) break;
|
if (!safe_to_flatten(prop.value, compressor)) break;
|
||||||
return make_node(AST_Sub, this, {
|
return make_node(AST_Sub, this, {
|
||||||
@@ -9333,7 +9342,6 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Dot, function(self, compressor) {
|
OPT(AST_Dot, function(self, compressor) {
|
||||||
@@ -9398,25 +9406,28 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
OPT(AST_Object, function(self, compressor) {
|
OPT(AST_Object, function(self, compressor) {
|
||||||
if (!compressor.option("objects") || compressor.has_directive("use strict")) return self;
|
if (!compressor.option("objects") || compressor.has_directive("use strict")) return self;
|
||||||
|
for (var i = self.properties.length; --i >= 0;) {
|
||||||
|
var prop = self.properties[i];
|
||||||
|
var key = prop.key;
|
||||||
|
if (key instanceof AST_Node) key = key.evaluate(compressor);
|
||||||
|
if (typeof key != "string" || /[0-9]+/.test(key)) break;
|
||||||
|
if (key !== prop.key) prop.key = "" + key;
|
||||||
|
}
|
||||||
var keys = new Dictionary();
|
var keys = new Dictionary();
|
||||||
var values = [];
|
var values = [];
|
||||||
self.properties.forEach(function(prop) {
|
self.properties.forEach(function(prop) {
|
||||||
if (typeof prop.key != "string") {
|
if (prop instanceof AST_ObjectKeyVal && typeof prop.key == "string") {
|
||||||
|
if (prop.value.has_side_effects(compressor)) flush();
|
||||||
|
keys.add(prop.key, prop.value);
|
||||||
|
} else {
|
||||||
flush();
|
flush();
|
||||||
values.push(prop);
|
values.push(prop);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (prop.value.has_side_effects(compressor)) {
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
keys.add(prop.key, prop.value);
|
|
||||||
});
|
});
|
||||||
flush();
|
flush();
|
||||||
if (self.properties.length != values.length) {
|
if (self.properties.length != values.length) return make_node(AST_Object, self, {
|
||||||
return make_node(AST_Object, self, {
|
|
||||||
properties: values
|
properties: values
|
||||||
});
|
});
|
||||||
}
|
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
function flush() {
|
function flush() {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -699,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
|
||||||
@@ -1289,12 +1290,19 @@ 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)) {
|
} else {
|
||||||
|
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")) {
|
if (quote && output.option("keep_quoted_props")) {
|
||||||
output.print_string(key, quote);
|
output.print_string(key, quote);
|
||||||
} else {
|
} else {
|
||||||
@@ -1304,10 +1312,11 @@ function OutputStream(options) {
|
|||||||
output.print_string(key, quote);
|
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);
|
||||||
});
|
});
|
||||||
@@ -1316,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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1488,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);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
92
lib/parse.js
92
lib/parse.js
@@ -753,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":
|
||||||
@@ -844,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);
|
||||||
|
|
||||||
@@ -1038,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);
|
||||||
@@ -1067,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;
|
||||||
@@ -1222,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 });
|
||||||
@@ -1340,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
|
||||||
break;
|
if (!options.strict && is("punc", "}")) 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,
|
||||||
|
value: func,
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!is("punc", ":") && start.type == "name") switch (key) {
|
||||||
|
case "get":
|
||||||
a.push(new AST_ObjectGetter({
|
a.push(new AST_ObjectGetter({
|
||||||
start: start,
|
start: start,
|
||||||
key : key,
|
key: as_property_key(),
|
||||||
value: create_accessor(),
|
value: create_accessor(),
|
||||||
end : prev()
|
end: prev(),
|
||||||
}));
|
}));
|
||||||
continue;
|
continue;
|
||||||
}
|
case "set":
|
||||||
if (name == "set") {
|
|
||||||
a.push(new AST_ObjectSetter({
|
a.push(new AST_ObjectSetter({
|
||||||
start: start,
|
start: start,
|
||||||
key : key,
|
key: as_property_key(),
|
||||||
value: create_accessor(),
|
value: create_accessor(),
|
||||||
end : prev()
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start: start,
|
||||||
|
key: key,
|
||||||
|
value: _make_symbol(AST_SymbolRef, start),
|
||||||
|
end: prev(),
|
||||||
}));
|
}));
|
||||||
continue;
|
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":
|
||||||
@@ -1395,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();
|
||||||
}
|
}
|
||||||
@@ -1408,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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1427,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);
|
||||||
}
|
}
|
||||||
@@ -1616,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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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.5",
|
"version": "3.11.6",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1135,3 +1135,93 @@ issue_4248: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4261: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const a = 42;
|
||||||
|
(function() {
|
||||||
|
function f() {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
while (f());
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
while (g());
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
{
|
||||||
|
const a = 42;
|
||||||
|
(function() {
|
||||||
|
function g() {
|
||||||
|
while (void console.log(a));
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
while (g());
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4274_1: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (;;) {
|
||||||
|
if (console.log("PASS")) {
|
||||||
|
const a = 0;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (; console.log("PASS");) {
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
}
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4274_2: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (;;) {
|
||||||
|
if (!console.log("PASS")) {
|
||||||
|
break;
|
||||||
|
var a;
|
||||||
|
} else {
|
||||||
|
const a = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (; console.log("PASS");) {
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
}
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
@@ -3047,3 +3047,30 @@ issue_4214: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "NaN"
|
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",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -5115,3 +5115,102 @@ issue_4233: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "number"
|
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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -950,3 +950,59 @@ issue_4248: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4274_1: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
for (;;) {
|
||||||
|
if (console.log("PASS")) {
|
||||||
|
let a;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
for (; console.log("PASS");) {
|
||||||
|
{
|
||||||
|
let a;
|
||||||
|
}
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4274_2: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
for (;;) {
|
||||||
|
if (!console.log("PASS")) {
|
||||||
|
break;
|
||||||
|
var a;
|
||||||
|
} else {
|
||||||
|
let a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
for (; console.log("PASS");) {
|
||||||
|
{
|
||||||
|
let a;
|
||||||
|
}
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1999,7 +1999,7 @@ issue_1606: {
|
|||||||
var a, b;
|
var a, b;
|
||||||
function g(){};
|
function g(){};
|
||||||
b = 2;
|
b = 2;
|
||||||
x(b);
|
x(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -276,6 +276,7 @@ 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_CONST = true;
|
||||||
|
var NO_DUPLICATE = true;
|
||||||
|
|
||||||
var VAR_NAMES = [
|
var VAR_NAMES = [
|
||||||
"a",
|
"a",
|
||||||
@@ -356,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(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -908,21 +913,27 @@ 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;
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
var prop1 = getDotKey();
|
switch (rng(3)) {
|
||||||
if (rng(2) == 0) {
|
case 0:
|
||||||
s = [
|
s = [
|
||||||
"get " + prop1 + "(){",
|
"get " + createObjectKey(recurmax, stmtDepth, canThrow) + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
defns(),
|
defns(),
|
||||||
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC),
|
createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC),
|
||||||
"},"
|
"},",
|
||||||
];
|
];
|
||||||
} else {
|
break;
|
||||||
|
case 1:
|
||||||
|
var prop1 = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
var prop2;
|
var prop2;
|
||||||
do {
|
do {
|
||||||
prop2 = getDotKey();
|
prop2 = getDotKey();
|
||||||
@@ -933,8 +944,18 @@ function createAccessor(recurmax, stmtDepth, canThrow) {
|
|||||||
defns(),
|
defns(),
|
||||||
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
"this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
"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;
|
||||||
@@ -944,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");
|
||||||
|
|||||||
Reference in New Issue
Block a user