Files
fabric-carpet/src/main/java/carpet/script/language/DataStructures.java
T
2020-10-11 11:59:22 -03:00

335 lines
14 KiB
Java

package carpet.script.language;
import carpet.script.Context;
import carpet.script.Expression;
import carpet.script.LazyValue;
import carpet.script.exception.InternalExpressionException;
import carpet.script.value.ContainerValueInterface;
import carpet.script.value.LContainerValue;
import carpet.script.value.LazyListValue;
import carpet.script.value.ListValue;
import carpet.script.value.MapValue;
import carpet.script.value.NumericValue;
import carpet.script.value.StringValue;
import carpet.script.value.Value;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;
public class DataStructures {
public static void apply(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);
});
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)
{
toJoin = new ArrayList<>(((ListValue)lv.get(1)).getItems());
}
else
{
toJoin = lv.subList(1,lv.size());
}
return new StringValue(toJoin.stream().map(Value::getString).collect(Collectors.joining(delimiter)));
});
expression.addBinaryFunction("split", (d, v) ->
{
String delimiter = d.getString();
String hwat = v.getString();
try
{
return ListValue.wrap(Arrays.stream(hwat.split(delimiter)).map(StringValue::new).collect(Collectors.toList()));
}
catch (PatternSyntaxException pse)
{
throw new InternalExpressionException("Incorrect pattern for 'split': "+pse.getMessage());
}
});
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();
long to = -1;
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)
{
toSort = new ArrayList<>(((ListValue)lv.get(0)).getItems());
}
Collections.sort(toSort);
return ListValue.wrap(toSort);
});
expression.addLazyFunction("sort_key", -1, (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))
throw new InternalExpressionException("First argument for 'sort_key' should be a List");
List<Value> toSort = new ArrayList<>(((ListValue) v).getItems());
if (lv.size()==1)
{
Collections.shuffle(toSort);
Value ret = ListValue.wrap(toSort);
return (_c, _t) -> ret;
}
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);
return ev1.compareTo(ev2);
});
//revering scope
c.setVariable("_", __);
return (cc, tt) -> ListValue.wrap(toSort);
});
expression.addFunction("range", (lv) ->
{
long from = 0;
long to = 0;
long step = 1;
int argsize = lv.size();
if (argsize == 0 || argsize > 3)
throw new InternalExpressionException("'range' accepts from 1 to 3 arguments, not "+argsize);
to = NumericValue.asNumber(lv.get(0)).getLong();
if (lv.size() > 1)
{
from = to;
to = NumericValue.asNumber(lv.get(1)).getLong();
if (lv.size() > 2)
{
step = NumericValue.asNumber(lv.get(2)).getLong();
}
}
return LazyListValue.range(from, to, step);
});
expression.addLazyFunction("m", -1, (c, t, llv) ->
{
List<Value> lv = new ArrayList<>();
for (LazyValue lazyParam : llv) {
lv.add(lazyParam.evalValue(c, Context.MAPDEF)); // none type default by design
}
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 (cc, tt) -> ret;
});
expression.addUnaryFunction("keys", v ->
{
if (v instanceof MapValue)
return new ListValue(((MapValue) v).getMap().keySet());
return Value.NULL;
});
expression.addUnaryFunction("values", v ->
{
if (v instanceof MapValue)
return new ListValue(((MapValue) v).getMap().values());
return 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())
).collect(Collectors.toList()));
return Value.NULL;
});
expression.addLazyBinaryOperator(":", Operators.precedence.get("attribute~:"),true, (c, t, container_lv, key_lv) ->
{
Value container = container_lv.evalValue(c);
if (container instanceof LContainerValue)
{
ContainerValueInterface outerContainer = ((LContainerValue) container).getContainer();
if (outerContainer == null)
{
Value innerLValue = new LContainerValue(null, null);
return (cc, tt) -> innerLValue;
}
Value innerContainer = outerContainer.get(((LContainerValue) container).getAddress());
if (!(innerContainer instanceof ContainerValueInterface))
{
Value innerLValue = new LContainerValue(null, null);
return (cc, tt) -> innerLValue;
}
Value innerLValue = new LContainerValue((ContainerValueInterface) innerContainer, key_lv.evalValue(c));
return (cc, tt) -> innerLValue;
}
if (!(container instanceof ContainerValueInterface))
if (t == Context.LVALUE)
return (cc, tt) -> new LContainerValue(null, null);
else
return (cc, tt) -> Value.NULL;
Value address = key_lv.evalValue(c);
if (t != Context.LVALUE)
{
Value retVal = ((ContainerValueInterface) container).get(address);
return (cc, ct) -> retVal;
}
Value retVal = new LContainerValue((ContainerValueInterface) container, address);
return (cc, ct) -> retVal;
});
expression.addLazyFunction("get", -1, (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))
return (cc, tt) -> Value.NULL;
ContainerValueInterface container = ((LContainerValue) v).getContainer();
if (container == null)
return (cc, tt) -> Value.NULL;
Value ret = container.get(((LContainerValue) v).getAddress());
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 == null)
return (cc, tt) -> Value.NULL;
Value finalContainer = container;
return (cc, tt) -> finalContainer;
});
expression.addLazyFunction("has", -1, (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))
return (cc, tt) -> Value.NULL;
ContainerValueInterface container = ((LContainerValue) v).getContainer();
if (container == null)
return (cc, tt) -> Value.NULL;
Value ret = new NumericValue(container.has(((LContainerValue) v).getAddress()));
return (cc, tt) -> ret;
}
Value container = lv.get(0).evalValue(c);
for (int i = 1; i < lv.size()-1; i++)
{
if (!(container instanceof ContainerValueInterface)) return (cc, tt) -> Value.NULL;
container = ((ContainerValueInterface) container).get(lv.get(i).evalValue(c));
}
if (!(container instanceof ContainerValueInterface))
return (cc, tt) -> Value.NULL;
Value ret = new NumericValue(((ContainerValueInterface) container).has(lv.get(lv.size()-1).evalValue(c)));
return (cc, tt) -> ret;
});
expression.addLazyFunction("put", -1, (c, t, lv) ->
{
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)
{
ContainerValueInterface internalContainer = ((LContainerValue) container).getContainer();
if (internalContainer == null)
{
return (cc, tt) -> Value.NULL;
}
Value address = ((LContainerValue) container).getAddress();
Value what = lv.get(1).evalValue(c);
Value retVal = new NumericValue( (lv.size() > 2)
? internalContainer.put(address, what, lv.get(2).evalValue(c))
: internalContainer.put(address, what));
return (cc, tt) -> retVal;
}
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))
{
return (cc, tt) -> Value.NULL;
}
Value where = lv.get(1).evalValue(c);
Value what = lv.get(2).evalValue(c);
Value retVal = new NumericValue( (lv.size()>3)
? ((ContainerValueInterface) container).put(where, what, lv.get(3).evalValue(c))
: ((ContainerValueInterface) container).put(where, what));
return (cc, tt) -> retVal;
});
expression.addLazyFunction("delete", -1, (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))
return (cc, tt) -> Value.NULL;
ContainerValueInterface container = ((LContainerValue) v).getContainer();
if (container == null)
return (cc, tt) -> Value.NULL;
Value ret = new NumericValue(container.delete(((LContainerValue) v).getAddress()));
return (cc, tt) -> ret;
}
Value container = lv.get(0).evalValue(c);
for (int i = 1; i < lv.size()-1; i++)
{
if (!(container instanceof ContainerValueInterface)) return (cc, tt) -> Value.NULL;
container = ((ContainerValueInterface) container).get(lv.get(i).evalValue(c));
}
if (!(container instanceof ContainerValueInterface))
return (cc, tt) -> Value.NULL;
Value ret = new NumericValue(((ContainerValueInterface) container).delete(lv.get(lv.size()-1).evalValue(c)));
return (cc, tt) -> ret;
});
}
}