parameterMirrors = new ArrayList<>();
- for(Type type : Type.getArgumentTypes(desc)) {
- parameterMirrors.add(new ClassReferenceMirror(type.getDescriptor()));
- }
- final AbstractMethodMirror methodMirror;
- if(ConstructorMirror.INIT.equals(name)) {
- methodMirror = new ConstructorMirror(
- classInfo.classReferenceMirror,
- new ModifierMirror(ModifierMirror.Type.METHOD, access),
- new ClassReferenceMirror(Type.getReturnType(desc).getDescriptor()),
- name,
- parameterMirrors,
- (access & ACC_VARARGS) == ACC_VARARGS,
- (access & ACC_SYNTHETIC) == ACC_SYNTHETIC,
- signature
- );
- } else {
- methodMirror = new MethodMirror(
- classInfo.classReferenceMirror,
- new ModifierMirror(ModifierMirror.Type.METHOD, access),
- new ClassReferenceMirror(Type.getReturnType(desc).getDescriptor()),
- name,
- parameterMirrors,
- (access & ACC_VARARGS) == ACC_VARARGS,
- (access & ACC_SYNTHETIC) == ACC_SYNTHETIC,
- signature
- );
- }
+
+ AbstractMethodMirror methodMirror = AbstractMethodMirror.fromVisitParameters(access, name, desc, signature,
+ exceptions, classInfo.classReferenceMirror);
return new MethodVisitor(Opcodes.ASM7, super.visitMethod(access, name, desc, signature, exceptions)) {
@Override
diff --git a/src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AggressiveDeprecation.java b/src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AggressiveDeprecation.java
new file mode 100644
index 0000000000..7fcfe159c1
--- /dev/null
+++ b/src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AggressiveDeprecation.java
@@ -0,0 +1,52 @@
+package com.laytonsmith.PureUtilities.Common.Annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An aggressively deprecated method is one that is binary compatible, but source incompatible. This means that methods
+ * that have been compiled against previously will continue to be available and work, but building against the latest
+ * version of the code will cause compile errors. This makes writing code which downstream dependencies use much easier,
+ * as this puts the onus completely on the developer and not the end user, but only when they go to make a new build
+ * for some other reason anyways.
+ *
+ * To use this annotation, simply tag the method that would otherwise be deprecated with this annotation in addition to
+ * the {@link Deprecated} annotation, {@code @deprecated} javadoc, and {@code @hidden} javadoc.
+ */
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface AggressiveDeprecation {
+ /**
+ * Returns the minimum version in which this will be actually removed. This is not
+ * strictly a guarantee, depending on external factors, but should inform the future
+ * decision.
+ * @return
+ */
+ String removalVersion();
+
+ /**
+ * Returns the date that this was deprecated, in YYYY-MM-DD format. In general, removals
+ * don't happen for at least a year, though that is not always the case, and this date is
+ * simply to inform the future decision about when to do the actual removal.
+ * @return
+ */
+
+ String deprecationDate();
+
+ /**
+ * The version in which this will (automatically) start being aggressively deprecated. The usual
+ * pattern is to set this to the next version number, and then the removal version to the one
+ * after that. Say that the current version is version 1.0.0. If you say that the deprecationVersion
+ * is 1.1.0, and the removal version is 1.2.0, then for dependencies building against 1.0.0, they
+ * will continue to work completely as is, and can continue to build just fine (though with a deprecation
+ * warning, assuming you also place the Deprecated annotation). Then, automatically, when the current
+ * version bumps to 1.1.0, it will automatically start being aggressively deprecated. Downstream
+ * dependencies built against 1.0.0 will continue to be binary compatible, but cannot be built
+ * against 1.1.0 without changes. Finally, 1.2.0, the method can actually be removed, as the
+ * binary compatibility was no longer guaranteed.
+ * @return
+ */
+ String deprecationVersion();
+}
diff --git a/src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AggressiveDeprecationTransformer.java b/src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AggressiveDeprecationTransformer.java
new file mode 100644
index 0000000000..e4032360fd
--- /dev/null
+++ b/src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AggressiveDeprecationTransformer.java
@@ -0,0 +1,114 @@
+package com.laytonsmith.PureUtilities.Common.Annotations;
+
+import com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery;
+import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.AbstractMethodMirror;
+import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.AnnotationMirror;
+import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassReferenceMirror;
+import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ConstructorMirror;
+import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.MethodMirror;
+import com.laytonsmith.PureUtilities.Common.StringUtils;
+import com.laytonsmith.PureUtilities.SimpleVersion;
+import com.laytonsmith.PureUtilities.TermColors;
+import com.laytonsmith.PureUtilities.Version;
+import com.laytonsmith.core.MSVersion;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ *
+ */
+public final class AggressiveDeprecationTransformer implements ClassFileTransformer {
+
+ private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd");
+
+ public byte[] transform(final InputStream input) throws IllegalClassFormatException, IOException {
+ final ClassReader classReader = new ClassReader(input);
+ ClassWriter classWriter = new ClassWriter(classReader, 0);
+ doAccept(classWriter, classReader);
+ return classWriter.toByteArray();
+ }
+
+ private void doAccept(final ClassWriter classWriter, final ClassReader classReader)
+ throws IllegalClassFormatException {
+ try {
+ classReader.accept(new TranslatingClassVisitor(classWriter), 0);
+ } catch(RuntimeException e) {
+ final Throwable cause = e.getCause();
+ if(cause instanceof IllegalClassFormatException illegalClassFormatException) {
+ throw illegalClassFormatException;
+ }
+ throw e;
+ }
+ }
+
+ private class TranslatingClassVisitor extends ClassVisitor {
+
+ ClassReferenceMirror> lastClass;
+ public TranslatingClassVisitor(final ClassWriter classWriter) {
+ super(Opcodes.ASM9, classWriter);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ lastClass = new ClassReferenceMirror(Type.getObjectType(name).getDescriptor());
+ }
+
+
+ @Override
+ public MethodVisitor visitMethod(int access, final String name, String methodDesc, final String signature,
+ final String[] exceptions) {
+ String methodDescLookup = methodDesc;
+ if(ConstructorMirror.INIT.matches(name)) {
+ // We have to do this replacement in order to match the lookup correctly, since the rewrite is done
+ // like this in ClassDiscovery as well.
+ methodDescLookup = StringUtils.replaceLast(methodDesc, "V", lastClass.getJVMName());
+ }
+ // We just use this method to construct the mirror enough to easily compare, but we need the MethodMirror
+ // from class discovery for it to contain all the information.
+ AbstractMethodMirror mirror = AbstractMethodMirror.fromVisitParameters(access, name, methodDescLookup, signature, exceptions, lastClass);
+ for(MethodMirror m : ClassDiscovery.getDefaultInstance().getMethodsWithAnnotation(AggressiveDeprecation.class)) {
+ if(m.getDeclaringClass().equals(mirror.getDeclaringClass())) {
+ if(m.getName().equals(mirror.getName())) {
+ if(m.getParams().equals(mirror.getParams())) {
+ mirror = m;
+ break;
+ }
+ }
+ }
+ }
+
+ AnnotationMirror aggressiveDeprecation = mirror.getAnnotation(AggressiveDeprecation.class);
+ if(aggressiveDeprecation != null
+ && MSVersion.LATEST
+ .gte(new SimpleVersion((String) aggressiveDeprecation.getValue("deprecationVersion")))) {
+// System.out.println(mirror.getDeclaringClass() + "." + mirror.getName() + "(" + mirror.getParams()
+// + ") needs rewrite");
+ access = access | Opcodes.ACC_BRIDGE | Opcodes.ACC_SYNTHETIC;
+ Version removalVersion = new SimpleVersion((String) aggressiveDeprecation.getValue("removalVersion"));
+ LocalDate deprecationDate =
+ LocalDate.parse((String) aggressiveDeprecation.getValue("deprecationDate"), FORMATTER);
+
+ if(MSVersion.LATEST.gte(removalVersion) || LocalDate.now()
+ .isAfter(deprecationDate.plusYears(1))) {
+ System.err.println(TermColors.YELLOW + mirror.getDeclaringClass() + "." + mirror.getName() + "(" + mirror.getParams()
+ + ") is slated for removal now, consider removing it from the codebase or updating"
+ + " the deprecation date or removal version." + TermColors.RESET);
+ }
+
+ }
+ return new MethodVisitor(Opcodes.ASM9,
+ super.visitMethod(access, name, methodDesc, signature, exceptions)){};
+ }
+ }
+}
diff --git a/src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AnnotationChecks.java b/src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AnnotationChecks.java
index 12bc3052cf..79ed6fd586 100644
--- a/src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AnnotationChecks.java
+++ b/src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AnnotationChecks.java
@@ -1,14 +1,23 @@
package com.laytonsmith.PureUtilities.Common.Annotations;
import com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery;
+import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.AbstractMethodMirror;
+import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.AnnotationMirror;
import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassMirror;
+import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassReferenceMirror;
import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.MethodMirror;
+import com.laytonsmith.PureUtilities.Common.FileUtil;
+import com.laytonsmith.PureUtilities.Common.FileWriteMode;
import com.laytonsmith.PureUtilities.Common.ReflectionUtils;
import com.laytonsmith.PureUtilities.Common.StringUtils;
import com.laytonsmith.PureUtilities.ExhaustiveVisitor;
import com.laytonsmith.annotations.NonInheritImplements;
import com.laytonsmith.annotations.typeof;
import com.laytonsmith.core.constructs.CClassType;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.instrument.IllegalClassFormatException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
@@ -21,6 +30,8 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* This class is run by maven at compile time, and checks to ensure that the various annotations referenced here are
@@ -41,8 +52,11 @@ public static void checkForTypeInTypeofClasses() throws Exception {
errors.add("TYPE is null? " + clazz.getClassName());
continue;
}
- if(!type.val().equals(clazz.getAnnotation(typeof.class).getValue("value"))) {
- errors.add(clazz.getClassName() + "'s TYPE value is different than the typeof annotation on it");
+ String classType = type.val().replaceAll("<.*>", "");
+ if(!classType.equals(clazz.getAnnotation(typeof.class).getValue("value"))) {
+ errors.add(clazz.getClassName() + "'s TYPE value is different than the typeof annotation on it"
+ + " (expected " + clazz.getAnnotation(typeof.class).getValue("value") + " but"
+ + " got " + type.val() + ")");
}
} catch (ReflectionUtils.ReflectionException ex) {
errors.add(clazz.getClassName() + " needs to add the following:\n\t@SuppressWarnings(\"FieldNameHidesFieldInSuperclass\")\n"
@@ -251,4 +265,38 @@ public static void verifyNonInheritImplements() throws ClassNotFoundException {
}
}
+ public static void rewriteAggressiveDeprecations() throws IOException {
+ System.out.println("Looking for aggressive deprecations to rewrite");
+ Set> toVerify = ClassDiscovery.getDefaultInstance()
+ .getKnownClasses();
+ Set> classesToRewrite = new HashSet<>();
+ String annotationJVMName = ClassReferenceMirror.fromClass(AggressiveDeprecation.class).getJVMName();
+ for(ClassMirror c : toVerify) {
+ methodLoop: for(AbstractMethodMirror m : c.getAllMethods()) {
+ for(AnnotationMirror am : m.getAnnotations()) {
+ if(am.getType().getJVMName().equals(annotationJVMName)) {
+ classesToRewrite.add(c);
+ break methodLoop;
+ }
+ }
+ }
+ }
+ for(ClassMirror c : classesToRewrite) {
+ if(!c.isReadOnly()) {
+// System.out.println("Rewriting " + c.getClassName());
+ InputStream stream = c.getClassStream();
+ try {
+ byte[] newClass = new AggressiveDeprecationTransformer().transform(stream);
+ System.out.println("Doing aggressive deprecation rewrite in " + c.getClassLocation().getPath());
+ File location = new File(c.getClassLocation().getPath());
+ FileUtil.write(newClass, location, FileWriteMode.OVERWRITE, false);
+ } catch(IllegalClassFormatException | IOException ex) {
+ Logger.getLogger(AnnotationChecks.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ } else {
+ System.out.println("Read only file! Cannot rewrite " + c.getClassName());
+ }
+ }
+ }
+
}
diff --git a/src/main/java/com/laytonsmith/PureUtilities/Common/ArrayUtils.java b/src/main/java/com/laytonsmith/PureUtilities/Common/ArrayUtils.java
index e199e61ba9..f79dcf82b5 100644
--- a/src/main/java/com/laytonsmith/PureUtilities/Common/ArrayUtils.java
+++ b/src/main/java/com/laytonsmith/PureUtilities/Common/ArrayUtils.java
@@ -703,6 +703,7 @@ public static T[] asArray(Class clazz, List list) {
for(int i = 0; i < list.size(); i++) {
obj[i] = list.get(i);
}
+ assert obj != null;
return obj;
}
diff --git a/src/main/java/com/laytonsmith/PureUtilities/Common/ReflectionUtils.java b/src/main/java/com/laytonsmith/PureUtilities/Common/ReflectionUtils.java
index aca00f8150..ea0860ba27 100644
--- a/src/main/java/com/laytonsmith/PureUtilities/Common/ReflectionUtils.java
+++ b/src/main/java/com/laytonsmith/PureUtilities/Common/ReflectionUtils.java
@@ -78,8 +78,8 @@ public static T newInstance(Class clazz, Class[] argTypes, Object[] args)
* @param variableName
* @return
*/
- public static Object get(Class clazz, String variableName) throws ReflectionException {
- return get(clazz, null, variableName);
+ public static T get(Class clazz, String variableName) throws ReflectionException {
+ return (T) get(clazz, null, variableName);
}
/**
@@ -97,7 +97,7 @@ public static Object get(Class clazz, String variableName) throws ReflectionExce
* @param variableName
* @return
*/
- public static Object get(Class clazz, Object instance, String variableName) throws ReflectionException {
+ public static T get(Class clazz, Object instance, String variableName) throws ReflectionException {
try {
if(variableName.contains(".")) {
String split[] = variableName.split("\\.");
@@ -107,11 +107,11 @@ public static Object get(Class clazz, Object instance, String variableName) thro
myInstance = get(myClazz, myInstance, var);
myClazz = myInstance.getClass();
}
- return myInstance;
+ return (T) myInstance;
} else {
Field f = clazz.getDeclaredField(variableName);
f.setAccessible(true);
- return f.get(instance);
+ return (T) f.get(instance);
}
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException ex) {
throw new ReflectionException(ex);
@@ -392,6 +392,60 @@ public static boolean hasMethod(Class> c, String methodName, Class returnType,
return true;
}
+ /**
+ * Checks to see if a method with the given signature exists.
+ *
+ * @param c The class to check
+ * @param methodName The method name
+ * @param returnType The return type of the method, or if it is otherwise castable to this. Sending null or
+ * Object.class implies that the return type doesn't matter.
+ * @param params The signature of the method
+ * @return True, if the method with this signature exists.
+ * @throws ReflectionException If a SecurityException is thrown by the underlying code, this will be thrown.
+ */
+ @SuppressWarnings("unchecked")
+ public static boolean hasDeclaredMethod(Class> c, String methodName, Class returnType, Class... params) throws ReflectionException {
+ Method m;
+ try {
+ m = c.getDeclaredMethod(methodName, params);
+ } catch (NoSuchMethodException ex) {
+ return false;
+ } catch (SecurityException ex) {
+ throw new ReflectionException(ex);
+ }
+ if(returnType != null) {
+ return returnType.isAssignableFrom(m.getReturnType());
+ }
+ return true;
+ }
+
+ /**
+ * Checks to see if a field with the given name and type exists.
+ *
+ * @param c The class to check in.
+ * @param fieldName The name of the field
+ * @param type May be null, in which case any type is accepted. Otherwise, checks to see if the field extends
+ * this type.
+ * @return True, if the field with the given name and optionally type exists.
+ * @throws com.laytonsmith.PureUtilities.Common.ReflectionUtils.ReflectionException
+ */
+ public static boolean hasField(Class> c, String fieldName, Class type) throws ReflectionException {
+ Field f;
+ try {
+ f = c.getField(fieldName);
+ } catch (NoSuchFieldException ex) {
+ return false;
+ } catch (SecurityException ex) {
+ throw new ReflectionException(ex);
+ }
+ if(type != null) {
+ if(!type.isAssignableFrom(f.getType())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Returns sun.misc.Unsafe. It is an object, which requires reflective calls made onto it. This is to prevent any
* warnings from the JVM.
diff --git a/src/main/java/com/laytonsmith/PureUtilities/Common/StackTraceUtils.java b/src/main/java/com/laytonsmith/PureUtilities/Common/StackTraceUtils.java
index 5900a76aba..4792a668ab 100644
--- a/src/main/java/com/laytonsmith/PureUtilities/Common/StackTraceUtils.java
+++ b/src/main/java/com/laytonsmith/PureUtilities/Common/StackTraceUtils.java
@@ -19,6 +19,9 @@ private StackTraceUtils() {
* @return
*/
public static String GetStacktrace(Throwable t) {
+ if(t == null) {
+ return "null";
+ }
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
boolean first = true;
diff --git a/src/main/java/com/laytonsmith/PureUtilities/Common/StringUtils.java b/src/main/java/com/laytonsmith/PureUtilities/Common/StringUtils.java
index 0057bd6b54..22d803e453 100644
--- a/src/main/java/com/laytonsmith/PureUtilities/Common/StringUtils.java
+++ b/src/main/java/com/laytonsmith/PureUtilities/Common/StringUtils.java
@@ -37,9 +37,6 @@ public static String Join(Map map, String entryGlue, String elementGlue) {
* @param entryGlue The glue to use between the key and value of each pair in the map
* @param elementGlue The glue to use between each key-value element pairs in the map
* @param lastElementGlue The glue for the last two elements
- * @param glueForTwoItems If only two items are in the map, then this glue is used instead. If it is null, then
- * lastElementGlue is used instead.
- * @param empty If the map is completely empty, this string is simply returned. If null, an empty string is used.
* @return The concatenated string
*/
public static String Join(Map map, String entryGlue, String elementGlue, String lastElementGlue) {
@@ -53,8 +50,8 @@ public static String Join(Map map, String entryGlue, String elementGlue, String
* @param entryGlue The glue to use between the key and value of each pair in the map
* @param elementGlue The glue to use between each key-value element pairs in the map
* @param lastElementGlue The glue for the last two elements
- * @param glueForTwoItems If only two items are in the map, then this glue is used instead. If it is null, then
- * lastElementGlue is used instead.
+ * @param elementGlueForTwoItems If only two items are in the map, then this glue is used instead. If it is null,
+ * then lastElementGlue is used instead.
* @return The concatenated string
*/
public static String Join(Map map, String entryGlue, String elementGlue, String lastElementGlue, String elementGlueForTwoItems) {
@@ -68,14 +65,14 @@ public static String Join(Map map, String entryGlue, String elementGlue, String
* @param entryGlue The glue to use between the key and value of each pair in the map
* @param elementGlue The glue to use between each key-value element pairs in the map
* @param lastElementGlue The glue for the last two elements
- * @param glueForTwoItems If only two items are in the map, then this glue is used instead. If it is null, then
- * lastElementGlue is used instead.
+ * @param elementGlueForTwoItems If only two items are in the map, then this glue is used instead. If it is null,
+ * then lastElementGlue is used instead.
* @param empty If the map is completely empty, this string is simply returned. If null, an empty string is used.
* @return The concatenated string
*/
public static String Join(Map map, String entryGlue, String elementGlue, String lastElementGlue, String elementGlueForTwoItems, String empty) {
//Just create a list of glued together entries, then send it to the other Join method
- List list = new ArrayList();
+ List list = new ArrayList<>();
for(Object key : map.keySet()) {
StringBuilder b = new StringBuilder();
b.append(key).append(entryGlue).append(map.get(key));
@@ -87,7 +84,9 @@ public static String Join(Map map, String entryGlue, String elementGlue, String
/**
* Joins a set together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the Object)
* using the specified string for glue.
- * @param list The set to concatenate
+ *
+ * @param The type of the items in the Set
+ * @param set The set to join
* @param glue The glue to use
* @return The concatenated string
*/
@@ -97,21 +96,50 @@ public static String Join(Set set, String glue) {
/**
* Joins a set together, rendering each item with the custom renderer.
- * @param set
- * @param glue
- * @param r
+ *
+ * @param The type of the items in the Set
+ * @param set The set to join
+ * @param glue The glue between each element
+ * @param r The renderer which should return a string representation of the item in the set.
* @return
*/
public static String Join(Set set, String glue, Renderer r) {
return Join(set, glue, null, null, null, r);
}
+ /**
+ * Joins a list together, rendering each item with the custom renderer.
+ *
+ * @param The type of the items in the List
+ * @param list The list to join
+ * @param glue The glue between each element
+ * @param r The renderer which should return a string representation of the item in the list.
+ * @return
+ */
+ public static String Join(List list, String glue, Renderer r) {
+ return Join(list, glue, null, null, null, r);
+ }
+
+ /**
+ * Joins an array together, rendering each item with the custom renderer.
+ *
+ * @param The type of the items in the array
+ * @param list The list to join
+ * @param glue The glue between each element
+ * @param r The renderer which should return a string representation of the item in the list.
+ * @return
+ */
+ public static String Join(T[] list, String glue, Renderer r) {
+ return Join(list, glue, null, null, null, r);
+ }
+
/**
* Joins a set together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the Object)
- * using the specified string for glue. If
- * lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for sets that are being read by a human, to have a proper conjunction at the end.
- * @param list The set to concatenate
+ * using the specified string for glue. If lastGlue is null, it is the same as glue, but otherwise it is used to
+ * glue just the last two items together, which is useful for sets that are being read by a human, to have a proper
+ * conjunction at the end.
+ *
+ * @param set The set to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements
* @return The concatenated string
@@ -122,10 +150,11 @@ public static String Join(Set set, String glue, String lastGlue) {
/**
* Joins a set together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the Object)
- * using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for sets that are being read by a human, to have a proper conjunction at the end.
- * @param list The set to concatenate
+ * using the specified string for glue. If lastGlue is null, it is the same as glue, but otherwise it is used to
+ * glue just the last two items together, which is useful for sets that are being read by a human, to have a proper
+ * conjunction at the end.
+ *
+ * @param set The set to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements
* @param glueForTwoItems If only two items are in the set, then this glue is used instead. If it is null, then
@@ -138,10 +167,12 @@ public static String Join(Set set, String glue, String lastGlue, String glueForT
/**
* Joins a set together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the Object)
- * using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for sets that are being read by a human, to have a proper conjunction at the end.
- * @param list The set to concatenate
+ * using the specified string for glue.If lastGlue is null, it is the same as glue, but otherwise it is used to glue
+ * just the last two items together, which is useful for sets that are being read by a human, to have a proper
+ * conjunction at the end.
+ *
+ * @param The renderer which should return a string representation of the item in the set.
+ * @param set The set to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements
* @param glueForTwoItems If only two items are in the set, then this glue is used instead. If it is null, then
@@ -155,19 +186,22 @@ public static String Join(Set set, String glue, String lastGlue, String g
/**
* Joins a set together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the Object)
- * using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for sets that are being read by a human, to have a proper conjunction at the end.
- * @param list The set to concatenate
+ * using the specified string for glue.If lastGlue is null, it is the same as glue, but otherwise it is used to glue
+ * just the last two items together, which is useful for sets that are being read by a human, to have a proper
+ * conjunction at the end.
+ *
+ * @param The type of the items in the Set
+ * @param set The set to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements
* @param glueForTwoItems If only two items are in the set, then this glue is used instead. If it is null, then
* lastGlue is used instead.
* @param empty If the set is completely empty, this string is simply returned. If null, an empty string is used.
+ * @param renderer The renderer which should return a string representation of the item in the set.
* @return The concatenated string
*/
public static String Join(Set set, String glue, String lastGlue, String glueForTwoItems, String empty, Renderer renderer) {
- final List list = new ArrayList(set);
+ final List list = new ArrayList<>(set);
return doJoin(new ItemGetter() {
@Override
@@ -188,8 +222,9 @@ public boolean isEmpty() {
}
/**
- * Joins an array together (using StringBuilder's {@link StringBuilder#append(Object)} method
- * to "toString" the Object) using the specified string for glue.
+ * Joins an array together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the
+ * Object) using the specified string for glue.
+ *
* @param list The array to concatenate
* @param glue The glue to use
* @return The concatenated string
@@ -199,10 +234,11 @@ public static String Join(Object[] list, String glue) {
}
/**
- * Joins an array together (using StringBuilder's {@link StringBuilder#append(Object)} method
- * to "toString" the Object) using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for lists that are being read by a human, to have a proper conjunction at the end.
+ * Joins an array together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the
+ * Object) using the specified string for glue. If lastGlue is null, it is the same as glue, but otherwise it is
+ * used to glue just the last two items together, which is useful for lists that are being read by a human, to have
+ * a proper conjunction at the end.
+ *
* @param list The array to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements
@@ -213,10 +249,11 @@ public static String Join(Object[] list, String glue, String lastGlue) {
}
/**
- * Joins an array together (using StringBuilder's {@link StringBuilder#append(Object)} method
- * to "toString" the Object) using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for lists that are being read by a human, to have a proper conjunction at the end.
+ * Joins an array together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the
+ * Object) using the specified string for glue. If lastGlue is null, it is the same as glue, but otherwise it is
+ * used to glue just the last two items together, which is useful for lists that are being read by a human, to have
+ * a proper conjunction at the end.
+ *
* @param list The array to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements
@@ -229,10 +266,11 @@ public static String Join(Object[] list, String glue, String lastGlue, String gl
}
/**
- * Joins an array together (using StringBuilder's {@link StringBuilder#append(Object)} method
- * to "toString" the Object) using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for lists that are being read by a human, to have a proper conjunction at the end.
+ * Joins an array together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the
+ * Object) using the specified string for glue. If lastGlue is null, it is the same as glue, but otherwise it is
+ * used to glue just the last two items together, which is useful for lists that are being read by a human, to have
+ * a proper conjunction at the end.
+ *
* @param list The array to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements
@@ -246,10 +284,11 @@ public static String Join(Object[] list, String glue, String lastGlue, String gl
}
/**
- * Joins an array together (using StringBuilder's {@link StringBuilder#append(Object)} method
- * to "toString" the Object) using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for lists that are being read by a human, to have a proper conjunction at the end.
+ * Joins an array together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the
+ * Object) using the specified string for glue. If lastGlue is null, it is the same as glue, but otherwise it is
+ * used to glue just the last two items together, which is useful for lists that are being read by a human, to have
+ * a proper conjunction at the end.
+ *
* @param The array type
* @param list The array to concatenate
* @param glue The glue to use
@@ -282,8 +321,9 @@ public boolean isEmpty() {
}
/**
- * Joins a list together (using StringBuilder's {@link StringBuilder#append(Object)} method
- * to "toString" the Object) using the specified string for glue.
+ * Joins a list together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the
+ * Object) using the specified string for glue.
+ *
* @param list The list to concatenate
* @param glue The glue to use
* @return The concatenated string
@@ -293,10 +333,11 @@ public static String Join(List list, String glue) {
}
/**
- * Joins a list together (using StringBuilder's {@link StringBuilder#append(Object)} method
- * to "toString" the Object) using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for lists that are being read by a human, to have a proper conjunction at the end.
+ * Joins a list together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the
+ * Object) using the specified string for glue. If lastGlue is null, it is the same as glue, but otherwise it is
+ * used to glue just the last two items together, which is useful for lists that are being read by a human, to have
+ * a proper conjunction at the end.
+ *
* @param list The list to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements
@@ -307,10 +348,11 @@ public static String Join(List list, String glue, String lastGlue) {
}
/**
- * Joins a list together (using StringBuilder's {@link StringBuilder#append(Object)} method
- * to "toString" the Object) using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for lists that are being read by a human, to have a proper conjunction at the end.
+ * Joins a list together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the
+ * Object) using the specified string for glue. If lastGlue is null, it is the same as glue, but otherwise it is
+ * used to glue just the last two items together, which is useful for lists that are being read by a human, to have
+ * a proper conjunction at the end.
+ *
* @param list The list to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements
@@ -323,10 +365,11 @@ public static String Join(List list, String glue, String lastGlue, String glueFo
}
/**
- * Joins a list together (using StringBuilder's {@link StringBuilder#append(Object)} method
- * to "toString" the Object) using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for lists that are being read by a human, to have a proper conjunction at the end.
+ * Joins a list together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the
+ * Object) using the specified string for glue. If lastGlue is null, it is the same as glue, but otherwise it is
+ * used to glue just the last two items together, which is useful for lists that are being read by a human, to have
+ * a proper conjunction at the end.
+ *
* @param list The list to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements
@@ -340,10 +383,12 @@ public static String Join(final List list, String glue, String lastGlue, String
}
/**
- * Joins a list together (using StringBuilder's {@link StringBuilder#append(Object)} method
- * to "toString" the Object) using the specified string for glue.
- * If lastGlue is null, it is the same as glue, but otherwise it is used to glue just the last two items together,
- * which is useful for lists that are being read by a human, to have a proper conjunction at the end.
+ * Joins a list together (using StringBuilder's {@link StringBuilder#append(Object)} method to "toString" the
+ * Object) using the specified string for glue.If lastGlue is null, it is the same as glue, but otherwise it is used
+ * to glue just the last two items together, which is useful for lists that are being read by a human, to have a
+ * proper conjunction at the end.
+ *
+ * @param The renderer which should return a string representation of the item in the list.
* @param list The list to concatenate
* @param glue The glue to use
* @param lastGlue The glue for the last two elements. If it is null, then glue is used instead.
@@ -683,20 +728,20 @@ public static String HumanReadableByteCount(long bytes, boolean si) {
long b = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
return b < 1000L ? bytes + " B"
: b < 999_950L ? String.format("%s%.1f kB", s, b / 1e3)
- : (b /= 1000) < 999_950L ? String.format("%s%.1f MB", s, b / 1e3)
- : (b /= 1000) < 999_950L ? String.format("%s%.1f GB", s, b / 1e3)
- : (b /= 1000) < 999_950L ? String.format("%s%.1f TB", s, b / 1e3)
- : (b /= 1000) < 999_950L ? String.format("%s%.1f PB", s, b / 1e3)
- : String.format("%s%.1f EB", s, b / 1e6);
+ : (b /= 1000) < 999_950L ? String.format("%s%.1f MB", s, b / 1e3)
+ : (b /= 1000) < 999_950L ? String.format("%s%.1f GB", s, b / 1e3)
+ : (b /= 1000) < 999_950L ? String.format("%s%.1f TB", s, b / 1e3)
+ : (b /= 1000) < 999_950L ? String.format("%s%.1f PB", s, b / 1e3)
+ : String.format("%s%.1f EB", s, b / 1e6);
} else {
long b = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
return b < 1024L ? bytes + " B"
: b <= 0xfffccccccccccccL >> 40 ? String.format("%.1f KiB", bytes / 0x1p10)
- : b <= 0xfffccccccccccccL >> 30 ? String.format("%.1f MiB", bytes / 0x1p20)
- : b <= 0xfffccccccccccccL >> 20 ? String.format("%.1f GiB", bytes / 0x1p30)
- : b <= 0xfffccccccccccccL >> 10 ? String.format("%.1f TiB", bytes / 0x1p40)
- : b <= 0xfffccccccccccccL ? String.format("%.1f PiB", (bytes >> 10) / 0x1p40)
- : String.format("%.1f EiB", (bytes >> 20) / 0x1p40);
+ : b <= 0xfffccccccccccccL >> 30 ? String.format("%.1f MiB", bytes / 0x1p20)
+ : b <= 0xfffccccccccccccL >> 20 ? String.format("%.1f GiB", bytes / 0x1p30)
+ : b <= 0xfffccccccccccccL >> 10 ? String.format("%.1f TiB", bytes / 0x1p40)
+ : b <= 0xfffccccccccccccL ? String.format("%.1f PiB", (bytes >> 10) / 0x1p40)
+ : String.format("%.1f EiB", (bytes >> 20) / 0x1p40);
}
}
@@ -704,12 +749,10 @@ public static String HumanReadableByteCount(long bytes, boolean si) {
* Returns a properly agreeing subject verb clause given a count, and singular subject. This version assumes that
* the plural subject can be made simply by appending s
to the singular subject, which is not always
* true. This is useful in cases where forming a sentence requires different wording depending on the count.
- * Usually, you might use a fairly complex tertiary statement, for instance:
- * String message = "There " + (count==1?"is":"are") + " " + count + " test failure" + (count==1?"":"s");
- *
This is time consuming, and easy to mess up or
- * accidentally reverse. Instead, you can use this function. Note that this will add is
or
- * are
for you. You need only to provide the count, singular subject, and plural subject. If the
- * subject cannot be made plural with just an s
, use
+ * Usually, you might use a fairly complex tertiary statement, for instance: String message = "There " + (count==1?"is":"are") + " " + count + " test failure" + (count==1?"":"s");
+ *
This is time consuming, and easy to mess up or accidentally reverse. Instead, you can use this function.
+ * Note that this will add is
or are
for you. You need only to provide the count, singular
+ * subject, and plural subject. If the subject cannot be made plural with just an s
, use
* {@link #PluralHelper(int, java.lang.String, java.lang.String)} instead. Usage example:
*
*
@@ -781,13 +824,6 @@ public static String PluralTemplateHelper(int count, String singularTemplate, St
*/
public static final String NL = System.getProperty("line.separator");
- /**
- * @deprecated Use {@link #NL} instead.
- */
- @SuppressWarnings("checkstyle:constantname") // Fixing this violation might break dependents.
- @Deprecated // Deprecated on 14-06-2018 dd-mm-yyyy.
- public static final String nl = NL;
-
/**
* This returns the system newline string. For instance, on windows, this would likely return \r\n, and unix systems
* would likely return \n.
@@ -911,6 +947,7 @@ public static List lineSplit(String text, int len) {
*
* @param str The string to word wrap
* @param wrapLength The max length of the line
+ * @return The word wrapped line.
*/
public static String lineWrap(String str, int wrapLength) {
return lineWrap(str, wrapLength, "\n", true);
diff --git a/src/main/java/com/laytonsmith/PureUtilities/Either.java b/src/main/java/com/laytonsmith/PureUtilities/Either.java
new file mode 100644
index 0000000000..64021d6193
--- /dev/null
+++ b/src/main/java/com/laytonsmith/PureUtilities/Either.java
@@ -0,0 +1,116 @@
+package com.laytonsmith.PureUtilities;
+
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * The {@code Either} class can contain neither of, or one of either the specified types of values.
+ * @param The first possible type.
+ * @param The second possible type.
+ */
+public final class Either {
+
+ /**
+ * Creates a new Either object with the first possible type.
+ * @param The first possible type, which is the type of the input parameter.
+ * @param The other possible type, which this value will not contain.
+ * @param value The value to store.
+ * @return A new Either object.
+ */
+ public static Either left(L value) {
+ return new Either<>(Optional.of(value), Optional.empty());
+ }
+
+ /**
+ * Creates a new Either object with the second possible type.
+ * @param The other possible type, which this value will not contain.
+ * @param The second possible type, which is the type of the input parameter.
+ * @param value The value to store.
+ * @return A new Either object.
+ */
+ public static Either right(R value) {
+ return new Either<>(Optional.empty(), Optional.of(value));
+ }
+
+ /**
+ * Creates a new Either object, which does not contain any value.
+ * @param The first possible type.
+ * @param The second possible type.
+ * @return A new, empty, Either object.
+ */
+ public static Either neither() {
+ return new Either<>(Optional.empty(), Optional.empty());
+ }
+
+ private final Optional left;
+ private final Optional right;
+
+ private Either(Optional left, Optional right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ /**
+ * Returns the left value. May be empty, even if the other value is also empty.
+ * @return
+ */
+ public Optional getLeft() {
+ return this.left;
+ }
+
+ /**
+ * Returns the left value. May be empty, even if the other value is also empty.
+ * @return
+ */
+ public Optional getRight() {
+ return this.right;
+ }
+
+ /**
+ * Returns if there was a left side.
+ * @return
+ */
+ public boolean hasLeft() {
+ return this.left.isPresent();
+ }
+
+ /**
+ * Returns if there was a right side.
+ * @return
+ */
+ public boolean hasRight() {
+ return this.right.isPresent();
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 3;
+ hash = 19 * hash + Objects.hashCode(this.left);
+ hash = 19 * hash + Objects.hashCode(this.right);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(this == obj) {
+ return true;
+ }
+ if(obj == null) {
+ return false;
+ }
+ if(getClass() != obj.getClass()) {
+ return false;
+ }
+ final Either, ?> other = (Either, ?>) obj;
+ if(!Objects.equals(this.left, other.left)) {
+ return false;
+ }
+ return Objects.equals(this.right, other.right);
+ }
+
+ @Override
+ public String toString() {
+ return "Either{" + "left=" + left + ", right=" + right + '}';
+ }
+
+}
diff --git a/src/main/java/com/laytonsmith/PureUtilities/ObjectHelpers.java b/src/main/java/com/laytonsmith/PureUtilities/ObjectHelpers.java
index 26d83899d3..7d996681ac 100644
--- a/src/main/java/com/laytonsmith/PureUtilities/ObjectHelpers.java
+++ b/src/main/java/com/laytonsmith/PureUtilities/ObjectHelpers.java
@@ -142,7 +142,7 @@ public static int DoHashCode(Object _this) {
if(calculatedFields.isEmpty()) {
return 0;
}
- return Arrays.hashCode(calculatedFields.toArray(new Object[calculatedFields.size()]));
+ return Arrays.hashCode(calculatedFields.toArray(Object[]::new));
}
/**
@@ -196,7 +196,7 @@ public static String DoToString(Object _this) {
}
// Do not recurse further, as self referential arrays would cause a SOE, and to properly
// avoid that would require a much more complex system.
- b.append(Objects.toString(Array.get(_this, i)));
+ b.append(Array.get(_this, i));
}
b.append('}');
return b.toString();
diff --git a/src/main/java/com/laytonsmith/PureUtilities/ZipReader.java b/src/main/java/com/laytonsmith/PureUtilities/ZipReader.java
index 04b51151d2..36a25338c9 100644
--- a/src/main/java/com/laytonsmith/PureUtilities/ZipReader.java
+++ b/src/main/java/com/laytonsmith/PureUtilities/ZipReader.java
@@ -388,6 +388,7 @@ public String getName() {
*/
public File[] listFiles() throws IOException {
if(!isZipped) {
+ assert file.listFiles() != null;
return file.listFiles();
} else {
initList();
@@ -405,7 +406,9 @@ public File[] listFiles() throws IOException {
}
}
}
- return ArrayUtils.asArray(File.class, files);
+ File[] ret = ArrayUtils.asArray(File.class, files);
+ assert ret != null;
+ return ret;
}
}
diff --git a/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitMCCommand.java b/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitMCCommand.java
index 9ce6045e67..8a154d286b 100644
--- a/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitMCCommand.java
+++ b/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitMCCommand.java
@@ -12,7 +12,9 @@
import com.laytonsmith.core.constructs.CBoolean;
import com.laytonsmith.core.constructs.CString;
import com.laytonsmith.core.constructs.Target;
+import com.laytonsmith.core.constructs.generics.GenericParameters;
import com.laytonsmith.core.environments.CommandHelperEnvironment;
+import com.laytonsmith.core.environments.Environment;
import com.laytonsmith.core.events.Driver;
import com.laytonsmith.core.events.EventUtils;
import com.laytonsmith.core.exceptions.CRE.CREPluginInternalException;
@@ -20,8 +22,6 @@
import com.laytonsmith.core.functions.Commands;
import com.laytonsmith.core.natives.interfaces.Callable;
import com.laytonsmith.core.natives.interfaces.Mixed;
-import java.util.ArrayList;
-import java.util.List;
import org.bukkit.command.Command;
import org.bukkit.command.CommandException;
import org.bukkit.command.CommandSender;
@@ -29,6 +29,9 @@
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.plugin.Plugin;
+import java.util.ArrayList;
+import java.util.List;
+
public class BukkitMCCommand implements MCCommand {
Command cmd;
@@ -211,24 +214,27 @@ public String toString() {
public List handleTabComplete(MCCommandSender sender, String alias, String[] args) {
if(Commands.onTabComplete.containsKey(cmd.getName().toLowerCase())) {
Target t = Target.UNKNOWN;
- CArray cargs = new CArray(t);
+ Callable closure = Commands.onTabComplete.get(cmd.getName().toLowerCase());
+ Environment env = closure.getEnv();
+ CArray cargs = new CArray(t, GenericParameters.emptyBuilder(CArray.TYPE)
+ .addNativeParameter(CString.TYPE, null).buildNative(), env);
for(String arg : args) {
- cargs.push(new CString(arg, t), t);
+ cargs.push(new CString(arg, t), t, env);
}
- Callable closure = Commands.onTabComplete.get(cmd.getName().toLowerCase());
+
closure.getEnv().getEnv(CommandHelperEnvironment.class).SetCommandSender(sender);
try {
Mixed fret = closure.executeCallable(null, t, new CString(alias, t), new CString(sender.getName(), t), cargs,
- new CArray(t) // reserved for an obgen style command array
+ new CArray(t, null, env) // reserved for an obgen style command array
);
- if(fret.isInstanceOf(CArray.TYPE)) {
+ if(fret.isInstanceOf(CArray.TYPE, null, env)) {
List ret = new ArrayList<>();
if(((CArray) fret).inAssociativeMode()) {
- for(Mixed key : ((CArray) fret).keySet()) {
- ret.add(((CArray) fret).get(key, Target.UNKNOWN).val());
+ for(Mixed key : ((CArray) fret).keySet(env)) {
+ ret.add(((CArray) fret).get(key, Target.UNKNOWN, env).val());
}
} else {
- for(Mixed value : ((CArray) fret).asList()) {
+ for(Mixed value : ((CArray) fret).asList(env)) {
ret.add(value.val());
}
}
@@ -247,22 +253,24 @@ public List handleTabComplete(MCCommandSender sender, String alias, Stri
@Override
public boolean handleCustomCommand(MCCommandSender sender, String label, String[] args) {
if(Commands.onCommand.containsKey(cmd.getName().toLowerCase())) {
+ Callable closure = Commands.onCommand.get(cmd.getName().toLowerCase());
+ Environment env = closure.getEnv();
Target t = Target.UNKNOWN;
- CArray cargs = new CArray(t);
+ CArray cargs = new CArray(t, GenericParameters.emptyBuilder(CArray.TYPE)
+ .addNativeParameter(CString.TYPE, null).buildNative(), env);
for(String arg : args) {
- cargs.push(new CString(arg, t), t);
+ cargs.push(new CString(arg, t), t, env);
}
- Callable closure = Commands.onCommand.get(cmd.getName().toLowerCase());
CommandHelperEnvironment cEnv = closure.getEnv().getEnv(CommandHelperEnvironment.class);
cEnv.SetCommandSender(sender);
cEnv.SetCommand("/" + label + StringUtils.Join(args, " "));
try {
Mixed fret = closure.executeCallable(null, t, new CString(label, t), new CString(sender.getName(), t), cargs,
- new CArray(t) // reserved for an obgen style command array
+ new CArray(t, null, env) // reserved for an obgen style command array
);
- if(fret.isInstanceOf(CBoolean.TYPE)) {
+ if(fret.isInstanceOf(CBoolean.TYPE, null, env)) {
return ((CBoolean) fret).getBoolean();
}
} catch (ConfigRuntimeException cre) {
diff --git a/src/main/java/com/laytonsmith/abstraction/bukkit/events/BukkitBlockEvents.java b/src/main/java/com/laytonsmith/abstraction/bukkit/events/BukkitBlockEvents.java
index 01a7bb84be..3bc882381b 100644
--- a/src/main/java/com/laytonsmith/abstraction/bukkit/events/BukkitBlockEvents.java
+++ b/src/main/java/com/laytonsmith/abstraction/bukkit/events/BukkitBlockEvents.java
@@ -43,6 +43,8 @@
import com.laytonsmith.core.constructs.CArray;
import com.laytonsmith.core.constructs.CString;
import com.laytonsmith.core.constructs.Target;
+import com.laytonsmith.core.constructs.generics.GenericParameters;
+import com.laytonsmith.core.environments.Environment;
import org.bukkit.block.Block;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockBurnEvent;
@@ -361,15 +363,6 @@ public BukkitMCSignChangeEvent(SignChangeEvent e) {
pie = e;
}
- public static BukkitMCSignChangeEvent _instantiate(MCBlock sign, MCPlayer player, CArray signtext) {
- String[] text = new String[4];
- for(int i = 0; i < signtext.size(); i++) {
- text[i] = signtext.get(i, Target.UNKNOWN).toString();
- }
- return new BukkitMCSignChangeEvent(new SignChangeEvent(((BukkitMCBlock) sign).__Block(), ((BukkitMCPlayer) player)._Player(),
- text));
- }
-
@Override
public MCPlayer getPlayer() {
return new BukkitMCPlayer(pie.getPlayer());
@@ -381,11 +374,12 @@ public CString getLine(int index) {
}
@Override
- public CArray getLines() {
- CArray retn = new CArray(Target.UNKNOWN);
+ public CArray getLines(Environment env) {
+ CArray retn = new CArray(Target.UNKNOWN, GenericParameters.emptyBuilder(CArray.TYPE)
+ .addNativeParameter(CString.TYPE, null).buildNative(), env);
for(int i = 0; i < 4; i++) {
- retn.push(new CString(pie.getLine(i), Target.UNKNOWN), Target.UNKNOWN);
+ retn.push(new CString(pie.getLine(i), Target.UNKNOWN), Target.UNKNOWN, env);
}
return retn;
diff --git a/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitWeatherListener.java b/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitWeatherListener.java
index 3fd2601bee..747c4961c2 100644
--- a/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitWeatherListener.java
+++ b/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitWeatherListener.java
@@ -14,16 +14,19 @@ public class BukkitWeatherListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onLightningStrike(LightningStrikeEvent event) {
- EventUtils.TriggerListener(Driver.LIGHTNING_STRIKE, "lightning_strike", new BukkitWeatherEvents.BukkitMCLightningStrikeEvent(event));
+ EventUtils.TriggerListener(Driver.LIGHTNING_STRIKE, "lightning_strike",
+ new BukkitWeatherEvents.BukkitMCLightningStrikeEvent(event));
}
@EventHandler(priority = EventPriority.LOWEST)
public void onThunderChange(ThunderChangeEvent event) {
- EventUtils.TriggerListener(Driver.THUNDER_CHANGE, "thunder_change", new BukkitWeatherEvents.BukkitMCThunderChangeEvent(event));
+ EventUtils.TriggerListener(Driver.THUNDER_CHANGE, "thunder_change",
+ new BukkitWeatherEvents.BukkitMCThunderChangeEvent(event));
}
@EventHandler(priority = EventPriority.LOWEST)
public void onWeatherChange(WeatherChangeEvent event) {
- EventUtils.TriggerListener(Driver.WEATHER_CHANGE, "weather_change", new BukkitWeatherEvents.BukkitMCWeatherChangeEvent(event));
+ EventUtils.TriggerListener(Driver.WEATHER_CHANGE, "weather_change",
+ new BukkitWeatherEvents.BukkitMCWeatherChangeEvent(event));
}
}
diff --git a/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitWorldListener.java b/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitWorldListener.java
index ec75cb2881..bce9216b5e 100644
--- a/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitWorldListener.java
+++ b/src/main/java/com/laytonsmith/abstraction/bukkit/events/drivers/BukkitWorldListener.java
@@ -15,21 +15,25 @@ public class BukkitWorldListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onStructureGrow(StructureGrowEvent event) {
- EventUtils.TriggerListener(Driver.TREE_GROW, "tree_grow", new BukkitWorldEvents.BukkitMCStructureGrowEvent(event));
+ EventUtils.TriggerListener(Driver.TREE_GROW, "tree_grow",
+ new BukkitWorldEvents.BukkitMCStructureGrowEvent(event));
}
@EventHandler(priority = EventPriority.LOWEST)
public void onWorldSave(WorldSaveEvent event) {
- EventUtils.TriggerListener(Driver.WORLD_SAVE, "world_save", new BukkitWorldEvents.BukkitMCWorldSaveEvent(event));
+ EventUtils.TriggerListener(Driver.WORLD_SAVE, "world_save",
+ new BukkitWorldEvents.BukkitMCWorldSaveEvent(event));
}
@EventHandler(priority = EventPriority.LOWEST)
public void onWorldUnload(WorldUnloadEvent event) {
- EventUtils.TriggerListener(Driver.WORLD_UNLOAD, "world_unload", new BukkitWorldEvents.BukkitMCWorldUnloadEvent(event));
+ EventUtils.TriggerListener(Driver.WORLD_UNLOAD, "world_unload",
+ new BukkitWorldEvents.BukkitMCWorldUnloadEvent(event));
}
@EventHandler(priority = EventPriority.LOWEST)
public void onWorldLoad(WorldLoadEvent event) {
- EventUtils.TriggerListener(Driver.WORLD_LOAD, "world_load", new BukkitWorldEvents.BukkitMCWorldLoadEvent(event));
+ EventUtils.TriggerListener(Driver.WORLD_LOAD, "world_load",
+ new BukkitWorldEvents.BukkitMCWorldLoadEvent(event));
}
}
diff --git a/src/main/java/com/laytonsmith/abstraction/events/MCSignChangeEvent.java b/src/main/java/com/laytonsmith/abstraction/events/MCSignChangeEvent.java
index eff7fcee8f..175c969a4d 100644
--- a/src/main/java/com/laytonsmith/abstraction/events/MCSignChangeEvent.java
+++ b/src/main/java/com/laytonsmith/abstraction/events/MCSignChangeEvent.java
@@ -5,6 +5,7 @@
import com.laytonsmith.abstraction.blocks.MCSign;
import com.laytonsmith.core.constructs.CArray;
import com.laytonsmith.core.constructs.CString;
+import com.laytonsmith.core.environments.Environment;
import com.laytonsmith.core.events.BindableEvent;
public interface MCSignChangeEvent extends BindableEvent {
@@ -19,7 +20,7 @@ public interface MCSignChangeEvent extends BindableEvent {
void setLines(String[] lines);
- CArray getLines();
+ CArray getLines(Environment env);
MCSign.Side getSide();
}
diff --git a/src/main/java/com/laytonsmith/core/AliasCore.java b/src/main/java/com/laytonsmith/core/AliasCore.java
index 8ce955878e..bc0edd5b62 100644
--- a/src/main/java/com/laytonsmith/core/AliasCore.java
+++ b/src/main/java/com/laytonsmith/core/AliasCore.java
@@ -88,6 +88,7 @@ public class AliasCore {
private final Set echoCommand = new HashSet<>();
private CompilerEnvironment compilerEnv;
private StaticRuntimeEnv staticRuntimeEnv;
+ private Environment env;
private List