276 lines
7.1 KiB
Java
276 lines
7.1 KiB
Java
package carpet.script.value;
|
|
|
|
import carpet.script.CarpetScriptServer;
|
|
import carpet.script.exception.InternalExpressionException;
|
|
import com.google.gson.JsonElement;
|
|
import com.google.gson.JsonPrimitive;
|
|
|
|
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 net.minecraft.nbt.Tag;
|
|
|
|
public abstract class Value implements Comparable<Value>, Cloneable
|
|
{
|
|
public static final NumericValue FALSE = BooleanValue.FALSE;
|
|
public static final NumericValue TRUE = BooleanValue.TRUE;
|
|
public static final NumericValue ZERO = new NumericValue(0);
|
|
public static final NumericValue ONE = new NumericValue(1);
|
|
|
|
public static final NullValue NULL = NullValue.NULL;
|
|
public static final UndefValue UNDEF = UndefValue.UNDEF;
|
|
|
|
public String boundVariable;
|
|
|
|
public boolean isBound()
|
|
{
|
|
return boundVariable != null;
|
|
}
|
|
|
|
public String getVariable()
|
|
{
|
|
return boundVariable;
|
|
}
|
|
|
|
public Value reboundedTo(final String value)
|
|
{
|
|
final Value copy;
|
|
try
|
|
{
|
|
copy = (Value) clone();
|
|
}
|
|
catch (final CloneNotSupportedException e)
|
|
{
|
|
// should not happen
|
|
CarpetScriptServer.LOG.error("Failed to clone variable", e);
|
|
throw new InternalExpressionException("Variable of type " + getTypeString() + " is not cloneable. Tell gnembon about it, this shoudn't happen");
|
|
}
|
|
copy.boundVariable = value;
|
|
return copy;
|
|
}
|
|
|
|
public Value bindTo(final String value)
|
|
{
|
|
this.boundVariable = value;
|
|
return this;
|
|
}
|
|
|
|
public abstract String getString();
|
|
|
|
public String getPrettyString()
|
|
{
|
|
return getString();
|
|
}
|
|
|
|
|
|
public abstract boolean getBoolean();
|
|
|
|
public Value add(final Value o)
|
|
{
|
|
if (o instanceof FormattedTextValue)
|
|
{
|
|
return FormattedTextValue.combine(this, o);
|
|
}
|
|
final String leftStr = this.getString();
|
|
final String rightStr = o.getString();
|
|
return new StringValue(leftStr + rightStr);
|
|
}
|
|
|
|
public Value subtract(final Value v)
|
|
{
|
|
return new StringValue(this.getString().replace(v.getString(), ""));
|
|
}
|
|
|
|
public Value multiply(final Value v)
|
|
{
|
|
return v instanceof NumericValue || v instanceof ListValue
|
|
? v.multiply(this)
|
|
: new StringValue(this.getString() + "." + v.getString());
|
|
}
|
|
|
|
public Value divide(final Value v)
|
|
{
|
|
if (v instanceof final NumericValue number)
|
|
{
|
|
final String lstr = getString();
|
|
return new StringValue(lstr.substring(0, (int) (lstr.length() / number.getDouble())));
|
|
}
|
|
return new StringValue(getString() + "/" + v.getString());
|
|
}
|
|
|
|
public Value()
|
|
{
|
|
this.boundVariable = null;
|
|
}
|
|
|
|
@Override
|
|
public int compareTo(final Value o)
|
|
{
|
|
return o instanceof NumericValue || o instanceof ListValue || o instanceof ThreadValue
|
|
? -o.compareTo(this)
|
|
: getString().compareTo(o.getString());
|
|
}
|
|
|
|
@Override // for hashmap key access, and == operator
|
|
public boolean equals(final Object o)
|
|
{
|
|
if (o instanceof final Value v)
|
|
{
|
|
return this.compareTo(v) == 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(final Value value1)
|
|
{
|
|
final Pattern p;
|
|
try
|
|
{
|
|
p = Pattern.compile(value1.getString());
|
|
}
|
|
catch (final PatternSyntaxException pse)
|
|
{
|
|
throw new InternalExpressionException("Incorrect matching pattern: " + pse.getMessage());
|
|
}
|
|
final Matcher m = p.matcher(this.getString());
|
|
if (!m.find())
|
|
{
|
|
return Value.NULL;
|
|
}
|
|
final int gc = m.groupCount();
|
|
if (gc == 0)
|
|
{
|
|
return new StringValue(m.group());
|
|
}
|
|
if (gc == 1)
|
|
{
|
|
return StringValue.of(m.group(1));
|
|
}
|
|
final List<Value> groups = new ArrayList<>(gc);
|
|
for (int i = 1; i <= gc; i++)
|
|
{
|
|
groups.add(StringValue.of(m.group(i)));
|
|
}
|
|
return ListValue.wrap(groups);
|
|
}
|
|
|
|
public int length()
|
|
{
|
|
return getString().length();
|
|
}
|
|
|
|
public Value slice(final long fromDesc, final Long toDesc)
|
|
{
|
|
final String value = this.getString();
|
|
final int size = value.length();
|
|
final int from = ListValue.normalizeIndex(fromDesc, size);
|
|
if (toDesc == null)
|
|
{
|
|
return new StringValue(value.substring(from));
|
|
}
|
|
final int to = ListValue.normalizeIndex(toDesc, size + 1);
|
|
if (from > to)
|
|
{
|
|
return StringValue.EMPTY;
|
|
}
|
|
return new StringValue(value.substring(from, to));
|
|
}
|
|
|
|
public Value split(Value delimiter)
|
|
{
|
|
if (delimiter == null)
|
|
{
|
|
delimiter = StringValue.EMPTY;
|
|
}
|
|
try
|
|
{
|
|
return ListValue.wrap(Arrays.stream(getString().split(delimiter.getString())).map(StringValue::new));
|
|
}
|
|
catch (final PatternSyntaxException pse)
|
|
{
|
|
throw new InternalExpressionException("Incorrect pattern for 'split': " + pse.getMessage());
|
|
}
|
|
}
|
|
|
|
public double readDoubleNumber()
|
|
{
|
|
final String s = getString();
|
|
try
|
|
{
|
|
return Double.parseDouble(s);
|
|
}
|
|
catch (final 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()
|
|
{
|
|
final String stringVal = getString();
|
|
return stringVal.isEmpty() ? 0 : ("s" + stringVal).hashCode();
|
|
}
|
|
|
|
public Value deepcopy()
|
|
{
|
|
try
|
|
{
|
|
return (Value) this.clone();
|
|
}
|
|
catch (final 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;
|
|
}
|
|
|
|
/**
|
|
* @return retrieves useful in-run value of an optimized code-base value.
|
|
* For immutable values (most of them) it can return itself,
|
|
* but for mutables, it needs to be its copy or deep copy.
|
|
*/
|
|
public Value fromConstant()
|
|
{
|
|
return this;
|
|
}
|
|
}
|