2022 - run sandboxes in separate routines

This commit is contained in:
Kartik K. Agaram 2015-08-16 19:13:45 -07:00
parent 221caac615
commit 5db2faebe2
3 changed files with 104 additions and 39 deletions

View File

@ -27,7 +27,7 @@ vector<recipe_ordinal> load(istream& in) {
// Command Handlers
if (command == "recipe") {
string recipe_name = next_word(in);
//? cerr << "recipe: " << recipe_name << '\n'; //? 1
//? cerr << "recipe: " << recipe_name << '\n'; //? 2
if (recipe_name.empty())
raise << "empty recipe name\n" << end();
if (Recipe_ordinal.find(recipe_name) == Recipe_ordinal.end()) {
@ -39,7 +39,7 @@ vector<recipe_ordinal> load(istream& in) {
}
// todo: save user-defined recipes to mu's memory
Recipe[Recipe_ordinal[recipe_name]] = slurp_recipe(in);
//? cerr << Recipe_ordinal[recipe_name] << ": " << recipe_name << '\n'; //? 1
//? cerr << Recipe_ordinal[recipe_name] << ": " << recipe_name << '\n'; //? 2
Recipe[Recipe_ordinal[recipe_name]].name = recipe_name;
// track added recipes because we may need to undo them in tests; see below
recently_added_recipes.push_back(Recipe_ordinal[recipe_name]);
@ -234,7 +234,8 @@ vector<recipe_ordinal> recently_added_recipes;
:(before "End Setup")
for (long long int i = 0; i < SIZE(recently_added_recipes); ++i) {
//? cout << "AAA clearing " << Recipe[recently_added_recipes.at(i)].name << '\n'; //? 2
Recipe_ordinal.erase(Recipe[recently_added_recipes.at(i)].name);
if (recently_added_recipes.at(i) >= Reserved_for_tests) // don't renumber existing recipes, like 'interactive'
Recipe_ordinal.erase(Recipe[recently_added_recipes.at(i)].name);
Recipe.erase(recently_added_recipes.at(i));
}
// Clear Other State For recently_added_recipes

View File

@ -130,6 +130,18 @@ START_RUNNING,
Recipe_ordinal["start-running"] = START_RUNNING;
:(before "End Primitive Recipe Implementations")
case START_RUNNING: {
if (ingredients.empty()) {
raise << "'start-running' requires at least one ingredient: the recipe to start running\n" << end();
break;
}
if (!scalar(ingredients.at(0))) {
raise << "first ingredient of 'start-running' should be a recipe, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
break;
}
if (!ingredients.at(0).at(0)) {
raise << "'start-running' received non-existent recipe: '" << current_instruction().to_string() << "'\n" << end();
break;
}
routine* new_routine = new routine(ingredients.at(0).at(0));
new_routine->parent_index = Current_routine_index;
// populate ingredients

View File

@ -42,7 +42,7 @@ case RUN_INTERACTIVE: {
products.at(1).push_back(trace_contents("warn"));
products.at(2).push_back(0);
products.at(3).push_back(trace_contents("app"));
clean_up_interactive();
cleanup_run_interactive();
break; // done with this instruction
}
else {
@ -59,8 +59,7 @@ Track_most_recent_products = false;
// all warnings.
// returns true if successfully called (no errors found during load and transform)
bool run_interactive(long long int address) {
if (Recipe_ordinal.find("interactive") == Recipe_ordinal.end())
Recipe_ordinal["interactive"] = Next_recipe_ordinal++;
assert(Recipe_ordinal.find("interactive") != Recipe_ordinal.end() && Recipe_ordinal["interactive"] != 0);
// try to sandbox the run as best you can
// todo: test this
if (!Current_scenario) {
@ -71,6 +70,7 @@ bool run_interactive(long long int address) {
if (command.empty()) return false;
Recipe.erase(Recipe_ordinal["interactive"]);
Name[Recipe_ordinal["interactive"]].clear();
// stuff to undo later, in cleanup_run_interactive()
Hide_warnings = true;
if (!Trace_stream) {
Trace_file = ""; // if there wasn't already a stream we don't want to save it
@ -81,17 +81,99 @@ bool run_interactive(long long int address) {
// call run(string) but without the scheduling
load(string("recipe interactive [\n") +
"local-scope\n" +
"screen:address <- new-fake-screen 30, 5\n" +
"screen:address <- next-ingredient\n" +
"$start-tracking-products\n" +
command + "\n" +
"$stop-tracking-products\n" +
"reply screen\n" +
"]\n");
transform_all();
if (trace_count("warn") > 0) return false;
Track_most_recent_products = true;
Current_routine->calls.push_front(call(Recipe_ordinal["interactive"]));
// now call 'sandbox' which will run 'interactive' in a separate routine,
// and wait for it
Current_routine->calls.push_front(call(Recipe_ordinal["sandbox"]));
return true;
}
:(before "End Load Recipes")
load(string(
"recipe interactive [\n") + // just a dummy version to initialize the Recipe_ordinal and so on
"]\n" +
"recipe sandbox [\n" +
"local-scope\n" +
"screen:address/shared <- new-fake-screen 30, 5\n" +
"r:number/routine_id <- start-running interactive:recipe, screen:address\n" +
"wait-for-routine r\n" +
"output:address:array:character <- $most-recent-products\n" +
"warnings:address:array:character <- save-trace [warn]\n" +
"stashes:address:array:character <- save-trace [app]\n" +
"$cleanup-run-interactive\n" +
"reply output, warnings, screen, stashes\n" +
"]\n");
transform_all();
recently_added_recipes.clear();
:(before "End Primitive Recipe Declarations")
_START_TRACKING_PRODUCTS,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["$start-tracking-products"] = _START_TRACKING_PRODUCTS;
:(before "End Primitive Recipe Implementations")
case _START_TRACKING_PRODUCTS: {
Track_most_recent_products = true;
break;
}
:(before "End Primitive Recipe Declarations")
_STOP_TRACKING_PRODUCTS,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["$stop-tracking-products"] = _STOP_TRACKING_PRODUCTS;
:(before "End Primitive Recipe Implementations")
case _STOP_TRACKING_PRODUCTS: {
Track_most_recent_products = false;
break;
}
:(before "End Primitive Recipe Declarations")
_MOST_RECENT_PRODUCTS,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["$most-recent-products"] = _MOST_RECENT_PRODUCTS;
:(before "End Primitive Recipe Implementations")
case _MOST_RECENT_PRODUCTS: {
products.resize(1);
products.at(0).push_back(new_mu_string(Most_recent_products));
break;
}
:(before "End Primitive Recipe Declarations")
SAVE_TRACE,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["save-trace"] = SAVE_TRACE;
:(before "End Primitive Recipe Implementations")
case SAVE_TRACE: {
products.resize(1);
products.at(0).push_back(trace_contents(current_instruction().ingredients.at(0).name));
break;
}
:(before "End Primitive Recipe Declarations")
_CLEANUP_RUN_INTERACTIVE,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["$cleanup-run-interactive"] = _CLEANUP_RUN_INTERACTIVE;
:(before "End Primitive Recipe Implementations")
case _CLEANUP_RUN_INTERACTIVE: {
cleanup_run_interactive();
break;
}
:(code)
void cleanup_run_interactive() {
Hide_warnings = false;
if (Trace_stream->is_narrowly_collecting("warn")) { // hack
delete Trace_stream;
Trace_stream = NULL;
}
}
:(scenario "run_interactive_returns_stringified_result")
recipe main [
# try to interactively add 2 and 2
@ -166,36 +248,6 @@ void track_most_recent_products(const instruction& instruction, const vector<vec
Most_recent_products = out.str();
}
//: Recipe 'interactive' doesn't return what 'run-interactive seems to return.
//: Massage results from former to latter.
:(after "Starting Reply")
if (Current_routine->calls.front().running_recipe == Recipe_ordinal["interactive"]) {
products.resize(4);
products.at(0).push_back(new_mu_string(Most_recent_products));
products.at(1).push_back(trace_contents("warn"));
assert(SIZE(ingredients) == 1);
assert(scalar(ingredients.at(0)));
products.at(2).push_back(ingredients.at(0).at(0)); // screen
products.at(3).push_back(trace_contents("app"));
--Callstack_depth;
Current_routine->calls.pop_front();
assert(!Current_routine->calls.empty());
clean_up_interactive();
break;
}
//: clean up reply after we've popped it off the call-stack
:(code)
void clean_up_interactive() {
Hide_warnings = false;
Track_most_recent_products = false;
if (Trace_stream->is_narrowly_collecting("warn")) { // hack
delete Trace_stream;
Trace_stream = NULL;
}
}
:(code)
string strip_comments(string in) {
ostringstream result;