semi-auto cleanup

This commit is contained in:
gnembon committed 2023-02-04 13:26:21 +01:00
1 parent cad80f82c6
commit 8f61271606
99 files changed
+11463 -8007

No files matched your search

+206 -111
View File
@@ -38,41 +38,45 @@ public abstract class ScriptHost
private final Set<String> deprecations = new HashSet<>();
public Random getRandom(long aLong)
public Random getRandom(final long aLong)
{
if (randomizers.size() > 65536)
{
randomizers.clear();
}
return randomizers.computeIfAbsent(aLong, Random::new);
}
public boolean resetRandom(long aLong) {
public boolean resetRandom(final long aLong)
{
return randomizers.remove(aLong) != null;
}
public static class ModuleData
{
Module parent;
public Map<String, FunctionValue> globalFunctions = new Object2ObjectOpenHashMap<>();
public Map<String, LazyValue> globalVariables = new Object2ObjectOpenHashMap<>();
public Map<String, ModuleData> functionImports = new Object2ObjectOpenHashMap<>(); // imported functions string to module
public Map<String, ModuleData> globalsImports = new Object2ObjectOpenHashMap<>(); // imported global variables string to module
public Map<String, ModuleData> futureImports = new Object2ObjectOpenHashMap<>(); // imports not known before used
public final Map<String, FunctionValue> globalFunctions = new Object2ObjectOpenHashMap<>();
public final Map<String, LazyValue> globalVariables = new Object2ObjectOpenHashMap<>();
public final Map<String, ModuleData> functionImports = new Object2ObjectOpenHashMap<>(); // imported functions string to module
public final Map<String, ModuleData> globalsImports = new Object2ObjectOpenHashMap<>(); // imported global variables string to module
public final Map<String, ModuleData> futureImports = new Object2ObjectOpenHashMap<>(); // imports not known before used
public ModuleData(Module parent, ModuleData other)
public ModuleData(final Module parent, final ModuleData other)
{
super();
// imports are just pointers, but they still point to the wrong modules (point to the parent)
this.parent = parent;
globalFunctions.putAll(other.globalFunctions);
other.globalVariables.forEach((key, value) ->
{
Value var = value.evalValue(null);
Value copy = var.deepcopy();
final Value var = value.evalValue(null);
final Value copy = var.deepcopy();
copy.boundVariable = var.boundVariable;
globalVariables.put(key, (c, t) -> copy);
});
}
public void setImportsBasedOn(ScriptHost host, ModuleData other)
public void setImportsBasedOn(final ScriptHost host, final ModuleData other)
{
// fixing imports
other.functionImports.forEach((name, targetData) -> {
@@ -87,20 +91,24 @@ public abstract class ScriptHost
}
public ModuleData(Module parent)
public ModuleData(final Module parent)
{
this.parent = parent;
}
}
protected final Map<String, ScriptHost> userHosts = new Object2ObjectOpenHashMap<>();
private Map<Module,ModuleData> moduleData = new HashMap<>(); // marking imports
private Map<String,Module> modules = new HashMap<>();
private final Map<Module, ModuleData> moduleData = new HashMap<>(); // marking imports
private final Map<String, Module> modules = new HashMap<>();
protected ScriptHost parent;
protected boolean perUser;
public String user;
public String getName() {return main ==null?null: main.name();}
public String getName()
{
return main == null ? null : main.name();
}
public final Module main;
@@ -109,9 +117,10 @@ public abstract class ScriptHost
{
List<String> apply(Expression expression, Tokenizer.Token token, Context context, String message);
}
public ErrorSnooper errorSnooper = null;
protected ScriptHost(Module code, ScriptServer scriptServer, boolean perUser, ScriptHost parent)
protected ScriptHost(final Module code, final ScriptServer scriptServer, final boolean perUser, final ScriptHost parent)
{
this.parent = parent;
this.main = code;
@@ -119,24 +128,30 @@ public abstract class ScriptHost
this.user = null;
this.strict = false;
this.scriptServer = scriptServer;
ModuleData moduleData = new ModuleData(code);
final ModuleData moduleData = new ModuleData(code);
initializeModuleGlobals(moduleData);
this.moduleData.put(code, moduleData);
this.modules.put(code==null?null:code.name(), code);
this.modules.put(code == null ? null : code.name(), code);
mainThread = Thread.currentThread();
}
void initializeModuleGlobals(ModuleData md)
void initializeModuleGlobals(final ModuleData md)
{
}
public void importModule(Context c, String moduleName)
public void importModule(final Context c, final String moduleName)
{
if (modules.containsKey(moduleName.toLowerCase(Locale.ROOT))) return; // aready imported
Module module = getModuleOrLibraryByName(moduleName);
if (modules.containsKey(module.name())) return; // aready imported, once again, in case some discrepancies in names?
if (modules.containsKey(moduleName.toLowerCase(Locale.ROOT)))
{
return; // aready imported
}
final Module module = getModuleOrLibraryByName(moduleName);
if (modules.containsKey(module.name()))
{
return; // aready imported, once again, in case some discrepancies in names?
}
modules.put(module.name(), module);
ModuleData data = new ModuleData(module);
final ModuleData data = new ModuleData(module);
initializeModuleGlobals(data);
moduleData.put(module, data);
runModuleCode(c, module);
@@ -144,20 +159,21 @@ public abstract class ScriptHost
//modules.remove(module.getName());
//throw new InternalExpressionException("Failed to import a module "+moduleName);
}
public void importNames(Context c, Module targetModule, String sourceModuleName, List<String> identifiers )
public void importNames(final Context c, final Module targetModule, final String sourceModuleName, final List<String> identifiers)
{
if (!moduleData.containsKey(targetModule))
{
throw new InternalExpressionException("Cannot import to module that doesn't exist");
}
Module source = modules.get(sourceModuleName);
ModuleData sourceData = moduleData.get(source);
ModuleData targetData = moduleData.get(targetModule);
final Module source = modules.get(sourceModuleName);
final ModuleData sourceData = moduleData.get(source);
final ModuleData targetData = moduleData.get(targetModule);
if (sourceData == null || targetData == null)
{
throw new InternalExpressionException("Cannot import from module that is not imported");
}
for (String identifier: identifiers)
for (final String identifier : identifiers)
{
if (sourceData.globalFunctions.containsKey(identifier))
{
@@ -174,10 +190,10 @@ public abstract class ScriptHost
}
}
public Stream<String> availableImports(String moduleName)
public Stream<String> availableImports(final String moduleName)
{
Module source = modules.get(moduleName);
ModuleData sourceData = moduleData.get(source);
final Module source = modules.get(moduleName);
final ModuleData sourceData = moduleData.get(source);
if (sourceData == null)
{
throw new InternalExpressionException("Cannot import from module that is not imported");
@@ -192,136 +208,195 @@ public abstract class ScriptHost
protected abstract void runModuleCode(Context c, Module module); // this should be shell out in the executor
public FunctionValue getFunction(String name) { return getFunction(main, name); }
public FunctionValue getAssertFunction(Module module, String name)
public FunctionValue getFunction(final String name)
{
FunctionValue ret = getFunction(module, name);
return getFunction(main, name);
}
public FunctionValue getAssertFunction(final Module module, final String name)
{
final FunctionValue ret = getFunction(module, name);
if (ret == null)
{
if (module == main)
throw new InternalExpressionException("Function '"+name+"' is not defined yet");
{
throw new InternalExpressionException("Function '" + name + "' is not defined yet");
}
else
throw new InternalExpressionException("Function '"+name+"' is not defined nor visible by its name in the imported module '"+module.name()+"'");
{
throw new InternalExpressionException("Function '" + name + "' is not defined nor visible by its name in the imported module '" + module.name() + "'");
}
}
return ret;
}
private FunctionValue getFunction(Module module, String name)
private FunctionValue getFunction(final Module module, final String name)
{
ModuleData local = getModuleData(module);
final ModuleData local = getModuleData(module);
FunctionValue ret = local.globalFunctions.get(name); // most uses would be from local scope anyways
if (ret != null) return ret;
if (ret != null)
{
return ret;
}
ModuleData target = local.functionImports.get(name);
if (target != null)
{
ret = target.globalFunctions.get(name);
if (ret != null) return ret;
if (ret != null)
{
return ret;
}
}
// not in local scope - will need to travel over import links
target = local.futureImports.get(name);
if (target == null) return null;
if (target == null)
{
return null;
}
target = findModuleDataFromFunctionImports(name, target, 0);
if (target == null) return null;
if (target == null)
{
return null;
}
local.futureImports.remove(name);
local.functionImports.put(name, target);
return target.globalFunctions.get(name);
}
private ModuleData findModuleDataFromFunctionImports(String name, ModuleData source, int ttl)
private ModuleData findModuleDataFromFunctionImports(final String name, final ModuleData source, final int ttl)
{
if (ttl > 64) throw new InternalExpressionException("Cannot import "+name+", either your imports are too deep or too loopy");
if (ttl > 64)
{
throw new InternalExpressionException("Cannot import " + name + ", either your imports are too deep or too loopy");
}
if (source.globalFunctions.containsKey(name))
{
return source;
}
if (source.functionImports.containsKey(name))
return findModuleDataFromFunctionImports(name, source.functionImports.get(name), ttl+1);
{
return findModuleDataFromFunctionImports(name, source.functionImports.get(name), ttl + 1);
}
if (source.futureImports.containsKey(name))
return findModuleDataFromFunctionImports(name, source.futureImports.get(name), ttl+1);
{
return findModuleDataFromFunctionImports(name, source.futureImports.get(name), ttl + 1);
}
return null;
}
public LazyValue getGlobalVariable(String name) { return getGlobalVariable(main, name); }
public LazyValue getGlobalVariable(Module module, String name)
public LazyValue getGlobalVariable(final String name)
{
ModuleData local = getModuleData(module);
return getGlobalVariable(main, name);
}
public LazyValue getGlobalVariable(final Module module, final String name)
{
final ModuleData local = getModuleData(module);
LazyValue ret = local.globalVariables.get(name); // most uses would be from local scope anyways
if (ret != null) return ret;
if (ret != null)
{
return ret;
}
ModuleData target = local.globalsImports.get(name);
if (target != null)
{
ret = target.globalVariables.get(name);
if (ret != null) return ret;
if (ret != null)
{
return ret;
}
}
// not in local scope - will need to travel over import links
target = local.futureImports.get(name);
if (target == null) return null;
if (target == null)
{
return null;
}
target = findModuleDataFromGlobalImports(name, target, 0);
if (target == null) return null;
if (target == null)
{
return null;
}
local.futureImports.remove(name);
local.globalsImports.put(name, target);
return target.globalVariables.get(name);
}
private ModuleData findModuleDataFromGlobalImports(String name, ModuleData source, int ttl)
private ModuleData findModuleDataFromGlobalImports(final String name, final ModuleData source, final int ttl)
{
if (ttl > 64) throw new InternalExpressionException("Cannot import "+name+", either your imports are too deep or too loopy");
if (ttl > 64)
{
throw new InternalExpressionException("Cannot import " + name + ", either your imports are too deep or too loopy");
}
if (source.globalVariables.containsKey(name))
{
return source;
}
if (source.globalsImports.containsKey(name))
return findModuleDataFromGlobalImports(name, source.globalsImports.get(name), ttl+1);
{
return findModuleDataFromGlobalImports(name, source.globalsImports.get(name), ttl + 1);
}
if (source.futureImports.containsKey(name))
return findModuleDataFromGlobalImports(name, source.futureImports.get(name), ttl+1);
{
return findModuleDataFromGlobalImports(name, source.futureImports.get(name), ttl + 1);
}
return null;
}
public void delFunctionWithPrefix(Module module, String prefix)
public void delFunctionWithPrefix(final Module module, final String prefix)
{
ModuleData data = getModuleData(module);
final ModuleData data = getModuleData(module);
data.globalFunctions.entrySet().removeIf(e -> e.getKey().startsWith(prefix));
data.functionImports.entrySet().removeIf(e -> e.getKey().startsWith(prefix));
}
public void delFunction(Module module, String funName)
public void delFunction(final Module module, final String funName)
{
ModuleData data = getModuleData(module);
final ModuleData data = getModuleData(module);
data.globalFunctions.remove(funName);
data.functionImports.remove(funName);
}
public void delGlobalVariableWithPrefix(Module module, String prefix)
public void delGlobalVariableWithPrefix(final Module module, final String prefix)
{
ModuleData data = getModuleData(module);
final ModuleData data = getModuleData(module);
data.globalVariables.entrySet().removeIf(e -> e.getKey().startsWith(prefix));
data.globalsImports.entrySet().removeIf(e -> e.getKey().startsWith(prefix));
}
public void delGlobalVariable(Module module, String varName)
public void delGlobalVariable(final Module module, final String varName)
{
ModuleData data = getModuleData(module);
final ModuleData data = getModuleData(module);
data.globalFunctions.remove(varName);
data.functionImports.remove(varName);
}
private ModuleData getModuleData(Module module)
private ModuleData getModuleData(final Module module)
{
ModuleData data = moduleData.get(module);
if (data == null) throw new IntegrityException("Module structure changed for the app. Did you reload the app with tasks running?");
final ModuleData data = moduleData.get(module);
if (data == null)
{
throw new IntegrityException("Module structure changed for the app. Did you reload the app with tasks running?");
}
return data;
}
protected void assertAppIntegrity(Module module)
protected void assertAppIntegrity(final Module module)
{
getModuleData(module);
}
public void addUserDefinedFunction(Context ctx, Module module, String name, FunctionValue fun)
public void addUserDefinedFunction(final Context ctx, final Module module, final String name, final FunctionValue fun)
{
getModuleData(module).globalFunctions.put(name, fun);
}
public void setGlobalVariable(Module module, String name, LazyValue lv)
public void setGlobalVariable(final Module module, final String name, final LazyValue lv)
{
getModuleData(module).globalVariables.put(name, lv);
}
public Stream<String> globalVariableNames(Module module, Predicate<String> predicate)
public Stream<String> globalVariableNames(final Module module, final Predicate<String> predicate)
{
return Stream.concat(Stream.concat(
getModuleData(module).globalVariables.keySet().stream(),
@@ -329,27 +404,33 @@ public abstract class ScriptHost
), getModuleData(module).futureImports.keySet().stream().filter(s -> s.startsWith("global_"))).filter(predicate);
}
public Stream<String> globalFunctionNames(Module module, Predicate<String> predicate)
public Stream<String> globalFunctionNames(final Module module, final Predicate<String> predicate)
{
return Stream.concat(Stream.concat(
getModuleData(module).globalFunctions.keySet().stream(),
getModuleData(module).functionImports.keySet().stream()
),getModuleData(module).futureImports.keySet().stream().filter(s -> !s.startsWith("global_"))).filter(predicate);
), getModuleData(module).futureImports.keySet().stream().filter(s -> !s.startsWith("global_"))).filter(predicate);
}
public ScriptHost retrieveForExecution(String /*Nullable*/ user)
public ScriptHost retrieveForExecution(final String /*Nullable*/ user)
{
if (!perUser) return this;
ScriptHost oldUserHost = userHosts.get(user);
if (oldUserHost != null) return oldUserHost;
ScriptHost userHost = this.duplicate();
if (!perUser)
{
return this;
}
final ScriptHost oldUserHost = userHosts.get(user);
if (oldUserHost != null)
{
return oldUserHost;
}
final ScriptHost userHost = this.duplicate();
userHost.user = user;
this.setupUserHost(userHost);
userHosts.put(user, userHost);
return userHost;
}
protected void setupUserHost(ScriptHost host)
protected void setupUserHost(final ScriptHost host)
{
// adding imports
host.modules.putAll(this.modules);
@@ -358,57 +439,65 @@ public abstract class ScriptHost
host.moduleData.forEach((module, data) -> data.setImportsBasedOn(host, this.moduleData.get(data.parent)));
}
synchronized public void handleExpressionException(String msg, ExpressionException exc)
public synchronized void handleExpressionException(final String msg, final ExpressionException exc)
{
System.out.println(msg+": "+exc);
System.out.println(msg + ": " + exc);
}
protected abstract ScriptHost duplicate();
public Object getLock(Value name)
public Object getLock(final Value name)
{
return locks.computeIfAbsent(name, (n) -> new Object());
return locks.computeIfAbsent(name, n -> new Object());
}
public ThreadPoolExecutor getExecutor(Value pool)
public ThreadPoolExecutor getExecutor(final Value pool)
{
if (inTermination) return null;
return executorServices.computeIfAbsent(pool, (v) -> (ThreadPoolExecutor) Executors.newCachedThreadPool());
if (inTermination)
{
return null;
}
return executorServices.computeIfAbsent(pool, v -> (ThreadPoolExecutor) Executors.newCachedThreadPool());
}
public int taskCount()
{
return executorServices.values().stream().map(ThreadPoolExecutor::getActiveCount).reduce(0, Integer::sum);
}
public int taskCount(Value pool)
public int taskCount(final Value pool)
{
if (executorServices.containsKey(pool))
{
return executorServices.get(pool).getActiveCount();
}
return 0;
return executorServices.containsKey(pool) ? executorServices.get(pool).getActiveCount() : 0;
}
public void onClose()
{
inTermination = true;
executorServices.values().forEach(ThreadPoolExecutor::shutdown);
for (ScriptHost uh : userHosts.values()) uh.onClose();
for (final ScriptHost uh : userHosts.values())
{
uh.onClose();
}
if (taskCount() > 0)
{
executorServices.values().forEach(e -> {
ExecutorService stopper = Executors.newSingleThreadExecutor();
stopper.submit( () -> {
try {
final ExecutorService stopper = Executors.newSingleThreadExecutor();
stopper.submit(() -> {
try
{
// Wait a while for existing tasks to terminate
if (!e.awaitTermination(1500, TimeUnit.MILLISECONDS)) {
if (!e.awaitTermination(1500, TimeUnit.MILLISECONDS))
{
e.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!e.awaitTermination(1500, TimeUnit.MILLISECONDS))
{
CarpetScriptServer.LOG.error("Failed to stop app's thread");
}
}
} catch (InterruptedException ie) {
}
catch (final InterruptedException ie)
{
// (Re-)Cancel if current thread also interrupted
e.shutdownNow();
// Preserve interrupt status
@@ -421,12 +510,15 @@ public abstract class ScriptHost
}
}
public void setPerPlayer(boolean isPerUser)
public void setPerPlayer(final boolean isPerUser)
{
perUser = isPerUser;
}
public boolean isPerUser() {return perUser;}
public boolean isPerUser()
{
return perUser;
}
public Set<String> getUserList()
{
@@ -436,21 +528,24 @@ public abstract class ScriptHost
public void resetErrorSnooper()
{
errorSnooper=null;
errorSnooper = null;
}
public static final Logger DEPRECATION_LOG = LoggerFactory.getLogger("Scarpet Deprecation Warnings");
public boolean issueDeprecation(String feature)
public boolean issueDeprecation(final String feature)
{
if (deprecations.contains(feature)) return false;
if (deprecations.contains(feature))
{
return false;
}
deprecations.add(feature);
DEPRECATION_LOG.warn("'"+feature+"' is deprecated and soon will be removed. Please consult the docs for their replacement");
DEPRECATION_LOG.warn("'" + feature + "' is deprecated and soon will be removed. Please consult the docs for their replacement");
return true;
}
public ScriptServer scriptServer()
{
return scriptServer;
}
public ScriptServer scriptServer()
{
return scriptServer;
}
}