Open-source multiplayer game server compatible with the RuneScape client https://www.openrs2.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
openrs2/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/AddSubTransformer.kt

122 lines
4.4 KiB

package org.openrs2.deob.ast.transform
import com.github.javaparser.ast.CompilationUnit
import com.github.javaparser.ast.expr.BinaryExpr
import com.github.javaparser.ast.expr.Expression
import com.github.javaparser.ast.expr.IntegerLiteralExpr
import com.github.javaparser.ast.expr.LiteralExpr
import com.github.javaparser.ast.expr.LongLiteralExpr
import com.github.javaparser.ast.expr.UnaryExpr
import jakarta.inject.Singleton
import org.openrs2.deob.ast.Library
import org.openrs2.deob.ast.LibraryGroup
import org.openrs2.deob.ast.util.hasSideEffects
import org.openrs2.deob.ast.util.isString
import org.openrs2.deob.ast.util.negate
import org.openrs2.deob.ast.util.walk
@Singleton
public class AddSubTransformer : Transformer() {
override fun transformUnit(group: LibraryGroup, library: Library, unit: CompilationUnit) {
unit.walk { expr: BinaryExpr ->
val op = expr.operator
if (op != BinaryExpr.Operator.PLUS && op != BinaryExpr.Operator.MINUS) {
return@walk
}
val type = expr.calculateResolvedType()
if (type.isString()) {
return@walk
}
val terms = mutableListOf<Expression>()
addTerms(terms, expr, negate = false)
terms.sortWith(Comparator { a, b ->
// preserve the order of adjacent expressions with side effects
val aHasSideEffects = a.hasSideEffects()
val bHasSideEffects = b.hasSideEffects()
if (aHasSideEffects && bHasSideEffects) {
return@Comparator 0
}
// push negative expressions to the right so we can replace unary minus with binary minus
val aNegative = a.isNegative()
val bNegative = b.isNegative()
if (aNegative && !bNegative) {
return@Comparator 1
} else if (!aNegative && bNegative) {
return@Comparator -1
}
// push literals to the right
val aLiteral = a is LiteralExpr
val bLiteral = b is LiteralExpr
if (aLiteral && !bLiteral) {
return@Comparator 1
} else if (!aLiteral && bLiteral) {
return@Comparator -1
}
return@Comparator 0
})
val newExpr = terms.reduce { left, right ->
if (right.isNegative()) {
BinaryExpr(left.clone(), right.negate(), BinaryExpr.Operator.MINUS)
} else {
BinaryExpr(left.clone(), right.clone(), BinaryExpr.Operator.PLUS)
}
}
expr.replace(newExpr)
}
}
private fun addTerms(terms: MutableList<Expression>, expr: Expression, negate: Boolean) {
when {
expr is UnaryExpr -> when {
expr.operator == UnaryExpr.Operator.MINUS -> addTerms(terms, expr.expression, !negate)
negate -> terms += expr.negate()
else -> terms += expr
}
expr is BinaryExpr -> when {
expr.operator == BinaryExpr.Operator.PLUS -> {
addTerms(terms, expr.left, negate)
addTerms(terms, expr.right, negate)
}
expr.operator == BinaryExpr.Operator.MINUS -> {
addTerms(terms, expr.left, negate)
addTerms(terms, expr.right, !negate)
}
negate -> terms += expr.negate()
else -> terms += expr
}
negate -> terms += expr.negate()
else -> terms += expr
}
}
private fun Expression.isNegative(): Boolean {
return when (this) {
is UnaryExpr -> operator == UnaryExpr.Operator.MINUS
is IntegerLiteralExpr -> when (val n = asNumber()) {
IntegerLiteralExpr.MAX_31_BIT_UNSIGNED_VALUE_AS_LONG -> false
is Int -> n < 0
else -> error("Invalid IntegerLiteralExpr type")
}
is LongLiteralExpr -> when (val n = asNumber()) {
LongLiteralExpr.MAX_63_BIT_UNSIGNED_VALUE_AS_BIG_INTEGER -> false
is Long -> n < 0
else -> error("Invalid LongLiteralExpr type")
}
else -> false
}
}
}