Skip to content

Instantly share code, notes, and snippets.

@gbluma
Created March 20, 2015 05:20
Show Gist options
  • Save gbluma/79e802872dab3e1f3363 to your computer and use it in GitHub Desktop.
Save gbluma/79e802872dab3e1f3363 to your computer and use it in GitHub Desktop.
// TODO: support more than just linux/osx
include "std/posix/filesystem";
// TODO: add this to std/io/textio.flx, it's missing
gen fopen_append : string -> ofile = '::std::fopen($1.c_str(), "a")';
object Repl () = {
// if a line starts with these, it is considered a definition and is retained.
val defs_regex = RE2("\s*(val|var|fun|gen|proc|struct).*");
val temp_dir = "/tmp/";
// generate a random session id
val session = str(rand());
// build some paths
val f_repl_path = temp_dir + session + "_repl.flx"; // immediate commands to execute
val f_defs_path = temp_dir + session + "_defs.flx"; // keep track of saved definitions
val f_repl_path_prev = temp_dir + session + "_repl_prev.flx"; // backup of commands for rollback
val f_defs_path_prev = temp_dir + session + "_defs_prev.flx"; // backup of definitions for rollback
// mutable state
var previous_line = "";
var inputLine = "";
// ------------------------------------------------------------------
// Show the >>> at the start of the line
method proc printLinePrefix = {
print ">>> ";
fflush stdout; // flush to *actually* show text
}
// ------------------------------------------------------------------
method proc init() {
// delete old garbage definitions first
var result = PosixFileSystem::unlink_file(f_defs_path);
// prompt user for input
println "Garrett's Fake Felix REPL (version 0.0.1)";
printLinePrefix();
}
// ------------------------------------------------------------------
method proc work() {
// prime input for loop
inputLine = rstrip(stdin.readln); // rstrip to remove newline (interferes with regex)
// loop on input
while (inputLine.len > 0.size) do
match Match(defs_regex, inputLine) with
| None =>
// ... just a command, run it
// write new line to repl (always overwrite)
var repl_filehandle = fopen_output(f_repl_path);
if FileStat::fileexists(f_defs_path) do
write(repl_filehandle, "include '"+temp_dir+session+"_defs"+"';\n");
done
write(repl_filehandle, inputLine);
fflush repl_filehandle;
repl_filehandle.fclose();
// evaluate repl
val executed = System::system("flx " + f_repl_path + " 2>/dev/null");
(executed > 0) ?? println("Couldn't interpret file " + f_repl_path);
| Some ?b =>
// ... a definition, save it.
// write new line to defs
val defs_filehandle = fopen_append(f_defs_path);
write(defs_filehandle, inputLine + "\n");
fflush defs_filehandle;
defs_filehandle.fclose();
// evaluate defs and recover if failed
val x = System::system("flx " + f_defs_path + " 2>/dev/null");
(x > 0) ?? var y = System::system("cat " + f_defs_path_prev + " > " + f_defs_path );
(x == 0) ?? var z = System::system("cat " + f_defs_path + " > " + f_defs_path_prev );
endmatch;
printLinePrefix();
// capture more input from stdin
inputLine = rstrip(readln(stdin));
done
}
// ------------------------------------------------------------------
method proc cleanup() {
// clean up output file
var defs_deleted = PosixFileSystem::unlink_file(f_defs_path);
(defs_deleted > 0) ?? println("Couldn't delete file " + f_defs_path );
}
}
val r = Repl();
r.init();
r.work;
r.cleanup;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment