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.InternalExpressionException;
import carpet.script.value.AbstractListValue;
import carpet.script.value.ContainerValueInterface;
import carpet.script.value.FunctionSignatureValue;
import carpet.script.value.GlobalValue;
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;
@@ -1227,7 +1229,12 @@ public class Expression implements Cloneable
*/
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::subtract);
addBinaryOperator("*", precedence.get("multiplication*/%"), true, Value::multiply);
@@ -1322,7 +1329,7 @@ public class Expression implements Cloneable
v1.assertAssignable();
String varname = v1.getVariable();
LazyValue boundedLHS;
if (v1 instanceof ListValue)
if (v1 instanceof ListValue || v1 instanceof MapValue)
{
((ListValue) v1).append(v2);
boundedLHS = (cc, tt)-> v1;
@@ -1872,7 +1879,46 @@ public class Expression implements Cloneable
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
addBinaryFunction("element", (v1, v2) ->
@@ -1892,27 +1938,36 @@ public class Expression implements Cloneable
{
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);
if (!(list instanceof ListValue))
Value container = lv.get(0);
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();
//List<Value> items = ((ListValue)lv.get(0)).getItems();
Value index = lv.get(1);
if (index == Value.NULL)
Value where = lv.get(1);
Value what = lv.get(2);
Value ret;
if (lv.size()>3)
{
((ListValue) list).extend(lv.subList(2,size));
return ((ContainerValueInterface) container).put(where, what, lv.get(3));
}
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'
//returns last successful expression or false
// while(cond, limit, expr) => ??
@@ -1,9 +1,15 @@
package carpet.script.value;
import carpet.script.exception.InternalExpressionException;
import java.util.Iterator;
public abstract class AbstractListValue extends Value
{
public abstract Iterator<Value> iterator();
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;
}
@Override
public Value getElementAt(Value v2)
{
throw new InternalExpressionException("get element can only be obtained for regular lists");
}
@Override
public String getTypeString()
{
@@ -9,7 +9,7 @@ import java.util.stream.Collectors;
import static java.lang.Math.abs;
public class ListValue extends AbstractListValue
public class ListValue extends AbstractListValue implements ContainerValueInterface
{
protected List<Value> items;
@Override
@@ -98,6 +98,7 @@ public class ListValue extends AbstractListValue
}
return output;
}
@Override
public void append(Value v)
{
items.add(v);
@@ -271,6 +272,8 @@ public class ListValue extends AbstractListValue
super(list);
}
}
@Override
public int length()
{
return items.size();
@@ -309,7 +312,30 @@ public class ListValue extends AbstractListValue
}
@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();
int numitems = items.size();
@@ -319,6 +345,24 @@ public class ListValue extends AbstractListValue
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
public String getTypeString()
{
+177 -4
View File
@@ -1,18 +1,32 @@
package carpet.script.value;
import java.util.Arrays;
import carpet.script.exception.InternalExpressionException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
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;
public MapValue()
private MapValue()
{
map = new HashMap<>();
}
public MapValue(List<Value> kvPairs)
{
this();
for (Value v : kvPairs)
{
put(v);
}
}
@Override
public Iterator<Value> iterator()
{
@@ -22,7 +36,20 @@ public class MapValue extends AbstractListValue
@Override
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
@@ -31,4 +58,150 @@ public class MapValue extends AbstractListValue
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.LazyValue;
import carpet.script.exception.InternalExpressionException;
import carpet.settings.CarpetSettings;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.block.entity.HopperBlockEntity;
@@ -20,17 +21,18 @@ import net.minecraft.nbt.StringNbtReader;
import net.minecraft.nbt.Tag;
import net.minecraft.util.math.BlockPos;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class NBTSerializableValue extends Value
public class NBTSerializableValue extends Value implements ContainerValueInterface
{
private String nbtString = null;
private Tag nbtTag = null;
private Supplier<CompoundTag> nbtSupplier = null;
private Supplier<Tag> nbtSupplier = null;
public NBTSerializableValue(ItemStack stack)
{
@@ -43,7 +45,7 @@ public class NBTSerializableValue extends Value
{
try
{
return (new StringNbtReader(new StringReader(nbtString))).parseCompoundTag();
return (new StringNbtReader(new StringReader(nbtString))).parseTag();
}
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 Object owner;
@@ -242,22 +320,7 @@ public class NBTSerializableValue extends Value
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
public String getTypeString()
@@ -173,11 +173,6 @@ public abstract class Value implements Comparable<Value>, Cloneable
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()
{
throw new InternalExpressionException("How did you get here? Cannot get type of an intenal type.");