about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-02-18 10:49:46 -0800
committerKartik K. Agaram <vc@akkartik.com>2015-02-18 10:49:46 -0800
commit36594a43e0503bef1a894320deb3182af74902dc (patch)
treefcbfe2e5fb8182f84f3f012a3a21ee1872586f95
parent5574fbaf794df7557fb6049e3721c4291556f3c1 (diff)
downloadmu-36594a43e0503bef1a894320deb3182af74902dc.tar.gz
779 - first scenario tested in literate C++ version
-rw-r--r--cpp/literate/002trace4
-rw-r--r--cpp/literate/002trace.tests12
-rw-r--r--cpp/literate/010vm34
-rw-r--r--cpp/literate/011load126
-rw-r--r--cpp/literate/tangle/030tangle.cc2
-rw-r--r--cpp/literate/tangle/030tangle.test.cc18
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();