diff --git a/src/main/java/ftbsc/lll/tools/InsnSequence.java b/src/main/java/ftbsc/lll/tools/InsnSequence.java index fbd5f5c..c23e5e1 100644 --- a/src/main/java/ftbsc/lll/tools/InsnSequence.java +++ b/src/main/java/ftbsc/lll/tools/InsnSequence.java @@ -27,5 +27,73 @@ public class InsnSequence extends InsnList implements Opcodes { throw new InstructionMismatchException("Nodes" + getFirst() + " and " + getLast() + " are not connected."); } - //TODO replace + /** + * Extends the existing get function from InsnList to allow for negative indexes. + * @param index the index of the instruction that must be returned + * @return the instruction whose index is given + */ + @Override + public AbstractInsnNode get(int index) { + if(index >= 0) + return super.get(index); + index = Math.abs(index); + if(index > size()) + throw new IndexOutOfBoundsException(); + return this.toArray()[size() - index]; + } + + /** + * Replaces a node with another one. Mostly used internally. + * @param oldNode node to replace + * @param newNode new node + */ + public void replaceNode(AbstractInsnNode oldNode, AbstractInsnNode newNode) { + super.insert(oldNode, newNode); + super.remove(oldNode); + } + + /** + * Replaces n occurrences of said opcode with the given node. + * @param opcode the opcode to replace + * @param newNode the replacement node + * @param amount how many occurrences to replace, set to 0 to replace all + * @return true if anything was changed, false otherwise + */ + public boolean replace(int opcode, AbstractInsnNode newNode, int amount) { + return replace(opcode, newNode, amount, false); + } + + /** + * Replaces n occurrences of said opcode with the given node. + * @param opcode the opcode to replace + * @param newNode the replacement node + * @param reverse whether the search should be done from the end + * @param amount how many occurrences to replace, set to 0 to replace all + * @return true if anything was changed, false otherwise + */ + public boolean replace(int opcode, AbstractInsnNode newNode, int amount, boolean reverse) { + boolean changed = false; + for(AbstractInsnNode cur = this.getFirst(); + cur != null && cur.getPrevious() != this.getLast() && cur.getNext() != this.getFirst(); + cur = reverse ? cur.getPrevious() : cur.getNext()) { + if(cur.getOpcode() == opcode) { + this.replaceNode(cur, newNode); + changed = true; + amount--; // will go to negative if it was already 0, causing it to go on until for loop finishes + if(amount == 0) + return changed; + } + } + return changed; + } + + /** + * Cut a number of nodes from the list. + * @param amount how many nodes to cut + * @param reverse true if should cut from the end, false otherwise + */ + public void cut(int amount, boolean reverse) { + for(int i = 0; i < amount; i++) + this.remove(reverse ? getLast() : getFirst()); + } }