From 9570363aec35e187e2395b1760a4b94e71580ac9 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Wed, 29 Jul 2015 15:55:05 -0700 Subject: 1885 --- html/000organization.cc.html | 11 +- html/001help.cc.html | 25 +- html/002test.cc.html | 43 +- html/003trace.cc.html | 155 +- html/003trace.test.cc.html | 35 +- html/010vm.cc.html | 115 +- html/011load.cc.html | 143 +- html/012transform.cc.html | 33 +- html/013literal_string.cc.html | 98 +- html/014literal_noninteger.cc.html | 30 +- html/020run.cc.html | 149 +- html/021arithmetic.cc.html | 85 +- html/022boolean.cc.html | 49 +- html/023jump.cc.html | 71 +- html/024compare.cc.html | 159 +- html/027trace.cc.html | 122 -- html/028assert.cc.html | 67 - html/029debug.cc.html | 69 - html/029tools.cc.html | 244 +++ html/030container.cc.html | 215 ++- html/031address.cc.html | 145 +- html/032array.cc.html | 191 ++- html/033exclusive_container.cc.html | 73 +- html/034call.cc.html | 65 +- html/035call_ingredient.cc.html | 41 +- html/036call_reply.cc.html | 71 +- html/037recipe.cc.html | 17 +- html/038scheduler.cc.html | 173 +- html/039wait.cc.html | 63 +- html/040brace.cc.html | 155 +- html/041jump_label.cc.html | 63 +- html/042name.cc.html | 196 +-- html/043new.cc.html | 163 +- html/044space.cc.html | 135 +- html/045space_surround.cc.html | 33 +- html/046closure_name.cc.html | 85 +- html/047global.cc.html | 45 +- html/048tangle.cc.html | 236 --- html/048typecheck.cc.html | 121 ++ html/049continuation.cc.html | 283 ---- html/050scenario.cc.html | 212 +-- html/051scenario_test.mu.html | 30 +- html/052tangle.cc.html | 235 +++ html/053continuation.cc.html | 282 ++++ html/060string.mu.html | 1187 +++++++------- html/061channel.mu.html | 342 ++-- html/062array.mu.html | 38 +- html/063list.mu.html | 50 +- html/064random.cc.html | 13 +- html/065duplex_list.mu.html | 476 +++--- html/066stream.mu.html | 40 +- html/070display.cc.html | 143 +- html/071print.mu.html | 716 +++++---- html/072scenario_screen.cc.html | 201 ++- html/073scenario_screen_test.mu.html | 10 +- html/074console.mu.html | 80 +- html/075scenario_console.cc.html | 77 +- html/076scenario_console_test.mu.html | 24 +- html/080trace_browser.cc.html | 171 +- html/081run_interactive.cc.html | 145 +- html/082persist.cc.html | 53 +- html/999spaces.cc.html | 2 +- html/callcc.mu.html | 10 +- html/channel.mu.html | 26 +- html/chessboard.mu.html | 587 ++++--- html/console.mu.html | 6 +- html/counters.mu.html | 24 +- html/display.mu.html | 14 +- html/edit.mu.html | 2800 +++++++++++++++++---------------- html/factorial.mu.html | 26 +- html/factorial.png | Bin 29444 -> 18316 bytes html/fork.mu.html | 6 +- html/global.mu.html | 6 +- html/screen.mu.html | 38 +- html/tangle.mu.html | 20 +- html/x.mu.html | 8 +- 76 files changed, 6225 insertions(+), 6145 deletions(-) delete mode 100644 html/027trace.cc.html delete mode 100644 html/028assert.cc.html delete mode 100644 html/029debug.cc.html create mode 100644 html/029tools.cc.html delete mode 100644 html/048tangle.cc.html create mode 100644 html/048typecheck.cc.html delete mode 100644 html/049continuation.cc.html create mode 100644 html/052tangle.cc.html create mode 100644 html/053continuation.cc.html (limited to 'html') diff --git a/html/000organization.cc.html b/html/000organization.cc.html index b882e19c..641dae8c 100644 --- a/html/000organization.cc.html +++ b/html/000organization.cc.html @@ -13,12 +13,11 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } -.Delimiter { color: #a04060; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } +.Identifier { color: #804000; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .PreProc { color: #c000c0; } -.Identifier { color: #804000; } +.Delimiter { color: #a04060; } --> @@ -132,7 +131,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } // Globals // End Globals -int main(int argc, char* argv[]) { +int main(int argc, char* argv[]) { atexit(teardown); // End One-time Setup @@ -149,11 +148,11 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } //: Without directives or with the :(code) directive, lines get added at the //: end. :(code) -void setup() { +void setup() { // End Setup } -void teardown() { +void teardown() { // End Teardown } diff --git a/html/001help.cc.html b/html/001help.cc.html index 2a89daac..b7f03457 100644 --- a/html/001help.cc.html +++ b/html/001help.cc.html @@ -14,13 +14,12 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background- body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .cSpecial { color: #008000; } -.SalientComment { color: #00ffff; } .Constant { color: #00a0a0; } -.PreProc { color: #c000c0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } +.SalientComment { color: #00ffff; } .Identifier { color: #804000; } +.PreProc { color: #c000c0; } --> @@ -36,7 +35,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } //: This should give you a sense for what to look forward to in later layers. :(before "End Commandline Parsing") -if (argc <= 1 || is_equal(argv[1], "--help")) { +if (argc <= 1 || is_equal(argv[1], "--help")) { // this is the functionality later layers will provide // currently no automated tests for commandline arg parsing cerr << "To load files and run 'main':\n" @@ -59,7 +58,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } //: way, our makefile contains a little command to automatically generate //: declarations for them. :(code) -bool is_equal(char* s, const char* lit) { +bool is_equal(char* s, const char* lit) { return strncmp(s, lit, strlen(lit)) == 0; } @@ -112,7 +111,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } // yadda-yadda. Instead use this macro below to perform an unsafe cast to // signed. We'll just give up immediately if a container's every too large. :(before "End Includes") -#define SIZE(X) (assert(X.size() < (1LL<<(sizeof(long long int)*8-2))), static_cast<long long int>(X.size())) +#define SIZE(X) (assert(X.size() < (1LL<<(sizeof(long long int)*8-2))), static_cast<long long int>(X.size())) // // 5. Integer overflow is still impossible to guard against. Maybe after // reading http://www.cs.utah.edu/~regehr/papers/overflow12.pdf @@ -121,16 +120,16 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } #include<assert.h> #include<iostream> -using std::istream; -using std::ostream; -using std::iostream; -using std::cin; -using std::cout; -using std::cerr; +using std::istream; +using std::ostream; +using std::iostream; +using std::cin; +using std::cout; +using std::cerr; #include<cstring> #include<string> -using std::string; +using std::string; diff --git a/html/002test.cc.html b/html/002test.cc.html index 6d7eb925..4c280e92 100644 --- a/html/002test.cc.html +++ b/html/002test.cc.html @@ -15,11 +15,10 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } -.CommentedCode { color: #6c6c6c; } .PreProc { color: #c000c0; } +.CommentedCode { color: #6c6c6c; } .Identifier { color: #804000; } --> @@ -43,19 +42,19 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } //: subsets of the program. :(before "End Types") -typedef void (*test_fn)(void); +typedef void (*test_fn)(void); :(before "End Globals") -const test_fn Tests[] = { +const test_fn Tests[] = { #include "test_list" // auto-generated; see makefile }; -bool Run_tests = false; -bool Passed = true; // set this to false inside any test to indicate failure -long Num_failures = 0; +bool Run_tests = false; +bool Passed = true; // set this to false inside any test to indicate failure +long Num_failures = 0; #define CHECK(X) \ - if (!(X)) { \ + if (!(X)) { \ ++Num_failures; \ cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): " << #X << '\n'; \ Passed = false; \ @@ -63,7 +62,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } } #define CHECK_EQ(X, Y) \ - if ((X) != (Y)) { \ + if ((X) != (Y)) { \ ++Num_failures; \ cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): " << #X << " == " << #Y << '\n'; \ cerr << " got " << (X) << '\n'; /* BEWARE: multiple eval */ \ @@ -75,25 +74,25 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } Passed = true; :(before "End Commandline Parsing") -if (argc > 1 && is_equal(argv[1], "test")) { +if (argc > 1 && is_equal(argv[1], "test")) { Run_tests = true; --argc; ++argv; // shift 'test' out of commandline args } :(before "End Main") -if (Run_tests) { +if (Run_tests) { // Test Runs // we run some tests and then exit; assume no state need be maintained afterward // End Test Run Initialization - time_t t; time(&t); + time_t t; time(&t); cerr << "C tests: " << ctime(&t); - for (size_t i=0; i < sizeof(Tests)/sizeof(Tests[0]); ++i) { + for (size_t i=0; i < sizeof(Tests)/sizeof(Tests[0]); ++i) { //? cerr << i << '\n'; //? 2 run_test(i); } // End Tests cerr << '\n'; - if (Num_failures > 0) { + if (Num_failures > 0) { cerr << Num_failures << " failure" << (Num_failures > 1 ? "s" : "") << '\n'; @@ -103,8 +102,8 @@ Passed = true; } :(code) -void run_test(size_t i) { - if (i >= sizeof(Tests)/sizeof(Tests[0])) { +void run_test(size_t i) { + if (i >= sizeof(Tests)/sizeof(Tests[0])) { cerr << "no test " << i << '\n'; return; } @@ -112,18 +111,18 @@ Passed = true; // End Test Setup (*Tests[i])(); teardown(); - if (Passed) cerr << "."; + if (Passed) cerr << "."; } -bool is_integer(const string& s) { +bool is_integer(const string& s) { return s.find_first_not_of("0123456789-") == string::npos; } -long long int to_integer(string n) { - char* end = NULL; +long long int to_integer(string n) { + char* end = NULL; // safe because string.c_str() is guaranteed to be null-terminated - long long int result = strtoll(n.c_str(), &end, /*any base*/0); - if (*end != '\0') cerr << "tried to convert " << n << " to number\n"; + long long int result = strtoll(n.c_str(), &end, /*any base*/0); + if (*end != '\0') cerr << "tried to convert " << n << " to number\n"; assert(*end == '\0'); return result; } diff --git a/html/003trace.cc.html b/html/003trace.cc.html index 2eabf9ff..ea09cda6 100644 --- a/html/003trace.cc.html +++ b/html/003trace.cc.html @@ -16,7 +16,6 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } .PreProc { color: #c000c0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .CommentedCode { color: #6c6c6c; } @@ -115,56 +114,56 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } // End Tracing // hack to ensure most code in this layer comes before anything else :(before "End Tracing") -bool Hide_warnings = false; +bool Hide_warnings = false; :(before "End Setup") //? cerr << "AAA setup\n"; //? 2 Hide_warnings = false; :(before "End Types") -struct trace_line { - int depth; // optional field just to help browse traces later +struct trace_line { + int depth; // optional field just to help browse traces later string label; string contents; trace_line(string l, string c) :depth(0), label(l), contents(c) {} - trace_line(int d, string l, string c) :depth(d), label(l), contents(c) {} + trace_line(int d, string l, string c) :depth(d), label(l), contents(c) {} }; :(before "End Tracing") -struct trace_stream { +struct trace_stream { vector<trace_line> past_lines; // accumulator for current line ostringstream* curr_stream; string curr_layer; - int curr_depth; + int curr_depth; string dump_layer; string collect_layer; // if set, ignore all other 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; } + ~trace_stream() { if (curr_stream) delete curr_stream; } ostream& stream(string layer) { return stream(0, layer); } - ostream& stream(int depth, string layer) { - if (!collect_layer.empty() && layer != collect_layer) return null_stream; - curr_stream = new ostringstream; + ostream& stream(int depth, string layer) { + if (!collect_layer.empty() && layer != collect_layer) return null_stream; + curr_stream = new ostringstream; curr_layer = layer; curr_depth = depth; return *curr_stream; } // be sure to call this before messing with curr_stream or curr_layer - void newline() { - if (!curr_stream) return; + void newline() { + if (!curr_stream) return; string curr_contents = curr_stream->str(); - if (curr_contents.empty()) return; + if (curr_contents.empty()) return; past_lines.push_back(trace_line(curr_depth, trim(curr_layer), curr_contents)); // preserve indent in contents - if (curr_layer == dump_layer || curr_layer == "dump" || dump_layer == "all" || + if (curr_layer == dump_layer || curr_layer == "dump" || dump_layer == "all" || (!Hide_warnings && curr_layer == "warn")) //? if (dump_layer == "all" && (Current_routine->id == 3 || curr_layer == "schedule")) //? 1 cerr << curr_layer << ": " << curr_contents << '\n'; - delete curr_stream; + delete curr_stream; curr_stream = NULL; curr_layer.clear(); curr_depth = 0; @@ -174,9 +173,9 @@ Hide_warnings = false;(string layer) { // missing layer = everything ostringstream output; layer = trim(layer); - for (vector<trace_line>::iterator p = past_lines.begin(); p != past_lines.end(); ++p) - if (layer.empty() || layer == p->label) { - if (p->depth) + for (vector<trace_line>::iterator p = past_lines.begin(); p != past_lines.end(); ++p) + if (layer.empty() || layer == p->label) { + if (p->depth) output << std::setw(4) << p->depth << ' '; output << p->label << ": " << p->contents << '\n'; } @@ -195,34 +194,34 @@ trace_stream* Trace_stream = NULL#define raise ((!Trace_stream || !Hide_warnings) ? (tb_shutdown(),cerr) /*do print*/ : Trace_stream->stream("warn")) :(before "End Types") -struct end {}; +struct end {}; :(before "End Tracing") -ostream& operator<<(ostream& os, unused end) { - if (Trace_stream) Trace_stream->newline(); +ostream& operator<<(ostream& os, unused end) { + if (Trace_stream) Trace_stream->newline(); return os; } -#define CLEAR_TRACE delete Trace_stream, Trace_stream = new trace_stream; +#define CLEAR_TRACE delete Trace_stream, Trace_stream = new trace_stream; -#define DUMP(layer) if (Trace_stream) cerr << Trace_stream->readable_contents(layer); +#define DUMP(layer) if (Trace_stream) cerr << Trace_stream->readable_contents(layer); // 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/"; +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; } +struct lease_tracer { + lease_tracer() { Trace_stream = new trace_stream; } ~lease_tracer() { //? cerr << "write to file? " << Trace_file << "$\n"; //? 2 - if (!Trace_file.empty()) { + if (!Trace_file.empty()) { //? cerr << "writing\n"; //? 2 ofstream fout((Trace_dir+Trace_file).c_str()); fout << Trace_stream->readable_contents(""); fout.close(); } - delete Trace_stream, Trace_stream = NULL, Trace_file = ""; + delete Trace_stream, Trace_stream = NULL, Trace_file = ""; } }; @@ -234,47 +233,47 @@ START_TRACING_UNTIL_END_OF_SCOPE #define CHECK_TRACE_CONTENTS(...) check_trace_contents(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) :(before "End Tracing") -bool check_trace_contents(string FUNCTION, string FILE, int LINE, string expected) { // missing layer == anywhere +bool check_trace_contents(string FUNCTION, string FILE, int LINE, string expected) { // missing layer == anywhere vector<string> expected_lines = split(expected, "^D"); - long long int curr_expected_line = 0; - while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) + long long int curr_expected_line = 0; + while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) ++curr_expected_line; - if (curr_expected_line == SIZE(expected_lines)) return true; + if (curr_expected_line == SIZE(expected_lines)) return true; string layer, contents; split_layer_contents(expected_lines.at(curr_expected_line), &layer, &contents); - for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { + for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { //? cerr << "AAA " << layer << ' ' << p->label << '\n'; //? 1 - if (layer != p->label) + if (layer != p->label) continue; //? cerr << "BBB ^" << contents << "$ ^" << p->contents << "$\n"; //? 1 - if (contents != trim(p->contents)) + if (contents != trim(p->contents)) continue; //? cerr << "CCC\n"; //? 1 ++curr_expected_line; - while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) + while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) ++curr_expected_line; - if (curr_expected_line == SIZE(expected_lines)) return true; + if (curr_expected_line == SIZE(expected_lines)) return true; split_layer_contents(expected_lines.at(curr_expected_line), &layer, &contents); } ++Num_failures; - cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << contents << "] in trace:\n"; + cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << contents << "] in trace:\n"; DUMP(layer); //? exit(0); //? 1 Passed = false; return false; } -void split_layer_contents(const string& s, string* layer, string* contents) { - static const string delim(": "); - size_t pos = s.find(delim); - if (pos == string::npos) { +void split_layer_contents(const string& s, string* layer, string* contents) { + static const string delim(": "); + size_t pos = s.find(delim); + if (pos == string::npos) { *layer = ""; *contents = trim(s); } - else { + else { *layer = trim(s.substr(0, pos)); *contents = trim(s.substr(pos+SIZE(delim))); } @@ -282,17 +281,17 @@ START_TRACING_UNTIL_END_OF_SCOPE ^L -int trace_count(string layer) { +int trace_count(string layer) { return trace_count(layer, ""); } -int trace_count(string layer, string line) { - long result = 0; - for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { - if (layer == p->label) { +int trace_count(string layer, string line) { + long result = 0; + for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { + if (layer == p->label) { //? cerr << "a: " << line << "$\n"; //? 1 //? cerr << "b: " << trim(p->contents) << "$\n"; //? 1 - if (line == "" || line == trim(p->contents)) + if (line == "" || line == trim(p->contents)) ++result; } } @@ -301,7 +300,7 @@ START_TRACING_UNTIL_END_OF_SCOPE #define CHECK_TRACE_WARNS() CHECK(trace_count("warn") > 0) #define CHECK_TRACE_DOESNT_WARN() \ - if (trace_count("warn") > 0) { \ + if (trace_count("warn") > 0) { \ ++Num_failures; \ cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): unexpected warnings\n"; \ DUMP("warn"); \ @@ -309,11 +308,11 @@ START_TRACING_UNTIL_END_OF_SCOPE return; \ } -bool trace_doesnt_contain(string layer, string line) { +bool trace_doesnt_contain(string layer, string line) { return trace_count(layer, line) == 0; } -bool trace_doesnt_contain(string expected) { +bool trace_doesnt_contain(string expected) { vector<string> tmp = split(expected, ": "); return trace_doesnt_contain(tmp.at(0), tmp.at(1)); } @@ -324,9 +323,9 @@ START_TRACING_UNTIL_END_OF_SCOPE vector<string> split(string s, string delim) { vector<string> result; - size_t begin=0, end=s.find(delim); - while (true) { - if (end == string::npos) { + size_t begin=0, end=s.find(delim); + while (true) { + if (end == string::npos) { result.push_back(string(s, begin, string::npos)); break; } @@ -337,14 +336,14 @@ vector<string> split(string sreturn result; } -string trim(const string& s) { +string trim(const string& s) { string::const_iterator first = s.begin(); - while (first != s.end() && isspace(*first)) + while (first != s.end() && isspace(*first)) ++first; - if (first == s.end()) return ""; + if (first == s.end()) return ""; string::const_iterator last = --s.end(); - while (last != s.begin() && isspace(*last)) + while (last != s.begin() && isspace(*last)) --last; ++last; return string(first, last); @@ -352,30 +351,30 @@ string trim(const str :(before "End Includes") #include<vector> -using std::vector; +using std::vector; #include<list> -using std::list; +using std::list; #include<map> -using std::map; +using std::map; #include<set> -using std::set; +using std::set; #include<algorithm> #include<iostream> -using std::istream; -using std::ostream; -using std::cin; -using std::cout; -using std::cerr; +using std::istream; +using std::ostream; +using std::cin; +using std::cout; +using std::cerr; #include<iomanip> #include<sstream> -using std::istringstream; -using std::ostringstream; +using std::istringstream; +using std::ostringstream; #include<fstream> -using std::ifstream; -using std::ofstream; +using std::ifstream; +using std::ofstream; #include"termbox/termbox.h" @@ -386,18 +385,18 @@ string trim(const str //: //: Mu 'applications' will be able to use depths 1-99 as they like. //: Depth 100 will be for scheduling (more on that later). -const int Scheduling_depth = 100; +const int Scheduling_depth = 100; //: Primitive statements will occupy 101-9998 -const int Initial_callstack_depth = 101; -const int Max_callstack_depth = 9998; +const int Initial_callstack_depth = 101; +const int Max_callstack_depth = 9998; //: (ignore this until the call layer) :(before "End Globals") -int Callstack_depth = 0; +int Callstack_depth = 0; :(before "End Setup") Callstack_depth = 0; //: Finally, details of primitive mu statements will occupy depth 9999 (more on that later as well) :(before "End Globals") -const int Primitive_recipe_depth = 9999; +const int Primitive_recipe_depth = 9999; //: //: This framework should help us hide some details at each level, mixing //: static ideas like layers with the dynamic notion of call-stack depth. diff --git a/html/003trace.test.cc.html b/html/003trace.test.cc.html index 4a720eca..e800a8cc 100644 --- a/html/003trace.test.cc.html +++ b/html/003trace.test.cc.html @@ -14,10 +14,9 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background- body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .cSpecial { color: #008000; } +.Delimiter { color: #a04060; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } -.Delimiter { color: #a04060; } --> @@ -29,60 +28,60 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
-void test_trace_check_compares() {
+void test_trace_check_compares() {
   trace("test layer") << "foo" << end();
   CHECK_TRACE_CONTENTS("test layer: foo");
 }
 
-void test_trace_check_ignores_other_layers() {
+void test_trace_check_ignores_other_layers() {
   trace("test layer 1") << "foo" << end();
   trace("test layer 2") << "bar" << end();
   CHECK_TRACE_CONTENTS("test layer 1: foo");
   CHECK_TRACE_DOESNT_CONTAIN("test layer 2: foo");
 }
 
-void test_trace_check_ignores_other_lines() {
+void test_trace_check_ignores_other_lines() {
   trace("test layer 1") << "foo" << end();
   trace("test layer 1") << "bar" << end();
   CHECK_TRACE_CONTENTS("test layer 1: foo");
 }
 
-void test_trace_check_ignores_other_lines2() {
+void test_trace_check_ignores_other_lines2() {
   trace("test layer 1") << "foo" << end();
   trace("test layer 1") << "bar" << end();
   CHECK_TRACE_CONTENTS("test layer 1: bar");
 }
 
-void test_trace_ignores_trailing_whitespace() {
+void test_trace_ignores_trailing_whitespace() {
   trace("test layer 1") << "foo\n" << end();
   CHECK_TRACE_CONTENTS("test layer 1: foo");
 }
 
-void test_trace_ignores_trailing_whitespace2() {
+void test_trace_ignores_trailing_whitespace2() {
   trace("test layer 1") << "foo " << end();
   CHECK_TRACE_CONTENTS("test layer 1: foo");
 }
 
-void test_trace_orders_across_layers() {
+void test_trace_orders_across_layers() {
   trace("test layer 1") << "foo" << end();
   trace("test layer 2") << "bar" << end();
   trace("test layer 1") << "qux" << end();
   CHECK_TRACE_CONTENTS("test layer 1: foo^Dtest layer 2: bar^Dtest layer 1: qux^D");
 }
 
-void test_trace_supports_count() {
+void test_trace_supports_count() {
   trace("test layer 1") << "foo" << end();
   trace("test layer 1") << "foo" << end();
   CHECK_EQ(trace_count("test layer 1", "foo"), 2);
 }
 
-void test_trace_supports_count2() {
+void test_trace_supports_count2() {
   trace("test layer 1") << "foo" << end();
   trace("test layer 1") << "bar" << end();
   CHECK_EQ(trace_count("test layer 1"), 2);
 }
 
-void test_trace_count_ignores_trailing_whitespace() {
+void test_trace_count_ignores_trailing_whitespace() {
   trace("test layer 1") << "foo\n" << end();
   CHECK(trace_count("test layer 1", "foo") == 1);
 }
@@ -100,26 +99,26 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 
 // can't check trace because trace methods call 'split'
 
-void test_split_returns_at_least_one_elem() {
+void test_split_returns_at_least_one_elem() {
   vector<string> result = split("", ",");
   CHECK_EQ(result.size(), 1);
   CHECK_EQ(result.at(0), "");
 }
 
-void test_split_returns_entire_input_when_no_delim() {
+void test_split_returns_entire_input_when_no_delim() {
   vector<string> result = split("abc", ",");
   CHECK_EQ(result.size(), 1);
   CHECK_EQ(result.at(0), "abc");
 }
 
-void test_split_works() {
+void test_split_works() {
   vector<string> result = split("abc,def", ",");
   CHECK_EQ(result.size(), 2);
   CHECK_EQ(result.at(0), "abc");
   CHECK_EQ(result.at(1), "def");
 }
 
-void test_split_works2() {
+void test_split_works2() {
   vector<string> result = split("abc,def,ghi", ",");
   CHECK_EQ(result.size(), 3);
   CHECK_EQ(result.at(0), "abc");
@@ -127,7 +126,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
   CHECK_EQ(result.at(2), "ghi");
 }
 
-void test_split_handles_multichar_delim() {
+void test_split_handles_multichar_delim() {
   vector<string> result = split("abc,,def,,ghi", ",,");
   CHECK_EQ(result.size(), 3);
   CHECK_EQ(result.at(0), "abc");
@@ -135,7 +134,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
   CHECK_EQ(result.at(2), "ghi");
 }
 
-void test_trim() {
+void test_trim() {
   CHECK_EQ(trim(""), "");
   CHECK_EQ(trim(" "), "");
   CHECK_EQ(trim("  "), "");
diff --git a/html/010vm.cc.html b/html/010vm.cc.html
index f028e2f1..4d1ed5fc 100644
--- a/html/010vm.cc.html
+++ b/html/010vm.cc.html
@@ -14,13 +14,12 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-
 body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 1.05em; }
 .cSpecial { color: #008000; }
-.SalientComment { color: #00ffff; }
 .Constant { color: #00a0a0; }
-.PreProc { color: #c000c0; }
-.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #a04060; }
+.SalientComment { color: #00ffff; }
 .CommentedCode { color: #6c6c6c; }
+.PreProc { color: #c000c0; }
 .Identifier { color: #804000; }
 -->
 
@@ -46,12 +45,12 @@ recipe_ordinal Next_recipe_ordinal = 1//: adding two phone numbers is meaningless. Here each recipe does something
 //: incommensurable with any other recipe.
 :(after "Types")
-typedef long long int recipe_ordinal;
+typedef long long int recipe_ordinal;
 
 :(before "End Types")
 // Recipes are lists of instructions. To perform or 'run' a recipe, the
 // computer runs its instructions.
-struct recipe {
+struct recipe {
   string name;
   vector<instruction> steps;
   // End recipe Fields
@@ -63,16 +62,16 @@ recipe_ordinal Next_recipe_ordinal = 1// or just a single 'label' starting with a non-alphanumeric character
 //   +label
 // Labels don't do anything, they're just waypoints.
-struct instruction {
-  bool is_label;
+struct instruction {
+  bool is_label;
   string label;  // only if is_label
   string name;  // only if !is_label
   recipe_ordinal operation;  // Recipe_ordinal[name]
   vector<reagent> ingredients;  // only if !is_label
   vector<reagent> products;  // only if !is_label
   instruction();
-  void clear();
-  string to_string() const;
+  void clear();
+  string to_string() const;
 };
 
 :(before "struct instruction")
@@ -80,27 +79,27 @@ recipe_ordinal Next_recipe_ordinal = 1// either to numbers or to locations in memory along with 'type' tags telling
 // us how to interpret them. They also can contain arbitrary other lists of
 // properties besides types, but we're getting ahead of ourselves.
-struct reagent {
+struct reagent {
   string original_string;
   vector<pair<string, vector<string> > > properties;
   string name;
-  double value;
-  bool initialized;
+  double value;
+  bool initialized;
   vector<type_ordinal> types;
   reagent(string s);
   reagent();
-  void set_value(double v) { value = v; initialized = true; }
-  string to_string() const;
+  void set_value(double v) { value = v; initialized = true; }
+  string to_string() const;
 };
 
 :(before "struct reagent")
-struct property {
+struct property {
   vector<string> values;
 };
 
 :(before "End Globals")
 // Locations refer to a common 'memory'. Each location can store a number.
-map<long long int, double> Memory;
+map<long long int, double> Memory;
 :(before "End Setup")
 Memory.clear();
 
@@ -113,13 +112,13 @@ Memory.clear();
 // Unlike most computers today, mu stores types in a single big table, shared
 // by all the mu programs on the computer. This is useful in providing a
 // seamless experience to help understand arbitrary mu programs.
-typedef long long int type_ordinal;
+typedef long long int type_ordinal;
 :(before "End Globals")
 map<string, type_ordinal> Type_ordinal;
 map<type_ordinal, type_info> Type;
 type_ordinal Next_type_ordinal = 1;
 :(code)
-void setup_types() {
+void setup_types() {
   Type.clear();  Type_ordinal.clear();
   Type_ordinal["literal"] = 0;
   Next_type_ordinal = 1;
@@ -153,23 +152,23 @@ setup_types();
 // container, but if bank accounts may be either for individuals or groups,
 // with different properties for each, that may require an exclusive container
 // whose variants are individual-account and joint-account containers.
-enum kind_of_type {
+enum kind_of_type {
   primitive,
   container,
   exclusive_container
 };
 
-struct type_info {
+struct type_info {
   string name;
   kind_of_type kind;
-  long long int size;  // only if type is not primitive; primitives and addresses have size 1 (except arrays are dynamic)
+  long long int size;  // only if type is not primitive; primitives and addresses have size 1 (except arrays are dynamic)
   vector<vector<type_ordinal> > elements;
   vector<string> element_names;
   // End type_info Fields
   type_info() :kind(primitive), size(0) {}
 };
 
-enum primitive_recipes {
+enum primitive_recipes {
   IDLE = 0,
   COPY,
   // End Primitive Recipe Declarations
@@ -180,7 +179,7 @@ setup_types();
 //: to know how to do *something* out of the box. For the following
 //: recipes there are only codes, no entries in the book, because mu just knows
 //: what to do for them.
-void setup_recipes() {
+void setup_recipes() {
   Recipe.clear();  Recipe_ordinal.clear();
   Recipe_ordinal["idle"] = IDLE;
   // Primitive Recipe Numbers
@@ -207,40 +206,42 @@ Next_recipe_ordinal = 1000
 
 :(code)
 instruction::instruction() :is_label(false), operation(IDLE) {}
-void instruction::clear() { is_label=false; label.clear(); operation=IDLE; ingredients.clear(); products.clear(); }
+void instruction::clear() { is_label=false; label.clear(); operation=IDLE; ingredients.clear(); products.clear(); }
 
 // Reagents have the form <name>:<type>:<type>:.../<property>/<property>/...
 reagent::reagent(string s) :original_string(s), value(0), initialized(false) {
+  // Parsing reagent(string s)
   istringstream in(s);
   in >> std::noskipws;
   // properties
-  while (!in.eof()) {
+  while (!in.eof()) {
     istringstream row(slurp_until(in, '/'));
     row >> std::noskipws;
     string name = slurp_until(row, ':');
     vector<string> values;
-    while (!row.eof())
+    while (!row.eof())
       values.push_back(slurp_until(row, ':'));
     properties.push_back(pair<string, vector<string> >(name, values));
   }
   // structures for the first row of properties
   name = properties.at(0).first;
-  for (long long int i = 0; i < SIZE(properties.at(0).second); ++i) {
+  for (long long int i = 0; i < SIZE(properties.at(0).second); ++i) {
     string type = properties.at(0).second.at(i);
-    if (Type_ordinal.find(type) == Type_ordinal.end()) {
+    if (Type_ordinal.find(type) == Type_ordinal.end()) {
 //?       cerr << type << " is " << Next_type_ordinal << '\n'; //? 1
       Type_ordinal[type] = Next_type_ordinal++;
     }
     types.push_back(Type_ordinal[type]);
   }
-  if (is_integer(name) && types.empty()) {
+  if (is_integer(name) && types.empty()) {
     types.push_back(0);
     properties.at(0).second.push_back("literal");
   }
-  if (name == "_" && types.empty()) {
+  if (name == "_" && types.empty()) {
     types.push_back(0);
     properties.at(0).second.push_back("dummy");
   }
+  // End Parsing reagent
 }
 
 reagent::reagent() :value(0), initialized(false) {
@@ -250,19 +251,19 @@ reagent::reagent() :value
   properties.push_back(pair<string, vector<string> >("", vector<string>()));
 }
 
-string reagent::to_string() const {
+string reagent::to_string() const {
   ostringstream out;
   out << "{name: \"" << name << "\"";
-  if (!properties.empty()) {
+  if (!properties.empty()) {
     out << ", properties: [";
-    for (long long int i = 0; i < SIZE(properties); ++i) {
+    for (long long int i = 0; i < SIZE(properties); ++i) {
       out << "\"" << properties.at(i).first << "\": ";
-      for (long long int j = 0; j < SIZE(properties.at(i).second); ++j) {
-        if (j > 0) out << ':';
+      for (long long int j = 0; j < SIZE(properties.at(i).second); ++j) {
+        if (j > 0) out << ':';
         out << "\"" << properties.at(i).second.at(j) << "\"";
       }
-      if (i < SIZE(properties)-1) out << ", ";
-      else out << "]";
+      if (i < SIZE(properties)-1) out << ", ";
+      else out << "]";
     }
   }
   out << "}";
@@ -270,27 +271,27 @@ string reagent::to_string() 
   return out.str();
 }
 
-string instruction::to_string() const {
-  if (is_label) return label;
+string instruction::to_string() const {
+  if (is_label) return label;
   ostringstream out;
-  for (long long int i = 0; i < SIZE(products); ++i) {
-    if (i > 0) out << ", ";
+  for (long long int i = 0; i < SIZE(products); ++i) {
+    if (i > 0) out << ", ";
     out << products.at(i).original_string;
   }
-  if (!products.empty()) out << " <- ";
+  if (!products.empty()) out << " <- ";
   out << name << ' ';
-  for (long long int i = 0; i < SIZE(ingredients); ++i) {
-    if (i > 0) out << ", ";
+  for (long long int i = 0; i < SIZE(ingredients); ++i) {
+    if (i > 0) out << ", ";
     out << ingredients.at(i).original_string;
   }
   return out.str();
 }
 
-string slurp_until(istream& in, char delim) {
+string slurp_until(istream& in, char delim) {
   ostringstream out;
-  char c;
-  while (in >> c) {
-    if (c == delim) {
+  char c;
+  while (in >> c) {
+    if (c == delim) {
       // drop the delim
       break;
     }
@@ -299,29 +300,29 @@ string slurp_until(istream& inreturn out.str();
 }
 
-bool has_property(reagent x, string name) {
-  for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) {
-    if (x.properties.at(i).first == name) return true;
+bool has_property(reagent x, string name) {
+  for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) {
+    if (x.properties.at(i).first == name) return true;
   }
   return false;
 }
 
-vector<string> property(const reagent& r, const string& name) {
-  for (long long int p = /*skip name:type*/1; p != SIZE(r.properties); ++p) {
-    if (r.properties.at(p).first == name)
+vector<string> property(const reagent& r, const string& name) {
+  for (long long int p = /*skip name:type*/1; p != SIZE(r.properties); ++p) {
+    if (r.properties.at(p).first == name)
       return r.properties.at(p).second;
   }
   return vector<string>();
 }
 
-void dump_memory() {
-  for (map<long long int, double>::iterator p = Memory.begin(); p != Memory.end(); ++p) {
+void dump_memory() {
+  for (map<long long int, double>::iterator p = Memory.begin(); p != Memory.end(); ++p) {
     cout << p->first << ": " << p->second << '\n';
   }
 }
 :(before "End Includes")
 #include<utility>
-using std::pair;
+using std::pair;
 
diff --git a/html/011load.cc.html b/html/011load.cc.html index bda6b17b..73e924c9 100644 --- a/html/011load.cc.html +++ b/html/011load.cc.html @@ -13,15 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } +.CommentedCode { color: #6c6c6c; } --> @@ -38,7 +37,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } :(scenarios load) // use 'load' instead of 'run' in all scenarios in this layer :(scenario first_recipe) recipe main [ - 1:number <- copy 23:literal + 1:number <- copy 23 ] +parse: instruction: copy +parse: ingredient: {name: "23", properties: ["23": "literal"]} @@ -54,21 +53,21 @@ vector<recipe_ordinal> load(string form(istream& in) { in >> std::noskipws; vector<recipe_ordinal> result; - while (!in.eof()) { + while (!in.eof()) { //? cerr << "===\n"; //? 1 skip_whitespace_and_comments(in); - if (in.eof()) break; + if (in.eof()) break; string command = next_word(in); // Command Handlers - if (command == "recipe") { + if (command == "recipe") { string recipe_name = next_word(in); //? cerr << "recipe: " << recipe_name << '\n'; //? 1 - if (recipe_name.empty()) + if (recipe_name.empty()) raise << "empty recipe name\n" << end(); - if (Recipe_ordinal.find(recipe_name) == Recipe_ordinal.end()) { + if (Recipe_ordinal.find(recipe_name) == Recipe_ordinal.end()) { Recipe_ordinal[recipe_name] = Next_recipe_ordinal++; } - if (warn_on_redefine(recipe_name) + if (warn_on_redefine(recipe_name) && Recipe.find(Recipe_ordinal[recipe_name]) != Recipe.end()) { raise << "redefining recipe " << Recipe[Recipe_ordinal[recipe_name]].name << "\n" << end(); } @@ -81,7 +80,7 @@ vector<recipe_ordinal> load(istream& in result.push_back(Recipe_ordinal[recipe_name]); } // End Command Handlers - else { + else { raise << "unknown top-level command: " << command << '\n' << end(); } } @@ -92,11 +91,11 @@ vector<recipe_ordinal> load(istream& in recipe slurp_recipe(istream& in) { recipe result; skip_whitespace(in); - if (in.get() != '[') + if (in.get() != '[') raise << "recipe body must begin with '['\n" << end(); skip_whitespace_and_comments(in); instruction curr; - while (next_instruction(in, &curr)) { + while (next_instruction(in, &curr)) { // End Rewrite Instruction(curr) //? cerr << "instruction: " << curr.to_string() << '\n'; //? 2 result.steps.push_back(curr); @@ -104,34 +103,34 @@ recipe slurp_recipe(istream& inreturn result; } -bool next_instruction(istream& in, instruction* curr) { +bool next_instruction(istream& in, instruction* curr) { in >> std::noskipws; curr->clear(); - if (in.eof()) return false; + if (in.eof()) return false; //? show_rest_of_stream(in); //? 1 - skip_whitespace(in); if (in.eof()) return false; + skip_whitespace(in); if (in.eof()) return false; //? show_rest_of_stream(in); //? 1 - skip_whitespace_and_comments(in); if (in.eof()) return false; + skip_whitespace_and_comments(in); if (in.eof()) return false; vector<string> words; //? show_rest_of_stream(in); //? 1 - while (in.peek() != '\n') { - skip_whitespace(in); if (in.eof()) return false; + while (in.peek() != '\n') { + skip_whitespace(in); if (in.eof()) return false; //? show_rest_of_stream(in); //? 1 - string word = next_word(in); if (in.eof()) return false; + string word = next_word(in); if (in.eof()) return false; //? cerr << "AAA: " << word << '\n'; //? 1 words.push_back(word); - skip_whitespace(in); if (in.eof()) return false; + skip_whitespace(in); if (in.eof()) return false; } - skip_whitespace_and_comments(in); if (in.eof()) return false; + skip_whitespace_and_comments(in); if (in.eof()) return false; //? if (SIZE(words) == 1) cout << words.at(0) << ' ' << SIZE(words.at(0)) << '\n'; //? 1 - if (SIZE(words) == 1 && words.at(0) == "]") { + if (SIZE(words) == 1 && words.at(0) == "]") { //? cout << "AAA\n"; //? 1 return false; // end of recipe } - if (SIZE(words) == 1 && !isalnum(words.at(0).at(0)) && words.at(0).at(0) != '$') { + if (SIZE(words) == 1 && !isalnum(words.at(0).at(0)) && words.at(0).at(0) != '$') { curr->is_label = true; curr->label = words.at(0); trace("parse") << "label: " << curr->label << end(); @@ -139,41 +138,41 @@ recipe slurp_recipe(istream& in} vector<string>::iterator p = words.begin(); - if (find(words.begin(), words.end(), "<-") != words.end()) { - for (; *p != "<-"; ++p) { - if (*p == ",") continue; + if (find(words.begin(), words.end(), "<-") != words.end()) { + for (; *p != "<-"; ++p) { + if (*p == ",") continue; curr->products.push_back(reagent(*p)); //? cerr << "product: " << curr->products.back().to_string() << '\n'; //? 1 } ++p; // skip <- } - if (p == words.end()) { + if (p == words.end()) { raise << "instruction prematurely ended with '<-'\n" << end() << end(); return false; } curr->name = *p; - if (Recipe_ordinal.find(*p) == Recipe_ordinal.end()) { + if (Recipe_ordinal.find(*p) == Recipe_ordinal.end()) { Recipe_ordinal[*p] = Next_recipe_ordinal++; //? cout << "AAA: " << *p << " is now " << Recipe_ordinal[*p] << '\n'; //? 1 } - if (Recipe_ordinal[*p] == 0) { + if (Recipe_ordinal[*p] == 0) { raise << "Recipe " << *p << " has number 0, which is reserved for IDLE.\n" << end() << end(); return false; } curr->operation = Recipe_ordinal[*p]; ++p; - for (; p != words.end(); ++p) { - if (*p == ",") continue; + for (; p != words.end(); ++p) { + if (*p == ",") continue; curr->ingredients.push_back(reagent(*p)); //? cerr << "ingredient: " << curr->ingredients.back().to_string() << '\n'; //? 1 } trace("parse") << "instruction: " << curr->name << end(); - for (vector<reagent>::iterator p = curr->ingredients.begin(); p != curr->ingredients.end(); ++p) { + for (vector<reagent>::iterator p = curr->ingredients.begin(); p != curr->ingredients.end(); ++p) { trace("parse") << " ingredient: " << p->to_string() << end(); } - for (vector<reagent>::iterator p = curr->products.begin(); p != curr->products.end(); ++p) { + for (vector<reagent>::iterator p = curr->products.begin(); p != curr->products.end(); ++p) { trace("parse") << " product: " << p->to_string() << end(); } return !in.eof(); @@ -190,17 +189,17 @@ string next_word(istream& inreturn out.str(); } -void slurp_word(istream& in, ostream& out) { +void slurp_word(istream& in, ostream& out) { //? cout << "AAA slurp_word\n"; //? 1 - char c; - if (in.peek() == ',') { + char c; + if (in.peek() == ',') { in >> c; out << c; return; } - while (in >> c) { + while (in >> c) { //? cout << c << '\n'; //? 1 - if (isspace(c) || c == ',') { + if (isspace(c) || c == ',') { in.putback(c); break; } @@ -208,30 +207,30 @@ string next_word(istream& in} } -void skip_whitespace(istream& in) { - while (isspace(in.peek()) && in.peek() != '\n') { +void skip_whitespace(istream& in) { + while (isspace(in.peek()) && in.peek() != '\n') { in.get(); } } -void skip_whitespace_and_comments(istream& in) { - while (true) { - if (isspace(in.peek())) in.get(); - else if (in.peek() == '#') skip_comment(in); - else break; +void skip_whitespace_and_comments(istream& in) { + while (true) { + if (isspace(in.peek())) in.get(); + else if (in.peek() == '#') skip_comment(in); + else break; } } -void skip_comment(istream& in) { - if (in.peek() == '#') { +void skip_comment(istream& in) { + if (in.peek() == '#') { in.get(); - while (in.peek() != '\n') in.get(); + while (in.peek() != '\n') in.get(); } } -void skip_comma(istream& in) { +void skip_comma(istream& in) { skip_whitespace(in); - if (in.peek() == ',') in.get(); + if (in.peek() == ',') in.get(); skip_whitespace(in); } @@ -239,24 +238,24 @@ string next_word(istream& in//: step on their own toes. But there'll be many occasions later where //: we'll want to disable the warnings. :(before "End Globals") -bool Disable_redefine_warnings = false; +bool Disable_redefine_warnings = false; :(before "End Setup") Disable_redefine_warnings = false; :(code) -bool warn_on_redefine(const string& recipe_name) { - if (Disable_redefine_warnings) return false; +bool warn_on_redefine(const string& recipe_name) { + if (Disable_redefine_warnings) return false; return true; } // for debugging :(before "End Globals") -bool Show_rest_of_stream = false; +bool Show_rest_of_stream = false; :(code) -void show_rest_of_stream(istream& in) { - if (!Show_rest_of_stream) return; +void show_rest_of_stream(istream& in) { + if (!Show_rest_of_stream) return; cerr << '^'; - char c; - while (in >> c) { + char c; + while (in >> c) { cerr << c; } cerr << "$\n"; @@ -267,7 +266,7 @@ Disable_redefine_warnings = false:(before "End Globals") vector<recipe_ordinal> recently_added_recipes; :(before "End Setup") -for (long long int i = 0; i < SIZE(recently_added_recipes); ++i) { +for (long long int i = 0; i < SIZE(recently_added_recipes); ++i) { //? cout << "AAA clearing " << Recipe[recently_added_recipes.at(i)].name << '\n'; //? 2 Recipe_ordinal.erase(Recipe[recently_added_recipes.at(i)].name); Recipe.erase(recently_added_recipes.at(i)); @@ -280,7 +279,7 @@ recently_added_recipes.clear# this comment will go through to 'load' recipe main [ - 1:number <- copy 23:literal + 1:number <- copy 23 ] +parse: instruction: copy +parse: ingredient: {name: "23", properties: ["23": "literal"]} @@ -289,7 +288,7 @@ recipe main [ :(scenario parse_comment_amongst_instruction) recipe main [ # comment - 1:number <- copy 23:literal + 1:number <- copy 23 ] +parse: instruction: copy +parse: ingredient: {name: "23", properties: ["23": "literal"]} @@ -298,7 +297,7 @@ recipe main [ :(scenario parse_comment_amongst_instruction2) recipe main [ # comment - 1:number <- copy 23:literal + 1:number <- copy 23 # comment ] +parse: instruction: copy @@ -307,9 +306,9 @@ recipe main [ :(scenario parse_comment_amongst_instruction3) recipe main [ - 1:number <- copy 23:literal + 1:number <- copy 23 # comment - 2:number <- copy 23:literal + 2:number <- copy 23 ] +parse: instruction: copy +parse: ingredient: {name: "23", properties: ["23": "literal"]} @@ -320,7 +319,7 @@ recipe main [ :(scenario parse_comment_after_instruction) recipe main [ - 1:number <- copy 23:literal # comment + 1:number <- copy 23 # comment ] +parse: instruction: copy +parse: ingredient: {name: "23", properties: ["23": "literal"]} @@ -340,7 +339,7 @@ recipe main [ :(scenario parse_multiple_properties) recipe main [ - 1:number <- copy 23:literal/foo:bar:baz + 1:number <- copy 23/foo:bar:baz ] +parse: instruction: copy +parse: ingredient: {name: "23", properties: ["23": "literal", "foo": "bar":"baz"]} @@ -348,7 +347,7 @@ recipe main [ :(scenario parse_multiple_products) recipe main [ - 1:number, 2:number <- copy 23:literal + 1:number, 2:number <- copy 23 ] +parse: instruction: copy +parse: ingredient: {name: "23", properties: ["23": "literal"]} @@ -357,7 +356,7 @@ recipe main [ :(scenario parse_multiple_ingredients) recipe main [ - 1:number, 2:number <- copy 23:literal, 4:number + 1:number, 2:number <- copy 23, 4:number ] +parse: instruction: copy +parse: ingredient: {name: "23", properties: ["23": "literal"]} @@ -367,7 +366,7 @@ recipe main [ :(scenario parse_multiple_types) recipe main [ - 1:number, 2:address:number <- copy 23:literal, 4:number + 1:number, 2:address:number <- copy 23, 4:number ] +parse: instruction: copy +parse: ingredient: {name: "23", properties: ["23": "literal"]} @@ -377,9 +376,9 @@ recipe main [ :(scenario parse_properties) recipe main [ - 1:number:address/deref <- copy 23:literal + 1:number:address/lookup <- copy 23 ] -+parse: product: {name: "1", properties: ["1": "number":"address", "deref": ]} ++parse: product: {name: "1", properties: ["1": "number":"address", "lookup": ]} diff --git a/html/012transform.cc.html b/html/012transform.cc.html index 21163e04..407e5be7 100644 --- a/html/012transform.cc.html +++ b/html/012transform.cc.html @@ -14,7 +14,6 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background- body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .CommentedCode { color: #6c6c6c; } @@ -36,23 +35,23 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } //: deconstructed alternative to conventional compilers. :(before "End recipe Fields") -long long int transformed_until; +long long int transformed_until; recipe() :transformed_until(-1) {} :(before "End Types") -typedef void (*transform_fn)(recipe_ordinal); +typedef void (*transform_fn)(recipe_ordinal); :(before "End Globals") vector<transform_fn> Transform; :(code) -void transform_all() { +void transform_all() { //? cerr << "AAA transform_all\n"; //? 2 - for (long long int t = 0; t < SIZE(Transform); ++t) { - for (map<recipe_ordinal, recipe>::iterator p = Recipe.begin(); p != Recipe.end(); ++p) { + for (long long int t = 0; t < SIZE(Transform); ++t) { + for (map<recipe_ordinal, recipe>::iterator p = Recipe.begin(); p != Recipe.end(); ++p) { recipe& r = p->second; - if (r.steps.empty()) continue; - if (r.transformed_until != t-1) continue; + if (r.steps.empty()) continue; + if (r.transformed_until != t-1) continue; (*Transform.at(t))(/*recipe_ordinal*/p->first); r.transformed_until = t; } @@ -60,27 +59,27 @@ vector<transform_fn> Transform; parse_int_reagents(); // do this after all other transforms have run } -void parse_int_reagents() { +void parse_int_reagents() { //? cout << "parse_int_reagents\n"; //? 1 - for (map<recipe_ordinal, recipe>::iterator p = Recipe.begin(); p != Recipe.end(); ++p) { + for (map<recipe_ordinal, recipe>::iterator p = Recipe.begin(); p != Recipe.end(); ++p) { recipe& r = p->second; - if (r.steps.empty()) continue; - for (long long int index = 0; index < SIZE(r.steps); ++index) { + if (r.steps.empty()) continue; + for (long long int index = 0; index < SIZE(r.steps); ++index) { instruction& inst = r.steps.at(index); - for (long long int i = 0; i < SIZE(inst.ingredients); ++i) { + for (long long int i = 0; i < SIZE(inst.ingredients); ++i) { populate_value(inst.ingredients.at(i)); } - for (long long int i = 0; i < SIZE(inst.products); ++i) { + for (long long int i = 0; i < SIZE(inst.products); ++i) { populate_value(inst.products.at(i)); } } } } -void populate_value(reagent& r) { - if (r.initialized) return; +void populate_value(reagent& r) { + if (r.initialized) return; // End Reagent-parsing Exceptions - if (!is_integer(r.name)) return; + if (!is_integer(r.name)) return; r.set_value(to_integer(r.name)); } diff --git a/html/013literal_string.cc.html b/html/013literal_string.cc.html index 03e3b5d3..b6c539cf 100644 --- a/html/013literal_string.cc.html +++ b/html/013literal_string.cc.html @@ -13,15 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } +.CommentedCode { color: #6c6c6c; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -57,7 +56,7 @@ recipe main [ Type_ordinal["literal-string"] = 0; :(after "string next_word(istream& in)") - if (in.peek() == '[') { + if (in.peek() == '[') { string result = slurp_quoted(in); skip_whitespace(in); skip_comment(in); @@ -68,26 +67,26 @@ Type_ordinal["literal-string"] = :(code) string slurp_quoted(istream& in) { ostringstream out; - assert(!in.eof()); assert(in.peek() == '['); out << static_cast<char>(in.get()); // slurp the '[' - if (code_string(in, out)) + assert(!in.eof()); assert(in.peek() == '['); out << static_cast<char>(in.get()); // slurp the '[' + if (code_string(in, out)) slurp_quoted_comment_aware(in, out); - else + else slurp_quoted_comment_oblivious(in, out); return out.str(); } // A string is a code string if it contains a newline before any non-whitespace // todo: support comments before the newline. But that gets messy. -bool code_string(istream& in, ostringstream& out) { - while (!in.eof()) { - char c = in.get(); - if (!isspace(c)) { +bool code_string(istream& in, ostringstream& out) { + while (!in.eof()) { + char c = in.get(); + if (!isspace(c)) { in.putback(c); //? cerr << "code_string: " << out.str() << '\n'; //? 1 return false; } out << c; - if (c == '\n') { + if (c == '\n') { //? cerr << "code_string: " << out.str() << '\n'; //? 1 return true; } @@ -97,70 +96,69 @@ string slurp_quoted(istream& in// Read a regular string. Regular strings can only contain other regular // strings. -void slurp_quoted_comment_oblivious(istream& in, ostringstream& out) { +void slurp_quoted_comment_oblivious(istream& in, ostringstream& out) { //? cerr << "comment oblivious\n"; //? 1 - int brace_depth = 1; - while (!in.eof()) { - char c = in.get(); + int brace_depth = 1; + while (!in.eof()) { + char c = in.get(); //? cerr << '%' << (int)c << ' ' << brace_depth << ": " << out.str() << "%$\n"; //? 1 //? cout << (int)c << ": " << brace_depth << '\n'; //? 2 - if (c == '\\') { - out << static_cast<char>(in.get()); + if (c == '\\') { + out << static_cast<char>(in.get()); continue; } out << c; //? cout << out.str() << "$\n"; //? 1 - if (c == '[') ++brace_depth; - if (c == ']') --brace_depth; - if (brace_depth == 0) break; + if (c == '[') ++brace_depth; + if (c == ']') --brace_depth; + if (brace_depth == 0) break; } - if (in.eof() && brace_depth > 0) { + if (in.eof() && brace_depth > 0) { raise << "unbalanced '['\n" << end(); out.clear(); } } // Read a code string. Code strings can contain either code or regular strings. -void slurp_quoted_comment_aware(istream& in, ostringstream& out) { +void slurp_quoted_comment_aware(istream& in, ostringstream& out) { //? cerr << "comment aware\n"; //? 1 - char c; - while (in >> c) { + char c; + while (in >> c) { //? cerr << '^' << (int)c << ": " << out.str() << "$\n"; //? 1 - if (c == '\\') { - out << static_cast<char>(in.get()); + if (c == '\\') { + out << static_cast<char>(in.get()); continue; } - if (c == '#') { + if (c == '#') { out << c; - while (!in.eof() && in.peek() != '\n') out << static_cast<char>(in.get()); + while (!in.eof() && in.peek() != '\n') out << static_cast<char>(in.get()); continue; } - if (c == '[') { + if (c == '[') { in.putback(c); // recurse out << slurp_quoted(in); continue; } out << c; - if (c == ']') return; + if (c == ']') return; } raise << "unbalanced '['\n" << end(); out.clear(); } -:(after "reagent::reagent(string s)") -//? cout << s.at(0) << '\n'; //? 1 - if (s.at(0) == '[') { - assert(*s.rbegin() == ']'); - // delete [] delimiters - s.erase(0, 1); - s.erase(SIZE(s)-1); - name = s; - types.push_back(0); - properties.push_back(pair<string, vector<string> >(name, vector<string>())); - properties.back().second.push_back("literal-string"); - return; - } +:(after "Parsing reagent(string s)") +if (s.at(0) == '[') { + assert(*s.rbegin() == ']'); + // delete [] delimiters + s.erase(0, 1); + s.erase(SIZE(s)-1); + name = s; + types.push_back(0); + properties.push_back(pair<string, vector<string> >(name, vector<string>())); + properties.back().second.push_back("literal-string"); + return; +} //: Two tweaks to printing literal strings compared to other reagents: //: a) Don't print the string twice in the representation, just put '_' in @@ -168,21 +166,21 @@ string slurp_quoted(istream& in//: b) Escape newlines in the string to make it more friendly to trace(). :(after "string reagent::to_string()") - if (!properties.at(0).second.empty() && properties.at(0).second.at(0) == "literal-string") { + if (!properties.at(0).second.empty() && properties.at(0).second.at(0) == "literal-string") { return emit_literal_string(name); } :(code) string emit_literal_string(string name) { - size_t pos = 0; - while (pos != string::npos) + size_t pos = 0; + while (pos != string::npos) pos = replace(name, "\n", "\\n", pos); return "{name: \""+name+"\", properties: [_: \"literal-string\"]}"; } -size_t replace(string& str, const string& from, const string& to, size_t n) { - size_t result = str.find(from, n); - if (result != string::npos) +size_t replace(string& str, const string& from, const string& to, size_t n) { + size_t result = str.find(from, n); + if (result != string::npos) str.replace(result, from.length(), to); return result; } diff --git a/html/014literal_noninteger.cc.html b/html/014literal_noninteger.cc.html index b2578e88..7235bf47 100644 --- a/html/014literal_noninteger.cc.html +++ b/html/014literal_noninteger.cc.html @@ -13,14 +13,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -33,7 +32,6 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 //: Support literal non-integers.
-//: '3.14159:literal' is ugly, so we'll just say '3.14159' for non-integers.
 
 :(scenarios load)
 :(scenario noninteger_literal)
@@ -42,26 +40,26 @@ recipe main [
 ]
 +parse:   ingredient: {name: "3.14159", properties: ["3.14159": "literal-number"]}
 
-:(after "reagent::reagent(string s)")
-  if (is_noninteger(s)) {
-    name = s;
-    types.push_back(0);
-    properties.push_back(pair<string, vector<string> >(name, vector<string>()));
-    properties.back().second.push_back("literal-number");
-    set_value(to_double(s));
-    return;
-  }
+:(after "Parsing reagent(string s)")
+if (is_noninteger(s)) {
+  name = s;
+  types.push_back(0);
+  properties.push_back(pair<string, vector<string> >(name, vector<string>()));
+  properties.back().second.push_back("literal-number");
+  set_value(to_double(s));
+  return;
+}
 
 :(code)
-bool is_noninteger(const string& s) {
+bool is_noninteger(const string& s) {
   return s.find_first_not_of("0123456789-.") == string::npos
       && s.find('.') != string::npos;
 }
 
-double to_double(string n) {
-  char* end = NULL;
+double to_double(string n) {
+  char* end = NULL;
   // safe because string.c_str() is guaranteed to be null-terminated
-  double result = strtod(n.c_str(), &end);
+  double result = strtod(n.c_str(), &end);
   assert(*end == '\0');
   return result;
 }
diff --git a/html/020run.cc.html b/html/020run.cc.html
index ffe4de8f..bf21779f 100644
--- a/html/020run.cc.html
+++ b/html/020run.cc.html
@@ -13,17 +13,16 @@
 pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
 body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 1.05em; }
+.traceContains { color: #008000; }
 .cSpecial { color: #008000; }
-.SalientComment { color: #00ffff; }
 .Constant { color: #00a0a0; }
-.CommentedCode { color: #6c6c6c; }
+.SalientComment { color: #00ffff; }
 .traceAbsent { color: #c00000; }
-.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #a04060; }
 .Special { color: #ff6060; }
+.CommentedCode { color: #6c6c6c; }
 .Identifier { color: #804000; }
-.traceContains { color: #008000; }
 -->
 
 
@@ -48,14 +47,14 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 
 :(scenario copy_literal)
 recipe main [
-  1:number <- copy 23:literal
+  1:number <- copy 23
 ]
-+run: 1:number <- copy 23:literal
++run: 1:number <- copy 23
 +mem: storing 23 in location 1
 
 :(scenario copy)
 recipe main [
-  1:number <- copy 23:literal
+  1:number <- copy 23
   2:number <- copy 1:number
 ]
 +run: 2:number <- copy 1:number
@@ -64,7 +63,7 @@ recipe main [
 
 :(scenario copy_multiple)
 recipe main [
-  1:number, 2:number <- copy 23:literal, 24:literal
+  1:number, 2:number <- copy 23, 24
 ]
 +mem: storing 23 in location 1
 +mem: storing 24 in location 2
@@ -72,120 +71,130 @@ recipe main [
 :(before "End Types")
 // Book-keeping while running a recipe.
 //: Later layers will change this.
-struct routine {
+struct routine {
   recipe_ordinal running_recipe;
-  long long int running_step_index;
+  long long int running_step_index;
   routine(recipe_ordinal r) :running_recipe(r), running_step_index(0) {}
-  bool completed() const;
+  bool completed() const;
 };
 
 :(before "End Globals")
 routine* Current_routine = NULL;
 
 :(code)
-void run(recipe_ordinal r) {
+void run(recipe_ordinal r) {
   routine rr(r);
   Current_routine = &rr;
   run_current_routine();
 }
 
-void run_current_routine()
+void run_current_routine()
 {  // curly on a separate line, because later layers will modify header
 //?   cerr << "AAA 6\n"; //? 3
-  while (!Current_routine->completed())  // later layers will modify condition
+  while (!Current_routine->completed())  // later layers will modify condition
   {
 //?     cerr << "AAA 7: " << current_step_index() << '\n'; //? 1
     // Running One Instruction
-    if (current_instruction().is_label) { ++current_step_index(); continue; }
+    if (current_instruction().is_label) { ++current_step_index(); continue; }
     trace(Initial_callstack_depth+Callstack_depth, "run") << current_instruction().to_string() << end();
-    if (Memory[0] != 0) {
+    if (Memory[0] != 0) {
       raise << "something wrote to location 0; this should never happen\n" << end();
       break;
     }
     // Read all ingredients from memory.
     // Each ingredient loads a vector of values rather than a single value; mu
     // permits operating on reagents spanning multiple locations.
-    vector<vector<double> > ingredients;
-    for (long long int i = 0; i < SIZE(current_instruction().ingredients); ++i) {
+    vector<vector<double> > ingredients;
+    for (long long int i = 0; i < SIZE(current_instruction().ingredients); ++i) {
       ingredients.push_back(read_memory(current_instruction().ingredients.at(i)));
     }
     // Instructions below will write to 'products'.
-    vector<vector<double> > products;
+    vector<vector<double> > products;
 //?     cerr << "AAA 8: " << current_instruction().operation << " ^" << Recipe[current_instruction().operation].name << "$\n"; //? 1
 //?     cerr << "% " << current_recipe_name() << "/" << current_step_index() << ": " << Memory[1013] << ' ' << Memory[1014] << '\n'; //? 1
-    switch (current_instruction().operation) {
+    switch (current_instruction().operation) {
       // Primitive Recipe Implementations
-      case COPY: {
+      case COPY: {
 //?         if (!ingredients.empty()) cerr << current_instruction().ingredients.at(0).to_string() << ' ' << ingredients.at(0).at(0) << '\n'; //? 1
         copy(ingredients.begin(), ingredients.end(), inserter(products, products.begin()));
         break;
       }
       // End Primitive Recipe Implementations
-      default: {
+      default: {
         cout << "not a primitive op: " << current_instruction().operation << '\n';
       }
     }
-    if (SIZE(products) < SIZE(current_instruction().products))
+    if (SIZE(products) < SIZE(current_instruction().products))
       raise << SIZE(products) << " vs " << SIZE(current_instruction().products) << ": failed to write to all products! " << current_instruction().to_string() << end();
-    for (long long int i = 0; i < SIZE(current_instruction().products); ++i) {
+    for (long long int i = 0; i < SIZE(current_instruction().products); ++i) {
       write_memory(current_instruction().products.at(i), products.at(i));
     }
     // End of Instruction
     ++current_step_index();
   }
 //?   cerr << "AAA 9\n"; //? 2
-  stop_running_current_routine:;
+  stop_running_current_routine:;
 }
 
 //: Some helpers.
 //: We'll need to override these later as we change the definition of routine.
 //: Important that they return referrences into the routine.
 
-inline long long int& current_step_index() {
+inline long long int& current_step_index() {
   return Current_routine->running_step_index;
 }
 
-inline const string& current_recipe_name() {
+inline const string& current_recipe_name() {
   return Recipe[Current_routine->running_recipe].name;
 }
 
-inline const instruction& current_instruction() {
+inline const instruction& current_instruction() {
   return Recipe[Current_routine->running_recipe].steps.at(Current_routine->running_step_index);
 }
 
-inline bool routine::completed() const {
+inline bool routine::completed() const {
   return running_step_index >= SIZE(Recipe[running_recipe].steps);
 }
 
 :(before "End Commandline Parsing")
 // Loading Commandline Files
-if (argc > 1) {
-  for (int i = 1; i < argc; ++i) {
+if (argc > 1) {
+  for (int i = 1; i < argc; ++i) {
     load_permanently(argv[i]);
   }
 }
 
 :(before "End Main")
-if (!Run_tests) {
+if (!Run_tests) {
   setup();
-//?   Trace_file = "interactive"; //? 1
-//?   START_TRACING_UNTIL_END_OF_SCOPE;
-//?   Trace_stream->dump_layer = "all"; //? 2
+//?   Trace_file = "interactive"; //? 2
+//?   START_TRACING_UNTIL_END_OF_SCOPE; //? 2
+//?   Trace_stream->collect_layer = "app"; //? 1
   transform_all();
   recipe_ordinal r = Recipe_ordinal[string("main")];
-//?   Trace_stream->dump_layer = "all"; //? 1
-  if (r) run(r);
+  if (r) run(r);
 //?   dump_memory(); //? 1
   teardown();
 }
 
 :(code)
-void load_permanently(string filename) {
+void cleanup_main() {
+  if (!Trace_file.empty()) {
+    ofstream fout(Trace_file.c_str());
+    fout << Trace_stream->readable_contents("");
+    fout.close();
+  }
+}
+:(before "End One-time Setup")
+atexit(cleanup_main);
+
+:(code)
+void load_permanently(string filename) {
   ifstream fin(filename.c_str());
   fin.peek();
 //?   cerr << "AAA: " << filename << ' ' << static_cast<bool>(fin) << ' ' << fin.fail() << '\n'; //? 1
 //?   return; //? 1
-  if (!fin) {
+  if (!fin) {
     raise << "no such file " << filename << '\n' << end();
     return;
   }
@@ -204,11 +213,11 @@ load_permanently("cor
 
 :(code)
 // helper for tests
-void run(string form) {
+void run(string form) {
 //?   cerr << "AAA 2\n"; //? 2
 //?   cerr << form << '\n'; //? 1
   vector<recipe_ordinal> tmp = load(form);
-  if (tmp.empty()) return;
+  if (tmp.empty()) return;
   transform_all();
 //?   cerr << "AAA 3\n"; //? 2
   run(tmp.front());
@@ -217,83 +226,85 @@ load_permanently("cor
 
 //:: Reading from memory, writing to memory.
 
-vector<double> read_memory(reagent x) {
+vector<double> read_memory(reagent x) {
 //?   cout << "read_memory: " << x.to_string() << '\n'; //? 2
-  vector<double> result;
-  if (is_literal(x)) {
+  vector<double> result;
+  if (is_literal(x)) {
     result.push_back(x.value);
     return result;
   }
-  long long int base = x.value;
-  long long int size = size_of(x);
-  for (long long int offset = 0; offset < size; ++offset) {
-    double val = Memory[base+offset];
+  long long int base = x.value;
+  long long int size = size_of(x);
+  for (long long int offset = 0; offset < size; ++offset) {
+    double val = Memory[base+offset];
     trace(Primitive_recipe_depth, "mem") << "location " << base+offset << " is " << val << end();
     result.push_back(val);
   }
   return result;
 }
 
-void write_memory(reagent x, vector<double> data) {
-  if (is_dummy(x)) return;
-  if (is_literal(x)) return;
-  long long int base = x.value;
-  if (size_mismatch(x, data)) {
-    raise << current_recipe_name() << ": size mismatch in storing to " << x.to_string() << " at " << current_instruction().to_string() << '\n' << end();
+void write_memory(reagent x, vector<double> data) {
+  if (is_dummy(x)) return;
+  if (is_literal(x)) return;
+  long long int base = x.value;
+  if (size_mismatch(x, data)) {
+    raise << current_recipe_name() << ": size mismatch in storing to " << x.original_string << " at '" << current_instruction().to_string() << "'\n" << end();
     return;
   }
-  for (long long int offset = 0; offset < SIZE(data); ++offset) {
+  for (long long int offset = 0; offset < SIZE(data); ++offset) {
     trace(Primitive_recipe_depth, "mem") << "storing " << data.at(offset) << " in location " << base+offset << end();
     Memory[base+offset] = data.at(offset);
   }
 }
 
 :(code)
-long long int size_of(const reagent& r) {
-  if (r.types.empty()) return 0;
+long long int size_of(const reagent& r) {
+  if (r.types.empty()) return 0;
   // End size_of(reagent) Cases
   return size_of(r.types);
 }
-long long int size_of(const vector<type_ordinal>& types) {
-  if (types.empty()) return 0;
+long long int size_of(const vector<type_ordinal>& types) {
+  if (types.empty()) return 0;
   // End size_of(types) Cases
   return 1;
 }
 
-bool size_mismatch(const reagent& x, const vector<double>& data) {
+bool size_mismatch(const reagent& x, const vector<double>& data) {
+  if (x.types.empty()) return true;
+  // End size_mismatch(x) Cases
 //?   if (size_of(x) != SIZE(data)) cerr << size_of(x) << " vs " << SIZE(data) << '\n'; //? 2
   return size_of(x) != SIZE(data);
 }
 
-bool is_dummy(const reagent& x) {
+bool is_dummy(const reagent& x) {
   return x.name == "_";
 }
 
-bool is_literal(const reagent& r) {
+bool is_literal(const reagent& r) {
   return SIZE(r.types) == 1 && r.types.at(0) == 0;
 }
 
 :(scenario run_label)
 recipe main [
   +foo
-  1:number <- copy 23:literal
+  1:number <- copy 23
   2:number <- copy 1:number
 ]
-+run: 1:number <- copy 23:literal
++run: 1:number <- copy 23
 +run: 2:number <- copy 1:number
 -run: +foo
 
 :(scenario run_dummy)
 recipe main [
-  _ <- copy 0:literal
+  _ <- copy 0
 ]
-+run: _ <- copy 0:literal
++run: _ <- copy 0
 
-:(scenario run_literal)
+:(scenario write_to_0_disallowed)
 recipe main [
-  0:literal/screen <- copy 0:literal
+  0 <- copy 34
 ]
--mem: storing 0 in location 0
+-mem: storing 34 in location 0
 
diff --git a/html/021arithmetic.cc.html b/html/021arithmetic.cc.html index 11c9267a..b43cb286 100644 --- a/html/021arithmetic.cc.html +++ b/html/021arithmetic.cc.html @@ -13,15 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.Special { color: #ff6060; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } +.Special { color: #ff6060; } .CommentedCode { color: #6c6c6c; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -40,10 +39,10 @@ ADD, :(before "End Primitive Recipe Numbers") Recipe_ordinal["add"] = ADD; :(before "End Primitive Recipe Implementations") -case ADD: { - double result = 0; +case ADD: { + double result = 0; //? if (!tb_is_active()) cerr << ingredients.at(1).at(0) << '\n'; //? 1 - for (long long int i = 0; i < SIZE(ingredients); ++i) { + for (long long int i = 0; i < SIZE(ingredients); ++i) { assert(scalar(ingredients.at(i))); result += ingredients.at(i).at(0); } @@ -54,21 +53,21 @@ Recipe_ordinal["add"] = ADD:(scenario add_literal) recipe main [ - 1:number <- add 23:literal, 34:literal + 1:number <- add 23, 34 ] +mem: storing 57 in location 1 :(scenario add) recipe main [ - 1:number <- copy 23:literal - 2:number <- copy 34:literal + 1:number <- copy 23 + 2:number <- copy 34 3:number <- add 1:number, 2:number ] +mem: storing 57 in location 3 :(scenario add_multiple) recipe main [ - 1:number <- add 3:literal, 4:literal, 5:literal + 1:number <- add 3, 4, 5 ] +mem: storing 12 in location 1 @@ -77,14 +76,14 @@ SUBTRACT, :(before "End Primitive Recipe Numbers") Recipe_ordinal["subtract"] = SUBTRACT; :(before "End Primitive Recipe Implementations") -case SUBTRACT: { - if (ingredients.empty()) { +case SUBTRACT: { + if (ingredients.empty()) { raise << current_recipe_name() << ": 'subtract' has no ingredients\n" << end(); break; } assert(scalar(ingredients.at(0))); - double result = ingredients.at(0).at(0); - for (long long int i = 1; i < SIZE(ingredients); ++i) { + double result = ingredients.at(0).at(0); + for (long long int i = 1; i < SIZE(ingredients); ++i) { assert(scalar(ingredients.at(i))); result -= ingredients.at(i).at(0); } @@ -95,21 +94,21 @@ Recipe_ordinal["subtract"] = SUBTRACT:(scenario subtract_literal) recipe main [ - 1:number <- subtract 5:literal, 2:literal + 1:number <- subtract 5, 2 ] +mem: storing 3 in location 1 :(scenario subtract) recipe main [ - 1:number <- copy 23:literal - 2:number <- copy 34:literal + 1:number <- copy 23 + 2:number <- copy 34 3:number <- subtract 1:number, 2:number ] +mem: storing -11 in location 3 :(scenario subtract_multiple) recipe main [ - 1:number <- subtract 6:literal, 3:literal, 2:literal + 1:number <- subtract 6, 3, 2 ] +mem: storing 1 in location 1 @@ -118,9 +117,9 @@ MULTIPLY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["multiply"] = MULTIPLY; :(before "End Primitive Recipe Implementations") -case MULTIPLY: { - double result = 1; - for (long long int i = 0; i < SIZE(ingredients); ++i) { +case MULTIPLY: { + double result = 1; + for (long long int i = 0; i < SIZE(ingredients); ++i) { assert(scalar(ingredients.at(i))); result *= ingredients.at(i).at(0); } @@ -131,21 +130,21 @@ Recipe_ordinal["multiply"] = MULTIPLY:(scenario multiply_literal) recipe main [ - 1:number <- multiply 2:literal, 3:literal + 1:number <- multiply 2, 3 ] +mem: storing 6 in location 1 :(scenario multiply) recipe main [ - 1:number <- copy 4:literal - 2:number <- copy 6:literal + 1:number <- copy 4 + 2:number <- copy 6 3:number <- multiply 1:number, 2:number ] +mem: storing 24 in location 3 :(scenario multiply_multiple) recipe main [ - 1:number <- multiply 2:literal, 3:literal, 4:literal + 1:number <- multiply 2, 3, 4 ] +mem: storing 24 in location 1 @@ -154,14 +153,14 @@ DIVIDE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["divide"] = DIVIDE; :(before "End Primitive Recipe Implementations") -case DIVIDE: { - if (ingredients.empty()) { +case DIVIDE: { + if (ingredients.empty()) { raise << current_recipe_name() << ": 'divide' has no ingredients\n" << end(); break; } assert(scalar(ingredients.at(0))); - double result = ingredients.at(0).at(0); - for (long long int i = 1; i < SIZE(ingredients); ++i) { + double result = ingredients.at(0).at(0); + for (long long int i = 1; i < SIZE(ingredients); ++i) { assert(scalar(ingredients.at(i))); result /= ingredients.at(i).at(0); } @@ -172,21 +171,21 @@ Recipe_ordinal["divide"] = DIVIDE:(scenario divide_literal) recipe main [ - 1:number <- divide 8:literal, 2:literal + 1:number <- divide 8, 2 ] +mem: storing 4 in location 1 :(scenario divide) recipe main [ - 1:number <- copy 27:literal - 2:number <- copy 3:literal + 1:number <- copy 27 + 2:number <- copy 3 3:number <- divide 1:number, 2:number ] +mem: storing 9 in location 3 :(scenario divide_multiple) recipe main [ - 1:number <- divide 12:literal, 3:literal, 2:literal + 1:number <- divide 12, 3, 2 ] +mem: storing 2 in location 1 @@ -197,13 +196,13 @@ DIVIDE_WITH_REMAINDER, :(before "End Primitive Recipe Numbers") Recipe_ordinal["divide-with-remainder"] = DIVIDE_WITH_REMAINDER; :(before "End Primitive Recipe Implementations") -case DIVIDE_WITH_REMAINDER: { - if (SIZE(ingredients) != 2) { +case DIVIDE_WITH_REMAINDER: { + if (SIZE(ingredients) != 2) { raise << current_recipe_name() << ": 'divide-with-remainder' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end(); break; } - long long int quotient = ingredients.at(0).at(0) / ingredients.at(1).at(0); - long long int remainder = static_cast<long long int>(ingredients.at(0).at(0)) % static_cast<long long int>(ingredients.at(1).at(0)); + long long int quotient = ingredients.at(0).at(0) / ingredients.at(1).at(0); + long long int remainder = static_cast<long long int>(ingredients.at(0).at(0)) % static_cast<long long int>(ingredients.at(1).at(0)); products.resize(2); // very large integers will lose precision products.at(0).push_back(quotient); @@ -213,15 +212,15 @@ Recipe_ordinal["divide-with-remainder"] :(scenario divide_with_remainder_literal) recipe main [ - 1:number, 2:number <- divide-with-remainder 9:literal, 2:literal + 1:number, 2:number <- divide-with-remainder 9, 2 ] +mem: storing 4 in location 1 +mem: storing 1 in location 2 :(scenario divide_with_remainder) recipe main [ - 1:number <- copy 27:literal - 2:number <- copy 11:literal + 1:number <- copy 27 + 2:number <- copy 11 3:number, 4:number <- divide-with-remainder 1:number, 2:number ] +mem: storing 2 in location 3 @@ -230,15 +229,15 @@ recipe main [ :(scenario divide_with_decimal_point) recipe main [ # todo: literal floats? - 1:number <- divide 5:literal, 2:literal + 1:number <- divide 5, 2 ] +mem: storing 2.5 in location 1 :(code) -inline bool scalar(const vector<long long int>& x) { +inline bool scalar(const vector<long long int>& x) { return SIZE(x) == 1; } -inline bool scalar(const vector<double>& x) { +inline bool scalar(const vector<double>& x) { return SIZE(x) == 1; } diff --git a/html/022boolean.cc.html b/html/022boolean.cc.html index a3a6d1c1..484cae1a 100644 --- a/html/022boolean.cc.html +++ b/html/022boolean.cc.html @@ -13,13 +13,12 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -38,9 +37,9 @@ AND, :(before "End Primitive Recipe Numbers") Recipe_ordinal["and"] = AND; :(before "End Primitive Recipe Implementations") -case AND: { - bool result = true; - for (long long int i = 0; i < SIZE(ingredients); ++i) { +case AND: { + bool result = true; + for (long long int i = 0; i < SIZE(ingredients); ++i) { assert(scalar(ingredients.at(i))); result = result && ingredients.at(i).at(0); } @@ -51,27 +50,27 @@ Recipe_ordinal["and"] = AND:(scenario and) recipe main [ - 1:boolean <- copy 1:literal - 2:boolean <- copy 0:literal - 3:boolean <- and 1:boolean, 2:boolean + 1:boolean <- copy 1 + 2:boolean <- copy 0 + 3:boolean <- and 1:boolean, 2:boolean ] +mem: storing 0 in location 3 :(scenario and2) recipe main [ - 1:boolean <- and 1:literal, 1:literal + 1:boolean <- and 1, 1 ] +mem: storing 1 in location 1 :(scenario and_multiple) recipe main [ - 1:boolean <- and 1:literal, 1:literal, 0:literal + 1:boolean <- and 1, 1, 0 ] +mem: storing 0 in location 1 :(scenario and_multiple2) recipe main [ - 1:boolean <- and 1:literal, 1:literal, 1:literal + 1:boolean <- and 1, 1, 1 ] +mem: storing 1 in location 1 @@ -80,9 +79,9 @@ OR, :(before "End Primitive Recipe Numbers") Recipe_ordinal["or"] = OR; :(before "End Primitive Recipe Implementations") -case OR: { - bool result = false; - for (long long int i = 0; i < SIZE(ingredients); ++i) { +case OR: { + bool result = false; + for (long long int i = 0; i < SIZE(ingredients); ++i) { assert(scalar(ingredients.at(i))); result = result || ingredients.at(i).at(0); } @@ -93,27 +92,27 @@ Recipe_ordinal["or"] = OR:(scenario or) recipe main [ - 1:boolean <- copy 1:literal - 2:boolean <- copy 0:literal - 3:boolean <- or 1:boolean, 2:boolean + 1:boolean <- copy 1 + 2:boolean <- copy 0 + 3:boolean <- or 1:boolean, 2:boolean ] +mem: storing 1 in location 3 :(scenario or2) recipe main [ - 1:boolean <- or 0:literal, 0:literal + 1:boolean <- or 0, 0 ] +mem: storing 0 in location 1 :(scenario or_multiple) recipe main [ - 1:boolean <- and 0:literal, 0:literal, 0:literal + 1:boolean <- and 0, 0, 0 ] +mem: storing 0 in location 1 :(scenario or_multiple2) recipe main [ - 1:boolean <- or 0:literal, 0:literal, 1:literal + 1:boolean <- or 0, 0, 1 ] +mem: storing 1 in location 1 @@ -122,9 +121,9 @@ NOT, :(before "End Primitive Recipe Numbers") Recipe_ordinal["not"] = NOT; :(before "End Primitive Recipe Implementations") -case NOT: { +case NOT: { products.resize(SIZE(ingredients)); - for (long long int i = 0; i < SIZE(ingredients); ++i) { + for (long long int i = 0; i < SIZE(ingredients); ++i) { assert(scalar(ingredients.at(i))); products.at(i).push_back(!ingredients.at(i).at(0)); } @@ -133,14 +132,14 @@ Recipe_ordinal["not"] = NOT:(scenario not) recipe main [ - 1:boolean <- copy 1:literal - 2:boolean <- not 1:boolean + 1:boolean <- copy 1 + 2:boolean <- not 1:boolean ] +mem: storing 0 in location 2 :(scenario not_multiple) recipe main [ - 1:boolean, 2:boolean, 3:boolean <- not 1:literal, 0:literal, 1:literal + 1:boolean, 2:boolean, 3:boolean <- not 1, 0, 1 ] +mem: storing 0 in location 1 +mem: storing 1 in location 2 diff --git a/html/023jump.cc.html b/html/023jump.cc.html index 16a89563..472a964b 100644 --- a/html/023jump.cc.html +++ b/html/023jump.cc.html @@ -13,16 +13,15 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } -.traceAbsent { color: #c00000; } -.Constant { color: #00a0a0; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } -.Special { color: #ff6060; } +.Constant { color: #00a0a0; } +.traceAbsent { color: #c00000; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } +.Special { color: #ff6060; } .CommentedCode { color: #6c6c6c; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -40,10 +39,10 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } #? % Trace_stream->dump_layer = "all"; #? 1 recipe main [ jump 1:offset - 1:number <- copy 1:literal + 1:number <- copy 1 ] +run: jump 1:offset --run: 1:number <- copy 1:literal +-run: 1:number <- copy 1 -mem: storing 1 in location 1 :(before "End Primitive Recipe Declarations") @@ -51,12 +50,12 @@ JUMP, :(before "End Primitive Recipe Numbers") Recipe_ordinal["jump"] = JUMP; :(before "End Primitive Recipe Implementations") -case JUMP: { - if (SIZE(ingredients) != 1) { +case JUMP: { + if (SIZE(ingredients) != 1) { raise << current_recipe_name() << ": 'jump' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'jump' should be a label or offset, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } @@ -86,21 +85,21 @@ JUMP_IF, :(before "End Primitive Recipe Numbers") Recipe_ordinal["jump-if"] = JUMP_IF; :(before "End Primitive Recipe Implementations") -case JUMP_IF: { - if (SIZE(ingredients) != 2) { +case JUMP_IF: { + if (SIZE(ingredients) != 2) { raise << current_recipe_name() << ": 'jump-if' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": 'jump-if' requires a boolean for its first ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } - if (!scalar(ingredients.at(1))) { + if (!scalar(ingredients.at(1))) { raise << current_recipe_name() << ": 'jump-if' requires a label or offset for its second ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } assert(current_instruction().ingredients.at(1).initialized); - if (!ingredients.at(0).at(0)) { + if (!ingredients.at(0).at(0)) { trace(Primitive_recipe_depth, "run") << "jump-if fell through" << end(); break; } @@ -111,22 +110,22 @@ Recipe_ordinal["jump-if"] = JUMP_IF:(scenario jump_if) recipe main [ - jump-if 999:literal, 1:offset - 123:number <- copy 1:literal + jump-if 999, 1:offset + 123:number <- copy 1 ] -+run: jump-if 999:literal, 1:offset ++run: jump-if 999, 1:offset +run: jumping to instruction 2 --run: 1:number <- copy 1:literal +-run: 1:number <- copy 1 -mem: storing 1 in location 123 :(scenario jump_if_fallthrough) recipe main [ - jump-if 0:literal, 1:offset - 123:number <- copy 1:literal + jump-if 0, 1:offset + 123:number <- copy 1 ] -+run: jump-if 0:literal, 1:offset ++run: jump-if 0, 1:offset +run: jump-if fell through -+run: 123:number <- copy 1:literal ++run: 123:number <- copy 1 +mem: storing 1 in location 123 :(before "End Primitive Recipe Declarations") @@ -134,21 +133,21 @@ JUMP_UNLESS, :(before "End Primitive Recipe Numbers") Recipe_ordinal["jump-unless"] = JUMP_UNLESS; :(before "End Primitive Recipe Implementations") -case JUMP_UNLESS: { - if (SIZE(ingredients) != 2) { +case JUMP_UNLESS: { + if (SIZE(ingredients) != 2) { raise << current_recipe_name() << ": 'jump-unless' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": 'jump-unless' requires a boolean for its first ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } - if (!scalar(ingredients.at(1))) { + if (!scalar(ingredients.at(1))) { raise << current_recipe_name() << ": 'jump-unless' requires a label or offset for its second ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } assert(current_instruction().ingredients.at(1).initialized); - if (ingredients.at(0).at(0)) { + if (ingredients.at(0).at(0)) { trace(Primitive_recipe_depth, "run") << "jump-unless fell through" << end(); break; } @@ -159,22 +158,22 @@ Recipe_ordinal["jump-unless"] = JUMP_UNL :(scenario jump_unless) recipe main [ - jump-unless 0:literal, 1:offset - 123:number <- copy 1:literal + jump-unless 0, 1:offset + 123:number <- copy 1 ] -+run: jump-unless 0:literal, 1:offset ++run: jump-unless 0, 1:offset +run: jumping to instruction 2 --run: 123:number <- copy 1:literal +-run: 123:number <- copy 1 -mem: storing 1 in location 123 :(scenario jump_unless_fallthrough) recipe main [ - jump-unless 999:literal, 1:offset - 123:number <- copy 1:literal + jump-unless 999, 1:offset + 123:number <- copy 1 ] -+run: jump-unless 999:literal, 1:offset ++run: jump-unless 999, 1:offset +run: jump-unless fell through -+run: 123:number <- copy 1:literal ++run: 123:number <- copy 1 +mem: storing 1 in location 123 diff --git a/html/024compare.cc.html b/html/024compare.cc.html index 38879a66..7944d4ff 100644 --- a/html/024compare.cc.html +++ b/html/024compare.cc.html @@ -13,14 +13,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -39,15 +38,15 @@ EQUAL, :(before "End Primitive Recipe Numbers") Recipe_ordinal["equal"] = EQUAL; :(before "End Primitive Recipe Implementations") -case EQUAL: { - if (SIZE(ingredients) <= 1) { +case EQUAL: { + if (SIZE(ingredients) <= 1) { raise << current_recipe_name() << ": 'equal' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end(); break; } - vector<double>& exemplar = ingredients.at(0); - bool result = true; - for (long long int i = 1; i < SIZE(ingredients); ++i) { - if (!equal(ingredients.at(i).begin(), ingredients.at(i).end(), exemplar.begin())) { + vector<double>& exemplar = ingredients.at(0); + bool result = true; + for (long long int i = 1; i < SIZE(ingredients); ++i) { + if (!equal(ingredients.at(i).begin(), ingredients.at(i).end(), exemplar.begin())) { result = false; break; } @@ -59,8 +58,8 @@ Recipe_ordinal["equal"] = EQUAL:(scenario equal) recipe main [ - 1:number <- copy 34:literal - 2:number <- copy 33:literal + 1:number <- copy 34 + 2:number <- copy 33 3:number <- equal 1:number, 2:number ] +mem: location 1 is 34 @@ -69,8 +68,8 @@ recipe main [ :(scenario equal2) recipe main [ - 1:number <- copy 34:literal - 2:number <- copy 34:literal + 1:number <- copy 34 + 2:number <- copy 34 3:number <- equal 1:number, 2:number ] +mem: location 1 is 34 @@ -79,13 +78,13 @@ recipe main [ :(scenario equal_multiple) recipe main [ - 1:number <- equal 34:literal, 34:literal, 34:literal + 1:number <- equal 34, 34, 34 ] +mem: storing 1 in location 1 :(scenario equal_multiple2) recipe main [ - 1:number <- equal 34:literal, 34:literal, 35:literal + 1:number <- equal 34, 34, 35 ] +mem: storing 0 in location 1 @@ -94,24 +93,24 @@ GREATER_THAN, :(before "End Primitive Recipe Numbers") Recipe_ordinal["greater-than"] = GREATER_THAN; :(before "End Primitive Recipe Implementations") -case GREATER_THAN: { - bool result = true; - if (SIZE(ingredients) <= 1) { +case GREATER_THAN: { + bool result = true; + if (SIZE(ingredients) <= 1) { raise << current_recipe_name() << ": 'greater-than' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end(); break; } - for (long long int i = 0; i < SIZE(ingredients); ++i) { - if (!scalar(ingredients.at(i))) { + for (long long int i = 0; i < SIZE(ingredients); ++i) { + if (!scalar(ingredients.at(i))) { raise << current_recipe_name() << ": 'greater-than' can only compare numbers; got " << current_instruction().ingredients.at(i).original_string << '\n' << end(); goto finish_greater_than; } } - for (long long int i = /**/1; i < SIZE(ingredients); ++i) { - if (ingredients.at(i-1).at(0) <= ingredients.at(i).at(0)) { + for (long long int i = /**/1; i < SIZE(ingredients); ++i) { + if (ingredients.at(i-1).at(0) <= ingredients.at(i).at(0)) { result = false; } } - finish_greater_than: + finish_greater_than: products.resize(1); products.at(0).push_back(result); break; @@ -119,29 +118,29 @@ Recipe_ordinal["greater-than"] = GREATER :(scenario greater_than) recipe main [ - 1:number <- copy 34:literal - 2:number <- copy 33:literal + 1:number <- copy 34 + 2:number <- copy 33 3:boolean <- greater-than 1:number, 2:number ] +mem: storing 1 in location 3 :(scenario greater_than2) recipe main [ - 1:number <- copy 34:literal - 2:number <- copy 34:literal + 1:number <- copy 34 + 2:number <- copy 34 3:boolean <- greater-than 1:number, 2:number ] +mem: storing 0 in location 3 :(scenario greater_than_multiple) recipe main [ - 1:boolean <- greater-than 36:literal, 35:literal, 34:literal + 1:boolean <- greater-than 36, 35, 34 ] +mem: storing 1 in location 1 :(scenario greater_than_multiple2) recipe main [ - 1:boolean <- greater-than 36:literal, 35:literal, 35:literal + 1:boolean <- greater-than 36, 35, 35 ] +mem: storing 0 in location 1 @@ -150,24 +149,24 @@ LESSER_THAN, :(before "End Primitive Recipe Numbers") Recipe_ordinal["lesser-than"] = LESSER_THAN; :(before "End Primitive Recipe Implementations") -case LESSER_THAN: { - bool result = true; - if (SIZE(ingredients) <= 1) { +case LESSER_THAN: { + bool result = true; + if (SIZE(ingredients) <= 1) { raise << current_recipe_name() << ": 'lesser-than' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end(); break; } - for (long long int i = 0; i < SIZE(ingredients); ++i) { - if (!scalar(ingredients.at(i))) { + for (long long int i = 0; i < SIZE(ingredients); ++i) { + if (!scalar(ingredients.at(i))) { raise << current_recipe_name() << ": 'lesser-than' can only compare numbers; got " << current_instruction().ingredients.at(i).original_string << '\n' << end(); goto finish_lesser_than; } } - for (long long int i = /**/1; i < SIZE(ingredients); ++i) { - if (ingredients.at(i-1).at(0) >= ingredients.at(i).at(0)) { + for (long long int i = /**/1; i < SIZE(ingredients); ++i) { + if (ingredients.at(i-1).at(0) >= ingredients.at(i).at(0)) { result = false; } } - finish_lesser_than: + finish_lesser_than: products.resize(1); products.at(0).push_back(result); break; @@ -175,29 +174,29 @@ Recipe_ordinal["lesser-than"] = LESSER_T :(scenario lesser_than) recipe main [ - 1:number <- copy 32:literal - 2:number <- copy 33:literal + 1:number <- copy 32 + 2:number <- copy 33 3:boolean <- lesser-than 1:number, 2:number ] +mem: storing 1 in location 3 :(scenario lesser_than2) recipe main [ - 1:number <- copy 34:literal - 2:number <- copy 33:literal + 1:number <- copy 34 + 2:number <- copy 33 3:boolean <- lesser-than 1:number, 2:number ] +mem: storing 0 in location 3 :(scenario lesser_than_multiple) recipe main [ - 1:boolean <- lesser-than 34:literal, 35:literal, 36:literal + 1:boolean <- lesser-than 34, 35, 36 ] +mem: storing 1 in location 1 :(scenario lesser_than_multiple2) recipe main [ - 1:boolean <- lesser-than 34:literal, 35:literal, 35:literal + 1:boolean <- lesser-than 34, 35, 35 ] +mem: storing 0 in location 1 @@ -206,24 +205,24 @@ GREATER_OR_EQUAL, :(before "End Primitive Recipe Numbers") Recipe_ordinal["greater-or-equal"] = GREATER_OR_EQUAL; :(before "End Primitive Recipe Implementations") -case GREATER_OR_EQUAL: { - bool result = true; - if (SIZE(ingredients) <= 1) { +case GREATER_OR_EQUAL: { + bool result = true; + if (SIZE(ingredients) <= 1) { raise << current_recipe_name() << ": 'greater-or-equal' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end(); break; } - for (long long int i = 0; i < SIZE(ingredients); ++i) { - if (!scalar(ingredients.at(i))) { + for (long long int i = 0; i < SIZE(ingredients); ++i) { + if (!scalar(ingredients.at(i))) { raise << current_recipe_name() << ": 'greater-or-equal' can only compare numbers; got " << current_instruction().ingredients.at(i).original_string << '\n' << end(); goto finish_greater_or_equal; } } - for (long long int i = /**/1; i < SIZE(ingredients); ++i) { - if (ingredients.at(i-1).at(0) < ingredients.at(i).at(0)) { + for (long long int i = /**/1; i < SIZE(ingredients); ++i) { + if (ingredients.at(i-1).at(0) < ingredients.at(i).at(0)) { result = false; } } - finish_greater_or_equal: + finish_greater_or_equal: products.resize(1); products.at(0).push_back(result); break; @@ -231,37 +230,37 @@ Recipe_ordinal["greater-or-equal"] = GRE :(scenario greater_or_equal) recipe main [ - 1:number <- copy 34:literal - 2:number <- copy 33:literal - 3:boolean <- greater-or-equal 1:number, 2:number + 1:number <- copy 34 + 2:number <- copy 33 + 3:boolean <- greater-or-equal 1:number, 2:number ] +mem: storing 1 in location 3 :(scenario greater_or_equal2) recipe main [ - 1:number <- copy 34:literal - 2:number <- copy 34:literal - 3:boolean <- greater-or-equal 1:number, 2:number + 1:number <- copy 34 + 2:number <- copy 34 + 3:boolean <- greater-or-equal 1:number, 2:number ] +mem: storing 1 in location 3 :(scenario greater_or_equal3) recipe main [ - 1:number <- copy 34:literal - 2:number <- copy 35:literal - 3:boolean <- greater-or-equal 1:number, 2:number + 1:number <- copy 34 + 2:number <- copy 35 + 3:boolean <- greater-or-equal 1:number, 2:number ] +mem: storing 0 in location 3 :(scenario greater_or_equal_multiple) recipe main [ - 1:boolean <- greater-or-equal 36:literal, 35:literal, 35:literal + 1:boolean <- greater-or-equal 36, 35, 35 ] +mem: storing 1 in location 1 :(scenario greater_or_equal_multiple2) recipe main [ - 1:boolean <- greater-or-equal 36:literal, 35:literal, 36:literal + 1:boolean <- greater-or-equal 36, 35, 36 ] +mem: storing 0 in location 1 @@ -270,24 +269,24 @@ LESSER_OR_EQUAL, :(before "End Primitive Recipe Numbers") Recipe_ordinal["lesser-or-equal"] = LESSER_OR_EQUAL; :(before "End Primitive Recipe Implementations") -case LESSER_OR_EQUAL: { - bool result = true; - if (SIZE(ingredients) <= 1) { +case LESSER_OR_EQUAL: { + bool result = true; + if (SIZE(ingredients) <= 1) { raise << current_recipe_name() << ": 'lesser-or-equal' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end(); break; } - for (long long int i = 0; i < SIZE(ingredients); ++i) { - if (!scalar(ingredients.at(i))) { + for (long long int i = 0; i < SIZE(ingredients); ++i) { + if (!scalar(ingredients.at(i))) { raise << current_recipe_name() << ": 'lesser-or-equal' can only compare numbers; got " << current_instruction().ingredients.at(i).original_string << '\n' << end(); goto finish_lesser_or_equal; } } - for (long long int i = /**/1; i < SIZE(ingredients); ++i) { - if (ingredients.at(i-1).at(0) > ingredients.at(i).at(0)) { + for (long long int i = /**/1; i < SIZE(ingredients); ++i) { + if (ingredients.at(i-1).at(0) > ingredients.at(i).at(0)) { result = false; } } - finish_lesser_or_equal: + finish_lesser_or_equal: products.resize(1); products.at(0).push_back(result); break; @@ -295,37 +294,37 @@ Recipe_ordinal["lesser-or-equal"] = LESS :(scenario lesser_or_equal) recipe main [ - 1:number <- copy 32:literal - 2:number <- copy 33:literal - 3:boolean <- lesser-or-equal 1:number, 2:number + 1:number <- copy 32 + 2:number <- copy 33 + 3:boolean <- lesser-or-equal 1:number, 2:number ] +mem: storing 1 in location 3 :(scenario lesser_or_equal2) recipe main [ - 1:number <- copy 33:literal - 2:number <- copy 33:literal - 3:boolean <- lesser-or-equal 1:number, 2:number + 1:number <- copy 33 + 2:number <- copy 33 + 3:boolean <- lesser-or-equal 1:number, 2:number ] +mem: storing 1 in location 3 :(scenario lesser_or_equal3) recipe main [ - 1:number <- copy 34:literal - 2:number <- copy 33:literal - 3:boolean <- lesser-or-equal 1:number, 2:number + 1:number <- copy 34 + 2:number <- copy 33 + 3:boolean <- lesser-or-equal 1:number, 2:number ] +mem: storing 0 in location 3 :(scenario lesser_or_equal_multiple) recipe main [ - 1:boolean <- lesser-or-equal 34:literal, 35:literal, 35:literal + 1:boolean <- lesser-or-equal 34, 35, 35 ] +mem: storing 1 in location 1 :(scenario lesser_or_equal_multiple2) recipe main [ - 1:boolean <- lesser-or-equal 34:literal, 35:literal, 34:literal + 1:boolean <- lesser-or-equal 34, 35, 34 ] +mem: storing 0 in location 1 diff --git a/html/027trace.cc.html b/html/027trace.cc.html deleted file mode 100644 index 1be9cffe..00000000 --- a/html/027trace.cc.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - -Mu - 027trace.cc - - - - - - - - - - -
-//: Allow mu programs to log facts just like we've been doing in C++ so far.
-
-:(scenario trace)
-recipe main [
-  trace [foo], [this is a trace in mu]
-]
-+foo: this is a trace in mu
-
-:(before "End Primitive Recipe Declarations")
-TRACE,
-:(before "End Primitive Recipe Numbers")
-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;
-  }
-  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;
-}
-
-:(before "End Primitive Recipe Declarations")
-HIDE_WARNINGS,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["hide-warnings"] = HIDE_WARNINGS;
-:(before "End Primitive Recipe Implementations")
-case HIDE_WARNINGS: {
-  Hide_warnings = true;
-  break;
-}
-
-:(before "End Primitive Recipe Declarations")
-SHOW_WARNINGS,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["show-warnings"] = SHOW_WARNINGS;
-:(before "End Primitive Recipe Implementations")
-case SHOW_WARNINGS: {
-  Hide_warnings = false;
-  break;
-}
-
-//: helpers for debugging
-
-:(before "End Primitive Recipe Declarations")
-_START_TRACING,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$start-tracing"] = _START_TRACING;
-:(before "End Primitive Recipe Implementations")
-case _START_TRACING: {
-  if (current_instruction().ingredients.empty())
-    Trace_stream->dump_layer = "all";
-  else
-    Trace_stream->dump_layer = current_instruction().ingredients.at(0).name;
-//?   cout << Trace_stream << ": " << Trace_stream->dump_layer << '\n'; //? 1
-  break;
-}
-
-:(before "End Primitive Recipe Declarations")
-_STOP_TRACING,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$stop-tracing"] = _STOP_TRACING;
-:(before "End Primitive Recipe Implementations")
-case _STOP_TRACING: {
-  Trace_stream->dump_layer = "";
-  break;
-}
-
-:(before "End Primitive Recipe Declarations")
-_CLOSE_TRACE,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$close-trace"] = _CLOSE_TRACE;
-:(before "End Primitive Recipe Implementations")
-case _CLOSE_TRACE: {
-  if (Trace_stream) {
-    delete Trace_stream;
-    Trace_stream = NULL;
-  }
-  break;
-}
-
- - - diff --git a/html/028assert.cc.html b/html/028assert.cc.html deleted file mode 100644 index 3adae63f..00000000 --- a/html/028assert.cc.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - -Mu - 028assert.cc - - - - - - - - - - -
-:(scenario assert)
-% 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]
-]
-+warn: this is an assert in mu
-
-:(before "End Primitive Recipe Declarations")
-ASSERT,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["assert"] = ASSERT;
-:(before "End Primitive Recipe Implementations")
-case ASSERT: {
-  if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'assert' takes exactly two ingredients rather than '" << current_instruction().to_string() << "'\n" << end();
-    break;
-  }
-  if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": 'assert' requires a boolean for its first ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
-    break;
-  }
-  if (!scalar(ingredients.at(1))) {
-    raise << current_recipe_name() << ": 'assert' requires a literal string for its second ingredient, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
-    break;
-  }
-  if (!ingredients.at(0).at(0)) {
-    raise << current_instruction().ingredients.at(1).name << '\n' << end();
-  }
-  break;
-}
-
- - - diff --git a/html/029debug.cc.html b/html/029debug.cc.html deleted file mode 100644 index 80f33d7d..00000000 --- a/html/029debug.cc.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - -Mu - 029debug.cc - - - - - - - - - - -
-:(before "End Primitive Recipe Declarations")
-_PRINT,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$print"] = _PRINT;
-:(before "End Primitive Recipe Implementations")
-case _PRINT: {
-  for (long long int i = 0; i < SIZE(ingredients); ++i) {
-    if (is_literal(current_instruction().ingredients.at(i))) {
-      trace(Primitive_recipe_depth, "run") << "$print: " << current_instruction().ingredients.at(i).name << end();
-      if (has_property(current_instruction().ingredients.at(i), "newline"))
-        cout << '\n';
-      else
-        cout << current_instruction().ingredients.at(i).name;
-    }
-    else {
-      for (long long int j = 0; j < SIZE(ingredients.at(i)); ++j) {
-        trace(Primitive_recipe_depth, "run") << "$print: " << ingredients.at(i).at(j) << end();
-        if (j > 0) cout << " ";
-        cout << ingredients.at(i).at(j);
-      }
-    }
-  }
-  break;
-}
-
-:(before "End Primitive Recipe Declarations")
-_EXIT,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$exit"] = _EXIT;
-:(before "End Primitive Recipe Implementations")
-case _EXIT: {
-  exit(0);
-  break;
-}
-
- - - diff --git a/html/029tools.cc.html b/html/029tools.cc.html new file mode 100644 index 00000000..58b813e1 --- /dev/null +++ b/html/029tools.cc.html @@ -0,0 +1,244 @@ + + + + +Mu - 029tools.cc + + + + + + + + + + +
+//: Allow mu programs to log facts just like we've been doing in C++ so far.
+
+:(scenario trace)
+recipe main [
+  trace [foo], [this is a trace in mu]
+]
++foo: this is a trace in mu
+
+:(before "End Primitive Recipe Declarations")
+TRACE,
+:(before "End Primitive Recipe Numbers")
+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;
+  }
+  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;
+}
+
+:(before "End Primitive Recipe Declarations")
+HIDE_WARNINGS,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["hide-warnings"] = HIDE_WARNINGS;
+:(before "End Primitive Recipe Implementations")
+case HIDE_WARNINGS: {
+  Hide_warnings = true;
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+SHOW_WARNINGS,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["show-warnings"] = SHOW_WARNINGS;
+:(before "End Primitive Recipe Implementations")
+case SHOW_WARNINGS: {
+  Hide_warnings = false;
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+_START_TRACING,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["$start-tracing"] = _START_TRACING;
+:(before "End Primitive Recipe Implementations")
+case _START_TRACING: {
+  if (current_instruction().ingredients.empty())
+    Trace_stream->dump_layer = "all";
+  else
+    Trace_stream->dump_layer = current_instruction().ingredients.at(0).name;
+//?   cout << Trace_stream << ": " << Trace_stream->dump_layer << '\n'; //? 1
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+_STOP_TRACING,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["$stop-tracing"] = _STOP_TRACING;
+:(before "End Primitive Recipe Implementations")
+case _STOP_TRACING: {
+  Trace_stream->dump_layer = "";
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+_CLOSE_TRACE,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["$close-trace"] = _CLOSE_TRACE;
+:(before "End Primitive Recipe Implementations")
+case _CLOSE_TRACE: {
+  if (Trace_stream) {
+    delete Trace_stream;
+    Trace_stream = NULL;
+  }
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+_DUMP_TRACE,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["$dump-trace"] = _DUMP_TRACE;
+:(before "End Primitive Recipe Implementations")
+case _DUMP_TRACE: {
+  if (ingredients.empty()) {
+    DUMP("");
+  }
+  else {
+    DUMP(current_instruction().ingredients.at(0).name);
+  }
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+_CLEAR_TRACE,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["$clear-trace"] = _CLEAR_TRACE;
+:(before "End Primitive Recipe Implementations")
+case _CLEAR_TRACE: {
+  CLEAR_TRACE;
+  break;
+}
+
+//: assert: perform sanity checks at runtime
+
+:(scenario assert)
+% 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, [this is an assert in mu]
+]
++warn: this is an assert in mu
+
+:(before "End Primitive Recipe Declarations")
+ASSERT,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["assert"] = ASSERT;
+:(before "End Primitive Recipe Implementations")
+case ASSERT: {
+  if (SIZE(ingredients) != 2) {
+    raise << current_recipe_name() << ": 'assert' takes exactly two ingredients rather than '" << current_instruction().to_string() << "'\n" << end();
+    break;
+  }
+  if (!scalar(ingredients.at(0))) {
+    raise << current_recipe_name() << ": 'assert' requires a boolean for its first ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    break;
+  }
+  if (!scalar(ingredients.at(1))) {
+    raise << current_recipe_name() << ": 'assert' requires a literal string for its second ingredient, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    break;
+  }
+  if (!ingredients.at(0).at(0)) {
+    raise << current_instruction().ingredients.at(1).name << '\n' << end();
+  }
+  break;
+}
+
+//:: 'cheating' by using the host system
+
+:(before "End Primitive Recipe Declarations")
+_PRINT,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["$print"] = _PRINT;
+:(before "End Primitive Recipe Implementations")
+case _PRINT: {
+  for (long long int i = 0; i < SIZE(ingredients); ++i) {
+    if (is_literal(current_instruction().ingredients.at(i))) {
+      trace(Primitive_recipe_depth, "run") << "$print: " << current_instruction().ingredients.at(i).name << end();
+      if (has_property(current_instruction().ingredients.at(i), "newline"))
+        cout << '\n';
+      else
+        cout << current_instruction().ingredients.at(i).name;
+    }
+    else {
+      for (long long int j = 0; j < SIZE(ingredients.at(i)); ++j) {
+        trace(Primitive_recipe_depth, "run") << "$print: " << ingredients.at(i).at(j) << end();
+        if (j > 0) cout << " ";
+        cout << ingredients.at(i).at(j);
+      }
+    }
+  }
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+_EXIT,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["$exit"] = _EXIT;
+:(before "End Primitive Recipe Implementations")
+case _EXIT: {
+  exit(0);
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+_SYSTEM,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["$system"] = _SYSTEM;
+:(before "End Primitive Recipe Implementations")
+case _SYSTEM: {
+  if (current_instruction().ingredients.empty()) {
+    raise << current_recipe_name() << ": '$system' requires exactly one ingredient, but got none\n" << end();
+    break;
+  }
+  products.resize(1);
+  int status = system(current_instruction().ingredients.at(0).name.c_str());
+  products.at(0).push_back(status);
+  break;
+}
+
+//:: helpers for debugging
+
+:(before "End Primitive Recipe Declarations")
+_DUMP_MEMORY,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["$dump-memory"] = _DUMP_MEMORY;
+:(before "End Primitive Recipe Implementations")
+case _DUMP_MEMORY: {
+  dump_memory();
+  break;
+}
+
+ + + diff --git a/html/030container.cc.html b/html/030container.cc.html index 74eab00b..5d939c14 100644 --- a/html/030container.cc.html +++ b/html/030container.cc.html @@ -13,17 +13,16 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } -.SalientComment { color: #00ffff; } .Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } +.SalientComment { color: #00ffff; } .traceAbsent { color: #c00000; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } +.CommentedCode { color: #6c6c6c; } --> @@ -56,8 +55,8 @@ Type[point].elements.
//: avoid warnings. :(scenario copy_multiple_locations) recipe main [ - 1:number <- copy 34:literal - 2:number <- copy 35:literal + 1:number <- copy 34 + 2:number <- copy 35 3:point <- copy 1:point/raw # unsafe ] +mem: storing 34 in location 3 @@ -79,9 +78,9 @@ Type[point_number].elements:(scenario copy_handles_nested_container_elements) recipe main [ - 12:number <- copy 34:literal - 13:number <- copy 35:literal - 14:number <- copy 36:literal + 12:number <- copy 34 + 13:number <- copy 35 + 14:number <- copy 36 15:point-number <- copy 12:point-number/raw # unsafe ] +mem: storing 36 in location 17 @@ -91,36 +90,36 @@ recipe main [ :(scenario compare_multiple_locations) recipe main [ - 1:number <- copy 34:literal # first - 2:number <- copy 35:literal - 3:number <- copy 36:literal - 4:number <- copy 34:literal # second - 5:number <- copy 35:literal - 6:number <- copy 36:literal + 1:number <- copy 34 # first + 2:number <- copy 35 + 3:number <- copy 36 + 4:number <- copy 34 # second + 5:number <- copy 35 + 6:number <- copy 36 7:boolean <- equal 1:point-number/raw, 4:point-number/raw # unsafe ] +mem: storing 1 in location 7 :(scenario compare_multiple_locations2) recipe main [ - 1:number <- copy 34:literal # first - 2:number <- copy 35:literal - 3:number <- copy 36:literal - 4:number <- copy 34:literal # second - 5:number <- copy 35:literal - 6:number <- copy 37:literal # different + 1:number <- copy 34 # first + 2:number <- copy 35 + 3:number <- copy 36 + 4:number <- copy 34 # second + 5:number <- copy 35 + 6:number <- copy 37 # different 7:boolean <- equal 1:point-number/raw, 4:point-number/raw # unsafe ] +mem: storing 0 in location 7 :(before "End size_of(types) Cases") type_info t = Type[types.at(0)]; -if (t.kind == container) { +if (t.kind == container) { // size of a container is the sum of the sizes of its elements - long long int result = 0; - for (long long int i = 0; i < SIZE(t.elements); ++i) { + long long int result = 0; + for (long long int i = 0; i < SIZE(t.elements); ++i) { // todo: strengthen assertion to disallow mutual type recursion - if (types.at(0) == t.elements.at(i).at(0)) { + if (types.at(0) == t.elements.at(i).at(0)) { raise << "container " << t.name << " can't include itself as a member\n" << end(); return 0; } @@ -132,8 +131,8 @@ type_info t = Type[types.at//:: To access elements of a container, use 'get' :(scenario get) recipe main [ - 12:number <- copy 34:literal - 13:number <- copy 35:literal + 12:number <- copy 34 + 13:number <- copy 35 15:number <- get 12:point/raw, 1:offset # unsafe ] +mem: storing 35 in location 15 @@ -143,30 +142,30 @@ GET, :(before "End Primitive Recipe Numbers") Recipe_ordinal["get"] = GET; :(before "End Primitive Recipe Implementations") -case GET: { - if (SIZE(ingredients) != 2) { +case GET: { + if (SIZE(ingredients) != 2) { raise << current_recipe_name() << ": 'get' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end(); break; } reagent base = current_instruction().ingredients.at(0); - long long int base_address = base.value; + long long int base_address = base.value; type_ordinal base_type = base.types.at(0); - if (Type[base_type].kind != container) { + if (Type[base_type].kind != container) { raise << current_recipe_name () << ": first ingredient of 'get' should be a container, but got " << base.original_string << '\n' << end(); break; } - if (!is_literal(current_instruction().ingredients.at(1))) { + if (!is_literal(current_instruction().ingredients.at(1))) { raise << current_recipe_name() << ": second ingredient of 'get' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); break; } assert(scalar(ingredients.at(1))); - long long int offset = ingredients.at(1).at(0); - long long int src = base_address; - for (long long int i = 0; i < offset; ++i) { + long long int offset = ingredients.at(1).at(0); + long long int src = base_address; + for (long long int i = 0; i < offset; ++i) { src += size_of(Type[base_type].elements.at(i)); } trace(Primitive_recipe_depth, "run") << "address to copy is " << src << end(); - if (offset < 0 || offset >= SIZE(Type[base_type].elements)) { + if (offset < 0 || offset >= SIZE(Type[base_type].elements)) { raise << current_recipe_name() << ": invalid offset " << offset << " for " << Type[base_type].name << '\n' << end(); products.resize(1); break; @@ -182,9 +181,9 @@ Recipe_ordinal["get"] = GET:(scenario get_handles_nested_container_elements) recipe main [ - 12:number <- copy 34:literal - 13:number <- copy 35:literal - 14:number <- copy 36:literal + 12:number <- copy 34 + 13:number <- copy 35 + 14:number <- copy 36 15:number <- get 12:point-number/raw, 1:offset # unsafe ] +mem: storing 36 in location 15 @@ -193,8 +192,8 @@ recipe main [ :(scenario get_address) recipe main [ - 12:number <- copy 34:literal - 13:number <- copy 35:literal + 12:number <- copy 34 + 13:number <- copy 35 15:address:number <- get-address 12:point/raw, 1:offset # unsafe ] +mem: storing 13 in location 15 @@ -202,9 +201,9 @@ recipe main [ :(scenario get_out_of_bounds) % Hide_warnings = true; recipe main [ - 12:number <- copy 34:literal - 13:number <- copy 35:literal - 14:number <- copy 36:literal + 12:number <- copy 34 + 13:number <- copy 35 + 14:number <- copy 36 get 12:point-number/raw, 2:offset # point-number occupies 3 locations but has only 2 fields; out of bounds ] +warn: main: invalid offset 2 for point-number @@ -212,9 +211,9 @@ recipe main [ :(scenario get_out_of_bounds2) % Hide_warnings = true; recipe main [ - 12:number <- copy 34:literal - 13:number <- copy 35:literal - 14:number <- copy 36:literal + 12:number <- copy 34 + 13:number <- copy 35 + 14:number <- copy 36 get 12:point-number/raw, -1:offset ] +warn: main: invalid offset -1 for point-number @@ -224,27 +223,27 @@ GET_ADDRESS, :(before "End Primitive Recipe Numbers") Recipe_ordinal["get-address"] = GET_ADDRESS; :(before "End Primitive Recipe Implementations") -case GET_ADDRESS: { +case GET_ADDRESS: { reagent base = current_instruction().ingredients.at(0); - long long int base_address = base.value; + long long int base_address = base.value; type_ordinal base_type = base.types.at(0); - if (Type[base_type].kind != container) { + if (Type[base_type].kind != container) { raise << current_recipe_name () << ": first ingredient of 'get-address' should be a container, but got " << base.original_string << '\n' << end(); break; } - if (!is_literal(current_instruction().ingredients.at(1))) { + if (!is_literal(current_instruction().ingredients.at(1))) { raise << current_recipe_name() << ": second ingredient of 'get-address' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); break; } assert(scalar(ingredients.at(1))); - long long int offset = ingredients.at(1).at(0); - if (offset < 0 || offset >= SIZE(Type[base_type].elements)) { + long long int offset = ingredients.at(1).at(0); + if (offset < 0 || offset >= SIZE(Type[base_type].elements)) { raise << "invalid offset " << offset << " for " << Type[base_type].name << '\n' << end(); products.resize(1); break; } - long long int result = base_address; - for (long long int i = 0; i < offset; ++i) { + long long int result = base_address; + for (long long int i = 0; i < offset; ++i) { result += size_of(Type[base_type].elements.at(i)); } trace(Primitive_recipe_depth, "run") << "address to copy is " << result << end(); @@ -256,9 +255,9 @@ Recipe_ordinal["get-address"] = GET_ADDR :(scenario get_address_out_of_bounds) % Hide_warnings = true; recipe main [ - 12:number <- copy 34:literal - 13:number <- copy 35:literal - 14:number <- copy 36:literal + 12:number <- copy 34 + 13:number <- copy 35 + 14:number <- copy 36 get-address 12:point-number/raw, 2:offset # point-number occupies 3 locations but has only 2 fields; out of bounds ] +warn: invalid offset 2 for point-number @@ -266,9 +265,9 @@ recipe main [ :(scenario get_address_out_of_bounds2) % Hide_warnings = true; recipe main [ - 12:number <- copy 34:literal - 13:number <- copy 35:literal - 14:number <- copy 36:literal + 12:number <- copy 34 + 13:number <- copy 35 + 14:number <- copy 36 get-address 12:point-number/raw, -1:offset ] +warn: invalid offset -1 for point-number @@ -278,8 +277,8 @@ recipe main [ :(scenarios load) :(scenario container) container foo [ - x:number - y:number + x:number + y:number ] +parse: reading container foo +parse: element name: x @@ -289,13 +288,13 @@ container foo [ :(scenario container_use_before_definition) container foo [ - x:number - y:bar + x:number + y:bar ] container bar [ - x:number - y:number + x:number + y:number ] +parse: reading container foo +parse: type number: 1000 @@ -307,19 +306,19 @@ container bar [ +parse: type number: 1001 :(before "End Command Handlers") -else if (command == "container") { +else if (command == "container") { insert_container(command, container, in); } :(code) -void insert_container(const string& command, kind_of_type kind, istream& in) { +void insert_container(const string& command, kind_of_type kind, istream& in) { skip_whitespace(in); string name = next_word(in); trace("parse") << "reading " << command << ' ' << name << end(); //? cout << name << '\n'; //? 2 //? if (Type_ordinal.find(name) != Type_ordinal.end()) //? 1 //? cerr << Type_ordinal[name] << '\n'; //? 1 - if (Type_ordinal.find(name) == Type_ordinal.end() + if (Type_ordinal.find(name) == Type_ordinal.end() || Type_ordinal[name] == 0) { Type_ordinal[name] = Next_type_ordinal++; } @@ -329,17 +328,17 @@ container bar [ recently_added_types.push_back(Type_ordinal[name]); t.name = name; t.kind = kind; - while (!in.eof()) { + while (!in.eof()) { skip_whitespace_and_comments(in); string element = next_word(in); - if (element == "]") break; + if (element == "]") break; istringstream inner(element); t.element_names.push_back(slurp_until(inner, ':')); trace("parse") << " element name: " << t.element_names.back() << end(); vector<type_ordinal> types; - while (!inner.eof()) { + while (!inner.eof()) { string type_name = slurp_until(inner, ':'); - if (Type_ordinal.find(type_name) == Type_ordinal.end()) { + if (Type_ordinal.find(type_name) == Type_ordinal.end()) { //? cerr << type_name << " is " << Next_type_ordinal << '\n'; //? 1 Type_ordinal[type_name] = Next_type_ordinal++; } @@ -358,7 +357,7 @@ vector<type_ordinal> recently_added_types; :(before "End load_permanently") //: for non-tests recently_added_types.clear(); :(before "End Setup") //: for tests -for (long long int i = 0; i < SIZE(recently_added_types); ++i) { +for (long long int i = 0; i < SIZE(recently_added_types); ++i) { //? cout << "erasing " << Type[recently_added_types.at(i)].name << '\n'; //? 1 Type_ordinal.erase(Type[recently_added_types.at(i)].name); Type.erase(recently_added_types.at(i)); @@ -367,14 +366,14 @@ recently_added_types.clear// delete recent type references // can't rely on recently_added_types to cleanup Type_ordinal, because of deliberately misbehaving tests with references to undefined types map<string, type_ordinal>::iterator p = Type_ordinal.begin(); -while(p != Type_ordinal.end()) { +while(p != Type_ordinal.end()) { // save current item string name = p->first; type_ordinal t = p->second; // increment iterator ++p; // now delete current item if necessary - if (t >= 1000) { + if (t >= 1000) { //? cerr << "AAA " << name << " " << t << '\n'; //? 1 Type_ordinal.erase(name); } @@ -396,18 +395,18 @@ Next_type_ordinal = 1000;< #? % Trace_stream->dump_layer = "run"; recipe main [ # integer is not a type - 1:integer <- copy 0:literal + 1:integer <- copy 0 ] +warn: unknown type: integer :(scenario run_allows_type_definition_after_use) % Hide_warnings = true; recipe main [ - 1:bar <- copy 0:literal + 1:bar <- copy 0 ] container bar [ - x:number + x:number ] -warn: unknown type: bar $warn: 0 @@ -416,22 +415,22 @@ $warn: 0 Transform.push_back(check_invalid_types); :(code) -void check_invalid_types(const recipe_ordinal r) { - for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) { - const instruction& inst = Recipe[r].steps.at(index); - for (long long int i = 0; i < SIZE(inst.ingredients); ++i) { +void check_invalid_types(const recipe_ordinal r) { + for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) { + const instruction& inst = Recipe[r].steps.at(index); + for (long long int i = 0; i < SIZE(inst.ingredients); ++i) { check_invalid_types(inst.ingredients.at(i)); } - for (long long int i = 0; i < SIZE(inst.products); ++i) { + for (long long int i = 0; i < SIZE(inst.products); ++i) { check_invalid_types(inst.products.at(i)); } } } -void check_invalid_types(const reagent& r) { - for (long long int i = 0; i < SIZE(r.types); ++i) { - if (r.types.at(i) == 0) continue; - if (Type.find(r.types.at(i)) == Type.end()) +void check_invalid_types(const reagent& r) { + for (long long int i = 0; i < SIZE(r.types); ++i) { + if (r.types.at(i) == 0) continue; + if (Type.find(r.types.at(i)) == Type.end()) raise << "unknown type: " << r.properties.at(0).second.at(i) << '\n' << end(); } } @@ -439,16 +438,16 @@ $warn: 0 :(scenario container_unknown_field) % Hide_warnings = true; container foo [ - x:number - y:bar + x:number + y:bar ] +warn: unknown type for field y in foo :(scenario read_container_with_bracket_in_comment) container foo [ - x:number + x:number # ']' in comment - y:number + y:number ] +parse: reading container foo +parse: element name: x @@ -460,14 +459,14 @@ container foo [ check_container_field_types(); :(code) -void check_container_field_types() { - for (map<type_ordinal, type_info>::iterator p = Type.begin(); p != Type.end(); ++p) { - const type_info& info = p->second; +void check_container_field_types() { + for (map<type_ordinal, type_info>::iterator p = Type.begin(); p != Type.end(); ++p) { + const type_info& info = p->second; //? cerr << "checking " << p->first << '\n'; //? 1 - for (long long int i = 0; i < SIZE(info.elements); ++i) { - for (long long int j = 0; j < SIZE(info.elements.at(i)); ++j) { - if (info.elements.at(i).at(j) == 0) continue; - if (Type.find(info.elements.at(i).at(j)) == Type.end()) + for (long long int i = 0; i < SIZE(info.elements); ++i) { + for (long long int j = 0; j < SIZE(info.elements.at(i)); ++j) { + if (info.elements.at(i).at(j) == 0) continue; + if (Type.find(info.elements.at(i).at(j)) == Type.end()) raise << "unknown type for field " << info.element_names.at(i) << " in " << info.name << '\n' << end(); } } @@ -481,22 +480,22 @@ MERGE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["merge"] = MERGE; :(before "End Primitive Recipe Implementations") -case MERGE: { +case MERGE: { products.resize(1); - for (long long int i = 0; i < SIZE(ingredients); ++i) - for (long long int j = 0; j < SIZE(ingredients.at(i)); ++j) + for (long long int i = 0; i < SIZE(ingredients); ++i) + for (long long int j = 0; j < SIZE(ingredients.at(i)); ++j) products.at(0).push_back(ingredients.at(i).at(j)); break; } :(scenario merge) container foo [ - x:number - y:number + x:number + y:number ] recipe main [ - 1:foo <- merge 3:literal, 4:literal + 1:foo <- merge 3, 4 ] +mem: storing 3 in location 1 +mem: storing 4 in location 2 @@ -504,9 +503,9 @@ recipe main [ //:: helpers :(code) -void skip_bracket(istream& in, string message) { +void skip_bracket(istream& in, string message) { skip_whitespace_and_comments(in); - if (in.get() != '[') + if (in.get() != '[') raise << message << '\n' << end(); } diff --git a/html/031address.cc.html b/html/031address.cc.html index 2f88d3e2..1709e1a1 100644 --- a/html/031address.cc.html +++ b/html/031address.cc.html @@ -13,16 +13,15 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } -.SalientComment { color: #00ffff; } .Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } +.SalientComment { color: #00ffff; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } +.CommentedCode { color: #6c6c6c; } --> @@ -35,14 +34,14 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 //: Instructions can read from addresses pointing at other locations using the
-//: 'deref' property.
+//: 'lookup' property.
 
 :(scenario copy_indirect)
 recipe main [
-  1:address:number <- copy 2:literal
-  2:number <- copy 34:literal
+  1:address:number <- copy 2
+  2:number <- copy 34
   # This loads location 1 as an address and looks up *that* location.
-  3:number <- copy 1:address:number/deref
+  3:number <- copy 1:address:number/lookup
 ]
 +mem: storing 34 in location 3
 
@@ -50,11 +49,11 @@ recipe main [
 x = canonize(x);
 
 //: similarly, write to addresses pointing at other locations using the
-//: 'deref' property
+//: 'lookup' property
 :(scenario store_indirect)
 recipe main [
-  1:address:number <- copy 2:literal
-  1:address:number/deref <- copy 34:literal
+  1:address:number <- copy 2
+  1:address:number/lookup <- copy 34
 ]
 +mem: storing 34 in location 2
 
@@ -63,26 +62,26 @@ x = canonize(x);
 
 :(code)
 reagent canonize(reagent x) {
-  if (is_literal(x)) return x;
+  if (is_literal(x)) return x;
 //?   cout << "canonize\n"; //? 1
   reagent r = x;
 //?   cout << x.to_string() << " => " << r.to_string() << '\n'; //? 1
-  while (has_property(r, "deref"))
-    r = deref(r);
+  while (has_property(r, "lookup"))
+    r = lookup_memory(r);
   return r;
 }
 
-reagent deref(reagent x) {
-//?   cout << "deref: " << x.to_string() << "\n"; //? 2
-  static const type_ordinal ADDRESS = Type_ordinal["address"];
+reagent lookup_memory(reagent x) {
+//?   cout << "lookup_memory: " << x.to_string() << "\n"; //? 2
+  static const type_ordinal ADDRESS = Type_ordinal["address"];
   reagent result;
-  if (x.types.at(0) != ADDRESS) {
-    raise << current_recipe_name() << ": tried to /deref " << x.original_string << " but it isn't an address\n" << end();
+  if (x.types.at(0) != ADDRESS) {
+    raise << current_recipe_name() << ": tried to /lookup " << x.original_string << " but it isn't an address\n" << end();
     return result;
   }
   // compute value
-  if (x.value == 0) {
-    raise << current_recipe_name() << ": tried to /deref 0\n" << end();
+  if (x.value == 0) {
+    raise << current_recipe_name() << ": tried to /lookup 0\n" << end();
     return result;
   }
   result.set_value(Memory[x.value]);
@@ -91,15 +90,15 @@ reagent deref(reagent x)<
   // populate types
   copy(++x.types.begin(), x.types.end(), inserter(result.types, result.types.begin()));
 
-  // drop-one 'deref'
-  long long int i = 0;
-  long long int len = SIZE(x.properties);
-  for (i = 0; i < len; ++i) {
-    if (x.properties.at(i).first == "deref") break;
+  // drop-one 'lookup'
+  long long int i = 0;
+  long long int len = SIZE(x.properties);
+  for (i = 0; i < len; ++i) {
+    if (x.properties.at(i).first == "lookup") break;
     result.properties.push_back(x.properties.at(i));
   }
-  ++i;  // skip first deref
-  for (; i < len; ++i) {
+  ++i;  // skip first lookup
+  for (; i < len; ++i) {
     result.properties.push_back(x.properties.at(i));
   }
   return result;
@@ -108,19 +107,19 @@ reagent deref(reagent x)<
 //:: 'get' can read from container address
 :(scenario get_indirect)
 recipe main [
-  1:number <- copy 2:literal
-  2:number <- copy 34:literal
-  3:number <- copy 35:literal
-  4:number <- get 1:address:point/deref, 0:offset
+  1:number <- copy 2
+  2:number <- copy 34
+  3:number <- copy 35
+  4:number <- get 1:address:point/lookup, 0:offset
 ]
 +mem: storing 34 in location 4
 
-:(scenario include_nonderef_properties)
+:(scenario include_nonlookup_properties)
 recipe main [
-  1:number <- copy 2:literal
-  2:number <- copy 34:literal
-  3:number <- copy 35:literal
-  4:number <- get 1:address:point/deref/foo, 0:offset
+  1:number <- copy 2
+  2:number <- copy 34
+  3:number <- copy 35
+  4:number <- get 1:address:point/lookup/foo, 0:offset
 ]
 +mem: storing 34 in location 4
 
@@ -130,78 +129,64 @@ base = canonize(base);:(scenario get_address_indirect)
 # 'get' can read from container address
 recipe main [
-  1:number <- copy 2:literal
-  2:number <- copy 34:literal
-  3:number <- copy 35:literal
-  4:number <- get-address 1:address:point/deref, 0:offset
+  1:number <- copy 2
+  2:number <- copy 34
+  3:number <- copy 35
+  4:number <- get-address 1:address:point/lookup, 0:offset
 ]
 +mem: storing 2 in location 4
 
 :(after "reagent base = " following "case GET_ADDRESS:")
 base = canonize(base);
 
-//:: Helpers for debugging
+//:: abbreviation for '/lookup': a prefix '*'
 
-:(before "End Primitive Recipe Declarations")
-_DUMP_TRACE,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$dump-trace"] = _DUMP_TRACE;
-:(before "End Primitive Recipe Implementations")
-case _DUMP_TRACE: {
-  if (ingredients.empty()) {
-    DUMP("");
-  }
-  else {
-    DUMP(current_instruction().ingredients.at(0).name);
-  }
-  break;
-}
+:(scenario lookup_abbreviation)
+recipe main [
+  1:address:number <- copy 2
+  2:number <- copy 34
+  3:number <- copy *1:address:number
+]
++mem: storing 34 in location 3
 
-:(before "End Primitive Recipe Declarations")
-_CLEAR_TRACE,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$clear-trace"] = _CLEAR_TRACE;
-:(before "End Primitive Recipe Implementations")
-case _CLEAR_TRACE: {
-  CLEAR_TRACE;
-  break;
+:(before "End Parsing reagent")
+{
+  while (!name.empty() && name.at(0) == '*') {
+    name.erase(0, 1);
+    properties.push_back(pair<string, vector<string> >("lookup", vector<string>()));
+  }
+  if (name.empty())
+    raise << "illegal name " << original_string << '\n' << end();
 }
 
-:(before "End Primitive Recipe Declarations")
-_DUMP_MEMORY,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$dump-memory"] = _DUMP_MEMORY;
-:(before "End Primitive Recipe Implementations")
-case _DUMP_MEMORY: {
-  dump_memory();
-  break;
-}
+//:: helpers for debugging
 
 :(before "End Primitive Recipe Declarations")
 _DUMP,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$dump"] = _DUMP;
 :(before "End Primitive Recipe Implementations")
-case _DUMP: {
+case _DUMP: {
   reagent after_canonize = canonize(current_instruction().ingredients.at(0));
   cerr << current_recipe_name() << ": " << current_instruction().ingredients.at(0).name << ' ' << current_instruction().ingredients.at(0).value << " => " << after_canonize.value << " => " << Memory[after_canonize.value] << '\n';
   break;
 }
 
 //: grab an address, and then dump its value at intervals
+//: useful for tracking down memory corruption (writing to an out-of-bounds address)
 :(before "End Globals")
-long long int foo = -1;
+long long int foo = -1;
 :(before "End Primitive Recipe Declarations")
 _FOO,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$foo"] = _FOO;
 :(before "End Primitive Recipe Implementations")
-case _FOO: {
-  if (current_instruction().ingredients.empty()) {
-    if (foo != -1) cerr << foo << ": " << Memory[foo] << '\n';
-    else cerr << '\n';
+case _FOO: {
+  if (current_instruction().ingredients.empty()) {
+    if (foo != -1) cerr << foo << ": " << Memory[foo] << '\n';
+    else cerr << '\n';
   }
-  else {
+  else {
     foo = canonize(current_instruction().ingredients.at(0)).value;
   }
   break;
diff --git a/html/032array.cc.html b/html/032array.cc.html
index b210893c..6086d339 100644
--- a/html/032array.cc.html
+++ b/html/032array.cc.html
@@ -13,15 +13,14 @@
 pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
 body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 1.05em; }
+.traceContains { color: #008000; }
 .cSpecial { color: #008000; }
-.SalientComment { color: #00ffff; }
 .Constant { color: #00a0a0; }
-.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
+.SalientComment { color: #00ffff; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #a04060; }
 .Special { color: #ff6060; }
 .Identifier { color: #804000; }
-.traceContains { color: #008000; }
 -->
 
 
@@ -47,10 +46,10 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 # Arrays can be copied around with a single instruction just like numbers,
 # no matter how large they are.
 recipe main [
-  1:number <- copy 3:literal  # length
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
+  1:number <- copy 3  # length
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
   5:array:number <- copy 1:array:number/raw  # unsafe
 ]
 +mem: storing 3 in location 5
@@ -60,12 +59,12 @@ recipe main [
 
 :(scenario copy_array_indirect)
 recipe main [
-  1:number <- copy 3:literal  # length
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
-  5:address:array:number <- copy 1:literal
-  6:array:number <- copy 5:address:array:number/deref
+  1:number <- copy 3  # length
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
+  5:address:array:number <- copy 1
+  6:array:number <- copy *5:address:array:number
 ]
 +mem: storing 3 in location 6
 +mem: storing 14 in location 7
@@ -73,11 +72,11 @@ recipe main [
 +mem: storing 16 in location 9
 
 //: disable the size mismatch check since the destination array need not be initialized
-:(after "bool size_mismatch(const reagent& x, const vector<double>& data)")
-if (x.types.at(0) == Type_ordinal["array"]) return false;
+:(before "End size_mismatch(x) Cases")
+if (x.types.at(0) == Type_ordinal["array"]) return false;
 :(before "End size_of(reagent) Cases")
-  if (r.types.at(0) == Type_ordinal["array"]) {
-    if (SIZE(r.types) == 1) {
+  if (r.types.at(0) == Type_ordinal["array"]) {
+    if (SIZE(r.types) == 1) {
       raise << current_recipe_name() << ": '" << r.original_string << "' is an array of what?\n" << end();
       return 1;
     }
@@ -89,21 +88,21 @@ recipe main [
 
 :(scenario index)
 recipe main [
-  1:number <- copy 3:literal  # length
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
-  5:number <- index 1:array:number/raw, 0:literal  # unsafe
+  1:number <- copy 3  # length
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
+  5:number <- index 1:array:number/raw, 0  # unsafe
 ]
 +mem: storing 14 in location 5
 
 :(scenario index_direct_offset)
 recipe main [
-  1:number <- copy 3:literal  # length
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
-  5:number <- copy 0:literal
+  1:number <- copy 3  # length
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
+  5:number <- copy 0
   6:number <- index 1:array:number/raw, 5:number  # unsafe
 ]
 +mem: storing 14 in location 6
@@ -113,26 +112,26 @@ INDEX,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["index"] = INDEX;
 :(before "End Primitive Recipe Implementations")
-case INDEX: {
-  if (SIZE(ingredients) != 2) {
+case INDEX: {
+  if (SIZE(ingredients) != 2) {
     raise << current_recipe_name() << ": 'index' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = canonize(current_instruction().ingredients.at(0));
-  long long int base_address = base.value;
-  if (base.types.at(0) != Type_ordinal["array"]) {
+  long long int base_address = base.value;
+  if (base.types.at(0) != Type_ordinal["array"]) {
     raise << current_recipe_name () << ": 'index' on a non-array " << base.original_string << '\n' << end();
     break;
   }
   reagent offset = canonize(current_instruction().ingredients.at(1));
-  vector<double> offset_val(read_memory(offset));
+  vector<double> offset_val(read_memory(offset));
   vector<type_ordinal> element_type = array_element(base.types);
-  if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
+  if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
     raise << current_recipe_name() << ": invalid index " << offset_val.at(0) << '\n' << end();
     products.resize(1);
     break;
   }
-  long long int src = base_address + 1 + offset_val.at(0)*size_of(element_type);
+  long long int src = base_address + 1 + offset_val.at(0)*size_of(element_type);
   trace(Primitive_recipe_depth, "run") << "address to copy is " << src << end();
   trace(Primitive_recipe_depth, "run") << "its type is " << Type[element_type.at(0)].name << end();
   reagent tmp;
@@ -143,48 +142,48 @@ Recipe_ordinal["index"] = INDEX}
 
 :(code)
-vector<type_ordinal> array_element(const vector<type_ordinal>& types) {
+vector<type_ordinal> array_element(const vector<type_ordinal>& types) {
   return vector<type_ordinal>(++types.begin(), types.end());
 }
 
 :(scenario index_indirect)
 recipe main [
-  1:number <- copy 3:literal  # length
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
-  5:address:array:number <- copy 1:literal
-  6:number <- index 5:address:array:number/deref, 1:literal
+  1:number <- copy 3  # length
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
+  5:address:array:number <- copy 1
+  6:number <- index *5:address:array:number, 1
 ]
 +mem: storing 15 in location 6
 
 :(scenario index_out_of_bounds)
 % Hide_warnings = true;
 recipe main [
-  1:number <- copy 3:literal  # 3 points
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
-  5:number <- copy 14:literal
-  6:number <- copy 15:literal
-  7:number <- copy 16:literal
-  8:address:array:point <- copy 1:literal
-  index 8:address:array:point/deref, 4:literal  # less than size of array in locations, but larger than its length in elements
+  1:number <- copy 3  # 3 points
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
+  5:number <- copy 14
+  6:number <- copy 15
+  7:number <- copy 16
+  8:address:array:point <- copy 1
+  index *8:address:array:point, 4  # less than size of array in locations, but larger than its length in elements
 ]
 +warn: main: invalid index 4
 
 :(scenario index_out_of_bounds2)
 % Hide_warnings = true;
 recipe main [
-  1:number <- copy 3:literal  # 3 points
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
-  5:number <- copy 14:literal
-  6:number <- copy 15:literal
-  7:number <- copy 16:literal
-  8:address:array:point <- copy 1:literal
-  index 8:address:array:point/deref, -1:literal
+  1:number <- copy 3  # 3 points
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
+  5:number <- copy 14
+  6:number <- copy 15
+  7:number <- copy 16
+  8:address:array:point <- copy 1
+  index *8:address:array:point, -1
 ]
 +warn: main: invalid index -1
 
@@ -192,11 +191,11 @@ recipe main [
 
 :(scenario index_address)
 recipe main [
-  1:number <- copy 3:literal  # length
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
-  5:number <- index-address 1:array:number/raw, 0:literal  # unsafe
+  1:number <- copy 3  # length
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
+  5:number <- index-address 1:array:number/raw, 0  # unsafe
 ]
 +mem: storing 2 in location 5
 
@@ -205,26 +204,26 @@ INDEX_ADDRESS,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["index-address"] = INDEX_ADDRESS;
 :(before "End Primitive Recipe Implementations")
-case INDEX_ADDRESS: {
-  if (SIZE(ingredients) != 2) {
+case INDEX_ADDRESS: {
+  if (SIZE(ingredients) != 2) {
     raise << current_recipe_name() << ": 'index-address' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = canonize(current_instruction().ingredients.at(0));
-  long long int base_address = base.value;
-  if (base.types.at(0) != Type_ordinal["array"]) {
+  long long int base_address = base.value;
+  if (base.types.at(0) != Type_ordinal["array"]) {
     raise << current_recipe_name () << ": 'index-address' on a non-array " << base.original_string << '\n' << end();
     break;
   }
   reagent offset = canonize(current_instruction().ingredients.at(1));
-  vector<double> offset_val(read_memory(offset));
+  vector<double> offset_val(read_memory(offset));
   vector<type_ordinal> element_type = array_element(base.types);
-  if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
+  if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
     raise << current_recipe_name() << ": invalid index " << offset_val.at(0) << '\n' << end();
     products.resize(1);
     break;
   }
-  long long int result = base_address + 1 + offset_val.at(0)*size_of(element_type);
+  long long int result = base_address + 1 + offset_val.at(0)*size_of(element_type);
   products.resize(1);
   products.at(0).push_back(result);
   break;
@@ -233,30 +232,30 @@ Recipe_ordinal["index-address"] = INDEX_
 :(scenario index_address_out_of_bounds)
 % Hide_warnings = true;
 recipe main [
-  1:number <- copy 3:literal  # 3 points
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
-  5:number <- copy 14:literal
-  6:number <- copy 15:literal
-  7:number <- copy 16:literal
-  8:address:array:point <- copy 1:literal
-  index-address 8:address:array:point/deref, 4:literal  # less than size of array in locations, but larger than its length in elements
+  1:number <- copy 3  # 3 points
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
+  5:number <- copy 14
+  6:number <- copy 15
+  7:number <- copy 16
+  8:address:array:point <- copy 1
+  index-address *8:address:array:point, 4  # less than size of array in locations, but larger than its length in elements
 ]
 +warn: main: invalid index 4
 
 :(scenario index_address_out_of_bounds2)
 % Hide_warnings = true;
 recipe main [
-  1:number <- copy 3:literal  # 3 points
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
-  5:number <- copy 14:literal
-  6:number <- copy 15:literal
-  7:number <- copy 16:literal
-  8:address:array:point <- copy 1:literal
-  index-address 8:address:array:point/deref, -1:literal
+  1:number <- copy 3  # 3 points
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
+  5:number <- copy 14
+  6:number <- copy 15
+  7:number <- copy 16
+  8:address:array:point <- copy 1
+  index-address *8:address:array:point, -1
 ]
 +warn: main: invalid index -1
 
@@ -264,10 +263,10 @@ recipe main [
 
 :(scenario array_length)
 recipe main [
-  1:number <- copy 3:literal  # length
-  2:number <- copy 14:literal
-  3:number <- copy 15:literal
-  4:number <- copy 16:literal
+  1:number <- copy 3  # length
+  2:number <- copy 14
+  3:number <- copy 15
+  4:number <- copy 16
   5:number <- length 1:array:number/raw  # unsafe
 ]
 +mem: storing 3 in location 5
@@ -277,13 +276,13 @@ LENGTH,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["length"] = LENGTH;
 :(before "End Primitive Recipe Implementations")
-case LENGTH: {
-  if (SIZE(ingredients) != 1) {
+case LENGTH: {
+  if (SIZE(ingredients) != 1) {
     raise << current_recipe_name() << ": 'length' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent x = canonize(current_instruction().ingredients.at(0));
-  if (x.types.at(0) != Type_ordinal["array"]) {
+  if (x.types.at(0) != Type_ordinal["array"]) {
     raise << "tried to calculate length of non-array " << x.original_string << '\n' << end();
     break;
   }
diff --git a/html/033exclusive_container.cc.html b/html/033exclusive_container.cc.html
index 3ab9bc99..2aaf30fb 100644
--- a/html/033exclusive_container.cc.html
+++ b/html/033exclusive_container.cc.html
@@ -13,15 +13,14 @@
 pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
 body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 1.05em; }
+.traceContains { color: #008000; }
 .cSpecial { color: #008000; }
-.SalientComment { color: #00ffff; }
 .Constant { color: #00a0a0; }
-.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
+.SalientComment { color: #00ffff; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #a04060; }
 .Special { color: #ff6060; }
 .Identifier { color: #804000; }
-.traceContains { color: #008000; }
 -->
 
 
@@ -62,23 +61,23 @@ Type[tmp].element_names.<
 :(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/raw  # unsafe
+  1:number <- copy 1  # 'point' variant
+  2:number <- copy 34
+  3:number <- copy 35
+  4:number-or-point <- copy 1:number-or-point/raw  # unsafe
 ]
 +mem: storing 1 in location 4
 +mem: storing 34 in location 5
 +mem: storing 35 in location 6
 
 :(before "End size_of(types) Cases")
-if (t.kind == exclusive_container) {
+if (t.kind == exclusive_container) {
   // size of an exclusive container is the size of its largest variant
   // (So like containers, it can't contain arrays.)
-  long long int result = 0;
-  for (long long int i = 0; i < t.size; ++i) {
-    long long int tmp = size_of(t.elements.at(i));
-    if (tmp > result) result = tmp;
+  long long int result = 0;
+  for (long long int i = 0; i < t.size; ++i) {
+    long long int tmp = size_of(t.elements.at(i));
+    if (tmp > result) result = tmp;
   }
   // ...+1 for its tag.
   return result+1;
@@ -96,19 +95,19 @@ Type_ordinal["variant"] = :(scenario maybe_convert)
 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/raw, 1:variant  # unsafe
+  12:number <- copy 1
+  13:number <- copy 35
+  14:number <- copy 36
+  20:address:point <- maybe-convert 12:number-or-point/raw, 1:variant  # unsafe
 ]
 +mem: storing 13 in location 20
 
 :(scenario maybe_convert_fail)
 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/raw, 0:variant  # unsafe
+  12:number <- copy 1
+  13:number <- copy 35
+  14:number <- copy 36
+  20:address:point <- maybe-convert 12:number-or-point/raw, 0:variant  # unsafe
 ]
 +mem: storing 0 in location 20
 
@@ -117,28 +116,28 @@ MAYBE_CONVERT,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["maybe-convert"] = MAYBE_CONVERT;
 :(before "End Primitive Recipe Implementations")
-case MAYBE_CONVERT: {
-  if (SIZE(ingredients) != 2) {
+case MAYBE_CONVERT: {
+  if (SIZE(ingredients) != 2) {
     raise << current_recipe_name() << ": 'maybe-convert' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = canonize(current_instruction().ingredients.at(0));
-  long long int base_address = base.value;
+  long long int base_address = base.value;
   type_ordinal base_type = base.types.at(0);
-  if (Type[base_type].kind != exclusive_container) {
+  if (Type[base_type].kind != exclusive_container) {
     raise << current_recipe_name () << ": first ingredient of 'maybe-convert' should be an exclusive-container, but got " << base.original_string << '\n' << end();
     break;
   }
-  if (!is_literal(current_instruction().ingredients.at(1))) {
+  if (!is_literal(current_instruction().ingredients.at(1))) {
     raise << current_recipe_name() << ": second ingredient of 'maybe-convert' should have type 'variant', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
-  long long int tag = current_instruction().ingredients.at(1).value;
-  long long int result;
-  if (tag == static_cast<long long int>(Memory[base_address])) {
+  long long int tag = current_instruction().ingredients.at(1).value;
+  long long int result;
+  if (tag == static_cast<long long int>(Memory[base_address])) {
     result = base_address+1;
   }
-  else {
+  else {
     result = 0;
   }
   products.resize(1);
@@ -150,8 +149,8 @@ Recipe_ordinal["maybe-convert"] = MAYBE_
 
 :(scenario exclusive_container)
 exclusive-container foo [
-  x:number
-  y:number
+  x:number
+  y:number
 ]
 +parse: reading exclusive-container foo
 +parse:   element name: x
@@ -160,21 +159,21 @@ exclusive-container foo [
 +parse:   type: 1
 
 :(before "End Command Handlers")
-else if (command == "exclusive-container") {
+else if (command == "exclusive-container") {
   insert_container(command, exclusive_container, in);
 }
 
 //:: To construct exclusive containers out of variant types, use 'merge'.
 :(scenario lift_to_exclusive_container)
 exclusive-container foo [
-  x:number
-  y:number
+  x:number
+  y:number
 ]
 
 recipe main [
-  1:number <- copy 34:literal
-  2:foo <- merge 0:literal/x, 1:number
-  4:foo <- merge 1:literal/x, 1:number
+  1:number <- copy 34
+  2:foo <- merge 0/x, 1:number
+  4:foo <- merge 1/x, 1:number
 ]
 +mem: storing 0 in location 2
 +mem: storing 34 in location 3
diff --git a/html/034call.cc.html b/html/034call.cc.html
index 9b978a5d..5e9d93b0 100644
--- a/html/034call.cc.html
+++ b/html/034call.cc.html
@@ -13,17 +13,16 @@
 pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
 body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 1.05em; }
+.traceContains { color: #008000; }
 .cSpecial { color: #008000; }
-.SalientComment { color: #00ffff; }
 .Constant { color: #00a0a0; }
-.CommentedCode { color: #6c6c6c; }
-.PreProc { color: #c000c0; }
-.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
+.SalientComment { color: #00ffff; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #a04060; }
 .Special { color: #ff6060; }
 .Identifier { color: #804000; }
-.traceContains { color: #008000; }
+.PreProc { color: #c000c0; }
+.CommentedCode { color: #6c6c6c; }
 -->
 
 
@@ -42,37 +41,37 @@ recipe main [
   f
 ]
 recipe f [
-  3:number <- add 2:literal, 2:literal
+  3:number <- add 2, 2
 ]
 +mem: storing 4 in location 3
 
 :(scenario return_on_fallthrough)
 recipe main [
   f
-  1:number <- copy 0:literal
-  2:number <- copy 0:literal
-  3:number <- copy 0:literal
+  1:number <- copy 0
+  2:number <- copy 0
+  3:number <- copy 0
 ]
 recipe f [
-  4:number <- copy 0:literal
-  5:number <- copy 0:literal
+  4:number <- copy 0
+  5:number <- copy 0
 ]
 +run: f
 # running f
-+run: 4:number <- copy 0:literal
-+run: 5:number <- copy 0:literal
++run: 4:number <- copy 0
++run: 5:number <- copy 0
 # back out to main
-+run: 1:number <- copy 0:literal
-+run: 2:number <- copy 0:literal
-+run: 3:number <- copy 0:literal
++run: 1:number <- copy 0
++run: 2:number <- copy 0
++run: 3:number <- copy 0
 
 :(before "struct routine {")
 // Everytime a recipe runs another, we interrupt it and start running the new
 // recipe. When that finishes, we continue this one where we left off.
 // This requires maintaining a 'stack' of interrupted recipes or 'calls'.
-struct call {
+struct call {
   recipe_ordinal running_recipe;
-  long long int running_step_index;
+  long long int running_step_index;
   // End call Fields
   call(recipe_ordinal r) {
     running_recipe = r;
@@ -80,15 +79,15 @@ recipe f [
     // End call Constructor
   }
 };
-typedef list<call> call_stack;
+typedef list<call> call_stack;
 
 :(replace{} "struct routine")
-struct routine {
+struct routine {
   call_stack calls;
   // End routine Fields
   routine(recipe_ordinal r);
-  bool completed() const;
-  const vector<instruction>& steps() const;
+  bool completed() const;
+  const vector<instruction>& steps() const;
 };
 :(code)
 routine::routine(recipe_ordinal r) {
@@ -99,30 +98,30 @@ routine::routine(recipe_ordinal r//:: now update routine's helpers
 
 :(replace{} "inline long long int& current_step_index()")
-inline long long int& current_step_index() {
+inline long long int& current_step_index() {
   assert(!Current_routine->calls.empty());
   return Current_routine->calls.front().running_step_index;
 }
 :(replace{} "inline const string& current_recipe_name()")
-inline const string& current_recipe_name() {
+inline const string& current_recipe_name() {
   assert(!Current_routine->calls.empty());
   return Recipe[Current_routine->calls.front().running_recipe].name;
 }
 :(replace{} "inline const instruction& current_instruction()")
-inline const instruction& current_instruction() {
+inline const instruction& current_instruction() {
   assert(!Current_routine->calls.empty());
   return Recipe[Current_routine->calls.front().running_recipe].steps.at(Current_routine->calls.front().running_step_index);
 }
 
 :(replace{} "default:" following "End Primitive Recipe Implementations")
-default: {
+default: {
   // not a primitive; try to look up the book of recipes
-  if (Recipe.find(current_instruction().operation) == Recipe.end()) {
+  if (Recipe.find(current_instruction().operation) == Recipe.end()) {
     raise << "undefined operation " << current_instruction().operation << ": " << current_instruction().to_string() << '\n' << end();
     break;
   }
   Current_routine->calls.push_front(call(current_instruction().operation));
-  call_housekeeping:
+  call_housekeeping:
   ++Callstack_depth;
   assert(Callstack_depth < 9000);  // 9998-101 plus cushion
   continue;  // not done with caller; don't increment current_step_index()
@@ -131,11 +130,11 @@ routine::routine(recipe_ordinal r//:: finally, we need to fix the termination conditions for the run loop
 
 :(replace{} "inline bool routine::completed() const")
-inline bool routine::completed() const {
+inline bool routine::completed() const {
   return calls.empty();
 }
 
-inline const vector<instruction>& routine::steps() const {
+inline const vector<instruction>& routine::steps() const {
   assert(!calls.empty());
   return Recipe[calls.front().running_recipe].steps;
 }
@@ -143,12 +142,12 @@ routine::routine(recipe_ordinal r:(before "Running One Instruction")
 // when we reach the end of one call, we may reach the end of the one below
 // it, and the one below that, and so on
-while (current_step_index() >= SIZE(Current_routine->steps())) {
+while (current_step_index() >= SIZE(Current_routine->steps())) {
   // Falling Through End Of Recipe
   --Callstack_depth;
 //?   cerr << "reply " << SIZE(Current_routine->calls) << '\n'; //? 2
   Current_routine->calls.pop_front();
-  if (Current_routine->calls.empty()) return;
+  if (Current_routine->calls.empty()) return;
   // Complete Call Fallthrough
   // todo: no products returned warning
   ++current_step_index();
@@ -156,7 +155,7 @@ routine::routine(recipe_ordinal r:(before "End Includes")
 #include <stack>
-using std::stack;
+using std::stack;
 
diff --git a/html/035call_ingredient.cc.html b/html/035call_ingredient.cc.html index 357f1178..14c718a6 100644 --- a/html/035call_ingredient.cc.html +++ b/html/035call_ingredient.cc.html @@ -13,14 +13,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -37,11 +36,11 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } :(scenario next_ingredient) recipe main [ - f 2:literal + f 2 ] recipe f [ 12:number <- next-ingredient - 13:number <- add 1:literal, 12:number + 13:number <- add 1, 12:number ] +mem: storing 3 in location 13 @@ -55,13 +54,13 @@ recipe f [ +mem: storing 0 in location 12 :(before "End call Fields") -vector<vector<double> > ingredient_atoms; -long long int next_ingredient_to_process; +vector<vector<double> > ingredient_atoms; +long long int next_ingredient_to_process; :(before "End call Constructor") next_ingredient_to_process = 0; :(after "call_housekeeping:") -for (long long int i = 0; i < SIZE(ingredients); ++i) { +for (long long int i = 0; i < SIZE(ingredients); ++i) { Current_routine->calls.front().ingredient_atoms.push_back(ingredients.at(i)); } @@ -70,20 +69,20 @@ NEXT_INGREDIENT, :(before "End Primitive Recipe Numbers") Recipe_ordinal["next-ingredient"] = NEXT_INGREDIENT; :(before "End Primitive Recipe Implementations") -case NEXT_INGREDIENT: { - if (!ingredients.empty()) { +case NEXT_INGREDIENT: { + if (!ingredients.empty()) { raise << current_recipe_name() << ": 'next-ingredient' didn't expect any ingredients in '" << current_instruction().to_string() << "'\n" << end(); break; } assert(!Current_routine->calls.empty()); - if (Current_routine->calls.front().next_ingredient_to_process < SIZE(Current_routine->calls.front().ingredient_atoms)) { + if (Current_routine->calls.front().next_ingredient_to_process < SIZE(Current_routine->calls.front().ingredient_atoms)) { products.push_back( Current_routine->calls.front().ingredient_atoms.at(Current_routine->calls.front().next_ingredient_to_process)); assert(SIZE(products) == 1); products.resize(2); // push a new vector products.at(1).push_back(1); ++Current_routine->calls.front().next_ingredient_to_process; } - else { + else { products.resize(2); products.at(0).push_back(0); // todo: will fail noisily if we try to read a compound value products.at(1).push_back(0); @@ -93,7 +92,7 @@ Recipe_ordinal["next-ingredient"] = NEXT :(scenario rewind_ingredients) recipe main [ - f 2:literal + f 2 ] recipe f [ 12:number <- next-ingredient # consume ingredient @@ -111,17 +110,17 @@ REWIND_INGREDIENTS, :(before "End Primitive Recipe Numbers") Recipe_ordinal["rewind-ingredients"] = REWIND_INGREDIENTS; :(before "End Primitive Recipe Implementations") -case REWIND_INGREDIENTS: { +case REWIND_INGREDIENTS: { Current_routine->calls.front().next_ingredient_to_process = 0; break; } :(scenario ingredient) recipe main [ - f 1:literal, 2:literal + f 1, 2 ] recipe f [ - 12:number <- ingredient 1:literal # consume second ingredient first + 12:number <- ingredient 1 # consume second ingredient first 13:number, 1:boolean <- next-ingredient # next-ingredient tries to scan past that ] +mem: storing 2 in location 12 @@ -132,17 +131,17 @@ INGREDIENT, :(before "End Primitive Recipe Numbers") Recipe_ordinal["ingredient"] = INGREDIENT; :(before "End Primitive Recipe Implementations") -case INGREDIENT: { - if (SIZE(ingredients) != 1) { +case INGREDIENT: { + if (SIZE(ingredients) != 1) { raise << current_recipe_name() << ": 'ingredient' expects exactly one ingredient, but got '" << current_instruction().to_string() << "'\n" << end(); break; } - if (!is_literal(current_instruction().ingredients.at(0))) { + if (!is_literal(current_instruction().ingredients.at(0))) { raise << current_recipe_name() << ": 'ingredient' expects a literal ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } assert(scalar(ingredients.at(0))); - if (static_cast<long long int>(ingredients.at(0).at(0)) < SIZE(Current_routine->calls.front().ingredient_atoms)) { + if (static_cast<long long int>(ingredients.at(0).at(0)) < SIZE(Current_routine->calls.front().ingredient_atoms)) { Current_routine->calls.front().next_ingredient_to_process = ingredients.at(0).at(0); products.push_back( Current_routine->calls.front().ingredient_atoms.at(Current_routine->calls.front().next_ingredient_to_process)); @@ -150,8 +149,8 @@ Recipe_ordinal["ingredient"] = INGREDIEN products.at(1).push_back(1); ++Current_routine->calls.front().next_ingredient_to_process; } - else { - if (SIZE(current_instruction().products) > 1) { + else { + if (SIZE(current_instruction().products) > 1) { products.resize(2); products.at(0).push_back(0); // todo: will fail noisily if we try to read a compound value products.at(1).push_back(0); diff --git a/html/036call_reply.cc.html b/html/036call_reply.cc.html index e5d028cc..b293886c 100644 --- a/html/036call_reply.cc.html +++ b/html/036call_reply.cc.html @@ -13,14 +13,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -36,11 +35,11 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } :(scenario reply) recipe main [ - 1:number, 2:number <- f 34:literal + 1:number, 2:number <- f 34 ] recipe f [ 12:number <- next-ingredient - 13:number <- add 1:literal, 12:number + 13:number <- add 1, 12:number reply 12:number, 13:number ] +mem: storing 34 in location 1 @@ -51,49 +50,49 @@ REPLY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["reply"] = REPLY; :(before "End Primitive Recipe Implementations") -case REPLY: { +case REPLY: { // Starting Reply - const instruction& reply_inst = current_instruction(); // save pointer into recipe before pop - const string& callee = current_recipe_name(); + const instruction& reply_inst = current_instruction(); // save pointer into recipe before pop + const string& callee = current_recipe_name(); --Callstack_depth; 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; - const instruction& caller_instruction = current_instruction(); + if (Current_routine->calls.empty()) goto stop_running_current_routine; + const instruction& caller_instruction = current_instruction(); // make reply products available to caller copy(ingredients.begin(), ingredients.end(), inserter(products, products.begin())); // check that any reply ingredients with /same-as-ingredient connect up // the corresponding ingredient and product in the caller. - if (SIZE(caller_instruction.products) > SIZE(ingredients)) + if (SIZE(caller_instruction.products) > SIZE(ingredients)) raise << "too few values replied from " << callee << '\n' << end(); - for (long long int i = 0; i < SIZE(caller_instruction.products); ++i) { + for (long long int i = 0; i < SIZE(caller_instruction.products); ++i) { trace(Primitive_recipe_depth, "run") << "result " << i << " is " << to_string(ingredients.at(i)) << end(); - if (has_property(reply_inst.ingredients.at(i), "same-as-ingredient")) { + if (has_property(reply_inst.ingredients.at(i), "same-as-ingredient")) { vector<string> tmp = property(reply_inst.ingredients.at(i), "same-as-ingredient"); - if (SIZE(tmp) != 1) { + if (SIZE(tmp) != 1) { raise << current_recipe_name() << ": 'same-as-ingredient' metadata should take exactly one value in " << reply_inst.to_string() << '\n' << end(); goto finish_reply; } - long long int ingredient_index = to_integer(tmp.at(0)); - if (ingredient_index >= SIZE(caller_instruction.ingredients)) + long long int ingredient_index = to_integer(tmp.at(0)); + if (ingredient_index >= SIZE(caller_instruction.ingredients)) raise << current_recipe_name() << ": 'same-as-ingredient' metadata overflows ingredients in: " << caller_instruction.to_string() << '\n' << end(); - if (!is_dummy(caller_instruction.products.at(i)) && caller_instruction.products.at(i).value != caller_instruction.ingredients.at(ingredient_index).value) + if (!is_dummy(caller_instruction.products.at(i)) && caller_instruction.products.at(i).value != caller_instruction.ingredients.at(ingredient_index).value) raise << current_recipe_name() << ": 'same-as-ingredient' result " << caller_instruction.products.at(i).value << " from call to " << callee << " must be location " << caller_instruction.ingredients.at(ingredient_index).value << '\n' << end(); } } // End Reply - finish_reply: + finish_reply: break; // continue to process rest of *caller* instruction } //: Products can include containers and exclusive containers, addresses and arrays. :(scenario reply_container) recipe main [ - 3:point <- f 2:literal + 3:point <- f 2 ] recipe f [ 12:number <- next-ingredient - 13:number <- copy 35:literal + 13:number <- copy 35 reply 12:point/raw # unsafe ] +run: result 0 is [2, 35] @@ -108,7 +107,7 @@ recipe f [ :(scenario reply_same_as_ingredient) % Hide_warnings = true; recipe main [ - 1:number <- copy 0:literal + 1:number <- copy 0 2:number <- test1 1:number # call with different ingredient and product ] recipe test1 [ @@ -120,7 +119,7 @@ recipe test1 [ :(scenario reply_same_as_ingredient_dummy) % Hide_warnings = true; recipe main [ - 1:number <- copy 0:literal + 1:number <- copy 0 _ <- test1 1:number # call with different ingredient and product ] recipe test1 [ @@ -130,16 +129,16 @@ recipe test1 [ $warn: 0 :(code) -string to_string(const vector<double>& in) { - if (in.empty()) return "[]"; +string to_string(const vector<double>& in) { + if (in.empty()) return "[]"; ostringstream out; - if (SIZE(in) == 1) { + if (SIZE(in) == 1) { out << in.at(0); return out.str(); } out << "["; - for (long long int i = 0; i < SIZE(in); ++i) { - if (i > 0) out << ", "; + for (long long int i = 0; i < SIZE(in); ++i) { + if (i > 0) out << ", "; out << in.at(i); } out << "]"; @@ -153,8 +152,8 @@ recipe main [ 1:number <- test1 ] recipe test1 [ - reply-if 0:literal, 34:literal - reply 35:literal + reply-if 0, 34 + reply 35 ] +mem: storing 35 in location 1 @@ -163,8 +162,8 @@ recipe main [ 1:number <- test1 ] recipe test1 [ - reply-if 1:literal, 34:literal - reply 35:literal + reply-if 1, 34 + reply 35 ] +mem: storing 34 in location 1 @@ -174,8 +173,8 @@ recipe test1 [ // jump-unless a, 1:offset // reply b, c, ... // ``` -if (curr.name == "reply-if") { - if (curr.products.empty()) { +if (curr.name == "reply-if") { + if (curr.products.empty()) { curr.operation = Recipe_ordinal["jump-unless"]; curr.name = "jump-unless"; vector<reagent> results; @@ -188,7 +187,7 @@ recipe test1 [ curr.name = "reply"; curr.ingredients.swap(results); } - else { + else { raise << "'reply-if' never yields any products\n" << end(); } } @@ -197,8 +196,8 @@ recipe test1 [ // jump-if a, 1:offset // reply b, c, ... // ``` -if (curr.name == "reply-unless") { - if (curr.products.empty()) { +if (curr.name == "reply-unless") { + if (curr.products.empty()) { curr.operation = Recipe_ordinal["jump-if"]; curr.name = "jump-if"; vector<reagent> results; @@ -211,7 +210,7 @@ recipe test1 [ curr.name = "reply"; curr.ingredients.swap(results); } - else { + else { raise << "'reply-unless' never yields any products\n" << end(); } } diff --git a/html/037recipe.cc.html b/html/037recipe.cc.html index ce2f2798..e0d7a2c4 100644 --- a/html/037recipe.cc.html +++ b/html/037recipe.cc.html @@ -13,15 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } -.CommentedCode { color: #6c6c6c; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } +.CommentedCode { color: #6c6c6c; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -39,7 +38,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } :(scenario call_literal_recipe) recipe main [ - 1:number <- call f:recipe, 34:literal + 1:number <- call f:recipe, 34 ] recipe f [ 2:number <- next-ingredient @@ -50,7 +49,7 @@ recipe f [ :(scenario call_variable) recipe main [ 1:recipe-ordinal <- copy f:recipe - 2:number <- call 1:recipe-ordinal, 34:literal + 2:number <- call 1:recipe-ordinal, 34 ] recipe f [ 3:number <- next-ingredient @@ -67,7 +66,7 @@ type_ordinal recipe_ordinal = Type_ordinal["recipe-o Type[recipe_ordinal].name = "recipe-ordinal"; :(before "End Reagent-parsing Exceptions") -if (!r.properties.at(0).second.empty() && r.properties.at(0).second.at(0) == "recipe") { +if (!r.properties.at(0).second.empty() && r.properties.at(0).second.at(0) == "recipe") { r.set_value(Recipe_ordinal[r.name]); return; } @@ -77,13 +76,13 @@ CALL, :(before "End Primitive Recipe Numbers") Recipe_ordinal["call"] = CALL; :(before "End Primitive Recipe Implementations") -case CALL: { - if (ingredients.empty()) { +case CALL: { + if (ingredients.empty()) { raise << current_recipe_name() << ": 'call' requires at least one ingredient (the recipe to call)\n" << end(); break; } // Begin Call - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'call' should be a recipe, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } diff --git a/html/038scheduler.cc.html b/html/038scheduler.cc.html index 56f3c3c4..667ad6e4 100644 --- a/html/038scheduler.cc.html +++ b/html/038scheduler.cc.html @@ -13,17 +13,16 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } -.traceAbsent { color: #c00000; } -.SalientComment { color: #00ffff; } -.Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.traceAbsent { color: #c00000; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } +.CommentedCode { color: #6c6c6c; } --> @@ -43,11 +42,11 @@ recipe f1 [ start-running f2:recipe # wait for f2 to run { - jump-unless 1:number, -1:literal + jump-unless 1:number, -1 } ] recipe f2 [ - 1:number <- copy 1:literal + 1:number <- copy 1 ] +schedule: f1 +schedule: f2 @@ -55,45 +54,45 @@ recipe f2 [ //: first, add a deadline to run(routine) //: these changes are ugly and brittle; just close your nose and get through the next few lines :(replace "void run_current_routine()") -void run_current_routine(long long int time_slice) +void run_current_routine(long long int time_slice) :(replace "while (!Current_routine->completed())" following "void run_current_routine(long long int time_slice)") -long long int ninstrs = 0; -while (Current_routine->state == RUNNING && ninstrs < time_slice) +long long int ninstrs = 0; +while (Current_routine->state == RUNNING && ninstrs < time_slice) :(after "Running One Instruction") ninstrs++; //: now the rest of the scheduler is clean :(before "struct routine") -enum routine_state { +enum routine_state { RUNNING, COMPLETED, // End routine States }; :(before "End routine Fields") -enum routine_state state; +enum routine_state state; :(before "End routine Constructor") state = RUNNING; :(before "End Globals") vector<routine*> Routines; -long long int Current_routine_index = 0; -long long int Scheduling_interval = 500; +long long int Current_routine_index = 0; +long long int Scheduling_interval = 500; :(before "End Setup") Scheduling_interval = 500; Routines.clear(); :(replace{} "void run(recipe_ordinal r)") -void run(recipe_ordinal r) { - Routines.push_back(new routine(r)); +void run(recipe_ordinal r) { + Routines.push_back(new routine(r)); Current_routine_index = 0, Current_routine = Routines.at(0); - while (!all_routines_done()) { + while (!all_routines_done()) { skip_to_next_routine(); assert(Current_routine); assert(Current_routine->state == RUNNING); trace("schedule") << current_routine_label() << end(); run_current_routine(Scheduling_interval); // Scheduler State Transitions - if (Current_routine->completed()) + if (Current_routine->completed()) Current_routine->state = COMPLETED; // End Scheduler State Transitions @@ -103,9 +102,9 @@ Routines.clear(); } :(code) -bool all_routines_done() { - for (long long int i = 0; i < SIZE(Routines); ++i) { - if (Routines.at(i)->state == RUNNING) { +bool all_routines_done() { + for (long long int i = 0; i < SIZE(Routines); ++i) { + if (Routines.at(i)->state == RUNNING) { return false; } } @@ -113,11 +112,11 @@ Routines.clear(); } // skip Current_routine_index past non-RUNNING routines -void skip_to_next_routine() { +void skip_to_next_routine() { assert(!Routines.empty()); assert(Current_routine_index < SIZE(Routines)); - for (long long int i = (Current_routine_index+1)%SIZE(Routines); i != Current_routine_index; i = (i+1)%SIZE(Routines)) { - if (Routines.at(i)->state == RUNNING) { + for (long long int i = (Current_routine_index+1)%SIZE(Routines); i != Current_routine_index; i = (i+1)%SIZE(Routines)) { + if (Routines.at(i)->state == RUNNING) { Current_routine_index = i; Current_routine = Routines.at(i); return; @@ -128,16 +127,16 @@ Routines.clear(); string current_routine_label() { ostringstream result; call_stack calls = Current_routine->calls; - for (call_stack::iterator p = calls.begin(); p != calls.end(); ++p) { - if (p != calls.begin()) result << '/'; + for (call_stack::iterator p = calls.begin(); p != calls.end(); ++p) { + if (p != calls.begin()) result << '/'; result << Recipe[p->running_recipe].name; } return result.str(); } :(before "End Teardown") -for (long long int i = 0; i < SIZE(Routines); ++i) - delete Routines.at(i); +for (long long int i = 0; i < SIZE(Routines); ++i) + delete Routines.at(i); Routines.clear(); //:: To schedule new routines to run, call 'start-running'. @@ -145,9 +144,9 @@ Routines.clear(); //: 'start-running' will return a unique id for the routine that was created. //: routine id is a number, but don't do any arithmetic on it :(before "End routine Fields") -long long int id; +long long int id; :(before "End Globals") -long long int Next_routine_id = 1; +long long int Next_routine_id = 1; :(before "End Setup") Next_routine_id = 1; :(before "End routine Constructor") @@ -157,7 +156,7 @@ Next_routine_id++; //: routines save the routine that spawned them :(before "End routine Fields") // todo: really should be routine_id, but that's less efficient. -long long int parent_index; // only < 0 if there's no parent_index +long long int parent_index; // only < 0 if there's no parent_index :(before "End routine Constructor") parent_index = -1; @@ -166,11 +165,11 @@ START_RUNNING, :(before "End Primitive Recipe Numbers") Recipe_ordinal["start-running"] = START_RUNNING; :(before "End Primitive Recipe Implementations") -case START_RUNNING: { - routine* new_routine = new routine(ingredients.at(0).at(0)); +case START_RUNNING: { + routine* new_routine = new routine(ingredients.at(0).at(0)); new_routine->parent_index = Current_routine_index; // populate ingredients - for (long long int i = 1; i < SIZE(current_instruction().ingredients); ++i) + for (long long int i = 1; i < SIZE(current_instruction().ingredients); ++i) new_routine->calls.front().ingredient_atoms.push_back(ingredients.at(i)); Routines.push_back(new_routine); products.resize(1); @@ -181,47 +180,47 @@ Recipe_ordinal["start-running"] = START_ :(scenario scheduler_runs_single_routine) % Scheduling_interval = 1; recipe f1 [ - 1:number <- copy 0:literal - 2:number <- copy 0:literal + 1:number <- copy 0 + 2:number <- copy 0 ] +schedule: f1 -+run: 1:number <- copy 0:literal ++run: 1:number <- copy 0 +schedule: f1 -+run: 2:number <- copy 0:literal ++run: 2:number <- copy 0 :(scenario scheduler_interleaves_routines) % Scheduling_interval = 1; recipe f1 [ start-running f2:recipe - 1:number <- copy 0:literal - 2:number <- copy 0:literal + 1:number <- copy 0 + 2:number <- copy 0 ] recipe f2 [ - 3:number <- copy 0:literal - 4:number <- copy 0:literal + 3:number <- copy 0 + 4:number <- copy 0 ] +schedule: f1 +run: start-running f2:recipe +schedule: f2 -+run: 3:number <- copy 0:literal ++run: 3:number <- copy 0 +schedule: f1 -+run: 1:number <- copy 0:literal ++run: 1:number <- copy 0 +schedule: f2 -+run: 4:number <- copy 0:literal ++run: 4:number <- copy 0 +schedule: f1 -+run: 2:number <- copy 0:literal ++run: 2:number <- copy 0 :(scenario start_running_takes_args) recipe f1 [ - start-running f2:recipe, 3:literal + start-running f2:recipe, 3 # wait for f2 to run { - jump-unless 1:number, -1:literal + jump-unless 1:number, -1 } ] recipe f2 [ 1:number <- next-ingredient - 2:number <- add 1:number, 1:literal + 2:number <- add 1:number, 1 ] +mem: storing 4 in location 2 @@ -230,22 +229,22 @@ recipe f1 [ 1:number <- start-running f2:recipe ] recipe f2 [ - 12:number <- copy 44:literal + 12:number <- copy 44 ] +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) -% recipe_ordinal f1 = load("recipe f1 [\n1:number <- copy 0:literal\n]").front(); -% recipe_ordinal f2 = load("recipe f2 [\n2:number <- copy 0:literal\n]").front(); +% recipe_ordinal f1 = load("recipe f1 [\n1:number <- copy 0\n]").front(); +% recipe_ordinal f2 = load("recipe f2 [\n2:number <- copy 0\n]").front(); % Routines.push_back(new routine(f1)); // f1 meant to run % Routines.push_back(new routine(f2)); % Routines.back()->state = COMPLETED; // f2 not meant to run #? % Trace_stream->dump_layer = "all"; # must have at least one routine without escaping recipe f3 [ - 3:number <- copy 0:literal + 3:number <- copy 0 ] # by interleaving '+' lines with '-' lines, we allow f1 and f3 to run in any order +schedule: f1 @@ -259,8 +258,8 @@ recipe f3 [ % Routines.push_back(new routine(COPY)); % Routines.back()->state = COMPLETED; recipe f1 [ - 1:number <- copy 0:literal - 2:number <- copy 0:literal + 1:number <- copy 0 + 2:number <- copy 0 ] +schedule: f1 -run: idle @@ -273,23 +272,23 @@ recipe main [ # f1 never actually runs because its parent completes without waiting for it ] recipe f1 [ - 1:number <- copy 0:literal + 1:number <- copy 0 ] -schedule: f1 :(before "End Scheduler Cleanup") -for (long long int i = 0; i < SIZE(Routines); ++i) { - if (Routines.at(i)->state == COMPLETED) continue; - if (Routines.at(i)->parent_index < 0) continue; // root thread - if (has_completed_parent(i)) { +for (long long int i = 0; i < SIZE(Routines); ++i) { + if (Routines.at(i)->state == COMPLETED) continue; + if (Routines.at(i)->parent_index < 0) continue; // root thread + if (has_completed_parent(i)) { Routines.at(i)->state = COMPLETED; } } :(code) -bool has_completed_parent(long long int routine_index) { - for (long long int j = routine_index; j >= 0; j = Routines.at(j)->parent_index) { - if (Routines.at(j)->state == COMPLETED) +bool has_completed_parent(long long int routine_index) { + for (long long int j = routine_index; j >= 0; j = Routines.at(j)->parent_index) { + if (Routines.at(j)->state == COMPLETED) return true; } return false; @@ -301,12 +300,12 @@ recipe f1 [ % Scheduling_interval = 2; recipe f1 [ 1:number/child-id <- start-running f2:recipe - 12:number <- copy 0:literal # race condition since we don't care about location 12 + 12:number <- copy 0 # race condition since we don't care about location 12 # thanks to Scheduling_interval, f2's one instruction runs in between here and completes 2:number/state <- routine-state 1:number/child-id ] recipe f2 [ - 12:number <- copy 0:literal + 12:number <- copy 0 # trying to run a second instruction marks routine as completed ] # recipe f2 should be in state COMPLETED @@ -317,19 +316,19 @@ ROUTINE_STATE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["routine-state"] = ROUTINE_STATE; :(before "End Primitive Recipe Implementations") -case ROUTINE_STATE: { - if (SIZE(ingredients) != 1) { +case ROUTINE_STATE: { + if (SIZE(ingredients) != 1) { raise << current_recipe_name() << ": 'routine-state' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'routine-state' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } - long long int id = ingredients.at(0).at(0); - long long int result = -1; - for (long long int i = 0; i < SIZE(Routines); ++i) { - if (Routines.at(i)->id == id) { + long long int id = ingredients.at(0).at(0); + long long int result = -1; + for (long long int i = 0; i < SIZE(Routines); ++i) { + if (Routines.at(i)->id == id) { result = Routines.at(i)->state; break; } @@ -346,18 +345,18 @@ RESTART, :(before "End Primitive Recipe Numbers") Recipe_ordinal["restart"] = RESTART; :(before "End Primitive Recipe Implementations") -case RESTART: { - if (SIZE(ingredients) != 1) { +case RESTART: { + if (SIZE(ingredients) != 1) { raise << current_recipe_name() << ": 'restart' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'restart' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } - long long int id = ingredients.at(0).at(0); - for (long long int i = 0; i < SIZE(Routines); ++i) { - if (Routines.at(i)->id == id) { + long long int id = ingredients.at(0).at(0); + for (long long int i = 0; i < SIZE(Routines); ++i) { + if (Routines.at(i)->id == id) { Routines.at(i)->state = RUNNING; break; } @@ -370,18 +369,18 @@ STOP, :(before "End Primitive Recipe Numbers") Recipe_ordinal["stop"] = STOP; :(before "End Primitive Recipe Implementations") -case STOP: { - if (SIZE(ingredients) != 1) { +case STOP: { + if (SIZE(ingredients) != 1) { raise << current_recipe_name() << ": 'stop' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'stop' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } - long long int id = ingredients.at(0).at(0); - for (long long int i = 0; i < SIZE(Routines); ++i) { - if (Routines.at(i)->id == id) { + long long int id = ingredients.at(0).at(0); + for (long long int i = 0; i < SIZE(Routines); ++i) { + if (Routines.at(i)->id == id) { Routines.at(i)->state = COMPLETED; break; } @@ -394,8 +393,8 @@ _DUMP_ROUTINES, :(before "End Primitive Recipe Numbers") Recipe_ordinal["$dump-routines"] = _DUMP_ROUTINES; :(before "End Primitive Recipe Implementations") -case _DUMP_ROUTINES: { - for (long long int i = 0; i < SIZE(Routines); ++i) { +case _DUMP_ROUTINES: { + for (long long int i = 0; i < SIZE(Routines); ++i) { cerr << i << ": " << Routines.at(i)->id << ' ' << Routines.at(i)->state << ' ' << Routines.at(i)->parent_index << '\n'; } break; diff --git a/html/039wait.cc.html b/html/039wait.cc.html index 1e56cf9d..311f37ca 100644 --- a/html/039wait.cc.html +++ b/html/039wait.cc.html @@ -13,14 +13,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -39,14 +38,14 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } :(scenario wait_for_location) recipe f1 [ - 1:number <- copy 0:literal + 1:number <- copy 0 start-running f2:recipe - wait-for-location 1:number + wait-for-location 1:number # now wait for f2 to run and modify location 1 before using its value 2:number <- copy 1:number ] recipe f2 [ - 1:number <- copy 34:literal + 1:number <- copy 34 ] # if we got the synchronization wrong we'd be storing 0 in location 2 +mem: storing 34 in location 2 @@ -57,8 +56,8 @@ recipe f2 [ WAITING, :(before "End routine Fields") // only if state == WAITING -long long int waiting_on_location; -int old_value_of_waiting_location; +long long int waiting_on_location; +int old_value_of_waiting_location; :(before "End routine Constructor") waiting_on_location = old_value_of_waiting_location = 0; @@ -69,7 +68,7 @@ WAIT_FOR_LOCATION, :(before "End Primitive Recipe Numbers") Recipe_ordinal["wait-for-location"] = WAIT_FOR_LOCATION; :(before "End Primitive Recipe Implementations") -case WAIT_FOR_LOCATION: { +case WAIT_FOR_LOCATION: { reagent loc = canonize(current_instruction().ingredients.at(0)); Current_routine->state = WAITING; Current_routine->waiting_on_location = loc.value; @@ -81,9 +80,9 @@ Recipe_ordinal["wait-for-location"] = WA //: scheduler tweak to get routines out of that state :(before "End Scheduler State Transitions") -for (long long int i = 0; i < SIZE(Routines); ++i) { - if (Routines.at(i)->state != WAITING) continue; - if (Routines.at(i)->waiting_on_location && +for (long long int i = 0; i < SIZE(Routines); ++i) { + if (Routines.at(i)->state != WAITING) continue; + if (Routines.at(i)->waiting_on_location && Memory[Routines.at(i)->waiting_on_location] != Routines.at(i)->old_value_of_waiting_location) { trace("schedule") << "waking up routine\n" << end(); Routines.at(i)->state = RUNNING; @@ -95,14 +94,14 @@ Recipe_ordinal["wait-for-location"] = WA :(scenario wait_for_routine) recipe f1 [ - 1:number <- copy 0:literal + 1:number <- copy 0 12:number/routine <- start-running f2:recipe - wait-for-routine 12:number/routine + wait-for-routine 12:number/routine # now wait for f2 to run and modify location 1 before using its value 3:number <- copy 1:number ] recipe f2 [ - 1:number <- copy 34:literal + 1:number <- copy 34 ] +schedule: f1 +run: waiting for routine 2 @@ -114,7 +113,7 @@ recipe f2 [ :(before "End routine Fields") // only if state == WAITING -long long int waiting_on_routine; +long long int waiting_on_routine; :(before "End routine Constructor") waiting_on_routine = 0; @@ -123,16 +122,16 @@ WAIT_FOR_ROUTINE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["wait-for-routine"] = WAIT_FOR_ROUTINE; :(before "End Primitive Recipe Implementations") -case WAIT_FOR_ROUTINE: { - if (SIZE(ingredients) != 1) { +case WAIT_FOR_ROUTINE: { + if (SIZE(ingredients) != 1) { raise << current_recipe_name() << ": 'wait-for-routine' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } - if (ingredients.at(0).at(0) == Current_routine->id) { + if (ingredients.at(0).at(0) == Current_routine->id) { raise << current_recipe_name() << ": routine can't wait for itself! " << current_instruction().to_string() << '\n' << end(); break; } @@ -146,13 +145,13 @@ Recipe_ordinal["wait-for-routine"] = WAI // Wake up any routines waiting for other routines to go to sleep. // Important: this must come after the scheduler loop above giving routines // waiting for locations to change a chance to wake up. -for (long long int i = 0; i < SIZE(Routines); ++i) { - if (Routines.at(i)->state != WAITING) continue; - if (!Routines.at(i)->waiting_on_routine) continue; - long long int id = Routines.at(i)->waiting_on_routine; +for (long long int i = 0; i < SIZE(Routines); ++i) { + if (Routines.at(i)->state != WAITING) continue; + if (!Routines.at(i)->waiting_on_routine) continue; + long long int id = Routines.at(i)->waiting_on_routine; assert(id != Routines.at(i)->id); // routine can't wait on itself - for (long long int j = 0; j < SIZE(Routines); ++j) { - if (Routines.at(j)->id == id && Routines.at(j)->state != RUNNING) { + for (long long int j = 0; j < SIZE(Routines); ++j) { + if (Routines.at(j)->id == id && Routines.at(j)->state != RUNNING) { trace("schedule") << "waking up routine " << Routines.at(i)->id << end(); Routines.at(i)->state = RUNNING; Routines.at(i)->waiting_on_routine = 0; @@ -165,9 +164,9 @@ SWITCH, :(before "End Primitive Recipe Numbers") Recipe_ordinal["switch"] = SWITCH; :(before "End Primitive Recipe Implementations") -case SWITCH: { - long long int id = some_other_running_routine(); - if (id) { +case SWITCH: { + long long int id = some_other_running_routine(); + if (id) { assert(id != Current_routine->id); Current_routine->state = WAITING; Current_routine->waiting_on_routine = id; @@ -176,12 +175,12 @@ Recipe_ordinal["switch"] = SWITCH} :(code) -long long int some_other_running_routine() { - for (long long int i = 0; i < SIZE(Routines); ++i) { - if (i == Current_routine_index) continue; +long long int some_other_running_routine() { + for (long long int i = 0; i < SIZE(Routines); ++i) { + if (i == Current_routine_index) continue; assert(Routines.at(i) != Current_routine); assert(Routines.at(i)->id != Current_routine->id); - if (Routines.at(i)->state == RUNNING) + if (Routines.at(i)->state == RUNNING) return Routines.at(i)->id; } return 0; diff --git a/html/040brace.cc.html b/html/040brace.cc.html index a4313315..7d468a9d 100644 --- a/html/040brace.cc.html +++ b/html/040brace.cc.html @@ -13,15 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } +.CommentedCode { color: #6c6c6c; } --> @@ -59,7 +58,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } recipe main [ { break - 1:number <- copy 0:literal + 1:number <- copy 0 } ] +after-brace: recipe main @@ -71,37 +70,37 @@ recipe main [ Transform.push_back(transform_braces); :(code) -void transform_braces(const recipe_ordinal r) { +void transform_braces(const recipe_ordinal r) { //? cout << "AAA transform_braces\n"; //? 1 //? exit(0); //? 1 - const int OPEN = 0, CLOSE = 1; + const int OPEN = 0, CLOSE = 1; // use signed integer for step index because we'll be doing arithmetic on it - list<pair<int/*OPEN/CLOSE*/, /*step*/long long int> > braces; - for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) { - const instruction& inst = Recipe[r].steps.at(index); - if (inst.label == "{") { + list<pair<int/*OPEN/CLOSE*/, /*step*/long long int> > braces; + for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) { + const instruction& inst = Recipe[r].steps.at(index); + if (inst.label == "{") { trace("brace") << r << ": push (open, " << index << ")" << end(); - braces.push_back(pair<int,long long int>(OPEN, index)); + braces.push_back(pair<int,long long int>(OPEN, index)); } - if (inst.label == "}") { + if (inst.label == "}") { trace("brace") << "push (close, " << index << ")" << end(); - braces.push_back(pair<int,long long int>(CLOSE, index)); + braces.push_back(pair<int,long long int>(CLOSE, index)); } } - stack</*step*/long long int> open_braces; + stack</*step*/long long int> open_braces; trace("after-brace") << "recipe " << Recipe[r].name << end(); - for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) { + for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) { instruction& inst = Recipe[r].steps.at(index); - if (inst.label == "{") { + if (inst.label == "{") { open_braces.push(index); continue; } - if (inst.label == "}") { + if (inst.label == "}") { open_braces.pop(); continue; } - if (inst.is_label) continue; - if (inst.operation != Recipe_ordinal["loop"] + if (inst.is_label) continue; + if (inst.operation != Recipe_ordinal["loop"] && inst.operation != Recipe_ordinal["loop-if"] && inst.operation != Recipe_ordinal["loop-unless"] && inst.operation != Recipe_ordinal["break"] @@ -111,23 +110,23 @@ recipe main [ continue; } // update instruction operation - if (inst.name.find("-if") != string::npos) + if (inst.name.find("-if") != string::npos) inst.operation = Recipe_ordinal["jump-if"]; - else if (inst.name.find("-unless") != string::npos) + else if (inst.name.find("-unless") != string::npos) inst.operation = Recipe_ordinal["jump-unless"]; - else + else inst.operation = Recipe_ordinal["jump"]; // check for explicitly provided targets - if (inst.name.find("-if") != string::npos || inst.name.find("-unless") != string::npos) { + if (inst.name.find("-if") != string::npos || inst.name.find("-unless") != string::npos) { // conditional branches check arg 1 - if (SIZE(inst.ingredients) > 1 && is_literal(inst.ingredients.at(1))) { + if (SIZE(inst.ingredients) > 1 && is_literal(inst.ingredients.at(1))) { trace("after-brace") << "jump " << inst.ingredients.at(1).name << ":offset" << end(); continue; } } - else { + else { // unconditional branches check arg 0 - if (!inst.ingredients.empty() && is_literal(inst.ingredients.at(0))) { + if (!inst.ingredients.empty() && is_literal(inst.ingredients.at(0))) { trace("after-brace") << "jump " << inst.ingredients.at(0).name << ":offset" << end(); continue; } @@ -136,38 +135,38 @@ recipe main [ reagent target; target.types.push_back(Type_ordinal["offset"]); target.set_value(0); - if (open_braces.empty()) + if (open_braces.empty()) raise << inst.name << " needs a '{' before\n" << end(); - else if (inst.name.find("loop") != string::npos) + else if (inst.name.find("loop") != string::npos) target.set_value(open_braces.top()-index); - else // break instruction + else // break instruction target.set_value(matching_brace(open_braces.top(), braces, r) - index - 1); inst.ingredients.push_back(target); // log computed target - if (inst.name.find("-if") != string::npos) + if (inst.name.find("-if") != string::npos) trace("after-brace") << "jump-if " << inst.ingredients.at(0).name << ", " << target.value << ":offset" << end(); - else if (inst.name.find("-unless") != string::npos) + else if (inst.name.find("-unless") != string::npos) trace("after-brace") << "jump-unless " << inst.ingredients.at(0).name << ", " << target.value << ":offset" << end(); - else + else trace("after-brace") << "jump " << target.value << ":offset" << end(); } } // returns a signed integer not just so that we can return -1 but also to // enable future signed arithmetic -long long int matching_brace(long long int index, const list<pair<int, long long int> >& braces, recipe_ordinal r) { - int stacksize = 0; - for (list<pair<int, long long int> >::const_iterator p = braces.begin(); p != braces.end(); ++p) { - if (p->second < index) continue; +long long int matching_brace(long long int index, const list<pair<int, long long int> >& braces, recipe_ordinal r) { + int stacksize = 0; + for (list<pair<int, long long int> >::const_iterator p = braces.begin(); p != braces.end(); ++p) { + if (p->second < index) continue; stacksize += (p->first ? 1 : -1); - if (stacksize == 0) return p->second; + if (stacksize == 0) return p->second; } raise << Recipe[r].name << ": unbalanced '{'\n" << end(); return SIZE(Recipe[r].steps); // exit current routine } // temporarily suppress run -void transform(string form) { +void transform(string form) { load(form); transform_all(); } @@ -192,10 +191,10 @@ Recipe_ordinal["loop-unless"] = LOOP_UNL :(scenario loop) recipe main [ - 1:number <- copy 0:literal - 2:number <- copy 0:literal + 1:number <- copy 0 + 2:number <- copy 0 { - 3:number <- copy 0:literal + 3:number <- copy 0 loop } ] @@ -207,7 +206,7 @@ recipe main [ :(scenario break_empty_block) recipe main [ - 1:number <- copy 0:literal + 1:number <- copy 0 { break } @@ -218,7 +217,7 @@ recipe main [ :(scenario break_cascading) recipe main [ - 1:number <- copy 0:literal + 1:number <- copy 0 { break } @@ -233,11 +232,11 @@ recipe main [ :(scenario break_cascading2) recipe main [ - 1:number <- copy 0:literal - 2:number <- copy 0:literal + 1:number <- copy 0 + 2:number <- copy 0 { break - 3:number <- copy 0:literal + 3:number <- copy 0 } { break @@ -252,11 +251,11 @@ recipe main [ :(scenario break_if) recipe main [ - 1:number <- copy 0:literal - 2:number <- copy 0:literal + 1:number <- copy 0 + 2:number <- copy 0 { - break-if 2:number - 3:number <- copy 0:literal + break-if 2:number + 3:number <- copy 0 } { break @@ -271,36 +270,36 @@ recipe main [ :(scenario break_nested) recipe main [ - 1:number <- copy 0:literal + 1:number <- copy 0 { - 2:number <- copy 0:literal + 2:number <- copy 0 break { - 3:number <- copy 0:literal + 3:number <- copy 0 } - 4:number <- copy 0:literal + 4:number <- copy 0 } ] +after-brace: jump 4:offset :(scenario break_nested_degenerate) recipe main [ - 1:number <- copy 0:literal + 1:number <- copy 0 { - 2:number <- copy 0:literal + 2:number <- copy 0 break { } - 4:number <- copy 0:literal + 4:number <- copy 0 } ] +after-brace: jump 3:offset :(scenario break_nested_degenerate2) recipe main [ - 1:number <- copy 0:literal + 1:number <- copy 0 { - 2:number <- copy 0:literal + 2:number <- copy 0 break { } @@ -311,7 +310,7 @@ recipe main [ :(scenario break_label) % Hide_warnings = true; recipe main [ - 1:number <- copy 0:literal + 1:number <- copy 0 { break +foo:offset } @@ -320,11 +319,11 @@ recipe main [ :(scenario break_unless) recipe main [ - 1:number <- copy 0:literal - 2:number <- copy 0:literal + 1:number <- copy 0 + 2:number <- copy 0 { break-unless 2:number - 3:number <- copy 0:literal + 3:number <- copy 0 } ] +after-brace: recipe main @@ -335,11 +334,11 @@ recipe main [ :(scenario loop_unless) recipe main [ - 1:number <- copy 0:literal - 2:number <- copy 0:literal + 1:number <- copy 0 + 2:number <- copy 0 { loop-unless 2:number - 3:number <- copy 0:literal + 3:number <- copy 0 } ] +after-brace: recipe main @@ -350,14 +349,14 @@ recipe main [ :(scenario loop_nested) recipe main [ - 1:number <- copy 0:literal + 1:number <- copy 0 { - 2:number <- copy 0:literal + 2:number <- copy 0 { - 3:number <- copy 0:literal + 3:number <- copy 0 } - loop-if 4:boolean - 5:number <- copy 0:literal + loop-if 4:boolean + 5:number <- copy 0 } ] +after-brace: recipe main @@ -365,9 +364,9 @@ recipe main [ :(scenario loop_label) recipe main [ - 1:number <- copy 0:literal + 1:number <- copy 0 +foo - 2:number <- copy 0:literal + 2:number <- copy 0 ] +after-brace: recipe main +after-brace: copy ... @@ -378,14 +377,14 @@ recipe main [ :(scenario brace_conversion_and_run) #? % Trace_stream->dump_layer = "run"; recipe test-factorial [ - 1:number <- copy 5:literal - 2:number <- copy 1:literal + 1:number <- copy 5 + 2:number <- copy 1 { - 3:boolean <- equal 1:number, 1:literal - break-if 3:boolean + 3:boolean <- equal 1:number, 1 + break-if 3:boolean # $print 1:number 2:number <- multiply 2:number, 1:number - 1:number <- subtract 1:number, 1:literal + 1:number <- subtract 1:number, 1 loop } 4:number <- copy 2:number # trigger a read diff --git a/html/041jump_label.cc.html b/html/041jump_label.cc.html index 8cf9292a..05493404 100644 --- a/html/041jump_label.cc.html +++ b/html/041jump_label.cc.html @@ -14,15 +14,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background- body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .traceAbsent { color: #c00000; } -.Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } .cSpecial { color: #008000; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } +.Constant { color: #00a0a0; } +.traceContains { color: #008000; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } +.CommentedCode { color: #6c6c6c; } --> @@ -35,13 +34,15 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 //: Support jumps to labels.
-//: We'll also treat 'break' and 'continue' as jumps. The choice of name is
-//: just documentation about intent.
+//: We'll also treat 'break' and 'loop' as jumps. The choice of name is
+//: just documentation about intent; use 'break' to indicate you're exiting
+//: one or more loop nests, and 'loop' to indicate you're skipping to the next
+//: iteration of some containing loop nest.
 
 :(scenario jump_to_label)
 recipe main [
   jump +target:label
-  1:number <- copy 0:literal
+  1:number <- copy 0
   +target
 ]
 -mem: storing 0 in location 1
@@ -53,25 +54,25 @@ Type_ordinal["label"] = .push_back(transform_labels);
 
 :(code)
-void transform_labels(const recipe_ordinal r) {
-  map<string, long long int> offset;
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    const instruction& inst = Recipe[r].steps.at(i);
-    if (!inst.label.empty()) offset[inst.label] = i;
+void transform_labels(const recipe_ordinal r) {
+  map<string, long long int> offset;
+  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
+    const instruction& inst = Recipe[r].steps.at(i);
+    if (!inst.label.empty()) offset[inst.label] = i;
   }
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
+  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
     instruction& inst = Recipe[r].steps.at(i);
-    if (inst.operation == Recipe_ordinal["jump"]) {
+    if (inst.operation == Recipe_ordinal["jump"]) {
       replace_offset(inst.ingredients.at(0), offset, i, r);
     }
-    if (inst.operation == Recipe_ordinal["jump-if"] || inst.operation == Recipe_ordinal["jump-unless"]) {
+    if (inst.operation == Recipe_ordinal["jump-if"] || inst.operation == Recipe_ordinal["jump-unless"]) {
       replace_offset(inst.ingredients.at(1), offset, i, r);
     }
-    if ((inst.operation == Recipe_ordinal["loop"] || inst.operation == Recipe_ordinal["break"])
+    if ((inst.operation == Recipe_ordinal["loop"] || inst.operation == Recipe_ordinal["break"])
         && SIZE(inst.ingredients) == 1) {
       replace_offset(inst.ingredients.at(0), offset, i, r);
     }
-    if ((inst.operation == Recipe_ordinal["loop-if"] || inst.operation == Recipe_ordinal["loop-unless"]
+    if ((inst.operation == Recipe_ordinal["loop-if"] || inst.operation == Recipe_ordinal["loop-unless"]
             || inst.operation == Recipe_ordinal["break-if"] || inst.operation == Recipe_ordinal["break-unless"])
         && SIZE(inst.ingredients) == 2) {
       replace_offset(inst.ingredients.at(1), offset, i, r);
@@ -80,14 +81,14 @@ Type_ordinal["label"] = }
 
 :(code)
-void replace_offset(reagent& x, /*const*/ map<string, long long int>& offset, const long long int current_offset, const recipe_ordinal r) {
-  if (!is_literal(x)) {
+void replace_offset(reagent& x, /*const*/ map<string, long long int>& offset, const long long int current_offset, const recipe_ordinal r) {
+  if (!is_literal(x)) {
     raise << Recipe[r].name << ": jump target must be offset or label but is " << x.original_string << '\n' << end();
     return;
   }
   assert(!x.initialized);
-  if (is_integer(x.name)) return;  // non-labels will be handled like other number operands
-  if (offset.find(x.name) == offset.end())
+  if (is_integer(x.name)) return;  // non-labels will be handled like other number operands
+  if (offset.find(x.name) == offset.end())
     raise << Recipe[r].name << ": can't find label " << x.name << '\n' << end();
   x.set_value(offset[x.name]-current_offset);
 }
@@ -98,7 +99,7 @@ recipe main [
   {
     {
       break +target:label
-      1:number <- copy 0:literal
+      1:number <- copy 0
     }
   }
   +target
@@ -109,8 +110,8 @@ recipe main [
 recipe main [
   {
     {
-      jump-if 1:literal, +target:label
-      1:number <- copy 0:literal
+      jump-if 1, +target:label
+      1:number <- copy 0
     }
   }
   +target
@@ -121,8 +122,8 @@ recipe main [
 recipe main [
   {
     {
-      loop-unless 0:literal, +target:label  # loop/break with a label don't care about braces
-      1:number <- copy 0:literal
+      loop-unless 0, +target:label  # loop/break with a label don't care about braces
+      1:number <- copy 0
     }
   }
   +target
@@ -132,13 +133,13 @@ recipe main [
 :(scenario jump_runs_code_after_label)
 recipe main [
   # first a few lines of padding to exercise the offset computation
-  1:number <- copy 0:literal
-  2:number <- copy 0:literal
-  3:number <- copy 0:literal
+  1:number <- copy 0
+  2:number <- copy 0
+  3:number <- copy 0
   jump +target:label
-  4:number <- copy 0:literal
+  4:number <- copy 0
   +target
-  5:number <- copy 0:literal
+  5:number <- copy 0
 ]
 +mem: storing 0 in location 5
 -mem: storing 0 in location 4
diff --git a/html/042name.cc.html b/html/042name.cc.html
index 9eddb2c5..1a0cc746 100644
--- a/html/042name.cc.html
+++ b/html/042name.cc.html
@@ -13,17 +13,16 @@
 pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
 body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 1.05em; }
+.traceContains { color: #008000; }
 .cSpecial { color: #008000; }
-.SalientComment { color: #00ffff; }
 .Constant { color: #00a0a0; }
-.CommentedCode { color: #6c6c6c; }
+.SalientComment { color: #00ffff; }
 .traceAbsent { color: #c00000; }
-.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #a04060; }
 .Special { color: #ff6060; }
 .Identifier { color: #804000; }
-.traceContains { color: #008000; }
+.CommentedCode { color: #6c6c6c; }
 -->
 
 
@@ -39,17 +38,17 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 //: locations. In mu, a transform called 'transform_names' provides this
 //: convenience.
 
-:(scenario convert_names)
+:(scenario transform_names)
 recipe main [
-  x:number <- copy 0:literal
+  x:number <- copy 0
 ]
 +name: assign x 1
 +mem: storing 0 in location 1
 
-:(scenario convert_names_warns)
+:(scenario transform_names_warns)
 % Hide_warnings = true;
 recipe main [
-  x:number <- copy y:number
+  x:number <- copy y:number
 ]
 +warn: use before set: y in main
 
@@ -57,41 +56,38 @@ recipe main [
   Transform.push_back(transform_names);
 
 :(before "End Globals")
-map<recipe_ordinal, map<string, long long int> > Name;
+map<recipe_ordinal, map<string, long long int> > Name;
 :(after "Clear Other State For recently_added_recipes")
-for (long long int i = 0; i < SIZE(recently_added_recipes); ++i) {
+for (long long int i = 0; i < SIZE(recently_added_recipes); ++i) {
   Name.erase(recently_added_recipes.at(i));
 }
 
 :(code)
-void transform_names(const recipe_ordinal r) {
-  bool names_used = false;
-  bool numeric_locations_used = false;
-  map<string, long long int>& names = Name[r];
-  map<string, vector<type_ordinal> > metadata;
+void transform_names(const recipe_ordinal r) {
+  bool names_used = false;
+  bool numeric_locations_used = false;
+  map<string, long long int>& names = Name[r];
   // store the indices 'used' so far in the map
-  long long int& curr_idx = names[""];
+  long long int& curr_idx = names[""];
   ++curr_idx;  // avoid using index 0, benign skip in some other cases
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
+  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
     instruction& inst = Recipe[r].steps.at(i);
     // 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), inst)) continue;
-      if (!already_transformed(inst.ingredients.at(in), names)) {
+    for (long long int in = 0; in < SIZE(inst.ingredients); ++in) {
+      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), inst)) continue;
+      if (!already_transformed(inst.ingredients.at(in), names)) {
         raise << "use before set: " << inst.ingredients.at(in).name << " in " << Recipe[r].name << '\n' << end();
       }
       inst.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), inst)) continue;
-      if (names.find(inst.products.at(out).name) == names.end()) {
+    for (long long int out = 0; out < SIZE(inst.products); ++out) {
+      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), inst)) continue;
+      if (names.find(inst.products.at(out).name) == names.end()) {
         trace("name") << "assign " << inst.products.at(out).name << " " << curr_idx << end();
         names[inst.products.at(out).name] = curr_idx;
         curr_idx += size_of(inst.products.at(out));
@@ -99,170 +95,150 @@ map<recipe_ordinal, map<string.products.at(out).set_value(lookup_name(inst.products.at(out), r));
     }
   }
-  if (names_used && numeric_locations_used && r != Recipe_ordinal["interactive"])
+  if (names_used && numeric_locations_used && r != Recipe_ordinal["interactive"])
     raise << "mixing variable names and numeric addresses in " << Recipe[r].name << '\n' << end();
 }
 
-void check_metadata(map<string, vector<type_ordinal> >& metadata, const reagent& x, const recipe_ordinal r) {
-  if (is_literal(x)) return;
-  if (is_raw(x)) return;
-  // if you use raw locations you're probably doing something unsafe
-  if (is_integer(x.name)) return;
-  if (x.types.empty()) return;  // will throw a more precise warning elsewhere
-  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' << end();
-}
-
-bool disqualified(/*mutable*/ reagent& x, const instruction& inst) {
+bool disqualified(/*mutable*/ reagent& x, const instruction& inst) {
 //?   cerr << x.to_string() << '\n'; //? 1
-  if (x.types.empty()) {
+  if (x.types.empty()) {
     raise << "missing type in '" << inst.to_string() << "'\n" << end();
     return true;
   }
-  if (is_raw(x)) return true;
-  if (is_literal(x)) return true;
-  if (is_integer(x.name)) return true;
+  if (is_raw(x)) return true;
+  if (is_literal(x)) return true;
+  if (is_integer(x.name)) return true;
   // End Disqualified Reagents
-  if (x.initialized) return true;
+  if (x.initialized) return true;
   return false;
 }
 
-bool already_transformed(const reagent& r, const map<string, long long int>& names) {
+bool already_transformed(const reagent& r, const map<string, long long int>& names) {
   return names.find(r.name) != names.end();
 }
 
-long long int lookup_name(const reagent& r, const recipe_ordinal default_recipe) {
+long long int lookup_name(const reagent& r, const recipe_ordinal default_recipe) {
   return Name[default_recipe][r.name];
 }
 
-type_ordinal skip_addresses(const vector<type_ordinal>& types) {
-  for (long long int i = 0; i < SIZE(types); ++i) {
-    if (types.at(i) != Type_ordinal["address"]) return types.at(i);
+type_ordinal skip_addresses(const vector<type_ordinal>& types) {
+  for (long long int i = 0; i < SIZE(types); ++i) {
+    if (types.at(i) != Type_ordinal["address"]) return types.at(i);
   }
   raise << "expected a container" << '\n' << end();
   return -1;
 }
 
-int find_element_name(const type_ordinal t, const string& name) {
-  const type_info& container = Type[t];
+int find_element_name(const type_ordinal t, const string& name) {
+  const type_info& container = Type[t];
 //?   cout << "looking for element " << name << " in type " << container.name << " with " << SIZE(container.element_names) << " elements\n"; //? 1
-  for (long long int i = 0; i < SIZE(container.element_names); ++i) {
-    if (container.element_names.at(i) == name) return i;
+  for (long long int i = 0; i < SIZE(container.element_names); ++i) {
+    if (container.element_names.at(i) == name) return i;
   }
   raise << "unknown element " << name << " in container " << Type[t].name << '\n' << end();
   return -1;
 }
 
-bool is_numeric_location(const reagent& x) {
-  if (is_literal(x)) return false;
-  if (is_raw(x)) return false;
-  if (x.name == "0") return false;  // used for chaining lexical scopes
+bool is_numeric_location(const reagent& x) {
+  if (is_literal(x)) return false;
+  if (is_raw(x)) return false;
+  if (x.name == "0") return false;  // used for chaining lexical scopes
   return is_integer(x.name);
 }
 
-bool is_named_location(const reagent& x) {
-  if (is_literal(x)) return false;
-  if (is_raw(x)) return false;
-  if (is_special_name(x.name)) return false;
+bool is_named_location(const reagent& x) {
+  if (is_literal(x)) return false;
+  if (is_raw(x)) return false;
+  if (is_special_name(x.name)) return false;
   return !is_integer(x.name);
 }
 
-bool is_raw(const reagent& r) {
-  for (long long int i = /*skip value+type*/1; i < SIZE(r.properties); ++i) {
-    if (r.properties.at(i).first == "raw") return true;
+bool is_raw(const reagent& r) {
+  for (long long int i = /*skip value+type*/1; i < SIZE(r.properties); ++i) {
+    if (r.properties.at(i).first == "raw") return true;
   }
   return false;
 }
 
-bool is_special_name(const string& s) {
-  if (s == "_") return true;
-  if (s == "0") return true;
+bool is_special_name(const string& s) {
+  if (s == "_") return true;
+  if (s == "0") return true;
   // End is_special_name Cases
   return false;
 }
 
-:(scenario convert_names_passes_dummy)
+:(scenario transform_names_passes_dummy)
 # _ is just a dummy result that never gets consumed
 recipe main [
-  _, x:number <- copy 0:literal, 1:literal
+  _, x:number <- copy 0, 1
 ]
 +name: assign x 1
 -name: assign _ 1
 
 //: an escape hatch to suppress name conversion that we'll use later
-:(scenario convert_names_passes_raw)
+:(scenario transform_names_passes_raw)
 recipe main [
-  x:number/raw <- copy 0:literal
+  x:number/raw <- copy 0
 ]
 -name: assign x 1
 
-:(scenario convert_names_warns_when_mixing_names_and_numeric_locations)
+:(scenario transform_names_warns_when_mixing_names_and_numeric_locations)
 % Hide_warnings = true;
 recipe main [
-  x:number <- copy 1:number
+  x:number <- copy 1:number
 ]
 +warn: mixing variable names and numeric addresses in main
 
-:(scenario convert_names_warns_when_mixing_names_and_numeric_locations2)
+:(scenario transform_names_warns_when_mixing_names_and_numeric_locations2)
 % Hide_warnings = true;
 recipe main [
-  x:number <- copy 1:literal
+  x:number <- copy 1
   1:number <- copy x:number
 ]
 +warn: mixing variable names and numeric addresses in main
 
-:(scenario convert_names_does_not_warn_when_mixing_names_and_raw_locations)
+:(scenario transform_names_does_not_warn_when_mixing_names_and_raw_locations)
 % Hide_warnings = true;
 recipe main [
-  x:number <- copy 1:number/raw
+  x:number <- copy 1:number/raw
 ]
 -warn: mixing variable names and numeric addresses in main
 $warn: 0
 
-:(scenario convert_names_does_not_warn_when_mixing_names_and_literals)
+:(scenario transform_names_does_not_warn_when_mixing_names_and_literals)
 % Hide_warnings = true;
 recipe main [
-  x:number <- copy 1:literal
+  x:number <- copy 1
 ]
 -warn: mixing variable names and numeric addresses in main
 $warn: 0
 
-:(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
 :(before "End Mu Types Initialization")
 Type[point].element_names.push_back("x");
 Type[point].element_names.push_back("y");
-:(scenario convert_names_transforms_container_elements)
+:(scenario transform_names_transforms_container_elements)
 recipe main [
-  p:address:point <- copy 0:literal  # unsafe
-  a:number <- get p:address:point/deref, y:offset
-  b:number <- get p:address:point/deref, x:offset
+  p:address:point <- copy 0  # unsafe
+  a:number <- get *p:address:point, y:offset
+  b:number <- get *p:address:point, x:offset
 ]
 +name: element y of type point is at offset 1
 +name: element x of type point is at offset 0
 
 :(after "Per-recipe Transforms")
 // replace element names of containers with offsets
-if (inst.operation == Recipe_ordinal["get"]
+if (inst.operation == Recipe_ordinal["get"]
     || inst.operation == Recipe_ordinal["get-address"]) {
-  if (SIZE(inst.ingredients) != 2) {
+  if (SIZE(inst.ingredients) != 2) {
     raise << Recipe[r].name << ": exactly 2 ingredients expected in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
-  if (!is_literal(inst.ingredients.at(1)))
+  if (!is_literal(inst.ingredients.at(1)))
     raise << Recipe[r].name << ": expected ingredient 1 of " << (inst.operation == Recipe_ordinal["get"] ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end();
-  if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
+  if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
     // since first non-address in base type must be a container, we don't have to canonize
     type_ordinal base_type = skip_addresses(inst.ingredients.at(0).types);
     inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name));
@@ -272,10 +248,10 @@ recipe main [
 
 //: this test is actually illegal so can't call run
 :(scenarios transform)
-:(scenario convert_names_handles_containers)
+:(scenario transform_names_handles_containers)
 recipe main [
-  a:point <- copy 0:literal
-  b:number <- copy 0:literal
+  a:point <- copy 0
+  b:number <- copy 0
 ]
 +name: assign a 1
 +name: assign b 3
@@ -283,25 +259,25 @@ recipe main [
 //:: Support variant names for exclusive containers in 'maybe-convert'.
 
 :(scenarios run)
-:(scenario maybe_convert_named)
+:(scenario transform_names_handles_exclusive_containers)
 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/raw, p:variant  # unsafe
+  12:number <- copy 1
+  13:number <- copy 35
+  14:number <- copy 36
+  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
 
 :(after "Per-recipe Transforms")
 // convert variant names of exclusive containers
-if (inst.operation == Recipe_ordinal["maybe-convert"]) {
-  if (SIZE(inst.ingredients) != 2) {
+if (inst.operation == Recipe_ordinal["maybe-convert"]) {
+  if (SIZE(inst.ingredients) != 2) {
     raise << Recipe[r].name << ": exactly 2 ingredients expected in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   assert(is_literal(inst.ingredients.at(1)));
-  if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
+  if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
     // since first non-address in base type must be an exclusive container, we don't have to canonize
     type_ordinal base_type = skip_addresses(inst.ingredients.at(0).types);
     inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name));
diff --git a/html/043new.cc.html b/html/043new.cc.html
index 83bbbef2..6175f3dc 100644
--- a/html/043new.cc.html
+++ b/html/043new.cc.html
@@ -13,16 +13,15 @@
 pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
 body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 1.05em; }
+.traceContains { color: #008000; }
 .cSpecial { color: #008000; }
-.SalientComment { color: #00ffff; }
 .Constant { color: #00a0a0; }
-.CommentedCode { color: #6c6c6c; }
-.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
+.SalientComment { color: #00ffff; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #a04060; }
 .Special { color: #ff6060; }
 .Identifier { color: #804000; }
-.traceContains { color: #008000; }
+.CommentedCode { color: #6c6c6c; }
 -->
 
 
@@ -40,21 +39,21 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 :(scenario new)
 # call new two times with identical arguments; you should get back different results
 recipe main [
-  1:address:number/raw <- new number:type
-  2:address:number/raw <- new number:type
+  1:address:number/raw <- new number:type
+  2:address:number/raw <- new number:type
   3:boolean/raw <- equal 1:address:number/raw, 2:address:number/raw
 ]
 +mem: storing 0 in location 3
 
 :(before "End Globals")
-long long int Reserved_for_tests = 1000;
-long long int Memory_allocated_until = Reserved_for_tests;
-long long int Initial_memory_per_routine = 100000;
+long long int Reserved_for_tests = 1000;
+long long int Memory_allocated_until = Reserved_for_tests;
+long long int Initial_memory_per_routine = 100000;
 :(before "End Setup")
 Memory_allocated_until = Reserved_for_tests;
 Initial_memory_per_routine = 100000;
 :(before "End routine Fields")
-long long int alloc, alloc_max;
+long long int alloc, alloc_max;
 :(before "End routine Constructor")
 alloc = Memory_allocated_until;
 Memory_allocated_until += Initial_memory_per_routine;
@@ -67,20 +66,20 @@ trace(Primitive_recipe_depth"type"] = 0;
 :(after "Per-recipe Transforms")
 // replace type names with type_ordinals
-if (inst.operation == Recipe_ordinal["new"]) {
+if (inst.operation == Recipe_ordinal["new"]) {
   // End NEW Transform Special-cases
   // first arg must be of type 'type'
-  if (inst.ingredients.empty())
+  if (inst.ingredients.empty())
     raise << Recipe[r].name << ": 'new' expects one or two ingredients\n" << end();
-  if (inst.ingredients.at(0).properties.empty()
+  if (inst.ingredients.at(0).properties.empty()
       || inst.ingredients.at(0).properties.at(0).second.empty()
       || inst.ingredients.at(0).properties.at(0).second.at(0) != "type")
     raise << Recipe[r].name << ": first ingredient of 'new' should be a type, but got " << inst.ingredients.at(0).original_string << '\n' << end();
-  if (Type_ordinal.find(inst.ingredients.at(0).name) == Type_ordinal.end())
+  if (Type_ordinal.find(inst.ingredients.at(0).name) == Type_ordinal.end())
     raise << Recipe[r].name << ": unknown type " << inst.ingredients.at(0).name << '\n' << end();
   inst.ingredients.at(0).set_value(Type_ordinal[inst.ingredients.at(0).name]);
   trace(Primitive_recipe_depth, "new") << inst.ingredients.at(0).name << " -> " << inst.ingredients.at(0).name << end();
-  end_new_transform:;
+  end_new_transform:;
 }
 
 //:: Now implement the primitive recipe.
@@ -91,27 +90,27 @@ NEW,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["new"] = NEW;
 :(before "End Primitive Recipe Implementations")
-case NEW: {
-  if (ingredients.empty() || SIZE(ingredients) > 2) {
+case NEW: {
+  if (ingredients.empty() || SIZE(ingredients) > 2) {
     raise << current_recipe_name() << ": 'new' requires one or two ingredients, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
+  if (!scalar(ingredients.at(0))) {
     raise << current_recipe_name() << ": first ingredient of 'new' should be a type, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
   }
   // compute the space we need
-  long long int size = 0;
-  long long int array_length = 0;
+  long long int size = 0;
+  long long int array_length = 0;
   {
     vector<type_ordinal> type;
     type.push_back(current_instruction().ingredients.at(0).value);
-    if (SIZE(current_instruction().ingredients) > 1) {
+    if (SIZE(current_instruction().ingredients) > 1) {
       // array
       array_length = ingredients.at(1).at(0);
       trace(Primitive_recipe_depth, "mem") << "array size is " << array_length << end();
       size = array_length*size_of(type) + /*space for length*/1;
     }
-    else {
+    else {
       // scalar
       size = size_of(type);
     }
@@ -121,16 +120,16 @@ Recipe_ordinal["new"] = NEW// compute the region of memory to return
   // really crappy at the moment
   ensure_space(size);
-  const long long int result = Current_routine->alloc;
+  const long long int result = Current_routine->alloc;
   trace(Primitive_recipe_depth, "mem") << "new alloc: " << result << end();
   // save result
   products.resize(1);
   products.at(0).push_back(result);
   // initialize allocated space
-  for (long long int address = result; address < result+size; ++address) {
+  for (long long int address = result; address < result+size; ++address) {
     Memory[address] = 0;
   }
-  if (SIZE(current_instruction().ingredients) > 1) {
+  if (SIZE(current_instruction().ingredients) > 1) {
     Memory[result] = array_length;
   }
   // bump
@@ -153,9 +152,9 @@ Recipe_ordinal["new"] = NEW//? cerr << SIZE(Memory) << '\n'; //? 1
 
 :(code)
-void ensure_space(long long int size) {
+void ensure_space(long long int size) {
   assert(size <= Initial_memory_per_routine);
-  if (Current_routine->alloc + size > Current_routine->alloc_max) {
+  if (Current_routine->alloc + size > Current_routine->alloc_max) {
     // waste the remaining space and create a new chunk
     Current_routine->alloc = Memory_allocated_until;
     Memory_allocated_until += Initial_memory_per_routine;
@@ -168,29 +167,29 @@ Recipe_ordinal["new"] = NEW% Memory_allocated_until = 10;
 % Memory[Memory_allocated_until] = 1;
 recipe main [
-  1:address:number <- new number:type
-  2:number <- copy 1:address:number/deref
+  1:address:number <- new number:type
+  2:number <- copy *1:address:number
 ]
 +mem: storing 0 in location 2
 
 :(scenario new_array)
 recipe main [
-  1:address:array:number/raw <- new number:type, 5:literal
-  2:address:number/raw <- new number:type
+  1:address:array:number/raw <- new number:type, 5
+  2:address:number/raw <- new number:type
   3:number/raw <- subtract 2:address:number/raw, 1:address:array:number/raw
 ]
-+run: 1:address:array:number/raw <- new number:type, 5:literal
++run: 1:address:array:number/raw <- new number:type, 5
 +mem: array size is 5
 # don't forget the extra location for array size
 +mem: storing 6 in location 3
 
 :(scenario new_empty_array)
 recipe main [
-  1:address:array:number/raw <- new number:type, 0:literal
-  2:address:number/raw <- new number:type
+  1:address:array:number/raw <- new number:type, 0
+  2:address:number/raw <- new number:type
   3:number/raw <- subtract 2:address:number/raw, 1:address:array:number/raw
 ]
-+run: 1:address:array:number/raw <- new number:type, 0:literal
++run: 1:address:array:number/raw <- new number:type, 0
 +mem: array size is 0
 +mem: storing 1 in location 3
 
@@ -198,18 +197,18 @@ recipe main [
 :(scenario new_concurrent)
 recipe f1 [
   start-running f2:recipe
-  1:address:number/raw <- new number:type
+  1:address:number/raw <- new number:type
   # wait for f2 to complete
   {
     loop-unless 4:number/raw
   }
 ]
 recipe f2 [
-  2:address:number/raw <- new number:type
+  2:address:number/raw <- new number:type
   # hack: assumes scheduler implementation
   3:boolean/raw <- equal 1:address:number/raw, 2:address:number/raw
   # signal f2 complete
-  4:number/raw <- copy 1:literal
+  4:number/raw <- copy 1
 ]
 +mem: storing 0 in location 3
 
@@ -217,8 +216,8 @@ recipe f2 [
 :(scenario new_overflow)
 % Initial_memory_per_routine = 2;
 recipe main [
-  1:address:number/raw <- new number:type
-  2:address:point/raw <- new point:type  # not enough room in initial page
+  1:address:number/raw <- new number:type
+  2:address:point/raw <- new point:type  # not enough room in initial page
 ]
 +new: routine allocated memory from 1000 to 1002
 +new: routine allocated memory from 1002 to 1004
@@ -228,16 +227,16 @@ recipe main [
 
 :(scenario new_reclaim)
 recipe main [
-  1:address:number <- new number:type
+  1:address:number <- new number:type
   abandon 1:address:number
-  2:address:number <- new number:type  # must be same size as abandoned memory to reuse
+  2:address:number <- new number:type  # must be same size as abandoned memory to reuse
   3:boolean <- equal 1:address:number, 2:address:number
 ]
 # both allocations should have returned the same address
 +mem: storing 1 in location 3
 
 :(before "End Globals")
-map<long long int, long long int> Free_list;
+map<long long int, long long int> Free_list;
 :(before "End Setup")
 Free_list.clear();
 
@@ -246,33 +245,33 @@ ABANDON,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["abandon"] = ABANDON;
 :(before "End Primitive Recipe Implementations")
-case ABANDON: {
-  if (SIZE(ingredients) != 1) {
+case ABANDON: {
+  if (SIZE(ingredients) != 1) {
     raise << current_recipe_name() << ": 'abandon' requires one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
+  if (!scalar(ingredients.at(0))) {
     raise << current_recipe_name() << ": first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
-  long long int address = ingredients.at(0).at(0);
+  long long int address = ingredients.at(0).at(0);
   reagent types = canonize(current_instruction().ingredients.at(0));
-  if (types.types.at(0) != Type_ordinal["address"]) {
+  if (types.types.at(0) != Type_ordinal["address"]) {
     raise << current_recipe_name() << ": first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
-  reagent target_type = deref(types);
+  reagent target_type = lookup_memory(types);
   abandon(address, size_of(target_type));
   break;
 }
 
 :(code)
-void abandon(long long int address, long long int size) {
+void abandon(long long int address, long long int size) {
 //?   Total_free += size; //? 1
 //?   Num_free++; //? 1
 //?   cerr << "abandon: " << size << '\n'; //? 2
   // clear memory
-  for (long long int curr = address; curr < address+size; ++curr)
+  for (long long int curr = address; curr < address+size; ++curr)
     Memory[curr] = 0;
   // append existing free list to address
   Memory[address] = Free_list[size];
@@ -280,18 +279,18 @@ Recipe_ordinal["abandon"] = ABANDON}
 
 :(before "ensure_space(size)" following "case NEW")
-if (Free_list[size]) {
-  long long int result = Free_list[size];
+if (Free_list[size]) {
+  long long int result = Free_list[size];
   Free_list[size] = Memory[result];
-  for (long long int curr = result+1; curr < result+size; ++curr) {
-    if (Memory[curr] != 0) {
+  for (long long int curr = result+1; curr < result+size; ++curr) {
+    if (Memory[curr] != 0) {
       raise << current_recipe_name() << ": memory in free list was not zeroed out: " << curr << '/' << result << "; somebody wrote to us after free!!!\n" << end();
       break;  // always fatal
     }
   }
-  if (SIZE(current_instruction().ingredients) > 1)
+  if (SIZE(current_instruction().ingredients) > 1)
     Memory[result] = array_length;
-  else
+  else
     Memory[result] = 0;
   products.resize(1);
   products.at(0).push_back(result);
@@ -300,9 +299,9 @@ Recipe_ordinal["abandon"] = ABANDON:(scenario new_differing_size_no_reclaim)
 recipe main [
-  1:address:number <- new number:type
+  1:address:number <- new number:type
   abandon 1:address:number
-  2:address:number <- new number:type, 2:literal  # different size
+  2:address:number <- new number:type, 2  # different size
   3:boolean <- equal 1:address:number, 2:address:number
 ]
 # no reuse
@@ -310,9 +309,9 @@ recipe main [
 
 :(scenario new_reclaim_array)
 recipe main [
-  1:address:array:number <- new number:type, 2:literal
+  1:address:array:number <- new number:type, 2
   abandon 1:address:array:number
-  2:address:array:number <- new number:type, 2:literal
+  2:address:array:number <- new number:type, 2
   3:boolean <- equal 1:address:array:number, 2:address:array:number
 ]
 # reuse
@@ -322,24 +321,24 @@ recipe main [
 
 :(scenario new_string)
 recipe main [
-  1:address:array:character <- new [abc def]
-  2:character <- index 1:address:array:character/deref, 5:literal
+  1:address:array:character <- new [abc def]
+  2:character <- index *1:address:array:character, 5
 ]
 # 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
+  1:address:array:character <- new [a«c]
+  2:number <- length *1:address:array:character
+  3:character <- index *1:address:array:character, 1
 ]
 +mem: storing 3 in location 2
 # unicode for '«'
 +mem: storing 171 in location 3
 
 :(before "End NEW Transform Special-cases")
-  if (!inst.ingredients.empty()
+  if (!inst.ingredients.empty()
       && !inst.ingredients.at(0).properties.empty()
       && !inst.ingredients.at(0).properties.at(0).second.empty()
       && inst.ingredients.at(0).properties.at(0).second.at(0) == "literal-string") {
@@ -349,7 +348,7 @@ recipe main [
   }
 
 :(after "case NEW" following "Primitive Recipe Implementations")
-if (is_literal(current_instruction().ingredients.at(0))
+if (is_literal(current_instruction().ingredients.at(0))
     && current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "literal-string") {
   products.resize(1);
   products.at(0).push_back(new_mu_string(current_instruction().ingredients.at(0).name));
@@ -357,20 +356,20 @@ recipe main [
 }
 
 :(code)
-long long int new_mu_string(const string& contents) {
+long long int new_mu_string(const string& contents) {
   // allocate an array just large enough for it
-  long long int string_length = unicode_length(contents);
+  long long int string_length = unicode_length(contents);
 //?   cout << "string_length is " << string_length << '\n'; //? 1
 //?   Total_alloc += string_length+1; //? 1
 //?   Num_alloc++; //? 1
   ensure_space(string_length+1);  // don't forget the extra location for array size
   // initialize string
-  long long int result = Current_routine->alloc;
+  long long int result = Current_routine->alloc;
   Memory[Current_routine->alloc++] = string_length;
-  long long int curr = 0;
-  const char* raw_contents = contents.c_str();
-  for (long long int i = 0; i < string_length; ++i) {
-    uint32_t curr_character;
+  long long int curr = 0;
+  const char* raw_contents = contents.c_str();
+  for (long long int i = 0; i < string_length; ++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;
@@ -385,19 +384,19 @@ recipe main [
 :(scenario new_string_overflow)
 % Initial_memory_per_routine = 2;
 recipe main [
-  1:address:number/raw <- new number:type
-  2:address:array:character/raw <- new [a]  # not enough room in initial page, if you take the array size into account
+  1:address:number/raw <- new number:type
+  2:address:array:character/raw <- new [a]  # not enough room in initial page, if you take the array size into account
 ]
 +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
+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]);
diff --git a/html/044space.cc.html b/html/044space.cc.html
index 14ef9f7a..7f4e742e 100644
--- a/html/044space.cc.html
+++ b/html/044space.cc.html
@@ -13,17 +13,16 @@
 pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
 body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 1.05em; }
-.traceAbsent { color: #c00000; }
-.SalientComment { color: #00ffff; }
-.Constant { color: #00a0a0; }
-.CommentedCode { color: #6c6c6c; }
+.traceContains { color: #008000; }
 .cSpecial { color: #008000; }
-.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
+.Constant { color: #00a0a0; }
+.SalientComment { color: #00ffff; }
+.traceAbsent { color: #c00000; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #a04060; }
 .Special { color: #ff6060; }
 .Identifier { color: #804000; }
-.traceContains { color: #008000; }
+.CommentedCode { color: #6c6c6c; }
 -->
 
 
@@ -43,42 +42,42 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 # if default-space is 10, and if an array of 5 locals lies from location 11 to 15 (inclusive),
 # then location 0 is really location 11, location 1 is really location 12, and so on.
 recipe main [
-  10:number <- copy 5:literal  # pretend array; in practice we'll use new
-  default-space:address:array:location <- copy 10:literal
-  1:number <- copy 23:literal
+  10:number <- copy 5  # pretend array; in practice we'll use new
+  default-space:address:array:location <- copy 10
+  1:number <- copy 23
 ]
 +mem: storing 23 in location 12
 
-:(scenario deref_sidesteps_default_space)
+:(scenario lookup_sidesteps_default_space)
 recipe main [
   # pretend pointer from outside
-  3:number <- copy 34:literal
+  3:number <- copy 34
   # pretend array
-  1000:number <- copy 5:literal
+  1000:number <- copy 5
   # actual start of this recipe
-  default-space:address:array:location <- copy 1000:literal
-  1:address:number <- copy 3:literal
-  8:number/raw <- copy 1:address:number/deref
+  default-space:address:array:location <- copy 1000
+  1:address:number <- copy 3
+  8:number/raw <- copy *1:address:number
 ]
 +mem: storing 34 in location 8
 
 //:: first disable name conversion for 'default-space'
 :(scenario convert_names_passes_default_space)
 recipe main [
-  default-space:number, x:number <- copy 0:literal, 1:literal
+  default-space:number, x:number <- copy 0, 1
 ]
 +name: assign x 1
 -name: assign default-space 1
 
 :(before "End Disqualified Reagents")
-if (x.name == "default-space")
+if (x.name == "default-space")
   x.initialized = true;
 :(before "End is_special_name Cases")
-if (s == "default-space") return true;
+if (s == "default-space") return true;
 
 //:: now implement space support
 :(before "End call Fields")
-long long int default_space;
+long long int default_space;
 :(before "End call Constructor")
 default_space = 0;
 
@@ -87,8 +86,8 @@ reagent r = absolutize(x)
 :(code)
 reagent absolutize(reagent x) {
 //?   cout << "absolutize " << x.to_string() << '\n'; //? 4
-  if (is_raw(x) || is_dummy(x)) return x;
-  if (!x.initialized) {
+  if (is_raw(x) || is_dummy(x)) return x;
+  if (!x.initialized) {
     raise << current_instruction().to_string() << ": reagent not initialized: " << x.original_string << end();
     return x;
   }
@@ -98,22 +97,22 @@ reagent absolutize(reagent x(is_raw(r));
   return r;
 }
-:(before "return result" following "reagent deref(reagent x)")
+:(before "return result" following "reagent lookup_memory(reagent x)")
 result.properties.push_back(pair<string, vector<string> >("raw", vector<string>()));
 
 //:: fix 'get'
 
-:(scenario deref_sidesteps_default_space_in_get)
+:(scenario lookup_sidesteps_default_space_in_get)
 recipe main [
   # pretend pointer to container from outside
-  12:number <- copy 34:literal
-  13:number <- copy 35:literal
+  12:number <- copy 34
+  13:number <- copy 35
   # pretend array
-  1000:number <- copy 5:literal
+  1000:number <- copy 5
   # actual start of this recipe
-  default-space:address:array:location <- copy 1000:literal
-  1:address:point <- copy 12:literal
-  9:number/raw <- get 1:address:point/deref, 1:offset
+  default-space:address:array:location <- copy 1000
+  1:address:point <- copy 12
+  9:number/raw <- get *1:address:point, 1:offset
 ]
 +mem: storing 35 in location 9
 
@@ -122,18 +121,18 @@ tmp.properties.pus
 
 //:: fix 'index'
 
-:(scenario deref_sidesteps_default_space_in_index)
+:(scenario lookup_sidesteps_default_space_in_index)
 recipe main [
   # pretend pointer to array from outside
-  12:number <- copy 2:literal
-  13:number <- copy 34:literal
-  14:number <- copy 35:literal
+  12:number <- copy 2
+  13:number <- copy 34
+  14:number <- copy 35
   # pretend array
-  1000:number <- copy 5:literal
+  1000:number <- copy 5
   # actual start of this recipe
-  default-space:address:array:location <- copy 1000:literal
-  1:address:array:number <- copy 12:literal
-  9:number/raw <- index 1:address:array:number/deref, 1:literal
+  default-space:address:array:location <- copy 1000
+  1:address:array:number <- copy 12
+  9:number/raw <- index *1:address:array:number, 1
 ]
 +mem: storing 35 in location 9
 
@@ -145,36 +144,36 @@ tmp.properties.pus
 
 :(scenario new_default_space)
 recipe main [
-  new-default-space
-  x:number <- copy 0:literal
-  y:number <- copy 3:literal
+  new-default-space
+  x:number <- copy 0
+  y:number <- copy 3
 ]
 # allocate space for x and y, as well as the chaining slot at 0
 +mem: array size is 3
 
 :(before "End Disqualified Reagents")
-if (x.name == "number-of-locals")
+if (x.name == "number-of-locals")
   x.initialized = true;
 :(before "End is_special_name Cases")
-if (s == "number-of-locals") return true;
+if (s == "number-of-locals") return true;
 
 :(before "End Rewrite Instruction(curr)")
 // rewrite `new-default-space` to
 //   `default-space:address:array:location <- new location:type, number-of-locals:literal`
 // where N is Name[recipe][""]
-if (curr.name == "new-default-space") {
+if (curr.name == "new-default-space") {
   rewrite_default_space_instruction(curr);
 }
 :(after "vector<double> read_memory(reagent x)")
-  if (x.name == "number-of-locals") {
-    vector<double> result;
+  if (x.name == "number-of-locals") {
+    vector<double> result;
     result.push_back(Name[Recipe_ordinal[current_recipe_name()]][""]);
-    if (result.back() == 0)
+    if (result.back() == 0)
       raise << "no space allocated for default-space in recipe " << current_recipe_name() << "; are you using names\n" << end();
     return result;
   }
 :(after "void write_memory(reagent x, vector<double> data)")
-  if (x.name == "number-of-locals") {
+  if (x.name == "number-of-locals") {
     raise << current_recipe_name() << ": can't write to special name 'number-of-locals'\n" << end();
     return;
   }
@@ -190,8 +189,8 @@ recipe main [
 ]
 recipe foo [
   local-scope
-  x:number <- copy 34:literal
-  reply default-space:address:array:location
+  x:number <- copy 34
+  reply default-space:address:array:location
 ]
 # both calls to foo should have received the same default-space
 +mem: storing 1 in location 3
@@ -204,28 +203,28 @@ try_reclaim_locals();
 //: now 'local-scope' is identical to 'new-default-space' except that we'll
 //: reclaim the default-space when the routine exits
 :(before "End Rewrite Instruction(curr)")
-if (curr.name == "local-scope") {
+if (curr.name == "local-scope") {
   rewrite_default_space_instruction(curr);
 }
 
 :(code)
-void try_reclaim_locals() {
+void try_reclaim_locals() {
   // only reclaim routines starting with 'local-scope'
-  const recipe_ordinal r = Recipe_ordinal[current_recipe_name()];
-  if (Recipe[r].steps.empty()) return;
-  const instruction& inst = Recipe[r].steps.at(0);
-  if (inst.name != "local-scope") return;
+  const recipe_ordinal r = Recipe_ordinal[current_recipe_name()];
+  if (Recipe[r].steps.empty()) return;
+  const instruction& inst = Recipe[r].steps.at(0);
+  if (inst.name != "local-scope") return;
   abandon(Current_routine->calls.front().default_space,
           /*array length*/1+/*number-of-locals*/Name[r][""]);
 }
 
-void rewrite_default_space_instruction(instruction& curr) {
+void rewrite_default_space_instruction(instruction& curr) {
   curr.operation = Recipe_ordinal["new"];
-  if (!curr.ingredients.empty())
+  if (!curr.ingredients.empty())
     raise << "new-default-space can't take any ingredients\n" << end();
   curr.ingredients.push_back(reagent("location:type"));
   curr.ingredients.push_back(reagent("number-of-locals:literal"));
-  if (!curr.products.empty())
+  if (!curr.products.empty())
     raise << "new-default-space can't take any results\n" << end();
   curr.products.push_back(reagent("default-space:address:array:location"));
 }
@@ -233,14 +232,14 @@ try_reclaim_locals();
 //:: helpers
 
 :(code)
-long long int space_base(const reagent& x) {
+long long int space_base(const reagent& x) {
   return Current_routine->calls.front().default_space;
 }
 
-long long int address(long long int offset, long long int base) {
-  if (base == 0) return offset;  // raw
+long long int address(long long int offset, long long int base) {
+  if (base == 0) return offset;  // raw
 //?   cout << base << '\n'; //? 2
-  if (offset >= static_cast<long long int>(Memory[base])) {
+  if (offset >= static_cast<long long int>(Memory[base])) {
     // todo: test
     raise << "location " << offset << " is out of bounds " << Memory[base] << " at " << base << '\n' << end();
   }
@@ -248,8 +247,8 @@ try_reclaim_locals();
 }
 
 :(after "void write_memory(reagent x, vector<double> data)")
-  if (x.name == "default-space") {
-    if (!scalar(data))
+  if (x.name == "default-space") {
+    if (!scalar(data))
       raise << current_recipe_name() << ": 'default-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
     Current_routine->calls.front().default_space = data.at(0);
     return;
@@ -257,14 +256,14 @@ try_reclaim_locals();
 
 :(scenario get_default_space)
 recipe main [
-  default-space:address:array:location <- copy 10:literal
-  1:number/raw <- copy default-space:address:array:location
+  default-space:address:array:location <- copy 10
+  1:number/raw <- copy default-space:address:array:location
 ]
 +mem: storing 10 in location 1
 
 :(after "vector<double> read_memory(reagent x)")
-  if (x.name == "default-space") {
-    vector<double> result;
+  if (x.name == "default-space") {
+    vector<double> result;
     result.push_back(Current_routine->calls.front().default_space);
     return result;
   }
diff --git a/html/045space_surround.cc.html b/html/045space_surround.cc.html
index 2bf9c648..1b356165 100644
--- a/html/045space_surround.cc.html
+++ b/html/045space_surround.cc.html
@@ -13,14 +13,13 @@
 pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
 body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 1.05em; }
+.traceContains { color: #008000; }
 .cSpecial { color: #008000; }
 .Constant { color: #00a0a0; }
-.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #a04060; }
 .Special { color: #ff6060; }
 .Identifier { color: #804000; }
-.traceContains { color: #008000; }
 -->
 
 
@@ -41,12 +40,12 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 :(scenario surrounding_space)
 # location 1 in space 1 refers to the space surrounding the default space, here 20.
 recipe main [
-  10:number <- copy 5:literal  # pretend array
-  20:number <- copy 5:literal  # pretend array
-  default-space:address:array:location <- copy 10:literal
-  0:address:array:location/names:dummy <- copy 20:literal  # later layers will explain the /names: property
-  1:number <- copy 32:literal
-  1:number/space:1 <- copy 33:literal
+  10:number <- copy 5  # pretend array
+  20:number <- copy 5  # pretend array
+  default-space:address:array:location <- copy 10
+  0:address:array:location/names:dummy <- copy 20  # later layers will explain the /names: property
+  1:number <- copy 32
+  1:number/space:1 <- copy 33
 ]
 # chain space
 +mem: storing 20 in location 11
@@ -60,22 +59,22 @@ recipe main [
 //: one.
 
 :(replace{} "long long int space_base(const reagent& x)")
-long long int space_base(const reagent& x) {
+long long int space_base(const reagent& x) {
   return space_base(x, space_index(x), Current_routine->calls.front().default_space);
 }
 
-long long int space_base(const reagent& x, long long int space_index, long long int base) {
-  if (space_index == 0) {
+long long int space_base(const reagent& x, long long int space_index, long long int base) {
+  if (space_index == 0) {
     return base;
   }
-  long long int result = space_base(x, space_index-1, Memory[base+1]);
+  long long int result = space_base(x, space_index-1, Memory[base+1]);
   return result;
 }
 
-long long int space_index(const reagent& x) {
-  for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) {
-    if (x.properties.at(i).first == "space") {
-      if (SIZE(x.properties.at(i).second) != 1)
+long long int space_index(const reagent& x) {
+  for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) {
+    if (x.properties.at(i).first == "space") {
+      if (SIZE(x.properties.at(i).second) != 1)
         raise << current_recipe_name() << ": /space metadata should take exactly one value in " << x.original_string << '\n' << end();
       return to_integer(x.properties.at(i).second.at(0));
     }
@@ -85,7 +84,7 @@ recipe main [
 
 :(scenario permit_space_as_variable_name)
 recipe main [
-  space:number <- copy 0:literal
+  space:number <- copy 0
 ]
 
diff --git a/html/046closure_name.cc.html b/html/046closure_name.cc.html index 83650402..b406f481 100644 --- a/html/046closure_name.cc.html +++ b/html/046closure_name.cc.html @@ -13,15 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } +.CommentedCode { color: #6c6c6c; } --> @@ -40,24 +39,24 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } :(scenario closure) recipe main [ - default-space:address:array:location <- new location:type, 30:literal - 1:address:array:location/names:new-counter <- new-counter - 2:number/raw <- increment-counter 1:address:array:location/names:new-counter - 3:number/raw <- increment-counter 1:address:array:location/names:new-counter + default-space:address:array:location <- new location:type, 30 + 1:address:array:location/names:new-counter <- new-counter + 2:number/raw <- increment-counter 1:address:array:location/names:new-counter + 3:number/raw <- increment-counter 1:address:array:location/names:new-counter ] -recipe new-counter [ - default-space:address:array:location <- new location:type, 30:literal - x:number <- copy 23:literal - y:number <- copy 3:literal # variable that will be incremented - reply default-space:address:array:location +recipe new-counter [ + default-space:address:array:location <- new location:type, 30 + x:number <- copy 23 + y:number <- copy 3 # variable that will be incremented + reply default-space:address:array:location ] recipe increment-counter [ - default-space:address:array:location <- new location:type, 30:literal - 0:address:array:location/names:new-counter <- next-ingredient # outer space must be created by 'new-counter' above - y:number/space:1 <- add y:number/space:1, 1:literal # increment - y:number <- copy 234:literal # dummy + default-space:address:array:location <- new location:type, 30 + 0:address:array:location/names:new-counter <- next-ingredient # outer space must be created by 'new-counter' above + y:number/space:1 <- add y:number/space:1, 1 # increment + y:number <- copy 234 # dummy reply y:number/space:1 ] @@ -74,14 +73,14 @@ map<recipe_ordinal, recipe_ordinal> Surroun Transform.push_back(collect_surrounding_spaces); :(code) -void collect_surrounding_spaces(const recipe_ordinal r) { - for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) { - const instruction& inst = Recipe[r].steps.at(i); - if (inst.is_label) continue; - for (long long int j = 0; j < SIZE(inst.products); ++j) { - if (is_literal(inst.products.at(j))) continue; - if (inst.products.at(j).name != "0") continue; - if (SIZE(inst.products.at(j).types) != 3 +void collect_surrounding_spaces(const recipe_ordinal r) { + for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) { + const instruction& inst = Recipe[r].steps.at(i); + if (inst.is_label) continue; + for (long long int j = 0; j < SIZE(inst.products); ++j) { + if (is_literal(inst.products.at(j))) continue; + if (inst.products.at(j).name != "0") continue; + if (SIZE(inst.products.at(j).types) != 3 || inst.products.at(j).types.at(0) != Type_ordinal["address"] || inst.products.at(j).types.at(1) != Type_ordinal["array"] || inst.products.at(j).types.at(2) != Type_ordinal["location"]) { @@ -89,13 +88,13 @@ map<recipe_ordinal, recipe_ordinal> Surroun continue; } vector<string> s = property(inst.products.at(j), "names"); - if (s.empty()) { + if (s.empty()) { raise << "slot 0 requires a /names property in recipe " << Recipe[r].name << end(); continue; } - if (SIZE(s) > 1) raise << "slot 0 should have a single value in /names, but got " << inst.products.at(j).to_string() << '\n' << end(); + if (SIZE(s) > 1) raise << "slot 0 should have a single value in /names, but got " << inst.products.at(j).to_string() << '\n' << end(); string surrounding_recipe_name = s.at(0); - if (Surrounding_space.find(r) != Surrounding_space.end() + if (Surrounding_space.find(r) != Surrounding_space.end() && Surrounding_space[r] != Recipe_ordinal[surrounding_recipe_name]) { raise << "recipe " << Recipe[r].name << " can have only one 'surrounding' recipe but has " << Recipe[Surrounding_space[r]].name << " and " << surrounding_recipe_name << '\n' << end(); continue; @@ -110,16 +109,16 @@ map<recipe_ordinal, recipe_ordinal> Surroun //: /space properties. :(replace{} "long long int lookup_name(const reagent& r, const recipe_ordinal default_recipe)") -long long int lookup_name(const reagent& x, const recipe_ordinal default_recipe) { +long long int lookup_name(const reagent& x, const recipe_ordinal default_recipe) { //? cout << "AAA " << default_recipe << " " << Recipe[default_recipe].name << '\n'; //? 2 //? cout << "AAA " << x.to_string() << '\n'; //? 1 - if (!has_property(x, "space")) { - if (Name[default_recipe].empty()) raise << "name not found: " << x.name << '\n' << end(); + if (!has_property(x, "space")) { + if (Name[default_recipe].empty()) raise << "name not found: " << x.name << '\n' << end(); return Name[default_recipe][x.name]; } vector<string> p = property(x, "space"); - if (SIZE(p) != 1) raise << "/space property should have exactly one (non-negative integer) value\n" << end(); - long long int n = to_integer(p.at(0)); + if (SIZE(p) != 1) raise << "/space property should have exactly one (non-negative integer) value\n" << end(); + long long int n = to_integer(p.at(0)); assert(n >= 0); recipe_ordinal surrounding_recipe = lookup_surrounding_recipe(default_recipe, n); set<recipe_ordinal> done; @@ -129,11 +128,11 @@ map<recipe_ordinal, recipe_ordinal> Surroun // If the recipe we need to lookup this name in doesn't have names done yet, // recursively call transform_names on it. -long long int lookup_name(const reagent& x, const recipe_ordinal r, set<recipe_ordinal>& done, vector<recipe_ordinal>& path) { - if (!Name[r].empty()) return Name[r][x.name]; - if (done.find(r) != done.end()) { +long long int lookup_name(const reagent& x, const recipe_ordinal r, set<recipe_ordinal>& done, vector<recipe_ordinal>& path) { + if (!Name[r].empty()) return Name[r][x.name]; + if (done.find(r) != done.end()) { raise << "can't compute address of " << x.to_string() << " because " << end(); - for (long long int i = 1; i < SIZE(path); ++i) { + for (long long int i = 1; i < SIZE(path); ++i) { raise << path.at(i-1) << " requires computing names of " << path.at(i) << '\n' << end(); } raise << path.at(SIZE(path)-1) << " requires computing names of " << r << "..ad infinitum\n" << end(); @@ -146,9 +145,9 @@ map<recipe_ordinal, recipe_ordinal> Surroun return Name[r][x.name]; } -recipe_ordinal lookup_surrounding_recipe(const recipe_ordinal r, long long int n) { - if (n == 0) return r; - if (Surrounding_space.find(r) == Surrounding_space.end()) { +recipe_ordinal lookup_surrounding_recipe(const recipe_ordinal r, long long int n) { + if (n == 0) return r; + if (Surrounding_space.find(r) == Surrounding_space.end()) { raise << "don't know surrounding recipe of " << Recipe[r].name << '\n' << end(); return 0; } @@ -158,14 +157,14 @@ recipe_ordinal lookup_surrounding_recipe(//: weaken use-before-set warnings just a tad :(replace{} "bool already_transformed(const reagent& r, const map<string, long long int>& names)") -bool already_transformed(const reagent& r, const map<string, long long int>& names) { - if (has_property(r, "space")) { +bool already_transformed(const reagent& r, const map<string, long long int>& names) { + if (has_property(r, "space")) { vector<string> p = property(r, "space"); - if (SIZE(p) != 1) { + if (SIZE(p) != 1) { raise << "/space property should have exactly one (non-negative integer) value in " << r.original_string << '\n' << end(); return false; } - if (p.at(0) != "0") return true; + if (p.at(0) != "0") return true; } return names.find(r.name) != names.end(); } diff --git a/html/047global.cc.html b/html/047global.cc.html index 3fcf82fc..941f8c90 100644 --- a/html/047global.cc.html +++ b/html/047global.cc.html @@ -13,14 +13,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -40,34 +39,34 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } :(scenario global_space) recipe main [ # pretend arrays; in practice we'll use new - 10:number <- copy 5:literal - 20:number <- copy 5:literal + 10:number <- copy 5 + 20:number <- copy 5 # actual start of this recipe - global-space:address:array:location <- copy 20:literal - default-space:address:array:location <- copy 10:literal - 1:number <- copy 23:literal - 1:number/space:global <- copy 24:literal + global-space:address:array:location <- copy 20 + default-space:address:array:location <- copy 10 + 1:number <- copy 23 + 1:number/space:global <- copy 24 ] +mem: storing 23 in location 12 +mem: storing 24 in location 22 //: to support it, create another special variable called global space :(before "End Disqualified Reagents") -if (x.name == "global-space") +if (x.name == "global-space") x.initialized = true; :(before "End is_special_name Cases") -if (s == "global-space") return true; +if (s == "global-space") return true; //: writes to this variable go to a field in the current routine :(before "End routine Fields") -long long int global_space; +long long int global_space; :(before "End routine Constructor") global_space = 0; :(after "void write_memory(reagent x, vector<double> data)") - if (x.name == "global-space") { - if (!scalar(data)) + if (x.name == "global-space") { + if (!scalar(data)) raise << current_recipe_name() << ": 'global-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end(); - if (Current_routine->global_space) + if (Current_routine->global_space) raise << "routine already has a global-space; you can't over-write your globals" << end(); Current_routine->global_space = data.at(0); return; @@ -75,8 +74,8 @@ global_space = 0; //: now marking variables as /space:global looks them up inside this field :(after "long long int space_base(const reagent& x)") - if (is_global(x)) { - if (!Current_routine->global_space) + if (is_global(x)) { + if (!Current_routine->global_space) raise << "routine has no global space\n" << end(); return Current_routine->global_space; } @@ -87,22 +86,22 @@ global_space = 0; :(scenario global_space_with_names) % Hide_warnings = true; recipe main [ - global-space:address:array:location <- new location:type, 10:literal - x:number <- copy 23:literal - 1:number/space:global <- copy 24:literal + global-space:address:array:location <- new location:type, 10 + x:number <- copy 23 + 1:number/space:global <- copy 24 ] # don't warn that we're mixing numeric addresses and names $warn: 0 :(after "bool is_numeric_location(const reagent& x)") - if (is_global(x)) return false; + if (is_global(x)) return false; //: helpers :(code) -bool is_global(const reagent& x) { - for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) { - if (x.properties.at(i).first == "space") +bool is_global(const reagent& x) { + for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) { + if (x.properties.at(i).first == "space") return !x.properties.at(i).second.empty() && x.properties.at(i).second.at(0) == "global"; } return false; diff --git a/html/048tangle.cc.html b/html/048tangle.cc.html deleted file mode 100644 index ac7d52e9..00000000 --- a/html/048tangle.cc.html +++ /dev/null @@ -1,236 +0,0 @@ - - - - -Mu - 048tangle.cc - - - - - - - - - - -
-//: Allow code for recipes to be pulled in from multiple places.
-//:
-//: TODO: switch recipe.steps to a more efficient data structure.
-
-:(scenario tangle_before)
-recipe main [
-  1:number <- copy 0:literal
-  +label1
-  3:number <- copy 0:literal
-]
-
-before +label1 [
-  2:number <- copy 0:literal
-]
-+mem: storing 0 in location 1
-+mem: storing 0 in location 2
-+mem: storing 0 in location 3
-# nothing else
-$mem: 3
-
-//: while loading recipes, load before/after fragments
-
-:(before "End Globals")
-map<string /*label*/, recipe> Before_fragments, After_fragments;
-:(before "End Setup")
-Before_fragments.clear();
-After_fragments.clear();
-
-:(before "End Command Handlers")
-else if (command == "before") {
-  string label = next_word(in);
-  recipe tmp = slurp_recipe(in);
-  Before_fragments[label].steps.insert(Before_fragments[label].steps.end(), tmp.steps.begin(), tmp.steps.end());
-}
-else if (command == "after") {
-  string label = next_word(in);
-  recipe tmp = slurp_recipe(in);
-  After_fragments[label].steps.insert(After_fragments[label].steps.begin(), tmp.steps.begin(), tmp.steps.end());
-}
-
-//: after all recipes are loaded, insert fragments at appropriate labels
-
-:(after "int main")
-  Transform.push_back(insert_fragments);
-
-:(code)
-void insert_fragments(const recipe_ordinal r) {
-  // Copy into a new vector because insertions invalidate iterators.
-  // But this way we can't insert into labels created inside before/after.
-  vector<instruction> result;
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    const instruction inst = Recipe[r].steps.at(i);
-    if (!inst.is_label) {
-      result.push_back(inst);
-      continue;
-    }
-    if (Before_fragments.find(inst.label) != Before_fragments.end()) {
-      result.insert(result.end(), Before_fragments[inst.label].steps.begin(), Before_fragments[inst.label].steps.end());
-    }
-    result.push_back(inst);
-    if (After_fragments.find(inst.label) != After_fragments.end()) {
-      result.insert(result.end(), After_fragments[inst.label].steps.begin(), After_fragments[inst.label].steps.end());
-    }
-  }
-//?   for (long long int i = 0; i < SIZE(result); ++i) { //? 1
-//?     cout << result.at(i).to_string() << '\n'; //? 1
-//?   } //? 1
-  Recipe[r].steps.swap(result);
-}
-
-:(scenario tangle_before_and_after)
-recipe main [
-  1:number <- copy 0:literal
-  +label1
-  4:number <- copy 0:literal
-]
-before +label1 [
-  2:number <- copy 0:literal
-]
-after +label1 [
-  3:number <- copy 0:literal
-]
-+mem: storing 0 in location 1
-+mem: storing 0 in location 2
-# label1
-+mem: storing 0 in location 3
-+mem: storing 0 in location 4
-# nothing else
-$mem: 4
-
-:(scenario tangle_keeps_labels_separate)
-recipe main [
-  1:number <- copy 0:literal
-  +label1
-  +label2
-  6:number <- copy 0:literal
-]
-before +label1 [
-  2:number <- copy 0:literal
-]
-after +label1 [
-  3:number <- copy 0:literal
-]
-before +label2 [
-  4:number <- copy 0:literal
-]
-after +label2 [
-  5:number <- copy 0:literal
-]
-+mem: storing 0 in location 1
-+mem: storing 0 in location 2
-# label1
-+mem: storing 0 in location 3
-# 'after' fragments for earlier label always go before 'before' fragments for later label
-+mem: storing 0 in location 4
-# label2
-+mem: storing 0 in location 5
-+mem: storing 0 in location 6
-# nothing else
-$mem: 6
-
-:(scenario tangle_stacks_multiple_fragments)
-recipe main [
-  1:number <- copy 0:literal
-  +label1
-  6:number <- copy 0:literal
-]
-before +label1 [
-  2:number <- copy 0:literal
-]
-after +label1 [
-  3:number <- copy 0:literal
-]
-before +label1 [
-  4:number <- copy 0:literal
-]
-after +label1 [
-  5:number <- copy 0:literal
-]
-+mem: storing 0 in location 1
-# 'before' fragments stack in order
-+mem: storing 0 in location 2
-+mem: storing 0 in location 4
-# label1
-# 'after' fragments stack in reverse order
-+mem: storing 0 in location 5
-+mem: storing 0 in location 3
-+mem: storing 0 in location 6
-# nothing else
-$mem: 6
-
-:(scenario tangle_supports_fragments_with_multiple_instructions)
-recipe main [
-  1:number <- copy 0:literal
-  +label1
-  6:number <- copy 0:literal
-]
-before +label1 [
-  2:number <- copy 0:literal
-  3:number <- copy 0:literal
-]
-after +label1 [
-  4:number <- copy 0:literal
-  5:number <- copy 0:literal
-]
-+mem: storing 0 in location 1
-+mem: storing 0 in location 2
-+mem: storing 0 in location 3
-# label1
-+mem: storing 0 in location 4
-+mem: storing 0 in location 5
-+mem: storing 0 in location 6
-# nothing else
-$mem: 6
-
-:(scenario tangle_tangles_into_all_labels_with_same_name)
-recipe main [
-  1:number <- copy 0:literal
-  +label1
-  +label1
-  4:number <- copy 0:literal
-]
-before +label1 [
-  2:number <- copy 0:literal
-]
-after +label1 [
-  3:number <- copy 0:literal
-]
-+mem: storing 0 in location 1
-+mem: storing 0 in location 2
-# label1
-+mem: storing 0 in location 3
-+mem: storing 0 in location 2
-# label1
-+mem: storing 0 in location 3
-+mem: storing 0 in location 4
-# nothing else
-$mem: 6
-
- - - diff --git a/html/048typecheck.cc.html b/html/048typecheck.cc.html new file mode 100644 index 00000000..aafbd8f5 --- /dev/null +++ b/html/048typecheck.cc.html @@ -0,0 +1,121 @@ + + + + +Mu - 048typecheck.cc + + + + + + + + + + +
+//: Some simple sanity checks for types, and also attempts to guess them where
+//: they aren't provided.
+//:
+//: You still have to provide the full type the first time you mention a
+//: variable in a recipe. You have to explicitly name :offset and :variant
+//: every single time. You can't use the same name with multiple types in a
+//: single recipe.
+
+:(scenario transform_types_warns_on_reusing_name_with_different_type)
+% Hide_warnings = true;
+recipe main [
+  x:number <- copy 1
+  x:boolean <- copy 1
+]
++warn: x used with multiple types in main
+
+:(after "int main")
+  Transform.push_back(transform_types);
+
+:(code)
+void transform_types(const recipe_ordinal r) {
+  map<string, vector<type_ordinal> > metadata;
+  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
+    instruction& inst = Recipe[r].steps.at(i);
+    for (long long int in = 0; in < SIZE(inst.ingredients); ++in) {
+      deduce_missing_type(metadata, inst.ingredients.at(in));
+      check_metadata(metadata, inst.ingredients.at(in), r);
+    }
+    for (long long int out = 0; out < SIZE(inst.products); ++out) {
+      deduce_missing_type(metadata, inst.products.at(out));
+      check_metadata(metadata, inst.products.at(out), r);
+    }
+  }
+}
+
+void check_metadata(map<string, vector<type_ordinal> >& metadata, const reagent& x, const recipe_ordinal r) {
+  if (is_literal(x)) return;
+  if (is_raw(x)) return;
+  // if you use raw locations you're probably doing something unsafe
+  if (is_integer(x.name)) return;
+  if (x.types.empty()) return;  // will throw a more precise warning elsewhere
+  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' << end();
+}
+
+:(scenario transform_types_fills_in_missing_types)
+recipe main [
+  x:number <- copy 1
+  y:number <- add x, 1
+]
+
+:(code)
+void deduce_missing_type(map<string, vector<type_ordinal> >& metadata, reagent& x) {
+  if (!x.types.empty()) return;
+  if (metadata.find(x.name) == metadata.end()) return;
+  copy(metadata[x.name].begin(), metadata[x.name].end(), inserter(x.types, x.types.begin()));
+  assert(x.properties.at(0).second.empty());
+  x.properties.at(0).second.push_back("as-before");
+}
+
+:(scenario transform_types_fills_in_missing_types_in_product)
+recipe main [
+  x:number <- copy 1
+  x <- copy 2
+]
+
+:(scenario transform_types_fills_in_missing_types_in_product_and_ingredient)
+recipe main [
+  x:number <- copy 1
+  x <- add x, 1
+]
++mem: storing 2 in location 1
+
+:(scenario transform_warns_on_missing_types_in_first_mention)
+% Hide_warnings = true;
+recipe main [
+  x <- copy 1
+  x:number <- copy 2
+]
++warn: missing type in 'x <- copy 1'
++warn: x <- copy 1: reagent not initialized: x
++warn: main: size mismatch in storing to x at 'x <- copy 1'
+
+ + + diff --git a/html/049continuation.cc.html b/html/049continuation.cc.html deleted file mode 100644 index 12ac59a9..00000000 --- a/html/049continuation.cc.html +++ /dev/null @@ -1,283 +0,0 @@ - - - - -Mu - 049continuation.cc - - - - - - - - - - -
-//: Continuations are a powerful primitive for constructing advanced kinds of
-//: control *policies* like back-tracking. They're usually provided using a
-//: primitive called 'call-cc': http://en.wikipedia.org/wiki/Call-with-current-continuation)
-//: But in mu 'call-cc' is constructed out of a combination of two primitives:
-//:   'current-continuation', which returns a continuation, and
-//:   'continue-from', which takes a continuation to switch to.
-
-//: todo: implement continuations in mu's memory
-:(before "End Globals")
-map<long long int, call_stack> Continuation;
-long long int Next_continuation_id = 0;
-:(before "End Setup")
-Continuation.clear();
-Next_continuation_id = 0;
-
-:(before "End Mu Types Initialization")
-type_ordinal continuation = Type_ordinal["continuation"] = Next_type_ordinal++;
-Type[continuation].name = "continuation";
-
-:(before "End Primitive Recipe Declarations")
-CURRENT_CONTINUATION,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["current-continuation"] = CURRENT_CONTINUATION;
-:(before "End Primitive Recipe Implementations")
-case CURRENT_CONTINUATION: {
-  // copy the current call stack
-  Continuation[Next_continuation_id] = Current_routine->calls;  // deep copy because calls have no pointers
-  // make sure calling the copy doesn't spawn the same continuation again
-  ++Continuation[Next_continuation_id].front().running_step_index;
-  products.resize(1);
-  products.at(0).push_back(Next_continuation_id);
-  ++Next_continuation_id;
-  trace("current-continuation") << "new continuation " << Next_continuation_id << end();
-  break;
-}
-
-:(before "End Primitive Recipe Declarations")
-CONTINUE_FROM,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["continue-from"] = CONTINUE_FROM;
-:(before "End Primitive Recipe Implementations")
-case CONTINUE_FROM: {
-  if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'continue-from' should be a continuation id generated by 'current-continuation', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
-    break;
-  }
-  long long int c = ingredients.at(0).at(0);
-  Current_routine->calls = Continuation[c];  // deep copy; calls have no pointers
-  continue;  // skip rest of this instruction
-}
-
-:(scenario continuation)
-# simulate a loop using continuations
-recipe main [
-  1:number <- copy 0:literal
-  2:continuation <- current-continuation
-  {
-#?     $print 1:number
-    3:boolean <- greater-or-equal 1:number, 3:literal
-    break-if 3:boolean
-    1:number <- add 1:number, 1:literal
-    continue-from 2:continuation  # loop
-  }
-]
-+mem: storing 1 in location 1
-+mem: storing 2 in location 1
-+mem: storing 3 in location 1
--mem: storing 4 in location 1
-# ensure every iteration doesn't copy the stack over and over
-$current-continuation: 1
-
-:(scenario continuation_inside_caller)
-#? % Trace_stream->dump_layer = "all"; #? 1
-recipe main [
-  1:number <- copy 0:literal
-  2:continuation <- loop-body
-  {
-    3:boolean <- greater-or-equal 1:number, 3:literal
-    break-if 3:boolean
-    continue-from 2:continuation  # loop
-  }
-]
-
-recipe loop-body [
-  4:continuation <- current-continuation
-  1:number <- add 1:number, 1:literal
-]
-+mem: storing 1 in location 1
-+mem: storing 2 in location 1
-+mem: storing 3 in location 1
--mem: storing 4 in location 1
-
-//:: A variant of continuations is the 'delimited' continuation that can be called like any other recipe.
-//:
-//: In mu, this is constructed out of two primitives:
-//:
-//:  * 'create-delimited-continuation' lays down a mark on the call
-//:    stack and calls the provided function (it is sometimes called 'prompt')
-//:  * 'reply-current-continuation' copies the top of the stack until the
-//:    mark, and returns it as the response of create-delimited-continuation
-//:    (which might be a distant ancestor on the call stack; intervening calls
-//:    don't return)
-//:
-//: The resulting slice of the stack can now be called just like a regular
-//: function.
-
-:(scenario delimited_continuation)
-recipe main [
-  1:continuation <- create-delimited-continuation f:recipe 12:literal  # 12 is an argument to f
-  2:number <- copy 5:literal
-  {
-    2:number <- call 1:continuation, 2:number  # 2 is an argument to g, the 'top' of the continuation
-    3:boolean <- greater-or-equal 2:number, 8:literal
-    break-if 3:boolean
-    loop
-  }
-]
-
-recipe f [
-  11:number <- next-ingredient
-  12:number <- g 11:number
-  reply 12:number
-]
-
-recipe g [
-  21:number <- next-ingredient
-  rewind-ingredients
-  reply-delimited-continuation
-  # calls of the continuation start from here
-  22:number <- next-ingredient
-  23:number <- add 22:number, 1:literal
-  reply 23:number
-]
-#? ?
-# first call of 'g' executes the part before reply-delimited-continuation
-+mem: storing 12 in location 21
-+run: 2:number <- copy 5:literal
-+mem: storing 5 in location 2
-# calls of the continuation execute the part after reply-delimited-continuation
-+run: 2:number <- call 1:continuation, 2:number
-+mem: storing 5 in location 22
-+mem: storing 6 in location 2
-+run: 2:number <- call 1:continuation, 2:number
-+mem: storing 6 in location 22
-+mem: storing 7 in location 2
-+run: 2:number <- call 1:continuation, 2:number
-+mem: storing 7 in location 22
-+mem: storing 8 in location 2
-# first call of 'g' does not execute the part after reply-delimited-continuation
--mem: storing 12 in location 22
-# calls of the continuation don't execute the part before reply-delimited-continuation
--mem: storing 5 in location 21
--mem: storing 6 in location 21
--mem: storing 7 in location 21
-# termination
--mem: storing 9 in location 2
-
-//: 'create-delimited-continuation' is like 'call' except it adds a 'reset' mark to
-//: the call stack
-
-:(before "End call Fields")
-bool is_reset;
-:(before "End call Constructor")
-is_reset = false;
-
-//: like call, but mark the current call as a 'reset' call before pushing the next one on it
-
-:(before "End Primitive Recipe Declarations")
-CREATE_DELIMITED_CONTINUATION,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["create-delimited-continuation"] = CREATE_DELIMITED_CONTINUATION;
-:(before "End Primitive Recipe Implementations")
-case CREATE_DELIMITED_CONTINUATION: {
-  Current_routine->calls.front().is_reset = true;
-  Current_routine->calls.push_front(call(Recipe_ordinal[current_instruction().ingredients.at(0).name]));
-  ingredients.erase(ingredients.begin());  // drop the callee
-  goto call_housekeeping;
-}
-
-//: save the slice of current call stack until the 'create-delimited-continuation'
-//: call, and return it as the result.
-//: todo: implement delimited continuations in mu's memory
-:(before "End Globals")
-map<long long int, call_stack> Delimited_continuation;
-long long int Next_delimited_continuation_id = 0;
-:(before "End Setup")
-Delimited_continuation.clear();
-Next_delimited_continuation_id = 0;
-
-:(before "End Primitive Recipe Declarations")
-REPLY_DELIMITED_CONTINUATION,
-:(before "End Primitive Recipe Numbers")
-Recipe_ordinal["reply-delimited-continuation"] = REPLY_DELIMITED_CONTINUATION;
-:(before "End Primitive Recipe Implementations")
-case REPLY_DELIMITED_CONTINUATION: {
-  // first clear any existing ingredients, to isolate the creation of the
-  // continuation from its calls
-  Current_routine->calls.front().ingredient_atoms.clear();
-  Current_routine->calls.front().next_ingredient_to_process = 0;
-  // copy the current call stack until the most recent 'reset' call
-  call_stack::iterator find_reset(call_stack& c);  // manual prototype containing '::'
-  call_stack::iterator reset = find_reset(Current_routine->calls);
-  if (reset == Current_routine->calls.end()) {
-    raise << current_recipe_name() << ": couldn't find a 'reset' call to jump out to\n" << end();
-    break;
-  }
-  Delimited_continuation[Next_delimited_continuation_id] = call_stack(Current_routine->calls.begin(), reset);
-  while (Current_routine->calls.begin() != reset) {
-    --Callstack_depth;
-    Current_routine->calls.pop_front();
-  }
-  // return it as the result of the 'reset' call
-  products.resize(1);
-  products.at(0).push_back(Next_delimited_continuation_id);
-  ++Next_delimited_continuation_id;
-  break;  // continue to process rest of 'reset' call
-}
-
-:(code)
-call_stack::iterator find_reset(call_stack& c) {
-  for (call_stack::iterator p = c.begin(); p != c.end(); ++p)
-    if (p->is_reset) return p;
-  return c.end();
-}
-
-//: overload 'call' for continuations
-:(after "Begin Call")
-  if (!current_instruction().ingredients.at(0).properties.empty()
-      && !current_instruction().ingredients.at(0).properties.at(0).second.empty()
-      && current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "continuation") {
-    // copy multiple calls on to current call stack
-    assert(scalar(ingredients.at(0)));
-    if (Delimited_continuation.find(ingredients.at(0).at(0)) == Delimited_continuation.end()) {
-      raise << current_recipe_name() << ": no such delimited continuation " << current_instruction().ingredients.at(0).original_string << '\n' << end();
-    }
-    const call_stack& new_calls = Delimited_continuation[ingredients.at(0).at(0)];
-    for (call_stack::const_reverse_iterator p = new_calls.rbegin(); p != new_calls.rend(); ++p)
-      Current_routine->calls.push_front(*p);
-    ++current_step_index();  // skip past the reply-delimited-continuation
-    ingredients.erase(ingredients.begin());  // drop the callee
-    goto call_housekeeping;
-  }
-
- - - diff --git a/html/050scenario.cc.html b/html/050scenario.cc.html index c6b6b2fd..dff6c56f 100644 --- a/html/050scenario.cc.html +++ b/html/050scenario.cc.html @@ -13,17 +13,16 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } -.SalientComment { color: #00ffff; } .Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } +.SalientComment { color: #00ffff; } .traceAbsent { color: #c00000; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } +.CommentedCode { color: #6c6c6c; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -45,7 +44,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } :(scenario scenario_block) scenario foo [ run [ - 1:number <- copy 13:literal + 1:number <- copy 13 ] memory-should-contain [ 1 <- 13 @@ -56,13 +55,13 @@ scenario foo [ :(scenario scenario_multiple_blocks) scenario foo [ run [ - 1:number <- copy 13:literal + 1:number <- copy 13 ] memory-should-contain [ 1 <- 13 ] run [ - 2:number <- copy 13:literal + 2:number <- copy 13 ] memory-should-contain [ 1 <- 13 @@ -73,24 +72,24 @@ scenario foo [ :(scenario scenario_check_memory_and_trace) scenario foo [ run [ - 1:number <- copy 13:literal + 1:number <- copy 13 trace [a], [a b c] ] memory-should-contain [ 1 <- 13 ] trace-should-contain [ - a: a b c + a: a b c ] - trace-should-not-contain [ - a: x y z + trace-should-not-contain [ + a: x y z ] ] //:: Core data structure :(before "End Types") -struct scenario { +struct scenario { string name; string to_run; }; @@ -102,7 +101,7 @@ vector<scenario> Scenarios; //: Simply store the text of the scenario. :(before "End Command Handlers") -else if (command == "scenario") { +else if (command == "scenario") { Scenarios.push_back(parse_scenario(in)); } @@ -129,13 +128,13 @@ scenario parse_scenario(istream& in:(scenario read_scenario_with_bracket_in_comment) scenario foo [ # ']' in comment - 1:number <- copy 0:literal + 1:number <- copy 0 ] -+run: 1:number <- copy 0:literal ++run: 1:number <- copy 0 :(scenario read_scenario_with_bracket_in_comment_in_nested_string) scenario foo [ - 1:address:array:character <- new [# not a comment] + 1:address:array:character <- new [# not a comment] ] +run: 1:address:array:character <- new [# not a comment] @@ -143,35 +142,35 @@ scenario foo [ //: Treat the text of the scenario as a regular series of instructions. :(before "End Tests") -time_t mu_time; time(&mu_time); +time_t mu_time; time(&mu_time); cerr << "\nMu tests: " << ctime(&mu_time); -for (long long int i = 0; i < SIZE(Scenarios); ++i) { +for (long long int i = 0; i < SIZE(Scenarios); ++i) { //? cerr << Passed << '\n'; //? 1 //? cerr << i << ": " << Scenarios.at(i).name << '\n'; //? 6 run_mu_scenario(Scenarios.at(i)); - if (Passed) cerr << "."; + if (Passed) cerr << "."; } //: Convenience: run a single named scenario. :(after "Test Runs") -for (long long int i = 0; i < SIZE(Scenarios); ++i) { - if (Scenarios.at(i).name == argv[argc-1]) { +for (long long int i = 0; i < SIZE(Scenarios); ++i) { + if (Scenarios.at(i).name == argv[argc-1]) { run_mu_scenario(Scenarios.at(i)); - if (Passed) cerr << ".\n"; + if (Passed) cerr << ".\n"; return 0; } } :(before "End Globals") -const scenario* Current_scenario = NULL; +const scenario* Current_scenario = NULL; :(code) -void run_mu_scenario(const scenario& s) { +void run_mu_scenario(const scenario& s) { Current_scenario = &s; - bool not_already_inside_test = !Trace_stream; + bool not_already_inside_test = !Trace_stream; //? cerr << s.name << '\n'; //? 12 - if (not_already_inside_test) { + if (not_already_inside_test) { Trace_file = s.name; - Trace_stream = new trace_stream; + Trace_stream = new trace_stream; setup(); } assert(Routines.empty()); @@ -179,12 +178,12 @@ cerr << "\n
(tmp.at(0)); transform_all(); run(tmp.front()); - if (not_already_inside_test && Trace_stream) { + if (not_already_inside_test && Trace_stream) { teardown(); ofstream fout((Trace_dir+Trace_file).c_str()); fout << Trace_stream->readable_contents(""); fout.close(); - delete Trace_stream; + delete Trace_stream; Trace_stream = NULL; Trace_file = ""; } @@ -198,16 +197,16 @@ cerr << "\n% Hide_warnings = true; % Disable_redefine_warnings = true; recipe scenario-foo [ - 1:number <- copy 34:literal + 1:number <- copy 34 ] recipe scenario-foo [ - 1:number <- copy 35:literal + 1:number <- copy 35 ] +warn: redefining recipe scenario-foo :(after "bool warn_on_redefine(const string& recipe_name)") -if (recipe_name.find("scenario-") == 0) return true; +if (recipe_name.find("scenario-") == 0) return true; //:: The special instructions we want to support inside scenarios. //: In a compiler for the mu VM these will require more work. @@ -218,7 +217,7 @@ recipe scenario-foo [ #? % Trace_stream->dump_layer = "all"; recipe main [ run [ - 1:number <- copy 13:literal + 1:number <- copy 13 ] ] +mem: storing 13 in location 1 @@ -228,7 +227,7 @@ RUN, :(before "End Primitive Recipe Numbers") Recipe_ordinal["run"] = RUN; :(before "End Primitive Recipe Implementations") -case RUN: { +case RUN: { //? cout << "recipe " << current_instruction().ingredients.at(0).name << '\n'; //? 1 ostringstream tmp; tmp << "recipe run" << Next_recipe_ordinal << " [ " << current_instruction().ingredients.at(0).name << " ]"; @@ -244,7 +243,7 @@ Recipe_ordinal["run"] = RUN// Some variables for fake resources always get special addresses in // scenarios. :(code) -void bind_special_scenario_names(recipe_ordinal r) { +void bind_special_scenario_names(recipe_ordinal r) { // Special Scenario Variable Names(r) // End Special Scenario Variable Names(r) } @@ -252,10 +251,10 @@ Recipe_ordinal["run"] = RUN:(scenario run_multiple) recipe main [ run [ - 1:number <- copy 13:literal + 1:number <- copy 13 ] run [ - 2:number <- copy 13:literal + 2:number <- copy 13 ] ] +mem: storing 13 in location 1 @@ -265,7 +264,7 @@ recipe main [ //: Also includes some special support for checking strings. :(before "End Globals") -bool Scenario_testing_scenario = false; +bool Scenario_testing_scenario = false; :(before "End Setup") Scenario_testing_scenario = false; @@ -285,44 +284,44 @@ MEMORY_SHOULD_CONTAIN, :(before "End Primitive Recipe Numbers") Recipe_ordinal["memory-should-contain"] = MEMORY_SHOULD_CONTAIN; :(before "End Primitive Recipe Implementations") -case MEMORY_SHOULD_CONTAIN: { - if (!Passed) break; +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; } :(code) -void check_memory(const string& s) { +void check_memory(const string& s) { istringstream in(s); in >> std::noskipws; - set<long long int> locations_checked; - while (true) { + set<long long int> locations_checked; + while (true) { skip_whitespace_and_comments(in); - if (in.eof()) break; + if (in.eof()) break; string lhs = next_word(in); - if (!is_integer(lhs)) { + if (!is_integer(lhs)) { check_type(lhs, in); continue; } - int address = to_integer(lhs); + int address = to_integer(lhs); skip_whitespace_and_comments(in); string _assign; in >> _assign; assert(_assign == "<-"); skip_whitespace_and_comments(in); - int value = 0; in >> value; - if (locations_checked.find(address) != locations_checked.end()) + int value = 0; in >> value; + if (locations_checked.find(address) != locations_checked.end()) raise << "duplicate expectation for location " << address << '\n' << end(); trace(Primitive_recipe_depth, "run") << "checking location " << address << end(); - if (Memory[address] != value) { - if (Current_scenario && !Scenario_testing_scenario) { + if (Memory[address] != value) { + if (Current_scenario && !Scenario_testing_scenario) { // genuine test in a mu file raise << "\nF - " << Current_scenario->name << ": expected location " << address << " to contain " << value << " but saw " << Memory[address] << '\n' << end(); } - else { + else { // just testing scenario support raise << "expected location " << address << " to contain " << value << " but saw " << Memory[address] << '\n' << end(); } - if (!Scenario_testing_scenario) { + if (!Scenario_testing_scenario) { Passed = false; ++Num_failures; } @@ -332,16 +331,16 @@ Recipe_ordinal["memory-should-contain"] } } -void check_type(const string& lhs, istream& in) { +void check_type(const string& lhs, istream& in) { reagent x(lhs); - if (x.properties.at(0).second.at(0) == "string") { + if (x.properties.at(0).second.at(0) == "string") { x.set_value(to_integer(x.name)); skip_whitespace_and_comments(in); string _assign = next_word(in); assert(_assign == "<-"); skip_whitespace_and_comments(in); string literal = next_word(in); - long long int address = x.value; + long long int address = x.value; // exclude quoting brackets assert(*literal.begin() == '['); literal.erase(literal.begin()); assert(*--literal.end() == ']'); literal.erase(--literal.end()); @@ -351,32 +350,32 @@ Recipe_ordinal["memory-should-contain"] raise << "don't know how to check memory for " << lhs << '\n' << end(); } -void check_string(long long int address, const string& literal) { +void check_string(long long int address, const string& literal) { trace(Primitive_recipe_depth, "run") << "checking string length at " << address << end(); - if (Memory[address] != SIZE(literal)) { - if (Current_scenario && !Scenario_testing_scenario) + if (Memory[address] != SIZE(literal)) { + if (Current_scenario && !Scenario_testing_scenario) raise << "\nF - " << Current_scenario->name << ": expected location " << address << " to contain length " << SIZE(literal) << " of string [" << literal << "] but saw " << Memory[address] << '\n' << end(); - else + else raise << "expected location " << address << " to contain length " << SIZE(literal) << " of string [" << literal << "] but saw " << Memory[address] << '\n' << end(); - if (!Scenario_testing_scenario) { + if (!Scenario_testing_scenario) { Passed = false; ++Num_failures; } return; } ++address; // now skip length - for (long long int i = 0; i < SIZE(literal); ++i) { + for (long long int i = 0; i < SIZE(literal); ++i) { trace(Primitive_recipe_depth, "run") << "checking location " << address+i << end(); - if (Memory[address+i] != literal.at(i)) { - if (Current_scenario && !Scenario_testing_scenario) { + if (Memory[address+i] != literal.at(i)) { + if (Current_scenario && !Scenario_testing_scenario) { // 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' << end(); } - else { + else { // just testing scenario support raise << "expected location " << (address+i) << " to contain " << literal.at(i) << " but saw " << Memory[address+i] << '\n' << end(); } - if (!Scenario_testing_scenario) { + if (!Scenario_testing_scenario) { Passed = false; ++Num_failures; } @@ -400,10 +399,10 @@ recipe main [ % Scenario_testing_scenario = true; % Hide_warnings = true; recipe main [ - 1:number <- copy 3:literal - 2:number <- copy 97:literal # 'a' - 3:number <- copy 98:literal # 'b' - 4:number <- copy 99:literal # 'c' + 1:number <- copy 3 + 2:number <- copy 97 # 'a' + 3:number <- copy 98 # 'b' + 4:number <- copy 99 # 'c' memory-should-contain [ 1:string <- [ab] ] @@ -412,10 +411,10 @@ recipe main [ :(scenario memory_check_string) recipe main [ - 1:number <- copy 3:literal - 2:number <- copy 97:literal # 'a' - 3:number <- copy 98:literal # 'b' - 4:number <- copy 99:literal # 'c' + 1:number <- copy 3 + 2:number <- copy 97 # 'a' + 3:number <- copy 98 # 'b' + 4:number <- copy 99 # 'c' memory-should-contain [ 1:string <- [abc] ] @@ -436,8 +435,8 @@ recipe main [ % Hide_warnings = true; recipe main [ trace-should-contain [ - a: b - a: d + a: b + a: d ] ] +warn: missing [b] in trace layer a @@ -447,8 +446,8 @@ TRACE_SHOULD_CONTAIN, :(before "End Primitive Recipe Numbers") Recipe_ordinal["trace-should-contain"] = TRACE_SHOULD_CONTAIN; :(before "End Primitive Recipe Implementations") -case TRACE_SHOULD_CONTAIN: { - if (!Passed) break; +case TRACE_SHOULD_CONTAIN: { + if (!Passed) break; check_trace(current_instruction().ingredients.at(0).name); break; } @@ -456,19 +455,19 @@ Recipe_ordinal["trace-should-contain"] = :(code) // simplified version of check_trace_contents() that emits warnings rather // than just printing to stderr -bool check_trace(const string& expected) { +bool check_trace(const string& expected) { //? cerr << "AAA " << expected << '\n'; //? 1 Trace_stream->newline(); vector<trace_line> expected_lines = parse_trace(expected); //? cerr << "BBB " << SIZE(expected_lines) << '\n'; //? 1 - if (expected_lines.empty()) return true; - long long int curr_expected_line = 0; - for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { - if (expected_lines.at(curr_expected_line).label != p->label) continue; - if (expected_lines.at(curr_expected_line).contents != trim(p->contents)) continue; + if (expected_lines.empty()) return true; + long long int curr_expected_line = 0; + for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { + if (expected_lines.at(curr_expected_line).label != p->label) continue; + if (expected_lines.at(curr_expected_line).contents != trim(p->contents)) continue; // match ++curr_expected_line; - if (curr_expected_line == SIZE(expected_lines)) { + if (curr_expected_line == SIZE(expected_lines)) { //? cerr << "ZZZ\n"; //? 1 return true; } @@ -480,13 +479,13 @@ Recipe_ordinal["trace-should-contain"] = return false; } -vector<trace_line> parse_trace(const string& expected) { +vector<trace_line> parse_trace(const string& expected) { vector<string> buf = split(expected, "\n"); vector<trace_line> result; - for (long long int i = 0; i < SIZE(buf); ++i) { + for (long long int i = 0; i < SIZE(buf); ++i) { buf.at(i) = trim(buf.at(i)); - if (buf.at(i).empty()) continue; - long long int delim = buf.at(i).find(": "); + if (buf.at(i).empty()) continue; + long long int delim = buf.at(i).find(": "); result.push_back(trace_line(trim(buf.at(i).substr(0, delim)), trim(buf.at(i).substr(delim+2)))); } return result; @@ -500,8 +499,8 @@ recipe main [ trace [a], [b] ] trace-should-contain [ - a: b - a: d + a: b + a: d ] ] +warn: missing [d] in trace layer a @@ -514,7 +513,7 @@ recipe main [ trace [a], [b] ] trace-should-contain [ - a: b + a: b ] ] -warn: missing [b] in trace layer a @@ -531,8 +530,8 @@ recipe main [ run [ trace [a], [b] ] - trace-should-not-contain [ - a: b + trace-should-not-contain [ + a: b ] ] +warn: unexpected [b] in trace layer a @@ -542,8 +541,8 @@ TRACE_SHOULD_NOT_CONTAIN, :(before "End Primitive Recipe Numbers") Recipe_ordinal["trace-should-not-contain"] = TRACE_SHOULD_NOT_CONTAIN; :(before "End Primitive Recipe Implementations") -case TRACE_SHOULD_NOT_CONTAIN: { - if (!Passed) break; +case TRACE_SHOULD_NOT_CONTAIN: { + if (!Passed) break; check_trace_missing(current_instruction().ingredients.at(0).name); break; } @@ -551,11 +550,11 @@ Recipe_ordinal["trace-should-not-contain":(code) // simplified version of check_trace_contents() that emits warnings rather // than just printing to stderr -bool check_trace_missing(const string& in) { +bool check_trace_missing(const string& in) { Trace_stream->newline(); vector<trace_line> lines = parse_trace(in); - for (long long int i = 0; i < SIZE(lines); ++i) { - if (trace_count(lines.at(i).label, lines.at(i).contents) != 0) { + for (long long int i = 0; i < SIZE(lines); ++i) { + if (trace_count(lines.at(i).label, lines.at(i).contents) != 0) { raise << "unexpected [" << lines.at(i).contents << "] in trace layer " << lines.at(i).label << '\n' << end(); Passed = false; return false; @@ -568,8 +567,8 @@ Recipe_ordinal["trace-should-not-contain"% Scenario_testing_scenario = true; % Hide_warnings = true; recipe main [ - trace-should-not-contain [ - a: b + trace-should-not-contain [ + a: b ] ] -warn: unexpected [b] in trace layer a @@ -582,18 +581,23 @@ recipe main [ run [ trace [a], [d] ] - trace-should-not-contain [ - a: b - a: d + trace-should-not-contain [ + a: b + a: d ] ] +warn: unexpected [d] in trace layer a +//: Minor detail: ignore 'system' calls in scenarios, since anything we do +//: with them is by definition impossible to test through mu. +:(after "case _SYSTEM:") + if (Current_scenario) break; + //:: Helpers :(code) // just for the scenarios running scenarios in C++ layers -void run_mu_scenario(const string& form) { +void run_mu_scenario(const string& form) { //? cerr << form << '\n'; //? 1 istringstream in(form); in >> std::noskipws; diff --git a/html/051scenario_test.mu.html b/html/051scenario_test.mu.html index 4a996b81..d02cc41a 100644 --- a/html/051scenario_test.mu.html +++ b/html/051scenario_test.mu.html @@ -32,20 +32,20 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } scenario first_scenario_in_mu [ run [ - 1:number <- add 2:literal, 2:literal + 1:number <- add 2, 2 ] memory-should-contain [ - 1 <- 4 + 1 <- 4 ] ] scenario scenario_with_comment_in_mu [ run [ # comment - 1:number <- add 2:literal, 2:literal + 1:number <- add 2, 2 ] memory-should-contain [ - 1 <- 4 + 1 <- 4 ] ] @@ -53,40 +53,40 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } run [ # comment1 # comment2 - 1:number <- add 2:literal, 2:literal + 1:number <- add 2, 2 ] memory-should-contain [ - 1 <- 4 + 1 <- 4 ] ] scenario check_string_in_memory [ run [ - 1:number <- copy 3:literal - 2:character <- copy 97:literal # 'a' - 3:character <- copy 98:literal # 'b' - 4:character <- copy 99:literal # 'c' + 1:number <- copy 3 + 2:character <- copy 97 # 'a' + 3:character <- copy 98 # 'b' + 4:character <- copy 99 # 'c' ] memory-should-contain [ - 1:string <- [abc] + 1:string <- [abc] ] ] scenario check_trace [ run [ - 1:number <- add 2:literal, 2:literal + 1:number <- add 2, 2 ] trace-should-contain [ - mem: storing 4 in location 1 + mem: storing 4 in location 1 ] ] scenario check_trace_negative [ run [ - 1:number <- add 2:literal, 2:literal + 1:number <- add 2, 2 ] trace-should-not-contain [ - mem: storing 5 in location 1 + mem: storing 5 in location 1 ] ] diff --git a/html/052tangle.cc.html b/html/052tangle.cc.html new file mode 100644 index 00000000..627640eb --- /dev/null +++ b/html/052tangle.cc.html @@ -0,0 +1,235 @@ + + + + +Mu - 052tangle.cc + + + + + + + + + + +
+//: Allow code for recipes to be pulled in from multiple places.
+//:
+//: TODO: switch recipe.steps to a more efficient data structure.
+
+:(scenario tangle_before)
+recipe main [
+  1:number <- copy 0
+  +label1
+  3:number <- copy 0
+]
+
+before +label1 [
+  2:number <- copy 0
+]
++mem: storing 0 in location 1
++mem: storing 0 in location 2
++mem: storing 0 in location 3
+# nothing else
+$mem: 3
+
+//: while loading recipes, load before/after fragments
+
+:(before "End Globals")
+map<string /*label*/, recipe> Before_fragments, After_fragments;
+:(before "End Setup")
+Before_fragments.clear();
+After_fragments.clear();
+
+:(before "End Command Handlers")
+else if (command == "before") {
+  string label = next_word(in);
+  recipe tmp = slurp_recipe(in);
+  Before_fragments[label].steps.insert(Before_fragments[label].steps.end(), tmp.steps.begin(), tmp.steps.end());
+}
+else if (command == "after") {
+  string label = next_word(in);
+  recipe tmp = slurp_recipe(in);
+  After_fragments[label].steps.insert(After_fragments[label].steps.begin(), tmp.steps.begin(), tmp.steps.end());
+}
+
+//: after all recipes are loaded, insert fragments at appropriate labels
+
+:(after "int main")
+  Transform.push_back(insert_fragments);
+
+:(code)
+void insert_fragments(const recipe_ordinal r) {
+  // Copy into a new vector because insertions invalidate iterators.
+  // But this way we can't insert into labels created inside before/after.
+  vector<instruction> result;
+  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
+    const instruction inst = Recipe[r].steps.at(i);
+    if (!inst.is_label) {
+      result.push_back(inst);
+      continue;
+    }
+    if (Before_fragments.find(inst.label) != Before_fragments.end()) {
+      result.insert(result.end(), Before_fragments[inst.label].steps.begin(), Before_fragments[inst.label].steps.end());
+    }
+    result.push_back(inst);
+    if (After_fragments.find(inst.label) != After_fragments.end()) {
+      result.insert(result.end(), After_fragments[inst.label].steps.begin(), After_fragments[inst.label].steps.end());
+    }
+  }
+//?   for (long long int i = 0; i < SIZE(result); ++i) { //? 1
+//?     cout << result.at(i).to_string() << '\n'; //? 1
+//?   } //? 1
+  Recipe[r].steps.swap(result);
+}
+
+:(scenario tangle_before_and_after)
+recipe main [
+  1:number <- copy 0
+  +label1
+  4:number <- copy 0
+]
+before +label1 [
+  2:number <- copy 0
+]
+after +label1 [
+  3:number <- copy 0
+]
++mem: storing 0 in location 1
++mem: storing 0 in location 2
+# label1
++mem: storing 0 in location 3
++mem: storing 0 in location 4
+# nothing else
+$mem: 4
+
+:(scenario tangle_keeps_labels_separate)
+recipe main [
+  1:number <- copy 0
+  +label1
+  +label2
+  6:number <- copy 0
+]
+before +label1 [
+  2:number <- copy 0
+]
+after +label1 [
+  3:number <- copy 0
+]
+before +label2 [
+  4:number <- copy 0
+]
+after +label2 [
+  5:number <- copy 0
+]
++mem: storing 0 in location 1
++mem: storing 0 in location 2
+# label1
++mem: storing 0 in location 3
+# 'after' fragments for earlier label always go before 'before' fragments for later label
++mem: storing 0 in location 4
+# label2
++mem: storing 0 in location 5
++mem: storing 0 in location 6
+# nothing else
+$mem: 6
+
+:(scenario tangle_stacks_multiple_fragments)
+recipe main [
+  1:number <- copy 0
+  +label1
+  6:number <- copy 0
+]
+before +label1 [
+  2:number <- copy 0
+]
+after +label1 [
+  3:number <- copy 0
+]
+before +label1 [
+  4:number <- copy 0
+]
+after +label1 [
+  5:number <- copy 0
+]
++mem: storing 0 in location 1
+# 'before' fragments stack in order
++mem: storing 0 in location 2
++mem: storing 0 in location 4
+# label1
+# 'after' fragments stack in reverse order
++mem: storing 0 in location 5
++mem: storing 0 in location 3
++mem: storing 0 in location 6
+# nothing else
+$mem: 6
+
+:(scenario tangle_supports_fragments_with_multiple_instructions)
+recipe main [
+  1:number <- copy 0
+  +label1
+  6:number <- copy 0
+]
+before +label1 [
+  2:number <- copy 0
+  3:number <- copy 0
+]
+after +label1 [
+  4:number <- copy 0
+  5:number <- copy 0
+]
++mem: storing 0 in location 1
++mem: storing 0 in location 2
++mem: storing 0 in location 3
+# label1
++mem: storing 0 in location 4
++mem: storing 0 in location 5
++mem: storing 0 in location 6
+# nothing else
+$mem: 6
+
+:(scenario tangle_tangles_into_all_labels_with_same_name)
+recipe main [
+  1:number <- copy 0
+  +label1
+  +label1
+  4:number <- copy 0
+]
+before +label1 [
+  2:number <- copy 0
+]
+after +label1 [
+  3:number <- copy 0
+]
++mem: storing 0 in location 1
++mem: storing 0 in location 2
+# label1
++mem: storing 0 in location 3
++mem: storing 0 in location 2
+# label1
++mem: storing 0 in location 3
++mem: storing 0 in location 4
+# nothing else
+$mem: 6
+
+ + + diff --git a/html/053continuation.cc.html b/html/053continuation.cc.html new file mode 100644 index 00000000..1118064c --- /dev/null +++ b/html/053continuation.cc.html @@ -0,0 +1,282 @@ + + + + +Mu - 053continuation.cc + + + + + + + + + + +
+//: Continuations are a powerful primitive for constructing advanced kinds of
+//: control *policies* like back-tracking. They're usually provided using a
+//: primitive called 'call-cc': http://en.wikipedia.org/wiki/Call-with-current-continuation)
+//: But in mu 'call-cc' is constructed out of a combination of two primitives:
+//:   'current-continuation', which returns a continuation, and
+//:   'continue-from', which takes a continuation to switch to.
+
+//: todo: implement continuations in mu's memory
+:(before "End Globals")
+map<long long int, call_stack> Continuation;
+long long int Next_continuation_id = 0;
+:(before "End Setup")
+Continuation.clear();
+Next_continuation_id = 0;
+
+:(before "End Mu Types Initialization")
+type_ordinal continuation = Type_ordinal["continuation"] = Next_type_ordinal++;
+Type[continuation].name = "continuation";
+
+:(before "End Primitive Recipe Declarations")
+CURRENT_CONTINUATION,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["current-continuation"] = CURRENT_CONTINUATION;
+:(before "End Primitive Recipe Implementations")
+case CURRENT_CONTINUATION: {
+  // copy the current call stack
+  Continuation[Next_continuation_id] = Current_routine->calls;  // deep copy because calls have no pointers
+  // make sure calling the copy doesn't spawn the same continuation again
+  ++Continuation[Next_continuation_id].front().running_step_index;
+  products.resize(1);
+  products.at(0).push_back(Next_continuation_id);
+  ++Next_continuation_id;
+  trace("current-continuation") << "new continuation " << Next_continuation_id << end();
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+CONTINUE_FROM,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["continue-from"] = CONTINUE_FROM;
+:(before "End Primitive Recipe Implementations")
+case CONTINUE_FROM: {
+  if (!scalar(ingredients.at(0))) {
+    raise << current_recipe_name() << ": first ingredient of 'continue-from' should be a continuation id generated by 'current-continuation', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    break;
+  }
+  long long int c = ingredients.at(0).at(0);
+  Current_routine->calls = Continuation[c];  // deep copy; calls have no pointers
+  continue;  // skip rest of this instruction
+}
+
+:(scenario continuation)
+# simulate a loop using continuations
+recipe main [
+  1:number <- copy 0
+  2:continuation <- current-continuation
+  {
+#?     $print 1:number
+    3:boolean <- greater-or-equal 1:number, 3
+    break-if 3:boolean
+    1:number <- add 1:number, 1
+    continue-from 2:continuation  # loop
+  }
+]
++mem: storing 1 in location 1
++mem: storing 2 in location 1
++mem: storing 3 in location 1
+-mem: storing 4 in location 1
+# ensure every iteration doesn't copy the stack over and over
+$current-continuation: 1
+
+:(scenario continuation_inside_caller)
+#? % Trace_stream->dump_layer = "all"; #? 1
+recipe main [
+  1:number <- copy 0
+  2:continuation <- loop-body
+  {
+    3:boolean <- greater-or-equal 1:number, 3
+    break-if 3:boolean
+    continue-from 2:continuation  # loop
+  }
+]
+
+recipe loop-body [
+  4:continuation <- current-continuation
+  1:number <- add 1:number, 1
+]
++mem: storing 1 in location 1
++mem: storing 2 in location 1
++mem: storing 3 in location 1
+-mem: storing 4 in location 1
+
+//:: A variant of continuations is the 'delimited' continuation that can be called like any other recipe.
+//:
+//: In mu, this is constructed out of two primitives:
+//:
+//:  * 'create-delimited-continuation' lays down a mark on the call
+//:    stack and calls the provided function (it is sometimes called 'prompt')
+//:  * 'reply-current-continuation' copies the top of the stack until the
+//:    mark, and returns it as the response of create-delimited-continuation
+//:    (which might be a distant ancestor on the call stack; intervening calls
+//:    don't return)
+//:
+//: The resulting slice of the stack can now be called just like a regular
+//: function.
+
+:(scenario delimited_continuation)
+recipe main [
+  1:continuation <- create-delimited-continuation f:recipe 12  # 12 is an argument to f
+  2:number <- copy 5
+  {
+    2:number <- call 1:continuation, 2:number  # 2 is an argument to g, the 'top' of the continuation
+    3:boolean <- greater-or-equal 2:number, 8
+    break-if 3:boolean
+    loop
+  }
+]
+
+recipe f [
+  11:number <- next-ingredient
+  12:number <- g 11:number
+  reply 12:number
+]
+
+recipe g [
+  21:number <- next-ingredient
+  rewind-ingredients
+  reply-delimited-continuation
+  # calls of the continuation start from here
+  22:number <- next-ingredient
+  23:number <- add 22:number, 1
+  reply 23:number
+]
+#? ?
+# first call of 'g' executes the part before reply-delimited-continuation
++mem: storing 12 in location 21
++run: 2:number <- copy 5
++mem: storing 5 in location 2
+# calls of the continuation execute the part after reply-delimited-continuation
++run: 2:number <- call 1:continuation, 2:number
++mem: storing 5 in location 22
++mem: storing 6 in location 2
++run: 2:number <- call 1:continuation, 2:number
++mem: storing 6 in location 22
++mem: storing 7 in location 2
++run: 2:number <- call 1:continuation, 2:number
++mem: storing 7 in location 22
++mem: storing 8 in location 2
+# first call of 'g' does not execute the part after reply-delimited-continuation
+-mem: storing 12 in location 22
+# calls of the continuation don't execute the part before reply-delimited-continuation
+-mem: storing 5 in location 21
+-mem: storing 6 in location 21
+-mem: storing 7 in location 21
+# termination
+-mem: storing 9 in location 2
+
+//: 'create-delimited-continuation' is like 'call' except it adds a 'reset' mark to
+//: the call stack
+
+:(before "End call Fields")
+bool is_reset;
+:(before "End call Constructor")
+is_reset = false;
+
+//: like call, but mark the current call as a 'reset' call before pushing the next one on it
+
+:(before "End Primitive Recipe Declarations")
+CREATE_DELIMITED_CONTINUATION,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["create-delimited-continuation"] = CREATE_DELIMITED_CONTINUATION;
+:(before "End Primitive Recipe Implementations")
+case CREATE_DELIMITED_CONTINUATION: {
+  Current_routine->calls.front().is_reset = true;
+  Current_routine->calls.push_front(call(Recipe_ordinal[current_instruction().ingredients.at(0).name]));
+  ingredients.erase(ingredients.begin());  // drop the callee
+  goto call_housekeeping;
+}
+
+//: save the slice of current call stack until the 'create-delimited-continuation'
+//: call, and return it as the result.
+//: todo: implement delimited continuations in mu's memory
+:(before "End Globals")
+map<long long int, call_stack> Delimited_continuation;
+long long int Next_delimited_continuation_id = 0;
+:(before "End Setup")
+Delimited_continuation.clear();
+Next_delimited_continuation_id = 0;
+
+:(before "End Primitive Recipe Declarations")
+REPLY_DELIMITED_CONTINUATION,
+:(before "End Primitive Recipe Numbers")
+Recipe_ordinal["reply-delimited-continuation"] = REPLY_DELIMITED_CONTINUATION;
+:(before "End Primitive Recipe Implementations")
+case REPLY_DELIMITED_CONTINUATION: {
+  // first clear any existing ingredients, to isolate the creation of the
+  // continuation from its calls
+  Current_routine->calls.front().ingredient_atoms.clear();
+  Current_routine->calls.front().next_ingredient_to_process = 0;
+  // copy the current call stack until the most recent 'reset' call
+  call_stack::iterator find_reset(call_stack& c);  // manual prototype containing '::'
+  call_stack::iterator reset = find_reset(Current_routine->calls);
+  if (reset == Current_routine->calls.end()) {
+    raise << current_recipe_name() << ": couldn't find a 'reset' call to jump out to\n" << end();
+    break;
+  }
+  Delimited_continuation[Next_delimited_continuation_id] = call_stack(Current_routine->calls.begin(), reset);
+  while (Current_routine->calls.begin() != reset) {
+    --Callstack_depth;
+    Current_routine->calls.pop_front();
+  }
+  // return it as the result of the 'reset' call
+  products.resize(1);
+  products.at(0).push_back(Next_delimited_continuation_id);
+  ++Next_delimited_continuation_id;
+  break;  // continue to process rest of 'reset' call
+}
+
+:(code)
+call_stack::iterator find_reset(call_stack& c) {
+  for (call_stack::iterator p = c.begin(); p != c.end(); ++p)
+    if (p->is_reset) return p;
+  return c.end();
+}
+
+//: overload 'call' for continuations
+:(after "Begin Call")
+  if (!current_instruction().ingredients.at(0).properties.empty()
+      && !current_instruction().ingredients.at(0).properties.at(0).second.empty()
+      && current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "continuation") {
+    // copy multiple calls on to current call stack
+    assert(scalar(ingredients.at(0)));
+    if (Delimited_continuation.find(ingredients.at(0).at(0)) == Delimited_continuation.end()) {
+      raise << current_recipe_name() << ": no such delimited continuation " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    }
+    const call_stack& new_calls = Delimited_continuation[ingredients.at(0).at(0)];
+    for (call_stack::const_reverse_iterator p = new_calls.rbegin(); p != new_calls.rend(); ++p)
+      Current_routine->calls.push_front(*p);
+    ++current_step_index();  // skip past the reply-delimited-continuation
+    ingredients.erase(ingredients.begin());  // drop the callee
+    goto call_housekeeping;
+  }
+
+ + + diff --git a/html/060string.mu.html b/html/060string.mu.html index 595a96b0..9b30c7fa 100644 --- a/html/060string.mu.html +++ b/html/060string.mu.html @@ -13,14 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } -.muScenario { color: #00af00; } +.muRecipe { color: #ff8700; } .Delimiter { color: #a04060; } -.CommentedCode { color: #6c6c6c; } +.muScenario { color: #00af00; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } +.CommentedCode { color: #6c6c6c; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -37,67 +37,67 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } recipe string-equal [ local-scope a:address:array:character <- next-ingredient - a-len:number <- length a:address:array:character/deref + a-len:number <- length *a b:address:array:character <- next-ingredient - b-len:number <- length b:address:array:character/deref + b-len:number <- length *b # compare lengths { trace [string-equal], [comparing lengths] - length-equal?:boolean <- equal a-len:number, b-len:number - break-if length-equal?:boolean - reply 0:literal + length-equal?:boolean <- equal a-len, b-len + break-if length-equal? + reply 0 } # compare each corresponding character trace [string-equal], [comparing characters] - i:number <- copy 0:literal + i:number <- copy 0 { - done?:boolean <- greater-or-equal i:number, a-len:number - break-if done?:boolean - a2:character <- index a:address:array:character/deref, i:number - b2:character <- index b:address:array:character/deref, i:number + done?:boolean <- greater-or-equal i, a-len + break-if done? + a2:character <- index *a, i + b2:character <- index *b, i { - chars-match?:boolean <- equal a2:character, b2:character - break-if chars-match?:boolean - reply 0:literal + chars-match?:boolean <- equal a2, b2 + break-if chars-match? + reply 0 } - i:number <- add i:number, 1:literal + i <- add i, 1 loop } - reply 1:literal + reply 1 ] scenario string-equal-reflexive [ run [ - default-space:address:array:location <- new location:type, 30:literal + default-space:address:array:location <- new location:type, 30 x:address:array:character <- new [abc] - 3:boolean/raw <- string-equal x:address:array:character, x:address:array:character + 3:boolean/raw <- string-equal x, x ] memory-should-contain [ - 3 <- 1 # x == x for all x + 3 <- 1 # x == x for all x ] ] scenario string-equal-identical [ run [ - default-space:address:array:location <- new location:type, 30:literal + default-space:address:array:location <- new location:type, 30 x:address:array:character <- new [abc] y:address:array:character <- new [abc] - 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character + 3:boolean/raw <- string-equal x, y ] memory-should-contain [ - 3 <- 1 # abc == abc + 3 <- 1 # abc == abc ] ] scenario string-equal-distinct-lengths [ run [ - default-space:address:array:location <- new location:type, 30:literal + default-space:address:array:location <- new location:type, 30 x:address:array:character <- new [abc] y:address:array:character <- new [abcd] - 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character + 3:boolean/raw <- string-equal x, y ] memory-should-contain [ - 3 <- 0 # abc != abcd + 3 <- 0 # abc != abcd ] trace-should-contain [ string-equal: comparing lengths @@ -109,25 +109,25 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } scenario string-equal-with-empty [ run [ - default-space:address:array:location <- new location:type, 30:literal + default-space:address:array:location <- new location:type, 30 x:address:array:character <- new [] y:address:array:character <- new [abcd] - 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character + 3:boolean/raw <- string-equal x, y ] memory-should-contain [ - 3 <- 0 # "" != abcd + 3 <- 0 # "" != abcd ] ] scenario string-equal-common-lengths-but-distinct [ run [ - default-space:address:array:location <- new location:type, 30:literal + default-space:address:array:location <- new location:type, 30 x:address:array:character <- new [abc] y:address:array:character <- new [abd] - 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character + 3:boolean/raw <- string-equal x, y ] memory-should-contain [ - 3 <- 0 # abc != abd + 3 <- 0 # abc != abd ] ] @@ -139,49 +139,49 @@ container buffer [ recipe new-buffer [ local-scope -#? $print default-space:address:array:location, 10:literal/newline +#? $print default-space:address:array:location, 10/newline result:address:buffer <- new buffer:type - len:address:number <- get-address result:address:buffer/deref, length:offset - len:address:number/deref <- copy 0:literal - s:address:address:array:character <- get-address result:address:buffer/deref, data:offset + len:address:number <- get-address *result, length:offset + *len:address:number <- copy 0 + s:address:address:array:character <- get-address *result, data:offset capacity:number, found?:boolean <- next-ingredient - assert found?:boolean, [new-buffer must get a capacity argument] - s:address:address:array:character/deref <- new character:type, capacity:number -#? $print s:address:address:array:character/deref, 10:literal/newline - reply result:address:buffer + assert found?, [new-buffer must get a capacity argument] + *s <- new character:type, capacity +#? $print *s, 10/newline + reply result ] recipe grow-buffer [ local-scope in:address:buffer <- next-ingredient # double buffer size - x:address:address:array:character <- get-address in:address:buffer/deref, data:offset - oldlen:number <- length x:address:address:array:character/deref/deref - newlen:number <- multiply oldlen:number, 2:literal - olddata:address:array:character <- copy x:address:address:array:character/deref - x:address:address:array:character/deref <- new character:type, newlen:number + x:address:address:array:character <- get-address *in, data:offset + oldlen:number <- length **x + newlen:number <- multiply oldlen, 2 + olddata:address:array:character <- copy *x + *x <- new character:type, newlen # copy old contents - i:number <- copy 0:literal + i:number <- copy 0 { - done?:boolean <- greater-or-equal i:number, oldlen:number - break-if done?:boolean - src:character <- index olddata:address:array:character/deref, i:number - dest:address:character <- index-address x:address:address:array:character/deref/deref, i:number - dest:address:character/deref <- copy src:character - i:number <- add i:number, 1:literal + done?:boolean <- greater-or-equal i, oldlen + break-if done? + src:character <- index *olddata, i + dest:address:character <- index-address **x, i + *dest <- copy src + i <- add i, 1 loop } - reply in:address:buffer + reply in ] recipe buffer-full? [ local-scope in:address:buffer <- next-ingredient - len:number <- get in:address:buffer/deref, length:offset - s:address:array:character <- get in:address:buffer/deref, data:offset - capacity:number <- length s:address:array:character/deref - result:boolean <- greater-or-equal len:number, capacity:number - reply result:boolean + len:number <- get *in, length:offset + s:address:array:character <- get *in, data:offset + capacity:number <- length *s + result:boolean <- greater-or-equal len, capacity + reply result ] # in:address:buffer <- buffer-append in:address:buffer, c:character @@ -189,84 +189,84 @@ container buffer [ local-scope in:address:buffer <- next-ingredient c:character <- next-ingredient - len:address:number <- get-address in:address:buffer/deref, length:offset + len:address:number <- get-address *in, length:offset { # backspace? just drop last character if it exists and return - backspace?:boolean <- equal c:character, 8:literal/backspace - break-unless backspace?:boolean - empty?:boolean <- lesser-or-equal len:address:number/deref, 0:literal - reply-if empty?:boolean, in:address:buffer/same-as-ingredient:0 - len:address:number/deref <- subtract len:address:number/deref, 1:literal - reply in:address:buffer/same-as-ingredient:0 + backspace?:boolean <- equal c, 8/backspace + break-unless backspace? + empty?:boolean <- lesser-or-equal *len, 0 + reply-if empty?, in/same-as-ingredient:0 + *len <- subtract *len, 1 + reply in/same-as-ingredient:0 } { # grow buffer if necessary - full?:boolean <- buffer-full? in:address:buffer - break-unless full?:boolean - in:address:buffer <- grow-buffer in:address:buffer + full?:boolean <- buffer-full? in + break-unless full? + in <- grow-buffer in } - s:address:array:character <- get in:address:buffer/deref, data:offset -#? $print [array underlying buf: ], s:address:array:character, 10:literal/newline -#? $print [index: ], len:address:number/deref, 10:literal/newline - dest:address:character <- index-address s:address:array:character/deref, len:address:number/deref -#? $print [storing ], c:character, [ in ], dest:address:character, 10:literal/newline - dest:address:character/deref <- copy c:character - len:address:number/deref <- add len:address:number/deref, 1:literal - reply in:address:buffer/same-as-ingredient:0 + s:address:array:character <- get *in, data:offset +#? $print [array underlying buf: ], s, 10/newline +#? $print [index: ], *len, 10/newline + dest:address:character <- index-address *s, *len +#? $print [storing ], c, [ in ], dest, 10/newline + *dest <- copy c + *len <- add *len, 1 + reply in/same-as-ingredient:0 ] scenario buffer-append-works [ run [ local-scope - x:address:buffer <- new-buffer 3:literal - s1:address:array:character <- get x:address:buffer/deref, data:offset - x:address:buffer <- buffer-append x:address:buffer, 97:literal # 'a' - x:address:buffer <- buffer-append x:address:buffer, 98:literal # 'b' - x:address:buffer <- buffer-append x:address:buffer, 99:literal # 'c' - s2:address:array:character <- get x:address:buffer/deref, data:offset - 1:boolean/raw <- equal s1:address:array:character, s2:address:array:character - 2:array:character/raw <- copy s2:address:array:character/deref + x:address:buffer <- new-buffer 3 + s1:address:array:character <- get *x:address:buffer, data:offset + x:address:buffer <- buffer-append x:address:buffer, 97 # 'a' + x:address:buffer <- buffer-append x:address:buffer, 98 # 'b' + x:address:buffer <- buffer-append x:address:buffer, 99 # 'c' + s2:address:array:character <- get *x:address:buffer, data:offset + 1:boolean/raw <- equal s1:address:array:character, s2:address:array:character + 2:array:character/raw <- copy *s2:address:array:character +buffer-filled - x:address:buffer <- buffer-append x:address:buffer, 100:literal # 'd' - s3:address:array:character <- get x:address:buffer/deref, data:offset - 10:boolean/raw <- equal s1:address:array:character, s3:address:array:character - 11:number/raw <- get x:address:buffer/deref, length:offset - 12:array:character/raw <- copy s3:address:array:character/deref + x:address:buffer <- buffer-append x:address:buffer, 100 # 'd' + s3:address:array:character <- get *x:address:buffer, data:offset + 10:boolean/raw <- equal s1:address:array:character, s3:address:array:character + 11:number/raw <- get *x:address:buffer, length:offset + 12:array:character/raw <- copy *s3:address:array:character ] memory-should-contain [ # before +buffer-filled - 1 <- 1 # no change in data pointer - 2 <- 3 # size of data - 3 <- 97 # data - 4 <- 98 - 5 <- 99 + 1 <- 1 # no change in data pointer + 2 <- 3 # size of data + 3 <- 97 # data + 4 <- 98 + 5 <- 99 # in the end - 10 <- 0 # data pointer has grown - 11 <- 4 # final length - 12 <- 6 # but data's capacity has doubled - 13 <- 97 # data - 14 <- 98 - 15 <- 99 - 16 <- 100 - 17 <- 0 - 18 <- 0 + 10 <- 0 # data pointer has grown + 11 <- 4 # final length + 12 <- 6 # but data's capacity has doubled + 13 <- 97 # data + 14 <- 98 + 15 <- 99 + 16 <- 100 + 17 <- 0 + 18 <- 0 ] ] scenario buffer-append-handles-backspace [ run [ local-scope - x:address:buffer <- new-buffer 3:literal - x:address:buffer <- buffer-append x:address:buffer, 97:literal # 'a' - x:address:buffer <- buffer-append x:address:buffer, 98:literal # 'b' - x:address:buffer <- buffer-append x:address:buffer, 8:literal/backspace + x:address:buffer <- new-buffer 3 + x:address:buffer <- buffer-append x:address:buffer, 97 # 'a' + x:address:buffer <- buffer-append x:address:buffer, 98 # 'b' + x:address:buffer <- buffer-append x:address:buffer, 8/backspace s:address:array:character <- buffer-to-array x:address:buffer - 1:array:character/raw <- copy s:address:array:character/deref + 1:array:character/raw <- copy *s:address:array:character ] memory-should-contain [ - 1 <- 1 # length - 2 <- 97 # contents - 3 <- 0 + 1 <- 1 # length + 2 <- 97 # contents + 3 <- 0 ] ] @@ -276,55 +276,53 @@ container buffer [ n:number <- next-ingredient # is it zero? { - break-if n:number + break-if n result:address:array:character <- new [0] - reply result:address:array:character + reply result } # save sign - negate-result:boolean <- copy 0:literal + negate-result:boolean <- copy 0 { - negative?:boolean <- lesser-than n:number, 0:literal - break-unless negative?:boolean - negate-result:boolean <- copy 1:literal - n:number <- multiply n:number, -1:literal + negative?:boolean <- lesser-than n, 0 + break-unless negative? + negate-result <- copy 1 + n <- multiply n, -1 } # add digits from right to left into intermediate buffer - tmp:address:buffer <- new-buffer 30:literal - digit-base:number <- copy 48:literal # '0' + tmp:address:buffer <- new-buffer 30 + digit-base:number <- copy 48 # '0' { - done?:boolean <- equal n:number, 0:literal - break-if done?:boolean - n:number, digit:number <- divide-with-remainder n:number, 10:literal - c:character <- add digit-base:number, digit:number - tmp:address:buffer <- buffer-append tmp:address:buffer, c:character + done?:boolean <- equal n, 0 + break-if done? + n, digit:number <- divide-with-remainder n, 10 + c:character <- add digit-base, digit + tmp:address:buffer <- buffer-append tmp, c loop } # add sign { break-unless negate-result:boolean - tmp:address:buffer <- buffer-append tmp:address:buffer, 45:literal # '-' + tmp <- buffer-append tmp, 45 # '-' } # reverse buffer into string result - len:number <- get tmp:address:buffer/deref, length:offset - buf:address:array:character <- get tmp:address:buffer/deref, data:offset - result:address:array:character <- new character:type, len:number - i:number <- subtract len:number, 1:literal - j:number <- copy 0:literal + len:number <- get *tmp, length:offset + buf:address:array:character <- get *tmp, data:offset + result:address:array:character <- new character:type, len + i:number <- subtract len, 1 # source index, decreasing + j:number <- copy 0 # destination index, increasing { # while i >= 0 - done?:boolean <- lesser-than i:number, 0:literal - break-if done?:boolean + done?:boolean <- lesser-than i, 0 + break-if done? # result[j] = tmp[i] - src:character <- index buf:address:array:character/deref, i:number - dest:address:character <- index-address result:address:array:character/deref, j:number - dest:address:character/deref <- copy src:character - # ++i - i:number <- subtract i:number, 1:literal - # --j - j:number <- add j:number, 1:literal + src:character <- index *buf, i + dest:address:character <- index-address *result, j + *dest <- copy src + i <- subtract i, 1 + j <- add j, 1 loop } - reply result:address:array:character + reply result ] recipe buffer-to-array [ @@ -332,57 +330,57 @@ container buffer [ in:address:buffer <- next-ingredient { # propagate null buffer - break-if in:address:buffer - reply 0:literal + break-if in + reply 0 } - len:number <- get in:address:buffer/deref, length:offset -#? $print [size ], len:number, 10:literal/newline - s:address:array:character <- get in:address:buffer/deref, data:offset + len:number <- get *in, length:offset +#? $print [size ], len, 10/newline + s:address:array:character <- get *in, data:offset # 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 + result:address:array:character <- new character:type, len + i:number <- copy 0 { -#? $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 +#? $print i #? 1 + done?:boolean <- greater-or-equal i, len + break-if done? + src:character <- index *s, i + dest:address:character <- index-address *result, i + *dest <- copy src + i <- add i, 1 loop } - reply result:address:array:character + reply result ] scenario integer-to-decimal-digit-zero [ run [ - 1:address:array:character/raw <- integer-to-decimal-string 0:literal - 2:array:character/raw <- copy 1:address:array:character/deref/raw + 1:address:array:character/raw <- integer-to-decimal-string 0 + 2:array:character/raw <- copy *1:address:array:character/raw ] memory-should-contain [ - 2:string <- [0] + 2:string <- [0] ] ] scenario integer-to-decimal-digit-positive [ run [ - 1:address:array:character/raw <- integer-to-decimal-string 234:literal - 2:array:character/raw <- copy 1:address:array:character/deref/raw + 1:address:array:character/raw <- integer-to-decimal-string 234 + 2:array:character/raw <- copy *1:address:array:character/raw ] memory-should-contain [ - 2:string <- [234] + 2:string <- [234] ] ] scenario integer-to-decimal-digit-negative [ run [ - 1:address:array:character/raw <- integer-to-decimal-string -1:literal - 2:array:character/raw <- copy 1:address:array:character/deref/raw + 1:address:array:character/raw <- integer-to-decimal-string -1 + 2:array:character/raw <- copy *1:address:array:character/raw ] memory-should-contain [ - 2 <- 2 - 3 <- 45 # '-' - 4 <- 49 # '1' + 2 <- 2 + 3 <- 45 # '-' + 4 <- 49 # '1' ] ] @@ -391,56 +389,52 @@ container buffer [ local-scope # result = new character[a.length + b.length] a:address:array:character <- next-ingredient - a-len:number <- length a:address:array:character/deref + a-len:number <- length *a b:address:array:character <- next-ingredient - b-len:number <- length b:address:array:character/deref - result-len:number <- add a-len:number, b-len:number - result:address:array:character <- new character:type, result-len:number + b-len:number <- length *b + result-len:number <- add a-len, b-len + result:address:array:character <- new character:type, result-len # copy a into result - result-idx:number <- copy 0:literal - i:number <- copy 0:literal + result-idx:number <- copy 0 + i:number <- copy 0 { # while i < a.length - a-done?:boolean <- greater-or-equal i:number, a-len:number - break-if a-done?:boolean + a-done?:boolean <- greater-or-equal i, a-len + break-if a-done? # result[result-idx] = a[i] - out:address:character <- index-address result:address:array:character/deref, result-idx:number - in:character <- index a:address:array:character/deref, i:number - out:address:character/deref <- copy in:character - # ++i - i:number <- add i:number, 1:literal - # ++result-idx - result-idx:number <- add result-idx:number, 1:literal + out:address:character <- index-address *result, result-idx + in:character <- index *a, i + *out <- copy in + i <- add i, 1 + result-idx <- add result-idx, 1 loop } # copy b into result - i:number <- copy 0:literal + i <- copy 0 { # while i < b.length - b-done?:boolean <- greater-or-equal i:number, b-len:number - break-if b-done?:boolean + b-done?:boolean <- greater-or-equal i, b-len + break-if b-done? # result[result-idx] = a[i] - out:address:character <- index-address result:address:array:character/deref, result-idx:number - in:character <- index b:address:array:character/deref, i:number - out:address:character/deref <- copy in:character - # ++i - i:number <- add i:number, 1:literal - # ++result-idx - result-idx:number <- add result-idx:number, 1:literal + out:address:character <- index-address *result, result-idx + in:character <- index *b, i + *out <- copy in + i <- add i, 1 + result-idx <- add result-idx, 1 loop } - reply result:address:array:character + reply result ] scenario string-append-1 [ run [ - 1:address:array:character/raw <- new [hello,] - 2:address:array:character/raw <- new [ world!] - 3:address:array:character/raw <- string-append 1:address:array:character/raw, 2:address:array:character/raw - 4:array:character/raw <- copy 3:address:array:character/raw/deref + 1:address:array:character/raw <- new [hello,] + 2:address:array:character/raw <- new [ world!] + 3:address:array:character/raw <- string-append 1:address:array:character/raw, 2:address:array:character/raw + 4:array:character/raw <- copy *3:address:array:character/raw ] memory-should-contain [ - 4:string <- [hello, world!] + 4:string <- [hello, world!] ] ] @@ -450,122 +444,115 @@ container buffer [ local-scope template:address:array:character <- next-ingredient # compute result-len, space to allocate for result - tem-len:number <- length template:address:array:character/deref - result-len:number <- copy tem-len:number + tem-len:number <- length *template + result-len:number <- copy tem-len { # while arg received a:address:array:character, arg-received?:boolean <- next-ingredient - break-unless arg-received?:boolean - # result-len = result-len + arg.length - 1 for the 'underscore' being replaced - a-len:number <- length a:address:array:character/deref - result-len:number <- add result-len:number, a-len:number - result-len:number <- subtract result-len:number, 1:literal + break-unless arg-received? + # result-len = result-len + arg.length - 1 (for the 'underscore' being replaced) + a-len:number <- length *a + result-len <- add result-len, a-len + result-len <- subtract result-len, 1 loop } -#? $print tem-len:number, [ ], $result-len:number, 10:literal/newline +#? $print tem-len, [ ], $result-len, 10/newline rewind-ingredients _ <- next-ingredient # skip template - # result = new array:character[result-len] - result:address:array:character <- new character:type, result-len:number + result:address:array:character <- new character:type, result-len # repeatedly copy sections of template and 'holes' into result - result-idx:number <- copy 0:literal - i:number <- copy 0:literal + result-idx:number <- copy 0 + i:number <- copy 0 { # while arg received a:address:array:character, arg-received?:boolean <- next-ingredient - break-unless arg-received?:boolean + break-unless arg-received? # copy template into result until '_' { # while i < template.length - tem-done?:boolean <- greater-or-equal i:number, tem-len:number - break-if tem-done?:boolean, +done:label + tem-done?:boolean <- greater-or-equal i, tem-len + break-if tem-done?, +done:label # while template[i] != '_' - in:character <- index template:address:array:character/deref, i:number - underscore?:boolean <- equal in:character, 95:literal # '_' - break-if underscore?:boolean + in:character <- index *template, i + underscore?:boolean <- equal in, 95/_ + break-if underscore? # result[result-idx] = template[i] - out:address:character <- index-address result:address:array:character/deref, result-idx:number - out:address:character/deref <- copy in:character - # ++i - i:number <- add i:number, 1:literal - # ++result-idx - result-idx:number <- add result-idx:number, 1:literal + out:address:character <- index-address *result, result-idx + *out <- copy in + i <- add i, 1 + result-idx <- add result-idx, 1 loop } # copy 'a' into result - j:number <- copy 0:literal + j:number <- copy 0 { # while j < a.length - arg-done?:boolean <- greater-or-equal j:number, a-len:number - break-if arg-done?:boolean + arg-done?:boolean <- greater-or-equal j, a-len + break-if arg-done? # result[result-idx] = a[j] - in:character <- index a:address:array:character/deref, j:number - out:address:character <- index-address result:address:array:character/deref, result-idx:number - out:address:character/deref <- copy in:character - # ++j - j:number <- add j:number, 1:literal - # ++result-idx - result-idx:number <- add result-idx:number, 1:literal + in:character <- index *a, j + out:address:character <- index-address *result, result-idx + *out <- copy in + j <- add j, 1 + result-idx <- add result-idx, 1 loop } # skip '_' in template - i:number <- add i:number, 1:literal + i <- add i, 1 loop # interpolate next arg } +done # done with holes; copy rest of template directly into result { # while i < template.length - tem-done?:boolean <- greater-or-equal i:number, tem-len:number - break-if tem-done?:boolean + tem-done?:boolean <- greater-or-equal i, tem-len + break-if tem-done? # result[result-idx] = template[i] - in:character <- index template:address:array:character/deref, i:number - out:address:character <- index-address result:address:array:character/deref, result-idx:number - out:address:character/deref <- copy in:character - # ++i - i:number <- add i:number, 1:literal - # ++result-idx - result-idx:number <- add result-idx:number, 1:literal + in:character <- index *template, i + out:address:character <- index-address *result, result-idx:number + *out <- copy in + i <- add i, 1 + result-idx <- add result-idx, 1 loop } - reply result:address:array:character + reply result ] scenario interpolate-works [ #? dump run #? 1 run [ - 1:address:array:character/raw <- new [abc _] - 2:address:array:character/raw <- new [def] - 3:address:array:character/raw <- interpolate 1:address:array:character/raw, 2:address:array:character/raw - 4:array:character/raw <- copy 3:address:array:character/raw/deref + 1:address:array:character/raw <- new [abc _] + 2:address:array:character/raw <- new [def] + 3:address:array:character/raw <- interpolate 1:address:array:character/raw, 2:address:array:character/raw + 4:array:character/raw <- copy *3:address:array:character/raw ] memory-should-contain [ - 4:string <- [abc def] + 4:string <- [abc def] ] ] scenario interpolate-at-start [ run [ - 1:address:array:character/raw <- new [_, hello!] - 2:address:array:character/raw <- new [abc] - 3:address:array:character/raw <- interpolate 1:address:array:character/raw, 2:address:array:character/raw - 4:array:character/raw <- copy 3:address:array:character/raw/deref + 1:address:array:character/raw <- new [_, hello!] + 2:address:array:character/raw <- new [abc] + 3:address:array:character/raw <- interpolate 1:address:array:character/raw, 2:address:array:character/raw + 4:array:character/raw <- copy *3:address:array:character/raw ] memory-should-contain [ - 4:string <- [abc, hello!] - 16 <- 0 # out of bounds + 4:string <- [abc, hello!] + 16 <- 0 # out of bounds ] ] scenario interpolate-at-end [ run [ - 1:address:array:character/raw <- new [hello, _] - 2:address:array:character/raw <- new [abc] - 3:address:array:character/raw <- interpolate 1:address:array:character/raw, 2:address:array:character/raw - 4:array:character/raw <- copy 3:address:array:character/raw/deref + 1:address:array:character/raw <- new [hello, _] + 2:address:array:character/raw <- new [abc] + 3:address:array:character/raw <- interpolate 1:address:array:character/raw, 2:address:array:character/raw + 4:array:character/raw <- copy *3:address:array:character/raw ] memory-should-contain [ - 4:string <- [hello, abc] + 4:string <- [hello, abc] ] ] @@ -574,274 +561,274 @@ container buffer [ local-scope c:character <- next-ingredient # most common case first - result:boolean <- equal c:character, 32:literal/space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 10:literal/newline - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 9:literal/tab - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 13:literal/carriage-return + result:boolean <- equal c, 32/space + jump-if result +reply:label + result <- equal c, 10/newline + jump-if result, +reply:label + result <- equal c, 9/tab + jump-if result, +reply:label + result <- equal c, 13/carriage-return + jump-if result, +reply:label # remaining uncommon cases in sorted order # http://unicode.org code-points in unicode-set Z and Pattern_White_Space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 11:literal/ctrl-k - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 12:literal/ctrl-l - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 133:literal/ctrl-0085 - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 160:literal/no-break-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 5760:literal/ogham-space-mark - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8192:literal/en-quad - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8193:literal/em-quad - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8194:literal/en-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8195:literal/em-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8196:literal/three-per-em-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8197:literal/four-per-em-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8198:literal/six-per-em-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8199:literal/figure-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8200:literal/punctuation-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8201:literal/thin-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8202:literal/hair-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8206:literal/left-to-right - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8207:literal/right-to-left - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8232:literal/line-separator - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8233:literal/paragraph-separator - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8239:literal/narrow-no-break-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 8287:literal/medium-mathematical-space - jump-if result:boolean, +reply:label - result:boolean <- equal c:character, 12288:literal/ideographic-space - jump-if result:boolean, +reply:label + result <- equal c, 11/ctrl-k + jump-if result, +reply:label + result <- equal c, 12/ctrl-l + jump-if result, +reply:label + result <- equal c, 133/ctrl-0085 + jump-if result, +reply:label + result <- equal c, 160/no-break-space + jump-if result, +reply:label + result <- equal c, 5760/ogham-space-mark + jump-if result, +reply:label + result <- equal c, 8192/en-quad + jump-if result, +reply:label + result <- equal c, 8193/em-quad + jump-if result, +reply:label + result <- equal c, 8194/en-space + jump-if result, +reply:label + result <- equal c, 8195/em-space + jump-if result, +reply:label + result <- equal c, 8196/three-per-em-space + jump-if result, +reply:label + result <- equal c, 8197/four-per-em-space + jump-if result, +reply:label + result <- equal c, 8198/six-per-em-space + jump-if result, +reply:label + result <- equal c, 8199/figure-space + jump-if result, +reply:label + result <- equal c, 8200/punctuation-space + jump-if result, +reply:label + result <- equal c, 8201/thin-space + jump-if result, +reply:label + result <- equal c, 8202/hair-space + jump-if result, +reply:label + result <- equal c, 8206/left-to-right + jump-if result, +reply:label + result <- equal c, 8207/right-to-left + jump-if result, +reply:label + result <- equal c, 8232/line-separator + jump-if result, +reply:label + result <- equal c, 8233/paragraph-separator + jump-if result, +reply:label + result <- equal c, 8239/narrow-no-break-space + jump-if result, +reply:label + result <- equal c, 8287/medium-mathematical-space + jump-if result, +reply:label + result <- equal c, 12288/ideographic-space + jump-if result, +reply:label +reply - reply result:boolean + reply result ] # result:address:array:character <- trim s:address:array:character recipe trim [ local-scope s:address:array:character <- next-ingredient - len:number <- length s:address:array:character/deref + len:number <- length *s # left trim: compute start - start:number <- copy 0:literal + start:number <- copy 0 { { - at-end?:boolean <- greater-or-equal start:number, len:number - break-unless at-end?:boolean - result:address:array:character <- new character:type, 0:literal - reply result:address:array:character + at-end?:boolean <- greater-or-equal start, len + break-unless at-end? + result:address:array:character <- new character:type, 0 + reply result } - curr:character <- index s:address:array:character/deref, start:number - whitespace?:boolean <- space? curr:character - break-unless whitespace?:boolean - start:number <- add start:number, 1:literal + curr:character <- index *s, start + whitespace?:boolean <- space? curr + break-unless whitespace? + start <- add start, 1 loop } # right trim: compute end - end:number <- subtract len:number, 1:literal + end:number <- subtract len, 1 { - not-at-start?:boolean <- greater-than end:number, start:number - assert not-at-start?:boolean [end ran up against start] - curr:character <- index s:address:array:character/deref, end:number - whitespace?:boolean <- space? curr:character - break-unless whitespace?:boolean - end:number <- subtract end:number, 1:literal + not-at-start?:boolean <- greater-than end, start + assert not-at-start?, [end ran up against start] + curr:character <- index *s, end + whitespace?:boolean <- space? curr + break-unless whitespace? + end <- subtract end, 1 loop } # result = new character[end+1 - start] - new-len:number <- subtract end:number, start:number, -1:literal - result:address:array:character <- new character:type, new-len:number + new-len:number <- subtract end, start, -1 + result:address:array:character <- new character:type, new-len # i = start, j = 0 - i:number <- copy start:number - j:number <- copy 0:literal + i:number <- copy start + j:number <- copy 0 { # while i <= end - done?:boolean <- greater-than i:number, end:number - break-if done?:boolean + done?:boolean <- greater-than i, end + break-if done? # result[j] = s[i] - src:character <- index s:address:array:character/deref, i:number - dest:address:character <- index-address result:address:array:character/deref, j:number - dest:address:character/deref <- copy src:character - # ++i, ++j - i:number <- add i:number, 1:literal - j:number <- add j:number, 1:literal + src:character <- index *s, i + dest:address:character <- index-address *result, j + *dest <- copy src + i <- add i, 1 + j <- add j, 1 loop } - reply result:address:array:character + reply result ] scenario trim-unmodified [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- trim 1:address:array:character - 3:array:character <- copy 2:address:array:character/deref + 1:address:array:character <- new [abc] + 2:address:array:character <- trim 1:address:array:character + 3:array:character <- copy *2:address:array:character ] memory-should-contain [ - 3:string <- [abc] + 3:string <- [abc] ] ] scenario trim-left [ run [ - 1:address:array:character <- new [ abc] - 2:address:array:character <- trim 1:address:array:character - 3:array:character <- copy 2:address:array:character/deref + 1:address:array:character <- new [ abc] + 2:address:array:character <- trim 1:address:array:character + 3:array:character <- copy *2:address:array:character ] memory-should-contain [ - 3:string <- [abc] + 3:string <- [abc] ] ] scenario trim-right [ run [ - 1:address:array:character <- new [abc ] - 2:address:array:character <- trim 1:address:array:character - 3:array:character <- copy 2:address:array:character/deref + 1:address:array:character <- new [abc ] + 2:address:array:character <- trim 1:address:array:character + 3:array:character <- copy *2:address:array:character ] memory-should-contain [ - 3:string <- [abc] + 3:string <- [abc] ] ] scenario trim-left-right [ run [ - 1:address:array:character <- new [ abc ] - 2:address:array:character <- trim 1:address:array:character - 3:array:character <- copy 2:address:array:character/deref + 1:address:array:character <- new [ abc ] + 2:address:array:character <- trim 1:address:array:character + 3:array:character <- copy *2:address:array:character ] memory-should-contain [ - 3:string <- [abc] + 3:string <- [abc] ] ] scenario trim-newline-tab [ run [ - 1:address:array:character <- new [ abc + 1:address:array:character <- new [ abc ] - 2:address:array:character <- trim 1:address:array:character - 3:array:character <- copy 2:address:array:character/deref + 2:address:array:character <- trim 1:address:array:character + 3:array:character <- copy *2:address:array:character ] memory-should-contain [ - 3:string <- [abc] + 3:string <- [abc] ] ] -# next-index:number <- find-next text:address:array:character, pattern:character +# next-index:number <- find-next text:address:array:character, pattern:character, idx:number recipe find-next [ local-scope text:address:array:character <- next-ingredient pattern:character <- next-ingredient idx:number <- next-ingredient - len:number <- length text:address:array:character/deref + len:number <- length *text { - eof?:boolean <- greater-or-equal idx:number, len:number - break-if eof?:boolean - curr:character <- index text:address:array:character/deref, idx:number - found?:boolean <- equal curr:character, pattern:character - break-if found?:boolean - idx:number <- add idx:number, 1:literal + eof?:boolean <- greater-or-equal idx, len + break-if eof? + curr:character <- index *text, idx + found?:boolean <- equal curr, pattern + break-if found? + idx <- add idx, 1 loop } - reply idx:number + reply idx ] scenario string-find-next [ run [ - 1:address:array:character <- new [a/b] - 2:number <- find-next 1:address:array:character, 47:literal/slash, 0:literal/start-index + 1:address:array:character <- new [a/b] + 2:number <- find-next 1:address:array:character, 47/slash, 0/start-index ] memory-should-contain [ - 2 <- 1 + 2 <- 1 ] ] scenario string-find-next-empty [ run [ - 1:address:array:character <- new [] - 2:number <- find-next 1:address:array:character, 47:literal/slash, 0:literal/start-index + 1:address:array:character <- new [] + 2:number <- find-next 1:address:array:character, 47/slash, 0/start-index ] memory-should-contain [ - 2 <- 0 + 2 <- 0 ] ] scenario string-find-next-initial [ run [ - 1:address:array:character <- new [/abc] - 2:number <- find-next 1:address:array:character, 47:literal/slash, 0:literal/start-index + 1:address:array:character <- new [/abc] + 2:number <- find-next 1:address:array:character, 47/slash, 0/start-index ] memory-should-contain [ - 2 <- 0 # prefix match + 2 <- 0 # prefix match ] ] scenario string-find-next-final [ run [ - 1:address:array:character <- new [abc/] - 2:number <- find-next 1:address:array:character, 47:literal/slash, 0:literal/start-index + 1:address:array:character <- new [abc/] + 2:number <- find-next 1:address:array:character, 47/slash, 0/start-index ] memory-should-contain [ - 2 <- 3 # suffix match + 2 <- 3 # suffix match ] ] scenario string-find-next-missing [ run [ - 1:address:array:character <- new [abc] - 2:number <- find-next 1:address:array:character, 47:literal/slash, 0:literal/start-index + 1:address:array:character <- new [abc] + 2:number <- find-next 1:address:array:character, 47/slash, 0/start-index ] memory-should-contain [ - 2 <- 3 # no match + 2 <- 3 # no match ] ] scenario string-find-next-invalid-index [ run [ - 1:address:array:character <- new [abc] - 2:number <- find-next 1:address:array:character, 47:literal/slash, 4:literal/start-index + 1:address:array:character <- new [abc] + 2:number <- find-next 1:address:array:character, 47/slash, 4/start-index ] memory-should-contain [ - 2 <- 4 # no change + 2 <- 4 # no change ] ] scenario string-find-next-first [ run [ - 1:address:array:character <- new [ab/c/] - 2:number <- find-next 1:address:array:character, 47:literal/slash, 0:literal/start-index + 1:address:array:character <- new [ab/c/] + 2:number <- find-next 1:address:array:character, 47/slash, 0/start-index ] memory-should-contain [ - 2 <- 2 # first '/' of multiple + 2 <- 2 # first '/' of multiple ] ] scenario string-find-next-second [ run [ - 1:address:array:character <- new [ab/c/] - 2:number <- find-next 1:address:array:character, 47:literal/slash, 3:literal/start-index + 1:address:array:character <- new [ab/c/] + 2:number <- find-next 1:address:array:character, 47/slash, 3/start-index ] memory-should-contain [ - 2 <- 4 # second '/' of multiple + 2 <- 4 # second '/' of multiple ] ] +# idx:number <- find-substring text:address:array:character, pattern:address:array:character, idx:number # like find-next, but searches for multiple characters # fairly dumb algorithm recipe find-substring [ @@ -849,75 +836,75 @@ container buffer [ text:address:array:character <- next-ingredient pattern:address:array:character <- next-ingredient idx:number <- next-ingredient - first:character <- index pattern:address:array:character/deref, 0:literal + first:character <- index *pattern, 0 # repeatedly check for match at current idx - len:number <- length text:address:array:character/deref + len:number <- length *text { # does some unnecessary work checking for substrings even when there isn't enough of text left - done?:boolean <- greater-or-equal idx:number, len:number - break-if done?:boolean - found?:boolean <- match-at text:address:array:character pattern:address:array:character, idx:number - break-if found?:boolean - idx:number <- add idx:number, 1:literal + done?:boolean <- greater-or-equal idx, len + break-if done? + found?:boolean <- match-at text, pattern, idx + break-if found? + idx <- add idx, 1 # optimization: skip past indices that definitely won't match - idx:number <- find-next text:address:array:character, first:character, idx:number + idx <- find-next text, first, idx loop } - reply idx:number + reply idx ] scenario find-substring-1 [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- new [bc] - 3:number <- find-substring 1:address:array:character, 2:address:array:character, 0:literal + 1:address:array:character <- new [abc] + 2:address:array:character <- new [bc] + 3:number <- find-substring 1:address:array:character, 2:address:array:character, 0 ] memory-should-contain [ - 3 <- 1 + 3 <- 1 ] ] scenario find-substring-2 [ run [ - 1:address:array:character <- new [abcd] - 2:address:array:character <- new [bc] - 3:number <- find-substring 1:address:array:character, 2:address:array:character, 1:literal + 1:address:array:character <- new [abcd] + 2:address:array:character <- new [bc] + 3:number <- find-substring 1:address:array:character, 2:address:array:character, 1 ] memory-should-contain [ - 3 <- 1 + 3 <- 1 ] ] scenario find-substring-no-match [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- new [bd] - 3:number <- find-substring 1:address:array:character, 2:address:array:character, 0:literal + 1:address:array:character <- new [abc] + 2:address:array:character <- new [bd] + 3:number <- find-substring 1:address:array:character, 2:address:array:character, 0 ] memory-should-contain [ - 3 <- 3 # not found + 3 <- 3 # not found ] ] scenario find-substring-suffix-match [ run [ - 1:address:array:character <- new [abcd] - 2:address:array:character <- new [cd] - 3:number <- find-substring 1:address:array:character, 2:address:array:character, 0:literal + 1:address:array:character <- new [abcd] + 2:address:array:character <- new [cd] + 3:number <- find-substring 1:address:array:character, 2:address:array:character, 0 ] memory-should-contain [ - 3 <- 2 + 3 <- 2 ] ] scenario find-substring-suffix-match-2 [ run [ - 1:address:array:character <- new [abcd] - 2:address:array:character <- new [cde] - 3:number <- find-substring 1:address:array:character, 2:address:array:character, 0:literal + 1:address:array:character <- new [abcd] + 2:address:array:character <- new [cde] + 3:number <- find-substring 1:address:array:character, 2:address:array:character, 0 ] memory-should-contain [ - 3 <- 4 # not found + 3 <- 4 # not found ] ] @@ -928,128 +915,128 @@ container buffer [ text:address:array:character <- next-ingredient pattern:address:array:character <- next-ingredient idx:number <- next-ingredient - pattern-len:number <- length pattern:address:array:character/deref + pattern-len:number <- length *pattern # check that there's space left for the pattern { - x:number <- length text:address:array:character/deref - x:number <- subtract x:number, pattern-len:number - enough-room?:boolean <- lesser-or-equal idx:number, x:number - break-if enough-room?:boolean - reply 0:literal/not-found + x:number <- length *text + x <- subtract x, pattern-len + enough-room?:boolean <- lesser-or-equal idx, x + break-if enough-room? + reply 0/not-found } # check each character of pattern - pattern-idx:number <- copy 0:literal + pattern-idx:number <- copy 0 { - done?:boolean <- greater-or-equal pattern-idx:number, pattern-len:number - break-if done?:boolean - c:character <- index text:address:array:character/deref, idx:number - exp:character <- index pattern:address:array:character/deref, pattern-idx:number + done?:boolean <- greater-or-equal pattern-idx, pattern-len + break-if done? + c:character <- index *text, idx + exp:character <- index *pattern, pattern-idx { - match?:boolean <- equal c:character, exp:character - break-if match?:boolean - reply 0:literal/not-found + match?:boolean <- equal c, exp + break-if match? + reply 0/not-found } - idx:number <- add idx:number, 1:literal - pattern-idx:number <- add pattern-idx:number, 1:literal + idx <- add idx, 1 + pattern-idx <- add pattern-idx, 1 loop } - reply 1:literal/found + reply 1/found ] scenario match-at-checks-substring-at-index [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- new [ab] - 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 0:literal + 1:address:array:character <- new [abc] + 2:address:array:character <- new [ab] + 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 0 ] memory-should-contain [ - 3 <- 1 # match found + 3 <- 1 # match found ] ] scenario match-at-reflexive [ run [ - 1:address:array:character <- new [abc] - 3:boolean <- match-at 1:address:array:character, 1:address:array:character, 0:literal + 1:address:array:character <- new [abc] + 3:boolean <- match-at 1:address:array:character, 1:address:array:character, 0 ] memory-should-contain [ - 3 <- 1 # match found + 3 <- 1 # match found ] ] scenario match-at-outside-bounds [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- new [a] - 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 4:literal + 1:address:array:character <- new [abc] + 2:address:array:character <- new [a] + 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 4 ] memory-should-contain [ - 3 <- 0 # never matches + 3 <- 0 # never matches ] ] scenario match-at-empty-pattern [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- new [] - 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 0:literal + 1:address:array:character <- new [abc] + 2:address:array:character <- new [] + 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 0 ] memory-should-contain [ - 3 <- 1 # always matches empty pattern given a valid index + 3 <- 1 # always matches empty pattern given a valid index ] ] scenario match-at-empty-pattern-outside-bound [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- new [] - 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 4:literal + 1:address:array:character <- new [abc] + 2:address:array:character <- new [] + 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 4 ] memory-should-contain [ - 3 <- 0 # no match + 3 <- 0 # no match ] ] scenario match-at-empty-text [ run [ - 1:address:array:character <- new [] - 2:address:array:character <- new [abc] - 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 0:literal + 1:address:array:character <- new [] + 2:address:array:character <- new [abc] + 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 0 ] memory-should-contain [ - 3 <- 0 # no match + 3 <- 0 # no match ] ] scenario match-at-empty-against-empty [ run [ - 1:address:array:character <- new [] - 3:boolean <- match-at 1:address:array:character, 1:address:array:character, 0:literal + 1:address:array:character <- new [] + 3:boolean <- match-at 1:address:array:character, 1:address:array:character, 0 ] memory-should-contain [ - 3 <- 1 # matches because pattern is also empty + 3 <- 1 # matches because pattern is also empty ] ] scenario match-at-inside-bounds [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- new [bc] - 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 1:literal + 1:address:array:character <- new [abc] + 2:address:array:character <- new [bc] + 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 1 ] memory-should-contain [ - 3 <- 1 # matches inner substring + 3 <- 1 # matches inner substring ] ] scenario match-at-inside-bounds-2 [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- new [bc] - 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 0:literal + 1:address:array:character <- new [abc] + 2:address:array:character <- new [bc] + 3:boolean <- match-at 1:address:array:character, 2:address:array:character, 0 ] memory-should-contain [ - 3 <- 0 # no match + 3 <- 0 # no match ] ] @@ -1059,127 +1046,127 @@ container buffer [ s:address:array:character <- next-ingredient delim:character <- next-ingredient # empty string? return empty array - len:number <- length s:address:array:character/deref + len:number <- length *s { - empty?:boolean <- equal len:number, 0:literal - break-unless empty?:boolean - result:address:array:address:array:character <- new location:type, 0:literal - reply result:address:array:address:array:character + empty?:boolean <- equal len, 0 + break-unless empty? + result:address:array:address:array:character <- new location:type, 0 + reply result } # count #pieces we need room for - count:number <- copy 1:literal # n delimiters = n+1 pieces - idx:number <- copy 0:literal + count:number <- copy 1 # n delimiters = n+1 pieces + idx:number <- copy 0 { - idx:number <- find-next s:address:array:character, delim:character, idx:number - done?:boolean <- greater-or-equal idx:number, len:number - break-if done?:boolean - idx:number <- add idx:number, 1:literal - count:number <- add count:number, 1:literal + idx <- find-next s, delim, idx + done?:boolean <- greater-or-equal idx, len + break-if done? + idx <- add idx, 1 + count <- add count, 1 loop } # allocate space - result:address:array:address:array:character <- new location:type, count:number + result:address:array:address:array:character <- new location:type, count # repeatedly copy slices start..end until delimiter into result[curr-result] - curr-result:number <- copy 0:literal - start:number <- copy 0:literal + curr-result:number <- copy 0 + start:number <- copy 0 { # while next delim exists - done?:boolean <- greater-or-equal start:number, len:number - break-if done?:boolean - end:number <- find-next s:address:array:character, delim:character, start:number + done?:boolean <- greater-or-equal start, len + break-if done? + end:number <- find-next s, delim, start # copy start..end into result[curr-result] - dest:address:address:array:character <- index-address result:address:array:address:array:character/deref, curr-result:number - dest:address:address:array:character/deref <- string-copy s:address:array:character, start:number, end:number + dest:address:address:array:character <- index-address *result, curr-result + *dest <- string-copy s, start, end # slide over to next slice - start:number <- add end:number, 1:literal - curr-result:number <- add curr-result:number, 1:literal + start <- add end, 1 + curr-result <- add curr-result, 1 loop } - reply result:address:array:address:array:character + reply result ] scenario string-split-1 [ run [ - 1:address:array:character <- new [a/b] - 2:address:array:address:array:character <- split 1:address:array:character, 47:literal/slash - 3:number <- length 2:address:array:address:array:character/deref - 4:address:array:character <- index 2:address:array:address:array:character/deref, 0:literal - 5:address:array:character <- index 2:address:array:address:array:character/deref, 1:literal - 10:array:character <- copy 4:address:array:character/deref - 20:array:character <- copy 5:address:array:character/deref + 1:address:array:character <- new [a/b] + 2:address:array:address:array:character <- split 1:address:array:character, 47/slash + 3:number <- length *2:address:array:address:array:character + 4:address:array:character <- index *2:address:array:address:array:character, 0 + 5:address:array:character <- index *2:address:array:address:array:character, 1 + 10:array:character <- copy *4:address:array:character + 20:array:character <- copy *5:address:array:character ] memory-should-contain [ - 3 <- 2 # length of result - 10:string <- [a] - 20:string <- [b] + 3 <- 2 # length of result + 10:string <- [a] + 20:string <- [b] ] ] scenario string-split-2 [ run [ - 1:address:array:character <- new [a/b/c] - 2:address:array:address:array:character <- split 1:address:array:character, 47:literal/slash - 3:number <- length 2:address:array:address:array:character/deref - 4:address:array:character <- index 2:address:array:address:array:character/deref, 0:literal - 5:address:array:character <- index 2:address:array:address:array:character/deref, 1:literal - 6:address:array:character <- index 2:address:array:address:array:character/deref, 2:literal - 10:array:character <- copy 4:address:array:character/deref - 20:array:character <- copy 5:address:array:character/deref - 30:array:character <- copy 6:address:array:character/deref + 1:address:array:character <- new [a/b/c] + 2:address:array:address:array:character <- split 1:address:array:character, 47/slash + 3:number <- length *2:address:array:address:array:character + 4:address:array:character <- index *2:address:array:address:array:character, 0 + 5:address:array:character <- index *2:address:array:address:array:character, 1 + 6:address:array:character <- index *2:address:array:address:array:character, 2 + 10:array:character <- copy *4:address:array:character + 20:array:character <- copy *5:address:array:character + 30:array:character <- copy *6:address:array:character ] memory-should-contain [ - 3 <- 3 # length of result - 10:string <- [a] - 20:string <- [b] - 30:string <- [c] + 3 <- 3 # length of result + 10:string <- [a] + 20:string <- [b] + 30:string <- [c] ] ] scenario string-split-missing [ run [ - 1:address:array:character <- new [abc] - 2:address:array:address:array:character <- split 1:address:array:character, 47:literal/slash - 3:number <- length 2:address:array:address:array:character/deref - 4:address:array:character <- index 2:address:array:address:array:character/deref, 0:literal - 10:array:character <- copy 4:address:array:character/deref + 1:address:array:character <- new [abc] + 2:address:array:address:array:character <- split 1:address:array:character, 47/slash + 3:number <- length *2:address:array:address:array:character + 4:address:array:character <- index *2:address:array:address:array:character, 0 + 10:array:character <- copy *4:address:array:character ] memory-should-contain [ - 3 <- 1 # length of result - 10:string <- [abc] + 3 <- 1 # length of result + 10:string <- [abc] ] ] scenario string-split-empty [ run [ - 1:address:array:character <- new [] - 2:address:array:address:array:character <- split 1:address:array:character, 47:literal/slash - 3:number <- length 2:address:array:address:array:character/deref + 1:address:array:character <- new [] + 2:address:array:address:array:character <- split 1:address:array:character, 47/slash + 3:number <- length *2:address:array:address:array:character ] memory-should-contain [ - 3 <- 0 # empty result + 3 <- 0 # empty result ] ] scenario string-split-empty-piece [ run [ - 1:address:array:character <- new [a/b//c] - 2:address:array:address:array:character <- split 1:address:array:character, 47:literal/slash - 3:number <- length 2:address:array:address:array:character/deref - 4:address:array:character <- index 2:address:array:address:array:character/deref, 0:literal - 5:address:array:character <- index 2:address:array:address:array:character/deref, 1:literal - 6:address:array:character <- index 2:address:array:address:array:character/deref, 2:literal - 7:address:array:character <- index 2:address:array:address:array:character/deref, 3:literal - 10:array:character <- copy 4:address:array:character/deref - 20:array:character <- copy 5:address:array:character/deref - 30:array:character <- copy 6:address:array:character/deref - 40:array:character <- copy 7:address:array:character/deref + 1:address:array:character <- new [a/b//c] + 2:address:array:address:array:character <- split 1:address:array:character, 47/slash + 3:number <- length *2:address:array:address:array:character + 4:address:array:character <- index *2:address:array:address:array:character, 0 + 5:address:array:character <- index *2:address:array:address:array:character, 1 + 6:address:array:character <- index *2:address:array:address:array:character, 2 + 7:address:array:character <- index *2:address:array:address:array:character, 3 + 10:array:character <- copy *4:address:array:character + 20:array:character <- copy *5:address:array:character + 30:array:character <- copy *6:address:array:character + 40:array:character <- copy *7:address:array:character ] memory-should-contain [ - 3 <- 4 # length of result - 10:string <- [a] - 20:string <- [b] - 30:string <- [] - 40:string <- [c] + 3 <- 4 # length of result + 10:string <- [a] + 20:string <- [b] + 30:string <- [] + 40:string <- [c] ] ] @@ -1189,31 +1176,31 @@ container buffer [ text:address:array:character <- next-ingredient delim:character <- next-ingredient # empty string? return empty strings - len:number <- length text:address:array:character/deref + len:number <- length *text { - empty?:boolean <- equal len:number, 0:literal - break-unless empty?:boolean + empty?:boolean <- equal len, 0 + break-unless empty? x:address:array:character <- new [] y:address:array:character <- new [] - reply x:address:array:character, y:address:array:character + reply x, y } - idx:number <- find-next text:address:array:character, delim:character, 0:literal - x:address:array:character <- string-copy text:address:array:character, 0:literal, idx:number - idx:number <- add idx:number, 1:literal - y:address:array:character <- string-copy text:address:array:character, idx:number, len:number - reply x:address:array:character, y:address:array:character + idx:number <- find-next text, delim, 0 + x:address:array:character <- string-copy text, 0, idx + idx <- add idx, 1 + y:address:array:character <- string-copy text, idx, len + reply x, y ] scenario string-split-first [ run [ - 1:address:array:character <- new [a/b] - 2:address:array:character, 3:address:array:character <- split-first 1:address:array:character, 47:literal/slash - 10:array:character <- copy 2:address:array:character/deref - 20:array:character <- copy 3:address:array:character/deref + 1:address:array:character <- new [a/b] + 2:address:array:character, 3:address:array:character <- split-first 1:address:array:character, 47/slash + 10:array:character <- copy *2:address:array:character + 20:array:character <- copy *3:address:array:character ] memory-should-contain [ - 10:string <- [a] - 20:string <- [b] + 10:string <- [a] + 20:string <- [b] ] ] @@ -1225,57 +1212,57 @@ container buffer [ start:number <- next-ingredient end:number <- next-ingredient # if end is out of bounds, trim it - len:number <- length buf:address:array:character/deref - end:number <- min len:number, end:number + len:number <- length *buf + end:number <- min len, end # allocate space for result - len:number <- subtract end:number, start:number - result:address:array:character <- new character:type, len:number + len <- subtract end, start + result:address:array:character <- new character:type, len # copy start..end into result[curr-result] - src-idx:number <- copy start:number - dest-idx:number <- copy 0:literal + src-idx:number <- copy start + dest-idx:number <- copy 0 { - done?:boolean <- greater-or-equal src-idx:number, end:number - break-if done?:boolean - src:character <- index buf:address:array:character/deref, src-idx:number - dest:address:character <- index-address result:address:array:character/deref, dest-idx:number - dest:address:character/deref <- copy src:character - src-idx:number <- add src-idx:number, 1:literal - dest-idx:number <- add dest-idx:number, 1:literal + done?:boolean <- greater-or-equal src-idx, end + break-if done? + src:character <- index *buf, src-idx + dest:address:character <- index-address *result, dest-idx + *dest <- copy src + src-idx <- add src-idx, 1 + dest-idx <- add dest-idx, 1 loop } - reply result:address:array:character + reply result ] scenario string-copy-copies-substring [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- string-copy 1:address:array:character, 1:literal, 3:literal - 3:array:character <- copy 2:address:array:character/deref + 1:address:array:character <- new [abc] + 2:address:array:character <- string-copy 1:address:array:character, 1, 3 + 3:array:character <- copy *2:address:array:character ] memory-should-contain [ - 3:string <- [bc] + 3:string <- [bc] ] ] scenario string-copy-out-of-bounds [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- string-copy 1:address:array:character, 2:literal, 4:literal - 3:array:character <- copy 2:address:array:character/deref + 1:address:array:character <- new [abc] + 2:address:array:character <- string-copy 1:address:array:character, 2, 4 + 3:array:character <- copy *2:address:array:character ] memory-should-contain [ - 3:string <- [c] + 3:string <- [c] ] ] scenario string-copy-out-of-bounds-2 [ run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- string-copy 1:address:array:character, 3:literal, 3:literal - 3:array:character <- copy 2:address:array:character/deref + 1:address:array:character <- new [abc] + 2:address:array:character <- string-copy 1:address:array:character, 3, 3 + 3:array:character <- copy *2:address:array:character ] memory-should-contain [ - 3:string <- [] + 3:string <- [] ] ] @@ -1284,11 +1271,11 @@ container buffer [ x:number <- next-ingredient y:number <- next-ingredient { - return-x?:boolean <- lesser-than x:number, y:number - break-if return-x?:boolean - reply y:number + return-x?:boolean <- lesser-than x, y + break-if return-x? + reply y } - reply x:number + reply x ] recipe max [ @@ -1296,11 +1283,11 @@ container buffer [ x:number <- next-ingredient y:number <- next-ingredient { - return-x?:boolean <- greater-than x:number, y:number - break-if return-x?:boolean - reply y:number + return-x?:boolean <- greater-than x, y + break-if return-x? + reply y } - reply x:number + reply x ] diff --git a/html/061channel.mu.html b/html/061channel.mu.html index 913265de..89df9b83 100644 --- a/html/061channel.mu.html +++ b/html/061channel.mu.html @@ -14,14 +14,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background- body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .muScenario { color: #00af00; } -.SalientComment { color: #00ffff; } .Delimiter { color: #a04060; } -.CommentedCode { color: #6c6c6c; } +.muRecipe { color: #ff8700; } +.SalientComment { color: #00ffff; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -45,12 +44,12 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } scenario channel [ run [ - 1:address:channel <- new-channel 3:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - 2:number, 1:address:channel <- read 1:address:channel + 1:address:channel <- new-channel 3/capacity + 1:address:channel <- write 1:address:channel, 34 + 2:number, 1:address:channel <- read 1:address:channel ] memory-should-contain [ - 2 <- 34 + 2 <- 34 ] ] @@ -72,17 +71,17 @@ container channel [ # result = new channel result:address:channel <- new channel:type # result.first-full = 0 - full:address:number <- get-address result:address:channel/deref, first-full:offset - full:address:number/deref <- copy 0:literal + full:address:number <- get-address *result, first-full:offset + *full <- copy 0 # result.first-free = 0 - free:address:number <- get-address result:address:channel/deref, first-free:offset - free:address:number/deref <- copy 0:literal + free:address:number <- get-address *result, first-free:offset + *free <- copy 0 # result.data = new location[ingredient+1] capacity:number <- next-ingredient - capacity:number <- add capacity:number, 1:literal # unused slot for 'full?' below - dest:address:address:array:location <- get-address result:address:channel/deref, data:offset - dest:address:address:array:location/deref <- new location:type, capacity:number - reply result:address:channel + capacity <- add capacity, 1 # unused slot for 'full?' below + dest:address:address:array:location <- get-address *result, data:offset + *dest <- new location:type, capacity + reply result ] # chan:address:channel <- write chan:address:channel, val:location @@ -92,26 +91,26 @@ container channel [ val:location <- next-ingredient { # block if chan is full - full:boolean <- channel-full? chan:address:channel - break-unless full:boolean - full-address:address:number <- get-address chan:address:channel/deref, first-full:offset - wait-for-location full-address:address:number/deref + full:boolean <- channel-full? chan + break-unless full + full-address:address:number <- get-address *chan, first-full:offset + wait-for-location *full-address } # store val - circular-buffer:address:array:location <- get chan:address:channel/deref, data:offset - free:address:number <- get-address chan:address:channel/deref, first-free:offset - dest:address:location <- index-address circular-buffer:address:array:location/deref, free:address:number/deref - dest:address:location/deref <- copy val:location - # increment free - free:address:number/deref <- add free:address:number/deref, 1:literal + circular-buffer:address:array:location <- get *chan, data:offset + free:address:number <- get-address *chan, first-free:offset + dest:address:location <- index-address *circular-buffer, *free + *dest <- copy val + # mark its slot as filled + *free <- add *free, 1 { # wrap free around to 0 if necessary - len:number <- length circular-buffer:address:array:location/deref - at-end?:boolean <- greater-or-equal free:address:number/deref, len:number - break-unless at-end?:boolean - free:address:number/deref <- copy 0:literal + len:number <- length *circular-buffer + at-end?:boolean <- greater-or-equal *free, len + break-unless at-end? + *free <- copy 0 } - reply chan:address:channel/same-as-ingredient:0 + reply chan/same-as-ingredient:0 ] # result:location, chan:address:channel <- read chan:address:channel @@ -120,99 +119,99 @@ container channel [ chan:address:channel <- next-ingredient { # block if chan is empty - empty:boolean <- channel-empty? chan:address:channel - break-unless empty:boolean - free-address:address:number <- get-address chan:address:channel/deref, first-free:offset - wait-for-location free-address:address:number/deref + empty?:boolean <- channel-empty? chan + break-unless empty? + free-address:address:number <- get-address *chan, first-free:offset + wait-for-location *free-address } # read result - full:address:number <- get-address chan:address:channel/deref, first-full:offset - circular-buffer:address:array:location <- get chan:address:channel/deref, data:offset - result:location <- index circular-buffer:address:array:location/deref, full:address:number/deref + full:address:number <- get-address *chan, first-full:offset + circular-buffer:address:array:location <- get *chan, data:offset + result:location <- index *circular-buffer, *full # increment full - full:address:number/deref <- add full:address:number/deref, 1:literal + *full <- add *full, 1 { # wrap full around to 0 if necessary - len:number <- length circular-buffer:address:array:location/deref - at-end?:boolean <- greater-or-equal full:address:number/deref, len:number - break-unless at-end?:boolean - full:address:number/deref <- copy 0:literal + len:number <- length *circular-buffer + at-end?:boolean <- greater-or-equal *full, len + break-unless at-end? + *full <- copy 0 } - reply result:location, chan:address:channel/same-as-ingredient:0 + reply result, chan/same-as-ingredient:0 ] recipe clear-channel [ local-scope chan:address:channel <- next-ingredient { - empty?:boolean <- channel-empty? chan:address:channel - break-if empty?:boolean - _, chan:address:channel <- read chan:address:channel + empty?:boolean <- channel-empty? chan + break-if empty? + _, chan <- read chan } - reply chan:address:channel/same-as-ingredient:0 + reply chan/same-as-ingredient:0 ] scenario channel-initialization [ run [ - 1:address:channel <- new-channel 3:literal/capacity - 2:number <- get 1:address:channel/deref, first-full:offset - 3:number <- get 1:address:channel/deref, first-free:offset + 1:address:channel <- new-channel 3/capacity + 2:number <- get *1:address:channel, first-full:offset + 3:number <- get *1:address:channel, first-free:offset ] memory-should-contain [ - 2 <- 0 # first-full - 3 <- 0 # first-free + 2 <- 0 # first-full + 3 <- 0 # first-free ] ] scenario channel-write-increments-free [ run [ - 1:address:channel <- new-channel 3:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - 2:number <- get 1:address:channel/deref, first-full:offset - 3:number <- get 1:address:channel/deref, first-free:offset + 1:address:channel <- new-channel 3/capacity + 1:address:channel <- write 1:address:channel, 34 + 2:number <- get *1:address:channel, first-full:offset + 3:number <- get *1:address:channel, first-free:offset ] memory-should-contain [ - 2 <- 0 # first-full - 3 <- 1 # first-free + 2 <- 0 # first-full + 3 <- 1 # first-free ] ] scenario channel-read-increments-full [ run [ - 1:address:channel <- new-channel 3:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - _, 1:address:channel <- read 1:address:channel - 2:number <- get 1:address:channel/deref, first-full:offset - 3:number <- get 1:address:channel/deref, first-free:offset + 1:address:channel <- new-channel 3/capacity + 1:address:channel <- write 1:address:channel, 34 + _, 1:address:channel <- read 1:address:channel + 2:number <- get *1:address:channel, first-full:offset + 3:number <- get *1:address:channel, first-free:offset ] memory-should-contain [ - 2 <- 1 # first-full - 3 <- 1 # first-free + 2 <- 1 # first-full + 3 <- 1 # first-free ] ] scenario channel-wrap [ run [ # channel with just 1 slot - 1:address:channel <- new-channel 1:literal/capacity + 1:address:channel <- new-channel 1/capacity # write and read a value - 1:address:channel <- write 1:address:channel, 34:literal - _, 1:address:channel <- read 1:address:channel + 1:address:channel <- write 1:address:channel, 34 + _, 1:address:channel <- read 1:address:channel # first-free will now be 1 - 2:number <- get 1:address:channel/deref, first-free:offset - 3:number <- get 1:address:channel/deref, first-free:offset + 2:number <- get *1:address:channel, first-free:offset + 3:number <- get *1:address:channel, first-free:offset # write second value, verify that first-free wraps - 1:address:channel <- write 1:address:channel, 34:literal - 4:number <- get 1:address:channel/deref, first-free:offset + 1:address:channel <- write 1:address:channel, 34 + 4:number <- get *1:address:channel, first-free:offset # read second value, verify that first-full wraps - _, 1:address:channel <- read 1:address:channel - 5:number <- get 1:address:channel/deref, first-full:offset + _, 1:address:channel <- read 1:address:channel + 5:number <- get *1:address:channel, first-full:offset ] memory-should-contain [ - 2 <- 1 # first-free after first write - 3 <- 1 # first-full after first read - 4 <- 0 # first-free after second write, wrapped - 5 <- 0 # first-full after second read, wrapped + 2 <- 1 # first-free after first write + 3 <- 1 # first-full after first read + 4 <- 0 # first-free after second write, wrapped + 5 <- 0 # first-full after second read, wrapped ] ] @@ -223,10 +222,10 @@ container channel [ local-scope chan:address:channel <- next-ingredient # return chan.first-full == chan.first-free - full:number <- get chan:address:channel/deref, first-full:offset - free:number <- get chan:address:channel/deref, first-free:offset - result:boolean <- equal full:number, free:number - reply result:boolean + full:number <- get *chan, first-full:offset + free:number <- get *chan, first-free:offset + result:boolean <- equal full, free + reply result ] # A full channel has first-empty just before first-full, wasting one slot. @@ -235,79 +234,79 @@ container channel [ local-scope chan:address:channel <- next-ingredient # tmp = chan.first-free + 1 - tmp:number <- get chan:address:channel/deref, first-free:offset - tmp:number <- add tmp:number, 1:literal + tmp:number <- get *chan, first-free:offset + tmp <- add tmp, 1 { # if tmp == chan.capacity, tmp = 0 - len:number <- channel-capacity chan:address:channel - at-end?:boolean <- greater-or-equal tmp:number, len:number - break-unless at-end?:boolean - tmp:number <- copy 0:literal + len:number <- channel-capacity chan + at-end?:boolean <- greater-or-equal tmp, len + break-unless at-end? + tmp <- copy 0 } # return chan.first-full == tmp - full:number <- get chan:address:channel/deref, first-full:offset - result:boolean <- equal full:number, tmp:number - reply result:boolean + full:number <- get *chan, first-full:offset + result:boolean <- equal full, tmp + reply result ] # result:number <- channel-capacity chan:address:channel recipe channel-capacity [ local-scope chan:address:channel <- next-ingredient - q:address:array:location <- get chan:address:channel/deref, data:offset - result:number <- length q:address:array:location/deref - reply result:number + q:address:array:location <- get *chan, data:offset + result:number <- length *q + reply result ] scenario channel-new-empty-not-full [ run [ - 1:address:channel <- new-channel 3:literal/capacity - 2:boolean <- channel-empty? 1:address:channel - 3:boolean <- channel-full? 1:address:channel + 1:address:channel <- new-channel 3/capacity + 2:boolean <- channel-empty? 1:address:channel + 3:boolean <- channel-full? 1:address:channel ] memory-should-contain [ - 2 <- 1 # empty? - 3 <- 0 # full? + 2 <- 1 # empty? + 3 <- 0 # full? ] ] scenario channel-write-not-empty [ run [ - 1:address:channel <- new-channel 3:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - 2:boolean <- channel-empty? 1:address:channel - 3:boolean <- channel-full? 1:address:channel + 1:address:channel <- new-channel 3/capacity + 1:address:channel <- write 1:address:channel, 34 + 2:boolean <- channel-empty? 1:address:channel + 3:boolean <- channel-full? 1:address:channel ] memory-should-contain [ - 2 <- 0 # empty? - 3 <- 0 # full? + 2 <- 0 # empty? + 3 <- 0 # full? ] ] scenario channel-write-full [ run [ - 1:address:channel <- new-channel 1:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - 2:boolean <- channel-empty? 1:address:channel - 3:boolean <- channel-full? 1:address:channel + 1:address:channel <- new-channel 1/capacity + 1:address:channel <- write 1:address:channel, 34 + 2:boolean <- channel-empty? 1:address:channel + 3:boolean <- channel-full? 1:address:channel ] memory-should-contain [ - 2 <- 0 # empty? - 3 <- 1 # full? + 2 <- 0 # empty? + 3 <- 1 # full? ] ] scenario channel-read-not-full [ run [ - 1:address:channel <- new-channel 1:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - _, 1:address:channel <- read 1:address:channel - 2:boolean <- channel-empty? 1:address:channel - 3:boolean <- channel-full? 1:address:channel + 1:address:channel <- new-channel 1/capacity + 1:address:channel <- write 1:address:channel, 34 + _, 1:address:channel <- read 1:address:channel + 2:boolean <- channel-empty? 1:address:channel + 3:boolean <- channel-full? 1:address:channel ] memory-should-contain [ - 2 <- 1 # empty? - 3 <- 0 # full? + 2 <- 1 # empty? + 3 <- 0 # full? ] ] @@ -315,105 +314,90 @@ container channel [ # out:address:channel <- buffer-lines in:address:channel, out:address:channel recipe buffer-lines [ local-scope -#? $print [buffer-lines: aaa -#? ] in:address:channel <- next-ingredient out:address:channel <- next-ingredient # repeat forever { - line:address:buffer <- new-buffer, 30:literal + line:address:buffer <- new-buffer, 30 # read characters from 'in' until newline, copy into line { +next-character - c:character, in:address:channel <- read in:address:channel + c:character, in <- read in # drop a character on backspace { # special-case: if it's a backspace - backspace?:boolean <- equal c:character, 8:literal - break-unless backspace?:boolean + backspace?:boolean <- equal c, 8 + break-unless backspace? # drop previous character -#? close-console #? 2 -#? $print [backspace! -#? ] #? 1 { - buffer-length:address:number <- get-address line:address:buffer/deref, length:offset - buffer-empty?:boolean <- equal buffer-length:address:number/deref, 0:literal - break-if buffer-empty?:boolean -#? $print [before: ], buffer-length:address:number/deref, 10:literal/newline - buffer-length:address:number/deref <- subtract buffer-length:address:number/deref, 1:literal -#? $print [after: ], buffer-length:address:number/deref, 10:literal/newline + buffer-length:address:number <- get-address *line, length:offset + buffer-empty?:boolean <- equal *buffer-length, 0 + break-if buffer-empty? + *buffer-length <- subtract *buffer-length, 1 } -#? $exit #? 2 # and don't append this one loop +next-character:label } # append anything else -#? $print [buffer-lines: appending ], c:character, 10:literal/newline - line:address:buffer <- buffer-append line:address:buffer, c:character - line-done?:boolean <- equal c:character, 10:literal/newline - break-if line-done?:boolean + line <- buffer-append line, c + line-done?:boolean <- equal c, 10/newline + break-if line-done? # stop buffering on eof (currently only generated by fake console) - eof?:boolean <- equal c:character, 0:literal/eof - break-if eof?:boolean + eof?:boolean <- equal c, 0/eof + break-if eof? loop } -#? close-console #? 1 # copy line into 'out' -#? $print [buffer-lines: emitting -#? ] - i:number <- copy 0:literal - line-contents:address:array:character <- get line:address:buffer/deref, data:offset - max:number <- get line:address:buffer/deref, length:offset + i:number <- copy 0 + line-contents:address:array:character <- get *line, data:offset + max:number <- get *line, length:offset { - done?:boolean <- greater-or-equal i:number, max:number - break-if done?:boolean - c:character <- index line-contents:address:array:character/deref, i:number - out:address:channel <- write out:address:channel, c:character -#? $print [writing ], i:number, [: ], c:character, 10:literal/newline - i:number <- add i:number, 1:literal + done?:boolean <- greater-or-equal i, max + break-if done? + c:character <- index *line-contents, i + out <- write out, c + i <- add i, 1 loop } -#? $dump-trace #? 1 -#? $exit #? 1 loop } - reply out:address:channel/same-as-ingredient:1 + reply out/same-as-ingredient:1 ] scenario buffer-lines-blocks-until-newline [ run [ - 1:address:channel/stdin <- new-channel 10:literal/capacity - 2:address:channel/buffered-stdin <- new-channel 10:literal/capacity - 3:boolean <- channel-empty? 2:address:channel/buffered-stdin - assert 3:boolean, [ + 1:address:channel/stdin <- new-channel 10/capacity + 2:address:channel/buffered-stdin <- new-channel 10/capacity + 3:boolean <- channel-empty? 2:address:channel/buffered-stdin + assert 3:boolean, [ F buffer-lines-blocks-until-newline: channel should be empty after init] # buffer stdin into buffered-stdin, try to read from buffered-stdin - 4:number/buffer-routine <- start-running buffer-lines:recipe, 1:address:channel/stdin, 2:address:channel/buffered-stdin - wait-for-routine 4:number/buffer-routine - 5:boolean <- channel-empty? 2:address:channel/buffered-stdin - assert 5:boolean, [ + 4:number/buffer-routine <- start-running buffer-lines:recipe, 1:address:channel/stdin, 2:address:channel/buffered-stdin + wait-for-routine 4:number/buffer-routine + 5:boolean <- channel-empty? 2:address:channel/buffered-stdin + assert 5:boolean, [ F buffer-lines-blocks-until-newline: channel should be empty after buffer-lines bring-up] # write 'a' - 1:address:channel <- write 1:address:channel, 97:literal/a - restart 4:number/buffer-routine - wait-for-routine 4:number/buffer-routine - 6:boolean <- channel-empty? 2:address:channel/buffered-stdin - assert 6:boolean, [ + 1:address:channel <- write 1:address:channel, 97/a + restart 4:number/buffer-routine + wait-for-routine 4:number/buffer-routine + 6:boolean <- channel-empty? 2:address:channel/buffered-stdin + assert 6:boolean, [ F buffer-lines-blocks-until-newline: channel should be empty after writing 'a'] # write 'b' - 1:address:channel <- write 1:address:channel, 98:literal/b - restart 4:number/buffer-routine - wait-for-routine 4:number/buffer-routine - 7:boolean <- channel-empty? 2:address:channel/buffered-stdin - assert 7:boolean, [ + 1:address:channel <- write 1:address:channel, 98/b + restart 4:number/buffer-routine + wait-for-routine 4:number/buffer-routine + 7:boolean <- channel-empty? 2:address:channel/buffered-stdin + assert 7:boolean, [ F buffer-lines-blocks-until-newline: channel should be empty after writing 'b'] # write newline - 1:address:channel <- write 1:address:channel, 10:literal/newline - restart 4:number/buffer-routine - wait-for-routine 4:number/buffer-routine - 8:boolean <- channel-empty? 2:address:channel/buffered-stdin - 9:boolean/completed? <- not 8:boolean - assert 9:boolean/completed?, [ + 1:address:channel <- write 1:address:channel, 10/newline + restart 4:number/buffer-routine + wait-for-routine 4:number/buffer-routine + 8:boolean <- channel-empty? 2:address:channel/buffered-stdin + 9:boolean/completed? <- not 8:boolean + assert 9:boolean/completed?, [ F buffer-lines-blocks-until-newline: channel should contain data after writing newline] trace [test], [reached end] ] diff --git a/html/062array.mu.html b/html/062array.mu.html index 50b72162..55169dfe 100644 --- a/html/062array.mu.html +++ b/html/062array.mu.html @@ -15,11 +15,11 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .muScenario { color: #00af00; } .Delimiter { color: #a04060; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -33,43 +33,43 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 scenario array-from-args [
   run [
-    1:address:array:location <- new-array 0:literal, 1:literal, 2:literal
-    2:array:location <- copy 1:address:array:location/deref
+    1:address:array:location <- new-array 0, 1, 2
+    2:array:location <- copy *1:address:array:location
   ]
   memory-should-contain [
-    2 <- 3  # array length
-    3 <- 0
-    4 <- 1
-    5 <- 2
+    2 <- 3  # array length
+    3 <- 0
+    4 <- 1
+    5 <- 2
   ]
 ]
 
 # create an array out of a list of scalar args
 recipe new-array [
   local-scope
-  capacity:number <- copy 0:literal
+  capacity:number <- copy 0
   {
     # while read curr-value
     curr-value:location, exists?:boolean <- next-ingredient
-    break-unless exists?:boolean
-    capacity:number <- add capacity:number, 1:literal
+    break-unless exists?
+    capacity <- add capacity, 1
     loop
   }
-  result:address:array:location <- new location:type, capacity:number
+  result:address:array:location <- new location:type, capacity
   rewind-ingredients
-  i:number <- copy 0:literal
+  i:number <- copy 0
   {
     # while read curr-value
-    done?:boolean <- greater-or-equal i:number, capacity:number
-    break-if done?:boolean
+    done?:boolean <- greater-or-equal i, capacity
+    break-if done?
     curr-value:location, exists?:boolean <- next-ingredient
-    assert exists?:boolean, [error in rewinding ingredients to new-array]
-    tmp:address:location <- index-address result:address:array:location/deref, i:number
-    tmp:address:location/deref <- copy curr-value:location
-    i:number <- add i:number, 1:literal
+    assert exists?, [error in rewinding ingredients to new-array]
+    tmp:address:location <- index-address *result, i
+    *tmp <- copy curr-value
+    i <- add i, 1
     loop
   }
-  reply result:address:array:location
+  reply result
 ]
 
diff --git a/html/063list.mu.html b/html/063list.mu.html index 9763729b..50060a5f 100644 --- a/html/063list.mu.html +++ b/html/063list.mu.html @@ -13,13 +13,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .muScenario { color: #00af00; } -.CommentedCode { color: #6c6c6c; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } +.CommentedCode { color: #6c6c6c; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -47,48 +47,48 @@ container list [ x:location <- next-ingredient in:address:list <- next-ingredient result:address:list <- new list:type - val:address:location <- get-address result:address:list/deref, value:offset - val:address:location/deref <- copy x:location - next:address:address:list <- get-address result:address:list/deref, next:offset - next:address:address:list/deref <- copy in:address:list - reply result:address:list + val:address:location <- get-address *result, value:offset + *val <- copy x + next:address:address:list <- get-address *result, next:offset + *next <- copy in + reply result ] # result:location <- first in:address:list recipe first [ local-scope in:address:list <- next-ingredient - result:location <- get in:address:list/deref, value:offset - reply result:location + result:location <- get *in, value:offset + reply result ] # result:address:list <- rest in:address:list recipe rest [ local-scope in:address:list <- next-ingredient - result:address:list <- get in:address:list/deref, next:offset - reply result:address:list + result:address:list <- get *in, next:offset + reply result ] scenario list-handling [ run [ #? $start-tracing #? 1 - 1:address:list <- copy 0:literal - 1:address:list <- push 3:literal, 1:address:list - 1:address:list <- push 4:literal, 1:address:list - 1:address:list <- push 5:literal, 1:address:list - 2:number <- first 1:address:list - 1:address:list <- rest 1:address:list - 3:number <- first 1:address:list - 1:address:list <- rest 1:address:list - 4:number <- first 1:address:list - 1:address:list <- rest 1:address:list + 1:address:list <- copy 0 + 1:address:list <- push 3, 1:address:list + 1:address:list <- push 4, 1:address:list + 1:address:list <- push 5, 1:address:list + 2:number <- first 1:address:list + 1:address:list <- rest 1:address:list + 3:number <- first 1:address:list + 1:address:list <- rest 1:address:list + 4:number <- first 1:address:list + 1:address:list <- rest 1:address:list ] memory-should-contain [ - 1 <- 0 # empty to empty, dust to dust.. - 2 <- 5 - 3 <- 4 - 4 <- 3 + 1 <- 0 # empty to empty, dust to dust.. + 2 <- 5 + 3 <- 4 + 4 <- 3 ] ] diff --git a/html/064random.cc.html b/html/064random.cc.html index c2cf118f..8735a580 100644 --- a/html/064random.cc.html +++ b/html/064random.cc.html @@ -13,15 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } .PreProc { color: #c000c0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -38,7 +37,7 @@ RANDOM, :(before "End Primitive Recipe Numbers") Recipe_ordinal["random"] = RANDOM; :(before "End Primitive Recipe Implementations") -case RANDOM: { +case RANDOM: { // todo: limited range of numbers, might be imperfectly random // todo: thread state in extra ingredients and products products.resize(1); @@ -51,7 +50,7 @@ MAKE_RANDOM_NONDETERMINISTIC, :(before "End Primitive Recipe Numbers") Recipe_ordinal["make-random-nondeterministic"] = MAKE_RANDOM_NONDETERMINISTIC; :(before "End Primitive Recipe Implementations") -case MAKE_RANDOM_NONDETERMINISTIC: { +case MAKE_RANDOM_NONDETERMINISTIC: { srand(time(NULL)); break; } @@ -61,12 +60,12 @@ ROUND, :(before "End Primitive Recipe Numbers") Recipe_ordinal["round"] = ROUND; :(before "End Primitive Recipe Implementations") -case ROUND: { - if (SIZE(ingredients) != 1) { +case ROUND: { + if (SIZE(ingredients) != 1) { raise << current_recipe_name() << ": 'round' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'round' should be a number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } diff --git a/html/065duplex_list.mu.html b/html/065duplex_list.mu.html index 2a517067..cbae7303 100644 --- a/html/065duplex_list.mu.html +++ b/html/065duplex_list.mu.html @@ -13,14 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } -.muScenario { color: #00af00; } +.muRecipe { color: #ff8700; } .Delimiter { color: #a04060; } -.CommentedCode { color: #6c6c6c; } +.muScenario { color: #00af00; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } +.CommentedCode { color: #6c6c6c; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -46,83 +46,83 @@ container duplex-list [ x:location <- next-ingredient in:address:duplex-list <- next-ingredient result:address:duplex-list <- new duplex-list:type - val:address:location <- get-address result:address:duplex-list/deref, value:offset - val:address:location/deref <- copy x:location - next:address:address:duplex-list <- get-address result:address:duplex-list/deref, next:offset - next:address:address:duplex-list/deref <- copy in:address:duplex-list - reply-unless in:address:duplex-list, result:address:duplex-list - prev:address:address:duplex-list <- get-address in:address:duplex-list/deref, prev:offset - prev:address:address:duplex-list/deref <- copy result:address:duplex-list - reply result:address:duplex-list + val:address:location <- get-address *result, value:offset + *val <- copy x + next:address:address:duplex-list <- get-address *result, next:offset + *next <- copy in + reply-unless in, result + prev:address:address:duplex-list <- get-address *in, prev:offset + *prev <- copy result + reply result ] # result:location <- first-duplex in:address:duplex-list recipe first-duplex [ local-scope in:address:duplex-list <- next-ingredient - reply-unless in:address:duplex-list, 0:literal - result:location <- get in:address:duplex-list/deref, value:offset - reply result:location + reply-unless in, 0 + result:location <- get *in, value:offset + reply result ] # result:address:duplex-list <- next-duplex in:address:duplex-list recipe next-duplex [ local-scope in:address:duplex-list <- next-ingredient - reply-unless in:address:duplex-list, 0:literal - result:address:duplex-list <- get in:address:duplex-list/deref, next:offset - reply result:address:duplex-list + reply-unless in, 0 + result:address:duplex-list <- get *in, next:offset + reply result ] # result:address:duplex-list <- prev-duplex in:address:duplex-list recipe prev-duplex [ local-scope in:address:duplex-list <- next-ingredient - reply-unless in:address:duplex-list, 0:literal - result:address:duplex-list <- get in:address:duplex-list/deref, prev:offset - reply result:address:duplex-list + reply-unless in, 0 + result:address:duplex-list <- get *in, prev:offset + reply result ] scenario duplex-list-handling [ run [ # reserve locations 0, 1 and 2 to check for missing null check - 1:number <- copy 34:literal - 2:number <- copy 35:literal - 3:address:duplex-list <- copy 0:literal - 3:address:duplex-list <- push-duplex 3:literal, 3:address:duplex-list - 3:address:duplex-list <- push-duplex 4:literal, 3:address:duplex-list - 3:address:duplex-list <- push-duplex 5:literal, 3:address:duplex-list - 4:address:duplex-list <- copy 3:address:duplex-list - 5:number <- first 4:address:duplex-list - 4:address:duplex-list <- next-duplex 4:address:duplex-list - 6:number <- first 4:address:duplex-list - 4:address:duplex-list <- next-duplex 4:address:duplex-list - 7:number <- first 4:address:duplex-list - 8:address:duplex-list <- next-duplex 4:address:duplex-list - 9:number <- first 8:address:duplex-list - 10:address:duplex-list <- next-duplex 8:address:duplex-list - 11:address:duplex-list <- prev-duplex 8:address:duplex-list - 4:address:duplex-list <- prev-duplex 4:address:duplex-list - 12:number <- first 4:address:duplex-list - 4:address:duplex-list <- prev-duplex 4:address:duplex-list - 13:number <- first 4:address:duplex-list - 14:boolean <- equal 3:address:duplex-list, 4:address:duplex-list + 1:number <- copy 34 + 2:number <- copy 35 + 3:address:duplex-list <- copy 0 + 3:address:duplex-list <- push-duplex 3, 3:address:duplex-list + 3:address:duplex-list <- push-duplex 4, 3:address:duplex-list + 3:address:duplex-list <- push-duplex 5, 3:address:duplex-list + 4:address:duplex-list <- copy 3:address:duplex-list + 5:number <- first 4:address:duplex-list + 4:address:duplex-list <- next-duplex 4:address:duplex-list + 6:number <- first 4:address:duplex-list + 4:address:duplex-list <- next-duplex 4:address:duplex-list + 7:number <- first 4:address:duplex-list + 8:address:duplex-list <- next-duplex 4:address:duplex-list + 9:number <- first 8:address:duplex-list + 10:address:duplex-list <- next-duplex 8:address:duplex-list + 11:address:duplex-list <- prev-duplex 8:address:duplex-list + 4:address:duplex-list <- prev-duplex 4:address:duplex-list + 12:number <- first 4:address:duplex-list + 4:address:duplex-list <- prev-duplex 4:address:duplex-list + 13:number <- first 4:address:duplex-list + 14:boolean <- equal 3:address:duplex-list, 4:address:duplex-list #? $dump-trace #? 1 ] memory-should-contain [ - 0 <- 0 # no modifications to null pointers - 1 <- 34 - 2 <- 35 - 5 <- 5 # scanning next - 6 <- 4 - 7 <- 3 - 8 <- 0 # null - 9 <- 0 # first of null - 10 <- 0 # next of null - 11 <- 0 # prev of null - 12 <- 4 # then start scanning prev - 13 <- 5 - 14 <- 1 # list back at start + 0 <- 0 # no modifications to null pointers + 1 <- 34 + 2 <- 35 + 5 <- 5 # scanning next + 6 <- 4 + 7 <- 3 + 8 <- 0 # null + 9 <- 0 # first of null + 10 <- 0 # next of null + 11 <- 0 # prev of null + 12 <- 4 # then start scanning prev + 13 <- 5 + 14 <- 1 # list back at start ] ] @@ -133,134 +133,134 @@ container duplex-list [ x:location <- next-ingredient in:address:duplex-list <- next-ingredient new-node:address:duplex-list <- new duplex-list:type - val:address:location <- get-address new-node:address:duplex-list/deref, value:offset - val:address:location/deref <- copy x:location - next-node:address:duplex-list <- get in:address:duplex-list/deref, next:offset + val:address:location <- get-address *new-node, value:offset + *val <- copy x + next-node:address:duplex-list <- get *in, next:offset # in.next = new-node - y:address:address:duplex-list <- get-address in:address:duplex-list/deref, next:offset - y:address:address:duplex-list/deref <- copy new-node:address:duplex-list + y:address:address:duplex-list <- get-address *in, next:offset + *y <- copy new-node # new-node.prev = in - y:address:address:duplex-list <- get-address new-node:address:duplex-list/deref, prev:offset - y:address:address:duplex-list/deref <- copy in:address:duplex-list + y <- get-address *new-node, prev:offset + *y <- copy in # new-node.next = next-node - y:address:address:duplex-list <- get-address new-node:address:duplex-list/deref, next:offset - y:address:address:duplex-list/deref <- copy next-node:address:duplex-list + y <- get-address *new-node, next:offset + *y <- copy next-node # if next-node is not null - reply-unless next-node:address:duplex-list, new-node:address:duplex-list + reply-unless next-node, new-node # next-node.prev = new-node - y:address:address:duplex-list <- get-address next-node:address:duplex-list/deref, prev:offset - y:address:address:duplex-list/deref <- copy new-node:address:duplex-list - reply new-node:address:duplex-list # just signalling something changed; don't rely on the result + y <- get-address *next-node, prev:offset + *y <- copy new-node + reply new-node # just signalling something changed; don't rely on the result ] scenario inserting-into-duplex-list [ run [ - 1:address:duplex-list <- copy 0:literal # 1 points to head of list - 1:address:duplex-list <- push-duplex 3:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 4:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 5:literal, 1:address:duplex-list - 2:address:duplex-list <- next-duplex 1:address:duplex-list # 2 points inside list - 2:address:duplex-list <- insert-duplex 6:literal, 2:address:duplex-list + 1:address:duplex-list <- copy 0 # 1 points to head of list + 1:address:duplex-list <- push-duplex 3, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 4, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 5, 1:address:duplex-list + 2:address:duplex-list <- next-duplex 1:address:duplex-list # 2 points inside list + 2:address:duplex-list <- insert-duplex 6, 2:address:duplex-list # check structure like before - 2:address:duplex-list <- copy 1:address:duplex-list - 3:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 4:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 5:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 6:number <- first 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 7:number <- first 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 8:number <- first 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 9:number <- first 2:address:duplex-list - 10:boolean <- equal 1:address:duplex-list, 2:address:duplex-list + 2:address:duplex-list <- copy 1:address:duplex-list + 3:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 4:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 5:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 6:number <- first 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 7:number <- first 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 8:number <- first 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 9:number <- first 2:address:duplex-list + 10:boolean <- equal 1:address:duplex-list, 2:address:duplex-list ] memory-should-contain [ - 3 <- 5 # scanning next - 4 <- 4 - 5 <- 6 # inserted element - 6 <- 3 - 7 <- 6 # then prev - 8 <- 4 - 9 <- 5 - 10 <- 1 # list back at start + 3 <- 5 # scanning next + 4 <- 4 + 5 <- 6 # inserted element + 6 <- 3 + 7 <- 6 # then prev + 8 <- 4 + 9 <- 5 + 10 <- 1 # list back at start ] ] scenario inserting-at-end-of-duplex-list [ run [ - 1:address:duplex-list <- copy 0:literal # 1 points to head of list - 1:address:duplex-list <- push-duplex 3:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 4:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 5:literal, 1:address:duplex-list - 2:address:duplex-list <- next-duplex 1:address:duplex-list # 2 points inside list - 2:address:duplex-list <- next-duplex 2:address:duplex-list # now at end of list - 2:address:duplex-list <- insert-duplex 6:literal, 2:address:duplex-list + 1:address:duplex-list <- copy 0 # 1 points to head of list + 1:address:duplex-list <- push-duplex 3, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 4, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 5, 1:address:duplex-list + 2:address:duplex-list <- next-duplex 1:address:duplex-list # 2 points inside list + 2:address:duplex-list <- next-duplex 2:address:duplex-list # now at end of list + 2:address:duplex-list <- insert-duplex 6, 2:address:duplex-list # check structure like before - 2:address:duplex-list <- copy 1:address:duplex-list - 3:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 4:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 5:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 6:number <- first 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 7:number <- first 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 8:number <- first 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 9:number <- first 2:address:duplex-list - 10:boolean <- equal 1:address:duplex-list, 2:address:duplex-list + 2:address:duplex-list <- copy 1:address:duplex-list + 3:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 4:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 5:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 6:number <- first 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 7:number <- first 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 8:number <- first 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 9:number <- first 2:address:duplex-list + 10:boolean <- equal 1:address:duplex-list, 2:address:duplex-list ] memory-should-contain [ - 3 <- 5 # scanning next - 4 <- 4 - 5 <- 3 - 6 <- 6 # inserted element - 7 <- 3 # then prev - 8 <- 4 - 9 <- 5 - 10 <- 1 # list back at start + 3 <- 5 # scanning next + 4 <- 4 + 5 <- 3 + 6 <- 6 # inserted element + 7 <- 3 # then prev + 8 <- 4 + 9 <- 5 + 10 <- 1 # list back at start ] ] scenario inserting-after-start-of-duplex-list [ run [ - 1:address:duplex-list <- copy 0:literal # 1 points to head of list - 1:address:duplex-list <- push-duplex 3:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 4:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 5:literal, 1:address:duplex-list - 2:address:duplex-list <- insert-duplex 6:literal, 1:address:duplex-list + 1:address:duplex-list <- copy 0 # 1 points to head of list + 1:address:duplex-list <- push-duplex 3, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 4, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 5, 1:address:duplex-list + 2:address:duplex-list <- insert-duplex 6, 1:address:duplex-list # check structure like before - 2:address:duplex-list <- copy 1:address:duplex-list - 3:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 4:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 5:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 6:number <- first 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 7:number <- first 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 8:number <- first 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 9:number <- first 2:address:duplex-list - 10:boolean <- equal 1:address:duplex-list, 2:address:duplex-list + 2:address:duplex-list <- copy 1:address:duplex-list + 3:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 4:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 5:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 6:number <- first 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 7:number <- first 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 8:number <- first 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 9:number <- first 2:address:duplex-list + 10:boolean <- equal 1:address:duplex-list, 2:address:duplex-list ] memory-should-contain [ - 3 <- 5 # scanning next - 4 <- 6 # inserted element - 5 <- 4 - 6 <- 3 - 7 <- 4 # then prev - 8 <- 6 - 9 <- 5 - 10 <- 1 # list back at start + 3 <- 5 # scanning next + 4 <- 6 # inserted element + 5 <- 4 + 6 <- 3 + 7 <- 4 # then prev + 8 <- 6 + 9 <- 5 + 10 <- 1 # list back at start ] ] @@ -274,131 +274,131 @@ container duplex-list [ local-scope in:address:duplex-list <- next-ingredient # if 'in' is null, return - reply-unless in:address:duplex-list, in:address:duplex-list - next-node:address:duplex-list <- get in:address:duplex-list/deref, next:offset - prev-node:address:duplex-list <- get in:address:duplex-list/deref, prev:offset + reply-unless in, in + next-node:address:duplex-list <- get *in, next:offset + prev-node:address:duplex-list <- get *in, prev:offset # null in's pointers - x:address:address:duplex-list <- get-address in:address:duplex-list/deref, next:offset - x:address:address:duplex-list/deref <- copy 0:literal - x:address:address:duplex-list <- get-address in:address:duplex-list/deref, prev:offset - x:address:address:duplex-list/deref <- copy 0:literal + x:address:address:duplex-list <- get-address *in, next:offset + *x <- copy 0 + x <- get-address *in, prev:offset + *x <- copy 0 { # if next-node is not null - break-unless next-node:address:duplex-list + break-unless next-node # next-node.prev = prev-node - x:address:address:duplex-list <- get-address next-node:address:duplex-list/deref, prev:offset - x:address:address:duplex-list/deref <- copy prev-node:address:duplex-list + x <- get-address *next-node, prev:offset + *x <- copy prev-node } { # if prev-node is not null - break-unless prev-node:address:duplex-list + break-unless prev-node # prev-node.next = next-node - x:address:address:duplex-list <- get-address prev-node:address:duplex-list/deref, next:offset - x:address:address:duplex-list/deref <- copy next-node:address:duplex-list - reply prev-node:address:duplex-list + x <- get-address *prev-node, next:offset + *x <- copy next-node + reply prev-node } - reply next-node:address:duplex-list + reply next-node ] scenario removing-from-duplex-list [ run [ - 1:address:duplex-list <- copy 0:literal # 1 points to head of list - 1:address:duplex-list <- push-duplex 3:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 4:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 5:literal, 1:address:duplex-list - 2:address:duplex-list <- next-duplex 1:address:duplex-list # 2 points at second element - 2:address:duplex-list <- remove-duplex 2:address:duplex-list - 3:boolean <- equal 2:address:duplex-list, 0:literal + 1:address:duplex-list <- copy 0 # 1 points to head of list + 1:address:duplex-list <- push-duplex 3, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 4, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 5, 1:address:duplex-list + 2:address:duplex-list <- next-duplex 1:address:duplex-list # 2 points at second element + 2:address:duplex-list <- remove-duplex 2:address:duplex-list + 3:boolean <- equal 2:address:duplex-list, 0 # check structure like before - 2:address:duplex-list <- copy 1:address:duplex-list - 4:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 5:number <- first 2:address:duplex-list - 6:address:duplex-list <- next-duplex 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 7:number <- first 2:address:duplex-list - 8:boolean <- equal 1:address:duplex-list, 2:address:duplex-list + 2:address:duplex-list <- copy 1:address:duplex-list + 4:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 5:number <- first 2:address:duplex-list + 6:address:duplex-list <- next-duplex 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 7:number <- first 2:address:duplex-list + 8:boolean <- equal 1:address:duplex-list, 2:address:duplex-list ] memory-should-contain [ - 3 <- 0 # remove returned non-null - 4 <- 5 # scanning next, skipping deleted element - 5 <- 3 - 6 <- 0 # no more elements - 7 <- 5 # prev of final element - 8 <- 1 # list back at start + 3 <- 0 # remove returned non-null + 4 <- 5 # scanning next, skipping deleted element + 5 <- 3 + 6 <- 0 # no more elements + 7 <- 5 # prev of final element + 8 <- 1 # list back at start ] ] scenario removing-from-start-of-duplex-list [ run [ - 1:address:duplex-list <- copy 0:literal # 1 points to head of list - 1:address:duplex-list <- push-duplex 3:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 4:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 5:literal, 1:address:duplex-list + 1:address:duplex-list <- copy 0 # 1 points to head of list + 1:address:duplex-list <- push-duplex 3, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 4, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 5, 1:address:duplex-list # removing from head? return value matters. - 1:address:duplex-list <- remove-duplex 1:address:duplex-list + 1:address:duplex-list <- remove-duplex 1:address:duplex-list # check structure like before - 2:address:duplex-list <- copy 1:address:duplex-list - 3:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 4:number <- first 2:address:duplex-list - 5:address:duplex-list <- next-duplex 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 6:number <- first 2:address:duplex-list - 7:boolean <- equal 1:address:duplex-list, 2:address:duplex-list + 2:address:duplex-list <- copy 1:address:duplex-list + 3:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 4:number <- first 2:address:duplex-list + 5:address:duplex-list <- next-duplex 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 6:number <- first 2:address:duplex-list + 7:boolean <- equal 1:address:duplex-list, 2:address:duplex-list ] memory-should-contain [ - 3 <- 4 # scanning next, skipping deleted element - 4 <- 3 - 5 <- 0 # no more elements - 6 <- 4 # prev of final element - 7 <- 1 # list back at start + 3 <- 4 # scanning next, skipping deleted element + 4 <- 3 + 5 <- 0 # no more elements + 6 <- 4 # prev of final element + 7 <- 1 # list back at start ] ] scenario removing-from-end-of-duplex-list [ run [ - 1:address:duplex-list <- copy 0:literal # 1 points to head of list - 1:address:duplex-list <- push-duplex 3:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 4:literal, 1:address:duplex-list - 1:address:duplex-list <- push-duplex 5:literal, 1:address:duplex-list + 1:address:duplex-list <- copy 0 # 1 points to head of list + 1:address:duplex-list <- push-duplex 3, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 4, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 5, 1:address:duplex-list # delete last element - 2:address:duplex-list <- next-duplex 1:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 2:address:duplex-list <- remove-duplex 2:address:duplex-list - 3:boolean <- equal 2:address:duplex-list, 0:literal + 2:address:duplex-list <- next-duplex 1:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 2:address:duplex-list <- remove-duplex 2:address:duplex-list + 3:boolean <- equal 2:address:duplex-list, 0 # check structure like before - 2:address:duplex-list <- copy 1:address:duplex-list - 4:number <- first 2:address:duplex-list - 2:address:duplex-list <- next-duplex 2:address:duplex-list - 5:number <- first 2:address:duplex-list - 6:address:duplex-list <- next-duplex 2:address:duplex-list - 2:address:duplex-list <- prev-duplex 2:address:duplex-list - 7:number <- first 2:address:duplex-list - 8:boolean <- equal 1:address:duplex-list, 2:address:duplex-list + 2:address:duplex-list <- copy 1:address:duplex-list + 4:number <- first 2:address:duplex-list + 2:address:duplex-list <- next-duplex 2:address:duplex-list + 5:number <- first 2:address:duplex-list + 6:address:duplex-list <- next-duplex 2:address:duplex-list + 2:address:duplex-list <- prev-duplex 2:address:duplex-list + 7:number <- first 2:address:duplex-list + 8:boolean <- equal 1:address:duplex-list, 2:address:duplex-list ] memory-should-contain [ - 3 <- 0 # remove returned non-null - 4 <- 5 # scanning next, skipping deleted element - 5 <- 4 - 6 <- 0 # no more elements - 7 <- 5 # prev of final element - 8 <- 1 # list back at start + 3 <- 0 # remove returned non-null + 4 <- 5 # scanning next, skipping deleted element + 5 <- 4 + 6 <- 0 # no more elements + 7 <- 5 # prev of final element + 8 <- 1 # list back at start ] ] scenario removing-from-singleton-list [ run [ - 1:address:duplex-list <- copy 0:literal # 1 points to singleton list - 1:address:duplex-list <- push-duplex 3:literal, 1:address:duplex-list - 2:address:duplex-list <- remove-duplex 1:address:duplex-list - 3:address:duplex-list <- get 1:address:duplex-list/deref, next:offset - 4:address:duplex-list <- get 1:address:duplex-list/deref, prev:offset + 1:address:duplex-list <- copy 0 # 1 points to singleton list + 1:address:duplex-list <- push-duplex 3, 1:address:duplex-list + 2:address:duplex-list <- remove-duplex 1:address:duplex-list + 3:address:duplex-list <- get *1:address:duplex-list, next:offset + 4:address:duplex-list <- get *1:address:duplex-list, prev:offset ] memory-should-contain [ - 2 <- 0 # remove returned null - 3 <- 0 # removed node is also detached - 4 <- 0 + 2 <- 0 # remove returned null + 3 <- 0 # removed node is also detached + 4 <- 0 ] ] diff --git a/html/066stream.mu.html b/html/066stream.mu.html index cd1ef1de..ad7aebdf 100644 --- a/html/066stream.mu.html +++ b/html/066stream.mu.html @@ -13,11 +13,11 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -38,40 +38,40 @@ container stream [ recipe new-stream [ local-scope result:address:stream <- new stream:type - i:address:number <- get-address result:address:stream/deref, index:offset - i:address:number/deref <- copy 0:literal - d:address:address:array:character <- get-address result:address:stream/deref, data:offset - d:address:address:array:character/deref <- next-ingredient - reply result:address:stream + i:address:number <- get-address *result, index:offset + *i <- copy 0 + d:address:address:array:character <- get-address *result, data:offset + *d <- next-ingredient + reply result ] recipe rewind-stream [ local-scope in:address:stream <- next-ingredient - x:address:number <- get-address in:address:stream/deref, index:offset - x:address:number/deref <- copy 0:literal - reply in:address:stream/same-as-arg:0 + x:address:number <- get-address *in, index:offset + *x <- copy 0 + reply in/same-as-arg:0 ] recipe read-line [ local-scope in:address:stream <- next-ingredient - idx:address:number <- get-address in:address:stream/deref, index:offset - s:address:array:character <- get in:address:stream/deref, data:offset - next-idx:number <- find-next s:address:array:character, 10:literal/newline, idx:address:number/deref - result:address:array:character <- string-copy s:address:array:character, idx:address:number/deref, next-idx:number - idx:address:number/deref <- add next-idx:number, 1:literal # skip newline - reply result:address:array:character + idx:address:number <- get-address *in, index:offset + s:address:array:character <- get *in, data:offset + next-idx:number <- find-next s, 10/newline, *idx + result:address:array:character <- string-copy s, *idx, next-idx + *idx <- add next-idx, 1 # skip newline + reply result ] recipe end-of-stream? [ local-scope in:address:stream <- next-ingredient - idx:number <- get in:address:stream/deref, index:offset - s:address:array:character <- get in:address:stream/deref, data:offset - len:number <- length s:address:array:character/deref - result:boolean <- greater-or-equal idx:number, len:number - reply result:boolean + idx:address:number <- get *in, index:offset + s:address:array:character <- get *in, data:offset + len:number <- length *s + result:boolean <- greater-or-equal idx, len + reply result ] diff --git a/html/070display.cc.html b/html/070display.cc.html index e09146cb..986d56be 100644 --- a/html/070display.cc.html +++ b/html/070display.cc.html @@ -14,11 +14,10 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background- body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .cSpecial { color: #008000; } -.SalientComment { color: #00ffff; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } +.SalientComment { color: #00ffff; } .CommentedCode { color: #6c6c6c; } .Identifier { color: #804000; } --> @@ -41,15 +40,15 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } //:: Display management :(before "End Globals") -long long int Display_row = 0, Display_column = 0; -bool Autodisplay = true; +long long int Display_row = 0, Display_column = 0; +bool Autodisplay = true; :(before "End Primitive Recipe Declarations") OPEN_CONSOLE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["open-console"] = OPEN_CONSOLE; :(before "End Primitive Recipe Implementations") -case OPEN_CONSOLE: { +case OPEN_CONSOLE: { tb_init(); Display_row = Display_column = 0; break; @@ -60,7 +59,7 @@ CLOSE_CONSOLE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["close-console"] = CLOSE_CONSOLE; :(before "End Primitive Recipe Implementations") -case CLOSE_CONSOLE: { +case CLOSE_CONSOLE: { tb_shutdown(); //? Trace_stream->dump_layer = "all"; //? 1 break; @@ -74,7 +73,7 @@ CLEAR_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["clear-display"] = CLEAR_DISPLAY; :(before "End Primitive Recipe Implementations") -case CLEAR_DISPLAY: { +case CLEAR_DISPLAY: { tb_clear(); Display_row = Display_column = 0; break; @@ -85,13 +84,13 @@ CLEAR_LINE_ON_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["clear-line-on-display"] = CLEAR_LINE_ON_DISPLAY; :(before "End Primitive Recipe Implementations") -case CLEAR_LINE_ON_DISPLAY: { - long long int width = tb_width(); - for (long long int x = Display_column; x < width; ++x) { +case CLEAR_LINE_ON_DISPLAY: { + long long int width = tb_width(); + for (long long int x = Display_column; x < width; ++x) { tb_change_cell(x, Display_row, ' ', TB_WHITE, TB_BLACK); } tb_set_cursor(Display_column, Display_row); - if (Autodisplay) tb_present(); + if (Autodisplay) tb_present(); break; } @@ -100,60 +99,60 @@ PRINT_CHARACTER_TO_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["print-character-to-display"] = PRINT_CHARACTER_TO_DISPLAY; :(before "End Primitive Recipe Implementations") -case PRINT_CHARACTER_TO_DISPLAY: { - int h=tb_height(), w=tb_width(); - long long int height = (h >= 0) ? h : 0; - long long int width = (w >= 0) ? w : 0; - if (ingredients.empty()) { +case PRINT_CHARACTER_TO_DISPLAY: { + int h=tb_height(), w=tb_width(); + long long int height = (h >= 0) ? h : 0; + long long int width = (w >= 0) ? w : 0; + if (ingredients.empty()) { raise << current_recipe_name() << ": 'print-character-to-display' requires at least one ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'print-character-to-display' should be a character, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } - long long int c = ingredients.at(0).at(0); - int color = TB_BLACK; - if (SIZE(ingredients) > 1) { - if (!scalar(ingredients.at(1))) { + long long int c = ingredients.at(0).at(0); + int color = TB_BLACK; + if (SIZE(ingredients) > 1) { + if (!scalar(ingredients.at(1))) { raise << current_recipe_name() << ": second ingredient of 'print-character-to-display' should be a foreground color number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); break; } color = ingredients.at(1).at(0); } - int bg_color = TB_BLACK; - if (SIZE(ingredients) > 2) { - if (!scalar(ingredients.at(2))) { + int bg_color = TB_BLACK; + if (SIZE(ingredients) > 2) { + if (!scalar(ingredients.at(2))) { raise << current_recipe_name() << ": third ingredient of 'print-character-to-display' should be a background color number, but got " << current_instruction().ingredients.at(2).original_string << '\n' << end(); break; } bg_color = ingredients.at(2).at(0); - if (bg_color == 0) bg_color = TB_BLACK; + if (bg_color == 0) bg_color = TB_BLACK; } tb_change_cell(Display_column, Display_row, c, color, bg_color); - if (c == '\n' || c == '\r') { - if (Display_row < height-1) { + if (c == '\n' || c == '\r') { + if (Display_row < height-1) { Display_column = 0; ++Display_row; tb_set_cursor(Display_column, Display_row); - if (Autodisplay) tb_present(); + if (Autodisplay) tb_present(); } break; } - if (c == '\b') { - if (Display_column > 0) { + if (c == '\b') { + if (Display_column > 0) { tb_change_cell(Display_column-1, Display_row, ' ', color, bg_color); --Display_column; tb_set_cursor(Display_column, Display_row); - if (Autodisplay) tb_present(); + if (Autodisplay) tb_present(); } break; } - if (Display_column < width-1) { + if (Display_column < width-1) { ++Display_column; tb_set_cursor(Display_column, Display_row); } - if (Autodisplay) tb_present(); + if (Autodisplay) tb_present(); break; } @@ -162,7 +161,7 @@ CURSOR_POSITION_ON_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["cursor-position-on-display"] = CURSOR_POSITION_ON_DISPLAY; :(before "End Primitive Recipe Implementations") -case CURSOR_POSITION_ON_DISPLAY: { +case CURSOR_POSITION_ON_DISPLAY: { products.resize(2); products.at(0).push_back(Display_row); products.at(1).push_back(Display_column); @@ -174,23 +173,23 @@ MOVE_CURSOR_ON_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["move-cursor-on-display"] = MOVE_CURSOR_ON_DISPLAY; :(before "End Primitive Recipe Implementations") -case MOVE_CURSOR_ON_DISPLAY: { - if (SIZE(ingredients) != 2) { +case MOVE_CURSOR_ON_DISPLAY: { + if (SIZE(ingredients) != 2) { raise << current_recipe_name() << ": 'move-cursor-on-display' requires two ingredients, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'move-cursor-on-display' should be a row number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } Display_row = ingredients.at(0).at(0); - if (!scalar(ingredients.at(1))) { + if (!scalar(ingredients.at(1))) { raise << current_recipe_name() << ": second ingredient of 'move-cursor-on-display' should be a column number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); break; } Display_column = ingredients.at(1).at(0); tb_set_cursor(Display_column, Display_row); - if (Autodisplay) tb_present(); + if (Autodisplay) tb_present(); break; } @@ -199,13 +198,13 @@ MOVE_CURSOR_DOWN_ON_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["move-cursor-down-on-display"] = MOVE_CURSOR_DOWN_ON_DISPLAY; :(before "End Primitive Recipe Implementations") -case MOVE_CURSOR_DOWN_ON_DISPLAY: { - int h=tb_height(); - long long int height = (h >= 0) ? h : 0; - if (Display_row < height-1) { +case MOVE_CURSOR_DOWN_ON_DISPLAY: { + int h=tb_height(); + long long int height = (h >= 0) ? h : 0; + if (Display_row < height-1) { Display_row++; tb_set_cursor(Display_column, Display_row); - if (Autodisplay) tb_present(); + if (Autodisplay) tb_present(); } break; } @@ -215,11 +214,11 @@ MOVE_CURSOR_UP_ON_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["move-cursor-up-on-display"] = MOVE_CURSOR_UP_ON_DISPLAY; :(before "End Primitive Recipe Implementations") -case MOVE_CURSOR_UP_ON_DISPLAY: { - if (Display_row > 0) { +case MOVE_CURSOR_UP_ON_DISPLAY: { + if (Display_row > 0) { Display_row--; tb_set_cursor(Display_column, Display_row); - if (Autodisplay) tb_present(); + if (Autodisplay) tb_present(); } break; } @@ -229,13 +228,13 @@ MOVE_CURSOR_RIGHT_ON_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["move-cursor-right-on-display"] = MOVE_CURSOR_RIGHT_ON_DISPLAY; :(before "End Primitive Recipe Implementations") -case MOVE_CURSOR_RIGHT_ON_DISPLAY: { - int w=tb_width(); - long long int width = (w >= 0) ? w : 0; - if (Display_column < width-1) { +case MOVE_CURSOR_RIGHT_ON_DISPLAY: { + int w=tb_width(); + long long int width = (w >= 0) ? w : 0; + if (Display_column < width-1) { Display_column++; tb_set_cursor(Display_column, Display_row); - if (Autodisplay) tb_present(); + if (Autodisplay) tb_present(); } break; } @@ -245,11 +244,11 @@ MOVE_CURSOR_LEFT_ON_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["move-cursor-left-on-display"] = MOVE_CURSOR_LEFT_ON_DISPLAY; :(before "End Primitive Recipe Implementations") -case MOVE_CURSOR_LEFT_ON_DISPLAY: { - if (Display_column > 0) { +case MOVE_CURSOR_LEFT_ON_DISPLAY: { + if (Display_column > 0) { Display_column--; tb_set_cursor(Display_column, Display_row); - if (Autodisplay) tb_present(); + if (Autodisplay) tb_present(); } break; } @@ -259,7 +258,7 @@ DISPLAY_WIDTH, :(before "End Primitive Recipe Numbers") Recipe_ordinal["display-width"] = DISPLAY_WIDTH; :(before "End Primitive Recipe Implementations") -case DISPLAY_WIDTH: { +case DISPLAY_WIDTH: { products.resize(1); products.at(0).push_back(tb_width()); break; @@ -270,7 +269,7 @@ DISPLAY_HEIGHT, :(before "End Primitive Recipe Numbers") Recipe_ordinal["display-height"] = DISPLAY_HEIGHT; :(before "End Primitive Recipe Implementations") -case DISPLAY_HEIGHT: { +case DISPLAY_HEIGHT: { products.resize(1); products.at(0).push_back(tb_height()); break; @@ -281,7 +280,7 @@ HIDE_CURSOR_ON_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["hide-cursor-on-display"] = HIDE_CURSOR_ON_DISPLAY; :(before "End Primitive Recipe Implementations") -case HIDE_CURSOR_ON_DISPLAY: { +case HIDE_CURSOR_ON_DISPLAY: { tb_set_cursor(TB_HIDE_CURSOR, TB_HIDE_CURSOR); break; } @@ -291,7 +290,7 @@ SHOW_CURSOR_ON_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["show-cursor-on-display"] = SHOW_CURSOR_ON_DISPLAY; :(before "End Primitive Recipe Implementations") -case SHOW_CURSOR_ON_DISPLAY: { +case SHOW_CURSOR_ON_DISPLAY: { tb_set_cursor(Display_row, Display_column); break; } @@ -301,7 +300,7 @@ HIDE_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["hide-display"] = HIDE_DISPLAY; :(before "End Primitive Recipe Implementations") -case HIDE_DISPLAY: { +case HIDE_DISPLAY: { Autodisplay = false; break; } @@ -311,7 +310,7 @@ SHOW_DISPLAY, :(before "End Primitive Recipe Numbers") Recipe_ordinal["show-display"] = SHOW_DISPLAY; :(before "End Primitive Recipe Implementations") -case SHOW_DISPLAY: { +case SHOW_DISPLAY: { Autodisplay = true; tb_present(); break; @@ -324,7 +323,7 @@ WAIT_FOR_SOME_INTERACTION, :(before "End Primitive Recipe Numbers") Recipe_ordinal["wait-for-some-interaction"] = WAIT_FOR_SOME_INTERACTION; :(before "End Primitive Recipe Implementations") -case WAIT_FOR_SOME_INTERACTION: { +case WAIT_FOR_SOME_INTERACTION: { tb_event event; tb_poll_event(&event); break; @@ -335,11 +334,11 @@ CHECK_FOR_INTERACTION, :(before "End Primitive Recipe Numbers") Recipe_ordinal["check-for-interaction"] = CHECK_FOR_INTERACTION; :(before "End Primitive Recipe Implementations") -case CHECK_FOR_INTERACTION: { +case CHECK_FOR_INTERACTION: { products.resize(2); // result and status tb_event event; - int event_type = tb_peek_event(&event, 5/*ms*/); - if (event_type == TB_EVENT_KEY && event.ch) { + int event_type = tb_peek_event(&event, 5/*ms*/); + if (event_type == TB_EVENT_KEY && event.ch) { products.at(0).push_back(/*text event*/0); products.at(0).push_back(event.ch); products.at(0).push_back(0); @@ -348,11 +347,11 @@ Recipe_ordinal["check-for-interaction"] break; } // treat keys within ascii as unicode characters - if (event_type == TB_EVENT_KEY && event.key < 0xff) { + if (event_type == TB_EVENT_KEY && event.key < 0xff) { products.at(0).push_back(/*text event*/0); - if (event.key == TB_KEY_CTRL_C) tb_shutdown(), exit(1); - if (event.key == TB_KEY_BACKSPACE2) event.key = TB_KEY_BACKSPACE; - if (event.key == TB_KEY_CARRIAGE_RETURN) event.key = TB_KEY_NEWLINE; + if (event.key == TB_KEY_CTRL_C) tb_shutdown(), exit(1); + if (event.key == TB_KEY_BACKSPACE2) event.key = TB_KEY_BACKSPACE; + if (event.key == TB_KEY_CARRIAGE_RETURN) event.key = TB_KEY_NEWLINE; products.at(0).push_back(event.key); products.at(0).push_back(0); products.at(0).push_back(0); @@ -360,7 +359,7 @@ Recipe_ordinal["check-for-interaction"] break; } // keys outside ascii aren't unicode characters but arbitrary termbox inventions - if (event_type == TB_EVENT_KEY) { + if (event_type == TB_EVENT_KEY) { products.at(0).push_back(/*keycode event*/1); products.at(0).push_back(event.key); products.at(0).push_back(0); @@ -368,7 +367,7 @@ Recipe_ordinal["check-for-interaction"] products.at(1).push_back(/*found*/true); break; } - if (event_type == TB_EVENT_MOUSE) { + if (event_type == TB_EVENT_MOUSE) { //? tb_shutdown(); //? 1 //? cerr << "AAA\n"; //? 1 products.at(0).push_back(/*touch event*/2); @@ -392,7 +391,7 @@ INTERACTIONS_LEFT, :(before "End Primitive Recipe Numbers") Recipe_ordinal["interactions-left?"] = INTERACTIONS_LEFT; :(before "End Primitive Recipe Implementations") -case INTERACTIONS_LEFT: { +case INTERACTIONS_LEFT: { products.resize(1); products.at(0).push_back(tb_event_ready()); break; diff --git a/html/071print.mu.html b/html/071print.mu.html index e622b83f..fb8d0ae7 100644 --- a/html/071print.mu.html +++ b/html/071print.mu.html @@ -13,14 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } -.muScenario { color: #00af00; } +.muRecipe { color: #ff8700; } .Delimiter { color: #a04060; } -.CommentedCode { color: #6c6c6c; } +.muScenario { color: #00af00; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } +.CommentedCode { color: #6c6c6c; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -51,676 +51,670 @@ container screen-cell [ recipe new-fake-screen [ local-scope result:address:screen <- new screen:type - width:address:number <- get-address result:address:screen/deref, num-columns:offset - width:address:number/deref <- next-ingredient - height:address:number <- get-address result:address:screen/deref, num-rows:offset - height:address:number/deref <- next-ingredient -#? $print height:address:number/deref, 10:literal/newline - row:address:number <- get-address result:address:screen/deref, cursor-row:offset - row:address:number/deref <- copy 0:literal - 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: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 + width:address:number <- get-address *result, num-columns:offset + *width <- next-ingredient + height:address:number <- get-address *result, num-rows:offset + *height <- next-ingredient + row:address:number <- get-address *result, cursor-row:offset + *row <- copy 0 + column:address:number <- get-address *result, cursor-column:offset + *column <- copy 0 + bufsize:number <- multiply *width, *height + buf:address:address:array:screen-cell <- get-address *result, data:offset + *buf <- new screen-cell:type, bufsize + clear-screen result + reply result ] recipe clear-screen [ local-scope - x:address:screen <- next-ingredient -#? $print [clearing screen -#? ] #? 1 + sc:address:screen <- next-ingredient # if x exists { - break-unless x:address:screen + break-unless sc # clear fake screen - 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 + buf:address:array:screen-cell <- get *sc, data:offset + max:number <- length *buf + i:number <- copy 0 { - done?:boolean <- greater-or-equal i:number, max:number - break-if done?:boolean - 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 + done?:boolean <- greater-or-equal i, max + break-if done? + curr:address:screen-cell <- index-address *buf, i + curr-content:address:character <- get-address *curr, contents:offset + *curr-content <- copy [ ] + curr-color:address:character <- get-address *curr, color:offset + *curr-color <- copy 7/white + i <- add i, 1 loop } # reset cursor - cur:address:number <- get-address x:address:screen/deref, cursor-row:offset - cur:address:number/deref <- copy 0:literal - cur:address:number <- get-address x:address:screen/deref, cursor-column:offset - cur:address:number/deref <- copy 0:literal - reply x:address:screen/same-as-ingredient:0 + x:address:number <- get-address *sc, cursor-row:offset + *x <- copy 0 + x <- get-address *sc, cursor-column:offset + *x <- copy 0 + reply sc/same-as-ingredient:0 } # otherwise, real screen clear-display - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 ] -recipe fake-screen-is-clear? [ +recipe fake-screen-is-empty? [ local-scope - screen:address:screen <- next-ingredient - reply-unless screen:address:screen, 1:literal/true - buf:address:array:screen-cell <- get screen:address:screen/deref, data:offset - i:number <- copy 0:literal - len:number <- length buf:address:array:screen-cell/deref + sc:address:screen <- next-ingredient + reply-unless sc, 1/true + buf:address:array:screen-cell <- get *sc, data:offset + i:number <- copy 0 + len:number <- length *buf { - done?:boolean <- greater-or-equal i:number, len:number - break-if done?:boolean - curr:screen-cell <- index buf:address:array:screen-cell/deref, i:number - curr-contents:character <- get curr:screen-cell, contents:offset - i:number <- add i:number, 1:literal - loop-unless curr-contents:character + done?:boolean <- greater-or-equal i, len + break-if done? + curr:screen-cell <- index *buf, i + curr-contents:character <- get curr, contents:offset + i <- add i, 1 + loop-unless curr-contents # not 0 - reply 0:literal/false + reply 0/false } - reply 1:literal/true + reply 1/true ] recipe print-character [ local-scope - x:address:screen <- next-ingredient + sc: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 + break-if color-found? + color <- copy 7/white } bg-color:number, bg-color-found?:boolean <- next-ingredient { # default bg-color to black - break-if bg-color-found?:boolean - bg-color:number <- copy 0:literal/black + break-if bg-color-found? + bg-color <- copy 0/black } #? trace [app], [print character] #? 1 { # if x exists # (handle special cases exactly like in the real screen) - break-unless x:address:screen - width:number <- get x:address:screen/deref, num-columns:offset - height:number <- get x:address:screen/deref, num-rows:offset + break-unless sc + width:number <- get *sc, num-columns:offset + height:number <- get *sc, num-rows:offset # if cursor is out of bounds, silently exit - row:address:number <- get-address x:address:screen/deref, cursor-row:offset - legal?:boolean <- greater-or-equal row:address:number/deref, 0:literal - reply-unless legal?:boolean, x:address:screen - legal?:boolean <- lesser-than row:address:number/deref, height:number - reply-unless legal?:boolean, x:address:screen - column:address:number <- get-address x:address:screen/deref, cursor-column:offset - legal?:boolean <- greater-or-equal column:address:number/deref, 0:literal - reply-unless legal?:boolean, x:address:screen - legal?:boolean <- lesser-than column:address:number/deref, width:number - reply-unless legal?:boolean, x:address:screen + row:address:number <- get-address *sc, cursor-row:offset + legal?:boolean <- greater-or-equal *row, 0 + reply-unless legal?, sc + legal? <- lesser-than *row, height + reply-unless legal?, sc + column:address:number <- get-address *sc, cursor-column:offset + legal? <- greater-or-equal *column, 0 + reply-unless legal?, sc + legal? <- lesser-than *column, width + reply-unless legal?, sc # special-case: newline { - newline?:boolean <- equal c:character, 10:literal/newline -#? $print c:character, [ ], newline?:boolean, 10:literal/newline - break-unless newline?:boolean + newline?:boolean <- equal c, 10/newline +#? $print c, [ ], newline?, 10/newline + break-unless newline? { # unless cursor is already at bottom - bottom:number <- subtract height:number, 1:literal - at-bottom?:boolean <- greater-or-equal row:address:number/deref, bottom:number - break-if at-bottom?:boolean + bottom:number <- subtract height, 1 + at-bottom?:boolean <- greater-or-equal *row, bottom + break-if at-bottom? # move it to the next row - column:address:number/deref <- copy 0:literal - row:address:number/deref <- add row:address:number/deref, 1:literal + *column <- copy 0 + *row <- add *row, 1 } - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 } # 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:screen-cell <- get x:address:screen/deref, data:offset - len:number <- length buf:address:array:screen-cell/deref + index:number <- multiply *row, width + index <- add index, *column + buf:address:array:screen-cell <- get *sc, data:offset + len:number <- length *buf # special-case: backspace { - backspace?:boolean <- equal c:character, 8:literal - break-unless backspace?:boolean + backspace?:boolean <- equal c, 8 + break-unless backspace? { # unless cursor is already at left margin - at-left?:boolean <- lesser-or-equal column:address:number/deref, 0:literal - break-if at-left?:boolean + at-left?:boolean <- lesser-or-equal *column, 0 + break-if at-left? # clear previous location - column:address:number/deref <- subtract column:address:number/deref, 1:literal - 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 + *column <- subtract *column, 1 + index <- subtract index, 1 + cursor:address:screen-cell <- index-address *buf, index + cursor-contents:address:character <- get-address *cursor, contents:offset + *cursor-contents <- copy 32/space + cursor-color:address:number <- get-address *cursor, color:offset + *cursor-color <- copy 7/white } - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 } -#? $print [saving character ], c:character, [ to fake screen ], cursor:address/screen, 10:literal/newline - 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 +#? $print [saving character ], c, [ to fake screen ], cursor, 10/newline + cursor:address:screen-cell <- index-address *buf, index + cursor-contents:address:character <- get-address *cursor, contents:offset + *cursor-contents <- copy c + cursor-color:address:number <- get-address *cursor, color:offset + *cursor-color <- copy color # increment column unless it's already all the way to the right { - right:number <- subtract width:number, 1:literal - at-right?:boolean <- greater-or-equal column:address:number/deref, right:number - break-if at-right?:boolean - column:address:number/deref <- add column:address:number/deref, 1:literal + right:number <- subtract width, 1 + at-right?:boolean <- greater-or-equal *column, right + break-if at-right? + *column <- add *column, 1 } - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 } # otherwise, real screen - print-character-to-display c:character, color:number, bg-color:number - reply x:address:screen/same-as-ingredient:0 + print-character-to-display c, color, bg-color + reply sc/same-as-ingredient:0 ] scenario print-character-at-top-left [ run [ #? $start-tracing #? 3 - 1:address:screen <- new-fake-screen 3:literal/width, 2:literal/height - 1:address:screen <- print-character 1:address:screen, 97:literal # 'a' - 2:address:array:screen-cell <- get 1:address:screen/deref, data:offset - 3:array:screen-cell <- copy 2:address:array:screen-cell/deref + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 2:address:array:screen-cell <- get *1:address:screen, data:offset + 3:array:screen-cell <- copy *2:address:array:screen-cell ] memory-should-contain [ - 3 <- 6 # width*height - 4 <- 97 # 'a' - 5 <- 7 # white - 6 <- 0 + 3 <- 6 # width*height + 4 <- 97 # 'a' + 5 <- 7 # white + 6 <- 0 ] ] scenario print-character-color [ run [ - 1:address:screen <- new-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 + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97/a, 1/red + 2:address:array:screen-cell <- get *1:address:screen, data:offset + 3:array:screen-cell <- copy *2:address:array:screen-cell ] memory-should-contain [ - 3 <- 6 # width*height - 4 <- 97 # 'a' - 5 <- 1 # red - 6 <- 0 + 3 <- 6 # width*height + 4 <- 97 # 'a' + 5 <- 1 # red + 6 <- 0 ] ] scenario print-backspace-character [ run [ #? $start-tracing #? 3 - 1:address:screen <- new-fake-screen 3:literal/width, 2:literal/height - 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:screen-cell <- get 1:address:screen/deref, data:offset - 4:array:screen-cell <- copy 3:address:array:screen-cell/deref + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 1:address:screen <- print-character 1:address:screen, 8 # backspace + 2:number <- get *1:address:screen, cursor-column:offset + 3:address:array:screen-cell <- get *1:address:screen, data:offset + 4:array:screen-cell <- copy *3:address:array:screen-cell ] memory-should-contain [ - 2 <- 0 # cursor column - 4 <- 6 # width*height - 5 <- 32 # space, not 'a' - 6 <- 7 # white - 7 <- 0 + 2 <- 0 # cursor column + 4 <- 6 # width*height + 5 <- 32 # space, not 'a' + 6 <- 7 # white + 7 <- 0 ] ] scenario print-extra-backspace-character [ run [ - 1:address:screen <- new-fake-screen 3:literal/width, 2:literal/height - 1:address:screen <- print-character 1:address:screen, 97:literal # 'a' - 1:address:screen <- print-character 1:address:screen, 8:literal # backspace - 1:address:screen <- print-character 1:address:screen, 8:literal # backspace - 2:number <- get 1:address:screen/deref, cursor-column:offset - 3:address:array:screen-cell <- get 1:address:screen/deref, data:offset - 4:array:screen-cell <- copy 3:address:array:screen-cell/deref + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 1:address:screen <- print-character 1:address:screen, 8 # backspace + 1:address:screen <- print-character 1:address:screen, 8 # backspace + 2:number <- get *1:address:screen, cursor-column:offset + 3:address:array:screen-cell <- get *1:address:screen, data:offset + 4:array:screen-cell <- copy *3:address:array:screen-cell ] memory-should-contain [ - 2 <- 0 # cursor column - 4 <- 6 # width*height - 5 <- 32 # space, not 'a' - 6 <- 7 # white - 7 <- 0 + 2 <- 0 # cursor column + 4 <- 6 # width*height + 5 <- 32 # space, not 'a' + 6 <- 7 # white + 7 <- 0 ] ] scenario print-at-right-margin [ run [ - 1:address:screen <- new-fake-screen 2:literal/width, 2:literal/height - 1:address:screen <- print-character 1:address:screen, 97:literal # 'a' - 1:address:screen <- print-character 1:address:screen, 98:literal # 'b' - 1:address:screen <- print-character 1:address:screen, 99:literal # 'c' - 2:number <- get 1:address:screen/deref, cursor-column:offset - 3:address:array:screen-cell <- get 1:address:screen/deref, data:offset - 4:array:screen-cell <- copy 3:address:array:screen-cell/deref + 1:address:screen <- new-fake-screen 2/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 1:address:screen <- print-character 1:address:screen, 98 # 'b' + 1:address:screen <- print-character 1:address:screen, 99 # 'c' + 2:number <- get *1:address:screen, cursor-column:offset + 3:address:array:screen-cell <- get *1:address:screen, data:offset + 4:array:screen-cell <- copy *3:address:array:screen-cell ] memory-should-contain [ - 2 <- 1 # cursor column - 4 <- 4 # width*height - 5 <- 97 # 'a' - 6 <- 7 # white - 7 <- 99 # 'c' over 'b' - 8 <- 7 # white - 9 <- 0 + 2 <- 1 # cursor column + 4 <- 4 # width*height + 5 <- 97 # 'a' + 6 <- 7 # white + 7 <- 99 # 'c' over 'b' + 8 <- 7 # white + 9 <- 0 ] ] scenario print-newline-character [ run [ #? $start-tracing #? 3 - 1:address:screen <- new-fake-screen 3:literal/width, 2:literal/height - 1:address:screen <- print-character 1:address:screen, 97:literal # 'a' - 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:screen-cell <- get 1:address:screen/deref, data:offset - 5:array:screen-cell <- copy 4:address:array:screen-cell/deref + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 1:address:screen <- print-character 1:address:screen, 10/newline + 2:number <- get *1:address:screen, cursor-row:offset + 3:number <- get *1:address:screen, cursor-column:offset + 4:address:array:screen-cell <- get *1:address:screen, data:offset + 5:array:screen-cell <- copy *4:address:array:screen-cell ] memory-should-contain [ - 2 <- 1 # cursor row - 3 <- 0 # cursor column - 5 <- 6 # width*height - 6 <- 97 # 'a' - 7 <- 7 # white - 8 <- 0 + 2 <- 1 # cursor row + 3 <- 0 # cursor column + 5 <- 6 # width*height + 6 <- 97 # 'a' + 7 <- 7 # white + 8 <- 0 ] ] scenario print-newline-at-bottom-line [ run [ - 1:address:screen <- new-fake-screen 3:literal/width, 2:literal/height - 1:address:screen <- print-character 1:address:screen, 10:literal/newline - 1:address:screen <- print-character 1:address:screen, 10:literal/newline - 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 + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 10/newline + 1:address:screen <- print-character 1:address:screen, 10/newline + 1:address:screen <- print-character 1:address:screen, 10/newline + 2:number <- get *1:address:screen, cursor-row:offset + 3:number <- get *1:address:screen, cursor-column:offset ] memory-should-contain [ - 2 <- 1 # cursor row - 3 <- 0 # cursor column + 2 <- 1 # cursor row + 3 <- 0 # cursor column ] ] scenario print-at-bottom-right [ run [ - 1:address:screen <- new-fake-screen 2:literal/width, 2:literal/height - 1:address:screen <- print-character 1:address:screen, 10:literal/newline - 1:address:screen <- print-character 1:address:screen, 97:literal # 'a' - 1:address:screen <- print-character 1:address:screen, 98:literal # 'b' - 1:address:screen <- print-character 1:address:screen, 99:literal # 'c' - 1:address:screen <- print-character 1:address:screen, 10:literal/newline - 1:address:screen <- print-character 1:address:screen, 100:literal # 'd' - 2:number <- get 1:address:screen/deref, cursor-row:offset - 3:number <- get 1:address:screen/deref, cursor-column:offset - 4:address:array:screen-cell <- get 1:address:screen/deref, data:offset - 5:array:screen-cell <- copy 4:address:array:screen-cell/deref + 1:address:screen <- new-fake-screen 2/width, 2/height + 1:address:screen <- print-character 1:address:screen, 10/newline + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 1:address:screen <- print-character 1:address:screen, 98 # 'b' + 1:address:screen <- print-character 1:address:screen, 99 # 'c' + 1:address:screen <- print-character 1:address:screen, 10/newline + 1:address:screen <- print-character 1:address:screen, 100 # 'd' + 2:number <- get *1:address:screen, cursor-row:offset + 3:number <- get *1:address:screen, cursor-column:offset + 4:address:array:screen-cell <- get *1:address:screen, data:offset + 5:array:screen-cell <- copy *4:address:array:screen-cell ] memory-should-contain [ - 2 <- 1 # cursor row - 3 <- 1 # cursor column - 5 <- 4 # width*height - 6 <- 0 # unused - 7 <- 7 # white - 8 <- 0 # unused - 9 <- 7 # white - 10 <- 97 # 'a' - 11 <- 7 # white - 12 <- 100 # 'd' over 'b' and 'c' and newline - 13 <- 7 # white - 14 <- 0 + 2 <- 1 # cursor row + 3 <- 1 # cursor column + 5 <- 4 # width*height + 6 <- 0 # unused + 7 <- 7 # white + 8 <- 0 # unused + 9 <- 7 # white + 10 <- 97 # 'a' + 11 <- 7 # white + 12 <- 100 # 'd' over 'b' and 'c' and newline + 13 <- 7 # white + 14 <- 0 ] ] recipe clear-line [ local-scope - x:address:screen <- next-ingredient + sc:address:screen <- next-ingredient # if x exists, clear line in fake screen { - break-unless x:address:screen - width:number <- get x:address:screen/deref, num-columns:offset - column:address:number <- get-address x:address:screen/deref, cursor-column:offset - original-column:number <- copy column:address:number/deref + break-unless sc + width:number <- get *sc, num-columns:offset + column:address:number <- get-address *sc, cursor-column:offset + original-column:number <- copy *column # space over the entire line #? $start-tracing #? 1 { -#? $print column:address:number/deref, 10:literal/newline - right:number <- subtract width:number, 1:literal - done?:boolean <- greater-or-equal column:address:number/deref, right:number - break-if done?:boolean - print-character x:address:screen, [ ] # implicitly updates 'column' +#? $print *column, 10/newline + right:number <- subtract width, 1 + done?:boolean <- greater-or-equal *column, right + break-if done? + print-character sc, [ ] # implicitly updates 'column' loop } # now back to where the cursor was - column:address:number/deref <- copy original-column:number - reply x:address:screen/same-as-ingredient:0 + *column <- copy original-column + reply sc/same-as-ingredient:0 } # otherwise, real screen clear-line-on-display - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 ] recipe cursor-position [ local-scope - x:address:screen <- next-ingredient + sc:address:screen <- next-ingredient # if x exists, lookup cursor in fake screen { - break-unless x:address:screen - row:number <- get x:address:screen/deref, cursor-row:offset - column:number <- get x:address:screen/deref, cursor-column:offset - reply row:number, column:number, x:address:screen/same-as-ingredient:0 + break-unless sc + row:number <- get *sc, cursor-row:offset + column:number <- get *sc, cursor-column:offset + reply row, column, sc/same-as-ingredient:0 } - row:number, column:number <- cursor-position-on-display - reply row:number, column:number, x:address:screen/same-as-ingredient:0 + row, column <- cursor-position-on-display + reply row, column, sc/same-as-ingredient:0 ] recipe move-cursor [ local-scope - x:address:screen <- next-ingredient + sc:address:screen <- next-ingredient new-row:number <- next-ingredient new-column:number <- next-ingredient # if x exists, move cursor in fake screen { - break-unless x:address:screen - row:address:number <- get-address x:address:screen/deref, cursor-row:offset - row:address:number/deref <- copy new-row:number - column:address:number <- get-address x:address:screen/deref, cursor-column:offset - column:address:number/deref <- copy new-column:number - reply x:address:screen/same-as-ingredient:0 + break-unless sc + row:address:number <- get-address *sc, cursor-row:offset + *row <- copy new-row + column:address:number <- get-address *sc, cursor-column:offset + *column <- copy new-column + reply sc/same-as-ingredient:0 } # otherwise, real screen - move-cursor-on-display new-row:number, new-column:number - reply x:address:screen/same-as-ingredient:0 + move-cursor-on-display new-row, new-column + reply sc/same-as-ingredient:0 ] scenario clear-line-erases-printed-characters [ run [ #? $start-tracing #? 4 - 1:address:screen <- new-fake-screen 3:literal/width, 2:literal/height + 1:address:screen <- new-fake-screen 3/width, 2/height # print a character - 1:address:screen <- print-character 1:address:screen, 97:literal # 'a' + 1:address:screen <- print-character 1:address:screen, 97 # 'a' # move cursor to start of line - 1:address:screen <- move-cursor 1:address:screen, 0:literal/row, 0:literal/column + 1:address:screen <- move-cursor 1:address:screen, 0/row, 0/column # clear line - 1:address:screen <- clear-line 1:address:screen - 2:address:array:screen-cell <- get 1:address:screen/deref, data:offset - 3:array:screen-cell <- copy 2:address:array:screen-cell/deref + 1:address:screen <- clear-line 1:address:screen + 2:address:array:screen-cell <- get *1:address:screen, data:offset + 3:array:screen-cell <- copy *2:address:array:screen-cell ] # screen should be blank memory-should-contain [ - 3 <- 6 # width*height - 4 <- 0 - 5 <- 7 - 6 <- 0 - 7 <- 7 - 8 <- 0 - 9 <- 7 - 10 <- 0 - 11 <- 7 - 12 <- 0 - 13 <- 7 - 14 <- 0 - 15 <- 7 + 3 <- 6 # width*height + 4 <- 0 + 5 <- 7 + 6 <- 0 + 7 <- 7 + 8 <- 0 + 9 <- 7 + 10 <- 0 + 11 <- 7 + 12 <- 0 + 13 <- 7 + 14 <- 0 + 15 <- 7 ] ] recipe cursor-down [ local-scope - x:address:screen <- next-ingredient + sc:address:screen <- next-ingredient # if x exists, move cursor in fake screen { - break-unless x:address:screen + break-unless sc { # if row < height-1 - height:number <- get x:address:screen/deref, num-rows:offset - row:address:number <- get-address x:address:screen/deref, cursor-row:offset - max:number <- subtract height:number, 1:literal - at-bottom?:boolean <- greater-or-equal row:address:number/deref, max:number - break-if at-bottom?:boolean + height:number <- get *sc, num-rows:offset + row:address:number <- get-address *sc, cursor-row:offset + max:number <- subtract height, 1 + at-bottom?:boolean <- greater-or-equal *row, max + break-if at-bottom? # row = row+1 -#? $print [AAA: ], row:address:number, [ -> ], row:address:number/deref, 10:literal/newline - row:address:number/deref <- add row:address:number/deref, 1:literal -#? $print [BBB: ], row:address:number, [ -> ], row:address:number/deref, 10:literal/newline -#? $start-tracing #? 1 + *row <- add *row, 1 } - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 } # otherwise, real screen move-cursor-down-on-display - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 ] recipe cursor-up [ local-scope - x:address:screen <- next-ingredient + sc:address:screen <- next-ingredient # if x exists, move cursor in fake screen { - break-unless x:address:screen + break-unless sc { # if row > 0 - row:address:number <- get-address x:address:screen/deref, cursor-row:offset - at-top?:boolean <- lesser-or-equal row:address:number/deref, 0:literal - break-if at-top?:boolean + row:address:number <- get-address *sc, cursor-row:offset + at-top?:boolean <- lesser-or-equal *row, 0 + break-if at-top? # row = row-1 - row:address:number/deref <- subtract row:address:number/deref, 1:literal + *row <- subtract *row, 1 } - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 } # otherwise, real screen move-cursor-up-on-display - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 ] recipe cursor-right [ local-scope - x:address:screen <- next-ingredient + sc:address:screen <- next-ingredient # if x exists, move cursor in fake screen { - break-unless x:address:screen + break-unless sc { # if column < width-1 - width:number <- get x:address:screen/deref, num-columns:offset - column:address:number <- get-address x:address:screen/deref, cursor-column:offset - max:number <- subtract width:number, 1:literal - at-bottom?:boolean <- greater-or-equal column:address:number/deref, max:number - break-if at-bottom?:boolean + width:number <- get *sc, num-columns:offset + column:address:number <- get-address *sc, cursor-column:offset + max:number <- subtract width, 1 + at-bottom?:boolean <- greater-or-equal *column, max + break-if at-bottom? # column = column+1 - column:address:number/deref <- add column:address:number/deref, 1:literal + *column <- add *column, 1 } - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 } # otherwise, real screen move-cursor-right-on-display - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 ] recipe cursor-left [ local-scope - x:address:screen <- next-ingredient + sc:address:screen <- next-ingredient # if x exists, move cursor in fake screen { - break-unless x:address:screen + break-unless sc { # if column > 0 - column:address:number <- get-address x:address:screen/deref, cursor-column:offset - at-top?:boolean <- lesser-or-equal column:address:number/deref, 0:literal - break-if at-top?:boolean + column:address:number <- get-address *sc, cursor-column:offset + at-top?:boolean <- lesser-or-equal *column, 0 + break-if at-top? # column = column-1 - column:address:number/deref <- subtract column:address:number/deref, 1:literal + *column <- subtract *column, 1 } - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 } # otherwise, real screen move-cursor-left-on-display - reply x:address:screen/same-as-ingredient:0 + reply sc/same-as-ingredient:0 ] recipe cursor-to-start-of-line [ local-scope - x:address:screen <- next-ingredient - row:number, _, x:address:screen <- cursor-position x:address:screen - column:number <- copy 0:literal - x:address:screen <- move-cursor x:address:screen, row:number, column:number - reply x:address:screen/same-as-ingredient:0 + sc:address:screen <- next-ingredient + row:number, _, sc <- cursor-position sc + column:number <- copy 0 + sc <- move-cursor sc, row, column + reply sc/same-as-ingredient:0 ] recipe cursor-to-next-line [ local-scope - x:address:screen <- next-ingredient - x:address:screen <- cursor-down x:address:screen - x:address:screen <- cursor-to-start-of-line x:address:screen - reply x:address:screen/same-as-ingredient:0 + screen:address <- next-ingredient + screen <- cursor-down screen + screen <- cursor-to-start-of-line screen + reply screen/same-as-ingredient:0 ] recipe screen-width [ local-scope - x:address:screen <- next-ingredient + sc:address:screen <- next-ingredient # if x exists, move cursor in fake screen { - break-unless x:address:screen - width:number <- get x:address:screen/deref, num-columns:offset - reply width:number + break-unless sc + width:number <- get *sc, num-columns:offset + reply width } # otherwise, real screen width:number <- display-width - reply width:number + reply width ] recipe screen-height [ local-scope - x:address:screen <- next-ingredient + sc:address:screen <- next-ingredient # if x exists, move cursor in fake screen { - break-unless x:address:screen - height:number <- get x:address:screen/deref, num-rows:offset - reply height:number + break-unless sc + height:number <- get *sc, num-rows:offset + reply height } # otherwise, real screen height:number <- display-height - reply height:number + reply height ] recipe hide-cursor [ local-scope - x:address:screen <- next-ingredient + screen:address <- next-ingredient # if x exists (not real display), do nothing { - break-unless x:address:screen - reply x:address:screen + break-unless screen + reply screen } # otherwise, real screen hide-cursor-on-display - reply x:address:screen + reply screen ] recipe show-cursor [ local-scope - x:address:screen <- next-ingredient + screen:address <- next-ingredient # if x exists (not real display), do nothing { - break-unless x:address:screen - reply x:address:screen + break-unless screen + reply screen } # otherwise, real screen show-cursor-on-display - reply x:address:screen + reply screen ] recipe hide-screen [ local-scope - x:address:screen <- next-ingredient + screen:address <- next-ingredient # if x exists (not real display), do nothing { - break-unless x:address:screen - reply x:address:screen + break-unless screen + reply screen } # otherwise, real screen hide-display - reply x:address:screen + reply screen ] recipe show-screen [ local-scope - x:address:screen <- next-ingredient + screen:address <- next-ingredient # if x exists (not real display), do nothing { - break-unless x:address:screen - reply x:address:screen + break-unless screen + reply screen } # otherwise, real screen show-display - reply x:address:screen + reply screen ] recipe print-string [ local-scope - x:address:screen <- next-ingredient + screen:address <- next-ingredient s:address:array: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 + break-if color-found? + color <- copy 7/white } bg-color:number, bg-color-found?:boolean <- next-ingredient { # default bg-color to black - break-if bg-color-found?:boolean - bg-color:number <- copy 0:literal/black + break-if bg-color-found? + bg-color <- copy 0/black } - len:number <- length s:address:array:character/deref - i:number <- copy 0:literal + len:number <- length *s + i:number <- copy 0 { - done?:boolean <- greater-or-equal i:number, len:number - break-if done?:boolean - c:character <- index s:address:array:character/deref, i:number - print-character x:address:screen, c:character, color:number, bg-color:number - i:number <- add i:number, 1:literal + done?:boolean <- greater-or-equal i, len + break-if done? + c:character <- index *s, i + print-character screen, c, color, bg-color + i <- add i, 1 loop } - reply x:address:screen/same-as-ingredient:0 + reply screen/same-as-ingredient:0 ] scenario print-string-stops-at-right-margin [ run [ - 1:address:screen <- new-fake-screen 3:literal/width, 2:literal/height - 2:address:array:character <- new [abcd] - 1:address:screen <- print-string 1:address:screen, 2:address:array:character - 3:address:array:screen-cell <- get 1:address:screen/deref, data:offset - 4:array:screen-cell <- copy 3:address:array:screen-cell/deref + 1:address:screen <- new-fake-screen 3/width, 2/height + 2:address:array:character <- new [abcd] + 1:address:screen <- print-string 1:address:screen, 2:address:array:character + 3:address:array:screen-cell <- get *1:address:screen, data:offset + 4:array:screen-cell <- copy *3:address:array:screen-cell ] memory-should-contain [ - 4 <- 6 # width*height - 5 <- 97 # 'a' - 6 <- 7 # white - 7 <- 98 # 'b' - 8 <- 7 # white - 9 <- 100 # 'd' overwrites 'c' - 10 <- 7 # white - 11 <- 0 # unused + 4 <- 6 # width*height + 5 <- 97 # 'a' + 6 <- 7 # white + 7 <- 98 # 'b' + 8 <- 7 # white + 9 <- 100 # 'd' overwrites 'c' + 10 <- 7 # white + 11 <- 0 # unused ] ] recipe print-integer [ local-scope - x:address:screen <- next-ingredient + screen:address <- next-ingredient n:number <- next-ingredient color:number, color-found?:boolean <- next-ingredient { # default color to white - break-if color-found?:boolean - color:number <- copy 7:literal/white + break-if color-found? + color <- copy 7/white } bg-color:number, bg-color-found?:boolean <- next-ingredient { # default bg-color to black - break-if bg-color-found?:boolean - bg-color:number <- copy 0:literal/black + break-if bg-color-found? + bg-color <- copy 0/black } # todo: other bases besides decimal - s:address:array:character <- integer-to-decimal-string n:number - print-string x:address:screen, s:address:array:character, color:number, bg-color:number - reply x:address:screen/same-as-ingredient:0 + s:address:array:character <- integer-to-decimal-string n + print-string screen, s, color, bg-color + reply screen/same-as-ingredient:0 ] diff --git a/html/072scenario_screen.cc.html b/html/072scenario_screen.cc.html index 5f24dd8c..44757729 100644 --- a/html/072scenario_screen.cc.html +++ b/html/072scenario_screen.cc.html @@ -13,15 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } -.traceAbsent { color: #c00000; } -.Constant { color: #00a0a0; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } +.Constant { color: #00a0a0; } +.traceAbsent { color: #c00000; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -42,9 +41,9 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } :(scenarios run_mu_scenario) :(scenario screen_in_scenario) scenario screen-in-scenario [ - assume-screen 5:literal/width, 3:literal/height + assume-screen 5/width, 3/height run [ - screen:address <- print-character screen:address, 97:literal # 'a' + screen:address <- print-character screen:address, 97 # 'a' ] screen-should-contain [ # 01234 @@ -56,10 +55,10 @@ scenario screen-in-scenario [ :(scenario screen_in_scenario_unicode) scenario screen-in-scenario-unicode-color [ - assume-screen 5:literal/width, 3:literal/height + assume-screen 5/width, 3/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:address <- print-character screen:address, 955/greek-small-lambda, 1/red + screen:address <- print-character screen:address, 97/a ] screen-should-contain [ # 01234 @@ -72,10 +71,10 @@ scenario screen-in-scenario-unicode-color [ :(scenario screen_in_scenario_color) # screen-should-contain can check unicode characters in the fake screen scenario screen-in-scenario-color [ - assume-screen 5:literal/width, 3:literal/height + assume-screen 5/width, 3/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, 7:literal/white + screen:address <- print-character screen:address, 955/greek-small-lambda, 1/red + screen:address <- print-character screen:address, 97/a, 7/white ] # screen-should-contain shows everything screen-should-contain [ @@ -86,14 +85,14 @@ scenario screen-in-scenario-color [ ] # 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, [ + screen-should-contain-in-color 7/white, [ # 01234 . a . . . . . ] # ..and the λ in red. - screen-should-contain-in-color 1:literal/red, [ + screen-should-contain-in-color 1/red, [ # 01234 .λ . . . @@ -105,9 +104,9 @@ scenario screen-in-scenario-color [ % Scenario_testing_scenario = true; % Hide_warnings = true; scenario screen-in-scenario-error [ - assume-screen 5:literal/width, 3:literal/height + assume-screen 5/width, 3/height run [ - screen:address <- print-character screen:address, 97:literal # 'a' + screen:address <- print-character screen:address, 97 # 'a' ] screen-should-contain [ # 01234 @@ -123,11 +122,11 @@ scenario screen-in-scenario-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 + assume-screen 5/width, 3/height run [ - screen:address <- print-character screen:address, 97:literal/a, 1:literal/red + screen:address <- print-character screen:address, 97/a, 1/red ] - screen-should-contain-in-color 2:literal/green, [ + screen-should-contain-in-color 2/green, [ # 01234 .a . . . @@ -138,14 +137,14 @@ scenario screen-in-scenario-color [ //: allow naming just for 'screen' :(before "End is_special_name Cases") -if (s == "screen") return true; +if (s == "screen") return true; :(scenarios run) :(scenario convert_names_does_not_warn_when_mixing_special_names_and_numeric_locations) % Scenario_testing_scenario = true; % Hide_warnings = true; recipe main [ - screen:number <- copy 1:number + screen:number <- copy 1:number ] -warn: mixing variable names and numeric addresses in main $warn: 0 @@ -155,8 +154,8 @@ $warn: 0 // Scenarios may not define default-space, so they should fit within the // initial area of memory reserved for tests. We'll put the predefined // variables available to them at the end of that region. -const long long int Max_variables_in_scenarios = Reserved_for_tests-100; -long long int Next_predefined_global_for_scenarios = Max_variables_in_scenarios; +const long long int Max_variables_in_scenarios = Reserved_for_tests-100; +long long int Next_predefined_global_for_scenarios = Max_variables_in_scenarios; :(before "End Setup") assert(Next_predefined_global_for_scenarios < Reserved_for_tests); :(after "transform_all()" following "case RUN:") @@ -167,7 +166,7 @@ assert(Name[tmp_recipe.:(before "End Globals") // Scenario Globals. -const long long int SCREEN = Next_predefined_global_for_scenarios++; +const long long int SCREEN = Next_predefined_global_for_scenarios++; // End Scenario Globals. :(before "End Special Scenario Variable Names(r)") Name[r]["screen"] = SCREEN; @@ -175,7 +174,7 @@ Name[r]["screen"] = SCREEN:(before "End Rewrite Instruction(curr)") // rewrite `assume-screen width, height` to // `screen:address <- new-fake-screen width, height` -if (curr.name == "assume-screen") { +if (curr.name == "assume-screen") { curr.operation = Recipe_ordinal["new-fake-screen"]; curr.name = "new-fake-screen"; assert(curr.operation); @@ -190,8 +189,8 @@ SCREEN_SHOULD_CONTAIN, :(before "End Primitive Recipe Numbers") Recipe_ordinal["screen-should-contain"] = SCREEN_SHOULD_CONTAIN; :(before "End Primitive Recipe Implementations") -case SCREEN_SHOULD_CONTAIN: { - if (!Passed) break; +case SCREEN_SHOULD_CONTAIN: { + if (!Passed) break; check_screen(current_instruction().ingredients.at(0).name, -1); break; } @@ -201,8 +200,8 @@ SCREEN_SHOULD_CONTAIN_IN_COLOR, :(before "End Primitive Recipe Numbers") Recipe_ordinal["screen-should-contain-in-color"] = SCREEN_SHOULD_CONTAIN_IN_COLOR; :(before "End Primitive Recipe Implementations") -case SCREEN_SHOULD_CONTAIN_IN_COLOR: { - if (!Passed) break; +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; @@ -210,57 +209,57 @@ Recipe_ordinal["screen-should-contain-in-color" :(before "End Types") // scan an array of characters in a unicode-aware, bounds-checked manner -struct raw_string_stream { - long long int index; - const long long int max; - const char* buf; +struct raw_string_stream { + long long int index; + const long long int max; + const char* buf; - raw_string_stream(const string&); - uint32_t get(); // unicode codepoint - uint32_t peek(); // unicode codepoint - bool at_end() const; - void skip_whitespace_and_comments(); + raw_string_stream(const string&); + uint32_t get(); // unicode codepoint + uint32_t peek(); // unicode codepoint + bool at_end() const; + void skip_whitespace_and_comments(); }; :(code) -void check_screen(const string& expected_contents, const int color) { +void check_screen(const string& expected_contents, const int color) { assert(!Current_routine->calls.front().default_space); // not supported - long long int screen_location = Memory[SCREEN]; - int data_offset = find_element_name(Type_ordinal["screen"], "data"); + long long int screen_location = Memory[SCREEN]; + int data_offset = find_element_name(Type_ordinal["screen"], "data"); assert(data_offset >= 0); - long long int screen_data_location = screen_location+data_offset; // type: address:array:character - long long int screen_data_start = Memory[screen_data_location]; // type: array:character - int width_offset = find_element_name(Type_ordinal["screen"], "num-columns"); - long long int screen_width = Memory[screen_location+width_offset]; - int height_offset = find_element_name(Type_ordinal["screen"], "num-rows"); - long long int screen_height = Memory[screen_location+height_offset]; + long long int screen_data_location = screen_location+data_offset; // type: address:array:character + long long int screen_data_start = Memory[screen_data_location]; // type: array:character + int width_offset = find_element_name(Type_ordinal["screen"], "num-columns"); + long long int screen_width = Memory[screen_location+width_offset]; + int height_offset = find_element_name(Type_ordinal["screen"], "num-rows"); + long long int screen_height = Memory[screen_location+height_offset]; raw_string_stream cursor(expected_contents); // todo: too-long expected_contents should fail - long long int addr = screen_data_start+1; // skip length - for (long long int row = 0; row < screen_height; ++row) { + long long int addr = screen_data_start+1; // skip length + for (long long int row = 0; row < screen_height; ++row) { cursor.skip_whitespace_and_comments(); - if (cursor.at_end()) break; + if (cursor.at_end()) break; assert(cursor.get() == '.'); - 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 (curr == ' ' && color != -1 && color != Memory[addr+cell_color_offset]) { + 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 (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; + 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 && !Scenario_testing_scenario) { + if (Current_scenario && !Scenario_testing_scenario) { // 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" << end(); } - else { + else { // just testing check_screen raise << "expected screen location (" << row << ", " << column << ") to be in color " << color << " instead of " << Memory[addr+cell_color_offset] << '\n' << end(); } - if (!Scenario_testing_scenario) { + if (!Scenario_testing_scenario) { Passed = false; ++Num_failures; } @@ -269,27 +268,27 @@ Recipe_ordinal["screen-should-contain-in-color" // 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 && !iscntrl(curr)) { + char expected_pretty[10] = {0}; + 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'; + 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 && !iscntrl(Memory[addr])) { + char actual_pretty[10] = {0}; + 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'; + 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 && !Scenario_testing_scenario) { + if (Current_scenario && !Scenario_testing_scenario) { // 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' << end(); dump_screen(); } - else { + else { // just testing check_screen raise << "expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << " instead of " << Memory[addr] << actual_pretty << '\n' << end(); } - if (!Scenario_testing_scenario) { + if (!Scenario_testing_scenario) { Passed = false; ++Num_failures; } @@ -301,43 +300,43 @@ Recipe_ordinal["screen-should-contain-in-color" assert(cursor.at_end()); } -raw_string_stream::raw_string_stream(const string& backing) :index(0), max(SIZE(backing)), buf(backing.c_str()) {} +raw_string_stream::raw_string_stream(const string& backing) :index(0), max(SIZE(backing)), buf(backing.c_str()) {} -bool raw_string_stream::at_end() const { - if (index >= max) return true; - if (tb_utf8_char_length(buf[index]) > max-index) { - raise << "unicode string seems corrupted at index "<< index << " character " << static_cast<int>(buf[index]) << '\n' << end(); +bool raw_string_stream::at_end() const { + if (index >= max) return true; + if (tb_utf8_char_length(buf[index]) > max-index) { + raise << "unicode string seems corrupted at index "<< index << " character " << static_cast<int>(buf[index]) << '\n' << end(); return true; } return false; } -uint32_t raw_string_stream::get() { +uint32_t raw_string_stream::get() { assert(index < max); // caller must check bounds before calling 'get' - uint32_t result = 0; - int length = tb_utf8_char_to_unicode(&result, &buf[index]); + uint32_t result = 0; + int length = tb_utf8_char_to_unicode(&result, &buf[index]); assert(length != TB_EOF); index += length; return result; } -uint32_t raw_string_stream::peek() { +uint32_t raw_string_stream::peek() { assert(index < max); // caller must check bounds before calling 'get' - uint32_t result = 0; - int length = tb_utf8_char_to_unicode(&result, &buf[index]); + uint32_t result = 0; + int length = tb_utf8_char_to_unicode(&result, &buf[index]); assert(length != TB_EOF); return result; } -void raw_string_stream::skip_whitespace_and_comments() { - while (!at_end()) { - if (isspace(peek())) get(); - else if (peek() == '#') { +void raw_string_stream::skip_whitespace_and_comments() { + while (!at_end()) { + if (isspace(peek())) get(); + else if (peek() == '#') { // skip comment get(); - while (peek() != '\n') get(); // implicitly also handles CRLF + while (peek() != '\n') get(); // implicitly also handles CRLF } - else break; + else break; } } @@ -346,31 +345,31 @@ _DUMP_SCREEN, :(before "End Primitive Recipe Numbers") Recipe_ordinal["$dump-screen"] = _DUMP_SCREEN; :(before "End Primitive Recipe Implementations") -case _DUMP_SCREEN: { +case _DUMP_SCREEN: { dump_screen(); break; } :(code) -void dump_screen() { +void dump_screen() { assert(!Current_routine->calls.front().default_space); // not supported - long long int screen_location = Memory[SCREEN]; - int width_offset = find_element_name(Type_ordinal["screen"], "num-columns"); - long long int screen_width = Memory[screen_location+width_offset]; - int height_offset = find_element_name(Type_ordinal["screen"], "num-rows"); - long long int screen_height = Memory[screen_location+height_offset]; - int data_offset = find_element_name(Type_ordinal["screen"], "data"); + long long int screen_location = Memory[SCREEN]; + int width_offset = find_element_name(Type_ordinal["screen"], "num-columns"); + long long int screen_width = Memory[screen_location+width_offset]; + int height_offset = find_element_name(Type_ordinal["screen"], "num-rows"); + long long int screen_height = Memory[screen_location+height_offset]; + int data_offset = find_element_name(Type_ordinal["screen"], "data"); assert(data_offset >= 0); - long long int screen_data_location = screen_location+data_offset; // type: address:array:character - long long int screen_data_start = Memory[screen_data_location]; // type: array:character + long long int screen_data_location = screen_location+data_offset; // type: address:array:character + long long int screen_data_start = Memory[screen_data_location]; // type: array:character assert(Memory[screen_data_start] == screen_width*screen_height); - long long int curr = screen_data_start+1; // skip length - for (long long int row = 0; row < screen_height; ++row) { + long long int curr = screen_data_start+1; // skip length + for (long long int row = 0; row < screen_height; ++row) { cerr << '.'; - for (long long int col = 0; col < screen_width; ++col) { - if (Memory[curr]) + for (long long int col = 0; col < screen_width; ++col) { + if (Memory[curr]) cerr << to_unicode(Memory[curr]); - else + else cerr << ' '; curr += /*size of screen-cell*/2; } diff --git a/html/073scenario_screen_test.mu.html b/html/073scenario_screen_test.mu.html index 229a2e90..71c878ca 100644 --- a/html/073scenario_screen_test.mu.html +++ b/html/073scenario_screen_test.mu.html @@ -31,9 +31,9 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } # To check our support for screens in scenarios, rewrite tests from print.mu scenario print-character-at-top-left2 [ - assume-screen 3:literal/width, 2:literal/height + assume-screen 3/width, 2/height run [ - screen:address <- print-character screen:address, 97:literal # 'a' + screen:address <- print-character screen:address, 97/a ] screen-should-contain [ .a . @@ -42,12 +42,12 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } ] scenario clear-line-erases-printed-characters2 [ - assume-screen 5:literal/width, 3:literal/height + assume-screen 5/width, 3/height run [ # print a character - screen:address <- print-character screen:address, 97:literal # 'a' + screen:address <- print-character screen:address, 97/a # move cursor to start of line - screen:address <- move-cursor screen:address, 0:literal/row, 0:literal/column + screen:address <- move-cursor screen:address, 0/row, 0/column # clear line screen:address <- clear-line screen:address ] diff --git a/html/074console.mu.html b/html/074console.mu.html index 104ac569..53c01cfe 100644 --- a/html/074console.mu.html +++ b/html/074console.mu.html @@ -13,13 +13,12 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Delimiter { color: #a04060; } -.CommentedCode { color: #6c6c6c; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -55,37 +54,35 @@ container console [ recipe new-fake-console [ local-scope result:address:console <- new console:type - buf:address:address:array:character <- get-address result:address:console/deref, data:offset -#? $start-tracing #? 1 - buf:address:address:array:character/deref <- next-ingredient -#? $stop-tracing #? 1 - idx:address:number <- get-address result:address:console/deref, index:offset - idx:address:number/deref <- copy 0:literal - reply result:address:console + buf:address:address:array:character <- get-address *result, data:offset + *buf <- next-ingredient + idx:address:number <- get-address *result, index:offset + *idx <- copy 0 + reply result ] recipe read-event [ local-scope x:address:console <- next-ingredient { - break-unless x:address:console - idx:address:number <- get-address x:address:console/deref, index:offset - buf:address:array:event <- get x:address:console/deref, data:offset + break-unless x + idx:address:number <- get-address *x, index:offset + buf:address:array:event <- get *x, data:offset { - max:number <- length buf:address:array:event/deref - done?:boolean <- greater-or-equal idx:address:number/deref, max:number - break-unless done?:boolean + max:number <- length *buf + done?:boolean <- greater-or-equal *idx, max + break-unless done? dummy:address:event <- new event:type - reply dummy:address:event/deref, x:address:console/same-as-ingredient:0, 1:literal/found, 1:literal/quit + reply *dummy, x/same-as-ingredient:0, 1/found, 1/quit } - result:event <- index buf:address:array:event/deref, idx:address:number/deref - idx:address:number/deref <- add idx:address:number/deref, 1:literal - reply result:event, x:address:console/same-as-ingredient:0, 1:literal/found, 0:literal/quit + result:event <- index *buf, *idx + *idx <- add *idx, 1 + reply result, x/same-as-ingredient:0, 1/found, 0/quit } # real event source is infrequent; avoid polling it too much switch result:event, found?:boolean <- check-for-interaction - reply result:event, x:address:console/same-as-ingredient:0, found?:boolean, 0:literal/quit + reply result, x/same-as-ingredient:0, found?, 0/quit ] # variant of read-event for just keyboard events. Discards everything that @@ -93,20 +90,13 @@ container console [ # newlines, tabs, ctrl-d.. recipe read-key [ local-scope -#? $print default-space:address:array:location #? 1 -#? $exit #? 1 -#? $start-tracing #? 1 console:address <- next-ingredient - x:event, console:address, found?:boolean, quit?:boolean <- read-event console:address -#? $print [aaa 1] #? 1 - reply-if quit?:boolean, 0:literal, console:address/same-as-ingredient:0, found?:boolean, quit?:boolean -#? $print [aaa 2] #? 1 - reply-unless found?:boolean, 0:literal, console:address/same-as-ingredient:0, found?:boolean, quit?:boolean -#? $print [aaa 3] #? 1 - c:address:character <- maybe-convert x:event, text:variant - reply-unless c:address:character, 0:literal, console:address/same-as-ingredient:0, 0:literal/found, 0:literal/quit -#? $print [aaa 4] #? 1 - reply c:address:character/deref, console:address/same-as-ingredient:0, 1:literal/found, 0:literal/quit + x:event, console, found?:boolean, quit?:boolean <- read-event console + reply-if quit?, 0, console/same-as-ingredient:0, found?, quit? + reply-unless found?, 0, console/same-as-ingredient:0, found?, quit? + c:address:character <- maybe-convert x, text:variant + reply-unless c, 0, console/same-as-ingredient:0, 0/found, 0/quit + reply *c, console/same-as-ingredient:0, 1/found, 0/quit ] recipe send-keys-to-channel [ @@ -115,23 +105,25 @@ container console [ chan:address:channel <- next-ingredient screen:address <- next-ingredient { - c:character, console:address, found?:boolean, quit?:boolean <- read-key console:address - loop-unless found?:boolean - break-if quit?:boolean - assert c:character, [invalid event, expected text] - print-character screen:address, c:character - chan:address:channel <- write chan:address:channel, c:character + c:character, console, found?:boolean, quit?:boolean <- read-key console + loop-unless found? + break-if quit? + assert c, [invalid event, expected text] + screen <- print-character screen, c + chan <- write chan, c loop } + reply console/same-as-ingredient:0, chan/same-as-ingredient:1, screen/same-as-ingredient:2 ] recipe wait-for-event [ local-scope console:address <- next-ingredient { - _, console:address, found?:boolean <- read-event console:address - loop-unless found?:boolean + _, console, found?:boolean <- read-event console + loop-unless found? } + reply console/same-as-ingredient:0 ] # use this helper to skip rendering if there's lots of other events queued up @@ -139,12 +131,12 @@ container console [ local-scope console:address <- next-ingredient { - break-unless console:address + break-unless console # fake consoles should be plenty fast; never skip - reply 0:literal/false + reply 0/false } result:boolean <- interactions-left? - reply result:boolean + reply result ] diff --git a/html/075scenario_console.cc.html b/html/075scenario_console.cc.html index c64534a7..3b965fdb 100644 --- a/html/075scenario_console.cc.html +++ b/html/075scenario_console.cc.html @@ -15,12 +15,11 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .Identifier { color: #804000; } +.CommentedCode { color: #6c6c6c; } --> @@ -64,13 +63,13 @@ scenario keyboard-in-scenario [ ] :(before "End Scenario Globals") -const long long int CONSOLE = Next_predefined_global_for_scenarios++; +const long long int CONSOLE = Next_predefined_global_for_scenarios++; :(before "End Special Scenario Variable Names(r)") Name[r]["console"] = CONSOLE; //: allow naming just for 'console' :(before "End is_special_name Cases") -if (s == "console") return true; +if (s == "console") return true; //: Unlike assume-keyboard, assume-console is easiest to implement as just a //: primitive recipe. @@ -79,22 +78,22 @@ ASSUME_CONSOLE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["assume-console"] = ASSUME_CONSOLE; :(before "End Primitive Recipe Implementations") -case ASSUME_CONSOLE: { +case ASSUME_CONSOLE: { //? cerr << "aaa: " << current_instruction().ingredients.at(0).name << '\n'; //? 2 // create a temporary recipe just for parsing; it won't contain valid instructions istringstream in("[" + current_instruction().ingredients.at(0).name + "]"); recipe r = slurp_recipe(in); - long long int num_events = count_events(r); + long long int num_events = count_events(r); //? cerr << "fff: " << num_events << '\n'; //? 3 // initialize the events - long long int size = num_events*size_of_event() + /*space for length*/1; + long long int size = num_events*size_of_event() + /*space for length*/1; ensure_space(size); - long long int event_data_address = Current_routine->alloc; + long long int event_data_address = Current_routine->alloc; Memory[event_data_address] = num_events; ++Current_routine->alloc; - for (long long int i = 0; i < SIZE(r.steps); ++i) { - const instruction& curr = r.steps.at(i); - if (curr.name == "left-click") { + for (long long int i = 0; i < SIZE(r.steps); ++i) { + const instruction& curr = r.steps.at(i); + if (curr.name == "left-click") { Memory[Current_routine->alloc] = /*tag for 'touch-event' variant of 'event' exclusive-container*/2; Memory[Current_routine->alloc+1+/*offset of 'type' in 'mouse-event'*/0] = TB_KEY_MOUSE_LEFT; Memory[Current_routine->alloc+1+/*offset of 'row' in 'mouse-event'*/1] = to_integer(curr.ingredients.at(0).name); @@ -102,24 +101,24 @@ Recipe_ordinal["assume-console"] = ASSUM //? cerr << "AA left click: " << Memory[Current_routine->alloc+2] << ' ' << Memory[Current_routine->alloc+3] << '\n'; //? 1 Current_routine->alloc += size_of_event(); } - else if (curr.name == "press") { + else if (curr.name == "press") { Memory[Current_routine->alloc] = /*tag for 'keycode' variant of 'event' exclusive-container*/1; Memory[Current_routine->alloc+1] = to_integer(curr.ingredients.at(0).name); //? cerr << "AA press: " << Memory[Current_routine->alloc+1] << '\n'; //? 3 Current_routine->alloc += size_of_event(); } // End Event Handlers - else { + else { // keyboard input assert(curr.name == "type"); - const string& contents = curr.ingredients.at(0).name; - const char* raw_contents = contents.c_str(); - long long int num_keyboard_events = unicode_length(contents); - long long int curr = 0; + const string& contents = curr.ingredients.at(0).name; + const char* raw_contents = contents.c_str(); + long long int num_keyboard_events = unicode_length(contents); + long long int curr = 0; //? cerr << "AAA: " << num_keyboard_events << '\n'; //? 1 - for (long long int i = 0; i < num_keyboard_events; ++i) { + for (long long int i = 0; i < num_keyboard_events; ++i) { Memory[Current_routine->alloc] = /*tag for 'text' variant of 'event' exclusive-container*/0; - uint32_t curr_character; + uint32_t curr_character; assert(curr < SIZE(contents)); tb_utf8_char_to_unicode(&curr_character, &raw_contents[curr]); //? cerr << "AA keyboard: " << curr_character << '\n'; //? 3 @@ -198,57 +197,57 @@ REPLACE_IN_CONSOLE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["replace-in-console"] = REPLACE_IN_CONSOLE; :(before "End Primitive Recipe Implementations") -case REPLACE_IN_CONSOLE: { +case REPLACE_IN_CONSOLE: { assert(scalar(ingredients.at(0))); //? cerr << "console: " << Memory[CONSOLE] << '\n'; //? 1 - if (!Memory[CONSOLE]) { + if (!Memory[CONSOLE]) { raise << "console not initialized\n" << end(); break; } - long long int console_data = Memory[Memory[CONSOLE]+1]; + long long int console_data = Memory[Memory[CONSOLE]+1]; //? cerr << "console data starts at " << console_data << '\n'; //? 1 - long long int size = Memory[console_data]; // array size + long long int size = Memory[console_data]; // array size //? cerr << "size of console data is " << size << '\n'; //? 1 - for (long long int i = 0, curr = console_data+1; i < size; ++i, curr+=size_of_event()) { + for (long long int i = 0, curr = console_data+1; i < size; ++i, curr+=size_of_event()) { //? cerr << curr << '\n'; //? 1 - if (Memory[curr] != /*text*/0) continue; - if (Memory[curr+1] != ingredients.at(0).at(0)) continue; - for (long long int n = 0; n < size_of_event(); ++n) + if (Memory[curr] != /*text*/0) continue; + if (Memory[curr+1] != ingredients.at(0).at(0)) continue; + for (long long int n = 0; n < size_of_event(); ++n) Memory[curr+n] = ingredients.at(1).at(n); } break; } :(code) -long long int count_events(const recipe& r) { - long long int result = 0; - for (long long int i = 0; i < SIZE(r.steps); ++i) { - const instruction& curr = r.steps.at(i); +long long int count_events(const recipe& r) { + long long int result = 0; + for (long long int i = 0; i < SIZE(r.steps); ++i) { + const instruction& curr = r.steps.at(i); //? cerr << "aa: " << curr.name << '\n'; //? 3 //? cerr << "bb: " << curr.ingredients.at(0).name << '\n'; //? 1 - if (curr.name == "type") + if (curr.name == "type") result += unicode_length(curr.ingredients.at(0).name); - else + else result++; //? cerr << "cc: " << result << '\n'; //? 1 } return result; } -long long int size_of_event() { +long long int size_of_event() { // memoize result if already computed - static long long int result = 0; - if (result) return result; + static long long int result = 0; + if (result) return result; vector<type_ordinal> type; type.push_back(Type_ordinal["event"]); result = size_of(type); return result; } -long long int size_of_events() { +long long int size_of_events() { // memoize result if already computed - static long long int result = 0; - if (result) return result; + static long long int result = 0; + if (result) return result; vector<type_ordinal> type; assert(Type_ordinal["console"]); type.push_back(Type_ordinal["console"]); diff --git a/html/076scenario_console_test.mu.html b/html/076scenario_console_test.mu.html index a3fa6101..b33cb4cd 100644 --- a/html/076scenario_console_test.mu.html +++ b/html/076scenario_console_test.mu.html @@ -37,20 +37,20 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } type [abc] ] run [ - 1:character, console:address, 2:boolean <- read-key console:address - 3:character, console:address, 4:boolean <- read-key console:address - 5:character, console:address, 6:boolean <- read-key console:address - 7:character, console:address, 8:boolean <- read-key console:address + 1:character, console:address, 2:boolean <- read-key console:address + 3:character, console:address, 4:boolean <- read-key console:address + 5:character, console:address, 6:boolean <- read-key console:address + 7:character, console:address, 8:boolean <- read-key console:address ] memory-should-contain [ - 1 <- 97 # 'a' - 2 <- 1 - 3 <- 98 # 'b' - 4 <- 1 - 5 <- 99 # 'c' - 6 <- 1 - 7 <- 0 # eof - 8 <- 1 + 1 <- 97 # 'a' + 2 <- 1 + 3 <- 98 # 'b' + 4 <- 1 + 5 <- 99 # 'c' + 6 <- 1 + 7 <- 0 # eof + 8 <- 1 ] ] diff --git a/html/080trace_browser.cc.html b/html/080trace_browser.cc.html index 07635388..f2139f3f 100644 --- a/html/080trace_browser.cc.html +++ b/html/080trace_browser.cc.html @@ -15,11 +15,10 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } -.CommentedCode { color: #6c6c6c; } .Identifier { color: #804000; } +.CommentedCode { color: #6c6c6c; } --> @@ -36,31 +35,31 @@ _BROWSE_TRACE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["$browse-trace"] = _BROWSE_TRACE; :(before "End Primitive Recipe Implementations") -case _BROWSE_TRACE: { +case _BROWSE_TRACE: { start_trace_browser(); break; } :(before "End Globals") -set<long long int> Visible; -long long int Top_of_screen = 0; -long long int Last_printed_row = 0; -map<int, long long int> Trace_index; // screen row -> trace index +set<long long int> Visible; +long long int Top_of_screen = 0; +long long int Last_printed_row = 0; +map<int, long long int> Trace_index; // screen row -> trace index :(code) -void start_trace_browser() { - if (!Trace_stream) return; +void start_trace_browser() { + if (!Trace_stream) return; cerr << "computing depth to display\n"; - long long int min_depth = 9999; - for (long long int i = 0; i < SIZE(Trace_stream->past_lines); ++i) { + long long int min_depth = 9999; + for (long long int i = 0; i < SIZE(Trace_stream->past_lines); ++i) { trace_line& curr_line = Trace_stream->past_lines.at(i); - if (curr_line.depth == 0) continue; - if (curr_line.depth < min_depth) min_depth = curr_line.depth; + if (curr_line.depth == 0) continue; + if (curr_line.depth < min_depth) min_depth = curr_line.depth; } cerr << "depth is " << min_depth << '\n'; cerr << "computing lines to display\n"; - for (long long int i = 0; i < SIZE(Trace_stream->past_lines); ++i) { - if (Trace_stream->past_lines.at(i).depth == min_depth) + for (long long int i = 0; i < SIZE(Trace_stream->past_lines); ++i) { + if (Trace_stream->past_lines.at(i).depth == min_depth) Visible.insert(i); } tb_init(); @@ -68,62 +67,62 @@ map<int, ; Top_of_screen = 0; refresh_screen_rows(); - while (true) { + while (true) { render(); - do { + do { tb_poll_event(&event); - } while (event.type != TB_EVENT_KEY); - long long int key = event.key ? event.key : event.ch; - if (key == 'q' || key == 'Q') break; - if (key == 'j' || key == TB_KEY_ARROW_DOWN) { + } while (event.type != TB_EVENT_KEY); + long long int key = event.key ? event.key : event.ch; + if (key == 'q' || key == 'Q') break; + if (key == 'j' || key == TB_KEY_ARROW_DOWN) { // move cursor one line down - if (Display_row < Last_printed_row) ++Display_row; + if (Display_row < Last_printed_row) ++Display_row; } - if (key == 'k' || key == TB_KEY_ARROW_UP) { + if (key == 'k' || key == TB_KEY_ARROW_UP) { // move cursor one line up - if (Display_row > 0) --Display_row; + if (Display_row > 0) --Display_row; } - if (key == 'H') { + if (key == 'H') { // move cursor to top of screen Display_row = 0; } - if (key == 'M') { + if (key == 'M') { // move cursor to center of screen Display_row = tb_height()/2; } - if (key == 'L') { + if (key == 'L') { // move cursor to bottom of screen Display_row = tb_height()-1; } - if (key == 'J' || key == TB_KEY_PGDN) { + if (key == 'J' || key == TB_KEY_PGDN) { // page-down - if (Trace_index.find(tb_height()-1) != Trace_index.end()) { + if (Trace_index.find(tb_height()-1) != Trace_index.end()) { Top_of_screen = Trace_index[tb_height()-1]+1; refresh_screen_rows(); } } - if (key == 'K' || key == TB_KEY_PGUP) { + if (key == 'K' || key == TB_KEY_PGUP) { // page-up is more convoluted //? tb_shutdown(); //? 1 //? cerr << "page-up: Top_of_screen is currently " << Top_of_screen << '\n'; //? 1 - for (int screen_row = tb_height(); 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()) + if (Top_of_screen <= 0) break; + while (Top_of_screen > 0 && Visible.find(Top_of_screen) == Visible.end()) --Top_of_screen; //? cerr << "now " << Top_of_screen << '\n'; //? 1 } //? exit(0); //? 1 - if (Top_of_screen > 0) + if (Top_of_screen > 0) refresh_screen_rows(); } - if (key == 'G') { + 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) { + 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()) + if (Top_of_screen <= 0) break; + while (Top_of_screen > 0 && Visible.find(Top_of_screen) == Visible.end()) --Top_of_screen; } refresh_screen_rows(); @@ -131,29 +130,29 @@ map<int, ; refresh_screen_rows(); } - if (key == TB_KEY_CARRIAGE_RETURN) { + if (key == TB_KEY_CARRIAGE_RETURN) { // expand lines under current by one level //? tb_shutdown(); assert(Trace_index.find(Display_row) != Trace_index.end()); - long long int start_index = Trace_index[Display_row]; + long long int start_index = Trace_index[Display_row]; //? cerr << "start_index is " << start_index << '\n'; - long long int index = 0; + long long int index = 0; // simultaneously compute end_index and min_depth - int min_depth = 9999; - for (index = start_index+1; index < SIZE(Trace_stream->past_lines); ++index) { - if (Visible.find(index) != Visible.end()) break; + int min_depth = 9999; + for (index = start_index+1; index < SIZE(Trace_stream->past_lines); ++index) { + if (Visible.find(index) != Visible.end()) break; trace_line& curr_line = Trace_stream->past_lines.at(index); - if (curr_line.depth == 0) continue; + if (curr_line.depth == 0) continue; assert(curr_line.depth > Trace_stream->past_lines.at(start_index).depth); - if (curr_line.depth < min_depth) min_depth = curr_line.depth; + if (curr_line.depth < min_depth) min_depth = curr_line.depth; } //? cerr << "min_depth is " << min_depth << '\n'; - long long int end_index = index; + long long int end_index = index; //? cerr << "end_index is " << end_index << '\n'; // mark as visible all intervening indices at min_depth - for (index = start_index; index < end_index; ++index) { + for (index = start_index; index < end_index; ++index) { trace_line& curr_line = Trace_stream->past_lines.at(index); - if (curr_line.depth == min_depth) { + if (curr_line.depth == min_depth) { //? cerr << "adding " << index << '\n'; Visible.insert(index); } @@ -161,22 +160,22 @@ map<int, //? exit(0); refresh_screen_rows(); } - if (key == TB_KEY_BACKSPACE || key == TB_KEY_BACKSPACE2) { + if (key == TB_KEY_BACKSPACE || key == TB_KEY_BACKSPACE2) { // collapse all lines under current assert(Trace_index.find(Display_row) != Trace_index.end()); - long long int start_index = Trace_index[Display_row]; - long long int index = 0; + long long int start_index = Trace_index[Display_row]; + long long int index = 0; // end_index is the next line at a depth same as or lower than start_index - int initial_depth = Trace_stream->past_lines.at(start_index).depth; - for (index = start_index+1; index < SIZE(Trace_stream->past_lines); ++index) { - if (Visible.find(index) == Visible.end()) continue; + int initial_depth = Trace_stream->past_lines.at(start_index).depth; + for (index = start_index+1; index < SIZE(Trace_stream->past_lines); ++index) { + if (Visible.find(index) == Visible.end()) continue; trace_line& curr_line = Trace_stream->past_lines.at(index); - if (curr_line.depth == 0) continue; - if (curr_line.depth <= initial_depth) break; + if (curr_line.depth == 0) continue; + if (curr_line.depth <= initial_depth) break; } - long long int end_index = index; + long long int end_index = index; // mark as visible all intervening indices at min_depth - for (index = start_index+1; index < end_index; ++index) { + for (index = start_index+1; index < end_index; ++index) { Visible.erase(index); } refresh_screen_rows(); @@ -186,40 +185,40 @@ map<int, } // update Trace_indices for each screen_row on the basis of Top_of_screen and Visible -void refresh_screen_rows() { - long long int screen_row = 0, index = 0; +void refresh_screen_rows() { + long long int screen_row = 0, index = 0; Trace_index.clear(); - for (screen_row = 0, index = Top_of_screen; screen_row < tb_height() && index < SIZE(Trace_stream->past_lines); ++screen_row, ++index) { + for (screen_row = 0, index = Top_of_screen; screen_row < tb_height() && index < SIZE(Trace_stream->past_lines); ++screen_row, ++index) { // skip lines without depth for now - while (Visible.find(index) == Visible.end()) { + while (Visible.find(index) == Visible.end()) { ++index; - if (index >= SIZE(Trace_stream->past_lines)) goto done; + if (index >= SIZE(Trace_stream->past_lines)) goto done; } assert(index < SIZE(Trace_stream->past_lines)); Trace_index[screen_row] = index; } -done:; +done:; } -void render() { - long long int screen_row = 0; - for (screen_row = 0; screen_row < tb_height(); ++screen_row) { - if (Trace_index.find(screen_row) == Trace_index.end()) break; +void render() { + long long int screen_row = 0; + for (screen_row = 0; screen_row < tb_height(); ++screen_row) { + if (Trace_index.find(screen_row) == Trace_index.end()) break; trace_line& curr_line = Trace_stream->past_lines.at(Trace_index[screen_row]); ostringstream out; out << std::setw(4) << curr_line.depth << ' ' << curr_line.label << ": " << curr_line.contents; - if (screen_row < tb_height()-1) { - long long int delta = lines_hidden(screen_row); + if (screen_row < tb_height()-1) { + long long int delta = lines_hidden(screen_row); // home-brew escape sequence for red - if (delta > 999) out << "{"; + if (delta > 999) out << "{"; out << " (" << lines_hidden(screen_row) << ")"; - if (delta > 999) out << "}"; + if (delta > 999) out << "}"; } render_line(screen_row, out.str()); } // clear rest of screen Last_printed_row = screen_row-1; - for (; screen_row < tb_height(); ++screen_row) { + for (; screen_row < tb_height(); ++screen_row) { render_line(screen_row, "~"); } // move cursor back to display row at the end @@ -227,26 +226,26 @@ map<int, (); } -long long int lines_hidden(long long int screen_row) { +long long int lines_hidden(long long int screen_row) { assert(Trace_index.find(screen_row) != Trace_index.end()); - if (Trace_index.find(screen_row+1) == Trace_index.end()) + if (Trace_index.find(screen_row+1) == Trace_index.end()) return SIZE(Trace_stream->past_lines)-Trace_index[screen_row]; - else + else return Trace_index[screen_row+1] - Trace_index[screen_row]; } -void render_line(int screen_row, const string& s) { - long long int col = 0; - int color = TB_WHITE; - for (col = 0; col < tb_width() && col < SIZE(s); ++col) { - char c = s.at(col); // todo: unicode - if (c == '\n') c = ';'; // replace newlines with semi-colons +void render_line(int screen_row, const string& s) { + long long int col = 0; + int color = TB_WHITE; + for (col = 0; col < tb_width() && col < SIZE(s); ++col) { + char c = s.at(col); // todo: unicode + if (c == '\n') c = ';'; // replace newlines with semi-colons // escapes. hack: can't start a line with them. - if (c == '{') { color = /*red*/1; c = ' '; } - if (c == '}') { color = TB_WHITE; c = ' '; } + if (c == '{') { color = /*red*/1; c = ' '; } + if (c == '}') { color = TB_WHITE; c = ' '; } tb_change_cell(col, screen_row, c, color, TB_BLACK); } - for (; col < tb_width(); ++col) { + for (; col < tb_width(); ++col) { tb_change_cell(col, screen_row, ' ', TB_WHITE, TB_BLACK); } } diff --git a/html/081run_interactive.cc.html b/html/081run_interactive.cc.html index ab064b17..03c1f523 100644 --- a/html/081run_interactive.cc.html +++ b/html/081run_interactive.cc.html @@ -13,15 +13,14 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.traceContains { color: #008000; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.CommentedCode { color: #6c6c6c; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } +.CommentedCode { color: #6c6c6c; } .Identifier { color: #804000; } -.traceContains { color: #008000; } --> @@ -38,14 +37,14 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } :(scenario run_interactive_code) recipe main [ - 2:address:array:character <- new [1:number <- copy 34:literal] + 2:address:array:character <- new [1:number <- copy 34] run-interactive 2:address:array:character ] +mem: storing 34 in location 1 :(scenario run_interactive_empty) recipe main [ - 1:address:array:character <- run-interactive 0:literal + 1:address:array:character <- run-interactive 0 ] # result is null +mem: storing 0 in location 1 @@ -60,32 +59,32 @@ RUN_INTERACTIVE, Recipe_ordinal["run-interactive"] = RUN_INTERACTIVE; //? cerr << "run-interactive: " << RUN_INTERACTIVE << '\n'; //? 1 :(before "End Primitive Recipe Implementations") -case RUN_INTERACTIVE: { - if (SIZE(ingredients) != 1) { +case RUN_INTERACTIVE: { + if (SIZE(ingredients) != 1) { raise << current_recipe_name() << ": 'run-interactive' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'run-interactive' should be a literal string, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } products.resize(3); - bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0)); - if (!new_code_pushed_to_stack) { + bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0)); + if (!new_code_pushed_to_stack) { products.at(0).push_back(0); products.at(1).push_back(warnings_from_trace()); products.at(2).push_back(0); clean_up_interactive(); break; // done with this instruction } - else { + else { continue; // not done with caller; don't increment current_step_index() } } :(before "End Globals") -bool Running_interactive = false; -long long int Old_screen = 0; // we can support one iteration of screen inside screen +bool Running_interactive = false; +long long int Old_screen = 0; // we can support one iteration of screen inside screen :(before "End Setup") Running_interactive = false; Old_screen = 0; @@ -93,16 +92,16 @@ Old_screen = 0; // reads a string, tries to call it as code (treating it as a test), saving // all warnings. // returns true if successfully called (no errors found during load and transform) -bool run_interactive(long long int address) { - if (Recipe_ordinal.find("interactive") == Recipe_ordinal.end()) +bool run_interactive(long long int address) { + if (Recipe_ordinal.find("interactive") == Recipe_ordinal.end()) Recipe_ordinal["interactive"] = Next_recipe_ordinal++; Old_screen = Memory[SCREEN]; //? cerr << "save screen: " << Old_screen << '\n'; //? 2 // try to sandbox the run as best you can // todo: test this - if (!Current_scenario) { + if (!Current_scenario) { // not already sandboxed - for (long long int i = 1; i < Reserved_for_tests; ++i) + for (long long int i = 1; i < Reserved_for_tests; ++i) Memory.erase(i); Name[Recipe_ordinal["interactive"]].clear(); } @@ -110,12 +109,12 @@ Old_screen = 0; Name[Recipe_ordinal["interactive"]]["screen"] = SCREEN; //? cerr << "screen now at " << Name[Recipe_ordinal["interactive"]]["screen"] << '\n'; //? 1 string command = trim(strip_comments(read_mu_string(address))); - if (command.empty()) return false; + if (command.empty()) return false; Recipe.erase(Recipe_ordinal["interactive"]); Hide_warnings = true; - if (!Trace_stream) { + 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 = new trace_stream; Trace_stream->collect_layer = "warn"; } // call run(string) but without the scheduling @@ -126,7 +125,7 @@ Old_screen = 0; command + "\n" + "]\n"); transform_all(); - if (trace_count("warn") > 0) return false; + if (trace_count("warn") > 0) return false; Running_interactive = true; Current_routine->calls.push_front(call(Recipe_ordinal["interactive"])); return true; @@ -135,9 +134,9 @@ Old_screen = 0; :(scenario "run_interactive_returns_stringified_result") recipe main [ # try to interactively add 2 and 2 - 1:address:array:character <- new [add 2:literal, 2:literal] + 1:address:array:character <- new [add 2, 2] 2:address:array:character <- run-interactive 1:address:array:character - 10:array:character <- copy 2:address:array:character/deref + 10:array:character <- copy 2:address:array:character/lookup ] # first letter in the output should be '4' in unicode +mem: storing 52 in location 11 @@ -145,13 +144,13 @@ recipe main [ :(scenario "run_interactive_returns_string") recipe main [ # try to interactively add 2 and 2 - 1:address:array:character <- new [ - 100:address:array:character <- new [a] - 101:address:array:character <- new [b] + 1:address:array:character <- new [ + 100:address:array:character <- new [a] + 101:address:array:character <- new [b] 102:address:array:character <- string-append 100:address:array:character, 101:address:array:character ] 2:address:array:character <- run-interactive 1:address:array:character - 10:array:character <- copy 2:address:array:character/deref + 10:array:character <- copy 2:address:array:character/lookup ] # output contains "ab" +mem: storing 97 in location 11 @@ -160,9 +159,9 @@ recipe main [ :(scenario "run_interactive_returns_warnings") recipe main [ # run a command that generates a warning - 1:address:array:character <- new [get 1234:number, foo:offset] + 1:address:array:character <- new [get 1234:number, foo:offset] 2:address:array:character, 3:address:array:character <- run-interactive 1:address:array:character - 10:array:character <- copy 3:address:array:character/deref + 10:array:character <- copy 3:address:array:character/lookup ] # warning should be "unknown element foo in container number" +mem: storing 117 in location 11 @@ -175,43 +174,43 @@ string Most_recent_results; :(before "End Setup") Most_recent_results = ""; :(before "End of Instruction") -if (Running_interactive) { +if (Running_interactive) { record_products(current_instruction(), products); } :(code) -void record_products(const instruction& instruction, const vector<vector<double> >& products) { +void record_products(const instruction& instruction, const vector<vector<double> >& products) { ostringstream out; - for (long long int i = 0; i < SIZE(products); ++i) { + for (long long int i = 0; i < SIZE(products); ++i) { // string - if (i < SIZE(instruction.products)) { - if (is_string(instruction.products.at(i))) { + if (i < SIZE(instruction.products)) { + if (is_string(instruction.products.at(i))) { assert(scalar(products.at(i))); out << read_mu_string(products.at(i).at(0)) << '\n'; continue; } // End Record Product Special-cases } - for (long long int j = 0; j < SIZE(products.at(i)); ++j) + for (long long int j = 0; j < SIZE(products.at(i)); ++j) out << products.at(i).at(j) << ' '; out << '\n'; } Most_recent_results = out.str(); } :(before "Complete Call Fallthrough") -if (current_instruction().operation == RUN_INTERACTIVE && !current_instruction().products.empty()) { +if (current_instruction().operation == RUN_INTERACTIVE && !current_instruction().products.empty()) { assert(SIZE(current_instruction().products) <= 3); // Send the results of the most recently executed instruction, regardless of // call depth, to be converted to string and potentially printed to string. - vector<double> result; + vector<double> result; result.push_back(new_mu_string(Most_recent_results)); write_memory(current_instruction().products.at(0), result); - if (SIZE(current_instruction().products) >= 2) { - vector<double> warnings; + if (SIZE(current_instruction().products) >= 2) { + vector<double> warnings; warnings.push_back(warnings_from_trace()); write_memory(current_instruction().products.at(1), warnings); } - if (SIZE(current_instruction().products) >= 3) { - vector<double> screen; + if (SIZE(current_instruction().products) >= 3) { + vector<double> screen; screen.push_back(Memory[SCREEN]); write_memory(current_instruction().products.at(2), screen); } @@ -220,21 +219,21 @@ Most_recent_results = ""//: clean up reply after we've popped it off the call-stack //: however, we need what was on the stack to decide whether to clean up :(after "Starting Reply") -bool must_clean_up_interactive = (current_recipe_name() == "interactive"); +bool must_clean_up_interactive = (current_recipe_name() == "interactive"); :(after "Falling Through End Of Recipe") -bool must_clean_up_interactive = (current_recipe_name() == "interactive"); +bool must_clean_up_interactive = (current_recipe_name() == "interactive"); :(before "End Reply") -if (must_clean_up_interactive) clean_up_interactive(); +if (must_clean_up_interactive) clean_up_interactive(); :(before "Complete Call Fallthrough") -if (must_clean_up_interactive) clean_up_interactive(); +if (must_clean_up_interactive) clean_up_interactive(); :(code) -void clean_up_interactive() { +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") { - delete Trace_stream; + if (Trace_stream->collect_layer == "warn") { + delete Trace_stream; Trace_stream = NULL; } //? cerr << "restore screen: " << Memory[SCREEN] << " to " << Old_screen << '\n'; //? 1 @@ -245,52 +244,52 @@ Most_recent_results = "":(code) string strip_comments(string in) { ostringstream result; - for (long long int i = 0; i < SIZE(in); ++i) { - if (in.at(i) != '#') { + for (long long int i = 0; i < SIZE(in); ++i) { + if (in.at(i) != '#') { result << in.at(i); } - else { - while (i < SIZE(in) && in.at(i) != '\n') + else { + while (i < SIZE(in) && in.at(i) != '\n') ++i; - if (i < SIZE(in) && in.at(i) == '\n') ++i; + if (i < SIZE(in) && in.at(i) == '\n') ++i; } } return result.str(); } -string read_mu_string(long long int address) { - long long int size = Memory[address]; - if (size == 0) return ""; +string read_mu_string(long long int address) { + long long int size = Memory[address]; + if (size == 0) return ""; ostringstream tmp; - for (long long int curr = address+1; curr <= address+size; ++curr) { + for (long long int curr = address+1; curr <= address+size; ++curr) { // todo: unicode - tmp << (char)(int)Memory[curr]; + tmp << (char)(int)Memory[curr]; } return tmp.str(); } -long long int stringified_value_of_location(long long int address) { +long long int stringified_value_of_location(long long int address) { // convert to string ostringstream out; out << Memory[address]; return new_mu_string(out.str()); } -bool is_string(const reagent& x) { +bool is_string(const reagent& x) { return SIZE(x.types) == 3 && x.types.at(0) == Type_ordinal["address"] && x.types.at(1) == Type_ordinal["array"] && x.types.at(2) == Type_ordinal["character"]; } -long long int warnings_from_trace() { - if (!Trace_stream) return 0; - if (trace_count("warn") <= 0) return 0; +long long int warnings_from_trace() { + if (!Trace_stream) return 0; + if (trace_count("warn") <= 0) return 0; ostringstream out; - for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { - if (p->label != "warn") continue; + for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { + if (p->label != "warn") continue; out << p->contents; - if (*--p->contents.end() != '\n') out << '\n'; + if (*--p->contents.end() != '\n') out << '\n'; } assert(!out.str().empty()); return new_mu_string(out.str()); @@ -303,18 +302,18 @@ RELOAD, :(before "End Primitive Recipe Numbers") Recipe_ordinal["reload"] = RELOAD; :(before "End Primitive Recipe Implementations") -case RELOAD: { - if (SIZE(ingredients) != 1) { +case RELOAD: { + if (SIZE(ingredients) != 1) { raise << current_recipe_name() << ": 'reload' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) { + if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'reload' should be a literal string, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } - if (!Trace_stream) { + 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 = new trace_stream; Trace_stream->collect_layer = "warn"; } Hide_warnings = true; @@ -326,8 +325,8 @@ Recipe_ordinal["reload"] = RELOADfalse; products.resize(1); products.at(0).push_back(warnings_from_trace()); - if (Trace_stream->collect_layer == "warn") { - delete Trace_stream; + if (Trace_stream->collect_layer == "warn") { + delete Trace_stream; Trace_stream = NULL; } break; diff --git a/html/082persist.cc.html b/html/082persist.cc.html index a450633a..bb5582ee 100644 --- a/html/082persist.cc.html +++ b/html/082persist.cc.html @@ -15,12 +15,11 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } .cSpecial { color: #008000; } .Constant { color: #00a0a0; } -.PreProc { color: #c000c0; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } -.CommentedCode { color: #6c6c6c; } .Identifier { color: #804000; } +.PreProc { color: #c000c0; } +.CommentedCode { color: #6c6c6c; } --> @@ -41,35 +40,36 @@ RESTORE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["restore"] = RESTORE; :(before "End Primitive Recipe Implementations") -case RESTORE: { - if (SIZE(ingredients) != 1) { +case RESTORE: { + if (SIZE(ingredients) != 1) { raise << current_recipe_name() << ": 'restore' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) + if (!scalar(ingredients.at(0))) raise << current_recipe_name() << ": first ingredient of 'restore' should be a literal string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end(); products.resize(1); + if (Current_scenario) break; // do nothing in tests string filename = current_instruction().ingredients.at(0).name; - if (!is_literal(current_instruction().ingredients.at(0))) + if (!is_literal(current_instruction().ingredients.at(0))) filename = to_string(ingredients.at(0).at(0)); string contents = slurp("lesson/"+filename); - if (contents.empty()) + if (contents.empty()) products.at(0).push_back(0); - else + else products.at(0).push_back(new_mu_string(contents)); break; } :(code) -string slurp(const string& filename) { +string slurp(const string& filename) { //? cerr << filename << '\n'; //? 1 ostringstream result; ifstream fin(filename.c_str()); fin.peek(); - if (!fin) return result.str(); // don't bother checking errno - const int N = 1024; - char buf[N]; - while (!fin.eof()) { + if (!fin) return result.str(); // don't bother checking errno + const int N = 1024; + char buf[N]; + while (!fin.eof()) { bzero(buf, N); fin.read(buf, N-1); // leave at least one null result << buf; @@ -84,37 +84,38 @@ SAVE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["save"] = SAVE; :(before "End Primitive Recipe Implementations") -case SAVE: { - if (SIZE(ingredients) != 2) { +case SAVE: { + if (SIZE(ingredients) != 2) { raise << current_recipe_name() << ": 'save' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end(); break; } - if (!scalar(ingredients.at(0))) + if (!scalar(ingredients.at(0))) raise << current_recipe_name() << ": first ingredient of 'save' should be a literal string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end(); + if (!scalar(ingredients.at(1))) + raise << current_recipe_name() << ": second ingredient of 'save' should be an address:array:character, but got " << current_instruction().ingredients.at(1).to_string() << '\n' << end(); + if (Current_scenario) break; // do nothing in tests string filename = current_instruction().ingredients.at(0).name; - if (!is_literal(current_instruction().ingredients.at(0))) + if (!is_literal(current_instruction().ingredients.at(0))) filename = to_string(ingredients.at(0).at(0)); ofstream fout(("lesson/"+filename).c_str()); - if (!scalar(ingredients.at(1))) - raise << current_recipe_name() << ": second ingredient of 'save' should be an address:array:character, but got " << current_instruction().ingredients.at(1).to_string() << '\n' << end(); string contents = read_mu_string(ingredients.at(1).at(0)); fout << contents; fout.close(); - if (!exists("lesson/.git")) break; + if (!exists("lesson/.git")) break; // bug in git: git diff -q messes up --exit-code - int status = system("cd lesson; git add .; git diff HEAD --exit-code >/dev/null || git commit -a -m . >/dev/null"); - if (status != 0) + int status = system("cd lesson; git add .; git diff HEAD --exit-code >/dev/null || git commit -a -m . >/dev/null"); + if (status != 0) raise << "error in commit: contents " << contents << '\n' << end(); break; } :(code) -bool exists(const string& filename) { - struct stat dummy; +bool exists(const string& filename) { + struct stat dummy; return 0 == stat(filename.c_str(), &dummy); } -string to_string(long long int x) { +string to_string(long long int x) { ostringstream tmp; tmp << x; return tmp.str(); diff --git a/html/999spaces.cc.html b/html/999spaces.cc.html index 9f5b995c..a9512b34 100644 --- a/html/999spaces.cc.html +++ b/html/999spaces.cc.html @@ -13,9 +13,9 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } -.Delimiter { color: #a04060; } .Constant { color: #00a0a0; } .Comment { color: #9090ff; } +.Delimiter { color: #a04060; } .SalientComment { color: #00ffff; } --> diff --git a/html/callcc.mu.html b/html/callcc.mu.html index e16e87c4..20ebd83c 100644 --- a/html/callcc.mu.html +++ b/html/callcc.mu.html @@ -13,11 +13,11 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -33,18 +33,18 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } recipe main [ c:continuation <- f - continue-from c:continuation # <-- ..when you hit this + continue-from c # <-- ..when you hit this ] recipe f [ c:continuation <- g - reply c:continuation + reply c ] recipe g [ c:continuation <- current-continuation # <-- loop back to here - $print 1:literal - reply c:continuation # threaded through unmodified after first iteration + $print 1 + reply c # threaded through unmodified after first iteration ] diff --git a/html/channel.mu.html b/html/channel.mu.html index 40a058af..45450112 100644 --- a/html/channel.mu.html +++ b/html/channel.mu.html @@ -13,12 +13,12 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Delimiter { color: #a04060; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -37,15 +37,15 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } local-scope chan:address:channel <- next-ingredient # n = 0 - n:number <- copy 0:literal + n:number <- copy 0 { - done?:boolean <- lesser-than n:number, 5:literal - break-unless done?:boolean + done?:boolean <- lesser-than n, 5 + break-unless done? # other threads might get between these prints - $print [produce: ], n:number, [ + $print [produce: ], n, [ ] - chan:address:channel <- write chan:address:channel, n:number - n:number <- add n:number, 1:literal + chan:address:channel <- write chan, n + n <- add n, 1 loop } ] @@ -56,7 +56,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } chan:address:channel <- next-ingredient { # read an integer from the channel - n:number, chan:address:channel <- read chan:address:channel + n:number, chan:address:channel <- read chan # other threads might get between these prints $print [consume: ], n:number, [ ] @@ -66,12 +66,12 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } recipe main [ local-scope - chan:address:channel <- new-channel 3:literal + chan:address:channel <- new-channel 3 # create two background 'routines' that communicate by a channel - routine1:number <- start-running producer:recipe, chan:address:channel - routine2:number <- start-running consumer:recipe, chan:address:channel - wait-for-routine routine1:number - wait-for-routine routine2:number + routine1:number <- start-running producer:recipe, chan + routine2:number <- start-running consumer:recipe, chan + wait-for-routine routine1 + wait-for-routine routine2 ] diff --git a/html/chessboard.mu.html b/html/chessboard.mu.html index d66e9ab1..d04f4df0 100644 --- a/html/chessboard.mu.html +++ b/html/chessboard.mu.html @@ -13,15 +13,15 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } +.Delimiter { color: #a04060; } .muScenario { color: #00af00; } .SalientComment { color: #00ffff; } -.Delimiter { color: #a04060; } -.CommentedCode { color: #6c6c6c; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } +.CommentedCode { color: #6c6c6c; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -52,7 +52,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } # # Here the console and screen are both 0, which usually indicates real # hardware rather than a fake for testing as you'll see below. - 0:literal/screen, 0:literal/console <- chessboard 0:literal/screen, 0:literal/console + 0/screen, 0/console <- chessboard 0/screen, 0/console close-console # cleanup screen, keyboard and mouse ] @@ -62,7 +62,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } scenario print-board-and-read-move [ $close-trace # administrivia: most scenarios save and check traces, but this one gets too large/slow # we'll make the screen really wide because the program currently prints out a long line - assume-screen 120:literal/width, 20:literal/height + assume-screen 120/width, 20/height # initialize keyboard to type in a move assume-console [ type [a2-a4 @@ -70,10 +70,8 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } ] run [ screen:address, console:address <- chessboard screen:address, console:address -#? $browse-trace #? 1 -#? $close-trace #? 1 # icon for the cursor - screen:address <- print-character screen:address, 9251:literal # '␣' + screen <- print-character screen, 9251/␣ ] screen-should-contain [ # 1 2 3 4 5 6 7 8 9 10 11 @@ -104,44 +102,41 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } ## Here's how 'chessboard' is implemented. recipe chessboard [ -#? $start-tracing [schedule] #? 2 -#? $start-tracing #? 1 local-scope screen:address <- next-ingredient console:address <- next-ingredient -#? $print [screen: ], screen:address, [, console: ], console:address, 10:literal/newline board:address:array:address:array:character <- initial-position # hook up stdin - stdin:address:channel <- new-channel 10:literal/capacity - start-running send-keys-to-channel:recipe, console:address, stdin:address:channel, screen:address + stdin:address:channel <- new-channel 10/capacity + start-running send-keys-to-channel:recipe, console, stdin, screen # buffer lines in stdin - buffered-stdin:address:channel <- new-channel 10:literal/capacity - start-running buffer-lines:recipe, stdin:address:channel, buffered-stdin:address:channel + buffered-stdin:address:channel <- new-channel 10/capacity + start-running buffer-lines:recipe, stdin, buffered-stdin { msg:address:array:character <- new [Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves. ] - print-string screen:address, msg:address:array:character - cursor-to-next-line screen:address - print-board screen:address, board:address:array:address:array:character - cursor-to-next-line screen:address - msg:address:array:character <- new [Type in your move as <from square>-<to square>. For example: 'a2-a4'. Then press <enter>. + print-string screen, msg + cursor-to-next-line screen + print-board screen, board + cursor-to-next-line screen + msg <- new [Type in your move as <from square>-<to square>. For example: 'a2-a4'. Then press <enter>. ] - print-string screen:address, msg:address:array:character - cursor-to-next-line screen:address - msg:address:array:character <- new [Hit 'q' to exit. + print-string screen, msg + cursor-to-next-line screen + msg <- new [Hit 'q' to exit. ] - print-string screen:address, msg:address:array:character + print-string screen, msg { - cursor-to-next-line screen:address - msg:address:array:character <- new [move: ] - print-string screen:address, msg:address:array:character - m:address:move, quit:boolean, error:boolean <- read-move buffered-stdin:address:channel, screen:address - break-if quit:boolean, +quit:offset - buffered-stdin:address:channel <- clear-channel buffered-stdin:address:channel # cleanup after error. todo: test this? - loop-if error:boolean + cursor-to-next-line screen + msg <- new [move: ] + print-string screen, msg + m:address:move, quit:boolean, error:boolean <- read-move buffered-stdin, screen + break-if quit, +quit:label + buffered-stdin <- clear-channel buffered-stdin # cleanup after error. todo: test this? + loop-if error } - board:address:array:address:array:character <- make-move board:address:array:address:array:character, m:address:move - clear-screen screen:address + board <- make-move board, m + clear-screen screen loop } +quit @@ -153,84 +148,84 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } local-scope initial-position:address:array:number <- next-ingredient # assert(length(initial-position) == 64) - len:number <- length initial-position:address:array:number/deref - correct-length?:boolean <- equal len:number, 64:literal - assert correct-length?:boolean, [chessboard had incorrect size] + len:number <- length *initial-position + correct-length?:boolean <- equal len, 64 + assert correct-length?, [chessboard had incorrect size] # board is an array of pointers to files; file is an array of characters - board:address:array:address:array:character <- new location:type, 8:literal - col:number <- copy 0:literal + board:address:array:address:array:character <- new location:type, 8 + col:number <- copy 0 { - done?:boolean <- equal col:number, 8:literal - break-if done?:boolean - file:address:address:array:character <- index-address board:address:array:address:array:character/deref, col:number - file:address:address:array:character/deref <- new-file initial-position:address:array:number, col:number - col:number <- add col:number, 1:literal + done?:boolean <- equal col, 8 + break-if done? + file:address:address:array:character <- index-address *board, col + *file <- new-file initial-position, col + col <- add col, 1 loop } - reply board:address:array:address:array:character + reply board ] recipe new-file [ local-scope position:address:array:number <- next-ingredient index:number <- next-ingredient - index:number <- multiply index:number, 8:literal - result:address:array:character <- new character:type, 8:literal - row:number <- copy 0:literal + index <- multiply index, 8 + result:address:array:character <- new character:type, 8 + row:number <- copy 0 { - done?:boolean <- equal row:number, 8:literal - break-if done?:boolean - dest:address:character <- index-address result:address:array:character/deref, row:number - dest:address:character/deref <- index position:address:array:number/deref, index:number - row:number <- add row:number, 1:literal - index:number <- add index:number, 1:literal + done?:boolean <- equal row, 8 + break-if done? + dest:address:character <- index-address *result, row + *dest <- index *position, index + row <- add row, 1 + index <- add index, 1 loop } - reply result:address:array:character + reply result ] recipe print-board [ local-scope screen:address <- next-ingredient board:address:array:address:array:character <- next-ingredient - row:number <- copy 7:literal # start printing from the top of the board + row:number <- copy 7 # start printing from the top of the board # print each row -#? $print [printing board to screen ], screen:address, 10:literal/newline +#? $print [printing board to screen ], screen, 10/newline { - done?:boolean <- lesser-than row:number, 0:literal - break-if done?:boolean -#? $print [printing rank ], row:number, 10:literal/newline + done?:boolean <- lesser-than row, 0 + break-if done? +#? $print [printing rank ], row, 10/newline # print rank number as a legend - rank:number <- add row:number, 1:literal - print-integer screen:address, rank:number + rank:number <- add row, 1 + print-integer screen, rank s:address:array:character <- new [ | ] - print-string screen:address, s:address:array:character + print-string screen, s # print each square in the row - col:number <- copy 0:literal + col:number <- copy 0 { - done?:boolean <- equal col:number, 8:literal + done?:boolean <- equal col:number, 8 break-if done?:boolean - f:address:array:character <- index board:address:array:address:array:character/deref, col:number - 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 + f:address:array:character <- index *board, col + c:character <- index *f, row + print-character screen, c + print-character screen, 32/space + col <- add col, 1 loop } - row:number <- subtract row:number, 1:literal - cursor-to-next-line screen:address + row <- subtract row, 1 + cursor-to-next-line screen loop } # print file letters as legend #? $print [printing legend #? ] #? 1 - s:address:array:character <- new [ +----------------] - print-string screen:address, s:address:array:character - screen:address <- cursor-to-next-line screen:address -#? screen:address <- print-character screen:address, 97:literal #? 1 - s:address:array:character <- new [ a b c d e f g h] - screen:address <- print-string screen:address, s:address:array:character - screen:address <- cursor-to-next-line screen:address + s <- new [ +----------------] + print-string screen, s + screen <- cursor-to-next-line screen +#? screen <- print-character screen, 97 #? 1 + s <- new [ a b c d e f g h] + screen <- print-string screen, s + screen <- cursor-to-next-line screen #? $print [done printing board #? ] #? 1 ] @@ -247,24 +242,24 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } # B P _ _ _ _ p B # N P _ _ _ _ p n # R P _ _ _ _ p r - initial-position:address:array:number <- new-array 82:literal/R, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 114:literal/r, 78:literal/N, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 110:literal/n, 66:literal/B, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 98:literal/b, 81:literal/Q, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 113:literal/q, 75:literal/K, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 107:literal/k, 66:literal/B, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 98:literal/b, 78:literal/N, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 110:literal/n, 82:literal/R, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 114:literal/r -#? 82:literal/R, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 114:literal/r, -#? 78:literal/N, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 110:literal/n, -#? 66:literal/B, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 98:literal/b, -#? 81:literal/Q, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 113:literal/q, -#? 75:literal/K, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 107:literal/k, -#? 66:literal/B, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 98:literal/b, -#? 78:literal/N, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 110:literal/n, -#? 82:literal/R, 80:literal/P, 32:literal/blank, 32:literal/blank, 32:literal/blank, 32:literal/blank, 112:literal/p, 114:literal/r - board:address:array:address:array:character <- new-board initial-position:address:array:number - reply board:address:array:address:array:character + initial-position:address:array:number <- new-array 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r, 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, 81/Q, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 113/q, 75/K, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 107/k, 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r +#? 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r, +#? 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, +#? 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, +#? 81/Q, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 113/q, +#? 75/K, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 107/k, +#? 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, +#? 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, +#? 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r + board:address:array:address:array:character <- new-board initial-position + reply board ] scenario printing-the-board [ - assume-screen 30:literal/width, 12:literal/height + assume-screen 30/width, 12/height run [ - 1:address:array:address:array:character/board <- initial-position - screen:address <- print-board screen:address, 1:address:array:address:array:character/board + 1:address:array:address:array:character/board <- initial-position + screen:address <- print-board screen:address, 1:address:array:address:array:character/board #? $dump-screen #? 1 ] screen-should-contain [ @@ -300,33 +295,30 @@ container move [ local-scope stdin:address:channel <- next-ingredient screen:address <- next-ingredient -#? $print screen:address #? 1 - from-file:number, quit?:boolean, error?:boolean <- read-file stdin:address:channel, screen:address - reply-if quit?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean - reply-if error?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean -#? close-console #? 1 + from-file:number, quit?:boolean, error?:boolean <- read-file stdin, screen + reply-if quit?, 0/dummy, quit?, error? + reply-if error?, 0/dummy, quit?, error? # construct the move object 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 - x:address:number/deref, quit?:boolean, error?:boolean <- read-rank stdin:address:channel, screen:address - reply-if quit?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean - reply-if error?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean - error?:boolean <- expect-from-channel stdin:address:channel, 45:literal/dash, screen:address - reply-if error?:boolean, 0:literal/dummy, 0:literal/quit, error?:boolean - x:address:number <- get-address result:address:move/deref, to-file:offset - x:address:number/deref, quit?:boolean, error?:boolean <- read-file stdin:address:channel, screen:address - reply-if quit?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean - reply-if error?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean - x:address:number <- get-address result:address:move/deref, to-rank:offset - x:address:number/deref, quit?:boolean, error?:boolean <- read-rank stdin:address:channel, screen:address - reply-if quit?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean - reply-if error?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean -#? $exit #? 1 - error?:boolean <- expect-from-channel stdin:address:channel, 10:literal/newline, screen:address - reply-if error?:boolean, 0:literal/dummy, 0:literal/quit, error?:boolean - reply result:address:move, quit?:boolean, error?:boolean + x:address:number <- get-address *result, from-file:offset + *x <- copy from-file + x <- get-address *result, from-rank:offset + *x, quit?, error? <- read-rank stdin, screen + reply-if quit?, 0/dummy, quit?, error? + reply-if error?, 0/dummy, quit?, error? + error? <- expect-from-channel stdin, 45/dash, screen + reply-if error?, 0/dummy, 0/quit, error? + x <- get-address *result, to-file:offset + *x, quit?, error? <- read-file stdin, screen + reply-if quit?:boolean, 0/dummy, quit?:boolean, error?:boolean + reply-if error?:boolean, 0/dummy, quit?:boolean, error?:boolean + x:address:number <- get-address *result, to-rank:offset + *x, quit?, error? <- read-rank stdin, screen + reply-if quit?, 0/dummy, quit?, error? + reply-if error?, 0/dummy, quit?, error? + error? <- expect-from-channel stdin, 10/newline, screen + reply-if error?, 0/dummy, 0/quit, error? + reply result, quit?, error? ] # file:number, quit:boolean, error:boolean <- read-file stdin:address:channel, screen:address @@ -335,50 +327,49 @@ container move [ local-scope stdin:address:channel <- next-ingredient screen:address <- next-ingredient - c:character, stdin:address:channel <- read stdin:address:channel + c:character, stdin <- read stdin { - q-pressed?:boolean <- equal c:character, 81:literal # 'Q' - break-unless q-pressed?:boolean - reply 0:literal/dummy, 1:literal/quit, 0:literal/error + q-pressed?:boolean <- equal c, 81/Q + break-unless q-pressed? + reply 0/dummy, 1/quit, 0/error } { - q-pressed?:boolean <- equal c:character, 113:literal # 'q' - break-unless q-pressed?:boolean - reply 0:literal/dummy, 1:literal/quit, 0:literal/error + q-pressed? <- equal c, 113/q + break-unless q-pressed? + reply 0/dummy, 1/quit, 0/error } { - empty-fake-keyboard?:boolean <- equal c:character, 0:literal/eof - break-unless empty-fake-keyboard?:boolean - reply 0:literal/dummy, 1:literal/quit, 0:literal/error + empty-fake-keyboard?:boolean <- equal c, 0/eof + break-unless empty-fake-keyboard? + reply 0/dummy, 1/quit, 0/error } { - newline?:boolean <- equal c:character, 10:literal/newline - break-unless newline?:boolean + newline?:boolean <- equal c, 10/newline + break-unless newline? error-message:address:array:character <- new [that's not enough] - print-string screen:address, error-message:address:array:character - reply 0:literal/dummy, 0:literal/quit, 1:literal/error + print-string screen, error-message + reply 0/dummy, 0/quit, 1/error } - file:number <- subtract c:character, 97:literal # 'a' -#? $print file:number, 10:literal/newline + file:number <- subtract c, 97/a # 'a' <= file <= 'h' { - above-min:boolean <- greater-or-equal file:number, 0:literal - break-if above-min:boolean + above-min:boolean <- greater-or-equal file, 0 + break-if above-min error-message:address:array:character <- new [file too low: ] - print-string screen:address, error-message:address:array:character - print-character screen:address, c:character - cursor-to-next-line screen:address - reply 0:literal/dummy, 0:literal/quit, 1:literal/error + print-string screen, error-message + print-character screen, c + cursor-to-next-line screen + reply 0/dummy, 0/quit, 1/error } { - below-max:boolean <- lesser-than file:number, 8:literal - break-if below-max:boolean - error-message:address:array:character <- new [file too high: ] - print-string screen:address, error-message:address:array:character - print-character screen:address, c:character - reply 0:literal/dummy, 0:literal/quit, 1:literal/error + below-max:boolean <- lesser-than file, 8 + break-if below-max + error-message <- new [file too high: ] + print-string screen, error-message + print-character screen, c + reply 0/dummy, 0/quit, 1/error } - reply file:number, 0:literal/quit, 0:literal/error + reply file, 0/quit, 0/error ] # rank:number <- read-rank stdin:address:channel, screen:address @@ -387,44 +378,43 @@ container move [ local-scope stdin:address:channel <- next-ingredient screen:address <- next-ingredient - c:character, stdin:address:channel <- read stdin:address:channel + c:character, stdin <- read stdin { - q-pressed?:boolean <- equal c:character, 81:literal # 'Q' - break-unless q-pressed?:boolean - reply 0:literal/dummy, 1:literal/quit, 0:literal/error + q-pressed?:boolean <- equal c, 8/Q + break-unless q-pressed? + reply 0/dummy, 1/quit, 0/error } { - q-pressed?:boolean <- equal c:character, 113:literal # 'q' - break-unless q-pressed?:boolean - reply 0:literal/dummy, 1:literal/quit, 0:literal/error + q-pressed? <- equal c, 113/q + break-unless q-pressed? + reply 0/dummy, 1/quit, 0/error } { - newline?:boolean <- equal c:character, 10:literal # newline - break-unless newline?:boolean + newline?:boolean <- equal c, 10 # newline + break-unless newline? error-message:address:array:character <- new [that's not enough] - print-string screen:address, error-message:address:array:character - reply 0:literal/dummy, 0:literal/quit, 1:literal/error + print-string screen, error-message + reply 0/dummy, 0/quit, 1/error } - rank:number <- subtract c:character, 49:literal # '1' -#? $print rank:number, 10:literal/newline + rank:number <- subtract c, 49/'1' # assert'1' <= rank <= '8' { - above-min:boolean <- greater-or-equal rank:number, 0:literal - break-if above-min:boolean - error-message:address:array:character <- new [rank too low: ] - print-string screen:address, error-message:address:array:character - print-character screen:address, c:character - reply 0:literal/dummy, 0:literal/quit, 1:literal/error + above-min:boolean <- greater-or-equal rank, 0 + break-if above-min + error-message <- new [rank too low: ] + print-string screen, error-message + print-character screen, c + reply 0/dummy, 0/quit, 1/error } { - below-max:boolean <- lesser-or-equal rank:number, 7:literal - break-if below-max:boolean - error-message:address:array:character <- new [rank too high: ] - print-string screen:address, error-message:address:array:character - print-character screen:address, c:character - reply 0:literal/dummy, 0:literal/quit, 1:literal/error + below-max:boolean <- lesser-or-equal rank, 7 + break-if below-max + error-message <- new [rank too high: ] + print-string screen, error-message + print-character screen, c + reply 0/dummy, 0/quit, 1/error } - reply rank:number, 0:literal/quit, 0:literal/error + reply rank, 0/quit, 0/error ] # read a character from the given channel and check that it's what we expect @@ -434,93 +424,81 @@ container move [ stdin:address:channel <- next-ingredient expected:character <- next-ingredient screen:address <- next-ingredient - c:character, stdin:address:channel <- read stdin:address:channel - match?:boolean <- equal c:character, expected:character + c:character, stdin <- read stdin { - break-if match?:boolean + match?:boolean <- equal c, expected + break-if match? s:address:array:character <- new [expected character not found] - print-string screen:address, s:address:array:character + print-string screen, s } - result:boolean <- not match?:boolean - reply result:boolean + result:boolean <- not match? + reply result ] scenario read-move-blocking [ - assume-screen 20:literal/width, 2:literal/height + assume-screen 20/width, 2/height run [ -#? $start-tracing #? 1 - 1:address:channel <- new-channel 2:literal -#? $print [aaa channel address: ], 1:address:channel, 10:literal/newline - 2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address + 1:address:channel <- new-channel 2 + 2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address # 'read-move' is waiting for input - wait-for-routine 2:number -#? $print [bbb channel address: ], 1:address:channel, 10:literal/newline - 3:number <- routine-state 2:number/id -#? $print [I: routine ], 2:number, [ state ], 3:number 10:literal/newline - 4:boolean/waiting? <- equal 3:number/routine-state, 2:literal/waiting - assert 4:boolean/waiting?, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number/id + 4:boolean/waiting? <- equal 3:number/routine-state, 2/waiting + assert 4:boolean/waiting?, [ F read-move-blocking: routine failed to pause after coming up (before any keys were pressed)] # press 'a' -#? $print [ccc channel address: ], 1:address:channel, 10:literal/newline -#? $exit #? 1 - 1:address:channel <- write 1:address:channel, 97:literal # 'a' - restart 2:number/routine + 1:address:channel <- write 1:address:channel, 97/a + restart 2:number/routine # 'read-move' still waiting for input - wait-for-routine 2:number - 3:number <- routine-state 2:number/id -#? $print [II: routine ], 2:number, [ state ], 3:number 10:literal/newline - 4:boolean/waiting? <- equal 3:number/routine-state, 2:literal/waiting - assert 4:boolean/waiting?, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number/id + 4:boolean/waiting? <- equal 3:number/routine-state, 2/waiting + assert 4:boolean/waiting?, [ F read-move-blocking: routine failed to pause after rank 'a'] # press '2' - 1:address:channel <- write 1:address:channel, 50:literal # '2' - restart 2:number/routine + 1:address:channel <- write 1:address:channel, 50/'2' + restart 2:number/routine # 'read-move' still waiting for input - wait-for-routine 2:number - 3:number <- routine-state 2:number/id -#? $print [III: routine ], 2:number, [ state ], 3:number 10:literal/newline - 4:boolean/waiting? <- equal 3:number/routine-state, 2:literal/waiting - assert 4:boolean/waiting?, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number/id + 4:boolean/waiting? <- equal 3:number/routine-state, 2/waiting + assert 4:boolean/waiting?, [ F read-move-blocking: routine failed to pause after file 'a2'] # press '-' - 1:address:channel <- write 1:address:channel, 45:literal # '-' - restart 2:number/routine + 1:address:channel <- write 1:address:channel, 45/'-' + restart 2:number/routine # 'read-move' still waiting for input - wait-for-routine 2:number - 3:number <- routine-state 2:number -#? $print [IV: routine ], 2:number, [ state ], 3:number 10:literal/newline - 4:boolean/waiting? <- equal 3:number/routine-state, 2:literal/waiting - assert 4:boolean/waiting?/routine-state, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number + 4:boolean/waiting? <- equal 3:number/routine-state, 2/waiting + assert 4:boolean/waiting?/routine-state, [ F read-move-blocking: routine failed to pause after hyphen 'a2-'] # press 'a' - 1:address:channel <- write 1:address:channel, 97:literal # 'a' - restart 2:number/routine + 1:address:channel <- write 1:address:channel, 97/a + restart 2:number/routine # 'read-move' still waiting for input - wait-for-routine 2:number - 3:number <- routine-state 2:number -#? $print [V: routine ], 2:number, [ state ], 3:number 10:literal/newline - 4:boolean/waiting? <- equal 3:number/routine-state, 2:literal/waiting - assert 4:boolean/waiting?/routine-state, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number + 4:boolean/waiting? <- equal 3:number/routine-state, 2/waiting + assert 4:boolean/waiting?/routine-state, [ F read-move-blocking: routine failed to pause after rank 'a2-a'] # press '4' - 1:address:channel <- write 1:address:channel, 52:literal # '4' - restart 2:number/routine + 1:address:channel <- write 1:address:channel, 52/'4' + restart 2:number/routine # 'read-move' still waiting for input - wait-for-routine 2:number - 3:number <- routine-state 2:number -#? $print [VI: routine ], 2:number, [ state ], 3:number 10:literal/newline - 4:boolean/waiting? <- equal 3:number/routine-state, 2:literal/waiting - assert 4:boolean/waiting?, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number + 4:boolean/waiting? <- equal 3:number/routine-state, 2/waiting + assert 4:boolean/waiting?, [ F read-move-blocking: routine failed to pause after file 'a2-a4'] # press 'newline' - 1:address:channel <- write 1:address:channel, 10:literal # newline - restart 2:number/routine + 1:address:channel <- write 1:address:channel, 10 # newline + restart 2:number/routine # 'read-move' now completes - wait-for-routine 2:number - 3:number <- routine-state 2:number -#? $print [VII: routine ], 2:number, [ state ], 3:number 10:literal/newline - 4:boolean/completed? <- equal 3:number/routine-state, 1:literal/completed - assert 4:boolean/completed?, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number + 4:boolean/completed? <- equal 3:number/routine-state, 1/completed + assert 4:boolean/completed?, [ F read-move-blocking: routine failed to terminate on newline] trace [test], [reached end] ] @@ -530,24 +508,24 @@ F read-move-blocking: routine failed to terminate on newline] ] scenario read-move-quit [ - assume-screen 20:literal/width, 2:literal/height + assume-screen 20/width, 2/height run [ - 1:address:channel <- new-channel 2:literal - 2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address + 1:address:channel <- new-channel 2 + 2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address # 'read-move' is waiting for input - wait-for-routine 2:number - 3:number <- routine-state 2:number/id - 4:boolean/waiting? <- equal 3:number/routine-state, 2:literal/waiting - assert 4:boolean/waiting?, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number/id + 4:boolean/waiting? <- equal 3:number/routine-state, 2/waiting + assert 4:boolean/waiting?, [ F read-move-quit: routine failed to pause after coming up (before any keys were pressed)] # press 'q' - 1:address:channel <- write 1:address:channel, 113:literal # 'q' - restart 2:number/routine + 1:address:channel <- write 1:address:channel, 113/q + restart 2:number/routine # 'read-move' completes - wait-for-routine 2:number - 3:number <- routine-state 2:number/id - 4:boolean/completed? <- equal 3:number/routine-state, 1:literal/completed - assert 4:boolean/completed?, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number/id + 4:boolean/completed? <- equal 3:number/routine-state, 1/completed + assert 4:boolean/completed?, [ F read-move-quit: routine failed to terminate on 'q'] trace [test], [reached end] ] @@ -557,19 +535,19 @@ F read-move-quit: routine failed to terminate on 'q'] ] scenario read-move-illegal-file [ - assume-screen 20:literal/width, 2:literal/height + assume-screen 20/width, 2/height run [ - 1:address:channel <- new-channel 2:literal - 2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address + 1:address:channel <- new-channel 2 + 2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address # 'read-move' is waiting for input - wait-for-routine 2:number - 3:number <- routine-state 2:number/id - 4:boolean/waiting? <- equal 3:number/routine-state, 2:literal/waiting - assert 4:boolean/waiting?, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number/id + 4:boolean/waiting? <- equal 3:number/routine-state, 2/waiting + assert 4:boolean/waiting?, [ F read-move-file: routine failed to pause after coming up (before any keys were pressed)] - 1:address:channel <- write 1:address:channel, 50:literal # '2' - restart 2:number/routine - wait-for-routine 2:number + 1:address:channel <- write 1:address:channel, 50/'2' + restart 2:number/routine + wait-for-routine 2:number ] screen-should-contain [ .file too low: 2 . @@ -578,20 +556,20 @@ F read-move-file: routine failed to pause after co ] scenario read-move-illegal-rank [ - assume-screen 20:literal/width, 2:literal/height + assume-screen 20/width, 2/height run [ - 1:address:channel <- new-channel 2:literal - 2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address + 1:address:channel <- new-channel 2 + 2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address # 'read-move' is waiting for input - wait-for-routine 2:number - 3:number <- routine-state 2:number/id - 4:boolean/waiting? <- equal 3:number/routine-state, 2:literal/waiting - assert 4:boolean/waiting?, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number/id + 4:boolean/waiting? <- equal 3:number/routine-state, 2/waiting + assert 4:boolean/waiting?, [ F read-move-file: routine failed to pause after coming up (before any keys were pressed)] - 1:address:channel <- write 1:address:channel, 97:literal # 'a' - 1:address:channel <- write 1:address:channel, 97:literal # 'a' - restart 2:number/routine - wait-for-routine 2:number + 1:address:channel <- write 1:address:channel, 97/a + 1:address:channel <- write 1:address:channel, 97/a + restart 2:number/routine + wait-for-routine 2:number ] screen-should-contain [ .rank too high: a . @@ -600,20 +578,20 @@ F read-move-file: routine failed to pause after co ] scenario read-move-empty [ - assume-screen 20:literal/width, 2:literal/height + assume-screen 20/width, 2/height run [ - 1:address:channel <- new-channel 2:literal - 2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address + 1:address:channel <- new-channel 2 + 2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address # 'read-move' is waiting for input - wait-for-routine 2:number - 3:number <- routine-state 2:number/id - 4:boolean/waiting? <- equal 3:number/routine-state, 2:literal/waiting - assert 4:boolean/waiting?, [ + wait-for-routine 2:number + 3:number <- routine-state 2:number/id + 4:boolean/waiting? <- equal 3:number/routine-state, 2/waiting + assert 4:boolean/waiting?, [ F read-move-file: routine failed to pause after coming up (before any keys were pressed)] - 1:address:channel <- write 1:address:channel, 10:literal/newline - 1:address:channel <- write 1:address:channel, 97:literal # 'a' - restart 2:number/routine - wait-for-routine 2:number + 1:address:channel <- write 1:address:channel, 10/newline + 1:address:channel <- write 1:address:channel, 97/a + restart 2:number/routine + wait-for-routine 2:number ] screen-should-contain [ .that's not enough . @@ -625,39 +603,34 @@ F read-move-file: routine failed to pause after co local-scope b:address:array:address:array:character <- next-ingredient m:address:move <- next-ingredient - from-file:number <- get m:address:move/deref, from-file:offset -#? $print from-file:number, 10:literal/newline - from-rank:number <- get m:address:move/deref, from-rank:offset -#? $print from-rank:number, 10:literal/newline - to-file:number <- get m:address:move/deref, to-file:offset -#? $print to-file:number, 10:literal/newline - to-rank:number <- get m:address:move/deref, to-rank:offset -#? $print to-rank:number, 10:literal/newline - f:address:array:character <- index b:address:array:address:array:character/deref, from-file:number - src:address:character/square <- index-address f:address:array:character/deref, from-rank:number - f:address:array:character <- index b:address:array:address:array:character/deref, to-file:number - dest:address:character/square <- index-address f:address:array:character/deref, to-rank:number -#? $print src:address:character/deref, 10:literal/newline - dest:address:character/deref/square <- copy src:address:character/deref/square - src:address:character/deref/square <- copy 32:literal # ' ' - reply b:address:array:address:array:character/same-as-ingredient:0 + from-file:number <- get *m, from-file:offset + from-rank:number <- get *m, from-rank:offset + to-file:number <- get *m, to-file:offset + to-rank:number <- get *m, to-rank:offset + f:address:array:character <- index *b, from-file + src:address:character/square <- index-address *f, from-rank + f <- index *b, to-file + dest:address:character/square <- index-address *f, to-rank + *dest <- copy *src + *src <- copy 32/space + reply b/same-as-ingredient:0 ] scenario making-a-move [ - assume-screen 30:literal/width, 12:literal/height + assume-screen 30/width, 12/height run [ - 2:address:array:address:array:character/board <- initial-position - 3:address:move <- new move:type - 4:address:number <- get-address 3:address:move/deref, from-file:offset - 4:address:number/deref <- copy 6:literal/g - 5:address:number <- get-address 3:address:move/deref, from-rank:offset - 5:address:number/deref <- copy 1:literal/2 - 6:address:number <- get-address 3:address:move/deref, to-file:offset - 6:address:number/deref <- copy 6:literal/g - 7:address:number <- get-address 3:address:move/deref, to-rank:offset - 7:address:number/deref <- copy 3:literal/4 - 2:address:array:address:array:character/board <- make-move 2:address:array:address:array:character/board, 3:address:move - screen:address <- print-board screen:address, 2:address:array:address:array:character/board + 2:address:array:address:array:character/board <- initial-position + 3:address:move <- new move:type + 4:address:number <- get-address *3:address:move, from-file:offset + *4:address:number <- copy 6/g + 5:address:number <- get-address *3:address:move, from-rank:offset + *5:address:number <- copy 1/'2' + 6:address:number <- get-address *3:address:move, to-file:offset + *6:address:number <- copy 6/g + 7:address:number <- get-address *3:address:move, to-rank:offset + *7:address:number <- copy 3/'4' + 2:address:array:address:array:character/board <- make-move 2:address:array:address:array:character/board, 3:address:move + screen:address <- print-board screen:address, 2:address:array:address:array:character/board ] screen-should-contain [ # 012345678901234567890123456789 diff --git a/html/console.mu.html b/html/console.mu.html index 098c7e43..8e0f4284 100644 --- a/html/console.mu.html +++ b/html/console.mu.html @@ -13,12 +13,12 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Constant { color: #00a0a0; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .Special { color: #ff6060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -38,8 +38,8 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } open-console { _, found?:boolean <- check-for-interaction - break-if found?:boolean - print-character-to-display 97:literal, 7:literal/white + break-if found? + print-character-to-display 97, 7/white loop } close-console diff --git a/html/counters.mu.html b/html/counters.mu.html index df75d6bd..926eca68 100644 --- a/html/counters.mu.html +++ b/html/counters.mu.html @@ -13,11 +13,11 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -33,34 +33,34 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } # (spaces) recipe new-counter [ - default-space:address:array:location <- new location:type, 30:literal + default-space:address:array:location <- new location:type, 30 n:number <- next-ingredient - reply default-space:address:array:location + reply default-space ] recipe increment-counter [ local-scope - 0:address:array:location/names:new-counter <- next-ingredient # setup outer space; it *must* come from 'new-counter' + 0:address:array:location/names:new-counter <- next-ingredient # setup outer space; it *must* come from 'new-counter' x:number <- next-ingredient - n:number/space:1 <- add n:number/space:1, x:number - reply n:number/space:1 + n:number/space:1 <- add n:number/space:1, x + reply n:number/space:1 ] recipe main [ local-scope # counter A - a:address:array:location <- new-counter 34:literal + a:address:array:location <- new-counter 34 # counter B - b:address:array:location <- new-counter 23:literal + b:address:array:location <- new-counter 23 # increment both by 2 but in different ways - increment-counter a:address:array:location, 1:literal - b-value:number <- increment-counter b:address:array:location, 2:literal - a-value:number <- increment-counter a:address:array:location, 1:literal + increment-counter a, 1 + b-value:number <- increment-counter b, 2 + a-value:number <- increment-counter a, 1 # check results $print [Contents of counters ] # trailing space in next line is to help with syntax highlighting - $print [a: ], a-value:number, [ b: ], b-value:number, [ + $print [a: ], a-value, [ b: ], b-value, [ ] ] diff --git a/html/display.mu.html b/html/display.mu.html index 04daf6de..baf12e83 100644 --- a/html/display.mu.html +++ b/html/display.mu.html @@ -13,11 +13,11 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } -.CommentedCode { color: #6c6c6c; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } -.muRecipe { color: #ff8700; } +.CommentedCode { color: #6c6c6c; } --> @@ -33,14 +33,14 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } recipe main [ open-console - print-character-to-display 97:literal, 1:literal/red, 2:literal/green - 1:number/raw, 2:number/raw <- cursor-position-on-display + print-character-to-display 97, 1/red, 2/green + 1:number/raw, 2:number/raw <- cursor-position-on-display wait-for-some-interaction clear-display - move-cursor-on-display 0:literal, 4:literal - print-character-to-display 98:literal + move-cursor-on-display 0, 4 + print-character-to-display 98 wait-for-some-interaction - move-cursor-on-display 0:literal, 0:literal + move-cursor-on-display 0, 0 clear-line-on-display wait-for-some-interaction move-cursor-down-on-display diff --git a/html/edit.mu.html b/html/edit.mu.html index f86b4c35..fa1b442f 100644 --- a/html/edit.mu.html +++ b/html/edit.mu.html @@ -13,15 +13,15 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } +.Delimiter { color: #a04060; } .muScenario { color: #00af00; } .SalientComment { color: #00ffff; } -.Delimiter { color: #a04060; } -.CommentedCode { color: #6c6c6c; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } +.CommentedCode { color: #6c6c6c; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -40,11 +40,11 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } open-console initial-recipe:address:array:character <- restore [recipes.mu] initial-sandbox:address:array:character <- new [] - env:address:programming-environment-data <- new-programming-environment 0:literal/screen, initial-recipe:address:array:character, initial-sandbox:address:array:character - env:address:programming-environment-data <- restore-sandboxes env:address:programming-environment-data - render-all 0:literal/screen, env:address:programming-environment-data - show-screen 0:literal/screen - event-loop 0:literal/screen, 0:literal/console, env:address:programming-environment-data + env:address:programming-environment-data <- new-programming-environment 0/screen, initial-recipe, initial-sandbox + env <- restore-sandboxes env + render-all 0/screen, env + show-screen 0/screen + event-loop 0/screen, 0/console, env # never gets here ] @@ -61,37 +61,37 @@ container programming-environment-data [ screen:address <- next-ingredient initial-recipe-contents:address:array:character <- next-ingredient initial-sandbox-contents:address:array:character <- next-ingredient - width:number <- screen-width screen:address - height:number <- screen-height screen:address + width:number <- screen-width screen + height:number <- screen-height screen # top menu result:address:programming-environment-data <- new programming-environment-data:type - draw-horizontal screen:address, 0:literal, 0:literal/left, width:number, 32:literal/space, 0:literal/black, 238:literal/grey - button-start:number <- subtract width:number, 20:literal - button-on-screen?:boolean <- greater-or-equal button-start:number, 0:literal - assert button-on-screen?:boolean, [screen too narrow for menu] - move-cursor screen:address, 0:literal/row, button-start:number/column - run-button:address:array:character <- new [ run (F10) ] - print-string screen:address, run-button:address:array:character, 255:literal/white, 161:literal/reddish + draw-horizontal screen, 0, 0/left, width, 32/space, 0/black, 238/grey + button-start:number <- subtract width, 20 + button-on-screen?:boolean <- greater-or-equal button-start, 0 + assert button-on-screen?, [screen too narrow for menu] + move-cursor screen, 0/row, button-start + run-button:address:array:character <- new [ run (F4) ] + print-string screen, run-button, 255/white, 161/reddish # dotted line down the middle - divider:number, _ <- divide-with-remainder width:number, 2:literal - draw-vertical screen:address, divider:number, 1:literal/top, height:number, 9482:literal/vertical-dotted + divider:number, _ <- divide-with-remainder width, 2 + draw-vertical screen, divider, 1/top, height, 9482/vertical-dotted # recipe editor on the left - recipes:address:address:editor-data <- get-address result:address:programming-environment-data/deref, recipes:offset - recipes:address:address:editor-data/deref <- new-editor initial-recipe-contents:address:array:character, screen:address, 0:literal/left, divider:number/right + recipes:address:address:editor-data <- get-address *result, recipes:offset + *recipes <- new-editor initial-recipe-contents, screen, 0/left, divider/right # sandbox editor on the right - new-left:number <- add divider:number, 1:literal - new-right:number <- add new-left:number, 5:literal - current-sandbox:address:address:editor-data <- get-address result:address:programming-environment-data/deref, current-sandbox:offset - current-sandbox:address:address:editor-data/deref <- new-editor initial-sandbox-contents:address:array:character, screen:address, new-left:number, width:number - screen:address <- render-all screen:address, result:address:programming-environment-data - reply result:address:programming-environment-data + new-left:number <- add divider, 1 + new-right:number <- add new-left, 5 + current-sandbox:address:address:editor-data <- get-address *result, current-sandbox:offset + *current-sandbox <- new-editor initial-sandbox-contents, screen, new-left, width/right + screen <- render-all screen, result + reply result ] scenario editor-initially-prints-string-to-screen [ - assume-screen 10:literal/width, 5:literal/height + assume-screen 10/width, 5/height run [ - 1:address:array:character <- new [abc] - new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 1:address:array:character <- new [abc] + new-editor 1:address:array:character, screen:address, 0/left, 10/right ] screen-should-contain [ . . @@ -129,60 +129,60 @@ container editor-data [ # no clipping of bounds left:number <- next-ingredient right:number <- next-ingredient - right:number <- subtract right:number, 1:literal + right <- subtract right, 1 result:address:editor-data <- new editor-data:type # initialize screen-related fields - x:address:number <- get-address result:address:editor-data/deref, left:offset - x:address:number/deref <- copy left:number - x:address:number <- get-address result:address:editor-data/deref, right:offset - x:address:number/deref <- copy right:number + x:address:number <- get-address *result, left:offset + *x <- copy left + x <- get-address *result, right:offset + *x <- copy right # initialize cursor - x:address:number <- get-address result:address:editor-data/deref, cursor-row:offset - x:address:number/deref <- copy 1:literal/top - x:address:number <- get-address result:address:editor-data/deref, cursor-column:offset - x:address:number/deref <- copy left:number - init:address:address:duplex-list <- get-address result:address:editor-data/deref, data:offset - init:address:address:duplex-list/deref <- push-duplex 167:literal/§, 0:literal/tail - y:address:address:duplex-list <- get-address result:address:editor-data/deref, before-cursor:offset - y:address:address:duplex-list/deref <- copy init:address:address:duplex-list/deref + x <- get-address *result, cursor-row:offset + *x <- copy 1/top + x <- get-address *result, cursor-column:offset + *x <- copy left + init:address:address:duplex-list <- get-address *result, data:offset + *init <- push-duplex 167/§, 0/tail + y:address:address:duplex-list <- get-address *result, before-cursor:offset + *y <- copy *init # early exit if s is empty - reply-unless s:address:array:character, result:address:editor-data - len:number <- length s:address:array:character/deref - reply-unless len:number, result:address:editor-data - idx:number <- copy 0:literal + reply-unless s, result + len:number <- length *s + reply-unless len, result + idx:number <- copy 0 # now we can start appending the rest, character by character - curr:address:duplex-list <- copy init:address:address:duplex-list/deref + curr:address:duplex-list <- copy *init { - done?:boolean <- greater-or-equal idx:number, len:number - break-if done?:boolean - c:character <- index s:address:array:character/deref, idx:number - insert-duplex c:character, curr:address:duplex-list + done?:boolean <- greater-or-equal idx, len + break-if done? + c:character <- index *s, idx + insert-duplex c, curr # next iter - curr:address:duplex-list <- next-duplex curr:address:duplex-list - idx:number <- add idx:number, 1:literal + curr <- next-duplex curr + idx <- add idx, 1 loop } # initialize cursor to top of screen - y:address:address:duplex-list <- get-address result:address:editor-data/deref, before-cursor:offset - y:address:address:duplex-list/deref <- copy init:address:address:duplex-list/deref + y <- get-address *result, before-cursor:offset + *y <- copy *init # initial render to screen, just for some old tests - _, screen:address <- render screen:address, result:address:editor-data - reply result:address:editor-data + _, screen <- render screen, result + reply result ] scenario editor-initializes-without-data [ - assume-screen 5:literal/width, 3:literal/height + assume-screen 5/width, 3/height run [ - 1:address:editor-data <- new-editor 0:literal/data, screen:address, 2:literal/left, 5:literal/right - 2:editor-data <- copy 1:address:editor-data/deref + 1:address:editor-data <- new-editor 0/data, screen:address, 2/left, 5/right + 2:editor-data <- copy *1:address:editor-data ] memory-should-contain [ # 2 (data) <- just the § sentinel # 3 (before cursor) <- the § sentinel - 4 <- 2 # left - 5 <- 4 # right (inclusive) - 6 <- 1 # cursor row - 7 <- 2 # cursor column + 4 <- 2 # left + 5 <- 4 # right (inclusive) + 6 <- 1 # cursor row + 7 <- 2 # cursor column ] screen-should-contain [ . . @@ -196,108 +196,108 @@ container editor-data [ local-scope screen:address <- next-ingredient editor:address:editor-data <- next-ingredient - reply-unless editor:address:editor-data, 1:literal/top, screen:address/same-as-ingredient:0 - left:number <- get editor:address:editor-data/deref, left:offset - screen-height:number <- screen-height screen:address - right:number <- get editor:address:editor-data/deref, right:offset - hide-screen screen:address + reply-unless editor, 1/top, screen/same-as-ingredient:0 + left:number <- get *editor, left:offset + screen-height:number <- screen-height screen + right:number <- get *editor, right:offset + hide-screen screen # highlight mu code with color - color:number <- copy 7:literal/white - highlighting-state:number <- copy 0:literal/normal + color:number <- copy 7/white + highlighting-state:number <- copy 0/normal # traversing editor - curr:address:duplex-list <- get editor:address:editor-data/deref, data:offset - prev:address:duplex-list <- copy curr:address:duplex-list - curr:address:duplex-list <- next-duplex curr:address:duplex-list + curr:address:duplex-list <- get *editor, data:offset + prev:address:duplex-list <- copy curr + curr <- next-duplex curr # traversing screen - row:number <- copy 1:literal/top - column:number <- copy left:number - cursor-row:address:number <- get-address editor:address:editor-data/deref, cursor-row:offset - cursor-column:address:number <- get-address editor:address:editor-data/deref, cursor-column:offset - before-cursor:address:address:duplex-list <- get-address editor:address:editor-data/deref, before-cursor:offset - move-cursor screen:address, row:number, column:number + row:number <- copy 1/top + column:number <- copy left + cursor-row:address:number <- get-address *editor, cursor-row:offset + cursor-column:address:number <- get-address *editor, cursor-column:offset + before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + move-cursor screen, row, column { +next-character - break-unless curr:address:duplex-list - off-screen?:boolean <- greater-or-equal row:number, screen-height:number - break-if off-screen?:boolean + break-unless curr + off-screen?:boolean <- greater-or-equal row, screen-height + break-if off-screen? # update editor-data.before-cursor # Doing so at the start of each iteration ensures it stays one step behind # the current character. { - at-cursor-row?:boolean <- equal row:number, cursor-row:address:number/deref - break-unless at-cursor-row?:boolean - at-cursor?:boolean <- equal column:number, cursor-column:address:number/deref - break-unless at-cursor?:boolean - before-cursor:address:address:duplex-list/deref <- prev-duplex curr:address:duplex-list + at-cursor-row?:boolean <- equal row, *cursor-row + break-unless at-cursor-row? + at-cursor?:boolean <- equal column, *cursor-column + break-unless at-cursor? + *before-cursor <- prev-duplex curr } - c:character <- get curr:address:duplex-list/deref, value:offset - color:number, highlighting-state:number <- get-color color:number, highlighting-state:number, c:character + c:character <- get *curr, value:offset + color, highlighting-state <- get-color color, highlighting-state, c { # newline? move to left rather than 0 - newline?:boolean <- equal c:character, 10:literal/newline - break-unless newline?:boolean + newline?:boolean <- equal c, 10/newline + break-unless newline? # adjust cursor if necessary { - at-cursor-row?:boolean <- equal row:number, cursor-row:address:number/deref - break-unless at-cursor-row?:boolean - left-of-cursor?:boolean <- lesser-than column:number, cursor-column:address:number/deref - break-unless left-of-cursor?:boolean - cursor-column:address:number/deref <- copy column:number - before-cursor:address:address:duplex-list/deref <- prev-duplex curr:address:duplex-list + at-cursor-row?:boolean <- equal row, *cursor-row + break-unless at-cursor-row? + left-of-cursor?:boolean <- lesser-than column, *cursor-column + break-unless left-of-cursor? + *cursor-column <- copy column + *before-cursor <- prev-duplex curr } # clear rest of line in this window - clear-line-delimited screen:address, column:number, right:number + clear-line-delimited screen, column, right # skip to next line - row:number <- add row:number, 1:literal - column:number <- copy left:number - move-cursor screen:address, row:number, column:number - curr:address:duplex-list <- next-duplex curr:address:duplex-list - prev:address:duplex-list <- next-duplex prev:address:duplex-list + row <- add row, 1 + column <- copy left + move-cursor screen, row, column + curr <- next-duplex curr + prev <- next-duplex prev loop +next-character:label } { # at right? wrap. even if there's only one more letter left; we need # room for clicking on the cursor after it. - at-right?:boolean <- equal column:number, right:number - break-unless at-right?:boolean + at-right?:boolean <- equal column, right + break-unless at-right? # print wrap icon - print-character screen:address, 8617:literal/loop-back-to-left, 245:literal/grey - column:number <- copy left:number - row:number <- add row:number, 1:literal - move-cursor screen:address, row:number, column:number + print-character screen, 8617/loop-back-to-left, 245/grey + column <- copy left + row <- add row, 1 + move-cursor screen, row, column # don't increment curr loop +next-character:label } - print-character screen:address, c:character, color:number - curr:address:duplex-list <- next-duplex curr:address:duplex-list - prev:address:duplex-list <- next-duplex prev:address:duplex-list - column:number <- add column:number, 1:literal + print-character screen, c, color + curr <- next-duplex curr + prev <- next-duplex prev + column <- add column, 1 loop } # is cursor to the right of the last line? move to end { - at-cursor-row?:boolean <- equal row:number, cursor-row:address:number/deref - cursor-outside-line?:boolean <- lesser-or-equal column:number, cursor-column:address:number/deref - before-cursor-on-same-line?:boolean <- and at-cursor-row?:boolean, cursor-outside-line?:boolean - above-cursor-row?:boolean <- lesser-than row:number, cursor-row:address:number/deref - before-cursor?:boolean <- or before-cursor-on-same-line?:boolean, above-cursor-row?:boolean - break-unless before-cursor?:boolean - cursor-row:address:number/deref <- copy row:number - cursor-column:address:number/deref <- copy column:number + at-cursor-row?:boolean <- equal row, *cursor-row + cursor-outside-line?:boolean <- lesser-or-equal column, *cursor-column + before-cursor-on-same-line?:boolean <- and at-cursor-row?, cursor-outside-line? + above-cursor-row?:boolean <- lesser-than row, *cursor-row + before-cursor?:boolean <- or before-cursor-on-same-line?, above-cursor-row? + break-unless before-cursor? + *cursor-row <- copy row + *cursor-column <- copy column # line not wrapped but cursor outside bounds? wrap cursor { - too-far-right?:boolean <- greater-than cursor-column:address:number/deref, right:number - break-unless too-far-right?:boolean - cursor-column:address:number/deref <- copy left:number - cursor-row:address:number/deref <- add cursor-row:address:number/deref, 1:literal - above-screen-bottom?:boolean <- lesser-than cursor-row:address:number/deref, screen-height:number - assert above-screen-bottom?:boolean, [unimplemented: wrapping cursor past bottom of screen] + too-far-right?:boolean <- greater-than *cursor-column, right + break-unless too-far-right? + *cursor-column <- copy left + *cursor-row <- add *cursor-row, 1 + above-screen-bottom?:boolean <- lesser-than *cursor-row, screen-height + assert above-screen-bottom?, [unimplemented: wrapping cursor past bottom of screen] } - before-cursor:address:address:duplex-list/deref <- copy prev:address:duplex-list + *before-cursor <- copy prev } # clear rest of current line - clear-line-delimited screen:address, column:number, right:number - reply row:number, screen:address/same-as-ingredient:0 + clear-line-delimited screen, column, right + reply row, screen/same-as-ingredient:0 ] # row:number, screen:address <- render-string screen:address, s:address:array:character, left:number, right:number, color:number, row:number @@ -312,62 +312,62 @@ container editor-data [ right:number <- next-ingredient color:number <- next-ingredient row:number <- next-ingredient - row:number <- add row:number, 1:literal - reply-unless s:address:array:character, row:number/same-as-ingredient:5, screen:address/same-as-ingredient:0 - column:number <- copy left:number - move-cursor screen:address, row:number, column:number - screen-height:number <- screen-height screen:address - i:number <- copy 0:literal - len:number <- length s:address:array:character/deref + row <- add row, 1 + reply-unless s, row/same-as-ingredient:5, screen/same-as-ingredient:0 + column:number <- copy left + move-cursor screen, row, column + screen-height:number <- screen-height screen + i:number <- copy 0 + len:number <- length *s { +next-character - done?:boolean <- greater-or-equal i:number, len:number - break-if done?:boolean - done?:boolean <- greater-or-equal row:number, screen-height:number - break-if done?:boolean - c:character <- index s:address:array:character/deref, i:number + done?:boolean <- greater-or-equal i, len + break-if done? + done? <- greater-or-equal row, screen-height + break-if done? + c:character <- index *s, i { # at right? wrap. - at-right?:boolean <- equal column:number, right:number - break-unless at-right?:boolean + at-right?:boolean <- equal column, right + break-unless at-right? # print wrap icon - print-character screen:address, 8617:literal/loop-back-to-left, 245:literal/grey - column:number <- copy left:number - row:number <- add row:number, 1:literal - move-cursor screen:address, row:number, column:number + print-character screen, 8617/loop-back-to-left, 245/grey + column <- copy left + row <- add row, 1 + move-cursor screen, row, column loop +next-character:label # retry i } - i:number <- add i:number, 1:literal + i <- add i, 1 { # newline? move to left rather than 0 - newline?:boolean <- equal c:character, 10:literal/newline - break-unless newline?:boolean + newline?:boolean <- equal c, 10/newline + break-unless newline? # clear rest of line in this window { - done?:boolean <- greater-than column:number, right:number - break-if done?:boolean - print-character screen:address, 32:literal/space - column:number <- add column:number, 1:literal + done?:boolean <- greater-than column, right + break-if done? + print-character screen, 32/space + column <- add column, 1 loop } - row:number <- add row:number, 1:literal - column:number <- copy left:number - move-cursor screen:address, row:number, column:number + row <- add row, 1 + column <- copy left + move-cursor screen, row, column loop +next-character:label } - print-character screen:address, c:character, color:number - column:number <- add column:number, 1:literal + print-character screen, c, color + column <- add column, 1 loop } { # clear rest of current line - line-done?:boolean <- greater-than column:number, right:number - break-if line-done?:boolean - print-character screen:address, 32:literal/space - column:number <- add column:number, 1:literal + line-done?:boolean <- greater-than column, right + break-if line-done? + print-character screen, 32/space + column <- add column, 1 loop } - reply row:number/same-as-ingredient:5, screen:address/same-as-ingredient:0 + reply row/same-as-ingredient:5, screen/same-as-ingredient:0 ] # row:number, screen:address <- render-screen screen:address, sandbox-screen:address, left:number, right:number, row:number @@ -380,63 +380,63 @@ container editor-data [ left:number <- next-ingredient right:number <- next-ingredient row:number <- next-ingredient - row:number <- add row:number, 1:literal - reply-unless s:address:screen, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 + row <- add row, 1 + reply-unless s, row/same-as-ingredient:4, screen/same-as-ingredient:0 # print 'screen:' header:address:array:character <- new [screen:] - row:number <- subtract row:number, 1:literal # compensate for render-string below - row:number <- render-string screen:address, header:address:array:character, left:number, right:number, 245:literal/grey, row:number + row <- subtract row, 1 # compensate for render-string below + row <- render-string screen, header, left, right, 245/grey, row # newline - row:number <- add row:number, 1:literal - move-cursor screen:address, row:number, left:number + row <- add row, 1 + move-cursor screen, row, left # start printing s - column:number <- copy left:number - s-width:number <- screen-width s:address:screen - s-height:number <- screen-height s:address:screen - buf:address:array:screen-cell <- get s:address:screen/deref, data:offset - stop-printing:number <- add left:number, s-width:number, 3:literal - max-column:number <- min stop-printing:number, right:number - i:number <- copy 0:literal - len:number <- length buf:address:array:screen-cell/deref - screen-height:number <- screen-height screen:address + column:number <- copy left + s-width:number <- screen-width s + s-height:number <- screen-height s + buf:address:array:screen-cell <- get *s, data:offset + stop-printing:number <- add left, s-width, 3 + max-column:number <- min stop-printing, right + i:number <- copy 0 + len:number <- length *buf + screen-height:number <- screen-height screen { - done?:boolean <- greater-or-equal i:number, len:number - break-if done?:boolean - done?:boolean <- greater-or-equal row:number, screen-height:number - break-if done?:boolean - column:number <- copy left:number - move-cursor screen:address, row:number, column:number + done?:boolean <- greater-or-equal i, len + break-if done? + done? <- greater-or-equal row, screen-height + break-if done? + column <- copy left + move-cursor screen, row, column # initial leader for each row: two spaces and a '.' - print-character screen:address, 32:literal/space, 245:literal/grey - print-character screen:address, 32:literal/space, 245:literal/grey - print-character screen:address, 46:literal/full-stop, 245:literal/grey - column:number <- add left:number, 3:literal + print-character screen, 32/space, 245/grey + print-character screen, 32/space, 245/grey + print-character screen, 46/full-stop, 245/grey + column <- add left, 3 { # print row - row-done?:boolean <- greater-or-equal column:number, max-column:number - break-if row-done?:boolean - curr:screen-cell <- index buf:address:array:screen-cell/deref, i:number - c:character <- get curr:screen-cell, contents:offset - print-character screen:address, c:character, 245:literal/grey - column:number <- add column:number, 1:literal - i:number <- add i:number, 1:literal + row-done?:boolean <- greater-or-equal column, max-column + break-if row-done? + curr:screen-cell <- index *buf, i + c:character <- get curr, contents:offset + print-character screen, c, 245/grey + column <- add column, 1 + i <- add i, 1 loop } # print final '.' - print-character screen:address, 46:literal/full-stop, 245:literal/grey - column:number <- add column:number, 1:literal + print-character screen, 46/full-stop, 245/grey + column <- add column, 1 { # clear rest of current line - line-done?:boolean <- greater-than column:number, right:number - break-if line-done?:boolean - print-character screen:address, 32:literal/space - column:number <- add column:number, 1:literal + line-done?:boolean <- greater-than column, right + break-if line-done? + print-character screen, 32/space + column <- add column, 1 loop } - row:number <- add row:number, 1:literal + row <- add row, 1 loop } - reply row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 + reply row/same-as-ingredient:4, screen/same-as-ingredient:0 ] recipe clear-line-delimited [ @@ -444,22 +444,22 @@ container editor-data [ screen:address <- next-ingredient left:number <- next-ingredient right:number <- next-ingredient - column:number <- copy left:number + column:number <- copy left { - done?:boolean <- greater-than column:number, right:number - break-if done?:boolean - print-character screen:address, 32:literal/space - column:number <- add column:number, 1:literal + done?:boolean <- greater-than column, right + break-if done? + print-character screen, 32/space + column <- add column, 1 loop } ] scenario editor-initially-prints-multiple-lines [ - assume-screen 5:literal/width, 5:literal/height + assume-screen 5/width, 5/height run [ s:address:array:character <- new [abc def] - new-editor s:address:array:character, screen:address, 0:literal/left, 5:literal/right + new-editor s:address:array:character, screen:address, 0/left, 5/right ] screen-should-contain [ . . @@ -470,10 +470,10 @@ container editor-data [ ] scenario editor-initially-handles-offsets [ - assume-screen 5:literal/width, 5:literal/height + assume-screen 5/width, 5/height run [ s:address:array:character <- new [abc] - new-editor s:address:array:character, screen:address, 1:literal/left, 5:literal/right + new-editor s:address:array:character, screen:address, 1/left, 5/right ] screen-should-contain [ . . @@ -483,11 +483,11 @@ container editor-data [ ] scenario editor-initially-prints-multiple-lines-at-offset [ - assume-screen 5:literal/width, 5:literal/height + assume-screen 5/width, 5/height run [ s:address:array:character <- new [abc def] - new-editor s:address:array:character, screen:address, 1:literal/left, 5:literal/right + new-editor s:address:array:character, screen:address, 1/left, 5/right ] screen-should-contain [ . . @@ -498,10 +498,10 @@ container editor-data [ ] scenario editor-initially-wraps-long-lines [ - assume-screen 5:literal/width, 5:literal/height + assume-screen 5/width, 5/height run [ s:address:array:character <- new [abc def] - new-editor s:address:array:character, screen:address, 0:literal/left, 5:literal/right + new-editor s:address:array:character, screen:address, 0/left, 5/right ] screen-should-contain [ . . @@ -509,7 +509,7 @@ container editor-data [ .def . . . ] - screen-should-contain-in-color 245:literal/grey [ + screen-should-contain-in-color 245/grey [ . . . ↩. . . @@ -518,10 +518,10 @@ container editor-data [ ] scenario editor-initially-wraps-barely-long-lines [ - assume-screen 5:literal/width, 5:literal/height + assume-screen 5/width, 5/height run [ s:address:array:character <- new [abcde] - new-editor s:address:array:character, screen:address, 0:literal/left, 5:literal/right + new-editor s:address:array:character, screen:address, 0/left, 5/right ] # still wrap, even though the line would fit. We need room to click on the # end of the line @@ -531,7 +531,7 @@ container editor-data [ .e . . . ] - screen-should-contain-in-color 245:literal/grey [ + screen-should-contain-in-color 245/grey [ . . . ↩. . . @@ -540,12 +540,12 @@ container editor-data [ ] scenario editor-initializes-empty-text [ - assume-screen 5:literal/width, 5:literal/height + assume-screen 5/width, 5/height run [ - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + 1:address:array:character <- new [] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] screen-should-contain [ . . @@ -553,20 +553,20 @@ container editor-data [ . . ] memory-should-contain [ - 3 <- 1 # cursor row - 4 <- 0 # cursor column + 3 <- 1 # cursor row + 4 <- 0 # cursor column ] ] ## highlighting mu code scenario render-colors-comments [ - assume-screen 5:literal/width, 5:literal/height + assume-screen 5/width, 5/height run [ s:address:array:character <- new [abc # de f] - new-editor s:address:array:character, screen:address, 0:literal/left, 5:literal/right + new-editor s:address:array:character, screen:address, 0/left, 5/right ] screen-should-contain [ . . @@ -575,14 +575,14 @@ container editor-data [ .f . . . ] - screen-should-contain-in-color 12:literal/lightblue, [ + screen-should-contain-in-color 12/lightblue, [ . . . . .# de . . . . . ] - screen-should-contain-in-color 7:literal/white, [ + screen-should-contain-in-color 7/white, [ . . .abc . . . @@ -597,56 +597,56 @@ container editor-data [ color:number <- next-ingredient highlighting-state:number <- next-ingredient c:character <- next-ingredient - color-is-white?:boolean <- equal color:number, 7:literal/white -#? $print [character: ], c:character, 10:literal/newline #? 1 + color-is-white?:boolean <- equal color, 7/white +#? $print [character: ], c, 10/newline #? 1 # if color is white and next character is '#', switch color to blue { - break-unless color-is-white?:boolean - starting-comment?:boolean <- equal c:character, 35:literal/# - break-unless starting-comment?:boolean -#? $print [switch color back to blue], 10:literal/newline #? 1 - color:number <- copy 12:literal/lightblue + break-unless color-is-white? + starting-comment?:boolean <- equal c, 35/# + break-unless starting-comment? +#? $print [switch color back to blue], 10/newline #? 1 + color <- copy 12/lightblue jump +exit:label } # if color is blue and next character is newline, switch color to white { - color-is-blue?:boolean <- equal color:number, 12:literal/lightblue - break-unless color-is-blue?:boolean - ending-comment?:boolean <- equal c:character, 10:literal/newline - break-unless ending-comment?:boolean -#? $print [switch color back to white], 10:literal/newline #? 1 - color:number <- copy 7:literal/white + color-is-blue?:boolean <- equal color, 12/lightblue + break-unless color-is-blue? + ending-comment?:boolean <- equal c, 10/newline + break-unless ending-comment? +#? $print [switch color back to white], 10/newline #? 1 + color <- copy 7/white jump +exit:label } # if color is white (no comments) and next character is '<', switch color to red { - break-unless color-is-white?:boolean - starting-assignment?:boolean <- equal c:character, 60:literal/< - break-unless starting-assignment?:boolean - color:number <- copy 1:literal/red + break-unless color-is-white? + starting-assignment?:boolean <- equal c, 60/< + break-unless starting-assignment? + color <- copy 1/red jump +exit:label } # if color is red and next character is space, switch color to white { - color-is-red?:boolean <- equal color:number, 1:literal/red - break-unless color-is-red?:boolean - ending-assignment?:boolean <- equal c:character, 32:literal/space - break-unless ending-assignment?:boolean - color:number <- copy 7:literal/white + color-is-red?:boolean <- equal color, 1/red + break-unless color-is-red? + ending-assignment?:boolean <- equal c, 32/space + break-unless ending-assignment? + color <- copy 7/white jump +exit:label } # otherwise no change +exit - reply color:number, highlighting-state:number + reply color, highlighting-state ] scenario render-colors-assignment [ - assume-screen 8:literal/width, 5:literal/height + assume-screen 8/width, 5/height run [ s:address:array:character <- new [abc d <- e f] - new-editor s:address:array:character, screen:address, 0:literal/left, 8:literal/right + new-editor s:address:array:character, screen:address, 0/left, 8/right ] screen-should-contain [ . . @@ -655,7 +655,7 @@ container editor-data [ .f . . . ] - screen-should-contain-in-color 1:literal/red, [ + screen-should-contain-in-color 1/red, [ . . . . . <- . @@ -671,58 +671,78 @@ container editor-data [ screen:address <- next-ingredient console:address <- next-ingredient env:address:programming-environment-data <- next-ingredient - recipes:address:editor-data <- get env:address:programming-environment-data/deref, recipes:offset - current-sandbox:address:editor-data <- get env:address:programming-environment-data/deref, current-sandbox:offset - sandbox-in-focus?:address:boolean <- get-address env:address:programming-environment-data/deref, sandbox-in-focus?:offset + recipes:address:editor-data <- get *env, recipes:offset + current-sandbox:address:editor-data <- get *env, current-sandbox:offset + sandbox-in-focus?:address:boolean <- get-address *env, sandbox-in-focus?:offset { # looping over each (keyboard or touch) event as it occurs +next-event - e:event, console:address, found?:boolean, quit?:boolean <- read-event console:address - loop-unless found?:boolean - break-if quit?:boolean # only in tests + e:event, console, found?:boolean, quit?:boolean <- read-event console + loop-unless found? + break-if quit? # only in tests trace [app], [next-event] # check for global events that will trigger regardless of which editor has focus { k:address:number <- maybe-convert e:event, keycode:variant - break-unless k:address:number - # F10? load all code and run all sandboxes. + break-unless k + # F4? load all code and run all sandboxes. + { + do-run?:boolean <- equal *k, 65532/F4 + break-unless do-run? + run-sandboxes env + # F4 might update warnings and results on both sides + screen <- render-all screen, env + update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + show-screen screen + loop +next-event:label + } + } + { + c:address:character <- maybe-convert e:event, text:variant + break-unless c + # ctrl-n? - switch focus { - do-run?:boolean <- equal k:address:number/deref, 65526:literal/F10 - break-unless do-run?:boolean - run-sandboxes env:address:programming-environment-data - # F10 might update warnings and results on both sides - screen:address <- render-all screen:address, env:address:programming-environment-data - update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:address:boolean/deref - show-screen screen:address + ctrl-n?:boolean <- equal *c, 14/ctrl-n + break-unless ctrl-n? + *sandbox-in-focus? <- not *sandbox-in-focus? + update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + show-screen screen loop +next-event:label } } # 'touch' event { t:address:touch-event <- maybe-convert e:event, touch:variant - break-unless t:address:touch-event + break-unless t + # ignore all but 'left-click' events for now + # todo: test this + touch-type:number <- get *t, type:offset + is-left-click?:boolean <- equal touch-type, 65513/mouse-left + loop-unless is-left-click?, +next-event:label # on a sandbox delete icon? process delete { - was-delete?:boolean <- delete-sandbox t:address:touch-event/deref, env:address:programming-environment-data - break-unless was-delete?:boolean - screen:address <- render-sandbox-side screen:address, env:address:programming-environment-data, 1:literal/clear - update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:address:boolean/deref + was-delete?:boolean <- delete-sandbox *t, env + break-unless was-delete? +#? trace [app], [delete clicked] #? 1 + screen <- render-sandbox-side screen, env, 1/clear + update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + show-screen screen loop +next-event:label } # if not, send to both editors - _ <- move-cursor-in-editor screen:address, recipes:address:editor-data, t:address:touch-event/deref - sandbox-in-focus?:address:boolean/deref <- move-cursor-in-editor screen:address, current-sandbox:address:editor-data, t:address:touch-event/deref + _ <- move-cursor-in-editor screen, recipes, *t + *sandbox-in-focus? <- move-cursor-in-editor screen, current-sandbox, *t jump +continue:label } # if it's not global, send to appropriate editor { { - break-if sandbox-in-focus?:address:boolean/deref - handle-event screen:address, console:address, recipes:address:editor-data, e:event + break-if *sandbox-in-focus? + handle-event screen, console, recipes, e:event } { - break-unless sandbox-in-focus?:address:boolean/deref - handle-event screen:address, console:address, current-sandbox:address:editor-data, e:event + break-unless *sandbox-in-focus? + handle-event screen, console, current-sandbox, e:event } } +continue @@ -731,9 +751,9 @@ container editor-data [ # they won't usually come fast enough to trigger this. # todo: test this { - more-events?:boolean <- has-more-events? console:address - break-if more-events?:boolean - render-minimal screen:address, env:address:programming-environment-data + more-events?:boolean <- has-more-events? console + break-if more-events? + render-minimal screen, env } loop } @@ -748,27 +768,27 @@ container editor-data [ { # looping over each (keyboard or touch) event as it occurs +next-event - e:event, console:address, found?:boolean, quit?:boolean <- read-event console:address - loop-unless found?:boolean - break-if quit?:boolean # only in tests + e:event, console:address, found?:boolean, quit?:boolean <- read-event console + loop-unless found? + break-if quit? # only in tests trace [app], [next-event] # 'touch' event - send to both editors { t:address:touch-event <- maybe-convert e:event, touch:variant - break-unless t:address:touch-event - move-cursor-in-editor screen:address, editor:address:editor-data, t:address:touch-event/deref + break-unless t + move-cursor-in-editor screen, editor, *t jump +continue:label } # other events - send to appropriate editor - handle-event screen:address, console:address, editor:address:editor-data, e:event + handle-event screen, console, editor, e:event +continue - row:number, screen:address <- render screen:address, editor:address:editor-data + row:number, screen <- render screen, editor # clear next line, in case we just processed a backspace - left:number <- get editor:address:editor-data/deref, left:offset - right:number <- get editor:address:editor-data/deref, right:offset - row:number <- add row:number, 1:literal - move-cursor screen:address, row:number, left:number - clear-line-delimited screen:address, left:number, right:number + left:number <- get *editor, left:offset + right:number <- get *editor, right:offset + row <- add row, 1 + move-cursor screen, row, left + clear-line-delimited screen, left, right loop } ] @@ -779,177 +799,185 @@ container editor-data [ console:address <- next-ingredient editor:address:editor-data <- next-ingredient e:event <- next-ingredient - reply-unless editor:address:editor-data + reply-unless editor # character { c:address:character <- maybe-convert e:event, text:variant - break-unless c:address:character - # check for special characters - # unless it's a backspace + break-unless c + ## check for special characters + # backspace - delete character before cursor + { + backspace?:boolean <- equal *c, 8/backspace + break-unless backspace? + delete-before-cursor editor + reply + } + # ctrl-a - move cursor to start of line { - backspace?:boolean <- equal c:address:character/deref, 8:literal/backspace - break-unless backspace?:boolean - delete-before-cursor editor:address:editor-data + ctrl-a?:boolean <- equal *c, 1/ctrl-a + break-unless ctrl-a? + move-to-start-of-line editor reply } - # ctrl-a + # ctrl-e - move cursor to end of line { - ctrl-a?:boolean <- equal c:address:character/deref, 1:literal/ctrl-a - break-unless ctrl-a?:boolean - move-to-start-of-line editor:address:editor-data + ctrl-e?:boolean <- equal *c, 5/ctrl-e + break-unless ctrl-e? + move-to-end-of-line editor reply } - # ctrl-e + # ctrl-u - delete until start of line (excluding cursor) { - ctrl-e?:boolean <- equal c:address:character/deref, 5:literal/ctrl-e - break-unless ctrl-e?:boolean - move-to-end-of-line editor:address:editor-data + ctrl-u?:boolean <- equal *c, 21/ctrl-u + break-unless ctrl-u? + delete-to-start-of-line editor reply } - # ctrl-u + # ctrl-k - delete until end of line (including cursor) { - ctrl-u?:boolean <- equal c:address:character/deref, 21:literal/ctrl-u - break-unless ctrl-u?:boolean - delete-to-start-of-line editor:address:editor-data + ctrl-k?:boolean <- equal *c, 11/ctrl-k + break-unless ctrl-k? + delete-to-end-of-line editor reply } - # ctrl-k + # tab - insert two spaces { - ctrl-k?:boolean <- equal c:address:character/deref, 11:literal/ctrl-k - break-unless ctrl-k?:boolean - delete-to-end-of-line editor:address:editor-data + tab?:boolean <- equal *c, 9/tab + break-unless tab?:boolean + insert-at-cursor editor, 32/space, screen + insert-at-cursor editor, 32/space, screen reply } # otherwise type it in - insert-at-cursor editor:address:editor-data, c:address:character/deref, screen:address + insert-at-cursor editor, *c, screen reply } # otherwise it's a special key k:address:number <- maybe-convert e:event, keycode:variant - assert k:address:number, [event was of unknown type; neither keyboard nor mouse] - d:address:duplex-list <- get editor:address:editor-data/deref, data:offset - before-cursor:address:address:duplex-list <- get-address editor:address:editor-data/deref, before-cursor:offset - cursor-row:address:number <- get-address editor:address:editor-data/deref, cursor-row:offset - cursor-column:address:number <- get-address editor:address:editor-data/deref, cursor-column:offset - screen-height:number <- screen-height screen:address - left:number <- get editor:address:editor-data/deref, left:offset - right:number <- get editor:address:editor-data/deref, right:offset + assert k, [event was of unknown type; neither keyboard nor mouse] + d:address:duplex-list <- get *editor, data:offset + before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + cursor-row:address:number <- get-address *editor, cursor-row:offset + cursor-column:address:number <- get-address *editor, cursor-column:offset + screen-height:number <- screen-height screen + left:number <- get *editor, left:offset + right:number <- get *editor, right:offset # arrows; update cursor-row and cursor-column, leave before-cursor to 'render'. # right arrow { - move-to-next-character?:boolean <- equal k:address:number/deref, 65514:literal/right-arrow - break-unless move-to-next-character?:boolean + move-to-next-character?:boolean <- equal *k, 65514/right-arrow + break-unless move-to-next-character? # if not at end of text - old-cursor:address:duplex-list <- next-duplex before-cursor:address:address:duplex-list/deref - break-unless old-cursor:address:duplex-list + old-cursor:address:duplex-list <- next-duplex *before-cursor + break-unless old-cursor # scan to next character - before-cursor:address:address:duplex-list/deref <- copy old-cursor:address:duplex-list + *before-cursor <- copy old-cursor # if crossed a newline, move cursor to start of next row { - old-cursor-character:character <- get before-cursor:address:address:duplex-list/deref/deref, value:offset - was-at-newline?:boolean <- equal old-cursor-character:character, 10:literal/newline - break-unless was-at-newline?:boolean - cursor-row:address:number/deref <- add cursor-row:address:number/deref, 1:literal - cursor-column:address:number/deref <- copy left:number + old-cursor-character:character <- get **before-cursor, value:offset + was-at-newline?:boolean <- equal old-cursor-character, 10/newline + break-unless was-at-newline? + *cursor-row <- add *cursor-row, 1 + *cursor-column <- copy left # todo: what happens when cursor is too far down? - screen-height:number <- screen-height screen:address - above-screen-bottom?:boolean <- lesser-than cursor-row:address:number/deref, screen-height:number - assert above-screen-bottom?:boolean, [unimplemented: moving past bottom of screen] + screen-height <- screen-height screen + above-screen-bottom?:boolean <- lesser-than *cursor-row, screen-height + assert above-screen-bottom?, [unimplemented: moving past bottom of screen] reply } # if the line wraps, move cursor to start of next row { # if we're at the column just before the wrap indicator - wrap-column:number <- subtract right:number, 1:literal - at-wrap?:boolean <- equal cursor-column:address:number/deref, wrap-column:number - break-unless at-wrap?:boolean + wrap-column:number <- subtract right, 1 + at-wrap?:boolean <- equal *cursor-column, wrap-column + break-unless at-wrap? # and if next character isn't newline - new-cursor:address:duplex-list <- next-duplex old-cursor:address:duplex-list - break-unless new-cursor:address:duplex-list - next-character:character <- get new-cursor:address:duplex-list/deref, value:offset - newline?:boolean <- equal next-character:character, 10:literal/newline - break-if newline?:boolean - cursor-row:address:number/deref <- add cursor-row:address:number/deref, 1:literal - cursor-column:address:number/deref <- copy left:number + new-cursor:address:duplex-list <- next-duplex old-cursor + break-unless new-cursor + next-character:character <- get *new-cursor, value:offset + newline?:boolean <- equal next-character, 10/newline + break-if newline? + *cursor-row <- add *cursor-row, 1 + *cursor-column <- copy left # todo: what happens when cursor is too far down? - above-screen-bottom?:boolean <- lesser-than cursor-row:address:number/deref, screen-height:number - assert above-screen-bottom?:boolean, [unimplemented: moving past bottom of screen] + above-screen-bottom?:boolean <- lesser-than *cursor-row, screen-height + assert above-screen-bottom?, [unimplemented: moving past bottom of screen] reply } # otherwise move cursor one character right - cursor-column:address:number/deref <- add cursor-column:address:number/deref, 1:literal + *cursor-column <- add *cursor-column, 1 } # left arrow { - move-to-previous-character?:boolean <- equal k:address:number/deref, 65515:literal/left-arrow - break-unless move-to-previous-character?:boolean + move-to-previous-character?:boolean <- equal *k, 65515/left-arrow + break-unless move-to-previous-character? #? trace [app], [left arrow] #? 1 # if not at start of text (before-cursor at § sentinel) - prev:address:duplex-list <- prev-duplex before-cursor:address:address:duplex-list/deref - break-unless prev:address:duplex-list + prev:address:duplex-list <- prev-duplex *before-cursor + break-unless prev # if cursor not at left margin, move one character left { - at-left-margin?:boolean <- equal cursor-column:address:number/deref, 0:literal - break-if at-left-margin?:boolean + at-left-margin?:boolean <- equal *cursor-column, 0 + break-if at-left-margin? #? trace [app], [decrementing] #? 1 - cursor-column:address:number/deref <- subtract cursor-column:address:number/deref, 1:literal + *cursor-column <- subtract *cursor-column, 1 reply } # if at left margin, there's guaranteed to be a previous line, since we're # not at start of text { # if before-cursor is at newline, figure out how long the previous line is - prevc:character <- get before-cursor:address:address:duplex-list/deref/deref, value:offset - previous-character-is-newline?:boolean <- equal prevc:character, 10:literal/newline - break-unless previous-character-is-newline?:boolean + prevc:character <- get **before-cursor, value:offset + previous-character-is-newline?:boolean <- equal prevc, 10/newline + break-unless previous-character-is-newline? #? trace [app], [previous line] #? 1 # compute length of previous line - end-of-line:number <- previous-line-length before-cursor:address:address:duplex-list/deref, d:address:duplex-list - cursor-row:address:number/deref <- subtract cursor-row:address:number/deref, 1:literal - cursor-column:address:number/deref <- copy end-of-line:number + end-of-line:number <- previous-line-length *before-cursor, d + *cursor-row <- subtract *cursor-row, 1 + *cursor-column <- copy end-of-line reply } # if before-cursor is not at newline, we're just at a wrapped line - assert cursor-row:address:number/deref, [unimplemented: moving cursor above top of screen] - cursor-row:address:number/deref <- subtract cursor-row:address:number/deref, 1:literal - cursor-column:address:number/deref <- subtract right:number, 1:literal # leave room for wrap icon + assert *cursor-row, [unimplemented: moving cursor above top of screen] + *cursor-row <- subtract *cursor-row, 1 + *cursor-column <- subtract right, 1 # leave room for wrap icon } # down arrow { - move-to-next-line?:boolean <- equal k:address:number/deref, 65516:literal/down-arrow - break-unless move-to-next-line?:boolean + move-to-next-line?:boolean <- equal *k, 65516/down-arrow + break-unless move-to-next-line? # todo: support scrolling - already-at-bottom?:boolean <- greater-or-equal cursor-row:address:number/deref, screen-height:number - break-if already-at-bottom?:boolean + already-at-bottom?:boolean <- greater-or-equal *cursor-row, screen-height + break-if already-at-bottom? #? $print [moving down #? ] #? 1 - cursor-row:address:number/deref <- add cursor-row:address:number/deref, 1:literal + *cursor-row <- add *cursor-row, 1 # that's it; render will adjust cursor-column as necessary } # up arrow { - move-to-previous-line?:boolean <- equal k:address:number/deref, 65517:literal/up-arrow - break-unless move-to-previous-line?:boolean + move-to-previous-line?:boolean <- equal *k, 65517/up-arrow + break-unless move-to-previous-line? # todo: support scrolling - already-at-top?:boolean <- lesser-or-equal cursor-row:address:number/deref, 1:literal/top - break-if already-at-top?:boolean + already-at-top?:boolean <- lesser-or-equal *cursor-row, 1/top + break-if already-at-top? #? $print [moving up #? ] #? 1 - cursor-row:address:number/deref <- subtract cursor-row:address:number/deref, 1:literal + *cursor-row <- subtract *cursor-row, 1 # that's it; render will adjust cursor-column as necessary } # home { - home?:boolean <- equal k:address:number/deref, 65521:literal/home - break-unless home?:boolean - move-to-start-of-line editor:address:editor-data + home?:boolean <- equal *k, 65521/home + break-unless home? + move-to-start-of-line editor reply } # end { - end?:boolean <- equal k:address:number/deref, 65520:literal/end - break-unless end?:boolean - move-to-end-of-line editor:address:editor-data + end?:boolean <- equal *k, 65520/end + break-unless end? + move-to-end-of-line editor reply } ] @@ -961,21 +989,21 @@ container editor-data [ screen:address <- next-ingredient editor:address:editor-data <- next-ingredient t:touch-event <- next-ingredient - reply-unless editor:address:editor-data, 0:literal/false - click-column:number <- get t:touch-event, column:offset - left:number <- get editor:address:editor-data/deref, left:offset - too-far-left?:boolean <- lesser-than click-column:number, left:number - reply-if too-far-left?:boolean, 0:literal/false - right:number <- get editor:address:editor-data/deref, right:offset - too-far-right?:boolean <- greater-than click-column:number, right:number - reply-if too-far-right?:boolean, 0:literal/false + reply-unless editor, 0/false + click-column:number <- get t, column:offset + left:number <- get *editor, left:offset + too-far-left?:boolean <- lesser-than click-column, left + reply-if too-far-left?, 0/false + right:number <- get *editor, right:offset + too-far-right?:boolean <- greater-than click-column, right + reply-if too-far-right?, 0/false # update cursor - cursor-row:address:number <- get-address editor:address:editor-data/deref, cursor-row:offset - cursor-row:address:number/deref <- get t:touch-event, row:offset - cursor-column:address:number <- get-address editor:address:editor-data/deref, cursor-column:offset - cursor-column:address:number/deref <- get t:touch-event, column:offset + cursor-row:address:number <- get-address *editor, cursor-row:offset + *cursor-row <- get t, row:offset + cursor-column:address:number <- get-address *editor, cursor-column:offset + *cursor-column <- get t, column:offset # gain focus - reply 1:literal/true + reply 1/true ] recipe insert-at-cursor [ @@ -983,63 +1011,76 @@ container editor-data [ editor:address:editor-data <- next-ingredient c:character <- next-ingredient screen:address <- next-ingredient -#? $print [insert ], c:character, 10:literal/newline - before-cursor:address:address:duplex-list <- get-address editor:address:editor-data/deref, before-cursor:offset - d:address:duplex-list <- get editor:address:editor-data/deref, data:offset - insert-duplex c:character, before-cursor:address:address:duplex-list/deref - before-cursor:address:address:duplex-list/deref <- next-duplex before-cursor:address:address:duplex-list/deref - cursor-row:address:number <- get-address editor:address:editor-data/deref, cursor-row:offset - cursor-column:address:number <- get-address editor:address:editor-data/deref, cursor-column:offset - left:number <- get editor:address:editor-data/deref, left:offset - right:number <- get editor:address:editor-data/deref, right:offset +#? $print [insert ], c, 10/newline #? 1 + before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + insert-duplex c, *before-cursor + *before-cursor <- next-duplex *before-cursor + cursor-row:address:number <- get-address *editor, cursor-row:offset + cursor-column:address:number <- get-address *editor, cursor-column:offset + left:number <- get *editor, left:offset + right:number <- get *editor, right:offset # update cursor: if newline, move cursor to start of next line # todo: bottom of screen { - newline?:boolean <- equal c:character, 10:literal/newline - break-unless newline?:boolean - cursor-row:address:number/deref <- add cursor-row:address:number/deref, 1:literal - cursor-column:address:number/deref <- copy left:number + newline?:boolean <- equal c, 10/newline + break-unless newline? + *cursor-row <- add *cursor-row, 1 + *cursor-column <- copy left + # indent if necessary +#? $print [computing indent], 10/newline #? 1 + d:address:duplex-list <- get *editor, data:offset + end-of-previous-line:address:duplex-list <- prev-duplex *before-cursor + indent:number <- line-indent end-of-previous-line, d +#? $print indent, 10/newline #? 1 + i:number <- copy 0 + { + indent-done?:boolean <- greater-or-equal i, indent + break-if indent-done? + insert-at-cursor editor, 32/space, screen + i <- add i, 1 + loop + } reply } # if the line wraps at the cursor, move cursor to start of next row { # if we're at the column just before the wrap indicator - wrap-column:number <- subtract right:number, 1:literal -#? $print [wrap? ], cursor-column:address:number/deref, [ vs ], wrap-column:number, 10:literal/newline - at-wrap?:boolean <- greater-or-equal cursor-column:address:number/deref, wrap-column:number - break-unless at-wrap?:boolean + wrap-column:number <- subtract right, 1 +#? $print [wrap? ], *cursor-column, [ vs ], wrap-column, 10/newline + at-wrap?:boolean <- greater-or-equal *cursor-column, wrap-column + break-unless at-wrap? #? $print [wrap! #? ] #? 1 - cursor-column:address:number/deref <- subtract cursor-column:address:number/deref, wrap-column:number - cursor-row:address:number/deref <- add cursor-row:address:number/deref, 1:literal + *cursor-column <- subtract *cursor-column, wrap-column + *cursor-row <- add *cursor-row, 1 # todo: what happens when cursor is too far down? - screen-height:number <- screen-height screen:address - above-screen-bottom?:boolean <- lesser-than cursor-row:address:number/deref, screen-height:number - assert above-screen-bottom?:boolean, [unimplemented: typing past bottom of screen] + screen-height:number <- screen-height screen + above-screen-bottom?:boolean <- lesser-than *cursor-row, screen-height + assert above-screen-bottom?, [unimplemented: typing past bottom of screen] #? $print [return #? ] #? 1 reply } # otherwise move cursor right - cursor-column:address:number/deref <- add cursor-column:address:number/deref, 1:literal + *cursor-column <- add *cursor-column, 1 ] recipe delete-before-cursor [ local-scope editor:address:editor-data <- next-ingredient - before-cursor:address:address:duplex-list <- get-address editor:address:editor-data/deref, before-cursor:offset - d:address:duplex-list <- get editor:address:editor-data/deref, data:offset + before-cursor:address:address:duplex-list <- get-address *editor:address:editor-data, before-cursor:offset + d:address:duplex-list <- get *editor:address:editor-data, data:offset # unless already at start - at-start?:boolean <- equal before-cursor:address:address:duplex-list/deref, d:address:duplex-list + at-start?:boolean <- equal *before-cursor:address:address:duplex-list, d:address:duplex-list reply-if at-start?:boolean # delete character - prev:address:duplex-list <- prev-duplex before-cursor:address:address:duplex-list/deref - remove-duplex before-cursor:address:address:duplex-list/deref + prev:address:duplex-list <- prev-duplex *before-cursor:address:address:duplex-list + remove-duplex *before-cursor:address:address:duplex-list # update cursor - before-cursor:address:address:duplex-list/deref <- copy prev:address:duplex-list - cursor-column:address:number <- get-address editor:address:editor-data/deref, cursor-column:offset - cursor-column:address:number/deref <- subtract cursor-column:address:number/deref, 1:literal -#? $print [delete-before-cursor: ], cursor-column:address:number/deref, 10:literal/newline + *before-cursor:address:address:duplex-list <- copy prev:address:duplex-list + cursor-column:address:number <- get-address *editor:address:editor-data, cursor-column:offset + *cursor-column:address:number <- subtract *cursor-column:address:number, 1 +#? $print [delete-before-cursor: ], *cursor-column:address:number, 10/newline ] # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts @@ -1048,43 +1089,77 @@ container editor-data [ local-scope curr:address:duplex-list <- next-ingredient start:address:duplex-list <- next-ingredient - result:number <- copy 0:literal - reply-unless curr:address:duplex-list, result:number - at-start?:boolean <- equal curr:address:duplex-list, start:address:duplex-list - reply-if at-start?:boolean, result:number + result:number <- copy 0 + reply-unless curr, result + at-start?:boolean <- equal curr, start + reply-if at-start?, result { - curr:address:duplex-list <- prev-duplex curr:address:duplex-list - break-unless curr:address:duplex-list - at-start?:boolean <- equal curr:address:duplex-list, start:address:duplex-list - break-if at-start?:boolean - c:character <- get curr:address:duplex-list/deref, value:offset - at-newline?:boolean <- equal c:character 10:literal/newline - break-if at-newline?:boolean - result:number <- add result:number, 1:literal + curr <- prev-duplex curr + break-unless curr + at-start?:boolean <- equal curr, start + break-if at-start? + c:character <- get *curr, value:offset + at-newline?:boolean <- equal c, 10/newline + break-if at-newline? + result <- add result, 1 loop } - reply result:number + reply result +] + +# takes a pointer 'curr' into the doubly-linked list and its sentinel, counts +# the number of spaces at the start of the line containing 'curr'. +recipe line-indent [ + local-scope + curr:address:duplex-list <- next-ingredient + start:address:duplex-list <- next-ingredient + result:number <- copy 0 + reply-unless curr, result + at-start?:boolean <- equal curr, start + reply-if at-start?, result + { + curr <- prev-duplex curr + break-unless curr + at-start?:boolean <- equal curr, start + break-if at-start? + c:character <- get *curr, value:offset + at-newline?:boolean <- equal c, 10/newline + break-if at-newline? + # if c is a space, increment result + is-space?:boolean <- equal c, 32/space + { + break-unless is-space? + result <- add result, 1 + } + # if c is not a space, reset result + { + break-if is-space? + result <- copy 0 + } + loop + } + reply result ] recipe move-to-start-of-line [ local-scope editor:address:editor-data <- next-ingredient # update cursor column - left:number <- get editor:address:editor-data/deref, left:offset - cursor-column:address:number <- get-address editor:address:editor-data/deref, cursor-column:offset - cursor-column:address:number/deref <- copy left:number + left:number <- get *editor, left:offset + cursor-column:address:number <- get-address *editor, cursor-column:offset + *cursor-column <- copy left # update before-cursor - before-cursor:address:address:duplex-list <- get-address editor:address:editor-data/deref, before-cursor:offset - init:address:duplex-list <- get editor:address:editor-data/deref, data:offset + before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + init:address:duplex-list <- get *editor, data:offset # while not at start of line, move { - at-start-of-text?:boolean <- equal before-cursor:address:address:duplex-list/deref, init:address:duplex-list - break-if at-start-of-text?:boolean - prev:character <- get before-cursor:address:address:duplex-list/deref/deref, value:offset - at-start-of-line?:boolean <- equal prev:character, 10:literal/newline - break-if at-start-of-line?:boolean - before-cursor:address:address:duplex-list/deref <- prev-duplex before-cursor:address:address:duplex-list/deref - assert before-cursor:address:address:duplex-list/deref, [move-to-start-of-line tried to move before start of text] + at-start-of-text?:boolean <- equal *before-cursor, init + break-if at-start-of-text? + prev:character <- get **before-cursor, value:offset + at-start-of-line?:boolean <- equal prev, 10/newline + break-if at-start-of-line? + *before-cursor <- prev-duplex *before-cursor + assert *before-cursor, [move-to-start-of-line tried to move before start of text] loop } ] @@ -1092,75 +1167,75 @@ container editor-data [ recipe move-to-end-of-line [ local-scope editor:address:editor-data <- next-ingredient - before-cursor:address:address:duplex-list <- get-address editor:address:editor-data/deref, before-cursor:offset - cursor-column:address:number <- get-address editor:address:editor-data/deref, cursor-column:offset + before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + cursor-column:address:number <- get-address *editor, cursor-column:offset # while not at start of line, move { - next:address:duplex-list <- next-duplex before-cursor:address:address:duplex-list/deref - break-unless next:address:duplex-list # end of text - nextc:character <- get next:address:duplex-list/deref, value:offset - at-end-of-line?:boolean <- equal nextc:character, 10:literal/newline - break-if at-end-of-line?:boolean - before-cursor:address:address:duplex-list/deref <- copy next:address:duplex-list - cursor-column:address:number/deref <- add cursor-column:address:number/deref, 1:literal + next:address:duplex-list <- next-duplex *before-cursor + break-unless next # end of text + nextc:character <- get *next, value:offset + at-end-of-line?:boolean <- equal nextc, 10/newline + break-if at-end-of-line? + *before-cursor <- copy next + *cursor-column <- add *cursor-column, 1 loop } - # move one past end of line - cursor-column:address:number/deref <- add cursor-column:address:number/deref, 1:literal + # move one past final character + *cursor-column <- add *cursor-column, 1 ] recipe delete-to-start-of-line [ local-scope editor:address:editor-data <- next-ingredient # compute range to delete - init:address:duplex-list <- get editor:address:editor-data/deref, data:offset - before-cursor:address:address:duplex-list <- get-address editor:address:editor-data/deref, before-cursor:offset - start:address:duplex-list <- copy before-cursor:address:address:duplex-list/deref - end:address:duplex-list <- next-duplex before-cursor:address:address:duplex-list/deref + init:address:duplex-list <- get *editor, data:offset + before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + start:address:duplex-list <- copy *before-cursor + end:address:duplex-list <- next-duplex *before-cursor { - at-start-of-text?:boolean <- equal start:address:duplex-list, init:address:duplex-list - break-if at-start-of-text?:boolean - curr:character <- get start:address:duplex-list/deref, value:offset - at-start-of-line?:boolean <- equal curr:character, 10:literal/newline - break-if at-start-of-line?:boolean - start:address:duplex-list <- prev-duplex start:address:duplex-list - assert start:address:duplex-list, [delete-to-start-of-line tried to move before start of text] + at-start-of-text?:boolean <- equal start, init + break-if at-start-of-text? + curr:character <- get *start, value:offset + at-start-of-line?:boolean <- equal curr, 10/newline + break-if at-start-of-line? + start <- prev-duplex start + assert start, [delete-to-start-of-line tried to move before start of text] loop } # snip it out - start-next:address:address:duplex-list <- get-address start:address:duplex-list/deref, next:offset - start-next:address:address:duplex-list/deref <- copy end:address:duplex-list - end-prev:address:address:duplex-list <- get-address end:address:duplex-list/deref, prev:offset - end-prev:address:address:duplex-list/deref <- copy start:address:duplex-list + start-next:address:address:duplex-list <- get-address *start, next:offset + *start-next <- copy end + end-prev:address:address:duplex-list <- get-address *end, prev:offset + *end-prev <- copy start # adjust cursor - before-cursor:address:address:duplex-list/deref <- prev-duplex end:address:duplex-list - left:number <- get editor:address:editor-data/deref, left:offset - cursor-column:address:number <- get-address editor:address:editor-data/deref, cursor-column:offset - cursor-column:address:number/deref <- copy left:number + *before-cursor <- prev-duplex end + left:number <- get *editor, left:offset + cursor-column:address:number <- get-address *editor, cursor-column:offset + *cursor-column <- copy left ] recipe delete-to-end-of-line [ local-scope editor:address:editor-data <- next-ingredient # compute range to delete - start:address:duplex-list <- get editor:address:editor-data/deref, before-cursor:offset - end:address:duplex-list <- next-duplex start:address:duplex-list + start:address:duplex-list <- get *editor, before-cursor:offset + end:address:duplex-list <- next-duplex start { - at-end-of-text?:boolean <- equal end:address:duplex-list, 0:literal/null - break-if at-end-of-text?:boolean - curr:character <- get end:address:duplex-list/deref, value:offset - at-end-of-line?:boolean <- equal curr:character, 10:literal/newline - break-if at-end-of-line?:boolean - end:address:duplex-list <- next-duplex end:address:duplex-list + at-end-of-text?:boolean <- equal end, 0/null + break-if at-end-of-text? + curr:character <- get *end, value:offset + at-end-of-line?:boolean <- equal curr, 10/newline + break-if at-end-of-line? + end <- next-duplex end loop } # snip it out - start-next:address:address:duplex-list <- get-address start:address:duplex-list/deref, next:offset - start-next:address:address:duplex-list/deref <- copy end:address:duplex-list + start-next:address:address:duplex-list <- get-address *start, next:offset + *start-next <- copy end { - break-unless end:address:duplex-list - end-prev:address:address:duplex-list <- get-address end:address:duplex-list/deref, prev:offset - end-prev:address:address:duplex-list/deref <- copy start:address:duplex-list + break-unless end + end-prev:address:address:duplex-list <- get-address *end, prev:offset + *end-prev <- copy start } ] @@ -1168,38 +1243,38 @@ container editor-data [ local-scope screen:address <- next-ingredient env:address:programming-environment-data <- next-ingredient - screen:address <- render-recipes screen:address, env:address:programming-environment-data, 1:literal/clear-below - screen:address <- render-sandbox-side screen:address, env:address:programming-environment-data, 1:literal/clear-below - recipes:address:editor-data <- get env:address:programming-environment-data/deref, recipes:offset - current-sandbox:address:editor-data <- get env:address:programming-environment-data/deref, current-sandbox:offset - sandbox-in-focus?:boolean <- get env:address:programming-environment-data/deref, sandbox-in-focus?:offset - update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:boolean - show-screen screen:address - reply screen:address/same-as-ingredient:0 + screen <- render-recipes screen, env, 1/clear-below + screen <- render-sandbox-side screen, env, 1/clear-below + recipes:address:editor-data <- get *env, recipes:offset + current-sandbox:address:editor-data <- get *env, current-sandbox:offset + sandbox-in-focus?:boolean <- get *env, sandbox-in-focus?:offset + update-cursor screen, recipes, current-sandbox, sandbox-in-focus? + show-screen screen + reply screen/same-as-ingredient:0 ] recipe render-minimal [ local-scope screen:address <- next-ingredient env:address:programming-environment-data <- next-ingredient - recipes:address:editor-data <- get env:address:programming-environment-data/deref, recipes:offset - current-sandbox:address:editor-data <- get env:address:programming-environment-data/deref, current-sandbox:offset - sandbox-in-focus?:boolean <- get env:address:programming-environment-data/deref, sandbox-in-focus?:offset + recipes:address:editor-data <- get *env, recipes:offset + current-sandbox:address:editor-data <- get *env, current-sandbox:offset + sandbox-in-focus?:boolean <- get *env, sandbox-in-focus?:offset { - break-if sandbox-in-focus?:boolean - screen:address <- render-recipes screen:address, env:address:programming-environment-data - cursor-row:number <- get recipes:address:editor-data/deref, cursor-row:offset - cursor-column:number <- get recipes:address:editor-data/deref, cursor-column:offset + break-if sandbox-in-focus? + screen <- render-recipes screen, env + cursor-row:number <- get *recipes, cursor-row:offset + cursor-column:number <- get *recipes, cursor-column:offset } { - break-unless sandbox-in-focus?:boolean - screen:address <- render-sandbox-side screen:address, env:address:programming-environment-data - cursor-row:number <- get current-sandbox:address:editor-data/deref, cursor-row:offset - cursor-column:number <- get current-sandbox:address:editor-data/deref, cursor-column:offset + break-unless sandbox-in-focus? + screen <- render-sandbox-side screen, env + cursor-row:number <- get *current-sandbox, cursor-row:offset + cursor-column:number <- get *current-sandbox, cursor-column:offset } - move-cursor screen:address, cursor-row:number, cursor-column:number - show-screen screen:address - reply screen:address/same-as-ingredient:0 + move-cursor screen, cursor-row, cursor-column + show-screen screen + reply screen/same-as-ingredient:0 ] recipe render-recipes [ @@ -1207,40 +1282,40 @@ container editor-data [ screen:address <- next-ingredient env:address:programming-environment-data <- next-ingredient clear:boolean <- next-ingredient - recipes:address:editor-data <- get env:address:programming-environment-data/deref, recipes:offset + recipes:address:editor-data <- get *env, recipes:offset # render recipes - left:number <- get recipes:address:editor-data/deref, left:offset - right:number <- get recipes:address:editor-data/deref, right:offset - row:number, screen:address <- render screen:address, recipes:address:editor-data - recipe-warnings:address:array:character <- get env:address:programming-environment-data/deref, recipe-warnings:offset + left:number <- get *recipes, left:offset + right:number <- get *recipes, right:offset + row:number, screen <- render screen, recipes + recipe-warnings:address:array:character <- get *env, recipe-warnings:offset { # print any warnings - break-unless recipe-warnings:address:array:character - row:number, screen:address <- render-string screen:address, recipe-warnings:address:array:character, left:number, right:number, 1:literal/red, row:number + break-unless recipe-warnings + row, screen <- render-string screen, recipe-warnings, left, right, 1/red, row } { # no warnings? move to next line - break-if recipe-warnings:address:array:character - row:number <- add row:number, 1:literal + break-if recipe-warnings + row <- add row, 1 } # draw dotted line after recipes - draw-horizontal screen:address, row:number, left:number, right:number, 9480:literal/horizontal-dotted + draw-horizontal screen, row, left, right, 9480/horizontal-dotted # clear next line, in case we just processed a backspace - row:number <- add row:number, 1:literal - move-cursor screen:address, row:number, left:number - clear-line-delimited screen:address, left:number, right:number + row <- add row, 1 + move-cursor screen, row, left + clear-line-delimited screen, left, right # clear rest of screen in this column, if requested - reply-unless clear:boolean, screen:address/same-as-ingredient:0 - screen-height:number <- screen-height screen:address + reply-unless clear, screen/same-as-ingredient:0 + screen-height:number <- screen-height screen { - at-bottom-of-screen?:boolean <- greater-or-equal row:number, screen-height:number - break-if at-bottom-of-screen?:boolean - move-cursor screen:address, row:number, left:number - clear-line-delimited screen:address, left:number, right:number - row:number <- add row:number, 1:literal + at-bottom-of-screen?:boolean <- greater-or-equal row, screen-height + break-if at-bottom-of-screen? + move-cursor screen, row, left + clear-line-delimited screen, left, right + row <- add row, 1 loop } - reply screen:address/same-as-ingredient:0 + reply screen/same-as-ingredient:0 ] recipe update-cursor [ @@ -1250,29 +1325,29 @@ container editor-data [ current-sandbox:address:editor-data <- next-ingredient sandbox-in-focus?:boolean <- next-ingredient { - break-if sandbox-in-focus?:boolean + break-if sandbox-in-focus? #? $print [recipes in focus #? ] #? 1 - cursor-row:number <- get recipes:address:editor-data/deref, cursor-row:offset - cursor-column:number <- get recipes:address:editor-data/deref, cursor-column:offset + cursor-row:number <- get *recipes, cursor-row:offset + cursor-column:number <- get *recipes, cursor-column:offset } { - break-unless sandbox-in-focus?:boolean + break-unless sandbox-in-focus? #? $print [sandboxes in focus #? ] #? 1 - cursor-row:number <- get current-sandbox:address:editor-data/deref, cursor-row:offset - cursor-column:number <- get current-sandbox:address:editor-data/deref, cursor-column:offset + cursor-row:number <- get *current-sandbox, cursor-row:offset + cursor-column:number <- get *current-sandbox, cursor-column:offset } - move-cursor screen:address, cursor-row:number, cursor-column:number + move-cursor screen, cursor-row, cursor-column ] scenario editor-handles-empty-event-queue [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1282,16 +1357,16 @@ container editor-data [ ] scenario editor-handles-mouse-clicks [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 1, 1 # on the 'b' + left-click 1, 1 # on the 'b' ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] screen-should-contain [ . . @@ -1299,80 +1374,80 @@ container editor-data [ . . ] memory-should-contain [ - 3 <- 1 # cursor is at row 0.. - 4 <- 1 # ..and column 1 + 3 <- 1 # cursor is at row 0.. + 4 <- 1 # ..and column 1 ] ] scenario editor-handles-mouse-clicks-outside-text [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 1, 7 # last line, to the right of text + left-click 1, 7 # last line, to the right of text ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 3 <- 1 # cursor row - 4 <- 3 # cursor column + 3 <- 1 # cursor row + 4 <- 3 # cursor column ] ] scenario editor-handles-mouse-clicks-outside-text-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 1, 7 # interior line, to the right of text + left-click 1, 7 # interior line, to the right of text ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 3 <- 1 # cursor row - 4 <- 3 # cursor column + 3 <- 1 # cursor row + 4 <- 3 # cursor column ] ] scenario editor-handles-mouse-clicks-outside-text-3 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 3, 7 # below text + left-click 3, 7 # below text ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 3 <- 2 # cursor row - 4 <- 3 # cursor column + 3 <- 2 # cursor row + 4 <- 3 # cursor column ] ] scenario editor-handles-mouse-clicks-outside-column [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] # editor occupies only left half of screen - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right assume-console [ # click on right half of screen - left-click 3, 8 + left-click 3, 8 ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] screen-should-contain [ . . @@ -1380,20 +1455,20 @@ container editor-data [ . . ] memory-should-contain [ - 3 <- 1 # no change to cursor row - 4 <- 0 # ..or column + 3 <- 1 # no change to cursor row + 4 <- 0 # ..or column ] ] scenario editor-inserts-characters-into-empty-editor [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right assume-console [ type [abc] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1403,16 +1478,16 @@ container editor-data [ ] scenario editor-inserts-characters-at-cursor [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ type [0] - left-click 1, 2 + left-click 1, 2 type [d] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1422,15 +1497,15 @@ container editor-data [ ] scenario editor-inserts-characters-at-cursor-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 1, 5 # right of last line + left-click 1, 5 # right of last line type [d] # should append ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1440,15 +1515,15 @@ container editor-data [ ] scenario editor-inserts-characters-at-cursor-3 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 3, 5 # below all text + left-click 3, 5 # below all text type [d] # should append ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1458,16 +1533,16 @@ container editor-data [ ] scenario editor-inserts-characters-at-cursor-4 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 3, 5 # below all text + left-click 3, 5 # below all text type [e] # should append ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1478,16 +1553,16 @@ container editor-data [ ] scenario editor-inserts-characters-at-cursor-5 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 3, 5 # below all text + left-click 3, 5 # below all text type [ef] # should append multiple characters in order ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1498,15 +1573,15 @@ container editor-data [ ] scenario editor-wraps-line-on-insert [ - assume-screen 5:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + assume-screen 5/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right # type a letter assume-console [ type [e] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # no wrap yet screen-should-contain [ @@ -1520,7 +1595,7 @@ container editor-data [ type [f] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # now wrap screen-should-contain [ @@ -1532,14 +1607,14 @@ container editor-data [ ] scenario editor-moves-cursor-after-inserting-characters [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [ab] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [ab] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right assume-console [ type [01] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1549,17 +1624,17 @@ container editor-data [ ] scenario editor-wraps-cursor-after-inserting-characters [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abcde] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abcde] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right assume-console [ - left-click 1, 4 # line is full; no wrap icon yet + left-click 1, 4 # line is full; no wrap icon yet type [f] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] screen-should-contain [ . . @@ -1568,23 +1643,23 @@ container editor-data [ . . ] memory-should-contain [ - 3 <- 2 # cursor row - 4 <- 1 # cursor column + 3 <- 2 # cursor row + 4 <- 1 # cursor column ] ] scenario editor-wraps-cursor-after-inserting-characters-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abcde] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abcde] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right assume-console [ - left-click 1, 3 # right before the wrap icon + left-click 1, 3 # right before the wrap icon type [f] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] screen-should-contain [ . . @@ -1593,21 +1668,21 @@ container editor-data [ . . ] memory-should-contain [ - 3 <- 2 # cursor row - 4 <- 0 # cursor column + 3 <- 2 # cursor row + 4 <- 0 # cursor column ] ] scenario editor-moves-cursor-down-after-inserting-newline [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ type [0 1] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1618,15 +1693,15 @@ container editor-data [ ] scenario editor-moves-cursor-down-after-inserting-newline-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 1:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 1/left, 10/right assume-console [ type [0 1] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1637,9 +1712,9 @@ container editor-data [ ] scenario editor-clears-previous-line-completely-after-inserting-newline [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abcde] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abcde] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right # press just a 'newline' assume-console [ type [ @@ -1653,7 +1728,7 @@ container editor-data [ . . ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # line should be fully cleared screen-should-contain [ @@ -1665,20 +1740,44 @@ container editor-data [ ] ] +scenario editor-inserts-indent-after-newline [ + assume-screen 10/width, 10/height + 1:address:array:character <- new [ab + cd +ef] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right + # position cursor after 'cd' and hit 'newline' + assume-console [ + left-click 2, 8 + type [ +] + ] + run [ + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset + ] + # cursor should be below start of previous line + memory-should-contain [ + 3 <- 3 # cursor row + 4 <- 2 # cursor column (indented) + ] +] + scenario editor-handles-backspace-key [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 1, 1 + left-click 1, 1 type [«] ] - 3:event/backspace <- merge 0:literal/text, 8:literal/backspace, 0:literal/dummy, 0:literal/dummy - replace-in-console 171:literal/«, 3:event/backspace + 3:event/backspace <- merge 0/text, 8/backspace, 0/dummy, 0/dummy + replace-in-console 171/«, 3:event/backspace run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 4:number <- get 2:address:editor-data/deref, cursor-row:offset - 5:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 4:number <- get *2:address:editor-data, cursor-row:offset + 5:number <- get *2:address:editor-data, cursor-column:offset ] screen-should-contain [ . . @@ -1686,25 +1785,25 @@ container editor-data [ . . ] memory-should-contain [ - 4 <- 1 - 5 <- 0 + 4 <- 1 + 5 <- 0 ] ] scenario editor-clears-last-line-on-backspace [ - assume-screen 10:literal/width, 5:literal/height + assume-screen 10/width, 5/height # just one character in final line - 1:address:array:character <- new [ab + 1:address:array:character <- new [ab cd] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right assume-console [ - left-click 2, 0 # cursor at only character in final line + left-click 2, 0 # cursor at only character in final line type [«] ] - 3:event/backspace <- merge 0:literal/text, 8:literal/backspace, 0:literal/dummy, 0:literal/dummy - replace-in-console 171:literal/«, 3:event/backspace + 3:event/backspace <- merge 0/text, 8/backspace, 0/dummy, 0/dummy + replace-in-console 171/«, 3:event/backspace run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1713,16 +1812,37 @@ container editor-data [ ] ] +scenario editor-inserts-two-spaces-on-tab [ + assume-screen 10/width, 5/height + # just one character in final line + 1:address:array:character <- new [ab +cd] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right + assume-console [ + type [»] + ] + 3:event/tab <- merge 0/text, 9/tab, 0/dummy, 0/dummy + replace-in-console 187/», 3:event/tab + run [ + editor-event-loop screen:address, console:address, 2:address:editor-data + ] + screen-should-contain [ + . . + . ab . + .cd . + ] +] + scenario editor-moves-cursor-right-with-key [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - press 65514 # right arrow + press 65514 # right arrow type [0] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1732,19 +1852,19 @@ container editor-data [ ] scenario editor-moves-cursor-to-next-line-with-right-arrow [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - press 65514 # right arrow - press 65514 # right arrow - press 65514 # right arrow - press 65514 # right arrow - next line + press 65514 # right arrow + press 65514 # right arrow + press 65514 # right arrow + press 65514 # right arrow - next line type [0] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1755,19 +1875,19 @@ container editor-data [ ] scenario editor-moves-cursor-to-next-line-with-right-arrow-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 1:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 1/left, 10/right assume-console [ - press 65514 # right arrow - press 65514 # right arrow - press 65514 # right arrow - press 65514 # right arrow - next line + press 65514 # right arrow + press 65514 # right arrow + press 65514 # right arrow + press 65514 # right arrow - next line type [0] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1778,17 +1898,17 @@ container editor-data [ ] scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abcdef] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abcdef] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right assume-console [ - left-click 1, 3 - press 65514 # right arrow + left-click 1, 3 + press 65514 # right arrow ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] screen-should-contain [ . . @@ -1797,57 +1917,57 @@ container editor-data [ . . ] memory-should-contain [ - 3 <- 2 - 4 <- 0 + 3 <- 2 + 4 <- 0 ] ] scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-2 [ - assume-screen 10:literal/width, 5:literal/height + assume-screen 10/width, 5/height # line just barely wrapping - 1:address:array:character <- new [abcde] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + 1:address:array:character <- new [abcde] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right # position cursor at last character before wrap and hit right-arrow assume-console [ - left-click 1, 3 - press 65514 # right arrow + left-click 1, 3 + press 65514 # right arrow ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 3 <- 2 - 4 <- 0 + 3 <- 2 + 4 <- 0 ] # now hit right arrow again assume-console [ - press 65514 + press 65514 ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 3 <- 2 - 4 <- 1 + 3 <- 2 + 4 <- 1 ] ] scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-3 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abcdef] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 1:literal/left, 6:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abcdef] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 1/left, 6/right assume-console [ - left-click 1, 4 - press 65514 # right arrow + left-click 1, 4 + press 65514 # right arrow ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] screen-should-contain [ . . @@ -1856,23 +1976,23 @@ container editor-data [ . . ] memory-should-contain [ - 3 <- 2 - 4 <- 1 + 3 <- 2 + 4 <- 1 ] ] scenario editor-moves-cursor-to-next-line-with-right-arrow-at-end-of-line [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 1, 3 - press 65514 # right arrow - next line + left-click 1, 3 + press 65514 # right arrow - next line type [0] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1883,16 +2003,16 @@ container editor-data [ ] scenario editor-moves-cursor-left-with-key [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 1, 2 - press 65515 # left arrow + left-click 1, 2 + press 65515 # left arrow type [0] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1902,43 +2022,43 @@ container editor-data [ ] scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line [ - assume-screen 10:literal/width, 5:literal/height + assume-screen 10/width, 5/height # initialize editor with two lines - 1:address:array:character <- new [abc + 1:address:array:character <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # position cursor at start of second line (so there's no previous newline) assume-console [ - left-click 2, 0 - press 65515 # left arrow + left-click 2, 0 + press 65515 # left arrow ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 3 <- 1 - 4 <- 3 + 3 <- 1 + 4 <- 3 ] ] scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-2 [ - assume-screen 10:literal/width, 5:literal/height + assume-screen 10/width, 5/height # initialize editor with three lines - 1:address:array:character <- new [abc + 1:address:array:character <- new [abc def g] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # position cursor further down (so there's a newline before the character at # the cursor) assume-console [ - left-click 3, 0 - press 65515 # left arrow + left-click 3, 0 + press 65515 # left arrow type [0] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1950,19 +2070,19 @@ container editor-data [ ] scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-3 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc def g] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # position cursor at start of text assume-console [ - left-click 1, 0 - press 65515 # left arrow should have no effect + left-click 1, 0 + press 65515 # left arrow should have no effect type [0] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1974,20 +2094,20 @@ container editor-data [ ] scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-4 [ - assume-screen 10:literal/width, 5:literal/height + assume-screen 10/width, 5/height # initialize editor with text containing an empty line - 1:address:array:character <- new [abc + 1:address:array:character <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # position cursor right after empty line assume-console [ - left-click 3, 0 - press 65515 # left arrow + left-click 3, 0 + press 65515 # left arrow type [0] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] screen-should-contain [ . . @@ -1999,10 +2119,10 @@ d] ] scenario editor-moves-across-screen-lines-across-wrap-with-left-arrow [ - assume-screen 10:literal/width, 5:literal/height + assume-screen 10/width, 5/height # initialize editor with text containing an empty line - 1:address:array:character <- new [abcdef] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 5:literal/right + 1:address:array:character <- new [abcdef] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 5/right screen-should-contain [ . . .abcd↩ . @@ -2011,227 +2131,227 @@ d] ] # position cursor right after empty line assume-console [ - left-click 2, 0 - press 65515 # left arrow + left-click 2, 0 + press 65515 # left arrow ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 3 <- 1 # previous row - 4 <- 3 # end of wrapped line + 3 <- 1 # previous row + 4 <- 3 # end of wrapped line ] ] scenario editor-moves-to-previous-line-with-up-arrow [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 2, 1 - press 65517 # up arrow + left-click 2, 1 + press 65517 # up arrow ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 3 <- 1 - 4 <- 1 + 3 <- 1 + 4 <- 1 ] ] scenario editor-moves-to-next-line-with-down-arrow [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # cursor starts out at (1, 0) assume-console [ - press 65516 # down arrow + press 65516 # down arrow ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] # ..and ends at (2, 0) memory-should-contain [ - 3 <- 2 - 4 <- 0 + 3 <- 2 + 4 <- 0 ] ] scenario editor-adjusts-column-at-previous-line [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [ab + assume-screen 10/width, 5/height + 1:address:array:character <- new [ab def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 2, 3 - press 65517 # up arrow + left-click 2, 3 + press 65517 # up arrow ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 3 <- 1 - 4 <- 2 + 3 <- 1 + 4 <- 2 ] ] scenario editor-adjusts-column-at-next-line [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc de] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 1, 3 - press 65516 # down arrow + left-click 1, 3 + press 65516 # down arrow ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 3 <- 2 - 4 <- 2 + 3 <- 2 + 4 <- 2 ] ] scenario editor-moves-to-start-of-line-with-ctrl-a [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on second line, press ctrl-a assume-console [ - left-click 2, 3 + left-click 2, 3 type [a] # ctrl-a ] - 3:event/ctrl-a <- merge 0:literal/text, 1:literal/ctrl-a, 0:literal/dummy, 0:literal/dummy - replace-in-console 97:literal/a, 3:event/ctrl-a + 3:event/ctrl-a <- merge 0/text, 1/ctrl-a, 0/dummy, 0/dummy + replace-in-console 97/a, 3:event/ctrl-a run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 4:number <- get 2:address:editor-data/deref, cursor-row:offset - 5:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 4:number <- get *2:address:editor-data, cursor-row:offset + 5:number <- get *2:address:editor-data, cursor-column:offset ] # cursor moves to start of line memory-should-contain [ - 4 <- 2 - 5 <- 0 + 4 <- 2 + 5 <- 0 ] ] scenario editor-moves-to-start-of-line-with-ctrl-a-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on first line (no newline before), press ctrl-a assume-console [ - left-click 1, 3 + left-click 1, 3 type [a] # ctrl-a ] - 3:event/ctrl-a <- merge 0:literal/text, 1:literal/ctrl-a, 0:literal/dummy, 0:literal/dummy - replace-in-console 97:literal/a, 3:event/ctrl-a + 3:event/ctrl-a <- merge 0/text, 1/ctrl-a, 0/dummy, 0/dummy + replace-in-console 97/a, 3:event/ctrl-a run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 4:number <- get 2:address:editor-data/deref, cursor-row:offset - 5:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 4:number <- get *2:address:editor-data, cursor-row:offset + 5:number <- get *2:address:editor-data, cursor-column:offset ] # cursor moves to start of line memory-should-contain [ - 4 <- 1 - 5 <- 0 + 4 <- 1 + 5 <- 0 ] ] scenario editor-moves-to-start-of-line-with-home [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on second line, press 'home' assume-console [ - left-click 2, 3 - press 65521 # 'home' + left-click 2, 3 + press 65521 # 'home' ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] # cursor moves to start of line memory-should-contain [ - 3 <- 2 - 4 <- 0 + 3 <- 2 + 4 <- 0 ] ] scenario editor-moves-to-start-of-line-with-home-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on first line (no newline before), press 'home' assume-console [ - left-click 1, 3 - press 65521 # 'home' + left-click 1, 3 + press 65521 # 'home' ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] # cursor moves to start of line memory-should-contain [ - 3 <- 1 - 4 <- 0 + 3 <- 1 + 4 <- 0 ] ] scenario editor-moves-to-start-of-line-with-ctrl-e [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on first line, press ctrl-e assume-console [ - left-click 1, 1 + left-click 1, 1 type [e] # ctrl-e ] - 3:event/ctrl-e <- merge 0:literal/text, 5:literal/ctrl-e, 0:literal/dummy, 0:literal/dummy - replace-in-console 101:literal/e, 3:event/ctrl-e + 3:event/ctrl-e <- merge 0/text, 5/ctrl-e, 0/dummy, 0/dummy + replace-in-console 101/e, 3:event/ctrl-e run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 4:number <- get 2:address:editor-data/deref, cursor-row:offset - 5:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 4:number <- get *2:address:editor-data, cursor-row:offset + 5:number <- get *2:address:editor-data, cursor-column:offset ] # cursor moves to end of line memory-should-contain [ - 4 <- 1 - 5 <- 3 + 4 <- 1 + 5 <- 3 ] # editor inserts future characters at cursor assume-console [ type [z] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 4:number <- get 2:address:editor-data/deref, cursor-row:offset - 5:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 4:number <- get *2:address:editor-data, cursor-row:offset + 5:number <- get *2:address:editor-data, cursor-column:offset ] memory-should-contain [ - 4 <- 1 - 5 <- 4 + 4 <- 1 + 5 <- 4 ] screen-should-contain [ . . @@ -2242,87 +2362,87 @@ d] ] scenario editor-moves-to-end-of-line-with-ctrl-e-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on second line (no newline after), press ctrl-e assume-console [ - left-click 2, 1 + left-click 2, 1 type [e] # ctrl-e ] - 3:event/ctrl-e <- merge 0:literal/text, 5:literal/ctrl-e, 0:literal/dummy, 0:literal/dummy - replace-in-console 101:literal/e, 3:event/ctrl-e + 3:event/ctrl-e <- merge 0/text, 5/ctrl-e, 0/dummy, 0/dummy + replace-in-console 101/e, 3:event/ctrl-e run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 4:number <- get 2:address:editor-data/deref, cursor-row:offset - 5:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 4:number <- get *2:address:editor-data, cursor-row:offset + 5:number <- get *2:address:editor-data, cursor-column:offset ] # cursor moves to end of line memory-should-contain [ - 4 <- 2 - 5 <- 3 + 4 <- 2 + 5 <- 3 ] ] scenario editor-moves-to-end-of-line-with-end [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on first line, press 'end' assume-console [ - left-click 1, 1 - press 65520 # 'end' + left-click 1, 1 + press 65520 # 'end' ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] # cursor moves to end of line memory-should-contain [ - 3 <- 1 - 4 <- 3 + 3 <- 1 + 4 <- 3 ] ] scenario editor-moves-to-end-of-line-with-end-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on second line (no newline after), press 'end' assume-console [ - left-click 2, 1 - press 65520 # 'end' + left-click 2, 1 + press 65520 # 'end' ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:number <- get 2:address:editor-data/deref, cursor-row:offset - 4:number <- get 2:address:editor-data/deref, cursor-column:offset + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset ] # cursor moves to end of line memory-should-contain [ - 3 <- 2 - 4 <- 3 + 3 <- 2 + 4 <- 3 ] ] scenario editor-deletes-to-start-of-line-with-ctrl-u [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on second line, press ctrl-u assume-console [ - left-click 2, 2 + left-click 2, 2 type [u] # ctrl-u ] - 3:event/ctrl-a <- merge 0:literal/text, 21:literal/ctrl-u, 0:literal/dummy, 0:literal/dummy - replace-in-console 117:literal/u, 3:event/ctrl-u + 3:event/ctrl-a <- merge 0/text, 21/ctrl-u, 0/dummy, 0/dummy + replace-in-console 117/u, 3:event/ctrl-u run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # cursor deletes to start of line screen-should-contain [ @@ -2334,19 +2454,19 @@ d] ] scenario editor-deletes-to-start-of-line-with-ctrl-u-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on first line (no newline before), press ctrl-u assume-console [ - left-click 1, 2 + left-click 1, 2 type [u] # ctrl-u ] - 3:event/ctrl-u <- merge 0:literal/text, 21:literal/ctrl-a, 0:literal/dummy, 0:literal/dummy - replace-in-console 117:literal/a, 3:event/ctrl-u + 3:event/ctrl-u <- merge 0/text, 21/ctrl-a, 0/dummy, 0/dummy + replace-in-console 117/a, 3:event/ctrl-u run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # cursor deletes to start of line screen-should-contain [ @@ -2358,19 +2478,19 @@ d] ] scenario editor-deletes-to-start-of-line-with-ctrl-u-3 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start past end of line, press ctrl-u assume-console [ - left-click 1, 3 + left-click 1, 3 type [u] # ctrl-u ] - 3:event/ctrl-u <- merge 0:literal/text, 21:literal/ctrl-a, 0:literal/dummy, 0:literal/dummy - replace-in-console 117:literal/a, 3:event/ctrl-u + 3:event/ctrl-u <- merge 0/text, 21/ctrl-a, 0/dummy, 0/dummy + replace-in-console 117/a, 3:event/ctrl-u run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # cursor deletes to start of line screen-should-contain [ @@ -2382,19 +2502,19 @@ d] ] scenario editor-deletes-to-end-of-line-with-ctrl-k [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on first line, press ctrl-k assume-console [ - left-click 1, 1 + left-click 1, 1 type [k] # ctrl-k ] - 3:event/ctrl-k <- merge 0:literal/text, 11:literal/ctrl-k, 0:literal/dummy, 0:literal/dummy - replace-in-console 107:literal/k, 3:event/ctrl-k + 3:event/ctrl-k <- merge 0/text, 11/ctrl-k, 0/dummy, 0/dummy + replace-in-console 107/k, 3:event/ctrl-k run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # cursor deletes to end of line screen-should-contain [ @@ -2406,19 +2526,19 @@ d] ] scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start on second line (no newline after), press ctrl-k assume-console [ - left-click 2, 1 + left-click 2, 1 type [k] # ctrl-k ] - 3:event/ctrl-k <- merge 0:literal/text, 11:literal/ctrl-k, 0:literal/dummy, 0:literal/dummy - replace-in-console 107:literal/k, 3:event/ctrl-k + 3:event/ctrl-k <- merge 0/text, 11/ctrl-k, 0/dummy, 0/dummy + replace-in-console 107/k, 3:event/ctrl-k run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # cursor deletes to end of line screen-should-contain [ @@ -2430,19 +2550,19 @@ d] ] scenario editor-deletes-to-end-of-line-with-ctrl-k-3 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start at end of line assume-console [ - left-click 1, 2 + left-click 1, 2 type [k] # ctrl-k ] - 3:event/ctrl-k <- merge 0:literal/text, 11:literal/ctrl-k, 0:literal/dummy, 0:literal/dummy - replace-in-console 107:literal/k, 3:event/ctrl-k + 3:event/ctrl-k <- merge 0/text, 11/ctrl-k, 0/dummy, 0/dummy + replace-in-console 107/k, 3:event/ctrl-k run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # cursor deletes to end of line screen-should-contain [ @@ -2454,19 +2574,19 @@ d] ] scenario editor-deletes-to-end-of-line-with-ctrl-k-4 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start past end of line assume-console [ - left-click 1, 3 + left-click 1, 3 type [k] # ctrl-k ] - 3:event/ctrl-k <- merge 0:literal/text, 11:literal/ctrl-k, 0:literal/dummy, 0:literal/dummy - replace-in-console 107:literal/k, 3:event/ctrl-k + 3:event/ctrl-k <- merge 0/text, 11/ctrl-k, 0/dummy, 0/dummy + replace-in-console 107/k, 3:event/ctrl-k run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # cursor deletes to end of line screen-should-contain [ @@ -2478,19 +2598,19 @@ d] ] scenario editor-deletes-to-end-of-line-with-ctrl-k-5 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start at end of text assume-console [ - left-click 2, 2 + left-click 2, 2 type [k] # ctrl-k ] - 3:event/ctrl-k <- merge 0:literal/text, 11:literal/ctrl-k, 0:literal/dummy, 0:literal/dummy - replace-in-console 107:literal/k, 3:event/ctrl-k + 3:event/ctrl-k <- merge 0/text, 11/ctrl-k, 0/dummy, 0/dummy + replace-in-console 107/k, 3:event/ctrl-k run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # cursor deletes to end of line screen-should-contain [ @@ -2502,19 +2622,19 @@ d] ] scenario editor-deletes-to-end-of-line-with-ctrl-k-6 [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [123 + assume-screen 10/width, 5/height + 1:address:array:character <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right # start past end of text assume-console [ - left-click 2, 3 + left-click 2, 3 type [k] # ctrl-k ] - 3:event/ctrl-k <- merge 0:literal/text, 11:literal/ctrl-k, 0:literal/dummy, 0:literal/dummy - replace-in-console 107:literal/k, 3:event/ctrl-k + 3:event/ctrl-k <- merge 0/text, 11/ctrl-k, 0/dummy, 0/dummy + replace-in-console 107/k, 3:event/ctrl-k run [ - editor-event-loop screen:address, console:address, 2:address:editor-data + editor-event-loop screen:address, console:address, 2:address:editor-data ] # cursor deletes to end of line screen-should-contain [ @@ -2527,67 +2647,67 @@ d] scenario point-at-multiple-editors [ $close-trace - assume-screen 30:literal/width, 5:literal/height + assume-screen 30/width, 5/height # initialize both halves of screen - 1:address:array:character <- new [abc] - 2:address:array:character <- new [def] - 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character + 1:address:array:character <- new [abc] + 2:address:array:character <- new [def] + 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character # focus on both sides assume-console [ - left-click 1, 1 - left-click 1, 17 + left-click 1, 1 + left-click 1, 17 ] # check cursor column in each run [ - event-loop screen:address, console:address, 3:address:programming-environment-data - 4:address:editor-data <- get 3:address:programming-environment-data/deref, recipes:offset - 5:number <- get 4:address:editor-data/deref, cursor-column:offset - 6:address:editor-data <- get 3:address:programming-environment-data/deref, current-sandbox:offset - 7:number <- get 6:address:editor-data/deref, cursor-column:offset + event-loop screen:address, console:address, 3:address:programming-environment-data + 4:address:editor-data <- get *3:address:programming-environment-data, recipes:offset + 5:number <- get *4:address:editor-data, cursor-column:offset + 6:address:editor-data <- get *3:address:programming-environment-data, current-sandbox:offset + 7:number <- get *6:address:editor-data, cursor-column:offset ] memory-should-contain [ - 5 <- 1 - 7 <- 17 + 5 <- 1 + 7 <- 17 ] ] scenario edit-multiple-editors [ $close-trace - assume-screen 30:literal/width, 5:literal/height + assume-screen 30/width, 5/height # initialize both halves of screen - 1:address:array:character <- new [abc] - 2:address:array:character <- new [def] - 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character + 1:address:array:character <- new [abc] + 2:address:array:character <- new [def] + 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character # type one letter in each of them assume-console [ - left-click 1, 1 + left-click 1, 1 type [0] - left-click 1, 17 + left-click 1, 17 type [1] ] run [ - event-loop screen:address, console:address, 3:address:programming-environment-data - 4:address:editor-data <- get 3:address:programming-environment-data/deref, recipes:offset - 5:number <- get 4:address:editor-data/deref, cursor-column:offset - 6:address:editor-data <- get 3:address:programming-environment-data/deref, current-sandbox:offset - 7:number <- get 6:address:editor-data/deref, cursor-column:offset + event-loop screen:address, console:address, 3:address:programming-environment-data + 4:address:editor-data <- get *3:address:programming-environment-data, recipes:offset + 5:number <- get *4:address:editor-data, cursor-column:offset + 6:address:editor-data <- get *3:address:programming-environment-data, current-sandbox:offset + 7:number <- get *6:address:editor-data, cursor-column:offset ] screen-should-contain [ - . run (F10) . # this line has a different background, but we don't test that yet + . run (F4) . # this line has a different background, but we don't test that yet .a0bc ┊d1ef . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━. . ┊ . ] memory-should-contain [ - 5 <- 2 # cursor column of recipe editor - 7 <- 18 # cursor column of sandbox editor + 5 <- 2 # cursor column of recipe editor + 7 <- 18 # cursor column of sandbox editor ] # show the cursor at the right window run [ - screen:address <- print-character screen:address, 9251:literal/␣ + screen:address <- print-character screen:address, 9251/␣ ] screen-should-contain [ - . run (F10) . + . run (F4) . .a0bc ┊d1␣f . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━. . ┊ . @@ -2596,15 +2716,15 @@ d] scenario multiple-editors-cover-only-their-own-areas [ $close-trace - assume-screen 60:literal/width, 10:literal/height + assume-screen 60/width, 10/height run [ - 1:address:array:character <- new [abc] - 2:address:array:character <- new [def] - 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character + 1:address:array:character <- new [abc] + 2:address:array:character <- new [def] + 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character ] # divider isn't messed up screen-should-contain [ - . run (F10) . + . run (F4) . .abc ┊def . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . @@ -2614,19 +2734,19 @@ d] scenario editor-in-focus-keeps-cursor [ $close-trace - assume-screen 30:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:array:character <- new [def] + assume-screen 30/width, 5/height + 1:address:array:character <- new [abc] + 2:address:array:character <- new [def] # initialize programming environment and highlight cursor assume-console [] run [ - 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:address <- print-character screen:address, 9251:literal/␣ + 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:address <- print-character screen:address, 9251/␣ ] # is cursor at the right place? screen-should-contain [ - . run (F10) . + . run (F4) . .␣bc ┊def . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━. . ┊ . @@ -2636,13 +2756,13 @@ d] type [z] ] run [ - 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:address <- print-character screen:address, 9251:literal/␣ + 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:address <- print-character screen:address, 9251/␣ ] # cursor should still be right screen-should-contain [ - . run (F10) . + . run (F4) . .z␣bc ┊def . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━. . ┊ . @@ -2662,43 +2782,43 @@ container sandbox-data [ scenario run-and-show-results [ $close-trace # trace too long for github - assume-screen 100:literal/width, 15:literal/height + assume-screen 100/width, 15/height # recipe editor is empty - 1:address:array:character <- new [] + 1:address:array:character <- new [] # sandbox editor contains an instruction without storing outputs - 2:address:array:character <- new [divide-with-remainder 11:literal, 3:literal] - 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character + 2:address:array:character <- new [divide-with-remainder 11, 3] + 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character # run the code in the editors assume-console [ - press 65526 # F10 + press 65532 # F4 ] run [ - event-loop screen:address, console:address, 3:address:programming-environment-data + event-loop screen:address, console:address, 3:address:programming-environment-data ] # check that screen prints the results screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ x. - . ┊divide-with-remainder 11:literal, 3:literal . + . ┊divide-with-remainder 11, 3 . . ┊3 . . ┊2 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . ] - screen-should-contain-in-color 7:literal/white, [ + screen-should-contain-in-color 7/white, [ . . . . . . . . - . divide-with-remainder 11:literal, 3:literal . + . divide-with-remainder 11, 3 . . . . . . . . . ] - screen-should-contain-in-color 245:literal/grey, [ + screen-should-contain-in-color 245/grey, [ . . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. @@ -2711,24 +2831,24 @@ container sandbox-data [ ] # run another command assume-console [ - left-click 1, 80 - type [add 2:literal, 2:literal] - press 65526 # F10 + left-click 1, 80 + type [add 2, 2] + press 65532 # F4 ] run [ - event-loop screen:address, console:address, 3:address:programming-environment-data + event-loop screen:address, console:address, 3:address:programming-environment-data ] # check that screen prints the results screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ x. - . ┊add 2:literal, 2:literal . + . ┊add 2, 2 . . ┊4 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ x. - . ┊divide-with-remainder 11:literal, 3:literal . + . ┊divide-with-remainder 11, 3 . . ┊3 . . ┊2 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. @@ -2739,55 +2859,57 @@ container sandbox-data [ recipe run-sandboxes [ local-scope env:address:programming-environment-data <- next-ingredient - recipes:address:editor-data <- get env:address:programming-environment-data/deref, recipes:offset - current-sandbox:address:editor-data <- get env:address:programming-environment-data/deref, current-sandbox:offset + recipes:address:editor-data <- get *env, recipes:offset + current-sandbox:address:editor-data <- get *env, current-sandbox:offset # copy code from recipe editor, persist, load into mu, save any warnings - in:address:array:character <- editor-contents recipes:address:editor-data - save [recipes.mu], in:address:array:character - recipe-warnings:address:address:array:character <- get-address env:address:programming-environment-data/deref, recipe-warnings:offset - recipe-warnings:address:address:array:character/deref <- reload in:address:array:character + in:address:array:character <- editor-contents recipes + save [recipes.mu], in + recipe-warnings:address:address:array:character <- get-address *env, recipe-warnings:offset + *recipe-warnings <- reload in # if recipe editor has errors, stop - reply-if recipe-warnings:address:address:array:character/deref + reply-if *recipe-warnings # check contents of right editor (sandbox) { - sandbox-contents:address:array:character <- editor-contents current-sandbox:address:editor-data - break-unless sandbox-contents:address:array:character + sandbox-contents:address:array:character <- editor-contents current-sandbox + break-unless sandbox-contents # if contents exist, first save them # run them and turn them into a new sandbox-data new-sandbox:address:sandbox-data <- new sandbox-data:type - data:address:address:array:character <- get-address new-sandbox:address:sandbox-data/deref, data:offset - data:address:address:array:character/deref <- copy sandbox-contents:address:array:character + data:address:address:array:character <- get-address *new-sandbox, data:offset + *data <- copy sandbox-contents # push to head of sandbox list - dest:address:address:sandbox-data <- get-address env:address:programming-environment-data/deref, sandbox:offset - next:address:address:sandbox-data <- get-address new-sandbox:address:sandbox-data/deref, next-sandbox:offset - next:address:address:sandbox-data/deref <- copy dest:address:address:sandbox-data/deref - dest:address:address:sandbox-data/deref <- copy new-sandbox:address:sandbox-data + dest:address:address:sandbox-data <- get-address *env, sandbox:offset + next:address:address:sandbox-data <- get-address *new-sandbox, next-sandbox:offset + *next <- copy *dest + *dest <- copy new-sandbox # clear sandbox editor - init:address:address:duplex-list <- get-address current-sandbox:address:editor-data/deref, data:offset - init:address:address:duplex-list/deref <- push-duplex 167:literal/§, 0:literal/tail + init:address:address:duplex-list <- get-address *current-sandbox, data:offset + *init <- push-duplex 167/§, 0/tail } # save all sandboxes before running, just in case we die when running - curr:address:sandbox-data <- get env:address:programming-environment-data/deref, sandbox:offset - filename:number <- copy 0:literal + # first clear previous versions, in case we deleted some sandbox + $system [rm lesson/[0-9]*] + curr:address:sandbox-data <- get *env, sandbox:offset + filename:number <- copy 0 { - break-unless curr:address:sandbox-data - data:address:address:array:character <- get-address curr:address:sandbox-data/deref, data:offset - save filename:number, data:address:address:array:character/deref - filename:number <- add filename:number, 1:literal - curr:address:sandbox-data <- get curr:address:sandbox-data/deref, next-sandbox:offset + break-unless curr + data:address:address:array:character <- get-address *curr, data:offset + save filename, *data + filename <- add filename, 1 + curr <- get *curr, next-sandbox:offset loop } # run all sandboxes - curr:address:sandbox-data <- get env:address:programming-environment-data/deref, sandbox:offset + curr <- get *env, sandbox:offset { - break-unless curr:address:sandbox-data - data:address:address:array:character <- get-address curr:address:sandbox-data/deref, data:offset - response:address:address:array:character <- get-address curr:address:sandbox-data/deref, response:offset - warnings:address:address:array:character <- get-address curr:address:sandbox-data/deref, warnings:offset - fake-screen:address:address:screen <- get-address curr:address:sandbox-data/deref, screen:offset - response:address:address:array:character/deref, warnings:address:address:array:character/deref, fake-screen:address:address:screen/deref <- run-interactive data:address:address:array:character/deref -#? $print warnings:address:address:array:character/deref, [ ], warnings:address:address:array:character/deref/deref, 10:literal/newline - curr:address:sandbox-data <- get curr:address:sandbox-data/deref, next-sandbox:offset + break-unless curr + 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 + fake-screen:address:address:screen <- get-address *curr, screen:offset + *response, *warnings, *fake-screen <- run-interactive *data +#? $print *warnings, [ ], **warnings, 10/newline + curr <- get *curr, next-sandbox:offset loop } ] @@ -2797,29 +2919,30 @@ container sandbox-data [ screen:address <- next-ingredient env:address:programming-environment-data <- next-ingredient clear:boolean <- next-ingredient - current-sandbox:address:editor-data <- get env:address:programming-environment-data/deref, current-sandbox:offset - left:number <- get current-sandbox:address:editor-data/deref, left:offset - right:number <- get current-sandbox:address:editor-data/deref, right:offset - row:number, screen:address <- render screen:address, current-sandbox:address:editor-data - row:number <- add row:number, 1:literal - draw-horizontal screen:address, row:number, left:number, right:number, 9473:literal/horizontal-double - sandbox:address:sandbox-data <- get env:address:programming-environment-data/deref, sandbox:offset - row:number, screen:address <- render-sandboxes screen:address, sandbox:address:sandbox-data, left:number, right:number, row:number +#? trace [app], [render sandbox side] #? 1 + current-sandbox:address:editor-data <- get *env, current-sandbox:offset + left:number <- get *current-sandbox, left:offset + right:number <- get *current-sandbox, right:offset + row:number, screen <- render screen, current-sandbox + row <- add row, 1 + draw-horizontal screen, row, left, right, 9473/horizontal-double + sandbox:address:sandbox-data <- get *env, sandbox:offset + row, screen <- render-sandboxes screen, sandbox, left, right, row # clear next line, in case we just processed a backspace - row:number <- add row:number, 1:literal - move-cursor screen:address, row:number, left:number - clear-line-delimited screen:address, left:number, right:number - reply-unless clear:boolean, screen:address/same-as-ingredient:0 - screen-height:number <- screen-height screen:address + row <- add row, 1 + move-cursor screen, row, left + clear-line-delimited screen, left, right + reply-unless clear, screen/same-as-ingredient:0 + screen-height:number <- screen-height screen { - at-bottom-of-screen?:boolean <- greater-or-equal row:number, screen-height:number - break-if at-bottom-of-screen?:boolean - move-cursor screen:address, row:number, left:number - clear-line-delimited screen:address, left:number, right:number - row:number <- add row:number, 1:literal + at-bottom-of-screen?:boolean <- greater-or-equal row, screen-height + break-if at-bottom-of-screen? + move-cursor screen, row, left + clear-line-delimited screen, left, right + row <- add row, 1 loop } - reply screen:address/same-as-ingredient:0 + reply screen/same-as-ingredient:0 ] recipe render-sandboxes [ @@ -2829,49 +2952,48 @@ container sandbox-data [ left:number <- next-ingredient right:number <- next-ingredient row:number <- next-ingredient - reply-unless sandbox:address:sandbox-data, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 - screen-height:number <- screen-height screen:address - at-bottom?:boolean <- greater-or-equal row:number screen-height:number - reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 -#? $print [rendering sandbox ], sandbox:address:sandbox-data, 10:literal/newline + reply-unless sandbox, row/same-as-ingredient:4, screen/same-as-ingredient:0 + screen-height:number <- screen-height screen + at-bottom?:boolean <- greater-or-equal row, screen-height + reply-if at-bottom?:boolean, row/same-as-ingredient:4, screen/same-as-ingredient:0 # render sandbox menu - row:number <- add row:number, 1:literal - move-cursor screen:address, row:number, left:number - clear-line-delimited screen:address, left:number, right:number - print-character screen:address, 120:literal/x, 245:literal/grey + row <- add row, 1 + move-cursor screen, row, left + clear-line-delimited screen, left, right + print-character screen, 120/x, 245/grey # save menu row so we can detect clicks to it later - starting-row:address:number <- get-address sandbox:address:sandbox-data/deref, starting-row-on-screen:offset - starting-row:address:number/deref <- copy row:number + starting-row:address:number <- get-address *sandbox, starting-row-on-screen:offset + *starting-row <- copy row # render sandbox contents - sandbox-data:address:array:character <- get sandbox:address:sandbox-data/deref, data:offset - row:number, screen:address <- render-string screen:address, sandbox-data:address:array:character, left:number, right:number, 7:literal/white, row:number + sandbox-data:address:array:character <- get *sandbox, data:offset + row, screen <- render-string screen, sandbox-data, left, right, 7/white, row # render sandbox warnings, screen or response, in that order - sandbox-response:address:array:character <- get sandbox:address:sandbox-data/deref, response:offset - sandbox-warnings:address:array:character <- get sandbox:address:sandbox-data/deref, warnings:offset - sandbox-screen:address <- get sandbox:address:sandbox-data/deref, screen:offset + 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 { - break-unless sandbox-warnings:address:array:character - row:number, screen:address <- render-string screen:address, sandbox-warnings:address:array:character, left:number, right:number, 1:literal/red, row:number + break-unless sandbox-warnings + row, screen <- render-string screen, sandbox-warnings, left, right, 1/red, row } { - break-if sandbox-warnings:address:array:character - empty-screen?:boolean <- fake-screen-is-clear? sandbox-screen:address - break-if empty-screen?:boolean - row:number, screen:address <- render-screen screen:address, sandbox-screen:address, left:number, right:number, row:number + break-if sandbox-warnings + empty-screen?:boolean <- fake-screen-is-empty? sandbox-screen + break-if empty-screen? + row, screen <- render-screen screen, sandbox-screen, left, right, row } { - break-if sandbox-warnings:address:array:character - break-unless empty-screen?:boolean - row:number, screen:address <- render-string screen:address, sandbox-response:address:array:character, left:number, right:number, 245:literal/grey, row:number + break-if sandbox-warnings + break-unless empty-screen? + row, screen <- render-string screen, sandbox-response, left, right, 245/grey, row } - at-bottom?:boolean <- greater-or-equal row:number screen-height:number - reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 + at-bottom?:boolean <- greater-or-equal row, screen-height + reply-if at-bottom?, row/same-as-ingredient:4, screen/same-as-ingredient:0 # draw solid line after sandbox - draw-horizontal screen:address, row:number, left:number, right:number, 9473:literal/horizontal-double + draw-horizontal screen, row, left, right, 9473/horizontal-double # draw next sandbox - next-sandbox:address:sandbox-data <- get sandbox:address:sandbox-data/deref, next-sandbox:offset - row:number, screen:address <- render-sandboxes screen:address, next-sandbox:address:sandbox-data, left:number, right:number, row:number - reply row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 + next-sandbox:address:sandbox-data <- get *sandbox, next-sandbox:offset + row, screen <- render-sandboxes screen, next-sandbox, left, right, row + reply row/same-as-ingredient:4, screen/same-as-ingredient:0 ] # assumes programming environment has no sandboxes; restores them from previous session @@ -2879,22 +3001,21 @@ container sandbox-data [ local-scope env:address:programming-environment-data <- next-ingredient # read all scenarios, pushing them to end of a list of scenarios - filename:number <- copy 0:literal - curr:address:address:sandbox-data <- get-address env:address:programming-environment-data/deref, sandbox:offset + filename:number <- copy 0 + curr:address:address:sandbox-data <- get-address *env, sandbox:offset { - contents:address:array:character <- restore filename:number - break-unless contents:address:array:character # stop at first error; assuming file didn't exist -#? $print contents:address:array:character, 10:literal/newline + contents:address:array:character <- restore filename + break-unless contents # stop at first error; assuming file didn't exist # create new sandbox for file - curr:address:address:sandbox-data/deref <- new sandbox-data:type - data:address:address:array:character <- get-address curr:address:address:sandbox-data/deref/deref, data:offset - data:address:address:array:character/deref <- copy contents:address:array:character + *curr <- new sandbox-data:type + data:address:address:array:character <- get-address **curr, data:offset + *data <- copy contents # increment loop variables - filename:number <- add filename:number, 1:literal - curr:address:address:sandbox-data <- get-address curr:address:address:sandbox-data/deref/deref, next-sandbox:offset + filename <- add filename, 1 + curr <- get-address **curr, next-sandbox:offset loop } - reply env:address:programming-environment-data/same-as-ingredient:0 + reply env/same-as-ingredient:0 ] # was-deleted?:boolean <- delete-sandbox t:touch-event, env:address:programming-environment-data @@ -2902,69 +3023,56 @@ container sandbox-data [ local-scope t:touch-event <- next-ingredient env:address:programming-environment-data <- next-ingredient - click-column:number <- get t:touch-event, column:offset - current-sandbox:address:editor-data <- get env:address:programming-environment-data/deref, current-sandbox:offset - right:number <- get current-sandbox:address:editor-data/deref, right:offset -#? $print [comparing column ], click-column:number, [ vs ], right:number, 10:literal/newline - at-right?:boolean <- equal click-column:number, right:number - reply-unless at-right?:boolean, 0:literal/false -#? $print [trying to delete -#? ] #? 1 - click-row:number <- get t:touch-event, row:offset - prev:address:address:sandbox-data <- get-address env:address:programming-environment-data/deref, sandbox:offset -#? $print [prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, 10:literal/newline - curr:address:sandbox-data <- get env:address:programming-environment-data/deref, sandbox:offset + click-column:number <- get t, column:offset + current-sandbox:address:editor-data <- get *env, current-sandbox:offset + right:number <- get *current-sandbox, right:offset + at-right?:boolean <- equal click-column, right + reply-unless at-right?, 0/false + click-row:number <- get t, row:offset + prev:address:address:sandbox-data <- get-address *env, sandbox:offset + curr:address:sandbox-data <- get *env, sandbox:offset { -#? $print [next sandbox -#? ] #? 1 - break-unless curr:address:sandbox-data + break-unless curr # more sandboxes to check { -#? $print [checking -#? ] #? 1 - target-row:number <- get curr:address:sandbox-data/deref, starting-row-on-screen:offset -#? $print [comparing row ], target-row:number, [ vs ], click-row:number, 10:literal/newline - delete-curr?:boolean <- equal target-row:number, click-row:number - break-unless delete-curr?:boolean -#? $print [found! -#? ] #? 1 + target-row:number <- get *curr, starting-row-on-screen:offset + delete-curr?:boolean <- equal target-row, click-row + break-unless delete-curr? # delete this sandbox, rerender and stop - prev:address:address:sandbox-data/deref <- get curr:address:sandbox-data/deref, next-sandbox:offset -#? $print [setting prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, 10:literal/newline - reply 1:literal/true + *prev <- get *curr, next-sandbox:offset + reply 1/true } - prev:address:address:sandbox-data <- get-address curr:address:sandbox-data/deref, next-sandbox:offset -#? $print [prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, 10:literal/newline - curr:address:sandbox-data <- get curr:address:sandbox-data/deref, next-sandbox:offset + prev <- get-address *curr, next-sandbox:offset + curr <- get *curr, next-sandbox:offset loop } - reply 0:literal/false + reply 0/false ] scenario run-updates-results [ $close-trace # trace too long for github - assume-screen 100:literal/width, 12:literal/height + assume-screen 100/width, 12/height # define a recipe (no indent for the 'add' line below so column numbers are more obvious) - 1:address:array:character <- new [ + 1:address:array:character <- new [ recipe foo [ -z:number <- add 2:literal, 2:literal +z:number <- add 2, 2 ]] # sandbox editor contains an instruction without storing outputs - 2:address:array:character <- new [foo] - 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character + 2:address:array:character <- new [foo] + 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character # run the code in the editors assume-console [ - press 65526 # F10 + press 65532 # F4 ] run [ - event-loop screen:address, console:address, 3:address:programming-environment-data + event-loop screen:address, console:address, 3:address:programming-environment-data ] # check that screen prints the results screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - .z:number <- add 2:literal, 2:literal ┊ x. + .z:number <- add 2, 2 ┊ x. .] ┊foo . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. @@ -2972,21 +3080,21 @@ container sandbox-data [ ] # make a change (incrementing one of the args to 'add'), then rerun assume-console [ - left-click 3, 28 # one past the value of the second arg + left-click 3, 28 # one past the value of the second arg type [«3] # replace - press 65526 # F10 + press 65532 # F4 ] - 4:event/backspace <- merge 0:literal/text, 8:literal/backspace, 0:literal/dummy, 0:literal/dummy - replace-in-console 171:literal/«, 4:event/backspace + 4:event/backspace <- merge 0/text, 8/backspace, 0/dummy, 0/dummy + replace-in-console 171/«, 4:event/backspace run [ - event-loop screen:address, console:address, 3:address:programming-environment-data + event-loop screen:address, console:address, 3:address:programming-environment-data ] # check that screen updates the result on the right screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - .z:number <- add 2:literal, 3:literal ┊ x. + .z:number <- add 2, 3 ┊ x. .] ┊foo . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊5 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. @@ -2996,22 +3104,22 @@ container sandbox-data [ scenario run-instruction-and-print-warnings [ $close-trace # trace too long for github - assume-screen 100:literal/width, 10:literal/height + assume-screen 100/width, 10/height # left editor is empty - 1:address:array:character <- new [] + 1:address:array:character <- new [] # right editor contains an illegal instruction - 2:address:array:character <- new [get 1234:number, foo:offset] - 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character + 2:address:array:character <- new [get 1234:number, foo:offset] + 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character # run the code in the editors assume-console [ - press 65526 # F10 + press 65532 # F4 ] run [ - event-loop screen:address, console:address, 3:address:programming-environment-data + event-loop screen:address, console:address, 3:address:programming-environment-data ] # check that screen prints error message in red screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ x. @@ -3020,7 +3128,7 @@ container sandbox-data [ . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . ] - screen-should-contain-in-color 7:literal/white, [ + screen-should-contain-in-color 7/white, [ . . . . . . @@ -3030,7 +3138,7 @@ container sandbox-data [ . . . . ] - screen-should-contain-in-color 1:literal/red, [ + screen-should-contain-in-color 1/red, [ . . . . . . @@ -3039,7 +3147,7 @@ container sandbox-data [ . unknown element foo in container number . . . ] - screen-should-contain-in-color 245:literal/grey, [ + screen-should-contain-in-color 245/grey, [ . . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. @@ -3053,23 +3161,23 @@ container sandbox-data [ scenario run-instruction-and-print-warnings-only-once [ $close-trace # trace too long for github - assume-screen 100:literal/width, 10:literal/height + assume-screen 100/width, 10/height # left editor is empty - 1:address:array:character <- new [] + 1:address:array:character <- new [] # right editor contains an illegal instruction - 2:address:array:character <- new [get 1234:number, foo:offset] - 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character + 2:address:array:character <- new [get 1234:number, foo:offset] + 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character # run the code in the editors multiple times assume-console [ - press 65526 # F10 - press 65526 # F10 + press 65532 # F4 + press 65532 # F4 ] run [ - event-loop screen:address, console:address, 3:address:programming-environment-data + event-loop screen:address, console:address, 3:address:programming-environment-data ] # check that screen prints error message just once screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ x. @@ -3082,31 +3190,31 @@ container sandbox-data [ scenario deleting-sandboxes [ $close-trace # trace too long for github - assume-screen 100:literal/width, 15:literal/height - 1:address:array:character <- new [] - 2:address:array:character <- new [] - 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character + assume-screen 100/width, 15/height + 1:address:array:character <- new [] + 2:address:array:character <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character # run a few commands assume-console [ - left-click 1, 80 - type [divide-with-remainder 11:literal, 3:literal] - press 65526 # F10 - type [add 2:literal, 2:literal] - press 65526 # F10 + left-click 1, 80 + type [divide-with-remainder 11, 3] + press 65532 # F4 + type [add 2, 2] + press 65532 # F4 ] run [ - event-loop screen:address, console:address, 3:address:programming-environment-data + event-loop screen:address, console:address, 3:address:programming-environment-data ] screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ x. - . ┊add 2:literal, 2:literal . + . ┊add 2, 2 . . ┊4 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ x. - . ┊divide-with-remainder 11:literal, 3:literal . + . ┊divide-with-remainder 11, 3 . . ┊3 . . ┊2 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. @@ -3114,17 +3222,17 @@ container sandbox-data [ ] # delete second sandbox assume-console [ - left-click 7, 99 + left-click 7, 99 ] run [ - event-loop screen:address, console:address, 3:address:programming-environment-data + event-loop screen:address, console:address, 3:address:programming-environment-data ] screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ x. - . ┊add 2:literal, 2:literal . + . ┊add 2, 2 . . ┊4 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . @@ -3132,13 +3240,13 @@ container sandbox-data [ ] # delete first sandbox assume-console [ - left-click 3, 99 + left-click 3, 99 ] run [ - event-loop screen:address, console:address, 3:address:programming-environment-data + event-loop screen:address, console:address, 3:address:programming-environment-data ] screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . @@ -3148,33 +3256,33 @@ container sandbox-data [ scenario run-instruction-manages-screen-per-sandbox [ $close-trace # trace too long for github #? 1 - assume-screen 100:literal/width, 20:literal/height + assume-screen 100/width, 20/height # left editor is empty - 1:address:array:character <- new [] + 1:address:array:character <- new [] # right editor contains an illegal instruction - 2:address:array:character <- new [print-integer screen:address, 4] - 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character + 2:address:array:character <- new [print-integer screen:address, 4] + 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character # run the code in the editor assume-console [ - press 65526 # F10 + press 65532 # F4 ] run [ - event-loop screen:address, console:address, 3:address:programming-environment-data + event-loop screen:address, console:address, 3:address:programming-environment-data ] # check that it prints a little 5x5 toy screen # hack: screen address is brittle screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ x. . ┊print-integer screen:address, 4 . . ┊screen: . - . ┊ .4 . . - . ┊ . . . - . ┊ . . . - . ┊ . . . - . ┊ . . . + . ┊ .4 . . + . ┊ . . . + . ┊ . . . + . ┊ . . . + . ┊ . . . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . ] @@ -3183,38 +3291,38 @@ container sandbox-data [ recipe editor-contents [ local-scope editor:address:editor-data <- next-ingredient - buf:address:buffer <- new-buffer 80:literal - curr:address:duplex-list <- get editor:address:editor-data/deref, data:offset + buf:address:buffer <- new-buffer 80 + curr:address:duplex-list <- get *editor, data:offset # skip § sentinel - assert curr:address:duplex-list, [editor without data is illegal; must have at least a sentinel] - curr:address:duplex-list <- next-duplex curr:address:duplex-list - reply-unless curr:address:duplex-list, 0:literal + assert curr, [editor without data is illegal; must have at least a sentinel] + curr <- next-duplex curr + reply-unless curr, 0 { - break-unless curr:address:duplex-list - c:character <- get curr:address:duplex-list/deref, value:offset - buffer-append buf:address:buffer, c:character - curr:address:duplex-list <- next-duplex curr:address:duplex-list + break-unless curr + c:character <- get *curr, value:offset + buffer-append buf, c + curr <- next-duplex curr loop } - result:address:array:character <- buffer-to-array buf:address:buffer - reply result:address:array:character + result:address:array:character <- buffer-to-array buf + reply result ] scenario editor-provides-edited-contents [ - assume-screen 10:literal/width, 5:literal/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0:literal/left, 10:literal/right + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right assume-console [ - left-click 1, 2 + left-click 1, 2 type [def] ] run [ - editor-event-loop screen:address, console:address, 2:address:editor-data - 3:address:array:character <- editor-contents 2:address:editor-data - 4:array:character <- copy 3:address:array:character/deref + editor-event-loop screen:address, console:address, 2:address:editor-data + 3:address:array:character <- editor-contents 2:address:editor-data + 4:array:character <- copy *3:address:array:character ] memory-should-contain [ - 4:string <- [abdefc] + 4:string <- [abdefc] ] ] @@ -3222,9 +3330,9 @@ container sandbox-data [ scenario run-shows-warnings-in-get [ $close-trace - assume-screen 100:literal/width, 15:literal/height + assume-screen 100/width, 15/height assume-console [ - press 65526 # F10 + press 65532 # F4 ] run [ x:address:array:character <- new [ @@ -3236,7 +3344,7 @@ container sandbox-data [ event-loop screen:address, console:address, env:address:programming-environment-data ] screen-should-contain [ - . run (F10) . + . run (F4) . . ┊foo . .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . get 123:number, foo:offset ┊ . @@ -3245,7 +3353,7 @@ container sandbox-data [ .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ . . ┊ . ] - screen-should-contain-in-color 1:literal/red, [ + screen-should-contain-in-color 1/red, [ . . . . . . @@ -3258,28 +3366,26 @@ container sandbox-data [ scenario run-shows-missing-type-warnings [ $close-trace - assume-screen 100:literal/width, 15:literal/height + assume-screen 100/width, 15/height assume-console [ - press 65526 # F10 + press 65532 # F4 ] run [ x:address:array:character <- new [ recipe foo [ - x:number <- copy 0 - copy x + x <- copy 0 ]] y:address:array:character <- new [foo] env:address:programming-environment-data <- new-programming-environment screen:address, x:address:array:character, y:address:array:character event-loop screen:address, console:address, env:address:programming-environment-data ] screen-should-contain [ - . run (F10) . + . run (F4) . . ┊foo . .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . x:number <- copy 0 ┊ . - . copy x ┊ . + . x <- copy 0 ┊ . .] ┊ . - .missing type in 'copy x' ┊ . + .missing type in 'x <- copy 0' ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ . . ┊ . ] @@ -3287,9 +3393,9 @@ container sandbox-data [ scenario run-shows-get-on-non-container-warnings [ $close-trace - assume-screen 100:literal/width, 15:literal/height + assume-screen 100/width, 15/height assume-console [ - press 65526 # F10 + press 65532 # F4 ] run [ x:address:array:character <- new [ @@ -3302,41 +3408,42 @@ container sandbox-data [ event-loop screen:address, console:address, env:address:programming-environment-data ] screen-should-contain [ - . run (F10) . + . run (F4) . . ┊ . .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . x:address:point <- new point:type ┊ x. . get x:address:point, 1:offset ┊foo . - .] ┊foo: 'get' on a non-container x:address:point . - .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .] ┊foo: first ingredient of 'get' should be a conta↩. + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊iner, but got x:address:point . + . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . ] ] scenario run-shows-non-literal-get-argument-warnings [ $close-trace - assume-screen 100:literal/width, 15:literal/height + assume-screen 100/width, 15/height assume-console [ - press 65526 # F10 + press 65532 # F4 ] run [ x:address:array:character <- new [ recipe foo [ x:number <- copy 0 y:address:point <- new point:type - get y:address:point/deref, x:number + get *y:address:point, x:number ]] y:address:array:character <- new [foo] env:address:programming-environment-data <- new-programming-environment screen:address, x:address:array:character, y:address:array:character event-loop screen:address, console:address, env:address:programming-environment-data ] screen-should-contain [ - . run (F10) . + . run (F4) . . ┊foo . .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . x:number <- copy 0 ┊ . . y:address:point <- new point:type ┊ . - . get y:address:point/deref, x:number ┊ . + . get *y:address:point, x:number ┊ . .] ┊ . .foo: expected ingredient 1 of 'get' to have type ↩┊ . .'offset'; got x:number ┊ . @@ -3357,22 +3464,22 @@ container sandbox-data [ color:number, color-found?:boolean <- next-ingredient { # default color to white - break-if color-found?:boolean - color:number <- copy 245:literal/grey + break-if color-found? + color <- copy 245/grey } # top border - draw-horizontal screen:address, top:number, left:number, right:number, color:number - draw-horizontal screen:address, bottom:number, left:number, right:number, color:number - draw-vertical screen:address, left:number, top:number, bottom:number, color:number - draw-vertical screen:address, right:number, top:number, bottom:number, color:number - draw-top-left screen:address, top:number, left:number, color:number - draw-top-right screen:address, top:number, right:number, color:number - draw-bottom-left screen:address, bottom:number, left:number, color:number - draw-bottom-right screen:address, bottom:number, right:number, color:number + draw-horizontal screen, top, left, right, color + draw-horizontal screen, bottom, left, right, color + draw-vertical screen, left, top, bottom, color + draw-vertical screen, right, top, bottom, color + draw-top-left screen, top, left, color + draw-top-right screen, top, right, color + draw-bottom-left screen, bottom, left, color + draw-bottom-right screen, bottom, right, color # position cursor inside box - move-cursor screen:address, top:number, left:number - cursor-down screen:address - cursor-right screen:address + move-cursor screen, top, left + cursor-down screen + cursor-right screen ] recipe draw-horizontal [ @@ -3383,26 +3490,26 @@ container sandbox-data [ right:number <- next-ingredient style:character, style-found?:boolean <- next-ingredient { - break-if style-found?:boolean - style:character <- copy 9472:literal/horizontal + break-if style-found? + style <- copy 9472/horizontal } color:number, color-found?:boolean <- next-ingredient { # default color to white - break-if color-found?:boolean - color:number <- copy 245:literal/grey + break-if color-found? + color <- copy 245/grey } bg-color:number, bg-color-found?:boolean <- next-ingredient { break-if bg-color-found?:boolean - bg-color:number <- copy 0:literal/black + bg-color <- copy 0/black } - move-cursor screen:address, row:number, x:number + move-cursor screen, row, x { - continue?:boolean <- lesser-or-equal x:number, right:number # right is inclusive, to match editor-data semantics - break-unless continue?:boolean - print-character screen:address, style:character, color:number, bg-color:number - x:number <- add x:number, 1:literal + continue?:boolean <- lesser-or-equal x, right # right is inclusive, to match editor-data semantics + break-unless continue? + print-character screen, style, color, bg-color + x <- add x, 1 loop } ] @@ -3411,25 +3518,25 @@ container sandbox-data [ local-scope screen:address <- next-ingredient col:number <- next-ingredient - x:number <- next-ingredient + y:number <- next-ingredient bottom:number <- next-ingredient style:character, style-found?:boolean <- next-ingredient { - break-if style-found?:boolean - style:character <- copy 9474:literal/vertical + break-if style-found? + style <- copy 9474/vertical } color:number, color-found?:boolean <- next-ingredient { # default color to white - break-if color-found?:boolean - color:number <- copy 245:literal/grey + break-if color-found? + color <- copy 245/grey } { - continue?:boolean <- lesser-than x:number, bottom:number - break-unless continue?:boolean - move-cursor screen:address, x:number, col:number - print-character screen:address, style:character, color:number - x:number <- add x:number, 1:literal + continue?:boolean <- lesser-than y, bottom + break-unless continue? + move-cursor screen, y, col + print-character screen, style, color + y <- add y, 1 loop } ] @@ -3442,11 +3549,11 @@ container sandbox-data [ color:number, color-found?:boolean <- next-ingredient { # default color to white - break-if color-found?:boolean - color:number <- copy 245:literal/grey + break-if color-found? + color <- copy 245/grey } - move-cursor screen:address, top:number, left:number - print-character screen:address, 9484:literal/down-right, color:number + move-cursor screen, top, left + print-character screen, 9484/down-right, color ] recipe draw-top-right [ @@ -3457,11 +3564,11 @@ container sandbox-data [ color:number, color-found?:boolean <- next-ingredient { # default color to white - break-if color-found?:boolean - color:number <- copy 245:literal/grey + break-if color-found? + color <- copy 245/grey } - move-cursor screen:address, top:number, right:number - print-character screen:address, 9488:literal/down-left, color:number + move-cursor screen, top, right + print-character screen, 9488/down-left, color ] recipe draw-bottom-left [ @@ -3472,11 +3579,11 @@ container sandbox-data [ color:number, color-found?:boolean <- next-ingredient { # default color to white - break-if color-found?:boolean - color:number <- copy 245:literal/grey + break-if color-found? + color <- copy 245/grey } - move-cursor screen:address, bottom:number, left:number - print-character screen:address, 9492:literal/up-right, color:number + move-cursor screen, bottom, left + print-character screen, 9492/up-right, color ] recipe draw-bottom-right [ @@ -3487,40 +3594,35 @@ container sandbox-data [ color:number, color-found?:boolean <- next-ingredient { # default color to white - break-if color-found?:boolean - color:number <- copy 245:literal/grey + break-if color-found? + color <- copy 245/grey } - move-cursor screen:address, bottom:number, right:number - print-character screen:address, 9496:literal/up-left, color:number + move-cursor screen, bottom, right + print-character screen, 9496/up-left, color ] recipe print-string-with-gradient-background [ local-scope - x:address:screen <- next-ingredient + screen:address <- next-ingredient s:address:array:character <- next-ingredient color:number <- next-ingredient bg-color1:number <- next-ingredient bg-color2:number <- next-ingredient - len:number <- length s:address:array:character/deref - color-range:number <- subtract bg-color2:number, bg-color1:number - color-quantum:number <- divide color-range:number, len:number -#? close-console #? 2 -#? $print len:number, [, ], color-range:number, [, ], color-quantum:number, 10:literal/newline -#? #? $exit #? 3 - bg-color:number <- copy bg-color1:number - i:number <- copy 0:literal + len:number <- length *s + color-range:number <- subtract bg-color2, bg-color1 + color-quantum:number <- divide color-range, len + bg-color:number <- copy bg-color1 + i:number <- copy 0 { - done?:boolean <- greater-or-equal i:number, len:number - break-if done?:boolean - c:character <- index s:address:array:character/deref, i:number - print-character x:address:screen, c:character, color:number, bg-color:number - i:number <- add i:number, 1:literal - bg-color:number <- add bg-color:number, color-quantum:number -#? $print [=> ], bg-color:number, 10:literal/newline + done?:boolean <- greater-or-equal i, len + break-if done? + c:character <- index *s, i + print-character screen, c, color, bg-color + i <- add i, 1 + bg-color <- add bg-color, color-quantum loop } -#? $exit #? 1 - reply x:address:screen/same-as-ingredient:0 + reply screen/same-as-ingredient:0 ] diff --git a/html/factorial.mu.html b/html/factorial.mu.html index 54a70688..8cdc3ef6 100644 --- a/html/factorial.mu.html +++ b/html/factorial.mu.html @@ -13,13 +13,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } -.muScenario { color: #00af00; } +.muRecipe { color: #ff8700; } .Delimiter { color: #a04060; } +.muScenario { color: #00af00; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -35,8 +35,8 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } recipe main [ local-scope - x:number <- factorial 5:literal - $print [result: ], x:number, [ + x:number <- factorial 5 + $print [result: ], x, [ ] ] @@ -45,24 +45,24 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } n:number <- next-ingredient { # if n=0 return 1 - zero?:boolean <- equal n:number, 0:literal - break-unless zero?:boolean - reply 1:literal + zero?:boolean <- equal n, 0 + break-unless zero? + reply 1 } # return n * factorial(n-1) - x:number <- subtract n:number, 1:literal - subresult:number <- factorial x:number - result:number <- multiply subresult:number, n:number - reply result:number + x:number <- subtract n, 1 + subresult:number <- factorial x + result:number <- multiply subresult, n + reply result ] # unit test scenario factorial-test [ run [ - 1:number <- factorial 5:literal + 1:number <- factorial 5 ] memory-should-contain [ - 1 <- 120 + 1 <- 120 ] ] diff --git a/html/factorial.png b/html/factorial.png index 19249bbe..93b63e8a 100644 Binary files a/html/factorial.png and b/html/factorial.png differ diff --git a/html/fork.mu.html b/html/fork.mu.html index 4d6b367c..3f47e9a2 100644 --- a/html/fork.mu.html +++ b/html/fork.mu.html @@ -13,11 +13,11 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Constant { color: #00a0a0; } .Comment { color: #9090ff; } .Delimiter { color: #a04060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -34,14 +34,14 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } recipe main [ start-running thread2:recipe { - $print 34:literal + $print 34 loop } ] recipe thread2 [ { - $print 35:literal + $print 35 loop } ] diff --git a/html/global.mu.html b/html/global.mu.html index aa060d5a..812e3a35 100644 --- a/html/global.mu.html +++ b/html/global.mu.html @@ -13,10 +13,10 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } -.muRecipe { color: #ff8700; } --> @@ -32,9 +32,9 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } recipe main [ # allocate 5 locations for globals - global-space:address:array:location <- new location:type, 5:literal + global-space:address:array:location <- new location:type, 5 # read to globals by using /space:global - 1:number/space:global <- copy 3:literal + 1:number/space:global <- copy 3 foo ] diff --git a/html/screen.mu.html b/html/screen.mu.html index 4618548a..6efea923 100644 --- a/html/screen.mu.html +++ b/html/screen.mu.html @@ -13,10 +13,10 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } -.muRecipe { color: #ff8700; } --> @@ -35,24 +35,24 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } recipe main [ open-console - print-character 0:literal/screen, 97:literal, 2:literal/red - 1:number/raw, 2:number/raw <- cursor-position 0:literal/screen - wait-for-event 0:literal/console - clear-screen 0:literal/screen - move-cursor 0:literal/screen, 0:literal/row, 4:literal/column - print-character 0:literal/screen, 98:literal - wait-for-event 0:literal/console - move-cursor 0:literal/screen, 0:literal/row, 0:literal/column - clear-line 0:literal/screen - wait-for-event 0:literal/console - cursor-down 0:literal/screen - wait-for-event 0:literal/console - cursor-right 0:literal/screen - wait-for-event 0:literal/console - cursor-left 0:literal/screen - wait-for-event 0:literal/console - cursor-up 0:literal/screen - wait-for-event 0:literal/console + print-character 0/screen, 97/a, 2/red + 1:number/raw, 2:number/raw <- cursor-position 0/screen + wait-for-event 0/console + clear-screen 0/screen + move-cursor 0/screen, 0/row, 4/column + print-character 0/screen, 98/b + wait-for-event 0/console + move-cursor 0/screen, 0/row, 0/column + clear-line 0/screen + wait-for-event 0/console + cursor-down 0/screen + wait-for-event 0/console + cursor-right 0/screen + wait-for-event 0/console + cursor-left 0/screen + wait-for-event 0/console + cursor-up 0/screen + wait-for-event 0/console close-console ] diff --git a/html/tangle.mu.html b/html/tangle.mu.html index 4c72404b..f4e8be60 100644 --- a/html/tangle.mu.html +++ b/html/tangle.mu.html @@ -13,12 +13,12 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Delimiter { color: #a04060; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } .muControl { color: #c0a020; } -.muRecipe { color: #ff8700; } --> @@ -49,22 +49,22 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } after +base-case [ # if n=0 return 1 - zero?:boolean <- equal n:number, 0:literal - break-unless zero?:boolean - reply 1:literal + zero?:boolean <- equal n, 0 + break-unless zero? + reply 1 ] after +recursive-case [ # return n * factorial(n - 1) - x:number <- subtract n:number, 1:literal - subresult:number <- factorial x:number - result:number <- multiply subresult:number, n:number - reply result:number + x:number <- subtract n, 1 + subresult:number <- factorial x + result:number <- multiply subresult, n + reply result ] recipe main [ - 1:number <- factorial 5:literal - $print [result: ], 1:number, [ + 1:number <- factorial 5 + $print [result: ], 1:number, [ ] ] diff --git a/html/x.mu.html b/html/x.mu.html index fa874a2d..7ff0e1aa 100644 --- a/html/x.mu.html +++ b/html/x.mu.html @@ -13,10 +13,10 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; } body { font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 1.05em; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #ff6060; } -.muRecipe { color: #ff8700; } --> @@ -31,9 +31,9 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } # example program: add two numbers recipe main [ - 11:number <- copy 1:literal - 12:number <- copy 3:literal - 13:number <- add 11:number, 12:number + 11:number <- copy 1 + 12:number <- copy 3 + 13:number <- add 11:number, 12:number $dump-memory ] -- cgit 1.4.1-2-gfad0