From 0ca56ed853c3d9bc8c26d1b014d8b665363fc2d0 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Thu, 15 Sep 2016 01:01:58 -0700 Subject: 3355 --- html/014literal_string.cc.html | 2 +- html/016dilated_reagent.cc.html | 2 +- html/017parse_tree.cc.html | 5 +- html/018type_abbreviations.cc.html | 259 +++++++---- html/020run.cc.html | 11 +- html/030container.cc.html | 69 ++- html/033exclusive_container.cc.html | 7 +- html/035lookup.cc.html | 2 +- html/041jump_target.cc.html | 4 +- html/047check_type_by_name.cc.html | 2 +- html/050scenario.cc.html | 2 +- html/053recipe_header.cc.html | 24 +- html/054static_dispatch.cc.html | 26 +- html/055shape_shifting_container.cc.html | 15 +- html/056shape_shifting_recipe.cc.html | 7 +- html/058to_text.cc.html | 62 +++ html/059to_text.mu.html | 66 +++ html/061text.mu.html | 289 ++++++------ html/062rewrite_stash.cc.html | 21 - html/064list.mu.html | 4 +- html/066stream.mu.html | 6 +- html/070table.mu.html | 4 +- html/071recipe.cc.html | 48 +- html/072scheduler.cc.html | 42 +- html/073wait.cc.html | 314 +++++++++---- html/075channel.mu.html | 68 ++- html/081print.mu.html | 8 +- html/088file.mu.html | 20 +- html/090scenario_filesystem_test.mu.html | 10 +- html/091socket.cc.html | 206 +++++++++ html/channel.mu.html | 1 + html/chessboard.mu.html | 42 +- html/edit/001-editor.mu.html | 42 +- html/edit/002-typing.mu.html | 100 ++--- html/edit/003-shortcuts.mu.html | 284 ++++++------ html/edit/004-programming-environment.mu.html | 38 +- html/edit/005-sandbox.mu.html | 84 ++-- html/edit/006-sandbox-copy.mu.html | 20 +- html/edit/007-sandbox-delete.mu.html | 30 +- html/edit/008-sandbox-edit.mu.html | 32 +- html/edit/009-sandbox-test.mu.html | 16 +- html/edit/010-sandbox-trace.mu.html | 26 +- html/edit/011-errors.mu.html | 112 ++--- html/edit/012-editor-undo.mu.html | 116 ++--- html/immutable-error.mu.html | 47 -- html/immutable_error.mu.html | 47 ++ html/lambda-to-mu.mu.html | 623 ------------------------- html/lambda_to_mu.mu.html | 624 ++++++++++++++++++++++++++ html/real-files.mu.html | 52 --- html/real_files.mu.html | 52 +++ html/server-socket.mu.html | 49 ++ index.html | 2 +- 52 files changed, 2384 insertions(+), 1660 deletions(-) create mode 100644 html/058to_text.cc.html create mode 100644 html/059to_text.mu.html create mode 100644 html/091socket.cc.html delete mode 100644 html/immutable-error.mu.html create mode 100644 html/immutable_error.mu.html delete mode 100644 html/lambda-to-mu.mu.html create mode 100644 html/lambda_to_mu.mu.html delete mode 100644 html/real-files.mu.html create mode 100644 html/real_files.mu.html create mode 100644 html/server-socket.mu.html diff --git a/html/014literal_string.cc.html b/html/014literal_string.cc.html index 199ac486..52a1b264 100644 --- a/html/014literal_string.cc.html +++ b/html/014literal_string.cc.html @@ -139,7 +139,7 @@ string slurp_quoted(istream& in} :(after "Parsing reagent(string s)") -if (s.at(0) == '[') { +if (starts_with(s, "[")) { if (*s.rbegin() != ']') return; // unbalanced bracket; handled elsewhere name = s; // delete [] delimiters diff --git a/html/016dilated_reagent.cc.html b/html/016dilated_reagent.cc.html index 60593460..3454ae68 100644 --- a/html/016dilated_reagent.cc.html +++ b/html/016dilated_reagent.cc.html @@ -128,7 +128,7 @@ string slurp_balanced_bracket(istream& in} :(after "Parsing reagent(string s)") -if (s.at(0) == '{') { +if (starts_with(s, "{")) { assert(properties.empty()); istringstream in(s); in >> std::noskipws; diff --git a/html/017parse_tree.cc.html b/html/017parse_tree.cc.html index 0acbc8cc..c9cfae37 100644 --- a/html/017parse_tree.cc.html +++ b/html/017parse_tree.cc.html @@ -40,6 +40,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color // the first element of a type tree is always an atom, and left and right // pointers of non-atoms are never NULL. All type trees are 'dotted' in lisp // parlance. +// +// For now you can't use the simpler 'colon-based' representation inside type +// trees. Once you start typing parens, keep on typing parens. :(scenarios load) :(scenario dilated_reagent_with_nested_brackets) @@ -56,7 +59,7 @@ type_names = parse_string_tree(type_names:(code) string_tree* parse_string_tree(string_tree* s) { assert(s->atom); - if (s->value.at(0) != '(') return s; + if (!starts_with(s->value, "(")) return s; string_tree* result = parse_string_tree(s->value); delete s; return result; diff --git a/html/018type_abbreviations.cc.html b/html/018type_abbreviations.cc.html index 5f2ff869..a025de1d 100644 --- a/html/018type_abbreviations.cc.html +++ b/html/018type_abbreviations.cc.html @@ -14,12 +14,12 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background- body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color: #080808; } * { font-size: 12pt; font-size: 1em; } .Constant { color: #00a0a0; } -.Special { color: #c00000; } -.traceContains { color: #008000; } .cSpecial { color: #008000; } +.traceContains { color: #008000; } +.SalientComment { color: #00ffff; } .Comment { color: #9090ff; } .Delimiter { color: #800080; } -.SalientComment { color: #00ffff; } +.Special { color: #c00000; } .Identifier { color: #fcb165; } .Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } --> @@ -33,96 +33,199 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
-//: For convenience, make some common types shorter.
-//:
-//:   a) Rewrite '&t' to 'address:t' and '@t' to 'array:type' (with the
-//:   ability to chain any combination of the two). This is not extensible.
-//:
-//:   b) Provide a facility to create new type names out of old ones.
-
-//:: a) expanding '&' and '@'
+//: For convenience, allow Mu types to be abbreviated.
 
-:(scenarios load)
-:(scenario abbreviations_for_address_and_array)
+:(scenarios transform)
+:(scenario type_abbreviations)
+type foo = number
 def main [
-  f 1:&number  # abbreviation for 'address:number'
-  f 2:@number  # abbreviation for 'array:number'
-  f 3:&@number  # combining '&' and '@'
-  f 4:&&@&@number  # ..any number of times
-  f 5:array:&number:3  # abbreviations take precedence over ':'
-  f {6: (array &number 3)}  # support for dilated reagents and more complex parse trees
-  f 7:@number:3  # *not* the same as array:number:3
+  a:foo <- copy 34
 ]
-+parse:   ingredient: {1: ("address" "number")}
-+parse:   ingredient: {2: ("array" "number")}
-+parse:   ingredient: {3: ("address" "array" "number")}
-+parse:   ingredient: {4: ("address" "address" "array" "address" "array" "number")}
-+parse:   ingredient: {5: ("array" ("address" "number") "3")}
-+parse:   ingredient: {6: ("array" ("address" "number") "3")}
-# not what you want
-+parse:   ingredient: {7: (("array" "number") "3")}
-
-:(scenario abbreviation_error)
++transform: product type after expanding abbreviations: "number"
+
+:(before "End Globals")
+map<string, type_tree*> Type_abbreviations, Type_abbreviations_snapshot;
+
+//:: Defining type abbreviations.
+
+:(before "End Command Handlers")
+else if (command == "type") {
+  load_type_abbreviations(in);
+}
+
+:(code)
+void load_type_abbreviations(istream& in) {
+  string new_type_name = next_word(in);
+  assert(has_data(in) || !new_type_name.empty());
+  if (!has_data(in) || new_type_name.empty()) {
+    raise << "incomplete 'type' statement; must be of the form 'type <new type name> = <type expression>'\n" << end();
+    return;
+  }
+  string arrow = next_word(in);
+  assert(has_data(in) || !arrow.empty());
+  if (arrow.empty()) {
+    raise << "incomplete 'type' statement 'type " << new_type_name << "'\n" << end();
+    return;
+  }
+  if (arrow != "=") {
+    raise << "'type' statements must be of the form 'type <new type name> = <type expression>' but got 'type " << new_type_name << ' ' << arrow << "'\n" << end();
+    return;
+  }
+  if (!has_data(in)) {
+    raise << "incomplete 'type' statement 'type " << new_type_name << " ='\n" << end();
+    return;
+  }
+  string old = next_word(in);
+  if (old.empty()) {
+    raise << "incomplete 'type' statement 'type " << new_type_name << " ='\n" << end();
+    raise << "'type' statements must be of the form 'type <new type name> = <type expression>' but got 'type " << new_type_name << ' ' << arrow << "'\n" << end();
+    return;
+  }
+  if (contains_key(Type_abbreviations, new_type_name)) {
+    raise << "'type' conflict: '" << new_type_name << "' defined as both '" << names_to_string_without_quotes(get(Type_abbreviations, new_type_name)) << "' and '" << old << "'\n" << end();
+    return;
+  }
+  trace(9990, "type") << "alias " << new_type_name << " = " << old << end();
+  type_tree* old_type = new_type_tree(old);
+  put(Type_abbreviations, new_type_name, old_type);
+}
+
+type_tree* new_type_tree(const string& x) {
+  string_tree* type_names = starts_with(x, "(") ? parse_string_tree(x) : parse_string_list(x);
+  type_tree* result = new_type_tree(type_names);
+  delete type_names;
+  expand_type_abbreviations(result);
+  return result;
+}
+
+string_tree* parse_string_list(const string& s) {
+  istringstream in(s);
+  in >> std::noskipws;
+  return parse_property_list(in);
+}
+
+:(scenario type_error1)
 % Hide_errors = true;
+type foo
++error: incomplete 'type' statement 'type foo'
+
+:(scenario type_error2)
+% Hide_errors = true;
+type foo =
++error: incomplete 'type' statement 'type foo ='
+
+:(scenario type_error3)
+% Hide_errors = true;
+type foo bar baz
++error: 'type' statements must be of the form 'type <new type name> = <type expression>' but got 'type foo bar'
+
+:(scenario type_conflict_error)
+% Hide_errors = true;
+type foo = bar
+type foo = baz
++error: 'type' conflict: 'foo' defined as both 'bar' and 'baz'
+
+:(scenario type_abbreviation_for_compound)
+type foo = address:number
 def main [
-  f 1:&&@&  # abbreviations without payload
+  a:foo <- copy 0
 ]
-+error: invalid type abbreviation &&@&
++transform: product type after expanding abbreviations: ("address" "number")
 
-:(before "End Parsing Reagent Type Property(type_names)")
-string_tree* new_type_names = replace_address_and_array_symbols(type_names);
-delete type_names;
-type_names = new_type_names;
-:(before "End Parsing Dilated Reagent Type Property(type_names)")
-string_tree* new_type_names = replace_address_and_array_symbols(type_names);
-delete type_names;
-type_names = new_type_names;
+//: cleaning up type abbreviations between tests and before exiting
 
+:(before "End save_snapshots")
+Type_abbreviations_snapshot = Type_abbreviations;
+:(before "End restore_snapshots")
+restore_type_abbreviations();
+:(before "End One-time Setup")
+atexit(clear_type_abbreviations);
 :(code)
-// simple version; lots of unnecessary allocations; always creates a new pointer
-string_tree* replace_address_and_array_symbols(string_tree* orig) {
-  if (orig == NULL) return NULL;
-  if (orig->atom)
-    return replace_address_and_array_symbols(orig->value);
-  return new string_tree(replace_address_and_array_symbols(orig->left),
-                         replace_address_and_array_symbols(orig->right));
+void restore_type_abbreviations() {
+  for (map<string, type_tree*>::iterator p = Type_abbreviations.begin(); p != Type_abbreviations.end(); ++p) {
+    if (!contains_key(Type_abbreviations_snapshot, p->first))
+      delete p->second;
+  }
+  Type_abbreviations.clear();
+  Type_abbreviations = Type_abbreviations_snapshot;
+}
+void clear_type_abbreviations() {
+  for (map<string, type_tree*>::iterator p = Type_abbreviations.begin(); p != Type_abbreviations.end(); ++p)
+    delete p->second;
+  Type_abbreviations.clear();
 }
 
-// todo: unicode
-string_tree* replace_address_and_array_symbols(const string& type_name) {
-  if (type_name.empty()) return NULL;
-  if (type_name.at(0) != '&' && type_name.at(0) != '@')
-    return new string_tree(type_name);
-  string_tree* result = NULL;
-  string_tree* curr = NULL;
-  int i = 0;
-  while (i < SIZE(type_name)) {
-    string_tree* new_node = NULL;
-    if (type_name.at(i) == '&')
-      new_node = new string_tree("address");
-    else if (type_name.at(i) == '@')
-      new_node = new string_tree("array");
-    else
-      break;
-    if (result == NULL)
-      result = curr = new string_tree(new_node, NULL);
-    else {
-      curr->right = new string_tree(new_node, NULL);
-      curr = curr->right;
+//:: A few default abbreviations.
+
+:(before "End Mu Types Initialization")
+put(Type_abbreviations, "&", new_type_tree("address"));
+put(Type_abbreviations, "@", new_type_tree("array"));
+put(Type_abbreviations, "num", new_type_tree("number"));
+put(Type_abbreviations, "bool", new_type_tree("boolean"));
+put(Type_abbreviations, "char", new_type_tree("character"));
+
+:(scenario use_type_abbreviations_when_declaring_type_abbreviations)
+type foo = &:num
+def main [
+  a:foo <- copy 0
+]
++transform: product type after expanding abbreviations: ("address" "number")
+
+//:: Expand type aliases before running.
+//: We'll do this in a transform so that we don't need to define abbreviations
+//: before we use them.
+
+:(scenario abbreviations_for_address_and_array)
+def main [
+  f 1:&:number  # abbreviation for 'address:number'
+  f 2:@:number  # abbreviation for 'array:number'
+  f 3:&:@:number  # combining '&' and '@'
+  f 4:&:&:@:&:@:number  # ..any number of times
+  f {5: (array (& number) 3)}  # support for dilated reagents and more complex parse trees
+]
+def f [
+]
++transform: --- expand type abbreviations in recipe 'main'
++transform: ingredient type after expanding abbreviations: ("address" "number")
++transform: ingredient type after expanding abbreviations: ("array" "number")
++transform: ingredient type after expanding abbreviations: ("address" "array" "number")
++transform: ingredient type after expanding abbreviations: ("address" "address" "array" "address" "array" "number")
++transform: ingredient type after expanding abbreviations: ("array" ("address" "number") "3")
+
+:(before "Transform.push_back(update_instruction_operations)")
+Transform.push_back(expand_type_abbreviations);  // idempotent
+// Begin Type Modifying Transforms
+// End Type Modifying Transforms
+
+:(code)
+void expand_type_abbreviations(const recipe_ordinal r) {
+  const recipe& caller = get(Recipe, r);
+  trace(9991, "transform") << "--- expand type abbreviations in recipe '" << caller.name << "'" << end();
+  for (int i = 0; i < SIZE(caller.steps); ++i) {
+    const instruction& inst = caller.steps.at(i);
+    trace(9991, "transform") << "instruction '" << inst.original_string << end();
+    for (long int i = 0; i < SIZE(inst.ingredients); ++i) {
+      expand_type_abbreviations(inst.ingredients.at(i).type);
+      trace(9992, "transform") << "ingredient type after expanding abbreviations: " << names_to_string(inst.ingredients.at(i).type) << end();
+    }
+    for (long int i = 0; i < SIZE(inst.products); ++i) {
+      expand_type_abbreviations(inst.products.at(i).type);
+      trace(9992, "transform") << "product type after expanding abbreviations: " << names_to_string(inst.products.at(i).type) << end();
     }
-    ++i;
   }
-  if (i < SIZE(type_name))
-    curr->right = new string_tree(type_name.substr(i));
-  else
-    raise << "invalid type abbreviation " << type_name << "\n" << end();
-  return result;
+  // End Expand Type Abbreviations(caller)
 }
 
-//:: b) extensible type abbreviations
-
-:(before "End Globals")
-map<string, type_tree*> Type_abbreviations;
+void expand_type_abbreviations(type_tree* type) {
+  if (!type) return;
+  if (!type->atom) {
+    expand_type_abbreviations(type->left);
+    expand_type_abbreviations(type->right);
+    return;
+  }
+  if (contains_key(Type_abbreviations, type->name))
+    *type = type_tree(*get(Type_abbreviations, type->name));
+}
 
diff --git a/html/020run.cc.html b/html/020run.cc.html index bf415da3..a4ddb087 100644 --- a/html/020run.cc.html +++ b/html/020run.cc.html @@ -94,10 +94,8 @@ map<string, int> run_current_routine(); } -void run_current_routine() -{ // curly on a separate line, because later layers will modify function header - while (!Current_routine->completed()) // later layers will modify condition - { +void run_current_routine() { + while (should_continue_running(Current_routine)) { // beware: later layers modify Current_routine here // Running One Instruction if (current_instruction().is_label) { ++current_step_index(); continue; } trace(Initial_callstack_depth + Trace_stream->callstack_depth, "run") << to_string(current_instruction()) << end(); @@ -140,6 +138,11 @@ map<string, int> stop_running_current_routine:; } +bool should_continue_running(const routine* current_routine) { + assert(current_routine == Current_routine); // argument passed in just to make caller readable above + return !Current_routine->completed(); +} + bool should_copy_ingredients() { // End should_copy_ingredients Special-cases return true; diff --git a/html/030container.cc.html b/html/030container.cc.html index cb41b4fd..38136c79 100644 --- a/html/030container.cc.html +++ b/html/030container.cc.html @@ -210,7 +210,7 @@ type_info t = get(Type,//: precompute Container_metadata before we need size_of //: also store a copy in each reagent in each instruction in each recipe -:(after "Begin Instruction Modifying Transforms") // needs to happen before transform_names, therefore after Type Modifying Transforms below +:(after "End Type Modifying Transforms") Transform.push_back(compute_container_sizes); :(code) void compute_container_sizes(recipe_ordinal r) { @@ -457,8 +457,9 @@ put(Recipe_ordinal,(get(Recipe, r).name) << "first ingredient of 'get' should be a container, but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); break; } - const type_tree* base_root_type = base.type->atom ? base.type : base.type->left; - if (!base_root_type->atom || base_root_type->value == 0 || !contains_key(Type, base_root_type->value) || get(Type, base_root_type->value).kind != CONTAINER) { + const type_tree* base_type = base.type; + // Update GET base_type in Check + if (!base_type->atom || base_type->value == 0 || !contains_key(Type, base_type->value) || get(Type, base_type->value).kind != CONTAINER) { raise << maybe(get(Recipe, r).name) << "first ingredient of 'get' should be a container, but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); break; } @@ -472,14 +473,14 @@ put(Recipe_ordinal,(offset.name); else offset_value = offset.value; - if (offset_value < 0 || offset_value >= SIZE(get(Type, base_root_type->value).elements)) { - raise << maybe(get(Recipe, r).name) << "invalid offset '" << offset_value << "' for '" << get(Type, base_root_type->value).name << "'\n" << end(); + if (offset_value < 0 || offset_value >= SIZE(get(Type, base_type->value).elements)) { + raise << maybe(get(Recipe, r).name) << "invalid offset '" << offset_value << "' for '" << get(Type, base_type->value).name << "'\n" << end(); break; } if (inst.products.empty()) break; reagent/*copy*/ product = inst.products.at(0); // Update GET product in Check - const reagent/*copy*/ element = element_type(base.type, offset_value); // not just base_root_type because later layers will introduce compound types + const reagent/*copy*/ element = element_type(base.type, offset_value); // not just base_type because later layers will introduce compound types if (!types_coercible(product, element)) { raise << maybe(get(Recipe, r).name) << "'get " << base.original_string << ", " << offset.original_string << "' should write to " << names_to_string_without_quotes(element.type) << " but '" << product.name << "' has type " << names_to_string_without_quotes(product.type) << '\n' << end(); break; @@ -495,13 +496,14 @@ put(Recipe_ordinal,(current_recipe_name()) << "tried to access location 0 in '" << to_original_string(current_instruction()) << "'\n" << end(); break; } - const type_tree* base_root_type = root_type(base.type); + const type_tree* base_type = base.type; + // Update GET base_type in Run int offset = ingredients.at(1).at(0); - if (offset < 0 || offset >= SIZE(get(Type, base_root_type->value).elements)) break; // copied from Check above + if (offset < 0 || offset >= SIZE(get(Type, base_type->value).elements)) break; // copied from Check above assert(base.metadata.size); int src = base_address + base.metadata.offset.at(offset); trace(9998, "run") << "address to copy is " << src << end(); - reagent/*copy*/ element = element_type(base.type, offset); // not just base_root_type because later layers will introduce compound types + reagent/*copy*/ element = element_type(base.type, offset); // not just base_type because later layers will introduce compound types element.set_value(src); trace(9998, "run") << "its type is " << names_to_string(element.type) << end(); // Read element @@ -600,8 +602,9 @@ put(Recipe_ordinal,(get(Recipe, r).name) << "first ingredient of 'put' should be a container, but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); break; } - const type_tree* base_root_type = base.type->atom ? base.type : base.type->left; - if (!base_root_type->atom || base_root_type->value == 0 || !contains_key(Type, base_root_type->value) || get(Type, base_root_type->value).kind != CONTAINER) { + const type_tree* base_type = base.type; + // Update PUT base_type in Check + if (!base_type->atom || base_type->value == 0 || !contains_key(Type, base_type->value) || get(Type, base_type->value).kind != CONTAINER) { raise << maybe(get(Recipe, r).name) << "first ingredient of 'put' should be a container, but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); break; } @@ -614,8 +617,8 @@ put(Recipe_ordinal,int offset_value = 0; if (is_integer(offset.name)) { // later layers permit non-integer offsets offset_value = to_integer(offset.name); - if (offset_value < 0 || offset_value >= SIZE(get(Type, base_root_type->value).elements)) { - raise << maybe(get(Recipe, r).name) << "invalid offset '" << offset_value << "' for '" << get(Type, base_root_type->value).name << "'\n" << end(); + if (offset_value < 0 || offset_value >= SIZE(get(Type, base_type->value).elements)) { + raise << maybe(get(Recipe, r).name) << "invalid offset '" << offset_value << "' for '" << get(Type, base_type->value).name << "'\n" << end(); break; } } @@ -623,7 +626,7 @@ put(Recipe_ordinal,.value; } const reagent& value = inst.ingredients.at(2); - const reagent& element = element_type(base.type, offset_value); // not just base_root_type because later layers will introduce compound types + const reagent& element = element_type(base.type, offset_value); // not just base_type because later layers will introduce compound types if (!types_coercible(element, value)) { raise << maybe(get(Recipe, r).name) << "'put " << base.original_string << ", " << offset.original_string << "' should write to " << names_to_string_without_quotes(element.type) << " but '" << value.name << "' has type " << names_to_string_without_quotes(value.type) << '\n' << end(); break; @@ -645,9 +648,10 @@ put(Recipe_ordinal,(current_recipe_name()) << "tried to access location 0 in '" << to_original_string(current_instruction()) << "'\n" << end(); break; } - const type_tree* base_root_type = root_type(base.type); + const type_tree* base_type = base.type; + // Update PUT base_type in Run int offset = ingredients.at(1).at(0); - if (offset < 0 || offset >= SIZE(get(Type, base_root_type->value).elements)) break; // copied from Check above + if (offset < 0 || offset >= SIZE(get(Type, base_type->value).elements)) break; // copied from Check above int address = base_address + base.metadata.offset.at(offset); trace(9998, "run") << "address to copy to is " << address << end(); // optimization: directly write the element rather than updating 'product' @@ -813,8 +817,33 @@ container foo [ ] +error: container 'foo' contains multiple elements on a single line. Containers and exclusive containers must only contain elements, one to a line, no code. -//: ensure scenarios are consistent by always starting them at the same type -//: number. +//: support type abbreviations in container definitions + +:(scenario type_abbreviations_in_containers) +type foo = number +container bar [ + x:foo +] +def main [ + 1:number <- copy 34 + 2:foo <- get 1:bar/unsafe, 0:offset +] ++mem: storing 34 in location 2 + +:(after "Transform.push_back(expand_type_abbreviations)") +Transform.push_back(expand_type_abbreviations_in_containers); +:(code) +// extremely inefficient; we process all types over and over again, once for every single recipe +// but it doesn't seem to cause any noticeable slowdown +void expand_type_abbreviations_in_containers(unused const recipe_ordinal r) { + for (map<type_ordinal, type_info>::iterator p = Type.begin(); p != Type.end(); ++p) { + for (int i = 0; i < SIZE(p->second.elements); ++i) + expand_type_abbreviations(p->second.elements.at(i).type); + } +} + +//: ensure scenarios are consistent by always starting new container +//: declarations at the same type number :(before "End Setup") //: for tests Next_type_ordinal = 1000; :(before "End Test Run Initialization") @@ -856,10 +885,8 @@ container bar [ ] $error: 0 -:(after "Begin Instruction Modifying Transforms") -// Begin Type Modifying Transforms +:(before "End Type Modifying Transforms") Transform.push_back(check_or_set_invalid_types); // idempotent -// End Type Modifying Transforms :(code) void check_or_set_invalid_types(const recipe_ordinal r) { diff --git a/html/033exclusive_container.cc.html b/html/033exclusive_container.cc.html index 5068a365..01cdfbfb 100644 --- a/html/033exclusive_container.cc.html +++ b/html/033exclusive_container.cc.html @@ -144,8 +144,9 @@ put(Recipe_ordinal,(caller.name) << "first ingredient of 'maybe-convert' should be an exclusive-container, but got '" << base.original_string << "'\n" << end(); break; } - const type_tree* root_type = base.type->atom ? base.type : base.type->left; - if (!root_type->atom || root_type->value == 0 || !contains_key(Type, root_type->value) || get(Type, root_type->value).kind != EXCLUSIVE_CONTAINER) { + const type_tree* base_type = base.type; + // Update MAYBE_CONVERT base_type in Check + if (!base_type->atom || base_type->value == 0 || !contains_key(Type, base_type->value) || get(Type, base_type->value).kind != EXCLUSIVE_CONTAINER) { raise << maybe(caller.name) << "first ingredient of 'maybe-convert' should be an exclusive-container, but got '" << base.original_string << "'\n" << end(); break; } @@ -162,7 +163,7 @@ put(Recipe_ordinal,// Update MAYBE_CONVERT product in Check reagent& offset = inst.ingredients.at(1); populate_value(offset); - if (offset.value >= SIZE(get(Type, root_type->value).elements)) { + if (offset.value >= SIZE(get(Type, base_type->value).elements)) { raise << maybe(caller.name) << "invalid tag " << offset.value << " in '" << inst.original_string << '\n' << end(); break; } diff --git a/html/035lookup.cc.html b/html/035lookup.cc.html index 43b6ffb1..a06d93c6 100644 --- a/html/035lookup.cc.html +++ b/html/035lookup.cc.html @@ -515,7 +515,7 @@ def main [ :(before "End Parsing reagent") { - while (!name.empty() && name.at(0) == '*') { + while (starts_with(name, "*")) { name.erase(0, 1); properties.push_back(pair<string, string_tree*>("lookup", NULL)); } diff --git a/html/041jump_target.cc.html b/html/041jump_target.cc.html index 045e3680..8fb25054 100644 --- a/html/041jump_target.cc.html +++ b/html/041jump_target.cc.html @@ -61,7 +61,7 @@ Transform.push_back(
, int> offset; for (int i = 0; i < SIZE(get(Recipe, r).steps); ++i) { const instruction& inst = get(Recipe, r).steps.at(i); - if (!inst.label.empty() && inst.label.at(0) == '+') { + if (starts_with(inst.label, "+")) { if (!contains_key(offset, inst.label)) { put(offset, inst.label, i); } @@ -123,7 +123,7 @@ Transform.push_back(} bool is_jump_target(string label) { - return label.at(0) == '+'; + return starts_with(label, "+"); } :(scenario break_to_label) diff --git a/html/047check_type_by_name.cc.html b/html/047check_type_by_name.cc.html index 507c7c2d..c7927417 100644 --- a/html/047check_type_by_name.cc.html +++ b/html/047check_type_by_name.cc.html @@ -48,7 +48,7 @@ def main [ ] +error: main: 'x' used with multiple types -:(after "Begin Instruction Modifying Transforms") +:(after "Transform.push_back(expand_type_abbreviations)") Transform.push_back(check_or_set_types_by_name); // idempotent :(code) diff --git a/html/050scenario.cc.html b/html/050scenario.cc.html index 7281a95b..7554e95a 100644 --- a/html/050scenario.cc.html +++ b/html/050scenario.cc.html @@ -121,7 +121,7 @@ scenario parse_scenario(istream& in// inside comments result.to_run = slurp_quoted(in); // delete [] delimiters - assert(result.to_run.at(0) == '['); + assert(starts_with(result.to_run, "[")); result.to_run.erase(0, 1); assert(result.to_run.at(SIZE(result.to_run)-1) == ']'); result.to_run.erase(SIZE(result.to_run)-1); diff --git a/html/053recipe_header.cc.html b/html/053recipe_header.cc.html index 3d785dc4..aa26c35c 100644 --- a/html/053recipe_header.cc.html +++ b/html/053recipe_header.cc.html @@ -179,6 +179,28 @@ def test [ trace(9999, "parse") << "recipe " << result.name << " has a header" << end(); } +//: Support type abbreviations in headers. + +:(scenario type_abbreviations_in_recipe_headers) +type string = address:array:character +def main [ + local-scope + a:string <- foo + 1:character/raw <- index *a, 0 +] +def foo -> a:string [ + local-scope + load-ingredients + a <- new [abc] +] ++mem: storing 97 in location 1 + +:(before "End Expand Type Abbreviations(caller)") +for (long int i = 0; i < SIZE(caller.ingredients); ++i) + expand_type_abbreviations(caller.ingredients.at(i).type); +for (long int i = 0; i < SIZE(caller.products); ++i) + expand_type_abbreviations(caller.products.at(i).type); + //: Rewrite 'load-ingredients' to instructions to create all reagents in the header. :(before "End Rewrite Instruction(curr, recipe result)") @@ -258,8 +280,8 @@ def foo x:number -> y:number [ Transform.push_back(check_calls_against_header); // idempotent :(code) void check_calls_against_header(const recipe_ordinal r) { - trace(9991, "transform") << "--- type-check calls inside recipe " << get(Recipe, r).name << end(); const recipe& caller = get(Recipe, r); + trace(9991, "transform") << "--- type-check calls inside recipe " << caller.name << end(); for (int i = 0; i < SIZE(caller.steps); ++i) { const instruction& inst = caller.steps.at(i); if (inst.operation < MAX_PRIMITIVE_RECIPES) continue; diff --git a/html/054static_dispatch.cc.html b/html/054static_dispatch.cc.html index d47162c6..8e4e06cb 100644 --- a/html/054static_dispatch.cc.html +++ b/html/054static_dispatch.cc.html @@ -103,14 +103,16 @@ string matching_variant_name(if (SIZE(r1.ingredients) != SIZE(r2.ingredients)) return false; if (SIZE(r1.products) != SIZE(r2.products)) return false; for (int i = 0; i < SIZE(r1.ingredients); ++i) { - if (!deeply_equal_type_names(r1.ingredients.at(i), r2.ingredients.at(i))) { + expand_type_abbreviations(r1.ingredients.at(i).type); + expand_type_abbreviations(r2.ingredients.at(i).type); + if (!deeply_equal_type_names(r1.ingredients.at(i), r2.ingredients.at(i))) return false; - } } for (int i = 0; i < SIZE(r1.products); ++i) { - if (!deeply_equal_type_names(r1.products.at(i), r2.products.at(i))) { + expand_type_abbreviations(r1.products.at(i).type); + expand_type_abbreviations(r2.products.at(i).type); + if (!deeply_equal_type_names(r1.products.at(i), r2.products.at(i))) return false; - } } return true; } @@ -646,6 +648,22 @@ def foo a:boolean -> b:number [ +error: main: missing type for 'x' in 'y:number <- foo x' +error: main: failed to find a matching call for 'y:number <- foo x' +:(scenario override_methods_with_type_abbreviations) +type string = address:array:character +def main [ + local-scope + s:address:array:character <- new [abc] + 1:number/raw <- foo s +] +def foo a:address:array:character -> result:number [ + return 34 +] +# identical to previous variant once you take type abbreviation into account +def! foo a:string -> result:number [ + return 35 +] ++mem: storing 35 in location 1 + :(before "End Includes") using std::abs; diff --git a/html/055shape_shifting_container.cc.html b/html/055shape_shifting_container.cc.html index cb17f5bb..d6bc71c3 100644 --- a/html/055shape_shifting_container.cc.html +++ b/html/055shape_shifting_container.cc.html @@ -44,6 +44,17 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color :(before "End is_mu_exclusive_container(type) Special-cases") if (!type->atom) return is_mu_exclusive_container(root_type(type)); +// a few calls to root_type() without the assertion (for better error handling) +:(after "Update GET base_type in Check") +if (!base_type->atom) base_type = base_type->left; +:(after "Update GET base_type in Run") +if (!base_type->atom) base_type = base_type->left; +:(after "Update PUT base_type in Check") +if (!base_type->atom) base_type = base_type->left; +:(after "Update PUT base_type in Run") +if (!base_type->atom) base_type = base_type->left; +:(after "Update MAYBE_CONVERT base_type in Check") +if (!base_type->atom) base_type = base_type->left; :(scenario size_of_shape_shifting_container) container foo:_t [ @@ -187,7 +198,7 @@ map<string, type_ordinal> type_ingredient_n raise << container_name << ": empty type ingredients not permitted\n" << end(); return false; } - if (curr.at(0) != '_') { + if (!starts_with(curr, "_")) { raise << container_name << ": type ingredient '" << curr << "' must begin with an underscore\n" << end(); return false; } @@ -216,7 +227,7 @@ map<string, type_ordinal> type_ingredient_n } :(code) bool is_type_ingredient_name(const string& type) { - return !type.empty() && type.at(0) == '_'; + return starts_with(type, "_"); } :(before "End Container Type Checks") diff --git a/html/056shape_shifting_recipe.cc.html b/html/056shape_shifting_recipe.cc.html index f03430ff..347be81a 100644 --- a/html/056shape_shifting_recipe.cc.html +++ b/html/056shape_shifting_recipe.cc.html @@ -62,8 +62,13 @@ def foo a:_t -> result:_t [ //: be rewriting such instructions to *specializations* with the type //: ingredients filled in. +//: One exception (and this makes things very ugly): we need to expand type +//: abbreviations in shape-shifting recipes because we need them types for +//: deciding which variant to specialize. + :(before "End Transform Checks") -if (any_type_ingredient_in_header(/*recipe_ordinal*/p->first)) continue; +r.transformed_until = t; +if (Transform.at(t) != static_cast<transform_fn>(expand_type_abbreviations) && any_type_ingredient_in_header(/*recipe_ordinal*/p->first)) continue; :(after "Running One Instruction") if (Current_routine->calls.front().running_step_index == 0 diff --git a/html/058to_text.cc.html b/html/058to_text.cc.html new file mode 100644 index 00000000..c79ad7fc --- /dev/null +++ b/html/058to_text.cc.html @@ -0,0 +1,62 @@ + + + + +Mu - 058to_text.cc + + + + + + + + + + +
+//: Primitive to convert any type to text (array of characters).
+//: Later layers will allow us to override this to do something smarter for
+//: specific types.
+
+:(before "End Mu Types Initialization")
+put(Type_abbreviations, "text", new_type_tree("address:array:character"));
+
+:(before "End Primitive Recipe Declarations")
+TO_TEXT,
+:(before "End Primitive Recipe Numbers")
+put(Recipe_ordinal, "to-text", TO_TEXT);
+:(before "End Primitive Recipe Checks")
+case TO_TEXT: {
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(get(Recipe, r).name) << "'to-text' requires a single ingredient, but got '" << inst.original_string << "'\n" << end();
+    break;
+  }
+  // can handle any type
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case TO_TEXT: {
+  products.resize(1);
+  products.at(0).push_back(new_mu_string(print_mu(current_instruction().ingredients.at(0), ingredients.at(0))));
+  break;
+}
+
+ + + diff --git a/html/059to_text.mu.html b/html/059to_text.mu.html new file mode 100644 index 00000000..deaacdf7 --- /dev/null +++ b/html/059to_text.mu.html @@ -0,0 +1,66 @@ + + + + +Mu - 059to_text.mu + + + + + + + + + + +
+# A couple of variants of `to-text` that we'll use implicitly in stashes (see
+# later layers).
+#
+# Mu code might specialize them to be smarter, but I don't anticipate any need
+# beyond specializing `to-text` itself.
+
+# 'shorter' variant of to-text, when you want to enable some sort of trimming
+# define it to be identical to 'to-text' by default
+def to-text-line x:_elem -> y:text [
+  local-scope
+  load-ingredients
+  y <- to-text x
+]
+
+# variant for arrays (since we can't pass them around otherwise)
+def array-to-text-line x:address:array:_elem -> y:text [
+  local-scope
+  load-ingredients
+  y <- to-text *x
+]
+
+scenario to-text-line-early-warning-for-static-dispatch [
+  x:text <- to-text-line 34
+  # just ensure there were no errors
+]
+
+scenario array-to-text-line-early-warning-for-static-dispatch [
+  n:address:array:number <- new number:type, 3
+  x:text <- array-to-text-line n
+  # just ensure there were no errors
+]
+
+ + + diff --git a/html/061text.mu.html b/html/061text.mu.html index 268d4275..e1a99fc8 100644 --- a/html/061text.mu.html +++ b/html/061text.mu.html @@ -34,22 +34,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 # Some useful helpers for dealing with text (arrays of characters)
 
-# to-text-line gets called implicitly in various places
-# define it to be identical to 'to-text' by default
-def to-text-line x:_elem -> y:address:array:character [
-  local-scope
-  load-ingredients
-  y <- to-text x
-]
-
-# variant for arrays (since we can't pass them around otherwise)
-def array-to-text-line x:address:array:_elem -> y:address:array:character [
-  local-scope
-  load-ingredients
-  y <- to-text *x
-]
-
-def equal a:address:array:character, b:address:array:character -> result:boolean [
+def equal a:text, b:text -> result:boolean [
   local-scope
   load-ingredients
   a-len:number <- length *a
@@ -83,7 +68,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-equal-reflexive [
   run [
     local-scope
-    x:address:array:character <- new [abc]
+    x:text <- new [abc]
     10:boolean/raw <- equal x, x
   ]
   memory-should-contain [
@@ -94,8 +79,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-equal-identical [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new [abc]
+    x:text <- new [abc]
+    y:text <- new [abc]
     10:boolean/raw <- equal x, y
   ]
   memory-should-contain [
@@ -106,8 +91,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-equal-distinct-lengths [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new [abcd]
+    x:text <- new [abc]
+    y:text <- new [abcd]
     10:boolean/raw <- equal x, y
   ]
   memory-should-contain [
@@ -124,8 +109,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-equal-with-empty [
   run [
     local-scope
-    x:address:array:character <- new []
-    y:address:array:character <- new [abcd]
+    x:text <- new []
+    y:text <- new [abcd]
     10:boolean/raw <- equal x, y
   ]
   memory-should-contain [
@@ -136,8 +121,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-equal-common-lengths-but-distinct [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new [abd]
+    x:text <- new [abc]
+    y:text <- new [abd]
     10:boolean/raw <- equal x, y
   ]
   memory-should-contain [
@@ -148,7 +133,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 # A new type to help incrementally construct texts.
 container buffer [
   length:number
-  data:address:array:character
+  data:text
 ]
 
 def new-buffer capacity:number -> result:address:buffer [
@@ -161,7 +146,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
     # capacity not provided
     capacity <- copy 10
   }
-  data:address:array:character <- new character:type, capacity
+  data:text <- new character:type, capacity
   *result <- put *result, data:offset, data
   return result
 ]
@@ -170,10 +155,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   local-scope
   load-ingredients
   # double buffer size
-  olddata:address:array:character <- get *in, data:offset
+  olddata:text <- get *in, data:offset
   oldlen:number <- length *olddata
   newlen:number <- multiply oldlen, 2
-  newdata:address:array:character <- new character:type, newlen
+  newdata:text <- new character:type, newlen
   *in <- put *in, data:offset, newdata
   # copy old contents
   i:number <- copy 0
@@ -191,7 +176,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   local-scope
   load-ingredients
   len:number <- get *in, length:offset
-  s:address:array:character <- get *in, data:offset
+  s:text <- get *in, data:offset
   capacity:number <- length *s
   result <- greater-or-equal len, capacity
 ]
@@ -200,7 +185,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 def append buf:address:buffer, x:_elem -> buf:address:buffer [
   local-scope
   load-ingredients
-  text:address:array:character <- to-text x
+  text:text <- to-text x
   len:number <- length *text
   i:number <- copy 0
   {
@@ -233,7 +218,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
     break-unless full?
     in <- grow-buffer in
   }
-  s:address:array:character <- get *in, data:offset
+  s:text <- get *in, data:offset
   *s <- put-index *s, len, c
   len <- add len, 1
   *in <- put *in, length:offset, len
@@ -243,20 +228,20 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   run [
     local-scope
     x:address:buffer <- new-buffer 3
-    s1:address:array:character <- get *x, data:offset
+    s1:text <- get *x, data:offset
     c:character <- copy 97/a
     x <- append x, c
     c:character <- copy 98/b
     x <- append x, c
     c:character <- copy 99/c
     x <- append x, c
-    s2:address:array:character <- get *x, data:offset
+    s2:text <- get *x, data:offset
     10:boolean/raw <- equal s1, s2
     11:array:character/raw <- copy *s2
     +buffer-filled
     c:character <- copy 100/d
     x <- append x, c
-    s3:address:array:character <- get *x, data:offset
+    s3:text <- get *x, data:offset
     20:boolean/raw <- equal s1, s3
     21:number/raw <- get *x, length:offset
     30:array:character/raw <- copy *s3
@@ -300,7 +285,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
     x <- append x, c
     c:character <- copy 8/backspace
     x <- append x, c
-    s:address:array:character <- buffer-to-array x
+    s:text <- buffer-to-array x
     10:array:character/raw <- copy *s
   ]
   memory-should-contain [
@@ -310,7 +295,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   ]
 ]
 
-def buffer-to-array in:address:buffer -> result:address:array:character [
+def buffer-to-array in:address:buffer -> result:text [
   local-scope
   load-ingredients
   {
@@ -319,7 +304,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
     return 0
   }
   len:number <- get *in, length:offset
-  s:address:array:character <- get *in, data:offset
+  s:text <- get *in, data:offset
   # we can't just return s because it is usually the wrong length
   result <- new character:type, len
   i:number <- copy 0
@@ -333,7 +318,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   }
 ]
 
-def append a:address:array:character, b:address:array:character -> result:address:array:character [
+def append a:text, b:text -> result:text [
   local-scope
   load-ingredients
   # handle null addresses
@@ -376,9 +361,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-append-1 [
   run [
     local-scope
-    x:address:array:character <- new [hello,]
-    y:address:array:character <- new [ world!]
-    z:address:array:character <- append x, y
+    x:text <- new [hello,]
+    y:text <- new [ world!]
+    z:text <- append x, y
     10:array:character/raw <- copy *z
   ]
   memory-should-contain [
@@ -389,9 +374,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-append-null [
   run [
     local-scope
-    x:address:array:character <- copy 0
-    y:address:array:character <- new [ world!]
-    z:address:array:character <- append x, y
+    x:text <- copy 0
+    y:text <- new [ world!]
+    z:text <- append x, y
     10:array:character/raw <- copy *z
   ]
   memory-should-contain [
@@ -402,9 +387,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-append-null-2 [
   run [
     local-scope
-    x:address:array:character <- new [hello,]
-    y:address:array:character <- copy 0
-    z:address:array:character <- append x, y
+    x:text <- new [hello,]
+    y:text <- copy 0
+    z:text <- append x, y
     10:array:character/raw <- copy *z
   ]
   memory-should-contain [
@@ -415,7 +400,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario replace-character-in-text [
   run [
     local-scope
-    x:address:array:character <- new [abc]
+    x:text <- new [abc]
     x <- replace x, 98/b, 122/z
     10:array:character/raw <- copy *x
   ]
@@ -424,7 +409,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   ]
 ]
 
-def replace s:address:array:character, oldc:character, newc:character, from:number/optional -> s:address:array:character [
+def replace s:text, oldc:character, newc:character, from:number/optional -> s:text [
   local-scope
   load-ingredients
   len:number <- length *s
@@ -439,7 +424,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario replace-character-at-start [
   run [
     local-scope
-    x:address:array:character <- new [abc]
+    x:text <- new [abc]
     x <- replace x, 97/a, 122/z
     10:array:character/raw <- copy *x
   ]
@@ -451,7 +436,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario replace-character-at-end [
   run [
     local-scope
-    x:address:array:character <- new [abc]
+    x:text <- new [abc]
     x <- replace x, 99/c, 122/z
     10:array:character/raw <- copy *x
   ]
@@ -463,7 +448,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario replace-character-missing [
   run [
     local-scope
-    x:address:array:character <- new [abc]
+    x:text <- new [abc]
     x <- replace x, 100/d, 122/z
     10:array:character/raw <- copy *x
   ]
@@ -475,7 +460,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario replace-all-characters [
   run [
     local-scope
-    x:address:array:character <- new [banana]
+    x:text <- new [banana]
     x <- replace x, 97/a, 122/z
     10:array:character/raw <- copy *x
   ]
@@ -485,7 +470,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 ]
 
 # replace underscores in first with remaining args
-def interpolate template:address:array:character -> result:address:array:character [
+def interpolate template:text -> result:text [
   local-scope
   load-ingredients  # consume just the template
   # compute result-len, space to allocate for result
@@ -493,7 +478,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   result-len:number <- copy tem-len
   {
     # while ingredients remain
-    a:address:array:character, arg-received?:boolean <- next-ingredient
+    a:text, arg-received?:boolean <- next-ingredient
     break-unless arg-received?
     # result-len = result-len + arg.length - 1 (for the 'underscore' being replaced)
     a-len:number <- length *a
@@ -509,7 +494,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   i:number <- copy 0
   {
     # while arg received
-    a:address:array:character, arg-received?:boolean <- next-ingredient
+    a:text, arg-received?:boolean <- next-ingredient
     break-unless arg-received?
     # copy template into result until '_'
     {
@@ -561,9 +546,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario interpolate-works [
   run [
     local-scope
-    x:address:array:character <- new [abc_ghi]
-    y:address:array:character <- new [def]
-    z:address:array:character <- interpolate x, y
+    x:text <- new [abc_ghi]
+    y:text <- new [def]
+    z:text <- interpolate x, y
     10:array:character/raw <- copy *z
   ]
   memory-should-contain [
@@ -574,9 +559,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario interpolate-at-start [
   run [
     local-scope
-    x:address:array:character <- new [_, hello!]
-    y:address:array:character <- new [abc]
-    z:address:array:character <- interpolate x, y
+    x:text <- new [_, hello!]
+    y:text <- new [abc]
+    z:text <- interpolate x, y
     10:array:character/raw <- copy *z
   ]
   memory-should-contain [
@@ -587,9 +572,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 
 scenario interpolate-at-end [
   run [
-    x:address:array:character <- new [hello, _]
-    y:address:array:character <- new [abc]
-    z:address:array:character <- interpolate x, y
+    x:text <- new [hello, _]
+    y:text <- new [abc]
+    z:text <- interpolate x, y
     10:array:character/raw <- copy *z
   ]
   memory-should-contain [
@@ -659,7 +644,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   result <- equal c, 12288/ideographic-space
 ]
 
-def trim s:address:array:character -> result:address:array:character [
+def trim s:text -> result:text [
   local-scope
   load-ingredients
   len:number <- length *s
@@ -691,7 +676,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   }
   # result = new character[end+1 - start]
   new-len:number <- subtract end, start, -1
-  result:address:array:character <- new character:type, new-len
+  result:text <- new character:type, new-len
   # copy the untrimmed parts between start and end
   i:number <- copy start
   j:number <- copy 0
@@ -711,8 +696,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario trim-unmodified [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- trim x
+    x:text <- new [abc]
+    y:text <- trim x
     1:array:character/raw <- copy *y
   ]
   memory-should-contain [
@@ -723,8 +708,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario trim-left [
   run [
     local-scope
-    x:address:array:character <- new [  abc]
-    y:address:array:character <- trim x
+    x:text <- new [  abc]
+    y:text <- trim x
     1:array:character/raw <- copy *y
   ]
   memory-should-contain [
@@ -735,8 +720,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario trim-right [
   run [
     local-scope
-    x:address:array:character <- new [abc  ]
-    y:address:array:character <- trim x
+    x:text <- new [abc  ]
+    y:text <- trim x
     1:array:character/raw <- copy *y
   ]
   memory-should-contain [
@@ -747,8 +732,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario trim-left-right [
   run [
     local-scope
-    x:address:array:character <- new [  abc   ]
-    y:address:array:character <- trim x
+    x:text <- new [  abc   ]
+    y:text <- trim x
     1:array:character/raw <- copy *y
   ]
   memory-should-contain [
@@ -759,9 +744,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario trim-newline-tab [
   run [
     local-scope
-    x:address:array:character <- new [  abc
+    x:text <- new [ abc
 ]
-    y:address:array:character <- trim x
+    y:text <- trim x
     1:array:character/raw <- copy *y
   ]
   memory-should-contain [
@@ -769,7 +754,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   ]
 ]
 
-def find-next text:address:array:character, pattern:character, idx:number -> next-index:number [
+def find-next text:text, pattern:character, idx:number -> next-index:number [
   local-scope
   load-ingredients
   len:number <- length *text
@@ -788,7 +773,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-find-next [
   run [
     local-scope
-    x:address:array:character <- new [a/b]
+    x:text <- new [a/b]
     10:number/raw <- find-next x, 47/slash, 0/start-index
   ]
   memory-should-contain [
@@ -799,7 +784,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-find-next-empty [
   run [
     local-scope
-    x:address:array:character <- new []
+    x:text <- new []
     10:number/raw <- find-next x, 47/slash, 0/start-index
   ]
   memory-should-contain [
@@ -810,7 +795,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-find-next-initial [
   run [
     local-scope
-    x:address:array:character <- new [/abc]
+    x:text <- new [/abc]
     10:number/raw <- find-next x, 47/slash, 0/start-index
   ]
   memory-should-contain [
@@ -821,7 +806,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-find-next-final [
   run [
     local-scope
-    x:address:array:character <- new [abc/]
+    x:text <- new [abc/]
     10:number/raw <- find-next x, 47/slash, 0/start-index
   ]
   memory-should-contain [
@@ -832,7 +817,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-find-next-missing [
   run [
     local-scope
-    x:address:array:character <- new [abcd]
+    x:text <- new [abcd]
     10:number/raw <- find-next x, 47/slash, 0/start-index
   ]
   memory-should-contain [
@@ -843,7 +828,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-find-next-invalid-index [
   run [
     local-scope
-    x:address:array:character <- new [abc]
+    x:text <- new [abc]
     10:number/raw <- find-next x, 47/slash, 4/start-index
   ]
   memory-should-contain [
@@ -854,7 +839,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-find-next-first [
   run [
     local-scope
-    x:address:array:character <- new [ab/c/]
+    x:text <- new [ab/c/]
     10:number/raw <- find-next x, 47/slash, 0/start-index
   ]
   memory-should-contain [
@@ -865,7 +850,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-find-next-second [
   run [
     local-scope
-    x:address:array:character <- new [ab/c/]
+    x:text <- new [ab/c/]
     10:number/raw <- find-next x, 47/slash, 3/start-index
   ]
   memory-should-contain [
@@ -875,7 +860,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 
 # search for a pattern of multiple characters
 # fairly dumb algorithm
-def find-next text:address:array:character, pattern:address:array:character, idx:number -> next-index:number [
+def find-next text:text, pattern:text, idx:number -> next-index:number [
   local-scope
   load-ingredients
   first:character <- index *pattern, 0
@@ -898,8 +883,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario find-next-text-1 [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new [bc]
+    x:text <- new [abc]
+    y:text <- new [bc]
     10:number/raw <- find-next x, y, 0
   ]
   memory-should-contain [
@@ -910,8 +895,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario find-next-text-2 [
   run [
     local-scope
-    x:address:array:character <- new [abcd]
-    y:address:array:character <- new [bc]
+    x:text <- new [abcd]
+    y:text <- new [bc]
     10:number/raw <- find-next x, y, 1
   ]
   memory-should-contain [
@@ -922,8 +907,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario find-next-no-match [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new [bd]
+    x:text <- new [abc]
+    y:text <- new [bd]
     10:number/raw <- find-next x, y, 0
   ]
   memory-should-contain [
@@ -934,8 +919,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario find-next-suffix-match [
   run [
     local-scope
-    x:address:array:character <- new [abcd]
-    y:address:array:character <- new [cd]
+    x:text <- new [abcd]
+    y:text <- new [cd]
     10:number/raw <- find-next x, y, 0
   ]
   memory-should-contain [
@@ -946,8 +931,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario find-next-suffix-match-2 [
   run [
     local-scope
-    x:address:array:character <- new [abcd]
-    y:address:array:character <- new [cde]
+    x:text <- new [abcd]
+    y:text <- new [cde]
     10:number/raw <- find-next x, y, 0
   ]
   memory-should-contain [
@@ -956,7 +941,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 ]
 
 # checks if pattern matches at index 'idx'
-def match-at text:address:array:character, pattern:address:array:character, idx:number -> result:boolean [
+def match-at text:text, pattern:text, idx:number -> result:boolean [
   local-scope
   load-ingredients
   pattern-len:number <- length *pattern
@@ -990,8 +975,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario match-at-checks-pattern-at-index [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new [ab]
+    x:text <- new [abc]
+    y:text <- new [ab]
     10:boolean/raw <- match-at x, y, 0
   ]
   memory-should-contain [
@@ -1002,7 +987,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario match-at-reflexive [
   run [
     local-scope
-    x:address:array:character <- new [abc]
+    x:text <- new [abc]
     10:boolean/raw <- match-at x, x, 0
   ]
   memory-should-contain [
@@ -1013,8 +998,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario match-at-outside-bounds [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new [a]
+    x:text <- new [abc]
+    y:text <- new [a]
     10:boolean/raw <- match-at x, y, 4
   ]
   memory-should-contain [
@@ -1025,8 +1010,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario match-at-empty-pattern [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new []
+    x:text <- new [abc]
+    y:text <- new []
     10:boolean/raw <- match-at x, y, 0
   ]
   memory-should-contain [
@@ -1037,8 +1022,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario match-at-empty-pattern-outside-bound [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new []
+    x:text <- new [abc]
+    y:text <- new []
     10:boolean/raw <- match-at x, y, 4
   ]
   memory-should-contain [
@@ -1049,8 +1034,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario match-at-empty-text [
   run [
     local-scope
-    x:address:array:character <- new []
-    y:address:array:character <- new [abc]
+    x:text <- new []
+    y:text <- new [abc]
     10:boolean/raw <- match-at x, y, 0
   ]
   memory-should-contain [
@@ -1061,7 +1046,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario match-at-empty-against-empty [
   run [
     local-scope
-    x:address:array:character <- new []
+    x:text <- new []
     10:boolean/raw <- match-at x, x, 0
   ]
   memory-should-contain [
@@ -1072,8 +1057,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario match-at-inside-bounds [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new [bc]
+    x:text <- new [abc]
+    y:text <- new [bc]
     10:boolean/raw <- match-at x, y, 1
   ]
   memory-should-contain [
@@ -1084,8 +1069,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario match-at-inside-bounds-2 [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- new [bc]
+    x:text <- new [abc]
+    y:text <- new [bc]
     10:boolean/raw <- match-at x, y, 0
   ]
   memory-should-contain [
@@ -1093,7 +1078,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   ]
 ]
 
-def split s:address:array:character, delim:character -> result:address:array:address:array:character [
+def split s:text, delim:character -> result:address:array:text [
   local-scope
   load-ingredients
   # empty text? return empty array
@@ -1126,7 +1111,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
     break-if done?
     end:number <- find-next s, delim, start
     # copy start..end into result[curr-result]
-    dest:address:array:character <- copy-range s, start, end
+    dest:text <- copy-range s, start, end
     *result <- put-index *result, curr-result, dest
     # slide over to next slice
     start <- add end, 1
@@ -1138,11 +1123,11 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-split-1 [
   run [
     local-scope
-    x:address:array:character <- new [a/b]
-    y:address:array:address:array:character <- split x, 47/slash
+    x:text <- new [a/b]
+    y:address:array:text <- split x, 47/slash
     10:number/raw <- length *y
-    a:address:array:character <- index *y, 0
-    b:address:array:character <- index *y, 1
+    a:text <- index *y, 0
+    b:text <- index *y, 1
     20:array:character/raw <- copy *a
     30:array:character/raw <- copy *b
   ]
@@ -1156,12 +1141,12 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-split-2 [
   run [
     local-scope
-    x:address:array:character <- new [a/b/c]
-    y:address:array:address:array:character <- split x, 47/slash
+    x:text <- new [a/b/c]
+    y:address:array:text <- split x, 47/slash
     10:number/raw <- length *y
-    a:address:array:character <- index *y, 0
-    b:address:array:character <- index *y, 1
-    c:address:array:character <- index *y, 2
+    a:text <- index *y, 0
+    b:text <- index *y, 1
+    c:text <- index *y, 2
     20:array:character/raw <- copy *a
     30:array:character/raw <- copy *b
     40:array:character/raw <- copy *c
@@ -1177,10 +1162,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-split-missing [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:address:array:character <- split x, 47/slash
+    x:text <- new [abc]
+    y:address:array:text <- split x, 47/slash
     10:number/raw <- length *y
-    a:address:array:character <- index *y, 0
+    a:text <- index *y, 0
     20:array:character/raw <- copy *a
   ]
   memory-should-contain [
@@ -1192,8 +1177,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-split-empty [
   run [
     local-scope
-    x:address:array:character <- new []
-    y:address:array:address:array:character <- split x, 47/slash
+    x:text <- new []
+    y:address:array:text <- split x, 47/slash
     10:number/raw <- length *y
   ]
   memory-should-contain [
@@ -1204,13 +1189,13 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-split-empty-piece [
   run [
     local-scope
-    x:address:array:character <- new [a/b//c]
-    y:address:array:address:array:character <- split x:address:array:character, 47/slash
+    x:text <- new [a/b//c]
+    y:address:array:text <- split x:text, 47/slash
     10:number/raw <- length *y
-    a:address:array:character <- index *y, 0
-    b:address:array:character <- index *y, 1
-    c:address:array:character <- index *y, 2
-    d:address:array:character <- index *y, 3
+    a:text <- index *y, 0
+    b:text <- index *y, 1
+    c:text <- index *y, 2
+    d:text <- index *y, 3
     20:array:character/raw <- copy *a
     30:array:character/raw <- copy *b
     40:array:character/raw <- copy *c
@@ -1225,7 +1210,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   ]
 ]
 
-def split-first text:address:array:character, delim:character -> x:address:array:character, y:address:array:character [
+def split-first text:text, delim:character -> x:text, y:text [
   local-scope
   load-ingredients
   # empty text? return empty texts
@@ -1233,21 +1218,21 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   {
     empty?:boolean <- equal len, 0
     break-unless empty?
-    x:address:array:character <- new []
-    y:address:array:character <- new []
+    x:text <- new []
+    y:text <- new []
     return
   }
   idx:number <- find-next text, delim, 0
-  x:address:array:character <- copy-range text, 0, idx
+  x:text <- copy-range text, 0, idx
   idx <- add idx, 1
-  y:address:array:character <- copy-range text, idx, len
+  y:text <- copy-range text, idx, len
 ]
 
 scenario text-split-first [
   run [
     local-scope
-    x:address:array:character <- new [a/b]
-    y:address:array:character, z:address:array:character <- split-first x, 47/slash
+    x:text <- new [a/b]
+    y:text, z:text <- split-first x, 47/slash
     10:array:character/raw <- copy *y
     20:array:character/raw <- copy *z
   ]
@@ -1257,7 +1242,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   ]
 ]
 
-def copy-range buf:address:array:character, start:number, end:number -> result:address:array:character [
+def copy-range buf:text, start:number, end:number -> result:text [
   local-scope
   load-ingredients
   # if end is out of bounds, trim it
@@ -1265,7 +1250,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   end:number <- min len, end
   # allocate space for result
   len <- subtract end, start
-  result:address:array:character <- new character:type, len
+  result:text <- new character:type, len
   # copy start..end into result[curr-result]
   src-idx:number <- copy start
   dest-idx:number <- copy 0
@@ -1283,8 +1268,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-copy-copies-partial-text [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- copy-range x, 1, 3
+    x:text <- new [abc]
+    y:text <- copy-range x, 1, 3
     1:array:character/raw <- copy *y
   ]
   memory-should-contain [
@@ -1295,8 +1280,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-copy-out-of-bounds [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- copy-range x, 2, 4
+    x:text <- new [abc]
+    y:text <- copy-range x, 2, 4
     1:array:character/raw <- copy *y
   ]
   memory-should-contain [
@@ -1307,8 +1292,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 scenario text-copy-out-of-bounds-2 [
   run [
     local-scope
-    x:address:array:character <- new [abc]
-    y:address:array:character <- copy-range x, 3, 3
+    x:text <- new [abc]
+    y:text <- copy-range x, 3, 3
     1:array:character/raw <- copy *y
   ]
   memory-should-contain [
diff --git a/html/062rewrite_stash.cc.html b/html/062rewrite_stash.cc.html
index 1d8adc6f..8ed4fa38 100644
--- a/html/062rewrite_stash.cc.html
+++ b/html/062rewrite_stash.cc.html
@@ -14,7 +14,6 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-
 body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 12pt; font-size: 1em; }
 .Constant { color: #00a0a0; }
-.cSpecial { color: #008000; }
 .traceContains { color: #008000; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #800080; }
@@ -178,26 +177,6 @@ recipe main [
   stash x
 ]
 +app: 34 35
-
-:(before "End Primitive Recipe Declarations")
-TO_TEXT,
-:(before "End Primitive Recipe Numbers")
-put(Recipe_ordinal, "to-text", TO_TEXT);
-:(before "End Primitive Recipe Checks")
-case TO_TEXT: {
-  if (SIZE(inst.ingredients) != 1) {
-    raise << maybe(get(Recipe, r).name) << "'to-text' requires a single ingredient, but got '" << inst.original_string << "'\n" << end();
-    break;
-  }
-  // can handle any type
-  break;
-}
-:(before "End Primitive Recipe Implementations")
-case TO_TEXT: {
-  products.resize(1);
-  products.at(0).push_back(new_mu_string(print_mu(current_instruction().ingredients.at(0), ingredients.at(0))));
-  break;
-}
 
diff --git a/html/064list.mu.html b/html/064list.mu.html index 3b81c73b..5c24849e 100644 --- a/html/064list.mu.html +++ b/html/064list.mu.html @@ -292,7 +292,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ] ] -def to-text in:address:list:_elem -> result:address:array:character [ +def to-text in:address:list:_elem -> result:text [ local-scope load-ingredients buf:address:buffer <- new-buffer 80 @@ -301,7 +301,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ] # variant of 'to-text' which stops printing after a few elements (and so is robust to cycles) -def to-text-line in:address:list:_elem -> result:address:array:character [ +def to-text-line in:address:list:_elem -> result:text [ local-scope load-ingredients buf:address:buffer <- new-buffer 80 diff --git a/html/066stream.mu.html b/html/066stream.mu.html index 28c4814c..02798ec8 100644 --- a/html/066stream.mu.html +++ b/html/066stream.mu.html @@ -74,7 +74,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color load-ingredients empty?:boolean <- copy 0/false idx:number <- get *in, index:offset - s:address:array:character <- get *in, data:offset + s:address:array:_elem <- get *in, data:offset len:number <- length *s at-end?:boolean <- greater-or-equal idx len { @@ -85,11 +85,11 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color result <- index *s, idx ] -def read-line in:address:stream:character -> result:address:array:character, in:address:stream:character [ +def read-line in:address:stream:character -> result:text, in:address:stream:character [ local-scope load-ingredients idx:number <- get *in, index:offset - s:address:array:character <- get *in, data:offset + s:text <- get *in, data:offset next-idx:number <- find-next s, 10/newline, idx result <- copy-range s, idx, next-idx idx <- add next-idx, 1 # skip newline diff --git a/html/070table.mu.html b/html/070table.mu.html index baa33458..6292dd74 100644 --- a/html/070table.mu.html +++ b/html/070table.mu.html @@ -50,8 +50,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario table-read-write-non-integer [ run [ local-scope - key:address:array:character <- new [abc def] - {tab: (address table (address array character) number)} <- new-table 30 + key:text <- new [abc def] + {tab: (address table text number)} <- new-table 30 put-index tab, key, 34 1:number/raw <- index tab, key ] diff --git a/html/071recipe.cc.html b/html/071recipe.cc.html index 47204f71..56f55901 100644 --- a/html/071recipe.cc.html +++ b/html/071recipe.cc.html @@ -212,22 +212,29 @@ Transform.push_back(} recipe from_reagent(const reagent& r) { - assert(!r.type->atom && r.type->left->atom && r.type->left->name == "recipe"); + assert(r.type); recipe result_header; // will contain only ingredients and products, nothing else result_header.has_header = true; + if (r.type->atom) { + assert(r.type->name == "recipe"); + return result_header; + } + assert(root_type(r.type)->name == "recipe"); const type_tree* curr = r.type->right; for (/*nada*/; curr && !curr->atom; curr = curr->right) { if (curr->left->atom && curr->left->name == "->") { curr = curr->right; // skip delimiter - break; + goto read_products; } result_header.ingredients.push_back(next_recipe_reagent(curr->left)); - if (curr->right && curr->right->atom) { - result_header.ingredients.push_back(next_recipe_reagent(curr->right)); - return result_header; // no products - } } - for (; curr && !curr->atom; curr=curr->right) + if (curr) { + assert(curr->atom); + result_header.ingredients.push_back(next_recipe_reagent(curr)); + return result_header; // no products + } + read_products: + for (/*nada*/; curr && !curr->atom; curr=curr->right) result_header.products.push_back(next_recipe_reagent(curr->left)); if (curr) { assert(curr->atom); @@ -236,8 +243,33 @@ recipe from_reagent(constreturn result_header; } -// todo: unit test: 'recipe number' vs 'recipe -> number' +:(before "End Unit Tests") +void test_from_reagent_atomic() { + reagent a("{f: recipe}"); + recipe r_header = from_reagent(a); + CHECK(r_header.ingredients.empty()); + CHECK(r_header.products.empty()); +} +void test_from_reagent_non_atomic() { + reagent a("{f: (recipe number -> number)}"); + recipe r_header = from_reagent(a); + CHECK_EQ(SIZE(r_header.ingredients), 1); + CHECK_EQ(SIZE(r_header.products), 1); +} +void test_from_reagent_reads_ingredient_at_end() { + reagent a("{f: (recipe number number)}"); + recipe r_header = from_reagent(a); + CHECK_EQ(SIZE(r_header.ingredients), 2); + CHECK(r_header.products.empty()); +} +void test_from_reagent_reads_sole_ingredient_at_end() { + reagent a("{f: (recipe number)}"); + recipe r_header = from_reagent(a); + CHECK_EQ(SIZE(r_header.ingredients), 1); + CHECK(r_header.products.empty()); +} +:(code) reagent next_recipe_reagent(const type_tree* curr) { if (!curr->left) return reagent("recipe:"+curr->name); reagent result; diff --git a/html/072scheduler.cc.html b/html/072scheduler.cc.html index 78ac7437..4af95f06 100644 --- a/html/072scheduler.cc.html +++ b/html/072scheduler.cc.html @@ -21,9 +21,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color .Comment { color: #9090ff; } .Delimiter { color: #800080; } .Special { color: #c00000; } -.CommentedCode { color: #6c6c6c; } -.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .Identifier { color: #fcb165; } +.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } +.CommentedCode { color: #6c6c6c; } --> @@ -53,14 +53,23 @@ def f2 [ +schedule: 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(int time_slice) -:(replace "while (!Current_routine->completed())" following "void run_current_routine(int time_slice)") -int ninstrs = 0; -while (Current_routine->state == RUNNING && ninstrs < time_slice) -:(after "Running One Instruction") -ninstrs++; +:(before "End Globals") +int Scheduling_interval = 500; +:(before "End routine Fields") +int instructions_run_this_scheduling_slice; +:(before "End routine Constructor") +instructions_run_this_scheduling_slice = 0; +:(before "Running One Instruction") + ++Current_routine->instructions_run_this_scheduling_slice; +:(replace{} "bool should_continue_running(const routine* current_routine)") +bool should_continue_running(const routine* current_routine) { + assert(current_routine == Current_routine); // argument passed in just to make caller readable above + return Current_routine->state == RUNNING + && Current_routine->instructions_run_this_scheduling_slice < Scheduling_interval; +} +:(after "stop_running_current_routine:") +// Reset instructions_run_this_scheduling_slice +Current_routine->instructions_run_this_scheduling_slice = 0; //: now the rest of the scheduler is clean @@ -78,7 +87,6 @@ state = RUNNING; :(before "End Globals") vector<routine*> Routines; int Current_routine_index = 0; -int Scheduling_interval = 500; :(before "End Setup") Scheduling_interval = 500; Routines.clear(); @@ -97,7 +105,7 @@ Routines.clear(); assert(Current_routine->state == RUNNING); trace(9990, "schedule") << current_routine_label() << end(); //? cerr << "schedule: " << current_routine_label() << '\n'; - run_current_routine(Scheduling_interval); + run_current_routine(); // Scheduler State Transitions if (Current_routine->completed()) Current_routine->state = COMPLETED; @@ -615,11 +623,11 @@ put(Recipe_ordinal,} :(before "End routine Fields") -int ninstrs; +int instructions_run; :(before "End routine Constructor") -ninstrs = 0; -:(after "stop_running_current_routine:") -Current_routine->ninstrs += ninstrs; +instructions_run = 0; +:(before "Reset instructions_run_this_scheduling_slice") +Current_routine->instructions_run += Current_routine->instructions_run_this_scheduling_slice; :(before "End Primitive Recipe Declarations") NUMBER_OF_INSTRUCTIONS, :(before "End Primitive Recipe Numbers") @@ -642,7 +650,7 @@ put(Recipe_ordinal,int result = -1; for (int i = 0; i < SIZE(Routines); ++i) { if (Routines.at(i)->id == id) { - result = Routines.at(i)->ninstrs; + result = Routines.at(i)->instructions_run; break; } } diff --git a/html/073wait.cc.html b/html/073wait.cc.html index 926c6b29..b99b8cc5 100644 --- a/html/073wait.cc.html +++ b/html/073wait.cc.html @@ -16,6 +16,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color .Constant { color: #00a0a0; } .cSpecial { color: #008000; } .traceContains { color: #008000; } +.SalientComment { color: #00ffff; } .Comment { color: #9090ff; } .Delimiter { color: #800080; } .Special { color: #c00000; } @@ -40,18 +41,22 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color :(scenario wait_for_location) def f1 [ - 1:number <- copy 0 + 10:number <- copy 34 start-running f2 - 2:location <- copy 1/unsafe - wait-for-location 2:location - # now wait for f2 to run and modify location 1 before using its value - 3:number <- copy 1:number + 20:location <- copy 10/unsafe + wait-for-reset-then-set 20:location + # wait for f2 to run and reset location 1 + 30:number <- copy 10:number ] def f2 [ - 1:number <- copy 34 + 10:location <- copy 0/unsafe ] -# if we got the synchronization wrong we'd be storing 0 in location 3 -+mem: storing 34 in location 3 ++schedule: f1 ++run: waiting for location 10 to reset ++schedule: f2 ++schedule: waking up routine 1 ++schedule: f1 ++mem: storing 1 in location 30 //: define the new state that all routines can be in @@ -60,9 +65,8 @@ WAITING, :(before "End routine Fields") // only if state == WAITING int waiting_on_location; -int old_value_of_waiting_location; :(before "End routine Constructor") -waiting_on_location = old_value_of_waiting_location = 0; +waiting_on_location = 0; :(before "End Mu Test Teardown") if (Passed && any_routines_waiting()) { @@ -94,30 +98,61 @@ waiting_on_location = old_value_of_waiting_location = 0} } -//: primitive recipe to put routines in that state +//: Primitive recipe to put routines in that state. +//: This primitive is also known elsewhere as compare-and-set (CAS). Used to +//: build locks. :(before "End Primitive Recipe Declarations") -WAIT_FOR_LOCATION, +WAIT_FOR_RESET_THEN_SET, :(before "End Primitive Recipe Numbers") -put(Recipe_ordinal, "wait-for-location", WAIT_FOR_LOCATION); +put(Recipe_ordinal, "wait-for-reset-then-set", WAIT_FOR_RESET_THEN_SET); :(before "End Primitive Recipe Checks") -case WAIT_FOR_LOCATION: { +case WAIT_FOR_RESET_THEN_SET: { if (SIZE(inst.ingredients) != 1) { - raise << maybe(get(Recipe, r).name) << "'wait-for-location' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end(); + raise << maybe(get(Recipe, r).name) << "'wait-for-reset-then-set' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end(); break; } if (!is_mu_location(inst.ingredients.at(0))) { - raise << maybe(get(Recipe, r).name) << "'wait-for-location' requires a location ingredient, but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); + raise << maybe(get(Recipe, r).name) << "'wait-for-reset-then-set' requires a location ingredient, but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); } break; } :(before "End Primitive Recipe Implementations") -case WAIT_FOR_LOCATION: { - int loc = ingredients.at(0).at(0); +case WAIT_FOR_RESET_THEN_SET: { + int loc = static_cast<int>(ingredients.at(0).at(0)); + trace(9998, "run") << "wait: *" << loc << " = " << get_or_insert(Memory, loc) << end(); + if (get_or_insert(Memory, loc) == 0) { + trace(9998, "run") << "location " << loc << " is already 0; setting" << end(); + put(Memory, loc, 1); + break; + } + trace(9998, "run") << "waiting for location " << loc << " to reset" << end(); Current_routine->state = WAITING; Current_routine->waiting_on_location = loc; - Current_routine->old_value_of_waiting_location = get_or_insert(Memory, loc); - trace(9998, "run") << "waiting for location " << loc << " to change from " << no_scientific(get_or_insert(Memory, loc)) << end(); + break; +} + +//: Counterpart to unlock a lock. +:(before "End Primitive Recipe Declarations") +RESET, +:(before "End Primitive Recipe Numbers") +put(Recipe_ordinal, "reset", RESET); +:(before "End Primitive Recipe Checks") +case RESET: { + if (SIZE(inst.ingredients) != 1) { + raise << maybe(get(Recipe, r).name) << "'reset' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end(); + break; + } + if (!is_mu_location(inst.ingredients.at(0))) { + raise << maybe(get(Recipe, r).name) << "'reset' requires a location ingredient, but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); + } + break; +} +:(before "End Primitive Recipe Implementations") +case RESET: { + int loc = static_cast<int>(ingredients.at(0).at(0)); + put(Memory, loc, 0); + trace(9998, "run") << "reset: *" << loc << " = " << get_or_insert(Memory, loc) << end(); break; } @@ -126,17 +161,18 @@ put(Recipe_ordinal,:(before "End Scheduler State Transitions") for (int i = 0; i < SIZE(Routines); ++i) { if (Routines.at(i)->state != WAITING) continue; - if (Routines.at(i)->waiting_on_location && - get_or_insert(Memory, Routines.at(i)->waiting_on_location) != Routines.at(i)->old_value_of_waiting_location) { - trace(9999, "schedule") << "waking up routine\n" << end(); + int loc = Routines.at(i)->waiting_on_location; + if (loc && get_or_insert(Memory, loc) == 0) { + trace(9999, "schedule") << "waking up routine " << Routines.at(i)->id << end(); + put(Memory, loc, 1); Routines.at(i)->state = RUNNING; - Routines.at(i)->waiting_on_location = Routines.at(i)->old_value_of_waiting_location = 0; + Routines.at(i)->waiting_on_location = 0; } } -//: primitive to help compute locations to wait for -//: only supports elements inside containers, no arrays or containers within -//: containers yet. +//: Primitive to help compute locations to wait on. +//: Only supports elements immediately inside containers; no arrays or +//: containers within containers yet. :(scenario get_location) def main [ @@ -275,166 +311,219 @@ def main [ ] +mem: storing 11 in location 21 -//: also allow waiting on a routine to block -//: (just for tests; use wait_for_routine below wherever possible) +//: allow waiting on a routine to complete -:(scenario wait_for_routine_to_block) +:(scenario wait_for_routine) def f1 [ + # add a few routines to run 1:number/routine <- start-running f2 - wait-for-routine-to-block 1:number/routine - # now wait for f2 to run and modify location 10 before using its value - 11:number <- copy 10:number + 2:number/routine <- start-running f3 + wait-for-routine 1:number/routine + # now wait for f2 to *complete* and modify location 13 before using its value + 20:number <- copy 13:number ] def f2 [ - 10:number <- copy 34 + 10:number <- copy 0 # just padding + switch # simulate a block; routine f1 shouldn't restart at this point + 13:number <- copy 34 +] +def f3 [ + # padding routine just to help simulate the block in f2 using 'switch' + 11:number <- copy 0 + 12:number <- copy 0 ] +schedule: f1 -+run: waiting for routine 2 to block ++run: waiting for routine 2 +schedule: f2 -+schedule: waking up blocked routine 1 ++schedule: f3 ++schedule: f2 ++schedule: waking up routine 1 +schedule: f1 -# if we got the synchronization wrong we'd be storing 0 in location 11 -+mem: storing 34 in location 11 +# if we got the synchronization wrong we'd be storing 0 in location 20 ++mem: storing 34 in location 20 :(before "End routine Fields") // only if state == WAITING -int waiting_on_routine_to_block; +int waiting_on_routine; :(before "End routine Constructor") -waiting_on_routine_to_block = 0; +waiting_on_routine = 0; :(before "End Primitive Recipe Declarations") -WAIT_FOR_ROUTINE_TO_BLOCK, +WAIT_FOR_ROUTINE, :(before "End Primitive Recipe Numbers") -put(Recipe_ordinal, "wait-for-routine-to-block", WAIT_FOR_ROUTINE_TO_BLOCK); +put(Recipe_ordinal, "wait-for-routine", WAIT_FOR_ROUTINE); :(before "End Primitive Recipe Checks") -case WAIT_FOR_ROUTINE_TO_BLOCK: { +case WAIT_FOR_ROUTINE: { if (SIZE(inst.ingredients) != 1) { - raise << maybe(get(Recipe, r).name) << "'wait-for-routine-to-block' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end(); + raise << maybe(get(Recipe, r).name) << "'wait-for-routine' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end(); break; } if (!is_mu_number(inst.ingredients.at(0))) { - raise << maybe(get(Recipe, r).name) << "first ingredient of 'wait-for-routine-to-block' should be a routine id generated by 'start-running', but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); + raise << maybe(get(Recipe, r).name) << "first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); break; } break; } :(before "End Primitive Recipe Implementations") -case WAIT_FOR_ROUTINE_TO_BLOCK: { +case WAIT_FOR_ROUTINE: { if (ingredients.at(0).at(0) == Current_routine->id) { raise << maybe(current_recipe_name()) << "routine can't wait for itself! '" << to_original_string(current_instruction()) << "'\n" << end(); break; } Current_routine->state = WAITING; - Current_routine->waiting_on_routine_to_block = ingredients.at(0).at(0); - trace(9998, "run") << "waiting for routine " << ingredients.at(0).at(0) << " to block" << end(); -//? cerr << Current_routine->id << ": waiting for routine " << ingredients.at(0).at(0) << " to block\n"; + Current_routine->waiting_on_routine = ingredients.at(0).at(0); + trace(9998, "run") << "waiting for routine " << ingredients.at(0).at(0) << end(); +//? cerr << Current_routine->id << ": waiting for routine " << ingredients.at(0).at(0) << '\n'; break; } :(before "End Scheduler State Transitions") -// Wake up any routines waiting for other routines to stop running. +// Wake up any routines waiting for other routines to complete. +// Important: this must come after the scheduler loop above giving routines +// waiting for locations to change a chance to wake up. for (int i = 0; i < SIZE(Routines); ++i) { if (Routines.at(i)->state != WAITING) continue; routine* waiter = Routines.at(i); - if (!waiter->waiting_on_routine_to_block) continue; - int id = waiter->waiting_on_routine_to_block; + if (!waiter->waiting_on_routine) continue; + int id = waiter->waiting_on_routine; assert(id != waiter->id); // routine can't wait on itself for (int j = 0; j < SIZE(Routines); ++j) { const routine* waitee = Routines.at(j); - if (waitee->id == id && waitee->state != RUNNING) { - // routine is WAITING or COMPLETED or DISCONTINUED - trace(9999, "schedule") << "waking up blocked routine " << waiter->id << end(); -//? cerr << id << " is now unblocked (" << waitee->state << "); waking up waiting routine " << waiter->id << '\n'; + if (waitee->id == id && waitee->state != RUNNING && waitee->state != WAITING) { + // routine is COMPLETED or DISCONTINUED + trace(9999, "schedule") << "waking up routine " << waiter->id << end(); +//? cerr << id << " is now done (" << waitee->state << "); waking up waiting routine " << waiter->id << '\n'; waiter->state = RUNNING; - waiter->waiting_on_routine_to_block = 0; + waiter->waiting_on_routine = 0; } } } -//: allow waiting on a routine to complete +//:: helpers for manipulating routines in tests +//: +//: Managing arbitrary scenarios requires the ability to: +//: a) stop the current routine (`switch`) +//: b) restart a routine (`restart`) +//: c) tell when a routine is blocked +//: +//: A routine is blocked either if it's waiting or if it explicitly signals +//: that it's blocked (even as it periodically wakes up and polls for some +//: event). +//: +//: Signalling blockedness might well be a huge hack. But Mu doesn't have Unix +//: signals to avoid polling with, because signals are also pretty hacky. -:(scenario wait_for_routine) +:(before "End routine Fields") +bool blocked; +:(before "End routine Constructor") +blocked = false; + +:(before "End Primitive Recipe Declarations") +CURRENT_ROUTINE_IS_BLOCKED, +:(before "End Primitive Recipe Numbers") +put(Recipe_ordinal, "current-routine-is-blocked", CURRENT_ROUTINE_IS_BLOCKED); +:(before "End Primitive Recipe Checks") +case CURRENT_ROUTINE_IS_BLOCKED: { + if (!inst.ingredients.empty()) { + raise << maybe(get(Recipe, r).name) << "'current-routine-is-blocked' should have no ingredients, but got '" << inst.original_string << "'\n" << end(); + break; + } + break; +} +:(before "End Primitive Recipe Implementations") +case CURRENT_ROUTINE_IS_BLOCKED: { + Current_routine->blocked = true; + break; +} + +:(before "End Primitive Recipe Declarations") +CURRENT_ROUTINE_IS_UNBLOCKED, +:(before "End Primitive Recipe Numbers") +put(Recipe_ordinal, "current-routine-is-unblocked", CURRENT_ROUTINE_IS_UNBLOCKED); +:(before "End Primitive Recipe Checks") +case CURRENT_ROUTINE_IS_UNBLOCKED: { + if (!inst.ingredients.empty()) { + raise << maybe(get(Recipe, r).name) << "'current-routine-is-unblocked' should have no ingredients, but got '" << inst.original_string << "'\n" << end(); + break; + } + break; +} +:(before "End Primitive Recipe Implementations") +case CURRENT_ROUTINE_IS_UNBLOCKED: { + Current_routine->blocked = false; + break; +} + +//: also allow waiting on a routine to block +//: (just for tests; use wait_for_routine above wherever possible) + +:(scenario wait_for_routine_to_block) def f1 [ - # add a few routines to run 1:number/routine <- start-running f2 - 2:number/routine <- start-running f3 - wait-for-routine 1:number/routine - # now wait for f2 to *complete* and modify location 13 before using its value - 20:number <- copy 13:number + wait-for-routine-to-block 1:number/routine + # now wait for f2 to run and modify location 10 before using its value + 11:number <- copy 10:number ] def f2 [ - 10:number <- copy 0 # just padding - switch # simulate a block; routine f1 shouldn't restart at this point - 13:number <- copy 34 -] -def f3 [ - # padding routine just to help simulate the block in f2 using 'switch' - 11:number <- copy 0 - 12:number <- copy 0 + 10:number <- copy 34 ] +schedule: f1 -+run: waiting for routine 2 -+schedule: f2 -+schedule: f3 ++run: waiting for routine 2 to block +schedule: f2 -+schedule: waking up routine 1 ++schedule: waking up routine 1 because routine 2 is blocked +schedule: f1 -# if we got the synchronization wrong we'd be storing 0 in location 20 -+mem: storing 34 in location 20 +# if we got the synchronization wrong we'd be storing 0 in location 11 ++mem: storing 34 in location 11 :(before "End routine Fields") // only if state == WAITING -int waiting_on_routine; +int waiting_on_routine_to_block; :(before "End routine Constructor") -waiting_on_routine = 0; +waiting_on_routine_to_block = 0; :(before "End Primitive Recipe Declarations") -WAIT_FOR_ROUTINE, +WAIT_FOR_ROUTINE_TO_BLOCK, :(before "End Primitive Recipe Numbers") -put(Recipe_ordinal, "wait-for-routine", WAIT_FOR_ROUTINE); +put(Recipe_ordinal, "wait-for-routine-to-block", WAIT_FOR_ROUTINE_TO_BLOCK); :(before "End Primitive Recipe Checks") -case WAIT_FOR_ROUTINE: { +case WAIT_FOR_ROUTINE_TO_BLOCK: { if (SIZE(inst.ingredients) != 1) { - raise << maybe(get(Recipe, r).name) << "'wait-for-routine' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end(); + raise << maybe(get(Recipe, r).name) << "'wait-for-routine-to-block' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end(); break; } if (!is_mu_number(inst.ingredients.at(0))) { - raise << maybe(get(Recipe, r).name) << "first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); + raise << maybe(get(Recipe, r).name) << "first ingredient of 'wait-for-routine-to-block' should be a routine id generated by 'start-running', but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); break; } break; } :(before "End Primitive Recipe Implementations") -case WAIT_FOR_ROUTINE: { +case WAIT_FOR_ROUTINE_TO_BLOCK: { if (ingredients.at(0).at(0) == Current_routine->id) { raise << maybe(current_recipe_name()) << "routine can't wait for itself! '" << to_original_string(current_instruction()) << "'\n" << end(); break; } Current_routine->state = WAITING; - Current_routine->waiting_on_routine = ingredients.at(0).at(0); - trace(9998, "run") << "waiting for routine " << ingredients.at(0).at(0) << end(); -//? cerr << Current_routine->id << ": waiting for routine " << ingredients.at(0).at(0) << '\n'; + Current_routine->waiting_on_routine_to_block = ingredients.at(0).at(0); + trace(9998, "run") << "waiting for routine " << ingredients.at(0).at(0) << " to block" << end(); break; } :(before "End Scheduler State Transitions") -// Wake up any routines waiting for other routines to complete. -// Important: this must come after the scheduler loop above giving routines -// waiting for locations to change a chance to wake up. +// Wake up any routines waiting for other routines to stop running. for (int i = 0; i < SIZE(Routines); ++i) { if (Routines.at(i)->state != WAITING) continue; routine* waiter = Routines.at(i); - if (!waiter->waiting_on_routine) continue; - int id = waiter->waiting_on_routine; + if (!waiter->waiting_on_routine_to_block) continue; + int id = waiter->waiting_on_routine_to_block; assert(id != waiter->id); // routine can't wait on itself for (int j = 0; j < SIZE(Routines); ++j) { const routine* waitee = Routines.at(j); - if (waitee->id == id && waitee->state != RUNNING && waitee->state != WAITING) { - // routine is COMPLETED or DISCONTINUED - trace(9999, "schedule") << "waking up routine " << waiter->id << end(); -//? cerr << id << " is now done (" << waitee->state << "); waking up waiting routine " << waiter->id << '\n'; + if (waitee->id != id) continue; + if (waitee->state != RUNNING || waitee->blocked) { + trace(9999, "schedule") << "waking up routine " << waiter->id << " because routine " << waitee->id << " is blocked" << end(); waiter->state = RUNNING; - waiter->waiting_on_routine = 0; + waiter->waiting_on_routine_to_block = 0; } } } @@ -498,6 +587,7 @@ put(Recipe_ordinal,if (Routines.at(i)->id == id) { if (Routines.at(i)->state == WAITING) Routines.at(i)->state = RUNNING; + Routines.at(i)->blocked = false; break; } } @@ -518,6 +608,32 @@ def f [ 1:number/raw <- copy 1 ] # shouldn't crash + +:(scenario restart_blocked_routine) +% Scheduling_interval = 1; +def main [ + local-scope + r:number/routine-id <- start-running f + wait-for-routine-to-block r # get past the block in f below + restart r + wait-for-routine-to-block r # should run f to completion +] +# function with one block +def f [ + current-routine-is-blocked + # 8 instructions of padding, many more than 'main' above + 1:number <- add 1:number, 1 + 1:number <- add 1:number, 1 + 1:number <- add 1:number, 1 + 1:number <- add 1:number, 1 + 1:number <- add 1:number, 1 + 1:number <- add 1:number, 1 + 1:number <- add 1:number, 1 + 1:number <- add 1:number, 1 + 1:number <- add 1:number, 1 +] +# make sure all of f ran ++mem: storing 8 in location 1 diff --git a/html/075channel.mu.html b/html/075channel.mu.html index 6f34b054..4912015e 100644 --- a/html/075channel.mu.html +++ b/html/075channel.mu.html @@ -21,6 +21,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color .Comment { color: #9090ff; } .Constant { color: #00a0a0; } .Special { color: #c00000; } +.CommentedCode { color: #6c6c6c; } .muControl { color: #c0a020; } --> @@ -33,20 +34,17 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
-# Mu synchronizes using channels rather than locks, like Erlang and Go.
-#
-# The two ends of a channel will usually belong to different routines, but
-# each end should (currently) only be used by a single one. Don't try to read
-# from or write to it from multiple routines at once.
+# Mu synchronizes between routines using channels rather than locks, like
+# Erlang and Go.
 #
 # Key properties of channels:
 #
-# a) Writing to a full channel or reading from an empty one will put the
-# current routine in 'waiting' state until the operation can be completed.
+#   a) Writing to a full channel or reading from an empty one will put the
+#   current routine in 'waiting' state until the operation can be completed.
 #
-# b) Writing to a channel implicitly performs a deep copy, to prevent
-# addresses from being shared between routines, thereby causing race
-# conditions.
+#   b) Writing to a channel implicitly performs a deep copy. This prevents
+#   addresses from being shared between routines, and therefore eliminates all
+#   possibility of race conditions.
 
 scenario channel [
   run [
@@ -62,9 +60,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 ]
 
 container channel:_elem [
-  # To avoid locking, writer and reader will never write to the same location.
-  # So channels will include fields in pairs, one for the writer and one for the
-  # reader.
+  lock:boolean  # inefficient but simple: serialize all reads as well as writes
   first-full:number  # for write
   first-free:number  # for read
   # A circular buffer contains values from index first-full up to (but not
@@ -105,13 +101,25 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   assert out, [write to null channel]
   chan:address:channel:_elem <- get *out, chan:offset
   <channel-write-initial>
+  # block until lock is acquired AND queue has room
+  lock:location <- get-location *chan, lock:offset
+#?   $print [write], 10/newline
   {
-    # block if chan is full
-    full:boolean <- channel-full? chan
-    break-unless full
-    full-address:location <- get-location *chan, first-full:offset
-    wait-for-location full-address
+#?     $print [trying to acquire lock for writing], 10/newline
+    wait-for-reset-then-set lock
+#?     $print [lock acquired for writing], 10/newline
+    full?:boolean <- channel-full? chan
+    break-unless full?
+#?     $print [but channel is full; relinquishing lock], 10/newline
+    # channel is full; relinquish lock and give a reader the opportunity to
+    # create room on it
+    reset lock
+    current-routine-is-blocked
+    switch  # avoid spinlocking
+    loop
   }
+  current-routine-is-unblocked
+#?   $print [performing write], 10/newline
   # store a deep copy of val
   circular-buffer:address:array:_elem <- get *chan, data:offset
   free:number <- get *chan, first-free:offset
@@ -128,6 +136,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   }
   # write back
   *chan <- put *chan, first-free:offset, free
+#?   $print [relinquishing lock after writing], 10/newline
+  reset lock
 ]
 
 def read in:address:source:_elem -> result:_elem, eof?:boolean, in:address:source:_elem [
@@ -136,14 +146,25 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   assert in, [read on null channel]
   eof? <- copy 0/false  # default result
   chan:address:channel:_elem <- get *in, chan:offset
+  # block until lock is acquired AND queue has data
+  lock:location <- get-location *chan, lock:offset
+#?   $print [read], 10/newline
   {
-    # block if chan is empty
+#?     $print [trying to acquire lock for reading], 10/newline
+    wait-for-reset-then-set lock
+#?     $print [lock acquired for reading], 10/newline
     empty?:boolean <- channel-empty? chan
     break-unless empty?
+#?     $print [but channel is empty; relinquishing lock], 10/newline
+    # channel is empty; relinquish lock and give a writer the opportunity to
+    # add to it
+    reset lock
+    current-routine-is-blocked
     <channel-read-empty>
-    free-address:location <- get-location *chan, first-free:offset
-    wait-for-location free-address
+    switch  # avoid spinlocking
+    loop
   }
+  current-routine-is-unblocked
   # pull result off
   full:number <- get *chan, first-full:offset
   circular-buffer:address:array:_elem <- get *chan, data:offset
@@ -162,6 +183,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   }
   # write back
   *chan <- put *chan, first-full:offset, full
+#?   $print [relinquishing lock after reading], 10/newline
+  reset lock
 ]
 
 def clear in:address:source:_elem -> in:address:source:_elem [
@@ -344,6 +367,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   {
     break-unless closed?
     empty-result:address:_elem <- new _elem:type
+    current-routine-is-unblocked
     return *empty-result, 1/true
   }
 ]
@@ -424,7 +448,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
     }
     # copy line into 'buffered-out'
     i:number <- copy 0
-    line-contents:address:array:character <- get *line, data:offset
+    line-contents:text <- get *line, data:offset
     max:number <- get *line, length:offset
     {
       done?:boolean <- greater-or-equal i, max
diff --git a/html/081print.mu.html b/html/081print.mu.html
index b6d2bd96..eecac93b 100644
--- a/html/081print.mu.html
+++ b/html/081print.mu.html
@@ -678,7 +678,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   show-display
 ]
 
-def print screen:address:screen, s:address:array:character -> screen:address:screen [
+def print screen:address:screen, s:text -> screen:address:screen [
   local-scope
   load-ingredients
   color:number, color-found?:boolean <- next-ingredient
@@ -709,8 +709,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   run [
     local-scope
     fake-screen:address:screen <- new-fake-screen 3/width, 2/height
-    s:address:array:character <- new [abcd]
-    fake-screen <- print fake-screen, s:address:array:character
+    s:text <- new [abcd]
+    fake-screen <- print fake-screen, s:text
     cell:address:array:screen-cell <- get *fake-screen, data:offset
     10:array:screen-cell/raw <- copy *cell
   ]
@@ -743,7 +743,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
     bg-color <- copy 0/black
   }
   # todo: other bases besides decimal
-  s:address:array:character <- to-text n
+  s:text <- to-text n
   screen <- print screen, s, color, bg-color
 ]
 
diff --git a/html/088file.mu.html b/html/088file.mu.html
index e86201ed..435e3439 100644
--- a/html/088file.mu.html
+++ b/html/088file.mu.html
@@ -39,11 +39,11 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 ]
 
 container file-mapping [
-  name:address:array:character
-  contents:address:array:character
+  name:text
+  contents:text
 ]
 
-def start-reading fs:address:filesystem, filename:address:array:character -> contents:address:source:character [
+def start-reading fs:address:filesystem, filename:text -> contents:address:source:character [
   local-scope
   load-ingredients
   {
@@ -64,11 +64,11 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
     break-if done?
     tmp:file-mapping <- index *data, i
     i <- add i, 1
-    curr-filename:address:array:character <- get tmp, name:offset
+    curr-filename:text <- get tmp, name:offset
     found?:boolean <- equal filename, curr-filename
     loop-unless found?
     contents:address:source:character, sink:address:sink:character <- new-channel 30
-    curr-contents:address:array:character <- get tmp, contents:offset
+    curr-contents:text <- get tmp, contents:offset
     start-running transmit-from-text curr-contents, sink
     return
   }
@@ -88,7 +88,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   file <- $close-file file
 ]
 
-def transmit-from-text contents:address:array:character, sink:address:sink:character -> sink:address:sink:character [
+def transmit-from-text contents:text, sink:address:sink:character -> sink:address:sink:character [
   local-scope
   load-ingredients
   i:number <- copy 0
@@ -104,7 +104,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   sink <- close sink
 ]
 
-def start-writing fs:address:filesystem, filename:address:array:character -> sink:address:sink:character, routine-id:number [
+def start-writing fs:address:filesystem, filename:text -> sink:address:sink:character, routine-id:number [
   local-scope
   load-ingredients
   source:address:source:character, sink:address:sink:character <- new-channel 30
@@ -133,7 +133,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   file <- $close-file file
 ]
 
-def transmit-to-fake-file fs:address:filesystem, filename:address:array:character, source:address:source:character -> fs:address:filesystem, source:address:source:character [
+def transmit-to-fake-file fs:address:filesystem, filename:text, source:address:source:character -> fs:address:filesystem, source:address:source:character [
   local-scope
   load-ingredients
   # compute new file contents
@@ -144,10 +144,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
     buf <- append buf, c
     loop
   }
-  contents:address:array:character <- buffer-to-array buf
+  contents:text <- buffer-to-array buf
   new-file-mapping:file-mapping <- merge filename, contents
   # write to filesystem
-  curr-filename:address:array:character <- copy 0
+  curr-filename:text <- copy 0
   data:address:array:file-mapping <- get *fs, data:offset
   # replace file contents if it already exists
   i:number <- copy 0
diff --git a/html/090scenario_filesystem_test.mu.html b/html/090scenario_filesystem_test.mu.html
index dc20709d..094f5e5d 100644
--- a/html/090scenario_filesystem_test.mu.html
+++ b/html/090scenario_filesystem_test.mu.html
@@ -64,7 +64,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   sink <- write sink, 121/y
   close sink
   wait-for-routine writer
-  contents-read-back:address:array:character <- slurp filesystem, [a]
+  contents-read-back:text <- slurp filesystem, [a]
   10:boolean/raw <- equal contents-read-back, [xy]
   memory-should-contain [
     10 <- 1  # file contents read back exactly match what was written
@@ -81,7 +81,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   sink <- write sink, 121/y
   close sink
   wait-for-routine writer
-  contents-read-back:address:array:character <- slurp filesystem, [a]
+  contents-read-back:text <- slurp filesystem, [a]
   10:boolean/raw <- equal contents-read-back, [xy]
   memory-should-contain [
     10 <- 1  # file contents read back exactly match what was written
@@ -101,9 +101,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   sink <- write sink, 121/y
   close sink
   wait-for-routine writer
-  contents-read-back:address:array:character <- slurp filesystem, [a]
+  contents-read-back:text <- slurp filesystem, [a]
   10:boolean/raw <- equal contents-read-back, [xy]
-  other-file-contents:address:array:character <- slurp filesystem, [b]
+  other-file-contents:text <- slurp filesystem, [b]
   11:boolean/raw <- equal other-file-contents, [bcd
 ]
   memory-should-contain [
@@ -112,7 +112,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
   ]
 ]
 
-def slurp fs:address:filesystem, filename:address:array:character -> contents:address:array:character [
+def slurp fs:address:filesystem, filename:text -> contents:text [
   local-scope
   load-ingredients
   source:address:source:character <- start-reading fs, filename
diff --git a/html/091socket.cc.html b/html/091socket.cc.html
new file mode 100644
index 00000000..306f3a31
--- /dev/null
+++ b/html/091socket.cc.html
@@ -0,0 +1,206 @@
+
+
+
+
+Mu - 091socket.cc
+
+
+
+
+
+
+
+
+
+
+
+:(before "End Includes")
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+:(before "End Types")
+struct socket_t {
+  int fd;
+  sockaddr_in addr;
+  socket_t() {
+    fd = 0;
+    bzero(&addr, sizeof(addr));
+  }
+};
+
+:(code)
+void server_socket(int portno, socket_t* server) {
+  server->fd = socket(AF_INET, SOCK_STREAM, 0);
+  int dummy;
+  setsockopt(server->fd, SOL_SOCKET, SO_REUSEADDR, &dummy, sizeof(dummy));
+  server->addr.sin_family = AF_INET;
+  server->addr.sin_addr.s_addr = INADDR_ANY;
+  server->addr.sin_port = htons(portno);
+  if (bind(server->fd, (struct sockaddr*)&server->addr, sizeof(server->addr)) < 0) {
+    server->fd = -1;
+    raise << "Failed to bind server socket to port " << portno << ". Something's already using that port." << "\n";
+    return;
+  }
+  listen(server->fd, 5);
+}
+
+:(before "End Primitive Recipe Declarations")
+_SOCKET,
+:(before "End Primitive Recipe Numbers")
+put(Recipe_ordinal, "$socket", _SOCKET);
+:(before "End Primitive Recipe Checks")
+case _SOCKET: {
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(get(Recipe, r).name) << "'$socket' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end();
+    break;
+  }
+  if (!is_mu_number(inst.ingredients.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "first ingredient of '$socket' should be a number, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end();
+    break;
+  }
+  if (SIZE(inst.products) != 1) {
+    raise << maybe(get(Recipe, r).name) << "'$socket' requires exactly one product, but got '" << inst.original_string << "'\n" << end();
+    break;
+  }
+  if (!is_mu_number(inst.products.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "first product of '$socket' should be a number (file handle), but got '" << to_string(inst.products.at(0)) << "'\n" << end();
+    break;
+  }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case _SOCKET: {
+  int port = ingredients.at(0).at(0);
+  socket_t server;
+  server_socket(port, &server);
+  if (server.fd < 0) {
+    break;
+  }
+  products.resize(1);
+  products.at(0).push_back(server.fd);
+  break;
+}
+
+:(code)
+void session_socket(int serverfd, socket_t* session) {
+  socklen_t dummy = sizeof(session->addr);
+  session->fd = accept(serverfd, (struct sockaddr*)&session->addr, &dummy);
+}
+:(before "End Primitive Recipe Declarations")
+_ACCEPT,
+:(before "End Primitive Recipe Numbers")
+put(Recipe_ordinal, "$accept", _ACCEPT);
+:(before "End Primitive Recipe Checks")
+case _ACCEPT: {
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(get(Recipe, r).name) << "'$accept' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end();
+    break;
+  }
+  if (!is_mu_number(inst.ingredients.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "first ingredient of '$accept' should be a number, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end();
+    break;
+  }
+  if (SIZE(inst.products) != 1) {
+    raise << maybe(get(Recipe, r).name) << "'$accept' requires exactly one product, but got '" << inst.original_string << "'\n" << end();
+    break;
+  }
+  if (!is_mu_number(inst.products.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "first product of '$accept' should be a number (file handle), but got '" << to_string(inst.products.at(0)) << "'\n" << end();
+    break;
+  }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case _ACCEPT: {
+  double socket_fd = ingredients.at(0).at(0);
+  socket_t session;
+  session_socket(socket_fd, &session);
+  products.resize(1);
+  products.at(0).push_back(session.fd);
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+_READ_FROM_SOCKET,
+:(before "End Primitive Recipe Numbers")
+put(Recipe_ordinal, "$read-from-socket", _READ_FROM_SOCKET);
+:(before "End Primitive Recipe Checks")
+case _READ_FROM_SOCKET: {
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(get(Recipe, r).name) << "'$read-from-socket' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end();
+    break;
+  }
+  if (!is_mu_number(inst.ingredients.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "first ingredient of '$read-from-socket' should be a number, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end();
+    break;
+  }
+  if (SIZE(inst.products) != 1) {
+    raise << maybe(get(Recipe, r).name) << "'$read-from-socket' requires exactly one product, but got '" << inst.original_string << "'\n" << end();
+    break;
+  }
+  if (!is_mu_character(inst.products.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "first product of '$read-from-socket' should be a character, but got '" << to_string(inst.products.at(0)) << "'\n" << end();
+    break;
+  }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case _READ_FROM_SOCKET: {
+  products.resize(1);
+  double socket_fd = ingredients.at(0).at(0);
+  char single_char[2];
+  bzero(single_char, 2);
+  if (read(socket_fd, single_char, 1) < 0) {
+    raise << maybe(current_recipe_name()) << "read from socket failed\n" << end();
+    products.at(0).push_back(0);
+    break;
+  }
+  products.at(0).push_back(single_char[0]);
+  break;
+}
+
+:(before "End Primitive Recipe Declarations")
+_CLOSE_SOCKET,
+:(before "End Primitive Recipe Numbers")
+put(Recipe_ordinal, "$close-socket", _CLOSE_SOCKET);
+:(before "End Primitive Recipe Checks")
+case _CLOSE_SOCKET: {
+  if (SIZE(inst.ingredients) != 2) {
+    raise << maybe(get(Recipe, r).name) << "'$close-socket' requires exactly two ingredient, but got '" << inst.original_string << "'\n" << end();
+    break;
+  }
+  if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "first ingredient of '$close-socket' should be a character, but got '" << to_string(inst.ingredients.at(0)) << "t\n" << end();
+    break;
+  }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case _CLOSE_SOCKET: {
+  double socket_fd = ingredients.at(0).at(0);
+  double session_fd = ingredients.at(1).at(0);
+  close(socket_fd);
+  close(session_fd);
+  break;
+}
+
+ + + diff --git a/html/channel.mu.html b/html/channel.mu.html index afa2f732..afe84b31 100644 --- a/html/channel.mu.html +++ b/html/channel.mu.html @@ -48,6 +48,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color n <- add n, 1 loop } + close sink ] def consumer source:address:source:character -> source:address:source:character [ diff --git a/html/chessboard.mu.html b/html/chessboard.mu.html index 95eea356..72986d0c 100644 --- a/html/chessboard.mu.html +++ b/html/chessboard.mu.html @@ -98,10 +98,12 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ## Here's how 'chessboard' is implemented. +type board = address:array:address:array:character + def chessboard screen:address:screen, console:address:console -> screen:address:screen, console:address:console [ local-scope load-ingredients - board:address:array:address:array:character <- initial-position + board:board <- initial-position # hook up stdin stdin-in:address:source:character, stdin-out:address:sink:character <- new-channel 10/capacity start-running send-keys-to-channel, console, stdin-out, screen @@ -136,7 +138,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ## a board is an array of files, a file is an array of characters (squares) -def new-board initial-position:address:array:character -> board:address:array:address:array:character [ +def new-board initial-position:address:array:character -> board:board [ local-scope load-ingredients # assert(length(initial-position) == 64) @@ -173,7 +175,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color } ] -def print-board screen:address:screen, board:address:array:address:array:character -> screen:address:screen [ +def print-board screen:address:screen, board:board -> screen:address:screen [ local-scope load-ingredients row:number <- copy 7 # start printing from the top of the board @@ -209,7 +211,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color cursor-to-next-line screen ] -def initial-position -> board:address:array:address:array:character [ +def initial-position -> board:board [ local-scope # layout in memory (in raster order): # R P _ _ _ _ p r @@ -236,7 +238,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color assume-screen 30/width, 12/height run [ local-scope - board:address:array:address:array:character <- initial-position + board:board <- initial-position screen:address:screen <- print-board screen:address:screen, board ] screen-should-contain [ @@ -406,7 +408,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # 'read-move' is waiting for input wait-for-routine-to-block read-move-routine read-move-state:number <- routine-state read-move-routine - waiting?:boolean <- equal read-move-state, 3/waiting + waiting?:boolean <- not-equal read-move-state, 2/discontinued assert waiting?, [ F read-move-blocking: routine failed to pause after coming up (before any keys were pressed)] # press 'a' @@ -415,7 +417,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # 'read-move' still waiting for input wait-for-routine-to-block read-move-routine read-move-state <- routine-state read-move-routine - waiting? <- equal read-move-state, 3/waiting + waiting? <- not-equal read-move-state, 2/discontinued assert waiting?, [ F read-move-blocking: routine failed to pause after rank 'a'] # press '2' @@ -424,7 +426,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # 'read-move' still waiting for input wait-for-routine-to-block read-move-routine read-move-state <- routine-state read-move-routine - waiting? <- equal read-move-state, 3/waiting + waiting? <- not-equal read-move-state, 2/discontinued assert waiting?, [ F read-move-blocking: routine failed to pause after file 'a2'] # press '-' @@ -433,7 +435,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # 'read-move' still waiting for input wait-for-routine-to-block read-move-routine read-move-state <- routine-state read-move-routine - waiting? <- equal read-move-state, 3/waiting + waiting? <- not-equal read-move-state, 2/discontinued assert waiting?, [ F read-move-blocking: routine failed to pause after hyphen 'a2-'] # press 'a' @@ -442,7 +444,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # 'read-move' still waiting for input wait-for-routine-to-block read-move-routine read-move-state <- routine-state read-move-routine - waiting? <- equal read-move-state, 3/waiting + waiting? <- not-equal read-move-state, 2/discontinued assert waiting?, [ F read-move-blocking: routine failed to pause after rank 'a2-a'] # press '4' @@ -451,7 +453,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # 'read-move' still waiting for input wait-for-routine-to-block read-move-routine read-move-state <- routine-state read-move-routine - waiting? <- equal read-move-state, 3/waiting + waiting? <- not-equal read-move-state, 2/discontinued assert waiting?, [ F read-move-blocking: routine failed to pause after file 'a2-a4'] # press 'newline' @@ -479,7 +481,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # 'read-move' is waiting for input wait-for-routine-to-block read-move-routine read-move-state:number <- routine-state read-move-routine - waiting?:boolean <- equal read-move-state, 3/waiting + waiting?:boolean <- not-equal read-move-state, 2/discontinued assert waiting?, [ F read-move-quit: routine failed to pause after coming up (before any keys were pressed)] # press 'q' @@ -507,9 +509,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # 'read-move' is waiting for input wait-for-routine-to-block read-move-routine read-move-state:number <- routine-state read-move-routine - waiting?:boolean <- equal read-move-state, 3/waiting + waiting?:boolean <- not-equal read-move-state, 2/discontinued assert waiting?, [ -F read-move-file: routine failed to pause after coming up (before any keys were pressed)] +F read-move-illegal-file: routine failed to pause after coming up (before any keys were pressed)] sink <- write sink, 50/'2' restart read-move-routine wait-for-routine-to-block read-move-routine @@ -529,9 +531,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # 'read-move' is waiting for input wait-for-routine-to-block read-move-routine read-move-state:number <- routine-state read-move-routine - waiting?:boolean <- equal read-move-state, 3/waiting + waiting?:boolean <- not-equal read-move-state, 2/discontinued assert waiting?, [ -F read-move-file: routine failed to pause after coming up (before any keys were pressed)] +F read-move-illegal-rank: routine failed to pause after coming up (before any keys were pressed)] sink <- write sink, 97/a sink <- write sink, 97/a restart read-move-routine @@ -552,9 +554,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # 'read-move' is waiting for input wait-for-routine-to-block read-move-routine read-move-state:number <- routine-state read-move-routine - waiting?:boolean <- equal read-move-state, 3/waiting + waiting?:boolean <- not-equal read-move-state, 2/discontinued assert waiting?, [ -F read-move-file: routine failed to pause after coming up (before any keys were pressed)] +F read-move-empty: routine failed to pause after coming up (before any keys were pressed)] sink <- write sink, 10/newline sink <- write sink, 97/a restart read-move-routine @@ -566,7 +568,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ] ] -def make-move board:address:array:address:array:character, m:address:move -> board:address:array:address:array:character [ +def make-move board:board, m:address:move -> board:board [ local-scope load-ingredients from-file:number <- get *m, from-file:offset @@ -584,7 +586,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color assume-screen 30/width, 12/height run [ local-scope - board:address:array:address:array:character <- initial-position + board:board <- initial-position move:address:move <- new move:type *move <- merge 6/g, 1/'2', 6/g, 3/'4' board <- make-move board, move diff --git a/html/edit/001-editor.mu.html b/html/edit/001-editor.mu.html index 6118097e..8eec4b3f 100644 --- a/html/edit/001-editor.mu.html +++ b/html/edit/001-editor.mu.html @@ -37,7 +37,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # temporary main for this layer: just render the given text at the given # screen dimensions, then stop -def! main text:address:array:character [ +def! main text:text [ local-scope load-ingredients open-console @@ -51,8 +51,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-initially-prints-text-to-screen [ assume-screen 10/width, 5/height run [ - 1:address:array:character <- new [abc] - new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + new-editor 1:text, screen:address:screen, 0/left, 10/right ] screen-should-contain [ # top line of screen reserved for menu @@ -83,7 +83,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # creates a new editor widget and renders its initial appearance to screen # top/left/right constrain the screen area available to the new editor # right is exclusive -def new-editor s:address:array:character, screen:address:screen, left:number, right:number -> result:address:editor-data, screen:address:screen [ +def new-editor s:text, screen:address:screen, left:number, right:number -> result:address:editor-data, screen:address:screen [ local-scope load-ingredients # no clipping of bounds @@ -106,7 +106,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <editor-initialization> ] -def insert-text editor:address:editor-data, text:address:array:character -> editor:address:editor-data [ +def insert-text editor:address:editor-data, text:text -> editor:address:editor-data [ local-scope load-ingredients # early exit if text is empty @@ -292,9 +292,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-initially-prints-multiple-lines [ assume-screen 5/width, 5/height run [ - s:address:array:character <- new [abc + s:text <- new [abc def] - new-editor s:address:array:character, screen:address:screen, 0/left, 5/right + new-editor s:text, screen:address:screen, 0/left, 5/right ] screen-should-contain [ . . @@ -307,8 +307,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-initially-handles-offsets [ assume-screen 5/width, 5/height run [ - s:address:array:character <- new [abc] - new-editor s:address:array:character, screen:address:screen, 1/left, 5/right + s:text <- new [abc] + new-editor s:text, screen:address:screen, 1/left, 5/right ] screen-should-contain [ . . @@ -320,9 +320,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-initially-prints-multiple-lines-at-offset [ assume-screen 5/width, 5/height run [ - s:address:array:character <- new [abc + s:text <- new [abc def] - new-editor s:address:array:character, screen:address:screen, 1/left, 5/right + new-editor s:text, screen:address:screen, 1/left, 5/right ] screen-should-contain [ . . @@ -335,8 +335,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-initially-wraps-long-lines [ assume-screen 5/width, 5/height run [ - s:address:array:character <- new [abc def] - new-editor s:address:array:character, screen:address:screen, 0/left, 5/right + s:text <- new [abc def] + new-editor s:text, screen:address:screen, 0/left, 5/right ] screen-should-contain [ . . @@ -355,8 +355,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-initially-wraps-barely-long-lines [ assume-screen 5/width, 5/height run [ - s:address:array:character <- new [abcde] - new-editor s:address:array:character, screen:address:screen, 0/left, 5/right + s:text <- new [abcde] + new-editor s:text, screen:address:screen, 0/left, 5/right ] # still wrap, even though the line would fit. We need room to click on the # end of the line @@ -377,8 +377,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-initializes-empty-text [ assume-screen 5/width, 5/height run [ - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 1:text <- new [] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right 3:number <- get *2:address:editor-data, cursor-row:offset 4:number <- get *2:address:editor-data, cursor-column:offset ] @@ -398,10 +398,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario render-colors-comments [ assume-screen 5/width, 5/height run [ - s:address:array:character <- new [abc + s:text <- new [abc # de f] - new-editor s:address:array:character, screen:address:screen, 0/left, 5/right + new-editor s:text, screen:address:screen, 0/left, 5/right ] screen-should-contain [ . . @@ -479,10 +479,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario render-colors-assignment [ assume-screen 8/width, 5/height run [ - s:address:array:character <- new [abc + s:text <- new [abc d <- e f] - new-editor s:address:array:character, screen:address:screen, 0/left, 8/right + new-editor s:text, screen:address:screen, 0/left, 8/right ] screen-should-contain [ . . diff --git a/html/edit/002-typing.mu.html b/html/edit/002-typing.mu.html index 69e1b614..bba168f6 100644 --- a/html/edit/002-typing.mu.html +++ b/html/edit/002-typing.mu.html @@ -37,7 +37,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # temporary main: interactive editor # hit ctrl-c to exit -def! main text:address:array:character [ +def! main text:text [ local-scope load-ingredients open-console @@ -317,8 +317,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-handles-empty-event-queue [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data assume-console [] run [ @@ -334,8 +334,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-handles-mouse-clicks [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -361,8 +361,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-handles-mouse-clicks-outside-text [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right $clear-trace assume-console [ left-click 1, 7 # last line, to the right of text @@ -381,9 +381,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-handles-mouse-clicks-outside-text-2 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right $clear-trace assume-console [ left-click 1, 7 # interior line, to the right of text @@ -402,9 +402,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-handles-mouse-clicks-outside-text-3 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right $clear-trace assume-console [ left-click 3, 7 # below text @@ -423,9 +423,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-handles-mouse-clicks-outside-column [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] + 1:text <- new [abc] # editor occupies only left half of screen - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -452,8 +452,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-handles-mouse-clicks-in-menu-area [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -474,8 +474,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-inserts-characters-into-empty-editor [ assume-screen 10/width, 5/height - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 1:text <- new [] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -495,8 +495,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-inserts-characters-at-cursor [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # type two letters at different places @@ -519,8 +519,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-inserts-characters-at-cursor-2 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -541,9 +541,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-inserts-characters-at-cursor-5 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -565,8 +565,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-inserts-characters-at-cursor-3 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -587,9 +587,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-inserts-characters-at-cursor-4 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -611,9 +611,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-inserts-characters-at-cursor-6 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -635,8 +635,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-after-inserting-characters [ assume-screen 10/width, 5/height - 1:address:array:character <- new [ab] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 1:text <- new [ab] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data assume-console [ type [01] @@ -656,8 +656,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-wraps-line-on-insert [ assume-screen 5/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data # type a letter assume-console [ @@ -694,9 +694,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-wraps-line-on-insert-2 [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [abcdefg + 1:text <- new [abcdefg defg] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data # type more text at the start assume-console [ @@ -776,8 +776,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-wraps-cursor-after-inserting-characters-in-middle-of-line [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abcde] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 1:text <- new [abcde] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right assume-console [ left-click 1, 3 # right before the wrap icon type [f] @@ -804,7 +804,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color local-scope assume-screen 10/width, 5/height # create an editor containing two lines - contents:address:array:character <- new [abc + contents:text <- new [abc xyz] 1:address:editor-data/raw <- new-editor contents, screen, 0/left, 5/right screen-should-contain [ @@ -831,8 +831,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-wraps-cursor-to-left-margin [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abcde] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 2/left, 7/right + 1:text <- new [abcde] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 2/left, 7/right assume-console [ left-click 1, 5 # line is full; no wrap icon yet type [01] @@ -867,8 +867,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-down-after-inserting-newline [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right assume-console [ type [0 1] @@ -973,8 +973,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-down-after-inserting-newline-2 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 1/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 1/left, 10/right assume-console [ type [0 1] @@ -993,8 +993,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-clears-previous-line-completely-after-inserting-newline [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abcde] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 1:text <- new [abcde] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right assume-console [ press enter ] @@ -1020,10 +1020,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-inserts-indent-after-newline [ assume-screen 10/width, 10/height - 1:address:array:character <- new [ab + 1:text <- new [ab cd ef] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # position cursor after 'cd' and hit 'newline' assume-console [ left-click 2, 8 @@ -1044,10 +1044,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-skips-indent-around-paste [ assume-screen 10/width, 10/height - 1:address:array:character <- new [ab + 1:text <- new [ab cd ef] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # position cursor after 'cd' and hit 'newline' surrounded by paste markers assume-console [ left-click 2, 8 diff --git a/html/edit/003-shortcuts.mu.html b/html/edit/003-shortcuts.mu.html index 61a2f538..ce053fd8 100644 --- a/html/edit/003-shortcuts.mu.html +++ b/html/edit/003-shortcuts.mu.html @@ -41,9 +41,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color 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 + 1:text <- new [ab cd] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right assume-console [ press tab ] @@ -74,8 +74,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-handles-backspace-key [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -252,9 +252,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-clears-last-line-on-backspace [ assume-screen 10/width, 5/height # just one character in final line - 1:address:array:character <- new [ab + 1:text <- new [ab cd] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right assume-console [ left-click 2, 0 # cursor at only character in final line press backspace @@ -279,9 +279,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-joins-and-wraps-lines-on-backspace [ assume-screen 10/width, 5/height # initialize editor with two long-ish but non-wrapping lines - 1:address:array:character <- new [abc def + 1:text <- new [abc def ghi jkl] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # position the cursor at the start of the second and hit backspace @@ -305,8 +305,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-wraps-long-lines-on-backspace [ assume-screen 10/width, 5/height # initialize editor in part of the screen with a long line - 1:address:array:character <- new [abc def ghij] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 8/right + 1:text <- new [abc def ghij] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 8/right editor-render screen, 2:address:editor-data # confirm that it wraps screen-should-contain [ @@ -338,8 +338,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-handles-delete-key [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -427,8 +427,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-right-with-key [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -524,9 +524,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-to-next-line-with-right-arrow [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # type right-arrow a few times to get to start of second line @@ -559,9 +559,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-to-next-line-with-right-arrow-2 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 1/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 1/left, 10/right editor-render screen, 2:address:editor-data assume-console [ press right-arrow @@ -584,8 +584,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abcdef] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 1:text <- new [abcdef] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -614,8 +614,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-2 [ 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:screen, 0/left, 5/right + 1:text <- new [abcde] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data $clear-trace # position cursor at last character before wrap and hit right-arrow @@ -650,8 +650,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-3 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abcdef] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 1/left, 6/right + 1:text <- new [abcdef] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 1/left, 6/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -679,9 +679,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-to-next-line-with-right-arrow-at-end-of-line [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # move to end of line, press right-arrow, type a character @@ -710,8 +710,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-left-with-key [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -753,9 +753,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line [ assume-screen 10/width, 5/height # initialize editor with two lines - 1:address:array:character <- new [abc + 1:text <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # position cursor at start of second line (so there's no previous newline) @@ -778,10 +778,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-2 [ assume-screen 10/width, 5/height # initialize editor with three lines - 1:address:array:character <- new [abc + 1:text <- new [abc def g] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # position cursor further down (so there's a newline before the character at @@ -806,10 +806,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-3 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def g] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # position cursor at start of text, press left-arrow, then type a character @@ -835,10 +835,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-4 [ assume-screen 10/width, 5/height # initialize editor with text containing an empty line - 1:address:array:character <- new [abc + 1:text <- new [abc d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # position cursor right after empty line @@ -863,8 +863,8 @@ d] scenario editor-moves-across-screen-lines-across-wrap-with-left-arrow [ assume-screen 10/width, 5/height # initialize editor with a wrapping line - 1:address:array:character <- new [abcdef] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 1:text <- new [abcdef] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data $clear-trace screen-should-contain [ @@ -894,9 +894,9 @@ d] scenario editor-moves-across-screen-lines-to-wrapping-line-with-left-arrow [ assume-screen 10/width, 5/height # initialize editor with a wrapping line followed by a second line - 1:address:array:character <- new [abcdef + 1:text <- new [abcdef g] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data $clear-trace screen-should-contain [ @@ -926,9 +926,9 @@ d] scenario editor-moves-across-screen-lines-to-non-wrapping-line-with-left-arrow [ assume-screen 10/width, 5/height # initialize editor with a line on the verge of wrapping, followed by a second line - 1:address:array:character <- new [abcd + 1:text <- new [abcd e] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right editor-render screen, 2:address:editor-data $clear-trace screen-should-contain [ @@ -961,9 +961,9 @@ d] scenario editor-moves-to-previous-line-with-up-arrow [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -1077,9 +1077,9 @@ d] scenario editor-adjusts-column-at-previous-line [ assume-screen 10/width, 5/height - 1:address:array:character <- new [ab + 1:text <- new [ab def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -1113,9 +1113,9 @@ d] scenario editor-adjusts-column-at-empty-line [ assume-screen 10/width, 5/height - 1:address:array:character <- new [ + 1:text <- new [ def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -1150,10 +1150,10 @@ d] scenario editor-moves-to-previous-line-from-left-margin [ assume-screen 10/width, 5/height # start out with three lines - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # click on the third line and hit up-arrow, so you end up just after a newline @@ -1190,9 +1190,9 @@ d] scenario editor-moves-to-next-line-with-down-arrow [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # cursor starts out at (1, 0) @@ -1295,9 +1295,9 @@ d] scenario editor-adjusts-column-at-next-line [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc de] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace assume-console [ @@ -1333,9 +1333,9 @@ d] scenario editor-moves-to-start-of-line-with-ctrl-a [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # start on second line, press ctrl-a @@ -1408,9 +1408,9 @@ d] scenario editor-moves-to-start-of-line-with-ctrl-a-2 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # start on first line (no newline before), press ctrl-a @@ -1433,9 +1433,9 @@ d] scenario editor-moves-to-start-of-line-with-home [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right $clear-trace # start on second line, press 'home' assume-console [ @@ -1457,9 +1457,9 @@ d] scenario editor-moves-to-start-of-line-with-home-2 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # start on first line (no newline before), press 'home' @@ -1484,9 +1484,9 @@ d] scenario editor-moves-to-end-of-line-with-ctrl-e [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # start on first line, press ctrl-e @@ -1576,9 +1576,9 @@ d] scenario editor-moves-to-end-of-line-with-ctrl-e-2 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # start on second line (no newline after), press ctrl-e @@ -1601,9 +1601,9 @@ d] scenario editor-moves-to-end-of-line-with-end [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # start on first line, press 'end' @@ -1626,9 +1626,9 @@ d] scenario editor-moves-to-end-of-line-with-end-2 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # start on second line (no newline after), press 'end' @@ -1653,9 +1653,9 @@ d] scenario editor-deletes-to-start-of-line-with-ctrl-u [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # start on second line, press ctrl-u assume-console [ left-click 2, 2 @@ -1716,9 +1716,9 @@ d] scenario editor-deletes-to-start-of-line-with-ctrl-u-2 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # start on first line (no newline before), press ctrl-u assume-console [ left-click 1, 2 @@ -1739,9 +1739,9 @@ d] scenario editor-deletes-to-start-of-line-with-ctrl-u-3 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # start past end of line, press ctrl-u assume-console [ left-click 1, 3 @@ -1762,9 +1762,9 @@ d] scenario editor-deletes-to-start-of-final-line-with-ctrl-u [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # start past end of final line, press ctrl-u assume-console [ left-click 2, 3 @@ -1787,9 +1787,9 @@ d] scenario editor-deletes-to-end-of-line-with-ctrl-k [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # start on first line, press ctrl-k assume-console [ left-click 1, 1 @@ -1842,9 +1842,9 @@ d] scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # start on second line (no newline after), press ctrl-k assume-console [ left-click 2, 1 @@ -1865,9 +1865,9 @@ d] scenario editor-deletes-to-end-of-line-with-ctrl-k-3 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # start at end of line assume-console [ left-click 1, 2 @@ -1888,9 +1888,9 @@ d] scenario editor-deletes-to-end-of-line-with-ctrl-k-4 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # start past end of line assume-console [ left-click 1, 3 @@ -1911,9 +1911,9 @@ d] scenario editor-deletes-to-end-of-line-with-ctrl-k-5 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # start at end of text assume-console [ left-click 2, 2 @@ -1934,9 +1934,9 @@ d] scenario editor-deletes-to-end-of-line-with-ctrl-k-6 [ assume-screen 10/width, 5/height - 1:address:array:character <- new [123 + 1:text <- new [123 456] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right # start past end of text assume-console [ left-click 2, 3 @@ -1961,11 +1961,11 @@ d] # screen has 1 line for menu + 3 lines assume-screen 10/width, 4/height # initialize editor with >3 lines - 1:address:array:character <- new [a + 1:text <- new [a b c d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right screen-should-contain [ . . .a . @@ -2039,11 +2039,11 @@ d] assume-screen 10/width, 4/height # initialize editor with a long, wrapped line and more than a screen of # other lines - 1:address:array:character <- new [abcdef + 1:text <- new [abcdef g h i] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right screen-should-contain [ . . .abcd↩ . @@ -2071,11 +2071,11 @@ d] # screen has 1 line for menu + 3 lines assume-screen 10/width, 4/height # editor starts with a long line wrapping twice - 1:address:array:character <- new [abcdefghij + 1:text <- new [abcdefghij k l m] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right # position cursor at last line, then try to move further down assume-console [ left-click 3, 0 @@ -2111,10 +2111,10 @@ d] # screen has 1 line for menu + 3 lines assume-screen 5/width, 4/height # editor contains a long line in the third line - 1:address:array:character <- new [a + 1:text <- new [a b cdef] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right # position cursor at end, type a character assume-console [ left-click 3, 4 @@ -2141,10 +2141,10 @@ d] scenario editor-scrolls-down-on-newline [ assume-screen 5/width, 4/height # position cursor after last line and type newline - 1:address:array:character <- new [a + 1:text <- new [a b c] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right assume-console [ left-click 3, 4 type [ @@ -2172,10 +2172,10 @@ d] # screen has 1 line for menu + 3 lines assume-screen 5/width, 4/height # editor contains a wrapped line - 1:address:array:character <- new [a + 1:text <- new [a b cdefgh] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right # position cursor at end of screen and try to move right assume-console [ left-click 3, 3 @@ -2203,11 +2203,11 @@ d] # screen has 1 line for menu + 3 lines assume-screen 5/width, 4/height # editor contains more lines than can fit on screen - 1:address:array:character <- new [a + 1:text <- new [a b c d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right # position cursor at end of screen and try to move right assume-console [ left-click 3, 3 @@ -2233,9 +2233,9 @@ d] scenario editor-scrolls-at-end-on-down-arrow [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc de] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data $clear-trace # try to move down past end of text @@ -2300,14 +2300,14 @@ d] # screen has 1 line for menu + 3 lines assume-screen 10/width, 4/height # initialize editor with a few pages of lines - 1:address:array:character <- new [a + 1:text <- new [a b c d e f g] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right # scroll down one page and one line assume-console [ press page-down @@ -2332,11 +2332,11 @@ d] # screen has 1 line for menu + 3 lines assume-screen 10/width, 4/height # initialize editor with >3 lines - 1:address:array:character <- new [a + 1:text <- new [a b c d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right screen-should-contain [ . . .a . @@ -2420,11 +2420,11 @@ d] assume-screen 10/width, 4/height # initialize editor with a long, wrapped line and more than a screen of # other lines - 1:address:array:character <- new [abcdef + 1:text <- new [abcdef g h i] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right screen-should-contain [ . . .abcd↩ . @@ -2464,11 +2464,11 @@ d] # screen has 1 line for menu + 4 lines assume-screen 10/width, 5/height # editor starts with a long line wrapping twice, occupying 3 of the 4 lines - 1:address:array:character <- new [abcdefghij + 1:text <- new [abcdefghij k l m] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right # position cursor at top of second page assume-console [ press page-down @@ -2537,11 +2537,11 @@ d] assume-screen 10/width, 4/height # initialize editor with a long, wrapped line and more than a screen of # other lines - 1:address:array:character <- new [abcdef + 1:text <- new [abcdef g h i] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 6/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 6/right screen-should-contain [ . . .abcde↩ . @@ -2581,13 +2581,13 @@ d] scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-4 [ assume-screen 10/width, 4/height # initialize editor with some lines around an empty line - 1:address:array:character <- new [a + 1:text <- new [a b c d e] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 6/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 6/right assume-console [ press page-down ] @@ -2630,12 +2630,12 @@ e] # screen has 1 line for menu + 3 lines assume-screen 5/width, 4/height # editor contains >3 lines - 1:address:array:character <- new [a + 1:text <- new [a b c d e] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right # position cursor at top of second page assume-console [ press page-down @@ -2675,11 +2675,11 @@ e] # screen has 1 line for menu + 3 lines assume-screen 10/width, 4/height # initialize editor with >3 lines - 1:address:array:character <- new [a + 1:text <- new [a b c d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right screen-should-contain [ . . .a . @@ -2723,11 +2723,11 @@ e] scenario editor-can-scroll [ assume-screen 10/width, 4/height - 1:address:array:character <- new [a + 1:text <- new [a b c d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right screen-should-contain [ . . .a . @@ -2810,9 +2810,9 @@ e] scenario editor-does-not-scroll-past-end [ assume-screen 10/width, 4/height - 1:address:array:character <- new [a + 1:text <- new [a b] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data screen-should-contain [ . . @@ -2840,11 +2840,11 @@ e] # screen has 1 line for menu + 3 lines for text assume-screen 10/width, 4/height # editor contains a long last line - 1:address:array:character <- new [a + 1:text <- new [a b cdefgh] # editor screen triggers wrap of last line - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 4/right # some part of last line is not displayed screen-should-contain [ . . @@ -2873,9 +2873,9 @@ e] assume-screen 10/width, 4/height # editor contains a very long line that occupies last two lines of screen # and still has something left over - 1:address:array:character <- new [a + 1:text <- new [a bcdefgh] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 4/right # some part of last line is not displayed screen-should-contain [ . . @@ -2903,11 +2903,11 @@ e] scenario editor-can-scroll-up [ assume-screen 10/width, 4/height - 1:address:array:character <- new [a + 1:text <- new [a b c d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right screen-should-contain [ . . .a . @@ -2999,7 +2999,7 @@ e] # screen has 1 line for menu + 3 lines assume-screen 10/width, 4/height # initialize editor with 8 lines - 1:address:array:character <- new [a + 1:text <- new [a b c d @@ -3007,7 +3007,7 @@ e] f g h] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right screen-should-contain [ . . .a . @@ -3063,7 +3063,7 @@ e] # screen has 1 line for menu + 5 lines for text assume-screen 10/width, 6/height # editor contains a long line in the first page - 1:address:array:character <- new [a + 1:text <- new [a b cdefgh i @@ -3074,7 +3074,7 @@ e] n o] # editor screen triggers wrap of last line - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 4/right # some part of last line is not displayed screen-should-contain [ . . @@ -3125,9 +3125,9 @@ e] assume-screen 10/width, 4/height # editor contains a very long line that occupies last two lines of screen # and still has something left over - 1:address:array:character <- new [a + 1:text <- new [a bcdefgh] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 4/right # some part of last line is not displayed screen-should-contain [ . . @@ -3168,7 +3168,7 @@ e] scenario editor-can-scroll-up-past-nonempty-lines [ assume-screen 10/width, 4/height # text with empty line in second screen - 1:address:array:character <- new [axx + 1:text <- new [axx bxx cxx dxx @@ -3177,7 +3177,7 @@ e] gxx hxx ] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 4/right screen-should-contain [ . . .axx . @@ -3226,7 +3226,7 @@ e] scenario editor-can-scroll-up-past-empty-lines [ assume-screen 10/width, 4/height # text with empty line in second screen - 1:address:array:character <- new [axy + 1:text <- new [axy bxy cxy @@ -3235,7 +3235,7 @@ exy fxy gxy ] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 4/right screen-should-contain [ . . .axy . diff --git a/html/edit/004-programming-environment.mu.html b/html/edit/004-programming-environment.mu.html index a640fa59..24b66e0d 100644 --- a/html/edit/004-programming-environment.mu.html +++ b/html/edit/004-programming-environment.mu.html @@ -42,8 +42,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color def! main [ local-scope open-console - initial-recipe:address:array:character <- restore [recipes.mu] - initial-sandbox:address:array:character <- new [] + initial-recipe:text <- restore [recipes.mu] + initial-sandbox:text <- new [] hide-screen 0/screen env:address:programming-environment-data <- new-programming-environment 0/screen, initial-recipe, initial-sandbox render-all 0/screen, env, render @@ -57,7 +57,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color sandbox-in-focus?:boolean # false => cursor in recipes; true => cursor in current-sandbox ] -def new-programming-environment screen:address:screen, initial-recipe-contents:address:array:character, initial-sandbox-contents:address:array:character -> result:address:programming-environment-data, screen:address:screen [ +def new-programming-environment screen:address:screen, initial-recipe-contents:text, initial-sandbox-contents:text -> result:address:programming-environment-data, screen:address:screen [ local-scope load-ingredients width:number <- screen-width screen @@ -332,9 +332,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long 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:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [abc] + 2:text <- new [def] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # focus on both sides assume-console [ left-click 1, 1 @@ -358,9 +358,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long 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:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [abc] + 2:text <- new [def] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render # type one letter in each of them assume-console [ @@ -403,9 +403,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long 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:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [abc] + 2:text <- new [def] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render ] # divider isn't messed up @@ -421,9 +421,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-in-focus-keeps-cursor [ trace-until 100/app # trace too long assume-screen 30/width, 5/height - 1:address:array:character <- new [abc] - 2:address:array:character <- new [def] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [abc] + 2:text <- new [def] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render # initialize programming environment and highlight cursor assume-console [] @@ -461,10 +461,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color #? trace-until 100/app # trace too long assume-screen 30/width, 5/height # initialize sandbox side with two lines - 1:address:array:character <- new [] - 2:address:array:character <- new [abc + 1:text <- new [] + 2:text <- new [abc def] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render screen-should-contain [ . run (F4) . @@ -576,7 +576,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ] # like 'render' for texts, but with colorization for comments like in the editor -def render-code screen:address:screen, s:address:array:character, left:number, right:number, row:number -> row:number, screen:address:screen [ +def render-code screen:address:screen, s:text, left:number, right:number, row:number -> row:number, screen:address:screen [ local-scope load-ingredients return-unless s diff --git a/html/edit/005-sandbox.mu.html b/html/edit/005-sandbox.mu.html index 7c4fe9e8..47a291e5 100644 --- a/html/edit/005-sandbox.mu.html +++ b/html/edit/005-sandbox.mu.html @@ -45,8 +45,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color def! main [ local-scope open-console - initial-recipe:address:array:character <- restore [recipes.mu] - initial-sandbox:address:array:character <- new [] + initial-recipe:text <- restore [recipes.mu] + initial-sandbox:text <- new [] hide-screen 0/screen env:address:programming-environment-data <- new-programming-environment 0/screen, initial-recipe, initial-sandbox env <- restore-sandboxes env @@ -66,8 +66,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ] container sandbox-data [ - data:address:array:character - response:address:array:character + data:text + response:text # coordinates to track clicks # constraint: will be 0 for sandboxes at positions before env.render-from starting-row-on-screen:number @@ -80,10 +80,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 15/height # recipe editor is empty - 1:address:array:character <- new [] + 1:text <- new [] # sandbox editor contains an instruction without storing outputs - 2:address:array:character <- new [divide-with-remainder 11, 3] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [divide-with-remainder 11, 3] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # run the code in the editors assume-console [ press F4 @@ -186,7 +186,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <run-sandboxes-begin> current-sandbox:address:editor-data <- get *env, current-sandbox:offset { - sandbox-contents:address:array:character <- editor-contents current-sandbox + sandbox-contents:text <- editor-contents current-sandbox break-unless sandbox-contents # if contents exist, first save them # run them and turn them into a new sandbox-data @@ -226,7 +226,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color local-scope load-ingredients recipes:address:editor-data <- get *env, recipes:offset - in:address:array:character <- editor-contents recipes + in:text <- editor-contents recipes save [recipes.mu], in # newlayer: persistence reload in errors-found? <- copy 0/false @@ -236,13 +236,13 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color def! update-sandbox sandbox:address:sandbox-data, env:address:programming-environment-data, idx:number -> sandbox:address:sandbox-data, env:address:programming-environment-data [ local-scope load-ingredients - data:address:array:character <- get *sandbox, data:offset - response:address:array:character, _, fake-screen:address:screen <- run-sandboxed data + data:text <- get *sandbox, data:offset + response:text, _, fake-screen:address:screen <- run-sandboxed data *sandbox <- put *sandbox, response:offset, response *sandbox <- put *sandbox, screen:offset, fake-screen ] -def update-status screen:address:screen, msg:address:array:character, color:number -> screen:address:screen [ +def update-status screen:address:screen, msg:text, color:number -> screen:address:screen [ local-scope load-ingredients screen <- move-cursor screen, 0, 2 @@ -259,8 +259,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color idx:number <- copy 0 { break-unless curr - data:address:array:character <- get *curr, data:offset - filename:address:array:character <- to-text idx + data:text <- get *curr, data:offset + filename:text <- to-text idx save filename, data <end-save-sandbox> idx <- add idx, 1 @@ -312,11 +312,11 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # render sandbox contents row <- add row, 1 screen <- move-cursor screen, row, left - sandbox-data:address:array:character <- get *sandbox, data:offset + sandbox-data:text <- get *sandbox, data:offset row, screen <- render-code screen, sandbox-data, left, right, row *sandbox <- put *sandbox, code-ending-row-on-screen:offset, row # render sandbox warnings, screen or response, in that order - sandbox-response:address:array:character <- get *sandbox, response:offset + sandbox-response:text <- get *sandbox, response:offset <render-sandbox-results> { sandbox-screen:address:screen <- get *sandbox, screen:offset @@ -390,7 +390,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # print a text 's' to 'editor' in 'color' starting at 'row' # clear rest of last line, move cursor to next line -def render-text screen:address:screen, s:address:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:screen [ +def render-text screen:address:screen, s:text, left:number, right:number, color:number, row:number -> row:number, screen:address:screen [ local-scope load-ingredients return-unless s @@ -459,8 +459,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color curr:address:sandbox-data <- copy 0 prev:address:sandbox-data <- copy 0 { - filename:address:array:character <- to-text idx - contents:address:array:character <- restore filename + filename:text <- to-text idx + contents:text <- restore filename break-unless contents # stop at first error; assuming file didn't exist # todo: handle empty sandbox # create new sandbox for file @@ -554,15 +554,15 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long 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:text <- new [ recipe foo [ local-scope z:number <- add 2, 2 reply z ]] # sandbox editor contains an instruction without storing outputs - 2:address:array:character <- new [foo] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [foo] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # run the code in the editors assume-console [ press F4 @@ -607,10 +607,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 20/height # left editor is empty - 1:address:array:character <- new [] + 1:text <- new [] # right editor contains an instruction - 2:address:array:character <- new [print-integer screen, 4] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [print-integer screen, 4] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # run the code in the editor assume-console [ press F4 @@ -636,7 +636,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ] ] -def editor-contents editor:address:editor-data -> result:address:array:character [ +def editor-contents editor:address:editor-data -> result:text [ local-scope load-ingredients buf:address:buffer <- new-buffer 80 @@ -657,16 +657,16 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-provides-edited-contents [ assume-screen 10/width, 5/height - 1:address:array:character <- new [abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right assume-console [ left-click 1, 2 type [def] ] run [ editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - 3:address:array:character <- editor-contents 2:address:editor-data - 4:array:character <- copy *3:address:array:character + 3:text <- editor-contents 2:address:editor-data + 4:array:character <- copy *3:text ] memory-should-contain [ 4:array:character <- [abdefc] @@ -833,9 +833,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # initialize sandbox side - 1:address:array:character <- new [] - 2:address:array:character <- new [add 2, 2] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [add 2, 2] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render assume-console [ # create a sandbox @@ -966,11 +966,11 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # initialize sandbox side and create a sandbox - 1:address:array:character <- new [ + 1:text <- new [ ] # create a sandbox - 2:address:array:character <- new [add 2, 2] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [add 2, 2] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render assume-console [ press F4 @@ -999,9 +999,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # initialize environment - 1:address:array:character <- new [] - 2:address:array:character <- new [] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render # create 2 sandboxes assume-console [ @@ -1151,9 +1151,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # initialize environment - 1:address:array:character <- new [] - 2:address:array:character <- new [] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render # create a sandbox assume-console [ diff --git a/html/edit/006-sandbox-copy.mu.html b/html/edit/006-sandbox-copy.mu.html index ccf5d361..fe86e811 100644 --- a/html/edit/006-sandbox-copy.mu.html +++ b/html/edit/006-sandbox-copy.mu.html @@ -39,16 +39,16 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # basic recipe - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ reply 4 ]] # run it - 2:address:array:character <- new [foo] + 2:text <- new [foo] assume-console [ press F4 ] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data screen-should-contain [ . run (F4) . @@ -101,16 +101,16 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # basic recipe - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ reply 4 ]] # run it - 2:address:array:character <- new [foo] + 2:text <- new [foo] assume-console [ press F4 ] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data screen-should-contain [ . run (F4) . @@ -201,7 +201,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color sandbox:address:sandbox-data <- find-sandbox env, click-row return-unless sandbox, 0/false clicked-on-copy-button? <- copy 1/true - text:address:array:character <- get *sandbox, data:offset + text:text <- get *sandbox, data:offset current-sandbox:address:editor-data <- get *env, current-sandbox:offset current-sandbox <- insert-text current-sandbox, text # reset scroll @@ -258,16 +258,16 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # basic recipe - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ reply 4 ]] # run it - 2:address:array:character <- new [foo] + 2:text <- new [foo] assume-console [ press F4 ] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data screen-should-contain [ . run (F4) . diff --git a/html/edit/007-sandbox-delete.mu.html b/html/edit/007-sandbox-delete.mu.html index f9f26d6f..94ca6a6c 100644 --- a/html/edit/007-sandbox-delete.mu.html +++ b/html/edit/007-sandbox-delete.mu.html @@ -37,9 +37,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario deleting-sandboxes [ trace-until 100/app # trace too long 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:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # run a few commands assume-console [ left-click 1, 80 @@ -185,9 +185,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # initialize environment - 1:address:array:character <- new [] - 2:address:array:character <- new [] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render # create 2 sandboxes and scroll to second assume-console [ @@ -231,9 +231,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # initialize environment - 1:address:array:character <- new [] - 2:address:array:character <- new [] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render # create 2 sandboxes and scroll to second assume-console [ @@ -277,9 +277,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # initialize environment - 1:address:array:character <- new [] - 2:address:array:character <- new [] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render # create 2 sandboxes and scroll to second assume-console [ @@ -325,9 +325,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # initialize environment - 1:address:array:character <- new [] - 2:address:array:character <- new [] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render # create 2 sandboxes assume-console [ diff --git a/html/edit/008-sandbox-edit.mu.html b/html/edit/008-sandbox-edit.mu.html index e79738c5..18926f44 100644 --- a/html/edit/008-sandbox-edit.mu.html +++ b/html/edit/008-sandbox-edit.mu.html @@ -38,16 +38,16 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # basic recipe - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ reply 4 ]] # run it - 2:address:array:character <- new [foo] + 2:text <- new [foo] assume-console [ press F4 ] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data screen-should-contain [ . run (F4) . @@ -98,16 +98,16 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # basic recipe - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ reply 4 ]] # run it - 2:address:array:character <- new [foo] + 2:text <- new [foo] assume-console [ press F4 ] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data screen-should-contain [ . run (F4) . @@ -197,7 +197,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color return-unless sandbox, 0/false clicked-on-edit-button? <- copy 1/true # 'edit' button = 'copy' button + 'delete' button - text:address:array:character <- get *sandbox, data:offset + text:text <- get *sandbox, data:offset current-sandbox:address:editor-data <- get *env, current-sandbox:offset current-sandbox <- insert-text current-sandbox, text env <- delete-sandbox env, sandbox @@ -211,10 +211,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 20/height # left editor is empty - 1:address:array:character <- new [] + 1:text <- new [] # right editor contains an instruction - 2:address:array:character <- new [print-integer screen, 4] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [print-integer screen, 4] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # run the sandbox assume-console [ press F4 @@ -255,9 +255,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # initialize environment - 1:address:array:character <- new [] - 2:address:array:character <- new [] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render # create 2 sandboxes and scroll to second assume-console [ @@ -303,9 +303,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # initialize environment - 1:address:array:character <- new [] - 2:address:array:character <- new [] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text render-all screen, 3:address:programming-environment-data, render # create 2 sandboxes assume-console [ diff --git a/html/edit/009-sandbox-test.mu.html b/html/edit/009-sandbox-test.mu.html index eeb61f7f..1772865b 100644 --- a/html/edit/009-sandbox-test.mu.html +++ b/html/edit/009-sandbox-test.mu.html @@ -39,16 +39,16 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # basic recipe - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ reply 4 ]] # run it - 2:address:array:character <- new [foo] + 2:text <- new [foo] assume-console [ press F4 ] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data screen-should-contain [ . run (F4) . @@ -122,13 +122,13 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # this requires tracking a couple more things container sandbox-data [ response-starting-row-on-screen:number - expected-response:address:array:character + expected-response:text ] # include expected response when saving or restoring a sandbox before <end-save-sandbox> [ { - expected-response:address:array:character <- get *curr, expected-response:offset + expected-response:text <- get *curr, expected-response:offset break-unless expected-response filename <- append filename, [.out] save filename, expected-response @@ -202,7 +202,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color def toggle-expected-response sandbox:address:sandbox-data -> sandbox:address:sandbox-data [ local-scope load-ingredients - expected-response:address:array:character <- get *sandbox, expected-response:offset + expected-response:text <- get *sandbox, expected-response:offset { # if expected-response is set, reset break-unless expected-response @@ -211,7 +211,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color { # if not, set expected response to the current response break-if expected-response - response:address:array:character <- get *sandbox, response:offset + response:text <- get *sandbox, response:offset *sandbox <- put *sandbox, expected-response:offset, response } ] @@ -221,7 +221,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color { break-unless sandbox-response *sandbox <- put *sandbox, response-starting-row-on-screen:offset, row - expected-response:address:array:character <- get *sandbox, expected-response:offset + expected-response:text <- get *sandbox, expected-response:offset break-unless expected-response # fall-through to print in grey response-is-expected?:boolean <- equal expected-response, sandbox-response { diff --git a/html/edit/010-sandbox-trace.mu.html b/html/edit/010-sandbox-trace.mu.html index a5c77f15..3c4956b7 100644 --- a/html/edit/010-sandbox-trace.mu.html +++ b/html/edit/010-sandbox-trace.mu.html @@ -39,16 +39,16 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # basic recipe - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ stash [abc] ]] # run it - 2:address:array:character <- new [foo] + 2:text <- new [foo] assume-console [ press F4 ] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data screen-should-contain [ . run (F4) . @@ -115,17 +115,17 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # basic recipe - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ stash [abc] reply 4 ]] # run it - 2:address:array:character <- new [foo] + 2:text <- new [foo] assume-console [ press F4 ] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data screen-should-contain [ . run (F4) . @@ -162,14 +162,14 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario clicking-on-app-trace-does-nothing [ trace-until 100/app # trace too long assume-screen 100/width, 10/height - 1:address:array:character <- new [] + 1:text <- new [] # create and expand the trace - 2:address:array:character <- new [stash 123456789] + 2:text <- new [stash 123456789] assume-console [ press F4 left-click 4, 51 ] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data screen-should-contain [ . run (F4) . @@ -204,7 +204,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ] container sandbox-data [ - trace:address:array:character + trace:text display-trace?:boolean ] @@ -212,8 +212,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color def! update-sandbox sandbox:address:sandbox-data, env:address:programming-environment-data, idx:number -> sandbox:address:sandbox-data, env:address:programming-environment-data [ local-scope load-ingredients - data:address:array:character <- get *sandbox, data:offset - response:address:array:character, _, fake-screen:address:screen, trace:address:array:character <- run-sandboxed data + data:text <- get *sandbox, data:offset + response:text, _, fake-screen:address:screen, trace:text <- run-sandboxed data *sandbox <- put *sandbox, response:offset, response *sandbox <- put *sandbox, screen:offset, fake-screen *sandbox <- put *sandbox, trace:offset, trace @@ -285,7 +285,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color { display-trace?:boolean <- get *sandbox, display-trace?:offset break-unless display-trace? - sandbox-trace:address:array:character <- get *sandbox, trace:offset + sandbox-trace:text <- get *sandbox, trace:offset break-unless sandbox-trace # nothing to print; move on row, screen <- render-text screen, sandbox-trace, left, right, 245/grey, row } diff --git a/html/edit/011-errors.mu.html b/html/edit/011-errors.mu.html index b9f46f1b..6d0117bb 100644 --- a/html/edit/011-errors.mu.html +++ b/html/edit/011-errors.mu.html @@ -36,7 +36,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ## handling malformed programs container programming-environment-data [ - recipe-errors:address:array:character + recipe-errors:text ] # copy code from recipe editor, persist, load into mu, save any errors @@ -44,9 +44,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color local-scope load-ingredients recipes:address:editor-data <- get *env, recipes:offset - in:address:array:character <- editor-contents recipes + in:text <- editor-contents recipes save [recipes.mu], in - recipe-errors:address:array:character <- reload in + recipe-errors:text <- reload in *env <- put *env, recipe-errors:offset, recipe-errors # if recipe editor has errors, stop { @@ -60,7 +60,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color before <render-components-end> [ trace 11, [app], [render status] - recipe-errors:address:array:character <- get *env, recipe-errors:offset + recipe-errors:text <- get *env, recipe-errors:offset { break-unless recipe-errors update-status screen, [errors found ], 1/red @@ -69,7 +69,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color before <render-recipe-components-end> [ { - recipe-errors:address:array:character <- get *env, recipe-errors:offset + recipe-errors:text <- get *env, recipe-errors:offset break-unless recipe-errors row, screen <- render-text screen, recipe-errors, left, right, 1/red, row } @@ -102,21 +102,21 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color error-index:number <- get *env, error-index:offset sandboxes-completed-successfully?:boolean <- equal error-index, -1 break-if sandboxes-completed-successfully? - error-index-text:address:array:character <- to-text error-index - status:address:array:character <- interpolate [errors found (_) ], error-index-text + error-index-text:text <- to-text error-index + status:text <- interpolate [errors found (_) ], error-index-text update-status screen, status, 1/red } ] container sandbox-data [ - errors:address:array:character + errors:text ] def! update-sandbox sandbox:address:sandbox-data, env:address:programming-environment-data, idx:number -> sandbox:address:sandbox-data, env:address:programming-environment-data [ local-scope load-ingredients - data:address:array:character <- get *sandbox, data:offset - response:address:array:character, errors:address:array:character, fake-screen:address:screen, trace:address:array:character, completed?:boolean <- run-sandboxed data + data:text <- get *sandbox, data:offset + response:text, errors:text, fake-screen:address:screen, trace:text, completed?:boolean <- run-sandboxed data *sandbox <- put *sandbox, response:offset, response *sandbox <- put *sandbox, errors:offset, errors *sandbox <- put *sandbox, screen:offset, fake-screen @@ -140,7 +140,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # make sure we render any trace after <render-sandbox-trace-done> [ { - sandbox-errors:address:array:character <- get *sandbox, errors:offset + sandbox-errors:text <- get *sandbox, errors:offset break-unless sandbox-errors *sandbox <- put *sandbox, response-starting-row-on-screen:offset, 0 # no response row, screen <- render-text screen, sandbox-errors, left, right, 1/red, row @@ -152,12 +152,12 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario run-shows-errors-in-get [ trace-until 100/app # trace too long assume-screen 100/width, 15/height - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ get 123:number, foo:offset ]] - 2:address:array:character <- new [foo] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [foo] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text assume-console [ press F4 ] @@ -192,9 +192,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario run-updates-status-with-first-erroneous-sandbox [ trace-until 100/app # trace too long 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:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text assume-console [ left-click 3, 80 # create invalid sandbox 1 @@ -216,9 +216,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario run-updates-status-with-first-erroneous-sandbox-2 [ trace-until 100/app # trace too long 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:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text assume-console [ left-click 3, 80 # create invalid sandbox 2 @@ -243,9 +243,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario run-hides-errors-from-past-sandboxes [ trace-until 100/app # trace too long assume-screen 100/width, 15/height - 1:address:array:character <- new [] - 2:address:array:character <- new [get foo, x:offset] # invalid - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 1:text <- new [] + 2:text <- new [get foo, x:offset] # invalid + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text assume-console [ press F4 # generate error ] @@ -278,14 +278,14 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 15/height # define a shape-shifting recipe with an error - 1:address:array:character <- new [recipe foo x:_elem -> z:_elem [ + 1:text <- new [recipe foo x:_elem -> z:_elem [ local-scope load-ingredients y:address:number <- copy 0 z <- add x, y ]] - 2:address:array:character <- new [foo 2] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [foo 2] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text assume-console [ press F4 ] @@ -326,12 +326,12 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 15/height # overload a well-known shape-shifting recipe - 1:address:array:character <- new [recipe length l:address:list:_elem -> n:number [ + 1:text <- new [recipe length l:address:list:_elem -> n:number [ ]] # call code that uses other variants of it, but not it itself - 2:address:array:character <- new [x:address:list:number <- copy 0 + 2:text <- new [x:address:list:number <- copy 0 to-text x] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # run it once assume-console [ press F4 @@ -385,12 +385,12 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario run-shows-missing-type-errors [ trace-until 100/app # trace too long assume-screen 100/width, 15/height - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ x <- copy 0 ]] - 2:address:array:character <- new [foo] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [foo] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text assume-console [ press F4 ] @@ -411,12 +411,12 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 15/height # recipe is incomplete (unbalanced '[') - 1:address:array:character <- new [ + 1:text <- new [ recipe foo \\[ x <- copy 0 ] - 2:address:array:character <- new [foo] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [foo] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text assume-console [ press F4 ] @@ -438,14 +438,14 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario run-shows-get-on-non-container-errors [ trace-until 100/app # trace too long assume-screen 100/width, 15/height - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ local-scope x:address:point <- new point:type get x:address:point, 1:offset ]] - 2:address:array:character <- new [foo] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [foo] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text assume-console [ press F4 ] @@ -470,15 +470,15 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario run-shows-non-literal-get-argument-errors [ trace-until 100/app # trace too long assume-screen 100/width, 15/height - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ local-scope x:number <- copy 0 y:address:point <- new point:type get *y:address:point, x:number ]] - 2:address:array:character <- new [foo] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [foo] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text assume-console [ press F4 ] @@ -505,13 +505,13 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long # try to run a file with an error assume-screen 100/width, 15/height - 1:address:array:character <- new [ + 1:text <- new [ recipe foo [ local-scope x:number <- copy y:number ]] - 2:address:array:character <- new [foo] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [foo] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text assume-console [ press F4 ] @@ -551,10 +551,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # left editor is empty - 1:address:array:character <- new [] + 1:text <- 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:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [get 1234:number, foo:offset] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # run the code in the editors assume-console [ press F4 @@ -614,10 +614,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # left editor is empty - 1:address:array:character <- new [] + 1:text <- 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:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [get 1234:number, foo:offset] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # run the code in the editors multiple times assume-console [ press F4 @@ -645,14 +645,14 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 20/height # left editor is empty - 1:address:array:character <- new [recipe foo [ + 1:text <- new [recipe foo [ { loop } ]] # right editor contains an instruction - 2:address:array:character <- new [foo] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [foo] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # run the sandbox assume-console [ press F4 @@ -676,7 +676,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color trace-until 100/app # trace too long assume-screen 100/width, 10/height # generate a stash and a error - 1:address:array:character <- new [recipe foo [ + 1:text <- new [recipe foo [ local-scope a:number <- next-ingredient b:number <- next-ingredient @@ -684,8 +684,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color _, c:number <- divide-with-remainder a, b reply b ]] - 2:address:array:character <- new [foo 4, 0] - 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character + 2:text <- new [foo 4, 0] + 3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:text, 2:text # run assume-console [ press F4 diff --git a/html/edit/012-editor-undo.mu.html b/html/edit/012-editor-undo.mu.html index 0518d0ad..ff375027 100644 --- a/html/edit/012-editor-undo.mu.html +++ b/html/edit/012-editor-undo.mu.html @@ -136,8 +136,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-typing [ # create an editor and type a character assume-screen 10/width, 5/height - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data assume-console [ type [0] @@ -266,8 +266,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-typing-multiple [ # create an editor and type multiple characters assume-screen 10/width, 5/height - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data assume-console [ type [012] @@ -292,8 +292,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-typing-multiple-2 [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [a] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [a] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # type some characters assume-console [ @@ -338,8 +338,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-typing-enter [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [ abc] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [ abc] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # new line assume-console [ @@ -401,8 +401,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-redo-typing [ # create an editor, type something, undo assume-screen 10/width, 5/height - 1:address:array:character <- new [a] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [a] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data assume-console [ type [012] @@ -465,8 +465,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-redo-typing-empty [ # create an editor, type something, undo assume-screen 10/width, 5/height - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data assume-console [ type [012] @@ -511,10 +511,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-work-clears-redo-stack [ # create an editor with some text, do some work, undo assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data assume-console [ type [1] @@ -553,8 +553,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-redo-typing-and-enter-and-tab [ # create an editor assume-screen 10/width, 5/height - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # insert some text and tabs, hit enter, some more text and tabs assume-console [ @@ -710,10 +710,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-touch [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # move the cursor assume-console [ @@ -801,10 +801,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color # screen has 1 line for menu + 3 lines assume-screen 5/width, 4/height # editor contains a wrapped line - 1:address:array:character <- new [a + 1:text <- new [a b cdefgh] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 5/right # position cursor at end of screen and try to move right assume-console [ left-click 3, 3 @@ -863,10 +863,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-left-arrow [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # move the cursor assume-console [ @@ -907,10 +907,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-up-arrow [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # move the cursor assume-console [ @@ -957,10 +957,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-down-arrow [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # move the cursor assume-console [ @@ -1001,13 +1001,13 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-ctrl-f [ # create an editor with multiple pages of text assume-screen 10/width, 5/height - 1:address:array:character <- new [a + 1:text <- new [a b c d e f] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # scroll the page assume-console [ @@ -1036,13 +1036,13 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-page-down [ # create an editor with multiple pages of text assume-screen 10/width, 5/height - 1:address:array:character <- new [a + 1:text <- new [a b c d e f] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # scroll the page assume-console [ @@ -1071,13 +1071,13 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-ctrl-b [ # create an editor with multiple pages of text assume-screen 10/width, 5/height - 1:address:array:character <- new [a + 1:text <- new [a b c d e f] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # scroll the page down and up assume-console [ @@ -1107,13 +1107,13 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-page-up [ # create an editor with multiple pages of text assume-screen 10/width, 5/height - 1:address:array:character <- new [a + 1:text <- new [a b c d e f] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # scroll the page down and up assume-console [ @@ -1143,10 +1143,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-ctrl-a [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # move the cursor, then to start of line assume-console [ @@ -1187,10 +1187,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-home [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # move the cursor, then to start of line assume-console [ @@ -1231,10 +1231,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-ctrl-e [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # move the cursor, then to start of line assume-console [ @@ -1275,10 +1275,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-end [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # move the cursor, then to start of line assume-console [ @@ -1319,10 +1319,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-multiple-arrows-in-the-same-direction [ # create an editor with some text assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # move the cursor assume-console [ @@ -1373,10 +1373,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-redo-touch [ # create an editor with some text, click on a character, undo assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def ghi] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data assume-console [ left-click 3, 1 @@ -1430,8 +1430,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-separates-undo-insert-from-undo-cursor-move [ # create an editor, type some text, move the cursor, type some more text assume-screen 10/width, 5/height - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data assume-console [ type [abc] @@ -1579,8 +1579,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-and-redo-backspace [ # create an editor assume-screen 10/width, 5/height - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # insert some text and hit backspace assume-console [ @@ -1724,8 +1724,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-and-redo-delete [ # create an editor assume-screen 10/width, 5/height - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # insert some text and hit delete and backspace a few times assume-console [ @@ -1913,9 +1913,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-and-redo-ctrl-k [ # create an editor assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # insert some text and hit delete and backspace a few times assume-console [ @@ -2015,9 +2015,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-and-redo-ctrl-u [ # create an editor assume-screen 10/width, 5/height - 1:address:array:character <- new [abc + 1:text <- new [abc def] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # insert some text and hit delete and backspace a few times assume-console [ @@ -2116,8 +2116,8 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color scenario editor-can-undo-and-redo-ctrl-u-2 [ # create an editor assume-screen 10/width, 5/height - 1:address:array:character <- new [] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + 1:text <- new [] + 2:address:editor-data <- new-editor 1:text, screen:address:screen, 0/left, 10/right editor-render screen, 2:address:editor-data # insert some text and hit delete and backspace a few times assume-console [ diff --git a/html/immutable-error.mu.html b/html/immutable-error.mu.html deleted file mode 100644 index 52c661c5..00000000 --- a/html/immutable-error.mu.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - -Mu - immutable-error.mu - - - - - - - - - - -
-# compare mutable.mu
-
-def main [
-  local-scope
-  x:address:number <- new number:type
-  foo x
-]
-
-def foo x:address:number [
-  local-scope
-  load-ingredients
-  *x <- copy 34  # will cause an error because x is immutable in this function
-]
-
- - - diff --git a/html/immutable_error.mu.html b/html/immutable_error.mu.html new file mode 100644 index 00000000..2d1fcae6 --- /dev/null +++ b/html/immutable_error.mu.html @@ -0,0 +1,47 @@ + + + + +Mu - immutable_error.mu + + + + + + + + + + +
+# compare mutable.mu
+
+def main [
+  local-scope
+  x:address:number <- new number:type
+  foo x
+]
+
+def foo x:address:number [
+  local-scope
+  load-ingredients
+  *x <- copy 34  # will cause an error because x is immutable in this function
+]
+
+ + + diff --git a/html/lambda-to-mu.mu.html b/html/lambda-to-mu.mu.html deleted file mode 100644 index d93a8b00..00000000 --- a/html/lambda-to-mu.mu.html +++ /dev/null @@ -1,623 +0,0 @@ - - - - -Mu - lambda-to-mu.mu - - - - - - - - - - -
-## experimental compiler to translate programs written in a generic
-## expression-oriented language called 'lambda' into mu
-
-scenario convert-lambda [
-  run [
-    local-scope
-    1:address:array:character/raw <- lambda-to-mu [(add a (multiply b c))]
-    2:array:character/raw <- copy *1:address:array:character/raw
-  ]
-  memory-should-contain [
-    2:array:character <- [t1 <- multiply b c
-result <- add a t1]
-  ]
-]
-
-def lambda-to-mu in:address:array:character -> out:address:array:character [
-  local-scope
-  load-ingredients
-  out <- copy 0
-  cells:address:cell <- parse in
-  out <- to-mu cells
-]
-
-# 'parse' will turn lambda expressions into trees made of cells
-exclusive-container cell [
-  atom:address:array:character
-  pair:pair
-]
-
-# printed below as < first | rest >
-container pair [
-  first:address:cell
-  rest:address:cell
-]
-
-def new-atom name:address:array:character -> result:address:cell [
-  local-scope
-  load-ingredients
-  result <- new cell:type
-  *result <- merge 0/tag:atom, name
-]
-
-def new-pair a:address:cell, b:address:cell -> result:address:cell [
-  local-scope
-  load-ingredients
-  result <- new cell:type
-  *result <- merge 1/tag:pair, a/first, b/rest
-]
-
-def is-atom? x:address:cell -> result:boolean [
-  local-scope
-  load-ingredients
-  reply-unless x, 0/false
-  _, result <- maybe-convert *x, atom:variant
-]
-
-def is-pair? x:address:cell -> result:boolean [
-  local-scope
-  load-ingredients
-  reply-unless x, 0/false
-  _, result <- maybe-convert *x, pair:variant
-]
-
-scenario atom-is-not-pair [
-  local-scope
-  s:address:array:character <- new [a]
-  x:address:cell <- new-atom s
-  10:boolean/raw <- is-atom? x
-  11:boolean/raw <- is-pair? x
-  memory-should-contain [
-    10 <- 1
-    11 <- 0
-  ]
-]
-
-scenario pair-is-not-atom [
-  local-scope
-  # construct (a . nil)
-  s:address:array:character <- new [a]
-  x:address:cell <- new-atom s
-  y:address:cell <- new-pair x, 0/nil
-  10:boolean/raw <- is-atom? y
-  11:boolean/raw <- is-pair? y
-  memory-should-contain [
-    10 <- 0
-    11 <- 1
-  ]
-]
-
-def atom-match? x:address:cell, pat:address:array:character -> result:boolean [
-  local-scope
-  load-ingredients
-  s:address:array:character, is-atom?:boolean <- maybe-convert *x, atom:variant
-  reply-unless is-atom?, 0/false
-  result <- equal pat, s
-]
-
-scenario atom-match [
-  local-scope
-  x:address:cell <- new-atom [abc]
-  10:boolean/raw <- atom-match? x, [abc]
-  memory-should-contain [
-    10 <- 1
-  ]
-]
-
-def first x:address:cell -> result:address:cell [
-  local-scope
-  load-ingredients
-  pair:pair, pair?:boolean <- maybe-convert *x, pair:variant
-  reply-unless pair?, 0/nil
-  result <- get pair, first:offset
-]
-
-def rest x:address:cell -> result:address:cell [
-  local-scope
-  load-ingredients
-  pair:pair, pair?:boolean <- maybe-convert *x, pair:variant
-  reply-unless pair?, 0/nil
-  result <- get pair, rest:offset
-]
-
-def set-first base:address:cell, new-first:address:cell -> base:address:cell [
-  local-scope
-  load-ingredients
-  pair:pair, is-pair?:boolean <- maybe-convert *base, pair:variant
-  reply-unless is-pair?
-  pair <- put pair, first:offset, new-first
-  *base <- merge 1/pair, pair
-]
-
-def set-rest base:address:cell, new-rest:address:cell -> base:address:cell [
-  local-scope
-  load-ingredients
-  pair:pair, is-pair?:boolean <- maybe-convert *base, pair:variant
-  reply-unless is-pair?
-  pair <- put pair, rest:offset, new-rest
-  *base <- merge 1/pair, pair
-]
-
-scenario cell-operations-on-atom [
-  local-scope
-  s:address:array:character <- new [a]
-  x:address:cell <- new-atom s
-  10:address:cell/raw <- first x
-  11:address:cell/raw <- rest x
-  memory-should-contain [
-    10 <- 0  # first is nil
-    11 <- 0  # rest is nil
-  ]
-]
-
-scenario cell-operations-on-pair [
-  local-scope
-  # construct (a . nil)
-  s:address:array:character <- new [a]
-  x:address:cell <- new-atom s
-  y:address:cell <- new-pair x, 0/nil
-  x2:address:cell <- first y
-  10:boolean/raw <- equal x, x2
-  11:address:cell/raw <- rest y
-  memory-should-contain [
-    10 <- 1  # first is correct
-    11 <- 0  # rest is nil
-  ]
-]
-
-## convert lambda text to a tree of cells
-
-def parse in:address:array:character -> out:address:cell [
-  local-scope
-  load-ingredients
-  s:address:stream:character <- new-stream in
-  out, s <- parse s
-  trace 2, [app/parse], out
-]
-
-def parse in:address:stream:character -> out:address:cell, in:address:stream:character [
-  local-scope
-  load-ingredients
-  # skip whitespace
-  in <- skip-whitespace in
-  c:character, eof?:boolean <- peek in
-  reply-if eof?, 0/nil
-  pair?:boolean <- equal c, 40/open-paren
-  {
-    break-if pair?
-    # atom
-    b:address:buffer <- new-buffer 30
-    {
-      done?:boolean <- end-of-stream? in
-      break-if done?
-      # stop before close paren or space
-      c:character <- peek in
-      done? <- equal c, 41/close-paren
-      break-if done?
-      done? <- space? c
-      break-if done?
-      c <- read in
-      b <- append b, c
-      loop
-    }
-    s:address:array:character <- buffer-to-array b
-    out <- new-atom s
-  }
-  {
-    break-unless pair?
-    # pair
-    read in  # skip the open-paren
-    out <- new cell:type  # start out with nil
-    # read in first element of pair
-    {
-      end?:boolean <- end-of-stream? in
-      not-end?:boolean <- not end?
-      assert not-end?, [unbalanced '(' in expression]
-      c <- peek in
-      close-paren?:boolean <- equal c, 41/close-paren
-      break-if close-paren?
-      first:address:cell, in <- parse in
-      *out <- merge 1/pair, first, 0/nil
-    }
-    # read in any remaining elements
-    curr:address:cell <- copy out
-    {
-      in <- skip-whitespace in
-      end?:boolean <- end-of-stream? in
-      not-end?:boolean <- not end?
-      assert not-end?, [unbalanced '(' in expression]
-      # termination check: ')'
-      c <- peek in
-      {
-        close-paren?:boolean <- equal c, 41/close-paren
-        break-unless close-paren?
-        read in  # skip ')'
-        break +end-pair:label
-      }
-      # still here? read next element of pair
-      next:address:cell, in <- parse in
-      is-dot?:boolean <- atom-match? next, [.]
-      {
-        break-if is-dot?
-        next-curr:address:cell <- new-pair next, 0/nil
-        curr <- set-rest curr, next-curr
-        curr <- rest curr
-      }
-      {
-        break-unless is-dot?
-        # deal with dotted pair
-        in <- skip-whitespace in
-        c <- peek in
-        not-close-paren?:boolean <- not-equal c, 41/close-paren
-        assert not-close-paren?, [')' cannot immediately follow '.']
-        final:address:cell <- parse in
-        curr <- set-rest curr, final
-        # we're not gonna update curr, so better make sure the next iteration
-        # is going to end the pair
-        in <- skip-whitespace in
-        c <- peek in
-        close-paren?:boolean <- equal c, 41/close-paren
-        assert close-paren?, ['.' must be followed by exactly one expression before ')']
-      }
-      loop
-    }
-    +end-pair
-  }
-]
-
-def skip-whitespace in:address:stream:character -> in:address:stream:character [
-  local-scope
-  load-ingredients
-  {
-    done?:boolean <- end-of-stream? in
-    reply-if done?, 0/null
-    c:character <- peek in
-    space?:boolean <- space? c
-    break-unless space?
-    read in  # skip
-    loop
-  }
-]
-
-def to-text x:address:cell -> out:address:array:character [
-  local-scope
-  load-ingredients
-  buf:address:buffer <- new-buffer 30
-  buf <- to-buffer x, buf
-  out <- buffer-to-array buf
-]
-
-def to-buffer x:address:cell, buf:address:buffer -> buf:address:buffer [
-  local-scope
-  load-ingredients
-  # base case: empty cell
-  {
-    break-if x
-    buf <- append buf, [<>]
-    reply
-  }
-  # base case: atom
-  {
-    s:address:array:character, atom?:boolean <- maybe-convert *x, atom:variant
-    break-unless atom?
-    buf <- append buf, s
-    reply
-  }
-  # recursive case: pair
-  buf <- append buf, [< ]
-  first:address:cell <- first x
-  buf <- to-buffer first, buf
-  buf <- append buf, [ | ]
-  rest:address:cell <- rest x
-  buf <- to-buffer rest, buf
-  buf <- append buf, [ >]
-]
-
-scenario parse-single-letter-atom [
-  local-scope
-  s:address:array:character <- new [a]
-  x:address:cell <- parse s
-  s2:address:array:character, 10:boolean/raw <- maybe-convert *x, atom:variant
-  11:array:character/raw <- copy *s2
-  memory-should-contain [
-    10 <- 1  # parse result is an atom
-    11:array:character <- [a]
-  ]
-]
-
-scenario parse-atom [
-  local-scope
-  s:address:array:character <- new [abc]
-  x:address:cell <- parse s
-  s2:address:array:character, 10:boolean/raw <- maybe-convert *x, atom:variant
-  11:array:character/raw <- copy *s2
-  memory-should-contain [
-    10 <- 1  # parse result is an atom
-    11:array:character <- [abc]
-  ]
-]
-
-scenario parse-list-of-two-atoms [
-  local-scope
-  s:address:array:character <- new [(abc def)]
-  x:address:cell <- parse s
-  trace-should-contain [
-    app/parse: < abc | < def | <> > >
-  ]
-  10:boolean/raw <- is-pair? x
-  x1:address:cell <- first x
-  x2:address:cell <- rest x
-  s1:address:array:character, 11:boolean/raw <- maybe-convert *x1, atom:variant
-  12:boolean/raw <- is-pair? x2
-  x3:address:cell <- first x2
-  s2:address:array:character, 13:boolean/raw <- maybe-convert *x3, atom:variant
-  14:address:cell/raw <- rest x2
-  20:array:character/raw <- copy *s1
-  30:array:character/raw <- copy *s2
-  memory-should-contain [
-    10 <- 1  # parse result is a pair
-    11 <- 1  # result.first is an atom
-    12 <- 1  # result.rest is a pair
-    13 <- 1  # result.rest.first is an atom
-    14 <- 0  # result.rest.rest is nil
-    20:array:character <- [abc]  # result.first
-    30:array:character <- [def]  # result.rest.first
-  ]
-]
-
-scenario parse-list-with-extra-spaces [
-  local-scope
-  s:address:array:character <- new [ ( abc  def ) ]  # extra spaces
-  x:address:cell <- parse s
-  trace-should-contain [
-    app/parse: < abc | < def | <> > >
-  ]
-  10:boolean/raw <- is-pair? x
-  x1:address:cell <- first x
-  x2:address:cell <- rest x
-  s1:address:array:character, 11:boolean/raw <- maybe-convert *x1, atom:variant
-  12:boolean/raw <- is-pair? x2
-  x3:address:cell <- first x2
-  s2:address:array:character, 13:boolean/raw <- maybe-convert *x3, atom:variant
-  14:address:cell/raw <- rest x2
-  20:array:character/raw <- copy *s1
-  30:array:character/raw <- copy *s2
-  memory-should-contain [
-    10 <- 1  # parse result is a pair
-    11 <- 1  # result.first is an atom
-    12 <- 1  # result.rest is a pair
-    13 <- 1  # result.rest.first is an atom
-    14 <- 0  # result.rest.rest is nil
-    20:array:character <- [abc]  # result.first
-    30:array:character <- [def]  # result.rest.first
-  ]
-]
-
-scenario parse-list-of-more-than-two-atoms [
-  local-scope
-  s:address:array:character <- new [(abc def ghi)]
-  x:address:cell <- parse s
-  trace-should-contain [
-    app/parse: < abc | < def | < ghi | <> > > >
-  ]
-  10:boolean/raw <- is-pair? x
-  x1:address:cell <- first x
-  x2:address:cell <- rest x
-  s1:address:array:character, 11:boolean/raw <- maybe-convert *x1, atom:variant
-  12:boolean/raw <- is-pair? x2
-  x3:address:cell <- first x2
-  s2:address:array:character, 13:boolean/raw <- maybe-convert *x3, atom:variant
-  x4:address:cell <- rest x2
-  14:boolean/raw <- is-pair? x4
-  x5:address:cell <- first x4
-  s3:address:array:character, 15:boolean/raw <- maybe-convert *x5, atom:variant
-  16:address:cell/raw <- rest x4
-  20:array:character/raw <- copy *s1
-  30:array:character/raw <- copy *s2
-  40:array:character/raw <- copy *s3
-  memory-should-contain [
-    10 <- 1  # parse result is a pair
-    11 <- 1  # result.first is an atom
-    12 <- 1  # result.rest is a pair
-    13 <- 1  # result.rest.first is an atom
-    14 <- 1  # result.rest.rest is a pair
-    15 <- 1  # result.rest.rest.first is an atom
-    16 <- 0  # result.rest.rest.rest is nil
-    20:array:character <- [abc]  # result.first
-    30:array:character <- [def]  # result.rest.first
-    40:array:character <- [ghi]  # result.rest.rest
-  ]
-]
-
-scenario parse-nested-list [
-  local-scope
-  s:address:array:character <- new [((abc))]
-  x:address:cell <- parse s
-  trace-should-contain [
-    app/parse: < < abc | <> > | <> >
-  ]
-  10:boolean/raw <- is-pair? x
-  x1:address:cell <- first x
-  11:boolean/raw <- is-pair? x
-  x2:address:cell <- first x1
-  s1:address:array:character, 12:boolean/raw <- maybe-convert *x2, atom:variant
-  13:address:cell/raw <- rest x1
-  14:address:cell/raw <- rest x
-  20:array:character/raw <- copy *s1
-  memory-should-contain [
-    10 <- 1  # parse result is a pair
-    11 <- 1  # result.first is a pair
-    12 <- 1  # result.first.first is an atom
-    13 <- 0  # result.first.rest is nil
-    14 <- 0  # result.rest is nil
-    20:array:character <- [abc]  # result.first.first
-  ]
-]
-
-scenario parse-nested-list-2 [
-  local-scope
-  s:address:array:character <- new [((abc) def)]
-  x:address:cell <- parse s
-  trace-should-contain [
-    app/parse: < < abc | <> > | < def | <> > >
-  ]
-  10:boolean/raw <- is-pair? x
-  x1:address:cell <- first x
-  11:boolean/raw <- is-pair? x
-  x2:address:cell <- first x1
-  s1:address:array:character, 12:boolean/raw <- maybe-convert *x2, atom:variant
-  13:address:cell/raw <- rest x1
-  x3:address:cell <- rest x
-  x4:address:cell <- first x3
-  s2:address:array:character, 14:boolean/raw <- maybe-convert *x4, atom:variant
-  15:address:cell/raw <- rest x3
-  20:array:character/raw <- copy *s1
-  30:array:character/raw <- copy *s2
-  memory-should-contain [
-    10 <- 1  # parse result is a pair
-    11 <- 1  # result.first is a pair
-    12 <- 1  # result.first.first is an atom
-    13 <- 0  # result.first.rest is nil
-    14 <- 1  # result.rest.first is an atom
-    15 <- 0  # result.rest.rest is nil
-    20:array:character <- [abc]  # result.first.first
-    30:array:character <- [def]  # result.rest.first
-  ]
-]
-
-# todo: uncomment these tests after we figure out how to continue tests after
-# assertion failures
-#? scenario parse-error [
-#?   local-scope
-#?   s:address:array:character <- new [(]
-#? #?   hide-errors
-#?   x:address:cell <- parse s
-#? #?   show-errors
-#?   trace-should-contain [
-#?     error: unbalanced '(' in expression
-#?   ]
-#? ]
-#? 
-#? scenario parse-error-after-element [
-#?   local-scope
-#?   s:address:array:character <- new [(abc]
-#? #?   hide-errors
-#?   x:address:cell <- parse s
-#? #?   show-errors
-#?   trace-should-contain [
-#?     error: unbalanced '(' in expression
-#?   ]
-#? ]
-
-scenario parse-dotted-list-of-two-atoms [
-  local-scope
-  s:address:array:character <- new [(abc . def)]
-  x:address:cell <- parse s
-  trace-should-contain [
-    app/parse: < abc | def >
-  ]
-  10:boolean/raw <- is-pair? x
-  x1:address:cell <- first x
-  x2:address:cell <- rest x
-  s1:address:array:character, 11:boolean/raw <- maybe-convert *x1, atom:variant
-  s2:address:array:character, 12:boolean/raw <- maybe-convert *x2, atom:variant
-  20:array:character/raw <- copy *s1
-  30:array:character/raw <- copy *s2
-  memory-should-contain [
-    # parses to < abc | def >
-    10 <- 1  # parse result is a pair
-    11 <- 1  # result.first is an atom
-    12 <- 1  # result.rest is an atom
-    20:array:character <- [abc]  # result.first
-    30:array:character <- [def]  # result.rest
-  ]
-]
-
-scenario parse-dotted-list-of-more-than-two-atoms [
-  local-scope
-  s:address:array:character <- new [(abc def . ghi)]
-  x:address:cell <- parse s
-  trace-should-contain [
-    app/parse: < abc | < def | ghi > >
-  ]
-  10:boolean/raw <- is-pair? x
-  x1:address:cell <- first x
-  x2:address:cell <- rest x
-  s1:address:array:character, 11:boolean/raw <- maybe-convert *x1, atom:variant
-  12:boolean/raw <- is-pair? x2
-  x3:address:cell <- first x2
-  s2:address:array:character, 13:boolean/raw <- maybe-convert *x3, atom:variant
-  x4:address:cell <- rest x2
-  s3:address:array:character, 14:boolean/raw <- maybe-convert *x4, atom:variant
-  20:array:character/raw <- copy *s1
-  30:array:character/raw <- copy *s2
-  40:array:character/raw <- copy *s3
-  memory-should-contain [
-    10 <- 1  # parse result is a pair
-    11 <- 1  # result.first is an atom
-    12 <- 1  # result.rest is a pair
-    13 <- 1  # result.rest.first is an atom
-    14 <- 1  # result.rest.rest is an atom
-    20:array:character <- [abc]  # result.first
-    30:array:character <- [def]  # result.rest.first
-    40:array:character <- [ghi]  # result.rest.rest
-  ]
-]
-
-## convert tree of cells to mu text
-
-def to-mu in:address:cell -> out:address:array:character [
-  local-scope
-  load-ingredients
-  buf:address:buffer <- new-buffer 30
-  buf <- to-mu in, buf
-  out <- buffer-to-array buf
-]
-
-def to-mu in:address:cell, buf:address:buffer -> buf:address:buffer, result-name:address:array:character [
-  local-scope
-  load-ingredients
-  # null cell? no change.
-  # pair with all atoms? gensym a new variable
-  # pair containing other pairs? recurse
-]
-
- - - diff --git a/html/lambda_to_mu.mu.html b/html/lambda_to_mu.mu.html new file mode 100644 index 00000000..a615b34f --- /dev/null +++ b/html/lambda_to_mu.mu.html @@ -0,0 +1,624 @@ + + + + +Mu - lambda_to_mu.mu + + + + + + + + + + +
+## experimental compiler to translate programs written in a generic
+## expression-oriented language called 'lambda' into mu
+
+scenario convert-lambda [
+  run [
+    local-scope
+    1:text/raw <- lambda-to-mu [(add a (multiply b c))]
+    2:array:character/raw <- copy *1:text/raw
+  ]
+  memory-should-contain [
+    2:array:character <- [t1 <- multiply b c
+result <- add a t1]
+  ]
+]
+
+def lambda-to-mu in:address:array:character -> out:address:array:character [
+  local-scope
+  load-ingredients
+  out <- copy 0
+  cells:address:cell <- parse in
+  out <- to-mu cells
+]
+
+# 'parse' will turn lambda expressions into trees made of cells
+exclusive-container cell [
+  atom:text
+  pair:pair
+]
+
+# printed below as < first | rest >
+container pair [
+  first:address:cell
+  rest:address:cell
+]
+
+def new-atom name:address:array:character -> result:address:cell [
+  local-scope
+  load-ingredients
+  result <- new cell:type
+  *result <- merge 0/tag:atom, name
+]
+
+def new-pair a:address:cell, b:address:cell -> result:address:cell [
+  local-scope
+  load-ingredients
+  result <- new cell:type
+  *result <- merge 1/tag:pair, a/first, b/rest
+]
+
+def is-atom? x:address:cell -> result:boolean [
+  local-scope
+  load-ingredients
+  reply-unless x, 0/false
+  _, result <- maybe-convert *x, atom:variant
+]
+
+def is-pair? x:address:cell -> result:boolean [
+  local-scope
+  load-ingredients
+  reply-unless x, 0/false
+  _, result <- maybe-convert *x, pair:variant
+]
+
+scenario atom-is-not-pair [
+  local-scope
+  s:text <- new [a]
+  x:address:cell <- new-atom s
+  10:boolean/raw <- is-atom? x
+  11:boolean/raw <- is-pair? x
+  memory-should-contain [
+    10 <- 1
+    11 <- 0
+  ]
+]
+
+scenario pair-is-not-atom [
+  local-scope
+  # construct (a . nil)
+  s:text <- new [a]
+  x:address:cell <- new-atom s
+  y:address:cell <- new-pair x, 0/nil
+  10:boolean/raw <- is-atom? y
+  11:boolean/raw <- is-pair? y
+  memory-should-contain [
+    10 <- 0
+    11 <- 1
+  ]
+]
+
+def atom-match? x:address:cell, pat:address:array:character -> result:boolean [
+  local-scope
+  load-ingredients
+  s:text, is-atom?:boolean <- maybe-convert *x, atom:variant
+  reply-unless is-atom?, 0/false
+  result <- equal pat, s
+]
+
+scenario atom-match [
+  local-scope
+  x:address:cell <- new-atom [abc]
+  10:boolean/raw <- atom-match? x, [abc]
+  memory-should-contain [
+    10 <- 1
+  ]
+]
+
+def first x:address:cell -> result:address:cell [
+  local-scope
+  load-ingredients
+  pair:pair, pair?:boolean <- maybe-convert *x, pair:variant
+  reply-unless pair?, 0/nil
+  result <- get pair, first:offset
+]
+
+def rest x:address:cell -> result:address:cell [
+  local-scope
+  load-ingredients
+  pair:pair, pair?:boolean <- maybe-convert *x, pair:variant
+  reply-unless pair?, 0/nil
+  result <- get pair, rest:offset
+]
+
+def set-first base:address:cell, new-first:address:cell -> base:address:cell [
+  local-scope
+  load-ingredients
+  pair:pair, is-pair?:boolean <- maybe-convert *base, pair:variant
+  reply-unless is-pair?
+  pair <- put pair, first:offset, new-first
+  *base <- merge 1/pair, pair
+]
+
+def set-rest base:address:cell, new-rest:address:cell -> base:address:cell [
+  local-scope
+  load-ingredients
+  pair:pair, is-pair?:boolean <- maybe-convert *base, pair:variant
+  reply-unless is-pair?
+  pair <- put pair, rest:offset, new-rest
+  *base <- merge 1/pair, pair
+]
+
+scenario cell-operations-on-atom [
+  local-scope
+  s:text <- new [a]
+  x:address:cell <- new-atom s
+  10:address:cell/raw <- first x
+  11:address:cell/raw <- rest x
+  memory-should-contain [
+    10 <- 0  # first is nil
+    11 <- 0  # rest is nil
+  ]
+]
+
+scenario cell-operations-on-pair [
+  local-scope
+  # construct (a . nil)
+  s:text <- new [a]
+  x:address:cell <- new-atom s
+  y:address:cell <- new-pair x, 0/nil
+  x2:address:cell <- first y
+  10:boolean/raw <- equal x, x2
+  11:address:cell/raw <- rest y
+  memory-should-contain [
+    10 <- 1  # first is correct
+    11 <- 0  # rest is nil
+  ]
+]
+
+## convert lambda text to a tree of cells
+
+def parse in:address:array:character -> out:address:cell [
+  local-scope
+  load-ingredients
+  s:address:stream:character <- new-stream in
+  out, s <- parse s
+  trace 2, [app/parse], out
+]
+
+def parse in:address:stream:character -> out:address:cell, in:address:stream:character [
+  local-scope
+  load-ingredients
+  # skip whitespace
+  in <- skip-whitespace in
+  c:character, eof?:boolean <- peek in
+  reply-if eof?, 0/nil
+  pair?:boolean <- equal c, 40/open-paren
+  {
+    break-if pair?
+    # atom
+    b:address:buffer <- new-buffer 30
+    {
+      done?:boolean <- end-of-stream? in
+      break-if done?
+      # stop before close paren or space
+      c:character <- peek in
+      done? <- equal c, 41/close-paren
+      break-if done?
+      done? <- space? c
+      break-if done?
+      c <- read in
+      b <- append b, c
+      loop
+    }
+    s:text <- buffer-to-array b
+    out <- new-atom s
+  }
+  {
+    break-unless pair?
+    # pair
+    read in  # skip the open-paren
+    out <- new cell:type  # start out with nil
+    # read in first element of pair
+    {
+      end?:boolean <- end-of-stream? in
+      not-end?:boolean <- not end?
+      assert not-end?, [unbalanced '(' in expression]
+      c <- peek in
+      close-paren?:boolean <- equal c, 41/close-paren
+      break-if close-paren?
+      first:address:cell, in <- parse in
+      *out <- merge 1/pair, first, 0/nil
+    }
+    # read in any remaining elements
+    curr:address:cell <- copy out
+    {
+      in <- skip-whitespace in
+      end?:boolean <- end-of-stream? in
+      not-end?:boolean <- not end?
+      assert not-end?, [unbalanced '(' in expression]
+      # termination check: ')'
+      c <- peek in
+      {
+        close-paren?:boolean <- equal c, 41/close-paren
+        break-unless close-paren?
+        read in  # skip ')'
+        break +end-pair:label
+      }
+      # still here? read next element of pair
+      next:address:cell, in <- parse in
+      is-dot?:boolean <- atom-match? next, [.]
+      {
+        break-if is-dot?
+        next-curr:address:cell <- new-pair next, 0/nil
+        curr <- set-rest curr, next-curr
+        curr <- rest curr
+      }
+      {
+        break-unless is-dot?
+        # deal with dotted pair
+        in <- skip-whitespace in
+        c <- peek in
+        not-close-paren?:boolean <- not-equal c, 41/close-paren
+        assert not-close-paren?, [')' cannot immediately follow '.']
+        final:address:cell <- parse in
+        curr <- set-rest curr, final
+        # we're not gonna update curr, so better make sure the next iteration
+        # is going to end the pair
+        in <- skip-whitespace in
+        c <- peek in
+        close-paren?:boolean <- equal c, 41/close-paren
+        assert close-paren?, ['.' must be followed by exactly one expression before ')']
+      }
+      loop
+    }
+    +end-pair
+  }
+]
+
+def skip-whitespace in:address:stream:character -> in:address:stream:character [
+  local-scope
+  load-ingredients
+  {
+    done?:boolean <- end-of-stream? in
+    reply-if done?, 0/null
+    c:character <- peek in
+    space?:boolean <- space? c
+    break-unless space?
+    read in  # skip
+    loop
+  }
+]
+
+def to-text x:address:cell -> out:address:array:character [
+  local-scope
+  load-ingredients
+  buf:address:buffer <- new-buffer 30
+  buf <- to-buffer x, buf
+  out <- buffer-to-array buf
+]
+
+def to-buffer x:address:cell, buf:address:buffer -> buf:address:buffer [
+  local-scope
+  load-ingredients
+  # base case: empty cell
+  {
+    break-if x
+    buf <- append buf, [<>]
+    reply
+  }
+  # base case: atom
+  {
+    s:text, atom?:boolean <- maybe-convert *x, atom:variant
+    break-unless atom?
+    buf <- append buf, s
+    reply
+  }
+  # recursive case: pair
+  buf <- append buf, [< ]
+  first:address:cell <- first x
+  buf <- to-buffer first, buf
+  buf <- append buf, [ | ]
+  rest:address:cell <- rest x
+  buf <- to-buffer rest, buf
+  buf <- append buf, [ >]
+]
+
+scenario parse-single-letter-atom [
+  local-scope
+  s:text <- new [a]
+  x:address:cell <- parse s
+  s2:text, 10:boolean/raw <- maybe-convert *x, atom:variant
+  11:array:character/raw <- copy *s2
+  memory-should-contain [
+    10 <- 1  # parse result is an atom
+    11:array:character <- [a]
+  ]
+]
+
+scenario parse-atom [
+  local-scope
+  s:text <- new [abc]
+  x:address:cell <- parse s
+  s2:text, 10:boolean/raw <- maybe-convert *x, atom:variant
+  11:array:character/raw <- copy *s2
+  memory-should-contain [
+    10 <- 1  # parse result is an atom
+    11:array:character <- [abc]
+  ]
+]
+
+scenario parse-list-of-two-atoms [
+  local-scope
+  s:text <- new [(abc def)]
+  x:address:cell <- parse s
+  trace-should-contain [
+    app/parse: < abc | < def | <> > >
+  ]
+  10:boolean/raw <- is-pair? x
+  x1:address:cell <- first x
+  x2:address:cell <- rest x
+  s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant
+  12:boolean/raw <- is-pair? x2
+  x3:address:cell <- first x2
+  s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant
+  14:address:cell/raw <- rest x2
+  20:array:character/raw <- copy *s1
+  30:array:character/raw <- copy *s2
+  memory-should-contain [
+    10 <- 1  # parse result is a pair
+    11 <- 1  # result.first is an atom
+    12 <- 1  # result.rest is a pair
+    13 <- 1  # result.rest.first is an atom
+    14 <- 0  # result.rest.rest is nil
+    20:array:character <- [abc]  # result.first
+    30:array:character <- [def]  # result.rest.first
+  ]
+]
+
+scenario parse-list-with-extra-spaces [
+  local-scope
+  s:text <- new [ ( abc  def ) ]  # extra spaces
+  x:address:cell <- parse s
+  trace-should-contain [
+    app/parse: < abc | < def | <> > >
+  ]
+  10:boolean/raw <- is-pair? x
+  x1:address:cell <- first x
+  x2:address:cell <- rest x
+  s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant
+  12:boolean/raw <- is-pair? x2
+  x3:address:cell <- first x2
+  s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant
+  14:address:cell/raw <- rest x2
+  20:array:character/raw <- copy *s1
+  30:array:character/raw <- copy *s2
+  memory-should-contain [
+    10 <- 1  # parse result is a pair
+    11 <- 1  # result.first is an atom
+    12 <- 1  # result.rest is a pair
+    13 <- 1  # result.rest.first is an atom
+    14 <- 0  # result.rest.rest is nil
+    20:array:character <- [abc]  # result.first
+    30:array:character <- [def]  # result.rest.first
+  ]
+]
+
+scenario parse-list-of-more-than-two-atoms [
+  local-scope
+  s:text <- new [(abc def ghi)]
+  x:address:cell <- parse s
+  trace-should-contain [
+    app/parse: < abc | < def | < ghi | <> > > >
+  ]
+  10:boolean/raw <- is-pair? x
+  x1:address:cell <- first x
+  x2:address:cell <- rest x
+  s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant
+  12:boolean/raw <- is-pair? x2
+  x3:address:cell <- first x2
+  s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant
+  x4:address:cell <- rest x2
+  14:boolean/raw <- is-pair? x4
+  x5:address:cell <- first x4
+  s3:text, 15:boolean/raw <- maybe-convert *x5, atom:variant
+  16:address:cell/raw <- rest x4
+  20:array:character/raw <- copy *s1
+  30:array:character/raw <- copy *s2
+  40:array:character/raw <- copy *s3
+  memory-should-contain [
+    10 <- 1  # parse result is a pair
+    11 <- 1  # result.first is an atom
+    12 <- 1  # result.rest is a pair
+    13 <- 1  # result.rest.first is an atom
+    14 <- 1  # result.rest.rest is a pair
+    15 <- 1  # result.rest.rest.first is an atom
+    16 <- 0  # result.rest.rest.rest is nil
+    20:array:character <- [abc]  # result.first
+    30:array:character <- [def]  # result.rest.first
+    40:array:character <- [ghi]  # result.rest.rest
+  ]
+]
+
+scenario parse-nested-list [
+  local-scope
+  s:text <- new [((abc))]
+  x:address:cell <- parse s
+  trace-should-contain [
+    app/parse: < < abc | <> > | <> >
+  ]
+  10:boolean/raw <- is-pair? x
+  x1:address:cell <- first x
+  11:boolean/raw <- is-pair? x
+  x2:address:cell <- first x1
+  s1:text, 12:boolean/raw <- maybe-convert *x2, atom:variant
+  13:address:cell/raw <- rest x1
+  14:address:cell/raw <- rest x
+  20:array:character/raw <- copy *s1
+  memory-should-contain [
+    10 <- 1  # parse result is a pair
+    11 <- 1  # result.first is a pair
+    12 <- 1  # result.first.first is an atom
+    13 <- 0  # result.first.rest is nil
+    14 <- 0  # result.rest is nil
+    20:array:character <- [abc]  # result.first.first
+  ]
+]
+
+scenario parse-nested-list-2 [
+  local-scope
+  s:text <- new [((abc) def)]
+  x:address:cell <- parse s
+  trace-should-contain [
+    app/parse: < < abc | <> > | < def | <> > >
+  ]
+  10:boolean/raw <- is-pair? x
+  x1:address:cell <- first x
+  11:boolean/raw <- is-pair? x
+  x2:address:cell <- first x1
+  s1:text, 12:boolean/raw <- maybe-convert *x2, atom:variant
+  13:address:cell/raw <- rest x1
+  x3:address:cell <- rest x
+  x4:address:cell <- first x3
+  s2:text, 14:boolean/raw <- maybe-convert *x4, atom:variant
+  15:address:cell/raw <- rest x3
+  20:array:character/raw <- copy *s1
+  30:array:character/raw <- copy *s2
+  memory-should-contain [
+    10 <- 1  # parse result is a pair
+    11 <- 1  # result.first is a pair
+    12 <- 1  # result.first.first is an atom
+    13 <- 0  # result.first.rest is nil
+    14 <- 1  # result.rest.first is an atom
+    15 <- 0  # result.rest.rest is nil
+    20:array:character <- [abc]  # result.first.first
+    30:array:character <- [def]  # result.rest.first
+  ]
+]
+
+# todo: uncomment these tests after we figure out how to continue tests after
+# assertion failures
+#? scenario parse-error [
+#?   local-scope
+#?   s:text <- new [(]
+#? #?   hide-errors
+#?   x:address:cell <- parse s
+#? #?   show-errors
+#?   trace-should-contain [
+#?     error: unbalanced '(' in expression
+#?   ]
+#? ]
+#? 
+#? scenario parse-error-after-element [
+#?   local-scope
+#?   s:text <- new [(abc]
+#? #?   hide-errors
+#?   x:address:cell <- parse s
+#? #?   show-errors
+#?   trace-should-contain [
+#?     error: unbalanced '(' in expression
+#?   ]
+#? ]
+
+scenario parse-dotted-list-of-two-atoms [
+  local-scope
+  s:text <- new [(abc . def)]
+  x:address:cell <- parse s
+  trace-should-contain [
+    app/parse: < abc | def >
+  ]
+  10:boolean/raw <- is-pair? x
+  x1:address:cell <- first x
+  x2:address:cell <- rest x
+  s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant
+  s2:text, 12:boolean/raw <- maybe-convert *x2, atom:variant
+  20:array:character/raw <- copy *s1
+  30:array:character/raw <- copy *s2
+  memory-should-contain [
+    # parses to < abc | def >
+    10 <- 1  # parse result is a pair
+    11 <- 1  # result.first is an atom
+    12 <- 1  # result.rest is an atom
+    20:array:character <- [abc]  # result.first
+    30:array:character <- [def]  # result.rest
+  ]
+]
+
+scenario parse-dotted-list-of-more-than-two-atoms [
+  local-scope
+  s:text <- new [(abc def . ghi)]
+  x:address:cell <- parse s
+  trace-should-contain [
+    app/parse: < abc | < def | ghi > >
+  ]
+  10:boolean/raw <- is-pair? x
+  x1:address:cell <- first x
+  x2:address:cell <- rest x
+  s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant
+  12:boolean/raw <- is-pair? x2
+  x3:address:cell <- first x2
+  s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant
+  x4:address:cell <- rest x2
+  s3:text, 14:boolean/raw <- maybe-convert *x4, atom:variant
+  20:array:character/raw <- copy *s1
+  30:array:character/raw <- copy *s2
+  40:array:character/raw <- copy *s3
+  memory-should-contain [
+    10 <- 1  # parse result is a pair
+    11 <- 1  # result.first is an atom
+    12 <- 1  # result.rest is a pair
+    13 <- 1  # result.rest.first is an atom
+    14 <- 1  # result.rest.rest is an atom
+    20:array:character <- [abc]  # result.first
+    30:array:character <- [def]  # result.rest.first
+    40:array:character <- [ghi]  # result.rest.rest
+  ]
+]
+
+## convert tree of cells to mu text
+
+def to-mu in:address:cell -> out:address:array:character [
+  local-scope
+  load-ingredients
+  buf:address:buffer <- new-buffer 30
+  buf <- to-mu in, buf
+  out <- buffer-to-array buf
+]
+
+def to-mu in:address:cell, buf:address:buffer -> buf:address:buffer, result-name:address:array:character [
+  local-scope
+  load-ingredients
+  # null cell? no change.
+  # pair with all atoms? gensym a new variable
+  # pair containing other pairs? recurse
+  result-name <- copy 0
+]
+
+ + + diff --git a/html/real-files.mu.html b/html/real-files.mu.html deleted file mode 100644 index 48cddbb8..00000000 --- a/html/real-files.mu.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - -Mu - real-files.mu - - - - - - - - - - -
-# example program: read a character from one file and write it to another
-# BEWARE: this will modify your file system
-# before running it, put a character into /tmp/mu-x
-# after running it, check /tmp/mu-y
-
-def main [
-  local-scope
-  f:number/file <- $open-file-for-reading [/tmp/mu-x]
-  $print [file to read from: ], f, 10/newline
-  c:character <- $read-from-file f
-  $print [copying ], c, 10/newline
-  f <- $close-file f
-  $print [file after closing: ], f, 10/newline
-  f <- $open-file-for-writing [/tmp/mu-y]
-  $print [file to write to: ], f, 10/newline
-  $write-to-file f, c
-  f <- $close-file f
-]
-
- - - diff --git a/html/real_files.mu.html b/html/real_files.mu.html new file mode 100644 index 00000000..7046a633 --- /dev/null +++ b/html/real_files.mu.html @@ -0,0 +1,52 @@ + + + + +Mu - real_files.mu + + + + + + + + + + +
+# example program: read a character from one file and write it to another
+# BEWARE: this will modify your file system
+# before running it, put a character into /tmp/mu-x
+# after running it, check /tmp/mu-y
+
+def main [
+  local-scope
+  f:number/file <- $open-file-for-reading [/tmp/mu-x]
+  $print [file to read from: ], f, 10/newline
+  c:character, eof?:boolean <- $read-from-file f
+  $print [copying ], c, 10/newline
+  f <- $close-file f
+  $print [file after closing: ], f, 10/newline
+  f <- $open-file-for-writing [/tmp/mu-y]
+  $print [file to write to: ], f, 10/newline
+  $write-to-file f, c
+  f <- $close-file f
+]
+
+ + + diff --git a/html/server-socket.mu.html b/html/server-socket.mu.html new file mode 100644 index 00000000..32782b5a --- /dev/null +++ b/html/server-socket.mu.html @@ -0,0 +1,49 @@ + + + + +Mu - server-socket.mu + + + + + + + + + + +
+def main [
+  local-scope
+  socket:number <- $socket 8080/port
+  $print [Mu socket creation returned ], socket, 10/newline
+  session:number <- $accept socket
+  {
+    client-message:address:buffer <- new-buffer 1024
+    c:character <- $read-from-socket session
+    break-unless c
+    $print c
+    loop
+  }
+  $close-socket socket, session
+]
+
+ + + diff --git a/index.html b/index.html index 2938f838..100cf7ad 100644 --- a/index.html +++ b/index.html @@ -209,7 +209,7 @@ convenience when debugging is the ability to add variables to the trace using the stash command. By default stash just prints out the locations in memory, one by one. To extend its display format specific types, -define a function called to-text +define a function called to-text with the appropriate ingredient type, returning a Mu string.
067random.cc: a random-number generator with a testable interface. -- cgit 1.4.1-2-gfad0