about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-02-19 13:42:45 -0800
committerKartik K. Agaram <vc@akkartik.com>2016-02-19 13:42:45 -0800
commit9f95c7451b940b6644cb6fd6783ea9c17168357e (patch)
treed1443c9c4dc48bdc6bd67c7e16b43b9185d6d835
parentb83b2cfd6676e0caa18b39f22f01bdebf41c9d58 (diff)
downloadmu-9f95c7451b940b6644cb6fd6783ea9c17168357e.tar.gz
2685
Stack of plans for cleaning up replace_type_ingredients() and a couple
of other things, from main problem to subproblems:

  include type names in the type_tree rather than in the separate properties vector
  make type_tree and string_tree real cons cells, with separate leaf nodes
  redo the vocabulary for dumping various objects:
    do we really need to_string and debug_string?
    can we have a version with *all* information?
    can we have to_string not call debug_string?

This commit nibbles at the edges of the final task, switching from
member method syntax to global function like almost everything else. I'm
mostly using methods just for STL in this project.
-rw-r--r--010vm.cc44
-rw-r--r--011load.cc8
-rw-r--r--014literal_string.cc6
-rw-r--r--020run.cc8
-rw-r--r--021check_instruction.cc2
-rw-r--r--022arithmetic.cc56
-rw-r--r--023boolean.cc2
-rw-r--r--024jump.cc6
-rw-r--r--025compare.cc10
-rw-r--r--029tools.cc4
-rw-r--r--030container.cc30
-rw-r--r--031address.cc4
-rw-r--r--032array.cc18
-rw-r--r--033exclusive_container.cc8
-rw-r--r--034call.cc2
-rw-r--r--035call_ingredient.cc4
-rw-r--r--036call_reply.cc6
-rw-r--r--037new.cc6
-rw-r--r--038location_array.cc2
-rw-r--r--042name.cc6
-rw-r--r--043space.cc4
-rw-r--r--045closure_name.cc6
-rw-r--r--050scenario.cc2
-rw-r--r--056recipe_header.cc14
-rw-r--r--057static_dispatch.cc10
-rw-r--r--059shape_shifting_recipe.cc10
-rw-r--r--060immutable.cc8
-rw-r--r--061recipe.cc4
-rw-r--r--062scheduler.cc8
-rw-r--r--063wait.cc4
-rw-r--r--074random.cc2
-rw-r--r--077hash.cc4
-rw-r--r--080display.cc4
-rw-r--r--091run_interactive.cc6
-rw-r--r--092persist.cc10
35 files changed, 162 insertions, 166 deletions
diff --git a/010vm.cc b/010vm.cc
index 970b88c5..ae262e42 100644
--- a/010vm.cc
+++ b/010vm.cc
@@ -21,7 +21,6 @@ struct recipe {
   vector<instruction> steps;
   // End recipe Fields
   recipe();
-  string to_string() const;
 };
 
 :(before "struct recipe")
@@ -43,7 +42,6 @@ struct instruction {
   instruction();
   void clear();
   bool is_clear();
-  string to_string() const;
 };
 
 :(before "struct instruction")
@@ -65,7 +63,6 @@ struct reagent {
   reagent(const reagent& old);
   reagent& operator=(const reagent& old);
   void set_value(double v) { value = v; initialized = true; }
-  string to_string() const;
 };
 
 :(before "struct reagent")
@@ -102,7 +99,6 @@ struct string_tree {
   // advanced: tree containing strings
   string_tree(string_tree* l, string_tree* r) :left(l), right(r) {}
   // print as s-expression
-  string to_string() const;
 };
 
 :(before "End Globals")
@@ -354,13 +350,13 @@ reagent::reagent() :value(0), initialized(false), type(NULL) {
   properties.push_back(pair<string, string_tree*>("", NULL));
 }
 
-string reagent::to_string() const {
+string to_string(const reagent& r) {
   ostringstream out;
-  if (!properties.empty()) {
+  if (!r.properties.empty()) {
     out << "{";
-    for (long long int i = 0; i < SIZE(properties); ++i) {
+    for (long long int i = 0; i < SIZE(r.properties); ++i) {
       if (i > 0) out << ", ";
-      out << "\"" << properties.at(i).first << "\": " << debug_string(properties.at(i).second);
+      out << "\"" << r.properties.at(i).first << "\": " << debug_string(r.properties.at(i).second);
     }
     out << "}";
   }
@@ -369,7 +365,7 @@ string reagent::to_string() const {
 
 string debug_string(const reagent& x) {
   ostringstream out;
-  out << x.name << ": " << debug_string(x.type) << " -- " << x.to_string();
+  out << x.name << ": " << debug_string(x.type) << " -- " << to_string(x);
   return out.str();
 }
 
@@ -430,18 +426,18 @@ void dump_type_name(type_ordinal type, ostream& out) {
     out << "?" << type;
 }
 
-string instruction::to_string() const {
-  if (is_label) return label;
+string to_string(const instruction& inst) {
+  if (inst.is_label) return inst.label;
   ostringstream out;
-  for (long long int i = 0; i < SIZE(products); ++i) {
+  for (long long int i = 0; i < SIZE(inst.products); ++i) {
     if (i > 0) out << ", ";
-    out << products.at(i).original_string;
+    out << inst.products.at(i).original_string;
   }
-  if (!products.empty()) out << " <- ";
-  out << name << ' ';
-  for (long long int i = 0; i < SIZE(ingredients); ++i) {
+  if (!inst.products.empty()) out << " <- ";
+  out << inst.name << ' ';
+  for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (i > 0) out << ", ";
-    out << ingredients.at(i).original_string;
+    out << inst.ingredients.at(i).original_string;
   }
   return out.str();
 }
@@ -452,7 +448,7 @@ string debug_string(const recipe& x) {
   // Begin debug_string(recipe x)
   for (long long int index = 0; index < SIZE(x.steps); ++index) {
     const instruction& inst = x.steps.at(index);
-    out << "inst: " << inst.to_string() << '\n';
+    out << "inst: " << to_string(inst) << '\n';
     out << "  ingredients\n";
     for (long long int i = 0; i < SIZE(inst.ingredients); ++i)
       out << "    " << debug_string(inst.ingredients.at(i)) << '\n';
@@ -497,18 +493,18 @@ void dump_memory() {
   }
 }
 
-string recipe::to_string() const {
+string to_string(const recipe& r) {
   ostringstream out;
-  out << "recipe " << name << " [\n";
-  for (long long int i = 0; i < SIZE(steps); ++i)
-    out << "  " << steps.at(i).to_string() << '\n';
+  out << "recipe " << r.name << " [\n";
+  for (long long int i = 0; i < SIZE(r.steps); ++i)
+    out << "  " << to_string(r.steps.at(i)) << '\n';
   out << "]\n";
   return out.str();
 }
 
-string string_tree::to_string() const {
+string to_string(const string_tree* x) {
   ostringstream out;
-  dump(this, out);
+  dump(x, out);
   return out.str();
 }
 
diff --git a/011load.cc b/011load.cc
index edde4044..2003eb7d 100644
--- a/011load.cc
+++ b/011load.cc
@@ -75,9 +75,9 @@ void slurp_body(istream& in, recipe& result) {
   instruction curr;
   while (next_instruction(in, &curr)) {
     // End Rewrite Instruction(curr, recipe result)
-    trace(9992, "load") << "after rewriting: " << curr.to_string() << end();
+    trace(9992, "load") << "after rewriting: " << to_string(curr) << end();
     if (!curr.is_clear()) {
-      curr.original_string = curr.to_string();
+      curr.original_string = to_string(curr);
       result.steps.push_back(curr);
     }
   }
@@ -140,10 +140,10 @@ bool next_instruction(istream& in, instruction* curr) {
   trace(9993, "parse") << "instruction: " << curr->name << end();
   trace(9993, "parse") << "  number of ingredients: " << SIZE(curr->ingredients) << end();
   for (vector<reagent>::iterator p = curr->ingredients.begin(); p != curr->ingredients.end(); ++p) {
-    trace(9993, "parse") << "  ingredient: " << p->to_string() << end();
+    trace(9993, "parse") << "  ingredient: " << to_string(*p) << end();
   }
   for (vector<reagent>::iterator p = curr->products.begin(); p != curr->products.end(); ++p) {
-    trace(9993, "parse") << "  product: " << p->to_string() << end();
+    trace(9993, "parse") << "  product: " << to_string(*p) << end();
   }
   if (!has_data(in)) {
     raise_error << "9: unbalanced '[' for recipe\n" << end();
diff --git a/014literal_string.cc b/014literal_string.cc
index 209a6428..a94d5451 100644
--- a/014literal_string.cc
+++ b/014literal_string.cc
@@ -118,9 +118,9 @@ if (s.at(0) == '[') {
 //: Unlike other reagents, escape newlines in literal strings to make them
 //: more friendly to trace().
 
-:(after "string reagent::to_string()")
-  if (is_literal_string(*this))
-    return emit_literal_string(name);
+:(after "string to_string(const reagent& r)")
+  if (is_literal_string(r))
+    return emit_literal_string(r.name);
 
 :(code)
 bool is_literal_string(const reagent& x) {
diff --git a/020run.cc b/020run.cc
index 60c1c428..c6617607 100644
--- a/020run.cc
+++ b/020run.cc
@@ -61,7 +61,7 @@ void run_current_routine()
   {
     // Running One Instruction
     if (current_instruction().is_label) { ++current_step_index(); continue; }
-    trace(Initial_callstack_depth + Trace_stream->callstack_depth, "run") << current_instruction().to_string() << end();
+    trace(Initial_callstack_depth + Trace_stream->callstack_depth, "run") << to_string(current_instruction()) << end();
     if (get_or_insert(Memory, 0) != 0) {
       raise_error << "something wrote to location 0; this should never happen\n" << end();
       put(Memory, 0, 0);
@@ -86,7 +86,7 @@ void run_current_routine()
       }
     }
     if (SIZE(products) < SIZE(current_instruction().products)) {
-      raise_error << SIZE(products) << " vs " << SIZE(current_instruction().products) << ": failed to write to all products! " << current_instruction().to_string() << '\n' << end();
+      raise_error << SIZE(products) << " vs " << SIZE(current_instruction().products) << ": failed to write to all products! " << to_string(current_instruction()) << '\n' << end();
     }
     else {
       for (long long int i = 0; i < SIZE(current_instruction().products); ++i) {
@@ -267,7 +267,7 @@ vector<double> read_memory(reagent x) {
 
 void write_memory(reagent x, vector<double> data) {
   if (!x.type) {
-    raise_error << "can't write to " << x.to_string() << "; no type\n" << end();
+    raise_error << "can't write to " << to_string(x) << "; no type\n" << end();
     return;
   }
   if (is_dummy(x)) return;
@@ -275,7 +275,7 @@ void write_memory(reagent x, vector<double> data) {
   long long int base = x.value;
   if (base == 0) return;
   if (size_mismatch(x, data)) {
-    raise_error << maybe(current_recipe_name()) << "size mismatch in storing to " << x.original_string << " (" << size_of(x.type) << " vs " << SIZE(data) << ") at '" << current_instruction().to_string() << "'\n" << end();
+    raise_error << maybe(current_recipe_name()) << "size mismatch in storing to " << x.original_string << " (" << size_of(x.type) << " vs " << SIZE(data) << ") at '" << to_string(current_instruction()) << "'\n" << end();
     return;
   }
   // End write_memory(reagent x, long long int base) Special-cases
diff --git a/021check_instruction.cc b/021check_instruction.cc
index cf0a8d74..63d933f3 100644
--- a/021check_instruction.cc
+++ b/021check_instruction.cc
@@ -23,7 +23,7 @@ void check_instruction(const recipe_ordinal r) {
       // Primitive Recipe Checks
       case COPY: {
         if (SIZE(inst.products) != SIZE(inst.ingredients)) {
-          raise_error << "ingredients and products should match in '" << inst.to_string() << "'\n" << end();
+          raise_error << "ingredients and products should match in '" << to_string(inst) << "'\n" << end();
           break;
         }
         for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
diff --git a/022arithmetic.cc b/022arithmetic.cc
index 5f158517..8389074e 100644
--- a/022arithmetic.cc
+++ b/022arithmetic.cc
@@ -14,7 +14,7 @@ case ADD: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'add' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'add' yields exactly one product in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
@@ -86,7 +86,7 @@ case SUBTRACT: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'subtract' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'subtract' yields exactly one product in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
@@ -142,7 +142,7 @@ case MULTIPLY: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'multiply' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'multiply' yields exactly one product in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
@@ -199,7 +199,7 @@ case DIVIDE: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'divide' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'divide' yields exactly one product in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
@@ -247,15 +247,15 @@ put(Recipe_ordinal, "divide-with-remainder", DIVIDE_WITH_REMAINDER);
 :(before "End Primitive Recipe Checks")
 case DIVIDE_WITH_REMAINDER: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise_error << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires number ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'divide-with-remainder' yields two products in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'divide-with-remainder' yields two products in '" << to_string(inst) << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.products); ++i) {
@@ -272,7 +272,7 @@ case DIVIDE_WITH_REMAINDER: {
   long long int a = static_cast<long long int>(ingredients.at(0).at(0));
   long long int b = static_cast<long long int>(ingredients.at(1).at(0));
   if (b == 0) {
-    raise_error << maybe(current_recipe_name()) << "divide by zero in '" << current_instruction().to_string() << "'\n" << end();
+    raise_error << maybe(current_recipe_name()) << "divide by zero in '" << to_string(current_instruction()) << "'\n" << end();
     products.resize(2);
     products.at(0).push_back(0);
     products.at(1).push_back(0);
@@ -331,15 +331,15 @@ put(Recipe_ordinal, "shift-left", SHIFT_LEFT);
 :(before "End Primitive Recipe Checks")
 case SHIFT_LEFT: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'shift-left' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'shift-left' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise_error << maybe(get(Recipe, r).name) << "'shift-left' requires number ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'shift-left' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'shift-left' yields one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'shift-left' yields one product in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
@@ -355,7 +355,7 @@ case SHIFT_LEFT: {
   long long int b = static_cast<long long int>(ingredients.at(1).at(0));
   products.resize(1);
   if (b < 0) {
-    raise_error << maybe(current_recipe_name()) << "second ingredient can't be negative in '" << current_instruction().to_string() << "'\n" << end();
+    raise_error << maybe(current_recipe_name()) << "second ingredient can't be negative in '" << to_string(current_instruction()) << "'\n" << end();
     products.at(0).push_back(0);
     break;
   }
@@ -402,15 +402,15 @@ put(Recipe_ordinal, "shift-right", SHIFT_RIGHT);
 :(before "End Primitive Recipe Checks")
 case SHIFT_RIGHT: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'shift-right' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'shift-right' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise_error << maybe(get(Recipe, r).name) << "'shift-right' requires number ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'shift-right' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'shift-right' yields one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'shift-right' yields one product in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
@@ -426,7 +426,7 @@ case SHIFT_RIGHT: {
   long long int b = static_cast<long long int>(ingredients.at(1).at(0));
   products.resize(1);
   if (b < 0) {
-    raise_error << maybe(current_recipe_name()) << "second ingredient can't be negative in '" << current_instruction().to_string() << "'\n" << end();
+    raise_error << maybe(current_recipe_name()) << "second ingredient can't be negative in '" << to_string(current_instruction()) << "'\n" << end();
     products.at(0).push_back(0);
     break;
   }
@@ -473,15 +473,15 @@ put(Recipe_ordinal, "and-bits", AND_BITS);
 :(before "End Primitive Recipe Checks")
 case AND_BITS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'and-bits' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'and-bits' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise_error << maybe(get(Recipe, r).name) << "'and-bits' requires number ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'and-bits' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'and-bits' yields one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'and-bits' yields one product in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
@@ -531,15 +531,15 @@ put(Recipe_ordinal, "or-bits", OR_BITS);
 :(before "End Primitive Recipe Checks")
 case OR_BITS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'or-bits' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'or-bits' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise_error << maybe(get(Recipe, r).name) << "'or-bits' requires number ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'or-bits' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'or-bits' yields one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'or-bits' yields one product in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
@@ -583,15 +583,15 @@ put(Recipe_ordinal, "xor-bits", XOR_BITS);
 :(before "End Primitive Recipe Checks")
 case XOR_BITS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'xor-bits' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'xor-bits' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise_error << maybe(get(Recipe, r).name) << "'xor-bits' requires number ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'xor-bits' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'xor-bits' yields one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'xor-bits' yields one product in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
@@ -635,15 +635,15 @@ put(Recipe_ordinal, "flip-bits", FLIP_BITS);
 :(before "End Primitive Recipe Checks")
 case FLIP_BITS: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'flip-bits' requires exactly one ingredient, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'flip-bits' requires exactly one ingredient, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(get(Recipe, r).name) << "'flip-bits' requires a number ingredient, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'flip-bits' requires a number ingredient, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'flip-bits' yields one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'flip-bits' yields one product in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
diff --git a/023boolean.cc b/023boolean.cc
index 13400c4c..fa962462 100644
--- a/023boolean.cc
+++ b/023boolean.cc
@@ -107,7 +107,7 @@ put(Recipe_ordinal, "not", NOT);
 :(before "End Primitive Recipe Checks")
 case NOT: {
   if (SIZE(inst.products) > SIZE(inst.ingredients)) {
-    raise_error << maybe(get(Recipe, r).name) << "'not' cannot have fewer ingredients than products in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'not' cannot have fewer ingredients than products in '" << to_string(inst) << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
diff --git a/024jump.cc b/024jump.cc
index 95e31c55..f7228f08 100644
--- a/024jump.cc
+++ b/024jump.cc
@@ -16,7 +16,7 @@ put(Recipe_ordinal, "jump", JUMP);
 :(before "End Primitive Recipe Checks")
 case JUMP: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'jump' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'jump' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
@@ -55,7 +55,7 @@ put(Recipe_ordinal, "jump-if", JUMP_IF);
 :(before "End Primitive Recipe Checks")
 case JUMP_IF: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'jump-if' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'jump-if' requires exactly two ingredients, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
@@ -107,7 +107,7 @@ put(Recipe_ordinal, "jump-unless", JUMP_UNLESS);
 :(before "End Primitive Recipe Checks")
 case JUMP_UNLESS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'jump-unless' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'jump-unless' requires exactly two ingredients, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
diff --git a/025compare.cc b/025compare.cc
index 056c859d..ca736ec9 100644
--- a/025compare.cc
+++ b/025compare.cc
@@ -7,7 +7,7 @@ put(Recipe_ordinal, "equal", EQUAL);
 :(before "End Primitive Recipe Checks")
 case EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'equal' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
     break;
   }
   break;
@@ -66,7 +66,7 @@ put(Recipe_ordinal, "greater-than", GREATER_THAN);
 :(before "End Primitive Recipe Checks")
 case GREATER_THAN: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'greater-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'greater-than' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
@@ -125,7 +125,7 @@ put(Recipe_ordinal, "lesser-than", LESSER_THAN);
 :(before "End Primitive Recipe Checks")
 case LESSER_THAN: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'lesser-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'lesser-than' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
@@ -184,7 +184,7 @@ put(Recipe_ordinal, "greater-or-equal", GREATER_OR_EQUAL);
 :(before "End Primitive Recipe Checks")
 case GREATER_OR_EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'greater-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'greater-or-equal' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
@@ -251,7 +251,7 @@ put(Recipe_ordinal, "lesser-or-equal", LESSER_OR_EQUAL);
 :(before "End Primitive Recipe Checks")
 case LESSER_OR_EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'lesser-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'lesser-or-equal' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
diff --git a/029tools.cc b/029tools.cc
index 7090abda..c379825a 100644
--- a/029tools.cc
+++ b/029tools.cc
@@ -13,7 +13,7 @@ put(Recipe_ordinal, "trace", TRACE);
 :(before "End Primitive Recipe Checks")
 case TRACE: {
   if (SIZE(inst.ingredients) < 3) {
-    raise_error << maybe(get(Recipe, r).name) << "'trace' takes three or more ingredients rather than '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'trace' takes three or more ingredients rather than '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
@@ -201,7 +201,7 @@ put(Recipe_ordinal, "assert", ASSERT);
 :(before "End Primitive Recipe Checks")
 case ASSERT: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'assert' takes exactly two ingredients rather than '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'assert' takes exactly two ingredients rather than '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
diff --git a/030container.cc b/030container.cc
index 15e6471f..e88b0692 100644
--- a/030container.cc
+++ b/030container.cc
@@ -133,7 +133,7 @@ put(Recipe_ordinal, "get", GET);
 :(before "End Primitive Recipe Checks")
 case GET: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'get' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'get' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);  // new copy for every invocation
@@ -173,7 +173,7 @@ case GET: {
   // Update GET base in Run
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
     break;
   }
   type_ordinal base_type = base.type->value;
@@ -270,7 +270,7 @@ put(Recipe_ordinal, "get-address", GET_ADDRESS);
 :(before "End Primitive Recipe Checks")
 case GET_ADDRESS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'get-address' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'get-address' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
@@ -314,7 +314,7 @@ case GET_ADDRESS: {
   // Update GET_ADDRESS base in Run
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
     break;
   }
   type_ordinal base_type = base.type->value;
@@ -550,11 +550,11 @@ void check_or_set_invalid_types(const recipe_ordinal r) {
     instruction& inst = caller.steps.at(index);
     for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
       check_or_set_invalid_types(inst.ingredients.at(i).type, inst.ingredients.at(i).properties.at(0).second,
-                                 maybe(caller.name), "'"+inst.to_string()+"'");
+                                 maybe(caller.name), "'"+to_string(inst)+"'");
     }
     for (long long int i = 0; i < SIZE(inst.products); ++i) {
       check_or_set_invalid_types(inst.products.at(i).type, inst.products.at(i).properties.at(0).second,
-                                 maybe(caller.name), "'"+inst.to_string()+"'");
+                                 maybe(caller.name), "'"+to_string(inst)+"'");
     }
   }
   // End check_or_set_invalid_types
@@ -613,11 +613,11 @@ void check_invalid_types(const recipe_ordinal r) {
     const instruction& inst = get(Recipe, r).steps.at(index);
     for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
       check_invalid_types(inst.ingredients.at(i).type,
-                          maybe(get(Recipe, r).name), "'"+inst.to_string()+"'");
+                          maybe(get(Recipe, r).name), "'"+to_string(inst)+"'");
     }
     for (long long int i = 0; i < SIZE(inst.products); ++i) {
       check_invalid_types(inst.products.at(i).type,
-                          maybe(get(Recipe, r).name), "'"+inst.to_string()+"'");
+                          maybe(get(Recipe, r).name), "'"+to_string(inst)+"'");
     }
   }
 }
@@ -752,19 +752,19 @@ void check_merge_calls(const recipe_ordinal r) {
     const instruction& inst = caller.steps.at(i);
     if (inst.name != "merge") continue;
     if (SIZE(inst.products) != 1) {
-      raise_error << maybe(caller.name) << "'merge' should yield a single product in '" << inst.to_string() << "'\n" << end();
+      raise_error << maybe(caller.name) << "'merge' should yield a single product in '" << to_string(inst) << "'\n" << end();
       continue;
     }
     reagent product = inst.products.at(0);
     // Update product While Type-checking Merge
     type_ordinal product_type = product.type->value;
     if (product_type == 0 || !contains_key(Type, product_type)) {
-      raise_error << maybe(caller.name) << "'merge' should yield a container in '" << inst.to_string() << "'\n" << end();
+      raise_error << maybe(caller.name) << "'merge' should yield a container in '" << to_string(inst) << "'\n" << end();
       continue;
     }
     const type_info& info = get(Type, product_type);
     if (info.kind != CONTAINER && info.kind != EXCLUSIVE_CONTAINER) {
-      raise_error << maybe(caller.name) << "'merge' should yield a container in '" << inst.to_string() << "'\n" << end();
+      raise_error << maybe(caller.name) << "'merge' should yield a container in '" << to_string(inst) << "'\n" << end();
       continue;
     }
     check_merge_call(inst.ingredients, product, caller, inst);
@@ -779,7 +779,7 @@ void check_merge_call(const vector<reagent>& ingredients, const reagent& product
     assert(!state.data.empty());
     trace(9999, "transform") << ingredient_index << " vs " << SIZE(ingredients) << end();
     if (ingredient_index >= SIZE(ingredients)) {
-      raise_error << maybe(caller.name) << "too few ingredients in '" << inst.to_string() << "'\n" << end();
+      raise_error << maybe(caller.name) << "too few ingredients in '" << to_string(inst) << "'\n" << end();
       return;
     }
     reagent& container = state.data.top().container;
@@ -796,7 +796,7 @@ void check_merge_call(const vector<reagent>& ingredients, const reagent& product
             state.data.pop();
             if (state.data.empty()) {
               if (ingredient_index < SIZE(ingredients))
-                raise_error << maybe(caller.name) << "too many ingredients in '" << inst.to_string() << "'\n" << end();
+                raise_error << maybe(caller.name) << "too many ingredients in '" << to_string(inst) << "'\n" << end();
               return;
             }
             ++state.data.top().container_element_index;
@@ -812,7 +812,7 @@ void check_merge_call(const vector<reagent>& ingredients, const reagent& product
       // End valid_merge Cases
       default: {
         if (!types_coercible(container, ingredients.at(ingredient_index))) {
-          raise_error << maybe(caller.name) << "incorrect type of ingredient " << ingredient_index << " in '" << inst.to_string() << "'\n" << end();
+          raise_error << maybe(caller.name) << "incorrect type of ingredient " << ingredient_index << " in '" << to_string(inst) << "'\n" << end();
           cerr << "  expected " << debug_string(container) << '\n';
           cerr << "  got " << debug_string(ingredients.at(ingredient_index)) << '\n';
           return;
@@ -823,7 +823,7 @@ void check_merge_call(const vector<reagent>& ingredients, const reagent& product
           state.data.pop();
           if (state.data.empty()) {
             if (ingredient_index < SIZE(ingredients))
-              raise_error << maybe(caller.name) << "too many ingredients in '" << inst.to_string() << "'\n" << end();
+              raise_error << maybe(caller.name) << "too many ingredients in '" << to_string(inst) << "'\n" << end();
             return;
           }
           ++state.data.top().container_element_index;
diff --git a/031address.cc b/031address.cc
index 5284dea1..be4dd8f8 100644
--- a/031address.cc
+++ b/031address.cc
@@ -25,7 +25,7 @@ recipe main [
 :(before "long long int base = x.value" following "void write_memory(reagent x, vector<double> data)")
 canonize(x);
 if (x.value == 0) {
-  raise_error << "can't write to location 0 in '" << current_instruction().to_string() << "'\n" << end();
+  raise_error << "can't write to location 0 in '" << to_string(current_instruction()) << "'\n" << end();
   return;
 }
 
@@ -91,7 +91,7 @@ if (!canonize_type(product)) continue;
 bool canonize_type(reagent& r) {
   while (has_property(r, "lookup")) {
     if (!r.type || r.type->value != get(Type_ordinal, "address")) {
-      raise_error << "can't lookup non-address: " << r.to_string() << ": " << debug_string(r.type) << '\n' << end();
+      raise_error << "can't lookup non-address: " << to_string(r) << ": " << debug_string(r.type) << '\n' << end();
       return false;
     }
     drop_from_type(r, "address");
diff --git a/032array.cc b/032array.cc
index b558d98f..d25ee7fa 100644
--- a/032array.cc
+++ b/032array.cc
@@ -20,7 +20,7 @@ put(Recipe_ordinal, "create-array", CREATE_ARRAY);
 :(before "End Primitive Recipe Checks")
 case CREATE_ARRAY: {
   if (inst.products.empty()) {
-    raise_error << maybe(get(Recipe, r).name) << "'create-array' needs one product and no ingredients but got '" << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'create-array' needs one product and no ingredients but got '" << to_string(inst) << '\n' << end();
     break;
   }
   reagent product = inst.products.at(0);
@@ -30,12 +30,12 @@ case CREATE_ARRAY: {
     break;
   }
   if (!product.type->right) {
-    raise_error << maybe(get(Recipe, r).name) << "create array of what? " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "create array of what? " << to_string(inst) << '\n' << end();
     break;
   }
   // 'create-array' will need to check properties rather than types
   if (!product.properties.at(0).second || !product.properties.at(0).second->right || !product.properties.at(0).second->right->right) {
-    raise_error << maybe(get(Recipe, r).name) << "create array of what size? " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "create array of what size? " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_integer(product.properties.at(0).second->right->right->value)) {
@@ -178,7 +178,7 @@ put(Recipe_ordinal, "index", INDEX);
 :(before "End Primitive Recipe Checks")
 case INDEX: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'index' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'index' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
@@ -205,7 +205,7 @@ case INDEX: {
   long long int base_address = base.value;
   trace(9998, "run") << "base address is " << base_address << end();
   if (base_address == 0) {
-    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
     break;
   }
   reagent offset = current_instruction().ingredients.at(1);
@@ -318,7 +318,7 @@ put(Recipe_ordinal, "index-address", INDEX_ADDRESS);
 :(before "End Primitive Recipe Checks")
 case INDEX_ADDRESS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'index-address' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'index-address' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
@@ -345,7 +345,7 @@ case INDEX_ADDRESS: {
   canonize(base);
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
     break;
   }
   reagent offset = current_instruction().ingredients.at(1);
@@ -426,7 +426,7 @@ put(Recipe_ordinal, "length", LENGTH);
 :(before "End Primitive Recipe Checks")
 case LENGTH: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'length' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'length' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
     break;
   }
   reagent x = inst.ingredients.at(0);
@@ -442,7 +442,7 @@ case LENGTH: {
   reagent x = current_instruction().ingredients.at(0);
   canonize(x);
   if (x.value == 0) {
-    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
     break;
   }
   products.resize(1);
diff --git a/033exclusive_container.cc b/033exclusive_container.cc
index ec77e639..b5116914 100644
--- a/033exclusive_container.cc
+++ b/033exclusive_container.cc
@@ -81,7 +81,7 @@ put(Recipe_ordinal, "maybe-convert", MAYBE_CONVERT);
 case MAYBE_CONVERT: {
   const recipe& caller = get(Recipe, r);
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(caller.name) << "'maybe-convert' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(caller.name) << "'maybe-convert' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
@@ -100,7 +100,7 @@ case MAYBE_CONVERT: {
   reagent& offset = inst.ingredients.at(1);
   populate_value(offset);
   if (offset.value >= SIZE(get(Type, base.type->value).elements)) {
-    raise_error << maybe(caller.name) << "invalid tag " << offset.value << " in '" << inst.to_string() << '\n' << end();
+    raise_error << maybe(caller.name) << "invalid tag " << offset.value << " in '" << to_string(inst) << '\n' << end();
     break;
   }
   reagent variant = variant_type(base, offset.value);
@@ -117,7 +117,7 @@ case MAYBE_CONVERT: {
   canonize(base);
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise_error << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
     break;
   }
   long long int tag = current_instruction().ingredients.at(1).value;
@@ -251,7 +251,7 @@ case EXCLUSIVE_CONTAINER: {
   reagent ingredient = ingredients.at(ingredient_index);  // unnecessary copy just to keep this function from modifying caller
   populate_value(ingredient);
   if (ingredient.value >= SIZE(container_info.elements)) {
-    raise_error << maybe(caller.name) << "invalid tag at " << ingredient_index << " for " << container_info.name << " in '" << inst.to_string() << '\n' << end();
+    raise_error << maybe(caller.name) << "invalid tag at " << ingredient_index << " for " << container_info.name << " in '" << to_string(inst) << '\n' << end();
     return;
   }
   reagent variant = variant_type(container, ingredient.value);
diff --git a/034call.cc b/034call.cc
index f9ba5def..6ab18ba4 100644
--- a/034call.cc
+++ b/034call.cc
@@ -97,7 +97,7 @@ inline const instruction& to_instruction(const call& call) {
 :(after "Defined Recipe Checks")
 // not a primitive; check that it's present in the book of recipes
 if (!contains_key(Recipe, inst.operation)) {
-  raise_error << maybe(get(Recipe, r).name) << "undefined operation in '" << inst.to_string() << "'\n" << end();
+  raise_error << maybe(get(Recipe, r).name) << "undefined operation in '" << to_string(inst) << "'\n" << end();
   break;
 }
 :(replace{} "default:" following "End Primitive Recipe Implementations")
diff --git a/035call_ingredient.cc b/035call_ingredient.cc
index f079f0c5..466078dc 100644
--- a/035call_ingredient.cc
+++ b/035call_ingredient.cc
@@ -42,7 +42,7 @@ put(Recipe_ordinal, "next-ingredient", NEXT_INGREDIENT);
 :(before "End Primitive Recipe Checks")
 case NEXT_INGREDIENT: {
   if (!inst.ingredients.empty()) {
-    raise_error << maybe(get(Recipe, r).name) << "'next-ingredient' didn't expect any ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'next-ingredient' didn't expect any ingredients in '" << to_string(inst) << "'\n" << end();
     break;
   }
   break;
@@ -141,7 +141,7 @@ put(Recipe_ordinal, "ingredient", INGREDIENT);
 :(before "End Primitive Recipe Checks")
 case INGREDIENT: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'ingredient' expects exactly one ingredient, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'ingredient' expects exactly one ingredient, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_literal(inst.ingredients.at(0)) && !is_mu_number(inst.ingredients.at(0))) {
diff --git a/036call_reply.cc b/036call_reply.cc
index eb4c1aba..ee295aa2 100644
--- a/036call_reply.cc
+++ b/036call_reply.cc
@@ -97,16 +97,16 @@ void check_types_of_reply_instructions(recipe_ordinal r) {
         if (has_property(reply_inst.ingredients.at(i), "same-as-ingredient")) {
           string_tree* tmp = property(reply_inst.ingredients.at(i), "same-as-ingredient");
           if (!tmp || tmp->right) {
-            raise_error << maybe(caller.name) << "'same-as-ingredient' metadata should take exactly one value in " << reply_inst.to_string() << '\n' << end();
+            raise_error << maybe(caller.name) << "'same-as-ingredient' metadata should take exactly one value in " << to_string(reply_inst) << '\n' << end();
             goto finish_reply_check;
           }
           long long int ingredient_index = to_integer(tmp->value);
           if (ingredient_index >= SIZE(caller_instruction.ingredients)) {
-            raise_error << maybe(caller.name) << "too few ingredients in '" << caller_instruction.to_string() << "'\n" << end();
+            raise_error << maybe(caller.name) << "too few ingredients in '" << to_string(caller_instruction) << "'\n" << end();
             goto finish_reply_check;
           }
           if (!is_dummy(caller_instruction.products.at(i)) && !is_literal(caller_instruction.ingredients.at(ingredient_index)) && caller_instruction.products.at(i).name != caller_instruction.ingredients.at(ingredient_index).name) {
-            raise_error << maybe(caller.name) << "'" << caller_instruction.to_string() << "' should write to " << caller_instruction.ingredients.at(ingredient_index).original_string << " rather than " << caller_instruction.products.at(i).original_string << '\n' << end();
+            raise_error << maybe(caller.name) << "'" << to_string(caller_instruction) << "' should write to " << caller_instruction.ingredients.at(ingredient_index).original_string << " rather than " << caller_instruction.products.at(i).original_string << '\n' << end();
           }
         }
       }
diff --git a/037new.cc b/037new.cc
index 95339edc..05d8a3e7 100644
--- a/037new.cc
+++ b/037new.cc
@@ -81,7 +81,7 @@ put(Recipe_ordinal, "new", NEW);
 case NEW: {
   const recipe& caller = get(Recipe, r);
   if (inst.ingredients.empty() || SIZE(inst.ingredients) > 2) {
-    raise_error << maybe(caller.name) << "'new' requires one or two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(caller.name) << "'new' requires one or two ingredients, but got " << to_string(inst) << '\n' << end();
     break;
   }
   // End NEW Check Special-cases
@@ -95,7 +95,7 @@ case NEW: {
     break;
   }
   if (!product_of_new_is_valid(inst)) {
-    raise_error << maybe(caller.name) << "product of 'new' has incorrect type: " << inst.to_string() << '\n' << end();
+    raise_error << maybe(caller.name) << "product of 'new' has incorrect type: " << to_string(inst) << '\n' << end();
     break;
   }
   break;
@@ -301,7 +301,7 @@ put(Recipe_ordinal, "abandon", ABANDON);
 :(before "End Primitive Recipe Checks")
 case ABANDON: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'abandon' requires one ingredient, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'abandon' requires one ingredient, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   reagent types = inst.ingredients.at(0);
diff --git a/038location_array.cc b/038location_array.cc
index b2ac48b1..cbb6d445 100644
--- a/038location_array.cc
+++ b/038location_array.cc
@@ -6,7 +6,7 @@ put(Recipe_ordinal, "to-location-array", TO_LOCATION_ARRAY);
 case TO_LOCATION_ARRAY: {
   const recipe& caller = get(Recipe, r);
   if (!is_shared_address_of_array_of_numbers(inst.products.at(0))) {
-    raise_error << maybe(caller.name) << "product of 'to-location-array' has incorrect type: " << inst.to_string() << '\n' << end();
+    raise_error << maybe(caller.name) << "product of 'to-location-array' has incorrect type: " << to_string(inst) << '\n' << end();
     break;
   }
   break;
diff --git a/042name.cc b/042name.cc
index bdaf50e9..733a8359 100644
--- a/042name.cc
+++ b/042name.cc
@@ -73,7 +73,7 @@ void transform_names(const recipe_ordinal r) {
 bool is_disqualified(/*mutable*/ reagent& x, const instruction& inst, const string& recipe_name) {
   if (!x.type) {
     // End Null-type is_disqualified Exceptions
-    raise_error << maybe(recipe_name) << "missing type for " << x.original_string << " in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(recipe_name) << "missing type for " << x.original_string << " in '" << to_string(inst) << "'\n" << end();
     return true;
   }
   if (is_raw(x)) return true;
@@ -196,7 +196,7 @@ recipe main [
 // replace element names of containers with offsets
 if (inst.name == "get" || inst.name == "get-address") {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_literal(inst.ingredients.at(1)))
@@ -238,7 +238,7 @@ recipe main [
 // convert variant names of exclusive containers
 if (inst.name == "maybe-convert") {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << to_string(inst) << "'\n" << end();
     break;
   }
   assert(is_literal(inst.ingredients.at(1)));
diff --git a/043space.cc b/043space.cc
index 145fd816..497d87be 100644
--- a/043space.cc
+++ b/043space.cc
@@ -56,7 +56,7 @@ void absolutize(reagent& x) {
   if (is_raw(x) || is_dummy(x)) return;
   if (x.name == "default-space") return;
   if (!x.initialized) {
-    raise_error << current_instruction().to_string() << ": reagent not initialized: " << x.original_string << '\n' << end();
+    raise_error << to_string(current_instruction()) << ": reagent not initialized: " << x.original_string << '\n' << end();
   }
   x.set_value(address(x.value, space_base(x)));
   x.properties.push_back(pair<string, string_tree*>("raw", NULL));
@@ -235,7 +235,7 @@ void try_reclaim_locals() {
 
 void rewrite_default_space_instruction(instruction& curr) {
   if (!curr.ingredients.empty())
-    raise_error << curr.to_string() << " can't take any ingredients\n" << end();
+    raise_error << to_string(curr) << " can't take any ingredients\n" << end();
   curr.name = "new";
   curr.ingredients.push_back(reagent("location:type"));
   curr.ingredients.push_back(reagent("number-of-locals:literal"));
diff --git a/045closure_name.cc b/045closure_name.cc
index d16175b1..52e415fc 100644
--- a/045closure_name.cc
+++ b/045closure_name.cc
@@ -58,7 +58,7 @@ void collect_surrounding_spaces(const recipe_ordinal r) {
           || !type->right->right->right
           || type->right->right->right->value != get(Type_ordinal, "location")
           || type->right->right->right->right) {
-        raise_error << "slot 0 should always have type address:shared:array:location, but is " << inst.products.at(j).to_string() << '\n' << end();
+        raise_error << "slot 0 should always have type address:shared:array:location, but is " << to_string(inst.products.at(j)) << '\n' << end();
         continue;
       }
       string_tree* s = property(inst.products.at(j), "names");
@@ -66,7 +66,7 @@ void collect_surrounding_spaces(const recipe_ordinal r) {
         raise_error << "slot 0 requires a /names property in recipe " << get(Recipe, r).name << end();
         continue;
       }
-      if (s->right) raise_error << "slot 0 should have a single value in /names, but got " << inst.products.at(j).to_string() << '\n' << end();
+      if (s->right) raise_error << "slot 0 should have a single value in /names, but got " << to_string(inst.products.at(j)) << '\n' << end();
       const string& surrounding_recipe_name = s->value;
       if (surrounding_recipe_name.empty()) {
         raise_error << "slot 0 doesn't initialize its /names property in recipe " << get(Recipe, r).name << end();
@@ -112,7 +112,7 @@ long long int lookup_name(const reagent& x, const recipe_ordinal default_recipe)
 long long int lookup_name(const reagent& x, const recipe_ordinal r, set<recipe_ordinal>& done, vector<recipe_ordinal>& path) {
   if (!Name[r].empty()) return Name[r][x.name];
   if (contains_key(done, r)) {
-    raise_error << "can't compute address of " << x.to_string() << " because " << end();
+    raise_error << "can't compute address of " << to_string(x) << " because " << end();
     for (long long int i = 1; i < SIZE(path); ++i) {
       raise_error << path.at(i-1) << " requires computing names of " << path.at(i) << '\n' << end();
     }
diff --git a/050scenario.cc b/050scenario.cc
index 63c446ef..6606f09b 100644
--- a/050scenario.cc
+++ b/050scenario.cc
@@ -594,7 +594,7 @@ put(Recipe_ordinal, "check-trace-count-for-label", CHECK_TRACE_COUNT_FOR_LABEL);
 :(before "End Primitive Recipe Checks")
 case CHECK_TRACE_COUNT_FOR_LABEL: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'check-trace-for-label' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'check-trace-for-label' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
diff --git a/056recipe_header.cc b/056recipe_header.cc
index f55c2ba8..757e57fe 100644
--- a/056recipe_header.cc
+++ b/056recipe_header.cc
@@ -218,17 +218,17 @@ void check_calls_against_header(const recipe_ordinal r) {
     for (long int i = 0; i < min(SIZE(inst.ingredients), SIZE(callee.ingredients)); ++i) {
       // ingredients coerced from call to callee
       if (!types_coercible(callee.ingredients.at(i), inst.ingredients.at(i)))
-        raise_error << maybe(caller.name) << "ingredient " << i << " has the wrong type at '" << inst.to_string() << "'\n" << end();
+        raise_error << maybe(caller.name) << "ingredient " << i << " has the wrong type at '" << to_string(inst) << "'\n" << end();
       if (is_unique_address(inst.ingredients.at(i)))
-        raise << maybe(caller.name) << "try to avoid passing non-shared addresses into calls, like ingredient " << i << " at '" << inst.to_string() << "'\n" << end();
+        raise << maybe(caller.name) << "try to avoid passing non-shared addresses into calls, like ingredient " << i << " at '" << to_string(inst) << "'\n" << end();
     }
     for (long int i = 0; i < min(SIZE(inst.products), SIZE(callee.products)); ++i) {
       if (is_dummy(inst.products.at(i))) continue;
       // products coerced from callee to call
       if (!types_coercible(inst.products.at(i), callee.products.at(i)))
-        raise_error << maybe(caller.name) << "product " << i << " has the wrong type at '" << inst.to_string() << "'\n" << end();
+        raise_error << maybe(caller.name) << "product " << i << " has the wrong type at '" << to_string(inst) << "'\n" << end();
       if (is_unique_address(inst.products.at(i)))
-        raise << maybe(caller.name) << "try to avoid getting non-shared addresses out of calls, like product " << i << " at '" << inst.to_string() << "'\n" << end();
+        raise << maybe(caller.name) << "try to avoid getting non-shared addresses out of calls, like product " << i << " at '" << to_string(inst) << "'\n" << end();
     }
   }
 }
@@ -292,12 +292,12 @@ void check_reply_instructions_against_header(const recipe_ordinal r) {
     const instruction& inst = caller_recipe.steps.at(i);
     if (inst.name != "reply") continue;
     if (SIZE(caller_recipe.products) != SIZE(inst.ingredients)) {
-      raise_error << maybe(caller_recipe.name) << "replied with the wrong number of products at '" << inst.to_string() << "'\n" << end();
+      raise_error << maybe(caller_recipe.name) << "replied with the wrong number of products at '" << to_string(inst) << "'\n" << end();
       continue;
     }
     for (long long int i = 0; i < SIZE(caller_recipe.products); ++i) {
       if (!types_match(caller_recipe.products.at(i), inst.ingredients.at(i)))
-        raise_error << maybe(caller_recipe.name) << "replied with the wrong type at '" << inst.to_string() << "'\n" << end();
+        raise_error << maybe(caller_recipe.name) << "replied with the wrong type at '" << to_string(inst) << "'\n" << end();
     }
   }
 }
@@ -378,7 +378,7 @@ void deduce_types_from_header(const recipe_ordinal r) {
   }
   for (long long int i = 0; i < SIZE(caller_recipe.steps); ++i) {
     instruction& inst = caller_recipe.steps.at(i);
-    trace(9992, "transform") << "instruction: " << inst.to_string() << end();
+    trace(9992, "transform") << "instruction: " << to_string(inst) << end();
     for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
       if (inst.ingredients.at(i).type) continue;
       if (header_type.find(inst.ingredients.at(i).name) == header_type.end())
diff --git a/057static_dispatch.cc b/057static_dispatch.cc
index 9c71ac38..576ef35f 100644
--- a/057static_dispatch.cc
+++ b/057static_dispatch.cc
@@ -194,14 +194,14 @@ string best_variant(instruction& inst, const recipe& caller_recipe) {
 
   // error messages
   if (get(Recipe_ordinal, inst.name) >= MAX_PRIMITIVE_RECIPES) {  // we currently don't check types for primitive variants
-    raise_error << maybe(caller_recipe.name) << "failed to find a matching call for '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(caller_recipe.name) << "failed to find a matching call for '" << to_string(inst) << "'\n" << end();
     for (list<call>::iterator p = /*skip*/++resolve_stack.begin(); p != resolve_stack.end(); ++p) {
       const recipe& specializer_recipe = get(Recipe, p->running_recipe);
       const instruction& specializer_inst = specializer_recipe.steps.at(p->running_step_index);
       if (specializer_recipe.name != "interactive")
-        raise_error << "  (from '" << specializer_inst.to_string() << "' in " << specializer_recipe.name << ")\n" << end();
+        raise_error << "  (from '" << to_string(specializer_inst) << "' in " << specializer_recipe.name << ")\n" << end();
       else
-        raise_error << "  (from '" << specializer_inst.to_string() << "')\n" << end();
+        raise_error << "  (from '" << to_string(specializer_inst) << "')\n" << end();
       // One special-case to help with the rewrite_stash transform. (cross-layer)
       if (specializer_inst.products.at(0).name.find("stash_") == 0) {
         instruction stash_inst;
@@ -525,10 +525,10 @@ string header_label(recipe_ordinal r) {
   ostringstream out;
   out << "recipe " << caller.name;
   for (long long int i = 0; i < SIZE(caller.ingredients); ++i)
-    out << ' ' << caller.ingredients.at(i).to_string();
+    out << ' ' << to_string(caller.ingredients.at(i));
   if (!caller.products.empty()) out << " ->";
   for (long long int i = 0; i < SIZE(caller.products); ++i)
-    out << ' ' << caller.products.at(i).to_string();
+    out << ' ' << to_string(caller.products.at(i));
   return out.str();
 }
 
diff --git a/059shape_shifting_recipe.cc b/059shape_shifting_recipe.cc
index 5bb1126d..5784af16 100644
--- a/059shape_shifting_recipe.cc
+++ b/059shape_shifting_recipe.cc
@@ -301,7 +301,7 @@ void compute_type_names(recipe& variant) {
     save_or_deduce_type_name(variant.products.at(i), type_names, variant);
   for (long long int i = 0; i < SIZE(variant.steps); ++i) {
     instruction& inst = variant.steps.at(i);
-    trace(9993, "transform") << "  instruction: " << inst.to_string() << end();
+    trace(9993, "transform") << "  instruction: " << to_string(inst) << end();
     for (long long int in = 0; in < SIZE(inst.ingredients); ++in)
       save_or_deduce_type_name(inst.ingredients.at(in), type_names, variant);
     for (long long int out = 0; out < SIZE(inst.products); ++out)
@@ -310,7 +310,7 @@ void compute_type_names(recipe& variant) {
 }
 
 void save_or_deduce_type_name(reagent& x, map<string, string_tree*>& type_name, const recipe& variant) {
-  trace(9994, "transform") << "    checking " << x.to_string() << ": " << debug_string(x.properties.at(0).second) << end();
+  trace(9994, "transform") << "    checking " << to_string(x) << ": " << debug_string(x.properties.at(0).second) << end();
   if (!x.properties.at(0).second && contains_key(type_name, x.name)) {
     x.properties.at(0).second = new string_tree(*get(type_name, x.name));
     trace(9994, "transform") << "    deducing type to " << debug_string(x.properties.at(0).second) << end();
@@ -374,7 +374,7 @@ void accumulate_type_ingredients(const string_tree* exemplar_type, const string_
     }
     else {
       if (!deeply_equal_types(get(mappings, exemplar_type->value), refinement_type)) {
-        raise_error << maybe(caller_recipe.name) << "no call found for '" << call_instruction.to_string() << "'\n" << end();
+        raise_error << maybe(caller_recipe.name) << "no call found for '" << to_string(call_instruction) << "'\n" << end();
 //?         cerr << exemplar_type->value << ": " << debug_string(get(mappings, exemplar_type->value)) << " vs " << debug_string(refinement_type) << '\n';
         *error = true;
         return;
@@ -404,7 +404,7 @@ void replace_type_ingredients(recipe& new_recipe, const map<string, const string
   // update its body
   for (long long int i = 0; i < SIZE(new_recipe.steps); ++i) {
     instruction& inst = new_recipe.steps.at(i);
-    trace(9993, "transform") << "replacing in instruction '" << inst.to_string() << "'" << end();
+    trace(9993, "transform") << "replacing in instruction '" << to_string(inst) << "'" << end();
     for (long long int j = 0; j < SIZE(inst.ingredients); ++j)
       replace_type_ingredients(inst.ingredients.at(j), mappings, new_recipe);
     for (long long int j = 0; j < SIZE(inst.products); ++j)
@@ -413,7 +413,7 @@ void replace_type_ingredients(recipe& new_recipe, const map<string, const string
     if (inst.name == "new" && inst.ingredients.at(0).properties.at(0).second->value != "literal-string") {
       string_tree* type_name = parse_string_tree(inst.ingredients.at(0).name);
       replace_type_ingredients(type_name, mappings);
-      inst.ingredients.at(0).name = type_name->to_string();
+      inst.ingredients.at(0).name = to_string(type_name);
       delete type_name;
     }
   }
diff --git a/060immutable.cc b/060immutable.cc
index 4d637d6c..496e33c7 100644
--- a/060immutable.cc
+++ b/060immutable.cc
@@ -243,9 +243,9 @@ void check_immutable_ingredient_in_instruction(const instruction& inst, const se
       // primitive recipe
       if (inst.operation == GET_ADDRESS || inst.operation == INDEX_ADDRESS) {
         if (current_ingredient_name == original_ingredient_name)
-          raise << maybe(caller.name) << "cannot modify ingredient " << current_ingredient_name << " after instruction '" << inst.to_string() << "' because it's not also a product of " << caller.name << '\n' << end();
+          raise << maybe(caller.name) << "cannot modify ingredient " << current_ingredient_name << " after instruction '" << to_string(inst) << "' because it's not also a product of " << caller.name << '\n' << end();
         else
-          raise << maybe(caller.name) << "cannot modify " << current_ingredient_name << " after instruction '" << inst.to_string() << "' because that would modify ingredient " << original_ingredient_name << " which is not also a product of " << caller.name << '\n' << end();
+          raise << maybe(caller.name) << "cannot modify " << current_ingredient_name << " after instruction '" << to_string(inst) << "' because that would modify ingredient " << original_ingredient_name << " which is not also a product of " << caller.name << '\n' << end();
       }
     }
     else {
@@ -253,9 +253,9 @@ void check_immutable_ingredient_in_instruction(const instruction& inst, const se
       if (!is_mu_address(current_ingredient)) return;  // making a copy is ok
       if (is_modified_in_recipe(inst.operation, current_ingredient_index, caller)) {
         if (current_ingredient_name == original_ingredient_name)
-          raise << maybe(caller.name) << "cannot modify ingredient " << current_ingredient_name << " at instruction '" << inst.to_string() << "' because it's not also a product of " << caller.name << '\n' << end();
+          raise << maybe(caller.name) << "cannot modify ingredient " << current_ingredient_name << " at instruction '" << to_string(inst) << "' because it's not also a product of " << caller.name << '\n' << end();
         else
-          raise << maybe(caller.name) << "cannot modify " << current_ingredient_name << " after instruction '" << inst.to_string() << "' because that would modify ingredient " << original_ingredient_name << " which is not also a product of " << caller.name << '\n' << end();
+          raise << maybe(caller.name) << "cannot modify " << current_ingredient_name << " after instruction '" << to_string(inst) << "' because that would modify ingredient " << original_ingredient_name << " which is not also a product of " << caller.name << '\n' << end();
       }
     }
   }
diff --git a/061recipe.cc b/061recipe.cc
index 5798f4df..4e6f2b83 100644
--- a/061recipe.cc
+++ b/061recipe.cc
@@ -115,12 +115,12 @@ void check_indirect_calls_against_header(const recipe_ordinal r) {
     if (!callee_header.has_header) continue;
     for (long int i = /*skip callee*/1; i < min(SIZE(inst.ingredients), SIZE(callee_header.ingredients)+/*skip callee*/1); ++i) {
       if (!types_coercible(callee_header.ingredients.at(i-/*skip callee*/1), inst.ingredients.at(i)))
-        raise_error << maybe(caller.name) << "ingredient " << i-/*skip callee*/1 << " has the wrong type at '" << inst.to_string() << "'\n" << end();
+        raise_error << maybe(caller.name) << "ingredient " << i-/*skip callee*/1 << " has the wrong type at '" << to_string(inst) << "'\n" << end();
     }
     for (long int i = 0; i < min(SIZE(inst.products), SIZE(callee_header.products)); ++i) {
       if (is_dummy(inst.products.at(i))) continue;
       if (!types_coercible(callee_header.products.at(i), inst.products.at(i)))
-        raise_error << maybe(caller.name) << "product " << i << " has the wrong type at '" << inst.to_string() << "'\n" << end();
+        raise_error << maybe(caller.name) << "product " << i << " has the wrong type at '" << to_string(inst) << "'\n" << end();
     }
   }
 }
diff --git a/062scheduler.cc b/062scheduler.cc
index ca22caae..348024c2 100644
--- a/062scheduler.cc
+++ b/062scheduler.cc
@@ -343,7 +343,7 @@ put(Recipe_ordinal, "routine-state", ROUTINE_STATE);
 :(before "End Primitive Recipe Checks")
 case ROUTINE_STATE: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'routine-state' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'routine-state' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
@@ -376,7 +376,7 @@ put(Recipe_ordinal, "restart", RESTART);
 :(before "End Primitive Recipe Checks")
 case RESTART: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'restart' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'restart' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
@@ -404,7 +404,7 @@ put(Recipe_ordinal, "stop", STOP);
 :(before "End Primitive Recipe Checks")
 case STOP: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'stop' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'stop' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
@@ -486,7 +486,7 @@ put(Recipe_ordinal, "limit-time", LIMIT_TIME);
 :(before "End Primitive Recipe Checks")
 case LIMIT_TIME: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'limit-time' requires exactly two ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'limit-time' requires exactly two ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
diff --git a/063wait.cc b/063wait.cc
index 888edcdf..37fbabb1 100644
--- a/063wait.cc
+++ b/063wait.cc
@@ -96,7 +96,7 @@ put(Recipe_ordinal, "wait-for-routine", WAIT_FOR_ROUTINE);
 :(before "End Primitive Recipe Checks")
 case WAIT_FOR_ROUTINE: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'wait-for-routine' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'wait-for-routine' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
@@ -108,7 +108,7 @@ case WAIT_FOR_ROUTINE: {
 :(before "End Primitive Recipe Implementations")
 case WAIT_FOR_ROUTINE: {
   if (ingredients.at(0).at(0) == Current_routine->id) {
-    raise_error << maybe(current_recipe_name()) << "routine can't wait for itself! " << current_instruction().to_string() << '\n' << end();
+    raise_error << maybe(current_recipe_name()) << "routine can't wait for itself! " << to_string(current_instruction()) << '\n' << end();
     break;
   }
   Current_routine->state = WAITING;
diff --git a/074random.cc b/074random.cc
index 69ed8b2c..fd70b71e 100644
--- a/074random.cc
+++ b/074random.cc
@@ -36,7 +36,7 @@ put(Recipe_ordinal, "round", ROUND);
 :(before "End Primitive Recipe Checks")
 case ROUND: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'round' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'round' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
diff --git a/077hash.cc b/077hash.cc
index a42b439a..88a5d1f7 100644
--- a/077hash.cc
+++ b/077hash.cc
@@ -15,7 +15,7 @@ put(Recipe_ordinal, "hash", HASH);
 :(before "End Primitive Recipe Checks")
 case HASH: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'hash' takes exactly one ingredient rather than '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'hash' takes exactly one ingredient rather than '" << to_string(inst) << "'\n" << end();
     break;
   }
   break;
@@ -363,7 +363,7 @@ put(Recipe_ordinal, "hash_old", HASH_OLD);
 :(before "End Primitive Recipe Checks")
 case HASH_OLD: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'hash_old' takes exactly one ingredient rather than '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'hash_old' takes exactly one ingredient rather than '" << to_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_string(inst.ingredients.at(0))) {
diff --git a/080display.cc b/080display.cc
index 7a807c62..79fcc697 100644
--- a/080display.cc
+++ b/080display.cc
@@ -100,7 +100,7 @@ put(Recipe_ordinal, "print-character-to-display", PRINT_CHARACTER_TO_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case PRINT_CHARACTER_TO_DISPLAY: {
   if (inst.ingredients.empty()) {
-    raise_error << maybe(get(Recipe, r).name) << "'print-character-to-display' requires at least one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'print-character-to-display' requires at least one ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
@@ -186,7 +186,7 @@ put(Recipe_ordinal, "move-cursor-on-display", MOVE_CURSOR_ON_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case MOVE_CURSOR_ON_DISPLAY: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'move-cursor-on-display' requires two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'move-cursor-on-display' requires two ingredients, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
diff --git a/091run_interactive.cc b/091run_interactive.cc
index 9ad77ebb..8930c935 100644
--- a/091run_interactive.cc
+++ b/091run_interactive.cc
@@ -30,11 +30,11 @@ put(Recipe_ordinal, "run-interactive", RUN_INTERACTIVE);
 :(before "End Primitive Recipe Checks")
 case RUN_INTERACTIVE: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'run-interactive' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'run-interactive' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_string(inst.ingredients.at(0))) {
-    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'run-interactive' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'run-interactive' should be a string, but got " << to_string(inst.ingredients.at(0)) << '\n' << end();
     break;
   }
   break;
@@ -449,7 +449,7 @@ put(Recipe_ordinal, "reload", RELOAD);
 :(before "End Primitive Recipe Checks")
 case RELOAD: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'reload' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'reload' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_string(inst.ingredients.at(0))) {
diff --git a/092persist.cc b/092persist.cc
index e0201cd0..ce7be5d3 100644
--- a/092persist.cc
+++ b/092persist.cc
@@ -9,7 +9,7 @@ put(Recipe_ordinal, "restore", RESTORE);
 :(before "End Primitive Recipe Checks")
 case RESTORE: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(get(Recipe, r).name) << "'restore' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'restore' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
     break;
   }
   string filename;
@@ -20,7 +20,7 @@ case RESTORE: {
     ;
   }
   else {
-    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'restore' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'restore' should be a string, but got " << to_string(inst.ingredients.at(0)) << '\n' << end();
     break;
   }
   break;
@@ -73,7 +73,7 @@ put(Recipe_ordinal, "save", SAVE);
 :(before "End Primitive Recipe Checks")
 case SAVE: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(get(Recipe, r).name) << "'save' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'save' requires exactly two ingredients, but got " << to_string(inst) << '\n' << end();
     break;
   }
   if (is_literal_string(inst.ingredients.at(0))) {
@@ -83,11 +83,11 @@ case SAVE: {
     ;
   }
   else {
-    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'save' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'save' should be a string, but got " << to_string(inst.ingredients.at(0)) << '\n' << end();
     break;
   }
   if (!is_mu_string(inst.ingredients.at(1))) {
-    raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'save' should be an address:array:character, but got " << inst.ingredients.at(1).to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'save' should be an address:array:character, but got " << to_string(inst.ingredients.at(1)) << '\n' << end();
     break;
   }
   break;