about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--020run.cc7
-rw-r--r--021check_instruction.cc2
-rw-r--r--022arithmetic.cc38
-rw-r--r--023boolean.cc8
-rw-r--r--024jump.cc16
-rw-r--r--025compare.cc18
-rw-r--r--029tools.cc14
-rw-r--r--030container.cc12
-rw-r--r--031address.cc6
-rw-r--r--032array.cc18
-rw-r--r--033exclusive_container.cc6
-rw-r--r--034call.cc2
-rw-r--r--035call_ingredient.cc8
-rw-r--r--036call_reply.cc6
-rw-r--r--037recipe.cc4
-rw-r--r--038scheduler.cc18
-rw-r--r--039wait.cc6
-rw-r--r--040brace.cc4
-rw-r--r--041jump_target.cc8
-rw-r--r--042name.cc44
-rw-r--r--043new.cc18
-rw-r--r--044space.cc4
-rw-r--r--045space_surround.cc2
-rw-r--r--047global.cc2
-rw-r--r--048check_type_by_name.cc6
-rw-r--r--050scenario.cc10
-rw-r--r--053continuation.cc6
-rw-r--r--064random.cc4
-rw-r--r--070display.cc14
-rw-r--r--072scenario_screen.cc18
-rw-r--r--081run_interactive.cc12
-rw-r--r--082persist.cc10
-rw-r--r--edit/010-warnings.mu10
33 files changed, 186 insertions, 175 deletions
diff --git a/020run.cc b/020run.cc
index d1e405a7..69829a00 100644
--- a/020run.cc
+++ b/020run.cc
@@ -266,7 +266,7 @@ void write_memory(reagent x, vector<double> data) {
   if (is_literal(x)) return;
   long long int base = x.value;
   if (size_mismatch(x, data)) {
-    raise << current_recipe_name() << ": size mismatch in storing to " << x.original_string << " (" << size_of(x.types) << " vs " << SIZE(data) << ") at '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "size mismatch in storing to " << x.original_string << " (" << size_of(x.types) << " vs " << SIZE(data) << ") at '" << current_instruction().to_string() << "'\n" << end();
     return;
   }
   for (long long int offset = 0; offset < SIZE(data); ++offset) {
@@ -303,6 +303,11 @@ bool is_literal(const reagent& r) {
   return SIZE(r.types) == 1 && r.types.at(0) == 0;
 }
 
+// hook to suppress inserting recipe name into warnings
+string maybe(string s) {
+  return s + ": ";
+}
+
 // helper for tests
 void run(string form) {
   vector<recipe_ordinal> tmp = load(form);
diff --git a/021check_instruction.cc b/021check_instruction.cc
index 5b12af7c..cb332e7d 100644
--- a/021check_instruction.cc
+++ b/021check_instruction.cc
@@ -20,7 +20,7 @@ void check_instruction(const recipe_ordinal r) {
         }
         for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
           if (!types_match(inst.products.at(i), inst.ingredients.at(i))) {
-            raise << Recipe[r].name << ": can't copy " << inst.ingredients.at(i).original_string << " to " << inst.products.at(i).original_string << "; types don't match\n" << end();
+            raise << maybe(Recipe[r].name) << "can't copy " << inst.ingredients.at(i).original_string << " to " << inst.products.at(i).original_string << "; types don't match\n" << end();
             goto finish_checking_instruction;
           }
         }
diff --git a/022arithmetic.cc b/022arithmetic.cc
index 5dc8bcee..fbf3029a 100644
--- a/022arithmetic.cc
+++ b/022arithmetic.cc
@@ -9,16 +9,16 @@ case ADD: {
   // primary goal of these checks is to forbid address arithmetic
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << Recipe[r].name << ": 'add' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'add' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise << Recipe[r].name << ": 'add' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'add' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -75,22 +75,22 @@ Recipe_ordinal["subtract"] = SUBTRACT;
 :(before "End Primitive Recipe Checks")
 case SUBTRACT: {
   if (inst.ingredients.empty()) {
-    raise << Recipe[r].name << ": 'subtract' has no ingredients\n" << end();
+    raise << maybe(Recipe[r].name) << "'subtract' has no ingredients\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (is_raw(inst.ingredients.at(i))) continue;  // permit address offset computations in tests
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'subtract' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'subtract' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << Recipe[r].name << ": 'subtract' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'subtract' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise << Recipe[r].name << ": 'subtract' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'subtract' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -133,16 +133,16 @@ Recipe_ordinal["multiply"] = MULTIPLY;
 case MULTIPLY: {
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << Recipe[r].name << ": 'multiply' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'multiply' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise << Recipe[r].name << ": 'multiply' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'multiply' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -185,21 +185,21 @@ Recipe_ordinal["divide"] = DIVIDE;
 :(before "End Primitive Recipe Checks")
 case DIVIDE: {
   if (inst.ingredients.empty()) {
-    raise << Recipe[r].name << ": 'divide' has no ingredients\n" << end();
+    raise << maybe(Recipe[r].name) << "'divide' has no ingredients\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'divide' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'divide' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << Recipe[r].name << ": 'divide' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'divide' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise << Recipe[r].name << ": 'divide' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'divide' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -243,20 +243,20 @@ Recipe_ordinal["divide-with-remainder"] = DIVIDE_WITH_REMAINDER;
 :(before "End Primitive Recipe Checks")
 case DIVIDE_WITH_REMAINDER: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << current_recipe_name() << ": 'divide-with-remainder' requires exactly two ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'divide-with-remainder' requires exactly two ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise << current_recipe_name() << ": 'divide-with-remainder' requires number ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'divide-with-remainder' requires number ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 2) {
-    raise << Recipe[r].name << ": 'divide-with-remainder' yields two products in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'divide-with-remainder' yields two products in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.products); ++i) {
     if (!is_dummy(inst.products.at(i)) && !is_mu_number(inst.products.at(i))) {
-      raise << Recipe[r].name << ": 'divide-with-remainder' should yield a number, but got " << inst.products.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'divide-with-remainder' should yield a number, but got " << inst.products.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -268,7 +268,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 << current_recipe_name() << ": divide by zero in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "divide by zero in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   long long int quotient = a / b;
diff --git a/023boolean.cc b/023boolean.cc
index e556f47c..24752e72 100644
--- a/023boolean.cc
+++ b/023boolean.cc
@@ -8,7 +8,7 @@ Recipe_ordinal["and"] = AND;
 case AND: {
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_scalar(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -58,7 +58,7 @@ Recipe_ordinal["or"] = OR;
 case OR: {
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_scalar(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -107,12 +107,12 @@ Recipe_ordinal["not"] = NOT;
 :(before "End Primitive Recipe Checks")
 case NOT: {
   if (SIZE(inst.products) > SIZE(inst.ingredients)) {
-    raise << Recipe[r].name << ": 'not' cannot have fewer ingredients than products in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'not' cannot have fewer ingredients than products in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_scalar(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'not' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'not' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
diff --git a/024jump.cc b/024jump.cc
index dabe33bb..b249535e 100644
--- a/024jump.cc
+++ b/024jump.cc
@@ -16,11 +16,11 @@ Recipe_ordinal["jump"] = JUMP;
 :(before "End Primitive Recipe Checks")
 case JUMP: {
   if (SIZE(inst.ingredients) != 1) {
-    raise << Recipe[r].name << ": 'jump' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise << Recipe[r].name << ": first ingredient of 'jump' should be a label or offset, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "first ingredient of 'jump' should be a label or offset, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -55,15 +55,15 @@ Recipe_ordinal["jump-if"] = JUMP_IF;
 :(before "End Primitive Recipe Checks")
 case JUMP_IF: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << Recipe[r].name << ": 'jump-if' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-if' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise << Recipe[r].name << ": 'jump-if' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-if' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(1))) {
-    raise << Recipe[r].name << ": 'jump-if' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-if' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -107,15 +107,15 @@ Recipe_ordinal["jump-unless"] = JUMP_UNLESS;
 :(before "End Primitive Recipe Checks")
 case JUMP_UNLESS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << Recipe[r].name << ": 'jump-unless' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-unless' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise << Recipe[r].name << ": 'jump-unless' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-unless' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(1))) {
-    raise << Recipe[r].name << ": 'jump-unless' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-unless' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
diff --git a/025compare.cc b/025compare.cc
index 745111d8..74f1e4f1 100644
--- a/025compare.cc
+++ b/025compare.cc
@@ -7,7 +7,7 @@ Recipe_ordinal["equal"] = EQUAL;
 :(before "End Primitive Recipe Checks")
 case EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << Recipe[r].name << ": 'equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   break;
@@ -66,12 +66,12 @@ Recipe_ordinal["greater-than"] = GREATER_THAN;
 :(before "End Primitive Recipe Checks")
 case GREATER_THAN: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << Recipe[r].name << ": 'greater-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'greater-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'greater-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'greater-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -125,12 +125,12 @@ Recipe_ordinal["lesser-than"] = LESSER_THAN;
 :(before "End Primitive Recipe Checks")
 case LESSER_THAN: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << Recipe[r].name << ": 'lesser-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'lesser-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'lesser-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'lesser-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -184,12 +184,12 @@ Recipe_ordinal["greater-or-equal"] = GREATER_OR_EQUAL;
 :(before "End Primitive Recipe Checks")
 case GREATER_OR_EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << Recipe[r].name << ": 'greater-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'greater-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'greater-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'greater-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -251,12 +251,12 @@ Recipe_ordinal["lesser-or-equal"] = LESSER_OR_EQUAL;
 :(before "End Primitive Recipe Checks")
 case LESSER_OR_EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << Recipe[r].name << ": 'lesser-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'lesser-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'lesser-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'lesser-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
diff --git a/029tools.cc b/029tools.cc
index e09b9d7a..1cf10474 100644
--- a/029tools.cc
+++ b/029tools.cc
@@ -13,15 +13,15 @@ Recipe_ordinal["trace"] = TRACE;
 :(before "End Primitive Recipe Checks")
 case TRACE: {
   if (SIZE(inst.ingredients) < 3) {
-    raise << Recipe[r].name << ": 'trace' takes three or more ingredients rather than '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'trace' takes three or more ingredients rather than '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise << Recipe[r].name << ": first ingredient of 'trace' should be a number (depth), but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "first ingredient of 'trace' should be a number (depth), but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_literal_string(inst.ingredients.at(1))) {
-    raise << Recipe[r].name << ": second ingredient of 'trace' should be a literal string (label), but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "second ingredient of 'trace' should be a literal string (label), but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   break;
@@ -182,15 +182,15 @@ Recipe_ordinal["assert"] = ASSERT;
 :(before "End Primitive Recipe Checks")
 case ASSERT: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << Recipe[r].name << ": 'assert' takes exactly two ingredients rather than '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'assert' takes exactly two ingredients rather than '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise << Recipe[r].name << ": 'assert' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'assert' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_literal_string(inst.ingredients.at(1))) {
-    raise << Recipe[r].name << ": 'assert' requires a literal string for its second ingredient, but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'assert' requires a literal string for its second ingredient, but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   break;
@@ -247,7 +247,7 @@ Recipe_ordinal["$system"] = _SYSTEM;
 :(before "End Primitive Recipe Checks")
 case _SYSTEM: {
   if (inst.ingredients.empty()) {
-    raise << Recipe[r].name << ": '$system' requires exactly one ingredient, but got none\n" << end();
+    raise << maybe(Recipe[r].name) << "'$system' requires exactly one ingredient, but got none\n" << end();
     break;
   }
   break;
diff --git a/030container.cc b/030container.cc
index 19d3a5af..142688eb 100644
--- a/030container.cc
+++ b/030container.cc
@@ -125,13 +125,13 @@ Recipe_ordinal["get"] = GET;
 :(before "End Primitive Recipe Implementations")
 case GET: {
   if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'get' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'get' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = current_instruction().ingredients.at(0);
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (base.types.empty() || Type[base.types.at(0)].kind != container) {
@@ -140,7 +140,7 @@ case GET: {
   }
   type_ordinal base_type = base.types.at(0);
   if (!is_literal(current_instruction().ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'get' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'get' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   assert(scalar(ingredients.at(1)));
@@ -151,7 +151,7 @@ case GET: {
   }
   trace(Primitive_recipe_depth, "run") << "address to copy is " << src << end();
   if (offset < 0 || offset >= SIZE(Type[base_type].elements)) {
-    raise << current_recipe_name() << ": invalid offset " << offset << " for " << Type[base_type].name << '\n' << end();
+    raise << maybe(current_recipe_name()) << "invalid offset " << offset << " for " << Type[base_type].name << '\n' << end();
     break;
   }
   type_ordinal src_type = Type[base_type].elements.at(offset).at(0);
@@ -211,7 +211,7 @@ case GET_ADDRESS: {
   reagent base = current_instruction().ingredients.at(0);
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (base.types.empty() || Type[base.types.at(0)].kind != container) {
@@ -220,7 +220,7 @@ case GET_ADDRESS: {
   }
   type_ordinal base_type = base.types.at(0);
   if (!is_literal(current_instruction().ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'get-address' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'get-address' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   assert(scalar(ingredients.at(1)));
diff --git a/031address.cc b/031address.cc
index 5514b8c2..c074fe76 100644
--- a/031address.cc
+++ b/031address.cc
@@ -52,12 +52,12 @@ reagent lookup_memory(reagent x) {
   static const type_ordinal ADDRESS = Type_ordinal["address"];
   reagent result;
   if (x.types.empty() || x.types.at(0) != ADDRESS) {
-    raise << current_recipe_name() << ": tried to /lookup " << x.original_string << " but it isn't an address\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to /lookup " << x.original_string << " but it isn't an address\n" << end();
     return result;
   }
   // compute value
   if (x.value == 0) {
-    raise << current_recipe_name() << ": tried to /lookup 0\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to /lookup 0\n" << end();
     return result;
   }
   result.set_value(Memory[x.value]);
@@ -184,7 +184,7 @@ Recipe_ordinal["$dump"] = _DUMP;
 :(before "End Primitive Recipe Implementations")
 case _DUMP: {
   reagent after_canonize = canonize(current_instruction().ingredients.at(0));
-  cerr << current_recipe_name() << ": " << current_instruction().ingredients.at(0).name << ' ' << no_scientific(current_instruction().ingredients.at(0).value) << " => " << no_scientific(after_canonize.value) << " => " << no_scientific(Memory[after_canonize.value]) << '\n';
+  cerr << maybe(current_recipe_name()) << "" << current_instruction().ingredients.at(0).name << ' ' << no_scientific(current_instruction().ingredients.at(0).value) << " => " << no_scientific(after_canonize.value) << " => " << no_scientific(Memory[after_canonize.value]) << '\n';
   break;
 }
 
diff --git a/032array.cc b/032array.cc
index 31f4832e..5ed97e7f 100644
--- a/032array.cc
+++ b/032array.cc
@@ -102,7 +102,7 @@ if (x.types.at(0) == Type_ordinal["array"]) return false;
 :(before "End size_of(reagent) Cases")
 if (r.types.at(0) == Type_ordinal["array"]) {
   if (SIZE(r.types) == 1) {
-    raise << current_recipe_name() << ": '" << r.original_string << "' is an array of what?\n" << end();
+    raise << maybe(current_recipe_name()) << "'" << r.original_string << "' is an array of what?\n" << end();
     return 1;
   }
   // skip the 'array' type to get at the element type
@@ -139,7 +139,7 @@ Recipe_ordinal["index"] = INDEX;
 :(before "End Primitive Recipe Implementations")
 case INDEX: {
   if (SIZE(current_instruction().ingredients) != 2) {
-    raise << current_recipe_name() << ": 'index' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'index' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = canonize(current_instruction().ingredients.at(0));
@@ -149,14 +149,14 @@ case INDEX: {
   }
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent offset = canonize(current_instruction().ingredients.at(1));
   vector<double> offset_val(read_memory(offset));
   vector<type_ordinal> element_type = array_element(base.types);
   if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
-    raise << current_recipe_name() << ": invalid index " << no_scientific(offset_val.at(0)) << '\n' << end();
+    raise << maybe(current_recipe_name()) << "invalid index " << no_scientific(offset_val.at(0)) << '\n' << end();
     break;
   }
   long long int src = base_address + 1 + offset_val.at(0)*size_of(element_type);
@@ -234,7 +234,7 @@ Recipe_ordinal["index-address"] = INDEX_ADDRESS;
 :(before "End Primitive Recipe Implementations")
 case INDEX_ADDRESS: {
   if (SIZE(current_instruction().ingredients) != 2) {
-    raise << current_recipe_name() << ": 'index-address' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'index-address' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = canonize(current_instruction().ingredients.at(0));
@@ -244,14 +244,14 @@ case INDEX_ADDRESS: {
   }
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent offset = canonize(current_instruction().ingredients.at(1));
   vector<double> offset_val(read_memory(offset));
   vector<type_ordinal> element_type = array_element(base.types);
   if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
-    raise << current_recipe_name() << ": invalid index " << no_scientific(offset_val.at(0)) << '\n' << end();
+    raise << maybe(current_recipe_name()) << "invalid index " << no_scientific(offset_val.at(0)) << '\n' << end();
     break;
   }
   long long int result = base_address + 1 + offset_val.at(0)*size_of(element_type);
@@ -309,7 +309,7 @@ Recipe_ordinal["length"] = LENGTH;
 :(before "End Primitive Recipe Implementations")
 case LENGTH: {
   if (SIZE(current_instruction().ingredients) != 1) {
-    raise << current_recipe_name() << ": 'length' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'length' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent x = canonize(current_instruction().ingredients.at(0));
@@ -318,7 +318,7 @@ case LENGTH: {
     break;
   }
   if (x.value == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   products.resize(1);
diff --git a/033exclusive_container.cc b/033exclusive_container.cc
index 58276b9a..ae4a7e4c 100644
--- a/033exclusive_container.cc
+++ b/033exclusive_container.cc
@@ -84,13 +84,13 @@ Recipe_ordinal["maybe-convert"] = MAYBE_CONVERT;
 :(before "End Primitive Recipe Implementations")
 case MAYBE_CONVERT: {
   if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'maybe-convert' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'maybe-convert' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = canonize(current_instruction().ingredients.at(0));
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (base.types.empty() || Type[base.types.at(0)].kind != exclusive_container) {
@@ -98,7 +98,7 @@ case MAYBE_CONVERT: {
     break;
   }
   if (!is_literal(current_instruction().ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'maybe-convert' should have type 'variant', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'maybe-convert' should have type 'variant', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   long long int tag = current_instruction().ingredients.at(1).value;
diff --git a/034call.cc b/034call.cc
index 4bf7140a..f1c82f7f 100644
--- a/034call.cc
+++ b/034call.cc
@@ -81,7 +81,7 @@ inline const instruction& current_instruction() {
 default: {
   // not a primitive; try to look up the book of recipes
   if (Recipe.find(current_instruction().operation) == Recipe.end()) {
-    raise << current_recipe_name() << ": undefined operation in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "undefined operation in '" << current_instruction().to_string() << "'\n" << end();
     // stop running this instruction immediately
     ++current_step_index();
     continue;
diff --git a/035call_ingredient.cc b/035call_ingredient.cc
index 8daca0cf..3cfc44ce 100644
--- a/035call_ingredient.cc
+++ b/035call_ingredient.cc
@@ -38,7 +38,7 @@ Recipe_ordinal["next-ingredient"] = NEXT_INGREDIENT;
 :(before "End Primitive Recipe Implementations")
 case NEXT_INGREDIENT: {
   if (!ingredients.empty()) {
-    raise << current_recipe_name() << ": 'next-ingredient' didn't expect any ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'next-ingredient' didn't expect any ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   assert(!Current_routine->calls.empty());
@@ -51,7 +51,7 @@ case NEXT_INGREDIENT: {
   }
   else {
     if (SIZE(current_instruction().products) < 2)
-      raise << current_recipe_name() << ": no ingredient to save in " << current_instruction().products.at(0).original_string << '\n' << end();
+      raise << maybe(current_recipe_name()) << "no ingredient to save in " << current_instruction().products.at(0).original_string << '\n' << end();
     products.resize(2);
     products.at(0).push_back(0);  // todo: will fail noisily if we try to read a compound value
     products.at(1).push_back(0);
@@ -112,11 +112,11 @@ Recipe_ordinal["ingredient"] = INGREDIENT;
 :(before "End Primitive Recipe Implementations")
 case INGREDIENT: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'ingredient' expects exactly one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'ingredient' expects exactly one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (!is_literal(current_instruction().ingredients.at(0))) {
-    raise << current_recipe_name() << ": 'ingredient' expects a literal ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'ingredient' expects a literal ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   assert(scalar(ingredients.at(0)));
diff --git a/036call_reply.cc b/036call_reply.cc
index 2cb4922e..cc146835 100644
--- a/036call_reply.cc
+++ b/036call_reply.cc
@@ -37,14 +37,14 @@ case REPLY: {
     if (has_property(reply_inst.ingredients.at(i), "same-as-ingredient")) {
       vector<string> tmp = property(reply_inst.ingredients.at(i), "same-as-ingredient");
       if (SIZE(tmp) != 1) {
-        raise << current_recipe_name() << ": 'same-as-ingredient' metadata should take exactly one value in " << reply_inst.to_string() << '\n' << end();
+        raise << maybe(current_recipe_name()) << "'same-as-ingredient' metadata should take exactly one value in " << reply_inst.to_string() << '\n' << end();
         goto finish_reply;
       }
       long long int ingredient_index = to_integer(tmp.at(0));
       if (ingredient_index >= SIZE(caller_instruction.ingredients))
-        raise << current_recipe_name() << ": 'same-as-ingredient' metadata overflows ingredients in: " << caller_instruction.to_string() << '\n' << end();
+        raise << maybe(current_recipe_name()) << "'same-as-ingredient' metadata overflows ingredients in: " << caller_instruction.to_string() << '\n' << end();
       if (!is_dummy(caller_instruction.products.at(i)) && caller_instruction.products.at(i).value != caller_instruction.ingredients.at(ingredient_index).value)
-        raise << current_recipe_name() << ": 'same-as-ingredient' product from call to " << callee << " must be " << caller_instruction.ingredients.at(ingredient_index).original_string << " rather than " << caller_instruction.products.at(i).original_string << '\n' << end();
+        raise << maybe(current_recipe_name()) << "'same-as-ingredient' product from call to " << callee << " must be " << caller_instruction.ingredients.at(ingredient_index).original_string << " rather than " << caller_instruction.products.at(i).original_string << '\n' << end();
     }
   }
   // End Reply
diff --git a/037recipe.cc b/037recipe.cc
index 7ec0191b..bbc197c8 100644
--- a/037recipe.cc
+++ b/037recipe.cc
@@ -43,12 +43,12 @@ Recipe_ordinal["call"] = CALL;
 :(before "End Primitive Recipe Implementations")
 case CALL: {
   if (ingredients.empty()) {
-    raise << current_recipe_name() << ": 'call' requires at least one ingredient (the recipe to call)\n" << end();
+    raise << maybe(current_recipe_name()) << "'call' requires at least one ingredient (the recipe to call)\n" << end();
     break;
   }
   // Begin Call
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'call' should be a recipe, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'call' should be a recipe, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   // todo: when we start doing type checking this will be a prime point of
diff --git a/038scheduler.cc b/038scheduler.cc
index 2e0e0322..2ae1b3b3 100644
--- a/038scheduler.cc
+++ b/038scheduler.cc
@@ -333,11 +333,11 @@ Recipe_ordinal["routine-state"] = ROUTINE_STATE;
 :(before "End Primitive Recipe Implementations")
 case ROUTINE_STATE: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'routine-state' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'routine-state' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'routine-state' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'routine-state' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int id = ingredients.at(0).at(0);
@@ -362,11 +362,11 @@ Recipe_ordinal["restart"] = RESTART;
 :(before "End Primitive Recipe Implementations")
 case RESTART: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'restart' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'restart' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'restart' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'restart' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int id = ingredients.at(0).at(0);
@@ -386,11 +386,11 @@ Recipe_ordinal["stop"] = STOP;
 :(before "End Primitive Recipe Implementations")
 case STOP: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'stop' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'stop' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'stop' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'stop' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int id = ingredients.at(0).at(0);
@@ -460,15 +460,15 @@ Recipe_ordinal["limit-time"] = LIMIT_TIME;
 :(before "End Primitive Recipe Implementations")
 case LIMIT_TIME: {
   if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'limit-time' requires exactly two ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'limit-time' requires exactly two ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'limit-time' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'limit-time' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'limit-time' should be a number (of instructions to run for), but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'limit-time' should be a number (of instructions to run for), but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   long long int id = ingredients.at(0).at(0);
diff --git a/039wait.cc b/039wait.cc
index 9a76e309..955ab4a8 100644
--- a/039wait.cc
+++ b/039wait.cc
@@ -91,15 +91,15 @@ Recipe_ordinal["wait-for-routine"] = WAIT_FOR_ROUTINE;
 :(before "End Primitive Recipe Implementations")
 case WAIT_FOR_ROUTINE: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'wait-for-routine' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'wait-for-routine' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (ingredients.at(0).at(0) == Current_routine->id) {
-    raise << current_recipe_name() << ": routine can't wait for itself! " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "routine can't wait for itself! " << current_instruction().to_string() << '\n' << end();
     break;
   }
   Current_routine->state = WAITING;
diff --git a/040brace.cc b/040brace.cc
index a26364e1..d5e89a6c 100644
--- a/040brace.cc
+++ b/040brace.cc
@@ -43,7 +43,7 @@ void transform_braces(const recipe_ordinal r) {
   for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) {
     const instruction& inst = Recipe[r].steps.at(index);
     if (inst.label == "{") {
-      trace("brace") << Recipe[r].name << ": push (open, " << index << ")" << end();
+      trace("brace") << maybe(Recipe[r].name) << "push (open, " << index << ")" << end();
       braces.push_back(pair<int,long long int>(OPEN, index));
     }
     if (inst.label == "}") {
@@ -132,7 +132,7 @@ long long int matching_brace(long long int index, const list<pair<int, long long
     stacksize += (p->first ? 1 : -1);
     if (stacksize == 0) return p->second;
   }
-  raise << Recipe[r].name << ": unbalanced '{'\n" << end();
+  raise << maybe(Recipe[r].name) << "unbalanced '{'\n" << end();
   return SIZE(Recipe[r].steps);  // exit current routine
 }
 
diff --git a/041jump_target.cc b/041jump_target.cc
index aaa01355..fad1e3c7 100644
--- a/041jump_target.cc
+++ b/041jump_target.cc
@@ -31,7 +31,7 @@ void transform_labels(const recipe_ordinal r) {
         offset[inst.label] = i;
       }
       else {
-        raise << Recipe[r].name << ": duplicate label '" << inst.label << "'" << end();
+        raise << maybe(Recipe[r].name) << "duplicate label '" << inst.label << "'" << end();
         // have all jumps skip some random but noticeable and deterministic amount of code
         offset[inst.label] = 9999;
       }
@@ -60,19 +60,19 @@ void transform_labels(const recipe_ordinal r) {
 :(code)
 void replace_offset(reagent& x, /*const*/ map<string, long long int>& offset, const long long int current_offset, const recipe_ordinal r) {
   if (!is_literal(x)) {
-    raise << Recipe[r].name << ": jump target must be offset or label but is " << x.original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "jump target must be offset or label but is " << x.original_string << '\n' << end();
     x.set_value(0);  // no jump by default
     return;
   }
   assert(!x.initialized);
   if (is_integer(x.name)) return;  // non-labels will be handled like other number operands
   if (!is_jump_target(x.name)) {
-    raise << Recipe[r].name << ": can't jump to label " << x.name << '\n' << end();
+    raise << maybe(Recipe[r].name) << "can't jump to label " << x.name << '\n' << end();
     x.set_value(0);  // no jump by default
     return;
   }
   if (offset.find(x.name) == offset.end()) {
-    raise << Recipe[r].name << ": can't find label " << x.name << '\n' << end();
+    raise << maybe(Recipe[r].name) << "can't find label " << x.name << '\n' << end();
     x.set_value(0);  // no jump by default
     return;
   }
diff --git a/042name.cc b/042name.cc
index 060f59e1..fbc83abd 100644
--- a/042name.cc
+++ b/042name.cc
@@ -15,7 +15,7 @@ recipe main [
 recipe main [
   x:number <- copy y:number
 ]
-+warn: use before set: y in main
++warn: main: use before set: y
 
 :(after "int main")
   Transform.push_back(transform_names);
@@ -42,16 +42,16 @@ void transform_names(const recipe_ordinal r) {
     for (long long int in = 0; in < SIZE(inst.ingredients); ++in) {
       if (is_numeric_location(inst.ingredients.at(in))) numeric_locations_used = true;
       if (is_named_location(inst.ingredients.at(in))) names_used = true;
-      if (disqualified(inst.ingredients.at(in), inst)) continue;
+      if (disqualified(inst.ingredients.at(in), inst, Recipe[r].name)) continue;
       if (!already_transformed(inst.ingredients.at(in), names)) {
-        raise << "use before set: " << inst.ingredients.at(in).name << " in " << Recipe[r].name << '\n' << end();
+        raise << maybe(Recipe[r].name) << "use before set: " << inst.ingredients.at(in).name << '\n' << end();
       }
       inst.ingredients.at(in).set_value(lookup_name(inst.ingredients.at(in), r));
     }
     for (long long int out = 0; out < SIZE(inst.products); ++out) {
       if (is_numeric_location(inst.products.at(out))) numeric_locations_used = true;
       if (is_named_location(inst.products.at(out))) names_used = true;
-      if (disqualified(inst.products.at(out), inst)) continue;
+      if (disqualified(inst.products.at(out), inst, Recipe[r].name)) continue;
       if (names.find(inst.products.at(out).name) == names.end()) {
         trace("name") << "assign " << inst.products.at(out).name << " " << curr_idx << end();
         names[inst.products.at(out).name] = curr_idx;
@@ -61,12 +61,12 @@ void transform_names(const recipe_ordinal r) {
     }
   }
   if (names_used && numeric_locations_used)
-    raise << "mixing variable names and numeric addresses in " << Recipe[r].name << '\n' << end();
+    raise << maybe(Recipe[r].name) << "mixing variable names and numeric addresses\n" << end();
 }
 
-bool disqualified(/*mutable*/ reagent& x, const instruction& inst) {
+bool disqualified(/*mutable*/ reagent& x, const instruction& inst, const string& recipe_name) {
   if (x.types.empty()) {
-    raise << "missing type for " << x.original_string << " in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(recipe_name) << "missing type for " << x.original_string << " in '" << inst.to_string() << "'\n" << end();
     return true;
   }
   if (is_raw(x)) return true;
@@ -85,20 +85,20 @@ long long int lookup_name(const reagent& r, const recipe_ordinal default_recipe)
   return Name[default_recipe][r.name];
 }
 
-type_ordinal skip_addresses(const vector<type_ordinal>& types) {
+type_ordinal skip_addresses(const vector<type_ordinal>& types, const string& recipe_name) {
   for (long long int i = 0; i < SIZE(types); ++i) {
     if (types.at(i) != Type_ordinal["address"]) return types.at(i);
   }
-  raise << "expected a container" << '\n' << end();
+  raise << maybe(recipe_name) << "expected a container" << '\n' << end();
   return -1;
 }
 
-int find_element_name(const type_ordinal t, const string& name) {
+int find_element_name(const type_ordinal t, const string& name, const string& recipe_name) {
   const type_info& container = Type[t];
   for (long long int i = 0; i < SIZE(container.element_names); ++i) {
     if (container.element_names.at(i) == name) return i;
   }
-  raise << "unknown element " << name << " in container " << Type[t].name << '\n' << end();
+  raise << maybe(recipe_name) << "unknown element " << name << " in container " << Type[t].name << '\n' << end();
   return -1;
 }
 
@@ -147,7 +147,7 @@ recipe main [
 recipe main [
   x:number <- copy 1:number
 ]
-+warn: mixing variable names and numeric addresses in main
++warn: main: mixing variable names and numeric addresses
 
 :(scenario transform_names_warns_when_mixing_names_and_numeric_locations_2)
 % Hide_warnings = true;
@@ -155,14 +155,14 @@ recipe main [
   x:number <- copy 1
   1:number <- copy x:number
 ]
-+warn: mixing variable names and numeric addresses in main
++warn: main: mixing variable names and numeric addresses
 
 :(scenario transform_names_does_not_warn_when_mixing_names_and_raw_locations)
 % Hide_warnings = true;
 recipe main [
   x:number <- copy 1:number/raw
 ]
--warn: mixing variable names and numeric addresses in main
+-warn: main: mixing variable names and numeric addresses
 $warn: 0
 
 :(scenario transform_names_does_not_warn_when_mixing_names_and_literals)
@@ -170,7 +170,7 @@ $warn: 0
 recipe main [
   x:number <- copy 1
 ]
--warn: mixing variable names and numeric addresses in main
+-warn: main: mixing variable names and numeric addresses
 $warn: 0
 
 //:: Support element names for containers in 'get' and 'get-address'.
@@ -193,15 +193,15 @@ recipe main [
 if (inst.operation == Recipe_ordinal["get"]
     || inst.operation == Recipe_ordinal["get-address"]) {
   if (SIZE(inst.ingredients) != 2) {
-    raise << Recipe[r].name << ": exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_literal(inst.ingredients.at(1)))
-    raise << Recipe[r].name << ": expected ingredient 1 of " << (inst.operation == Recipe_ordinal["get"] ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "expected ingredient 1 of " << (inst.operation == Recipe_ordinal["get"] ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end();
   if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
     // since first non-address in base type must be a container, we don't have to canonize
-    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).types);
-    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name));
+    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).types, Recipe[r].name);
+    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, Recipe[r].name));
     trace("name") << "element " << inst.ingredients.at(1).name << " of type " << Type[base_type].name << " is at offset " << no_scientific(inst.ingredients.at(1).value) << end();
   }
 }
@@ -233,14 +233,14 @@ recipe main [
 // convert variant names of exclusive containers
 if (inst.operation == Recipe_ordinal["maybe-convert"]) {
   if (SIZE(inst.ingredients) != 2) {
-    raise << Recipe[r].name << ": exactly 2 ingredients expected in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "exactly 2 ingredients expected in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   assert(is_literal(inst.ingredients.at(1)));
   if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
     // since first non-address in base type must be an exclusive container, we don't have to canonize
-    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).types);
-    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name));
+    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).types, Recipe[r].name);
+    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, Recipe[r].name));
     trace("name") << "variant " << inst.ingredients.at(1).name << " of type " << Type[base_type].name << " has tag " << no_scientific(inst.ingredients.at(1).value) << end();
   }
 }
diff --git a/043new.cc b/043new.cc
index a99296f2..d6761dad 100644
--- a/043new.cc
+++ b/043new.cc
@@ -34,13 +34,13 @@ if (inst.operation == Recipe_ordinal["new"]) {
   // End NEW Transform Special-cases
   // first arg must be of type 'type'
   if (inst.ingredients.empty())
-    raise << Recipe[r].name << ": 'new' expects one or two ingredients\n" << end();
+    raise << maybe(Recipe[r].name) << "'new' expects one or two ingredients\n" << end();
   if (inst.ingredients.at(0).properties.empty()
       || inst.ingredients.at(0).properties.at(0).second.empty()
       || inst.ingredients.at(0).properties.at(0).second.at(0) != "type")
-    raise << Recipe[r].name << ": first ingredient of 'new' should be a type, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "first ingredient of 'new' should be a type, but got " << inst.ingredients.at(0).original_string << '\n' << end();
   if (Type_ordinal.find(inst.ingredients.at(0).name) == Type_ordinal.end())
-    raise << Recipe[r].name << ": unknown type " << inst.ingredients.at(0).name << '\n' << end();
+    raise << maybe(Recipe[r].name) << "unknown type " << inst.ingredients.at(0).name << '\n' << end();
   inst.ingredients.at(0).set_value(Type_ordinal[inst.ingredients.at(0).name]);
   trace(Primitive_recipe_depth, "new") << inst.ingredients.at(0).name << " -> " << inst.ingredients.at(0).name << end();
   end_new_transform:;
@@ -56,11 +56,11 @@ Recipe_ordinal["new"] = NEW;
 :(before "End Primitive Recipe Implementations")
 case NEW: {
   if (ingredients.empty() || SIZE(ingredients) > 2) {
-    raise << current_recipe_name() << ": 'new' requires one or two ingredients, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'new' requires one or two ingredients, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'new' should be a type, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'new' should be a type, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   // compute the space we need
@@ -216,17 +216,17 @@ Recipe_ordinal["abandon"] = ABANDON;
 :(before "End Primitive Recipe Implementations")
 case ABANDON: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'abandon' requires one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'abandon' requires one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int address = ingredients.at(0).at(0);
   reagent types = canonize(current_instruction().ingredients.at(0));
   if (types.types.empty() || types.types.at(0) != Type_ordinal["address"]) {
-    raise << current_recipe_name() << ": first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   reagent target_type = lookup_memory(types);
@@ -253,7 +253,7 @@ if (Free_list[size]) {
   Free_list[size] = Memory[result];
   for (long long int curr = result+1; curr < result+size; ++curr) {
     if (Memory[curr] != 0) {
-      raise << current_recipe_name() << ": memory in free list was not zeroed out: " << curr << '/' << result << "; somebody wrote to us after free!!!\n" << end();
+      raise << maybe(current_recipe_name()) << "memory in free list was not zeroed out: " << curr << '/' << result << "; somebody wrote to us after free!!!\n" << end();
       break;  // always fatal
     }
   }
diff --git a/044space.cc b/044space.cc
index a9251364..59b292a5 100644
--- a/044space.cc
+++ b/044space.cc
@@ -138,7 +138,7 @@ if (curr.name == "new-default-space") {
   }
 :(after "void write_memory(reagent x, vector<double> data)")
   if (x.name == "number-of-locals") {
-    raise << current_recipe_name() << ": can't write to special name 'number-of-locals'\n" << end();
+    raise << maybe(current_recipe_name()) << "can't write to special name 'number-of-locals'\n" << end();
     return;
   }
 
@@ -212,7 +212,7 @@ long long int address(long long int offset, long long int base) {
 :(after "void write_memory(reagent x, vector<double> data)")
   if (x.name == "default-space") {
     if (!scalar(data))
-      raise << current_recipe_name() << ": 'default-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
+      raise << maybe(current_recipe_name()) << "'default-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
     Current_routine->calls.front().default_space = data.at(0);
     return;
   }
diff --git a/045space_surround.cc b/045space_surround.cc
index 68d23c93..94a717a0 100644
--- a/045space_surround.cc
+++ b/045space_surround.cc
@@ -42,7 +42,7 @@ long long int space_index(const reagent& x) {
   for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) {
     if (x.properties.at(i).first == "space") {
       if (SIZE(x.properties.at(i).second) != 1)
-        raise << current_recipe_name() << ": /space metadata should take exactly one value in " << x.original_string << '\n' << end();
+        raise << maybe(current_recipe_name()) << "/space metadata should take exactly one value in " << x.original_string << '\n' << end();
       return to_integer(x.properties.at(i).second.at(0));
     }
   }
diff --git a/047global.cc b/047global.cc
index 90646f49..00e8ff15 100644
--- a/047global.cc
+++ b/047global.cc
@@ -32,7 +32,7 @@ global_space = 0;
 :(after "void write_memory(reagent x, vector<double> data)")
   if (x.name == "global-space") {
     if (!scalar(data))
-      raise << current_recipe_name() << ": 'global-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
+      raise << maybe(current_recipe_name()) << "'global-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
     if (Current_routine->global_space)
       raise << "routine already has a global-space; you can't over-write your globals" << end();
     Current_routine->global_space = data.at(0);
diff --git a/048check_type_by_name.cc b/048check_type_by_name.cc
index e4b4f6d0..26920057 100644
--- a/048check_type_by_name.cc
+++ b/048check_type_by_name.cc
@@ -12,7 +12,7 @@ recipe main [
   x:number <- copy 1
   x:boolean <- copy 1
 ]
-+warn: x used with multiple types in main
++warn: main: x used with multiple types
 
 :(after "int main")
   Transform.push_back(check_types_by_name);
@@ -42,7 +42,7 @@ void check_metadata(map<string, vector<type_ordinal> >& metadata, const reagent&
   if (metadata.find(x.name) == metadata.end())
     metadata[x.name] = x.types;
   if (metadata[x.name] != x.types)
-    raise << x.name << " used with multiple types in " << Recipe[r].name << '\n' << end();
+    raise << maybe(Recipe[r].name) << "" << x.name << " used with multiple types\n" << end();
 }
 
 :(scenario transform_fills_in_missing_types)
@@ -80,7 +80,7 @@ recipe main [
   x <- copy 1
   x:number <- copy 2
 ]
-+warn: missing type for x in 'x <- copy 1'
++warn: main: missing type for x in 'x <- copy 1'
 
 :(scenario typo_in_address_type_warns)
 % Hide_warnings = true;
diff --git a/050scenario.cc b/050scenario.cc
index 5378ff5d..65e161b3 100644
--- a/050scenario.cc
+++ b/050scenario.cc
@@ -560,16 +560,16 @@ Recipe_ordinal["check-trace-count-for-label"] = CHECK_TRACE_COUNT_FOR_LABEL;
 case CHECK_TRACE_COUNT_FOR_LABEL: {
   if (!Passed) break;
   if (SIZE(current_instruction().ingredients) != 2) {
-    raise << current_recipe_name() << ": 'check-trace-for-label' requires exactly two ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'check-trace-for-label' requires exactly two ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'check-trace-for-label' should be a number (count), but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'check-trace-for-label' should be a number (count), but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int expected_count = ingredients.at(0).at(0);
   if (!is_literal_string(current_instruction().ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'check-trace-for-label' should be a literal string (label), but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'check-trace-for-label' should be a literal string (label), but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   string label = current_instruction().ingredients.at(1).name;
@@ -577,13 +577,13 @@ case CHECK_TRACE_COUNT_FOR_LABEL: {
   if (count != expected_count) {
     if (Current_scenario && !Scenario_testing_scenario) {
       // genuine test in a mu file
-      raise << "\nF - " << Current_scenario->name << ": " << current_recipe_name() << ": expected " << expected_count << " lines in trace with label " << label << " in trace: ";
+      raise << "\nF - " << Current_scenario->name << ": " << maybe(current_recipe_name()) << "expected " << expected_count << " lines in trace with label " << label << " in trace: ";
       DUMP(label);
       raise;
     }
     else {
       // just testing scenario support
-      raise << current_recipe_name() << ": expected " << expected_count << " lines in trace with label " << label << " in trace\n" << end();
+      raise << maybe(current_recipe_name()) << "expected " << expected_count << " lines in trace with label " << label << " in trace\n" << end();
     }
     if (!Scenario_testing_scenario) {
       Passed = false;
diff --git a/053continuation.cc b/053continuation.cc
index 769e09e8..42f32f6d 100644
--- a/053continuation.cc
+++ b/053continuation.cc
@@ -41,7 +41,7 @@ Recipe_ordinal["continue-from"] = CONTINUE_FROM;
 :(before "End Primitive Recipe Implementations")
 case CONTINUE_FROM: {
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'continue-from' should be a continuation id generated by 'current-continuation', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'continue-from' should be a continuation id generated by 'current-continuation', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int c = ingredients.at(0).at(0);
@@ -198,7 +198,7 @@ case REPLY_DELIMITED_CONTINUATION: {
   call_stack::iterator find_reset(call_stack& c);  // manual prototype containing '::'
   call_stack::iterator reset = find_reset(Current_routine->calls);
   if (reset == Current_routine->calls.end()) {
-    raise << current_recipe_name() << ": couldn't find a 'reset' call to jump out to\n" << end();
+    raise << maybe(current_recipe_name()) << "couldn't find a 'reset' call to jump out to\n" << end();
     break;
   }
   Delimited_continuation[Next_delimited_continuation_id] = call_stack(Current_routine->calls.begin(), reset);
@@ -228,7 +228,7 @@ call_stack::iterator find_reset(call_stack& c) {
     // copy multiple calls on to current call stack
     assert(scalar(ingredients.at(0)));
     if (Delimited_continuation.find(ingredients.at(0).at(0)) == Delimited_continuation.end()) {
-      raise << current_recipe_name() << ": no such delimited continuation " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+      raise << maybe(current_recipe_name()) << "no such delimited continuation " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     }
     const call_stack& new_calls = Delimited_continuation[ingredients.at(0).at(0)];
     for (call_stack::const_reverse_iterator p = new_calls.rbegin(); p != new_calls.rend(); ++p)
diff --git a/064random.cc b/064random.cc
index bd171132..07667cc2 100644
--- a/064random.cc
+++ b/064random.cc
@@ -28,11 +28,11 @@ Recipe_ordinal["round"] = ROUND;
 :(before "End Primitive Recipe Implementations")
 case ROUND: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'round' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'round' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'round' should be a number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'round' should be a number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   products.resize(1);
diff --git a/070display.cc b/070display.cc
index 8c02bc57..1f42e5ba 100644
--- a/070display.cc
+++ b/070display.cc
@@ -83,18 +83,18 @@ case PRINT_CHARACTER_TO_DISPLAY: {
   long long int height = (h >= 0) ? h : 0;
   long long int width = (w >= 0) ? w : 0;
   if (ingredients.empty()) {
-    raise << current_recipe_name() << ": 'print-character-to-display' requires at least one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'print-character-to-display' requires at least one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'print-character-to-display' should be a character, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'print-character-to-display' should be a character, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int c = ingredients.at(0).at(0);
   int color = TB_BLACK;
   if (SIZE(ingredients) > 1) {
     if (!scalar(ingredients.at(1))) {
-      raise << current_recipe_name() << ": second ingredient of 'print-character-to-display' should be a foreground color number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+      raise << maybe(current_recipe_name()) << "second ingredient of 'print-character-to-display' should be a foreground color number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
       break;
     }
     color = ingredients.at(1).at(0);
@@ -102,7 +102,7 @@ case PRINT_CHARACTER_TO_DISPLAY: {
   int bg_color = TB_BLACK;
   if (SIZE(ingredients) > 2) {
     if (!scalar(ingredients.at(2))) {
-      raise << current_recipe_name() << ": third ingredient of 'print-character-to-display' should be a background color number, but got " << current_instruction().ingredients.at(2).original_string << '\n' << end();
+      raise << maybe(current_recipe_name()) << "third ingredient of 'print-character-to-display' should be a background color number, but got " << current_instruction().ingredients.at(2).original_string << '\n' << end();
       break;
     }
     bg_color = ingredients.at(2).at(0);
@@ -154,16 +154,16 @@ Recipe_ordinal["move-cursor-on-display"] = MOVE_CURSOR_ON_DISPLAY;
 :(before "End Primitive Recipe Implementations")
 case MOVE_CURSOR_ON_DISPLAY: {
   if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'move-cursor-on-display' requires two ingredients, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'move-cursor-on-display' requires two ingredients, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'move-cursor-on-display' should be a row number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'move-cursor-on-display' should be a row number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   Display_row = ingredients.at(0).at(0);
   if (!scalar(ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'move-cursor-on-display' should be a column number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'move-cursor-on-display' should be a column number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   Display_column = ingredients.at(1).at(0);
diff --git a/072scenario_screen.cc b/072scenario_screen.cc
index 29ae4c5d..732a2999 100644
--- a/072scenario_screen.cc
+++ b/072scenario_screen.cc
@@ -191,13 +191,13 @@ struct raw_string_stream {
 void check_screen(const string& expected_contents, const int color) {
   assert(!Current_routine->calls.front().default_space);  // not supported
   long long int screen_location = Memory[SCREEN];
-  int data_offset = find_element_name(Type_ordinal["screen"], "data");
+  int data_offset = find_element_name(Type_ordinal["screen"], "data", "");
   assert(data_offset >= 0);
   long long int screen_data_location = screen_location+data_offset;  // type: address:array:character
   long long int screen_data_start = Memory[screen_data_location];  // type: array:character
-  int width_offset = find_element_name(Type_ordinal["screen"], "num-columns");
+  int width_offset = find_element_name(Type_ordinal["screen"], "num-columns", "");
   long long int screen_width = Memory[screen_location+width_offset];
-  int height_offset = find_element_name(Type_ordinal["screen"], "num-rows");
+  int height_offset = find_element_name(Type_ordinal["screen"], "num-rows", "");
   long long int screen_height = Memory[screen_location+height_offset];
   raw_string_stream cursor(expected_contents);
   // todo: too-long expected_contents should fail
@@ -245,14 +245,16 @@ void check_screen(const string& expected_contents, const int color) {
         actual_pretty[0] = ' ', actual_pretty[1] = '(', actual_pretty[2] = '\'', actual_pretty[3] = static_cast<unsigned char>(Memory[addr]), actual_pretty[4] = '\'', actual_pretty[5] = ')', actual_pretty[6] = '\0';
       }
 
+      ostringstream color_phrase;
+      if (color != -1) color_phrase << " in color " << color;
       if (Current_scenario && !Scenario_testing_scenario) {
         // genuine test in a mu file
-        raise << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << " instead of " << no_scientific(Memory[addr]) << actual_pretty << '\n' << end();
+        raise << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << color_phrase.str() << " instead of " << no_scientific(Memory[addr]) << actual_pretty << '\n' << end();
         dump_screen();
       }
       else {
         // just testing check_screen
-        raise << "expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << " instead of " << no_scientific(Memory[addr]) << actual_pretty << '\n' << end();
+        raise << "expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << color_phrase.str() << " instead of " << no_scientific(Memory[addr]) << actual_pretty << '\n' << end();
       }
       if (!Scenario_testing_scenario) {
         Passed = false;
@@ -320,11 +322,11 @@ case _DUMP_SCREEN: {
 void dump_screen() {
   assert(!Current_routine->calls.front().default_space);  // not supported
   long long int screen_location = Memory[SCREEN];
-  int width_offset = find_element_name(Type_ordinal["screen"], "num-columns");
+  int width_offset = find_element_name(Type_ordinal["screen"], "num-columns", "");
   long long int screen_width = Memory[screen_location+width_offset];
-  int height_offset = find_element_name(Type_ordinal["screen"], "num-rows");
+  int height_offset = find_element_name(Type_ordinal["screen"], "num-rows", "");
   long long int screen_height = Memory[screen_location+height_offset];
-  int data_offset = find_element_name(Type_ordinal["screen"], "data");
+  int data_offset = find_element_name(Type_ordinal["screen"], "data", "");
   assert(data_offset >= 0);
   long long int screen_data_location = screen_location+data_offset;  // type: address:array:character
   long long int screen_data_start = Memory[screen_data_location];  // type: array:character
diff --git a/081run_interactive.cc b/081run_interactive.cc
index dd3fc5c3..eccf2d07 100644
--- a/081run_interactive.cc
+++ b/081run_interactive.cc
@@ -29,11 +29,11 @@ Recipe_ordinal["run-interactive"] = RUN_INTERACTIVE;
 :(before "End Primitive Recipe Implementations")
 case RUN_INTERACTIVE: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'run-interactive' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'run-interactive' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'run-interactive' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'run-interactive' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
     break;
   }
   bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0));
@@ -140,6 +140,10 @@ load(string(
 transform_all();
 recently_added_recipes.clear();
 
+//: adjust warnings in the sandbox
+:(after "string maybe(string s)")
+  if (s == "interactive") return "";
+
 :(scenario run_interactive_comments)
 recipe main [
   1:address:array:character <- new [# ab
@@ -342,11 +346,11 @@ Recipe_ordinal["reload"] = RELOAD;
 :(before "End Primitive Recipe Implementations")
 case RELOAD: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'reload' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'reload' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'reload' should be a literal string, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'reload' should be a literal string, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   // clear any containers in advance
diff --git a/082persist.cc b/082persist.cc
index 853ccb62..40241eb2 100644
--- a/082persist.cc
+++ b/082persist.cc
@@ -9,7 +9,7 @@ Recipe_ordinal["restore"] = RESTORE;
 :(before "End Primitive Recipe Implementations")
 case RESTORE: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'restore' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'restore' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   string filename;
@@ -20,7 +20,7 @@ case RESTORE: {
     filename = read_mu_string(ingredients.at(0).at(0));
   }
   else {
-    raise << current_recipe_name() << ": first ingredient of 'restore' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'restore' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
     break;
   }
   if (Current_scenario) {
@@ -62,7 +62,7 @@ Recipe_ordinal["save"] = SAVE;
 :(before "End Primitive Recipe Implementations")
 case SAVE: {
   if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'save' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'save' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (Current_scenario) break;  // do nothing in tests
@@ -74,11 +74,11 @@ case SAVE: {
     filename = read_mu_string(ingredients.at(0).at(0));
   }
   else {
-    raise << current_recipe_name() << ": first ingredient of 'save' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'save' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'save' should be an address:array:character, but got " << current_instruction().ingredients.at(1).to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'save' should be an address:array:character, but got " << current_instruction().ingredients.at(1).to_string() << '\n' << end();
     break;
   }
   ofstream fout(("lesson/"+filename).c_str());
diff --git a/edit/010-warnings.mu b/edit/010-warnings.mu
index 6c93a95c..10f05325 100644
--- a/edit/010-warnings.mu
+++ b/edit/010-warnings.mu
@@ -96,7 +96,7 @@ recipe foo [
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .  get 123:number, foo:offset                      ┊                                                 .
     .]                                                 ┊                                                 .
-    .unknown element foo in container number           ┊                                                 .
+    .foo: unknown element foo in container number      ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -106,7 +106,7 @@ recipe foo [
     .                                                                                                    .
     .                                                                                                    .
     .                                                                                                    .
-    .unknown element foo in container number                                                             .
+    .foo: unknown element foo in container number                                                        .
     .                                                                                                    .
   ]
 ]
@@ -132,7 +132,7 @@ recipe foo [
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .  x <- copy 0                                     ┊                                                 .
     .]                                                 ┊                                                 .
-    .missing type for x in 'x <- copy 0'               ┊                                                 .
+    .foo: missing type for x in 'x <- copy 0'          ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -250,7 +250,7 @@ recipe foo [
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .  x:number <- copy y:number                       ┊                                                 .
     .]                                                 ┊                                                 .
-    .use before set: y in foo                          ┊                                                 .
+    .foo: use before set: y                            ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -267,7 +267,7 @@ recipe foo [
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .  x:number <- copy y:number                       ┊                                                 .
     .]                                                 ┊                                                 .
-    .use before set: y in foo                          ┊                                                 .
+    .foo: use before set: y                            ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]