Skip to content

Commit

Permalink
JS: revert the reversal of <,<=, fixes #462
Browse files Browse the repository at this point in the history
  • Loading branch information
tdewolff committed Jan 25, 2022
1 parent f322d2d commit 154d2f7
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 54 deletions.
20 changes: 6 additions & 14 deletions js/js.go
Original file line number Diff line number Diff line change
Expand Up @@ -924,20 +924,12 @@ func (m *jsMinifier) minifyExpr(i js.IExpr, prec js.OpPrec) {
m.write(closeParenBytes)
}
} else {
if expr.Op == js.LtToken {
// switch < for > (GZIP improvement)
expr.Op = js.GtToken
expr.X, expr.Y = expr.Y, expr.X
} else if expr.Op == js.LtEqToken {
// switch <= for >= (GZIP improvement)
expr.Op = js.GtEqToken
expr.X, expr.Y = expr.Y, expr.X
} else if expr.Op == js.EqEqToken || expr.Op == js.NotEqToken || expr.Op == js.EqEqEqToken || expr.Op == js.NotEqEqToken {
// switch a==const for const==a, such as typeof a=="undefined" for "undefined"==typeof a (GZIP improvement)
if _, ok := expr.Y.(*js.LiteralExpr); ok {
expr.X, expr.Y = expr.Y, expr.X
}
}
//if expr.Op == js.EqEqToken || expr.Op == js.NotEqToken || expr.Op == js.EqEqEqToken || expr.Op == js.NotEqEqToken {
// // switch a==const for const==a, such as typeof a=="undefined" for "undefined"==typeof a (GZIP improvement)
// if _, ok := expr.Y.(*js.LiteralExpr); ok {
// expr.X, expr.Y = expr.Y, expr.X
// }
//}

m.minifyExpr(expr.X, precLeft)
// 0 < len(m.prev) always
Expand Down
54 changes: 27 additions & 27 deletions js/js_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ func TestJS(t *testing.T) {
{`a - ++b`, `a-++b`},
{`a-- > b`, `a-- >b`},
{`(a--) > b`, `a-- >b`},
{`a-- < b`, `b>a--`},
{`a < !--b`, `!--b>a`},
{`a-- < b`, `a--<b`},
{`a < !--b`, `a<! --b`},
{`a > !--b`, `a>!--b`},
{`!--b`, `!--b`},
{`/a/ + b`, `/a/+b`},
Expand Down Expand Up @@ -104,8 +104,8 @@ func TestJS(t *testing.T) {
{`class a extends(!b){}`, `class a extends(!b){}`},
{`class a { f(a) {a} }`, `class a{f(a){a}}`},
{`class a { f(a) {a}; static g(b) {b} }`, `class a{f(a){a}static g(b){b}}`},
{`for (var a = 5; a < 10; a++){a}`, `for(var a=5;10>a;a++)a`},
{`for (a,b = 5; a < 10; a++){a}`, `for(a,b=5;10>a;a++)a`},
{`for (var a = 5; a < 10; a++){a}`, `for(var a=5;a<10;a++)a`},
{`for (a,b = 5; a < 10; a++){a}`, `for(a,b=5;a<10;a++)a`},
{`async function f(){for await (var a of b){a}}`, `async function f(){for await(var a of b)a}`},
{`for (var a in b){a}`, `for(var a in b)a`},
{`for (a in b){a}`, `for(a in b)a`},
Expand All @@ -114,12 +114,12 @@ func TestJS(t *testing.T) {
{`for (;;){let a;a}`, `for(;;){let a;a}`},
{`var a;for(var b;;){let a;a++}a,b`, `for(var a,b;;){let a;a++}a,b`},
{`var a;for(var b;;){let c = 10;c++}a,b`, `for(var a,b;;){let c=10;c++}a,b`},
{`while(a < 10){a}`, `for(;10>a;)a`},
{`while(a < 10){a;b}`, `for(;10>a;)a,b`},
{`while(a < 10){while(b);c}`, `for(;10>a;){for(;b;);c}`},
{`do {a} while(a < 10)`, `do a;while(10>a)`},
{`do [a]=5; while(a < 10)`, `do[a]=5;while(10>a)`},
{`do [a]=5; while(a < 10);return a`, `do[a]=5;while(10>a)return a`},
{`while(a < 10){a}`, `for(;a<10;)a`},
{`while(a < 10){a;b}`, `for(;a<10;)a,b`},
{`while(a < 10){while(b);c}`, `for(;a<10;){for(;b;);c}`},
{`do {a} while(a < 10)`, `do a;while(a<10)`},
{`do [a]=5; while(a < 10)`, `do[a]=5;while(a<10)`},
{`do [a]=5; while(a < 10);return a`, `do[a]=5;while(a<10)return a`},
{`throw a`, `throw a`},
{`throw [a]`, `throw[a]`},
{`try {a} catch {b}`, `try{a}catch{b}`},
Expand Down Expand Up @@ -547,8 +547,8 @@ func TestJS(t *testing.T) {
{`a!==b?false:5`, `a===b&&5`},
{`a==b?5:true`, `a!=b||5`},
{`a==b?5:false`, `a==b&&5`},
{`a<b?5:true`, `!(b>a)||5`},
{`!(a<b)?5:true`, `b>a||5`},
{`a<b?5:true`, `!(a<b)||5`},
{`!(a<b)?5:true`, `a<b||5`},
{`!true?5:true`, `!0`},
{`true?a:b`, `a`},
{`false?a:b`, `b`},
Expand All @@ -567,8 +567,8 @@ func TestJS(t *testing.T) {
{`!42`, `!1`},
{`!"str"`, `!1`},
{`!/regexp/`, `!1`},
{`typeof a==='object'`, `"object"==typeof a`},
{`typeof a!=='object'`, `"object"!=typeof a`},
{`typeof a==='object'`, `typeof a=="object"`},
{`typeof a!=='object'`, `typeof a!="object"`},
{`'object'===typeof a`, `"object"==typeof a`},
{`'object'!==typeof a`, `"object"!=typeof a`},
{`typeof a===b`, `typeof a===b`},
Expand All @@ -586,8 +586,8 @@ func TestJS(t *testing.T) {
{`a&&=b`, `a&&=b`},
{`a||=b`, `a||=b`},
{`a??=b`, `a??=b`},
{`a==false`, `!1==a`},
{`a===false`, `!1===a`},
{`a==false`, `a==!1`},
{`a===false`, `a===!1`},

// other
{`async function g(){await x+y}`, `async function g(){await x+y}`},
Expand Down Expand Up @@ -678,14 +678,14 @@ func TestJS(t *testing.T) {
{`1.5.a`, `1.5.a`},
{`1e4.a`, `1e4.a`},
{`t0.a`, `t0.a`},
{`for(;a < !--script;);`, `for(;!--script>a;);`},
{`for(;a < /script>/;);`, `for(;/script>/>a;);`},
{`for(;a < !--script;);`, `for(;a<! --script;);`},
{`for(;a < /script>/;);`, `for(;a< /script>/;);`},
{`a<<!--script`, `a<<! --script`},
{`a<</script>/`, `a<< /script>/`},
{`function f(a,b){a();for(const c of b){const b=0}}`, `function f(a,b){a();for(const c of b){const b=0}}`},
{`return a,b,void 0`, `return a,b`},
{`a<b`, `b>a`},
{`a<=b`, `b>=a`},
//{`var arr=[];var slice=arr.slice;var concat=arr.concat;var push=arr.push;var indexOf=arr.indexOf;var class2type={};`, `var arr=[],slice=arr.slice,concat=arr.concat,push=arr.push,indexOf=arr.indexOf,class2type={}`},
//{`var arr=[];var class2type={};a=5;var rlocalProtocol=0`, `var arr=[],class2type={};a=5;var rlocalProtocol=0`},

// bugs
{`({"":a})`, `({"":a})`}, // go-fuzz
Expand Down Expand Up @@ -769,13 +769,13 @@ func TestJSVarRenaming(t *testing.T) {
`name=function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,_,$,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an,ao,ap,aq,ar,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aI,aJ,aK,aL,aM,aN,aO,aP,aQ,aR,aS,aT,aU,aV,aW,aX,aY,aZ,a_,a$,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,ba,bb;a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,_,$,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an,ao,ap,aq,ar,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aI,aJ,aK,aL,aM,aN,aO,aP,aQ,aR,aS,aT,aU,aV,aW,aX,aY,aZ,a_,a$,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,ba,bb}`}, // 'as' is a keyword
{`a=>{for(let b of c){b,a;{var d}}}`, `a=>{for(let d of c){d,a;var b}}`}, // #334
//{`({x,y,z})=>x+y+z`, `({x,y,z})=>x+y+z`},
{`function f(a){let b=0;if(a===0){return 0}else{let b=3;return b}}`, `function f(a){let c=0;if(0===a)return 0;let b=3;return b}`}, // #405
{`!function(a){let b=0;if(a===0){return 0}else{let b=3;return b}}`, `!function(a){let c=0;if(0===a)return 0;let b=3;return b}`}, // #405
{`a=>{let b=0;if(a===0){return 0}else{let b=3;return b}}`, `a=>{let c=0;if(0===a)return 0;let b=3;return b}`}, // #405
{`{let b=0;if(a===0){return 0}else{let b=3;return b}}`, `{let c=0;if(0===a)return 0;let b=3;return b}`}, // #405
{`class x{f(a){let b=0;if(a===0){return 0}else{let b=3;return b}}}`, `class x{f(a){let c=0;if(0===a)return 0;let b=3;return b}}`}, // #405
{`for(;;){let b=0;if(a===0){return 0}else{let b=3;return b}}`, `for(;;){let c=0;if(0===a)return 0;let b=3;return b}`}, // #405
{`try{let b=0;if(a===0){return 0}else{let b=3;return b}}catch{}`, `try{let c=0;if(0===a)return 0;let b=3;return b}catch{}`}, // #405
{`function f(a){let b=0;if(a===0){return 0}else{let b=3;return b}}`, `function f(a){let c=0;if(a===0)return 0;let b=3;return b}`}, // #405
{`!function(a){let b=0;if(a===0){return 0}else{let b=3;return b}}`, `!function(a){let c=0;if(a===0)return 0;let b=3;return b}`}, // #405
{`a=>{let b=0;if(a===0){return 0}else{let b=3;return b}}`, `a=>{let c=0;if(a===0)return 0;let b=3;return b}`}, // #405
{`{let b=0;if(a===0){return 0}else{let b=3;return b}}`, `{let c=0;if(a===0)return 0;let b=3;return b}`}, // #405
{`class x{f(a){let b=0;if(a===0){return 0}else{let b=3;return b}}}`, `class x{f(a){let c=0;if(a===0)return 0;let b=3;return b}}`}, // #405
{`for(;;){let b=0;if(a===0){return 0}else{let b=3;return b}}`, `for(;;){let c=0;if(a===0)return 0;let b=3;return b}`}, // #405
{`try{let b=0;if(a===0){return 0}else{let b=3;return b}}catch{}`, `try{let c=0;if(a===0)return 0;let b=3;return b}catch{}`}, // #405
{`let a=0;switch(a){case 0:let b=1;case 1:let c=2}`, `let a=0;switch(a){case 0:let a=1;case 1:let b=2}`},
{`({a:b=1}={})=>b`, `({a=1}={})=>a`}, // #422
{`()=>{var a;if(x){const b=0;while(true);}}`, `()=>{if(x){const b=0;for(var a;!0;);}}`},
Expand Down
19 changes: 11 additions & 8 deletions js/stmtlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,14 +171,24 @@ func (m *jsMinifier) optimizeStmtList(list []js.IStmt, blockType blockType) []js
} else if ifStmt, ok := list[i].(*js.IfStmt); ok {
ifStmt.Cond = commaExpr(left.Value, ifStmt.Cond)
j--
} else if varDecl, ok := list[i].(*js.VarDecl); ok {
if merge := mergeVarDeclExprStmt(varDecl, left, true); merge {
j--
}
}
} else if left, ok := list[i-1].(*js.VarDecl); ok {
if right, ok := list[i].(*js.VarDecl); ok && left.TokenType == right.TokenType {
// merge const and let declarations
right.List = append(left.List, right.List...)
j--
} else if left.TokenType == js.VarToken {
if forStmt, ok := list[i].(*js.ForStmt); ok {
if exprStmt, ok := list[i].(*js.ExprStmt); ok {
// pull in assignments to variables into the declaration, e.g. var a;a=5 => var a=5
if merge := mergeVarDeclExprStmt(left, exprStmt, false); merge {
list[i] = list[i-1]
j--
}
} else if forStmt, ok := list[i].(*js.ForStmt); ok {
// TODO: only merge statements that don't have 'in' or 'of' keywords (slow to check?)
if forStmt.Init == nil {
forStmt.Init = left
Expand Down Expand Up @@ -206,13 +216,6 @@ func (m *jsMinifier) optimizeStmtList(list []js.IStmt, blockType blockType) []js
}
list[i] = &js.ForStmt{Init: left, Cond: whileStmt.Cond, Post: nil, Body: body}
j--
} else if exprStmt, ok := list[i].(*js.ExprStmt); ok {
// pull in assignments to variables into the declaration, e.g. var a;a=5 => var a=5
merge := mergeVarDeclExprStmt(left, exprStmt)
if merge {
list[i] = list[i-1]
j--
}
}
}
}
Expand Down
18 changes: 13 additions & 5 deletions js/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,16 +246,20 @@ func mergeVarDecls(dst, src *js.VarDecl) bool {
return merge
}

func mergeVarDeclExprStmt(decl *js.VarDecl, exprStmt *js.ExprStmt) bool {
func mergeVarDeclExprStmt(decl *js.VarDecl, exprStmt *js.ExprStmt, swapped bool) bool {
if src, ok := exprStmt.Value.(*js.VarDecl); ok {
// this happens when a variable declarations is converted to an expression
return mergeVarDecls(decl, src)
} else if commaExpr, ok := exprStmt.Value.(*js.CommaExpr); ok {
n := 0
for _, item := range commaExpr.List {
for i := 0; i < len(commaExpr.List); i++ {
item := commaExpr.List[i]
if swapped {
item = commaExpr.List[len(commaExpr.List)-i-1]
}
if binaryExpr, ok := item.(*js.BinaryExpr); ok && binaryExpr.Op == js.EqToken {
if v, ok := binaryExpr.X.(*js.Var); ok && v.Decl == js.VariableDecl {
if addDefinition(decl, v, binaryExpr.Y, false) {
if addDefinition(decl, v, binaryExpr.Y, swapped) {
n++
continue
}
Expand All @@ -264,11 +268,15 @@ func mergeVarDeclExprStmt(decl *js.VarDecl, exprStmt *js.ExprStmt) bool {
break
}
merge := n == len(commaExpr.List)
commaExpr.List = commaExpr.List[n:]
if !swapped {
commaExpr.List = commaExpr.List[n:]
} else {
commaExpr.List = commaExpr.List[:len(commaExpr.List)-n]
}
return merge
} else if binaryExpr, ok := exprStmt.Value.(*js.BinaryExpr); ok && binaryExpr.Op == js.EqToken {
if v, ok := binaryExpr.X.(*js.Var); ok && v.Decl == js.VariableDecl {
if addDefinition(decl, v, binaryExpr.Y, false) {
if addDefinition(decl, v, binaryExpr.Y, swapped) {
return true
}
}
Expand Down

0 comments on commit 154d2f7

Please sign in to comment.