From d6852155e5308e2bb347402bf9e069c7153c2319 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Wed, 15 Apr 2015 15:23:46 -0700 Subject: 1068 - better line numbers Line numbers were broken after inserting some lines from elsewhere. Now we add a #line directive not just before the lines but also after. --- cpp/tangle/030tangle.cc | 61 ++++++++++++++++++++++++++++++++++++++------ cpp/tangle/030tangle.test.cc | 38 ++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 9 deletions(-) (limited to 'cpp') diff --git a/cpp/tangle/030tangle.cc b/cpp/tangle/030tangle.cc index 59533ce8..adbf925b 100644 --- a/cpp/tangle/030tangle.cc +++ b/cpp/tangle/030tangle.cc @@ -1,3 +1,4 @@ +#include #include size_t Line_number = 0; @@ -17,6 +18,7 @@ int tangle(int argc, const char* argv[]) { void tangle(istream& in, list& out) { Line_number = 1; + out.push_back(line_directive(Line_number, Filename)); string curr_line; while (!in.eof()) { getline(in, curr_line); @@ -33,14 +35,7 @@ string Toplevel = "run"; void process_next_hunk(istream& in, const string& directive, list& out) { list 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()); - } + hunk.push_back(line_directive(Line_number, Filename)); string curr_line; while (!in.eof()) { std::streampos old = in.tellg(); @@ -85,20 +80,29 @@ void process_next_hunk(istream& in, const string& directive, list& out) return; } + size_t end_line_number = 0; + string end_filename; + scan_up_to_last_line_directive(target, out.begin(), end_line_number, end_filename); + indent_all(hunk, target); if (cmd == "before") { + hunk.push_back(line_directive(end_line_number, end_filename)); out.splice(target, hunk); } else if (cmd == "after") { + ++end_line_number; + hunk.push_back(line_directive(end_line_number, end_filename)); ++target; out.splice(target, hunk); } else if (cmd == "replace" || cmd == "delete") { + hunk.push_back(line_directive(end_line_number, end_filename)); out.splice(target, hunk); out.erase(target); } else if (cmd == "replace{}" || cmd == "delete{}") { + hunk.push_back(line_directive(end_line_number, end_filename)); if (find_trim(hunk, ":OLD_CONTENTS") == hunk.end()) { out.splice(target, hunk); out.erase(target, balancing_curly(target)); @@ -369,3 +373,44 @@ string trim(const string& s) { ++last; return string(first, last); } + +string line_directive(size_t line_number, string filename) { + ostringstream result; + if (filename.empty()) + result << "#line " << line_number; + else + result << "#line " << line_number << " \"" << filename << '"'; + return result.str(); +} + +void scan_up_to_last_line_directive(list::iterator p, list::iterator begin, size_t& line_number, string& filename) { +//? cout << "scan: " << *p << " until " << *begin << '\n'; //? 1 + int delta = 0; + if (p != begin) { + for (--p; p != begin; --p) { +//? cout << " " << *p << ' ' << delta << '\n'; //? 1 + if (starts_with(*p, "#line")) continue; +//? cout << "incrementing\n"; //? 1 + ++delta; + } +//? cout << "delta: " << delta << '\n'; //? 1 + } + if (p == begin) { + assert(starts_with(*p, "#line")); +//? cout << "hit begin\n"; +//? line_number = delta; +//? return; + } + istringstream in(*p); + string directive_; + in >> directive_; + assert(directive_ == "#line"); + in >> line_number; + line_number += delta; +//? cout << line_number << '\n'; //? 1 + if (in.eof()) return; + in >> filename; + if (filename[0] == '"') filename.erase(0, 1); + if (filename[filename.size()-1] == '"') filename.erase(filename.size()-1); +//? cout << filename << '\n'; //? 1 +} diff --git a/cpp/tangle/030tangle.test.cc b/cpp/tangle/030tangle.test.cc index 4bc9fd6f..4aab6316 100644 --- a/cpp/tangle/030tangle.test.cc +++ b/cpp/tangle/030tangle.test.cc @@ -9,7 +9,7 @@ void test_tangle_with_linenumber() { istringstream in("a\nb\nc\n:(before b)\nd\n"); list dummy; tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "a#line 5dbc"); + CHECK_TRACE_CONTENTS("tangle", "a#line 5d#line 2bc"); } void test_tangle_with_filename() { @@ -21,6 +21,33 @@ void test_tangle_with_filename() { CHECK_TRACE_CONTENTS("tangle", "a#line 5 \"foo\"dbc"); } +void test_tangle_with_multiple_filenames() { + istringstream in1("a\nb\nc"); + list dummy; + Filename = "foo"; + tangle(in1, dummy); + CLEAR_TRACE; + Filename = "bar"; + istringstream in2(":(before b)\nd\n"); + tangle(in2, dummy); + Filename = ""; + CHECK_TRACE_CONTENTS("tangle", "a#line 2 \"bar\"d#line 2 \"foo\"bc"); +} + +void test_tangle_with_multiple_filenames_after() { + istringstream in1("a\nb\nc"); + list dummy; + Filename = "foo"; + tangle(in1, dummy); + CLEAR_TRACE; + Filename = "bar"; + istringstream in2(":(after b)\nd\n"); + tangle(in2, dummy); + Filename = ""; + CHECK_TRACE_CONTENTS("tangle", "ab#line 2 \"bar\"d#line 3 \"foo\"c"); +//? exit(0); //? 1 +} + void test_tangle2() { istringstream in("a\nb\nc\n:(after b)\nd\n"); list dummy; @@ -114,6 +141,7 @@ void test_tangle_supports_scenarios() { istringstream in(":(scenario does_bar)\nabc def\n+layer1: pqr\n+layer2: xyz"); list lines; tangle(in, lines); + CHECK_EQ(lines.front(), "#line 1"); lines.pop_front(); 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(); @@ -126,6 +154,7 @@ void test_tangle_supports_configurable_toplevel() { istringstream in(":(scenarios foo)\n:(scenario does_bar)\nabc def\n+layer1: pqr"); list lines; tangle(in, lines); + CHECK_EQ(lines.front(), "#line 1"); lines.pop_front(); 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(); @@ -141,6 +170,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 lines; tangle(in, lines); + CHECK_EQ(lines.front(), "#line 1"); lines.pop_front(); 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(); @@ -154,6 +184,7 @@ void test_tangle_supports_strings_in_scenarios() { istringstream in(":(scenario does_bar)\nabc \"def\"\n+layer1: pqr\n+layer2: \"xyz\""); list lines; tangle(in, lines); + CHECK_EQ(lines.front(), "#line 1"); lines.pop_front(); 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(); @@ -166,6 +197,7 @@ void test_tangle_supports_strings_in_scenarios2() { istringstream in(":(scenario does_bar)\nabc \"\"\n+layer1: pqr\n+layer2: \"\""); list lines; tangle(in, lines); + CHECK_EQ(lines.front(), "#line 1"); lines.pop_front(); 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(); @@ -178,6 +210,7 @@ void test_tangle_supports_multiline_input_in_scenarios() { istringstream in(":(scenario does_bar)\nabc def\n efg\n+layer1: pqr\n+layer2: \"\""); list lines; tangle(in, lines); + CHECK_EQ(lines.front(), "#line 1"); lines.pop_front(); 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(); @@ -190,6 +223,7 @@ void test_tangle_supports_reset_in_scenarios() { istringstream in(":(scenario does_bar)\nabc def\n===\nefg\n+layer1: pqr\n+layer2: \"\""); list lines; tangle(in, lines); + CHECK_EQ(lines.front(), "#line 1"); lines.pop_front(); 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(); @@ -204,6 +238,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 lines; tangle(in, lines); + CHECK_EQ(lines.front(), "#line 1"); lines.pop_front(); 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(); @@ -217,6 +252,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 lines; tangle(in, lines); + CHECK_EQ(lines.front(), "#line 1"); lines.pop_front(); 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(); -- cgit 1.4.1-2-gfad0