diff options
-rw-r--r-- | cpp/literate/002trace | 4 | ||||
-rw-r--r-- | cpp/literate/002trace.tests | 12 | ||||
-rw-r--r-- | cpp/literate/010vm | 34 | ||||
-rw-r--r-- | cpp/literate/011load | 126 | ||||
-rw-r--r-- | cpp/literate/tangle/030tangle.cc | 2 | ||||
-rw-r--r-- | cpp/literate/tangle/030tangle.test.cc | 18 |
6 files changed, 176 insertions, 20 deletions
diff --git a/cpp/literate/002trace b/cpp/literate/002trace index 046f4154..4d584cb1 100644 --- a/cpp/literate/002trace +++ b/cpp/literate/002trace @@ -161,7 +161,7 @@ trace_stream* Trace_stream = NULL; #define trace(layer) !Trace_stream ? cerr /*print nothing*/ : Trace_stream->stream(layer) // Warnings should go straight to cerr by default since calls to trace() have // some unfriendly constraints (they delay printing, they can't nest) -#define RAISE ((!Trace_stream || !Hide_warnings) ? cerr /*do print*/ : Trace_stream->stream("warn")) << __FILE__ << ":" << __LINE__ << " " +#define raise ((!Trace_stream || !Hide_warnings) ? cerr /*do print*/ : Trace_stream->stream("warn")) << __FILE__ << ":" << __LINE__ << " " // A separate helper for debugging. We should only trace domain-specific // facts. For everything else use log. @@ -170,7 +170,7 @@ trace_stream* Trace_stream = NULL; #define log cerr :(before "End Types") -// RAISE << die exits after printing -- unless Hide_warnings is set. +// raise << die exits after printing -- unless Hide_warnings is set. struct die {}; :(before "End Tracing") ostream& operator<<(ostream& os, unused die) { diff --git a/cpp/literate/002trace.tests b/cpp/literate/002trace.tests index e0db457c..00705346 100644 --- a/cpp/literate/002trace.tests +++ b/cpp/literate/002trace.tests @@ -117,12 +117,12 @@ void test_trace_supports_count2() { // pending: DUMP tests // pending: readable_contents() adds newline if necessary. -// pending: RAISE also prints to stderr. -// pending: RAISE doesn't print to stderr if Hide_warnings is set. -// pending: RAISE doesn't have to be saved if Hide_warnings is set, just printed. -// pending: RAISE prints to stderr if Trace_stream is NULL. -// pending: RAISE prints to stderr if Trace_stream is NULL even if Hide_warnings is set. -// pending: RAISE << ... die() doesn't die if Hide_warnings is set. +// pending: raise also prints to stderr. +// pending: raise doesn't print to stderr if Hide_warnings is set. +// pending: raise doesn't have to be saved if Hide_warnings is set, just printed. +// pending: raise prints to stderr if Trace_stream is NULL. +// pending: raise prints to stderr if Trace_stream is NULL even if Hide_warnings is set. +// pending: raise << ... die() doesn't die if Hide_warnings is set. diff --git a/cpp/literate/010vm b/cpp/literate/010vm index 8d427c43..4ae5c16a 100644 --- a/cpp/literate/010vm +++ b/cpp/literate/010vm @@ -14,8 +14,6 @@ struct recipe { vector<instruction> step; }; -const int idle = 0; // always the first entry in the recipe book - :(before "struct recipe") // Each instruction is either of the form: // product1, product2, product3, ... <- operation ingredient1, ingredient2, ingredient3, ... @@ -53,6 +51,8 @@ struct property { :(before "End Globals") // Locations refer to a common 'memory'. Each location can store a number. unordered_map<int, int> Memory; +:(before "End Setup") + Memory.clear(); :(after "Types") // Types encode how the numbers stored in different parts of memory are @@ -68,6 +68,16 @@ typedef int type_number; unordered_map<string, type_number> Type_number; unordered_map<type_number, type_info> Type; int Next_type_number = 1; +:(code) +void setup_types() { + Type.clear(); Type_number.clear(); + Type_number["literal"] = 0; + Next_type_number = 1; + int integer = Type_number["integer"] = Next_type_number++; + Type[integer].size = 1; +} +:(before "End Setup") + setup_types(); :(before "End Types") // You can construct arbitrary new types. Types are either 'records', containing @@ -83,6 +93,22 @@ struct type_info { type_info() :size(0) {} }; +:(code) +// It's all very well to construct recipes out of other recipes, but we need +// to know how to do *something* out of the box. For the following +// recipes there are only codes, no entries in the book, because mu just knows +// what to do for them. +void setup_recipes() { + Recipe.clear(); Recipe_number.clear(); + Recipe_number["idle"] = 0; + Next_recipe_number = 1; + Recipe_number["copy"] = Next_recipe_number++; +} +:(before "End Types") +const int idle = 0; // always the first entry in the recipe book +:(before "End Setup") + setup_recipes(); + :(code) @@ -113,3 +139,7 @@ string slurp_until(istream& in, char delim) { } return out.str(); } + + + +:(before "End Setup") diff --git a/cpp/literate/011load b/cpp/literate/011load new file mode 100644 index 00000000..5811f77a --- /dev/null +++ b/cpp/literate/011load @@ -0,0 +1,126 @@ +// It's often convenient to express recipes in a textual fashion. +:(scenario add_recipe) +recipe main [ + 1:integer <- copy 23:literal +] ++parse: instruction: 1 ++parse: ingredient: {name: "23", type: 0} ++parse: product: {name: "1", type: 1} + +:(code) +void run(string text) { + add_recipe(text); +} + +void add_recipe(string form) { + istringstream in(form); + in >> std::noskipws; + + string _recipe = next_word(in); + if (_recipe != "recipe") + raise << "top-level forms must be of the form 'recipe _name_ [ _instruction_ ... ]'\n"; + + string recipe_name = next_word(in); + if (recipe_name.empty()) + raise << "empty recipe name in " << form << '\n'; + int r = Recipe_number[recipe_name] = Next_recipe_number++; + + if (next_word(in) != "[") + raise << "recipe body must begin with '['\n"; + + skip_newlines(in); + + instruction curr; + while (next_instruction(in, &curr)) { + Recipe[r].step.push_back(curr); + } +} + +bool next_instruction(istream& in, instruction* curr) { + curr->clear(); + if (in.eof()) return false; + skip_whitespace(in); if (in.eof()) return false; + skip_newlines(in); if (in.eof()) return false; + + vector<string> words; + while (in.peek() != '\n') { + skip_whitespace(in); if (in.eof()) return false; + string word = next_word(in); if (in.eof()) return false; + words.push_back(word); + skip_whitespace(in); if (in.eof()) return false; + } + skip_newlines(in); if (in.eof()) return false; + + if (words.size() == 1 && *(words[0].end()-1) == ':') { + curr->is_label = true; + words[0].erase(words[0].end()-1); + curr->label = words[0]; + trace("parse") << "label: " << curr->label; + return !in.eof(); + } + + 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 <- + } + + curr->operation = Recipe_number[*p]; ++p; + + for (; p != words.end(); ++p) { + if (*p == ",") continue; + curr->ingredients.push_back(reagent(*p)); + } + + trace("parse") << "instruction: " << curr->operation; + for (vector<reagent>::iterator p = curr->ingredients.begin(); p != curr->ingredients.end(); ++p) { + trace("parse") << " ingredient: " << p->to_string(); + } + for (vector<reagent>::iterator p = curr->products.begin(); p != curr->products.end(); ++p) { + trace("parse") << " product: " << p->to_string(); + } + return !in.eof(); +} + +string next_word(istream& in) { + ostringstream out; + skip_whitespace(in); + slurp_word(in, out); + return out.str(); +} + +void slurp_word(istream& in, ostream& out) { + char c; + if (in.peek() == ',') { + in >> c; + out << c; + return; + } + while (in >> c) { + if (isspace(c) || c == ',') { + in.putback(c); + break; + } + out << c; + } +} + +void skip_whitespace(istream& in) { + while (isspace(in.peek()) && in.peek() != '\n') { + in.get(); + } +} + +void skip_newlines(istream& in) { + while (in.peek() == '\n') + in.get(); +} + +void skip_comma(istream& in) { + skip_whitespace(in); + if (in.peek() == ',') in.get(); + skip_whitespace(in); +} diff --git a/cpp/literate/tangle/030tangle.cc b/cpp/literate/tangle/030tangle.cc index 2bf193f4..2dda8667 100644 --- a/cpp/literate/tangle/030tangle.cc +++ b/cpp/literate/tangle/030tangle.cc @@ -210,7 +210,7 @@ void emit_test(const string& name, list<string>& lines, list<string>& result) { } void emit_session(list<string>& lines, list<string>& result) { - result.push_back(" rmref("+Toplevel+"(\""+input_lines(lines)+"\"));"); + result.push_back(" "+Toplevel+"(\""+input_lines(lines)+"\");"); } void emit_result_checking_session(list<string>& lines, list<string>& result) { diff --git a/cpp/literate/tangle/030tangle.test.cc b/cpp/literate/tangle/030tangle.test.cc index 307486fa..36ce2d1f 100644 --- a/cpp/literate/tangle/030tangle.test.cc +++ b/cpp/literate/tangle/030tangle.test.cc @@ -85,7 +85,7 @@ void test_tangle_supports_scenarios() { list<string> lines; tangle(in, lines); CHECK_EQ(lines.front(), "void test_does_bar() {"); lines.pop_front(); - CHECK_EQ(lines.front(), " rmref(run(\"abc def\\n\"));"); lines.pop_front(); + CHECK_EQ(lines.front(), " run(\"abc def\\n\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: xyz\");"); lines.pop_front(); CHECK_EQ(lines.front(), "}"); lines.pop_front(); CHECK(lines.empty()); @@ -96,7 +96,7 @@ void test_tangle_supports_configurable_toplevel() { list<string> lines; tangle(in, lines); CHECK_EQ(lines.front(), "void test_does_bar() {"); lines.pop_front(); - CHECK_EQ(lines.front(), " rmref(foo(\"abc def\\n\"));"); lines.pop_front(); + CHECK_EQ(lines.front(), " foo(\"abc def\\n\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CHECK_TRACE_CONTENTS(\"layer1: pqr\");"); lines.pop_front(); CHECK_EQ(lines.front(), "}"); lines.pop_front(); CHECK(lines.empty()); @@ -110,7 +110,7 @@ void test_tangle_supports_strings_in_scenarios() { list<string> lines; tangle(in, lines); CHECK_EQ(lines.front(), "void test_does_bar() {"); lines.pop_front(); - CHECK_EQ(lines.front(), " rmref(run(\"abc \\\"def\\\"\\n\"));"); lines.pop_front(); + CHECK_EQ(lines.front(), " run(\"abc \\\"def\\\"\\n\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: \\\"xyz\\\"\");"); lines.pop_front(); CHECK_EQ(lines.front(), "}"); lines.pop_front(); CHECK(lines.empty()); @@ -121,7 +121,7 @@ void test_tangle_supports_strings_in_scenarios2() { list<string> lines; tangle(in, lines); CHECK_EQ(lines.front(), "void test_does_bar() {"); lines.pop_front(); - CHECK_EQ(lines.front(), " rmref(run(\"abc \\\"\\\"\\n\"));"); lines.pop_front(); + CHECK_EQ(lines.front(), " run(\"abc \\\"\\\"\\n\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: \\\"\\\"\");"); lines.pop_front(); CHECK_EQ(lines.front(), "}"); lines.pop_front(); CHECK(lines.empty()); @@ -132,7 +132,7 @@ void test_tangle_supports_multiline_input_in_scenarios() { list<string> lines; tangle(in, lines); CHECK_EQ(lines.front(), "void test_does_bar() {"); lines.pop_front(); - CHECK_EQ(lines.front(), " rmref(run(\"abc def\\n efg\\n\"));"); lines.pop_front(); + CHECK_EQ(lines.front(), " run(\"abc def\\n efg\\n\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: \\\"\\\"\");"); lines.pop_front(); CHECK_EQ(lines.front(), "}"); lines.pop_front(); CHECK(lines.empty()); @@ -143,9 +143,9 @@ void test_tangle_supports_reset_in_scenarios() { list<string> lines; tangle(in, lines); CHECK_EQ(lines.front(), "void test_does_bar() {"); lines.pop_front(); - CHECK_EQ(lines.front(), " rmref(run(\"abc def\\n\"));"); lines.pop_front(); + CHECK_EQ(lines.front(), " run(\"abc def\\n\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CLEAR_TRACE;"); lines.pop_front(); - CHECK_EQ(lines.front(), " rmref(run(\"efg\\n\"));"); lines.pop_front(); + CHECK_EQ(lines.front(), " run(\"efg\\n\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: \\\"\\\"\");"); lines.pop_front(); CHECK_EQ(lines.front(), "}"); lines.pop_front(); CHECK(lines.empty()); @@ -156,7 +156,7 @@ void test_tangle_can_check_for_absence_at_end_of_scenarios() { list<string> lines; tangle(in, lines); CHECK_EQ(lines.front(), "void test_does_bar() {"); lines.pop_front(); - CHECK_EQ(lines.front(), " rmref(run(\"abc def\\n efg\\n\"));"); lines.pop_front(); + CHECK_EQ(lines.front(), " run(\"abc def\\n efg\\n\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CHECK_TRACE_CONTENTS(\"layer1: pqr\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CHECK_TRACE_DOESNT_CONTAIN(\"layer1: xyz\");"); lines.pop_front(); CHECK_EQ(lines.front(), "}"); lines.pop_front(); @@ -168,7 +168,7 @@ void test_tangle_can_check_for_absence_at_end_of_scenarios2() { list<string> lines; tangle(in, lines); CHECK_EQ(lines.front(), "void test_does_bar() {"); lines.pop_front(); - CHECK_EQ(lines.front(), " rmref(run(\"abc def\\n efg\\n\"));"); lines.pop_front(); + CHECK_EQ(lines.front(), " run(\"abc def\\n efg\\n\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CHECK_TRACE_DOESNT_CONTAIN(\"layer1: pqr\");"); lines.pop_front(); CHECK_EQ(lines.front(), " CHECK_TRACE_DOESNT_CONTAIN(\"layer1: xyz\");"); lines.pop_front(); CHECK_EQ(lines.front(), "}"); lines.pop_front(); |