about summary refs log tree commit diff stats
path: root/cpp/tangle
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/tangle')
-rw-r--r--cpp/tangle/030tangle.cc17
-rw-r--r--cpp/tangle/030tangle.test.cc25
2 files changed, 42 insertions, 0 deletions
diff --git a/cpp/tangle/030tangle.cc b/cpp/tangle/030tangle.cc
index 088ba7e8..59533ce8 100644
--- a/cpp/tangle/030tangle.cc
+++ b/cpp/tangle/030tangle.cc
@@ -1,9 +1,13 @@
 #include<sys/param.h>
 
+size_t Line_number = 0;
+string Filename;
+
 int tangle(int argc, const char* argv[]) {
   list<string> result;
   for (int i = 1; i < argc; ++i) {
     ifstream in(argv[i]);
+    Filename = argv[i];
     tangle(in, result);
   }
   for (list<string>::iterator p = result.begin(); p != result.end(); ++p)
@@ -12,9 +16,11 @@ int tangle(int argc, const char* argv[]) {
 }
 
 void tangle(istream& in, list<string>& out) {
+  Line_number = 1;
   string curr_line;
   while (!in.eof()) {
     getline(in, curr_line);
+    Line_number++;
     if (starts_with(curr_line, ":("))
       process_next_hunk(in, trim(curr_line), out);
     else
@@ -27,6 +33,14 @@ string Toplevel = "run";
 
 void process_next_hunk(istream& in, const string& directive, list<string>& out) {
   list<string> hunk;
+  {
+    ostringstream line_directive;
+    if (Filename.empty())
+      line_directive << "#line " << Line_number;
+    else
+      line_directive << "#line " << Line_number << " \"" << Filename << '"';
+    hunk.push_back(line_directive.str());
+  }
   string curr_line;
   while (!in.eof()) {
     std::streampos old = in.tellg();
@@ -36,6 +50,7 @@ void process_next_hunk(istream& in, const string& directive, list<string>& out)
       break;
     }
     else {
+      ++Line_number;
       hunk.push_back(curr_line);
     }
   }
@@ -56,6 +71,8 @@ void process_next_hunk(istream& in, const string& directive, list<string>& out)
   if (cmd == "scenario") {
     list<string> result;
     string name = next_tangle_token(directive_stream);
+    result.push_back(hunk.front());  // line number directive
+    hunk.pop_front();
     emit_test(name, hunk, result);
     out.insert(out.end(), result.begin(), result.end());
     return;
diff --git a/cpp/tangle/030tangle.test.cc b/cpp/tangle/030tangle.test.cc
index 18fe62ad..4bc9fd6f 100644
--- a/cpp/tangle/030tangle.test.cc
+++ b/cpp/tangle/030tangle.test.cc
@@ -5,6 +5,22 @@ void test_tangle() {
   CHECK_TRACE_CONTENTS("tangle", "adbc");
 }
 
+void test_tangle_with_linenumber() {
+  istringstream in("a\nb\nc\n:(before b)\nd\n");
+  list<string> dummy;
+  tangle(in, dummy);
+  CHECK_TRACE_CONTENTS("tangle", "a#line 5dbc");
+}
+
+void test_tangle_with_filename() {
+  istringstream in("a\nb\nc\n:(before b)\nd\n");
+  list<string> dummy;
+  Filename = "foo";
+  tangle(in, dummy);
+  Filename = "";
+  CHECK_TRACE_CONTENTS("tangle", "a#line 5 \"foo\"dbc");
+}
+
 void test_tangle2() {
   istringstream in("a\nb\nc\n:(after b)\nd\n");
   list<string> dummy;
@@ -98,6 +114,7 @@ void test_tangle_supports_scenarios() {
   istringstream in(":(scenario does_bar)\nabc def\n+layer1: pqr\n+layer2: xyz");
   list<string> lines;
   tangle(in, lines);
+  CHECK_EQ(lines.front(), "#line 2");  lines.pop_front();
   CHECK_EQ(lines.front(), "TEST(does_bar)");  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();
@@ -109,6 +126,7 @@ void test_tangle_supports_configurable_toplevel() {
   istringstream in(":(scenarios foo)\n:(scenario does_bar)\nabc def\n+layer1: pqr");
   list<string> lines;
   tangle(in, lines);
+  CHECK_EQ(lines.front(), "#line 3");  lines.pop_front();
   CHECK_EQ(lines.front(), "TEST(does_bar)");  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();
@@ -123,6 +141,7 @@ void test_tangle_can_hide_warnings_in_scenarios() {
   istringstream in(":(scenario does_bar)\nhide warnings\nabc def\n+layer1: pqr\n+layer2: xyz");
   list<string> lines;
   tangle(in, lines);
+  CHECK_EQ(lines.front(), "#line 2");  lines.pop_front();
   CHECK_EQ(lines.front(), "TEST(does_bar)");  lines.pop_front();
   CHECK_EQ(lines.front(), "  Hide_warnings = true;");  lines.pop_front();
   CHECK_EQ(lines.front(), "  run(\"abc def\\n\");");  lines.pop_front();
@@ -135,6 +154,7 @@ void test_tangle_supports_strings_in_scenarios() {
   istringstream in(":(scenario does_bar)\nabc \"def\"\n+layer1: pqr\n+layer2: \"xyz\"");
   list<string> lines;
   tangle(in, lines);
+  CHECK_EQ(lines.front(), "#line 2");  lines.pop_front();
   CHECK_EQ(lines.front(), "TEST(does_bar)");  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();
@@ -146,6 +166,7 @@ void test_tangle_supports_strings_in_scenarios2() {
   istringstream in(":(scenario does_bar)\nabc \"\"\n+layer1: pqr\n+layer2: \"\"");
   list<string> lines;
   tangle(in, lines);
+  CHECK_EQ(lines.front(), "#line 2");  lines.pop_front();
   CHECK_EQ(lines.front(), "TEST(does_bar)");  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();
@@ -157,6 +178,7 @@ void test_tangle_supports_multiline_input_in_scenarios() {
   istringstream in(":(scenario does_bar)\nabc def\n  efg\n+layer1: pqr\n+layer2: \"\"");
   list<string> lines;
   tangle(in, lines);
+  CHECK_EQ(lines.front(), "#line 2");  lines.pop_front();
   CHECK_EQ(lines.front(), "TEST(does_bar)");  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();
@@ -168,6 +190,7 @@ void test_tangle_supports_reset_in_scenarios() {
   istringstream in(":(scenario does_bar)\nabc def\n===\nefg\n+layer1: pqr\n+layer2: \"\"");
   list<string> lines;
   tangle(in, lines);
+  CHECK_EQ(lines.front(), "#line 2");  lines.pop_front();
   CHECK_EQ(lines.front(), "TEST(does_bar)");  lines.pop_front();
   CHECK_EQ(lines.front(), "  run(\"abc def\\n\");");  lines.pop_front();
   CHECK_EQ(lines.front(), "  CLEAR_TRACE;");  lines.pop_front();
@@ -181,6 +204,7 @@ void test_tangle_can_check_for_absence_at_end_of_scenarios() {
   istringstream in(":(scenario does_bar)\nabc def\n  efg\n+layer1: pqr\n-layer1: xyz");
   list<string> lines;
   tangle(in, lines);
+  CHECK_EQ(lines.front(), "#line 2");  lines.pop_front();
   CHECK_EQ(lines.front(), "TEST(does_bar)");  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();
@@ -193,6 +217,7 @@ void test_tangle_can_check_for_absence_at_end_of_scenarios2() {
   istringstream in(":(scenario does_bar)\nabc def\n  efg\n-layer1: pqr\n-layer1: xyz");
   list<string> lines;
   tangle(in, lines);
+  CHECK_EQ(lines.front(), "#line 2");  lines.pop_front();
   CHECK_EQ(lines.front(), "TEST(does_bar)");  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();