nbt support WIP and proper container API

This commit is contained in:
gnembon committed 2019-10-02 03:09:22 -03:00
1 parent 8b7b285503
commit 718a619128
8 files changed
+393 -49

No files matched your search

+69 -14
View File
@@ -13,10 +13,12 @@ import carpet.script.Fluff.TriFunction;
import carpet.script.exception.ExpressionException; import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.value.AbstractListValue; import carpet.script.value.AbstractListValue;
import carpet.script.value.ContainerValueInterface;
import carpet.script.value.FunctionSignatureValue; import carpet.script.value.FunctionSignatureValue;
import carpet.script.value.GlobalValue; import carpet.script.value.GlobalValue;
import carpet.script.value.LazyListValue; import carpet.script.value.LazyListValue;
import carpet.script.value.ListValue; import carpet.script.value.ListValue;
import carpet.script.value.MapValue;
import carpet.script.value.NumericValue; import carpet.script.value.NumericValue;
import carpet.script.value.StringValue; import carpet.script.value.StringValue;
import carpet.script.value.Value; import carpet.script.value.Value;
@@ -1227,7 +1229,12 @@ public class Expression implements Cloneable
*/ */
public void Operators() public void Operators()
{ {
addBinaryOperator(".", precedence.get("attribute~."),true, Value::getElementAt); addBinaryOperator(".", precedence.get("attribute~."),true, (container, key) ->
{
if (container instanceof ContainerValueInterface)
return ((ContainerValueInterface) container).get(key);
throw new InternalExpressionException("Cannot access elements of a non-container");
});
addBinaryOperator("+", precedence.get("addition+-"), true, Value::add); addBinaryOperator("+", precedence.get("addition+-"), true, Value::add);
addBinaryOperator("-", precedence.get("addition+-"), true, Value::subtract); addBinaryOperator("-", precedence.get("addition+-"), true, Value::subtract);
addBinaryOperator("*", precedence.get("multiplication*/%"), true, Value::multiply); addBinaryOperator("*", precedence.get("multiplication*/%"), true, Value::multiply);
@@ -1322,7 +1329,7 @@ public class Expression implements Cloneable
v1.assertAssignable(); v1.assertAssignable();
String varname = v1.getVariable(); String varname = v1.getVariable();
LazyValue boundedLHS; LazyValue boundedLHS;
if (v1 instanceof ListValue) if (v1 instanceof ListValue || v1 instanceof MapValue)
{ {
((ListValue) v1).append(v2); ((ListValue) v1).append(v2);
boundedLHS = (cc, tt)-> v1; boundedLHS = (cc, tt)-> v1;
@@ -1872,7 +1879,46 @@ public class Expression implements Cloneable
return LazyListValue.range(from, to, step); return LazyListValue.range(from, to, step);
}); });
addBinaryFunction("get", Value::getElementAt); addFunction("m", lv ->
{
if (lv.size() == 1 && lv.get(0) instanceof LazyListValue)
return new MapValue(((LazyListValue) lv.get(0)).unroll());
return new MapValue(lv);
});
addUnaryFunction("keys", v -> {
if (v instanceof MapValue)
return new ListValue(((MapValue) v).getMap().keySet());
throw new InternalExpressionException("keys applies only to maps");
});
addUnaryFunction("values", v -> {
if (v instanceof MapValue)
return new ListValue(((MapValue) v).getMap().values());
throw new InternalExpressionException("keys applies only to maps");
});
addUnaryFunction("pairs", v -> {
if (v instanceof MapValue)
return new ListValue(((MapValue) v).getMap().entrySet().stream().map(
(p) -> ListValue.of(p.getKey(), p.getValue())
).collect(Collectors.toList()));
throw new InternalExpressionException("pairs applies only to maps");
});
addBinaryFunction("get", (container, key) ->
{
if (container instanceof ContainerValueInterface)
return ((ContainerValueInterface) container).get(key);
throw new InternalExpressionException("Cannot access elements of a non-container");
});
addBinaryFunction("has", (container, key) ->
{
if (container instanceof ContainerValueInterface)
return new NumericValue(((ContainerValueInterface) container).has(key));
throw new InternalExpressionException("Cannot access elements of a non-container");
});
//Deprecated, use "get" instead //Deprecated, use "get" instead
addBinaryFunction("element", (v1, v2) -> addBinaryFunction("element", (v1, v2) ->
@@ -1892,27 +1938,36 @@ public class Expression implements Cloneable
{ {
if(lv.size()<3) if(lv.size()<3)
{ {
throw new InternalExpressionException("put takes at least three arguments, a list, index, and values to insert at that index"); throw new InternalExpressionException("put takes at least three arguments, a container, address, and values to insert at that index");
} }
Value list = lv.get(0); Value container = lv.get(0);
if (!(list instanceof ListValue)) if (!(container instanceof ContainerValueInterface))
{ {
throw new InternalExpressionException("First argument of element should be a list"); throw new InternalExpressionException("First argument of put should be a container: list, map or nbt");
} }
int size = lv.size(); Value where = lv.get(1);
//List<Value> items = ((ListValue)lv.get(0)).getItems(); Value what = lv.get(2);
Value index = lv.get(1); Value ret;
if (index == Value.NULL) if (lv.size()>3)
{ {
((ListValue) list).extend(lv.subList(2,size)); return ((ContainerValueInterface) container).put(where, what, lv.get(3));
} }
else else
{ {
((ListValue) list).addAtIndex((int) NumericValue.asNumber(index).getLong(), lv.subList(2,size)); return ((ContainerValueInterface) container).put(where, what);
} }
return new NumericValue(size-2);
}); });
addBinaryFunction("delete", (container, address) ->
{
if (container instanceof ContainerValueInterface)
{
return ((ContainerValueInterface) container).remove(address);
}
throw new InternalExpressionException("First argument of remove should be a container: list, map or nbt");
});
//condition and expression will get a bound 'i' //condition and expression will get a bound 'i'
//returns last successful expression or false //returns last successful expression or false
// while(cond, limit, expr) => ?? // while(cond, limit, expr) => ??
@@ -1,9 +1,15 @@
package carpet.script.value; package carpet.script.value;
import carpet.script.exception.InternalExpressionException;
import java.util.Iterator; import java.util.Iterator;
public abstract class AbstractListValue extends Value public abstract class AbstractListValue extends Value
{ {
public abstract Iterator<Value> iterator(); public abstract Iterator<Value> iterator();
public void fatality() { } public void fatality() { }
public void append(Value v)
{
throw new InternalExpressionException("Cannot append a value to abstract list");
}
} }
@@ -0,0 +1,13 @@
package carpet.script.value;
public interface ContainerValueInterface
{
public Value put(Value where, Value value);
default Value put(Value where, Value value, Value conditions)
{
return put(where, value);
}
public Value get(Value where);
public boolean has(Value where);
public Value remove(Value where);
}
@@ -126,11 +126,6 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
return false; return false;
} }
@Override
public Value getElementAt(Value v2)
{
throw new InternalExpressionException("get element can only be obtained for regular lists");
}
@Override @Override
public String getTypeString() public String getTypeString()
{ {
@@ -9,7 +9,7 @@ import java.util.stream.Collectors;
import static java.lang.Math.abs; import static java.lang.Math.abs;
public class ListValue extends AbstractListValue public class ListValue extends AbstractListValue implements ContainerValueInterface
{ {
protected List<Value> items; protected List<Value> items;
@Override @Override
@@ -98,6 +98,7 @@ public class ListValue extends AbstractListValue
} }
return output; return output;
} }
@Override
public void append(Value v) public void append(Value v)
{ {
items.add(v); items.add(v);
@@ -271,6 +272,8 @@ public class ListValue extends AbstractListValue
super(list); super(list);
} }
} }
@Override
public int length() public int length()
{ {
return items.size(); return items.size();
@@ -309,7 +312,30 @@ public class ListValue extends AbstractListValue
} }
@Override @Override
public Value getElementAt(Value value) public Value put(Value ind, Value value)
{
if (ind == Value.NULL)
{
items.add(value);
return items.get(items.size()-1);
}
else
{
int numitems = items.size();
int index = (int) NumericValue.asNumber(ind).getLong();
if (index < 0)
{
long range = abs(index) / numitems;
index += (range + 2) * numitems;
index = index % numitems;
}
while (index >= items.size()) items.add(Value.NULL);
return items.set(index, value);
}
}
@Override
public Value get(Value value)
{ {
long index = NumericValue.asNumber(value).getLong(); long index = NumericValue.asNumber(value).getLong();
int numitems = items.size(); int numitems = items.size();
@@ -319,6 +345,24 @@ public class ListValue extends AbstractListValue
return items.get((int)index); return items.get((int)index);
} }
@Override
public boolean has(Value where)
{
long index = NumericValue.asNumber(where).getLong();
return index >= 0 && index < items.size();
}
@Override
public Value remove(Value where)
{
long index = NumericValue.asNumber(where).getLong();
int numitems = items.size();
long range = abs(index)/numitems;
index += (range+2)*numitems;
index = index % numitems;
return items.remove((int)index);
}
@Override @Override
public String getTypeString() public String getTypeString()
{ {
+177 -4
View File
@@ -1,18 +1,32 @@
package carpet.script.value; package carpet.script.value;
import java.util.Arrays; import carpet.script.exception.InternalExpressionException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
public class MapValue extends AbstractListValue public class MapValue extends AbstractListValue implements ContainerValueInterface
{ {
private Map<Value, Value> map; private Map<Value, Value> map;
public MapValue()
private MapValue()
{ {
map = new HashMap<>(); map = new HashMap<>();
} }
public MapValue(List<Value> kvPairs)
{
this();
for (Value v : kvPairs)
{
put(v);
}
}
@Override @Override
public Iterator<Value> iterator() public Iterator<Value> iterator()
{ {
@@ -22,7 +36,20 @@ public class MapValue extends AbstractListValue
@Override @Override
public String getString() public String getString()
{ {
return Arrays.toString(map.entrySet().toArray()); return "{"+map.entrySet().stream().map((p) -> p.getKey().getString()+": "+p.getValue().getString()).collect(Collectors.joining(", "))+"}";
}
@Override
public String getPrettyString()
{
if (map.size()<6)
return "{"+map.entrySet().stream().map((p) -> p.getKey().getPrettyString()+": "+p.getValue().getPrettyString()).collect(Collectors.joining(", "))+"}";
List<Value> keys = new ArrayList<>(map.keySet());
int max = keys.size();
return "{"+keys.get(0).getPrettyString()+": "+map.get(keys.get(0)).getPrettyString()+", "+
keys.get(1).getPrettyString()+": "+map.get(keys.get(1)).getPrettyString()+", ..., "+
keys.get(max-2).getPrettyString()+": "+map.get(keys.get(max-2)).getPrettyString()+", "+
keys.get(max-1).getPrettyString()+": "+map.get(keys.get(max-1)).getPrettyString()+"}";
} }
@Override @Override
@@ -31,4 +58,150 @@ public class MapValue extends AbstractListValue
return !map.isEmpty(); return !map.isEmpty();
} }
@Override
public Value clone()
{
return new MapValue(map);
}
public MapValue(Map<Value,Value> other)
{
map = new HashMap<>(other);
}
@Override
public Value add(Value o)
{
throw new InternalExpressionException("cannot add to a map value");
}
@Override
public Value subtract(Value v)
{
throw new InternalExpressionException("cannot subtract to a map value");
}
@Override
public Value multiply(Value v)
{
throw new InternalExpressionException("cannot multiply to a map value");
}
@Override
public Value divide(Value v)
{
throw new InternalExpressionException("cannot divide to a map value");
}
public void put(Value v)
{
if (!(v instanceof ListValue))
{
map.put(v, Value.NULL);
return;
}
ListValue pair = (ListValue)v;
if (pair.getItems().size() != 2)
{
throw new InternalExpressionException("map constructor requires elements that have two elements");
}
map.put(pair.getItems().get(0), pair.getItems().get(1));
}
@Override
public void append(Value v)
{
put(v);
}
@Override
public int compareTo(Value o)
{
throw new InternalExpressionException("cannot compare to a map value");
}
@Override
public boolean equals(final Value o)
{
if (o instanceof MapValue)
{
MapValue ol = (MapValue)o;
int this_size = this.map.keySet().size();
int o_size = ol.map.keySet().size();
if (this_size != o_size) return false;
if (this_size == 0) return true;
return this.map.keySet().equals(ol.map.keySet());
}
return false;
}
public Map<Value, Value> getMap()
{
return map;
}
public void extend(List<Value> subList)
{
for (Value v: subList) put(v);
}
@Override
public int length()
{
return map.size();
}
@Override
public Value in(Value value1)
{
if (map.containsKey(value1)) return value1;
return Value.NULL;
}
@Override
public Value slice(long from, long to)
{
throw new InternalExpressionException("cannot slice a map value");
}
@Override
public double readNumber()
{
return (double)map.size();
}
@Override
public Value get(Value v2)
{
return map.getOrDefault(v2, Value.NULL);
}
@Override
public boolean has(Value where)
{
return map.containsKey(where);
}
@Override
public Value remove(Value where)
{
return map.remove(where);
}
@Override
public Value put(Value key, Value value)
{
return map.put(key, value);
}
@Override
public String getTypeString()
{
return "map";
}
@Override
public int hashCode()
{
return map.hashCode();
}
} }
@@ -3,6 +3,7 @@ package carpet.script.value;
import carpet.script.CarpetContext; import carpet.script.CarpetContext;
import carpet.script.LazyValue; import carpet.script.LazyValue;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.settings.CarpetSettings;
import com.mojang.brigadier.StringReader; import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.block.entity.HopperBlockEntity; import net.minecraft.block.entity.HopperBlockEntity;
@@ -20,17 +21,18 @@ import net.minecraft.nbt.StringNbtReader;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class NBTSerializableValue extends Value public class NBTSerializableValue extends Value implements ContainerValueInterface
{ {
private String nbtString = null; private String nbtString = null;
private Tag nbtTag = null; private Tag nbtTag = null;
private Supplier<CompoundTag> nbtSupplier = null; private Supplier<Tag> nbtSupplier = null;
public NBTSerializableValue(ItemStack stack) public NBTSerializableValue(ItemStack stack)
{ {
@@ -43,7 +45,7 @@ public class NBTSerializableValue extends Value
{ {
try try
{ {
return (new StringNbtReader(new StringReader(nbtString))).parseCompoundTag(); return (new StringNbtReader(new StringReader(nbtString))).parseTag();
} }
catch (CommandSyntaxException e) catch (CommandSyntaxException e)
{ {
@@ -207,6 +209,82 @@ public class NBTSerializableValue extends Value
} }
} }
@Override
public Value put(Value where, Value value)
{
/// WIP
NbtPathArgumentType.NbtPath path = cachePath(where.getString());
Tag tagToInsert = value instanceof NBTSerializableValue ?
((NBTSerializableValue) value).getTag() :
new NBTSerializableValue(value.getString()).getTag();
CarpetSettings.LOG.error("Inserting tag of class: "+tagToInsert.getClass().getSimpleName());
Tag tag = getTag().copy();
try
{
Collection<Tag> collection_1 = path.get(tag); //, CompoundTag::new);
for(Tag t: collection_1)
{
((CompoundTag)t).copyFrom((CompoundTag) tagToInsert);
}
if (collection_1.size() > 0)
{
nbtSupplier = () -> tag;
nbtTag = tag;
}
return this;
}
catch (CommandSyntaxException e)
{
return Value.NULL;
}
}
@Override
public Value put(Value where, Value value, Value conditions)
{
throw new InternalExpressionException("not implemented");
}
@Override
public Value get(Value value)
{
NbtPathArgumentType.NbtPath path = cachePath(value.getString());
try
{
List<Tag> tags = path.get(getTag());
if (tags.size()==0)
return Value.NULL;
if (tags.size()==1)
return NBTSerializableValue.decodeTag(tags.get(0));
return ListValue.wrap(tags.stream().map(NBTSerializableValue::decodeTag).collect(Collectors.toList()));
}
catch (CommandSyntaxException ignored) { }
return Value.NULL;
}
@Override
public boolean has(Value where)
{
return cachePath(where.getString()).count(getTag()) > 0;
}
@Override
public Value remove(Value where)
{
NbtPathArgumentType.NbtPath path = cachePath(where.getString());
Tag tag = getTag().copy();
int removed = path.remove(tag);
if (removed > 0)
{
nbtSupplier = null;
nbtTag = tag;
return Value.TRUE;
}
return Value.FALSE;
}
public static class InventoryLocator public static class InventoryLocator
{ {
public Object owner; public Object owner;
@@ -242,22 +320,7 @@ public class NBTSerializableValue extends Value
return res; return res;
} }
@Override
public Value getElementAt(Value value)
{
NbtPathArgumentType.NbtPath path = cachePath(value.getString());
try
{
List<Tag> tags = path.get(getTag());
if (tags.size()==0)
return Value.NULL;
if (tags.size()==1)
return NBTSerializableValue.decodeTag(tags.get(0));
return ListValue.wrap(tags.stream().map(NBTSerializableValue::decodeTag).collect(Collectors.toList()));
}
catch (CommandSyntaxException ignored) { }
return Value.NULL;
}
@Override @Override
public String getTypeString() public String getTypeString()
@@ -173,11 +173,6 @@ public abstract class Value implements Comparable<Value>, Cloneable
return (long)readNumber(); return (long)readNumber();
} }
public Value getElementAt(Value v2)
{
throw new InternalExpressionException("get element can only be obtained for lists and nbt values");
}
public String getTypeString() public String getTypeString()
{ {
throw new InternalExpressionException("How did you get here? Cannot get type of an intenal type."); throw new InternalExpressionException("How did you get here? Cannot get type of an intenal type.");