about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-07-29 18:40:36 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-07-29 18:40:36 -0700
commit89b87bc7c493670ecb598784e1073a09f691d43e (patch)
treeb645853bb524a9a57a897a729269786aad8c4ce6
parent9570363aec35e187e2395b1760a4b94e71580ac9 (diff)
downloadmu-89b87bc7c493670ecb598784e1073a09f691d43e.tar.gz
1886 - gracefully handle malformed ingredients
For example:
  x:number <- index y:address:array:number, 3
(forgetting to do a lookup)

Thanks Caleb Couch.
-rw-r--r--021arithmetic.cc6
-rw-r--r--024compare.cc10
-rw-r--r--029tools.cc2
-rw-r--r--030container.cc6
-rw-r--r--032array.cc7
-rw-r--r--033exclusive_container.cc2
-rw-r--r--035call_ingredient.cc3
-rw-r--r--038scheduler.cc2
-rw-r--r--043new.cc3
-rw-r--r--053continuation.cc2
-rw-r--r--064random.cc2
-rw-r--r--081run_interactive.cc4
-rw-r--r--082persist.cc6
13 files changed, 32 insertions, 23 deletions
diff --git a/021arithmetic.cc b/021arithmetic.cc
index 1485e194..2a21c2cf 100644
--- a/021arithmetic.cc
+++ b/021arithmetic.cc
@@ -43,6 +43,7 @@ SUBTRACT,
 Recipe_ordinal["subtract"] = SUBTRACT;
 :(before "End Primitive Recipe Implementations")
 case SUBTRACT: {
+  products.resize(1);
   if (ingredients.empty()) {
     raise << current_recipe_name() << ": 'subtract' has no ingredients\n" << end();
     break;
@@ -53,7 +54,6 @@ case SUBTRACT: {
     assert(scalar(ingredients.at(i)));
     result -= ingredients.at(i).at(0);
   }
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
@@ -120,6 +120,7 @@ DIVIDE,
 Recipe_ordinal["divide"] = DIVIDE;
 :(before "End Primitive Recipe Implementations")
 case DIVIDE: {
+  products.resize(1);
   if (ingredients.empty()) {
     raise << current_recipe_name() << ": 'divide' has no ingredients\n" << end();
     break;
@@ -130,7 +131,6 @@ case DIVIDE: {
     assert(scalar(ingredients.at(i)));
     result /= ingredients.at(i).at(0);
   }
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
@@ -163,13 +163,13 @@ DIVIDE_WITH_REMAINDER,
 Recipe_ordinal["divide-with-remainder"] = DIVIDE_WITH_REMAINDER;
 :(before "End Primitive Recipe Implementations")
 case DIVIDE_WITH_REMAINDER: {
+  products.resize(2);
   if (SIZE(ingredients) != 2) {
     raise << current_recipe_name() << ": 'divide-with-remainder' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   long long int quotient = ingredients.at(0).at(0) / ingredients.at(1).at(0);
   long long int remainder = static_cast<long long int>(ingredients.at(0).at(0)) % static_cast<long long int>(ingredients.at(1).at(0));
-  products.resize(2);
   // very large integers will lose precision
   products.at(0).push_back(quotient);
   products.at(1).push_back(remainder);
diff --git a/024compare.cc b/024compare.cc
index fb3481fd..7fb8c2e8 100644
--- a/024compare.cc
+++ b/024compare.cc
@@ -6,6 +6,7 @@ EQUAL,
 Recipe_ordinal["equal"] = EQUAL;
 :(before "End Primitive Recipe Implementations")
 case EQUAL: {
+  products.resize(1);
   if (SIZE(ingredients) <= 1) {
     raise << current_recipe_name() << ": 'equal' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end();
     break;
@@ -18,7 +19,6 @@ case EQUAL: {
       break;
     }
   }
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
@@ -61,6 +61,7 @@ GREATER_THAN,
 Recipe_ordinal["greater-than"] = GREATER_THAN;
 :(before "End Primitive Recipe Implementations")
 case GREATER_THAN: {
+  products.resize(1);
   bool result = true;
   if (SIZE(ingredients) <= 1) {
     raise << current_recipe_name() << ": 'greater-than' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end();
@@ -78,7 +79,6 @@ case GREATER_THAN: {
     }
   }
   finish_greater_than:
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
@@ -117,6 +117,7 @@ LESSER_THAN,
 Recipe_ordinal["lesser-than"] = LESSER_THAN;
 :(before "End Primitive Recipe Implementations")
 case LESSER_THAN: {
+  products.resize(1);
   bool result = true;
   if (SIZE(ingredients) <= 1) {
     raise << current_recipe_name() << ": 'lesser-than' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end();
@@ -134,7 +135,6 @@ case LESSER_THAN: {
     }
   }
   finish_lesser_than:
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
@@ -173,6 +173,7 @@ GREATER_OR_EQUAL,
 Recipe_ordinal["greater-or-equal"] = GREATER_OR_EQUAL;
 :(before "End Primitive Recipe Implementations")
 case GREATER_OR_EQUAL: {
+  products.resize(1);
   bool result = true;
   if (SIZE(ingredients) <= 1) {
     raise << current_recipe_name() << ": 'greater-or-equal' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end();
@@ -190,7 +191,6 @@ case GREATER_OR_EQUAL: {
     }
   }
   finish_greater_or_equal:
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
@@ -237,6 +237,7 @@ LESSER_OR_EQUAL,
 Recipe_ordinal["lesser-or-equal"] = LESSER_OR_EQUAL;
 :(before "End Primitive Recipe Implementations")
 case LESSER_OR_EQUAL: {
+  products.resize(1);
   bool result = true;
   if (SIZE(ingredients) <= 1) {
     raise << current_recipe_name() << ": 'lesser-or-equal' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end();
@@ -254,7 +255,6 @@ case LESSER_OR_EQUAL: {
     }
   }
   finish_lesser_or_equal:
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
diff --git a/029tools.cc b/029tools.cc
index 9e25f16f..cd4123fa 100644
--- a/029tools.cc
+++ b/029tools.cc
@@ -182,11 +182,11 @@ _SYSTEM,
 Recipe_ordinal["$system"] = _SYSTEM;
 :(before "End Primitive Recipe Implementations")
 case _SYSTEM: {
+  products.resize(1);
   if (current_instruction().ingredients.empty()) {
     raise << current_recipe_name() << ": '$system' requires exactly one ingredient, but got none\n" << end();
     break;
   }
-  products.resize(1);
   int status = system(current_instruction().ingredients.at(0).name.c_str());
   products.at(0).push_back(status);
   break;
diff --git a/030container.cc b/030container.cc
index 46314d00..15a6eb6f 100644
--- a/030container.cc
+++ b/030container.cc
@@ -109,6 +109,7 @@ Recipe_ordinal["get"] = GET;
 case GET: {
   if (SIZE(ingredients) != 2) {
     raise << current_recipe_name() << ": 'get' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    products.resize(1);
     break;
   }
   reagent base = current_instruction().ingredients.at(0);
@@ -116,10 +117,12 @@ case GET: {
   type_ordinal base_type = base.types.at(0);
   if (Type[base_type].kind != container) {
     raise << current_recipe_name () << ": first ingredient of 'get' should be a container, but got " << base.original_string << '\n' << end();
+    products.resize(1);
     break;
   }
   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();
+    products.resize(1);
     break;
   }
   assert(scalar(ingredients.at(1)));
@@ -188,6 +191,7 @@ GET_ADDRESS,
 Recipe_ordinal["get-address"] = GET_ADDRESS;
 :(before "End Primitive Recipe Implementations")
 case GET_ADDRESS: {
+  products.resize(1);
   reagent base = current_instruction().ingredients.at(0);
   long long int base_address = base.value;
   type_ordinal base_type = base.types.at(0);
@@ -203,7 +207,6 @@ case GET_ADDRESS: {
   long long int offset = ingredients.at(1).at(0);
   if (offset < 0 || offset >= SIZE(Type[base_type].elements)) {
     raise << "invalid offset " << offset << " for " << Type[base_type].name << '\n' << end();
-    products.resize(1);
     break;
   }
   long long int result = base_address;
@@ -211,7 +214,6 @@ case GET_ADDRESS: {
     result += size_of(Type[base_type].elements.at(i));
   }
   trace(Primitive_recipe_depth, "run") << "address to copy is " << result << end();
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
diff --git a/032array.cc b/032array.cc
index 9f816ceb..5911f1c3 100644
--- a/032array.cc
+++ b/032array.cc
@@ -81,12 +81,14 @@ Recipe_ordinal["index"] = INDEX;
 case INDEX: {
   if (SIZE(ingredients) != 2) {
     raise << current_recipe_name() << ": 'index' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    products.resize(1);
     break;
   }
   reagent base = canonize(current_instruction().ingredients.at(0));
   long long int base_address = base.value;
   if (base.types.at(0) != Type_ordinal["array"]) {
     raise << current_recipe_name () << ": 'index' on a non-array " << base.original_string << '\n' << end();
+    products.resize(1);
     break;
   }
   reagent offset = canonize(current_instruction().ingredients.at(1));
@@ -171,6 +173,7 @@ INDEX_ADDRESS,
 Recipe_ordinal["index-address"] = INDEX_ADDRESS;
 :(before "End Primitive Recipe Implementations")
 case INDEX_ADDRESS: {
+  products.resize(1);
   if (SIZE(ingredients) != 2) {
     raise << current_recipe_name() << ": 'index-address' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
@@ -186,11 +189,9 @@ case INDEX_ADDRESS: {
   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 " << offset_val.at(0) << '\n' << end();
-    products.resize(1);
     break;
   }
   long long int result = base_address + 1 + offset_val.at(0)*size_of(element_type);
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
@@ -243,6 +244,7 @@ LENGTH,
 Recipe_ordinal["length"] = LENGTH;
 :(before "End Primitive Recipe Implementations")
 case LENGTH: {
+  products.resize(1);
   if (SIZE(ingredients) != 1) {
     raise << current_recipe_name() << ": 'length' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
@@ -252,7 +254,6 @@ case LENGTH: {
     raise << "tried to calculate length of non-array " << x.original_string << '\n' << end();
     break;
   }
-  products.resize(1);
   products.at(0).push_back(Memory[x.value]);
   break;
 }
diff --git a/033exclusive_container.cc b/033exclusive_container.cc
index 3893d46f..65995b14 100644
--- a/033exclusive_container.cc
+++ b/033exclusive_container.cc
@@ -83,6 +83,7 @@ MAYBE_CONVERT,
 Recipe_ordinal["maybe-convert"] = MAYBE_CONVERT;
 :(before "End Primitive Recipe Implementations")
 case MAYBE_CONVERT: {
+  products.resize(1);
   if (SIZE(ingredients) != 2) {
     raise << current_recipe_name() << ": 'maybe-convert' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
@@ -106,7 +107,6 @@ case MAYBE_CONVERT: {
   else {
     result = 0;
   }
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
diff --git a/035call_ingredient.cc b/035call_ingredient.cc
index 599906da..a2dd97ad 100644
--- a/035call_ingredient.cc
+++ b/035call_ingredient.cc
@@ -39,6 +39,7 @@ Recipe_ordinal["next-ingredient"] = NEXT_INGREDIENT;
 case NEXT_INGREDIENT: {
   if (!ingredients.empty()) {
     raise << current_recipe_name() << ": 'next-ingredient' didn't expect any ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    products.resize(2);
     break;
   }
   assert(!Current_routine->calls.empty());
@@ -101,10 +102,12 @@ Recipe_ordinal["ingredient"] = INGREDIENT;
 case INGREDIENT: {
   if (SIZE(ingredients) != 1) {
     raise << current_recipe_name() << ": 'ingredient' expects exactly one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
+    products.resize(2);
     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();
+    products.resize(2);
     break;
   }
   assert(scalar(ingredients.at(0)));
diff --git a/038scheduler.cc b/038scheduler.cc
index d32fb76a..5925abab 100644
--- a/038scheduler.cc
+++ b/038scheduler.cc
@@ -281,6 +281,7 @@ ROUTINE_STATE,
 Recipe_ordinal["routine-state"] = ROUTINE_STATE;
 :(before "End Primitive Recipe Implementations")
 case ROUTINE_STATE: {
+  products.resize(1);
   if (SIZE(ingredients) != 1) {
     raise << current_recipe_name() << ": 'routine-state' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
@@ -297,7 +298,6 @@ case ROUTINE_STATE: {
       break;
     }
   }
-  products.resize(1);
   products.at(0).push_back(result);
   break;
 }
diff --git a/043new.cc b/043new.cc
index 191d9e87..c324bff7 100644
--- a/043new.cc
+++ b/043new.cc
@@ -56,12 +56,14 @@ NEW,
 Recipe_ordinal["new"] = NEW;
 :(before "End Primitive Recipe Implementations")
 case NEW: {
+  products.resize(1);
   if (ingredients.empty() || SIZE(ingredients) > 2) {
     raise << 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();
+    break;
   }
   // compute the space we need
   long long int size = 0;
@@ -88,7 +90,6 @@ case NEW: {
   const long long int result = Current_routine->alloc;
   trace(Primitive_recipe_depth, "mem") << "new alloc: " << result << end();
   // save result
-  products.resize(1);
   products.at(0).push_back(result);
   // initialize allocated space
   for (long long int address = result; address < result+size; ++address) {
diff --git a/053continuation.cc b/053continuation.cc
index 20cf1b05..5885fd40 100644
--- a/053continuation.cc
+++ b/053continuation.cc
@@ -193,6 +193,7 @@ REPLY_DELIMITED_CONTINUATION,
 Recipe_ordinal["reply-delimited-continuation"] = REPLY_DELIMITED_CONTINUATION;
 :(before "End Primitive Recipe Implementations")
 case REPLY_DELIMITED_CONTINUATION: {
+  products.resize(1);
   // first clear any existing ingredients, to isolate the creation of the
   // continuation from its calls
   Current_routine->calls.front().ingredient_atoms.clear();
@@ -210,7 +211,6 @@ case REPLY_DELIMITED_CONTINUATION: {
     Current_routine->calls.pop_front();
   }
   // return it as the result of the 'reset' call
-  products.resize(1);
   products.at(0).push_back(Next_delimited_continuation_id);
   ++Next_delimited_continuation_id;
   break;  // continue to process rest of 'reset' call
diff --git a/064random.cc b/064random.cc
index bd171132..cdc519c9 100644
--- a/064random.cc
+++ b/064random.cc
@@ -27,6 +27,7 @@ ROUND,
 Recipe_ordinal["round"] = ROUND;
 :(before "End Primitive Recipe Implementations")
 case ROUND: {
+  products.resize(1);
   if (SIZE(ingredients) != 1) {
     raise << current_recipe_name() << ": 'round' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
@@ -35,7 +36,6 @@ case ROUND: {
     raise << 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);
   products.at(0).push_back(rint(ingredients.at(0).at(0)));
   break;
 }
diff --git a/081run_interactive.cc b/081run_interactive.cc
index 242578c7..1f6c0407 100644
--- a/081run_interactive.cc
+++ b/081run_interactive.cc
@@ -26,6 +26,7 @@ Recipe_ordinal["run-interactive"] = RUN_INTERACTIVE;
 //? cerr << "run-interactive: " << RUN_INTERACTIVE << '\n'; //? 1
 :(before "End Primitive Recipe Implementations")
 case RUN_INTERACTIVE: {
+  products.resize(3);
   if (SIZE(ingredients) != 1) {
     raise << current_recipe_name() << ": 'run-interactive' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
@@ -34,7 +35,6 @@ case RUN_INTERACTIVE: {
     raise << current_recipe_name() << ": first ingredient of 'run-interactive' should be a literal string, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
-  products.resize(3);
   bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0));
   if (!new_code_pushed_to_stack) {
     products.at(0).push_back(0);
@@ -269,6 +269,7 @@ RELOAD,
 Recipe_ordinal["reload"] = RELOAD;
 :(before "End Primitive Recipe Implementations")
 case RELOAD: {
+  products.resize(1);
   if (SIZE(ingredients) != 1) {
     raise << current_recipe_name() << ": 'reload' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
@@ -289,7 +290,6 @@ case RELOAD: {
   Trace_stream->newline();  // flush trace
   Disable_redefine_warnings = false;
   Hide_warnings = false;
-  products.resize(1);
   products.at(0).push_back(warnings_from_trace());
   if (Trace_stream->collect_layer == "warn") {
     delete Trace_stream;
diff --git a/082persist.cc b/082persist.cc
index d663773c..d63176bd 100644
--- a/082persist.cc
+++ b/082persist.cc
@@ -8,13 +8,15 @@ RESTORE,
 Recipe_ordinal["restore"] = RESTORE;
 :(before "End Primitive Recipe Implementations")
 case RESTORE: {
+  products.resize(1);
   if (SIZE(ingredients) != 1) {
     raise << current_recipe_name() << ": 'restore' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
-  if (!scalar(ingredients.at(0)))
+  if (!scalar(ingredients.at(0))) {
     raise << current_recipe_name() << ": first ingredient of 'restore' should be a literal string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
-  products.resize(1);
+    break;
+  }
   if (Current_scenario) break;  // do nothing in tests
   string filename = current_instruction().ingredients.at(0).name;
   if (!is_literal(current_instruction().ingredients.at(0)))