feat: implemented descriptorbuilder, added feature to InsnSequence

This commit is contained in:
zaaarf 2023-02-07 16:20:36 +01:00
parent f2145f8ab7
commit 2cdad9a482
No known key found for this signature in database
GPG key ID: 82240E075E31FA4C
2 changed files with 158 additions and 0 deletions

View file

@ -0,0 +1,141 @@
package ftbsc.lll.tools;
import jdk.internal.org.objectweb.asm.Type;
import java.util.ArrayList;
/**
* Builds a method descriptor for you.
* Parameters must be given in a specific order.
* Return type should always be specified for clarity, but defaults to void.
*/
public class DescriptorBuilder {
/**
* The descriptor of the return type.
*/
private String returnType;
/**
* The descriptors of the parameters.
*/
private final ArrayList<String> params;
/**
* Public constructor.
* Initialises default values.
*/
public DescriptorBuilder() {
this.returnType = Type.getDescriptor(void.class);
this.params = new ArrayList<>();
}
/**
* Sets the return type to the given type.
* WARNING: will most likely cause problems if used with objects outside the
* Java SDK. Pass the fully qualified name as a String rather than the Class
* object for non-standard types (such as Minecraft classes).
* @param returnType the Class object corresponding to the return type
* @return the builder's state after the change
*/
public DescriptorBuilder setReturnType(Class<?> returnType) {
this.returnType = Type.getDescriptor(returnType);
return this;
}
/**
* Sets the return type to the Object specified here as a fully
* qualified name. Example: java.lang.String.
* No validity checks are performed: it's up to the user to ensure the name is correct.
* @param returnType the fully qualified name of the desired Object.
* @return the builder's state after the change
*/
public DescriptorBuilder setReturnType(String returnType) {
return this.setReturnType(returnType, 0);
}
/**
* Sets the return type to the Object specified here as a fully
* qualified name (example: java.lang.String), with the specified array level.
* No validity checks are performed: it's up to the user to ensure the name is correct.
* @param returnType the fully qualified name of the desired Object.
* @param arrayLevel how many levels of array are there
* (example: String is 0, String[] is 1, String[][] is 2, etc.)
* @return the builder's state after the change
*/
public DescriptorBuilder setReturnType(String returnType, int arrayLevel) {
this.returnType = nameToDescriptor(returnType, arrayLevel);
return this;
}
/**
* Adds a parameter of the given class type to the method.
* Parameter order matters.
* WARNING: will most likely cause problems if used with objects outside the
* Java SDK. Pass the fully qualified name as a String rather than the Class
* object for non-standard types (such as Minecraft classes).
* @param param the Class object corresponding to the parameter
* @return the builder's state after the change
*/
public DescriptorBuilder addParameter(Class<?> param) {
this.params.add(Type.getDescriptor(param));
return this;
}
/**
* Adds a parameter with the type specified by the given fully
* qualified name to the method. Example: java.lang.String.
* Parameter order matters.
* No validity checks are performed: it's up to the user to ensure the name is correct.
* @param param the fully qualified name of the parameter type
* @return the builder's state after the change
*/
public DescriptorBuilder addParameter(String param) {
return this.addParameter(param, 0);
}
/**
* Adds a parameter with the type specified by the given fully
* qualified name (example: java.lang.String) to the method, with
* the specified array level.
* Parameter order matters.
* No validity checks are performed: it's up to the user to ensure the name is correct.
* @param param the fully qualified name of the parameter type
* @param arrayLevel how many levels of array are there
* (example: String is 0, String[] is 1, String[][] is 2, etc.)
* @return the builder's state after the change
*/
public DescriptorBuilder addParameter(String param, int arrayLevel) {
this.params.add(nameToDescriptor(param, arrayLevel));
return this;
}
/**
* Builds the descriptor into a string.
* Example result: int m(Object[] o) -> ([Ljava/lang/Object;)I
* @return the resulting descriptor
*/
public String build() {
StringBuilder sb = new StringBuilder();
sb.append('(');
for(String p : params)
sb.append(p);
sb.append(')').append(returnType);
return sb.toString();
}
/**
* Converts a fully qualified name and array level to a descriptor.
* @param name the fully qualified name of the object type
* @param arrayLevel how many levels of array are there
* (example: String is 0, String[] is 1, String[][] is 2, etc.)
* @return object descriptor
*/
public static String nameToDescriptor(String name, int arrayLevel) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < arrayLevel; i++)
sb.append('[');
sb.append('L').append(name.replace('.', '/')).append(';');
return sb.toString();
}
}

View file

@ -11,6 +11,14 @@ import java.util.Objects;
* Extends InsnList, but provides additional flexibility.
*/
public class InsnSequence extends InsnList {
/**
* Public constructor.
* This creates an empty sequence.
*/
public InsnSequence() {
super();
}
/**
* Public constructor.
* Must be given two non-null, connected nodes.
@ -41,6 +49,15 @@ public class InsnSequence extends InsnList {
return this.toArray()[size() - index];
}
/**
* Adds an array of nodes to the list.
* @param nodes the nodes to add
*/
public void add(AbstractInsnNode... nodes) {
for(AbstractInsnNode node : nodes)
super.add(node);
}
/**
* Replaces a node with another one. Mostly used internally.
* @param oldNode node to replace