about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-03-21 02:25:52 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-03-21 02:25:52 -0700
commitacc4792d2f7c787aad064876a1eb2d00bdf076b2 (patch)
tree22aaf0d8ff820082d66008311607e639c2d48989
parentdad3bedd1ca78162f87a235c10b036a06492a5f5 (diff)
downloadmu-acc4792d2f7c787aad064876a1eb2d00bdf076b2.tar.gz
2803
Show more thorough information about instructions in the trace, but keep
the original form in error messages.
-rw-r--r--010vm.cc36
-rw-r--r--011load.cc56
-rw-r--r--014literal_string.cc22
-rw-r--r--015literal_noninteger.cc2
-rw-r--r--020run.cc18
-rw-r--r--021check_instruction.cc3
-rw-r--r--022arithmetic.cc56
-rw-r--r--023boolean.cc6
-rw-r--r--024jump.cc32
-rw-r--r--025compare.cc20
-rw-r--r--029tools.cc4
-rw-r--r--030container.cc42
-rw-r--r--031address.cc4
-rw-r--r--032array.cc18
-rw-r--r--033exclusive_container.cc12
-rw-r--r--034call.cc12
-rw-r--r--035call_ingredient.cc4
-rw-r--r--036call_reply.cc6
-rw-r--r--037new.cc44
-rw-r--r--038location_array.cc2
-rw-r--r--042name.cc6
-rw-r--r--043space.cc4
-rw-r--r--050scenario.cc6
-rw-r--r--053dilated_reagent.cc4
-rw-r--r--054parse_tree.cc4
-rw-r--r--055recipe_header.cc16
-rw-r--r--056static_dispatch.cc6
-rw-r--r--058shape_shifting_recipe.cc4
-rw-r--r--060immutable.cc10
-rw-r--r--061recipe.cc4
-rw-r--r--062scheduler.cc22
-rw-r--r--063wait.cc4
-rw-r--r--071rewrite_stash.cc6
-rw-r--r--075random.cc2
-rw-r--r--078hash.cc4
-rw-r--r--080display.cc4
-rw-r--r--091run_interactive.cc4
-rw-r--r--092persist.cc4
38 files changed, 264 insertions, 249 deletions
diff --git a/010vm.cc b/010vm.cc
index 1120280c..c3618ffe 100644
--- a/010vm.cc
+++ b/010vm.cc
@@ -34,7 +34,7 @@ struct instruction {
   string label;  // only if is_label
   string name;  // only if !is_label
   string old_name;  // before our automatic rewrite rules
-  string original_string;
+  string original_string;  // for error messages
   recipe_ordinal operation;  // get(Recipe_ordinal, name)
   vector<reagent> ingredients;  // only if !is_label
   vector<reagent> products;  // only if !is_label
@@ -451,7 +451,7 @@ string debug_string(const recipe& x) {
   return out.str();
 }
 
-string to_string(const instruction& inst) {
+string to_original_string(const instruction& inst) {
   if (inst.is_label) return inst.label;
   ostringstream out;
   for (int i = 0; i < SIZE(inst.products); ++i) {
@@ -467,20 +467,40 @@ string to_string(const instruction& inst) {
   return out.str();
 }
 
+string to_string(const instruction& inst) {
+  if (inst.is_label) return inst.label;
+  ostringstream out;
+  for (int i = 0; i < SIZE(inst.products); ++i) {
+    if (i > 0) out << ", ";
+    out << to_string(inst.products.at(i));
+  }
+  if (!inst.products.empty()) out << " <- ";
+  out << inst.name << ' ';
+  for (int i = 0; i < SIZE(inst.ingredients); ++i) {
+    if (i > 0) out << ", ";
+    out << to_string(inst.ingredients.at(i));
+  }
+  return out.str();
+}
+
 string to_string(const reagent& r) {
+  if (is_dummy(r)) return "_";
   ostringstream out;
+  out << "{";
   out << r.name << ": " << names_to_string(r.type);
   if (!r.properties.empty()) {
-    out << ", {";
-    for (int i = 0; i < SIZE(r.properties); ++i) {
-      if (i > 0) out << ", ";
-      out << "\"" << r.properties.at(i).first << "\": " << to_string(r.properties.at(i).second);
-    }
-    out << "}";
+    for (int i = 0; i < SIZE(r.properties); ++i)
+      out << ", \"" << r.properties.at(i).first << "\": " << to_string(r.properties.at(i).second);
   }
+  out << "}";
   return out.str();
 }
 
+// special name for ignoring some products
+inline bool is_dummy(const reagent& x) {
+  return x.name == "_";
+}
+
 string debug_string(const reagent& x) {
   ostringstream out;
   out << x.name << ": " << x.value << ' ' << to_string(x.type) << " -- " << to_string(x);
diff --git a/011load.cc b/011load.cc
index d71a67b5..5ebb87e0 100644
--- a/011load.cc
+++ b/011load.cc
@@ -6,8 +6,8 @@ def main [
   1:number <- copy 23
 ]
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal"
-+parse:   product: 1: "number"
++parse:   ingredient: {23: "literal"}
++parse:   product: {1: "number"}
 
 :(code)
 vector<recipe_ordinal> load(string form) {
@@ -235,8 +235,8 @@ def main [
   1:number <- copy 23
 ]
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal"
-+parse:   product: 1: "number"
++parse:   ingredient: {23: "literal"}
++parse:   product: {1: "number"}
 
 :(scenario parse_comment_amongst_instruction)
 def main [
@@ -244,8 +244,8 @@ def main [
   1:number <- copy 23
 ]
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal"
-+parse:   product: 1: "number"
++parse:   ingredient: {23: "literal"}
++parse:   product: {1: "number"}
 
 :(scenario parse_comment_amongst_instruction_2)
 def main [
@@ -254,8 +254,8 @@ def main [
   # comment
 ]
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal"
-+parse:   product: 1: "number"
++parse:   ingredient: {23: "literal"}
++parse:   product: {1: "number"}
 
 :(scenario parse_comment_amongst_instruction_3)
 def main [
@@ -264,19 +264,19 @@ def main [
   2:number <- copy 23
 ]
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal"
-+parse:   product: 1: "number"
++parse:   ingredient: {23: "literal"}
++parse:   product: {1: "number"}
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal"
-+parse:   product: 2: "number"
++parse:   ingredient: {23: "literal"}
++parse:   product: {2: "number"}
 
 :(scenario parse_comment_after_instruction)
 def main [
   1:number <- copy 23  # comment
 ]
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal"
-+parse:   product: 1: "number"
++parse:   ingredient: {23: "literal"}
++parse:   product: {1: "number"}
 
 :(scenario parse_label)
 def main [
@@ -295,43 +295,43 @@ def main [
   1:number <- copy 23/foo:bar:baz
 ]
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal", {"foo": ("bar" "baz")}
-+parse:   product: 1: "number"
++parse:   ingredient: {23: "literal", "foo": ("bar" "baz")}
++parse:   product: {1: "number"}
 
 :(scenario parse_multiple_products)
 def main [
   1:number, 2:number <- copy 23
 ]
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal"
-+parse:   product: 1: "number"
-+parse:   product: 2: "number"
++parse:   ingredient: {23: "literal"}
++parse:   product: {1: "number"}
++parse:   product: {2: "number"}
 
 :(scenario parse_multiple_ingredients)
 def main [
   1:number, 2:number <- copy 23, 4:number
 ]
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal"
-+parse:   ingredient: 4: "number"
-+parse:   product: 1: "number"
-+parse:   product: 2: "number"
++parse:   ingredient: {23: "literal"}
++parse:   ingredient: {4: "number"}
++parse:   product: {1: "number"}
++parse:   product: {2: "number"}
 
 :(scenario parse_multiple_types)
 def main [
   1:number, 2:address:number <- copy 23, 4:number
 ]
 +parse: instruction: copy
-+parse:   ingredient: 23: "literal"
-+parse:   ingredient: 4: "number"
-+parse:   product: 1: "number"
-+parse:   product: 2: ("address" "number")
++parse:   ingredient: {23: "literal"}
++parse:   ingredient: {4: "number"}
++parse:   product: {1: "number"}
++parse:   product: {2: ("address" "number")}
 
 :(scenario parse_properties)
 def main [
   1:address:number/lookup <- copy 23
 ]
-+parse:   product: 1: ("address" "number"), {"lookup": ()}
++parse:   product: {1: ("address" "number"), "lookup": ()}
 
 //: this test we can't represent with a scenario
 :(code)
diff --git a/014literal_string.cc b/014literal_string.cc
index f0fe8d7f..a195c195 100644
--- a/014literal_string.cc
+++ b/014literal_string.cc
@@ -11,13 +11,13 @@
 def main [
   1:address:array:character <- copy [abc def]  # copy can't really take a string
 ]
-+parse:   ingredient: "abc def": "literal-string"
++parse:   ingredient: {"abc def": "literal-string"}
 
 :(scenario string_literal_with_colons)
 def main [
   1:address:array:character <- copy [abc:def/ghi]
 ]
-+parse:   ingredient: "abc:def/ghi": "literal-string"
++parse:   ingredient: {"abc:def/ghi": "literal-string"}
 
 :(before "End Mu Types Initialization")
 put(Type_ordinal, "literal-string", 0);
@@ -131,7 +131,7 @@ string emit_literal_string(string name) {
   size_t pos = 0;
   while (pos != string::npos)
     pos = replace(name, "\n", "\\n", pos);
-  return '"'+name+"\": \"literal-string\"";
+  return "{\""+name+"\": \"literal-string\"}";
 }
 
 size_t replace(string& str, const string& from, const string& to, size_t n) {
@@ -149,20 +149,20 @@ void strip_last(string& s) {
 def main [
   1:address:array:character <- copy [abc [def]]
 ]
-+parse:   ingredient: "abc [def]": "literal-string"
++parse:   ingredient: {"abc [def]": "literal-string"}
 
 :(scenario string_literal_escaped)
 def main [
   1:address:array:character <- copy [abc \[def]
 ]
-+parse:   ingredient: "abc [def": "literal-string"
++parse:   ingredient: {"abc [def": "literal-string"}
 
 :(scenario string_literal_escaped_comment_aware)
 def main [
   1:address:array:character <- copy [
 abc \\\[def]
 ]
-+parse:   ingredient: "\nabc \[def": "literal-string"
++parse:   ingredient: {"\nabc \[def": "literal-string"}
 
 :(scenario string_literal_and_comment)
 def main [
@@ -171,15 +171,15 @@ def main [
 +parse: --- defining main
 +parse: instruction: copy
 +parse:   number of ingredients: 1
-+parse:   ingredient: "abc": "literal-string"
-+parse:   product: 1: ("address" "array" "character")
++parse:   ingredient: {"abc": "literal-string"}
++parse:   product: {1: ("address" "array" "character")}
 
 :(scenario string_literal_escapes_newlines_in_trace)
 def main [
   copy [abc
 def]
 ]
-+parse:   ingredient: "abc\ndef": "literal-string"
++parse:   ingredient: {"abc\ndef": "literal-string"}
 
 :(scenario string_literal_can_skip_past_comments)
 def main [
@@ -188,10 +188,10 @@ def main [
     bar
   ]
 ]
-+parse:   ingredient: "\n    # ']' inside comment\n    bar\n  ": "literal-string"
++parse:   ingredient: {"\n    # ']' inside comment\n    bar\n  ": "literal-string"}
 
 :(scenario string_literal_empty)
 def main [
   copy []
 ]
-+parse:   ingredient: "": "literal-string"
++parse:   ingredient: {"": "literal-string"}
diff --git a/015literal_noninteger.cc b/015literal_noninteger.cc
index 29f539e8..554bcdd5 100644
--- a/015literal_noninteger.cc
+++ b/015literal_noninteger.cc
@@ -5,7 +5,7 @@
 def main [
   1:number <- copy 3.14159
 ]
-+parse:   ingredient: 3.14159: "literal-fractional-number"
++parse:   ingredient: {3.14159: "literal-fractional-number"}
 
 :(after "Parsing reagent(string s)")
 if (is_noninteger(s)) {
diff --git a/020run.cc b/020run.cc
index 3f68cb9c..95bdbe87 100644
--- a/020run.cc
+++ b/020run.cc
@@ -13,7 +13,7 @@
 def main [
   1:number <- copy 23
 ]
-+run: 1:number <- copy 23
++run: {1: "number"} <- copy {23: "literal"}
 +mem: storing 23 in location 1
 
 :(scenario copy)
@@ -21,7 +21,7 @@ def main [
   1:number <- copy 23
   2:number <- copy 1:number
 ]
-+run: 2:number <- copy 1:number
++run: {2: "number"} <- copy {1: "number"}
 +mem: location 1 is 23
 +mem: storing 23 in location 2
 
@@ -87,7 +87,7 @@ void run_current_routine()
       }
     }
     if (SIZE(products) < SIZE(current_instruction().products)) {
-      raise << SIZE(products) << " vs " << SIZE(current_instruction().products) << ": failed to write to all products! " << to_string(current_instruction()) << '\n' << end();
+      raise << SIZE(products) << " vs " << SIZE(current_instruction().products) << ": failed to write to all products! " << to_original_string(current_instruction()) << '\n' << end();
     }
     else {
       for (int i = 0; i < SIZE(current_instruction().products); ++i) {
@@ -275,7 +275,7 @@ void write_memory(reagent x, const vector<double>& data) {
   // End Preprocess write_memory(x)
   if (x.value == 0) return;
   if (size_mismatch(x, data)) {
-    raise << 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();
+    raise << maybe(current_recipe_name()) << "size mismatch in storing to " << x.original_string << " (" << size_of(x.type) << " vs " << SIZE(data) << ") at '" << to_original_string(current_instruction()) << "'\n" << end();
     return;
   }
   // End write_memory(reagent x) Special-cases
@@ -305,10 +305,6 @@ bool size_mismatch(const reagent& x, const vector<double>& data) {
   return size_of(x) != SIZE(data);
 }
 
-inline bool is_dummy(const reagent& x) {
-  return x.name == "_";
-}
-
 inline bool is_literal(const reagent& r) {
   if (!r.type) return false;
   if (r.type->value == 0)
@@ -343,15 +339,15 @@ def main [
   1:number <- copy 23
   2:number <- copy 1:number
 ]
-+run: 1:number <- copy 23
-+run: 2:number <- copy 1:number
++run: {1: "number"} <- copy {23: "literal"}
++run: {2: "number"} <- copy {1: "number"}
 -run: +foo
 
 :(scenario run_dummy)
 def main [
   _ <- copy 0
 ]
-+run: _ <- copy 0
++run: _ <- copy {0: "literal"}
 
 :(scenario write_to_0_disallowed)
 % Hide_errors = true;
diff --git a/021check_instruction.cc b/021check_instruction.cc
index 355b51ab..898b3214 100644
--- a/021check_instruction.cc
+++ b/021check_instruction.cc
@@ -14,7 +14,6 @@ Transform.push_back(check_instruction);  // idempotent
 :(code)
 void check_instruction(const recipe_ordinal r) {
   trace(9991, "transform") << "--- perform checks for recipe " << get(Recipe, r).name << end();
-//?   cerr << "--- perform checks for recipe " << get(Recipe, r).name << '\n';
   map<string, vector<type_ordinal> > metadata;
   for (int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
     instruction& inst = get(Recipe, r).steps.at(i);
@@ -23,7 +22,7 @@ void check_instruction(const recipe_ordinal r) {
       // Primitive Recipe Checks
       case COPY: {
         if (SIZE(inst.products) != SIZE(inst.ingredients)) {
-          raise << "ingredients and products should match in '" << to_string(inst) << "'\n" << end();
+          raise << "ingredients and products should match in '" << to_original_string(inst) << "'\n" << end();
           break;
         }
         for (int i = 0; i < SIZE(inst.ingredients); ++i) {
diff --git a/022arithmetic.cc b/022arithmetic.cc
index f6eca412..21adb0b0 100644
--- a/022arithmetic.cc
+++ b/022arithmetic.cc
@@ -14,7 +14,7 @@ case ADD: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'add' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'add' yields exactly one product in '" << to_original_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 << maybe(get(Recipe, r).name) << "'subtract' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'subtract' yields exactly one product in '" << to_original_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 << maybe(get(Recipe, r).name) << "'multiply' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'multiply' yields exactly one product in '" << to_original_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 << maybe(get(Recipe, r).name) << "'divide' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'divide' yields exactly one product in '" << to_original_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 << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 2) {
-    raise << maybe(get(Recipe, r).name) << "'divide-with-remainder' yields two products in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'divide-with-remainder' yields two products in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   for (int i = 0; i < SIZE(inst.products); ++i) {
@@ -272,7 +272,7 @@ case DIVIDE_WITH_REMAINDER: {
   int a = static_cast<int>(ingredients.at(0).at(0));
   int b = static_cast<int>(ingredients.at(1).at(0));
   if (b == 0) {
-    raise << maybe(current_recipe_name()) << "divide by zero in '" << to_string(current_instruction()) << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "divide by zero in '" << to_original_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 << maybe(get(Recipe, r).name) << "'shift-left' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'shift-left' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise << maybe(get(Recipe, r).name) << "'shift-left' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'shift-left' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'shift-left' yields one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'shift-left' yields one product in '" << to_original_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: {
   int b = static_cast<int>(ingredients.at(1).at(0));
   products.resize(1);
   if (b < 0) {
-    raise << maybe(current_recipe_name()) << "second ingredient can't be negative in '" << to_string(current_instruction()) << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "second ingredient can't be negative in '" << to_original_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 << maybe(get(Recipe, r).name) << "'shift-right' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'shift-right' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise << maybe(get(Recipe, r).name) << "'shift-right' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'shift-right' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'shift-right' yields one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'shift-right' yields one product in '" << to_original_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: {
   int b = static_cast<int>(ingredients.at(1).at(0));
   products.resize(1);
   if (b < 0) {
-    raise << maybe(current_recipe_name()) << "second ingredient can't be negative in '" << to_string(current_instruction()) << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "second ingredient can't be negative in '" << to_original_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 << maybe(get(Recipe, r).name) << "'and-bits' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'and-bits' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise << maybe(get(Recipe, r).name) << "'and-bits' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'and-bits' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'and-bits' yields one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'and-bits' yields one product in '" << to_original_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 << maybe(get(Recipe, r).name) << "'or-bits' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'or-bits' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise << maybe(get(Recipe, r).name) << "'or-bits' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'or-bits' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'or-bits' yields one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'or-bits' yields one product in '" << to_original_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 << maybe(get(Recipe, r).name) << "'xor-bits' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'xor-bits' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise << maybe(get(Recipe, r).name) << "'xor-bits' requires number ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'xor-bits' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'xor-bits' yields one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'xor-bits' yields one product in '" << to_original_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 << maybe(get(Recipe, r).name) << "'flip-bits' requires exactly one ingredient, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'flip-bits' requires exactly one ingredient, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise << maybe(get(Recipe, r).name) << "'flip-bits' requires a number ingredient, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'flip-bits' requires a number ingredient, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'flip-bits' yields one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'flip-bits' yields one product in '" << to_original_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 fdc22fcf..d43c889b 100644
--- a/023boolean.cc
+++ b/023boolean.cc
@@ -13,7 +13,7 @@ case AND: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'and' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'and' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
@@ -71,7 +71,7 @@ case OR: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'or' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'or' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
@@ -123,7 +123,7 @@ put(Recipe_ordinal, "not", NOT);
 :(before "End Primitive Recipe Checks")
 case NOT: {
   if (SIZE(inst.products) > SIZE(inst.ingredients)) {
-    raise << maybe(get(Recipe, r).name) << "'not' cannot have fewer ingredients than products in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'not' cannot have fewer ingredients than products in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   for (int i = 0; i < SIZE(inst.ingredients); ++i) {
diff --git a/024jump.cc b/024jump.cc
index c11a6464..7a1d938a 100644
--- a/024jump.cc
+++ b/024jump.cc
@@ -5,8 +5,8 @@ def main [
   jump 1:offset
   1:number <- copy 1
 ]
-+run: jump 1:offset
--run: 1:number <- copy 1
++run: jump {1: "offset"}
+-run: {1: "number"} <- copy {1: "literal"}
 -mem: storing 1 in location 1
 
 :(before "End Primitive Recipe Declarations")
@@ -16,7 +16,7 @@ put(Recipe_ordinal, "jump", JUMP);
 :(before "End Primitive Recipe Checks")
 case JUMP: {
   if (SIZE(inst.ingredients) != 1) {
-    raise << maybe(get(Recipe, r).name) << "'jump' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'jump' requires exactly one ingredient, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
@@ -44,9 +44,9 @@ def main [
                  #   \/  /\ |
   jump -2:offset #  2 +-->+ |
 ]                #         \/ 3
-+run: jump 1:offset
-+run: jump -2:offset
-+run: jump 3:offset
++run: jump {1: "offset"}
++run: jump {-2: "offset"}
++run: jump {3: "offset"}
 
 :(before "End Primitive Recipe Declarations")
 JUMP_IF,
@@ -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 << maybe(get(Recipe, r).name) << "'jump-if' requires exactly two ingredients, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'jump-if' requires exactly two ingredients, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
@@ -85,9 +85,9 @@ def main [
   jump-if 999, 1:offset
   123:number <- copy 1
 ]
-+run: jump-if 999, 1:offset
++run: jump-if {999: "literal"}, {1: "offset"}
 +run: jumping to instruction 2
--run: 1:number <- copy 1
+-run: {1: "number"} <- copy {1: "literal"}
 -mem: storing 1 in location 123
 
 :(scenario jump_if_fallthrough)
@@ -95,9 +95,9 @@ def main [
   jump-if 0, 1:offset
   123:number <- copy 1
 ]
-+run: jump-if 0, 1:offset
++run: jump-if {0: "literal"}, {1: "offset"}
 +run: jump-if fell through
-+run: 123:number <- copy 1
++run: {123: "number"} <- copy {1: "literal"}
 +mem: storing 1 in location 123
 
 :(before "End Primitive Recipe Declarations")
@@ -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 << maybe(get(Recipe, r).name) << "'jump-unless' requires exactly two ingredients, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'jump-unless' requires exactly two ingredients, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
@@ -137,9 +137,9 @@ def main [
   jump-unless 0, 1:offset
   123:number <- copy 1
 ]
-+run: jump-unless 0, 1:offset
++run: jump-unless {0: "literal"}, {1: "offset"}
 +run: jumping to instruction 2
--run: 123:number <- copy 1
+-run: {123: "number"} <- copy {1: "literal"}
 -mem: storing 1 in location 123
 
 :(scenario jump_unless_fallthrough)
@@ -147,7 +147,7 @@ def main [
   jump-unless 999, 1:offset
   123:number <- copy 1
 ]
-+run: jump-unless 999, 1:offset
++run: jump-unless {999: "literal"}, {1: "offset"}
 +run: jump-unless fell through
-+run: 123:number <- copy 1
++run: {123: "number"} <- copy {1: "literal"}
 +mem: storing 1 in location 123
diff --git a/025compare.cc b/025compare.cc
index bb020c3a..39baa232 100644
--- a/025compare.cc
+++ b/025compare.cc
@@ -7,11 +7,11 @@ put(Recipe_ordinal, "equal", EQUAL);
 :(before "End Primitive Recipe Checks")
 case EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << maybe(get(Recipe, r).name) << "'equal' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'equal' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'equal' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
@@ -74,7 +74,7 @@ put(Recipe_ordinal, "greater-than", GREATER_THAN);
 :(before "End Primitive Recipe Checks")
 case GREATER_THAN: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << maybe(get(Recipe, r).name) << "'greater-than' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'greater-than' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   for (int i = 0; i < SIZE(inst.ingredients); ++i) {
@@ -84,7 +84,7 @@ case GREATER_THAN: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'greater-than' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'greater-than' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
@@ -141,7 +141,7 @@ put(Recipe_ordinal, "lesser-than", LESSER_THAN);
 :(before "End Primitive Recipe Checks")
 case LESSER_THAN: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << maybe(get(Recipe, r).name) << "'lesser-than' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'lesser-than' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   for (int i = 0; i < SIZE(inst.ingredients); ++i) {
@@ -151,7 +151,7 @@ case LESSER_THAN: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'lesser-than' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'lesser-than' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
@@ -208,7 +208,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 << maybe(get(Recipe, r).name) << "'greater-or-equal' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   for (int i = 0; i < SIZE(inst.ingredients); ++i) {
@@ -218,7 +218,7 @@ case GREATER_OR_EQUAL: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
@@ -283,7 +283,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 << maybe(get(Recipe, r).name) << "'lesser-or-equal' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'lesser-or-equal' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   for (int i = 0; i < SIZE(inst.ingredients); ++i) {
@@ -293,7 +293,7 @@ case LESSER_OR_EQUAL: {
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
diff --git a/029tools.cc b/029tools.cc
index 13c5172a..2a52cb2e 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 << maybe(get(Recipe, r).name) << "'trace' takes three or more ingredients rather than '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'trace' takes three or more ingredients rather than '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
@@ -199,7 +199,7 @@ put(Recipe_ordinal, "assert", ASSERT);
 :(before "End Primitive Recipe Checks")
 case ASSERT: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << maybe(get(Recipe, r).name) << "'assert' takes exactly two ingredients rather than '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'assert' takes exactly two ingredients rather than '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
diff --git a/030container.cc b/030container.cc
index a29f7171..4c41b8c1 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 << maybe(get(Recipe, r).name) << "'get' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'get' expects exactly 2 ingredients in '" << to_original_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
   int base_address = base.value;
   if (base_address == 0) {
-    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_original_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 << maybe(get(Recipe, r).name) << "'get-address' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'get-address' expects exactly 2 ingredients in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
@@ -314,7 +314,7 @@ case GET_ADDRESS: {
   // Update GET_ADDRESS base in Run
   int base_address = base.value;
   if (base_address == 0) {
-    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_original_string(current_instruction()) << "'\n" << end();
     break;
   }
   type_ordinal base_type = base.type->value;
@@ -373,8 +373,8 @@ container foo [
   y:number
 ]
 +parse: --- defining container foo
-+parse: element: x: "number"
-+parse: element: y: "number"
++parse: element: {x: "number"}
++parse: element: {y: "number"}
 
 :(scenario container_use_before_definition)
 container foo [
@@ -388,15 +388,15 @@ container bar [
 ]
 +parse: --- defining container foo
 +parse: type number: 1000
-+parse:   element: x: "number"
++parse:   element: {x: "number"}
 # todo: brittle
 # type bar is unknown at this point, but we assign it a number
-+parse:   element: y: "bar"
++parse:   element: {y: "bar"}
 # later type bar geon
 +parse: --- defining container bar
 +parse: type number: 1001
-+parse:   element: x: "number"
-+parse:   element: y: "number"
++parse:   element: {x: "number"}
++parse:   element: {y: "number"}
 
 :(before "End Command Handlers")
 else if (command == "container") {
@@ -514,9 +514,9 @@ void check_or_set_invalid_types(const recipe_ordinal r) {
   for (int index = 0; index < SIZE(caller.steps); ++index) {
     instruction& inst = caller.steps.at(index);
     for (int i = 0; i < SIZE(inst.ingredients); ++i)
-      check_or_set_invalid_types(inst.ingredients.at(i).type, maybe(caller.name), "'"+to_string(inst)+"'");
+      check_or_set_invalid_types(inst.ingredients.at(i).type, maybe(caller.name), "'"+to_original_string(inst)+"'");
     for (int i = 0; i < SIZE(inst.products); ++i)
-      check_or_set_invalid_types(inst.products.at(i).type, maybe(caller.name), "'"+to_string(inst)+"'");
+      check_or_set_invalid_types(inst.products.at(i).type, maybe(caller.name), "'"+to_original_string(inst)+"'");
   }
   // End check_or_set_invalid_types
 }
@@ -551,8 +551,8 @@ container foo [
   y:number
 ]
 +parse: --- defining container foo
-+parse: element: x: "number"
-+parse: element: y: "number"
++parse: element: {x: "number"}
++parse: element: {y: "number"}
 
 :(before "End Transform All")
 check_container_field_types();
@@ -693,19 +693,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 << maybe(caller.name) << "'merge' should yield a single product in '" << to_string(inst) << "'\n" << end();
+      raise << maybe(caller.name) << "'merge' should yield a single product in '" << to_original_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 << maybe(caller.name) << "'merge' should yield a container in '" << to_string(inst) << "'\n" << end();
+      raise << maybe(caller.name) << "'merge' should yield a container in '" << to_original_string(inst) << "'\n" << end();
       continue;
     }
     const type_info& info = get(Type, product_type);
     if (info.kind != CONTAINER && info.kind != EXCLUSIVE_CONTAINER) {
-      raise << maybe(caller.name) << "'merge' should yield a container in '" << to_string(inst) << "'\n" << end();
+      raise << maybe(caller.name) << "'merge' should yield a container in '" << to_original_string(inst) << "'\n" << end();
       continue;
     }
     check_merge_call(inst.ingredients, product, caller, inst);
@@ -720,7 +720,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 << maybe(caller.name) << "too few ingredients in '" << to_string(inst) << "'\n" << end();
+      raise << maybe(caller.name) << "too few ingredients in '" << to_original_string(inst) << "'\n" << end();
       return;
     }
     reagent& container = state.data.top().container;
@@ -737,7 +737,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 << maybe(caller.name) << "too many ingredients in '" << to_string(inst) << "'\n" << end();
+                raise << maybe(caller.name) << "too many ingredients in '" << to_original_string(inst) << "'\n" << end();
               return;
             }
             ++state.data.top().container_element_index;
@@ -753,7 +753,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 << maybe(caller.name) << "incorrect type of ingredient " << ingredient_index << " in '" << to_string(inst) << "'\n" << end();
+          raise << maybe(caller.name) << "incorrect type of ingredient " << ingredient_index << " in '" << to_original_string(inst) << "'\n" << end();
           cerr << "  expected " << debug_string(container) << '\n';
           cerr << "  got " << debug_string(ingredients.at(ingredient_index)) << '\n';
           return;
@@ -764,7 +764,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 << maybe(caller.name) << "too many ingredients in '" << to_string(inst) << "'\n" << end();
+              raise << maybe(caller.name) << "too many ingredients in '" << to_original_string(inst) << "'\n" << end();
             return;
           }
           ++state.data.top().container_element_index;
diff --git a/031address.cc b/031address.cc
index 0bbe8ab8..16e29dbd 100644
--- a/031address.cc
+++ b/031address.cc
@@ -25,7 +25,7 @@ def main [
 :(before "End Preprocess write_memory(x)")
 canonize(x);
 if (x.value == 0) {
-  raise << "can't write to location 0 in '" << to_string(current_instruction()) << "'\n" << end();
+  raise << "can't write to location 0 in '" << to_original_string(current_instruction()) << "'\n" << end();
   return;
 }
 
@@ -189,7 +189,7 @@ def main [
   2:number <- copy 34
   3:number <- copy *1:address:number
 ]
-+parse: ingredient: 1: ("address" "number"), {"lookup": ()}
++parse: ingredient: {1: ("address" "number"), "lookup": ()}
 +mem: storing 34 in location 3
 
 :(before "End Parsing reagent")
diff --git a/032array.cc b/032array.cc
index b7fa44b0..0fd1d0a4 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 << maybe(get(Recipe, r).name) << "'create-array' needs one product and no ingredients but got '" << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'create-array' needs one product and no ingredients but got '" << to_original_string(inst) << '\n' << end();
     break;
   }
   reagent product = inst.products.at(0);
@@ -30,12 +30,12 @@ case CREATE_ARRAY: {
     break;
   }
   if (!product.type->right) {
-    raise << maybe(get(Recipe, r).name) << "create array of what? " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "create array of what? " << to_original_string(inst) << '\n' << end();
     break;
   }
   // 'create-array' will need to check properties rather than types
   if (!product.type->right->right) {
-    raise << maybe(get(Recipe, r).name) << "create array of what size? " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "create array of what size? " << to_original_string(inst) << '\n' << end();
     break;
   }
   if (!is_integer(product.type->right->right->name)) {
@@ -176,7 +176,7 @@ put(Recipe_ordinal, "index", INDEX);
 :(before "End Primitive Recipe Checks")
 case INDEX: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << maybe(get(Recipe, r).name) << "'index' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'index' expects exactly 2 ingredients in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
@@ -203,7 +203,7 @@ case INDEX: {
   int base_address = base.value;
   trace(9998, "run") << "base address is " << base_address << end();
   if (base_address == 0) {
-    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_original_string(current_instruction()) << "'\n" << end();
     break;
   }
   reagent offset = current_instruction().ingredients.at(1);
@@ -320,7 +320,7 @@ put(Recipe_ordinal, "index-address", INDEX_ADDRESS);
 :(before "End Primitive Recipe Checks")
 case INDEX_ADDRESS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << maybe(get(Recipe, r).name) << "'index-address' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'index-address' expects exactly 2 ingredients in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
@@ -347,7 +347,7 @@ case INDEX_ADDRESS: {
   canonize(base);
   int base_address = base.value;
   if (base_address == 0) {
-    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_original_string(current_instruction()) << "'\n" << end();
     break;
   }
   reagent offset = current_instruction().ingredients.at(1);
@@ -428,7 +428,7 @@ put(Recipe_ordinal, "length", LENGTH);
 :(before "End Primitive Recipe Checks")
 case LENGTH: {
   if (SIZE(inst.ingredients) != 1) {
-    raise << maybe(get(Recipe, r).name) << "'length' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'length' expects exactly 2 ingredients in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   reagent x = inst.ingredients.at(0);
@@ -444,7 +444,7 @@ case LENGTH: {
   reagent x = current_instruction().ingredients.at(0);
   canonize(x);
   if (x.value == 0) {
-    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_original_string(current_instruction()) << "'\n" << end();
     break;
   }
   products.resize(1);
diff --git a/033exclusive_container.cc b/033exclusive_container.cc
index 453ed82f..5c1fe6ad 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 << maybe(caller.name) << "'maybe-convert' expects exactly 2 ingredients in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(caller.name) << "'maybe-convert' expects exactly 2 ingredients in '" << to_original_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 << maybe(caller.name) << "invalid tag " << offset.value << " in '" << to_string(inst) << '\n' << end();
+    raise << maybe(caller.name) << "invalid tag " << offset.value << " in '" << to_original_string(inst) << '\n' << end();
     break;
   }
   reagent variant = variant_type(base, offset.value);
@@ -117,7 +117,7 @@ case MAYBE_CONVERT: {
   canonize(base);
   int base_address = base.value;
   if (base_address == 0) {
-    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_string(current_instruction()) << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_original_string(current_instruction()) << "'\n" << end();
     break;
   }
   int tag = current_instruction().ingredients.at(1).value;
@@ -163,8 +163,8 @@ exclusive-container foo [
   y:number
 ]
 +parse: --- defining exclusive-container foo
-+parse: element: x: "number"
-+parse: element: y: "number"
++parse: element: {x: "number"}
++parse: element: {y: "number"}
 
 :(before "End Command Handlers")
 else if (command == "exclusive-container") {
@@ -248,7 +248,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 << maybe(caller.name) << "invalid tag at " << ingredient_index << " for " << container_info.name << " in '" << to_string(inst) << '\n' << end();
+    raise << maybe(caller.name) << "invalid tag at " << ingredient_index << " for " << container_info.name << " in '" << to_original_string(inst) << '\n' << end();
     return;
   }
   reagent variant = variant_type(container, ingredient.value);
diff --git a/034call.cc b/034call.cc
index a878caad..dd240936 100644
--- a/034call.cc
+++ b/034call.cc
@@ -22,12 +22,12 @@ def f [
 ]
 +run: f
 # running f
-+run: 4:number <- copy 0
-+run: 5:number <- copy 0
++run: {4: "number"} <- copy {0: "literal"}
++run: {5: "number"} <- copy {0: "literal"}
 # back out to main
-+run: 1:number <- copy 0
-+run: 2:number <- copy 0
-+run: 3:number <- copy 0
++run: {1: "number"} <- copy {0: "literal"}
++run: {2: "number"} <- copy {0: "literal"}
++run: {3: "number"} <- copy {0: "literal"}
 
 :(before "struct routine {")
 // Everytime a recipe runs another, we interrupt it and start running the new
@@ -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 << maybe(get(Recipe, r).name) << "undefined operation in '" << to_string(inst) << "'\n" << end();
+  raise << maybe(get(Recipe, r).name) << "undefined operation in '" << to_original_string(inst) << "'\n" << end();
   break;
 }
 :(replace{} "default:" following "End Primitive Recipe Implementations")
diff --git a/035call_ingredient.cc b/035call_ingredient.cc
index 10672548..4feaeed8 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 << maybe(get(Recipe, r).name) << "'next-ingredient' didn't expect any ingredients in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'next-ingredient' didn't expect any ingredients in '" << to_original_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 << maybe(get(Recipe, r).name) << "'ingredient' expects exactly one ingredient, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'ingredient' expects exactly one ingredient, but got '" << to_original_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 f0f37137..9f6718c2 100644
--- a/036call_reply.cc
+++ b/036call_reply.cc
@@ -98,16 +98,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 << maybe(caller.name) << "'same-as-ingredient' metadata should take exactly one value in " << to_string(reply_inst) << '\n' << end();
+            raise << maybe(caller.name) << "'same-as-ingredient' metadata should take exactly one value in " << to_original_string(reply_inst) << '\n' << end();
             goto finish_reply_check;
           }
           int ingredient_index = to_integer(tmp->value);
           if (ingredient_index >= SIZE(caller_instruction.ingredients)) {
-            raise << maybe(caller.name) << "too few ingredients in '" << to_string(caller_instruction) << "'\n" << end();
+            raise << maybe(caller.name) << "too few ingredients in '" << to_original_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 << 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();
+            raise << maybe(caller.name) << "'" << to_original_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 feebd58e..435b332a 100644
--- a/037new.cc
+++ b/037new.cc
@@ -82,7 +82,7 @@ put(Recipe_ordinal, "new", NEW);
 case NEW: {
   const recipe& caller = get(Recipe, r);
   if (inst.ingredients.empty() || SIZE(inst.ingredients) > 2) {
-    raise << maybe(caller.name) << "'new' requires one or two ingredients, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(caller.name) << "'new' requires one or two ingredients, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   // End NEW Check Special-cases
@@ -96,7 +96,7 @@ case NEW: {
     break;
   }
   if (!product_of_new_is_valid(inst)) {
-    raise << maybe(caller.name) << "product of 'new' has incorrect type: " << to_string(inst) << '\n' << end();
+    raise << maybe(caller.name) << "product of 'new' has incorrect type: " << to_original_string(inst) << '\n' << end();
     break;
   }
   break;
@@ -249,7 +249,7 @@ def main [
   2:address:shared:number/raw <- new number:type
   3:number/raw <- subtract 2:address:shared:number/raw, 1:address:shared:array:number/raw
 ]
-+run: 1:address:shared:array:number/raw <- new number:type, 5
++run: {1: ("address" "shared" "array" "number"), "raw": ()} <- new {number: "type"}, {5: "literal"}
 +mem: array size is 5
 # don't forget the extra location for array size, and the second extra location for the refcount
 +mem: storing 7 in location 3
@@ -260,7 +260,7 @@ def main [
   2:address:shared:number/raw <- new number:type
   3:number/raw <- subtract 2:address:shared:number/raw, 1:address:shared:array:number/raw
 ]
-+run: 1:address:shared:array:number/raw <- new number:type, 0
++run: {1: ("address" "shared" "array" "number"), "raw": ()} <- new {number: "type"}, {0: "literal"}
 +mem: array size is 0
 # one location for array size, and one for the refcount
 +mem: storing 2 in location 3
@@ -301,7 +301,7 @@ put(Recipe_ordinal, "abandon", ABANDON);
 :(before "End Primitive Recipe Checks")
 case ABANDON: {
   if (SIZE(inst.ingredients) != 1) {
-    raise << maybe(get(Recipe, r).name) << "'abandon' requires one ingredient, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'abandon' requires one ingredient, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   reagent types = inst.ingredients.at(0);
@@ -395,7 +395,7 @@ def main [
   abandon 1:address:shared:number
 ]
 # reuse
-+run: abandon 1:address:shared:number
++run: abandon {1: ("address" "shared" "number")}
 +mem: resetting location 1
 
 //:: Manage refcounts when copying addresses.
@@ -407,13 +407,13 @@ def main [
   1:address:shared:number <- copy 0
   2:address:shared:number <- copy 0
 ]
-+run: 1:address:shared:number <- copy 1000/unsafe
++run: {1: ("address" "shared" "number")} <- copy {1000: "literal", "unsafe": ()}
 +mem: incrementing refcount of 1000: 0 -> 1
-+run: 2:address:shared:number <- copy 1:address:shared:number
++run: {2: ("address" "shared" "number")} <- copy {1: ("address" "shared" "number")}
 +mem: incrementing refcount of 1000: 1 -> 2
-+run: 1:address:shared:number <- copy 0
++run: {1: ("address" "shared" "number")} <- copy {0: "literal"}
 +mem: decrementing refcount of 1000: 2 -> 1
-+run: 2:address:shared:number <- copy 0
++run: {2: ("address" "shared" "number")} <- copy {0: "literal"}
 +mem: decrementing refcount of 1000: 1 -> 0
 # the /unsafe corrupts memory but fortunately we won't be running any more 'new' in this scenario
 +mem: automatically abandoning 1000
@@ -466,9 +466,9 @@ def main [
   1:address:shared:number <- new number:type
   1:address:shared:number <- copy 0
 ]
-+run: 1:address:shared:number <- new number:type
++run: {1: ("address" "shared" "number")} <- new {number: "type"}
 +mem: incrementing refcount of 1000: 0 -> 1
-+run: 1:address:shared:number <- new number:type
++run: {1: ("address" "shared" "number")} <- new {number: "type"}
 +mem: automatically abandoning 1000
 
 :(scenario refcounts_3)
@@ -483,13 +483,13 @@ def foo [
   # return does NOT yet decrement refcount; memory must be explicitly managed
   2:address:shared:number <- copy 0
 ]
-+run: 1:address:shared:number <- new number:type
++run: {1: ("address" "shared" "number")} <- new {number: "type"}
 +mem: incrementing refcount of 1000: 0 -> 1
-+run: 2:address:shared:number <- next-ingredient
++run: {2: ("address" "shared" "number")} <- next-ingredient
 +mem: incrementing refcount of 1000: 1 -> 2
-+run: 2:address:shared:number <- copy 0
++run: {2: ("address" "shared" "number")} <- copy {0: "literal"}
 +mem: decrementing refcount of 1000: 2 -> 1
-+run: 1:address:shared:number <- copy 0
++run: {1: ("address" "shared" "number")} <- copy {0: "literal"}
 +mem: decrementing refcount of 1000: 1 -> 0
 +mem: automatically abandoning 1000
 
@@ -499,9 +499,9 @@ def main [
   # idempotent copies leave refcount unchanged
   1:address:shared:number <- copy 1:address:shared:number
 ]
-+run: 1:address:shared:number <- new number:type
++run: {1: ("address" "shared" "number")} <- new {number: "type"}
 +mem: incrementing refcount of 1000: 0 -> 1
-+run: 1:address:shared:number <- copy 1:address:shared:number
++run: {1: ("address" "shared" "number")} <- copy {1: ("address" "shared" "number")}
 +mem: decrementing refcount of 1000: 1 -> 0
 +mem: incrementing refcount of 1000: 0 -> 1
 
@@ -516,11 +516,11 @@ def main [
 def foo [
   2:address:shared:number <- next-ingredient
 ]
-+run: 1:address:shared:number <- new number:type
++run: {1: ("address" "shared" "number")} <- new {number: "type"}
 +mem: incrementing refcount of 1000: 0 -> 1
-+run: 2:address:shared:number <- next-ingredient
++run: {2: ("address" "shared" "number")} <- next-ingredient
 +mem: incrementing refcount of 1000: 1 -> 2
-+run: 1:address:shared:number <- new number:type
++run: {1: ("address" "shared" "number")} <- new {number: "type"}
 +mem: decrementing refcount of 1000: 2 -> 1
 
 :(scenario refcounts_array)
@@ -532,7 +532,7 @@ def main [
   # allocate another array in its place, implicitly freeing the previous allocation
   10:address:shared:array:number <- new number:type, 25
 ]
-+run: 10:address:shared:array:number <- new number:type, 20
++run: {10: ("address" "shared" "array" "number")} <- new {number: "type"}, {20: "literal"}
 # abandoned array is of old size (20, not 25)
 +abandon: saving in free-list of size 22
 
diff --git a/038location_array.cc b/038location_array.cc
index 543a384d..86cf8e97 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 << maybe(caller.name) << "product of 'to-location-array' has incorrect type: " << to_string(inst) << '\n' << end();
+    raise << maybe(caller.name) << "product of 'to-location-array' has incorrect type: " << to_original_string(inst) << '\n' << end();
     break;
   }
   break;
diff --git a/042name.cc b/042name.cc
index 872b5678..6a9858a6 100644
--- a/042name.cc
+++ b/042name.cc
@@ -92,7 +92,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 << maybe(recipe_name) << "missing type for " << x.original_string << " in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(recipe_name) << "missing type for " << x.original_string << " in '" << to_original_string(inst) << "'\n" << end();
     return true;
   }
   if (is_raw(x)) return true;
@@ -213,7 +213,7 @@ def main [
 // replace element names of containers with offsets
 if (inst.name == "get" || inst.name == "get-address") {
   if (SIZE(inst.ingredients) != 2) {
-    raise << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_literal(inst.ingredients.at(1)))
@@ -255,7 +255,7 @@ def main [
 // convert variant names of exclusive containers
 if (inst.name == "maybe-convert") {
   if (SIZE(inst.ingredients) != 2) {
-    raise << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   assert(is_literal(inst.ingredients.at(1)));
diff --git a/043space.cc b/043space.cc
index c65f456f..06cd09b1 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 << to_string(current_instruction()) << ": reagent not initialized: " << x.original_string << '\n' << end();
+    raise << to_original_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));
@@ -271,7 +271,7 @@ bool escaping(const reagent& r) {
 
 void rewrite_default_space_instruction(instruction& curr) {
   if (!curr.ingredients.empty())
-    raise << to_string(curr) << " can't take any ingredients\n" << end();
+    raise << to_original_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/050scenario.cc b/050scenario.cc
index 3e69a7a0..ea376179 100644
--- a/050scenario.cc
+++ b/050scenario.cc
@@ -95,13 +95,13 @@ scenario foo [
   # ']' in comment
   1:number <- copy 0
 ]
-+run: 1:number <- copy 0
++run: {1: "number"} <- copy {0: "literal"}
 
 :(scenario read_scenario_with_bracket_in_comment_in_nested_string)
 scenario foo [
   1:address:shared:array:character <- new [# not a comment]
 ]
-+run: 1:address:shared:array:character <- new [# not a comment]
++run: {1: ("address" "shared" "array" "character")} <- new {"# not a comment": "literal-string"}
 
 //:: Run scenarios when we run 'mu test'.
 //: Treat the text of the scenario as a regular series of instructions.
@@ -626,7 +626,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 << maybe(get(Recipe, r).name) << "'check-trace-for-label' requires exactly two ingredients, but got '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'check-trace-for-label' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
diff --git a/053dilated_reagent.cc b/053dilated_reagent.cc
index 8e141a43..868c98f5 100644
--- a/053dilated_reagent.cc
+++ b/053dilated_reagent.cc
@@ -7,7 +7,7 @@
 def main [
   {1: number, foo: bar} <- copy 34
 ]
-+parse:   product: 1: "number", {"foo": "bar"}
++parse:   product: {1: "number", "foo": "bar"}
 
 :(scenario load_trailing_space_after_curly_bracket)
 def main [
@@ -21,7 +21,7 @@ def main [
 def main [
   {1: number, foo: bar} <- copy 34  # test comment
 ]
-+parse:   product: 1: "number", {"foo": "bar"}
++parse:   product: {1: "number", "foo": "bar"}
 $error: 0
 
 :(scenario dilated_reagent_with_comment_immediately_following)
diff --git a/054parse_tree.cc b/054parse_tree.cc
index a65f87e7..8724b6f4 100644
--- a/054parse_tree.cc
+++ b/054parse_tree.cc
@@ -7,7 +7,7 @@
 def main [
   {1: number, foo: (bar (baz quux))} <- copy 34
 ]
-+parse:   product: 1: "number", {"foo": ("bar" ("baz" "quux"))}
++parse:   product: {1: "number", "foo": ("bar" ("baz" "quux"))}
 
 :(before "End Parsing Reagent Property(value)")
 value = parse_string_tree(value);
@@ -67,7 +67,7 @@ container foo [
 ]
 container bar [
 ]
-+parse:   product: 1: ("foo" ("address" "array" "character") ("bar" "number"))
++parse:   product: {1: ("foo" ("address" "array" "character") ("bar" "number"))}
 
 :(scenario dilated_reagent_in_static_array)
 def main [
diff --git a/055recipe_header.cc b/055recipe_header.cc
index d6caf76b..cb95020a 100644
--- a/055recipe_header.cc
+++ b/055recipe_header.cc
@@ -219,17 +219,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 << maybe(caller.name) << "ingredient " << i << " has the wrong type at '" << to_string(inst) << "'\n" << end();
+        raise << maybe(caller.name) << "ingredient " << i << " has the wrong type at '" << to_original_string(inst) << "'\n" << end();
       if (is_unique_address(inst.ingredients.at(i)))
-        raise << maybe(caller.name) << "avoid passing non-shared addresses into calls, like ingredient " << i << " at '" << to_string(inst) << "'\n" << end();
+        raise << maybe(caller.name) << "avoid passing non-shared addresses into calls, like ingredient " << i << " at '" << to_original_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 << maybe(caller.name) << "product " << i << " has the wrong type at '" << to_string(inst) << "'\n" << end();
+        raise << maybe(caller.name) << "product " << i << " has the wrong type at '" << to_original_string(inst) << "'\n" << end();
       if (is_unique_address(inst.products.at(i)))
-        raise << maybe(caller.name) << "avoid getting non-shared addresses out of calls, like product " << i << " at '" << to_string(inst) << "'\n" << end();
+        raise << maybe(caller.name) << "avoid getting non-shared addresses out of calls, like product " << i << " at '" << to_original_string(inst) << "'\n" << end();
     }
   }
 }
@@ -293,12 +293,12 @@ void check_reply_instructions_against_header(const recipe_ordinal r) {
     const instruction& inst = caller_recipe.steps.at(i);
     if (inst.name != "reply" && inst.name != "return") continue;
     if (SIZE(caller_recipe.products) != SIZE(inst.ingredients)) {
-      raise << maybe(caller_recipe.name) << "replied with the wrong number of products at '" << to_string(inst) << "'\n" << end();
+      raise << maybe(caller_recipe.name) << "replied with the wrong number of products at '" << to_original_string(inst) << "'\n" << end();
       continue;
     }
     for (int i = 0; i < SIZE(caller_recipe.products); ++i) {
       if (!types_match(caller_recipe.products.at(i), inst.ingredients.at(i)))
-        raise << maybe(caller_recipe.name) << "replied with the wrong type at '" << to_string(inst) << "'\n" << end();
+        raise << maybe(caller_recipe.name) << "replied with the wrong type at '" << to_original_string(inst) << "'\n" << end();
     }
   }
 }
@@ -473,7 +473,7 @@ def add2 x:number, y:number -> z:number [
   load-ingredients
   z <- add x, y
 ]
-+transform: instruction: reply z:number
++transform: instruction: reply {z: "number"}
 +mem: storing 8 in location 1
 
 :(scenario reply_on_fallthrough_already_exists)
@@ -486,7 +486,7 @@ def add2 x:number, y:number -> z:number [
   z <- add x, y  # no type for z
   return z
 ]
-+transform: instruction: return z
++transform: instruction: return {z: ()}
 -transform: instruction: reply z:number
 +mem: storing 8 in location 1
 
diff --git a/056static_dispatch.cc b/056static_dispatch.cc
index 263dc2bf..1d57872d 100644
--- a/056static_dispatch.cc
+++ b/056static_dispatch.cc
@@ -187,14 +187,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 << maybe(caller_recipe.name) << "failed to find a matching call for '" << to_string(inst) << "'\n" << end();
+    raise << maybe(caller_recipe.name) << "failed to find a matching call for '" << to_original_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 << "  (from '" << to_string(specializer_inst) << "' in " << specializer_recipe.name << ")\n" << end();
+        raise << "  (from '" << to_original_string(specializer_inst) << "' in " << specializer_recipe.name << ")\n" << end();
       else
-        raise << "  (from '" << to_string(specializer_inst) << "')\n" << end();
+        raise << "  (from '" << to_original_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;
diff --git a/058shape_shifting_recipe.cc b/058shape_shifting_recipe.cc
index f80edb3b..c892774d 100644
--- a/058shape_shifting_recipe.cc
+++ b/058shape_shifting_recipe.cc
@@ -314,7 +314,7 @@ void accumulate_type_ingredients(const type_tree* exemplar_type, const type_tree
   if (!refinement_type) {
     // todo: make this smarter; only flag an error if exemplar_type contains some *new* type ingredient
     raise << maybe(exemplar.name) << "missing type ingredient for " << exemplar_reagent.original_string << '\n' << end();
-    raise << "  (called from '" << to_string(call_instruction) << "')\n" << end();
+    raise << "  (called from '" << to_original_string(call_instruction) << "')\n" << end();
     return;
   }
   if (is_type_ingredient_name(exemplar_type->name)) {
@@ -333,7 +333,7 @@ void accumulate_type_ingredients(const type_tree* exemplar_type, const type_tree
     }
     else {
       if (!deeply_equal_type_names(get(mappings, exemplar_type->name), curr_refinement_type)) {
-        raise << maybe(caller_recipe.name) << "no call found for '" << to_string(call_instruction) << "'\n" << end();
+        raise << maybe(caller_recipe.name) << "no call found for '" << to_original_string(call_instruction) << "'\n" << end();
         *error = true;
         delete curr_refinement_type;
         return;
diff --git a/060immutable.cc b/060immutable.cc
index a936797a..98e43f60 100644
--- a/060immutable.cc
+++ b/060immutable.cc
@@ -360,7 +360,7 @@ void check_immutable_ingredient_in_instruction(const instruction& inst, const se
   for (int i = 0; i < SIZE(inst.products); ++i) {
     if (has_property(inst.products.at(i), "lookup")
         && current_ingredient_and_aliases.find(inst.products.at(i)) != current_ingredient_and_aliases.end()) {
-      raise << maybe(caller.name) << "cannot modify " << inst.products.at(i).name << " in instruction '" << to_string(inst) << "' because it's not also a product of " << caller.name << '\n' << end();
+      raise << maybe(caller.name) << "cannot modify " << inst.products.at(i).name << " in instruction '" << to_original_string(inst) << "' because it's not also a product of " << caller.name << '\n' << end();
       return;
     }
   }
@@ -377,9 +377,9 @@ void check_immutable_ingredient_in_instruction(const instruction& inst, const se
       if (inst.operation == GET_ADDRESS || inst.operation == INDEX_ADDRESS) {
         // only reason to use get-address or index-address is to modify, so stop right there
         if (current_ingredient_name == original_ingredient_name)
-          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();
+          raise << maybe(caller.name) << "cannot modify ingredient " << current_ingredient_name << " after instruction '" << to_original_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 '" << to_string(inst) << "' 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_original_string(inst) << "' because that would modify ingredient " << original_ingredient_name << " which is not also a product of " << caller.name << '\n' << end();
       }
     }
     else {
@@ -387,9 +387,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 '" << to_string(inst) << "' 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_original_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 '" << to_string(inst) << "' 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_original_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 73f9444b..7ff8dcb9 100644
--- a/061recipe.cc
+++ b/061recipe.cc
@@ -116,12 +116,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 << maybe(caller.name) << "ingredient " << i-/*skip callee*/1 << " has the wrong type at '" << to_string(inst) << "'\n" << end();
+        raise << maybe(caller.name) << "ingredient " << i-/*skip callee*/1 << " has the wrong type at '" << to_original_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 << maybe(caller.name) << "product " << i << " has the wrong type at '" << to_string(inst) << "'\n" << end();
+        raise << maybe(caller.name) << "product " << i << " has the wrong type at '" << to_original_string(inst) << "'\n" << end();
     }
   }
 }
diff --git a/062scheduler.cc b/062scheduler.cc
index d7b554b0..c2438b03 100644
--- a/062scheduler.cc
+++ b/062scheduler.cc
@@ -186,9 +186,9 @@ def f1 [
   2:number <- copy 0
 ]
 +schedule: f1
-+run: 1:number <- copy 0
++run: {1: "number"} <- copy {0: "literal"}
 +schedule: f1
-+run: 2:number <- copy 0
++run: {2: "number"} <- copy {0: "literal"}
 
 :(scenario scheduler_interleaves_routines)
 % Scheduling_interval = 1;
@@ -202,15 +202,15 @@ def f2 [
   4:number <- copy 0
 ]
 +schedule: f1
-+run: start-running f2
++run: start-running {f2: "recipe-literal"}
 +schedule: f2
-+run: 3:number <- copy 0
++run: {3: "number"} <- copy {0: "literal"}
 +schedule: f1
-+run: 1:number <- copy 0
++run: {1: "number"} <- copy {0: "literal"}
 +schedule: f2
-+run: 4:number <- copy 0
++run: {4: "number"} <- copy {0: "literal"}
 +schedule: f1
-+run: 2:number <- copy 0
++run: {2: "number"} <- copy {0: "literal"}
 
 :(scenario start_running_takes_ingredients)
 def f1 [
@@ -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 << maybe(get(Recipe, r).name) << "'routine-state' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'routine-state' requires exactly one ingredient, but got " << to_original_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 << maybe(get(Recipe, r).name) << "'restart' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'restart' requires exactly one ingredient, but got " << to_original_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 << maybe(get(Recipe, r).name) << "'stop' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'stop' requires exactly one ingredient, but got " << to_original_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 << maybe(get(Recipe, r).name) << "'limit-time' requires exactly two ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'limit-time' requires exactly two ingredient, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
diff --git a/063wait.cc b/063wait.cc
index 072a73ca..46bd406f 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 << maybe(get(Recipe, r).name) << "'wait-for-routine' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'wait-for-routine' requires exactly one ingredient, but got " << to_original_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 << maybe(current_recipe_name()) << "routine can't wait for itself! " << to_string(current_instruction()) << '\n' << end();
+    raise << maybe(current_recipe_name()) << "routine can't wait for itself! " << to_original_string(current_instruction()) << '\n' << end();
     break;
   }
   Current_routine->state = WAITING;
diff --git a/071rewrite_stash.cc b/071rewrite_stash.cc
index 058bd481..a41fa72f 100644
--- a/071rewrite_stash.cc
+++ b/071rewrite_stash.cc
@@ -8,8 +8,8 @@ recipe main [
   n:number <- copy 34
   stash n
 ]
-+transform: stash_2_0:address:shared:array:character <- to-text-line n
-+transform: stash stash_2_0:address:shared:array:character
++transform: {stash_2_0: ("address" "shared" "array" "character")} <- to-text-line {n: ()}
++transform: stash {stash_2_0: ("address" "shared" "array" "character")}
 
 :(before "End Instruction Inserting/Deleting Transforms")
 Transform.push_back(rewrite_stashes_to_text);
@@ -73,7 +73,7 @@ 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 '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'to-text' requires a single ingredient, but got '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   break;
diff --git a/075random.cc b/075random.cc
index 4be8f05b..1992649b 100644
--- a/075random.cc
+++ b/075random.cc
@@ -36,7 +36,7 @@ put(Recipe_ordinal, "round", ROUND);
 :(before "End Primitive Recipe Checks")
 case ROUND: {
   if (SIZE(inst.ingredients) != 1) {
-    raise << maybe(get(Recipe, r).name) << "'round' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'round' requires exactly one ingredient, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
diff --git a/078hash.cc b/078hash.cc
index f8003cbe..454a9003 100644
--- a/078hash.cc
+++ b/078hash.cc
@@ -15,7 +15,7 @@ put(Recipe_ordinal, "hash", HASH);
 :(before "End Primitive Recipe Checks")
 case HASH: {
   if (SIZE(inst.ingredients) != 1) {
-    raise << maybe(get(Recipe, r).name) << "'hash' takes exactly one ingredient rather than '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'hash' takes exactly one ingredient rather than '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   break;
@@ -362,7 +362,7 @@ put(Recipe_ordinal, "hash_old", HASH_OLD);
 :(before "End Primitive Recipe Checks")
 case HASH_OLD: {
   if (SIZE(inst.ingredients) != 1) {
-    raise << maybe(get(Recipe, r).name) << "'hash_old' takes exactly one ingredient rather than '" << to_string(inst) << "'\n" << end();
+    raise << maybe(get(Recipe, r).name) << "'hash_old' takes exactly one ingredient rather than '" << to_original_string(inst) << "'\n" << end();
     break;
   }
   if (!is_mu_string(inst.ingredients.at(0))) {
diff --git a/080display.cc b/080display.cc
index 39bc90cf..4f0f962e 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 << maybe(get(Recipe, r).name) << "'print-character-to-display' requires at least one ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'print-character-to-display' requires at least one ingredient, but got " << to_original_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 << maybe(get(Recipe, r).name) << "'move-cursor-on-display' requires two ingredients, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'move-cursor-on-display' requires two ingredients, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
diff --git a/091run_interactive.cc b/091run_interactive.cc
index b84d8ca9..a4e0d21b 100644
--- a/091run_interactive.cc
+++ b/091run_interactive.cc
@@ -30,7 +30,7 @@ put(Recipe_ordinal, "run-interactive", RUN_INTERACTIVE);
 :(before "End Primitive Recipe Checks")
 case RUN_INTERACTIVE: {
   if (SIZE(inst.ingredients) != 1) {
-    raise << maybe(get(Recipe, r).name) << "'run-interactive' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'run-interactive' requires exactly one ingredient, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_string(inst.ingredients.at(0))) {
@@ -437,7 +437,7 @@ put(Recipe_ordinal, "reload", RELOAD);
 :(before "End Primitive Recipe Checks")
 case RELOAD: {
   if (SIZE(inst.ingredients) != 1) {
-    raise << maybe(get(Recipe, r).name) << "'reload' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'reload' requires exactly one ingredient, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   if (!is_mu_string(inst.ingredients.at(0))) {
diff --git a/092persist.cc b/092persist.cc
index 3e833f35..8894d463 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 << maybe(get(Recipe, r).name) << "'restore' requires exactly one ingredient, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'restore' requires exactly one ingredient, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   string filename;
@@ -73,7 +73,7 @@ put(Recipe_ordinal, "save", SAVE);
 :(before "End Primitive Recipe Checks")
 case SAVE: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << maybe(get(Recipe, r).name) << "'save' requires exactly two ingredients, but got " << to_string(inst) << '\n' << end();
+    raise << maybe(get(Recipe, r).name) << "'save' requires exactly two ingredients, but got " << to_original_string(inst) << '\n' << end();
     break;
   }
   if (is_literal_string(inst.ingredients.at(0))) {