From 4bbd3ded0b767ae0919551776e4c17189140e735 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sat, 30 May 2015 19:30:33 -0700 Subject: 1517 --- html/000organization.cc.html | 8 +- html/001help.cc.html | 4 +- html/002test.cc.html | 8 +- html/003trace.cc.html | 19 +- html/003trace.test.cc.html | 6 +- html/010vm.cc.html | 8 +- html/011load.cc.html | 10 +- html/012transform.cc.html | 6 +- html/013literal_string.cc.html | 33 +- html/014literal_noninteger.cc.html | 6 +- html/020run.cc.html | 12 +- html/021arithmetic.cc.html | 6 +- html/022boolean.cc.html | 6 +- html/023jump.cc.html | 8 +- html/024compare.cc.html | 6 +- html/025trace.cc.html | 8 +- html/026assert.cc.html | 8 +- html/027debug.cc.html | 6 +- html/030container.cc.html | 43 ++- html/031address.cc.html | 10 +- html/032array.cc.html | 19 +- html/034exclusive_container.cc.html | 19 +- html/035call.cc.html | 8 +- html/036call_ingredient.cc.html | 6 +- html/037call_reply.cc.html | 14 +- html/038scheduler.cc.html | 16 +- html/039wait.cc.html | 8 +- html/040brace.cc.html | 8 +- html/041name.cc.html | 34 +- html/042new.cc.html | 52 ++- html/043space.cc.html | 16 +- html/044space_surround.cc.html | 8 +- html/045closure_name.cc.html | 8 +- html/046tangle.cc.html | 8 +- html/047jump_label.cc.html | 10 +- html/048call_variable.cc.html | 8 +- html/049continuation.cc.html | 12 +- html/050scenario.cc.html | 95 ++++-- html/051scenario_test.mu.html | 6 +- html/060string.mu.html | 36 +- html/061channel.mu.html | 10 +- html/062array.mu.html | 8 +- html/063list.mu.html | 8 +- html/064random.cc.html | 8 +- html/070display.cc.html | 24 +- html/071print.mu.html | 111 ++++-- html/072scenario_screen.cc.html | 127 +++++-- html/073scenario_screen_test.mu.html | 6 +- html/074keyboard.mu.html | 12 +- html/075scenario_keyboard.cc.html | 30 +- html/076scenario_keyboard_test.mu.html | 6 +- html/077trace_browser.cc.html | 23 +- html/999spaces.cc.html | 4 +- html/callcc.mu.html | 10 +- html/channel.mu.html | 6 +- html/chessboard.mu.html | 17 +- html/counters.mu.html | 6 +- html/display.mu.html | 6 +- html/factorial.mu.html | 8 +- html/fork.mu.html | 6 +- html/keyboard.mu.html | 6 +- html/repl.mu.html | 606 +++++++++++++++++++++++++++++++++ html/screen.mu.html | 8 +- html/tangle.mu.html | 6 +- html/x.mu.html | 6 +- 65 files changed, 1320 insertions(+), 360 deletions(-) create mode 100644 html/repl.mu.html (limited to 'html') diff --git a/html/000organization.cc.html b/html/000organization.cc.html index 3767d420..6ec61434 100644 --- a/html/000organization.cc.html +++ b/html/000organization.cc.html @@ -10,14 +10,14 @@ diff --git a/html/001help.cc.html b/html/001help.cc.html index 9fd816a7..d131b7a4 100644 --- a/html/001help.cc.html +++ b/html/001help.cc.html @@ -10,8 +10,8 @@ @@ -86,6 +87,7 @@ if (Run_tests) ; time(&t); cerr << "C tests: " << ctime(&t); for (size_t i=0; i < sizeof(Tests)/sizeof(Tests[0]); ++i) { +//? cerr << i << '\n'; //? 1 run_test(i); } // End Tests diff --git a/html/003trace.cc.html b/html/003trace.cc.html index 2fe22df3..2c04a850 100644 --- a/html/003trace.cc.html +++ b/html/003trace.cc.html @@ -10,17 +10,16 @@ @@ -213,9 +212,12 @@ ostream& operator<<(ostream& os#define DUMP(layer) if (Trace_stream) cerr << Trace_stream->readable_contents(layer); -// Trace_stream is a resource, lease_tracer uses RAII to manage it. -string Trace_file; +// All scenarios save their traces in the repo, just like code. This gives +// future readers more meat when they try to make sense of a new project. static string Trace_dir = ".traces/"; +string Trace_file; + +// Trace_stream is a resource, lease_tracer uses RAII to manage it. struct lease_tracer { lease_tracer() { Trace_stream = new trace_stream; } ~lease_tracer() { @@ -230,9 +232,6 @@ struct lease_tracer { } }; -// To transparently save traces, start tests with the TEST() macro. -#define TEST(name) void test_##name() { Trace_file = #name; - #define START_TRACING_UNTIL_END_OF_SCOPE lease_tracer leased_tracer; :(before "End Test Setup") START_TRACING_UNTIL_END_OF_SCOPE diff --git a/html/003trace.test.cc.html b/html/003trace.test.cc.html index d32bdc77..704fd64e 100644 --- a/html/003trace.test.cc.html +++ b/html/003trace.test.cc.html @@ -10,12 +10,12 @@ diff --git a/html/010vm.cc.html b/html/010vm.cc.html index 5545f2ae..5a971a6d 100644 --- a/html/010vm.cc.html +++ b/html/010vm.cc.html @@ -10,17 +10,17 @@ diff --git a/html/011load.cc.html b/html/011load.cc.html index ed5f8bb3..7b1807c5 100644 --- a/html/011load.cc.html +++ b/html/011load.cc.html @@ -10,17 +10,17 @@ @@ -34,7 +34,7 @@ body { font-family: monospace; color: #d0d0d0; background-color: #000000; }
 //: Phase 1 of running mu code: load it from a textual representation.
 
-:(scenarios load)
+:(scenarios load)  // use 'load' instead of 'run' in all scenarios in this layer
 :(scenario first_recipe)
 recipe main [
   1:number <- copy 23:literal
diff --git a/html/012transform.cc.html b/html/012transform.cc.html
index 0ebf0874..aca6b62b 100644
--- a/html/012transform.cc.html
+++ b/html/012transform.cc.html
@@ -10,14 +10,14 @@
 
 
 
diff --git a/html/013literal_string.cc.html b/html/013literal_string.cc.html
index 51b60ee4..19683498 100644
--- a/html/013literal_string.cc.html
+++ b/html/013literal_string.cc.html
@@ -10,16 +10,17 @@
 
 
 
@@ -67,15 +68,23 @@ string slurp_quoted(istream& in(!in.eof());
   assert(in.peek() == '[');
   ostringstream out;
-  int size = 0;
+  int brace_depth = 0;
   while (!in.eof()) {
     char c = in.get();
-//?     cout << c << '\n'; //? 1
+//?     cout << (int)c << ": " << brace_depth << '\n'; //? 2
+    if (c == '\\') {
+      out << (char)in.get();
+      continue;
+    }
     out << c;
 //?     cout << out.str() << "$\n"; //? 1
-    if (c == '[') ++size;
-    if (c == ']') --size;
-    if (size == 0) break;
+    if (c == '[') ++brace_depth;
+    if (c == ']') --brace_depth;
+    if (brace_depth == 0) break;
+  }
+  if (in.eof() && brace_depth > 0) {
+    raise << "unbalanced '['\n";
+    return "";
   }
   return out.str();
 }
@@ -100,6 +109,12 @@ recipe main [
 ]
 +parse:   ingredient: {name: "abc [def]", properties: ["abc [def]": "literal-string"]}
 
+:(scenario string_literal_escaped)
+recipe main [
+  1:address:array:character <- copy [abc \[def]
+]
++parse:   ingredient: {name: "abc [def", properties: ["abc [def": "literal-string"]}
+
 :(scenario string_literal_and_comment)
 recipe main [
   1:address:array:character <- copy [abc]  # comment
diff --git a/html/014literal_noninteger.cc.html b/html/014literal_noninteger.cc.html
index 20d580cb..9c9b9286 100644
--- a/html/014literal_noninteger.cc.html
+++ b/html/014literal_noninteger.cc.html
@@ -10,16 +10,16 @@
 
 
 
diff --git a/html/020run.cc.html b/html/020run.cc.html
index 5a02657c..2c39d12c 100644
--- a/html/020run.cc.html
+++ b/html/020run.cc.html
@@ -10,19 +10,19 @@
 
 
 
diff --git a/html/021arithmetic.cc.html b/html/021arithmetic.cc.html
index 5f041ea7..321d66f0 100644
--- a/html/021arithmetic.cc.html
+++ b/html/021arithmetic.cc.html
@@ -10,15 +10,15 @@
 
 
 
diff --git a/html/022boolean.cc.html b/html/022boolean.cc.html
index 66e35c16..72539bf2 100644
--- a/html/022boolean.cc.html
+++ b/html/022boolean.cc.html
@@ -10,15 +10,15 @@
 
 
 
diff --git a/html/023jump.cc.html b/html/023jump.cc.html
index 0cf48bbf..842651db 100644
--- a/html/023jump.cc.html
+++ b/html/023jump.cc.html
@@ -10,16 +10,16 @@
 
 
 
diff --git a/html/024compare.cc.html b/html/024compare.cc.html
index 9bb84e86..1a145d00 100644
--- a/html/024compare.cc.html
+++ b/html/024compare.cc.html
@@ -10,15 +10,15 @@
 
 
 
diff --git a/html/025trace.cc.html b/html/025trace.cc.html
index 5ee0e70b..7951bfb5 100644
--- a/html/025trace.cc.html
+++ b/html/025trace.cc.html
@@ -10,14 +10,14 @@
 
 
 
@@ -47,7 +47,7 @@ case TRACE: {
   string label = current_instruction().ingredients.at(0).name;
   assert(isa_literal(current_instruction().ingredients.at(1)));
   string message = current_instruction().ingredients.at(1).name;
-  trace(label) << message;
+  trace(1, label) << message;
   break;
 }
 
diff --git a/html/026assert.cc.html b/html/026assert.cc.html
index 66ff0180..2cfeff0d 100644
--- a/html/026assert.cc.html
+++ b/html/026assert.cc.html
@@ -10,15 +10,15 @@
 
 
 
@@ -31,7 +31,7 @@ body { font-family: monospace; color: #d0d0d0; background-color: #000000; }
 
 
 :(scenario assert)
-% Hide_warnings = true;
+% Hide_warnings = true;  // '%' lines insert arbitrary C code into tests before calling 'run' with the lines below. Must be immediately after :(scenario) line.
 recipe main [
   assert 0:literal, [this is an assert in mu]
 ]
diff --git a/html/027debug.cc.html b/html/027debug.cc.html
index 61a5577b..1cfa4300 100644
--- a/html/027debug.cc.html
+++ b/html/027debug.cc.html
@@ -10,14 +10,14 @@
 
 
 
diff --git a/html/030container.cc.html b/html/030container.cc.html
index 4da2e138..5e7b1ff1 100644
--- a/html/030container.cc.html
+++ b/html/030container.cc.html
@@ -10,19 +10,19 @@
 
 
 
@@ -50,11 +50,14 @@ Type[point].elements.//: Containers can be copied around with a single instruction just like
 //: numbers, no matter how large they are.
 
+//: Tests in this layer often explicitly setup memory before reading it as a
+//: container. Don't do this in general. I'm tagging exceptions with /raw to
+//: avoid warnings.
 :(scenario copy_multiple_locations)
 recipe main [
   1:number <- copy 34:literal
   2:number <- copy 35:literal
-  3:point <- copy 1:point
+  3:point <- copy 1:point/raw  # unsafe
 ]
 +mem: storing 34 in location 3
 +mem: storing 35 in location 4
@@ -78,7 +81,7 @@ recipe main [
   12:number <- copy 34:literal
   13:number <- copy 35:literal
   14:number <- copy 36:literal
-  15:point-number <- copy 12:point-number
+  15:point-number <- copy 12:point-number/raw  # unsafe
 ]
 +mem: storing 36 in location 17
 
@@ -93,7 +96,7 @@ recipe main [
   4:number <- copy 34:literal  # second
   5:number <- copy 35:literal
   6:number <- copy 36:literal
-  7:boolean <- equal 1:point-number, 4:point-number
+  7:boolean <- equal 1:point-number/raw, 4:point-number/raw  # unsafe
 ]
 +mem: storing 1 in location 7
 
@@ -105,7 +108,7 @@ recipe main [
   4:number <- copy 34:literal  # second
   5:number <- copy 35:literal
   6:number <- copy 37:literal  # different
-  7:boolean <- equal 1:point-number, 4:point-number
+  7:boolean <- equal 1:point-number/raw, 4:point-number/raw  # unsafe
 ]
 +mem: storing 0 in location 7
 
@@ -127,7 +130,7 @@ if (t.kind == cont
 recipe main [
   12:number <- copy 34:literal
   13:number <- copy 35:literal
-  15:number <- get 12:point, 1:offset
+  15:number <- get 12:point/raw, 1:offset  # unsafe
 ]
 +mem: storing 35 in location 15
 
@@ -165,7 +168,7 @@ recipe main [
   12:number <- copy 34:literal
   13:number <- copy 35:literal
   14:number <- copy 36:literal
-  15:number <- get 12:point-number, 1:offset
+  15:number <- get 12:point-number/raw, 1:offset  # unsafe
 ]
 +mem: storing 36 in location 15
 
@@ -175,7 +178,7 @@ recipe main [
 recipe main [
   12:number <- copy 34:literal
   13:number <- copy 35:literal
-  15:address:number <- get-address 12:point, 1:offset
+  15:address:number <- get-address 12:point/raw, 1:offset  # unsafe
 ]
 +mem: storing 13 in location 15
 
@@ -372,6 +375,18 @@ container foo [
 ]
 +warn: unknown type for field y in foo
 
+:(scenario read_container_with_bracket_in_comment)
+container foo [
+  x:number
+  # ']' in comment
+  y:number
+]
++parse: reading container foo
++parse:   element name: x
++parse:   type: 1
++parse:   element name: y
++parse:   type: 1
+
 :(before "End Load Sanity Checks")
 check_container_field_types();
 
diff --git a/html/031address.cc.html b/html/031address.cc.html
index 35bc04e3..de366c9a 100644
--- a/html/031address.cc.html
+++ b/html/031address.cc.html
@@ -10,17 +10,17 @@
 
 
 
diff --git a/html/032array.cc.html b/html/032array.cc.html
index cac483a1..ac8d1636 100644
--- a/html/032array.cc.html
+++ b/html/032array.cc.html
@@ -13,15 +13,15 @@
 pre { white-space: pre-wrap; font-family: monospace; color: #d0d0d0; background-color: #080808; }
 body { font-family: monospace; color: #d0d0d0; background-color: #080808; }
 * { font-size: 1em; }
+.traceContains { color: #008000; }
 .cSpecial { color: #008000; }
-.CommentedCode { color: #6c6c6c; }
 .Constant { color: #008080; }
+.SalientComment { color: #00ffff; }
 .Comment { color: #8080ff; }
 .Delimiter { color: #c000c0; }
 .Special { color: #ff6060; }
 .Identifier { color: #008080; }
-.SalientComment { color: #00ffff; }
-.traceContains { color: #008000; }
+.CommentedCode { color: #6c6c6c; }
 -->
 
 
@@ -40,6 +40,9 @@ body { font-family: monospace; color: #d0d0d0; background-color: #080808; }
 //: elements of a fixed size, so you can't create containers containing arrays.
 //: Create containers containing addresses to arrays instead.
 
+//: Tests in this layer often explicitly setup memory before reading it as an
+//: array. Don't do this in general. I'm tagging exceptions with /raw to
+//: avoid warnings.
 :(scenario copy_array)
 # Arrays can be copied around with a single instruction just like numbers,
 # no matter how large they are.
@@ -48,7 +51,7 @@ recipe main [
   2:number <- copy 14:literal
   3:number <- copy 15:literal
   4:number <- copy 16:literal
-  5:array:number <- copy 1:array:number
+  5:array:number <- copy 1:array:number/raw  # unsafe
 ]
 +mem: storing 3 in location 5
 +mem: storing 14 in location 6
@@ -87,7 +90,7 @@ recipe main [
   2:number <- copy 14:literal
   3:number <- copy 15:literal
   4:number <- copy 16:literal
-  5:number <- index 1:array:number, 0:literal
+  5:number <- index 1:array:number/raw, 0:literal  # unsafe
 ]
 +mem: storing 14 in location 5
 
@@ -98,7 +101,7 @@ recipe main [
   3:number <- copy 15:literal
   4:number <- copy 16:literal
   5:number <- copy 0:literal
-  6:number <- index 1:array:number, 5:number
+  6:number <- index 1:array:number/raw, 5:number  # unsafe
 ]
 +mem: storing 14 in location 6
 
@@ -140,7 +143,7 @@ recipe main [
   2:number <- copy 14:literal
   3:number <- copy 15:literal
   4:number <- copy 16:literal
-  5:number <- index-address 1:array:number, 0:literal
+  5:number <- index-address 1:array:number/raw, 0:literal  # unsafe
 ]
 +mem: storing 2 in location 5
 
@@ -183,7 +186,7 @@ recipe main [
   2:number <- copy 14:literal
   3:number <- copy 15:literal
   4:number <- copy 16:literal
-  5:number <- length 1:array:number
+  5:number <- length 1:array:number/raw  # unsafe
 ]
 +mem: storing 3 in location 5
 
diff --git a/html/034exclusive_container.cc.html b/html/034exclusive_container.cc.html
index 3da49c53..842c2789 100644
--- a/html/034exclusive_container.cc.html
+++ b/html/034exclusive_container.cc.html
@@ -10,17 +10,17 @@
 
 
 
@@ -59,13 +59,16 @@ Type[tmp].element_names.<
 Type[tmp].element_names.push_back("p");
 }
 
+//: Tests in this layer often explicitly setup memory before reading it as an
+//: array. Don't do this in general. I'm tagging exceptions with /raw to
+//: avoid warnings.
 :(scenario copy_exclusive_container)
 # Copying exclusive containers copies all their contents and an extra location for the tag.
 recipe main [
   1:number <- copy 1:literal  # 'point' variant
   2:number <- copy 34:literal
   3:number <- copy 35:literal
-  4:number-or-point <- copy 1:number-or-point
+  4:number-or-point <- copy 1:number-or-point/raw  # unsafe
 ]
 +mem: storing 1 in location 4
 +mem: storing 34 in location 5
@@ -103,7 +106,7 @@ recipe main [
   12:number <- copy 1:literal
   13:number <- copy 35:literal
   14:number <- copy 36:literal
-  20:address:point <- maybe-convert 12:number-or-point, 1:variant
+  20:address:point <- maybe-convert 12:number-or-point/raw, 1:variant  # unsafe
 ]
 +mem: storing 13 in location 20
 
@@ -112,7 +115,7 @@ recipe main [
   12:number <- copy 1:literal
   13:number <- copy 35:literal
   14:number <- copy 36:literal
-  20:address:point <- maybe-convert 12:number-or-point, 0:variant
+  20:address:point <- maybe-convert 12:number-or-point/raw, 0:variant  # unsafe
 ]
 +mem: storing 0 in location 20
 
diff --git a/html/035call.cc.html b/html/035call.cc.html
index 5ba49098..73ba8d07 100644
--- a/html/035call.cc.html
+++ b/html/035call.cc.html
@@ -10,18 +10,18 @@
 
 
 
diff --git a/html/036call_ingredient.cc.html b/html/036call_ingredient.cc.html
index 15645498..45c81074 100644
--- a/html/036call_ingredient.cc.html
+++ b/html/036call_ingredient.cc.html
@@ -10,15 +10,15 @@
 
 
 
diff --git a/html/037call_reply.cc.html b/html/037call_reply.cc.html
index 22509da6..60363350 100644
--- a/html/037call_reply.cc.html
+++ b/html/037call_reply.cc.html
@@ -10,16 +10,17 @@
 
 
 
@@ -53,6 +54,10 @@ Recipe_number["reply"] = REPLY{
   const instruction& reply_inst = current_instruction();  // save pointer into recipe before pop
   --Callstack_depth;
+//?   if (tb_is_active()) { //? 1
+//?     tb_clear(); //? 1
+//?     cerr << Recipe[Current_routine->calls.front().running_recipe].name << ' ' << current_step_index() << '\n'; //? 1
+//?   } //? 1
   Current_routine->calls.pop_front();
   // just in case 'main' returns a value, drop it for now
   if (Current_routine->calls.empty()) goto stop_running_current_routine;
@@ -62,6 +67,7 @@ case REPLY: {
   // check that any reply ingredients with /same-as-ingredient connect up
   // the corresponding ingredient and product in the caller.
   for (long long int i = 0; i < SIZE(caller_instruction.products); ++i) {
+//?     cerr << Recipe[Current_routine->calls.front().running_recipe].name << '\n'; //? 1
     trace(Primitive_recipe_depth, "run") << "result " << i << " is " << to_string(ingredients.at(i));
     if (has_property(reply_inst.ingredients.at(i), "same-as-ingredient")) {
       vector<string> tmp = property(reply_inst.ingredients.at(i), "same-as-ingredient");
@@ -84,7 +90,7 @@ recipe main [
 recipe f [
   12:number <- next-ingredient
   13:number <- copy 35:literal
-  reply 12:point
+  reply 12:point/raw  # unsafe
 ]
 +run: result 0 is [2, 35]
 +mem: storing 2 in location 3
diff --git a/html/038scheduler.cc.html b/html/038scheduler.cc.html
index 8bdb1488..abf7f469 100644
--- a/html/038scheduler.cc.html
+++ b/html/038scheduler.cc.html
@@ -10,19 +10,19 @@
 
 
 
@@ -246,9 +246,9 @@ recipe f2 [
 ]
 +mem: storing 2 in location 1
 
+//: this scenario will require some careful setup in escaped C++
+//: (straining our tangle capabilities to near-breaking point)
 :(scenario scheduler_skips_completed_routines)
-# this scenario will require some careful setup in escaped C++
-# (straining our tangle capabilities to near-breaking point)
 % recipe_number f1 = load("recipe f1 [\n1:number <- copy 0:literal\n]").front();
 % recipe_number f2 = load("recipe f2 [\n2:number <- copy 0:literal\n]").front();
 % Routines.push_back(new routine(f1));  // f1 meant to run
diff --git a/html/039wait.cc.html b/html/039wait.cc.html
index b5325799..fb60ffc8 100644
--- a/html/039wait.cc.html
+++ b/html/039wait.cc.html
@@ -10,17 +10,17 @@
 
 
 
diff --git a/html/040brace.cc.html b/html/040brace.cc.html
index d864ce4f..c6c12f8c 100644
--- a/html/040brace.cc.html
+++ b/html/040brace.cc.html
@@ -10,16 +10,16 @@
 
 
 
diff --git a/html/041name.cc.html b/html/041name.cc.html
index 35e2067e..ee937835 100644
--- a/html/041name.cc.html
+++ b/html/041name.cc.html
@@ -10,19 +10,19 @@
 
 
 
@@ -67,6 +67,7 @@ void transform_names(const recipe_number rfalse;
   bool numeric_locations_used = false;
   map<string, long long int>& names = Name[r];
+  map<string, vector<type_number> > metadata;
   // store the indices 'used' so far in the map
   long long int& curr_idx = names[""];
   ++curr_idx;  // avoid using index 0, benign skip in some other cases
@@ -75,6 +76,7 @@ void transform_names(const recipe_number r// Per-recipe Transforms
     // map names to addresses
     for (long long int in = 0; in < SIZE(inst.ingredients); ++in) {
+      check_metadata(metadata, inst.ingredients.at(in), r);
       if (is_numeric_location(inst.ingredients.at(in))) numeric_locations_used = true;
       if (is_named_location(inst.ingredients.at(in))) names_used = true;
       if (disqualified(inst.ingredients.at(in))) continue;
@@ -84,6 +86,7 @@ void transform_names(const recipe_number r.ingredients.at(in).set_value(lookup_name(inst.ingredients.at(in), r));
     }
     for (long long int out = 0; out < SIZE(inst.products); ++out) {
+      check_metadata(metadata, inst.products.at(out), r);
       if (is_numeric_location(inst.products.at(out))) numeric_locations_used = true;
       if (is_named_location(inst.products.at(out))) names_used = true;
       if (disqualified(inst.products.at(out))) continue;
@@ -99,6 +102,15 @@ void transform_names(const recipe_number r"mixing variable names and numeric addresses in " << Recipe[r].name << '\n';
 }
 
+void check_metadata(map<string, vector<type_number> >& metadata, const reagent& x, const recipe_number r) {
+  if (isa_literal(x)) return;
+  if (is_raw(x)) return;
+  if (metadata.find(x.name) == metadata.end())
+    metadata[x.name] = x.types;
+  if (metadata[x.name] != x.types)
+    raise << x.name << " used with multiple types in " << Recipe[r].name << '\n';
+}
+
 bool disqualified(/*mutable*/ reagent& x) {
   if (x.types.empty())
     raise << "missing type in " << x.to_string() << '\n';
@@ -216,6 +228,14 @@ recipe main [
 ]
 -warn: mixing variable names and numeric addresses in main
 
+:(scenario convert_names_warns_on_reusing_name_with_different_type)
+% Hide_warnings = true;
+recipe main [
+  x:number <- copy 1:literal
+  x:boolean <- copy 1:literal
+]
++warn: x used with multiple types in main
+
 //:: Support element names for containers in 'get' and 'get-address'.
 
 //: update our running example container for the next test
@@ -264,7 +284,7 @@ recipe main [
   12:number <- copy 1:literal
   13:number <- copy 35:literal
   14:number <- copy 36:literal
-  20:address:point <- maybe-convert 12:number-or-point, p:variant
+  20:address:point <- maybe-convert 12:number-or-point/raw, p:variant  # unsafe
 ]
 +name: variant p of type number-or-point has tag 1
 +mem: storing 13 in location 20
diff --git a/html/042new.cc.html b/html/042new.cc.html
index ad722ef0..b19775ab 100644
--- a/html/042new.cc.html
+++ b/html/042new.cc.html
@@ -10,18 +10,19 @@
 
 
 
@@ -194,7 +195,7 @@ recipe main [
 +new: routine allocated memory from 1000 to 1002
 +new: routine allocated memory from 1002 to 1004
 
-//:: Next, extend 'new' to handle a string literal argument.
+//:: Next, extend 'new' to handle a unicode string literal argument.
 
 :(scenario new_string)
 recipe main [
@@ -204,6 +205,16 @@ recipe main [
 # number code for 'e'
 +mem: storing 101 in location 2
 
+:(scenario new_string_handles_unicode)
+recipe main [
+  1:address:array:character <- new [a«c]
+  2:number <- length 1:address:array:character/deref
+  3:character <- index 1:address:array:character/deref, 1:literal
+]
++mem: storing 3 in location 2
+# unicode for '«'
++mem: storing 171 in location 3
+
 :(before "End NEW Transform Special-cases")
   if (inst.ingredients.at(0).properties.at(0).second.at(0) == "literal-string") {
     // skip transform
@@ -215,7 +226,7 @@ recipe main [
 if (isa_literal(current_instruction().ingredients.at(0))
     && current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "literal-string") {
   // allocate an array just large enough for it
-  long long int string_length = SIZE(current_instruction().ingredients.at(0).name);
+  long long int string_length = unicode_length(current_instruction().ingredients.at(0).name);
 //?   cout << "string_length is " << string_length << '\n'; //? 1
   ensure_space(string_length+1);  // don't forget the extra location for array size
   products.resize(1);
@@ -223,8 +234,16 @@ if (isa_literal(cu
   // initialize string
 //?   cout << "new string literal: " << current_instruction().ingredients.at(0).name << '\n'; //? 1
   Memory[Current_routine->alloc++] = string_length;
+  long long int curr = 0;
+  const string& contents = current_instruction().ingredients.at(0).name;
+  const char* raw_contents = contents.c_str();
   for (long long int i = 0; i < string_length; ++i) {
-    Memory[Current_routine->alloc++] = current_instruction().ingredients.at(0).name.at(i);
+    uint32_t curr_character;
+    assert(curr < SIZE(contents));
+    tb_utf8_char_to_unicode(&curr_character, &raw_contents[curr]);
+    Memory[Current_routine->alloc] = curr_character;
+    curr += tb_utf8_char_length(raw_contents[curr]);
+    ++Current_routine->alloc;
   }
   // mu strings are not null-terminated in memory
   break;
@@ -239,6 +258,23 @@ recipe main [
 ]
 +new: routine allocated memory from 1000 to 1002
 +new: routine allocated memory from 1002 to 1004
+
+//: helpers
+:(code)
+long long int unicode_length(const string& s) {
+  const char* in = s.c_str();
+  long long int result = 0;
+  long long int curr = 0;
+  while (curr < SIZE(s)) {  // carefully bounds-check on the string
+    // before accessing its raw pointer
+    ++result;
+    curr += tb_utf8_char_length(in[curr]);
+  }
+  return result;
+}
+
+:(before "End Includes")
+#include"termbox/termbox.h"  // for unicode primitives
 
diff --git a/html/043space.cc.html b/html/043space.cc.html index 6de55942..05e1c8d3 100644 --- a/html/043space.cc.html +++ b/html/043space.cc.html @@ -10,19 +10,19 @@ @@ -153,7 +153,7 @@ long long int address(long long int offset//? cout << base << '\n'; //? 2 if (offset >= static_cast<long long int>(Memory[base])) { // todo: test - raise << "location " << offset << " is out of bounds " << Memory[base] << '\n'; + raise << "location " << offset << " is out of bounds " << Memory[base] << " at " << base << '\n'; } return base+1 + offset; } diff --git a/html/044space_surround.cc.html b/html/044space_surround.cc.html index c2b69607..74620675 100644 --- a/html/044space_surround.cc.html +++ b/html/044space_surround.cc.html @@ -10,16 +10,16 @@ diff --git a/html/045closure_name.cc.html b/html/045closure_name.cc.html index d76f6297..1520e46b 100644 --- a/html/045closure_name.cc.html +++ b/html/045closure_name.cc.html @@ -10,17 +10,17 @@ diff --git a/html/046tangle.cc.html b/html/046tangle.cc.html index fc8f475a..9604310f 100644 --- a/html/046tangle.cc.html +++ b/html/046tangle.cc.html @@ -10,16 +10,16 @@ diff --git a/html/047jump_label.cc.html b/html/047jump_label.cc.html index 44a23965..4547dcb2 100644 --- a/html/047jump_label.cc.html +++ b/html/047jump_label.cc.html @@ -10,18 +10,18 @@ diff --git a/html/048call_variable.cc.html b/html/048call_variable.cc.html index 286c83c1..6d7bf3b4 100644 --- a/html/048call_variable.cc.html +++ b/html/048call_variable.cc.html @@ -10,16 +10,16 @@ diff --git a/html/049continuation.cc.html b/html/049continuation.cc.html index 2cf647ca..341d6fa9 100644 --- a/html/049continuation.cc.html +++ b/html/049continuation.cc.html @@ -10,18 +10,18 @@ diff --git a/html/050scenario.cc.html b/html/050scenario.cc.html index fa3c0d55..92d38825 100644 --- a/html/050scenario.cc.html +++ b/html/050scenario.cc.html @@ -10,19 +10,19 @@ @@ -107,15 +107,30 @@ else if (command == " :(code) scenario parse_scenario(istream& in) { +//? cerr << "parse scenario\n"; //? 1 scenario result; result.name = next_word(in); - skip_bracket(in, "'scenario' must begin with '['"); - ostringstream buffer; - slurp_until_matching_bracket(in, buffer); - result.to_run = buffer.str(); + skip_whitespace_and_comments(in); + assert(in.peek() == '['); + // scenarios are take special 'code' strings so we need to ignore brackets + // inside comments + result.to_run = slurp_quoted_ignoring_comments(in); return result; } +:(scenario read_scenario_with_bracket_in_comment) +scenario foo [ + # ']' in comment + 1:number <- copy 0:literal +] ++run: 1:number <- copy 0:literal + +:(scenario read_scenario_with_bracket_in_comment_in_nested_string) +scenario foo [ + 1:address:array:character <- new [# not a comment] +] ++run: 1:address:array:character <- new [# not a comment] + //:: Run scenarios when we run 'mu test'. //: Treat the text of the scenario as a regular series of instructions. @@ -124,7 +139,7 @@ time_t mu_time; time("\nMu tests: " << ctime(&mu_time); for (long long int i = 0; i < SIZE(Scenarios); ++i) { //? cerr << Passed << '\n'; //? 1 -//? cerr << i << ": " << Scenarios.at(i).name << '\n'; //? 3 +//? cerr << i << ": " << Scenarios.at(i).name << '\n'; //? 5 run_mu_scenario(Scenarios.at(i)); if (Passed) cerr << "."; } @@ -151,6 +166,7 @@ void run_mu_scenario(const scenario& s; setup(); } +//? cerr << '^' << s.to_run << "$\n"; //? 1 run("recipe "+s.name+" [ " + s.to_run + " ]"); if (not_already_inside_test && Trace_stream) { teardown(); @@ -229,6 +245,7 @@ MEMORY_SHOULD_CONTAIN, Recipe_number["memory-should-contain"] = MEMORY_SHOULD_CONTAIN; :(before "End Primitive Recipe Implementations") case MEMORY_SHOULD_CONTAIN: { + if (!Passed) break; //? cout << current_instruction().ingredients.at(0).name << '\n'; //? 1 check_memory(current_instruction().ingredients.at(0).name); break; @@ -256,11 +273,18 @@ void check_memory(const string& s"duplicate expectation for location " << address << '\n'; trace(Primitive_recipe_depth, "run") << "checking location " << address; if (Memory[address] != value) { - if (Current_scenario) + if (Current_scenario && !Hide_warnings) { + // genuine test in a mu file raise << "\nF - " << Current_scenario->name << ": expected location " << address << " to contain " << value << " but saw " << Memory[address] << '\n'; - else + } + else { + // just testing scenario support raise << "expected location " << address << " to contain " << value << " but saw " << Memory[address] << '\n'; - Passed = false; + } + if (!Hide_warnings) { + Passed = false; + ++Num_failures; + } return; } locations_checked.insert(address); @@ -303,10 +327,14 @@ void check_string(long long int address(long long int i = 0; i < SIZE(literal); ++i) { trace(Primitive_recipe_depth, "run") << "checking location " << address+i; if (Memory[address+i] != literal.at(i)) { - if (Current_scenario && !Hide_warnings) + if (Current_scenario && !Hide_warnings) { + // genuine test in a mu file raise << "\nF - " << Current_scenario->name << ": expected location " << (address+i) << " to contain " << literal.at(i) << " but saw " << Memory[address+i] << '\n'; - else + } + else { + // just testing scenario support raise << "expected location " << (address+i) << " to contain " << literal.at(i) << " but saw " << Memory[address+i] << '\n'; + } if (!Hide_warnings) { Passed = false; ++Num_failures; @@ -380,6 +408,7 @@ TRACE_SHOULD_CONTAIN, Recipe_number["trace-should-contain"] = TRACE_SHOULD_CONTAIN; :(before "End Primitive Recipe Implementations") case TRACE_SHOULD_CONTAIN: { + if (!Passed) break; check_trace(current_instruction().ingredients.at(0).name); break; } @@ -470,6 +499,7 @@ TRACE_SHOULD_NOT_CONTAIN, Recipe_number["trace-should-not-contain"] = TRACE_SHOULD_NOT_CONTAIN; :(before "End Primitive Recipe Implementations") case TRACE_SHOULD_NOT_CONTAIN: { + if (!Passed) break; check_trace_missing(current_instruction().ingredients.at(0).name); break; } @@ -517,24 +547,45 @@ recipe main [ :(code) // just for the scenarios running scenarios in C++ layers void run_mu_scenario(const string& form) { +//? cerr << form << '\n'; //? 1 istringstream in(form); in >> std::noskipws; + skip_whitespace_and_comments(in); string _scenario = next_word(in); -//? cout << _scenario << '\n'; //? 1 +//? cout << _scenario << '\n'; //? 2 assert(_scenario == "scenario"); scenario s = parse_scenario(in); run_mu_scenario(s); } -void slurp_until_matching_bracket(istream& in, ostream& out) { - int brace_depth = 1; // just scanned '[' +string slurp_quoted_ignoring_comments(istream& in) { + assert(in.get() == '['); // drop initial '[' char c; + ostringstream out; while (in >> c) { - if (c == '[') ++brace_depth; - if (c == ']') --brace_depth; - if (brace_depth == 0) break; // drop final ']' +//? cerr << c << '\n'; //? 3 + if (c == '#') { + // skip comment + in.putback(c); + skip_comment(in); + continue; + } + if (c == '[') { + // nested strings won't detect comments + // can't yet handle scenarios inside strings inside scenarios.. + in.putback(c); + out << slurp_quoted(in); +//? cerr << "snapshot: ^" << out.str() << "$\n"; //? 1 + continue; + } + if (c == ']') { + // must be at the outermost level; drop final ']' + break; + } out << c; } +//? cerr << "done\n"; //? 2 + return out.str(); }
diff --git a/html/051scenario_test.mu.html b/html/051scenario_test.mu.html index 46f28e16..4097cb74 100644 --- a/html/051scenario_test.mu.html +++ b/html/051scenario_test.mu.html @@ -10,13 +10,13 @@ diff --git a/html/060string.mu.html b/html/060string.mu.html index 90a06d40..ee17699c 100644 --- a/html/060string.mu.html +++ b/html/060string.mu.html @@ -10,17 +10,17 @@ @@ -313,6 +313,34 @@ container buffer [ reply result:address:array:character ] +recipe buffer-to-array [ + default-space:address:array:character <- new location:type, 30:literal + in:address:buffer <- next-ingredient + len:number <- get in:address:buffer/deref, length:offset +#? $print [size ], len:number, [ +#? ] #? 1 + s:address:array:character <- get in:address:buffer/deref, data:offset + { + # propagate null buffer + break-if s:address:array:character + reply 0:literal + } + # we can't just return s because it is usually the wrong length + result:address:array:character <- new character:type, len:number + i:number <- copy 0:literal + { +#? $print i:number #? 1 + done?:boolean <- greater-or-equal i:number, len:number + break-if done?:boolean + src:character <- index s:address:array:character/deref, i:number + dest:address:character <- index-address result:address:array:character/deref, i:number + dest:address:character/deref <- copy src:character + i:number <- add i:number, 1:literal + loop + } + reply result:address:array:character +] + scenario integer-to-decimal-digit-zero [ run [ 1:address:array:character/raw <- integer-to-decimal-string 0:literal diff --git a/html/061channel.mu.html b/html/061channel.mu.html index 3c27efcb..8860c45b 100644 --- a/html/061channel.mu.html +++ b/html/061channel.mu.html @@ -10,18 +10,18 @@ diff --git a/html/062array.mu.html b/html/062array.mu.html index 8aa099b6..b1909132 100644 --- a/html/062array.mu.html +++ b/html/062array.mu.html @@ -10,16 +10,16 @@ diff --git a/html/063list.mu.html b/html/063list.mu.html index 9c53db7d..87b1b52b 100644 --- a/html/063list.mu.html +++ b/html/063list.mu.html @@ -10,16 +10,16 @@ diff --git a/html/064random.cc.html b/html/064random.cc.html index 7056e553..d2157fda 100644 --- a/html/064random.cc.html +++ b/html/064random.cc.html @@ -10,16 +10,16 @@ diff --git a/html/070display.cc.html b/html/070display.cc.html index 590d1613..f18bcf20 100644 --- a/html/070display.cc.html +++ b/html/070display.cc.html @@ -10,17 +10,17 @@ @@ -105,6 +105,9 @@ case PRINT_CHARACTER_TO_DISPLAY: { long long int width = (w >= 0) ? w : 0; assert(scalar(ingredients.at(0))); long long int c = ingredients.at(0).at(0); +//? tb_shutdown(); //? 1 +//? cerr << "AAA " << c << ' ' << (int)'\n' << ' ' << (int)'\r' << '\n'; //? 1 +//? exit(1); //? 1 if (c == '\n' || c == '\r') { if (Display_row < height-1) { Display_column = 0; @@ -123,10 +126,13 @@ case PRINT_CHARACTER_TO_DISPLAY: { } break; } - int color = TB_WHITE; + int color = TB_DEFAULT; if (SIZE(ingredients) > 1) { assert(scalar(ingredients.at(1))); - color = ingredients.at(1).at(0); + color = ingredients.at(1).at(0)+1/*skip default*/; +//? tb_shutdown(); //? 1 +//? cerr << "AAA " << color << '\n'; //? 1 +//? exit(1); //? 1 } tb_change_cell(Display_column, Display_row, c, color, TB_DEFAULT); if (Display_column < width-1) { @@ -236,8 +242,12 @@ case WAIT_FOR_KEY_FROM_KEYBOARD: { do { tb_poll_event(&event); } while (event.type != TB_EVENT_KEY); + long long int result = event.key ? event.key : event.ch; + if (result == TB_KEY_CTRL_C) tb_shutdown(), exit(1); + if (result == TB_KEY_BACKSPACE2) result = TB_KEY_BACKSPACE; + if (result == TB_KEY_CARRIAGE_RETURN) result = TB_KEY_NEWLINE; products.resize(1); - products.at(0).push_back(event.ch); + products.at(0).push_back(result); break; } diff --git a/html/071print.mu.html b/html/071print.mu.html index 06e65a38..736cda4e 100644 --- a/html/071print.mu.html +++ b/html/071print.mu.html @@ -10,17 +10,17 @@ @@ -40,7 +40,12 @@ container screen [ num-columns:number cursor-row:number cursor-column:number - data:address:array:character + data:address:array:screen-cell +] + +container screen-cell [ + contents:character + color:number ] recipe init-fake-screen [ @@ -55,8 +60,8 @@ container screen [ column:address:number <- get-address result:address:screen/deref, cursor-column:offset column:address:number/deref <- copy 0:literal bufsize:number <- multiply width:address:number/deref, height:address:number/deref - buf:address:address:array:character <- get-address result:address:screen/deref, data:offset - buf:address:address:array:character/deref <- new character:type, bufsize:number + buf:address:address:array:screen-cell <- get-address result:address:screen/deref, data:offset + buf:address:address:array:screen-cell/deref <- new screen-cell:type, bufsize:number clear-screen result:address:screen reply result:address:screen ] @@ -70,14 +75,17 @@ container screen [ { break-unless x:address:screen # clear fake screen - buf:address:array:character <- get x:address:screen/deref, data:offset - max:number <- length buf:address:array:character/deref + buf:address:array:screen-cell <- get x:address:screen/deref, data:offset + max:number <- length buf:address:array:screen-cell/deref i:number <- copy 0:literal { done?:boolean <- greater-or-equal i:number, max:number break-if done?:boolean - c:address:character <- index-address buf:address:array:character/deref, i:number - c:address:character/deref <- copy [ ] + curr:address:screen-cell <- index-address buf:address:array:screen-cell/deref, i:number + curr-content:address:character <- get-address curr:address:screen-cell/deref, contents:offset + curr-content:address:character/deref <- copy [ ] + curr-color:address:character <- get-address curr:address:screen-cell/deref, color:offset + curr-color:address:character/deref <- copy 7:literal/white i:number <- add i:number, 1:literal loop } @@ -97,6 +105,12 @@ container screen [ default-space:address:array:location <- new location:type, 30:literal x:address:screen <- next-ingredient c:character <- next-ingredient + color:number, color-found?:boolean <- next-ingredient + { + # default color to white + break-if color-found?:boolean + color:number <- copy 7:literal/white + } { # if x exists # (handle special cases exactly like in the real screen) @@ -108,7 +122,7 @@ container screen [ max-row:number <- subtract height:number, 1:literal # special-case: newline { - newline?:boolean <- equal c:character, 10:literal/newlin + newline?:boolean <- equal c:character, 10:literal/newline #? $print c:character, [ ], newline?:boolean, [ #? ] #? 1 break-unless newline?:boolean @@ -125,8 +139,7 @@ container screen [ # save character in fake screen index:number <- multiply row:address:number/deref, width:number index:number <- add index:number, column:address:number/deref - buf:address:array:character <- get x:address:screen/deref, data:offset - cursor:address:character <- index-address buf:address:array:character/deref, index:number + buf:address:array:screen-cell <- get x:address:screen/deref, data:offset # special-case: backspace { backspace?:boolean <- equal c:character, 8:literal @@ -137,14 +150,22 @@ container screen [ break-if at-left?:boolean # clear previous location column:address:number/deref <- subtract column:address:number/deref, 1:literal - cursor:address:character <- subtract cursor:address:character, 1:literal - cursor:address:character/deref <- copy 32:literal/space + index:number <- subtract index:number, 1:literal + cursor:address:screen-cell <- index-address buf:address:array:screen-cell/deref, index:number + cursor-contents:address:character <- get-address cursor:address:screen-cell/deref, contents:offset + cursor-color:address:number <- get-address cursor:address:screen-cell/deref, color:offset + cursor-contents:address:character/deref <- copy 32:literal/space + cursor-color:address:number/deref <- copy 7:literal/white } reply x:address:screen/same-as-ingredient:0 } #? $print [saving character ], c:character, [ to fake screen ], cursor:address/screen, [ #? ] #? 1 - cursor:address:character/deref <- copy c:character + cursor:address:screen-cell <- index-address buf:address:array:screen-cell/deref, index:number + cursor-contents:address:character <- get-address cursor:address:screen-cell/deref, contents:offset + cursor-color:address:number <- get-address cursor:address:screen-cell/deref, color:offset + cursor-contents:address:character/deref <- copy c:character + cursor-color:address:number/deref <- copy color:number # increment column unless it's already all the way to the right { at-right?:boolean <- equal column:address:number/deref, width:number @@ -154,7 +175,7 @@ container screen [ reply x:address:screen/same-as-ingredient:0 } # otherwise, real screen - print-character-to-display c:character + print-character-to-display c:character, color:number reply x:address:screen/same-as-ingredient:0 ] @@ -163,13 +184,29 @@ container screen [ #? $start-tracing #? 3 1:address:screen <- init-fake-screen 3:literal/width, 2:literal/height 1:address:screen <- print-character 1:address:screen, 97:literal # 'a' - 2:address:array:character <- get 1:address:screen/deref, data:offset - 3:array:character <- copy 2:address:array:character/deref + 2:address:array:screen-cell <- get 1:address:screen/deref, data:offset + 3:array:screen-cell <- copy 2:address:array:screen-cell/deref + ] + memory-should-contain [ + 3 <- 6 # width*height + 4 <- 97 # 'a' + 5 <- 7 # white + 6 <- 0 + ] +] + +scenario print-character-color [ + run [ + 1:address:screen <- init-fake-screen 3:literal/width, 2:literal/height + 1:address:screen <- print-character 1:address:screen, 97:literal/a, 1:literal/red + 2:address:array:screen-cell <- get 1:address:screen/deref, data:offset + 3:array:screen-cell <- copy 2:address:array:screen-cell/deref ] memory-should-contain [ 3 <- 6 # width*height 4 <- 97 # 'a' - 5 <- 0 + 5 <- 1 # red + 6 <- 0 ] ] @@ -180,14 +217,15 @@ container screen [ 1:address:screen <- print-character 1:address:screen, 97:literal # 'a' 1:address:screen <- print-character 1:address:screen, 8:literal # backspace 2:number <- get 1:address:screen/deref, cursor-column:offset - 3:address:array:character <- get 1:address:screen/deref, data:offset - 4:array:character <- copy 3:address:array:character/deref + 3:address:array:screen-cell <- get 1:address:screen/deref, data:offset + 4:array:screen-cell <- copy 3:address:array:screen-cell/deref ] memory-should-contain [ 2 <- 0 # cursor column 4 <- 6 # width*height 5 <- 32 # space, not 'a' - 6 <- 0 + 6 <- 7 # white + 7 <- 0 ] ] @@ -199,15 +237,16 @@ container screen [ 1:address:screen <- print-character 1:address:screen, 10:literal/newline 2:number <- get 1:address:screen/deref, cursor-row:offset 3:number <- get 1:address:screen/deref, cursor-column:offset - 4:address:array:character <- get 1:address:screen/deref, data:offset - 5:array:character <- copy 4:address:array:character/deref + 4:address:array:screen-cell <- get 1:address:screen/deref, data:offset + 5:array:screen-cell <- copy 4:address:array:screen-cell/deref ] memory-should-contain [ 2 <- 1 # cursor row 3 <- 0 # cursor column 5 <- 6 # width*height 6 <- 97 # 'a' - 7 <- 0 + 7 <- 7 # white + 8 <- 0 ] ] @@ -282,18 +321,24 @@ container screen [ 1:address:screen <- move-cursor 1:address:screen, 0:literal/row, 0:literal/column # clear line 1:address:screen <- clear-line 1:address:screen - 2:address:array:character <- get 1:address:screen/deref, data:offset - 3:array:character <- copy 2:address:array:character/deref + 2:address:array:screen-cell <- get 1:address:screen/deref, data:offset + 3:array:screen-cell <- copy 2:address:array:screen-cell/deref ] # screen should be blank memory-should-contain [ 3 <- 6 # width*height 4 <- 0 - 5 <- 0 + 5 <- 7 6 <- 0 - 7 <- 0 + 7 <- 7 8 <- 0 - 9 <- 0 + 9 <- 7 + 10 <- 0 + 11 <- 7 + 12 <- 0 + 13 <- 7 + 14 <- 0 + 15 <- 7 ] ] diff --git a/html/072scenario_screen.cc.html b/html/072scenario_screen.cc.html index ecf37ed3..093a0173 100644 --- a/html/072scenario_screen.cc.html +++ b/html/072scenario_screen.cc.html @@ -10,17 +10,17 @@ @@ -35,12 +35,13 @@ body { font-family: monospace; color: #d0d0d0; background-color: #000000; } //: Clean syntax to manipulate and check the screen in scenarios. //: Instructions 'assume-screen' and 'screen-should-contain' implicitly create //: a variable called 'screen' that is accessible inside other 'run' -//: instructions in the scenario. +//: instructions in the scenario. 'screen-should-contain' can check unicode +//: characters in the fake screen :(scenarios run_mu_scenario) :(scenario screen_in_scenario) scenario screen-in-scenario [ -#? $start-tracing +#? $start-tracing #? 2 assume-screen 5:literal/width, 3:literal/height run [ screen:address <- print-character screen:address, 97:literal # 'a' @@ -51,17 +52,50 @@ scenario screen-in-scenario [ . . . . ] -#? $exit +#? $exit #? 1 ] :(scenario screen_in_scenario_unicode) +scenario screen-in-scenario-unicode-color [ + assume-screen 5:literal/width, 3:literal/height + run [ + screen:address <- print-character screen:address, 955:literal/greek-small-lambda, 1:literal/red + screen:address <- print-character screen:address, 97:literal/a + ] + screen-should-contain [ + # 01234 + .λa . + . . + . . + ] +#? $exit +] + +:(scenario screen_in_scenario_color) # screen-should-contain can check unicode characters in the fake screen -scenario screen-in-scenario [ +scenario screen-in-scenario-color [ assume-screen 5:literal/width, 3:literal/height run [ - screen:address <- print-character screen:address, 955:literal # 'λ' + screen:address <- print-character screen:address, 955:literal/greek-small-lambda, 1:literal/red + screen:address <- print-character screen:address, 97:literal/a, 7:literal/white ] + # screen-should-contain shows everything screen-should-contain [ + # 01234 + .λa . + . . + . . + ] + # screen-should-contain-in-color filters out everything except the given + # color, all you see is the 'a' in white. + screen-should-contain-in-color 7:literal/white, [ + # 01234 + . a . + . . + . . + ] + # ..and the λ in red. + screen-should-contain-in-color 1:literal/red, [ # 01234 .λ . . . @@ -71,7 +105,6 @@ scenario screen-in-scenario [ ] :(scenario screen_in_scenario_error) -#? % cerr << "AAA\n"; % Hide_warnings = true; scenario screen-in-scenario-error [ assume-screen 5:literal/width, 3:literal/height @@ -87,6 +120,23 @@ scenario screen-in-scenario-error [ ] +warn: expected screen location (0, 0) to contain 98 ('b') instead of 97 ('a') +:(scenario screen_in_scenario_color_error) +% Hide_warnings = true; +# screen-should-contain can check unicode characters in the fake screen +scenario screen-in-scenario-color [ + assume-screen 5:literal/width, 3:literal/height + run [ + screen:address <- print-character screen:address, 97:literal/a, 1:literal/red + ] + screen-should-contain-in-color 2:literal/green, [ + # 01234 + .a . + . . + . . + ] +] ++warn: expected screen location (0, 0) to be in color 2 instead of 1 + //: allow naming just for 'screen' :(before "End is_special_name Cases") if (s == "screen") return true; @@ -132,8 +182,20 @@ SCREEN_SHOULD_CONTAIN, Recipe_number["screen-should-contain"] = SCREEN_SHOULD_CONTAIN; :(before "End Primitive Recipe Implementations") case SCREEN_SHOULD_CONTAIN: { -//? cout << "AAA\n"; //? 1 - check_screen(current_instruction().ingredients.at(0).name); + if (!Passed) break; + check_screen(current_instruction().ingredients.at(0).name, -1); + break; +} + +:(before "End Primitive Recipe Declarations") +SCREEN_SHOULD_CONTAIN_IN_COLOR, +:(before "End Primitive Recipe Numbers") +Recipe_number["screen-should-contain-in-color"] = SCREEN_SHOULD_CONTAIN_IN_COLOR; +:(before "End Primitive Recipe Implementations") +case SCREEN_SHOULD_CONTAIN_IN_COLOR: { + if (!Passed) break; + assert(scalar(ingredients.at(0))); + check_screen(current_instruction().ingredients.at(1).name, ingredients.at(0).at(0)); break; } @@ -152,8 +214,8 @@ struct raw_string_stream { }; :(code) -void check_screen(const string& expected_contents) { -//? cerr << "Checking screen\n"; //? 1 +void check_screen(const string& expected_contents, const int color) { +//? cerr << "Checking screen for color " << color << "\n"; //? 2 assert(!Current_routine->calls.front().default_space); // not supported long long int screen_location = Memory[SCREEN]; int data_offset = find_element_name(Type_number["screen"], "data"); @@ -171,26 +233,49 @@ void check_screen(const string& expected_cont cursor.skip_whitespace_and_comments(); if (cursor.at_end()) break; assert(cursor.get() == '.'); - for (long long int column = 0; column < screen_width; ++column, ++addr) { + for (long long int column = 0; column < screen_width; ++column, addr+= /*size of screen-cell*/2) { + const int cell_color_offset = 1; uint32_t curr = cursor.get(); if (Memory[addr] == 0 && isspace(curr)) continue; - if (Memory[addr] != 0 && Memory[addr] == curr) continue; - // mismatch +//? cerr << color << " vs " << Memory[addr+1] << '\n'; //? 1 + if (curr == ' ' && color != -1 && color != Memory[addr+cell_color_offset]) { + // filter out other colors + continue; + } + if (Memory[addr] != 0 && Memory[addr] == curr) { + if (color == -1 || color == Memory[addr+cell_color_offset]) continue; + // contents match but color is off + if (Current_scenario && !Hide_warnings) { + // genuine test in a mu file + raise << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ", address " << addr << ", value " << Memory[addr] << ") to be in color " << color << " instead of " << Memory[addr+cell_color_offset] << "'\n"; + } + else { + // just testing check_screen + raise << "expected screen location (" << row << ", " << column << ") to be in color " << color << " instead of " << Memory[addr+cell_color_offset] << '\n'; + } + if (!Hide_warnings) { + Passed = false; + ++Num_failures; + } + return; + } + + // really a mismatch // can't print multi-byte unicode characters in warnings just yet. not very useful for debugging anyway. char expected_pretty[10] = {0}; - if (curr < 256) { + if (curr < 256 && !iscntrl(curr)) { // " ('<curr>')" expected_pretty[0] = ' ', expected_pretty[1] = '(', expected_pretty[2] = '\'', expected_pretty[3] = static_cast<unsigned char>(curr), expected_pretty[4] = '\'', expected_pretty[5] = ')', expected_pretty[6] = '\0'; } char actual_pretty[10] = {0}; - if (Memory[addr] < 256) { + if (Memory[addr] < 256 && !iscntrl(Memory[addr])) { // " ('<curr>')" actual_pretty[0] = ' ', actual_pretty[1] = '(', actual_pretty[2] = '\'', actual_pretty[3] = static_cast<unsigned char>(Memory[addr]), actual_pretty[4] = '\'', actual_pretty[5] = ')', actual_pretty[6] = '\0'; } if (Current_scenario && !Hide_warnings) { // genuine test in a mu file - raise << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << " instead of " << Memory[addr] << actual_pretty << "'\n"; + raise << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << " instead of " << Memory[addr] << actual_pretty << '\n'; dump_screen(); } else { @@ -278,7 +363,7 @@ void dump_screen() {
//? cerr << curr << ":\n"; //? 1 for (long long int col = 0; col < screen_width; ++col) { cerr << static_cast<char>(Memory[curr]); - ++curr; + curr += /*size of screen-cell*/2; } cerr << '\n'; } diff --git a/html/073scenario_screen_test.mu.html b/html/073scenario_screen_test.mu.html index 6422dd59..8df66f7b 100644 --- a/html/073scenario_screen_test.mu.html +++ b/html/073scenario_screen_test.mu.html @@ -10,13 +10,13 @@ diff --git a/html/074keyboard.mu.html b/html/074keyboard.mu.html index 558c8d16..dc0ab783 100644 --- a/html/074keyboard.mu.html +++ b/html/074keyboard.mu.html @@ -10,16 +10,16 @@ @@ -80,7 +80,7 @@ container keyboard [ # can't think of another word like { break-unless x:address:keyboard # on fake keyboards 'wait-for-key' behaves just like 'read-key' - c:character, x:address:keyboard <- read-key x:address:keyboard + c:character, found?:boolean, x:address:keyboard <- read-key x:address:keyboard reply c:character, x:address:keyboard/same-as-ingredient:0 } c:character <- wait-for-key-from-keyboard @@ -93,7 +93,7 @@ container keyboard [ # can't think of another word like chan:address:channel <- next-ingredient screen:address <- next-ingredient { - c:character, found?:boolean <- read-key keyboard:address + c:character, found?:boolean, keyboard:address <- read-key keyboard:address loop-unless found?:boolean #? print-integer screen:address, c:character #? 1 print-character screen:address, c:character diff --git a/html/075scenario_keyboard.cc.html b/html/075scenario_keyboard.cc.html index dc14321b..9ebee7a4 100644 --- a/html/075scenario_keyboard.cc.html +++ b/html/075scenario_keyboard.cc.html @@ -10,14 +10,15 @@ @@ -32,7 +33,8 @@ body { font-family: monospace; color: #d0d0d0; background-color: #000000; } //: Clean syntax to manipulate and check the keyboard in scenarios. //: Instruction 'assume-keyboard' implicitly creates a variable called //: 'keyboard' that is accessible inside other 'run' instructions in the -//: scenario. +//: scenario. Like with the fake screen, 'assume-keyboard' transparently +//: supports unicode. :(scenarios run_mu_scenario) :(scenario keyboard_in_scenario) @@ -89,6 +91,28 @@ if (curr.name == < curr.products.push_back(reagent("keyboard:address")); curr.products.at(0).set_value(KEYBOARD); } + +//: Since we don't yet have a clean way to represent characters like backspace +//: in literal strings we can't easily pretend they were typed into the fake +//: keyboard. So we'll use special unicode characters in the literal and then +//: manually replace them with backspace. +:(before "End Primitive Recipe Declarations") +REPLACE_IN_KEYBOARD, +:(before "End Primitive Recipe Numbers") +Recipe_number["replace-in-keyboard"] = REPLACE_IN_KEYBOARD; +:(before "End Primitive Recipe Implementations") +case REPLACE_IN_KEYBOARD: { + long long int size = Memory[KEYBOARD]; + assert(scalar(ingredients.at(0))); + assert(scalar(ingredients.at(1))); + for (long long int curr = KEYBOARD+1; curr <= KEYBOARD+size; ++curr) { + if (Memory[curr] == ingredients.at(0).at(0)) { +//? cerr << "replacing\n"; //? 1 + Memory[curr] = ingredients.at(1).at(0); + } + } + break; +} diff --git a/html/076scenario_keyboard_test.mu.html b/html/076scenario_keyboard_test.mu.html index 974b9ff8..cb73c7ac 100644 --- a/html/076scenario_keyboard_test.mu.html +++ b/html/076scenario_keyboard_test.mu.html @@ -10,13 +10,13 @@ diff --git a/html/077trace_browser.cc.html b/html/077trace_browser.cc.html index 567371cc..d600ef8b 100644 --- a/html/077trace_browser.cc.html +++ b/html/077trace_browser.cc.html @@ -10,15 +10,15 @@ @@ -103,10 +103,9 @@ void start_trace_browser() } if (key == 'K') { // page-up is more convoluted - int max = tb_height(); //? tb_shutdown(); //? 1 //? cerr << "page-up: Top_of_screen is currently " << Top_of_screen << '\n'; //? 1 - for (int screen_row = max; screen_row > 0 && Top_of_screen > 0; --screen_row) { + for (int screen_row = tb_height(); screen_row > 0 && Top_of_screen > 0; --screen_row) { --Top_of_screen; if (Top_of_screen <= 0) break; while (Top_of_screen > 0 && Visible.find(Top_of_screen) == Visible.end()) @@ -117,6 +116,20 @@ void start_trace_browser() (Top_of_screen > 0) refresh_screen_rows(); } + if (key == 'G') { + // go to bottom of screen; largely like page-up, interestingly + Top_of_screen = SIZE(Trace_stream->past_lines)-1; + for (int screen_row = tb_height(); screen_row > 0 && Top_of_screen > 0; --screen_row) { + --Top_of_screen; + if (Top_of_screen <= 0) break; + while (Top_of_screen > 0 && Visible.find(Top_of_screen) == Visible.end()) + --Top_of_screen; + } + refresh_screen_rows(); + // move cursor to bottom + Display_row = Last_printed_row; + refresh_screen_rows(); + } if (key == TB_KEY_CARRIAGE_RETURN) { // expand lines under current by one level //? tb_shutdown(); diff --git a/html/999spaces.cc.html b/html/999spaces.cc.html index 4e3fe2f2..99c38f35 100644 --- a/html/999spaces.cc.html +++ b/html/999spaces.cc.html @@ -10,8 +10,8 @@ @@ -33,7 +33,7 @@ body { font-family: monospace; color: #d0d0d0; background-color: #000000; } recipe main [ c:continuation <- f - continue-from c:continuation # <-- ..when you hit this + continue-from c:continuation # <-- ..when you hit this ] recipe f [ @@ -42,7 +42,7 @@ body { font-family: monospace; color: #d0d0d0; background-color: #000000; } ] recipe g [ - c:continuation <- current-continuation # <-- loop back to here + c:continuation <- current-continuation # <-- loop back to here $print 1:literal reply c:continuation # threaded through unmodified after first iteration ] diff --git a/html/channel.mu.html b/html/channel.mu.html index 2460211d..e6d5a456 100644 --- a/html/channel.mu.html +++ b/html/channel.mu.html @@ -10,15 +10,15 @@ diff --git a/html/chessboard.mu.html b/html/chessboard.mu.html index 6602d663..457df812 100644 --- a/html/chessboard.mu.html +++ b/html/chessboard.mu.html @@ -10,18 +10,18 @@ @@ -223,8 +223,8 @@ body { font-family: monospace; color: #d0d0d0; background-color: #000000; } done?:boolean <- equal col:number, 8:literal break-if done?:boolean f:address:array:character <- index board:address:array:address:array:character/deref, col:number - s:character <- index f:address:array:character/deref, row:number - print-character screen:address, s:character + c:character <- index f:address:array:character/deref, row:number + print-character screen:address, c:character print-character screen:address, 32:literal # ' ' col:number <- add col:number, 1:literal loop @@ -318,7 +318,7 @@ container move [ reply-if error?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean #? return-to-console #? 1 # construct the move object - result:address:move <- new move:literal + result:address:move <- new move:type x:address:number <- get-address result:address:move/deref, from-file:offset x:address:number/deref <- copy from-file:number x:address:number <- get-address result:address:move/deref, from-rank:offset @@ -701,7 +701,6 @@ F read-move-file: routine failed to pause after co . +---------------- . . a b c d e f g h . . . - . . ] ] diff --git a/html/counters.mu.html b/html/counters.mu.html index 2baae9e4..5b762232 100644 --- a/html/counters.mu.html +++ b/html/counters.mu.html @@ -10,14 +10,14 @@ diff --git a/html/display.mu.html b/html/display.mu.html index 01b8d90f..253d9eba 100644 --- a/html/display.mu.html +++ b/html/display.mu.html @@ -10,13 +10,13 @@ diff --git a/html/factorial.mu.html b/html/factorial.mu.html index c7c7723b..d8d58b93 100644 --- a/html/factorial.mu.html +++ b/html/factorial.mu.html @@ -10,16 +10,16 @@ diff --git a/html/fork.mu.html b/html/fork.mu.html index 414dfd3d..1dbd922c 100644 --- a/html/fork.mu.html +++ b/html/fork.mu.html @@ -10,14 +10,14 @@ diff --git a/html/keyboard.mu.html b/html/keyboard.mu.html index ac1d9a87..5b700513 100644 --- a/html/keyboard.mu.html +++ b/html/keyboard.mu.html @@ -10,15 +10,15 @@ diff --git a/html/repl.mu.html b/html/repl.mu.html new file mode 100644 index 00000000..807e9308 --- /dev/null +++ b/html/repl.mu.html @@ -0,0 +1,606 @@ + + + + +Mu - repl.mu + + + + + + + + + + +
+# interactive prompt for mu
+
+recipe main [
+  default-space:address:array:location <- new location:type, 30:literal
+  switch-to-display
+  msg:address:array:character <- new [ready! type in an instruction, then hit enter. ctrl-d exits.
+]
+  0:literal/real-screen <- print-string 0:literal/real-screen, msg:address:array:character
+  {
+    inst:address:array:character, 0:literal/real-keyboard, 0:literal/real-screen <- read-instruction 0:literal/real-keyboard, 0:literal/real-screen
+    break-unless inst:address:array:character
+    0:literal/real-screen <- print-string 0:literal/real-screen, inst:address:array:character
+    loop
+  }
+  return-to-console
+]
+
+# basic keyboard input; just text and enter
+scenario read-instruction1 [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [x <- copy y
+]
+  run [
+    1:address:array:character <- read-instruction keyboard:address, screen:address
+    2:address:array:character <- new [=> ]
+    print-string screen:address, 2:address:array:character
+    print-string screen:address, 1:address:array:character
+  ]
+  screen-should-contain [
+    .x <- copy y                   .
+    .=> x <- copy y                .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .x <- copy y                   .
+    .=> x <- copy y                .
+    .                              .
+  ]
+]
+
+# Read characters as they're typed at the keyboard, print them to the screen,
+# accumulate them in a string, return the string at the end.
+# Most of the complexity is for the printing to screen, to highlight strings
+# and comments specially. Especially in the presence of backspacing.
+recipe read-instruction [
+  default-space:address:array:location <- new location:type, 60:literal
+  k:address:keyboard <- next-ingredient
+  x:address:screen <- next-ingredient
+  result:address:buffer <- init-buffer 10:literal  # string to maybe add to
+  trace [app], [read-instruction]
+  # start state machine by calling slurp-regular-characters, which will return
+  # by calling the complete continuation
+  complete:continuation <- current-continuation
+  # If result is not empty, we've run slurp-regular-characters below, called
+  # the continuation and so bounced back here. We're done.
+  len:number <- get result:address:buffer/deref, length:offset
+  completed?:boolean <- greater-than len:number, 0:literal
+  jump-if completed?:boolean, +completed:label
+  # Otherwise we're just getting started.
+  result:address:buffer, k:address:keyboard, x:address:screen <- slurp-regular-characters result:address:buffer, k:address:keyboard, x:address:screen, complete:continuation
+  trace [error], [slurp-regular-characters should never return normally]
+  +completed
+  result2:address:array:character <- buffer-to-array result:address:buffer
+  trace [app], [exiting read-instruction]
+  reply result2:address:array:character, k:address:keyboard/same-as-ingredient:0, x:address:screen/same-as-ingredient:1
+]
+
+# read characters from the keyboard, print them to the screen in *white*.
+# Transition to other routines for comments and strings.
+recipe slurp-regular-characters [
+  default-space:address:array:location <- new location:type, 60:literal
+  result:address:buffer <- next-ingredient
+  k:address:keyboard <- next-ingredient
+  x:address:screen <- next-ingredient
+  complete:continuation <- next-ingredient
+  trace [app], [slurp-regular-characters]
+  characters-slurped:number <- copy 0:literal
+  {
+    +next-character
+    # read character
+    c:character, k:address:keyboard <- wait-for-key k:address:keyboard
+    # quit?
+    {
+      ctrl-d?:boolean <- equal c:character, 4:literal/ctrl-d/eof
+      break-unless ctrl-d?:boolean
+      trace [app], [slurp-regular-characters: ctrl-d]
+      reply 0:literal, k:address:keyboard/same-as-ingredient:1, x:address:screen/same-as-ingredient:2
+    }
+    {
+      null?:boolean <- equal c:character, 0:literal/null
+      break-unless null?:boolean
+      trace [app], [slurp-regular-characters: null]
+      reply 0:literal, k:address:keyboard/same-as-ingredient:1, x:address:screen/same-as-ingredient:2
+    }
+    # comment?
+    {
+      comment?:boolean <- equal c:character, 35:literal/hash
+      break-unless comment?:boolean
+      print-character x:address:screen, c:character, 4:literal/blue
+      result:address:buffer <- buffer-append result:address:buffer, c:character
+      result:address:buffer, k:address:keyboard, x:address:screen <- slurp-comment result:address:buffer, k:address:keyboard, x:address:screen, complete:continuation
+      # continue appending to this instruction, whether comment ended or was backspaced out of
+      loop +next-character:label
+    }
+    # string
+    {
+      string?:boolean <- equal c:character, 91:literal/open-bracket
+      break-unless string?:boolean
+      print-character x:address:screen, c:character, 6:literal/cyan
+      result:address:buffer <- buffer-append result:address:buffer, c:character
+      result:address:buffer, _, k:address:keyboard, x:address:screen <- slurp-string result:address:buffer, k:address:keyboard, x:address:screen, complete:continuation
+      loop +next-character:label
+    }
+    # print
+    print-character x:address:screen, c:character  # default color
+    # append
+    result:address:buffer <- buffer-append result:address:buffer, c:character
+    # backspace? decrement and maybe return
+    {
+      backspace?:boolean <- equal c:character, 8:literal/backspace
+      break-unless backspace?:boolean
+      characters-slurped:number <- subtract characters-slurped:number, 1:literal
+      {
+        done?:boolean <- lesser-or-equal characters-slurped:number, 0:literal
+        break-unless done?:boolean
+        trace [app], [slurp-regular-characters: too many backspaces; returning]
+        reply result:address:buffer, k:address:keyboard/same-as-ingredient:1, x:address:screen/same-as-ingredient:2
+      }
+      loop +next-character:label
+    }
+    # otherwise increment
+    characters-slurped:number <- add characters-slurped:number, 1:literal
+    # done with this instruction?
+    done?:boolean <- equal c:character, 10:literal/newline
+    break-if done?:boolean
+    loop
+  }
+  # newline encountered; terminate all recursive calls
+#?   xx:address:array:character <- new [completing!] #? 1
+#?   print-string x:address:screen, xx:address:array:character #? 1
+  trace [app], [slurp-regular-characters: newline encountered; unwinding stack]
+  continue-from complete:continuation
+]
+
+# read characters from keyboard, print them to screen in the comment color.
+#
+# Simpler version of slurp-regular-characters; doesn't handle comments or
+# strings. Tracks an extra count in case we backspace out of it
+recipe slurp-comment [
+  default-space:address:array:location <- new location:type, 60:literal
+  result:address:buffer <- next-ingredient
+  k:address:keyboard <- next-ingredient
+  x:address:screen <- next-ingredient
+  complete:continuation <- next-ingredient
+  trace [app], [slurp-comment]
+  # use this to track when backspace should reset color
+  characters-slurped:number <- copy 1:literal  # for the initial '#' that's already appended to result
+  {
+    +next-character
+    # read character
+    c:character, k:address:keyboard <- wait-for-key k:address:keyboard
+    # quit?
+    {
+      ctrl-d?:boolean <- equal c:character, 4:literal/ctrl-d/eof
+      break-unless ctrl-d?:boolean
+      trace [app], [slurp-comment: ctrl-d]
+      reply 0:literal, k:address:keyboard/same-as-ingredient:1, x:address:screen/same-as-ingredient:2
+    }
+    {
+      null?:boolean <- equal c:character, 0:literal/null
+      break-unless null?:boolean
+      trace [app], [slurp-comment: null]
+      reply 0:literal, k:address:keyboard/same-as-ingredient:1, x:address:screen/same-as-ingredient:2
+    }
+    # print
+    print-character x:address:screen, c:character, 4:literal/blue
+    # append
+    result:address:buffer <- buffer-append result:address:buffer, c:character
+    # backspace? decrement
+    {
+      backspace?:boolean <- equal c:character, 8:literal/backspace
+      break-unless backspace?:boolean
+      characters-slurped:number <- subtract characters-slurped:number, 1:literal
+      {
+        reset-color?:boolean <- lesser-or-equal characters-slurped:number, 0:literal
+        break-unless reset-color?:boolean
+        trace [app], [slurp-comment: too many backspaces; returning]
+        reply result:address:buffer, k:address:keyboard/same-as-ingredient:1, x:address:screen/same-as-ingredient:2
+      }
+      loop +next-character:label
+    }
+    # otherwise increment
+    characters-slurped:number <- add characters-slurped:number, 1:literal
+    # done with this instruction?
+    done?:boolean <- equal c:character, 10:literal/newline
+    break-if done?:boolean
+    loop
+  }
+  trace [app], [slurp-regular-characters: newline encountered; returning]
+  reply result:address:buffer, k:address:keyboard/same-as-ingredient:1, x:address:screen/same-as-ingredient:2
+]
+
+# read characters from keyboard, print them to screen in the string color and
+# accumulate them into a buffer.
+#
+# Version of slurp-regular-characters that:
+#   a) doesn't handle comments
+#   b) handles nested strings using recursive calls to itself. Tracks an extra
+#   count in case we backspace out of it.
+recipe slurp-string [
+  default-space:address:array:location <- new location:type, 60:literal
+  result:address:buffer <- next-ingredient
+  k:address:keyboard <- next-ingredient
+  x:address:screen <- next-ingredient
+  complete:continuation <- next-ingredient
+  nested-string?:boolean <- next-ingredient
+  trace [app], [slurp-string]
+  # use this to track when backspace should reset color
+  characters-slurped:number <- copy 1:literal  # for the initial '[' that's already appended to result
+  {
+    +next-character
+    # read character
+    c:character, k:address:keyboard <- wait-for-key k:address:keyboard
+    # quit?
+    {
+      ctrl-d?:boolean <- equal c:character, 4:literal/ctrl-d/eof
+      break-unless ctrl-d?:boolean
+      trace [app], [slurp-string: ctrl-d]
+      reply 0:literal, 0:literal, k:address:keyboard/same-as-ingredient:1, x:address:screen/same-as-ingredient:2
+    }
+    {
+      null?:boolean <- equal c:character, 0:literal/null
+      break-unless null?:boolean
+      trace [app], [slurp-string: null]
+      reply 0:literal, 0:literal, k:address:keyboard/same-as-ingredient:1, x:address:screen/same-as-ingredient:2
+    }
+    # string
+    {
+      string?:boolean <- equal c:character, 91:literal/open-bracket
+      break-unless string?:boolean
+      trace [app], [slurp-string: open-bracket encountered; recursing]
+      print-character x:address:screen, c:character, 6:literal/cyan
+      result:address:buffer <- buffer-append result:address:buffer, c:character
+      # make a recursive call to handle nested strings
+      result:address:buffer, tmp:number, k:address:keyboard, x:address:screen <- slurp-string result:address:buffer, k:address:keyboard, x:address:screen, complete:continuation, 1:literal/nested?
+      # but if we backspace over a completed nested string, handle it in the caller
+      characters-slurped:number <- add characters-slurped:number, tmp:number, 1:literal  # for the leading '['
+      loop +next-character:label
+    }
+    # print
+    print-character x:address:screen, c:character, 6:literal/cyan
+    # append
+    result:address:buffer <- buffer-append result:address:buffer, c:character
+    # backspace? decrement
+    {
+      backspace?:boolean <- equal c:character, 8:literal/backspace
+      break-unless backspace?:boolean
+      characters-slurped:number <- subtract characters-slurped:number, 1:literal
+      {
+        reset-color?:boolean <- lesser-or-equal characters-slurped:number, 0:literal
+        break-unless reset-color?:boolean
+        trace [app], [slurp-string: too many backspaces; returning]
+        reply result:address:buffer/same-as-ingredient:0, 0:literal, k:address:keyboard/same-as-ingredient:1, x:address:screen/same-as-ingredient:2
+      }
+      loop +next-character:label
+    }
+    # otherwise increment
+    characters-slurped:number <- add characters-slurped:number, 1:literal
+    # done with this instruction?
+    done?:boolean <- equal c:character, 93:literal/close-bracket
+    break-if done?:boolean
+    loop
+  }
+  {
+    break-unless nested-string?:boolean
+    # nested string? return like a normal recipe
+    reply result:address:buffer, characters-slurped:number, k:address:keyboard, x:address:screen
+  }
+  # top-level string call? recurse
+  trace [app], [slurp-string: close-bracket encountered; recursing to regular characters]
+  result:address:buffer, k:address:keyboard, x:address:screen <- slurp-regular-characters result:address:buffer, k:address:keyboard, x:address:screen, complete:continuation
+  # backspaced back into this string
+  trace [app], [slurp-string: backspaced back into string; restarting]
+  jump +next-character:label
+]
+
+scenario read-instruction-color-comment [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [# comment
+]
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain-in-color 4:literal/blue, [
+    .# comment                     .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .                              .
+    .                              .
+  ]
+]
+
+scenario read-instruction-cancel-comment-on-backspace [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [#a««z
+]
+  replace-in-keyboard 171:literal/«, 8:literal/backspace
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain-in-color 4:literal/blue, [
+    .                              .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .z                             .
+    .                              .
+  ]
+]
+
+scenario read-instruction-cancel-comment-on-backspace2 [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [#ab«««z
+]
+  replace-in-keyboard 171:literal/«, 8:literal/backspace
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain-in-color 4:literal/blue, [
+    .                              .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .z                             .
+    .                              .
+  ]
+]
+
+scenario read-instruction-cancel-comment-on-backspace3 [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [#a«z
+]
+  replace-in-keyboard 171:literal/«, 8:literal/backspace
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain-in-color 4:literal/blue, [
+    .#z                            .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .                              .
+    .                              .
+  ]
+]
+
+scenario read-instruction-color-string [
+#?   $start-tracing #? 1
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [abc [string]
+]
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain [
+    .abc [string]                  .
+    .                              .
+  ]
+  screen-should-contain-in-color 6:literal/cyan, [
+    .    [string]                  .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .abc                           .
+    .                              .
+  ]
+]
+
+scenario read-instruction-color-string-multiline [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [abc [line1
+line2]
+]
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain [
+    .abc [line1                    .
+    .line2]                        .
+    .                              .
+  ]
+  screen-should-contain-in-color 6:literal/cyan, [
+    .    [line1                    .
+    .line2]                        .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .abc                           .
+    .                              .
+    .                              .
+  ]
+]
+
+scenario read-instruction-color-string-and-comment [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [abc [string]  # comment
+]
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain [
+    .abc [string]  # comment       .
+    .                              .
+  ]
+  screen-should-contain-in-color 4:literal/blue, [
+    .              # comment       .
+    .                              .
+  ]
+  screen-should-contain-in-color 6:literal/cyan, [
+    .    [string]                  .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .abc                           .
+    .                              .
+  ]
+]
+
+scenario read-instruction-ignore-comment-inside-string [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [abc [string # not a comment]
+]
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain [
+    .abc [string # not a comment]  .
+    .                              .
+  ]
+  screen-should-contain-in-color 6:literal/cyan, [
+    .    [string # not a comment]  .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .abc                           .
+    .                              .
+  ]
+  screen-should-contain-in-color 4:literal/blue, [
+    .                              .
+    .                              .
+  ]
+]
+
+scenario read-instruction-ignore-string-inside-comment [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [abc # comment [not a string]
+]
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain [
+    .abc # comment [not a string]  .
+    .                              .
+  ]
+  screen-should-contain-in-color 6:literal/cyan, [
+    .                              .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .abc                           .
+    .                              .
+  ]
+  screen-should-contain-in-color 4:literal/blue, [
+    .    # comment [not a string]  .
+    .                              .
+  ]
+]
+
+scenario read-instruction-color-string-inside-string [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [abc [string [inner string]]
+]
+  run [
+#?     $start-tracing #? 1
+    read-instruction keyboard:address, screen:address
+#?     $stop-tracing #? 1
+#?     $browse-trace #? 1
+  ]
+  screen-should-contain [
+    .abc [string [inner string]]   .
+    .                              .
+  ]
+  screen-should-contain-in-color 6:literal/cyan, [
+    .    [string [inner string]]   .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .abc                           .
+    .                              .
+  ]
+]
+
+scenario read-instruction-cancel-string-on-backspace [
+  assume-screen 30:literal/width, 5:literal/height
+  # need to escape the '[' once for 'scenario' and once for 'assume-keyboard'
+  assume-keyboard [\\\[a««z
+]
+  replace-in-keyboard 171:literal/«, 8:literal/backspace
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain-in-color 6:literal/cyan, [
+    .                              .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .z                             .
+    .                              .
+  ]
+]
+
+scenario read-instruction-cancel-string-inside-string-on-backspace [
+  assume-screen 30:literal/width, 5:literal/height
+  assume-keyboard [[a[b]«««b]
+]
+  replace-in-keyboard 171:literal/«, 8:literal/backspace
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain-in-color 6:literal/cyan, [
+    .[ab]                          .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .                              .
+    .                              .
+  ]
+]
+
+scenario read-instruction-backspace-back-into-string [
+  assume-screen 30:literal/width, 5:literal/height
+  # need to escape the '[' once for 'scenario' and once for 'assume-keyboard'
+  assume-keyboard [[a]«b
+]
+  replace-in-keyboard 171:literal/«, 8:literal/backspace
+  run [
+    read-instruction keyboard:address, screen:address
+  ]
+  screen-should-contain [
+    .\\\[ab                           .
+    .                              .
+  ]
+  screen-should-contain-in-color 6:literal/cyan, [
+    .\\\[ab                           .
+    .                              .
+  ]
+  screen-should-contain-in-color 7:literal/white, [
+    .                              .
+    .                              .
+  ]
+  # todo: trace sequence of events
+  #   slurp-regular-characters: [
+  #   slurp-regular-characters/slurp-string: a
+  #   slurp-regular-characters/slurp-string: ]
+  #   slurp-regular-characters/slurp-string/slurp-regular-characters: backspace
+  #   slurp-regular-characters/slurp-string: b
+]
+
+ + + diff --git a/html/screen.mu.html b/html/screen.mu.html index e893b214..9956cfa3 100644 --- a/html/screen.mu.html +++ b/html/screen.mu.html @@ -10,13 +10,13 @@ @@ -35,7 +35,7 @@ body { font-family: monospace; color: #d0d0d0; background-color: #000000; } recipe main [ switch-to-display - print-character 0:literal/screen, 97:literal + print-character 0:literal/screen, 97:literal, 2:literal/red 1:number/raw, 2:number/raw <- cursor-position 0:literal/screen wait-for-key 0:literal/keyboard clear-screen 0:literal/screen diff --git a/html/tangle.mu.html b/html/tangle.mu.html index d0a41559..8dd2b7f9 100644 --- a/html/tangle.mu.html +++ b/html/tangle.mu.html @@ -10,15 +10,15 @@ diff --git a/html/x.mu.html b/html/x.mu.html index 15451361..4c5803d2 100644 --- a/html/x.mu.html +++ b/html/x.mu.html @@ -10,14 +10,14 @@ -- cgit 1.4.1-2-gfad0