2015-04-24 07:28:24 +00:00
|
|
|
//: Phase 1 of running mu code: load it from a textual representation.
|
2015-04-17 18:22:59 +00:00
|
|
|
|
2015-05-27 18:27:50 +00:00
|
|
|
:(scenarios load) // use 'load' instead of 'run' in all scenarios in this layer
|
2015-02-18 18:56:19 +00:00
|
|
|
:(scenario first_recipe)
|
2015-02-18 18:49:46 +00:00
|
|
|
recipe main [
|
2015-07-28 21:33:22 +00:00
|
|
|
1:number <- copy 23
|
2015-02-18 18:49:46 +00:00
|
|
|
]
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal"}
|
|
|
|
+parse: product: {"1": "number"}
|
2015-02-18 18:49:46 +00:00
|
|
|
|
|
|
|
:(code)
|
2015-07-04 16:40:50 +00:00
|
|
|
vector<recipe_ordinal> load(string form) {
|
2015-02-18 18:49:46 +00:00
|
|
|
istringstream in(form);
|
2015-04-06 17:14:29 +00:00
|
|
|
in >> std::noskipws;
|
2015-04-24 07:28:24 +00:00
|
|
|
return load(in);
|
2015-04-06 18:33:29 +00:00
|
|
|
}
|
|
|
|
|
2015-07-04 16:40:50 +00:00
|
|
|
vector<recipe_ordinal> load(istream& in) {
|
2015-06-15 20:58:08 +00:00
|
|
|
in >> std::noskipws;
|
2015-07-04 16:40:50 +00:00
|
|
|
vector<recipe_ordinal> result;
|
2015-04-06 17:20:54 +00:00
|
|
|
while (!in.eof()) {
|
2015-05-02 22:50:59 +00:00
|
|
|
skip_whitespace_and_comments(in);
|
2015-04-06 17:20:54 +00:00
|
|
|
if (in.eof()) break;
|
|
|
|
string command = next_word(in);
|
|
|
|
// Command Handlers
|
2015-04-06 19:02:38 +00:00
|
|
|
if (command == "recipe") {
|
2015-09-05 16:51:46 +00:00
|
|
|
result.push_back(slurp_recipe(in));
|
|
|
|
}
|
|
|
|
else if (command == "recipe!") {
|
|
|
|
Disable_redefine_warnings = true;
|
|
|
|
result.push_back(slurp_recipe(in));
|
|
|
|
Disable_redefine_warnings = false;
|
2015-04-06 19:02:38 +00:00
|
|
|
}
|
2015-04-06 17:20:54 +00:00
|
|
|
// End Command Handlers
|
2015-04-06 19:02:38 +00:00
|
|
|
else {
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "unknown top-level command: " << command << '\n' << end();
|
2015-04-06 19:02:38 +00:00
|
|
|
}
|
2015-04-06 17:20:54 +00:00
|
|
|
}
|
2015-03-14 00:39:32 +00:00
|
|
|
return result;
|
|
|
|
}
|
2015-02-18 18:49:46 +00:00
|
|
|
|
2015-09-05 16:51:46 +00:00
|
|
|
long long int slurp_recipe(istream& in) {
|
|
|
|
string recipe_name = next_word(in);
|
|
|
|
if (recipe_name.empty())
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "empty recipe name\n" << end();
|
2015-09-05 16:51:46 +00:00
|
|
|
if (Recipe_ordinal.find(recipe_name) == Recipe_ordinal.end()) {
|
|
|
|
Recipe_ordinal[recipe_name] = Next_recipe_ordinal++;
|
|
|
|
}
|
2015-10-26 04:42:18 +00:00
|
|
|
if (Recipe.find(Recipe_ordinal[recipe_name]) != Recipe.end()) {
|
|
|
|
if (warn_on_redefine(recipe_name))
|
|
|
|
raise << "redefining recipe " << Recipe[Recipe_ordinal[recipe_name]].name << "\n" << end();
|
|
|
|
Recipe.erase(Recipe_ordinal[recipe_name]);
|
2015-09-05 16:51:46 +00:00
|
|
|
}
|
|
|
|
// todo: save user-defined recipes to mu's memory
|
|
|
|
Recipe[Recipe_ordinal[recipe_name]] = slurp_body(in);
|
|
|
|
Recipe[Recipe_ordinal[recipe_name]].name = recipe_name;
|
|
|
|
// track added recipes because we may need to undo them in tests; see below
|
|
|
|
recently_added_recipes.push_back(Recipe_ordinal[recipe_name]);
|
|
|
|
return Recipe_ordinal[recipe_name];
|
|
|
|
}
|
|
|
|
|
2015-09-05 16:44:35 +00:00
|
|
|
recipe slurp_body(istream& in) {
|
2015-10-25 21:57:40 +00:00
|
|
|
in >> std::noskipws;
|
2015-05-06 06:50:50 +00:00
|
|
|
recipe result;
|
2015-03-31 04:22:29 +00:00
|
|
|
skip_whitespace(in);
|
|
|
|
if (in.get() != '[')
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "recipe body must begin with '['\n" << end();
|
2015-05-02 22:50:59 +00:00
|
|
|
skip_whitespace_and_comments(in);
|
2015-02-18 18:49:46 +00:00
|
|
|
instruction curr;
|
|
|
|
while (next_instruction(in, &curr)) {
|
2015-05-04 17:31:52 +00:00
|
|
|
// End Rewrite Instruction(curr)
|
2015-05-06 06:50:50 +00:00
|
|
|
result.steps.push_back(curr);
|
2015-02-18 18:49:46 +00:00
|
|
|
}
|
2015-05-06 06:50:50 +00:00
|
|
|
return result;
|
2015-02-18 18:49:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool next_instruction(istream& in, instruction* curr) {
|
|
|
|
curr->clear();
|
2015-08-20 05:13:15 +00:00
|
|
|
if (in.eof()) {
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "0: unbalanced '[' for recipe\n" << end();
|
2015-08-20 05:13:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
skip_whitespace(in);
|
|
|
|
if (in.eof()) {
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "1: unbalanced '[' for recipe\n" << end();
|
2015-08-20 05:13:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
skip_whitespace_and_comments(in);
|
|
|
|
if (in.eof()) {
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "2: unbalanced '[' for recipe\n" << end();
|
2015-08-20 05:13:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-02-18 18:49:46 +00:00
|
|
|
|
|
|
|
vector<string> words;
|
2015-08-20 05:13:15 +00:00
|
|
|
while (in.peek() != '\n' && !in.eof()) {
|
|
|
|
skip_whitespace(in);
|
|
|
|
if (in.eof()) {
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "3: unbalanced '[' for recipe\n" << end();
|
2015-08-20 05:13:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
string word = next_word(in);
|
2015-02-18 18:49:46 +00:00
|
|
|
words.push_back(word);
|
2015-08-20 05:13:15 +00:00
|
|
|
skip_whitespace(in);
|
2015-02-18 18:49:46 +00:00
|
|
|
}
|
2015-08-20 05:13:15 +00:00
|
|
|
skip_whitespace_and_comments(in);
|
2015-05-17 09:22:41 +00:00
|
|
|
if (SIZE(words) == 1 && words.at(0) == "]") {
|
2015-03-14 00:39:32 +00:00
|
|
|
return false; // end of recipe
|
|
|
|
}
|
|
|
|
|
2015-05-17 09:22:41 +00:00
|
|
|
if (SIZE(words) == 1 && !isalnum(words.at(0).at(0)) && words.at(0).at(0) != '$') {
|
2015-02-18 18:49:46 +00:00
|
|
|
curr->is_label = true;
|
2015-05-07 22:49:40 +00:00
|
|
|
curr->label = words.at(0);
|
2015-07-25 07:02:20 +00:00
|
|
|
trace("parse") << "label: " << curr->label << end();
|
2015-08-20 05:13:15 +00:00
|
|
|
if (in.eof()) {
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "7: unbalanced '[' for recipe\n" << end();
|
2015-08-20 05:13:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2015-02-18 18:49:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vector<string>::iterator p = words.begin();
|
|
|
|
if (find(words.begin(), words.end(), "<-") != words.end()) {
|
|
|
|
for (; *p != "<-"; ++p) {
|
|
|
|
if (*p == ",") continue;
|
|
|
|
curr->products.push_back(reagent(*p));
|
|
|
|
}
|
|
|
|
++p; // skip <-
|
|
|
|
}
|
|
|
|
|
2015-07-25 07:02:20 +00:00
|
|
|
if (p == words.end()) {
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "instruction prematurely ended with '<-'\n" << end();
|
2015-07-25 07:02:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-03-17 06:41:01 +00:00
|
|
|
curr->name = *p;
|
2015-07-04 16:40:50 +00:00
|
|
|
if (Recipe_ordinal.find(*p) == Recipe_ordinal.end()) {
|
|
|
|
Recipe_ordinal[*p] = Next_recipe_ordinal++;
|
2015-04-08 06:48:22 +00:00
|
|
|
}
|
2015-07-04 16:40:50 +00:00
|
|
|
if (Recipe_ordinal[*p] == 0) {
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "Recipe " << *p << " has number 0, which is reserved for IDLE.\n" << end();
|
2015-07-25 07:02:20 +00:00
|
|
|
return false;
|
2015-04-08 06:48:22 +00:00
|
|
|
}
|
2015-07-04 16:40:50 +00:00
|
|
|
curr->operation = Recipe_ordinal[*p]; ++p;
|
2015-02-18 18:49:46 +00:00
|
|
|
|
|
|
|
for (; p != words.end(); ++p) {
|
|
|
|
if (*p == ",") continue;
|
|
|
|
curr->ingredients.push_back(reagent(*p));
|
|
|
|
}
|
|
|
|
|
2015-07-25 07:02:20 +00:00
|
|
|
trace("parse") << "instruction: " << curr->name << end();
|
2015-02-18 18:49:46 +00:00
|
|
|
for (vector<reagent>::iterator p = curr->ingredients.begin(); p != curr->ingredients.end(); ++p) {
|
2015-07-25 07:02:20 +00:00
|
|
|
trace("parse") << " ingredient: " << p->to_string() << end();
|
2015-02-18 18:49:46 +00:00
|
|
|
}
|
|
|
|
for (vector<reagent>::iterator p = curr->products.begin(); p != curr->products.end(); ++p) {
|
2015-07-25 07:02:20 +00:00
|
|
|
trace("parse") << " product: " << p->to_string() << end();
|
2015-02-18 18:49:46 +00:00
|
|
|
}
|
2015-08-20 05:13:15 +00:00
|
|
|
if (in.eof()) {
|
2015-10-07 05:15:45 +00:00
|
|
|
raise_error << "9: unbalanced '[' for recipe\n" << end();
|
2015-08-20 05:13:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2015-02-18 18:49:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string next_word(istream& in) {
|
|
|
|
skip_whitespace(in);
|
2015-10-27 18:31:05 +00:00
|
|
|
// End next_word Special-cases
|
|
|
|
ostringstream out;
|
2015-02-18 18:49:46 +00:00
|
|
|
slurp_word(in, out);
|
2015-03-17 05:47:28 +00:00
|
|
|
skip_whitespace(in);
|
|
|
|
skip_comment(in);
|
2015-02-18 18:49:46 +00:00
|
|
|
return out.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
void slurp_word(istream& in, ostream& out) {
|
2015-10-27 03:54:45 +00:00
|
|
|
static string terminators(",()[]{}");
|
2015-02-18 18:49:46 +00:00
|
|
|
char c;
|
2015-10-27 03:54:45 +00:00
|
|
|
if (!in.eof() && terminators.find(in.peek()) != string::npos) {
|
2015-02-18 18:49:46 +00:00
|
|
|
in >> c;
|
|
|
|
out << c;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (in >> c) {
|
2015-10-27 03:54:45 +00:00
|
|
|
if (isspace(c) || terminators.find(c) != string::npos) {
|
2015-02-18 18:49:46 +00:00
|
|
|
in.putback(c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
out << c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-02 22:50:59 +00:00
|
|
|
void skip_whitespace_and_comments(istream& in) {
|
|
|
|
while (true) {
|
2015-09-03 04:18:58 +00:00
|
|
|
if (in.eof()) break;
|
2015-05-02 22:50:59 +00:00
|
|
|
if (isspace(in.peek())) in.get();
|
|
|
|
else if (in.peek() == '#') skip_comment(in);
|
|
|
|
else break;
|
2015-02-21 04:32:05 +00:00
|
|
|
}
|
2015-02-18 18:49:46 +00:00
|
|
|
}
|
|
|
|
|
2015-03-17 05:47:28 +00:00
|
|
|
void skip_comment(istream& in) {
|
2015-09-03 04:18:58 +00:00
|
|
|
if (!in.eof() && in.peek() == '#') {
|
2015-03-17 05:47:28 +00:00
|
|
|
in.get();
|
2015-09-03 04:18:58 +00:00
|
|
|
while (!in.eof() && in.peek() != '\n') in.get();
|
2015-03-17 05:47:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-25 03:41:39 +00:00
|
|
|
//: Warn if a recipe gets redefined, because large codebases can accidentally
|
|
|
|
//: step on their own toes. But there'll be many occasions later where
|
|
|
|
//: we'll want to disable the warnings.
|
|
|
|
:(before "End Globals")
|
2015-07-25 07:24:12 +00:00
|
|
|
bool Disable_redefine_warnings = false;
|
2015-07-25 03:41:39 +00:00
|
|
|
:(before "End Setup")
|
2015-07-25 07:24:12 +00:00
|
|
|
Disable_redefine_warnings = false;
|
2015-07-25 07:20:35 +00:00
|
|
|
:(code)
|
|
|
|
bool warn_on_redefine(const string& recipe_name) {
|
2015-07-25 07:24:12 +00:00
|
|
|
if (Disable_redefine_warnings) return false;
|
2015-07-25 07:20:35 +00:00
|
|
|
return true;
|
2015-07-25 03:41:39 +00:00
|
|
|
}
|
|
|
|
|
2015-05-02 22:50:59 +00:00
|
|
|
// for debugging
|
|
|
|
:(code)
|
|
|
|
void show_rest_of_stream(istream& in) {
|
|
|
|
cerr << '^';
|
|
|
|
char c;
|
|
|
|
while (in >> c) {
|
|
|
|
cerr << c;
|
|
|
|
}
|
|
|
|
cerr << "$\n";
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2015-04-08 08:15:41 +00:00
|
|
|
//: Have tests clean up any recipes they added.
|
2015-04-08 08:02:42 +00:00
|
|
|
:(before "End Globals")
|
2015-07-04 16:40:50 +00:00
|
|
|
vector<recipe_ordinal> recently_added_recipes;
|
2015-08-22 00:17:54 +00:00
|
|
|
long long int Reserved_for_tests = 1000;
|
2015-04-08 08:02:42 +00:00
|
|
|
:(before "End Setup")
|
2015-05-17 09:22:41 +00:00
|
|
|
for (long long int i = 0; i < SIZE(recently_added_recipes); ++i) {
|
2015-08-17 02:13:45 +00:00
|
|
|
if (recently_added_recipes.at(i) >= Reserved_for_tests) // don't renumber existing recipes, like 'interactive'
|
|
|
|
Recipe_ordinal.erase(Recipe[recently_added_recipes.at(i)].name);
|
2015-05-07 22:49:40 +00:00
|
|
|
Recipe.erase(recently_added_recipes.at(i));
|
2015-04-08 08:02:42 +00:00
|
|
|
}
|
2015-04-13 03:47:49 +00:00
|
|
|
// Clear Other State For recently_added_recipes
|
2015-04-08 08:02:42 +00:00
|
|
|
recently_added_recipes.clear();
|
|
|
|
|
2015-10-27 03:00:38 +00:00
|
|
|
:(code)
|
2015-03-17 05:47:28 +00:00
|
|
|
:(scenario parse_comment_outside_recipe)
|
2015-05-02 22:26:13 +00:00
|
|
|
# this comment will be dropped by the tangler, so we need a dummy recipe to stop that
|
|
|
|
recipe f1 [ ]
|
|
|
|
# this comment will go through to 'load'
|
2015-03-17 05:47:28 +00:00
|
|
|
recipe main [
|
2015-07-28 21:33:22 +00:00
|
|
|
1:number <- copy 23
|
2015-03-17 05:47:28 +00:00
|
|
|
]
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal"}
|
|
|
|
+parse: product: {"1": "number"}
|
2015-03-17 05:47:28 +00:00
|
|
|
|
|
|
|
:(scenario parse_comment_amongst_instruction)
|
|
|
|
recipe main [
|
|
|
|
# comment
|
2015-07-28 21:33:22 +00:00
|
|
|
1:number <- copy 23
|
2015-03-17 05:47:28 +00:00
|
|
|
]
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal"}
|
|
|
|
+parse: product: {"1": "number"}
|
2015-03-17 05:47:28 +00:00
|
|
|
|
2015-08-09 19:26:31 +00:00
|
|
|
:(scenario parse_comment_amongst_instruction_2)
|
2015-03-17 05:47:28 +00:00
|
|
|
recipe main [
|
|
|
|
# comment
|
2015-07-28 21:33:22 +00:00
|
|
|
1:number <- copy 23
|
2015-03-17 05:47:28 +00:00
|
|
|
# comment
|
|
|
|
]
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal"}
|
|
|
|
+parse: product: {"1": "number"}
|
2015-03-17 05:47:28 +00:00
|
|
|
|
2015-08-09 19:26:31 +00:00
|
|
|
:(scenario parse_comment_amongst_instruction_3)
|
2015-03-17 05:47:28 +00:00
|
|
|
recipe main [
|
2015-07-28 21:33:22 +00:00
|
|
|
1:number <- copy 23
|
2015-03-17 05:47:28 +00:00
|
|
|
# comment
|
2015-07-28 21:33:22 +00:00
|
|
|
2:number <- copy 23
|
2015-03-17 05:47:28 +00:00
|
|
|
]
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal"}
|
|
|
|
+parse: product: {"1": "number"}
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal"}
|
|
|
|
+parse: product: {"2": "number"}
|
2015-03-17 05:47:28 +00:00
|
|
|
|
|
|
|
:(scenario parse_comment_after_instruction)
|
|
|
|
recipe main [
|
2015-07-28 21:33:22 +00:00
|
|
|
1:number <- copy 23 # comment
|
2015-03-17 05:47:28 +00:00
|
|
|
]
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal"}
|
|
|
|
+parse: product: {"1": "number"}
|
2015-03-17 05:47:28 +00:00
|
|
|
|
2015-02-18 18:56:19 +00:00
|
|
|
:(scenario parse_label)
|
|
|
|
recipe main [
|
2015-03-17 04:14:16 +00:00
|
|
|
+foo
|
2015-02-18 18:56:19 +00:00
|
|
|
]
|
2015-03-17 04:14:16 +00:00
|
|
|
+parse: label: +foo
|
2015-02-18 18:56:19 +00:00
|
|
|
|
2015-04-30 07:02:54 +00:00
|
|
|
:(scenario parse_dollar_as_recipe_name)
|
|
|
|
recipe main [
|
|
|
|
$foo
|
|
|
|
]
|
|
|
|
+parse: instruction: $foo
|
|
|
|
|
2015-03-17 05:52:04 +00:00
|
|
|
:(scenario parse_multiple_properties)
|
|
|
|
recipe main [
|
2015-07-28 21:33:22 +00:00
|
|
|
1:number <- copy 23/foo:bar:baz
|
2015-03-17 05:52:04 +00:00
|
|
|
]
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal", "foo": <"bar" : "baz">}
|
|
|
|
+parse: product: {"1": "number"}
|
2015-03-17 05:52:04 +00:00
|
|
|
|
2015-02-18 18:56:19 +00:00
|
|
|
:(scenario parse_multiple_products)
|
|
|
|
recipe main [
|
2015-07-28 21:33:22 +00:00
|
|
|
1:number, 2:number <- copy 23
|
2015-02-18 18:56:19 +00:00
|
|
|
]
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal"}
|
|
|
|
+parse: product: {"1": "number"}
|
|
|
|
+parse: product: {"2": "number"}
|
2015-02-18 18:56:19 +00:00
|
|
|
|
|
|
|
:(scenario parse_multiple_ingredients)
|
|
|
|
recipe main [
|
2015-07-28 21:33:22 +00:00
|
|
|
1:number, 2:number <- copy 23, 4:number
|
2015-02-18 18:56:19 +00:00
|
|
|
]
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal"}
|
|
|
|
+parse: ingredient: {"4": "number"}
|
|
|
|
+parse: product: {"1": "number"}
|
|
|
|
+parse: product: {"2": "number"}
|
2015-02-21 07:46:04 +00:00
|
|
|
|
|
|
|
:(scenario parse_multiple_types)
|
|
|
|
recipe main [
|
2015-07-28 21:33:22 +00:00
|
|
|
1:number, 2:address:number <- copy 23, 4:number
|
2015-02-21 07:46:04 +00:00
|
|
|
]
|
2015-04-30 04:49:09 +00:00
|
|
|
+parse: instruction: copy
|
2015-10-26 08:19:27 +00:00
|
|
|
+parse: ingredient: {"23": "literal"}
|
|
|
|
+parse: ingredient: {"4": "number"}
|
|
|
|
+parse: product: {"1": "number"}
|
|
|
|
+parse: product: {"2": <"address" : "number">}
|
2015-02-21 19:20:55 +00:00
|
|
|
|
|
|
|
:(scenario parse_properties)
|
|
|
|
recipe main [
|
2015-07-28 22:03:46 +00:00
|
|
|
1:number:address/lookup <- copy 23
|
2015-02-21 19:20:55 +00:00
|
|
|
]
|
2015-10-27 03:00:38 +00:00
|
|
|
+parse: product: {"1": <"number" : "address">, "lookup": <>}
|
2015-09-03 04:18:58 +00:00
|
|
|
|
|
|
|
//: this test we can't represent with a scenario
|
|
|
|
:(code)
|
|
|
|
void test_parse_comment_terminated_by_eof() {
|
|
|
|
Trace_file = "parse_comment_terminated_by_eof";
|
|
|
|
load("recipe main [\n"
|
|
|
|
" a:number <- copy 34\n"
|
|
|
|
"]\n"
|
|
|
|
"# abc"); // no newline after comment
|
|
|
|
cerr << "."; // termination = success
|
|
|
|
}
|
2015-09-05 16:51:46 +00:00
|
|
|
|
|
|
|
:(scenario warn_on_redefine)
|
|
|
|
% Hide_warnings = true;
|
|
|
|
recipe main [
|
|
|
|
1:number <- copy 23
|
|
|
|
]
|
|
|
|
recipe main [
|
|
|
|
1:number <- copy 24
|
|
|
|
]
|
|
|
|
+warn: redefining recipe main
|
|
|
|
|
|
|
|
:(scenario redefine_without_warning)
|
|
|
|
% Hide_warnings = true;
|
|
|
|
recipe main [
|
|
|
|
1:number <- copy 23
|
|
|
|
]
|
|
|
|
recipe! main [
|
|
|
|
1:number <- copy 24
|
|
|
|
]
|
|
|
|
-warn: redefining recipe main
|
|
|
|
$warn: 0
|