aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDan Wolff <dan.d.wolff@gmail.com>2013-09-19 10:58:50 +0200
committerMihai Bazon <mihai@bazon.net>2013-09-19 13:03:03 +0300
commit8d14efe818d9a33821a6acc26b612aaf1fd6e967 (patch)
tree605f3381dd15398f63e0426d46bba915934be1be /lib
parent83ba338bd0e59267080c37bd235e1b0a601edf36 (diff)
downloadtracifyjs-8d14efe818d9a33821a6acc26b612aaf1fd6e967.tar.gz
tracifyjs-8d14efe818d9a33821a6acc26b612aaf1fd6e967.zip
Concatenate strings also on the right-hand side of an expression that cannot be evaluated. Fix #126
E.g. converts: a+'Hello'+'World' to a+'HelloWorld'
Diffstat (limited to 'lib')
-rw-r--r--lib/compress.js99
1 files changed, 59 insertions, 40 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 0d2053e7..8bd58bb1 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -636,7 +636,8 @@ merge(Compressor.prototype, {
AST_Node.DEFMETHOD("evaluate", function(compressor){
if (!compressor.option("evaluate")) return [ this ];
try {
- var val = this._eval(), ast = make_node_from_constant(compressor, val, this);
+ var val = this._eval(compressor);
+ var ast = val instanceof AST_Binary ? val : make_node_from_constant(compressor, val, this);
return [ best_of(ast, this), val ];
} catch(ex) {
if (ex !== def) throw ex;
@@ -653,8 +654,8 @@ merge(Compressor.prototype, {
// places too. :-( Wish JS had multiple inheritance.
throw def;
});
- function ev(node) {
- return node._eval();
+ function ev(node, compressor) {
+ return node._eval(compressor);
};
def(AST_Node, function(){
throw def; // not constant
@@ -662,69 +663,87 @@ merge(Compressor.prototype, {
def(AST_Constant, function(){
return this.getValue();
});
- def(AST_UnaryPrefix, function(){
+ def(AST_UnaryPrefix, function(compressor){
var e = this.expression;
switch (this.operator) {
- case "!": return !ev(e);
+ case "!": return !ev(e, compressor);
case "typeof":
// Function would be evaluated to an array and so typeof would
// incorrectly return 'object'. Hence making is a special case.
if (e instanceof AST_Function) return typeof function(){};
- e = ev(e);
+ e = ev(e, compressor);
// typeof <RegExp> returns "object" or "function" on different platforms
// so cannot evaluate reliably
if (e instanceof RegExp) throw def;
return typeof e;
- case "void": return void ev(e);
- case "~": return ~ev(e);
+ case "void": return void ev(e, compressor);
+ case "~": return ~ev(e, compressor);
case "-":
- e = ev(e);
+ e = ev(e, compressor);
if (e === 0) throw def;
return -e;
- case "+": return +ev(e);
+ case "+": return +ev(e, compressor);
}
throw def;
});
- def(AST_Binary, function(){
+ def(AST_Binary, function(c){
var left = this.left, right = this.right;
switch (this.operator) {
- case "&&" : return ev(left) && ev(right);
- case "||" : return ev(left) || ev(right);
- case "|" : return ev(left) | ev(right);
- case "&" : return ev(left) & ev(right);
- case "^" : return ev(left) ^ ev(right);
- case "+" : return ev(left) + ev(right);
- case "*" : return ev(left) * ev(right);
- case "/" : return ev(left) / ev(right);
- case "%" : return ev(left) % ev(right);
- case "-" : return ev(left) - ev(right);
- case "<<" : return ev(left) << ev(right);
- case ">>" : return ev(left) >> ev(right);
- case ">>>" : return ev(left) >>> ev(right);
- case "==" : return ev(left) == ev(right);
- case "===" : return ev(left) === ev(right);
- case "!=" : return ev(left) != ev(right);
- case "!==" : return ev(left) !== ev(right);
- case "<" : return ev(left) < ev(right);
- case "<=" : return ev(left) <= ev(right);
- case ">" : return ev(left) > ev(right);
- case ">=" : return ev(left) >= ev(right);
- case "in" : return ev(left) in ev(right);
- case "instanceof" : return ev(left) instanceof ev(right);
+ case "&&" : return ev(left, c) && ev(right, c);
+ case "||" : return ev(left, c) || ev(right, c);
+ case "|" : return ev(left, c) | ev(right, c);
+ case "&" : return ev(left, c) & ev(right, c);
+ case "^" : return ev(left, c) ^ ev(right, c);
+ case "+" :
+ // handle concatenating strings even if the left part cannot
+ // be evaluated, e.g. (variable + "str") + "str"
+ if (!(c instanceof Compressor)) {
+ throw new Error("Compressor must be passed!!");
+ }
+ if (left instanceof AST_Binary && left.operator == "+" && left.is_string(c)) {
+ return make_node(AST_Binary, this, {
+ operator: "+",
+ left: left.left,
+ right: make_node(AST_String, null, {
+ value : "" + ev(left.right, c) + ev(right, c),
+ start : left.right.start,
+ end : right.end
+ })
+ });
+ } else {
+ return ev(left, c) + ev(right, c);
+ }
+ case "*" : return ev(left, c) * ev(right, c);
+ case "/" : return ev(left, c) / ev(right, c);
+ case "%" : return ev(left, c) % ev(right, c);
+ case "-" : return ev(left, c) - ev(right, c);
+ case "<<" : return ev(left, c) << ev(right, c);
+ case ">>" : return ev(left, c) >> ev(right, c);
+ case ">>>" : return ev(left, c) >>> ev(right, c);
+ case "==" : return ev(left, c) == ev(right, c);
+ case "===" : return ev(left, c) === ev(right, c);
+ case "!=" : return ev(left, c) != ev(right, c);
+ case "!==" : return ev(left, c) !== ev(right, c);
+ case "<" : return ev(left, c) < ev(right, c);
+ case "<=" : return ev(left, c) <= ev(right, c);
+ case ">" : return ev(left, c) > ev(right, c);
+ case ">=" : return ev(left, c) >= ev(right, c);
+ case "in" : return ev(left, c) in ev(right, c);
+ case "instanceof" : return ev(left, c) instanceof ev(right, c);
}
throw def;
});
- def(AST_Conditional, function(){
- return ev(this.condition)
- ? ev(this.consequent)
- : ev(this.alternative);
+ def(AST_Conditional, function(compressor){
+ return ev(this.condition, compressor)
+ ? ev(this.consequent, compressor)
+ : ev(this.alternative, compressor);
});
- def(AST_SymbolRef, function(){
+ def(AST_SymbolRef, function(compressor){
var d = this.definition();
- if (d && d.constant && d.init) return ev(d.init);
+ if (d && d.constant && d.init) return ev(d.init, compressor);
throw def;
});
})(function(node, func){