From b4fc1ebc8d41a7196af67d8f1888e0dbf40a8b3f Mon Sep 17 00:00:00 2001
From: Pieter12345
Date: Wed, 27 Sep 2023 04:03:07 +0200
Subject: [PATCH 1/3] Fix NPE if allDynamicProcs would be used
---
src/main/java/com/laytonsmith/core/compiler/FileOptions.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/laytonsmith/core/compiler/FileOptions.java b/src/main/java/com/laytonsmith/core/compiler/FileOptions.java
index 5ed2c7cc3..0f8a2280f 100644
--- a/src/main/java/com/laytonsmith/core/compiler/FileOptions.java
+++ b/src/main/java/com/laytonsmith/core/compiler/FileOptions.java
@@ -68,7 +68,7 @@ public FileOptions(Map parsedOptions) {
compilerOptions = parseEnumSet(getDefault(parsedOptions, "compileroptions", ""), CompilerOption.class);
copyright = getDefault(parsedOptions, "copyright", "").trim();
license = getDefault(parsedOptions, "license", "").trim();
- allDynamicProcs = parseBoolean(getDefault(parsedOptions, "allDynamicProcs", null));
+ allDynamicProcs = parseBoolean(getDefault(parsedOptions, "allDynamicProcs", "false"));
}
private String getDefault(Map map, String key, String defaultIfNone) {
From 9476d46be74aed7ad4e4f88f280318553be0fac4 Mon Sep 17 00:00:00 2001
From: Pieter12345
Date: Wed, 27 Sep 2023 04:39:32 +0200
Subject: [PATCH 2/3] Fix allDynamicProcs file option
---
src/main/java/com/laytonsmith/core/compiler/FileOptions.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/laytonsmith/core/compiler/FileOptions.java b/src/main/java/com/laytonsmith/core/compiler/FileOptions.java
index 0f8a2280f..7c02bb79b 100644
--- a/src/main/java/com/laytonsmith/core/compiler/FileOptions.java
+++ b/src/main/java/com/laytonsmith/core/compiler/FileOptions.java
@@ -68,7 +68,7 @@ public FileOptions(Map parsedOptions) {
compilerOptions = parseEnumSet(getDefault(parsedOptions, "compileroptions", ""), CompilerOption.class);
copyright = getDefault(parsedOptions, "copyright", "").trim();
license = getDefault(parsedOptions, "license", "").trim();
- allDynamicProcs = parseBoolean(getDefault(parsedOptions, "allDynamicProcs", "false"));
+ allDynamicProcs = parseBoolean(getDefault(parsedOptions, "alldynamicprocs", "false"));
}
private String getDefault(Map map, String key, String defaultIfNone) {
From a6772ac53e58a3055b001caf98d0d5d8e7db7f41 Mon Sep 17 00:00:00 2001
From: Pieter12345
Date: Wed, 27 Sep 2023 04:47:55 +0200
Subject: [PATCH 3/3] Add cmdlinePauseOnException file option
Allows users to see exceptions from scripts that were executed through an extension associated with `mscript.exe`.
---
.../core/compiler/FileOptions.java | 11 ++++++
.../com/laytonsmith/tools/Interpreter.java | 39 ++++++++++++++++++-
2 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/laytonsmith/core/compiler/FileOptions.java b/src/main/java/com/laytonsmith/core/compiler/FileOptions.java
index 7c02bb79b..89e7f65c5 100644
--- a/src/main/java/com/laytonsmith/core/compiler/FileOptions.java
+++ b/src/main/java/com/laytonsmith/core/compiler/FileOptions.java
@@ -50,6 +50,8 @@ public final class FileOptions {
private final String license;
@Option("Disables undefined proc errors in the typechecker")
private final Boolean allDynamicProcs;
+ @Option("Do not close terminal when an exception occurs in a cmdline mode script")
+ private final Boolean cmdlinePauseOnException;
private final Map rawOptions;
//TODO: Make this non-public once this is all finished.
@@ -69,6 +71,7 @@ public FileOptions(Map parsedOptions) {
copyright = getDefault(parsedOptions, "copyright", "").trim();
license = getDefault(parsedOptions, "license", "").trim();
allDynamicProcs = parseBoolean(getDefault(parsedOptions, "alldynamicprocs", "false"));
+ cmdlinePauseOnException = parseBoolean(getDefault(parsedOptions, "cmdlinepauseonexception", "false"));
}
private String getDefault(Map map, String key, String defaultIfNone) {
@@ -222,6 +225,14 @@ public boolean isAllDynamicProcs() {
return allDynamicProcs;
}
+ /**
+ * Get whether the terminal should be held open when an exception occurs in a cmdline script.
+ * @return
+ */
+ public boolean isCmdlinePauseOnException() {
+ return cmdlinePauseOnException;
+ }
+
/**
* The specification for FileOptions states that options that are not recognized are not an error. Given that,
* it should be possible to retrieve these unknown options from the list of options. In general, fully supported
diff --git a/src/main/java/com/laytonsmith/tools/Interpreter.java b/src/main/java/com/laytonsmith/tools/Interpreter.java
index 1159f4097..bfad78b5f 100644
--- a/src/main/java/com/laytonsmith/tools/Interpreter.java
+++ b/src/main/java/com/laytonsmith/tools/Interpreter.java
@@ -85,11 +85,13 @@
import com.laytonsmith.core.exceptions.CRE.CREFormatException;
import com.laytonsmith.core.exceptions.CRE.CREIOException;
import com.laytonsmith.core.exceptions.CRE.CREThrowable;
+import com.laytonsmith.core.exceptions.AbstractCompileException;
import com.laytonsmith.core.exceptions.CancelCommandException;
import com.laytonsmith.core.exceptions.ConfigCompileException;
import com.laytonsmith.core.exceptions.ConfigCompileGroupException;
import com.laytonsmith.core.exceptions.ConfigRuntimeException;
import com.laytonsmith.core.functions.Cmdline;
+import com.laytonsmith.core.functions.Cmdline.prompt_char;
import com.laytonsmith.core.functions.Echoes;
import com.laytonsmith.core.functions.ExampleScript;
import com.laytonsmith.core.functions.Function;
@@ -785,7 +787,29 @@ public void execute(String script, List args, File fromFile) throws Conf
final ParseTree tree;
try {
TokenStream stream = MethodScriptCompiler.lex(script, env, fromFile, true);
- tree = MethodScriptCompiler.compile(stream, env, env.getEnvClasses(), staticAnalysis);
+ try {
+ tree = MethodScriptCompiler.compile(stream, env, env.getEnvClasses(), staticAnalysis);
+ } catch (AbstractCompileException e) {
+
+ // Pause on script exception in cmdline mode if set in the file options.
+ if(env.getEnv(GlobalEnv.class).inCmdlineMode()
+ && System.console() != null && stream.getFileOptions().isCmdlinePauseOnException()) {
+ compile.stop();
+ if(e instanceof ConfigCompileException ex) {
+ ConfigRuntimeException.HandleUncaughtException(ex, null, null);
+ } else if(e instanceof ConfigCompileGroupException ex) {
+ ConfigRuntimeException.HandleUncaughtException(ex, null);
+ } else {
+ throw e;
+ }
+ StreamUtils.GetSystemOut().println(TermColors.reset());
+ prompt_char.promptChar("Press any key to continue...");
+ return;
+ }
+
+ // Pass exception to caller.
+ throw e;
+ }
staticAnalysis = new StaticAnalysis(staticAnalysis.getEndScope(), true); // Continue analysis in end scope.
} finally {
compile.stop();
@@ -854,10 +878,21 @@ public void done(String output) {
}
} catch (ConfigRuntimeException e) {
ConfigRuntimeException.HandleUncaughtException(e, env);
- //No need for the full stack trace
+
+ // No need for the full stack trace.
if(System.console() == null) {
System.exit(1);
}
+
+ // Pause on script exception in cmdline mode if set in the file options.
+ if(env.getEnv(GlobalEnv.class).inCmdlineMode()
+ && tree.getFileOptions().isCmdlinePauseOnException()) {
+ try {
+ prompt_char.promptChar("Press any key to continue...");
+ } catch (IOException e1) {
+ // Ignore.
+ }
+ }
} catch (NoClassDefFoundError e) {
StreamUtils.GetSystemErr().println(RED + Static.getNoClassDefFoundErrorMessage(e) + reset());
StreamUtils.GetSystemErr().println("Since you're running from standalone interpreter mode, this is not a fatal error, but one of the functions you just used required"