about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--011load.cc21
-rw-r--r--016dilated_reagent.cc21
-rw-r--r--017parse_tree.cc22
-rw-r--r--030container.cc10
-rw-r--r--050scenario.cc30
-rw-r--r--052tangle.cc10
-rw-r--r--053recipe_header.cc10
-rw-r--r--089scenario_filesystem.cc15
8 files changed, 130 insertions, 9 deletions
diff --git a/011load.cc b/011load.cc
index 9dc54922..23126647 100644
--- a/011load.cc
+++ b/011load.cc
@@ -26,6 +26,10 @@ vector<recipe_ordinal> load(istream& in) {
     skip_whitespace_and_comments(in);
     if (!has_data(in)) break;
     string command = next_word(in);
+    if (command.empty()) {
+      assert(!has_data(in));
+      break;
+    }
     // Command Handlers
     if (command == "recipe" || command == "def") {
       recipe_ordinal r = slurp_recipe(in);
@@ -50,6 +54,11 @@ vector<recipe_ordinal> load(istream& in) {
 int slurp_recipe(istream& in) {
   recipe result;
   result.name = next_word(in);
+  if (result.name.empty()) {
+    assert(!has_data(in));
+    raise << "file ended with 'recipe'\n" << end();
+    return -1;
+  }
   // End Load Recipe Name
   skip_whitespace_but_not_newline(in);
   // End Recipe Refinements
@@ -89,7 +98,7 @@ bool next_instruction(istream& in, instruction* curr) {
   curr->clear();
   skip_whitespace_and_comments(in);
   if (!has_data(in)) {
-    raise << "0: unbalanced '[' for recipe\n" << end();
+    raise << "incomplete recipe at end of file (0)\n" << end();
     return false;
   }
 
@@ -97,10 +106,15 @@ bool next_instruction(istream& in, instruction* curr) {
   while (has_data(in) && in.peek() != '\n') {
     skip_whitespace_but_not_newline(in);
     if (!has_data(in)) {
-      raise << "1: unbalanced '[' for recipe\n" << end();
+      raise << "incomplete recipe at end of file (1)\n" << end();
       return false;
     }
     string word = next_word(in);
+    if (word.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete recipe at end of file (2)\n" << end();
+      return false;
+    }
     words.push_back(word);
     skip_whitespace_but_not_newline(in);
   }
@@ -113,7 +127,7 @@ bool next_instruction(istream& in, instruction* curr) {
     curr->label = words.at(0);
     trace(9993, "parse") << "label: " << curr->label << end();
     if (!has_data(in)) {
-      raise << "7: unbalanced '[' for recipe\n" << end();
+      raise << "incomplete recipe at end of file (3)\n" << end();
       return false;
     }
     return true;
@@ -149,6 +163,7 @@ bool next_instruction(istream& in, instruction* curr) {
   return true;
 }
 
+// can return empty string -- only if `in` has no more data
 string next_word(istream& in) {
   skip_whitespace_but_not_newline(in);
   // End next_word Special-cases
diff --git a/016dilated_reagent.cc b/016dilated_reagent.cc
index b7c8ecc4..1d89ba8d 100644
--- a/016dilated_reagent.cc
+++ b/016dilated_reagent.cc
@@ -107,7 +107,13 @@ if (starts_with(s, "{")) {
     return;
   }
   {
-    string_tree* type_names = new string_tree(next_word(in));
+    string s = next_word(in);
+    if (s.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete dilated reagent at end of file (0)\n" << end();
+      return;
+    }
+    string_tree* type_names = new string_tree(s);
     // End Parsing Dilated Reagent Type Property(type_names)
     type = new_type_tree(type_names);
     delete type_names;
@@ -116,7 +122,13 @@ if (starts_with(s, "{")) {
     string key = slurp_key(in);
     if (key.empty()) continue;
     if (key == "}") continue;
-    string_tree* value = new string_tree(next_word(in));
+    string s = next_word(in);
+    if (s.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete dilated reagent at end of file (1)\n" << end();
+      return;
+    }
+    string_tree* value = new string_tree(s);
     // End Parsing Dilated Reagent Property(value)
     properties.push_back(pair<string, string_tree*>(key, value));
   }
@@ -126,6 +138,11 @@ if (starts_with(s, "{")) {
 :(code)
 string slurp_key(istream& in) {
   string result = next_word(in);
+  if (result.empty()) {
+    assert(!has_data(in));
+    raise << "incomplete dilated reagent at end of file (2)\n" << end();
+    return result;
+  }
   while (!result.empty() && *result.rbegin() == ':')
     strip_last(result);
   while (isspace(in.peek()) || in.peek() == ':')
diff --git a/017parse_tree.cc b/017parse_tree.cc
index c7e7473b..eb1fb85d 100644
--- a/017parse_tree.cc
+++ b/017parse_tree.cc
@@ -46,7 +46,13 @@ string_tree* parse_string_tree(istream& in) {
     return NULL;
   }
   if (in.peek() != '(') {
-    string_tree* result = new string_tree(next_word(in));
+    string s = next_word(in);
+    if (s.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete string tree at end of file (0)\n" << end();
+      return NULL;
+    }
+    string_tree* result = new string_tree(s);
     return result;
   }
   in.get();  // skip '('
@@ -57,10 +63,18 @@ string_tree* parse_string_tree(istream& in) {
     assert(has_data(in));
     if (in.peek() == ')') break;
     *curr = new string_tree(NULL, NULL);
-    if (in.peek() == '(')
+    if (in.peek() == '(') {
       (*curr)->left = parse_string_tree(in);
-    else
-      (*curr)->left = new string_tree(next_word(in));
+    }
+    else {
+      string s = next_word(in);
+      if (s.empty()) {
+        assert(!has_data(in));
+        raise << "incomplete string tree at end of file (1)\n" << end();
+        return NULL;
+      }
+      (*curr)->left = new string_tree(s);
+    }
     curr = &(*curr)->right;
   }
   in.get();  // skip ')'
diff --git a/030container.cc b/030container.cc
index 110a8970..6abbbcc6 100644
--- a/030container.cc
+++ b/030container.cc
@@ -721,6 +721,11 @@ Num_calls_to_transform_all_at_first_definition = -1;
 void insert_container(const string& command, kind_of_type kind, istream& in) {
   skip_whitespace_but_not_newline(in);
   string name = next_word(in);
+  if (name.empty()) {
+    assert(!has_data(in));
+    raise << "incomplete container definition at end of file (0)\n" << end();
+    return;
+  }
   // End container Name Refinements
   trace(9991, "parse") << "--- defining " << command << ' ' << name << end();
   if (!contains_key(Type_ordinal, name)
@@ -744,6 +749,11 @@ void insert_container(const string& command, kind_of_type kind, istream& in) {
   while (has_data(in)) {
     skip_whitespace_and_comments(in);
     string element = next_word(in);
+    if (element.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete container definition at end of file (1)\n" << end();
+      return;
+    }
     if (element == "]") break;
     if (in.peek() != '\n') {
       raise << command << " '" << name << "' contains multiple elements on a single line. Containers and exclusive containers must only contain elements, one to a line, no code.\n" << end();
diff --git a/050scenario.cc b/050scenario.cc
index 2e0d1ca7..a4f57cf5 100644
--- a/050scenario.cc
+++ b/050scenario.cc
@@ -78,6 +78,11 @@ else if (command == "pending-scenario") {
 scenario parse_scenario(istream& in) {
   scenario result;
   result.name = next_word(in);
+  if (result.name.empty()) {
+    assert(!has_data(in));
+    raise << "incomplete scenario at end of file\n" << end();
+    return result;
+  }
   skip_whitespace_and_comments(in);
   if (in.peek() != '[') {
     raise << "Expected '[' after scenario '" << result.name << "'\n" << end();
@@ -329,6 +334,11 @@ void check_memory(const string& s) {
     skip_whitespace_and_comments(in);
     if (!has_data(in)) break;
     string lhs = next_word(in);
+    if (lhs.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete 'memory-should-contain' block at end of file (0)\n" << end();
+      return;
+    }
     if (!is_integer(lhs)) {
       check_type(lhs, in);
       continue;
@@ -338,6 +348,11 @@ void check_memory(const string& s) {
     string _assign;  in >> _assign;  assert(_assign == "<-");
     skip_whitespace_and_comments(in);
     string rhs = next_word(in);
+    if (rhs.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete 'memory-should-contain' block at end of file (1)\n" << end();
+      return;
+    }
     if (!is_integer(rhs) && !is_noninteger(rhs)) {
       if (Current_scenario && !Scenario_testing_scenario)
         // genuine test in a mu file
@@ -374,9 +389,19 @@ void check_type(const string& lhs, istream& in) {
     x.set_value(to_integer(x.name));
     skip_whitespace_and_comments(in);
     string _assign = next_word(in);
+    if (_assign.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete 'memory-should-contain' block at end of file (2)\n" << end();
+      return;
+    }
     assert(_assign == "<-");
     skip_whitespace_and_comments(in);
     string literal = next_word(in);
+    if (literal.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete 'memory-should-contain' block at end of file (3)\n" << end();
+      return;
+    }
     int address = x.value;
     // exclude quoting brackets
     assert(*literal.begin() == '[');  literal.erase(literal.begin());
@@ -750,6 +775,11 @@ void run_mu_scenario(const string& form) {
   in >> std::noskipws;
   skip_whitespace_and_comments(in);
   string _scenario = next_word(in);
+  if (_scenario.empty()) {
+    assert(!has_data(in));
+    raise << "no scenario in string passed into run_mu_scenario()\n" << end();
+    return;
+  }
   assert(_scenario == "scenario");
   scenario s = parse_scenario(in);
   run_mu_scenario(s);
diff --git a/052tangle.cc b/052tangle.cc
index 50c74076..8aaecbd1 100644
--- a/052tangle.cc
+++ b/052tangle.cc
@@ -34,6 +34,11 @@ Fragments_used.clear();
 :(before "End Command Handlers")
 else if (command == "before") {
   string label = next_word(in);
+  if (label.empty()) {
+    assert(!has_data(in));
+    raise << "incomplete 'before' block at end of file\n" << end();
+    return result;
+  }
   recipe tmp;
   slurp_body(in, tmp);
   if (is_waypoint(label))
@@ -44,6 +49,11 @@ else if (command == "before") {
 }
 else if (command == "after") {
   string label = next_word(in);
+  if (label.empty()) {
+    assert(!has_data(in));
+    raise << "incomplete 'after' block at end of file\n" << end();
+    return result;
+  }
   recipe tmp;
   slurp_body(in, tmp);
   if (is_waypoint(label))
diff --git a/053recipe_header.cc b/053recipe_header.cc
index b23614c8..450a0142 100644
--- a/053recipe_header.cc
+++ b/053recipe_header.cc
@@ -33,6 +33,11 @@ void load_recipe_header(istream& in, recipe& result) {
   result.has_header = true;
   while (has_data(in) && in.peek() != '[' && in.peek() != '\n') {
     string s = next_word(in);
+    if (s.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete recipe header at end of file (0)\n" << end();
+      return;
+    }
     if (s == "<-")
       raise << "recipe " << result.name << " should say '->' and not '<-'\n" << end();
     if (s == "->") break;
@@ -42,6 +47,11 @@ void load_recipe_header(istream& in, recipe& result) {
   }
   while (has_data(in) && in.peek() != '[' && in.peek() != '\n') {
     string s = next_word(in);
+    if (s.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete recipe header at end of file (1)\n" << end();
+      return;
+    }
     result.products.push_back(reagent(s));
     trace(9999, "parse") << "header product: " << result.products.back().original_string << end();
     skip_whitespace_but_not_newline(in);
diff --git a/089scenario_filesystem.cc b/089scenario_filesystem.cc
index c761ee93..6af3166b 100644
--- a/089scenario_filesystem.cc
+++ b/089scenario_filesystem.cc
@@ -115,6 +115,11 @@ void parse_resources(const string& data, map<string, string>& out, const string&
     skip_whitespace_and_comments(in);
     if (!has_data(in)) break;
     string filename = next_word(in);
+    if (filename.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete 'resources' block at end of file (0)\n" << end();
+      return;
+    }
     if (*filename.begin() != '[') {
       raise << caller << ": assume-resources: filename '" << filename << "' must begin with a '['\n" << end();
       break;
@@ -130,6 +135,11 @@ void parse_resources(const string& data, map<string, string>& out, const string&
       break;
     }
     string arrow = next_word(in);
+    if (arrow.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete 'resources' block at end of file (1)\n" << end();
+      return;
+    }
     if (arrow != "<-") {
       raise << caller << ": assume-resources: expected '<-' after filename '" << filename << "' but got '" << arrow << "'\n" << end();
       break;
@@ -139,6 +149,11 @@ void parse_resources(const string& data, map<string, string>& out, const string&
       break;
     }
     string contents = next_word(in);
+    if (contents.empty()) {
+      assert(!has_data(in));
+      raise << "incomplete 'resources' block at end of file (2)\n" << end();
+      return;
+    }
     if (*contents.begin() != '[') {
       raise << caller << ": assume-resources: file contents '" << contents << "' for filename '" << filename << "' must begin with a '['\n" << end();
       break;