aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/ftbsc/lll/tools/PatternMatcher.java
diff options
context:
space:
mode:
author zaaarf <me@zaaarf.foo>2024-01-24 17:16:50 +0100
committer zaaarf <me@zaaarf.foo>2024-01-24 17:16:50 +0100
commitd06b6211bc0815c36d44c65312c097058901b1c5 (patch)
tree1a942f8d9dfd08ff8f06c576f63ba0663ce051b0 /src/main/java/ftbsc/lll/tools/PatternMatcher.java
parent660730086dc6b8895eb871a3df98956041453983 (diff)
chore: internal reorganisation (breaking)0.5.0
Diffstat (limited to 'src/main/java/ftbsc/lll/tools/PatternMatcher.java')
-rw-r--r--src/main/java/ftbsc/lll/tools/PatternMatcher.java250
1 files changed, 0 insertions, 250 deletions
diff --git a/src/main/java/ftbsc/lll/tools/PatternMatcher.java b/src/main/java/ftbsc/lll/tools/PatternMatcher.java
deleted file mode 100644
index fff84db..0000000
--- a/src/main/java/ftbsc/lll/tools/PatternMatcher.java
+++ /dev/null
@@ -1,250 +0,0 @@
-package ftbsc.lll.tools;
-
-import ftbsc.lll.exceptions.PatternNotFoundException;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Predicate;
-
-/**
- * Describes a pattern to match on a list of ASM instructions.
- */
-public class PatternMatcher {
- /**
- * The list of predicates to match.
- */
- private final List<Predicate<AbstractInsnNode>> predicates;
-
- /**
- * Whether pattern search should be done from the end.
- */
- private final boolean reverse;
-
- /**
- * Patterns flagged with this ignore labels.
- */
- private final boolean ignoreLabels;
-
- /**
- * Patterns flagged with this ignore FRAME instructions.
- */
- private final boolean ignoreFrames;
-
- /**
- * Patterns flagged with this ignore LINENUMBER instructions.
- */
- private final boolean ignoreLineNumbers;
-
- /**
- * Private constructor because a PatternMatcher should only ever be initialized
- * through the builder.
- * @param predicates the list of predicates to match
- * @param reverse search direction
- * @param ignoreLabels whether LABEL instructions should be ignored
- * @param ignoreFrames whether FRAME instructions should be ignored
- * @param ignoreLineNumbers whether LINENUMBER instructions should be ignored
- */
- private PatternMatcher(List<Predicate<AbstractInsnNode>> predicates, boolean reverse,
- boolean ignoreLabels, boolean ignoreFrames, boolean ignoreLineNumbers) {
- this.predicates = predicates;
- this.reverse = reverse;
- this.ignoreLabels = ignoreLabels;
- this.ignoreFrames = ignoreFrames;
- this.ignoreLineNumbers = ignoreLineNumbers;
- }
-
- /**
- * @return the Builder object for this {@link PatternMatcher}
- */
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * Tries to match the given pattern on a given {@link MethodNode}.
- * @param node the {@link MethodNode} to search
- * @return the InsnSequence object representing the matched pattern
- */
- public InsnSequence find(MethodNode node) {
- return find(reverse ? node.instructions.getLast() : node.instructions.getFirst());
- }
-
- /**
- * Tries to match the given pattern starting from a given node.
- * @param node the node to start the search on
- * @return the {@link InsnSequence} object representing the matched pattern
- */
- public InsnSequence find(AbstractInsnNode node) {
- if(node != null) {
- AbstractInsnNode first, last;
- for(AbstractInsnNode cur = node; cur != null; cur = reverse ? cur.getPrevious() : cur.getNext()) {
- if(predicates.size() == 0) return new InsnSequence(cur); //match whatever
- first = cur;
- last = cur;
- for(int match = 0; last != null && match < predicates.size(); last = reverse ? last.getPrevious() : last.getNext()) {
- if(match != 0) {
- if(ignoreLabels && last.getType() == AbstractInsnNode.LABEL) continue;
- if(ignoreFrames && last.getType() == AbstractInsnNode.FRAME) continue;
- if(ignoreLineNumbers && last.getType() == AbstractInsnNode.LINE) continue;
- }
- if(!predicates.get(match).test(last)) break;
- if(match == predicates.size() - 1) {
- if(reverse) return new InsnSequence(last, first); //we are matching backwards
- else return new InsnSequence(first, last);
- } else match++;
- }
- }
- }
- throw new PatternNotFoundException("Failed to find pattern!");
- }
-
- /**
- * The Builder object for {@link PatternMatcher}.
- */
- public static class Builder {
-
- /**
- * List of predicates the pattern has to match.
- */
- private final List<Predicate<AbstractInsnNode>> predicates = new ArrayList<>();
-
- /**
- * Whether the pattern matching should proceed in reversed order.
- */
- private boolean reverse = false;
-
- /**
- * Patterns flagged with this ignore labels.
- */
- private boolean ignoreLabels = false;
-
- /**
- * Patterns flagged with this ignore FRAME instructions.
- */
- private boolean ignoreFrames = false;
-
- /**
- * Patterns flagged with this ignore LINENUMBER instructions.
- */
- private boolean ignoreLineNumbers = false;
-
- /**
- * Builds the pattern defined so far.
- * @return the built {@link PatternMatcher}
- */
- public PatternMatcher build() {
- return new PatternMatcher(predicates, reverse, ignoreLabels, ignoreFrames, ignoreLineNumbers);
- }
-
- /**
- * Sets the pattern to match starting from the end.
- * @return the builder's state after the operation
- */
- public Builder reverse() {
- this.reverse = true;
- return this;
- }
-
- /**
- * Adds a custom predicate to the list. Also used internally.
- * @param predicate the predicate to add
- * @return the builder's state after the operation
- */
- public Builder check(Predicate<AbstractInsnNode> predicate) {
- predicates.add(predicate);
- return this;
- }
-
- /**
- * Wildcard, matches any kind of node.
- * @return the builder's state after the operation
- */
- public Builder any() {
- return check(i -> true);
- }
-
- /**
- * Matches a specific opcode.
- * @param opcode opcode to match
- * @return the builder's state after the operation
- */
- public Builder opcode(int opcode) {
- return check(i -> i.getOpcode() == opcode);
- }
-
- /**
- * Matches a list of opcodes.
- * @param opcodes list of opcodes to match
- * @return the builder's state after the operation
- */
- public Builder opcodes(int... opcodes) {
- Builder res = this;
- for(int o : opcodes)
- res = opcode(o);
- return res;
- }
-
- /**
- * Matches a method invokation of any kind: one of INVOKEVIRTUAL,
- * INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
- * @return the builder's state after the operation
- */
- public Builder method() {
- return check(i -> i.getType() == AbstractInsnNode.METHOD_INSN);
- }
-
- /**
- * Matches a field invokation of any kind: one of GETSTATIC, PUTSTATIC,
- * GETFIELD or PUTFIELD.
- * @return the builder's state after the operation
- */
- public Builder field() {
- return check(i -> i.getType() == AbstractInsnNode.FIELD_INSN);
- }
-
- /**
- * Matches any kind of jump instruction.
- * @return the builder's state after the operation
- */
- public Builder jump() {
- return check(i -> i.getType() == AbstractInsnNode.JUMP_INSN);
- }
-
- /**
- * Matches any kind of label.
- * @return the builder's state after the operation
- */
- public Builder label() {
- return check(i -> i.getType() == AbstractInsnNode.LABEL);
- }
-
- /**
- * Tells the pattern matcher to ignore LABEL instructions.
- * @return the builder's state after the operation
- */
- public Builder ignoreLabels() {
- this.ignoreLabels = true;
- return this;
- }
-
- /**
- * Tells the pattern matcher to ignore FRAME instructions.
- * @return the builder's state after the operation
- */
- public Builder ignoreFrames() {
- this.ignoreFrames = true;
- return this;
- }
-
- /**
- * Tells the pattern matcher to ignore LINENUMBER instructions.
- * @return the builder's state after the operation
- */
- public Builder ignoreLineNumbers() {
- this.ignoreLineNumbers = true;
- return this;
- }
- }
-}