aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2017-05-14 02:10:34 +0800
committerGitHub <noreply@github.com>2017-05-14 02:10:34 +0800
commit3ca902258c24209699f0b5bd5b9654252e492272 (patch)
treeda7dbf1bc1e3bd70e463da43d0f7ebc06a36b2db /lib
parentfd0951231cce6aa2710bdb4f0ff8a963596f842c (diff)
downloadtracifyjs-3ca902258c24209699f0b5bd5b9654252e492272.tar.gz
tracifyjs-3ca902258c24209699f0b5bd5b9654252e492272.zip
fix bugs with getter/setter (#1926)
- `reduce_vars` - `side_effects` - property access for object - `AST_SymbolAccessor` as key names enhance `test/ufuzz.js` - add object getter & setter - property assignment to setter - avoid infinite recursion in setter - fix & adjust assignment operators - 50% `=` - 25% `+=` - 2.5% each for the rest - avoid "Invalid array length" - fix `console.log()` - bypass getter - curb recursive reference - deprecate `-E`, always report runtime errors
Diffstat (limited to 'lib')
-rw-r--r--lib/ast.js4
-rw-r--r--lib/compress.js49
-rw-r--r--lib/parse.js9
-rw-r--r--lib/scope.js5
4 files changed, 40 insertions, 27 deletions
diff --git a/lib/ast.js b/lib/ast.js
index 57956233..2972b7aa 100644
--- a/lib/ast.js
+++ b/lib/ast.js
@@ -685,8 +685,8 @@ var AST_Object = DEFNODE("Object", "properties", {
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
$documentation: "Base class for literal object properties",
$propdoc: {
- key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.",
- value: "[AST_Node] property value. For setters and getters this is an AST_Function."
+ key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an AST_SymbolAccessor.",
+ value: "[AST_Node] property value. For setters and getters this is an AST_Accessor."
},
_walk: function(visitor) {
return visitor._visit(this, function(){
diff --git a/lib/compress.js b/lib/compress.js
index 892bceef..f168b942 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -368,6 +368,13 @@ merge(Compressor.prototype, {
pop();
return true;
}
+ if (node instanceof AST_Accessor) {
+ var save_ids = safe_ids;
+ safe_ids = Object.create(null);
+ descend();
+ safe_ids = save_ids;
+ return true;
+ }
if (node instanceof AST_Binary
&& (node.operator == "&&" || node.operator == "||")) {
node.left.walk(tw);
@@ -1220,12 +1227,12 @@ merge(Compressor.prototype, {
&& !node.expression.has_side_effects(compressor);
}
- // may_eq_null()
- // returns true if this node may evaluate to null or undefined
+ // may_throw_on_access()
+ // returns true if this node may be null, undefined or contain `AST_Accessor`
(function(def) {
- AST_Node.DEFMETHOD("may_eq_null", function(compressor) {
+ AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
var pure_getters = compressor.option("pure_getters");
- return !pure_getters || this._eq_null(pure_getters);
+ return !pure_getters || this._throw_on_access(pure_getters);
});
function is_strict(pure_getters) {
@@ -1237,7 +1244,12 @@ merge(Compressor.prototype, {
def(AST_Undefined, return_true);
def(AST_Constant, return_false);
def(AST_Array, return_false);
- def(AST_Object, return_false);
+ def(AST_Object, function(pure_getters) {
+ if (!is_strict(pure_getters)) return false;
+ for (var i = this.properties.length; --i >=0;)
+ if (this.properties[i].value instanceof AST_Accessor) return true;
+ return false;
+ });
def(AST_Function, return_false);
def(AST_UnaryPostfix, return_false);
def(AST_UnaryPrefix, function() {
@@ -1246,33 +1258,33 @@ merge(Compressor.prototype, {
def(AST_Binary, function(pure_getters) {
switch (this.operator) {
case "&&":
- return this.left._eq_null(pure_getters);
+ return this.left._throw_on_access(pure_getters);
case "||":
- return this.left._eq_null(pure_getters)
- && this.right._eq_null(pure_getters);
+ return this.left._throw_on_access(pure_getters)
+ && this.right._throw_on_access(pure_getters);
default:
return false;
}
})
def(AST_Assign, function(pure_getters) {
return this.operator == "="
- && this.right._eq_null(pure_getters);
+ && this.right._throw_on_access(pure_getters);
})
def(AST_Conditional, function(pure_getters) {
- return this.consequent._eq_null(pure_getters)
- || this.alternative._eq_null(pure_getters);
+ return this.consequent._throw_on_access(pure_getters)
+ || this.alternative._throw_on_access(pure_getters);
})
def(AST_Sequence, function(pure_getters) {
- return this.expressions[this.expressions.length - 1]._eq_null(pure_getters);
+ return this.expressions[this.expressions.length - 1]._throw_on_access(pure_getters);
});
def(AST_SymbolRef, function(pure_getters) {
if (this.is_undefined) return true;
if (!is_strict(pure_getters)) return false;
var fixed = this.fixed_value();
- return !fixed || fixed._eq_null(pure_getters);
+ return !fixed || fixed._throw_on_access(pure_getters);
});
})(function(node, func) {
- node.DEFMETHOD("_eq_null", func);
+ node.DEFMETHOD("_throw_on_access", func);
});
/* -----[ boolean/negation helpers ]----- */
@@ -1813,11 +1825,11 @@ merge(Compressor.prototype, {
return any(this.elements, compressor);
});
def(AST_Dot, function(compressor){
- return this.expression.may_eq_null(compressor)
+ return this.expression.may_throw_on_access(compressor)
|| this.expression.has_side_effects(compressor);
});
def(AST_Sub, function(compressor){
- return this.expression.may_eq_null(compressor)
+ return this.expression.may_throw_on_access(compressor)
|| this.expression.has_side_effects(compressor)
|| this.property.has_side_effects(compressor);
});
@@ -2370,6 +2382,7 @@ merge(Compressor.prototype, {
var args = trim(this.args, compressor, first_in_statement);
return args && make_sequence(this, args);
});
+ def(AST_Accessor, return_null);
def(AST_Function, return_null);
def(AST_Binary, function(compressor, first_in_statement){
var right = this.right.drop_side_effect_free(compressor);
@@ -2437,11 +2450,11 @@ merge(Compressor.prototype, {
return values && make_sequence(this, values);
});
def(AST_Dot, function(compressor, first_in_statement){
- if (this.expression.may_eq_null(compressor)) return this;
+ if (this.expression.may_throw_on_access(compressor)) return this;
return this.expression.drop_side_effect_free(compressor, first_in_statement);
});
def(AST_Sub, function(compressor, first_in_statement){
- if (this.expression.may_eq_null(compressor)) return this;
+ if (this.expression.may_throw_on_access(compressor)) return this;
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
var property = this.property.drop_side_effect_free(compressor);
diff --git a/lib/parse.js b/lib/parse.js
index c432ad7a..f1089501 100644
--- a/lib/parse.js
+++ b/lib/parse.js
@@ -1310,10 +1310,15 @@ function parse($TEXT, options) {
var type = start.type;
var name = as_property_name();
if (type == "name" && !is("punc", ":")) {
+ var key = new AST_SymbolAccessor({
+ start: S.token,
+ name: as_property_name(),
+ end: prev()
+ });
if (name == "get") {
a.push(new AST_ObjectGetter({
start : start,
- key : as_atom_node(),
+ key : key,
value : create_accessor(),
end : prev()
}));
@@ -1322,7 +1327,7 @@ function parse($TEXT, options) {
if (name == "set") {
a.push(new AST_ObjectSetter({
start : start,
- key : as_atom_node(),
+ key : key,
value : create_accessor(),
end : prev()
}));
diff --git a/lib/scope.js b/lib/scope.js
index ea08d775..14ffb46f 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -360,11 +360,6 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options){
return this.definition().unmangleable(options);
});
-// property accessors are not mangleable
-AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){
- return true;
-});
-
// labels are always mangleable
AST_Label.DEFMETHOD("unmangleable", function(){
return false;