about summary refs log tree commit diff stats
path: root/081run_interactive.cc
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-07-17 12:51:32 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-07-17 12:58:37 -0700
commit32cd40ec3c9dad33738caf6f55fb742a316bd5be (patch)
treec6612fefc35741b43e1058826445d2913e94b3ba /081run_interactive.cc
parentfe9e53ed19f84a1771d56bfa0cf7d1d017e07559 (diff)
downloadmu-32cd40ec3c9dad33738caf6f55fb742a316bd5be.tar.gz
1799 - continue to debug memory corruption of 1795
Things I figured out:
- 'row' in render-screen doesn't perfectly track cursor-row in screen
- proximal cause was forgetting to add left:number to stop-printing
- trying to print to screen outside bounds was silently succeeding and
  corrupting simulated memory
- if we silently ignore prints outside bounds things are fine

But why are prints outside screen bounds working? We should be accessing
screen data using 'index', and that's checking its bounds.
Diffstat (limited to '081run_interactive.cc')
-rw-r--r--081run_interactive.cc76
1 files changed, 55 insertions, 21 deletions
diff --git a/081run_interactive.cc b/081run_interactive.cc
index 1d317d4b..f54a73e3 100644
--- a/081run_interactive.cc
+++ b/081run_interactive.cc
@@ -15,8 +15,10 @@ recipe main [
 # result is null
 +mem: storing 0 in location 1
 
-//: run code in 'interactive mode', i.e. with warnings off, and recording
-//: output in case we want to print it to screen
+//: run code in 'interactive mode', i.e. with warnings off and return:
+//:   stringified output in case we want to print it to screen
+//:   any warnings encountered
+//:   simulated screen any prints went to
 :(before "End Primitive Recipe Declarations")
 RUN_INTERACTIVE,
 :(before "End Primitive Recipe Numbers")
@@ -25,11 +27,12 @@ Recipe_ordinal["run-interactive"] = RUN_INTERACTIVE;
 :(before "End Primitive Recipe Implementations")
 case RUN_INTERACTIVE: {
   assert(scalar(ingredients.at(0)));
-  products.resize(2);
+  products.resize(3);
   bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0));
   if (!new_code_pushed_to_stack) {
     products.at(0).push_back(0);
     products.at(1).push_back(warnings_from_trace());
+    products.at(2).push_back(0);
     clean_up_interactive();
     break;  // done with this instruction
   }
@@ -40,8 +43,10 @@ case RUN_INTERACTIVE: {
 
 :(before "End Globals")
 bool Running_interactive = false;
+long long int Old_screen = 0;  // we can support one iteration of screen inside screen
 :(before "End Setup")
 Running_interactive = false;
+Old_screen = 0;
 :(code)
 // reads a string, tries to call it as code (treating it as a test), saving
 // all warnings.
@@ -49,6 +54,8 @@ Running_interactive = false;
 bool run_interactive(long long int address) {
   if (Recipe_ordinal.find("interactive") == Recipe_ordinal.end())
     Recipe_ordinal["interactive"] = Next_recipe_ordinal++;
+  Old_screen = Memory[SCREEN];
+  cerr << "save screen: " << Old_screen << '\n'; //? 1
   // try to sandbox the run as best you can
   // todo: test this
   if (!Current_scenario) {
@@ -57,6 +64,9 @@ bool run_interactive(long long int address) {
       Memory.erase(i);
     Name[Recipe_ordinal["interactive"]].clear();
   }
+//?   cerr << "screen was at " << Name[Recipe_ordinal["interactive"]]["screen"] << '\n'; //? 1
+  Name[Recipe_ordinal["interactive"]]["screen"] = SCREEN;
+//?   cerr << "screen now at " << Name[Recipe_ordinal["interactive"]]["screen"] << '\n'; //? 1
   string command = trim(strip_comments(to_string(address)));
   if (command.empty()) return false;
   Recipe.erase(Recipe_ordinal["interactive"]);
@@ -67,7 +77,12 @@ bool run_interactive(long long int address) {
     Trace_stream->collect_layer = "warn";
   }
   // call run(string) but without the scheduling
-  load("recipe interactive [\n"+command+"\n]\n");
+  // we won't create a local scope so that we can get to the new screen after
+  // we return from 'interactive'.
+  load(string("recipe interactive [\n") +
+          "screen:address <- new-fake-screen 5, 5\n" +
+          command + "\n" +
+       "]\n");
   transform_all();
   if (trace_count("warn") > 0) return false;
   Running_interactive = true;
@@ -75,21 +90,6 @@ bool run_interactive(long long int address) {
   return true;
 }
 
-:(after "Starting Reply")
-if (current_recipe_name() == "interactive") clean_up_interactive();
-:(after "Falling Through End Of Recipe")
-if (current_recipe_name() == "interactive") clean_up_interactive();
-:(code)
-void clean_up_interactive() {
-  Hide_warnings = false;
-  Running_interactive = false;
-  // hack: assume collect_layer isn't set anywhere else
-  if (Trace_stream->collect_layer == "warn") {
-    delete Trace_stream;
-    Trace_stream = NULL;
-  }
-}
-
 :(scenario "run_interactive_returns_stringified_result")
 recipe main [
   # try to interactively add 2 and 2
@@ -157,17 +157,51 @@ void record_products(const instruction& instruction, const vector<vector<double>
 }
 :(before "Complete Call Fallthrough")
 if (current_instruction().operation == RUN_INTERACTIVE && !current_instruction().products.empty()) {
-  assert(SIZE(current_instruction().products) <= 2);
+  assert(SIZE(current_instruction().products) <= 3);
   // Send the results of the most recently executed instruction, regardless of
   // call depth, to be converted to string and potentially printed to string.
   vector<double> result;
   result.push_back(new_string(Most_recent_results));
   write_memory(current_instruction().products.at(0), result);
-  if (SIZE(current_instruction().products) == 2) {
+  if (SIZE(current_instruction().products) >= 2) {
     vector<double> warnings;
     warnings.push_back(warnings_from_trace());
     write_memory(current_instruction().products.at(1), warnings);
   }
+  if (SIZE(current_instruction().products) >= 3) {
+    vector<double> screen;
+    cerr << "returning screen " << Memory[SCREEN] << " to " << current_instruction().products.at(2).to_string() << " value " << current_instruction().products.at(2).value << '\n';
+    screen.push_back(Memory[SCREEN]);
+    write_memory(current_instruction().products.at(2), screen);
+  }
+}
+
+//: clean up reply after we've popped it off the call-stack
+//: however, we need what was on the stack to decide whether to clean up
+:(after "Starting Reply")
+bool must_clean_up_interactive = (current_recipe_name() == "interactive");
+//? cerr << "reply: " << Memory[SCREEN] << '\n'; //? 1
+//? cerr << "reply2: " << Name[Recipe_ordinal["render-sandboxes"]]["screen"] << '\n'; //? 1
+:(after "Falling Through End Of Recipe")
+bool must_clean_up_interactive = (current_recipe_name() == "interactive");
+//? cerr << "pop: " << Memory[SCREEN] << '\n'; //? 1
+//? cerr << "pop2: " << Name[Recipe_ordinal["render-sandboxes"]]["screen"] << '\n'; //? 1
+:(before "End Reply")
+if (must_clean_up_interactive) clean_up_interactive();
+:(before "Complete Call Fallthrough")
+if (must_clean_up_interactive) clean_up_interactive();
+:(code)
+void clean_up_interactive() {
+  Hide_warnings = false;
+  Running_interactive = false;
+  // hack: assume collect_layer isn't set anywhere else
+  if (Trace_stream->collect_layer == "warn") {
+    delete Trace_stream;
+    Trace_stream = NULL;
+  }
+  cerr << "restore screen: " << Memory[SCREEN] << " to " << Old_screen << '\n';
+  Memory[SCREEN] = Old_screen;
+  Old_screen = 0;
 }
 
 :(code)