diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2016-10-21 01:08:09 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2016-10-21 01:13:27 -0700 |
commit | 66abe7c1bd54ca227b9e035d52a1c2f1ea387b5e (patch) | |
tree | 9fc885faa5b4878247d4411bd0d72c1c59cc5f92 /011load.cc | |
parent | 22d93b76718a9e260c1969adf53fc0559cf24355 (diff) | |
download | mu-66abe7c1bd54ca227b9e035d52a1c2f1ea387b5e.tar.gz |
3539
Always check if next_word() returned an empty string (if it hit eof). Thanks Rebecca Allard for running into a crash when a .mu file ends with '{' (without a following newline). Open question: how to express the constraint that next_word() should always check if its result is empty? Can *any* type system do that?! Even the usual constraint that we must use a result isn't iron-clad: you could save the result in a variable but then ignore it. Unless you go to Go's extraordinary lengths of considering any dead code an error.
Diffstat (limited to '011load.cc')
-rw-r--r-- | 011load.cc | 21 |
1 files changed, 18 insertions, 3 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 |