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