feature request: "import" in command-line MiniScript
Mini Micro has a cool "import" feature described here. (And to close some of the questions open in that thread: yes, you can use if globals == locals to tell when you're running as an import, and you access variables at the module scope using outer.)
I've gotten requests to support import in command-line MiniScript. The C++ version has all the language features (including outer) needed to make this work. It would just need (1) some standard location or environment variable to look for the import modules in, and (2) the code to find the specified module and import it.
For reference, here is the (C#) code from Mini Micro that implements import.
f = Intrinsic.Create("import");
f.AddParam("libname");
f.code = (context, partialResult) => {
if (partialResult != null) {
// When we're invoked with a partial result, it means that the import
// function has finished, and stored its result (the values that were
// created by the import code) in Temp 0.
ValMap importedValues = context.GetTemp(0) as ValMap;
// Now we're going to do something slightly evil. We're going to reach
// up into the *parent* context, and store these imported values under
// the import library name. Thus, there will always be a standard name
// by which you can refer to the imported stuff.
TAC.Context callerContext = context.parent;
callerContext.SetVar(partialResult.result.ToString(), importedValues);
return Intrinsic.Result.Null;
}
// When we're invoked without a partial result, it's time to start the import.
// Begin by finding the actual code.
Shell sh = context.interpreter.hostData as Shell;
Value libnameVal = context.GetVar("libname");
string libname = libnameVal == null ? null : libnameVal.ToString();
if (string.IsNullOrEmpty(libname)) {
throw new RuntimeException("import: libname required");
}
string searchPaths = sh.GetEnv("includePaths") + ";/sys/lib;/usr/lib";
string[] libDirs = searchPaths.Split(new char[] {';'});
Debug.Log("Got " + libDirs.Length + " lib dirs: " + string.Join(", ", libDirs));
List<string> lines = null;
foreach (string dir in libDirs) {
string path = dir + "/" + libname + ".ms";
Disk disk = FileUtils.GetDisk(ref path);
if (disk == null) continue;
lines = disk.ReadLines(path);
if (lines != null) break;
}
if (lines == null) throw new RuntimeException("import: library not found: " + libname);
// Now, parse that code, and build a function around it that returns
// its own locals as its result. Push a manual call.
var parser = new Parser();
parser.Parse(string.Join("\n", lines.ToArray()));
Function import = parser.CreateImport();
sh.interpreter.vm.ManuallyPushCall(new ValFunction(import), new ValTemp(0));
// That call will not be able to run until we return from this intrinsic.
// So, return a partial result, with the lib name. We'll get invoked
// again after the import function has finished running.
return new Intrinsic.Result(new ValString(libname), false);
};
Implemented for v1.6 (and available now, if you want to build it yourself).