package com.laytonsmith.core.functions;
import com.laytonsmith.PureUtilities.Common.ReflectionUtils;
import com.laytonsmith.PureUtilities.Common.StringUtils;
import com.laytonsmith.PureUtilities.Version;
import com.laytonsmith.annotations.MEnum;
import com.laytonsmith.annotations.api;
import com.laytonsmith.annotations.core;
import com.laytonsmith.annotations.seealso;
import com.laytonsmith.core.ArgumentValidation;
import com.laytonsmith.core.CHVersion;
import com.laytonsmith.core.Optimizable;
import com.laytonsmith.core.ParseTree;
import com.laytonsmith.core.Script;
import com.laytonsmith.core.Static;
import com.laytonsmith.core.compiler.FileOptions;
import com.laytonsmith.core.compiler.OptimizationUtilities;
import com.laytonsmith.core.constructs.CArray;
import com.laytonsmith.core.constructs.CDouble;
import com.laytonsmith.core.constructs.CFunction;
import com.laytonsmith.core.constructs.CInt;
import com.laytonsmith.core.constructs.CMutablePrimitive;
import com.laytonsmith.core.constructs.Construct;
import com.laytonsmith.core.constructs.IVariable;
import com.laytonsmith.core.constructs.Target;
import com.laytonsmith.core.environments.Environment;
import com.laytonsmith.core.environments.GlobalEnv;
import com.laytonsmith.core.exceptions.CRE.CRECastException;
import com.laytonsmith.core.exceptions.CRE.CREFormatException;
import com.laytonsmith.core.exceptions.CRE.CREInsufficientArgumentsException;
import com.laytonsmith.core.exceptions.CRE.CREPluginInternalException;
import com.laytonsmith.core.exceptions.CRE.CRERangeException;
import com.laytonsmith.core.exceptions.CRE.CREThrowable;
import com.laytonsmith.core.exceptions.CancelCommandException;
import com.laytonsmith.core.exceptions.ConfigCompileException;
import com.laytonsmith.core.exceptions.ConfigRuntimeException;
import com.laytonsmith.core.natives.interfaces.ArrayAccess;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
*/
@core
public class Math {
public static String docs() {
return "Provides mathematical functions to scripts";
}
@api
@seealso({subtract.class, multiply.class, divide.class})
public static class add extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "add";
}
@Override
public Integer[] numArgs() {
return new Integer[]{Integer.MAX_VALUE};
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
if (Static.anyDoubles(args)) {
double tally = Static.getNumber(args[0], t);
for (int i = 1; i < args.length; i++) {
tally += Static.getNumber(args[i], t);
}
return new CDouble(tally, t);
} else {
long tally = Static.getInt(args[0], t);
for (int i = 1; i < args.length; i++) {
tally += Static.getInt(args[i], t);
}
return new CInt(tally, t);
}
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public String docs() {
return "mixed {var1, [var2...]} Adds all the arguments together, and returns either a double or an integer."
+ " Operator syntax is also supported: @a + @b";
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_1;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Demonstrates adding two numbers together", "msg(add(2, 2))"),
new ExampleScript("Demonstrates adding two numbers together, using the operator syntax", "2 + 2"),
new ExampleScript("Demonstrates grouping with parenthesis", "(2 + 5) * 2"),
new ExampleScript("Demonstrates order of operations", "2 + 5 * 2"),
};
}
@Override
public ParseTree optimizeDynamic(Target t, List<ParseTree> children, FileOptions fileOptions) throws ConfigCompileException, ConfigRuntimeException {
OptimizationUtilities.pullUpLikeFunctions(children, this.getName());
return null;
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.OPTIMIZE_DYNAMIC,
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
@seealso({add.class, multiply.class, divide.class})
public static class subtract extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "subtract";
}
@Override
public Integer[] numArgs() {
return new Integer[]{Integer.MAX_VALUE};
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
if (Static.anyDoubles(args)) {
double tally = Static.getNumber(args[0], t);
for (int i = 1; i < args.length; i++) {
tally -= Static.getNumber(args[i], t);
}
return new CDouble(tally, t);
} else {
long tally = Static.getInt(args[0], t);
for (int i = 1; i < args.length; i++) {
tally -= Static.getInt(args[i], t);
}
return new CInt(tally, t);
}
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public String docs() {
return "mixed {var1, [var2...]} Subtracts the arguments from left to right, and returns either a double or an integer."
+ " Operator syntax is also supported: @a - @b";
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_1;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Demonstrates basic usage", "subtract(4 - 3)"),
new ExampleScript("Demonstrates operator syntax", "12 - 5"),};
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
@seealso({divide.class, add.class, subtract.class})
public static class multiply extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "multiply";
}
@Override
public Integer[] numArgs() {
return new Integer[]{Integer.MAX_VALUE};
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
if (Static.anyDoubles(args)) {
double tally = Static.getNumber(args[0], t);
for (int i = 1; i < args.length; i++) {
tally *= Static.getNumber(args[i], t);
}
return new CDouble(tally, t);
} else {
long tally = Static.getInt(args[0], t);
for (int i = 1; i < args.length; i++) {
tally *= Static.getInt(args[i], t);
}
return new CInt(tally, t);
}
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public String docs() {
return "mixed {var1, [var2...]} Multiplies the arguments together, and returns either a double or an integer. Operator syntax"
+ " is also supported: 2 * 2";
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_1;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public ParseTree optimizeDynamic(Target t, List<ParseTree> children, FileOptions fileOptions) throws ConfigCompileException, ConfigRuntimeException {
OptimizationUtilities.pullUpLikeFunctions(children, this.getName());
return null;
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Functional usage", "multiply(8, 8)"),
new ExampleScript("Operator syntax", "8 * 8"),};
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.OPTIMIZE_DYNAMIC,
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
@seealso({multiply.class, add.class, subtract.class})
public static class divide extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "divide";
}
@Override
public Integer[] numArgs() {
return new Integer[]{Integer.MAX_VALUE};
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
double tally = Static.getNumber(args[0], t);
for (int i = 1; i < args.length; i++) {
double next = Static.getNumber(args[i], t);
if (next == 0) {
throw new CRERangeException("Division by 0!", t);
}
tally /= next;
}
if (tally == (int) tally) {
return new CInt((long) tally, t);
} else {
return new CDouble(tally, t);
}
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CRERangeException.class};
}
@Override
public String docs() {
return "mixed {var1, [var2...]} Divides the arguments from left to right, and returns either a double or an integer."
+ " If you divide by zero, a RangeException is thrown. Operator syntax is also supported:"
+ " 2 / 2";
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_1;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Functional usage", "divide(4, 2)"),
new ExampleScript("Demonstrates double return", "divide(2, 4)"),
new ExampleScript("Operator syntax", "2 / 4"),
new ExampleScript("Demonstrates divide by zero error", "@zero = 0;\nmsg(1 / @zero);"),};
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class mod extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "mod";
}
@Override
public Integer[] numArgs() {
return new Integer[]{2};
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
long arg1 = Static.getInt(args[0], t);
long arg2 = Static.getInt(args[1], t);
if(arg2 == 0) {
throw new CRERangeException("Modulo by 0!", t);
}
return new CInt(arg1 % arg2, t);
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CRERangeException.class};
}
@Override
public String docs() {
return "int {x, n} Returns x modulo n. Throws a RangeException when n is 0. Operator syntax is also supported: @x % @n";
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_1;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Functional usage", "mod(2, 2)"),
new ExampleScript("Operator syntax", "2 % 2"),};
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class pow extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "pow";
}
@Override
public Integer[] numArgs() {
return new Integer[]{2};
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
double arg1 = Static.getNumber(args[0], t);
double arg2 = Static.getNumber(args[1], t);
return new CDouble(java.lang.Math.pow(arg1, arg2), t);
}
@Override
public String docs() {
return "double {x, n} Returns x to the power of n. Operator syntax is also supported: @x ** @n";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_1;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Functional usage", "pow(2, 4)"),
new ExampleScript("Operator syntax", "2 ** 4"),};
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
/**
* If we have the case {@code @array[0]++}, we have to increment it as
* though it were a variable, so we have to do that with execs. This method
* consolidates the code to do so.
* @return
*/
protected static Construct doIncrementDecrement(ParseTree[] nodes,
Script parent, Environment env, Target t,
Function func, boolean pre, boolean inc){
if(nodes[0].getData() instanceof CFunction){
Function f;
try {
f = ((CFunction)nodes[0].getData()).getFunction();
} catch (ConfigCompileException ex) {
// This can't really happen, as the compiler would have already caught this
throw new Error(ex);
}
if(f.getName().equals(new ArrayHandling.array_get().getName())){
//Ok, so, this is it, we're in charge here.
long temp;
long newVal;
//First, pull out the current value. We're gonna do this manually though, and we will actually
//skip the whole array_get execution.
ParseTree eval = nodes[0];
Construct array = parent.seval(eval.getChildAt(0), env);
Construct index = parent.seval(eval.getChildAt(1), env);
Construct cdelta = new CInt(1, t);
if(nodes.length == 2){
cdelta = parent.seval(nodes[1], env);
}
long delta = Static.getInt(cdelta, t);
//First, error check, then get the old value, and store it in temp.
if(!(array instanceof CArray) && !(array instanceof ArrayAccess)){
//Let's just evaluate this like normal with array_get, so it will
//throw the appropriate exception.
new ArrayHandling.array_get().exec(t, env, array, index);
throw ConfigRuntimeException.CreateUncatchableException("Shouldn't have gotten here. Please report this error, and how you got here.", t);
} else if(!(array instanceof CArray)){
//It's an ArrayAccess type, but we can't use that here, so, throw our
//own exception.
throw new CRECastException("Cannot increment/decrement a non-array array"
+ " accessed value. (The value passed in was \"" + array.val() + "\")", t);
} else {
//Ok, we're good. Data types should all be correct.
CArray myArray = ((CArray)array);
Construct value = myArray.get(index, t);
if(value instanceof CInt || value instanceof CDouble){
temp = Static.getInt(value, t);
//Alright, now let's actually perform the increment, and store that in the array.
if(inc){
newVal = temp + delta;
} else {
newVal = temp - delta;
}
new ArrayHandling.array_set().exec(t, env, array, index, new CInt(newVal, t));
} else {
throw new CRECastException("Cannot increment/decrement a non numeric value.", t);
}
}
long valueToReturn;
if(pre){
valueToReturn = newVal;
} else {
valueToReturn = temp;
}
return new CInt(valueToReturn, t);
}
}
Construct [] args = new Construct[nodes.length];
for(int i = 0; i < args.length; i++){
args[i] = parent.eval(nodes[i], env);
}
return func.exec(t, env, args);
}
@api
@seealso({dec.class, postdec.class, postinc.class})
public static class inc extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "inc";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public boolean useSpecialExec() {
return true;
}
@Override
public Construct execs(Target t, Environment env, Script parent, ParseTree... nodes) {
return doIncrementDecrement(nodes, parent, env, t, this, true, true);
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
long value = 1;
if (args.length == 2) {
if (args[1] instanceof IVariable) {
IVariable cur2 = (IVariable) args[1];
args[1] = env.getEnv(GlobalEnv.class).GetVarList().get(cur2.getVariableName(), cur2.getTarget());
}
value = Static.getInt(args[1], t);
}
if (args[0] instanceof IVariable) {
IVariable cur = (IVariable) args[0];
IVariable v = env.getEnv(GlobalEnv.class).GetVarList().get(cur.getVariableName(), cur.getTarget());
Construct newVal;
if (Static.anyDoubles(v.ival())) {
newVal = new CDouble(Static.getDouble(v.ival(), t) + value, t);
} else {
newVal = new CInt(Static.getInt(v.ival(), t) + value, t);
}
if(v.ival() instanceof CMutablePrimitive){
newVal = ((CMutablePrimitive)v.ival()).setAndReturn(newVal, t);
}
v = new IVariable(v.getDefinedType(), v.getVariableName(), newVal, t);
env.getEnv(GlobalEnv.class).GetVarList().set(v);
return v;
} else {
if (Static.anyDoubles(args[0])) {
return new CDouble(Static.getNumber(args[0], t) + value, t);
} else {
return new CInt(Static.getInt(args[0], t) + value, t);
}
}
}
@Override
public String docs() {
return "ivar {var, [x]} Adds x to var, and stores the new value. Equivalent to ++var in other languages. Expects ivar to be a variable, then"
+ " returns the ivar, or, if var is a constant number, simply adds x to it, and returns the new number. Operator syntax"
+ " is also supported: ++@var";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public boolean preResolveVariables() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_1;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Demonstrates basic usage", "@x = 0;\nmsg(@x);\ninc(@x);\nmsg(@x);"),
new ExampleScript("Demonstrates symbolic usage", "@x = 0;\n"
+ "msg(@x);\n"
+ "(++@x); // Note the use of parenthesis, which is required in this case, otherwise it applies to the previous operation\n"
+ "msg(@x);"),};
}
@Override
public Construct optimize(Target t, Construct... args) throws ConfigCompileException {
if(args[0] instanceof IVariable){
return null;
} else {
return exec(t, null, args);
}
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.OPTIMIZE_CONSTANT
);
}
}
@api
@seealso({postdec.class, inc.class, dec.class})
public static class postinc extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "postinc";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public boolean useSpecialExec() {
return true;
}
@Override
public Construct execs(Target t, Environment env, Script parent, ParseTree... nodes) {
return Math.doIncrementDecrement(nodes, parent, env, t, this, false, true);
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
long value = 1;
if (args.length == 2) {
if (args[1] instanceof IVariable) {
IVariable cur2 = (IVariable) args[1];
args[1] = env.getEnv(GlobalEnv.class).GetVarList().get(cur2.getVariableName(), cur2.getTarget());
}
value = Static.getInt(args[1], t);
}
if (args[0] instanceof IVariable) {
IVariable cur = (IVariable) args[0];
IVariable v = env.getEnv(GlobalEnv.class).GetVarList().get(cur.getVariableName(), cur.getTarget());
Construct newVal;
if (Static.anyDoubles(v.ival())) {
newVal = new CDouble(Static.getDouble(v.ival(), t) + value, t);
} else {
newVal = new CInt(Static.getInt(v.ival(), t) + value, t);
}
if(v.ival() instanceof CMutablePrimitive){
newVal = ((CMutablePrimitive)v.ival()).setAndReturn(newVal, t);
}
Construct oldVal = null;
try {
oldVal = v.ival().clone();
} catch (CloneNotSupportedException ex) {
Logger.getLogger(Math.class.getName()).log(Level.SEVERE, null, ex);
}
v = new IVariable(v.getDefinedType(), v.getVariableName(), newVal, t);
env.getEnv(GlobalEnv.class).GetVarList().set(v);
return oldVal;
} else {
if (Static.anyDoubles(args[0])) {
return new CDouble(Static.getNumber(args[0], t) + value, t);
} else {
return new CInt(Static.getInt(args[0], t) + value, t);
}
}
}
@Override
public String docs() {
return "ivar {var, [x]} Adds x to var, and stores the new value. Equivalent to var++ in other languages. Expects ivar to be a variable, then"
+ " returns a copy of the old ivar, or, if var is a constant number, simply adds x to it, and returns the new number. Operator"
+ " notation is also supported: @var++";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public boolean preResolveVariables() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct optimize(Target t, Construct... args) throws ConfigCompileException {
if(args[0] instanceof IVariable){
return null;
} else {
return exec(t, null, args);
}
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.OPTIMIZE_CONSTANT
);
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Basic functional usage", "@a = 5;\n"
+ "msg(postinc(@a));\n"
+ "msg(@a);"),
new ExampleScript("Basic functional usage, with optional value set", "@a = 5;\n"
+ "msg(postinc(@a, 6));\n"
+ "msg(@a);"),
new ExampleScript("Operator syntax", "@a = 5;\n"
+ "msg(@a++);\n"
+ "msg(@a);"),
};
}
}
@api
@seealso({inc.class, postdec.class, postinc.class})
public static class dec extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "dec";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public boolean useSpecialExec() {
return true;
}
@Override
public Construct execs(Target t, Environment env, Script parent, ParseTree... nodes) {
return doIncrementDecrement(nodes, parent, env, t, this, true, false);
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
long value = 1;
if (args.length == 2) {
if (args[1] instanceof IVariable) {
IVariable cur2 = (IVariable) args[1];
args[1] = env.getEnv(GlobalEnv.class).GetVarList().get(cur2.getVariableName(), cur2.getTarget());
}
value = Static.getInt(args[1], t);
}
if (args[0] instanceof IVariable) {
IVariable cur = (IVariable) args[0];
IVariable v = env.getEnv(GlobalEnv.class).GetVarList().get(cur.getVariableName(), cur.getTarget());
Construct newVal;
if (Static.anyDoubles(v.ival())) {
newVal = new CDouble(Static.getDouble(v.ival(), t) - value, t);
} else {
newVal = new CInt(Static.getInt(v.ival(), t) - value, t);
}
if(v.ival() instanceof CMutablePrimitive){
newVal = ((CMutablePrimitive)v.ival()).setAndReturn(newVal, t);
}
v = new IVariable(v.getDefinedType(), v.getVariableName(), newVal, t);
env.getEnv(GlobalEnv.class).GetVarList().set(v);
return v;
} else {
if (Static.anyDoubles(args[0])) {
return new CDouble(Static.getNumber(args[0], t) - value, t);
} else {
return new CInt(Static.getInt(args[0], t) - value, t);
}
}
}
@Override
public String docs() {
return "ivar {var, [value]} Subtracts value from var, and stores the new value. Value defaults to 1. Equivalent to --var (or var -= value) in other languages. Expects ivar to be a variable, then"
+ " returns the ivar, or if var is a constant number, simply adds x to it, and returns the new number. Operator"
+ " syntax is also supported: --@var";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public boolean preResolveVariables() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_1;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct optimize(Target t, Construct... args) throws ConfigCompileException {
if(args[0] instanceof IVariable){
return null;
} else {
return exec(t, null, args);
}
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.OPTIMIZE_CONSTANT
);
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Demonstrates basic usage", "@x = 1;\nmsg(@x);\ndec(@x);\nmsg(@x);"),
new ExampleScript("Demonstrates symbolic usage", "@x = 1;\n"
+ "msg(@x);\n"
+ "(--@x); // Note the use of parenthesis, which is required in this case, otherwise it applies to the previous operation\n"
+ "msg(@x);"),};
}
}
@api
@seealso({postinc.class, inc.class, dec.class})
public static class postdec extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "postdec";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public boolean useSpecialExec() {
return true;
}
@Override
public Construct execs(Target t, Environment env, Script parent, ParseTree... nodes) {
return doIncrementDecrement(nodes, parent, env, t, this, false, false);
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
long value = 1;
if (args.length == 2) {
if (args[1] instanceof IVariable) {
IVariable cur2 = (IVariable) args[1];
args[1] = env.getEnv(GlobalEnv.class).GetVarList().get(cur2.getVariableName(), cur2.getTarget());
}
value = Static.getInt(args[1], t);
}
if (args[0] instanceof IVariable) {
IVariable cur = (IVariable) args[0];
IVariable v = env.getEnv(GlobalEnv.class).GetVarList().get(cur.getVariableName(), cur.getTarget());
Construct newVal;
if (Static.anyDoubles(v.ival())) {
newVal = new CDouble(Static.getDouble(v.ival(), t) - value, t);
} else {
newVal = new CInt(Static.getInt(v.ival(), t) - value, t);
}
if(v.ival() instanceof CMutablePrimitive){
newVal = ((CMutablePrimitive)v.ival()).setAndReturn(newVal, t);
}
Construct oldVal = null;
try {
oldVal = v.ival().clone();
} catch (CloneNotSupportedException ex) {
Logger.getLogger(Math.class.getName()).log(Level.SEVERE, null, ex);
}
v = new IVariable(v.getDefinedType(), v.getVariableName(), newVal, t);
env.getEnv(GlobalEnv.class).GetVarList().set(v);
return oldVal;
} else {
if (Static.anyDoubles(args[0])) {
return new CDouble(Static.getNumber(args[0], t) - value, t);
} else {
return new CInt(Static.getInt(args[0], t) - value, t);
}
}
}
@Override
public String docs() {
return "ivar {var, [x]} Subtracts x from var, and stores the new value. Equivalent to var-- in other languages. Expects ivar to be a variable, then"
+ " returns a copy of the old ivar, , or, if var is a constant number, simply adds x to it, and returns the new number."
+ " Operator syntax is also supported: @var--";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public boolean preResolveVariables() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct optimize(Target t, Construct... args) throws ConfigCompileException {
if(args[0] instanceof IVariable){
return null;
} else {
return exec(t, null, args);
}
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.OPTIMIZE_CONSTANT
);
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Basic functional usage", "@a = 5;\n"
+ "msg(postdec(@a));\n"
+ "msg(@a);"),
new ExampleScript("Basic functional usage, with optional value set", "@a = 5;\n"
+ "msg(postdec(@a, 6));\n"
+ "msg(@a);"),
new ExampleScript("Operator syntax", "@a = 5;\n"
+ "msg(@a--);\n"
+ "msg(@a);"),
};
}
}
@api
public static class rand extends AbstractFunction {
Random r = new Random();
@Override
public String getName() {
return "rand";
}
@Override
public Integer[] numArgs() {
return new Integer[]{0, 1, 2};
}
@Override
public String docs() {
return "mixed {[] | min/max, [max]} Returns a random number from 0 to max, or min to max, depending on usage. Max is exclusive. Min must"
+ " be less than max, and both numbers must be >= 0. This will return an integer. Alternatively, you can pass no arguments, and a random"
+ " double, from 0 to 1 will be returned.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRERangeException.class, CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_1;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
if(args.length == 0){
return new CDouble(java.lang.Math.random(), t);
} else {
long min = 0;
long max = 0;
if (args.length == 1) {
max = Static.getInt(args[0], t);
} else {
min = Static.getInt(args[0], t);
max = Static.getInt(args[1], t);
}
if (max > Integer.MAX_VALUE || min > Integer.MAX_VALUE) {
throw new CRERangeException("max and min must be below int max, defined as " + Integer.MAX_VALUE,
t);
}
long range = max - min;
if (range <= 0) {
throw new CRERangeException("max - min must be greater than 0", t);
}
long rand = java.lang.Math.abs(r.nextLong());
long i = (rand % (range)) + min;
return new CInt(i, t);
}
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Basic usage, with one paramter", "rand(10)", ":5"),
new ExampleScript("Basic usage, with a range", "rand(50, 100)", ":95"),
new ExampleScript("Usage with no parameters", "rand()", ":0.720543709668052")
};
}
}
@api
public static class abs extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "abs";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "mixed {arg} Returns the absolute value of the argument.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_1_2;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
if (args[0] instanceof CInt){
return new CInt(java.lang.Math.abs(Static.getInt(args[0], t)), t);
}else{
return new CDouble(java.lang.Math.abs(Static.getDouble(args[0], t)), t);
}
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Demonstrates a positive number", "abs(5)"),
new ExampleScript("Demonstrates a negative number", "abs(-5)")
};
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class floor extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "floor";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "int {number} Returns the floor of any given number. For example, floor(3.8) returns 3, and floor(-1.1) returns 2";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_1_3;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CInt((long) java.lang.Math.floor(Static.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class ceil extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "ceil";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "int {number} Returns the ceiling of any given number. For example, ceil(3.2) returns 4, and ceil(-1.1) returns -1";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_1_3;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CInt((long) java.lang.Math.ceil(Static.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class sqrt extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "sqrt";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "number {number} Returns the square root of a number. Note that this is mathematically equivalent to pow(number, .5)."
+ " Imaginary numbers are not supported, so number must be positive.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRERangeException.class, CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_2_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
double d = Static.getNumber(args[0], t);
if (d < 0) {
throw new CRERangeException("sqrt expects a number >= 0", t);
}
double m = java.lang.Math.sqrt(d);
if (m == (int) m) {
return new CInt((long) m, t);
} else {
return new CDouble(m, t);
}
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class min extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "min";
}
@Override
public Integer[] numArgs() {
return new Integer[]{Integer.MAX_VALUE};
}
@Override
public String docs() {
return "number {num1, [num2...]} Returns the lowest number in a given list of numbers. If any of the arguments"
+ " are arrays, they are expanded into individual numbers, and also compared.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREInsufficientArgumentsException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_2_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
if (args.length == 0) {
throw new CREInsufficientArgumentsException("You must send at least one parameter to min", t);
}
double lowest = Double.POSITIVE_INFINITY;
List<Construct> list = new ArrayList<Construct>();
recList(list, args);
for (Construct c : list) {
double d = Static.getNumber(c, t);
if (d < lowest) {
lowest = d;
}
}
if (lowest == (long) lowest) {
return new CInt((long) lowest, t);
} else {
return new CDouble(lowest, t);
}
}
public List<Construct> recList(List<Construct> list, Construct... args) {
for (Construct c : args) {
if (c instanceof CArray) {
for (int i = 0; i < ((CArray) c).size(); i++) {
recList(list, ((CArray) c).get(i, Target.UNKNOWN));
}
} else {
list.add(c);
}
}
return list;
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class max extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "max";
}
@Override
public Integer[] numArgs() {
return new Integer[]{Integer.MAX_VALUE};
}
@Override
public String docs() {
return "number {num1, [num2...]} Returns the highest number in a given list of numbers. If any of the arguments"
+ " are arrays, they are expanded into individual numbers, and also compared.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREInsufficientArgumentsException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_2_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
if (args.length == 0) {
throw new CREInsufficientArgumentsException("You must send at least one parameter to max", t);
}
double highest = Double.NEGATIVE_INFINITY;
List<Construct> list = new ArrayList<Construct>();
recList(list, args);
for (Construct c : list) {
double d = Static.getNumber(c, t);
if (d > highest) {
highest = d;
}
}
if (highest == (long) highest) {
return new CInt((long) highest, t);
} else {
return new CDouble(highest, t);
}
}
public List<Construct> recList(List<Construct> list, Construct... args) {
for (Construct c : args) {
if (c instanceof CArray) {
for (int i = 0; i < ((CArray) c).size(); i++) {
recList(list, ((CArray) c).get(i, Target.UNKNOWN));
}
} else {
list.add(c);
}
}
return list;
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class sin extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "sin";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Returns the sin of the number";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CDouble(java.lang.Math.sin(Static.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class cos extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "cos";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Returns the cos of the number";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CDouble(java.lang.Math.cos(Static.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class tan extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "tan";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Returns the tan of the number";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CDouble(java.lang.Math.tan(Static.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class asin extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "asin";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Returns the arc sin of the number";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CDouble(java.lang.Math.asin(Static.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class acos extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "acos";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Returns the arc cos of the number";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CDouble(java.lang.Math.acos(Static.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class atan extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "atan";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Returns the arc tan of the number";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CDouble(java.lang.Math.atan(Static.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class sinh extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "sinh";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Returns the hyperbolic sine of the number";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public Version since() {
return CHVersion.V3_3_2;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return Static.getNumber(java.lang.Math.sinh(ArgumentValidation.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class cosh extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "cosh";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Returns the hyperbolic cosine of the number";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public Version since() {
return CHVersion.V3_3_2;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return Static.getNumber(java.lang.Math.cosh(ArgumentValidation.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
Optimizable.OptimizationOption.CONSTANT_OFFLINE,
Optimizable.OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class tanh extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "tanh";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Returns the hyperbolic tangent of the number";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public Version since() {
return CHVersion.V3_3_2;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return Static.getNumber(java.lang.Math.tanh(ArgumentValidation.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
Optimizable.OptimizationOption.CONSTANT_OFFLINE,
Optimizable.OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class to_radians extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "to_radians";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Converts the number to radians (which is assumed to have been in degrees)";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CDouble(java.lang.Math.toRadians(Static.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class to_degrees extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "to_degrees";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {number} Converts the number to degrees (which is assumed to have been in radians)";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CDouble(java.lang.Math.toDegrees(Static.getNumber(args[0], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class atan2 extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "atan2";
}
@Override
public Integer[] numArgs() {
return new Integer[]{2};
}
@Override
public String docs() {
//lolcopypaste
return "double {y, x} Returns the angle theta from the conversion"
+ " of rectangular coordinates (x, y) to polar coordinates"
+ " (r, theta). This method computes the phase theta by"
+ " computing an arc tangent of y/x in the range of -pi to pi.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CDouble(java.lang.Math.atan2(Static.getNumber(args[0], t), Static.getNumber(args[1], t)), t);
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class round extends AbstractFunction implements Optimizable{
@Override
public String getName() {
return "round";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public String docs() {
return "double {number, [precision]} Unlike floor and ceil, rounds the number to the nearest double that is equal to an integer. Precision defaults to 0, but if set to 1 or more, rounds decimal places."
+ " For instance, round(2.29, 1) would return 2.3. If precision is < 0, a RangeException is thrown.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CRERangeException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
double number = Static.getNumber(args[0], t);
int precision = 0;
if(args.length > 1){
precision = Static.getInt32(args[1], t);
}
if(precision < 0){
throw new CRERangeException("precision cannot be less than 0, was " + precision, t);
}
number = number * java.lang.Math.pow(10, precision);
number = java.lang.Math.round(number);
number = number / java.lang.Math.pow(10, precision);
return new CDouble(number, t);
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Rounding up", "round(2.5)"),
new ExampleScript("Rounding down", "round(2.229)"),
new ExampleScript("Higher precision round", "round(2.229, 2)"),
};
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class round15 extends AbstractFunction implements Optimizable {
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
double x = Static.getDouble(args[0], t) + 1;
DecimalFormat twoDForm = new DecimalFormat("0.##############E0");
String str = twoDForm.format(x);
double d = Double.valueOf(str) - 1;
return new CDouble(d, t);
}
@Override
public String getName() {
return "round15";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "double {value} Rounds value to the 15th place. This is useful when doing math using approximations. For instance,"
+ " sin(math_const('PI')) returns 1.2246467991473532E-16, but sin of pi is actually 0. This happens because"
+ " pi cannot be accurately represented on a computer, it is an approximation. Using round15, you can round to the"
+ " next nearest value, which often time should give a more useful answer to display. For instance,"
+ " round15(sin(math_const('PI'))) is 0. This functionality is not provided by default in methods like sin(),"
+ " because it technically makes the result less accurate, given the inputs. In general, you should only use this"
+ " function just before displaying the value to the user. Internally, you should keep the value returned by the input"
+ " functions.";
}
@Override
public Version since() {
return CHVersion.V3_3_2;
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Without round15", "sin(math_const('PI'));"),
new ExampleScript("With round15", "round15(sin(math_const('PI')));")
};
}
}
@api
public static class expr extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "expr";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public String docs() {
return "double {expression, [valueArray]} Sometimes, when you need to calculate an advanced"
+ " mathematical expression, it is messy to write out everything in terms of functions."
+ " This function will allow you to evaluate a mathematical expression as a string, using"
+ " common mathematical notation. For example, (2 + 3) * 4 would return 20. Variables can"
+ " also be included, and their values given as an associative array. expr('(x + y) * z',"
+ " array(x: 2, y: 3, z: 4)) would be the same thing as the above example."
+ " This function requires WorldEdit in plugins, lib, or the server root in order to run.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CREFormatException.class, CRECastException.class, CREPluginInternalException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
String expr = args[0].val().trim();
if("".equals(expr)){
throw new CREFormatException("Expression may not be empty", t);
}
CArray vars = null;
if (args.length == 2 && args[1] instanceof CArray) {
vars = (CArray) args[1];
} else if (args.length == 2 && !(args[1] instanceof CArray)) {
throw new CRECastException("The second argument of expr() should be an array", t);
}
if (vars != null && !vars.inAssociativeMode()) {
throw new CRECastException("The array provided to expr() must be an associative array", t);
}
double[] da;
String[] varNames;
if (vars != null) {
int i = 0;
da = new double[(int)vars.size()];
varNames = new String[(int)vars.size()];
for (String key : vars.stringKeySet()) {
varNames[i] = key;
da[i] = Static.getDouble(vars.get(key, t), t);
i++;
}
} else {
da = new double[0];
varNames = new String[0];
}
/*try {
Expression e = Expression.compile(expr, varNames);
return new CDouble(e.evaluate(da), t);
} catch (ExpressionException ex) {
throw new CREPluginInternalException("Your expression was invalidly formatted", t, ex);
}*/
String eClass = "com.sk89q.worldedit.internal.expression.Expression";
String errClass = "com.sk89q.worldedit.internal.expression.ExpressionException";
Class eClazz, errClazz;
try {
eClazz = Class.forName(eClass);
errClazz = Class.forName(errClass);
} catch (ClassNotFoundException cnf) {
throw new CREPluginInternalException("You are missing a required dependency: " + eClass, t);
}
try {
Object e = ReflectionUtils.invokeMethod(eClazz, null, "compile",
new Class[]{String.class, String[].class}, new Object[]{expr, varNames});
Object d = ReflectionUtils.invokeMethod(eClazz, e, "evaluate",
new Class[]{double[].class}, new Object[]{da});
return new CDouble((double) d, t);
} catch (ReflectionUtils.ReflectionException rex) {
if (rex.getCause().getClass().isAssignableFrom(errClazz)) {
throw new CREPluginInternalException("Your expression was invalidly formatted", args[0].getTarget(), rex.getCause());
} else {
throw new CREPluginInternalException(rex.getMessage(),
args[0].getTarget(), rex.getCause());
}
}
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class neg extends AbstractFunction implements Optimizable {
@Override
public String getName() {
return "neg";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "number {number} Negates a number, essentially multiplying the number by -1";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
if (args[0] instanceof CInt) {
return new CInt(-(Static.getInt(args[0], t)), t);
} else {
return new CDouble(-(Static.getDouble(args[0], t)), t);
}
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(
OptimizationOption.CONSTANT_OFFLINE,
OptimizationOption.CACHE_RETURN
);
}
}
@api
public static class logarithm extends AbstractFunction implements Optimizable {
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CRERangeException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public Boolean runAsync() {
return null;
}
@Override
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
double val = Static.getDouble(args[0], t);
if(val <= 0){
throw new CRERangeException("val was <= 0", t);
}
double r;
if(args.length == 1){
r = java.lang.Math.log(val);
} else {// if(args.length == 2){
r = java.lang.Math.log(val) / java.lang.Math.log(Static.getDouble(args[1], t));
}
return new CDouble(r, t);
}
@Override
public String getName() {
return "logarithm";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public String docs() {
return "double {val, [base]} Return the log of a number to the specified base, or the mathematical"
+ " constant e if no base is provided (or ln). If val is less than or equal to zero, a RangeException is thrown."
+ " Mathematically speaking, if val is 0, then the result would be negative infinity, and if it"
+ " is less than 0 it is undefined (NaN), but since MethodScript has no way of representing either"
+ " of these, a RangeException is thrown instead.";
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(OptimizationOption.CONSTANT_OFFLINE);
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("log base e (mathematical equivalent of ln)", "logarithm(1)"),
new ExampleScript("log base e (mathematical equivalent of ln)", "logarithm(3)"),
new ExampleScript("log base 10", "logarithm(100)"),
new ExampleScript("log base 10", "logarithm(1000)"),
new ExampleScript("log base n", "logarithm(123, 3)"),
new ExampleScript("Error condition", "logarithm(0)"),
new ExampleScript("Error condition", "logarithm(-1)"),
};
}
}
@api
public static class math_const extends AbstractFunction implements Optimizable {
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public Boolean runAsync() {
return null;
}
@MEnum("MathConstants")
public static enum MathConstants {
NaN(Double.NaN, "A representation of an undefinied number (Not a Number), per the IEEE 754 standard"),
NEGATIVE_INFINITY(Double.NEGATIVE_INFINITY, "A representation of negative infinity, per the IEEE 754 standard"),
INFINITY(Double.POSITIVE_INFINITY, "A representation of positive infinity, per the IEEE 754 standard"),
DOUBLE_MAX(Double.MAX_VALUE, "The higest number that can be represented as a double"),
DOUBLE_MIN(Double.MIN_VALUE, "The lowest number that can be represented as a double"),
LONG_MAX(Long.MAX_VALUE, "The higest number that can be represented as a long"),
LONG_MIN(Long.MIN_VALUE, "The lowest number that can be represented as a long"),
SHORT_MAX(Short.MAX_VALUE, "The higest number that can be represented as a short"),
SHORT_MIN(Short.MIN_VALUE, "The lowest number that can be represented as a short"),
INTEGER_MAX(Integer.MAX_VALUE, "The higest number that can be represented as a integer"),
INTEGER_MIN(Integer.MIN_VALUE, "The lowest number that can be represented as an integer"),
FLOAT_MAX(Float.MAX_VALUE, "The higest number that can be represented as a float"),
FLOAT_MIN(Float.MIN_VALUE, "The lowest number that can be represented as a float"),
BYTE_MAX(Byte.MAX_VALUE, "The higest number that can be represented as a byte"),
BYTE_MIN(Byte.MIN_VALUE, "The lowest number that can be represented as a byte"),
E(java.lang.Math.E, "The mathematical constant e, also known as Euler's number (not to be confused with the Euler-Mascheroni constant)"),
PI(java.lang.Math.PI, "The value of π (pi)"),
PHI(1.6180339887498948482045868343656381177203091798057628621, "The golden ratio"),
C(2.99792458e8, "The speed of light in a vacuum, in meters per second"),
EULER(0.5772156649015627, "The Euler-Mascheroni constant γ (not to be confused with e)")
;
private final Number value;
private final String doc;
private MathConstants(Number value, String doc){
this.value = value;
this.doc = doc;
}
public Number getValue(){
return this.value;
}
public String getDoc(){
return doc;
}
}
@Override
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
try {
MathConstants c = MathConstants.valueOf(args[0].val());
Number v = c.getValue();
if(v instanceof Double){
return new CDouble((Double)c.getValue(), t);
} else {
return new CInt((Integer)c.getValue(), t);
}
} catch(IllegalArgumentException ex){
throw new CRECastException("No constant with the value " + args[0].val() + " exists.", t);
}
}
@Override
public String getName() {
return "math_const";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
String docs = "number {constant} Returns the value of various math constants. The constant argument must be one of the following: "
+ StringUtils.Join(MathConstants.values(), ", ", ", or ") + "\n";
docs += "---- The following table lists the values, and a brief description of each:\n"
+ "{| cellspacing=\"1\" cellpadding=\"1\" border=\"1\" class=\"wikitable\"\n"
+ "|-\n"
+ "! Constant Name\n"
+ "! Description\n"
+ "! Value\n";
for(MathConstants value : MathConstants.values()){
docs += "|-\n"
+ "| " + value.name() + "\n"
+ "| " + value.getDoc() + "\n"
+ "| " + value.getValue() + "\n";
}
docs += "|}\n\n"
+ "Note that this function is optimized, and when given a constant value for the parameter, is resolved at compile time.";
return docs;
}
@Override
public Version since() {
return CHVersion.V3_3_1;
}
@Override
public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(OptimizationOption.CONSTANT_OFFLINE);
}
@Override
public ExampleScript[] examples() throws ConfigCompileException {
return new ExampleScript[]{
new ExampleScript("Basic usage", "math_const('PI');")
};
}
}
}