improved explain, still hidden
This commit is contained in:
1 parent
41a7d8df46
commit
156fc7eb21
10 files changed
+244
-112
No files matched your search
@@ -25,6 +25,7 @@ import java.util.function.Predicate;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import carpet.script.Expression;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
@@ -331,7 +332,7 @@ public class SettingsManager {
|
|||||||
{
|
{
|
||||||
if (RuleHelper.getBooleanValue(rule) || (rule.type() == String.class && !rule.value().equals("false")))
|
if (RuleHelper.getBooleanValue(rule) || (rule.type() == String.class && !rule.value().equals("false")))
|
||||||
{
|
{
|
||||||
CarpetServer.scriptServer.addScriptHost(source, rule.scarpetApp, s -> CommandHelper.canUseCommand(s, rule.value()), false, false, true, null);
|
CarpetServer.scriptServer.addScriptHost(source, rule.scarpetApp, s -> CommandHelper.canUseCommand(s, rule.value()), false, false, true, null, Expression.LoadOverride.DEFAULT);
|
||||||
} else {
|
} else {
|
||||||
CarpetServer.scriptServer.removeScriptHost(source, rule.scarpetApp, false, true);
|
CarpetServer.scriptServer.removeScriptHost(source, rule.scarpetApp, false, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import carpet.script.value.Value;
|
|||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -93,8 +94,9 @@ public class CarpetExpression
|
|||||||
return scriptServer.events.handleEvents.getWhileDisabled(() -> this.expr.executeAndEvaluate(
|
return scriptServer.events.handleEvents.getWhileDisabled(() -> this.expr.executeAndEvaluate(
|
||||||
context,
|
context,
|
||||||
Vanilla.ScriptServer_scriptOptimizations(scriptServer.server),
|
Vanilla.ScriptServer_scriptOptimizations(scriptServer.server),
|
||||||
|
host.loadOverrides,
|
||||||
Vanilla.ScriptServer_scriptDebugging(scriptServer.server) ? CarpetScriptServer.LOG::info : null
|
Vanilla.ScriptServer_scriptDebugging(scriptServer.server) ? CarpetScriptServer.LOG::info : null
|
||||||
).getBoolean());
|
).getLeft().getBoolean());
|
||||||
}
|
}
|
||||||
catch (ExpressionException e)
|
catch (ExpressionException e)
|
||||||
{
|
{
|
||||||
@@ -110,7 +112,7 @@ public class CarpetExpression
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Value scriptRunCommand(ScriptHost host, BlockPos pos)
|
public Pair<Value, Expression.ExpressionNode> scriptRunCommand(ScriptHost host, BlockPos pos)
|
||||||
{
|
{
|
||||||
CarpetScriptServer scriptServer = (CarpetScriptServer) host.scriptServer();
|
CarpetScriptServer scriptServer = (CarpetScriptServer) host.scriptServer();
|
||||||
if (scriptServer.stopAll)
|
if (scriptServer.stopAll)
|
||||||
@@ -137,6 +139,7 @@ public class CarpetExpression
|
|||||||
return scriptServer.events.handleEvents.getWhileDisabled(() -> this.expr.executeAndEvaluate(
|
return scriptServer.events.handleEvents.getWhileDisabled(() -> this.expr.executeAndEvaluate(
|
||||||
context,
|
context,
|
||||||
Vanilla.ScriptServer_scriptOptimizations(scriptServer.server),
|
Vanilla.ScriptServer_scriptOptimizations(scriptServer.server),
|
||||||
|
host.loadOverrides,
|
||||||
Vanilla.ScriptServer_scriptDebugging(scriptServer.server) ? CarpetScriptServer.LOG::info : null
|
Vanilla.ScriptServer_scriptDebugging(scriptServer.server) ? CarpetScriptServer.LOG::info : null
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -154,7 +157,7 @@ public class CarpetExpression
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Token> explain(ScriptHost host, @Nullable String method, @Nullable String style, BlockPos pos)
|
public List<Token> explain(ScriptHost host, @Nullable String code, @Nullable String method, @Nullable String style, BlockPos pos)
|
||||||
{
|
{
|
||||||
CarpetScriptServer scriptServer = (CarpetScriptServer) host.scriptServer();
|
CarpetScriptServer scriptServer = (CarpetScriptServer) host.scriptServer();
|
||||||
try
|
try
|
||||||
@@ -174,7 +177,7 @@ public class CarpetExpression
|
|||||||
Value playerValue = new EntityValue(e).bindTo("p");
|
Value playerValue = new EntityValue(e).bindTo("p");
|
||||||
context.with("p", (cc, tt) -> playerValue);
|
context.with("p", (cc, tt) -> playerValue);
|
||||||
}
|
}
|
||||||
return scriptServer.events.handleEvents.getWhileDisabled(() -> this.expr.explain(context, method, style));
|
return scriptServer.events.handleEvents.getWhileDisabled(() -> this.expr.explain(context, code, method, style));
|
||||||
}
|
}
|
||||||
catch (ExpressionException e)
|
catch (ExpressionException e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -78,9 +78,9 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
public AppStoreManager.StoreNode storeSource;
|
public AppStoreManager.StoreNode storeSource;
|
||||||
boolean hasCommand;
|
boolean hasCommand;
|
||||||
|
|
||||||
private CarpetScriptHost(CarpetScriptServer server, @Nullable Module code, boolean perUser, ScriptHost parent, Map<Value, Value> config, Map<String, CommandArgument> argTypes, Predicate<CommandSourceStack> commandValidator, boolean isRuleApp)
|
private CarpetScriptHost(CarpetScriptServer server, @Nullable Module code, boolean perUser, ScriptHost parent, Map<Value, Value> config, Map<String, CommandArgument> argTypes, Predicate<CommandSourceStack> commandValidator, boolean isRuleApp, Expression.LoadOverride override)
|
||||||
{
|
{
|
||||||
super(code, server, perUser, parent);
|
super(code, server, perUser, parent, override);
|
||||||
this.saveTimeout = 0;
|
this.saveTimeout = 0;
|
||||||
persistenceRequired = true;
|
persistenceRequired = true;
|
||||||
if (parent == null && code != null) // app, not a global host
|
if (parent == null && code != null) // app, not a global host
|
||||||
@@ -99,9 +99,9 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
storeSource = null;
|
storeSource = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CarpetScriptHost create(CarpetScriptServer scriptServer, @Nullable Module module, boolean perPlayer, CommandSourceStack source, Predicate<CommandSourceStack> commandValidator, boolean isRuleApp, AppStoreManager.StoreNode storeSource)
|
public static CarpetScriptHost create(CarpetScriptServer scriptServer, @Nullable Module module, boolean perPlayer, CommandSourceStack source, Predicate<CommandSourceStack> commandValidator, boolean isRuleApp, AppStoreManager.StoreNode storeSource, Expression.LoadOverride override)
|
||||||
{
|
{
|
||||||
CarpetScriptHost host = new CarpetScriptHost(scriptServer, module, perPlayer, null, Collections.emptyMap(), new HashMap<>(), commandValidator, isRuleApp);
|
CarpetScriptHost host = new CarpetScriptHost(scriptServer, module, perPlayer, null, Collections.emptyMap(), new HashMap<>(), commandValidator, isRuleApp, override);
|
||||||
// parse code and convert to expression
|
// parse code and convert to expression
|
||||||
if (module != null)
|
if (module != null)
|
||||||
{
|
{
|
||||||
@@ -111,7 +111,7 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
CarpetExpression ex = new CarpetExpression(host.main, module.code(), source, new BlockPos(0, 0, 0));
|
CarpetExpression ex = new CarpetExpression(host.main, module.code(), source, new BlockPos(0, 0, 0));
|
||||||
ex.getExpr().asATextSource();
|
ex.getExpr().asATextSource();
|
||||||
host.storeSource = storeSource;
|
host.storeSource = storeSource;
|
||||||
ex.scriptRunCommand(host, BlockPos.containing(source.getPosition()));
|
host.root = ex.scriptRunCommand(host, BlockPos.containing(source.getPosition())).getRight();
|
||||||
}
|
}
|
||||||
catch (CarpetExpressionException e)
|
catch (CarpetExpressionException e)
|
||||||
{
|
{
|
||||||
@@ -132,6 +132,10 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
host.storeSource = null;
|
host.storeSource = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
host.root = Expression.ExpressionNode.ofConstant(Value.NULL, new Token());
|
||||||
|
}
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +257,7 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
@Override
|
@Override
|
||||||
protected ScriptHost duplicate()
|
protected ScriptHost duplicate()
|
||||||
{
|
{
|
||||||
return new CarpetScriptHost(scriptServer(), main, false, this, appConfig, appArgTypes, commandValidator, isRuleApp);
|
return new CarpetScriptHost(scriptServer(), main, false, this, appConfig, appArgTypes, commandValidator, isRuleApp, loadOverrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ public class CarpetScriptServer extends ScriptServer
|
|||||||
tickStart = 0L;
|
tickStart = 0L;
|
||||||
stopAll = false;
|
stopAll = false;
|
||||||
holyMoly = server.getCommands().getDispatcher().getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toSet());
|
holyMoly = server.getCommands().getDispatcher().getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toSet());
|
||||||
globalHost = CarpetScriptHost.create(this, null, false, null, p -> true, false, null);
|
globalHost = CarpetScriptHost.create(this, null, false, null, p -> true, false, null, Expression.LoadOverride.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeForWorld()
|
public void initializeForWorld()
|
||||||
@@ -130,7 +130,7 @@ public class CarpetScriptServer extends ScriptServer
|
|||||||
{
|
{
|
||||||
for (String moduleName : listAvailableModules(false))
|
for (String moduleName : listAvailableModules(false))
|
||||||
{
|
{
|
||||||
addScriptHost(server.createCommandSourceStack(), moduleName, null, true, true, false, null);
|
addScriptHost(server.createCommandSourceStack(), moduleName, null, true, true, false, null, Expression.LoadOverride.DEFAULT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CarpetEventServer.Event.START.onTick(server);
|
CarpetEventServer.Event.START.onTick(server);
|
||||||
@@ -232,8 +232,8 @@ public class CarpetScriptServer extends ScriptServer
|
|||||||
return name == null ? globalHost : modules.get(name);
|
return name == null ? globalHost : modules.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addScriptHost(CommandSourceStack source, String name, @Nullable Predicate<CommandSourceStack> commandValidator,
|
public int addScriptHost(CommandSourceStack source, String name, @Nullable Predicate<CommandSourceStack> commandValidator,
|
||||||
boolean perPlayer, boolean autoload, boolean isRuleApp, AppStoreManager.StoreNode installer)
|
boolean perPlayer, boolean autoload, boolean isRuleApp, AppStoreManager.StoreNode installer, Expression.LoadOverride override)
|
||||||
{
|
{
|
||||||
Runnable token = Carpet.startProfilerSection("Scarpet load");
|
Runnable token = Carpet.startProfilerSection("Scarpet load");
|
||||||
if (commandValidator == null)
|
if (commandValidator == null)
|
||||||
@@ -247,7 +247,7 @@ public class CarpetScriptServer extends ScriptServer
|
|||||||
{
|
{
|
||||||
if (isRuleApp)
|
if (isRuleApp)
|
||||||
{
|
{
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
removeScriptHost(source, name, false, isRuleApp);
|
removeScriptHost(source, name, false, isRuleApp);
|
||||||
reload = true;
|
reload = true;
|
||||||
@@ -256,17 +256,17 @@ public class CarpetScriptServer extends ScriptServer
|
|||||||
if (module == null)
|
if (module == null)
|
||||||
{
|
{
|
||||||
Carpet.Messenger_message(source, "r Failed to add " + name + " app: App not found");
|
Carpet.Messenger_message(source, "r Failed to add " + name + " app: App not found");
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
CarpetScriptHost newHost;
|
CarpetScriptHost newHost;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
newHost = CarpetScriptHost.create(this, module, perPlayer, source, commandValidator, isRuleApp, installer);
|
newHost = CarpetScriptHost.create(this, module, perPlayer, source, commandValidator, isRuleApp, installer, override);
|
||||||
}
|
}
|
||||||
catch (LoadException e)
|
catch (LoadException e)
|
||||||
{
|
{
|
||||||
Carpet.Messenger_message(source, "r Failed to add " + name + " app" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
|
Carpet.Messenger_message(source, "r Failed to add " + name + " app" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
modules.put(name, newHost);
|
modules.put(name, newHost);
|
||||||
@@ -278,7 +278,7 @@ public class CarpetScriptServer extends ScriptServer
|
|||||||
if (autoload && !newHost.persistenceRequired)
|
if (autoload && !newHost.persistenceRequired)
|
||||||
{
|
{
|
||||||
removeScriptHost(source, name, false, false);
|
removeScriptHost(source, name, false, false);
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
String action = (installer != null) ? (reload ? "reinstalled" : "installed") : (reload ? "reloaded" : "loaded");
|
String action = (installer != null) ? (reload ? "reinstalled" : "installed") : (reload ? "reloaded" : "loaded");
|
||||||
|
|
||||||
@@ -292,7 +292,7 @@ public class CarpetScriptServer extends ScriptServer
|
|||||||
if (isCommandAdded == null) // error should be dispatched
|
if (isCommandAdded == null) // error should be dispatched
|
||||||
{
|
{
|
||||||
removeScriptHost(source, name, false, isRuleApp);
|
removeScriptHost(source, name, false, isRuleApp);
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (isCommandAdded)
|
else if (isCommandAdded)
|
||||||
{
|
{
|
||||||
@@ -330,7 +330,7 @@ public class CarpetScriptServer extends ScriptServer
|
|||||||
token.run();
|
token.run();
|
||||||
long end = System.nanoTime();
|
long end = System.nanoTime();
|
||||||
LOG.info("App " + name + " loaded in " + (end - start) / 1000000 + " ms");
|
LOG.info("App " + name + " loaded in " + (end - start) / 1000000 + " ms");
|
||||||
return true;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInvalidCommandRoot(String appName)
|
public boolean isInvalidCommandRoot(String appName)
|
||||||
@@ -458,11 +458,11 @@ public class CarpetScriptServer extends ScriptServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private record TransferData(boolean perUser, Predicate<CommandSourceStack> commandValidator,
|
private record TransferData(boolean perUser, Predicate<CommandSourceStack> commandValidator,
|
||||||
boolean isRuleApp)
|
boolean isRuleApp, Expression.LoadOverride override)
|
||||||
{
|
{
|
||||||
private TransferData(CarpetScriptHost host)
|
private TransferData(CarpetScriptHost host)
|
||||||
{
|
{
|
||||||
this(host.perUser, host.commandValidator, host.isRuleApp);
|
this(host.perUser, host.commandValidator, host.isRuleApp, host.loadOverrides);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +473,7 @@ public class CarpetScriptServer extends ScriptServer
|
|||||||
apps.keySet().forEach(s -> removeScriptHost(server.createCommandSourceStack(), s, false, false));
|
apps.keySet().forEach(s -> removeScriptHost(server.createCommandSourceStack(), s, false, false));
|
||||||
CarpetEventServer.Event.clearAllBuiltinEvents();
|
CarpetEventServer.Event.clearAllBuiltinEvents();
|
||||||
init();
|
init();
|
||||||
apps.forEach((s, data) -> addScriptHost(server.createCommandSourceStack(), s, data.commandValidator, data.perUser, false, data.isRuleApp, null));
|
apps.forEach((s, data) -> addScriptHost(server.createCommandSourceStack(), s, data.commandValidator, data.perUser, false, data.isRuleApp, null, data.override));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reAddCommands()
|
public void reAddCommands()
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
|
|||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
@@ -95,6 +96,9 @@ public class Expression
|
|||||||
@Nullable
|
@Nullable
|
||||||
private LazyValue ast = null;
|
private LazyValue ast = null;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ExpressionNode root = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* script specific operatos and built-in functions
|
* script specific operatos and built-in functions
|
||||||
*/
|
*/
|
||||||
@@ -1070,7 +1074,7 @@ public class Expression
|
|||||||
*/
|
*/
|
||||||
public Expression(String expression)
|
public Expression(String expression)
|
||||||
{
|
{
|
||||||
this.expression = expression.stripTrailing().replaceAll("\\r\\n?", "\n").replaceAll("\\t", " ");
|
this.expression = stripExpression(expression);
|
||||||
Operators.apply(this);
|
Operators.apply(this);
|
||||||
ControlFlow.apply(this);
|
ControlFlow.apply(this);
|
||||||
Functions.apply(this);
|
Functions.apply(this);
|
||||||
@@ -1084,6 +1088,11 @@ public class Expression
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String stripExpression(String expression)
|
||||||
|
{
|
||||||
|
return expression.stripTrailing().replaceAll("\\r\\n?", "\n").replaceAll("\\t", " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private List<Token> shuntingYard(Context c, List<Token> tokens)
|
private List<Token> shuntingYard(Context c, List<Token> tokens)
|
||||||
{
|
{
|
||||||
@@ -1238,13 +1247,29 @@ public class Expression
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Value executeAndEvaluate(Context c, boolean optimize, @Nullable Consumer<String> logger)
|
public enum LoadOverride {
|
||||||
|
DEFAULT("clean"), CANONICAL("canonical"), OPTIMIZED("optimized"), FUNCTIONAL("functional"), FUNCTIONAL_OPTIMIZED("functional_optimized");
|
||||||
|
public String equivalent;
|
||||||
|
LoadOverride(String equivalent) {
|
||||||
|
this.equivalent = equivalent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pair<Value, ExpressionNode> executeAndEvaluate(Context c, boolean optimize, LoadOverride override, @Nullable Consumer<String> logger)
|
||||||
{
|
{
|
||||||
if (ast == null)
|
if (ast == null)
|
||||||
{
|
{
|
||||||
ast = getAST(c, optimize, logger);
|
boolean functions = false;
|
||||||
|
if (override != LoadOverride.DEFAULT) {
|
||||||
|
optimize = override == LoadOverride.OPTIMIZED || override == LoadOverride.FUNCTIONAL_OPTIMIZED;
|
||||||
|
functions = override == LoadOverride.FUNCTIONAL || override == LoadOverride.FUNCTIONAL_OPTIMIZED;
|
||||||
}
|
}
|
||||||
return evaluatePartial(() -> ast, c, Context.Type.NONE);
|
|
||||||
|
Pair<ExpressionNode, LazyValue> ret = getAST(c, optimize, functions, logger);
|
||||||
|
ast = ret.getRight();
|
||||||
|
root = ret.getLeft();
|
||||||
|
}
|
||||||
|
return Pair.of(evaluatePartial(() -> ast, c, Context.Type.NONE), root);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Value evaluatePartial(Supplier<LazyValue> exprProvider, Context c, Context.Type expectedType)
|
public Value evaluatePartial(Supplier<LazyValue> exprProvider, Context c, Context.Type expectedType)
|
||||||
@@ -1301,30 +1326,30 @@ public class Expression
|
|||||||
return new ExpressionNode(new LazyValue.Constant(val), Collections.emptyList(), token);
|
return new ExpressionNode(new LazyValue.Constant(val), Collections.emptyList(), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Token> tokensRecursive(Expression expression) {
|
public List<Token> tokensRecursive(Expression expression, List<Token> reference, Map<Pair<Integer, Integer>, List<Integer>> referencePointers){
|
||||||
List<Token> tokens = new ArrayList<>();
|
List<Token> tokens = new ArrayList<>();
|
||||||
switch (token.type) {
|
switch (token.type) {
|
||||||
case FUNCTION -> {
|
case FUNCTION -> {
|
||||||
tokens.add(token);
|
tokens.add(token);
|
||||||
tokens.add(token.morphedInto(Token.TokenType.OPEN_PAREN, "("));
|
tokens.add(findToken(token, Token.TokenType.OPEN_PAREN, "(", reference, referencePointers));
|
||||||
if (!args.isEmpty()) {
|
if (!args.isEmpty()) {
|
||||||
for (ExpressionNode arg : args) {
|
for (ExpressionNode arg : args) {
|
||||||
List<Token> argTokens = arg.tokensRecursive(expression);
|
List<Token> argTokens = arg.tokensRecursive(expression, reference, referencePointers);
|
||||||
tokens.addAll(argTokens);
|
tokens.addAll(argTokens);
|
||||||
tokens.add(argTokens.getLast().morphedInto(Token.TokenType.COMMA, ",").disguiseAs(", ", null));
|
tokens.add(findToken(argTokens.getLast(), Token.TokenType.COMMA, ",", reference, referencePointers).disguiseAs(", ", null));
|
||||||
}
|
}
|
||||||
tokens.removeLast();
|
tokens.removeLast();
|
||||||
}
|
}
|
||||||
tokens.add(tokens.getLast().morphedInto(Token.TokenType.CLOSE_PAREN, ")"));
|
tokens.add(findToken(tokens.getLast(), Token.TokenType.CLOSE_PAREN, ")", reference, referencePointers));
|
||||||
}
|
}
|
||||||
case OPERATOR -> {
|
case OPERATOR -> {
|
||||||
tokens.addAll(createOperatorArgumentTokens(expression, args.get(0)));
|
tokens.addAll(createOperatorArgumentTokens(expression, args.get(0), reference, referencePointers));
|
||||||
tokens.add(token.disguiseAs(" "+token.surface+" ", null));
|
tokens.add(token.disguiseAs(token.surface.equals(";") ? (token.surface+" ") : (" "+token.surface+" "), null));
|
||||||
tokens.addAll(createOperatorArgumentTokens(expression, args.get(1)));
|
tokens.addAll(createOperatorArgumentTokens(expression, args.get(1), reference, referencePointers));
|
||||||
}
|
}
|
||||||
case UNARY_OPERATOR -> {
|
case UNARY_OPERATOR -> {
|
||||||
tokens.add(token.disguiseAs(" "+StringUtils.chop(token.surface),null));
|
tokens.add(token.disguiseAs(" "+StringUtils.chop(token.surface),null));
|
||||||
tokens.addAll(createOperatorArgumentTokens(expression, args.get(0)));
|
tokens.addAll(createOperatorArgumentTokens(expression, args.get(0), reference, referencePointers));
|
||||||
}
|
}
|
||||||
case VARIABLE, LITERAL, HEX_LITERAL, CONSTANT -> tokens.add(token);
|
case VARIABLE, LITERAL, HEX_LITERAL, CONSTANT -> tokens.add(token);
|
||||||
case STRINGPARAM -> tokens.add(token.disguiseAs("'"+token.surface+"'", null));
|
case STRINGPARAM -> tokens.add(token.disguiseAs("'"+token.surface+"'", null));
|
||||||
@@ -1336,7 +1361,29 @@ public class Expression
|
|||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Token> createOperatorArgumentTokens(Expression expression, ExpressionNode operand) {
|
public Token findToken(Token previous, Token.TokenType type, String expectedSurface, List<Token> reference, Map<Pair<Integer, Integer>, List<Integer>> referencePointers)
|
||||||
|
{
|
||||||
|
List<Integer> indices = referencePointers.get(Pair.of(previous.lineno, previous.linepos));
|
||||||
|
if (indices == null)
|
||||||
|
{
|
||||||
|
return previous.morphedInto(type, expectedSurface);
|
||||||
|
}
|
||||||
|
for (int index : indices)
|
||||||
|
{
|
||||||
|
if (index + 1 == reference.size())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Token token = reference.get(index + 1);
|
||||||
|
if (token.type == type)
|
||||||
|
{
|
||||||
|
return token.morphedInto(type, expectedSurface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return previous.morphedInto(type, expectedSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Token> createOperatorArgumentTokens(Expression expression, ExpressionNode operand, List<Token> reference, Map<Pair<Integer, Integer>, List<Integer>> referencePointers) {
|
||||||
boolean needsBrackets = false;
|
boolean needsBrackets = false;
|
||||||
var operators = expression.operators;
|
var operators = expression.operators;
|
||||||
if (operators.containsKey(operand.token.surface) && operators.containsKey(token.surface)) {
|
if (operators.containsKey(operand.token.surface) && operators.containsKey(token.surface)) {
|
||||||
@@ -1344,15 +1391,15 @@ public class Expression
|
|||||||
needsBrackets = true;
|
needsBrackets = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<Token> argumentTokens = operand.tokensRecursive(expression);
|
List<Token> argumentTokens = operand.tokensRecursive(expression, reference, referencePointers);
|
||||||
if (!needsBrackets) {
|
if (!needsBrackets) {
|
||||||
return argumentTokens;
|
return argumentTokens;
|
||||||
}
|
}
|
||||||
List<Token> bracketed = new ArrayList<>();
|
List<Token> bracketed = new ArrayList<>();
|
||||||
bracketed.add(argumentTokens.getFirst().morphedInto(Token.TokenType.OPEN_PAREN, "("));
|
bracketed.add(findToken(argumentTokens.getFirst(), Token.TokenType.OPEN_PAREN, "(", reference, referencePointers));
|
||||||
bracketed.get(0).swapPlace(argumentTokens.getFirst());
|
bracketed.get(0).swapPlace(argumentTokens.getFirst());
|
||||||
bracketed.addAll(argumentTokens);
|
bracketed.addAll(argumentTokens);
|
||||||
bracketed.add(argumentTokens.getLast().morphedInto(Token.TokenType.CLOSE_PAREN, ")"));
|
bracketed.add(findToken(argumentTokens.getLast(), Token.TokenType.CLOSE_PAREN, ")", reference, referencePointers));
|
||||||
return bracketed;
|
return bracketed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1367,24 +1414,32 @@ public class Expression
|
|||||||
case UNARY_OPERATOR -> {
|
case UNARY_OPERATOR -> {
|
||||||
ExpressionNode node = nodeStack.pop();
|
ExpressionNode node = nodeStack.pop();
|
||||||
LazyValue result = (c, t) -> operators.get(token.surface).lazyEval(c, t, this, token, node.op, null).evalValue(c, t);
|
LazyValue result = (c, t) -> operators.get(token.surface).lazyEval(c, t, this, token, node.op, null).evalValue(c, t);
|
||||||
nodeStack.push(new ExpressionNode(result, Collections.singletonList(node), token));
|
ExpressionNode newNode = new ExpressionNode(result, Collections.singletonList(node), token);
|
||||||
|
token.node = newNode;
|
||||||
|
nodeStack.push(newNode);
|
||||||
}
|
}
|
||||||
case OPERATOR -> {
|
case OPERATOR -> {
|
||||||
ExpressionNode v1 = nodeStack.pop();
|
ExpressionNode v1 = nodeStack.pop();
|
||||||
ExpressionNode v2 = nodeStack.pop();
|
ExpressionNode v2 = nodeStack.pop();
|
||||||
LazyValue result = (c, t) -> operators.get(token.surface).lazyEval(c, t, this, token, v2.op, v1.op).evalValue(c, t);
|
LazyValue result = (c, t) -> operators.get(token.surface).lazyEval(c, t, this, token, v2.op, v1.op).evalValue(c, t);
|
||||||
nodeStack.push(new ExpressionNode(result, List.of(v2, v1), token));
|
ExpressionNode newNode = new ExpressionNode(result, List.of(v2, v1), token);
|
||||||
|
token.node = newNode;
|
||||||
|
nodeStack.push(newNode);
|
||||||
}
|
}
|
||||||
case VARIABLE -> {
|
case VARIABLE -> {
|
||||||
Value constant = getConstantFor(token.surface);
|
Value constant = getConstantFor(token.surface);
|
||||||
if (constant != null)
|
if (constant != null)
|
||||||
{
|
{
|
||||||
token.morph(Token.TokenType.CONSTANT, token.surface);
|
token.morph(Token.TokenType.CONSTANT, token.surface);
|
||||||
nodeStack.push(new ExpressionNode(LazyValue.ofConstant(constant), Collections.emptyList(), token));
|
ExpressionNode newNode = new ExpressionNode(LazyValue.ofConstant(constant), Collections.emptyList(), token);
|
||||||
|
token.node = newNode;
|
||||||
|
nodeStack.push(newNode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nodeStack.push(new ExpressionNode(((c, t) -> getOrSetAnyVariable(c, token.surface).evalValue(c, t)), Collections.emptyList(), token));
|
ExpressionNode newNode = new ExpressionNode(((c, t) -> getOrSetAnyVariable(c, token.surface).evalValue(c, t)), Collections.emptyList(), token);
|
||||||
|
token.node = newNode;
|
||||||
|
nodeStack.push(newNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case FUNCTION -> {
|
case FUNCTION -> {
|
||||||
@@ -1419,12 +1474,17 @@ public class Expression
|
|||||||
nodeStack.pop();
|
nodeStack.pop();
|
||||||
}
|
}
|
||||||
List<LazyValue> params = p.stream().map(n -> n.op).collect(Collectors.toList());
|
List<LazyValue> params = p.stream().map(n -> n.op).collect(Collectors.toList());
|
||||||
nodeStack.push(new ExpressionNode(
|
ExpressionNode newNode = new ExpressionNode(
|
||||||
(c, t) -> f.lazyEval(c, t, this, token, params).evalValue(c, t),
|
(c, t) -> f.lazyEval(c, t, this, token, params).evalValue(c, t),
|
||||||
p, token
|
p, token
|
||||||
));
|
);
|
||||||
|
token.node = newNode;
|
||||||
|
nodeStack.push(newNode);
|
||||||
|
}
|
||||||
|
case OPEN_PAREN -> {
|
||||||
|
token.node = ExpressionNode.PARAMS_START;
|
||||||
|
nodeStack.push(ExpressionNode.PARAMS_START);
|
||||||
}
|
}
|
||||||
case OPEN_PAREN -> nodeStack.push(ExpressionNode.PARAMS_START);
|
|
||||||
case LITERAL -> {
|
case LITERAL -> {
|
||||||
Value number;
|
Value number;
|
||||||
try
|
try
|
||||||
@@ -1436,11 +1496,15 @@ public class Expression
|
|||||||
throw new ExpressionException(context, this, token, "Not a number");
|
throw new ExpressionException(context, this, token, "Not a number");
|
||||||
}
|
}
|
||||||
//token.morph(Token.TokenType.CONSTANT, token.surface);
|
//token.morph(Token.TokenType.CONSTANT, token.surface);
|
||||||
nodeStack.push(ExpressionNode.ofConstant(number, token));
|
ExpressionNode newNode = ExpressionNode.ofConstant(number, token);
|
||||||
|
token.node = newNode;
|
||||||
|
nodeStack.push(newNode);
|
||||||
}
|
}
|
||||||
case STRINGPARAM -> {
|
case STRINGPARAM -> {
|
||||||
//token.morph(Token.TokenType.CONSTANT, token.surface);
|
//token.morph(Token.TokenType.CONSTANT, token.surface);
|
||||||
nodeStack.push(ExpressionNode.ofConstant(new StringValue(token.surface), token));
|
ExpressionNode newNode = ExpressionNode.ofConstant(new StringValue(token.surface), token);
|
||||||
|
token.node = newNode;
|
||||||
|
nodeStack.push(newNode);
|
||||||
}
|
}
|
||||||
case HEX_LITERAL -> {
|
case HEX_LITERAL -> {
|
||||||
Value hexNumber;
|
Value hexNumber;
|
||||||
@@ -1453,7 +1517,9 @@ public class Expression
|
|||||||
throw new ExpressionException(context, this, token, "Not a number");
|
throw new ExpressionException(context, this, token, "Not a number");
|
||||||
}
|
}
|
||||||
//token.morph(Token.TokenType.CONSTANT, token.surface);
|
//token.morph(Token.TokenType.CONSTANT, token.surface);
|
||||||
nodeStack.push(ExpressionNode.ofConstant(hexNumber, token));
|
ExpressionNode newNode = ExpressionNode.ofConstant(hexNumber, token);
|
||||||
|
token.node = newNode;
|
||||||
|
nodeStack.push(newNode);
|
||||||
}
|
}
|
||||||
default -> throw new ExpressionException(context, this, token, "Unexpected token '" + token.surface + "'");
|
default -> throw new ExpressionException(context, this, token, "Unexpected token '" + token.surface + "'");
|
||||||
}
|
}
|
||||||
@@ -1461,7 +1527,7 @@ public class Expression
|
|||||||
return nodeStack.pop();
|
return nodeStack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private LazyValue getAST(Context context, boolean optimize, @Nullable Consumer<String> logger)
|
private Pair<ExpressionNode, LazyValue> getAST(Context context, boolean optimize, boolean functional, @Nullable Consumer<String> logger)
|
||||||
{
|
{
|
||||||
Tokenizer tokenizer = new Tokenizer(context, this, expression, allowComments, allowNewlineSubstitutions);
|
Tokenizer tokenizer = new Tokenizer(context, this, expression, allowComments, allowNewlineSubstitutions);
|
||||||
// stripping lousy but acceptable semicolons
|
// stripping lousy but acceptable semicolons
|
||||||
@@ -1470,19 +1536,22 @@ public class Expression
|
|||||||
List<Token> rpn = shuntingYard(context, cleanedTokens);
|
List<Token> rpn = shuntingYard(context, cleanedTokens);
|
||||||
validate(context, rpn);
|
validate(context, rpn);
|
||||||
ExpressionNode root = RPNToParseTree(rpn, context);
|
ExpressionNode root = RPNToParseTree(rpn, context);
|
||||||
if (!optimize)
|
if (!optimize && !functional)
|
||||||
{
|
{
|
||||||
return root.op;
|
return Pair.of(root, root.op);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context optimizeOnlyContext = new Context.ContextForErrorReporting(context);
|
Context optimizeOnlyContext = new Context.ContextForErrorReporting(context);
|
||||||
// flipping to full functional representation makes it little underperforming, might be related
|
// flipping to full functional representation makes it little underperforming, might be related
|
||||||
// to the fact that operators are running from a bigger pool or function execution is slower
|
// to the fact that operators are running from a bigger pool or function execution is slower
|
||||||
optimizeTree(root, optimizeOnlyContext, logger, false);
|
optimizeTree(root, optimizeOnlyContext, logger, optimize, functional);
|
||||||
return extractOp(optimizeOnlyContext, root, Context.Type.NONE);
|
if (!optimize) {
|
||||||
|
return Pair.of(root, root.op);
|
||||||
|
}
|
||||||
|
return Pair.of(root, extractOp(optimizeOnlyContext, root, Context.Type.NONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void optimizeTree(ExpressionNode root, Context optimizeOnlyContext, @Nullable Consumer<String> logger, boolean toFunctional) {
|
private void optimizeTree(ExpressionNode root, Context optimizeOnlyContext, @Nullable Consumer<String> logger, boolean optimize, boolean toFunctional) {
|
||||||
if (logger != null)
|
if (logger != null)
|
||||||
{
|
{
|
||||||
logger.accept("Input code size for " + getModuleName() + ": " + treeSize(root) + " nodes, " + treeDepth(root) + " deep");
|
logger.accept("Input code size for " + getModuleName() + ": " + treeSize(root) + " nodes, " + treeDepth(root) + " deep");
|
||||||
@@ -1503,7 +1572,7 @@ public class Expression
|
|||||||
prevTreeSize = treeSize(root);
|
prevTreeSize = treeSize(root);
|
||||||
prevTreeDepth = treeDepth(root);
|
prevTreeDepth = treeDepth(root);
|
||||||
}
|
}
|
||||||
boolean optimized = compactTree(root, Context.Type.NONE, 0, logger, toFunctional);
|
boolean optimized = compactTree(root, Context.Type.NONE, 0, logger, optimize, toFunctional);
|
||||||
if (!optimized)
|
if (!optimized)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@@ -1514,7 +1583,7 @@ public class Expression
|
|||||||
logger.accept("Compacted from " + prevTreeSize + " nodes, " + prevTreeDepth + " code depth to " + treeSize(root) + " nodes, " + treeDepth(root) + " code depth");
|
logger.accept("Compacted from " + prevTreeSize + " nodes, " + prevTreeDepth + " code depth to " + treeSize(root) + " nodes, " + treeDepth(root) + " code depth");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (true)
|
while (optimize)
|
||||||
{
|
{
|
||||||
if (logger != null)
|
if (logger != null)
|
||||||
{
|
{
|
||||||
@@ -1535,10 +1604,48 @@ public class Expression
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Token> explain(Context context, @Nullable String method, @Nullable String style)
|
public List<Token> explain(Context context, @Nullable String code, @Nullable String method, @Nullable String style)
|
||||||
{
|
{
|
||||||
|
if (code == null)
|
||||||
|
{
|
||||||
|
ExpressionNode node;
|
||||||
|
if (method != null)
|
||||||
|
{
|
||||||
|
FunctionValue function = context.host.getFunction(method);
|
||||||
|
if (function == null) {
|
||||||
|
throw new ExpressionException(context, this, "Unknown function " + method);
|
||||||
|
}
|
||||||
|
node = function.getToken().node;
|
||||||
|
if (node == null) {
|
||||||
|
throw new ExpressionException(context, this, "Function " + method + " is not a compiled function");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
node = context.host.root;
|
||||||
|
}
|
||||||
|
if (node == null || node.token.type == null) {
|
||||||
|
throw new ExpressionException(context, this, "No code to explain");
|
||||||
|
}
|
||||||
|
|
||||||
|
// grab source reference
|
||||||
|
Tokenizer tokenizer = new Tokenizer(context, this, context.host.main == null ? "" : stripExpression(context.host.main.code()) , true, true);
|
||||||
|
List<Token> input = tokenizer.parseTokens();
|
||||||
|
List<Token> cleanedTokens = Tokenizer.postProcess(input);
|
||||||
|
|
||||||
|
Map<Pair<Integer, Integer>, List<Integer>> tokenPointers = new HashMap<>();
|
||||||
|
for (int i = 0; i < cleanedTokens.size(); i++) {
|
||||||
|
Token token = cleanedTokens.get(i);
|
||||||
|
tokenPointers.computeIfAbsent(Pair.of(token.lineno, token.linepos), k -> new ArrayList<>()).add(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.tokensRecursive(this, cleanedTokens, tokenPointers);
|
||||||
|
}
|
||||||
|
if (style == null) {
|
||||||
|
style = context.host.loadOverrides.equivalent;
|
||||||
|
}
|
||||||
|
|
||||||
//todo convert to explain
|
//todo convert to explain
|
||||||
Tokenizer tokenizer = new Tokenizer(context, this, expression, true, true);
|
Tokenizer tokenizer = new Tokenizer(context, this, stripExpression(code), true, true);
|
||||||
// stripping lousy but acceptable semicolons
|
// stripping lousy but acceptable semicolons
|
||||||
List<Token> input = tokenizer.parseTokens();
|
List<Token> input = tokenizer.parseTokens();
|
||||||
if (style.equalsIgnoreCase("raw")) {
|
if (style.equalsIgnoreCase("raw")) {
|
||||||
@@ -1552,15 +1659,22 @@ public class Expression
|
|||||||
List<Token> rpn = shuntingYard(context, cleanedTokens);
|
List<Token> rpn = shuntingYard(context, cleanedTokens);
|
||||||
validate(context, rpn);
|
validate(context, rpn);
|
||||||
ExpressionNode root = RPNToParseTree(rpn, context);
|
ExpressionNode root = RPNToParseTree(rpn, context);
|
||||||
List<Token> parsedTokens = root.tokensRecursive(this);
|
|
||||||
|
Map<Pair<Integer, Integer>, List<Integer>> tokenPointers = new HashMap<>();
|
||||||
|
for (int i = 0; i < cleanedTokens.size(); i++) {
|
||||||
|
Token token = cleanedTokens.get(i);
|
||||||
|
tokenPointers.computeIfAbsent(Pair.of(token.lineno, token.linepos), k -> new ArrayList<>()).add(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Token> parsedTokens = root.tokensRecursive(this, cleanedTokens, tokenPointers);
|
||||||
if (style.equalsIgnoreCase("canonical")) {
|
if (style.equalsIgnoreCase("canonical")) {
|
||||||
return parsedTokens;
|
return parsedTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context optimizeOnlyContext = new Context.ContextForErrorReporting(context);
|
Context optimizeOnlyContext = new Context.ContextForErrorReporting(context);
|
||||||
// pure functional
|
// pure functional
|
||||||
optimizeTree(root, optimizeOnlyContext, null, style.equalsIgnoreCase("functional"));
|
optimizeTree(root, optimizeOnlyContext, null, style.contains("optimized"), style.contains("functional"));
|
||||||
List<Token> compileTimeOptimized = root.tokensRecursive(this);
|
List<Token> compileTimeOptimized = root.tokensRecursive(this, cleanedTokens, tokenPointers);
|
||||||
|
|
||||||
return compileTimeOptimized;
|
return compileTimeOptimized;
|
||||||
}
|
}
|
||||||
@@ -1576,7 +1690,7 @@ public class Expression
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean compactTree(ExpressionNode node, Context.Type expectedType, int indent, @Nullable Consumer<String> logger, boolean toFunctional)
|
private boolean compactTree(ExpressionNode node, Context.Type expectedType, int indent, @Nullable Consumer<String> logger, boolean optimize, boolean toFunctional)
|
||||||
{
|
{
|
||||||
// ctx is just to report errors, not values evaluation
|
// ctx is just to report errors, not values evaluation
|
||||||
boolean optimized = false;
|
boolean optimized = false;
|
||||||
@@ -1596,13 +1710,13 @@ public class Expression
|
|||||||
Context.Type requestedType = operation.staticType(expectedType);
|
Context.Type requestedType = operation.staticType(expectedType);
|
||||||
for (ExpressionNode arg : node.args)
|
for (ExpressionNode arg : node.args)
|
||||||
{
|
{
|
||||||
if (compactTree(arg, requestedType, indent + 1, logger, toFunctional))
|
if (compactTree(arg, requestedType, indent + 1, logger, optimize, toFunctional))
|
||||||
{
|
{
|
||||||
optimized = true;
|
optimized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expectedType != Context.Type.MAPDEF && symbol.equals("->") && node.args.size() == 2)
|
if (optimize && expectedType != Context.Type.MAPDEF && (symbol.equals("->") || symbol.equals("define") ) && node.args.size() == 2)
|
||||||
{
|
{
|
||||||
String rop = node.args.get(1).token.surface;
|
String rop = node.args.get(1).token.surface;
|
||||||
ExpressionNode returnNode = null;
|
ExpressionNode returnNode = null;
|
||||||
@@ -1648,7 +1762,7 @@ public class Expression
|
|||||||
{
|
{
|
||||||
String operator = pair.getKey();
|
String operator = pair.getKey();
|
||||||
String function = pair.getValue();
|
String function = pair.getValue();
|
||||||
if ((symbol.equals(operator) || symbol.equals(function)) && !node.args.isEmpty())
|
if (optimize && (symbol.equals(operator) || symbol.equals(function)) && !node.args.isEmpty())
|
||||||
{
|
{
|
||||||
boolean leftOptimizable = operators.get(operator).isLeftAssoc();
|
boolean leftOptimizable = operators.get(operator).isLeftAssoc();
|
||||||
ExpressionNode optimizedChild = node.args.get(leftOptimizable ? 0 : (node.args.size() - 1));
|
ExpressionNode optimizedChild = node.args.get(leftOptimizable ? 0 : (node.args.size() - 1));
|
||||||
|
|||||||
@@ -294,18 +294,18 @@ public class ScriptCommand
|
|||||||
LiteralArgumentBuilder<CommandSourceStack> a = literal("load").requires(Vanilla::ServerPlayer_canScriptACE).
|
LiteralArgumentBuilder<CommandSourceStack> a = literal("load").requires(Vanilla::ServerPlayer_canScriptACE).
|
||||||
then(argument("app", StringArgumentType.word()).
|
then(argument("app", StringArgumentType.word()).
|
||||||
suggests((cc, bb) -> suggest(ss(cc).listAvailableModules(true), bb)).
|
suggests((cc, bb) -> suggest(ss(cc).listAvailableModules(true), bb)).
|
||||||
executes((cc) ->
|
executes((cc) -> ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, true, false, false, null, Expression.LoadOverride.DEFAULT)).
|
||||||
{
|
//then(literal("canonical").executes((cc) -> ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, true, false, false, null, Expression.LoadOverride.CANONICAL))).
|
||||||
boolean success = ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, true, false, false, null);
|
//then(literal("optimized").executes((cc) -> ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, true, false, false, null, Expression.LoadOverride.OPTIMIZED))).
|
||||||
return success ? 1 : 0;
|
//then(literal("functional").executes((cc) -> ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, true, false, false, null, Expression.LoadOverride.FUNCTIONAL))).
|
||||||
}).
|
//then(literal("functional_optimized").executes((cc) -> ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, true, false, false, null, Expression.LoadOverride.FUNCTIONAL_OPTIMIZED))).
|
||||||
then(literal("global").
|
then(literal("global").
|
||||||
executes((cc) ->
|
executes((cc) -> ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, false, false, false, null, Expression.LoadOverride.DEFAULT))
|
||||||
{
|
//.
|
||||||
boolean success = ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, false, false, false, null);
|
//then(literal("canonical").executes((cc) -> ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, false, false, false, null, Expression.LoadOverride.CANONICAL))).
|
||||||
return success ? 1 : 0;
|
//then(literal("optimized").executes((cc) -> ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, false, false, false, null, Expression.LoadOverride.OPTIMIZED))).
|
||||||
}
|
//then(literal("functional").executes((cc) -> ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, false, false, false, null, Expression.LoadOverride.FUNCTIONAL))).
|
||||||
)
|
//then(literal("functional_optimized").executes((cc) -> ss(cc).addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, false, false, false, null, Expression.LoadOverride.FUNCTIONAL_OPTIMIZED)))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
LiteralArgumentBuilder<CommandSourceStack> f = literal("unload").requires(Vanilla::ServerPlayer_canScriptACE).
|
LiteralArgumentBuilder<CommandSourceStack> f = literal("unload").requires(Vanilla::ServerPlayer_canScriptACE).
|
||||||
@@ -366,23 +366,22 @@ public class ScriptCommand
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> x = literal("explain").requires(Vanilla::ServerPlayer_canScriptACE).
|
LiteralArgumentBuilder<CommandSourceStack> x = literal("explain").requires(Vanilla::ServerPlayer_canScriptACE).
|
||||||
then(argument("style", StringArgumentType.word()).suggests((cc, bb) -> suggest(List.of("raw", "clean", "functional", "canonical", "optimized"), bb)).
|
executes((cc) -> explain(cc, null, null, null)).
|
||||||
executes((cc) -> explain(
|
then(literal("expression").
|
||||||
cc,
|
then(argument("style", StringArgumentType.word()).suggests((cc, bb) -> suggest(List.of("raw", "clean", "functional", "canonical", "optimized", "functional_optimized"), bb)).
|
||||||
null, null, StringArgumentType.getString(cc, "style"))).
|
then(argument("expr", StringArgumentType.greedyString()).suggests(ScriptCommand::suggestCode).
|
||||||
then(literal("run").then(argument("expr", StringArgumentType.greedyString()).suggests(ScriptCommand::suggestCode).
|
executes((cc) -> explain(cc, StringArgumentType.getString(cc, "expr"), null, StringArgumentType.getString(cc, "style")))
|
||||||
executes((cc) -> explain(
|
)
|
||||||
cc,
|
)
|
||||||
StringArgumentType.getString(cc, "expr"), null, StringArgumentType.getString(cc, "style"))))).
|
).
|
||||||
then(literal("invoke").
|
then(literal("invoke").
|
||||||
then(argument("call", StringArgumentType.word()).suggests((cc, bb) -> suggest(suggestFunctionCalls(cc), bb)).
|
then(argument("call", StringArgumentType.word()).suggests((cc, bb) -> suggest(suggestFunctionCalls(cc), bb)).
|
||||||
executes((cc) -> explain(
|
executes((cc) -> explain(cc, null, StringArgumentType.getString(cc, "call"), null))
|
||||||
cc,
|
|
||||||
null,
|
|
||||||
StringArgumentType.getString(cc, "call"),
|
|
||||||
StringArgumentType.getString(cc, "style")
|
|
||||||
))
|
|
||||||
)
|
)
|
||||||
|
).
|
||||||
|
then(literal("source").
|
||||||
|
then(argument("style", StringArgumentType.word()).suggests((cc, bb) -> suggest(List.of("raw", "clean", "functional", "canonical", "optimized", "functional_optimized"), bb)).
|
||||||
|
executes((cc) -> explain(cc, null, null, StringArgumentType.getString(cc, "style")))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -559,17 +558,19 @@ public class ScriptCommand
|
|||||||
CarpetScriptHost host = getHost(context);
|
CarpetScriptHost host = getHost(context);
|
||||||
return handleCall(source, host, () -> {
|
return handleCall(source, host, () -> {
|
||||||
CarpetExpression ex = new CarpetExpression(host.main, expr, source, new BlockPos(0, 0, 0));
|
CarpetExpression ex = new CarpetExpression(host.main, expr, source, new BlockPos(0, 0, 0));
|
||||||
return ex.scriptRunCommand(host, BlockPos.containing(source.getPosition()));
|
return ex.scriptRunCommand(host, BlockPos.containing(source.getPosition())).getLeft();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int explain(CommandContext<CommandSourceStack> context, @Nullable String expr, @Nullable String method, String style) throws CommandSyntaxException
|
private static int explain(CommandContext<CommandSourceStack> context, @Nullable String expr, @Nullable String method, @Nullable String style) throws CommandSyntaxException
|
||||||
{
|
{
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
CarpetScriptHost host = getHost(context);
|
CarpetScriptHost host = getHost(context);
|
||||||
return handleCall(source, host, () -> {
|
return handleCall(source, host, () -> {
|
||||||
CarpetExpression ex = new CarpetExpression(host.main, expr == null ? ( host.main == null ? "" : host.main.code() ) : expr, source, BlockPos.ZERO);
|
// expression is irrelevant as we pass approprirate strings for parsing directly
|
||||||
List<Token> results = ex.explain(host, method, style, BlockPos.containing(source.getPosition()));
|
// we only really need access to operators and functions?
|
||||||
|
CarpetExpression ex = new CarpetExpression(host.main, "", source, BlockPos.ZERO);
|
||||||
|
List<Token> results = ex.explain(host, expr != null ? expr : (style != null? (host.main != null ? host.main.code() : "") :null), method, style, BlockPos.containing(source.getPosition()));
|
||||||
prettyPrintTokens(source, results);
|
prettyPrintTokens(source, results);
|
||||||
return NumericValue.of(results.size());
|
return NumericValue.of(results.size());
|
||||||
});
|
});
|
||||||
@@ -584,6 +585,7 @@ public class ScriptCommand
|
|||||||
}
|
}
|
||||||
List<Integer> lines = new ArrayList<>(indents.keySet());
|
List<Integer> lines = new ArrayList<>(indents.keySet());
|
||||||
Collections.sort(lines);
|
Collections.sort(lines);
|
||||||
|
int lineMax = String.valueOf(lines.getLast()).length();
|
||||||
Deque<Integer> indentsStack = new ArrayDeque<>(lines);
|
Deque<Integer> indentsStack = new ArrayDeque<>(lines);
|
||||||
|
|
||||||
List<Component> elements = new ArrayList<>();
|
List<Component> elements = new ArrayList<>();
|
||||||
@@ -609,7 +611,8 @@ public class ScriptCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
int lastPos = indents.getOrDefault(token.lineno, 0);
|
int lastPos = indents.getOrDefault(token.lineno, 0);
|
||||||
elements.add(Carpet.Messenger_compose("w " + " ".repeat(lastPos)));
|
elements.add(Carpet.Messenger_compose("fi " + " ".repeat(lineMax - String.valueOf(token.lineno).length()) + token.lineno));
|
||||||
|
elements.add(Carpet.Messenger_compose("g | " + " ".repeat(lastPos)));
|
||||||
}
|
}
|
||||||
elements.add(tokenToComponent(token));
|
elements.add(tokenToComponent(token));
|
||||||
}
|
}
|
||||||
@@ -625,7 +628,7 @@ public class ScriptCommand
|
|||||||
}
|
}
|
||||||
if (token.comment.isEmpty())
|
if (token.comment.isEmpty())
|
||||||
{
|
{
|
||||||
return Carpet.Messenger_compose(styleForToken(token) + " " + surface);
|
return Carpet.Messenger_compose(styleForToken(token) + " " + surface);//, "^gi " + String.format("%s: line %s, pos %s", token.surface, token.lineno, token.linepos));
|
||||||
}
|
}
|
||||||
return Carpet.Messenger_compose(styleForToken(token)+"u " + surface, "^gi " + token.comment);
|
return Carpet.Messenger_compose(styleForToken(token)+"u " + surface, "^gi " + token.comment);
|
||||||
}
|
}
|
||||||
@@ -642,7 +645,7 @@ public class ScriptCommand
|
|||||||
case Token.TokenType.VARIABLE -> "y";
|
case Token.TokenType.VARIABLE -> "y";
|
||||||
case Token.TokenType.STRINGPARAM -> "c";
|
case Token.TokenType.STRINGPARAM -> "c";
|
||||||
default -> // marker
|
default -> // marker
|
||||||
"f";
|
"r";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ public abstract class ScriptHost
|
|||||||
private final ScriptServer scriptServer;
|
private final ScriptServer scriptServer;
|
||||||
protected boolean inTermination = false;
|
protected boolean inTermination = false;
|
||||||
public boolean strict;
|
public boolean strict;
|
||||||
|
public Expression.LoadOverride loadOverrides;
|
||||||
|
@Nullable
|
||||||
|
public Expression.ExpressionNode root;
|
||||||
|
|
||||||
private final Set<String> deprecations = new HashSet<>();
|
private final Set<String> deprecations = new HashSet<>();
|
||||||
|
|
||||||
@@ -143,13 +146,14 @@ public abstract class ScriptHost
|
|||||||
|
|
||||||
public ErrorSnooper errorSnooper = null;
|
public ErrorSnooper errorSnooper = null;
|
||||||
|
|
||||||
protected ScriptHost(@Nullable Module code, ScriptServer scriptServer, boolean perUser, ScriptHost parent)
|
protected ScriptHost(@Nullable Module code, ScriptServer scriptServer, boolean perUser, ScriptHost parent, Expression.LoadOverride loadOverrides)
|
||||||
{
|
{
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.main = code;
|
this.main = code;
|
||||||
this.perUser = perUser;
|
this.perUser = perUser;
|
||||||
this.user = null;
|
this.user = null;
|
||||||
this.strict = false;
|
this.strict = false;
|
||||||
|
this.loadOverrides = loadOverrides;
|
||||||
this.scriptServer = scriptServer;
|
this.scriptServer = scriptServer;
|
||||||
ModuleData moduleData = new ModuleData(code);
|
ModuleData moduleData = new ModuleData(code);
|
||||||
initializeModuleGlobals(moduleData);
|
initializeModuleGlobals(moduleData);
|
||||||
@@ -231,6 +235,7 @@ public abstract class ScriptHost
|
|||||||
|
|
||||||
protected abstract void runModuleCode(Context c, Module module); // this should be shell out in the executor
|
protected abstract void runModuleCode(Context c, Module module); // this should be shell out in the executor
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public FunctionValue getFunction(String name)
|
public FunctionValue getFunction(String name)
|
||||||
{
|
{
|
||||||
return getFunction(main, name);
|
return getFunction(main, name);
|
||||||
@@ -253,6 +258,7 @@ public abstract class ScriptHost
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private FunctionValue getFunction(Module module, String name)
|
private FunctionValue getFunction(Module module, String name)
|
||||||
{
|
{
|
||||||
ModuleData local = getModuleData(module);
|
ModuleData local = getModuleData(module);
|
||||||
@@ -286,6 +292,7 @@ public abstract class ScriptHost
|
|||||||
return target.globalFunctions.get(name);
|
return target.globalFunctions.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private ModuleData findModuleDataFromFunctionImports(String name, ModuleData source, int ttl)
|
private ModuleData findModuleDataFromFunctionImports(String name, ModuleData source, int ttl)
|
||||||
{
|
{
|
||||||
if (ttl > 64)
|
if (ttl > 64)
|
||||||
@@ -460,6 +467,7 @@ public abstract class ScriptHost
|
|||||||
this.moduleData.forEach((key, value) -> host.moduleData.put(key, new ModuleData(key, value)));
|
this.moduleData.forEach((key, value) -> host.moduleData.put(key, new ModuleData(key, value)));
|
||||||
// fixing imports
|
// fixing imports
|
||||||
host.moduleData.forEach((module, data) -> data.setImportsBasedOn(host, this.moduleData.get(data.parent)));
|
host.moduleData.forEach((module, data) -> data.setImportsBasedOn(host, this.moduleData.get(data.parent)));
|
||||||
|
host.root = this.root;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void handleExpressionException(String msg, ExpressionException exc)
|
public synchronized void handleExpressionException(String msg, ExpressionException exc)
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ public class Token implements Comparable<Token> {
|
|||||||
public int ordinal = 0;
|
public int ordinal = 0;
|
||||||
public int linepos;
|
public int linepos;
|
||||||
public int lineno;
|
public int lineno;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Expression.ExpressionNode node = null;
|
||||||
|
|
||||||
public static final Token NONE = new Token();
|
public static final Token NONE = new Token();
|
||||||
|
|
||||||
public Token morphedInto(TokenType newType, String newSurface) {
|
public Token morphedInto(TokenType newType, String newSurface) {
|
||||||
@@ -44,6 +48,7 @@ public class Token implements Comparable<Token> {
|
|||||||
created.pos = pos;
|
created.pos = pos;
|
||||||
created.linepos = linepos;
|
created.linepos = linepos;
|
||||||
created.lineno = lineno;
|
created.lineno = lineno;
|
||||||
|
created.node = node;
|
||||||
created.ordinal = ordinal + 1;
|
created.ordinal = ordinal + 1;
|
||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -388,14 +388,8 @@ public class Tokenizer
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
token.type = Token.TokenType.OPERATOR;
|
token.type = Token.TokenType.OPERATOR;
|
||||||
if (token.surface.equals(";"))
|
token.disguiseAs(token.surface.equals(";") ? (token.surface + " ") : (" " + token.surface + " "), null);
|
||||||
{
|
|
||||||
token.disguiseAs(token.surface + " ", null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
token.disguiseAs(" " + token.surface + " ", null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (expression != null && context != null && previousToken != null &&
|
if (expression != null && context != null && previousToken != null &&
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package carpet.script.utils;
|
|||||||
|
|
||||||
import carpet.script.CarpetScriptHost;
|
import carpet.script.CarpetScriptHost;
|
||||||
import carpet.script.CarpetScriptServer;
|
import carpet.script.CarpetScriptServer;
|
||||||
|
import carpet.script.Expression;
|
||||||
import carpet.script.exception.InternalExpressionException;
|
import carpet.script.exception.InternalExpressionException;
|
||||||
import carpet.script.external.Carpet;
|
import carpet.script.external.Carpet;
|
||||||
import carpet.script.external.Vanilla;
|
import carpet.script.external.Vanilla;
|
||||||
@@ -283,8 +284,7 @@ public class AppStoreManager
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
boolean success = Vanilla.MinecraftServer_getScriptServer(source.getServer()).addScriptHost(source, nodeInfo.name().replaceFirst("\\.sc$", ""), null, true, false, false, nodeInfo.source());
|
return Vanilla.MinecraftServer_getScriptServer(source.getServer()).addScriptHost(source, nodeInfo.name().replaceFirst("\\.sc$", ""), null, true, false, false, nodeInfo.source(), Expression.LoadOverride.DEFAULT);
|
||||||
return success ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in new issue
Block a user