about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--003trace.cc12
-rw-r--r--020run.cc2
-rw-r--r--029tools.cc23
-rw-r--r--031address.cc4
-rw-r--r--042name.cc2
-rw-r--r--081run_interactive.cc27
-rwxr-xr-xbuild_and_test_until4
-rw-r--r--edit.mu153
8 files changed, 201 insertions, 26 deletions
diff --git a/003trace.cc b/003trace.cc
index 3695703a..d2afb21c 100644
--- a/003trace.cc
+++ b/003trace.cc
@@ -103,7 +103,7 @@ struct trace_stream {
   string curr_layer;
   int curr_depth;
   string dump_layer;
-  string collect_layer;  // if set, ignore all other layers
+  set<string> collect_layers;  // if not empty, ignore all absent layers
   ofstream null_stream;  // never opens a file, so writes silently fail
   trace_stream() :curr_stream(NULL), curr_depth(0) {}
   ~trace_stream() { if (curr_stream) delete curr_stream; }
@@ -113,13 +113,21 @@ struct trace_stream {
   }
 
   ostream& stream(int depth, string layer) {
-    if (!collect_layer.empty() && layer != collect_layer) return null_stream;
+    if (!is_collecting(layer)) return null_stream;
     curr_stream = new ostringstream;
     curr_layer = layer;
     curr_depth = depth;
     return *curr_stream;
   }
 
+  bool is_collecting(const string& layer) {
+    return collect_layers.empty() || collect_layers.find(layer) != collect_layers.end();
+  }
+
+  bool is_narrowly_collecting(const string& layer) {
+    return collect_layers.find(layer) != collect_layers.end();
+  }
+
   // be sure to call this before messing with curr_stream or curr_layer
   void newline() {
     if (!curr_stream) return;
diff --git a/020run.cc b/020run.cc
index a4b75db6..72fc2b7c 100644
--- a/020run.cc
+++ b/020run.cc
@@ -133,7 +133,7 @@ if (!Run_tests) {
   setup();
 //?   Trace_file = "interactive"; //? 2
 //?   START_TRACING_UNTIL_END_OF_SCOPE; //? 2
-//?   Trace_stream->collect_layer = "app"; //? 1
+//?   Trace_stream->collect_layer.insert("app"); //? 1
   transform_all();
   recipe_ordinal r = Recipe_ordinal[string("main")];
   if (r) run(r);
diff --git a/029tools.cc b/029tools.cc
index cd4123fa..587818ea 100644
--- a/029tools.cc
+++ b/029tools.cc
@@ -12,15 +12,22 @@ TRACE,
 Recipe_ordinal["trace"] = TRACE;
 :(before "End Primitive Recipe Implementations")
 case TRACE: {
-  if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'trace' takes exactly two ingredients rather than '" << current_instruction().to_string() << "'\n" << end();
-    break;
+  if (SIZE(ingredients) == 2) {
+    assert(is_literal(current_instruction().ingredients.at(0)));
+    string label = current_instruction().ingredients.at(0).name;
+    assert(is_literal(current_instruction().ingredients.at(1)));
+    string message = current_instruction().ingredients.at(1).name;
+    trace(1, label) << message << end();
+  }
+  else if (SIZE(ingredients) == 1) {
+    assert(is_literal(current_instruction().ingredients.at(0)));
+    string message = current_instruction().ingredients.at(0).name;
+    cerr << "tracing " << message << '\n';
+    trace(1, "app") << message << end();
+  }
+  else {
+    raise << current_recipe_name() << ": 'trace' takes one or two ingredients rather than '" << current_instruction().to_string() << "'\n" << end();
   }
-  assert(is_literal(current_instruction().ingredients.at(0)));
-  string label = current_instruction().ingredients.at(0).name;
-  assert(is_literal(current_instruction().ingredients.at(1)));
-  string message = current_instruction().ingredients.at(1).name;
-  trace(1, label) << message << end();
   break;
 }
 
diff --git a/031address.cc b/031address.cc
index e79ff314..b7b395c6 100644
--- a/031address.cc
+++ b/031address.cc
@@ -25,7 +25,7 @@ recipe main [
 :(before "long long int base = x.value" following "void write_memory(reagent x, vector<double> data)")
 x = canonize(x);
 if (x.value == 0) {
-  raise << "can't write to location 0\n" << end();
+  raise << "can't write to location 0 in '" << current_instruction().to_string() << "'\n" << end();
   return;
 }
 
@@ -37,7 +37,7 @@ recipe main [
   1:address:number/lookup <- copy 34
 ]
 -mem: storing 34 in location 0
-+warn: can't write to location 0
++warn: can't write to location 0 in '1:address:number/lookup <- copy 34'
 
 :(code)
 reagent canonize(reagent x) {
diff --git a/042name.cc b/042name.cc
index 304d050d..45f5a3b2 100644
--- a/042name.cc
+++ b/042name.cc
@@ -148,7 +148,7 @@ recipe main [
   x:number/raw <- copy 0
 ]
 -name: assign x 1
-+warn: can't write to location 0
++warn: can't write to location 0 in 'x:number/raw <- copy 0'
 
 :(scenarios transform)
 :(scenario transform_names_warns_when_mixing_names_and_numeric_locations)
diff --git a/081run_interactive.cc b/081run_interactive.cc
index e8032100..59c79432 100644
--- a/081run_interactive.cc
+++ b/081run_interactive.cc
@@ -19,6 +19,7 @@ recipe main [
 //:   stringified output in case we want to print it to screen
 //:   any warnings encountered
 //:   simulated screen any prints went to
+//:   any 'app' layer traces generated
 :(before "End Primitive Recipe Declarations")
 RUN_INTERACTIVE,
 :(before "End Primitive Recipe Numbers")
@@ -26,7 +27,7 @@ Recipe_ordinal["run-interactive"] = RUN_INTERACTIVE;
 //? cerr << "run-interactive: " << RUN_INTERACTIVE << '\n'; //? 1
 :(before "End Primitive Recipe Implementations")
 case RUN_INTERACTIVE: {
-  products.resize(3);
+  products.resize(4);
   if (SIZE(ingredients) != 1) {
     raise << current_recipe_name() << ": 'run-interactive' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
@@ -40,6 +41,7 @@ case RUN_INTERACTIVE: {
     products.at(0).push_back(0);
     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();
     break;  // done with this instruction
   }
@@ -81,7 +83,8 @@ bool run_interactive(long long int address) {
   if (!Trace_stream) {
     Trace_file = "";  // if there wasn't already a stream we don't want to save it
     Trace_stream = new trace_stream;
-    Trace_stream->collect_layer = "warn";
+    Trace_stream->collect_layers.insert("warn");
+    Trace_stream->collect_layers.insert("app");
   }
   // call run(string) but without the scheduling
   // we won't create a local scope so that we can get to the new screen after
@@ -164,7 +167,7 @@ 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) <= 3);
+  assert(SIZE(current_instruction().products) <= 4);
   // 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;
@@ -180,6 +183,12 @@ if (current_instruction().operation == RUN_INTERACTIVE && !current_instruction()
     screen.push_back(Memory[SCREEN]);
     write_memory(current_instruction().products.at(2), screen);
   }
+  if (SIZE(current_instruction().products) >= 4) {
+//?     cerr << "emitting trace\n"; //? 1
+    vector<double> trace;
+    trace.push_back(trace_contents("app"));
+    write_memory(current_instruction().products.at(3), trace);
+  }
 }
 
 //: clean up reply after we've popped it off the call-stack
@@ -197,8 +206,8 @@ void clean_up_interactive() {
   Trace_stream->newline();  // flush trace
   Hide_warnings = false;
   Running_interactive = false;
-  // hack: assume collect_layer isn't set anywhere else
-  if (Trace_stream->collect_layer == "warn") {
+  // hack: assume collect_layers isn't set anywhere else
+  if (Trace_stream->is_narrowly_collecting("warn")) {
     delete Trace_stream;
     Trace_stream = NULL;
   }
@@ -250,7 +259,9 @@ bool is_mu_string(const reagent& x) {
 
 long long int trace_contents(const string& layer) {
   if (!Trace_stream) return 0;
+//?   cerr << "trace stream exists\n"; //? 1
   if (trace_count(layer) <= 0) return 0;
+//?   cerr << layer << " has something\n"; //? 1
   ostringstream out;
   for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) {
     if (p->label != layer) continue;
@@ -258,6 +269,7 @@ long long int trace_contents(const string& layer) {
     if (*--p->contents.end() != '\n') out << '\n';
   }
   assert(!out.str().empty());
+//?   cerr << layer << ":\n" << out.str() << "\n--\n"; //? 1
   return new_mu_string(out.str());
 }
 
@@ -281,7 +293,7 @@ case RELOAD: {
   if (!Trace_stream) {
     Trace_file = "";  // if there wasn't already a stream we don't want to save it
     Trace_stream = new trace_stream;
-    Trace_stream->collect_layer = "warn";
+    Trace_stream->collect_layers.insert("warn");
   }
   Hide_warnings = true;
   Disable_redefine_warnings = true;
@@ -291,7 +303,8 @@ case RELOAD: {
   Disable_redefine_warnings = false;
   Hide_warnings = false;
   products.at(0).push_back(trace_contents("warn"));
-  if (Trace_stream->collect_layer == "warn") {
+  // hack: assume collect_layers isn't set anywhere else
+  if (Trace_stream->is_narrowly_collecting("warn")) {
     delete Trace_stream;
     Trace_stream = NULL;
   }
diff --git a/build_and_test_until b/build_and_test_until
index b83db304..20845064 100755
--- a/build_and_test_until
+++ b/build_and_test_until
@@ -9,5 +9,5 @@ make enumerate/enumerate
 ./tangle/tangle $(./enumerate/enumerate --until $* |grep -v '.mu$') |grep -v "^\s*//:" > mu.cc
 cat /dev/null $(./enumerate/enumerate --until $* |grep '.mu$') > core.mu
 make autogenerated_lists
-make valgrind
-#? make test #? 2
+make valgrind #? 1
+#? make test #? 3
diff --git a/edit.mu b/edit.mu
index a19fd07d..82f81c5d 100644
--- a/edit.mu
+++ b/edit.mu
@@ -2673,10 +2673,12 @@ container sandbox-data [
   data:address:array:character
   response:address:array:character
   warnings:address:array:character
+  trace:address:array:character
   expected-response:address:array:character
   # coordinates to track clicks
   starting-row-on-screen:number
   response-starting-row-on-screen:number
+  display-trace?:boolean
   screen:address:screen  # prints in the sandbox go here
   next-sandbox:address:sandbox-data
 ]
@@ -2812,9 +2814,9 @@ recipe run-sandboxes [
     data <- get-address *curr, data:offset
     response:address:address:array:character <- get-address *curr, response:offset
     warnings:address:address:array:character <- get-address *curr, warnings:offset
+    trace:address:address:array:character <- get-address *curr, trace:offset
     fake-screen:address:address:screen <- get-address *curr, screen:offset
-    *response, *warnings, *fake-screen <- run-interactive *data
-#?     $print *warnings, [ ], **warnings, 10/newline
+    *response, *warnings, *fake-screen, *trace <- run-interactive *data
     curr <- get *curr, next-sandbox:offset
     loop
   }
@@ -2901,6 +2903,7 @@ recipe render-sandboxes [
   sandbox-response:address:array:character <- get *sandbox, response:offset
   sandbox-warnings:address:array:character <- get *sandbox, warnings:offset
   sandbox-screen:address <- get *sandbox, screen:offset
+  +render-sandbox-results
   {
     break-unless sandbox-warnings
     *response-starting-row <- copy 0  # no response
@@ -3237,7 +3240,7 @@ recipe foo [
   ]
   # click somewhere on the sandbox
   assume-console [
-    left-click 4, 30
+    left-click 3, 30
   ]
   run [
     event-loop screen:address, console:address, 3:address:programming-environment-data
@@ -3623,6 +3626,150 @@ after +render-sandbox-response [
   }
 ]
 
+## click on the code typed into a sandbox to toggle its trace
+
+scenario sandbox-click-on-code-toggles-app-trace [
+  $close-trace
+  assume-screen 40/width, 10/height
+  # basic recipe
+  1:address:array:character <- new [ 
+recipe foo [
+  trace [abc]
+]]
+  # run it
+  2:address:array:character <- new [foo]
+  assume-console [
+    press 65532  # F4
+  ]
+  3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
+  event-loop screen:address, console:address, 3:address:programming-environment-data
+  screen-should-contain [
+    .                     run (F4)           .
+    .                    ┊                   .
+    .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.
+    .  trace [abc]       ┊                  x.
+    .]                   ┊foo                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.
+    .                    ┊                   .
+  ]
+  # click on the 'foo' line in the sandbox
+  assume-console [
+    left-click 4, 21
+  ]
+  run [
+    event-loop screen:address, console:address, 3:address:programming-environment-data
+  ]
+  # trace now printed
+  screen-should-contain [
+    .                     run (F4)           .
+    .                    ┊                   .
+    .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.
+    .  trace [abc]       ┊                  x.
+    .]                   ┊foo                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc                .
+    .                    ┊━━━━━━━━━━━━━━━━━━━.
+    .                    ┊                   .
+  ]
+  screen-should-contain-in-color 245/grey, [
+    .                                        .
+    .                    ┊                   .
+    .                    ┊━━━━━━━━━━━━━━━━━━━.
+    .                    ┊                  x.
+    .                    ┊                   .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc                .
+    .                    ┊━━━━━━━━━━━━━━━━━━━.
+    .                    ┊                   .
+  ]
+  # click again on the same region
+  assume-console [
+    left-click 4, 25
+  ]
+  run [
+    event-loop screen:address, console:address, 3:address:programming-environment-data
+  ]
+  # trace hidden again
+  screen-should-contain [
+    .                     run (F4)           .
+    .                    ┊                   .
+    .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.
+    .  trace [abc]       ┊                  x.
+    .]                   ┊foo                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.
+    .                    ┊                   .
+  ]
+]
+
+# clicks on sandbox code toggle its display-trace? flag
+after +global-touch [
+  # right side of screen? check if it's inside the code of any sandbox
+  {
+    sandbox-left-margin:number <- get *current-sandbox, left:offset
+    click-column:number <- get *t, column:offset
+    on-sandbox-side?:boolean <- greater-or-equal click-column, sandbox-left-margin
+    break-unless on-sandbox-side?
+    first-sandbox:address:sandbox-data <- get *env, sandbox:offset
+    break-unless first-sandbox
+    first-sandbox-begins:number <- get *first-sandbox, starting-row-on-screen:offset
+    click-row:number <- get *t, row:offset
+    below-sandbox-editor?:boolean <- greater-or-equal click-row, first-sandbox-begins
+    break-unless below-sandbox-editor?
+    # identify the sandbox whose code is being clicked on
+    sandbox:address:sandbox-data <- find-click-in-sandbox-code env, click-row
+    break-unless sandbox
+    # toggle its display-trace? property
+    x:address:boolean <- get-address *sandbox, display-trace?:offset
+    *x <- not *x
+    screen <- render-sandbox-side screen, env, 1/clear
+    # no change in cursor
+    show-screen screen
+    loop +next-event:label
+  }
+]
+
+recipe find-click-in-sandbox-code [
+  local-scope
+  env:address:programming-environment-data <- next-ingredient
+  click-row:number <- next-ingredient
+  # assert click-row >= sandbox.starting-row-on-screen
+  sandbox:address:sandbox-data <- get *env, sandbox:offset
+  start:number <- get *sandbox, starting-row-on-screen:offset
+  clicked-on-sandboxes?:boolean <- greater-or-equal click-row, start
+  assert clicked-on-sandboxes?, [extract-sandbox called on click to sandbox editor]
+  # while click-row < sandbox.next-sandbox.starting-row-on-screen
+  {
+    next-sandbox:address:sandbox-data <- get *sandbox, next-sandbox:offset
+    break-unless next-sandbox
+    next-start:number <- get *next-sandbox, starting-row-on-screen:offset
+    found?:boolean <- lesser-than click-row, next-start
+    break-if found?
+    sandbox <- copy next-sandbox
+    loop
+  }
+  # return sandbox if click is in its code region
+  response-starting-row:number <- get *sandbox, response-starting-row-on-screen:offset
+  click-above-response?:boolean <- lesser-than click-row, response-starting-row
+  start:number <- get *sandbox, starting-row-on-screen:offset
+  click-below-menu?:boolean <- greater-than click-row, start
+  click-on-sandbox-code?:boolean <- and click-above-response?, click-below-menu?
+  {
+    break-if click-on-sandbox-code?
+    reply 0/no-click-in-sandbox-output
+  }
+  reply sandbox
+]
+
+# when rendering a sandbox, dump its trace if display-trace? property is set
+after +render-sandbox-results [
+  {
+    display-trace?:boolean <- get *sandbox, display-trace?:offset
+    break-unless display-trace?
+    sandbox-trace:address:array:character <- get *sandbox, trace:offset
+    break-unless sandbox-trace  # nothing to print; move on
+    row, screen <- render-string, screen, sandbox-trace, left, right, 245/grey, row
+    jump +render-sandbox-end:label
+  }
+]
+
 ## handling malformed programs
 
 scenario run-shows-warnings-in-get [