Merge pull request #1307 from gnembon/strict_and_null_initialization
Strict config and null initialization
This commit is contained in:
7 files changed
+152
-3
No files matched your search
@@ -40,8 +40,12 @@ apps `__on_close()` will execute once per app, and with `'player'` scoped apps,
|
|||||||
### App config via `__config()` function
|
### App config via `__config()` function
|
||||||
|
|
||||||
If an app defines `__config` method, and that method returns a map, it will be used to apply custom settings
|
If an app defines `__config` method, and that method returns a map, it will be used to apply custom settings
|
||||||
for this app. Currently the following options are supported:
|
for this app. Currently, the following options are supported:
|
||||||
|
|
||||||
|
* `'strict'` : if `true`, any use of an uninitialized variable will result in program failure. Defaults to `false` if
|
||||||
|
not specified. With `'strict'`you have to assign an initial value to any variable before using it. It is very useful
|
||||||
|
to use this setting for app debugging and for beginner programmers. Explicit initialization is not required for your
|
||||||
|
code to work, but mistakes may result from improper assumptions about initial variable values of `null`.
|
||||||
* `'scope'`: default scope for global variables for the app, Default is `'player'`, which means that globals and defined
|
* `'scope'`: default scope for global variables for the app, Default is `'player'`, which means that globals and defined
|
||||||
functions will be unique for each player so that apps for each player will run in isolation. This is useful in
|
functions will be unique for each player so that apps for each player will run in isolation. This is useful in
|
||||||
tool-like applications, where behaviour of things is always from a player's perspective. With player scope the initial run
|
tool-like applications, where behaviour of things is always from a player's perspective. With player scope the initial run
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
else if (parent != null)
|
else if (parent != null)
|
||||||
{
|
{
|
||||||
persistenceRequired = ((CarpetScriptHost)parent).persistenceRequired;
|
persistenceRequired = ((CarpetScriptHost)parent).persistenceRequired;
|
||||||
|
strict = parent.strict;
|
||||||
}
|
}
|
||||||
appConfig = config;
|
appConfig = config;
|
||||||
appArgTypes = argTypes;
|
appArgTypes = argTypes;
|
||||||
@@ -306,6 +307,7 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
Map<Value, Value> config = ((MapValue) ret).getMap();
|
Map<Value, Value> config = ((MapValue) ret).getMap();
|
||||||
setPerPlayer(config.getOrDefault(new StringValue("scope"), new StringValue("player")).getString().equalsIgnoreCase("player"));
|
setPerPlayer(config.getOrDefault(new StringValue("scope"), new StringValue("player")).getString().equalsIgnoreCase("player"));
|
||||||
persistenceRequired = config.getOrDefault(new StringValue("stay_loaded"), Value.TRUE).getBoolean();
|
persistenceRequired = config.getOrDefault(new StringValue("stay_loaded"), Value.TRUE).getBoolean();
|
||||||
|
strict = config.getOrDefault(StringValue.of("strict"), Value.FALSE).getBoolean();
|
||||||
// check requires
|
// check requires
|
||||||
Value loadRequirements = config.get(new StringValue("requires"));
|
Value loadRequirements = config.get(new StringValue("requires"));
|
||||||
if (loadRequirements instanceof FunctionValue)
|
if (loadRequirements instanceof FunctionValue)
|
||||||
|
|||||||
@@ -738,7 +738,7 @@ public class Expression
|
|||||||
}
|
}
|
||||||
var = c.host.getGlobalVariable(module, name);
|
var = c.host.getGlobalVariable(module, name);
|
||||||
if (var != null) return var;
|
if (var != null) return var;
|
||||||
var = (_c, _t ) -> Value.ZERO.reboundedTo(name);
|
var = (_c, _t ) -> _c.host.strict ? Value.UNDEF.reboundedTo(name) : Value.NULL.reboundedTo(name);
|
||||||
setAnyVariable(c, name, var);
|
setAnyVariable(c, name, var);
|
||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public abstract class ScriptHost
|
|||||||
private final Map<Value, ThreadPoolExecutor> executorServices = new HashMap<>();
|
private final Map<Value, ThreadPoolExecutor> executorServices = new HashMap<>();
|
||||||
private final Map<Value, Object> locks = new ConcurrentHashMap<>();
|
private final Map<Value, Object> locks = new ConcurrentHashMap<>();
|
||||||
protected boolean inTermination = false;
|
protected boolean inTermination = false;
|
||||||
|
public boolean strict;
|
||||||
|
|
||||||
private final Set<String> deprecations = new HashSet<>();
|
private final Set<String> deprecations = new HashSet<>();
|
||||||
|
|
||||||
@@ -118,6 +119,7 @@ public abstract class ScriptHost
|
|||||||
this.main = code;
|
this.main = code;
|
||||||
this.perUser = perUser;
|
this.perUser = perUser;
|
||||||
this.user = null;
|
this.user = null;
|
||||||
|
this.strict = false;
|
||||||
ModuleData moduleData = new ModuleData(code);
|
ModuleData moduleData = new ModuleData(code);
|
||||||
initializeModuleGlobals(moduleData);
|
initializeModuleGlobals(moduleData);
|
||||||
this.moduleData.put(code, moduleData);
|
this.moduleData.put(code, moduleData);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class NullValue extends NumericValue // TODO check nonsingleton code
|
|||||||
{
|
{
|
||||||
return new NullValue();
|
return new NullValue();
|
||||||
}
|
}
|
||||||
private NullValue() {super(0);}
|
protected NullValue() {super(0);}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object o)
|
public boolean equals(final Object o)
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
package carpet.script.value;
|
||||||
|
|
||||||
|
import carpet.script.exception.InternalExpressionException;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
|
||||||
|
public class UndefValue extends NullValue {
|
||||||
|
public static final UndefValue UNDEF = new UndefValue();
|
||||||
|
|
||||||
|
private RuntimeException getError() {
|
||||||
|
return new InternalExpressionException("variable "+boundVariable+" was used before initialization under 'strict' app config");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getString()
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPrettyString()
|
||||||
|
{
|
||||||
|
return "undefined";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getBoolean()
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value clone()
|
||||||
|
{
|
||||||
|
return new UndefValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o)
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value slice(long fromDesc, Long toDesc) {
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NumericValue opposite() {
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int length() {
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Value o)
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value in(Value value) {
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTypeString()
|
||||||
|
{
|
||||||
|
return "undef";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tag toTag(boolean force)
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value split(Value delimiter) {
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement toJson()
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNull() {
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value add(Value v) {
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value subtract(Value v)
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value multiply(Value v)
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value divide(Value v)
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double readDoubleNumber()
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readInteger()
|
||||||
|
{
|
||||||
|
throw getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ public abstract class Value implements Comparable<Value>, Cloneable
|
|||||||
public static NumericValue ONE = new NumericValue(1);
|
public static NumericValue ONE = new NumericValue(1);
|
||||||
|
|
||||||
public static NullValue NULL = NullValue.NULL;
|
public static NullValue NULL = NullValue.NULL;
|
||||||
|
public static UndefValue UNDEF = UndefValue.UNDEF;
|
||||||
|
|
||||||
public String boundVariable;
|
public String boundVariable;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user