Open Withered-Flower-0422 opened 7 months ago
Properly breaking out of the code (without exiting the environment) is more involved than it sounds, but it's certainly doable. For reference, here is the C# code that handles a break in Mini Micro:
public bool Break(bool silent=false) {
//Debug.Log($"Break({silent})");
if (!silent) {
var opts = env.GetMap("bootOpts");
allowControlCBreak = opts.GetBool("controlC", true);
if (!allowControlCBreak) return false;
}
// grab the full stack and tuck it away for future reference
ValList stack = stackAtLastErr;
if (stack == null) stack = Intrinsics.StackList(interpreter.vm);
//Debug.Log($"Break found stack: {stack.ToString()}");
// also find the first non-null entry, to display right away
SourceLoc loc = null;
if (interpreter.vm != null) {
foreach (var stackLoc in interpreter.vm.GetStack()) {
loc = stackLoc;
if (loc != null) break;
}
}
interpreter.Stop();
console.AbortInput();
console.keyBuffer.Clear();
if (!silent) {
string msg = "BREAK";
if (loc != null) {
msg += " at ";
if (loc.context != null) msg += loc.context + " ";
msg += "line " + loc.lineNum;
}
textDisplay.Print(msg + "\n");
//Debug.Log("printed: " + msg);
}
// Reset the interpreter (creating a new VM), but copy the globals
// and various type maps out of the old one.
var oldVM = interpreter.vm;
interpreter.Reset();
interpreter.REPL(""); // (forces creation of a VM)
CreateVersionMap();
interpreter.vm.globalContext.variables = oldVM.globalContext.variables;
interpreter.vm.listType = oldVM.listType;
interpreter.vm.mapType = oldVM.mapType;
interpreter.vm.numberType = oldVM.numberType;
interpreter.vm.stringType = oldVM.stringType;
interpreter.vm.versionMap = oldVM.versionMap;
oldVM = null;
// and set the _stackAtBreak global to our stack
interpreter.vm.globalContext.variables.SetElem(_stackAtBreak, stack);
//Debug.Log("Rebuilt VM and restored " + globals.Count + " globals");
doLaunchShell = false;
isRunningShell = false;
runProgram = false;
return true;
}
For C++, specifically for Windows, the handler would be set like this:
SetConsoleCtrlHandler(CtrlHandler, TRUE);
A sample handler:
#include <windows.h>
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
case CTRL_C_EVENT:
// MiniScript break here
return TRUE; // We are handling this event.
default:
return FALSE; // We want other handlers to consume the event.
}
For *nix, the C++ implementation would need to deal with signals.
For the handler in C#, I haven't done this yet myself, but quick web-searching seems to indicate you set it like this:
Console.CancelKeyPress += new ConsoleCancelEventHandler(consoleBreakHandler)
A sample handler:
protected static void consoleBreakHandler(object sender, ConsoleCancelEventArgs args)
{
// MiniScript break here
args.Cancel = true; // We don't want the program to quit.
}
References:
When pressing Ctrl+C, you quit from MiniScript environment. It seems there's no way to interrupt the running code simply. Ctrl+C is more suitable to do a BREAK thing, not an ABORT thing. So just let Ctrl+C interrupt the running code, instead of aborting MiniScript. If you want to abort MiniScript, type Ctrl+Z. (This is already available.)
This is how python does. I feel it more reasonable. Python won't abort until you type Ctrl+Z.
See on Discord