From 6e1eeeebfb453fa7c871869c19375ce60fbd7413 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sat, 27 Jul 2019 16:01:55 -0700 Subject: 5485 - promote SubX to top-level --- html/011load.cc.html | 480 --------------------------------------------------- 1 file changed, 480 deletions(-) delete mode 100644 html/011load.cc.html (limited to 'html/011load.cc.html') diff --git a/html/011load.cc.html b/html/011load.cc.html deleted file mode 100644 index 15b930ca..00000000 --- a/html/011load.cc.html +++ /dev/null @@ -1,480 +0,0 @@ - - - - -Mu - 011load.cc - - - - - - - - - - -https://github.com/akkartik/mu/blob/master/011load.cc -
-  1 //: Phase 1 of running Mu code: load it from a textual representation.
-  2 //:
-  3 //: The process of running Mu code:
-  4 //:   load -> transform -> run
-  5 
-  6 :(scenarios load)  // use 'load' instead of 'run' in all scenarios in this layer
-  7 :(scenario first_recipe)
-  8 def main [
-  9   1:number <- copy 23
- 10 ]
- 11 +parse: instruction: copy
- 12 +parse:   ingredient: {23: "literal"}
- 13 +parse:   product: {1: "number"}
- 14 
- 15 :(code)
- 16 vector<recipe_ordinal> load(string form) {
- 17   istringstream in(form);
- 18   in >> std::noskipws;
- 19   return load(in);
- 20 }
- 21 
- 22 vector<recipe_ordinal> load(istream& in) {
- 23   in >> std::noskipws;
- 24   vector<recipe_ordinal> result;
- 25   while (has_data(in)) {
- 26     skip_whitespace_and_comments(in);
- 27     if (!has_data(in)) break;
- 28     string command = next_word(in);
- 29     if (command.empty()) {
- 30       assert(!has_data(in));
- 31       break;
- 32     }
- 33     // Command Handlers
- 34     if (command == "recipe" || command == "def") {
- 35       recipe_ordinal r = slurp_recipe(in);
- 36       if (r > 0) result.push_back(r);
- 37     }
- 38     else if (command == "recipe!" || command == "def!") {
- 39       Disable_redefine_checks = true;
- 40       recipe_ordinal r = slurp_recipe(in);
- 41       if (r > 0) result.push_back(r);
- 42       Disable_redefine_checks = false;
- 43     }
- 44     // End Command Handlers
- 45     else {
- 46       raise << "unknown top-level command: " << command << '\n' << end();
- 47     }
- 48   }
- 49   return result;
- 50 }
- 51 
- 52 // return the recipe ordinal slurped, or -1 if it failed
- 53 int slurp_recipe(istream& in) {
- 54   recipe result;
- 55   result.name = next_word(in);
- 56   if (result.name.empty()) {
- 57     assert(!has_data(in));
- 58     raise << "file ended with 'recipe'\n" << end();
- 59     return -1;
- 60   }
- 61   // End Load Recipe Name
- 62   skip_whitespace_but_not_newline(in);
- 63   // End Recipe Refinements
- 64   if (result.name.empty())
- 65     raise << "empty result.name\n" << end();
- 66   trace(9991, "parse") << "--- defining " << result.name << end();
- 67   if (!contains_key(Recipe_ordinal, result.name))
- 68     put(Recipe_ordinal, result.name, Next_recipe_ordinal);
- 69   result.ordinal = get(Recipe_ordinal, result.name);
- 70   ++Next_recipe_ordinal;
- 71   if (Recipe.find(get(Recipe_ordinal, result.name)) != Recipe.end()) {
- 72     trace(9991, "parse") << "already exists" << end();
- 73     if (should_check_for_redefine(result.name))
- 74       raise << "redefining recipe " << result.name << "\n" << end();
- 75     Recipe.erase(get(Recipe_ordinal, result.name));
- 76   }
- 77   slurp_body(in, result);
- 78   // End Recipe Body(result)
- 79   put(Recipe, get(Recipe_ordinal, result.name), result);
- 80   return get(Recipe_ordinal, result.name);
- 81 }
- 82 
- 83 void slurp_body(istream& in, recipe& result) {
- 84   in >> std::noskipws;
- 85   skip_whitespace_but_not_newline(in);
- 86   if (in.get() != '[')
- 87     raise << result.name << ": recipe body must begin with '['\n" << end();
- 88   skip_whitespace_and_comments(in);  // permit trailing comment after '['
- 89   instruction curr;
- 90   while (next_instruction(in, &curr)) {
- 91     curr.original_string = to_original_string(curr);
- 92     // End Rewrite Instruction(curr, recipe result)
- 93     trace(9992, "load") << "after rewriting: " << to_string(curr) << end();
- 94     if (!curr.is_empty()) result.steps.push_back(curr);
- 95   }
- 96 }
- 97 
- 98 bool next_instruction(istream& in, instruction* curr) {
- 99   curr->clear();
-100   skip_whitespace_and_comments(in);
-101   if (!has_data(in)) {
-102     raise << "incomplete recipe at end of file (0)\n" << end();
-103     return false;
-104   }
-105 
-106   vector<string> words;
-107   while (has_data(in) && in.peek() != '\n') {
-108     skip_whitespace_but_not_newline(in);
-109     if (!has_data(in)) {
-110       raise << "incomplete recipe at end of file (1)\n" << end();
-111       return false;
-112     }
-113     string word = next_word(in);
-114     if (word.empty()) {
-115       assert(!has_data(in));
-116       raise << "incomplete recipe at end of file (2)\n" << end();
-117       return false;
-118     }
-119     words.push_back(word);
-120     skip_whitespace_but_not_newline(in);
-121   }
-122   skip_whitespace_and_comments(in);
-123   if (SIZE(words) == 1 && words.at(0) == "]")
-124     return false;  // end of recipe
-125 
-126   if (SIZE(words) == 1 && is_label_word(words.at(0))) {
-127     curr->is_label = true;
-128     curr->label = words.at(0);
-129     trace(9993, "parse") << "label: " << curr->label << end();
-130     if (!has_data(in)) {
-131       raise << "incomplete recipe at end of file (3)\n" << end();
-132       return false;
-133     }
-134     return true;
-135   }
-136 
-137   vector<string>::iterator p = words.begin();
-138   if (find(words.begin(), words.end(), "<-") != words.end()) {
-139     for (;  *p != "<-";  ++p)
-140       curr->products.push_back(reagent(*p));
-141     ++p;  // skip <-
-142   }
-143 
-144   if (p == words.end()) {
-145     raise << "instruction prematurely ended with '<-'\n" << end();
-146     return false;
-147   }
-148   curr->name = *p;  ++p;
-149   // curr->operation will be set at transform time
-150 
-151   for (;  p != words.end();  ++p)
-152     curr->ingredients.push_back(reagent(*p));
-153 
-154   trace(9993, "parse") << "instruction: " << curr->name << end();
-155   trace(9993, "parse") << "  number of ingredients: " << SIZE(curr->ingredients) << end();
-156   for (vector<reagent>::iterator p = curr->ingredients.begin();  p != curr->ingredients.end();  ++p)
-157     trace(9993, "parse") << "  ingredient: " << to_string(*p) << end();
-158   for (vector<reagent>::iterator p = curr->products.begin();  p != curr->products.end();  ++p)
-159     trace(9993, "parse") << "  product: " << to_string(*p) << end();
-160   if (!has_data(in)) {
-161     raise << "9: unbalanced '[' for recipe\n" << end();
-162     return false;
-163   }
-164   // End next_instruction(curr)
-165   return true;
-166 }
-167 
-168 // can return empty string -- only if 'in' has no more data
-169 string next_word(istream& in) {
-170   skip_whitespace_but_not_newline(in);
-171   // End next_word Special-cases
-172   ostringstream out;
-173   slurp_word(in, out);
-174   skip_whitespace_and_comments_but_not_newline(in);
-175   string result = out.str();
-176   if (result != "[" && ends_with(result, '['))
-177     raise << "insert a space before '[' in '" << result << "'\n" << end();
-178   return result;
-179 }
-180 
-181 bool is_label_word(const string& word) {
-182   if (word.empty()) return false;  // error raised elsewhere
-183   return !isalnum(word.at(0)) && string("$_*@&,=-[]()").find(word.at(0)) == string::npos;
-184 }
-185 
-186 bool ends_with(const string& s, const char c) {
-187   if (s.empty()) return false;
-188   return *s.rbegin() == c;
-189 }
-190 
-191 :(before "End Globals")
-192 // word boundaries
-193 extern const string Terminators("(){}");
-194 :(code)
-195 void slurp_word(istream& in, ostream& out) {
-196   char c;
-197   if (has_data(in) && Terminators.find(in.peek()) != string::npos) {
-198     in >> c;
-199     out << c;
-200     return;
-201   }
-202   while (in >> c) {
-203     if (isspace(c) || Terminators.find(c) != string::npos || Ignore.find(c) != string::npos) {
-204       in.putback(c);
-205       break;
-206     }
-207     out << c;
-208   }
-209 }
-210 
-211 void skip_whitespace_and_comments(istream& in) {
-212   while (true) {
-213     if (!has_data(in)) break;
-214     if (isspace(in.peek())) in.get();
-215     else if (Ignore.find(in.peek()) != string::npos) in.get();
-216     else if (in.peek() == '#') skip_comment(in);
-217     else break;
-218   }
-219 }
-220 
-221 // confusing; move to the next line only to skip a comment, but never otherwise
-222 void skip_whitespace_and_comments_but_not_newline(istream& in) {
-223   while (true) {
-224     if (!has_data(in)) break;
-225     if (in.peek() == '\n') break;
-226     if (isspace(in.peek())) in.get();
-227     else if (Ignore.find(in.peek()) != string::npos) in.get();
-228     else if (in.peek() == '#') skip_comment(in);
-229     else break;
-230   }
-231 }
-232 
-233 void skip_comment(istream& in) {
-234   if (has_data(in) && in.peek() == '#') {
-235     in.get();
-236     while (has_data(in) && in.peek() != '\n') in.get();
-237   }
-238 }
-239 
-240 :(scenario recipe_instead_of_def)
-241 recipe main [
-242   1:number <- copy 23
-243 ]
-244 +parse: instruction: copy
-245 +parse:   ingredient: {23: "literal"}
-246 +parse:   product: {1: "number"}
-247 
-248 :(scenario parse_comment_outside_recipe)
-249 # this comment will be dropped by the tangler, so we need a dummy recipe to stop that
-250 def f1 [
-251 ]
-252 # this comment will go through to 'load'
-253 def main [
-254   1:number <- copy 23
-255 ]
-256 +parse: instruction: copy
-257 +parse:   ingredient: {23: "literal"}
-258 +parse:   product: {1: "number"}
-259 
-260 :(scenario parse_comment_amongst_instruction)
-261 def main [
-262   # comment
-263   1:number <- copy 23
-264 ]
-265 +parse: instruction: copy
-266 +parse:   ingredient: {23: "literal"}
-267 +parse:   product: {1: "number"}
-268 
-269 :(scenario parse_comment_amongst_instruction_2)
-270 def main [
-271   # comment
-272   1:number <- copy 23
-273   # comment
-274 ]
-275 +parse: instruction: copy
-276 +parse:   ingredient: {23: "literal"}
-277 +parse:   product: {1: "number"}
-278 
-279 :(scenario parse_comment_amongst_instruction_3)
-280 def main [
-281   1:number <- copy 23
-282   # comment
-283   2:number <- copy 23
-284 ]
-285 +parse: instruction: copy
-286 +parse:   ingredient: {23: "literal"}
-287 +parse:   product: {1: "number"}
-288 +parse: instruction: copy
-289 +parse:   ingredient: {23: "literal"}
-290 +parse:   product: {2: "number"}
-291 
-292 :(scenario parse_comment_after_instruction)
-293 def main [
-294   1:number <- copy 23  # comment
-295 ]
-296 +parse: instruction: copy
-297 +parse:   ingredient: {23: "literal"}
-298 +parse:   product: {1: "number"}
-299 
-300 :(scenario parse_label)
-301 def main [
-302   +foo
-303 ]
-304 +parse: label: +foo
-305 
-306 :(scenario parse_dollar_as_recipe_name)
-307 def main [
-308   $foo
-309 ]
-310 +parse: instruction: $foo
-311 
-312 :(scenario parse_multiple_properties)
-313 def main [
-314   1:number <- copy 23/foo:bar:baz
-315 ]
-316 +parse: instruction: copy
-317 +parse:   ingredient: {23: "literal", "foo": ("bar" "baz")}
-318 +parse:   product: {1: "number"}
-319 
-320 :(scenario parse_multiple_products)
-321 def main [
-322   1:number, 2:number <- copy 23
-323 ]
-324 +parse: instruction: copy
-325 +parse:   ingredient: {23: "literal"}
-326 +parse:   product: {1: "number"}
-327 +parse:   product: {2: "number"}
-328 
-329 :(scenario parse_multiple_ingredients)
-330 def main [
-331   1:number, 2:number <- copy 23, 4:number
-332 ]
-333 +parse: instruction: copy
-334 +parse:   ingredient: {23: "literal"}
-335 +parse:   ingredient: {4: "number"}
-336 +parse:   product: {1: "number"}
-337 +parse:   product: {2: "number"}
-338 
-339 :(scenario parse_multiple_types)
-340 def main [
-341   1:number, 2:address:number <- copy 23, 4:number
-342 ]
-343 +parse: instruction: copy
-344 +parse:   ingredient: {23: "literal"}
-345 +parse:   ingredient: {4: "number"}
-346 +parse:   product: {1: "number"}
-347 +parse:   product: {2: ("address" "number")}
-348 
-349 :(scenario parse_properties)
-350 def main [
-351   1:address:number/lookup <- copy 23
-352 ]
-353 +parse:   product: {1: ("address" "number"), "lookup": ()}
-354 
-355 //: this test we can't represent with a scenario
-356 :(code)
-357 void test_parse_comment_terminated_by_eof() {
-358   load("recipe main [\n"
-359        "  a:number <- copy 34\n"
-360        "]\n"
-361        "# abc");  // no newline after comment
-362   cerr << ".";  // termination = success
-363 }
-364 
-365 :(scenario warn_on_missing_space_before_bracket)
-366 % Hide_errors = true;
-367 def main[
-368   1:number <- copy 23
-369 ]
-370 +error: insert a space before '[' in 'main['
-371 
-372 //: Warn if a recipe gets redefined, because large codebases can accidentally
-373 //: step on their own toes. But there'll be many occasions later where
-374 //: we'll want to disable the errors.
-375 :(before "End Globals")
-376 bool Disable_redefine_checks = false;
-377 :(before "End Reset")
-378 Disable_redefine_checks = false;
-379 :(code)
-380 bool should_check_for_redefine(const string& recipe_name) {
-381   if (Disable_redefine_checks) return false;
-382   return true;
-383 }
-384 
-385 :(scenario forbid_redefining_recipes)
-386 % Hide_errors = true;
-387 def main [
-388   1:number <- copy 23
-389 ]
-390 def main [
-391   1:number <- copy 24
-392 ]
-393 +error: redefining recipe main
-394 
-395 :(scenario permit_forcibly_redefining_recipes)
-396 def main [
-397   1:number <- copy 23
-398 ]
-399 def! main [
-400   1:number <- copy 24
-401 ]
-402 -error: redefining recipe main
-403 $error: 0
-404 
-405 :(code)
-406 // for debugging
-407 void show_rest_of_stream(istream& in) {
-408   cerr << '^';
-409   char c;
-410   while (in >> c)
-411     cerr << c;
-412   cerr << "$\n";
-413   exit(0);
-414 }
-
- - - -- cgit 1.4.1-2-gfad0