about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--029tools.cc44
-rw-r--r--035call_ingredient.cc29
-rw-r--r--036call_reply.cc4
-rw-r--r--037recipe.cc19
-rw-r--r--038scheduler.cc82
-rw-r--r--039wait.cc22
-rw-r--r--043new.cc47
-rw-r--r--050scenario.cc38
-rw-r--r--053continuation.cc22
-rw-r--r--064random.cc22
-rw-r--r--070display.cc104
-rw-r--r--072scenario_screen.cc12
-rw-r--r--075scenario_console.cc10
-rw-r--r--080trace_browser.cc4
-rw-r--r--081run_interactive.cc48
-rw-r--r--082persist.cc57
16 files changed, 435 insertions, 129 deletions
diff --git a/029tools.cc b/029tools.cc
index 1cf10474..92c29963 100644
--- a/029tools.cc
+++ b/029tools.cc
@@ -44,6 +44,10 @@ case TRACE: {
 STASH,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["stash"] = STASH;
+:(before "End Primitive Recipe Checks")
+case STASH: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case STASH: {
   ostringstream out;
@@ -89,6 +93,10 @@ string print_mu(const reagent& r, const vector<double>& data) {
 HIDE_WARNINGS,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["hide-warnings"] = HIDE_WARNINGS;
+:(before "End Primitive Recipe Checks")
+case HIDE_WARNINGS: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case HIDE_WARNINGS: {
   Hide_warnings = true;
@@ -99,6 +107,10 @@ case HIDE_WARNINGS: {
 SHOW_WARNINGS,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["show-warnings"] = SHOW_WARNINGS;
+:(before "End Primitive Recipe Checks")
+case SHOW_WARNINGS: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case SHOW_WARNINGS: {
   Hide_warnings = false;
@@ -109,6 +121,10 @@ case SHOW_WARNINGS: {
 _START_TRACING,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$start-tracing"] = _START_TRACING;
+:(before "End Primitive Recipe Checks")
+case _START_TRACING: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _START_TRACING: {
   if (current_instruction().ingredients.empty())
@@ -122,6 +138,10 @@ case _START_TRACING: {
 _STOP_TRACING,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$stop-tracing"] = _STOP_TRACING;
+:(before "End Primitive Recipe Checks")
+case _STOP_TRACING: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _STOP_TRACING: {
   Trace_stream->dump_layer = "";
@@ -132,6 +152,10 @@ case _STOP_TRACING: {
 _CLOSE_TRACE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$close-trace"] = _CLOSE_TRACE;
+:(before "End Primitive Recipe Checks")
+case _CLOSE_TRACE: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _CLOSE_TRACE: {
   if (Trace_stream) {
@@ -145,6 +169,10 @@ case _CLOSE_TRACE: {
 _DUMP_TRACE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$dump-trace"] = _DUMP_TRACE;
+:(before "End Primitive Recipe Checks")
+case _DUMP_TRACE: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _DUMP_TRACE: {
   if (ingredients.empty()) {
@@ -160,6 +188,10 @@ case _DUMP_TRACE: {
 _CLEAR_TRACE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$clear-trace"] = _CLEAR_TRACE;
+:(before "End Primitive Recipe Checks")
+case _CLEAR_TRACE: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _CLEAR_TRACE: {
   CLEAR_TRACE;
@@ -209,6 +241,10 @@ case ASSERT: {
 _PRINT,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$print"] = _PRINT;
+:(before "End Primitive Recipe Checks")
+case _PRINT: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _PRINT: {
   for (long long int i = 0; i < SIZE(ingredients); ++i) {
@@ -234,6 +270,10 @@ case _PRINT: {
 _EXIT,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$exit"] = _EXIT;
+:(before "End Primitive Recipe Checks")
+case _EXIT: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _EXIT: {
   exit(0);
@@ -266,6 +306,10 @@ case _SYSTEM: {
 _DUMP_MEMORY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$dump-memory"] = _DUMP_MEMORY;
+:(before "End Primitive Recipe Checks")
+case _DUMP_MEMORY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _DUMP_MEMORY: {
   dump_memory();
diff --git a/035call_ingredient.cc b/035call_ingredient.cc
index 3cfc44ce..3772c644 100644
--- a/035call_ingredient.cc
+++ b/035call_ingredient.cc
@@ -35,12 +35,16 @@ for (long long int i = 0; i < SIZE(ingredients); ++i) {
 NEXT_INGREDIENT,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["next-ingredient"] = NEXT_INGREDIENT;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case NEXT_INGREDIENT: {
-  if (!ingredients.empty()) {
-    raise << maybe(current_recipe_name()) << "'next-ingredient' didn't expect any ingredients in '" << current_instruction().to_string() << "'\n" << end();
+  if (!inst.ingredients.empty()) {
+    raise << maybe(Recipe[r].name) << "'next-ingredient' didn't expect any ingredients in '" << inst.to_string() << "'\n" << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case NEXT_INGREDIENT: {
   assert(!Current_routine->calls.empty());
   if (Current_routine->calls.front().next_ingredient_to_process < SIZE(Current_routine->calls.front().ingredient_atoms)) {
     products.push_back(
@@ -88,6 +92,10 @@ recipe f [
 REWIND_INGREDIENTS,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["rewind-ingredients"] = REWIND_INGREDIENTS;
+:(before "End Primitive Recipe Checks")
+case REWIND_INGREDIENTS: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case REWIND_INGREDIENTS: {
   Current_routine->calls.front().next_ingredient_to_process = 0;
@@ -109,17 +117,20 @@ recipe f [
 INGREDIENT,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["ingredient"] = INGREDIENT;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case INGREDIENT: {
-  if (SIZE(ingredients) != 1) {
-    raise << maybe(current_recipe_name()) << "'ingredient' expects exactly one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(Recipe[r].name) << "'ingredient' expects exactly one ingredient, but got '" << inst.to_string() << "'\n" << end();
     break;
   }
-  if (!is_literal(current_instruction().ingredients.at(0))) {
-    raise << maybe(current_recipe_name()) << "'ingredient' expects a literal ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+  if (!is_literal(inst.ingredients.at(0)) && !is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "'ingredient' expects a literal ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
-  assert(scalar(ingredients.at(0)));
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case INGREDIENT: {
   if (static_cast<long long int>(ingredients.at(0).at(0)) < SIZE(Current_routine->calls.front().ingredient_atoms)) {
     Current_routine->calls.front().next_ingredient_to_process = ingredients.at(0).at(0);
     products.push_back(
diff --git a/036call_reply.cc b/036call_reply.cc
index cc146835..ce231d19 100644
--- a/036call_reply.cc
+++ b/036call_reply.cc
@@ -16,6 +16,10 @@ recipe f [
 REPLY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["reply"] = REPLY;
+:(before "End Primitive Recipe Checks")
+case REPLY: {
+  break;  // continue to process rest of *caller* instruction
+}
 :(before "End Primitive Recipe Implementations")
 case REPLY: {
   // Starting Reply
diff --git a/037recipe.cc b/037recipe.cc
index bbc197c8..c3f258da 100644
--- a/037recipe.cc
+++ b/037recipe.cc
@@ -40,20 +40,21 @@ if (!r.properties.at(0).second.empty() && r.properties.at(0).second.at(0) == "re
 CALL,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["call"] = CALL;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case CALL: {
-  if (ingredients.empty()) {
-    raise << maybe(current_recipe_name()) << "'call' requires at least one ingredient (the recipe to call)\n" << end();
+  if (inst.ingredients.empty()) {
+    raise << maybe(Recipe[r].name) << "'call' requires at least one ingredient (the recipe to call)\n" << end();
     break;
   }
-  // Begin Call
-  if (!scalar(ingredients.at(0))) {
-    raise << maybe(current_recipe_name()) << "first ingredient of 'call' should be a recipe, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'call' should be a recipe, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
-  // todo: when we start doing type checking this will be a prime point of
-  // attention, so we don't accidentally allow external data to a program to
-  // run as code.
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case CALL: {
+  // Begin Call
   Current_routine->calls.push_front(call(ingredients.at(0).at(0)));
   ingredients.erase(ingredients.begin());  // drop the callee
   goto call_housekeeping;
diff --git a/038scheduler.cc b/038scheduler.cc
index 2ae1b3b3..6158ab41 100644
--- a/038scheduler.cc
+++ b/038scheduler.cc
@@ -144,20 +144,20 @@ parent_index = -1;
 START_RUNNING,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["start-running"] = START_RUNNING;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case START_RUNNING: {
-  if (ingredients.empty()) {
-    raise << "'start-running' requires at least one ingredient: the recipe to start running\n" << end();
-    break;
-  }
-  if (!scalar(ingredients.at(0))) {
-    raise << "first ingredient of 'start-running' should be a recipe, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+  if (inst.ingredients.empty()) {
+    raise << maybe(Recipe[r].name) << "'start-running' requires at least one ingredient: the recipe to start running\n" << end();
     break;
   }
-  if (!ingredients.at(0).at(0)) {
-    raise << "'start-running' received non-existent recipe: '" << current_instruction().to_string() << "'\n" << end();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'start-running' should be a recipe, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case START_RUNNING: {
   routine* new_routine = new routine(ingredients.at(0).at(0));
   new_routine->parent_index = Current_routine_index;
   // populate ingredients
@@ -330,16 +330,20 @@ recipe f2 [
 ROUTINE_STATE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["routine-state"] = ROUTINE_STATE;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case ROUTINE_STATE: {
-  if (SIZE(ingredients) != 1) {
-    raise << maybe(current_recipe_name()) << "'routine-state' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(Recipe[r].name) << "'routine-state' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'routine-state' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case ROUTINE_STATE: {
   long long int id = ingredients.at(0).at(0);
   long long int result = -1;
   for (long long int i = 0; i < SIZE(Routines); ++i) {
@@ -359,16 +363,20 @@ case ROUTINE_STATE: {
 RESTART,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["restart"] = RESTART;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case RESTART: {
-  if (SIZE(ingredients) != 1) {
-    raise << maybe(current_recipe_name()) << "'restart' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(Recipe[r].name) << "'restart' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'restart' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case RESTART: {
   long long int id = ingredients.at(0).at(0);
   for (long long int i = 0; i < SIZE(Routines); ++i) {
     if (Routines.at(i)->id == id) {
@@ -383,16 +391,20 @@ case RESTART: {
 STOP,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["stop"] = STOP;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case STOP: {
-  if (SIZE(ingredients) != 1) {
-    raise << maybe(current_recipe_name()) << "'stop' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(Recipe[r].name) << "'stop' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'stop' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case STOP: {
   long long int id = ingredients.at(0).at(0);
   for (long long int i = 0; i < SIZE(Routines); ++i) {
     if (Routines.at(i)->id == id) {
@@ -407,6 +419,10 @@ case STOP: {
 _DUMP_ROUTINES,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$dump-routines"] = _DUMP_ROUTINES;
+:(before "End Primitive Recipe Checks")
+case _DUMP_ROUTINES: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _DUMP_ROUTINES: {
   for (long long int i = 0; i < SIZE(Routines); ++i) {
@@ -457,20 +473,24 @@ limit = -1;  /* no limit */
 LIMIT_TIME,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["limit-time"] = LIMIT_TIME;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case LIMIT_TIME: {
-  if (SIZE(ingredients) != 2) {
-    raise << maybe(current_recipe_name()) << "'limit-time' requires exactly two ingredient, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 2) {
+    raise << maybe(Recipe[r].name) << "'limit-time' requires exactly two ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'limit-time' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(1))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(1))) {
+    raise << maybe(Recipe[r].name) << "second ingredient of 'limit-time' should be a number (of instructions to run for), but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case LIMIT_TIME: {
   long long int id = ingredients.at(0).at(0);
   for (long long int i = 0; i < SIZE(Routines); ++i) {
     if (Routines.at(i)->id == id) {
diff --git a/039wait.cc b/039wait.cc
index 955ab4a8..b21f92ca 100644
--- a/039wait.cc
+++ b/039wait.cc
@@ -34,6 +34,10 @@ waiting_on_location = old_value_of_waiting_location = 0;
 WAIT_FOR_LOCATION,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["wait-for-location"] = WAIT_FOR_LOCATION;
+:(before "End Primitive Recipe Checks")
+case WAIT_FOR_LOCATION: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case WAIT_FOR_LOCATION: {
   reagent loc = canonize(current_instruction().ingredients.at(0));
@@ -88,16 +92,20 @@ waiting_on_routine = 0;
 WAIT_FOR_ROUTINE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["wait-for-routine"] = WAIT_FOR_ROUTINE;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case WAIT_FOR_ROUTINE: {
-  if (SIZE(ingredients) != 1) {
-    raise << maybe(current_recipe_name()) << "'wait-for-routine' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(Recipe[r].name) << "'wait-for-routine' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case WAIT_FOR_ROUTINE: {
   if (ingredients.at(0).at(0) == Current_routine->id) {
     raise << maybe(current_recipe_name()) << "routine can't wait for itself! " << current_instruction().to_string() << '\n' << end();
     break;
@@ -130,6 +138,10 @@ for (long long int i = 0; i < SIZE(Routines); ++i) {
 SWITCH,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["switch"] = SWITCH;
+:(before "End Primitive Recipe Checks")
+case SWITCH: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case SWITCH: {
   long long int id = some_other_running_routine();
diff --git a/043new.cc b/043new.cc
index d6761dad..6bd733d1 100644
--- a/043new.cc
+++ b/043new.cc
@@ -53,16 +53,21 @@ if (inst.operation == Recipe_ordinal["new"]) {
 NEW,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["new"] = NEW;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case NEW: {
-  if (ingredients.empty() || SIZE(ingredients) > 2) {
-    raise << maybe(current_recipe_name()) << "'new' requires one or two ingredients, but got " << current_instruction().to_string() << '\n' << end();
+  if (inst.ingredients.empty() || SIZE(inst.ingredients) > 2) {
+    raise << maybe(Recipe[r].name) << "'new' requires one or two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    raise << maybe(current_recipe_name()) << "first ingredient of 'new' should be a type, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+  reagent type = inst.ingredients.at(0);
+  if (!is_mu_scalar(type) && !is_literal(type)) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'new' should be a type, but got " << type.original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case NEW: {
   // compute the space we need
   long long int size = 0;
   long long int array_length = 0;
@@ -213,22 +218,24 @@ Free_list.clear();
 ABANDON,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["abandon"] = ABANDON;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case ABANDON: {
-  if (SIZE(ingredients) != 1) {
-    raise << maybe(current_recipe_name()) << "'abandon' requires one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(Recipe[r].name) << "'abandon' requires one ingredient, but got '" << inst.to_string() << "'\n" << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    raise << maybe(current_recipe_name()) << "first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+  reagent types = inst.ingredients.at(0);
+  canonize_type(types);
+  if (types.types.empty() || types.types.at(0) != Type_ordinal["address"]) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'abandon' should be an address, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case ABANDON: {
   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 << 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);
   abandon(address, size_of(target_type));
   break;
@@ -317,12 +324,12 @@ recipe main [
   }
 
 :(after "case NEW" following "Primitive Recipe Implementations")
-if (is_literal(current_instruction().ingredients.at(0))
-    && current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "literal-string") {
-  products.resize(1);
-  products.at(0).push_back(new_mu_string(current_instruction().ingredients.at(0).name));
-  break;
-}
+  if (is_literal(current_instruction().ingredients.at(0))
+      && current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "literal-string") {
+    products.resize(1);
+    products.at(0).push_back(new_mu_string(current_instruction().ingredients.at(0).name));
+    break;
+  }
 
 :(code)
 long long int new_mu_string(const string& contents) {
diff --git a/050scenario.cc b/050scenario.cc
index 65e161b3..5f92fec8 100644
--- a/050scenario.cc
+++ b/050scenario.cc
@@ -189,6 +189,10 @@ recipe main [
 RUN,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["run"] = RUN;
+:(before "End Primitive Recipe Checks")
+case RUN: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case RUN: {
   ostringstream tmp;
@@ -243,6 +247,10 @@ recipe main [
 MEMORY_SHOULD_CONTAIN,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["memory-should-contain"] = MEMORY_SHOULD_CONTAIN;
+:(before "End Primitive Recipe Checks")
+case MEMORY_SHOULD_CONTAIN: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case MEMORY_SHOULD_CONTAIN: {
   if (!Passed) break;
@@ -404,6 +412,10 @@ recipe main [
 TRACE_SHOULD_CONTAIN,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["trace-should-contain"] = TRACE_SHOULD_CONTAIN;
+:(before "End Primitive Recipe Checks")
+case TRACE_SHOULD_CONTAIN: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case TRACE_SHOULD_CONTAIN: {
   if (!Passed) break;
@@ -496,6 +508,10 @@ recipe main [
 TRACE_SHOULD_NOT_CONTAIN,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["trace-should-not-contain"] = TRACE_SHOULD_NOT_CONTAIN;
+:(before "End Primitive Recipe Checks")
+case TRACE_SHOULD_NOT_CONTAIN: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case TRACE_SHOULD_NOT_CONTAIN: {
   if (!Passed) break;
@@ -556,22 +572,26 @@ recipe main [
 CHECK_TRACE_COUNT_FOR_LABEL,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["check-trace-count-for-label"] = CHECK_TRACE_COUNT_FOR_LABEL;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case CHECK_TRACE_COUNT_FOR_LABEL: {
-  if (!Passed) break;
-  if (SIZE(current_instruction().ingredients) != 2) {
-    raise << maybe(current_recipe_name()) << "'check-trace-for-label' requires exactly two ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
+  if (SIZE(inst.ingredients) != 2) {
+    raise << maybe(Recipe[r].name) << "'check-trace-for-label' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'check-trace-for-label' should be a number (count), but got " << inst.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 << 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();
+  if (!is_literal_string(inst.ingredients.at(1))) {
+    raise << maybe(Recipe[r].name) << "second ingredient of 'check-trace-for-label' should be a literal string (label), but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case CHECK_TRACE_COUNT_FOR_LABEL: {
+  if (!Passed) break;
+  long long int expected_count = ingredients.at(0).at(0);
   string label = current_instruction().ingredients.at(1).name;
   long long int count = trace_count(label);
   if (count != expected_count) {
diff --git a/053continuation.cc b/053continuation.cc
index 42f32f6d..18174cc1 100644
--- a/053continuation.cc
+++ b/053continuation.cc
@@ -21,6 +21,10 @@ Type[continuation].name = "continuation";
 CURRENT_CONTINUATION,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["current-continuation"] = CURRENT_CONTINUATION;
+:(before "End Primitive Recipe Checks")
+case CURRENT_CONTINUATION: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case CURRENT_CONTINUATION: {
   // copy the current call stack
@@ -38,12 +42,16 @@ case CURRENT_CONTINUATION: {
 CONTINUE_FROM,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["continue-from"] = CONTINUE_FROM;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case CONTINUE_FROM: {
-  if (!scalar(ingredients.at(0))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'continue-from' should be a continuation id generated by 'current-continuation', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case CONTINUE_FROM: {
   long long int c = ingredients.at(0).at(0);
   Current_routine->calls = Continuation[c];  // deep copy; calls have no pointers
   continue;  // skip rest of this instruction
@@ -166,6 +174,10 @@ is_reset = false;
 CREATE_DELIMITED_CONTINUATION,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["create-delimited-continuation"] = CREATE_DELIMITED_CONTINUATION;
+:(before "End Primitive Recipe Checks")
+case CREATE_DELIMITED_CONTINUATION: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case CREATE_DELIMITED_CONTINUATION: {
   Current_routine->calls.front().is_reset = true;
@@ -188,6 +200,10 @@ Next_delimited_continuation_id = 0;
 REPLY_DELIMITED_CONTINUATION,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["reply-delimited-continuation"] = REPLY_DELIMITED_CONTINUATION;
+:(before "End Primitive Recipe Checks")
+case REPLY_DELIMITED_CONTINUATION: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case REPLY_DELIMITED_CONTINUATION: {
   // first clear any existing ingredients, to isolate the creation of the
diff --git a/064random.cc b/064random.cc
index 07667cc2..de304714 100644
--- a/064random.cc
+++ b/064random.cc
@@ -2,6 +2,10 @@
 RANDOM,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["random"] = RANDOM;
+:(before "End Primitive Recipe Checks")
+case RANDOM: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case RANDOM: {
   // todo: limited range of numbers, might be imperfectly random
@@ -15,6 +19,10 @@ case RANDOM: {
 MAKE_RANDOM_NONDETERMINISTIC,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["make-random-nondeterministic"] = MAKE_RANDOM_NONDETERMINISTIC;
+:(before "End Primitive Recipe Checks")
+case MAKE_RANDOM_NONDETERMINISTIC: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case MAKE_RANDOM_NONDETERMINISTIC: {
   srand(time(NULL));
@@ -25,16 +33,20 @@ case MAKE_RANDOM_NONDETERMINISTIC: {
 ROUND,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["round"] = ROUND;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case ROUND: {
-  if (SIZE(ingredients) != 1) {
-    raise << maybe(current_recipe_name()) << "'round' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(Recipe[r].name) << "'round' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    raise << maybe(current_recipe_name()) << "first ingredient of 'round' should be a number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'round' should be a number, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case ROUND: {
   products.resize(1);
   products.at(0).push_back(rint(ingredients.at(0).at(0)));
   break;
diff --git a/070display.cc b/070display.cc
index 1f42e5ba..8859a909 100644
--- a/070display.cc
+++ b/070display.cc
@@ -10,6 +10,10 @@ bool Autodisplay = true;
 OPEN_CONSOLE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["open-console"] = OPEN_CONSOLE;
+:(before "End Primitive Recipe Checks")
+case OPEN_CONSOLE: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case OPEN_CONSOLE: {
   tb_init();
@@ -28,6 +32,10 @@ case OPEN_CONSOLE: {
 CLOSE_CONSOLE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["close-console"] = CLOSE_CONSOLE;
+:(before "End Primitive Recipe Checks")
+case CLOSE_CONSOLE: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case CLOSE_CONSOLE: {
   tb_shutdown();
@@ -41,6 +49,10 @@ tb_shutdown();
 CLEAR_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["clear-display"] = CLEAR_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case CLEAR_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case CLEAR_DISPLAY: {
   tb_clear();
@@ -52,6 +64,10 @@ case CLEAR_DISPLAY: {
 SYNC_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["sync-display"] = SYNC_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case SYNC_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case SYNC_DISPLAY: {
   tb_sync();
@@ -62,6 +78,10 @@ case SYNC_DISPLAY: {
 CLEAR_LINE_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["clear-line-on-display"] = CLEAR_LINE_ON_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case CLEAR_LINE_ON_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case CLEAR_LINE_ON_DISPLAY: {
   long long int width = tb_width();
@@ -77,6 +97,10 @@ case CLEAR_LINE_ON_DISPLAY: {
 PRINT_CHARACTER_TO_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["print-character-to-display"] = PRINT_CHARACTER_TO_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case PRINT_CHARACTER_TO_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case PRINT_CHARACTER_TO_DISPLAY: {
   int h=tb_height(), w=tb_width();
@@ -139,6 +163,10 @@ case PRINT_CHARACTER_TO_DISPLAY: {
 CURSOR_POSITION_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["cursor-position-on-display"] = CURSOR_POSITION_ON_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case CURSOR_POSITION_ON_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case CURSOR_POSITION_ON_DISPLAY: {
   products.resize(2);
@@ -151,21 +179,25 @@ case CURSOR_POSITION_ON_DISPLAY: {
 MOVE_CURSOR_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["move-cursor-on-display"] = MOVE_CURSOR_ON_DISPLAY;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case MOVE_CURSOR_ON_DISPLAY: {
-  if (SIZE(ingredients) != 2) {
-    raise << maybe(current_recipe_name()) << "'move-cursor-on-display' requires two ingredients, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 2) {
+    raise << maybe(Recipe[r].name) << "'move-cursor-on-display' requires two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'move-cursor-on-display' should be a row number, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
-  Display_row = ingredients.at(0).at(0);
-  if (!scalar(ingredients.at(1))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(1))) {
+    raise << maybe(Recipe[r].name) << "second ingredient of 'move-cursor-on-display' should be a column number, but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case MOVE_CURSOR_ON_DISPLAY: {
+  Display_row = ingredients.at(0).at(0);
   Display_column = ingredients.at(1).at(0);
   tb_set_cursor(Display_column, Display_row);
   if (Autodisplay) tb_present();
@@ -176,6 +208,10 @@ case MOVE_CURSOR_ON_DISPLAY: {
 MOVE_CURSOR_DOWN_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["move-cursor-down-on-display"] = MOVE_CURSOR_DOWN_ON_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case MOVE_CURSOR_DOWN_ON_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case MOVE_CURSOR_DOWN_ON_DISPLAY: {
   int h=tb_height();
@@ -192,6 +228,10 @@ case MOVE_CURSOR_DOWN_ON_DISPLAY: {
 MOVE_CURSOR_UP_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["move-cursor-up-on-display"] = MOVE_CURSOR_UP_ON_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case MOVE_CURSOR_UP_ON_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case MOVE_CURSOR_UP_ON_DISPLAY: {
   if (Display_row > 0) {
@@ -206,6 +246,10 @@ case MOVE_CURSOR_UP_ON_DISPLAY: {
 MOVE_CURSOR_RIGHT_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["move-cursor-right-on-display"] = MOVE_CURSOR_RIGHT_ON_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case MOVE_CURSOR_RIGHT_ON_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case MOVE_CURSOR_RIGHT_ON_DISPLAY: {
   int w=tb_width();
@@ -222,6 +266,10 @@ case MOVE_CURSOR_RIGHT_ON_DISPLAY: {
 MOVE_CURSOR_LEFT_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["move-cursor-left-on-display"] = MOVE_CURSOR_LEFT_ON_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case MOVE_CURSOR_LEFT_ON_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case MOVE_CURSOR_LEFT_ON_DISPLAY: {
   if (Display_column > 0) {
@@ -236,6 +284,10 @@ case MOVE_CURSOR_LEFT_ON_DISPLAY: {
 DISPLAY_WIDTH,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["display-width"] = DISPLAY_WIDTH;
+:(before "End Primitive Recipe Checks")
+case DISPLAY_WIDTH: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case DISPLAY_WIDTH: {
   products.resize(1);
@@ -247,6 +299,10 @@ case DISPLAY_WIDTH: {
 DISPLAY_HEIGHT,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["display-height"] = DISPLAY_HEIGHT;
+:(before "End Primitive Recipe Checks")
+case DISPLAY_HEIGHT: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case DISPLAY_HEIGHT: {
   products.resize(1);
@@ -258,6 +314,10 @@ case DISPLAY_HEIGHT: {
 HIDE_CURSOR_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["hide-cursor-on-display"] = HIDE_CURSOR_ON_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case HIDE_CURSOR_ON_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case HIDE_CURSOR_ON_DISPLAY: {
   tb_set_cursor(TB_HIDE_CURSOR, TB_HIDE_CURSOR);
@@ -268,6 +328,10 @@ case HIDE_CURSOR_ON_DISPLAY: {
 SHOW_CURSOR_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["show-cursor-on-display"] = SHOW_CURSOR_ON_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case SHOW_CURSOR_ON_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case SHOW_CURSOR_ON_DISPLAY: {
   tb_set_cursor(Display_row, Display_column);
@@ -278,6 +342,10 @@ case SHOW_CURSOR_ON_DISPLAY: {
 HIDE_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["hide-display"] = HIDE_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case HIDE_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case HIDE_DISPLAY: {
   Autodisplay = false;
@@ -288,6 +356,10 @@ case HIDE_DISPLAY: {
 SHOW_DISPLAY,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["show-display"] = SHOW_DISPLAY;
+:(before "End Primitive Recipe Checks")
+case SHOW_DISPLAY: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case SHOW_DISPLAY: {
   Autodisplay = true;
@@ -301,6 +373,10 @@ case SHOW_DISPLAY: {
 WAIT_FOR_SOME_INTERACTION,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["wait-for-some-interaction"] = WAIT_FOR_SOME_INTERACTION;
+:(before "End Primitive Recipe Checks")
+case WAIT_FOR_SOME_INTERACTION: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case WAIT_FOR_SOME_INTERACTION: {
   tb_event event;
@@ -312,6 +388,10 @@ case WAIT_FOR_SOME_INTERACTION: {
 CHECK_FOR_INTERACTION,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["check-for-interaction"] = CHECK_FOR_INTERACTION;
+:(before "End Primitive Recipe Checks")
+case CHECK_FOR_INTERACTION: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case CHECK_FOR_INTERACTION: {
   products.resize(2);  // result and status
@@ -375,6 +455,10 @@ case CHECK_FOR_INTERACTION: {
 INTERACTIONS_LEFT,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["interactions-left?"] = INTERACTIONS_LEFT;
+:(before "End Primitive Recipe Checks")
+case INTERACTIONS_LEFT: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case INTERACTIONS_LEFT: {
   products.resize(1);
@@ -388,6 +472,10 @@ case INTERACTIONS_LEFT: {
 CLEAR_DISPLAY_FROM,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["clear-display-from"] = CLEAR_DISPLAY_FROM;
+:(before "End Primitive Recipe Checks")
+case CLEAR_DISPLAY_FROM: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case CLEAR_DISPLAY_FROM: {
   // todo: error checking
diff --git a/072scenario_screen.cc b/072scenario_screen.cc
index 732a2999..76900238 100644
--- a/072scenario_screen.cc
+++ b/072scenario_screen.cc
@@ -154,6 +154,10 @@ if (curr.name == "assume-screen") {
 SCREEN_SHOULD_CONTAIN,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["screen-should-contain"] = SCREEN_SHOULD_CONTAIN;
+:(before "End Primitive Recipe Checks")
+case SCREEN_SHOULD_CONTAIN: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case SCREEN_SHOULD_CONTAIN: {
   if (!Passed) break;
@@ -165,6 +169,10 @@ case SCREEN_SHOULD_CONTAIN: {
 SCREEN_SHOULD_CONTAIN_IN_COLOR,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["screen-should-contain-in-color"] = SCREEN_SHOULD_CONTAIN_IN_COLOR;
+:(before "End Primitive Recipe Checks")
+case SCREEN_SHOULD_CONTAIN_IN_COLOR: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case SCREEN_SHOULD_CONTAIN_IN_COLOR: {
   if (!Passed) break;
@@ -312,6 +320,10 @@ void raw_string_stream::skip_whitespace_and_comments() {
 _DUMP_SCREEN,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$dump-screen"] = _DUMP_SCREEN;
+:(before "End Primitive Recipe Checks")
+case _DUMP_SCREEN: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _DUMP_SCREEN: {
   dump_screen();
diff --git a/075scenario_console.cc b/075scenario_console.cc
index 0f7d649f..06bf7d63 100644
--- a/075scenario_console.cc
+++ b/075scenario_console.cc
@@ -38,12 +38,14 @@ Name[r]["console"] = CONSOLE;
 :(before "End is_special_name Cases")
 if (s == "console") return true;
 
-//: Unlike assume-keyboard, assume-console is easiest to implement as just a
-//: primitive recipe.
 :(before "End Primitive Recipe Declarations")
 ASSUME_CONSOLE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["assume-console"] = ASSUME_CONSOLE;
+:(before "End Primitive Recipe Checks")
+case ASSUME_CONSOLE: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case ASSUME_CONSOLE: {
   // create a temporary recipe just for parsing; it won't contain valid instructions
@@ -225,6 +227,10 @@ scenario events-in-scenario [
 REPLACE_IN_CONSOLE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["replace-in-console"] = REPLACE_IN_CONSOLE;
+:(before "End Primitive Recipe Checks")
+case REPLACE_IN_CONSOLE: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case REPLACE_IN_CONSOLE: {
   assert(scalar(ingredients.at(0)));
diff --git a/080trace_browser.cc b/080trace_browser.cc
index f399ae7e..9c5c5e86 100644
--- a/080trace_browser.cc
+++ b/080trace_browser.cc
@@ -2,6 +2,10 @@
 _BROWSE_TRACE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$browse-trace"] = _BROWSE_TRACE;
+:(before "End Primitive Recipe Checks")
+case _BROWSE_TRACE: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _BROWSE_TRACE: {
   start_trace_browser();
diff --git a/081run_interactive.cc b/081run_interactive.cc
index eccf2d07..8548f568 100644
--- a/081run_interactive.cc
+++ b/081run_interactive.cc
@@ -26,16 +26,20 @@ recipe main [
 RUN_INTERACTIVE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["run-interactive"] = RUN_INTERACTIVE;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case RUN_INTERACTIVE: {
-  if (SIZE(ingredients) != 1) {
-    raise << maybe(current_recipe_name()) << "'run-interactive' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(Recipe[r].name) << "'run-interactive' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'run-interactive' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case RUN_INTERACTIVE: {
   bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0));
   if (!new_code_pushed_to_stack) {
     products.resize(5);
@@ -166,6 +170,10 @@ recipe main [
 _START_TRACKING_PRODUCTS,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$start-tracking-products"] = _START_TRACKING_PRODUCTS;
+:(before "End Primitive Recipe Checks")
+case _START_TRACKING_PRODUCTS: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _START_TRACKING_PRODUCTS: {
   Track_most_recent_products = true;
@@ -176,6 +184,10 @@ case _START_TRACKING_PRODUCTS: {
 _STOP_TRACKING_PRODUCTS,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$stop-tracking-products"] = _STOP_TRACKING_PRODUCTS;
+:(before "End Primitive Recipe Checks")
+case _STOP_TRACKING_PRODUCTS: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _STOP_TRACKING_PRODUCTS: {
   Track_most_recent_products = false;
@@ -186,6 +198,10 @@ case _STOP_TRACKING_PRODUCTS: {
 _MOST_RECENT_PRODUCTS,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$most-recent-products"] = _MOST_RECENT_PRODUCTS;
+:(before "End Primitive Recipe Checks")
+case _MOST_RECENT_PRODUCTS: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _MOST_RECENT_PRODUCTS: {
   products.resize(1);
@@ -197,6 +213,10 @@ case _MOST_RECENT_PRODUCTS: {
 SAVE_TRACE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["save-trace"] = SAVE_TRACE;
+:(before "End Primitive Recipe Checks")
+case SAVE_TRACE: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case SAVE_TRACE: {
   products.resize(1);
@@ -208,6 +228,10 @@ case SAVE_TRACE: {
 _CLEANUP_RUN_INTERACTIVE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["$cleanup-run-interactive"] = _CLEANUP_RUN_INTERACTIVE;
+:(before "End Primitive Recipe Checks")
+case _CLEANUP_RUN_INTERACTIVE: {
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case _CLEANUP_RUN_INTERACTIVE: {
   run_code_end();
@@ -343,16 +367,20 @@ void truncate(string& x) {
 RELOAD,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["reload"] = RELOAD;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case RELOAD: {
-  if (SIZE(ingredients) != 1) {
-    raise << maybe(current_recipe_name()) << "'reload' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(Recipe[r].name) << "'reload' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0))) {
-    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();
+  if (!is_mu_scalar(inst.ingredients.at(0))) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'reload' should be a literal string, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case RELOAD: {
   // clear any containers in advance
   for (long long int i = 0; i < SIZE(recently_added_types); ++i) {
     Type_ordinal.erase(Type[recently_added_types.at(i)].name);
diff --git a/082persist.cc b/082persist.cc
index 40241eb2..0a0064d3 100644
--- a/082persist.cc
+++ b/082persist.cc
@@ -6,12 +6,27 @@
 RESTORE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["restore"] = RESTORE;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case RESTORE: {
-  if (SIZE(ingredients) != 1) {
-    raise << maybe(current_recipe_name()) << "'restore' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 1) {
+    raise << maybe(Recipe[r].name) << "'restore' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    break;
+  }
+  string filename;
+  if (is_literal_string(inst.ingredients.at(0))) {
+    ;
+  }
+  else if (is_mu_string(inst.ingredients.at(0))) {
+    ;
+  }
+  else {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'restore' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
     break;
   }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case RESTORE: {
   string filename;
   if (is_literal_string(current_instruction().ingredients.at(0))) {
     filename = current_instruction().ingredients.at(0).name;
@@ -19,10 +34,6 @@ case RESTORE: {
   else if (is_mu_string(current_instruction().ingredients.at(0))) {
     filename = read_mu_string(ingredients.at(0).at(0));
   }
-  else {
-    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) {
     // do nothing in tests
     products.resize(1);
@@ -59,12 +70,30 @@ string slurp(const string& filename) {
 SAVE,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["save"] = SAVE;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case SAVE: {
-  if (SIZE(ingredients) != 2) {
-    raise << maybe(current_recipe_name()) << "'save' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end();
+  if (SIZE(inst.ingredients) != 2) {
+    raise << maybe(Recipe[r].name) << "'save' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
+  if (is_literal_string(inst.ingredients.at(0))) {
+    ;
+  }
+  else if (is_mu_string(inst.ingredients.at(0))) {
+    ;
+  }
+  else {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'save' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
+    break;
+  }
+  if (!is_mu_scalar(inst.ingredients.at(1))) {
+    raise << maybe(Recipe[r].name) << "second ingredient of 'save' should be an address:array:character, but got " << inst.ingredients.at(1).to_string() << '\n' << end();
+    break;
+  }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case SAVE: {
   if (Current_scenario) break;  // do nothing in tests
   string filename;
   if (is_literal_string(current_instruction().ingredients.at(0))) {
@@ -73,14 +102,6 @@ case SAVE: {
   else if (is_mu_string(current_instruction().ingredients.at(0))) {
     filename = read_mu_string(ingredients.at(0).at(0));
   }
-  else {
-    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 << 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());
   string contents = read_mu_string(ingredients.at(1).at(0));
   fout << contents;