259 lines
6.9 KiB
Java
259 lines
6.9 KiB
Java
package carpet.script.value;
|
|
|
|
import carpet.script.exception.InternalExpressionException;
|
|
import com.google.gson.JsonElement;
|
|
import com.google.gson.JsonPrimitive;
|
|
import net.minecraft.nbt.Tag;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import java.util.regex.PatternSyntaxException;
|
|
import java.util.stream.Collectors;
|
|
|
|
public abstract class Value implements Comparable<Value>, Cloneable
|
|
{
|
|
public static NumericValue FALSE = new NumericValue(0);
|
|
public static NumericValue TRUE = new NumericValue(1);
|
|
public static NumericValue ZERO = FALSE;
|
|
public static NumericValue ONE = TRUE;
|
|
|
|
public static NullValue NULL = new NullValue();
|
|
|
|
public String boundVariable;
|
|
|
|
public static <T> T assertNotNull(T t)
|
|
{
|
|
if (t == null)
|
|
throw new InternalExpressionException("Operand may not be null");
|
|
return t;
|
|
}
|
|
|
|
public static <T> void assertNotNull(T t1, T t2)
|
|
{
|
|
if (t1 == null)
|
|
throw new InternalExpressionException("First operand may not be null");
|
|
if (t2 == null)
|
|
throw new InternalExpressionException("Second operand may not be null");
|
|
}
|
|
|
|
public boolean isBound()
|
|
{
|
|
return boundVariable != null;
|
|
}
|
|
public String getVariable()
|
|
{
|
|
return boundVariable;
|
|
}
|
|
public Value reboundedTo(String var)
|
|
{
|
|
Value copy;
|
|
try
|
|
{
|
|
copy = (Value)clone();
|
|
}
|
|
catch (CloneNotSupportedException e)
|
|
{
|
|
// should not happen
|
|
e.printStackTrace();
|
|
throw new InternalExpressionException("Variable of type "+getTypeString()+" is not cloneable. Tell gnembon about it, this shoudn't happen");
|
|
}
|
|
copy.boundVariable = var;
|
|
return copy;
|
|
}
|
|
public Value bindTo(String var)
|
|
{
|
|
this.boundVariable = var;
|
|
return this;
|
|
}
|
|
|
|
public abstract String getString();
|
|
|
|
public String getPrettyString()
|
|
{
|
|
return getString();
|
|
}
|
|
|
|
|
|
public abstract boolean getBoolean();
|
|
|
|
public Value add(Value o) {
|
|
String lstr = this.getString();
|
|
if (o instanceof FormattedTextValue)
|
|
{
|
|
return FormattedTextValue.combine(this, o);
|
|
}
|
|
if (lstr == null) // null
|
|
return new StringValue(o.getString());
|
|
String rstr = o.getString();
|
|
if (rstr == null)
|
|
{
|
|
return new StringValue(lstr);
|
|
}
|
|
return new StringValue(lstr+rstr);
|
|
}
|
|
public Value subtract(Value v)
|
|
{
|
|
return new StringValue(this.getString().replace(v.getString(),""));
|
|
}
|
|
public Value multiply(Value v)
|
|
{
|
|
if (v instanceof NumericValue || v instanceof ListValue)
|
|
{
|
|
return v.multiply(this);
|
|
}
|
|
return new StringValue(this.getString()+"."+v.getString());
|
|
}
|
|
public Value divide(Value v)
|
|
{
|
|
if (v instanceof NumericValue)
|
|
{
|
|
String lstr = getString();
|
|
return new StringValue(lstr.substring(0, (int)(lstr.length()/ ((NumericValue) v).getDouble())));
|
|
}
|
|
return new StringValue(getString()+"/"+v.getString());
|
|
}
|
|
|
|
public Value()
|
|
{
|
|
this.boundVariable = null;
|
|
}
|
|
|
|
@Override
|
|
public int compareTo(final Value o)
|
|
{
|
|
if (o instanceof NumericValue || o instanceof ListValue || o instanceof ThreadValue)
|
|
{
|
|
return -o.compareTo(this);
|
|
}
|
|
return getString().compareTo(o.getString());
|
|
}
|
|
|
|
@Override // for hashmap key access, and == operator
|
|
public boolean equals(final Object o)
|
|
{
|
|
if (o instanceof Value)
|
|
return this.compareTo((Value) o)==0;
|
|
return false;
|
|
}
|
|
|
|
public void assertAssignable()
|
|
{
|
|
if (boundVariable == null || boundVariable.startsWith("_"))
|
|
{
|
|
if (boundVariable != null)
|
|
{
|
|
throw new InternalExpressionException(boundVariable+ " cannot be assigned a new value");
|
|
}
|
|
throw new InternalExpressionException(getString()+ " is not a variable");
|
|
|
|
}
|
|
}
|
|
|
|
public Value in(Value value1)
|
|
{
|
|
final Pattern p;
|
|
try
|
|
{
|
|
p = Pattern.compile(value1.getString());
|
|
}
|
|
catch (PatternSyntaxException pse)
|
|
{
|
|
throw new InternalExpressionException("Incorrect matching pattern: "+pse.getMessage());
|
|
}
|
|
final Matcher m = p.matcher(this.getString());
|
|
if (!m.find()) return Value.NULL;
|
|
int gc = m.groupCount();
|
|
if (gc == 0) return new StringValue(m.group());
|
|
if (gc == 1) return new StringValue(m.group(1));
|
|
List<Value> groups = new ArrayList<>(gc);
|
|
for (int i = 1; i <= gc; i++)
|
|
{
|
|
groups.add(new StringValue(m.group(i)));
|
|
}
|
|
return ListValue.wrap(groups);
|
|
}
|
|
public int length()
|
|
{
|
|
return getString().length();
|
|
}
|
|
|
|
public Value slice(long fromDesc, Long toDesc)
|
|
{
|
|
String value = this.getString();
|
|
int size = value.length();
|
|
int from = ListValue.normalizeIndex(fromDesc, size);
|
|
if (toDesc == null) return new StringValue(value.substring(from));
|
|
int to = ListValue.normalizeIndex(toDesc, size);
|
|
if (from > to) return StringValue.EMPTY;
|
|
return new StringValue(value.substring(from, to));
|
|
}
|
|
|
|
public Value split(Value delimiter)
|
|
{
|
|
try
|
|
{
|
|
return ListValue.wrap(Arrays.stream(getString().split(delimiter.getString())).map(StringValue::new).collect(Collectors.toList()));
|
|
}
|
|
catch (PatternSyntaxException pse)
|
|
{
|
|
throw new InternalExpressionException("Incorrect pattern for 'split': "+pse.getMessage());
|
|
}
|
|
}
|
|
|
|
public double readDoubleNumber()
|
|
{
|
|
String s = getString();
|
|
try
|
|
{
|
|
return Double.valueOf(s);
|
|
}
|
|
catch (NumberFormatException e)
|
|
{
|
|
return Double.NaN;
|
|
}
|
|
}
|
|
|
|
public long readInteger()
|
|
{
|
|
return (long) readDoubleNumber();
|
|
}
|
|
|
|
public String getTypeString()
|
|
{
|
|
throw new InternalExpressionException("How did you get here? Cannot get type of an intenal type.");
|
|
}
|
|
|
|
@Override
|
|
public int hashCode()
|
|
{
|
|
String stringVal = getString();
|
|
if (stringVal.isEmpty()) return 0;
|
|
return ("s"+stringVal).hashCode();
|
|
}
|
|
|
|
public Value deepcopy()
|
|
{
|
|
try
|
|
{
|
|
return (Value)this.clone();
|
|
}
|
|
catch (CloneNotSupportedException e)
|
|
{
|
|
// should never happen
|
|
throw new InternalExpressionException("Cannot make a copy of value: "+this);
|
|
}
|
|
}
|
|
|
|
public abstract Tag toTag(boolean force);
|
|
|
|
public JsonElement toJson()
|
|
{
|
|
return new JsonPrimitive(getString());
|
|
}
|
|
|
|
public boolean isNull() { return false; }
|
|
}
|