diff --git a/src/main/java/com/laytonsmith/core/compiler/FileOptions.java b/src/main/java/com/laytonsmith/core/compiler/FileOptions.java index 5ed2c7cc3..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. @@ -68,7 +70,8 @@ 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")); + 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"