forked from openrs2/openrs2
parent
9b81c813dd
commit
53160e422d
@ -1,158 +0,0 @@ |
||||
package dev.openrs2.deob.ast.transform; |
||||
|
||||
import com.github.javaparser.ast.CompilationUnit; |
||||
import com.github.javaparser.ast.Node; |
||||
import com.github.javaparser.ast.stmt.BlockStmt; |
||||
import com.github.javaparser.ast.stmt.IfStmt; |
||||
import com.github.javaparser.ast.stmt.Statement; |
||||
import dev.openrs2.deob.ast.util.ExprUtils; |
||||
import dev.openrs2.deob.ast.util.NodeUtils; |
||||
|
||||
public final class IfElseTransformer extends Transformer { |
||||
private static boolean isIf(Statement stmt) { |
||||
if (stmt.isIfStmt()) { |
||||
return true; |
||||
} else if (stmt.isBlockStmt()) { |
||||
var stmts = stmt.asBlockStmt().getStatements(); |
||||
return stmts.size() == 1 && stmts.get(0).isIfStmt(); |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static Statement getIf(Statement stmt) { |
||||
if (stmt.isIfStmt()) { |
||||
return stmt.clone(); |
||||
} else if (stmt.isBlockStmt()) { |
||||
var stmts = stmt.asBlockStmt().getStatements(); |
||||
if (stmts.size() == 1) { |
||||
Statement head = stmts.get(0); |
||||
if (head.isIfStmt()) { |
||||
return head.clone(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException(); |
||||
} |
||||
|
||||
private static boolean isTailThrowOrReturn(Statement stmt) { |
||||
if (stmt.isThrowStmt() || stmt.isReturnStmt()) { |
||||
return true; |
||||
} else if (stmt.isBlockStmt()) { |
||||
var stmts = stmt.asBlockStmt().getStatements(); |
||||
if (stmts.isEmpty()) { |
||||
return false; |
||||
} |
||||
|
||||
var tail = stmts.get(stmts.size() - 1); |
||||
return tail.isThrowStmt() || tail.isReturnStmt(); |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void transform(CompilationUnit unit) { |
||||
NodeUtils.walk(unit, Node.TreeTraversal.POSTORDER, IfStmt.class, stmt -> { |
||||
stmt.getElseStmt().ifPresent(elseStmt -> { |
||||
var condition = stmt.getCondition(); |
||||
var thenStmt = stmt.getThenStmt(); |
||||
if (isIf(thenStmt) && !isIf(elseStmt)) { |
||||
stmt.setCondition(ExprUtils.not(condition)); |
||||
stmt.setThenStmt(elseStmt.clone()); |
||||
stmt.setElseStmt(thenStmt.clone()); |
||||
} else if (!isIf(thenStmt) && isIf(elseStmt)) { |
||||
/* |
||||
* Don't consider any more conditions for swapping the |
||||
* if/else branches, as it'll introduce another level of |
||||
* indentation. |
||||
*/ |
||||
return; |
||||
} |
||||
|
||||
/* Prefer fewer NOTs in the if condition. */ |
||||
var notCondition = ExprUtils.not(condition); |
||||
if (ExprUtils.countNots(notCondition) < ExprUtils.countNots(condition)) { |
||||
stmt.setCondition(notCondition); |
||||
if (elseStmt.isIfStmt()) { |
||||
var block = new BlockStmt(); |
||||
block.getStatements().add(elseStmt.clone()); |
||||
stmt.setThenStmt(block); |
||||
} else { |
||||
stmt.setThenStmt(elseStmt.clone()); |
||||
} |
||||
stmt.setElseStmt(thenStmt.clone()); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
NodeUtils.walk(unit, Node.TreeTraversal.POSTORDER, IfStmt.class, stmt -> { |
||||
stmt.getElseStmt().ifPresent(elseStmt -> { |
||||
if (isIf(elseStmt)) { |
||||
stmt.setElseStmt(getIf(elseStmt)); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
/* |
||||
* Rewrite: |
||||
* |
||||
* ... |
||||
* } else { |
||||
* if (x != 123) { |
||||
* ... |
||||
* throw ...; |
||||
* } |
||||
* ... |
||||
* } |
||||
* |
||||
* to: |
||||
* |
||||
* ... |
||||
* } else if (x == 123) { |
||||
* ... |
||||
* } else { |
||||
* ... |
||||
* throw ...; |
||||
* } |
||||
*/ |
||||
NodeUtils.walk(unit, Node.TreeTraversal.POSTORDER, IfStmt.class, stmt -> { |
||||
stmt.getElseStmt().ifPresent(elseStmt -> { |
||||
/* match */ |
||||
if (!elseStmt.isBlockStmt()) { |
||||
return; |
||||
} |
||||
|
||||
var blockStmt = elseStmt.asBlockStmt(); |
||||
var statements = blockStmt.getStatements(); |
||||
if (statements.isEmpty()) { |
||||
return; |
||||
} |
||||
|
||||
var head = statements.get(0); |
||||
if (!head.isIfStmt()) { |
||||
return; |
||||
} |
||||
|
||||
var ifStmt = head.asIfStmt(); |
||||
if (ifStmt.getElseStmt().isPresent()) { |
||||
return; |
||||
} |
||||
|
||||
var thenStmt = ifStmt.getThenStmt(); |
||||
if (!isTailThrowOrReturn(thenStmt)) { |
||||
return; |
||||
} |
||||
|
||||
/* rewrite */ |
||||
var condition = ExprUtils.not(ifStmt.getCondition()); |
||||
|
||||
var tail = blockStmt.clone(); |
||||
tail.getStatements().remove(0); |
||||
|
||||
elseStmt.replace(new IfStmt(condition, tail, thenStmt.clone())); |
||||
}); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,158 @@ |
||||
package dev.openrs2.deob.ast.transform |
||||
|
||||
import com.github.javaparser.ast.CompilationUnit |
||||
import com.github.javaparser.ast.Node |
||||
import com.github.javaparser.ast.stmt.BlockStmt |
||||
import com.github.javaparser.ast.stmt.IfStmt |
||||
import com.github.javaparser.ast.stmt.Statement |
||||
import dev.openrs2.deob.ast.util.ExprUtils |
||||
import dev.openrs2.deob.ast.util.NodeUtils |
||||
|
||||
class IfElseTransformer : Transformer() { |
||||
override fun transform(unit: CompilationUnit) { |
||||
NodeUtils.walk(unit, Node.TreeTraversal.POSTORDER, IfStmt::class.java) { stmt -> |
||||
stmt.elseStmt.ifPresent { elseStmt: Statement -> |
||||
val condition = stmt.condition |
||||
val thenStmt = stmt.thenStmt |
||||
if (isIf(thenStmt) && !isIf(elseStmt)) { |
||||
stmt.condition = ExprUtils.not(condition) |
||||
stmt.thenStmt = elseStmt.clone() |
||||
stmt.setElseStmt(thenStmt.clone()) |
||||
} else if (!isIf(thenStmt) && isIf(elseStmt)) { |
||||
/* |
||||
* Don't consider any more conditions for swapping the |
||||
* if/else branches, as it'll introduce another level of |
||||
* indentation. |
||||
*/ |
||||
return@ifPresent |
||||
} |
||||
|
||||
// Prefer fewer NOTs in the if condition |
||||
val notCondition = ExprUtils.not(condition) |
||||
if (ExprUtils.countNots(notCondition) < ExprUtils.countNots(condition)) { |
||||
stmt.condition = notCondition |
||||
if (elseStmt.isIfStmt) { |
||||
val block = BlockStmt() |
||||
block.statements.add(elseStmt.clone()) |
||||
stmt.thenStmt = block |
||||
} else { |
||||
stmt.thenStmt = elseStmt.clone() |
||||
} |
||||
stmt.setElseStmt(thenStmt.clone()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
NodeUtils.walk(unit, Node.TreeTraversal.POSTORDER, IfStmt::class.java) { stmt -> |
||||
stmt.elseStmt.ifPresent { elseStmt -> |
||||
if (isIf(elseStmt)) { |
||||
stmt.setElseStmt(getIf(elseStmt)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Rewrite: |
||||
* |
||||
* ... |
||||
* } else { |
||||
* if (x != 123) { |
||||
* ... |
||||
* throw ...; |
||||
* } |
||||
* ... |
||||
* } |
||||
* |
||||
* to: |
||||
* |
||||
* ... |
||||
* } else if (x == 123) { |
||||
* ... |
||||
* } else { |
||||
* ... |
||||
* throw ...; |
||||
* } |
||||
*/ |
||||
NodeUtils.walk(unit, Node.TreeTraversal.POSTORDER, IfStmt::class.java) { stmt -> |
||||
stmt.elseStmt.ifPresent { elseStmt -> |
||||
// match |
||||
if (!elseStmt.isBlockStmt) { |
||||
return@ifPresent |
||||
} |
||||
|
||||
val blockStmt = elseStmt.asBlockStmt() |
||||
val statements = blockStmt.statements |
||||
if (statements.isEmpty()) { |
||||
return@ifPresent |
||||
} |
||||
|
||||
val head = statements[0] |
||||
if (!head.isIfStmt) { |
||||
return@ifPresent |
||||
} |
||||
|
||||
val ifStmt = head.asIfStmt() |
||||
if (ifStmt.elseStmt.isPresent) { |
||||
return@ifPresent |
||||
} |
||||
|
||||
val thenStmt = ifStmt.thenStmt |
||||
if (!isTailThrowOrReturn(thenStmt)) { |
||||
return@ifPresent |
||||
} |
||||
|
||||
// rewrite |
||||
val condition = ExprUtils.not(ifStmt.condition) |
||||
|
||||
val tail = blockStmt.clone() |
||||
tail.statements.removeAt(0) |
||||
|
||||
elseStmt.replace(IfStmt(condition, tail, thenStmt.clone())) |
||||
} |
||||
} |
||||
} |
||||
|
||||
companion object { |
||||
private fun isIf(stmt: Statement): Boolean { |
||||
return if (stmt.isIfStmt) { |
||||
true |
||||
} else if (stmt.isBlockStmt) { |
||||
val stmts = stmt.asBlockStmt().statements |
||||
stmts.size == 1 && stmts[0].isIfStmt |
||||
} else { |
||||
false |
||||
} |
||||
} |
||||
|
||||
private fun getIf(stmt: Statement): Statement { |
||||
if (stmt.isIfStmt) { |
||||
return stmt.clone() |
||||
} else if (stmt.isBlockStmt) { |
||||
val stmts = stmt.asBlockStmt().statements |
||||
if (stmts.size == 1) { |
||||
val head = stmts[0] |
||||
if (head.isIfStmt) { |
||||
return head.clone() |
||||
} |
||||
} |
||||
} |
||||
throw IllegalArgumentException() |
||||
} |
||||
|
||||
private fun isTailThrowOrReturn(stmt: Statement): Boolean { |
||||
return if (stmt.isThrowStmt || stmt.isReturnStmt) { |
||||
true |
||||
} else if (stmt.isBlockStmt) { |
||||
val stmts = stmt.asBlockStmt().statements |
||||
if (stmts.isEmpty()) { |
||||
return false |
||||
} |
||||
|
||||
val tail = stmts[stmts.size - 1] |
||||
tail.isThrowStmt || tail.isReturnStmt |
||||
} else { |
||||
false |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue