Skip to content

Commit

Permalink
JS: better compression of if/else statements with return/throw
Browse files Browse the repository at this point in the history
  • Loading branch information
tdewolff committed Apr 5, 2022
1 parent a2eb81a commit 3ae425a
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 2 deletions.
1 change: 1 addition & 0 deletions js/js_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ func TestJS(t *testing.T) {
{`if(a,b)b;else d`, `a,b||d`},
{`if(a=b)a;else b`, `(a=b)||b`},
{`if(!a&&!b){return true}else if(!a||!b){return false}return c&&d`, `return!a&&!b||!(!a||!b)&&c&&d`},
{`if(!a){if(b){throw c}else{return c}}else{return a}`, `if(a)return a;if(b)throw c;return c`},

// var declarations
{`var a;var b;a,b`, `var a,b;a,b`},
Expand Down
7 changes: 6 additions & 1 deletion js/stmtlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,12 @@ func optimizeStmtList(list []js.IStmt, blockType blockType) []js.IStmt {
j := 0 // write index
for i := 0; i < len(list); i++ { // read index
if ifStmt, ok := list[i].(*js.IfStmt); ok && !isEmptyStmt(ifStmt.Else) && isFlowStmt(lastStmt(ifStmt.Body)) {
// if body ends in flow statement (return, throw, break, continue), so we can remove the else statement and put its body in the current scope
// if(!a)b;else c => if(a)c; else b
if unary, ok := ifStmt.Cond.(*js.UnaryExpr); ok && unary.Op == js.NotToken {
ifStmt.Cond = unary.X
ifStmt.Body, ifStmt.Else = ifStmt.Else, ifStmt.Body
}
// if body ends in flow statement (return, throw, break, continue), we can remove the else statement and put its body in the current scope
if blockStmt, ok := ifStmt.Else.(*js.BlockStmt); ok {
blockStmt.Scope.Unscope()
list = append(list[:i+1], append(blockStmt.List, list[i+1:]...)...)
Expand Down
10 changes: 9 additions & 1 deletion js/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,15 @@ func isFlowStmt(stmt js.IStmt) bool {

func lastStmt(stmt js.IStmt) js.IStmt {
if block, ok := stmt.(*js.BlockStmt); ok && 0 < len(block.List) {
return block.List[len(block.List)-1]
return lastStmt(block.List[len(block.List)-1])
} else if ifStmt, ok := stmt.(*js.IfStmt); ok {
if isEmptyStmt(ifStmt.Else) {
if block, ok := ifStmt.Else.(*js.BlockStmt); !ok || len(block.List) == 1 {
return lastStmt(ifStmt.Else)
}
} else if block, ok := ifStmt.Body.(*js.BlockStmt); !ok || len(block.List) == 1 {
return lastStmt(ifStmt.Body)
}
}
return stmt
}
Expand Down

0 comments on commit 3ae425a

Please sign in to comment.