semi-auto cleanup
This commit is contained in:
1 parent
cad80f82c6
commit
8f61271606
99 files changed
+11463
-8007
No files matched your search
@@ -8,16 +8,17 @@ import carpet.script.value.ListValue;
|
||||
import carpet.script.value.NumericValue;
|
||||
import carpet.script.value.Value;
|
||||
|
||||
public class Arithmetic {
|
||||
public class Arithmetic
|
||||
{
|
||||
public static final Value PI = new NumericValue(Math.PI);
|
||||
public static final Value euler = new NumericValue(Math.E);
|
||||
|
||||
public static void apply(Expression expression)
|
||||
public static void apply(final Expression expression)
|
||||
{
|
||||
expression.addTypedContextFunction("not", 1, Context.Type.BOOLEAN, (c, t, lv) -> BooleanValue.of(lv.get(0).getBoolean()) );
|
||||
expression.addTypedContextFunction("not", 1, Context.Type.BOOLEAN, (c, t, lv) -> BooleanValue.of(lv.get(0).getBoolean()));
|
||||
expression.addUnaryFunction("fact", (v) ->
|
||||
{
|
||||
long number = NumericValue.asNumber(v).getLong();
|
||||
final long number = NumericValue.asNumber(v).getLong();
|
||||
if (number < 21)
|
||||
{
|
||||
long factorial = 1;
|
||||
@@ -40,72 +41,81 @@ public class Arithmetic {
|
||||
return new NumericValue(factorial);
|
||||
|
||||
});
|
||||
expression.addMathematicalUnaryFunction("sin", (d) -> Math.sin(Math.toRadians(d)));
|
||||
expression.addMathematicalUnaryFunction("cos", (d) -> Math.cos(Math.toRadians(d)));
|
||||
expression.addMathematicalUnaryFunction("tan", (d) -> Math.tan(Math.toRadians(d)));
|
||||
expression.addMathematicalUnaryFunction("asin", (d) -> Math.toDegrees(Math.asin(d)));
|
||||
expression.addMathematicalUnaryFunction("acos", (d) -> Math.toDegrees(Math.acos(d)));
|
||||
expression.addMathematicalUnaryFunction("atan", (d) -> Math.toDegrees(Math.atan(d)));
|
||||
expression.addMathematicalBinaryFunction("atan2", (d, d2) -> Math.toDegrees(Math.atan2(d, d2)) );
|
||||
expression.addMathematicalUnaryFunction("sinh", Math::sinh );
|
||||
expression.addMathematicalUnaryFunction("cosh", Math::cosh );
|
||||
expression.addMathematicalUnaryFunction("tanh", Math::tanh );
|
||||
expression.addMathematicalUnaryFunction("sec", (d) -> 1.0 / Math.cos(Math.toRadians(d)) ); // Formula: sec(x) = 1 / cos(x)
|
||||
expression.addMathematicalUnaryFunction("csc", (d) -> 1.0 / Math.sin(Math.toRadians(d)) ); // Formula: csc(x) = 1 / sin(x)
|
||||
expression.addMathematicalUnaryFunction("sech", (d) -> 1.0 / Math.cosh(d) ); // Formula: sech(x) = 1 / cosh(x)
|
||||
expression.addMathematicalUnaryFunction("csch", (d) -> 1.0 / Math.sinh(d) ); // Formula: csch(x) = 1 / sinh(x)
|
||||
expression.addMathematicalUnaryFunction("cot", (d) -> 1.0 / Math.tan(Math.toRadians(d)) ); // Formula: cot(x) = cos(x) / sin(x) = 1 / tan(x)
|
||||
expression.addMathematicalUnaryFunction("acot", (d) -> Math.toDegrees(Math.atan(1.0 / d)) );// Formula: acot(x) = atan(1/x)
|
||||
expression.addMathematicalUnaryFunction("coth", (d) -> 1.0 / Math.tanh(d) ); // Formula: coth(x) = 1 / tanh(x)
|
||||
expression.addMathematicalUnaryFunction("asinh", (d) -> Math.log(d + (Math.sqrt(Math.pow(d, 2) + 1)))); // Formula: asinh(x) = ln(x + sqrt(x^2 + 1))
|
||||
expression.addMathematicalUnaryFunction("acosh", (d) -> Math.log(d + (Math.sqrt(Math.pow(d, 2) - 1)))); // Formula: acosh(x) = ln(x + sqrt(x^2 - 1))
|
||||
expression.addMathematicalUnaryFunction("atanh", (d) -> // Formula: atanh(x) = 0.5*ln((1 + x)/(1 - x))
|
||||
expression.addMathematicalUnaryFunction("sin", d -> Math.sin(Math.toRadians(d)));
|
||||
expression.addMathematicalUnaryFunction("cos", d -> Math.cos(Math.toRadians(d)));
|
||||
expression.addMathematicalUnaryFunction("tan", d -> Math.tan(Math.toRadians(d)));
|
||||
expression.addMathematicalUnaryFunction("asin", d -> Math.toDegrees(Math.asin(d)));
|
||||
expression.addMathematicalUnaryFunction("acos", d -> Math.toDegrees(Math.acos(d)));
|
||||
expression.addMathematicalUnaryFunction("atan", d -> Math.toDegrees(Math.atan(d)));
|
||||
expression.addMathematicalBinaryFunction("atan2", (d, d2) -> Math.toDegrees(Math.atan2(d, d2)));
|
||||
expression.addMathematicalUnaryFunction("sinh", Math::sinh);
|
||||
expression.addMathematicalUnaryFunction("cosh", Math::cosh);
|
||||
expression.addMathematicalUnaryFunction("tanh", Math::tanh);
|
||||
expression.addMathematicalUnaryFunction("sec", d -> 1.0 / Math.cos(Math.toRadians(d))); // Formula: sec(x) = 1 / cos(x)
|
||||
expression.addMathematicalUnaryFunction("csc", d -> 1.0 / Math.sin(Math.toRadians(d))); // Formula: csc(x) = 1 / sin(x)
|
||||
expression.addMathematicalUnaryFunction("sech", d -> 1.0 / Math.cosh(d)); // Formula: sech(x) = 1 / cosh(x)
|
||||
expression.addMathematicalUnaryFunction("csch", d -> 1.0 / Math.sinh(d)); // Formula: csch(x) = 1 / sinh(x)
|
||||
expression.addMathematicalUnaryFunction("cot", d -> 1.0 / Math.tan(Math.toRadians(d))); // Formula: cot(x) = cos(x) / sin(x) = 1 / tan(x)
|
||||
expression.addMathematicalUnaryFunction("acot", d -> Math.toDegrees(Math.atan(1.0 / d)));// Formula: acot(x) = atan(1/x)
|
||||
expression.addMathematicalUnaryFunction("coth", d -> 1.0 / Math.tanh(d)); // Formula: coth(x) = 1 / tanh(x)
|
||||
expression.addMathematicalUnaryFunction("asinh", d -> Math.log(d + (Math.sqrt(Math.pow(d, 2) + 1)))); // Formula: asinh(x) = ln(x + sqrt(x^2 + 1))
|
||||
expression.addMathematicalUnaryFunction("acosh", d -> Math.log(d + (Math.sqrt(Math.pow(d, 2) - 1)))); // Formula: acosh(x) = ln(x + sqrt(x^2 - 1))
|
||||
expression.addMathematicalUnaryFunction("atanh", d -> // Formula: atanh(x) = 0.5*ln((1 + x)/(1 - x))
|
||||
{
|
||||
if (Math.abs(d) > 1 || Math.abs(d) == 1)
|
||||
{
|
||||
throw new InternalExpressionException("Number must be |x| < 1");
|
||||
}
|
||||
return 0.5 * Math.log((1 + d) / (1 - d));
|
||||
});
|
||||
expression.addMathematicalUnaryFunction("rad", Math::toRadians);
|
||||
expression.addMathematicalUnaryFunction("rad", Math::toRadians);
|
||||
expression.addMathematicalUnaryFunction("deg", Math::toDegrees);
|
||||
expression.addMathematicalUnaryFunction("ln", Math::log);
|
||||
expression.addMathematicalUnaryFunction("ln1p", Math::log1p);
|
||||
expression.addMathematicalUnaryFunction("log10", Math::log10);
|
||||
expression.addMathematicalUnaryFunction("log", a -> Math.log(a)/Math.log(2));
|
||||
expression.addMathematicalUnaryFunction("log1p", x -> Math.log1p(x)/Math.log(2));
|
||||
expression.addMathematicalUnaryFunction("log", a -> Math.log(a) / Math.log(2));
|
||||
expression.addMathematicalUnaryFunction("log1p", x -> Math.log1p(x) / Math.log(2));
|
||||
expression.addMathematicalUnaryFunction("sqrt", Math::sqrt);
|
||||
expression.addMathematicalUnaryFunction("abs", Math::abs);
|
||||
expression.addMathematicalUnaryIntFunction("round", Math::round);
|
||||
expression.addMathematicalUnaryIntFunction("floor", n -> (long)Math.floor(n));
|
||||
expression.addMathematicalUnaryIntFunction("ceil", n -> (long)Math.ceil(n));
|
||||
expression.addMathematicalUnaryIntFunction("floor", n -> (long) Math.floor(n));
|
||||
expression.addMathematicalUnaryIntFunction("ceil", n -> (long) Math.ceil(n));
|
||||
|
||||
expression.addContextFunction("mandelbrot", 3, (c, t, lv) -> {
|
||||
double a0 = NumericValue.asNumber(lv.get(0)).getDouble();
|
||||
double b0 = NumericValue.asNumber(lv.get(1)).getDouble();
|
||||
long maxiter = NumericValue.asNumber(lv.get(2)).getLong();
|
||||
final double a0 = NumericValue.asNumber(lv.get(0)).getDouble();
|
||||
final double b0 = NumericValue.asNumber(lv.get(1)).getDouble();
|
||||
final long maxiter = NumericValue.asNumber(lv.get(2)).getLong();
|
||||
double a = 0.0D;
|
||||
double b = 0.0D;
|
||||
long iter = 0;
|
||||
while(a*a+b*b<4 && iter < maxiter)
|
||||
while (a * a + b * b < 4 && iter < maxiter)
|
||||
{
|
||||
double temp = a*a-b*b+a0;
|
||||
b = 2*a*b+b0;
|
||||
final double temp = a * a - b * b + a0;
|
||||
b = 2 * a * b + b0;
|
||||
a = temp;
|
||||
iter++;
|
||||
}
|
||||
long iFinal = iter;
|
||||
final long iFinal = iter;
|
||||
return new NumericValue(iFinal);
|
||||
});
|
||||
|
||||
expression.addFunction("max", (lv) ->
|
||||
{
|
||||
if (lv.size() == 0)
|
||||
throw new InternalExpressionException("'max' requires at least one parameter");
|
||||
Value max = null;
|
||||
if (lv.size()==1 && lv.get(0) instanceof ListValue)
|
||||
lv = ((ListValue) lv.get(0)).getItems();
|
||||
for (Value parameter : lv)
|
||||
{
|
||||
if (max == null || parameter.compareTo(max) > 0) max = parameter;
|
||||
throw new InternalExpressionException("'max' requires at least one parameter");
|
||||
}
|
||||
Value max = null;
|
||||
if (lv.size() == 1 && lv.get(0) instanceof ListValue)
|
||||
{
|
||||
lv = ((ListValue) lv.get(0)).getItems();
|
||||
}
|
||||
for (final Value parameter : lv)
|
||||
{
|
||||
if (max == null || parameter.compareTo(max) > 0)
|
||||
{
|
||||
max = parameter;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
});
|
||||
@@ -113,17 +123,24 @@ public class Arithmetic {
|
||||
expression.addFunction("min", (lv) ->
|
||||
{
|
||||
if (lv.size() == 0)
|
||||
throw new InternalExpressionException("'min' requires at least one parameter");
|
||||
Value min = null;
|
||||
if (lv.size()==1 && lv.get(0) instanceof ListValue)
|
||||
lv = ((ListValue) lv.get(0)).getItems();
|
||||
for (Value parameter : lv)
|
||||
{
|
||||
if (min == null || parameter.compareTo(min) < 0) min = parameter;
|
||||
throw new InternalExpressionException("'min' requires at least one parameter");
|
||||
}
|
||||
Value min = null;
|
||||
if (lv.size() == 1 && lv.get(0) instanceof ListValue)
|
||||
{
|
||||
lv = ((ListValue) lv.get(0)).getItems();
|
||||
}
|
||||
for (final Value parameter : lv)
|
||||
{
|
||||
if (min == null || parameter.compareTo(min) < 0)
|
||||
{
|
||||
min = parameter;
|
||||
}
|
||||
}
|
||||
return min;
|
||||
});
|
||||
|
||||
expression.addUnaryFunction("relu", (v) -> v.compareTo(Value.ZERO) < 0 ? Value.ZERO : v);
|
||||
expression.addUnaryFunction("relu", v -> v.compareTo(Value.ZERO) < 0 ? Value.ZERO : v);
|
||||
}
|
||||
}
|
||||
@@ -17,21 +17,25 @@ import carpet.script.value.Value;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ControlFlow {
|
||||
public static void apply(Expression expression) // public just to get the javadoc right
|
||||
public class ControlFlow
|
||||
{
|
||||
public static void apply(final Expression expression) // public just to get the javadoc right
|
||||
{
|
||||
// needs to be lazy cause of custom contextualization
|
||||
expression.addLazyBinaryOperator(";", Operators.precedence.get("nextop;"), true, true, t -> Context.Type.VOID, (c, t, lv1, lv2) ->
|
||||
{
|
||||
lv1.evalValue(c, Context.VOID);
|
||||
Value v2 = lv2.evalValue(c, t);
|
||||
final Value v2 = lv2.evalValue(c, t);
|
||||
return (cc, tt) -> v2;
|
||||
});
|
||||
|
||||
expression.addPureLazyFunction("then", -1, t -> Context.Type.VOID, (c, t, lv) -> {
|
||||
int imax = lv.size()-1;
|
||||
for (int i = 0; i < imax; i++) lv.get(i).evalValue(c, Context.VOID);
|
||||
Value v = lv.get(imax).evalValue(c, t);
|
||||
final int imax = lv.size() - 1;
|
||||
for (int i = 0; i < imax; i++)
|
||||
{
|
||||
lv.get(i).evalValue(c, Context.VOID);
|
||||
}
|
||||
final Value v = lv.get(imax).evalValue(c, t);
|
||||
return (cc, tt) -> v;
|
||||
});
|
||||
expression.addFunctionalEquivalence(";", "then");
|
||||
@@ -40,78 +44,80 @@ public class ControlFlow {
|
||||
// obvious lazy due to conditional evaluation of arguments
|
||||
expression.addLazyFunction("if", (c, t, lv) ->
|
||||
{
|
||||
if ( lv.size() < 2 )
|
||||
if (lv.size() < 2)
|
||||
{
|
||||
throw new InternalExpressionException("'if' statement needs to have at least one condition and one case");
|
||||
for (int i=0; i<lv.size()-1; i+=2)
|
||||
}
|
||||
for (int i = 0; i < lv.size() - 1; i += 2)
|
||||
{
|
||||
if (lv.get(i).evalValue(c, Context.BOOLEAN).getBoolean())
|
||||
{
|
||||
//int iFinal = i;
|
||||
Value ret = lv.get(i+1).evalValue(c, t);
|
||||
final Value ret = lv.get(i + 1).evalValue(c, t);
|
||||
return (cc, tt) -> ret;
|
||||
}
|
||||
}
|
||||
if (lv.size()%2 == 1)
|
||||
if (lv.size() % 2 == 1)
|
||||
{
|
||||
Value ret = lv.get(lv.size() - 1).evalValue(c, t);
|
||||
final Value ret = lv.get(lv.size() - 1).evalValue(c, t);
|
||||
return (cc, tt) -> ret;
|
||||
}
|
||||
return (cc, tt) -> Value.NULL;
|
||||
});
|
||||
|
||||
expression.addImpureFunction("exit", (lv) -> { throw new ExitStatement(lv.size()==0?Value.NULL:lv.get(0)); });
|
||||
expression.addImpureFunction("exit", (lv) -> {
|
||||
throw new ExitStatement(lv.size() == 0 ? Value.NULL : lv.get(0));
|
||||
});
|
||||
|
||||
expression.addImpureFunction("throw", lv->
|
||||
expression.addImpureFunction("throw", lv ->
|
||||
{
|
||||
switch (lv.size())
|
||||
switch (lv.size())
|
||||
{
|
||||
case 0:
|
||||
throw new ThrowStatement(Value.NULL, Throwables.USER_DEFINED);
|
||||
case 1:
|
||||
throw new ThrowStatement(lv.get(0), Throwables.USER_DEFINED );
|
||||
case 2:
|
||||
throw new ThrowStatement(lv.get(1), Throwables.getTypeForException(lv.get(0).getString()));
|
||||
case 3:
|
||||
throw new ThrowStatement(lv.get(2), Throwables.getTypeForException(lv.get(1).getString()), lv.get(0).getString());
|
||||
default:
|
||||
throw new InternalExpressionException("throw() can't accept more than 3 parameters");
|
||||
case 0 -> throw new ThrowStatement(Value.NULL, Throwables.USER_DEFINED);
|
||||
case 1 -> throw new ThrowStatement(lv.get(0), Throwables.USER_DEFINED);
|
||||
case 2 -> throw new ThrowStatement(lv.get(1), Throwables.getTypeForException(lv.get(0).getString()));
|
||||
case 3 -> throw new ThrowStatement(lv.get(2), Throwables.getTypeForException(lv.get(1).getString()), lv.get(0).getString());
|
||||
default -> throw new InternalExpressionException("throw() can't accept more than 3 parameters");
|
||||
}
|
||||
});
|
||||
|
||||
// needs to be lazy since execution of parameters but first one are conditional
|
||||
expression.addLazyFunction("try", (c, t, lv) ->
|
||||
{
|
||||
if (lv.size()==0)
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("'try' needs at least an expression block, and either a catch_epr, or a number of pairs of filters and catch_expr");
|
||||
}
|
||||
try
|
||||
{
|
||||
Value retval = lv.get(0).evalValue(c, t);
|
||||
final Value retval = lv.get(0).evalValue(c, t);
|
||||
return (c_, t_) -> retval;
|
||||
}
|
||||
catch (ProcessedThrowStatement ret)
|
||||
catch (final ProcessedThrowStatement ret)
|
||||
{
|
||||
if (lv.size() == 1)
|
||||
{
|
||||
if (!ret.thrownExceptionType.isUserException())
|
||||
{
|
||||
throw ret;
|
||||
}
|
||||
return (c_, t_) -> Value.NULL;
|
||||
}
|
||||
if (lv.size() > 3 && lv.size() % 2 == 0)
|
||||
{
|
||||
throw new InternalExpressionException("Try-catch block needs the code to run, and either a catch expression for user thrown exceptions, or a number of pairs of filters and catch expressions");
|
||||
}
|
||||
|
||||
|
||||
Value val = null; // This is always assigned at some point, just the compiler doesn't know
|
||||
|
||||
LazyValue __ = c.getVariable("_");
|
||||
|
||||
final LazyValue __ = c.getVariable("_");
|
||||
c.setVariable("_", (__c, __t) -> ret.data.reboundedTo("_"));
|
||||
LazyValue _trace = c.getVariable("_trace");
|
||||
final LazyValue _trace = c.getVariable("_trace");
|
||||
c.setVariable("_trace", (__c, __t) -> MapValue.wrap(Map.of(
|
||||
StringValue.of("stack"), ListValue.wrap(ret.stack.stream().map(f -> ListValue.of(
|
||||
StringValue.of(f.getModule().name()),
|
||||
StringValue.of(f.getString()),
|
||||
NumericValue.of(f.getToken().lineno+1),
|
||||
NumericValue.of(f.getToken().linepos+1)
|
||||
NumericValue.of(f.getToken().lineno + 1),
|
||||
NumericValue.of(f.getToken().linepos + 1)
|
||||
))),
|
||||
|
||||
StringValue.of("locals"), MapValue.wrap(ret.context.variables.entrySet().stream().filter(e -> !e.getKey().equals("_trace")).collect(Collectors.toMap(
|
||||
@@ -120,20 +126,22 @@ public class ControlFlow {
|
||||
))),
|
||||
StringValue.of("token"), ListValue.of(
|
||||
StringValue.of(ret.token.surface),
|
||||
NumericValue.of(ret.token.lineno+1),
|
||||
NumericValue.of(ret.token.linepos+1)
|
||||
NumericValue.of(ret.token.lineno + 1),
|
||||
NumericValue.of(ret.token.linepos + 1)
|
||||
)
|
||||
)));
|
||||
|
||||
if (lv.size() == 2)
|
||||
{
|
||||
if (ret.thrownExceptionType.isUserException())
|
||||
{
|
||||
val = lv.get(1).evalValue(c, t);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int pointer = 1;
|
||||
while (pointer < lv.size() -1)
|
||||
while (pointer < lv.size() - 1)
|
||||
{
|
||||
if (ret.thrownExceptionType.isRelevantFor(lv.get(pointer).evalValue(c).getString()))
|
||||
{
|
||||
@@ -145,14 +153,18 @@ public class ControlFlow {
|
||||
}
|
||||
c.setVariable("_", __);
|
||||
if (_trace != null)
|
||||
{
|
||||
c.setVariable("_trace", _trace);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.delVariable("_trace");
|
||||
}
|
||||
if (val == null) // not handled
|
||||
{
|
||||
throw ret;
|
||||
}
|
||||
Value retval = val;
|
||||
final Value retval = val;
|
||||
return (c_, t_) -> retval;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -25,42 +25,42 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DataStructures {
|
||||
public static void apply(Expression expression)
|
||||
public class DataStructures
|
||||
{
|
||||
public static void apply(final Expression expression)
|
||||
{
|
||||
expression.addFunction("l", lv ->
|
||||
{
|
||||
if (lv.size() == 1 && lv.get(0) instanceof LazyListValue)
|
||||
return ListValue.wrap(((LazyListValue) lv.get(0)).unroll());
|
||||
return new ListValue.ListConstructorValue(lv);
|
||||
});
|
||||
lv.size() == 1 && lv.get(0) instanceof final LazyListValue llv
|
||||
? ListValue.wrap(llv.unroll())
|
||||
: new ListValue.ListConstructorValue(lv));
|
||||
|
||||
expression.addFunction("join", (lv) ->
|
||||
{
|
||||
if (lv.size() < 2)
|
||||
{
|
||||
throw new InternalExpressionException("'join' takes at least 2 arguments");
|
||||
String delimiter = lv.get(0).getString();
|
||||
List<Value> toJoin;
|
||||
if (lv.size()==2 && lv.get(1) instanceof LazyListValue)
|
||||
{
|
||||
toJoin = ((LazyListValue) lv.get(1)).unroll();
|
||||
|
||||
}
|
||||
else if (lv.size() == 2 && lv.get(1) instanceof ListValue)
|
||||
final String delimiter = lv.get(0).getString();
|
||||
final List<Value> toJoin;
|
||||
if (lv.size() == 2 && lv.get(1) instanceof final LazyListValue llv)
|
||||
{
|
||||
toJoin = new ArrayList<>(((ListValue)lv.get(1)).getItems());
|
||||
toJoin = llv.unroll();
|
||||
}
|
||||
else if (lv.size() == 2 && lv.get(1) instanceof final ListValue llv)
|
||||
{
|
||||
toJoin = new ArrayList<>(llv.getItems());
|
||||
}
|
||||
else
|
||||
{
|
||||
toJoin = lv.subList(1,lv.size());
|
||||
toJoin = lv.subList(1, lv.size());
|
||||
}
|
||||
return new StringValue(toJoin.stream().map(Value::getString).collect(Collectors.joining(delimiter)));
|
||||
});
|
||||
|
||||
expression.addFunction("split", (lv) ->
|
||||
{
|
||||
Value delimiter;
|
||||
Value hwat;
|
||||
final Value delimiter;
|
||||
final Value hwat;
|
||||
if (lv.size() == 1)
|
||||
{
|
||||
hwat = lv.get(0);
|
||||
@@ -80,23 +80,26 @@ public class DataStructures {
|
||||
|
||||
expression.addFunction("slice", (lv) ->
|
||||
{
|
||||
|
||||
if (lv.size() != 2 && lv.size() != 3)
|
||||
{
|
||||
throw new InternalExpressionException("'slice' takes 2 or 3 arguments");
|
||||
Value hwat = lv.get(0);
|
||||
long from = NumericValue.asNumber(lv.get(1)).getLong();
|
||||
}
|
||||
final Value hwat = lv.get(0);
|
||||
final long from = NumericValue.asNumber(lv.get(1)).getLong();
|
||||
Long to = null;
|
||||
if (lv.size()== 3)
|
||||
if (lv.size() == 3)
|
||||
{
|
||||
to = NumericValue.asNumber(lv.get(2)).getLong();
|
||||
}
|
||||
return hwat.slice(from, to);
|
||||
});
|
||||
|
||||
expression.addFunction("sort", (lv) ->
|
||||
{
|
||||
List<Value> toSort = lv;
|
||||
if (lv.size()==1 && lv.get(0) instanceof ListValue)
|
||||
if (lv.size() == 1 && lv.get(0) instanceof final ListValue llv)
|
||||
{
|
||||
toSort = new ArrayList<>(((ListValue)lv.get(0)).getItems());
|
||||
toSort = new ArrayList<>(llv.getItems());
|
||||
}
|
||||
Collections.sort(toSort);
|
||||
return ListValue.wrap(toSort);
|
||||
@@ -106,30 +109,34 @@ public class DataStructures {
|
||||
expression.addLazyFunction("sort_key", (c, t, lv) -> //get working with iterators
|
||||
{
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("First argument for 'sort_key' should be a List");
|
||||
Value v = lv.get(0).evalValue(c);
|
||||
if (!(v instanceof ListValue))
|
||||
}
|
||||
final Value v = lv.get(0).evalValue(c);
|
||||
if (!(v instanceof final ListValue list))
|
||||
{
|
||||
throw new InternalExpressionException("First argument for 'sort_key' should be a List");
|
||||
List<Value> toSort = new ArrayList<>(((ListValue) v).getItems());
|
||||
if (lv.size()==1)
|
||||
}
|
||||
final List<Value> toSort = new ArrayList<>(list.getItems());
|
||||
if (lv.size() == 1)
|
||||
{
|
||||
Collections.shuffle(toSort);
|
||||
Value ret = ListValue.wrap(toSort);
|
||||
final Value ret = ListValue.wrap(toSort);
|
||||
return (_c, _t) -> ret;
|
||||
}
|
||||
LazyValue sortKey = lv.get(1);
|
||||
final LazyValue sortKey = lv.get(1);
|
||||
//scoping
|
||||
LazyValue __ = c.getVariable("_");
|
||||
Collections.sort(toSort,(v1, v2) -> {
|
||||
c.setVariable("_",(cc, tt) -> v1);
|
||||
Value ev1 = sortKey.evalValue(c);
|
||||
c.setVariable("_",(cc, tt) -> v2);
|
||||
Value ev2 = sortKey.evalValue(c);
|
||||
final LazyValue __ = c.getVariable("_");
|
||||
toSort.sort((v1, v2) -> {
|
||||
c.setVariable("_", (cc, tt) -> v1);
|
||||
final Value ev1 = sortKey.evalValue(c);
|
||||
c.setVariable("_", (cc, tt) -> v2);
|
||||
final Value ev2 = sortKey.evalValue(c);
|
||||
return ev1.compareTo(ev2);
|
||||
});
|
||||
//revering scope
|
||||
c.setVariable("_", __);
|
||||
Value ret = ListValue.wrap(toSort);
|
||||
final Value ret = ListValue.wrap(toSort);
|
||||
return (cc, tt) -> ret;
|
||||
});
|
||||
|
||||
@@ -138,9 +145,11 @@ public class DataStructures {
|
||||
NumericValue from = Value.ZERO;
|
||||
NumericValue to;
|
||||
NumericValue step = Value.ONE;
|
||||
int argsize = lv.size();
|
||||
final int argsize = lv.size();
|
||||
if (argsize == 0 || argsize > 3)
|
||||
throw new InternalExpressionException("'range' accepts from 1 to 3 arguments, not "+argsize);
|
||||
{
|
||||
throw new InternalExpressionException("'range' accepts from 1 to 3 arguments, not " + argsize);
|
||||
}
|
||||
to = NumericValue.asNumber(lv.get(0));
|
||||
if (lv.size() > 1)
|
||||
{
|
||||
@@ -157,79 +166,84 @@ public class DataStructures {
|
||||
});
|
||||
|
||||
expression.addTypedContextFunction("m", -1, Context.MAPDEF, (c, t, lv) ->
|
||||
{
|
||||
Value ret;
|
||||
if (lv.size() == 1 && lv.get(0) instanceof LazyListValue)
|
||||
ret = new MapValue(((LazyListValue) lv.get(0)).unroll());
|
||||
else
|
||||
ret = new MapValue(lv);
|
||||
return ret;
|
||||
});
|
||||
lv.size() == 1 && lv.get(0) instanceof final LazyListValue llv
|
||||
? new MapValue(llv.unroll())
|
||||
: new MapValue(lv)
|
||||
);
|
||||
|
||||
expression.addUnaryFunction("keys", v ->
|
||||
{
|
||||
if (v instanceof MapValue)
|
||||
return new ListValue(((MapValue) v).getMap().keySet());
|
||||
return Value.NULL;
|
||||
});
|
||||
v instanceof final MapValue map
|
||||
? new ListValue(map.getMap().keySet())
|
||||
: Value.NULL
|
||||
);
|
||||
|
||||
expression.addUnaryFunction("values", v ->
|
||||
{
|
||||
if (v instanceof MapValue)
|
||||
return new ListValue(((MapValue) v).getMap().values());
|
||||
return Value.NULL;
|
||||
});
|
||||
v instanceof final MapValue map
|
||||
? new ListValue(map.getMap().values())
|
||||
: Value.NULL
|
||||
);
|
||||
|
||||
expression.addUnaryFunction("pairs", v ->
|
||||
{
|
||||
if (v instanceof MapValue)
|
||||
return ListValue.wrap(((MapValue) v).getMap().entrySet().stream().map(
|
||||
(p) -> ListValue.of(p.getKey(), p.getValue())
|
||||
));
|
||||
return Value.NULL;
|
||||
});
|
||||
v instanceof final MapValue map
|
||||
? ListValue.wrap(map.getMap().entrySet().stream().map(p -> ListValue.of(p.getKey(), p.getValue())))
|
||||
: Value.NULL);
|
||||
|
||||
expression.addBinaryContextOperator(":", Operators.precedence.get("attribute~:"),true, true, false, (ctx, t, container, address) ->
|
||||
expression.addBinaryContextOperator(":", Operators.precedence.get("attribute~:"), true, true, false, (ctx, t, container, address) ->
|
||||
{
|
||||
if (container instanceof LContainerValue)
|
||||
if (container instanceof final LContainerValue lcv)
|
||||
{
|
||||
ContainerValueInterface outerContainer = ((LContainerValue) container).getContainer();
|
||||
if (outerContainer == null) return LContainerValue.NULL_CONTAINER;
|
||||
Value innerContainer = outerContainer.get(((LContainerValue) container).getAddress());
|
||||
if (!(innerContainer instanceof ContainerValueInterface)) return LContainerValue.NULL_CONTAINER;
|
||||
return new LContainerValue((ContainerValueInterface) innerContainer, address);
|
||||
final ContainerValueInterface outerContainer = lcv.container();
|
||||
if (outerContainer == null)
|
||||
{
|
||||
return LContainerValue.NULL_CONTAINER;
|
||||
}
|
||||
return outerContainer.get(lcv.address()) instanceof final ContainerValueInterface cvi
|
||||
? new LContainerValue(cvi, address)
|
||||
: LContainerValue.NULL_CONTAINER;
|
||||
}
|
||||
if (!(container instanceof ContainerValueInterface))
|
||||
if (!(container instanceof final ContainerValueInterface cvi))
|
||||
{
|
||||
return t == Context.LVALUE ? LContainerValue.NULL_CONTAINER : Value.NULL;
|
||||
if (t != Context.LVALUE) return ((ContainerValueInterface) container).get(address);
|
||||
return new LContainerValue((ContainerValueInterface) container, address);
|
||||
}
|
||||
return t != Context.LVALUE ? cvi.get(address) : new LContainerValue(cvi, address);
|
||||
});
|
||||
|
||||
// lazy cause conditional typing - questionable
|
||||
expression.addLazyFunction("get", (c, t, lv) ->
|
||||
{
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("'get' requires parameters");
|
||||
}
|
||||
if (lv.size() == 1)
|
||||
{
|
||||
Value v = lv.get(0).evalValue(c, Context.LVALUE);
|
||||
if (!(v instanceof LContainerValue))
|
||||
final Value v = lv.get(0).evalValue(c, Context.LVALUE);
|
||||
if (!(v instanceof final LContainerValue lcv))
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
ContainerValueInterface container = ((LContainerValue) v).getContainer();
|
||||
}
|
||||
final ContainerValueInterface container = lcv.container();
|
||||
if (container == null)
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
Value ret = container.get(((LContainerValue) v).getAddress());
|
||||
}
|
||||
final Value ret = container.get(lcv.address());
|
||||
return (cc, tt) -> ret;
|
||||
}
|
||||
Value container = lv.get(0).evalValue(c);
|
||||
for (int i = 1; i < lv.size(); i++)
|
||||
{
|
||||
if (!(container instanceof ContainerValueInterface)) return (cc, tt) -> Value.NULL;
|
||||
container = ((ContainerValueInterface) container).get(lv.get(i).evalValue(c));
|
||||
if (!(container instanceof final ContainerValueInterface cvi))
|
||||
{
|
||||
return (cc, tt) -> Value.NULL;
|
||||
}
|
||||
container = cvi.get(lv.get(i).evalValue(c));
|
||||
}
|
||||
if (container == null)
|
||||
{
|
||||
return (cc, tt) -> Value.NULL;
|
||||
Value finalContainer = container;
|
||||
}
|
||||
final Value finalContainer = container;
|
||||
return (cc, tt) -> finalContainer;
|
||||
});
|
||||
|
||||
@@ -237,66 +251,77 @@ public class DataStructures {
|
||||
expression.addLazyFunction("has", (c, t, lv) ->
|
||||
{
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("'has' requires parameters");
|
||||
}
|
||||
if (lv.size() == 1)
|
||||
{
|
||||
Value v = lv.get(0).evalValue(c, Context.LVALUE);
|
||||
if (!(v instanceof LContainerValue))
|
||||
final Value v = lv.get(0).evalValue(c, Context.LVALUE);
|
||||
if (!(v instanceof final LContainerValue lcv))
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
ContainerValueInterface container = ((LContainerValue) v).getContainer();
|
||||
}
|
||||
final ContainerValueInterface container = lcv.container();
|
||||
if (container == null)
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
Value ret = BooleanValue.of(container.has(((LContainerValue) v).getAddress()));
|
||||
}
|
||||
final Value ret = BooleanValue.of(container.has(lcv.address()));
|
||||
return (cc, tt) -> ret;
|
||||
}
|
||||
Value container = lv.get(0).evalValue(c);
|
||||
for (int i = 1; i < lv.size()-1; i++)
|
||||
for (int i = 1; i < lv.size() - 1; i++)
|
||||
{
|
||||
if (!(container instanceof ContainerValueInterface)) return LazyValue.NULL;
|
||||
container = ((ContainerValueInterface) container).get(lv.get(i).evalValue(c));
|
||||
if (!(container instanceof final ContainerValueInterface cvi))
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
}
|
||||
container = cvi.get(lv.get(i).evalValue(c));
|
||||
}
|
||||
if (!(container instanceof ContainerValueInterface))
|
||||
if (!(container instanceof final ContainerValueInterface cvi))
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
Value ret = BooleanValue.of(((ContainerValueInterface) container).has(lv.get(lv.size()-1).evalValue(c)));
|
||||
}
|
||||
final Value ret = BooleanValue.of(cvi.has(lv.get(lv.size() - 1).evalValue(c)));
|
||||
return (cc, tt) -> ret;
|
||||
});
|
||||
|
||||
// same as `get`
|
||||
expression.addLazyFunction("put", (c, t, lv) ->
|
||||
{
|
||||
if(lv.size()<2)
|
||||
if (lv.size() < 2)
|
||||
{
|
||||
throw new InternalExpressionException("'put' takes at least three arguments, a container, address, and values to insert at that index");
|
||||
}
|
||||
Value container = lv.get(0).evalValue(c, Context.LVALUE);
|
||||
if (container instanceof LContainerValue)
|
||||
final Value container = lv.get(0).evalValue(c, Context.LVALUE);
|
||||
if (container instanceof final LContainerValue lcv)
|
||||
{
|
||||
ContainerValueInterface internalContainer = ((LContainerValue) container).getContainer();
|
||||
final ContainerValueInterface internalContainer = lcv.container();
|
||||
if (internalContainer == null)
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
}
|
||||
Value address = ((LContainerValue) container).getAddress();
|
||||
Value what = lv.get(1).evalValue(c);
|
||||
Value retVal = BooleanValue.of((lv.size() > 2)
|
||||
final Value address = lcv.address();
|
||||
final Value what = lv.get(1).evalValue(c);
|
||||
final Value retVal = BooleanValue.of((lv.size() > 2)
|
||||
? internalContainer.put(address, what, lv.get(2).evalValue(c))
|
||||
: internalContainer.put(address, what));
|
||||
return (cc, tt) -> retVal;
|
||||
|
||||
}
|
||||
if(lv.size()<3)
|
||||
if (lv.size() < 3)
|
||||
{
|
||||
throw new InternalExpressionException("'put' takes at least three arguments, a container, address, and values to insert at that index");
|
||||
}
|
||||
if (!(container instanceof ContainerValueInterface))
|
||||
if (!(container instanceof final ContainerValueInterface cvi))
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
}
|
||||
Value where = lv.get(1).evalValue(c);
|
||||
Value what = lv.get(2).evalValue(c);
|
||||
Value retVal = BooleanValue.of((lv.size()>3)
|
||||
? ((ContainerValueInterface) container).put(where, what, lv.get(3).evalValue(c))
|
||||
: ((ContainerValueInterface) container).put(where, what));
|
||||
final Value where = lv.get(1).evalValue(c);
|
||||
final Value what = lv.get(2).evalValue(c);
|
||||
final Value retVal = BooleanValue.of((lv.size() > 3)
|
||||
? cvi.put(where, what, lv.get(3).evalValue(c))
|
||||
: cvi.put(where, what));
|
||||
return (cc, tt) -> retVal;
|
||||
});
|
||||
|
||||
@@ -304,44 +329,61 @@ public class DataStructures {
|
||||
expression.addLazyFunction("delete", (c, t, lv) ->
|
||||
{
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("'delete' requires parameters");
|
||||
}
|
||||
if (lv.size() == 1)
|
||||
{
|
||||
Value v = lv.get(0).evalValue(c, Context.LVALUE);
|
||||
if (!(v instanceof LContainerValue))
|
||||
final Value v = lv.get(0).evalValue(c, Context.LVALUE);
|
||||
if (!(v instanceof final LContainerValue lcv))
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
ContainerValueInterface container = ((LContainerValue) v).getContainer();
|
||||
}
|
||||
final ContainerValueInterface container = lcv.container();
|
||||
if (container == null)
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
Value ret = BooleanValue.of(container.delete(((LContainerValue) v).getAddress()));
|
||||
}
|
||||
final Value ret = BooleanValue.of(container.delete(lcv.address()));
|
||||
return (cc, tt) -> ret;
|
||||
}
|
||||
Value container = lv.get(0).evalValue(c);
|
||||
for (int i = 1; i < lv.size()-1; i++)
|
||||
for (int i = 1; i < lv.size() - 1; i++)
|
||||
{
|
||||
if (!(container instanceof ContainerValueInterface)) return LazyValue.NULL;
|
||||
container = ((ContainerValueInterface) container).get(lv.get(i).evalValue(c));
|
||||
if (!(container instanceof final ContainerValueInterface cvi))
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
}
|
||||
container = cvi.get(lv.get(i).evalValue(c));
|
||||
}
|
||||
if (!(container instanceof ContainerValueInterface))
|
||||
if (!(container instanceof final ContainerValueInterface cvi))
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
Value ret = BooleanValue.of(((ContainerValueInterface) container).delete(lv.get(lv.size()-1).evalValue(c)));
|
||||
}
|
||||
final Value ret = BooleanValue.of(cvi.delete(lv.get(lv.size() - 1).evalValue(c)));
|
||||
return (cc, tt) -> ret;
|
||||
});
|
||||
|
||||
expression.addUnaryFunction("encode_b64", v -> StringValue.of(Base64.getEncoder().encodeToString(v.getString().getBytes(StandardCharsets.UTF_8))));
|
||||
expression.addUnaryFunction("decode_b64", v -> {
|
||||
try {
|
||||
try
|
||||
{
|
||||
return StringValue.of(new String(Base64.getDecoder().decode(v.getString()), StandardCharsets.UTF_8));
|
||||
} catch (IllegalArgumentException iae){
|
||||
}
|
||||
catch (final IllegalArgumentException iae)
|
||||
{
|
||||
throw new ThrowStatement("Invalid b64 string: " + v.getString(), Throwables.B64_ERROR);
|
||||
}
|
||||
});
|
||||
|
||||
expression.addUnaryFunction("encode_json", v -> StringValue.of(v.toJson().toString()));
|
||||
expression.addUnaryFunction("decode_json", v -> {
|
||||
try {
|
||||
try
|
||||
{
|
||||
return Auxiliary.GSON.fromJson(v.getString(), Value.class);
|
||||
} catch (JsonParseException jpe){
|
||||
}
|
||||
catch (final JsonParseException jpe)
|
||||
{
|
||||
throw new ThrowStatement("Invalid json string: " + v.getString(), Throwables.JSON_ERROR);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -19,61 +19,70 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Functions {
|
||||
public static void apply(Expression expression) // public just to get the javadoc right
|
||||
public class Functions
|
||||
{
|
||||
public static void apply(final Expression expression) // public just to get the javadoc right
|
||||
{
|
||||
// artificial construct to handle user defined functions and function definitions
|
||||
expression.addContextFunction("import", -1, (c, t, lv) ->
|
||||
{
|
||||
if (lv.size() < 1) throw new InternalExpressionException("'import' needs at least a module name to import, and list of values to import");
|
||||
if (lv.size() < 1)
|
||||
{
|
||||
throw new InternalExpressionException("'import' needs at least a module name to import, and list of values to import");
|
||||
}
|
||||
String moduleName = lv.get(0).getString();
|
||||
c.host.importModule(c, moduleName);
|
||||
moduleName = moduleName.toLowerCase(Locale.ROOT);
|
||||
if (lv.size() > 1)
|
||||
{
|
||||
c.host.importNames(c, expression.module, moduleName, lv.subList(1, lv.size()).stream().map(Value::getString).toList());
|
||||
if (t == Context.VOID)
|
||||
return Value.NULL;
|
||||
return ListValue.wrap(c.host.availableImports(moduleName).map(StringValue::new));
|
||||
}
|
||||
return t == Context.VOID ? Value.NULL : ListValue.wrap(c.host.availableImports(moduleName).map(StringValue::new));
|
||||
});
|
||||
|
||||
|
||||
// needs to be lazy because of custom context of execution of arguments as a signature
|
||||
expression.addCustomFunction("call", new Fluff.AbstractLazyFunction(-1, "call") {
|
||||
expression.addCustomFunction("call", new Fluff.AbstractLazyFunction(-1, "call")
|
||||
{
|
||||
@Override
|
||||
public LazyValue lazyEval(Context c, Context.Type t, Expression expr, Tokenizer.Token tok, List<LazyValue> lv)
|
||||
public LazyValue lazyEval(final Context c, final Context.Type t, final Expression expr, final Tokenizer.Token tok, final List<LazyValue> lv)
|
||||
{
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("'call' expects at least function name to call");
|
||||
}
|
||||
//lv.remove(lv.size()-1); // aint gonna cut it // maybe it will because of the eager eval changes
|
||||
if (t != Context.SIGNATURE) // just call the function
|
||||
{
|
||||
List<Value> args = Fluff.AbstractFunction.unpackLazy(lv, c, Context.NONE);
|
||||
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, args, 0, false, true);
|
||||
FunctionValue fun = functionArgument.function;
|
||||
final List<Value> args = Fluff.AbstractFunction.unpackLazy(lv, c, Context.NONE);
|
||||
final FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, args, 0, false, true);
|
||||
final FunctionValue fun = functionArgument.function;
|
||||
return fun.callInContext(c, t, functionArgument.args);
|
||||
}
|
||||
// gimme signature
|
||||
String name = lv.get(0).evalValue(c, Context.NONE).getString();
|
||||
List<String> args = new ArrayList<>();
|
||||
List<String> globals = new ArrayList<>();
|
||||
final String name = lv.get(0).evalValue(c, Context.NONE).getString();
|
||||
final List<String> args = new ArrayList<>();
|
||||
final List<String> globals = new ArrayList<>();
|
||||
String varArgs = null;
|
||||
for (int i = 1; i < lv.size(); i++)
|
||||
{
|
||||
Value v = lv.get(i).evalValue(c, Context.LOCALIZATION);
|
||||
final Value v = lv.get(i).evalValue(c, Context.LOCALIZATION);
|
||||
if (!v.isBound())
|
||||
{
|
||||
throw new InternalExpressionException("Only variables can be used in function signature, not " + v.getString());
|
||||
}
|
||||
if (v instanceof FunctionAnnotationValue)
|
||||
if (v instanceof final FunctionAnnotationValue fav)
|
||||
{
|
||||
if (((FunctionAnnotationValue) v).type == FunctionAnnotationValue.Type.GLOBAL)
|
||||
if (fav.type == FunctionAnnotationValue.Type.GLOBAL)
|
||||
{
|
||||
globals.add(v.boundVariable);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (varArgs != null)
|
||||
throw new InternalExpressionException("Variable argument identifier is already defined as "+varArgs+", trying to overwrite with "+v.boundVariable);
|
||||
{
|
||||
throw new InternalExpressionException("Variable argument identifier is already defined as " + varArgs + ", trying to overwrite with " + v.boundVariable);
|
||||
}
|
||||
varArgs = v.boundVariable;
|
||||
}
|
||||
}
|
||||
@@ -82,7 +91,7 @@ public class Functions {
|
||||
args.add(v.boundVariable);
|
||||
}
|
||||
}
|
||||
Value retval = new FunctionSignatureValue(name, args, varArgs, globals);
|
||||
final Value retval = new FunctionSignatureValue(name, args, varArgs, globals);
|
||||
return (cc, tt) -> retval;
|
||||
}
|
||||
|
||||
@@ -93,14 +102,15 @@ public class Functions {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transitive() {
|
||||
public boolean transitive()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context.Type staticType(Context.Type outerType)
|
||||
public Context.Type staticType(final Context.Type outerType)
|
||||
{
|
||||
return outerType==Context.SIGNATURE?Context.LOCALIZATION:Context.NONE;
|
||||
return outerType == Context.SIGNATURE ? Context.LOCALIZATION : Context.NONE;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -108,7 +118,9 @@ public class Functions {
|
||||
expression.addContextFunction("outer", 1, (c, t, lv) ->
|
||||
{
|
||||
if (t != Context.LOCALIZATION)
|
||||
{
|
||||
throw new InternalExpressionException("Outer scoping of variables is only possible in function signatures.");
|
||||
}
|
||||
return new FunctionAnnotationValue(lv.get(0), FunctionAnnotationValue.Type.GLOBAL);
|
||||
});
|
||||
|
||||
@@ -118,16 +130,20 @@ public class Functions {
|
||||
{
|
||||
if (type == Context.MAPDEF)
|
||||
{
|
||||
Value result = ListValue.of(lv1.evalValue(c), lv2.evalValue(c));
|
||||
final Value result = ListValue.of(lv1.evalValue(c), lv2.evalValue(c));
|
||||
return (cc, tt) -> result;
|
||||
}
|
||||
Value v1 = lv1.evalValue(c, Context.SIGNATURE);
|
||||
if (!(v1 instanceof FunctionSignatureValue sign))
|
||||
final Value v1 = lv1.evalValue(c, Context.SIGNATURE);
|
||||
if (!(v1 instanceof final FunctionSignatureValue sign))
|
||||
{
|
||||
throw new InternalExpressionException("'->' operator requires a function signature on the LHS");
|
||||
Value result = expression.createUserDefinedFunction(c, sign.getName(), e, t, sign.getArgs(), sign.getVarArgs(), sign.getGlobals(), lv2);
|
||||
}
|
||||
final Value result = expression.createUserDefinedFunction(c, sign.identifier(), e, t, sign.arguments(), sign.varArgs(), sign.globals(), lv2);
|
||||
return (cc, tt) -> result;
|
||||
});
|
||||
|
||||
expression.addImpureFunction("return", (lv) -> { throw new ReturnStatement(lv.size()==0?Value.NULL:lv.get(0));} );
|
||||
expression.addImpureFunction("return", (lv) -> {
|
||||
throw new ReturnStatement(lv.size() == 0 ? Value.NULL : lv.get(0));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -15,55 +15,74 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class Loops {
|
||||
public static void apply(Expression expression)
|
||||
public class Loops
|
||||
{
|
||||
public static void apply(final Expression expression)
|
||||
{
|
||||
// condition and expression will get a bound '_i'
|
||||
// returns last successful expression or false
|
||||
// while(cond, limit, expr) => ??
|
||||
expression.addImpureFunction("break", lv ->
|
||||
{
|
||||
if (lv.size()==0) throw new BreakStatement(null);
|
||||
if (lv.size()==1) throw new BreakStatement(lv.get(0));
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new BreakStatement(null);
|
||||
}
|
||||
if (lv.size() == 1)
|
||||
{
|
||||
throw new BreakStatement(lv.get(0));
|
||||
}
|
||||
throw new InternalExpressionException("'break' can only be called with zero or one argument");
|
||||
});
|
||||
|
||||
expression.addImpureFunction("continue", lv ->
|
||||
{
|
||||
if (lv.size()==0) throw new ContinueStatement(null);
|
||||
if (lv.size()==1) throw new ContinueStatement(lv.get(0));
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new ContinueStatement(null);
|
||||
}
|
||||
if (lv.size() == 1)
|
||||
{
|
||||
throw new ContinueStatement(lv.get(0));
|
||||
}
|
||||
throw new InternalExpressionException("'continue' can only be called with zero or one argument");
|
||||
});
|
||||
|
||||
// lazy
|
||||
expression.addLazyFunction("while", 3, (c, t, lv) ->
|
||||
{
|
||||
long limit = NumericValue.asNumber(lv.get(1).evalValue(c)).getLong();
|
||||
LazyValue condition = lv.get(0);
|
||||
LazyValue expr = lv.get(2);
|
||||
final long limit = NumericValue.asNumber(lv.get(1).evalValue(c)).getLong();
|
||||
final LazyValue condition = lv.get(0);
|
||||
final LazyValue expr = lv.get(2);
|
||||
long i = 0;
|
||||
Value lastOne = Value.NULL;
|
||||
//scoping
|
||||
LazyValue _val = c.getVariable("_");
|
||||
c.setVariable("_",(cc, tt) -> new NumericValue(0).bindTo("_"));
|
||||
while (i<limit && condition.evalValue(c, Context.BOOLEAN).getBoolean() )
|
||||
final LazyValue _val = c.getVariable("_");
|
||||
c.setVariable("_", (cc, tt) -> new NumericValue(0).bindTo("_"));
|
||||
while (i < limit && condition.evalValue(c, Context.BOOLEAN).getBoolean())
|
||||
{
|
||||
try
|
||||
{
|
||||
lastOne = expr.evalValue(c, t);
|
||||
}
|
||||
catch (BreakStatement | ContinueStatement stmt)
|
||||
catch (final BreakStatement | ContinueStatement stmt)
|
||||
{
|
||||
if (stmt.retval != null) lastOne = stmt.retval;
|
||||
if (stmt instanceof BreakStatement) break;
|
||||
if (stmt.retval != null)
|
||||
{
|
||||
lastOne = stmt.retval;
|
||||
}
|
||||
if (stmt instanceof BreakStatement)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
long seriously = i;
|
||||
final long seriously = i;
|
||||
c.setVariable("_", (cc, tt) -> new NumericValue(seriously).bindTo("_"));
|
||||
}
|
||||
//revering scope
|
||||
c.setVariable("_", _val);
|
||||
Value lastValueNoKidding = lastOne;
|
||||
final Value lastValueNoKidding = lastOne;
|
||||
return (cc, tt) -> lastValueNoKidding;
|
||||
});
|
||||
|
||||
@@ -71,28 +90,34 @@ public class Loops {
|
||||
// expr receives bounded variable '_' indicating iteration
|
||||
expression.addLazyFunction("loop", 2, (c, t, lv) ->
|
||||
{
|
||||
long limit = NumericValue.asNumber(lv.get(0).evalValue(c, Context.NONE)).getLong();
|
||||
final long limit = NumericValue.asNumber(lv.get(0).evalValue(c, Context.NONE)).getLong();
|
||||
Value lastOne = Value.NULL;
|
||||
LazyValue expr = lv.get(1);
|
||||
final LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
LazyValue _val = c.getVariable("_");
|
||||
for (long i=0; i < limit; i++)
|
||||
final LazyValue _val = c.getVariable("_");
|
||||
for (long i = 0; i < limit; i++)
|
||||
{
|
||||
long whyYouAsk = i;
|
||||
final long whyYouAsk = i;
|
||||
c.setVariable("_", (cc, tt) -> new NumericValue(whyYouAsk).bindTo("_"));
|
||||
try
|
||||
{
|
||||
lastOne = expr.evalValue(c, t);
|
||||
}
|
||||
catch (BreakStatement | ContinueStatement stmt)
|
||||
catch (final BreakStatement | ContinueStatement stmt)
|
||||
{
|
||||
if (stmt.retval != null) lastOne = stmt.retval;
|
||||
if (stmt instanceof BreakStatement) break;
|
||||
if (stmt.retval != null)
|
||||
{
|
||||
lastOne = stmt.retval;
|
||||
}
|
||||
if (stmt instanceof BreakStatement)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//revering scope
|
||||
c.setVariable("_", _val);
|
||||
Value trulyLastOne = lastOne;
|
||||
final Value trulyLastOne = lastOne;
|
||||
return (cc, tt) -> trulyLastOne;
|
||||
});
|
||||
|
||||
@@ -100,31 +125,39 @@ public class Loops {
|
||||
// receives bounded variable '_' with the expression
|
||||
expression.addLazyFunction("map", 2, (c, t, lv) ->
|
||||
{
|
||||
Value rval= lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull()) return ListValue.lazyEmpty();
|
||||
if (!(rval instanceof AbstractListValue))
|
||||
throw new InternalExpressionException("First argument of 'map' function should be a list or iterator");
|
||||
Iterator<Value> iterator = ((AbstractListValue) rval).iterator();
|
||||
LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
LazyValue _val = c.getVariable("_");
|
||||
LazyValue _iter = c.getVariable("_i");
|
||||
List<Value> result = new ArrayList<>();
|
||||
for (int i=0; iterator.hasNext(); i++)
|
||||
final Value rval = lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull())
|
||||
{
|
||||
Value next = iterator.next();
|
||||
String var = next.boundVariable;
|
||||
return ListValue.lazyEmpty();
|
||||
}
|
||||
if (!(rval instanceof final AbstractListValue alv))
|
||||
{
|
||||
throw new InternalExpressionException("First argument of 'map' function should be a list or iterator");
|
||||
}
|
||||
final Iterator<Value> iterator = alv.iterator();
|
||||
final LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
final LazyValue _val = c.getVariable("_");
|
||||
final LazyValue _iter = c.getVariable("_i");
|
||||
final List<Value> result = new ArrayList<>();
|
||||
for (int i = 0; iterator.hasNext(); i++)
|
||||
{
|
||||
final Value next = iterator.next();
|
||||
final String var = next.boundVariable;
|
||||
next.bindTo("_");
|
||||
int doYouReally = i;
|
||||
final int doYouReally = i;
|
||||
c.setVariable("_", (cc, tt) -> next);
|
||||
c.setVariable("_i", (cc, tt) -> new NumericValue(doYouReally).bindTo("_i"));
|
||||
try
|
||||
{
|
||||
result.add(expr.evalValue(c, t));
|
||||
}
|
||||
catch (BreakStatement | ContinueStatement stmt)
|
||||
catch (final BreakStatement | ContinueStatement stmt)
|
||||
{
|
||||
if (stmt.retval != null) result.add(stmt.retval);
|
||||
if (stmt.retval != null)
|
||||
{
|
||||
result.add(stmt.retval);
|
||||
}
|
||||
if (stmt instanceof BreakStatement)
|
||||
{
|
||||
next.boundVariable = var;
|
||||
@@ -134,11 +167,11 @@ public class Loops {
|
||||
next.boundVariable = var;
|
||||
}
|
||||
((AbstractListValue) rval).fatality();
|
||||
Value ret = ListValue.wrap(result);
|
||||
final Value ret = ListValue.wrap(result);
|
||||
//revering scope
|
||||
c.setVariable("_", _val);
|
||||
c.setVariable("_i", _iter);
|
||||
return (cc, tt) -> ret;
|
||||
return (cc, tt) -> ret;
|
||||
});
|
||||
|
||||
// grep(list or num, expr) => list
|
||||
@@ -146,32 +179,42 @@ public class Loops {
|
||||
// produces list of values for which the expression is true
|
||||
expression.addLazyFunction("filter", 2, (c, t, lv) ->
|
||||
{
|
||||
Value rval= lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull()) return ListValue.lazyEmpty();
|
||||
if (!(rval instanceof AbstractListValue))
|
||||
throw new InternalExpressionException("First argument of 'filter' function should be a list or iterator");
|
||||
Iterator<Value> iterator = ((AbstractListValue) rval).iterator();
|
||||
LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
LazyValue _val = c.getVariable("_");
|
||||
LazyValue _iter = c.getVariable("_i");
|
||||
List<Value> result = new ArrayList<>();
|
||||
for (int i=0; iterator.hasNext(); i++)
|
||||
final Value rval = lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull())
|
||||
{
|
||||
Value next = iterator.next();
|
||||
String var = next.boundVariable;
|
||||
return ListValue.lazyEmpty();
|
||||
}
|
||||
if (!(rval instanceof final AbstractListValue alv))
|
||||
{
|
||||
throw new InternalExpressionException("First argument of 'filter' function should be a list or iterator");
|
||||
}
|
||||
final Iterator<Value> iterator = alv.iterator();
|
||||
final LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
final LazyValue _val = c.getVariable("_");
|
||||
final LazyValue _iter = c.getVariable("_i");
|
||||
final List<Value> result = new ArrayList<>();
|
||||
for (int i = 0; iterator.hasNext(); i++)
|
||||
{
|
||||
final Value next = iterator.next();
|
||||
final String var = next.boundVariable;
|
||||
next.bindTo("_");
|
||||
int seriously = i;
|
||||
final int seriously = i;
|
||||
c.setVariable("_", (cc, tt) -> next);
|
||||
c.setVariable("_i", (cc, tt) -> new NumericValue(seriously).bindTo("_i"));
|
||||
try
|
||||
{
|
||||
if(expr.evalValue(c, Context.BOOLEAN).getBoolean())
|
||||
if (expr.evalValue(c, Context.BOOLEAN).getBoolean())
|
||||
{
|
||||
result.add(next);
|
||||
}
|
||||
}
|
||||
catch (BreakStatement | ContinueStatement stmt)
|
||||
catch (final BreakStatement | ContinueStatement stmt)
|
||||
{
|
||||
if (stmt.retval != null && stmt.retval.getBoolean()) result.add(next);
|
||||
if (stmt.retval != null && stmt.retval.getBoolean())
|
||||
{
|
||||
result.add(next);
|
||||
}
|
||||
if (stmt instanceof BreakStatement)
|
||||
{
|
||||
next.boundVariable = var;
|
||||
@@ -181,7 +224,7 @@ public class Loops {
|
||||
next.boundVariable = var;
|
||||
}
|
||||
((AbstractListValue) rval).fatality();
|
||||
Value ret = ListValue.wrap(result);
|
||||
final Value ret = ListValue.wrap(result);
|
||||
//revering scope
|
||||
c.setVariable("_", _val);
|
||||
c.setVariable("_i", _iter);
|
||||
@@ -193,41 +236,45 @@ public class Loops {
|
||||
// returns first element on the list for which the expr is true
|
||||
expression.addLazyFunction("first", 2, (c, t, lv) ->
|
||||
{
|
||||
|
||||
Value rval= lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull()) return LazyValue.NULL;
|
||||
if (!(rval instanceof AbstractListValue))
|
||||
throw new InternalExpressionException("First argument of 'first' function should be a list or iterator");
|
||||
Iterator<Value> iterator = ((AbstractListValue) rval).iterator();
|
||||
LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
LazyValue _val = c.getVariable("_");
|
||||
LazyValue _iter = c.getVariable("_i");
|
||||
Value result = Value.NULL;
|
||||
for (int i=0; iterator.hasNext(); i++)
|
||||
final Value rval = lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull())
|
||||
{
|
||||
Value next = iterator.next();
|
||||
String var = next.boundVariable;
|
||||
return LazyValue.NULL;
|
||||
}
|
||||
if (!(rval instanceof final AbstractListValue alv))
|
||||
{
|
||||
throw new InternalExpressionException("First argument of 'first' function should be a list or iterator");
|
||||
}
|
||||
final Iterator<Value> iterator = alv.iterator();
|
||||
final LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
final LazyValue _val = c.getVariable("_");
|
||||
final LazyValue _iter = c.getVariable("_i");
|
||||
Value result = Value.NULL;
|
||||
for (int i = 0; iterator.hasNext(); i++)
|
||||
{
|
||||
final Value next = iterator.next();
|
||||
final String var = next.boundVariable;
|
||||
next.bindTo("_");
|
||||
int seriously = i;
|
||||
final int seriously = i;
|
||||
c.setVariable("_", (cc, tt) -> next);
|
||||
c.setVariable("_i", (cc, tt) -> new NumericValue(seriously).bindTo("_i"));
|
||||
try
|
||||
{
|
||||
if(expr.evalValue(c, Context.BOOLEAN).getBoolean())
|
||||
if (expr.evalValue(c, Context.BOOLEAN).getBoolean())
|
||||
{
|
||||
result = next;
|
||||
next.boundVariable = var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (BreakStatement stmt)
|
||||
catch (final BreakStatement stmt)
|
||||
{
|
||||
result = stmt.retval == null? next : stmt.retval;
|
||||
result = stmt.retval == null ? next : stmt.retval;
|
||||
next.boundVariable = var;
|
||||
break;
|
||||
}
|
||||
catch (ContinueStatement ignored)
|
||||
catch (final ContinueStatement ignored)
|
||||
{
|
||||
throw new InternalExpressionException("'continue' inside 'first' function has no sense");
|
||||
}
|
||||
@@ -235,7 +282,7 @@ public class Loops {
|
||||
}
|
||||
//revering scope
|
||||
((AbstractListValue) rval).fatality();
|
||||
Value whyWontYouTrustMeJava = result;
|
||||
final Value whyWontYouTrustMeJava = result;
|
||||
c.setVariable("_", _val);
|
||||
c.setVariable("_i", _iter);
|
||||
return (cc, tt) -> whyWontYouTrustMeJava;
|
||||
@@ -246,25 +293,30 @@ public class Loops {
|
||||
// returns true if expr is true for all items
|
||||
expression.addLazyFunction("all", 2, (c, t, lv) ->
|
||||
{
|
||||
Value rval= lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull()) return LazyValue.TRUE;
|
||||
if (!(rval instanceof AbstractListValue))
|
||||
throw new InternalExpressionException("First argument of 'all' function should be a list or iterator");
|
||||
Iterator<Value> iterator = ((AbstractListValue) rval).iterator();
|
||||
LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
LazyValue _val = c.getVariable("_");
|
||||
LazyValue _iter = c.getVariable("_i");
|
||||
LazyValue result = LazyValue.TRUE;
|
||||
for (int i=0; iterator.hasNext(); i++)
|
||||
final Value rval = lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull())
|
||||
{
|
||||
Value next = iterator.next();
|
||||
String var = next.boundVariable;
|
||||
return LazyValue.TRUE;
|
||||
}
|
||||
if (!(rval instanceof final AbstractListValue alv))
|
||||
{
|
||||
throw new InternalExpressionException("First argument of 'all' function should be a list or iterator");
|
||||
}
|
||||
final Iterator<Value> iterator = alv.iterator();
|
||||
final LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
final LazyValue _val = c.getVariable("_");
|
||||
final LazyValue _iter = c.getVariable("_i");
|
||||
LazyValue result = LazyValue.TRUE;
|
||||
for (int i = 0; iterator.hasNext(); i++)
|
||||
{
|
||||
final Value next = iterator.next();
|
||||
final String var = next.boundVariable;
|
||||
next.bindTo("_");
|
||||
int seriously = i;
|
||||
final int seriously = i;
|
||||
c.setVariable("_", (cc, tt) -> next);
|
||||
c.setVariable("_i", (cc, tt) -> new NumericValue(seriously).bindTo("_i"));
|
||||
if(!expr.evalValue(c, Context.BOOLEAN).getBoolean())
|
||||
if (!expr.evalValue(c, Context.BOOLEAN).getBoolean())
|
||||
{
|
||||
result = LazyValue.FALSE;
|
||||
next.boundVariable = var;
|
||||
@@ -282,10 +334,10 @@ public class Loops {
|
||||
// runs traditional for(init, condition, increment, body) tri-argument for loop with body in between
|
||||
expression.addLazyFunction("c_for", 4, (c, t, lv) ->
|
||||
{
|
||||
LazyValue initial = lv.get(0);
|
||||
LazyValue condition = lv.get(1);
|
||||
LazyValue increment = lv.get(2);
|
||||
LazyValue body = lv.get(3);
|
||||
final LazyValue initial = lv.get(0);
|
||||
final LazyValue condition = lv.get(1);
|
||||
final LazyValue increment = lv.get(2);
|
||||
final LazyValue body = lv.get(3);
|
||||
int iterations = 0;
|
||||
for (initial.evalValue(c, Context.VOID); condition.evalValue(c, Context.BOOLEAN).getBoolean(); increment.evalValue(c, Context.VOID))
|
||||
{
|
||||
@@ -293,16 +345,16 @@ public class Loops {
|
||||
{
|
||||
body.evalValue(c, Context.VOID);
|
||||
}
|
||||
catch (BreakStatement stmt)
|
||||
catch (final BreakStatement stmt)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (ContinueStatement ignored)
|
||||
catch (final ContinueStatement ignored)
|
||||
{
|
||||
}
|
||||
iterations++;
|
||||
}
|
||||
int finalIterations = iterations;
|
||||
final int finalIterations = iterations;
|
||||
return (cc, tt) -> new NumericValue(finalIterations);
|
||||
});
|
||||
|
||||
@@ -311,22 +363,27 @@ public class Loops {
|
||||
// can be substituted for first and all, but first is more efficient and all doesn't require knowing list size
|
||||
expression.addLazyFunction("for", 2, (c, t, lv) ->
|
||||
{
|
||||
Value rval= lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull()) return LazyValue.ZERO;
|
||||
if (!(rval instanceof AbstractListValue))
|
||||
throw new InternalExpressionException("First argument of 'for' function should be a list or iterator");
|
||||
Iterator<Value> iterator = ((AbstractListValue) rval).iterator();
|
||||
LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
LazyValue _val = c.getVariable("_");
|
||||
LazyValue _ite = c.getVariable("_i");
|
||||
int successCount = 0;
|
||||
for (int i=0; iterator.hasNext(); i++)
|
||||
final Value rval = lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull())
|
||||
{
|
||||
Value next = iterator.next();
|
||||
String var = next.boundVariable;
|
||||
return LazyValue.ZERO;
|
||||
}
|
||||
if (!(rval instanceof final AbstractListValue alv))
|
||||
{
|
||||
throw new InternalExpressionException("First argument of 'for' function should be a list or iterator");
|
||||
}
|
||||
final Iterator<Value> iterator = alv.iterator();
|
||||
final LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
final LazyValue _val = c.getVariable("_");
|
||||
final LazyValue _ite = c.getVariable("_i");
|
||||
int successCount = 0;
|
||||
for (int i = 0; iterator.hasNext(); i++)
|
||||
{
|
||||
final Value next = iterator.next();
|
||||
final String var = next.boundVariable;
|
||||
next.bindTo("_");
|
||||
int seriously = i;
|
||||
final int seriously = i;
|
||||
c.setVariable("_", (cc, tt) -> next);
|
||||
c.setVariable("_i", (cc, tt) -> new NumericValue(seriously).bindTo("_i"));
|
||||
Value result = Value.FALSE;
|
||||
@@ -334,24 +391,29 @@ public class Loops {
|
||||
{
|
||||
result = expr.evalValue(c, t);
|
||||
}
|
||||
catch (BreakStatement | ContinueStatement stmt)
|
||||
catch (final BreakStatement | ContinueStatement stmt)
|
||||
{
|
||||
if (stmt.retval != null) result = stmt.retval;
|
||||
if (stmt.retval != null)
|
||||
{
|
||||
result = stmt.retval;
|
||||
}
|
||||
if (stmt instanceof BreakStatement)
|
||||
{
|
||||
next.boundVariable = var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(t != Context.VOID && result.getBoolean())
|
||||
if (t != Context.VOID && result.getBoolean())
|
||||
{
|
||||
successCount++;
|
||||
}
|
||||
next.boundVariable = var;
|
||||
}
|
||||
//revering scope
|
||||
((AbstractListValue) rval).fatality();
|
||||
c.setVariable("_", _val);
|
||||
c.setVariable("_i", _ite);
|
||||
long promiseWontChange = successCount;
|
||||
final long promiseWontChange = successCount;
|
||||
return (cc, tt) -> new NumericValue(promiseWontChange);
|
||||
});
|
||||
|
||||
@@ -363,32 +425,37 @@ public class Loops {
|
||||
expression.addLazyFunction("reduce", 3, (c, t, lv) ->
|
||||
{
|
||||
|
||||
Value rval= lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull()) return ListValue.lazyEmpty();
|
||||
if (!(rval instanceof AbstractListValue))
|
||||
final Value rval = lv.get(0).evalValue(c, Context.NONE);
|
||||
if (rval.isNull())
|
||||
{
|
||||
return ListValue.lazyEmpty();
|
||||
}
|
||||
if (!(rval instanceof final AbstractListValue alv))
|
||||
{
|
||||
throw new InternalExpressionException("First argument of 'reduce' should be a list or iterator");
|
||||
LazyValue expr = lv.get(1);
|
||||
}
|
||||
final LazyValue expr = lv.get(1);
|
||||
Value acc = lv.get(2).evalValue(c, Context.NONE);
|
||||
Iterator<Value> iterator = ((AbstractListValue) rval).iterator();
|
||||
final Iterator<Value> iterator = alv.iterator();
|
||||
|
||||
if (!iterator.hasNext())
|
||||
{
|
||||
Value seriouslyWontChange = acc;
|
||||
final Value seriouslyWontChange = acc;
|
||||
return (cc, tt) -> seriouslyWontChange;
|
||||
}
|
||||
|
||||
//scoping
|
||||
LazyValue _val = c.getVariable("_");
|
||||
LazyValue _acc = c.getVariable("_a");
|
||||
LazyValue _ite = c.getVariable("_i");
|
||||
final LazyValue _val = c.getVariable("_");
|
||||
final LazyValue _acc = c.getVariable("_a");
|
||||
final LazyValue _ite = c.getVariable("_i");
|
||||
|
||||
for (int i=0; iterator.hasNext(); i++)
|
||||
for (int i = 0; iterator.hasNext(); i++)
|
||||
{
|
||||
Value next = iterator.next();
|
||||
String var = next.boundVariable;
|
||||
final Value next = iterator.next();
|
||||
final String var = next.boundVariable;
|
||||
next.bindTo("_");
|
||||
Value promiseWontChangeYou = acc;
|
||||
int seriously = i;
|
||||
final Value promiseWontChangeYou = acc;
|
||||
final int seriously = i;
|
||||
c.setVariable("_a", (cc, tt) -> promiseWontChangeYou.bindTo("_a"));
|
||||
c.setVariable("_", (cc, tt) -> next);
|
||||
c.setVariable("_i", (cc, tt) -> new NumericValue(seriously).bindTo("_i"));
|
||||
@@ -396,9 +463,12 @@ public class Loops {
|
||||
{
|
||||
acc = expr.evalValue(c, t);
|
||||
}
|
||||
catch (BreakStatement | ContinueStatement stmt)
|
||||
catch (final BreakStatement | ContinueStatement stmt)
|
||||
{
|
||||
if (stmt.retval != null) acc = stmt.retval;
|
||||
if (stmt.retval != null)
|
||||
{
|
||||
acc = stmt.retval;
|
||||
}
|
||||
if (stmt instanceof BreakStatement)
|
||||
{
|
||||
next.boundVariable = var;
|
||||
@@ -413,7 +483,7 @@ public class Loops {
|
||||
c.setVariable("_", _val);
|
||||
c.setVariable("_i", _ite);
|
||||
|
||||
Value hopeItsEnoughPromise = acc;
|
||||
final Value hopeItsEnoughPromise = acc;
|
||||
return (cc, tt) -> hopeItsEnoughPromise;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,8 +21,10 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Operators {
|
||||
public static final Map<String, Integer> precedence = new HashMap<String, Integer>() {{
|
||||
public class Operators
|
||||
{
|
||||
public static final Map<String, Integer> precedence = new HashMap<>()
|
||||
{{
|
||||
put("attribute~:", 80);
|
||||
put("unary+-!...", 60);
|
||||
put("exponent^", 40);
|
||||
@@ -37,44 +39,68 @@ public class Operators {
|
||||
put("nextop;", 1);
|
||||
}};
|
||||
|
||||
public static void apply(Expression expression)
|
||||
public static void apply(final Expression expression)
|
||||
{
|
||||
expression.addBinaryOperator("+", precedence.get("addition+-"), true, Value::add);
|
||||
expression.addFunction("sum", lv -> {
|
||||
int size = lv.size();
|
||||
if (size == 0) return Value.NULL;
|
||||
final int size = lv.size();
|
||||
if (size == 0)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
Value accumulator = lv.get(0);
|
||||
for (Value v: lv.subList(1, size)) accumulator = accumulator.add(v);
|
||||
for (final Value v : lv.subList(1, size))
|
||||
{
|
||||
accumulator = accumulator.add(v);
|
||||
}
|
||||
return accumulator;
|
||||
});
|
||||
expression.addFunctionalEquivalence("+", "sum");
|
||||
|
||||
expression.addBinaryOperator("-", precedence.get("addition+-"), true, Value::subtract);
|
||||
expression.addFunction("difference", lv -> {
|
||||
int size = lv.size();
|
||||
if (size == 0) return Value.NULL;
|
||||
final int size = lv.size();
|
||||
if (size == 0)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
Value accumulator = lv.get(0);
|
||||
for (Value v: lv.subList(1, size)) accumulator = accumulator.subtract(v);
|
||||
for (final Value v : lv.subList(1, size))
|
||||
{
|
||||
accumulator = accumulator.subtract(v);
|
||||
}
|
||||
return accumulator;
|
||||
});
|
||||
expression.addFunctionalEquivalence("-", "difference");
|
||||
|
||||
expression.addBinaryOperator("*", precedence.get("multiplication*/%"), true, Value::multiply);
|
||||
expression.addFunction("product", lv -> {
|
||||
int size = lv.size();
|
||||
if (size == 0) return Value.NULL;
|
||||
final int size = lv.size();
|
||||
if (size == 0)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
Value accumulator = lv.get(0);
|
||||
for (Value v: lv.subList(1, size)) accumulator = accumulator.multiply(v);
|
||||
for (final Value v : lv.subList(1, size))
|
||||
{
|
||||
accumulator = accumulator.multiply(v);
|
||||
}
|
||||
return accumulator;
|
||||
});
|
||||
expression.addFunctionalEquivalence("*", "product");
|
||||
|
||||
expression.addBinaryOperator("/", precedence.get("multiplication*/%"), true, Value::divide);
|
||||
expression.addFunction("quotient", lv -> {
|
||||
int size = lv.size();
|
||||
if (size == 0) return Value.NULL;
|
||||
final int size = lv.size();
|
||||
if (size == 0)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
Value accumulator = lv.get(0);
|
||||
for (Value v: lv.subList(1, size)) accumulator = accumulator.divide(v);
|
||||
for (final Value v : lv.subList(1, size))
|
||||
{
|
||||
accumulator = accumulator.divide(v);
|
||||
}
|
||||
return accumulator;
|
||||
});
|
||||
expression.addFunctionalEquivalence("/", "quotient");
|
||||
@@ -85,51 +111,79 @@ public class Operators {
|
||||
new NumericValue(java.lang.Math.pow(NumericValue.asNumber(v1).getDouble(), NumericValue.asNumber(v2).getDouble())));
|
||||
|
||||
expression.addFunction("bitwise_and", lv -> {
|
||||
int size = lv.size();
|
||||
if (size == 0) return Value.NULL;
|
||||
final int size = lv.size();
|
||||
if (size == 0)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
long accumulator = NumericValue.asNumber(lv.get(0)).getLong();
|
||||
for (Value v: lv.subList(1, size)) accumulator = accumulator & NumericValue.asNumber(v).getLong();
|
||||
for (final Value v : lv.subList(1, size))
|
||||
{
|
||||
accumulator = accumulator & NumericValue.asNumber(v).getLong();
|
||||
}
|
||||
return new NumericValue(accumulator);
|
||||
});
|
||||
|
||||
expression.addFunction("bitwise_xor", lv -> {
|
||||
int size = lv.size();
|
||||
if (size == 0) return Value.NULL;
|
||||
final int size = lv.size();
|
||||
if (size == 0)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
long accumulator = NumericValue.asNumber(lv.get(0)).getLong();
|
||||
for (Value v: lv.subList(1, size)) accumulator = accumulator ^ NumericValue.asNumber(v).getLong();
|
||||
for (final Value v : lv.subList(1, size))
|
||||
{
|
||||
accumulator = accumulator ^ NumericValue.asNumber(v).getLong();
|
||||
}
|
||||
return new NumericValue(accumulator);
|
||||
});
|
||||
|
||||
expression.addFunction("bitwise_or", lv -> {
|
||||
int size = lv.size();
|
||||
if (size == 0) return Value.NULL;
|
||||
final int size = lv.size();
|
||||
if (size == 0)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
long accumulator = NumericValue.asNumber(lv.get(0)).getLong();
|
||||
for (Value v: lv.subList(1, size)) accumulator = accumulator | NumericValue.asNumber(v).getLong();
|
||||
for (final Value v : lv.subList(1, size))
|
||||
{
|
||||
accumulator = accumulator | NumericValue.asNumber(v).getLong();
|
||||
}
|
||||
return new NumericValue(accumulator);
|
||||
});
|
||||
|
||||
// lazy cause RHS is only conditional
|
||||
expression.addLazyBinaryOperator("&&", precedence.get("and&&"), false, true, t -> Context.Type.BOOLEAN, (c, t, lv1, lv2) ->
|
||||
{ // todo check how is optimizations going
|
||||
Value v1 = lv1.evalValue(c, Context.BOOLEAN);
|
||||
if (!v1.getBoolean()) return (cc, tt) -> v1;
|
||||
return lv2;
|
||||
final Value v1 = lv1.evalValue(c, Context.BOOLEAN);
|
||||
return v1.getBoolean() ? lv2 : ((cc, tt) -> v1);
|
||||
});
|
||||
|
||||
expression.addPureLazyFunction("and", -1, t -> Context.Type.BOOLEAN, (c, t, lv) -> {
|
||||
int last = lv.size()-1;
|
||||
if (last == -1) return LazyValue.TRUE;
|
||||
for (LazyValue l: lv.subList(0, last))
|
||||
final int last = lv.size() - 1;
|
||||
if (last == -1)
|
||||
{
|
||||
Value val = l.evalValue(c, Context.Type.BOOLEAN);
|
||||
if (val instanceof FunctionUnpackedArgumentsValue)
|
||||
return LazyValue.TRUE;
|
||||
}
|
||||
for (final LazyValue l : lv.subList(0, last))
|
||||
{
|
||||
final Value val = l.evalValue(c, Context.Type.BOOLEAN);
|
||||
if (val instanceof final FunctionUnpackedArgumentsValue fuav)
|
||||
{
|
||||
for (Value it : (FunctionUnpackedArgumentsValue) val)
|
||||
if (!it.getBoolean()) return (cc, tt) -> it;
|
||||
for (final Value it : fuav)
|
||||
{
|
||||
if (!it.getBoolean())
|
||||
{
|
||||
return (cc, tt) -> it;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!val.getBoolean()) return (cc, tt) -> val;
|
||||
if (!val.getBoolean())
|
||||
{
|
||||
return (cc, tt) -> val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lv.get(last);
|
||||
@@ -139,25 +193,35 @@ public class Operators {
|
||||
// lazy cause RHS is only conditional
|
||||
expression.addLazyBinaryOperator("||", precedence.get("or||"), false, true, t -> Context.Type.BOOLEAN, (c, t, lv1, lv2) ->
|
||||
{
|
||||
Value v1 = lv1.evalValue(c, Context.BOOLEAN);
|
||||
if (v1.getBoolean()) return (cc, tt) -> v1;
|
||||
return lv2;
|
||||
final Value v1 = lv1.evalValue(c, Context.BOOLEAN);
|
||||
return v1.getBoolean() ? ((cc, tt) -> v1) : lv2;
|
||||
});
|
||||
|
||||
expression.addPureLazyFunction("or", -1, t -> Context.Type.BOOLEAN, (c, t, lv) -> {
|
||||
int last = lv.size()-1;
|
||||
if (last == -1) return LazyValue.FALSE;
|
||||
for (LazyValue l: lv.subList(0, last))
|
||||
final int last = lv.size() - 1;
|
||||
if (last == -1)
|
||||
{
|
||||
Value val = l.evalValue(c, Context.Type.BOOLEAN);
|
||||
if (val instanceof FunctionUnpackedArgumentsValue)
|
||||
return LazyValue.FALSE;
|
||||
}
|
||||
for (final LazyValue l : lv.subList(0, last))
|
||||
{
|
||||
final Value val = l.evalValue(c, Context.Type.BOOLEAN);
|
||||
if (val instanceof final FunctionUnpackedArgumentsValue fuav)
|
||||
{
|
||||
for (Value it : (FunctionUnpackedArgumentsValue) val)
|
||||
if (it.getBoolean()) return (cc, tt) -> it;
|
||||
for (final Value it : fuav)
|
||||
{
|
||||
if (it.getBoolean())
|
||||
{
|
||||
return (cc, tt) -> it;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (val.getBoolean()) return (cc, tt) -> val;
|
||||
if (val.getBoolean())
|
||||
{
|
||||
return (cc, tt) -> val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lv.get(last);
|
||||
@@ -169,12 +233,18 @@ public class Operators {
|
||||
expression.addBinaryOperator(">", precedence.get("compare>=><=<"), false, (v1, v2) ->
|
||||
BooleanValue.of(v1.compareTo(v2) > 0));
|
||||
expression.addFunction("decreasing", lv -> {
|
||||
int size = lv.size();
|
||||
if (size < 2) return Value.TRUE;
|
||||
Value prev = lv.get(0);
|
||||
for (Value next: lv.subList(1, size))
|
||||
final int size = lv.size();
|
||||
if (size < 2)
|
||||
{
|
||||
if (prev.compareTo(next) <= 0) return Value.FALSE;
|
||||
return Value.TRUE;
|
||||
}
|
||||
Value prev = lv.get(0);
|
||||
for (final Value next : lv.subList(1, size))
|
||||
{
|
||||
if (prev.compareTo(next) <= 0)
|
||||
{
|
||||
return Value.FALSE;
|
||||
}
|
||||
prev = next;
|
||||
}
|
||||
return Value.TRUE;
|
||||
@@ -184,12 +254,18 @@ public class Operators {
|
||||
expression.addBinaryOperator(">=", precedence.get("compare>=><=<"), false, (v1, v2) ->
|
||||
BooleanValue.of(v1.compareTo(v2) >= 0));
|
||||
expression.addFunction("nonincreasing", lv -> {
|
||||
int size = lv.size();
|
||||
if (size < 2) return Value.TRUE;
|
||||
Value prev = lv.get(0);
|
||||
for (Value next: lv.subList(1, size))
|
||||
final int size = lv.size();
|
||||
if (size < 2)
|
||||
{
|
||||
if (prev.compareTo(next) < 0) return Value.FALSE;
|
||||
return Value.TRUE;
|
||||
}
|
||||
Value prev = lv.get(0);
|
||||
for (final Value next : lv.subList(1, size))
|
||||
{
|
||||
if (prev.compareTo(next) < 0)
|
||||
{
|
||||
return Value.FALSE;
|
||||
}
|
||||
prev = next;
|
||||
}
|
||||
return Value.TRUE;
|
||||
@@ -199,12 +275,18 @@ public class Operators {
|
||||
expression.addBinaryOperator("<", precedence.get("compare>=><=<"), false, (v1, v2) ->
|
||||
BooleanValue.of(v1.compareTo(v2) < 0));
|
||||
expression.addFunction("increasing", lv -> {
|
||||
int size = lv.size();
|
||||
if (size < 2) return Value.TRUE;
|
||||
Value prev = lv.get(0);
|
||||
for (Value next: lv.subList(1, size))
|
||||
final int size = lv.size();
|
||||
if (size < 2)
|
||||
{
|
||||
if (prev.compareTo(next) >= 0) return Value.FALSE;
|
||||
return Value.TRUE;
|
||||
}
|
||||
Value prev = lv.get(0);
|
||||
for (final Value next : lv.subList(1, size))
|
||||
{
|
||||
if (prev.compareTo(next) >= 0)
|
||||
{
|
||||
return Value.FALSE;
|
||||
}
|
||||
prev = next;
|
||||
}
|
||||
return Value.TRUE;
|
||||
@@ -214,79 +296,84 @@ public class Operators {
|
||||
expression.addBinaryOperator("<=", precedence.get("compare>=><=<"), false, (v1, v2) ->
|
||||
BooleanValue.of(v1.compareTo(v2) <= 0));
|
||||
expression.addFunction("nondecreasing", lv -> {
|
||||
int size = lv.size();
|
||||
if (size < 2) return Value.TRUE;
|
||||
Value prev = lv.get(0);
|
||||
for (Value next: lv.subList(1, size))
|
||||
final int size = lv.size();
|
||||
if (size < 2)
|
||||
{
|
||||
if (prev.compareTo(next) > 0) return Value.FALSE;
|
||||
return Value.TRUE;
|
||||
}
|
||||
Value prev = lv.get(0);
|
||||
for (final Value next : lv.subList(1, size))
|
||||
{
|
||||
if (prev.compareTo(next) > 0)
|
||||
{
|
||||
return Value.FALSE;
|
||||
}
|
||||
prev = next;
|
||||
}
|
||||
return Value.TRUE;
|
||||
});
|
||||
expression.addFunctionalEquivalence("<=", "nondecreasing");
|
||||
|
||||
expression.addMathematicalBinaryIntFunction("bitwise_shift_left", (num, amount) -> {
|
||||
return num << amount;
|
||||
});
|
||||
expression.addMathematicalBinaryIntFunction("bitwise_shift_right", (num, amount) -> {
|
||||
return num >> amount;
|
||||
});
|
||||
expression.addMathematicalBinaryIntFunction("bitwise_shift_left", (num, amount) -> num << amount);
|
||||
expression.addMathematicalBinaryIntFunction("bitwise_shift_right", (num, amount) -> num >> amount);
|
||||
expression.addMathematicalBinaryIntFunction("bitwise_roll_left", (num, num2) -> {
|
||||
long amount = num2 % 64;
|
||||
|
||||
long amountToRoll = 64 - amount;
|
||||
long rolledBits = ((-1L) >> amountToRoll) << amountToRoll;
|
||||
long rolledAmount = (num & rolledBits) >> amountToRoll;
|
||||
final long amount = num2 % 64;
|
||||
final long amountToRoll = 64 - amount;
|
||||
final long rolledBits = ((-1L) >> amountToRoll) << amountToRoll;
|
||||
final long rolledAmount = (num & rolledBits) >> amountToRoll;
|
||||
return num << amount | rolledAmount;
|
||||
});
|
||||
expression.addMathematicalBinaryIntFunction("bitwise_roll_right", (num, num2) -> {
|
||||
long amount = num2 % 64;
|
||||
|
||||
long amountToRoll = 64 - amount;
|
||||
long rolledBits = ((-1L) << amountToRoll) >> amountToRoll;
|
||||
long rolledAmount = (num & rolledBits) << amountToRoll;
|
||||
final long amount = num2 % 64;
|
||||
final long amountToRoll = 64 - amount;
|
||||
final long rolledBits = ((-1L) << amountToRoll) >> amountToRoll;
|
||||
final long rolledAmount = (num & rolledBits) << amountToRoll;
|
||||
return num >> amount | rolledAmount;
|
||||
});
|
||||
expression.addMathematicalUnaryIntFunction("bitwise_not", d -> {
|
||||
long num = d.longValue();
|
||||
return num ^ (-1L);
|
||||
final long num = (long) d;
|
||||
return ~num;
|
||||
});
|
||||
expression.addMathematicalUnaryIntFunction("bitwise_popcount", d -> Long.valueOf(Long.bitCount(d.longValue())));
|
||||
|
||||
expression.addMathematicalUnaryIntFunction("bitwise_popcount", d -> (long) Long.bitCount((long)d));
|
||||
expression.addMathematicalUnaryIntFunction("double_to_long_bits", Double::doubleToLongBits);
|
||||
expression.addUnaryFunction("long_to_double_bits", v -> {
|
||||
return new NumericValue(Double.longBitsToDouble(NumericValue.asNumber(v).getLong()));
|
||||
});
|
||||
|
||||
|
||||
expression.addUnaryFunction("long_to_double_bits", v ->
|
||||
new NumericValue(Double.longBitsToDouble(NumericValue.asNumber(v).getLong())));
|
||||
expression.addBinaryOperator("==", precedence.get("equal==!="), false, (v1, v2) ->
|
||||
v1.equals(v2) ? Value.TRUE : Value.FALSE);
|
||||
expression.addFunction("equal", lv -> {
|
||||
int size = lv.size();
|
||||
if (size < 2) return Value.TRUE;
|
||||
Value prev = lv.get(0);
|
||||
for (Value next: lv.subList(1, size))
|
||||
final int size = lv.size();
|
||||
if (size < 2)
|
||||
{
|
||||
if (!prev.equals(next)) return Value.FALSE;
|
||||
return Value.TRUE;
|
||||
}
|
||||
Value prev = lv.get(0);
|
||||
for (final Value next : lv.subList(1, size))
|
||||
{
|
||||
if (!prev.equals(next))
|
||||
{
|
||||
return Value.FALSE;
|
||||
}
|
||||
prev = next;
|
||||
}
|
||||
return Value.TRUE;
|
||||
});
|
||||
expression.addFunctionalEquivalence("==", "equal");
|
||||
|
||||
|
||||
expression.addBinaryOperator("!=", precedence.get("equal==!="), false, (v1, v2) ->
|
||||
v1.equals(v2) ? Value.FALSE : Value.TRUE);
|
||||
expression.addFunction("unique", lv -> {
|
||||
int size = lv.size();
|
||||
if (size < 2) return Value.TRUE;
|
||||
final int size = lv.size();
|
||||
if (size < 2)
|
||||
{
|
||||
return Value.TRUE;
|
||||
}
|
||||
// need to order them so same obejects will be next to each other.
|
||||
lv.sort(Comparator.comparingInt(Value::hashCode));
|
||||
Value prev = lv.get(0);
|
||||
for (Value next: lv.subList(1, size))
|
||||
for (final Value next : lv.subList(1, size))
|
||||
{
|
||||
if (prev.equals(next)) return Value.FALSE;
|
||||
if (prev.equals(next))
|
||||
{
|
||||
return Value.FALSE;
|
||||
}
|
||||
prev = next;
|
||||
}
|
||||
return Value.TRUE;
|
||||
@@ -296,38 +383,52 @@ public class Operators {
|
||||
// lazy cause of assignment which is non-trivial
|
||||
expression.addLazyBinaryOperator("=", precedence.get("assign=<>"), false, false, t -> Context.Type.LVALUE, (c, t, lv1, lv2) ->
|
||||
{
|
||||
Value v1 = lv1.evalValue(c, Context.LVALUE);
|
||||
Value v2 = lv2.evalValue(c);
|
||||
if (v1 instanceof ListValue.ListConstructorValue && v2 instanceof ListValue)
|
||||
final Value v1 = lv1.evalValue(c, Context.LVALUE);
|
||||
final Value v2 = lv2.evalValue(c);
|
||||
if (v1 instanceof final ListValue.ListConstructorValue lcv && v2 instanceof final ListValue list)
|
||||
{
|
||||
List<Value> ll = ((ListValue)v1).getItems();
|
||||
List<Value> rl = ((ListValue)v2).getItems();
|
||||
if (ll.size() < rl.size()) throw new InternalExpressionException("Too many values to unpack");
|
||||
if (ll.size() > rl.size()) throw new InternalExpressionException("Too few values to unpack");
|
||||
for (Value v: ll) v.assertAssignable();
|
||||
Iterator<Value> li = ll.iterator();
|
||||
Iterator<Value> ri = rl.iterator();
|
||||
while(li.hasNext())
|
||||
final List<Value> ll = lcv.getItems();
|
||||
final List<Value> rl = list.getItems();
|
||||
if (ll.size() < rl.size())
|
||||
{
|
||||
String lname = li.next().getVariable();
|
||||
Value vval = ri.next().reboundedTo(lname);
|
||||
throw new InternalExpressionException("Too many values to unpack");
|
||||
}
|
||||
if (ll.size() > rl.size())
|
||||
{
|
||||
throw new InternalExpressionException("Too few values to unpack");
|
||||
}
|
||||
for (final Value v : ll)
|
||||
{
|
||||
v.assertAssignable();
|
||||
}
|
||||
final Iterator<Value> li = ll.iterator();
|
||||
final Iterator<Value> ri = rl.iterator();
|
||||
while (li.hasNext())
|
||||
{
|
||||
final String lname = li.next().getVariable();
|
||||
final Value vval = ri.next().reboundedTo(lname);
|
||||
expression.setAnyVariable(c, lname, (cc, tt) -> vval);
|
||||
}
|
||||
return (cc, tt) -> Value.TRUE;
|
||||
}
|
||||
if (v1 instanceof LContainerValue)
|
||||
if (v1 instanceof final LContainerValue lcv)
|
||||
{
|
||||
ContainerValueInterface container = ((LContainerValue) v1).getContainer();
|
||||
final ContainerValueInterface container = lcv.container();
|
||||
if (container == null)
|
||||
{
|
||||
return (cc, tt) -> Value.NULL;
|
||||
Value address = ((LContainerValue) v1).getAddress();
|
||||
if (!(container.put(address, v2))) return (cc, tt) -> Value.NULL;
|
||||
}
|
||||
final Value address = lcv.address();
|
||||
if (!(container.put(address, v2)))
|
||||
{
|
||||
return (cc, tt) -> Value.NULL;
|
||||
}
|
||||
return (cc, tt) -> v2;
|
||||
}
|
||||
v1.assertAssignable();
|
||||
String varname = v1.getVariable();
|
||||
Value copy = v2.reboundedTo(varname);
|
||||
LazyValue boundedLHS = (cc, tt) -> copy;
|
||||
final String varname = v1.getVariable();
|
||||
final Value copy = v2.reboundedTo(varname);
|
||||
final LazyValue boundedLHS = (cc, tt) -> copy;
|
||||
expression.setAnyVariable(c, varname, boundedLHS);
|
||||
return boundedLHS;
|
||||
});
|
||||
@@ -335,35 +436,44 @@ public class Operators {
|
||||
// lazy due to assignment
|
||||
expression.addLazyBinaryOperator("+=", precedence.get("assign=<>"), false, false, t -> Context.Type.LVALUE, (c, t, lv1, lv2) ->
|
||||
{
|
||||
Value v1 = lv1.evalValue(c, Context.LVALUE);
|
||||
Value v2 = lv2.evalValue(c);
|
||||
if (v1 instanceof ListValue.ListConstructorValue && v2 instanceof ListValue)
|
||||
final Value v1 = lv1.evalValue(c, Context.LVALUE);
|
||||
final Value v2 = lv2.evalValue(c);
|
||||
if (v1 instanceof final ListValue.ListConstructorValue lcv && v2 instanceof final ListValue list)
|
||||
{
|
||||
List<Value> ll = ((ListValue)v1).getItems();
|
||||
List<Value> rl = ((ListValue)v2).getItems();
|
||||
if (ll.size() < rl.size()) throw new InternalExpressionException("Too many values to unpack");
|
||||
if (ll.size() > rl.size()) throw new InternalExpressionException("Too few values to unpack");
|
||||
for (Value v: ll) v.assertAssignable();
|
||||
Iterator<Value> li = ll.iterator();
|
||||
Iterator<Value> ri = rl.iterator();
|
||||
while(li.hasNext())
|
||||
final List<Value> ll = lcv.getItems();
|
||||
final List<Value> rl = list.getItems();
|
||||
if (ll.size() < rl.size())
|
||||
{
|
||||
Value lval = li.next();
|
||||
String lname = lval.getVariable();
|
||||
Value result = lval.add(ri.next()).bindTo(lname);
|
||||
throw new InternalExpressionException("Too many values to unpack");
|
||||
}
|
||||
if (ll.size() > rl.size())
|
||||
{
|
||||
throw new InternalExpressionException("Too few values to unpack");
|
||||
}
|
||||
for (final Value v : ll)
|
||||
{
|
||||
v.assertAssignable();
|
||||
}
|
||||
final Iterator<Value> li = ll.iterator();
|
||||
final Iterator<Value> ri = rl.iterator();
|
||||
while (li.hasNext())
|
||||
{
|
||||
final Value lval = li.next();
|
||||
final String lname = lval.getVariable();
|
||||
final Value result = lval.add(ri.next()).bindTo(lname);
|
||||
expression.setAnyVariable(c, lname, (cc, tt) -> result);
|
||||
}
|
||||
return (cc, tt) -> Value.TRUE;
|
||||
}
|
||||
if (v1 instanceof LContainerValue)
|
||||
if (v1 instanceof final LContainerValue lcv)
|
||||
{
|
||||
ContainerValueInterface cvi = ((LContainerValue) v1).getContainer();
|
||||
final ContainerValueInterface cvi = lcv.container();
|
||||
if (cvi == null)
|
||||
{
|
||||
throw new InternalExpressionException("Failed to resolve left hand side of the += operation");
|
||||
}
|
||||
Value key = ((LContainerValue) v1).getAddress();
|
||||
Value value = cvi.get(key);
|
||||
final Value key = lcv.address();
|
||||
final Value value = cvi.get(key);
|
||||
if (value instanceof ListValue || value instanceof MapValue)
|
||||
{
|
||||
((AbstractListValue) value).append(v2);
|
||||
@@ -371,22 +481,22 @@ public class Operators {
|
||||
}
|
||||
else
|
||||
{
|
||||
Value res = value.add(v2);
|
||||
final Value res = value.add(v2);
|
||||
cvi.put(key, res);
|
||||
return (cc, tt) -> res;
|
||||
}
|
||||
}
|
||||
v1.assertAssignable();
|
||||
String varname = v1.getVariable();
|
||||
LazyValue boundedLHS;
|
||||
final String varname = v1.getVariable();
|
||||
final LazyValue boundedLHS;
|
||||
if (v1 instanceof ListValue || v1 instanceof MapValue)
|
||||
{
|
||||
((AbstractListValue) v1).append(v2);
|
||||
boundedLHS = (cc, tt)-> v1;
|
||||
boundedLHS = (cc, tt) -> v1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Value result = v1.add(v2).bindTo(varname);
|
||||
final Value result = v1.add(v2).bindTo(varname);
|
||||
boundedLHS = (cc, tt) -> result;
|
||||
}
|
||||
expression.setAnyVariable(c, varname, boundedLHS);
|
||||
@@ -395,22 +505,34 @@ public class Operators {
|
||||
|
||||
expression.addBinaryContextOperator("<>", precedence.get("assign=<>"), false, false, false, (c, t, v1, v2) ->
|
||||
{
|
||||
if (v1 instanceof ListValue.ListConstructorValue && v2 instanceof ListValue.ListConstructorValue)
|
||||
if (v1 instanceof final ListValue.ListConstructorValue lcv1 && v2 instanceof final ListValue.ListConstructorValue lcv2)
|
||||
{
|
||||
List<Value> ll = ((ListValue)v1).getItems();
|
||||
List<Value> rl = ((ListValue)v2).getItems();
|
||||
if (ll.size() < rl.size()) throw new InternalExpressionException("Too many values to unpack");
|
||||
if (ll.size() > rl.size()) throw new InternalExpressionException("Too few values to unpack");
|
||||
for (Value v: ll) v.assertAssignable();
|
||||
for (Value v: rl) v.assertAssignable();
|
||||
Iterator<Value> li = ll.iterator();
|
||||
Iterator<Value> ri = rl.iterator();
|
||||
while(li.hasNext())
|
||||
final List<Value> ll = lcv1.getItems();
|
||||
final List<Value> rl = lcv2.getItems();
|
||||
if (ll.size() < rl.size())
|
||||
{
|
||||
Value lval = li.next();
|
||||
Value rval = ri.next();
|
||||
String lname = lval.getVariable();
|
||||
String rname = rval.getVariable();
|
||||
throw new InternalExpressionException("Too many values to unpack");
|
||||
}
|
||||
if (ll.size() > rl.size())
|
||||
{
|
||||
throw new InternalExpressionException("Too few values to unpack");
|
||||
}
|
||||
for (final Value v : ll)
|
||||
{
|
||||
v.assertAssignable();
|
||||
}
|
||||
for (final Value v : rl)
|
||||
{
|
||||
v.assertAssignable();
|
||||
}
|
||||
final Iterator<Value> li = ll.iterator();
|
||||
final Iterator<Value> ri = rl.iterator();
|
||||
while (li.hasNext())
|
||||
{
|
||||
final Value lval = li.next();
|
||||
final Value rval = ri.next();
|
||||
final String lname = lval.getVariable();
|
||||
final String rname = rval.getVariable();
|
||||
lval.reboundedTo(rname);
|
||||
rval.reboundedTo(lname);
|
||||
expression.setAnyVariable(c, lname, (cc, tt) -> rval);
|
||||
@@ -420,36 +542,37 @@ public class Operators {
|
||||
}
|
||||
v1.assertAssignable();
|
||||
v2.assertAssignable();
|
||||
String lvalvar = v1.getVariable();
|
||||
String rvalvar = v2.getVariable();
|
||||
Value lval = v2.reboundedTo(lvalvar);
|
||||
Value rval = v1.reboundedTo(rvalvar);
|
||||
final String lvalvar = v1.getVariable();
|
||||
final String rvalvar = v2.getVariable();
|
||||
final Value lval = v2.reboundedTo(lvalvar);
|
||||
final Value rval = v1.reboundedTo(rvalvar);
|
||||
expression.setAnyVariable(c, lvalvar, (cc, tt) -> lval);
|
||||
expression.setAnyVariable(c, rvalvar, (cc, tt) -> rval);
|
||||
return lval;
|
||||
});
|
||||
|
||||
expression.addUnaryOperator("-", false, v -> NumericValue.asNumber(v).opposite());
|
||||
expression.addUnaryOperator("-", false, v -> NumericValue.asNumber(v).opposite());
|
||||
|
||||
expression.addUnaryOperator("+", false, NumericValue::asNumber);
|
||||
|
||||
// could be non-lazy, but who cares - its a small one.
|
||||
expression.addLazyUnaryOperator("!", precedence.get("unary+-!..."), false, true, x -> Context.Type.BOOLEAN, (c, t, lv) ->
|
||||
lv.evalValue(c, Context.BOOLEAN).getBoolean() ? (cc, tt)-> Value.FALSE : (cc, tt) -> Value.TRUE
|
||||
lv.evalValue(c, Context.BOOLEAN).getBoolean() ? (cc, tt) -> Value.FALSE : (cc, tt) -> Value.TRUE
|
||||
); // might need context boolean
|
||||
|
||||
// lazy because of typed evaluation of the argument
|
||||
expression.addLazyUnaryOperator("...", Operators.precedence.get("unary+-!..."), false, true, t -> t== Context.Type.LOCALIZATION?Context.NONE:t, (c, t, lv) ->
|
||||
expression.addLazyUnaryOperator("...", Operators.precedence.get("unary+-!..."), false, true, t -> t == Context.Type.LOCALIZATION ? Context.NONE : t, (c, t, lv) ->
|
||||
{
|
||||
if (t == Context.LOCALIZATION)
|
||||
{
|
||||
return (cc, tt) -> new FunctionAnnotationValue(lv.evalValue(c), FunctionAnnotationValue.Type.VARARG);
|
||||
|
||||
Value params = lv.evalValue(c, t);
|
||||
if (!(params instanceof AbstractListValue))
|
||||
}
|
||||
if (!(lv.evalValue(c, t) instanceof final AbstractListValue alv))
|
||||
{
|
||||
throw new InternalExpressionException("Unable to unpack a non-list");
|
||||
FunctionUnpackedArgumentsValue fuaval = new FunctionUnpackedArgumentsValue( ((AbstractListValue) params).unpack());
|
||||
}
|
||||
final FunctionUnpackedArgumentsValue fuaval = new FunctionUnpackedArgumentsValue(alv.unpack());
|
||||
return (cc, tt) -> fuaval;
|
||||
//throw new InternalExpressionException("That functionality has not been implemented yet.");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package carpet.script.language;
|
||||
import carpet.script.Context;
|
||||
import carpet.script.Expression;
|
||||
import carpet.script.LazyValue;
|
||||
import carpet.script.ScriptHost;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.utils.PerlinNoiseSampler;
|
||||
import carpet.script.utils.SimplexNoiseSampler;
|
||||
@@ -27,12 +26,13 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
public class Sys {
|
||||
public class Sys
|
||||
{
|
||||
public static final Random randomizer = new Random();
|
||||
// %[argument_index$][flags][width][.precision][t]conversion
|
||||
private static final Pattern formatPattern = Pattern.compile("%(\\d+\\$)?([-#+ 0,(<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])");
|
||||
|
||||
public static void apply(Expression expression)
|
||||
public static void apply(final Expression expression)
|
||||
{
|
||||
expression.addUnaryFunction("hash_code", v -> new NumericValue(v.hashCode()));
|
||||
|
||||
@@ -40,21 +40,23 @@ public class Sys {
|
||||
|
||||
expression.addTypedContextFunction("bool", 1, Context.BOOLEAN, (c, t, lv) ->
|
||||
{
|
||||
Value v = lv.get(0);
|
||||
final Value v = lv.get(0);
|
||||
if (v instanceof StringValue)
|
||||
{
|
||||
String str = v.getString().toLowerCase(Locale.ROOT);
|
||||
if ("false".equals(str) || "null".equals(str)) return Value.FALSE;
|
||||
final String str = v.getString().toLowerCase(Locale.ROOT);
|
||||
if ("false".equals(str) || "null".equals(str))
|
||||
{
|
||||
return Value.FALSE;
|
||||
}
|
||||
}
|
||||
return BooleanValue.of(v.getBoolean());
|
||||
});
|
||||
|
||||
expression.addUnaryFunction("number", v ->
|
||||
{
|
||||
if (v instanceof NumericValue num)
|
||||
if (v instanceof final NumericValue num)
|
||||
{
|
||||
if (num.isInteger()) return new NumericValue(num.getLong());
|
||||
return new NumericValue(num.getDouble());
|
||||
return new NumericValue(num.isInteger() ? num.getLong() : num.getDouble());
|
||||
}
|
||||
if (v instanceof ListValue || v instanceof MapValue)
|
||||
{
|
||||
@@ -64,7 +66,7 @@ public class Sys {
|
||||
{
|
||||
return new NumericValue(v.getString());
|
||||
}
|
||||
catch (NumberFormatException format)
|
||||
catch (final NumberFormatException format)
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
@@ -73,51 +75,65 @@ public class Sys {
|
||||
expression.addFunction("str", lv ->
|
||||
{
|
||||
if (lv.size() == 0)
|
||||
throw new InternalExpressionException("'str' requires at least one argument");
|
||||
String format = lv.get(0).getString();
|
||||
if (lv.size() == 1)
|
||||
return new StringValue(format);
|
||||
int argIndex = 1;
|
||||
if (lv.get(1) instanceof ListValue && lv.size() == 2)
|
||||
{
|
||||
lv = ((ListValue) lv.get(1)).getItems();
|
||||
throw new InternalExpressionException("'str' requires at least one argument");
|
||||
}
|
||||
final String format = lv.get(0).getString();
|
||||
if (lv.size() == 1)
|
||||
{
|
||||
return new StringValue(format);
|
||||
}
|
||||
int argIndex = 1;
|
||||
if (lv.get(1) instanceof final ListValue list && lv.size() == 2)
|
||||
{
|
||||
lv = list.getItems();
|
||||
argIndex = 0;
|
||||
}
|
||||
List<Object> args = new ArrayList<>();
|
||||
Matcher m = formatPattern.matcher(format);
|
||||
final List<Object> args = new ArrayList<>();
|
||||
final Matcher m = formatPattern.matcher(format);
|
||||
|
||||
for (int i = 0, len = format.length(); i < len; ) {
|
||||
if (m.find(i)) {
|
||||
for (int i = 0, len = format.length(); i < len; )
|
||||
{
|
||||
if (m.find(i))
|
||||
{
|
||||
// Anything between the start of the string and the beginning
|
||||
// of the format specifier is either fixed text or contains
|
||||
// an invalid format string.
|
||||
// [[scarpet]] but we skip it and let the String.format fail
|
||||
char fmt = m.group(6).toLowerCase().charAt(0);
|
||||
final char fmt = m.group(6).toLowerCase().charAt(0);
|
||||
if (fmt == 's')
|
||||
{
|
||||
if (argIndex >= lv.size())
|
||||
throw new InternalExpressionException("Not enough arguments for "+m.group(0));
|
||||
{
|
||||
throw new InternalExpressionException("Not enough arguments for " + m.group(0));
|
||||
}
|
||||
args.add(lv.get(argIndex).getString());
|
||||
argIndex++;
|
||||
}
|
||||
else if (fmt == 'd' || fmt == 'o' || fmt == 'x')
|
||||
{
|
||||
if (argIndex >= lv.size())
|
||||
throw new InternalExpressionException("Not enough arguments for "+m.group(0));
|
||||
{
|
||||
throw new InternalExpressionException("Not enough arguments for " + m.group(0));
|
||||
}
|
||||
args.add(lv.get(argIndex).readInteger());
|
||||
argIndex++;
|
||||
}
|
||||
else if (fmt == 'a' || fmt == 'e' || fmt == 'f' || fmt == 'g')
|
||||
{
|
||||
if (argIndex >= lv.size())
|
||||
throw new InternalExpressionException("Not enough arguments for "+m.group(0));
|
||||
{
|
||||
throw new InternalExpressionException("Not enough arguments for " + m.group(0));
|
||||
}
|
||||
args.add(lv.get(argIndex).readDoubleNumber());
|
||||
argIndex++;
|
||||
}
|
||||
else if (fmt == 'b')
|
||||
{
|
||||
if (argIndex >= lv.size())
|
||||
throw new InternalExpressionException("Not enough arguments for "+m.group(0));
|
||||
{
|
||||
throw new InternalExpressionException("Not enough arguments for " + m.group(0));
|
||||
}
|
||||
args.add(lv.get(argIndex).getBoolean());
|
||||
argIndex++;
|
||||
}
|
||||
@@ -127,11 +143,13 @@ public class Sys {
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalExpressionException("Format not supported: "+m.group(6));
|
||||
throw new InternalExpressionException("Format not supported: " + m.group(6));
|
||||
}
|
||||
|
||||
i = m.end();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// No more valid format specifiers. Check for possible invalid
|
||||
// format specifiers.
|
||||
// [[scarpet]] but we skip it and let the String.format fail
|
||||
@@ -142,9 +160,9 @@ public class Sys {
|
||||
{
|
||||
return new StringValue(String.format(Locale.ROOT, format, args.toArray()));
|
||||
}
|
||||
catch (IllegalFormatException ife)
|
||||
catch (final IllegalFormatException ife)
|
||||
{
|
||||
throw new InternalExpressionException("Illegal string format: "+ife.getMessage());
|
||||
throw new InternalExpressionException("Illegal string format: " + ife.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -156,32 +174,40 @@ public class Sys {
|
||||
|
||||
expression.addFunction("replace", (lv) ->
|
||||
{
|
||||
if (lv.size() != 3 && lv.size() !=2)
|
||||
if (lv.size() != 3 && lv.size() != 2)
|
||||
{
|
||||
throw new InternalExpressionException("'replace' expects string to read, pattern regex, and optional replacement string");
|
||||
String data = lv.get(0).getString();
|
||||
String regex = lv.get(1).getString();
|
||||
}
|
||||
final String data = lv.get(0).getString();
|
||||
final String regex = lv.get(1).getString();
|
||||
String replacement = "";
|
||||
if (lv.size() == 3)
|
||||
{
|
||||
replacement = lv.get(2).getString();
|
||||
}
|
||||
try
|
||||
{
|
||||
return new StringValue(data.replaceAll(regex, replacement));
|
||||
}
|
||||
catch (PatternSyntaxException pse)
|
||||
catch (final PatternSyntaxException pse)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect pattern for 'replace': "+pse.getMessage());
|
||||
throw new InternalExpressionException("Incorrect pattern for 'replace': " + pse.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
expression.addFunction("replace_first", (lv) ->
|
||||
{
|
||||
if (lv.size() != 3 && lv.size() !=2)
|
||||
if (lv.size() != 3 && lv.size() != 2)
|
||||
{
|
||||
throw new InternalExpressionException("'replace_first' expects string to read, pattern regex, and optional replacement string");
|
||||
String data = lv.get(0).getString();
|
||||
String regex = lv.get(1).getString();
|
||||
}
|
||||
final String data = lv.get(0).getString();
|
||||
final String regex = lv.get(1).getString();
|
||||
String replacement = "";
|
||||
if (lv.size() == 3)
|
||||
{
|
||||
replacement = lv.get(2).getString();
|
||||
}
|
||||
return new StringValue(data.replaceFirst(regex, replacement));
|
||||
});
|
||||
|
||||
@@ -189,31 +215,36 @@ public class Sys {
|
||||
expression.addUnaryFunction("length", v -> new NumericValue(v.length()));
|
||||
expression.addContextFunction("rand", -1, (c, t, lv) ->
|
||||
{
|
||||
int argsize = lv.size();
|
||||
final int argsize = lv.size();
|
||||
Random randomizer = Sys.randomizer;
|
||||
if (argsize != 1 && argsize != 2)
|
||||
throw new InternalExpressionException("'rand' takes one (range) or two arguments (range and seed)");
|
||||
if (argsize == 2) randomizer = c.host.getRandom(NumericValue.asNumber(lv.get(1)).getLong());
|
||||
Value argument = lv.get(0);
|
||||
if (argument instanceof ListValue)
|
||||
{
|
||||
List<Value> list = ((ListValue) argument).getItems();
|
||||
throw new InternalExpressionException("'rand' takes one (range) or two arguments (range and seed)");
|
||||
}
|
||||
if (argsize == 2)
|
||||
{
|
||||
randomizer = c.host.getRandom(NumericValue.asNumber(lv.get(1)).getLong());
|
||||
}
|
||||
final Value argument = lv.get(0);
|
||||
if (argument instanceof final ListValue listValue)
|
||||
{
|
||||
final List<Value> list = listValue.getItems();
|
||||
return list.get(randomizer.nextInt(list.size()));
|
||||
}
|
||||
double value = NumericValue.asNumber(argument).getDouble()*randomizer.nextDouble();
|
||||
if (t == Context.BOOLEAN)
|
||||
return BooleanValue.of(value >= 1.0D);
|
||||
return new NumericValue(value);
|
||||
final double value = NumericValue.asNumber(argument).getDouble() * randomizer.nextDouble();
|
||||
return t == Context.BOOLEAN ? BooleanValue.of(value >= 1.0D) : new NumericValue(value);
|
||||
});
|
||||
expression.addContextFunction("reset_seed", 1, (c, t, lv) -> {
|
||||
boolean gotIt = c.host.resetRandom(NumericValue.asNumber(lv.get(0)).getLong());
|
||||
final boolean gotIt = c.host.resetRandom(NumericValue.asNumber(lv.get(0)).getLong());
|
||||
return BooleanValue.of(gotIt);
|
||||
});
|
||||
|
||||
expression.addFunction("perlin", lv ->
|
||||
{
|
||||
PerlinNoiseSampler sampler;
|
||||
Value x, y, z;
|
||||
final PerlinNoiseSampler sampler;
|
||||
final Value x;
|
||||
Value y;
|
||||
Value z;
|
||||
|
||||
if (lv.size() >= 4)
|
||||
{
|
||||
@@ -227,36 +258,45 @@ public class Sys {
|
||||
sampler = PerlinNoiseSampler.instance;
|
||||
y = Value.NULL;
|
||||
z = Value.NULL;
|
||||
if (lv.size() == 0 )
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("'perlin' requires at least one dimension to sample from");
|
||||
}
|
||||
x = NumericValue.asNumber(lv.get(0));
|
||||
if (lv.size() > 1)
|
||||
{
|
||||
y = NumericValue.asNumber(lv.get(1));
|
||||
if (lv.size() > 2)
|
||||
{
|
||||
z = NumericValue.asNumber(lv.get(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double result;
|
||||
final double result;
|
||||
|
||||
if (z.isNull())
|
||||
if (y.isNull())
|
||||
result = sampler.sample1d(NumericValue.asNumber(x).getDouble());
|
||||
else
|
||||
result = sampler.sample2d(NumericValue.asNumber(x).getDouble(), NumericValue.asNumber(y).getDouble());
|
||||
{
|
||||
result = y.isNull()
|
||||
? sampler.sample1d(NumericValue.asNumber(x).getDouble())
|
||||
: sampler.sample2d(NumericValue.asNumber(x).getDouble(), NumericValue.asNumber(y).getDouble());
|
||||
}
|
||||
else
|
||||
{
|
||||
result = sampler.sample3d(
|
||||
NumericValue.asNumber(x).getDouble(),
|
||||
NumericValue.asNumber(y).getDouble(),
|
||||
NumericValue.asNumber(z).getDouble());
|
||||
}
|
||||
return new NumericValue(result);
|
||||
});
|
||||
|
||||
expression.addFunction("simplex", lv ->
|
||||
{
|
||||
SimplexNoiseSampler sampler;
|
||||
Value x, y, z;
|
||||
final SimplexNoiseSampler sampler;
|
||||
final Value x;
|
||||
final Value y;
|
||||
Value z;
|
||||
|
||||
if (lv.size() >= 4)
|
||||
{
|
||||
@@ -269,22 +309,30 @@ public class Sys {
|
||||
{
|
||||
sampler = SimplexNoiseSampler.instance;
|
||||
z = Value.NULL;
|
||||
if (lv.size() < 2 )
|
||||
if (lv.size() < 2)
|
||||
{
|
||||
throw new InternalExpressionException("'simplex' requires at least two dimensions to sample from");
|
||||
}
|
||||
x = NumericValue.asNumber(lv.get(0));
|
||||
y = NumericValue.asNumber(lv.get(1));
|
||||
if (lv.size() > 2)
|
||||
{
|
||||
z = NumericValue.asNumber(lv.get(2));
|
||||
}
|
||||
}
|
||||
double result;
|
||||
final double result;
|
||||
|
||||
if (z.isNull())
|
||||
{
|
||||
result = sampler.sample2d(NumericValue.asNumber(x).getDouble(), NumericValue.asNumber(y).getDouble());
|
||||
}
|
||||
else
|
||||
{
|
||||
result = sampler.sample3d(
|
||||
NumericValue.asNumber(x).getDouble(),
|
||||
NumericValue.asNumber(y).getDouble(),
|
||||
NumericValue.asNumber(z).getDouble());
|
||||
}
|
||||
return new NumericValue(result);
|
||||
});
|
||||
|
||||
@@ -303,17 +351,23 @@ public class Sys {
|
||||
expression.addFunction("convert_date", lv ->
|
||||
{
|
||||
int argsize = lv.size();
|
||||
if (lv.size() == 0) throw new InternalExpressionException("'convert_date' requires at least one parameter");
|
||||
Value value = lv.get(0);
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("'convert_date' requires at least one parameter");
|
||||
}
|
||||
final Value value = lv.get(0);
|
||||
if (argsize == 1 && !(value instanceof ListValue))
|
||||
{
|
||||
Calendar cal = new GregorianCalendar(Locale.ROOT);
|
||||
final Calendar cal = new GregorianCalendar(Locale.ROOT);
|
||||
cal.setTimeInMillis(NumericValue.asNumber(value, "timestamp").getLong());
|
||||
int weekday = cal.get(Calendar.DAY_OF_WEEK)-1;
|
||||
if (weekday == 0) weekday = 7;
|
||||
int weekday = cal.get(Calendar.DAY_OF_WEEK) - 1;
|
||||
if (weekday == 0)
|
||||
{
|
||||
weekday = 7;
|
||||
}
|
||||
return ListValue.ofNums(
|
||||
cal.get(Calendar.YEAR),
|
||||
cal.get(Calendar.MONTH)+1,
|
||||
cal.get(Calendar.MONTH) + 1,
|
||||
cal.get(Calendar.DAY_OF_MONTH),
|
||||
cal.get(Calendar.HOUR_OF_DAY),
|
||||
cal.get(Calendar.MINUTE),
|
||||
@@ -323,18 +377,18 @@ public class Sys {
|
||||
cal.get(Calendar.WEEK_OF_YEAR)
|
||||
);
|
||||
}
|
||||
else if(value instanceof ListValue)
|
||||
else if (value instanceof final ListValue list)
|
||||
{
|
||||
lv = ((ListValue) value).getItems();
|
||||
lv = list.getItems();
|
||||
argsize = lv.size();
|
||||
}
|
||||
Calendar cal = new GregorianCalendar(0, 0, 0, 0, 0, 0);
|
||||
final Calendar cal = new GregorianCalendar(0, 0, 0, 0, 0, 0);
|
||||
|
||||
if (argsize == 3)
|
||||
{
|
||||
cal.set(
|
||||
NumericValue.asNumber(lv.get(0)).getInt(),
|
||||
NumericValue.asNumber(lv.get(1)).getInt()-1,
|
||||
NumericValue.asNumber(lv.get(1)).getInt() - 1,
|
||||
NumericValue.asNumber(lv.get(2)).getInt()
|
||||
);
|
||||
}
|
||||
@@ -342,29 +396,32 @@ public class Sys {
|
||||
{
|
||||
cal.set(
|
||||
NumericValue.asNumber(lv.get(0)).getInt(),
|
||||
NumericValue.asNumber(lv.get(1)).getInt()-1,
|
||||
NumericValue.asNumber(lv.get(1)).getInt() - 1,
|
||||
NumericValue.asNumber(lv.get(2)).getInt(),
|
||||
NumericValue.asNumber(lv.get(3)).getInt(),
|
||||
NumericValue.asNumber(lv.get(4)).getInt(),
|
||||
NumericValue.asNumber(lv.get(5)).getInt()
|
||||
);
|
||||
}
|
||||
else throw new InternalExpressionException("Date conversion requires 3 arguments for Dates or 6 arguments, for time");
|
||||
else
|
||||
{
|
||||
throw new InternalExpressionException("Date conversion requires 3 arguments for Dates or 6 arguments, for time");
|
||||
}
|
||||
return new NumericValue(cal.getTimeInMillis());
|
||||
});
|
||||
|
||||
// lazy cause evaluates expression multiple times
|
||||
expression.addLazyFunction("profile_expr", 1, (c, t, lv) ->
|
||||
{
|
||||
LazyValue lazy = lv.get(0);
|
||||
long end = System.nanoTime()+50000000L;
|
||||
final LazyValue lazy = lv.get(0);
|
||||
final long end = System.nanoTime() + 50000000L;
|
||||
long it = 0;
|
||||
while (System.nanoTime()<end)
|
||||
while (System.nanoTime() < end)
|
||||
{
|
||||
lazy.evalValue(c);
|
||||
it++;
|
||||
}
|
||||
Value res = new NumericValue(it);
|
||||
final Value res = new NumericValue(it);
|
||||
return (cc, tt) -> res;
|
||||
});
|
||||
|
||||
@@ -373,16 +430,18 @@ public class Sys {
|
||||
|
||||
expression.addContextFunction("undef", 1, (c, t, lv) ->
|
||||
{
|
||||
Value remove = lv.get(0);
|
||||
final Value remove = lv.get(0);
|
||||
if (remove instanceof FunctionValue)
|
||||
{
|
||||
c.host.delFunction(expression.module, remove.getString());
|
||||
return Value.NULL;
|
||||
}
|
||||
String varname = remove.getString();
|
||||
boolean isPrefix = varname.endsWith("*");
|
||||
final boolean isPrefix = varname.endsWith("*");
|
||||
if (isPrefix)
|
||||
{
|
||||
varname = varname.replaceAll("\\*+$", "");
|
||||
}
|
||||
if (isPrefix)
|
||||
{
|
||||
c.host.delFunctionWithPrefix(expression.module, varname);
|
||||
@@ -413,8 +472,8 @@ public class Sys {
|
||||
//deprecate
|
||||
expression.addContextFunction("vars", 1, (c, t, lv) ->
|
||||
{
|
||||
String prefix = lv.get(0).getString();
|
||||
List<Value> values = new ArrayList<>();
|
||||
final String prefix = lv.get(0).getString();
|
||||
final List<Value> values = new ArrayList<>();
|
||||
if (prefix.startsWith("global"))
|
||||
{
|
||||
c.host.globalVariableNames(expression.module, (s) -> s.startsWith(prefix)).forEach(s -> values.add(new StringValue(s)));
|
||||
@@ -429,19 +488,23 @@ public class Sys {
|
||||
// lazy cause default expression may not be executed if not needed
|
||||
expression.addLazyFunction("system_variable_get", (c, t, lv) ->
|
||||
{
|
||||
if (lv.size() == 0) throw new InternalExpressionException("'system_variable_get' expects at least a key to be fetched");
|
||||
Value key = lv.get(0).evalValue(c);
|
||||
if (lv.size() > 1) c.host.scriptServer().systemGlobals.computeIfAbsent(key, k -> lv.get(1).evalValue(c));
|
||||
Value res = c.host.scriptServer().systemGlobals.get(key);
|
||||
if (res!=null) return (cc, tt) -> res;
|
||||
return LazyValue.NULL;
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("'system_variable_get' expects at least a key to be fetched");
|
||||
}
|
||||
final Value key = lv.get(0).evalValue(c);
|
||||
if (lv.size() > 1)
|
||||
{
|
||||
c.host.scriptServer().systemGlobals.computeIfAbsent(key, k -> lv.get(1).evalValue(c));
|
||||
}
|
||||
final Value res = c.host.scriptServer().systemGlobals.get(key);
|
||||
return res == null ? LazyValue.NULL : ((cc, tt) -> res);
|
||||
});
|
||||
|
||||
expression.addContextFunction("system_variable_set", 2, (c, t, lv) ->
|
||||
{
|
||||
Value res = c.host.scriptServer().systemGlobals.put(lv.get(0), lv.get(1));
|
||||
if (res!=null) return res;
|
||||
return Value.NULL;
|
||||
final Value res = c.host.scriptServer().systemGlobals.put(lv.get(0), lv.get(1));
|
||||
return res == null ? Value.NULL : res;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -11,14 +11,16 @@ import carpet.script.value.Value;
|
||||
|
||||
public class Threading
|
||||
{
|
||||
public static void apply(Expression expression)
|
||||
public static void apply(final Expression expression)
|
||||
{
|
||||
expression.addFunctionWithDelegation("task", -1, false, false, (c, t, expr, tok, lv) ->
|
||||
{
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("'task' requires at least function to call as a parameter");
|
||||
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, true);
|
||||
ThreadValue thread = new ThreadValue(Value.NULL, functionArgument.function, expr, tok, c, functionArgument.checkedArgs());
|
||||
}
|
||||
final FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, true);
|
||||
final ThreadValue thread = new ThreadValue(Value.NULL, functionArgument.function, expr, tok, c, functionArgument.checkedArgs());
|
||||
Thread.yield();
|
||||
return thread;
|
||||
});
|
||||
@@ -26,30 +28,36 @@ public class Threading
|
||||
expression.addFunctionWithDelegation("task_thread", -1, false, false, (c, t, expr, tok, lv) ->
|
||||
{
|
||||
if (lv.size() < 2)
|
||||
{
|
||||
throw new InternalExpressionException("'task' requires at least function to call as a parameter");
|
||||
Value queue = lv.get(0);
|
||||
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, true);
|
||||
ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, functionArgument.checkedArgs());
|
||||
}
|
||||
final Value queue = lv.get(0);
|
||||
final FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, true);
|
||||
final ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, functionArgument.checkedArgs());
|
||||
Thread.yield();
|
||||
return thread;
|
||||
});
|
||||
|
||||
|
||||
expression.addContextFunction("task_count", -1, (c, t, lv) ->
|
||||
(lv.size() > 0)? new NumericValue(c.host.taskCount(lv.get(0))):new NumericValue(c.host.taskCount()));
|
||||
(lv.size() > 0) ? new NumericValue(c.host.taskCount(lv.get(0))) : new NumericValue(c.host.taskCount()));
|
||||
|
||||
expression.addUnaryFunction("task_value", (v) ->
|
||||
{
|
||||
if (!(v instanceof ThreadValue))
|
||||
if (!(v instanceof final ThreadValue tv))
|
||||
{
|
||||
throw new InternalExpressionException("'task_value' could only be used with a task value");
|
||||
return ((ThreadValue) v).getValue();
|
||||
}
|
||||
return tv.getValue();
|
||||
});
|
||||
|
||||
expression.addUnaryFunction("task_join", (v) ->
|
||||
{
|
||||
if (!(v instanceof ThreadValue))
|
||||
if (!(v instanceof final ThreadValue tv))
|
||||
{
|
||||
throw new InternalExpressionException("'task_join' could only be used with a task value");
|
||||
return ((ThreadValue) v).join();
|
||||
}
|
||||
return tv.join();
|
||||
});
|
||||
|
||||
expression.addLazyFunction("task_dock", 1, (c, t, lv) ->
|
||||
@@ -61,15 +69,20 @@ public class Threading
|
||||
|
||||
expression.addUnaryFunction("task_completed", (v) ->
|
||||
{
|
||||
if (!(v instanceof ThreadValue))
|
||||
if (!(v instanceof final ThreadValue tv))
|
||||
{
|
||||
throw new InternalExpressionException("'task_completed' could only be used with a task value");
|
||||
return BooleanValue.of(((ThreadValue) v).isFinished());
|
||||
}
|
||||
return BooleanValue.of(tv.isFinished());
|
||||
});
|
||||
|
||||
// lazy cause expr is evaluated in the same type
|
||||
expression.addLazyFunction("synchronize", (c, t, lv) ->
|
||||
{
|
||||
if (lv.size() == 0) throw new InternalExpressionException("'synchronize' require at least an expression to synchronize");
|
||||
if (lv.size() == 0)
|
||||
{
|
||||
throw new InternalExpressionException("'synchronize' require at least an expression to synchronize");
|
||||
}
|
||||
Value lockValue = Value.NULL;
|
||||
int ind = 0;
|
||||
if (lv.size() == 2)
|
||||
@@ -79,7 +92,7 @@ public class Threading
|
||||
}
|
||||
synchronized (c.host.getLock(lockValue))
|
||||
{
|
||||
Value ret = lv.get(ind).evalValue(c, t);
|
||||
final Value ret = lv.get(ind).evalValue(c, t);
|
||||
return (_c, _t) -> ret;
|
||||
}
|
||||
});
|
||||
@@ -87,15 +100,21 @@ public class Threading
|
||||
// lazy since exception expression is very conditional
|
||||
expression.addLazyFunction("sleep", (c, t, lv) ->
|
||||
{
|
||||
long time = lv.isEmpty()?0L:NumericValue.asNumber(lv.get(0).evalValue(c)).getLong();
|
||||
final long time = lv.isEmpty() ? 0L : NumericValue.asNumber(lv.get(0).evalValue(c)).getLong();
|
||||
boolean interrupted = false;
|
||||
try
|
||||
{
|
||||
if (Thread.interrupted()) interrupted = true;
|
||||
if (time > 0) Thread.sleep(time);
|
||||
if (Thread.interrupted())
|
||||
{
|
||||
interrupted = true;
|
||||
}
|
||||
if (time > 0)
|
||||
{
|
||||
Thread.sleep(time);
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
catch (InterruptedException ignored)
|
||||
catch (final InterruptedException ignored)
|
||||
{
|
||||
interrupted = true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user