about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--cpp/011load.cc4
-rw-r--r--cpp/tangle/030tangle.cc43
-rw-r--r--cpp/tangle/030tangle.test.cc14
3 files changed, 45 insertions, 16 deletions
diff --git a/cpp/011load.cc b/cpp/011load.cc
index df64cae7..35a9bf23 100644
--- a/cpp/011load.cc
+++ b/cpp/011load.cc
@@ -202,7 +202,9 @@ for (size_t i = 0; i < recently_added_recipes.size(); ++i) {
 recently_added_recipes.clear();
 
 :(scenario parse_comment_outside_recipe)
-# comment
+# 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'
 recipe main [
   1:integer <- copy 23:literal
 ]
diff --git a/cpp/tangle/030tangle.cc b/cpp/tangle/030tangle.cc
index fd01deba..5e25c742 100644
--- a/cpp/tangle/030tangle.cc
+++ b/cpp/tangle/030tangle.cc
@@ -100,6 +100,7 @@ void process_next_hunk(istream& in, const string& directive, const string& filen
 
   // first slurp all lines until next directive
   list<Line> hunk;
+  bool end_of_scenario_input = false;
   {
     string curr_line;
     while (!in.eof()) {
@@ -114,15 +115,21 @@ void process_next_hunk(istream& in, const string& directive, const string& filen
         ++line_number;
         continue;
       }
-      if (cmd == "scenario" && starts_with(curr_line, "#")) {
-        // scenarios can contain mu comments
-        ++line_number;
-        continue;
-      }
-      if (cmd == "scenario" && trim(curr_line).empty()) {
-        // ignore empty lines in scenarios
-        ++line_number;
-        continue;
+      if (cmd == "scenario") {
+        // ignore mu comments in scenarios, but only after the end of input
+        if (!starts_with(curr_line, "#") && !is_input(curr_line)) {
+          // remaining lines are checks
+          end_of_scenario_input = true;
+        }
+        else if (end_of_scenario_input && starts_with(curr_line, "#")) {
+          ++line_number;
+          continue;
+        }
+        if (trim(curr_line).empty()) {
+          // ignore empty lines in scenarios, whether in input of after
+          ++line_number;
+          continue;
+        }
       }
       hunk.push_back(Line(curr_line, filename, line_number));
       ++line_number;
@@ -282,15 +289,23 @@ list<Line>::iterator balancing_curly(list<Line>::iterator curr) {
 }
 
 // A scenario is one or more sessions separated by calls to CLEAR_TRACE ('===')
-//  A session is one or more lines of input, followed optionally by (in order):
-//   one or more lines expected in trace in order ('+')
-//   one or more lines trace shouldn't include ('-')
-//   one or more lines expressing counts of specific layers emitted in trace ('$')
-//   a directive to print the trace just for debugging ('?')
+//   A session is:
+//     one or more lines of escaped setup in C/C++ ('%')
+//   followed by one or more lines of input,
+//   followed optionally by (in order):
+//     one or more lines expected in trace in order ('+')
+//     one or more lines trace shouldn't include ('-')
+//     one or more lines expressing counts of specific layers emitted in trace ('$')
+//     a directive to print the trace just for debugging ('?')
 // Remember to update is_input below if you add to this format.
 void emit_test(const string& name, list<Line>& lines, list<Line>& result) {
   result.push_back(Line("TEST("+name+")", front(lines).filename, front(lines).line_number-1));  // use line number of directive
   while (!lines.empty()) {
+    // hack: drop mu comments at the start, just in case there's a '%' line after them
+    // So the tangler only passes through mu comments inside scenarios between
+    // the first input line and the last input line.
+    while (!lines.empty() && starts_with(front(lines).contents, "#"))
+      lines.pop_front();
     while (!lines.empty() && starts_with(front(lines).contents, "% ")) {
       result.push_back(Line("  "+front(lines).contents.substr(strlen("% ")), front(lines)));
       lines.pop_front();
diff --git a/cpp/tangle/030tangle.test.cc b/cpp/tangle/030tangle.test.cc
index c811881d..0d4da899 100644
--- a/cpp/tangle/030tangle.test.cc
+++ b/cpp/tangle/030tangle.test.cc
@@ -307,7 +307,7 @@ void test_tangle_can_handle_mu_comments_in_scenario() {
   list<Line> lines;
   tangle(in, lines);
   CHECK_EQ(lines.front().contents, "TEST(does_bar)");  lines.pop_front();
-  CHECK_EQ(lines.front().contents, "  run(\"abc def\\n  efg\\n\");");  lines.pop_front();
+  CHECK_EQ(lines.front().contents, "  run(\"abc def\\n# comment1\\n  efg\\n  # indented comment 2\\n\");");  lines.pop_front();
   CHECK_EQ(lines.front().contents, "  CHECK_TRACE_CONTENTS(\"layer1: pqrlayer1: xyz\");");  lines.pop_front();
   CHECK_EQ(lines.front().contents, "  CHECK_TRACE_DOESNT_CONTAIN(\"layer1: z\");");  lines.pop_front();
   CHECK_EQ(lines.front().contents, "  CHECK_EQ(trace_count(\"layer1\"), 2);");  lines.pop_front();
@@ -315,6 +315,18 @@ void test_tangle_can_handle_mu_comments_in_scenario() {
   CHECK(lines.empty());
 }
 
+void test_tangle_can_handle_escaped_setup_after_mu_comments() {
+  istringstream in(":(scenario does_bar)\n# comment\n% int x = 1;\nabc\n+layer1: pqr\n");
+  list<Line> lines;
+  tangle(in, lines);
+  CHECK_EQ(lines.front().contents, "TEST(does_bar)");  lines.pop_front();
+  CHECK_EQ(lines.front().contents, "  int x = 1;"); lines.pop_front();
+  CHECK_EQ(lines.front().contents, "  run(\"abc\\n\");");  lines.pop_front();
+  CHECK_EQ(lines.front().contents, "  CHECK_TRACE_CONTENTS(\"layer1: pqr\");");  lines.pop_front();
+  CHECK_EQ(lines.front().contents, "}");  lines.pop_front();
+  CHECK(lines.empty());
+}
+
 
 
 void test_trim() {