diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-05-05 21:17:24 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-05-05 21:17:24 -0700 |
commit | b96af395b9af2ff9df94b3e82213171f30827c8d (patch) | |
tree | 17c8c12648ccc25625e2534ec8d74fbe8f1542cc /cpp/tangle | |
parent | 2e3b597fe85b654e82b891c22d50754fa5a26156 (diff) | |
download | mu-b96af395b9af2ff9df94b3e82213171f30827c8d.tar.gz |
1276 - make C++ version the default
I've tried to update the Readme, but there are at least a couple of issues.
Diffstat (limited to 'cpp/tangle')
-rw-r--r-- | cpp/tangle/000test.cc | 26 | ||||
-rw-r--r-- | cpp/tangle/001trace.cc | 340 | ||||
-rw-r--r-- | cpp/tangle/001trace.test.cc | 164 | ||||
-rw-r--r-- | cpp/tangle/002main.cc | 52 | ||||
-rw-r--r-- | cpp/tangle/030tangle.cc | 466 | ||||
-rw-r--r-- | cpp/tangle/030tangle.test.cc | 366 | ||||
-rw-r--r-- | cpp/tangle/boot.cc | 51 | ||||
-rw-r--r-- | cpp/tangle/makefile | 23 |
8 files changed, 0 insertions, 1488 deletions
diff --git a/cpp/tangle/000test.cc b/cpp/tangle/000test.cc deleted file mode 100644 index 2754b254..00000000 --- a/cpp/tangle/000test.cc +++ /dev/null @@ -1,26 +0,0 @@ -typedef void (*test_fn)(void); - -const test_fn Tests[] = { - #include "test_list" // auto-generated; see makefile -}; - -bool Passed = true; - -long Num_failures = 0; - -#define CHECK(X) \ - if (!(X)) { \ - ++Num_failures; \ - cerr << "\nF " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): " << #X << '\n'; \ - Passed = false; \ - return; \ - } - -#define CHECK_EQ(X, Y) \ - if ((X) != (Y)) { \ - ++Num_failures; \ - cerr << "\nF " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): " << #X << " == " << #Y << '\n'; \ - cerr << " got " << (X) << '\n'; /* BEWARE: multiple eval */ \ - Passed = false; \ - return; \ - } diff --git a/cpp/tangle/001trace.cc b/cpp/tangle/001trace.cc deleted file mode 100644 index a02cacd4..00000000 --- a/cpp/tangle/001trace.cc +++ /dev/null @@ -1,340 +0,0 @@ -bool Hide_warnings = false; - -struct trace_stream { - vector<pair<string, pair<int, string> > > past_lines; // [(layer label, frame, line)] - map<string, int> frame; - // accumulator for current line - ostringstream* curr_stream; - string curr_layer; - string dump_layer; - trace_stream() :curr_stream(NULL) {} - ~trace_stream() { if (curr_stream) delete curr_stream; } - - ostringstream& stream(string layer) { - newline(); - curr_stream = new ostringstream; - curr_layer = layer; - return *curr_stream; - } - - // be sure to call this before messing with curr_stream or curr_layer or frame - void newline() { - if (!curr_stream) return; - string curr_contents = curr_stream->str(); - curr_contents.erase(curr_contents.find_last_not_of("\r\n")+1); - past_lines.push_back(pair<string, pair<int, string> >(curr_layer, pair<int, string>(frame[curr_layer], curr_contents))); - if (curr_layer == "dump") - cerr << with_newline(curr_stream->str()); - else if ((!dump_layer.empty() && prefix_match(dump_layer, curr_layer)) - || (!Hide_warnings && curr_layer == "warn")) - cerr << curr_layer << "/" << frame[curr_layer] << ": " << with_newline(curr_stream->str()); - delete curr_stream; - curr_stream = NULL; - } - - string readable_contents(string layer) { // missing layer = everything, frame, hierarchical layers - newline(); - ostringstream output; - string real_layer, frame; - parse_layer_and_frame(layer, &real_layer, &frame); - for (vector<pair<string, pair<int, string> > >::iterator p = past_lines.begin(); p != past_lines.end(); ++p) - if (layer.empty() || prefix_match(real_layer, p->first)) - output << p->first << "/" << p->second.first << ": " << with_newline(p->second.second); - return output.str(); - } - - void dump_browseable_contents(string layer) { - ofstream dump("dump"); - dump << "<div class='frame' frame_index='1'>start</div>\n"; - for (vector<pair<string, pair<int, string> > >::iterator p = past_lines.begin(); p != past_lines.end(); ++p) { - if (p->first != layer) continue; - dump << "<div class='frame"; - if (p->second.first > 1) dump << " hidden"; - dump << "' frame_index='" << p->second.first << "'>"; - dump << p->second.second; - dump << "</div>\n"; - } - dump.close(); - } - - string with_newline(string s) { - if (s[s.size()-1] != '\n') return s+'\n'; - return s; - } -}; - - - -trace_stream* Trace_stream = NULL; - -// Top-level helper. IMPORTANT: can't nest. -#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__ << " " -// Just debug logging without any test support. -#define dbg cerr << __FUNCTION__ << '(' << __FILE__ << ':' << __LINE__ << ") " - -// raise << die exits after printing -- unless Hide_warnings is set. -struct die {}; -ostream& operator<<(ostream& os, unused die) { - if (Hide_warnings) return os; - os << "dying"; - exit(1); -} - -#define CLEAR_TRACE delete Trace_stream, Trace_stream = new trace_stream; - -#define DUMP(layer) cerr << Trace_stream->readable_contents(layer) - -// Trace_stream is a resource, lease_tracer uses RAII to manage it. -struct lease_tracer { - lease_tracer() { Trace_stream = new trace_stream; } - ~lease_tracer() { delete Trace_stream, Trace_stream = NULL; } -}; - -#define START_TRACING_UNTIL_END_OF_SCOPE lease_tracer leased_tracer; - -void trace_all(const string& label, const list<string>& in) { - for (list<string>::const_iterator p = in.begin(); p != in.end(); ++p) - trace(label) << *p; -} - -bool check_trace_contents(string FUNCTION, string FILE, int LINE, string expected) { // missing layer == anywhere, frame, hierarchical layers - vector<string> expected_lines = split(expected, ""); - size_t curr_expected_line = 0; - while (curr_expected_line < expected_lines.size() && expected_lines[curr_expected_line].empty()) - ++curr_expected_line; - if (curr_expected_line == expected_lines.size()) return true; - Trace_stream->newline(); - ostringstream output; - string layer, frame, contents; - parse_layer_frame_contents(expected_lines[curr_expected_line], &layer, &frame, &contents); - for (vector<pair<string, pair<int, string> > >::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { - if (!layer.empty() && !prefix_match(layer, p->first)) - continue; - - if (!frame.empty() && strtol(frame.c_str(), NULL, 0) != p->second.first) - continue; - - if (contents != p->second.second) - continue; - - ++curr_expected_line; - while (curr_expected_line < expected_lines.size() && expected_lines[curr_expected_line].empty()) - ++curr_expected_line; - if (curr_expected_line == expected_lines.size()) return true; - parse_layer_frame_contents(expected_lines[curr_expected_line], &layer, &frame, &contents); - } - - ++Num_failures; - cerr << "\nF " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << contents << "] in trace:\n"; - DUMP(layer); - Passed = false; - return false; -} - -void parse_layer_frame_contents(const string& orig, string* layer, string* frame, string* contents) { - string layer_and_frame; - parse_contents(orig, ": ", &layer_and_frame, contents); - parse_layer_and_frame(layer_and_frame, layer, frame); -} - -void parse_contents(const string& s, const string& delim, string* prefix, string* contents) { - string::size_type pos = s.find(delim); - if (pos == NOT_FOUND) { - *prefix = ""; - *contents = s; - } - else { - *prefix = s.substr(0, pos); - *contents = s.substr(pos+delim.size()); - } -} - -void parse_layer_and_frame(const string& orig, string* layer, string* frame) { - size_t last_slash = orig.rfind('/'); - if (last_slash == NOT_FOUND - || last_slash == orig.size()-1 // trailing slash indicates hierarchical layer - || orig.find_last_not_of("0123456789") != last_slash) { - *layer = orig; - *frame = ""; - } - else { - *layer = orig.substr(0, last_slash); - *frame = orig.substr(last_slash+1); - } -} - - - -bool check_trace_contents(string FUNCTION, string FILE, int LINE, string layer, string expected) { // empty layer == everything, multiple layers, hierarchical layers - vector<string> expected_lines = split(expected, ""); - size_t curr_expected_line = 0; - while (curr_expected_line < expected_lines.size() && expected_lines[curr_expected_line].empty()) - ++curr_expected_line; - if (curr_expected_line == expected_lines.size()) return true; - Trace_stream->newline(); - ostringstream output; - vector<string> layers = split(layer, ","); - for (vector<pair<string, pair<int, string> > >::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { - if (!layer.empty() && !any_prefix_match(layers, p->first)) - continue; - if (p->second.second != expected_lines[curr_expected_line]) - continue; - ++curr_expected_line; - while (curr_expected_line < expected_lines.size() && expected_lines[curr_expected_line].empty()) - ++curr_expected_line; - if (curr_expected_line == expected_lines.size()) return true; - } - - ++Num_failures; - cerr << "\nF " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << expected_lines[curr_expected_line] << "] in trace:\n"; - DUMP(layer); - Passed = false; - return false; -} - -#define CHECK_TRACE_CONTENTS(...) check_trace_contents(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) - -int trace_count(string layer) { - return trace_count(layer, ""); -} - -int trace_count(string layer, string line) { - Trace_stream->newline(); - long result = 0; - vector<string> layers = split(layer, ","); - for (vector<pair<string, pair<int, string> > >::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { - if (any_prefix_match(layers, p->first)) - if (line == "" || p->second.second == line) - ++result; - } - return result; -} - -int trace_count(string layer, int frame, string line) { - Trace_stream->newline(); - long result = 0; - vector<string> layers = split(layer, ","); - for (vector<pair<string, pair<int, string> > >::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { - if (any_prefix_match(layers, p->first) && p->second.first == frame) - if (line == "" || p->second.second == line) - ++result; - } - return result; -} - -#define CHECK_TRACE_WARNS() CHECK(trace_count("warn") > 0) -#define CHECK_TRACE_DOESNT_WARN() \ - if (trace_count("warn") > 0) { \ - ++Num_failures; \ - cerr << "\nF " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): unexpected warnings\n"; \ - DUMP("warn"); \ - Passed = false; \ - return; \ - } - -bool trace_doesnt_contain(string layer, string line) { - return trace_count(layer, line) == 0; -} - -bool trace_doesnt_contain(string expected) { - vector<string> tmp = split(expected, ": "); - return trace_doesnt_contain(tmp[0], tmp[1]); -} - -bool trace_doesnt_contain(string layer, int frame, string line) { - return trace_count(layer, frame, line) == 0; -} - -#define CHECK_TRACE_DOESNT_CONTAIN(...) CHECK(trace_doesnt_contain(__VA_ARGS__)) - - - -// manage layer counts in Trace_stream using RAII -struct lease_trace_frame { - string layer; - lease_trace_frame(string l) :layer(l) { - if (!Trace_stream) return; - Trace_stream->newline(); - ++Trace_stream->frame[layer]; - } - ~lease_trace_frame() { - if (!Trace_stream) return; - Trace_stream->newline(); - --Trace_stream->frame[layer]; - } -}; -#define new_trace_frame(layer) lease_trace_frame leased_frame(layer); - -bool check_trace_contents(string FUNCTION, string FILE, int LINE, string layer, int frame, string expected) { // multiple layers, hierarchical layers - vector<string> expected_lines = split(expected, ""); // hack: doesn't handle newlines in embedded in lines - size_t curr_expected_line = 0; - while (curr_expected_line < expected_lines.size() && expected_lines[curr_expected_line].empty()) - ++curr_expected_line; - if (curr_expected_line == expected_lines.size()) return true; - Trace_stream->newline(); - ostringstream output; - vector<string> layers = split(layer, ","); - for (vector<pair<string, pair<int, string> > >::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { - if (!layer.empty() && !any_prefix_match(layers, p->first)) - continue; - if (p->second.first != frame) - continue; - if (p->second.second != expected_lines[curr_expected_line]) - continue; - ++curr_expected_line; - while (curr_expected_line < expected_lines.size() && expected_lines[curr_expected_line].empty()) - ++curr_expected_line; - if (curr_expected_line == expected_lines.size()) return true; - } - - ++Num_failures; - cerr << "\nF " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << expected_lines[curr_expected_line] << "] in trace/" << frame << ":\n"; - DUMP(layer); - Passed = false; - return false; -} - -#define CHECK_TRACE_TOP(layer, expected) CHECK_TRACE_CONTENTS(layer, 1, expected) - - - -vector<string> split(string s, string delim) { - vector<string> result; - string::size_type begin=0, end=s.find(delim); - while (true) { - if (end == NOT_FOUND) { - result.push_back(string(s, begin, NOT_FOUND)); - break; - } - result.push_back(string(s, begin, end-begin)); - begin = end+delim.size(); - end = s.find(delim, begin); - } - return result; -} - -bool any_prefix_match(const vector<string>& pats, const string& needle) { - if (pats.empty()) return false; - if (*pats[0].rbegin() != '/') - // prefix match not requested - return find(pats.begin(), pats.end(), needle) != pats.end(); - // first pat ends in a '/'; assume all pats do. - for (vector<string>::const_iterator p = pats.begin(); p != pats.end(); ++p) - if (headmatch(needle, *p)) return true; - return false; -} - -bool prefix_match(const string& pat, const string& needle) { - if (*pat.rbegin() != '/') - // prefix match not requested - return pat == needle; - return headmatch(needle, pat); -} - -bool headmatch(const string& s, const string& pat) { - if (pat.size() > s.size()) return false; - return std::mismatch(pat.begin(), pat.end(), s.begin()).first == pat.end(); -} diff --git a/cpp/tangle/001trace.test.cc b/cpp/tangle/001trace.test.cc deleted file mode 100644 index e0db457c..00000000 --- a/cpp/tangle/001trace.test.cc +++ /dev/null @@ -1,164 +0,0 @@ -void test_trace_check_compares() { - CHECK_TRACE_CONTENTS("test layer", ""); - trace("test layer") << "foo"; - CHECK_TRACE_CONTENTS("test layer", "foo"); -} - -void test_trace_check_filters_layers() { - trace("test layer 1") << "foo"; - trace("test layer 2") << "bar"; - CHECK_TRACE_CONTENTS("test layer 1", "foo"); -} - -void test_trace_check_ignores_other_lines() { - trace("test layer 1") << "foo"; - trace("test layer 1") << "bar"; - CHECK_TRACE_CONTENTS("test layer 1", "foo"); -} - -void test_trace_check_always_finds_empty_lines() { - CHECK_TRACE_CONTENTS("test layer 1", ""); -} - -void test_trace_check_treats_empty_layers_as_wildcards() { - trace("test layer 1") << "foo"; - CHECK_TRACE_CONTENTS("", "foo"); -} - -void test_trace_check_multiple_lines_at_once() { - trace("test layer 1") << "foo"; - trace("test layer 2") << "bar"; - CHECK_TRACE_CONTENTS("", "foobar"); -} - -void test_trace_check_always_finds_empty_lines2() { - CHECK_TRACE_CONTENTS("test layer 1", ""); -} - -void test_trace_orders_across_layers() { - trace("test layer 1") << "foo"; - trace("test layer 2") << "bar"; - trace("test layer 1") << "qux"; - CHECK_TRACE_CONTENTS("", "foobarqux"); -} - -void test_trace_orders_across_layers2() { - trace("test layer 1") << "foo"; - trace("test layer 2") << "bar"; - trace("test layer 1") << "qux"; - CHECK_TRACE_CONTENTS("foobarqux"); -} - -void test_trace_checks_ordering_spanning_multiple_layers() { - trace("layer1") << "foo"; - trace("layer2") << "bar"; - trace("layer1") << "qux"; - CHECK_TRACE_CONTENTS("layer1: foolayer2: barlayer1: qux"); -} - -void test_trace_segments_within_layers() { - trace("test layer 1") << "foo"; - trace("test layer 2") << "bar"; - new_trace_frame("test layer 1"); - trace("test layer 1") << "qux"; - CHECK_TRACE_CONTENTS("test layer 1", "fooqux"); - CHECK_TRACE_CONTENTS("test layer 1", 0, "foo"); - CHECK_TRACE_DOESNT_CONTAIN("test layer 1", 1, "foo"); -} - -void test_trace_checks_ordering_across_layers_and_frames() { - trace("test layer 1") << "foo"; - trace("test layer 2") << "bar"; - new_trace_frame("test layer 1"); - trace("test layer 1") << "qux"; - CHECK_TRACE_CONTENTS("test layer 1/0: footest layer 2: bartest layer 1: qux"); - CHECK_TRACE_CONTENTS("test layer 1: footest layer 2: bartest layer 1/1: qux"); -} - -void trace_test_fn(int n) { - if (n == 0) return; - new_trace_frame("foo"); - trace("foo") << "before: " << n; - trace_test_fn(n-1); - trace("foo") << "after: " << n; -} - -void test_trace_keeps_level_together() { - CHECK_TRACE_CONTENTS("foo", ""); - trace_test_fn(4); - CHECK_TRACE_CONTENTS("foo", 2, "before: 3after: 3"); -} - -void test_trace_supports_multiple_layers() { - trace("test layer 1") << "foo"; - trace("test layer 2") << "bar"; - trace("test layer 1") << "qux"; - CHECK_TRACE_CONTENTS("test layer 1,test layer 2", "foobarqux"); -} - -void test_trace_supports_hierarchical_layers() { - trace("test layer/a") << "foo"; - trace("different layer/c") << "foo 2"; - trace("test layer/b") << "bar"; - CHECK_TRACE_CONTENTS("test layer/", "foobar"); -} - -void test_trace_supports_count() { - trace("test layer 1") << "foo"; - trace("test layer 1") << "foo"; - CHECK_EQ(trace_count("test layer 1", "foo"), 2); -} - -void test_trace_supports_count2() { - trace("test layer 1") << "foo"; - trace("test layer 1") << "bar"; - CHECK_EQ(trace_count("test layer 1"), 2); -} - -// 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. - - - -// can't check trace because trace methods call 'split' - -void test_split_returns_at_least_one_elem() { - vector<string> result = split("", ","); - CHECK_EQ(result.size(), 1); - CHECK_EQ(result[0], ""); -} - -void test_split_returns_entire_input_when_no_delim() { - vector<string> result = split("abc", ","); - CHECK_EQ(result.size(), 1); - CHECK_EQ(result[0], "abc"); -} - -void test_split_works() { - vector<string> result = split("abc,def", ","); - CHECK_EQ(result.size(), 2); - CHECK_EQ(result[0], "abc"); - CHECK_EQ(result[1], "def"); -} - -void test_split_works2() { - vector<string> result = split("abc,def,ghi", ","); - CHECK_EQ(result.size(), 3); - CHECK_EQ(result[0], "abc"); - CHECK_EQ(result[1], "def"); - CHECK_EQ(result[2], "ghi"); -} - -void test_split_handles_multichar_delim() { - vector<string> result = split("abc,,def,,ghi", ",,"); - CHECK_EQ(result.size(), 3); - CHECK_EQ(result[0], "abc"); - CHECK_EQ(result[1], "def"); - CHECK_EQ(result[2], "ghi"); -} diff --git a/cpp/tangle/002main.cc b/cpp/tangle/002main.cc deleted file mode 100644 index aaa91e6f..00000000 --- a/cpp/tangle/002main.cc +++ /dev/null @@ -1,52 +0,0 @@ -int main(int argc, const char* argv[]) { - if (flag("test", argc, argv)) - return run_tests(); - return tangle(argc, argv); -} - -bool flag(const string& flag, int argc, const char* argv[]) { - for (int i = 1; i < argc; ++i) - if (string(argv[i]) == flag) - return true; - return false; -} - -string flag_value(const string& flag, int argc, const char* argv[]) { - for (int i = 1; i < argc-1; ++i) - if (string(argv[i]) == flag) - return argv[i+1]; - return ""; -} - - - -//// test harness - -int run_tests() { - for (unsigned long i=0; i < sizeof(Tests)/sizeof(Tests[0]); ++i) { - START_TRACING_UNTIL_END_OF_SCOPE; - setup(); - (*Tests[i])(); - verify(); - } - - cerr << '\n'; - if (Num_failures > 0) - cerr << Num_failures << " failure" - << (Num_failures > 1 ? "s" : "") - << '\n'; - return Num_failures; -} - -void verify() { - Hide_warnings = false; - if (!Passed) - ; - else - cerr << "."; -} - -void setup() { - Hide_warnings = false; - Passed = true; -} diff --git a/cpp/tangle/030tangle.cc b/cpp/tangle/030tangle.cc deleted file mode 100644 index 5e25c742..00000000 --- a/cpp/tangle/030tangle.cc +++ /dev/null @@ -1,466 +0,0 @@ -// Reorder a file based on directives starting with ':(' (tangle directives). -// Insert #line directives to preserve line numbers in the original. -// Clear lines starting with '//:' (tangle comments). - -//// Preliminaries regarding line number management - -struct Line { - string filename; - size_t line_number; - string contents; - Line() :line_number(0) {} - Line(const string& text) :line_number(0) { - contents = text; - } - Line(const string& text, const string& f, const size_t& l) { - contents = text; - filename = f; - line_number = l; - } - Line(const string& text, const Line& origin) { - contents = text; - filename = origin.filename; - line_number = origin.line_number; - } -}; - -// Emit a list of line contents, inserting directives just at discontinuities. -// Needs to be a macro because 'out' can have the side effect of creating a -// new trace in Trace_stream. -#define EMIT(lines, out) if (!lines.empty()) { \ - string last_file = lines.begin()->filename; \ - size_t last_line = lines.begin()->line_number-1; \ - out << line_directive(lines.begin()->line_number, lines.begin()->filename) << '\n'; \ - for (list<Line>::const_iterator p = lines.begin(); p != lines.end(); ++p) { \ - if (last_file != p->filename || last_line != p->line_number-1) \ - out << line_directive(p->line_number, p->filename) << '\n'; \ - out << p->contents << '\n'; \ - last_file = p->filename; \ - last_line = p->line_number; \ - } \ -} - -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(); -} - -//// Tangle - -string Toplevel = "run"; - -int tangle(int argc, const char* argv[]) { - list<Line> result; - for (int i = 1; i < argc; ++i) { -//? cerr << "new file " << argv[i] << '\n'; //? 1 - Toplevel = "run"; - ifstream in(argv[i]); - tangle(in, argv[i], result); - } - - EMIT(result, cout); - return 0; -} - -void tangle(istream& in, const string& filename, list<Line>& out) { - string curr_line; - size_t line_number = 1; - while (!in.eof()) { - getline(in, curr_line); - if (starts_with(curr_line, ":(")) { - ++line_number; - process_next_hunk(in, trim(curr_line), filename, line_number, out); - continue; - } - if (starts_with(curr_line, "//:")) { - ++line_number; - continue; - } - out.push_back(Line(curr_line, filename, line_number)); - ++line_number; - } - - // Trace all line contents, inserting directives just at discontinuities. - if (!Trace_stream) return; - EMIT(out, Trace_stream->stream("tangle")); -} - -// just for tests -void tangle(istream& in, list<Line>& out) { - tangle(in, "", out); -} - -void process_next_hunk(istream& in, const string& directive, const string& filename, size_t& line_number, list<Line>& out) { - istringstream directive_stream(directive.substr(2)); // length of ":(" - string cmd = next_tangle_token(directive_stream); - - // first slurp all lines until next directive - list<Line> hunk; - bool end_of_scenario_input = false; - { - string curr_line; - while (!in.eof()) { - std::streampos old = in.tellg(); - getline(in, curr_line); - if (starts_with(curr_line, ":(")) { - in.seekg(old); - break; - } - if (starts_with(curr_line, "//:")) { - // tangle comments - ++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; - } - } - - if (cmd == "code") { - out.insert(out.end(), hunk.begin(), hunk.end()); - return; - } - - if (cmd == "scenarios") { - Toplevel = next_tangle_token(directive_stream); - return; - } - - if (cmd == "scenario") { - list<Line> result; - string name = next_tangle_token(directive_stream); - emit_test(name, hunk, result); -//? cerr << out.size() << " " << result.size() << '\n'; //? 1 - out.insert(out.end(), result.begin(), result.end()); -//? cerr << out.size() << " " << result.size() << '\n'; //? 1 - return; - } - - if (cmd == "before" || cmd == "after" || cmd == "replace" || cmd == "replace{}" || cmd == "delete" || cmd == "delete{}") { - list<Line>::iterator target = locate_target(out, directive_stream); - if (target == out.end()) { - raise << "Couldn't find target " << directive << '\n' << die(); - return; - } - - indent_all(hunk, target); - - if (cmd == "before") { - out.splice(target, hunk); - } - else if (cmd == "after") { - ++target; - out.splice(target, hunk); - } - else if (cmd == "replace" || cmd == "delete") { - out.splice(target, hunk); - out.erase(target); - } - else if (cmd == "replace{}" || cmd == "delete{}") { - if (find_trim(hunk, ":OLD_CONTENTS") == hunk.end()) { - out.splice(target, hunk); - out.erase(target, balancing_curly(target)); - } - else { - list<Line>::iterator next = balancing_curly(target); - list<Line> old_version; - old_version.splice(old_version.begin(), out, target, next); - old_version.pop_back(); old_version.pop_front(); // contents only please, not surrounding curlies - - list<Line>::iterator new_pos = find_trim(hunk, ":OLD_CONTENTS"); - indent_all(old_version, new_pos); - hunk.splice(new_pos, old_version); - hunk.erase(new_pos); - out.splice(next, hunk); - } - } - return; - } - - raise << "unknown directive " << cmd << '\n'; -} - -list<Line>::iterator locate_target(list<Line>& out, istream& directive_stream) { - string pat = next_tangle_token(directive_stream); - if (pat == "") return out.end(); - - string next_token = next_tangle_token(directive_stream); - if (next_token == "") { - return find_substr(out, pat); - } - // first way to do nested pattern: pattern 'following' intermediate - else if (next_token == "following") { - string pat2 = next_tangle_token(directive_stream); - if (pat2 == "") return out.end(); - list<Line>::iterator intermediate = find_substr(out, pat2); - if (intermediate == out.end()) return out.end(); - return find_substr(out, intermediate, pat); - } - // second way to do nested pattern: intermediate 'then' pattern - else if (next_token == "then") { - list<Line>::iterator intermediate = find_substr(out, pat); - if (intermediate == out.end()) return out.end(); - string pat2 = next_tangle_token(directive_stream); - if (pat2 == "") return out.end(); - return find_substr(out, intermediate, pat2); - } - raise << "unknown keyword in directive: " << next_token << '\n'; - return out.end(); -} - -// indent all lines in l like indentation at exemplar -void indent_all(list<Line>& l, list<Line>::iterator exemplar) { - string curr_indent = indent(exemplar->contents); - for (list<Line>::iterator p = l.begin(); p != l.end(); ++p) - if (!p->contents.empty()) - p->contents.insert(p->contents.begin(), curr_indent.begin(), curr_indent.end()); -} - -string next_tangle_token(istream& in) { - in >> std::noskipws; - ostringstream out; - skip_whitespace(in); - if (in.peek() == '"') - slurp_tangle_string(in, out); - else - slurp_word(in, out); - return out.str(); -} - -void slurp_tangle_string(istream& in, ostream& out) { - in.get(); - char c; - while (in >> c) { - if (c == '\\') // only works for double-quotes - continue; - if (c == '"') - break; - out << c; - } -} - -void slurp_word(istream& in, ostream& out) { - char c; - while (in >> c) { - if (isspace(c) || c == ')') { - in.putback(c); - break; - } - out << c; - } -} - -void skip_whitespace(istream& in) { - while (isspace(in.peek())) - in.get(); -} - -list<Line>::iterator balancing_curly(list<Line>::iterator curr) { - long open_curlies = 0; - do { - for (string::iterator p = curr->contents.begin(); p != curr->contents.end(); ++p) { - if (*p == '{') ++open_curlies; - if (*p == '}') --open_curlies; - } - ++curr; - // no guard so far against unbalanced curly, including inside comments or strings - } while (open_curlies != 0); - return curr; -} - -// A scenario is one or more sessions separated by calls to CLEAR_TRACE ('===') -// 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(); - } - result.push_back(input_lines(lines)); - if (!lines.empty() && !front(lines).contents.empty() && front(lines).contents[0] == '+') - result.push_back(expected_in_trace(lines)); - while (!lines.empty() && !front(lines).contents.empty() && front(lines).contents[0] == '-') { - result.push_back(expected_not_in_trace(front(lines))); - lines.pop_front(); - } - if (!lines.empty() && front(lines).contents[0] == '$') { - const string& in = front(lines).contents; - size_t pos = in.find(": "); - string layer = in.substr(1, pos-1); - string count = in.substr(pos+2); - result.push_back(Line(" CHECK_EQ(trace_count(\""+layer+"\"), "+count+");", front(lines))); - lines.pop_front(); - } - if (!lines.empty() && front(lines).contents == "===") { - result.push_back(Line(" CLEAR_TRACE;", front(lines))); - lines.pop_front(); - } - if (!lines.empty() && front(lines).contents == "?") { - result.push_back(Line(" DUMP(\"\");", front(lines))); - lines.pop_front(); - } - } - result.push_back(Line("}")); -} - -bool is_input(const string& line) { - if (line.empty()) return true; - return line != "===" && line[0] != '+' && line[0] != '-' && line[0] != '$' && line[0] != '?'; -} - -Line input_lines(list<Line>& hunk) { - Line result; - result.line_number = hunk.front().line_number; - result.filename = hunk.front().filename; - while (!hunk.empty() && is_input(hunk.front().contents)) { - result.contents += hunk.front().contents+""; // temporary delimiter; replace with escaped newline after escaping other backslashes - hunk.pop_front(); - } - result.contents = " "+Toplevel+"(\""+escape(result.contents)+"\");"; - return result; -} - -Line expected_in_trace(list<Line>& hunk) { - Line result; - result.line_number = hunk.front().line_number; - result.filename = hunk.front().filename; - while (!hunk.empty() && !front(hunk).contents.empty() && front(hunk).contents[0] == '+') { - hunk.front().contents.erase(0, 1); - result.contents += hunk.front().contents+""; - hunk.pop_front(); - } - result.contents = " CHECK_TRACE_CONTENTS(\""+escape(result.contents)+"\");"; - return result; -} - -Line expected_not_in_trace(const Line& line) { - Line result; - result.line_number = line.line_number; - result.filename = line.filename; - result.contents = " CHECK_TRACE_DOESNT_CONTAIN(\""+escape(line.contents.substr(1))+"\");"; - return result; -} - -list<Line>::iterator find_substr(list<Line>& in, const string& pat) { - for (list<Line>::iterator p = in.begin(); p != in.end(); ++p) - if (p->contents.find(pat) != NOT_FOUND) - return p; - return in.end(); -} - -list<Line>::iterator find_substr(list<Line>& in, list<Line>::iterator p, const string& pat) { - for (; p != in.end(); ++p) - if (p->contents.find(pat) != NOT_FOUND) - return p; - return in.end(); -} - -list<Line>::iterator find_trim(list<Line>& in, const string& pat) { - for (list<Line>::iterator p = in.begin(); p != in.end(); ++p) - if (trim(p->contents) == pat) - return p; - return in.end(); -} - -string escape(string s) { - s = replace_all(s, "\\", "\\\\"); - s = replace_all(s, "\"", "\\\""); - s = replace_all(s, "", "\\n"); - return s; -} - -string replace_all(string s, const string& a, const string& b) { - for (size_t pos = s.find(a); pos != NOT_FOUND; pos = s.find(a, pos+b.size())) - s = s.replace(pos, a.size(), b); - return s; -} - -bool any_line_starts_with(const list<Line>& lines, const string& pat) { - for (list<Line>::const_iterator p = lines.begin(); p != lines.end(); ++p) - if (starts_with(p->contents, pat)) return true; - return false; -} - -bool any_non_input_line(const list<Line>& lines) { - for (list<Line>::const_iterator p = lines.begin(); p != lines.end(); ++p) - if (!is_input(p->contents)) return true; - return false; -} - -// does s start with pat, after skipping whitespace? -// pat can't start with whitespace -bool starts_with(const string& s, const string& pat) { - for (size_t pos = 0; pos < s.size(); ++pos) - if (!isspace(s[pos])) - return s.compare(pos, pat.size(), pat) == 0; - return false; -} - -string indent(const string& s) { - for (size_t pos = 0; pos < s.size(); ++pos) - if (!isspace(s[pos])) - return s.substr(0, pos); - return ""; -} - -string strip_indent(const string& s, size_t n) { - if (s.empty()) return ""; - string::const_iterator curr = s.begin(); - while (curr != s.end() && n > 0 && isspace(*curr)) { - ++curr; - --n; - } - return string(curr, s.end()); -} - -string trim(const string& s) { - string::const_iterator first = s.begin(); - while (first != s.end() && isspace(*first)) - ++first; - if (first == s.end()) return ""; - - string::const_iterator last = --s.end(); - while (last != s.begin() && isspace(*last)) - --last; - ++last; - return string(first, last); -} - -const Line& front(const list<Line>& l) { - assert(!l.empty()); - return l.front(); -} diff --git a/cpp/tangle/030tangle.test.cc b/cpp/tangle/030tangle.test.cc deleted file mode 100644 index 0d4da899..00000000 --- a/cpp/tangle/030tangle.test.cc +++ /dev/null @@ -1,366 +0,0 @@ -void test_tangle() { - istringstream in("a\nb\nc\n:(before b)\nd\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "adbc"); -} - -void test_tangle_with_linenumber() { - istringstream in("a\nb\nc\n:(before b)\nd\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "#line 1a#line 5d#line 2bc"); - // no other #line directives - CHECK_TRACE_DOESNT_CONTAIN("tangle", "#line 3"); - CHECK_TRACE_DOESNT_CONTAIN("tangle", "#line 4"); -} - -void test_tangle_linenumbers_with_filename() { - istringstream in("a\nb\nc\n:(before b)\nd\n"); - list<Line> dummy; - tangle(in, "foo", dummy); - CHECK_TRACE_CONTENTS("tangle", "a#line 5 \"foo\"dbc"); -} - -void test_tangle_linenumbers_with_multiple_filenames() { - istringstream in1("a\nb\nc"); - list<Line> dummy; - tangle(in1, "foo", dummy); - CLEAR_TRACE; - istringstream in2(":(before b)\nd\n"); - tangle(in2, "bar", dummy); - CHECK_TRACE_CONTENTS("tangle", "a#line 2 \"bar\"d#line 2 \"foo\"bc"); -} - -void test_tangle_linenumbers_with_multiple_directives() { - istringstream in1("a\nb\nc"); - list<Line> dummy; - tangle(in1, "foo", dummy); - CLEAR_TRACE; - istringstream in2(":(before b)\nd\n:(before c)\ne"); - tangle(in2, "bar", dummy); - CHECK_TRACE_CONTENTS("tangle", "a#line 2 \"bar\"d#line 2 \"foo\"b#line 4 \"bar\"e#line 3 \"foo\"c"); -} - -void test_tangle_with_multiple_filenames_after() { - istringstream in1("a\nb\nc"); - list<Line> dummy; - tangle(in1, "foo", dummy); - CLEAR_TRACE; - istringstream in2(":(after b)\nd\n"); - tangle(in2, "bar", dummy); - CHECK_TRACE_CONTENTS("tangle", "ab#line 2 \"bar\"d#line 3 \"foo\"c"); -//? exit(0); //? 1 -} - -void test_tangle_skip_tanglecomments() { - istringstream in("a\nb\nc\n//: 1\n//: 2\nd\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "abcd"); - CHECK_TRACE_DOESNT_CONTAIN("tangle", "//: 1"); -} - -void test_tangle_with_tanglecomments_and_directive() { - istringstream in("a\n//: 1\nb\nc\n:(before b)\nd\n:(code)\ne\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "a#line 6d#line 3bc#line 8e"); - CHECK_TRACE_DOESNT_CONTAIN("tangle", "//: 1"); -} - -void test_tangle_with_tanglecomments_inside_directive() { - istringstream in("a\n//: 1\nb\nc\n:(before b)\n//: abc\nd\n:(code)\ne\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "a#line 7d#line 3bc#line 9e"); - CHECK_TRACE_DOESNT_CONTAIN("tangle", "//: 1"); -} - -void test_tangle2() { - istringstream in("a\nb\nc\n:(after b)\nd\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "abdc"); -} - -void test_tangle_at_end() { - istringstream in("a\nb\nc\n:(after c)\nd\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "abcd"); -} - -void test_tangle_indents_hunks_correctly() { - istringstream in("a\n b\nc\n:(after b)\nd\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "a b dc"); -} - -void test_tangle_warns_on_missing_target() { - Hide_warnings = true; - istringstream in(":(before)\nabc def\n"); - list<Line> lines; - tangle(in, lines); - CHECK_TRACE_WARNS(); -} - -void test_tangle_warns_on_unknown_target() { - Hide_warnings = true; - istringstream in(":(before \"foo\")\nabc def\n"); - list<Line> lines; - tangle(in, lines); - CHECK_TRACE_WARNS(); -} - -void test_tangle_delete_range_of_lines() { - istringstream in("a\nb {\nc\n}\n:(delete{} \"b\")\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "a"); - CHECK_TRACE_DOESNT_CONTAIN("tangle", "b"); - CHECK_TRACE_DOESNT_CONTAIN("tangle", "c"); -} - -void test_tangle_replace() { - istringstream in("a\nb\nc\n:(replace b)\nd\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "adc"); - CHECK_TRACE_DOESNT_CONTAIN("tangle", "b"); -} - -void test_tangle_replace_range_of_lines() { - istringstream in("a\nb {\nc\n}\n:(replace{} \"b\")\nd\ne\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "ade"); - CHECK_TRACE_DOESNT_CONTAIN("tangle", "b {"); - CHECK_TRACE_DOESNT_CONTAIN("tangle", "c"); -} - -void test_tangle_replace_tracks_old_lines() { - istringstream in("a\nb {\nc\n}\n:(replace{} \"b\")\nd\n:OLD_CONTENTS\ne\n"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "adce"); - CHECK_TRACE_DOESNT_CONTAIN("tangle", "b {"); -} - -void test_tangle_nested_patterns() { - istringstream in("a\nc\nb\nc\nd\n:(after \"b\" then \"c\")\ne"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "acbced"); -} - -void test_tangle_nested_patterns2() { - istringstream in("a\nc\nb\nc\nd\n:(after \"c\" following \"b\")\ne"); - list<Line> dummy; - tangle(in, dummy); - CHECK_TRACE_CONTENTS("tangle", "acbced"); -} - -// todo: include line numbers in tangle errors - - - -void test_tangle_supports_scenarios() { - istringstream in(":(scenario does_bar)\nabc def\n+layer1: pqr\n+layer2: xyz"); - 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\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: xyz\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - CHECK(lines.empty()); -} - -void test_tangle_ignores_empty_lines_in_scenarios() { - istringstream in(":(scenario does_bar)\nabc def\n+layer1: pqr\n \n+layer2: xyz"); - 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\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: xyz\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - CHECK(lines.empty()); -} - -void test_tangle_handles_empty_lines_in_scenarios() { - istringstream in(":(scenario does_bar)\nabc def\n\n+layer1: pqr\n+layer2: xyz"); - list<Line> lines; - tangle(in, lines); - // no infinite loop -} - -void test_tangle_supports_configurable_toplevel() { - istringstream in(":(scenarios foo)\n:(scenario does_bar)\nabc def\n+layer1: pqr"); - list<Line> lines; - tangle(in, lines); - CHECK_EQ(lines.front().contents, "TEST(does_bar)"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " foo(\"abc def\\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()); - - istringstream cleanup(":(scenarios run)\n"); - tangle(cleanup, lines); -} - -void test_tangle_can_hide_warnings_in_scenarios() { - istringstream in(":(scenario does_bar)\n% Hide_warnings = true;\nabc def\n+layer1: pqr\n+layer2: xyz"); - list<Line> lines; - tangle(in, lines); - CHECK_EQ(lines.front().contents, "TEST(does_bar)"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " Hide_warnings = true;"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " run(\"abc def\\n\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: xyz\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - CHECK(lines.empty()); -} - -void test_tangle_supports_strings_in_scenarios() { - istringstream in(":(scenario does_bar)\nabc \"def\"\n+layer1: pqr\n+layer2: \"xyz\""); - 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\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: \\\"xyz\\\"\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - CHECK(lines.empty()); -} - -void test_tangle_supports_strings_in_scenarios2() { - istringstream in(":(scenario does_bar)\nabc \"\"\n+layer1: pqr\n+layer2: \"\""); - list<Line> lines; - tangle(in, lines); - CHECK_EQ(lines.front().contents, "TEST(does_bar)"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " run(\"abc \\\"\\\"\\n\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: \\\"\\\"\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - CHECK(lines.empty()); -} - -void test_tangle_supports_multiline_input_in_scenarios() { - istringstream in(":(scenario does_bar)\nabc def\n efg\n+layer1: pqr\n+layer2: \"\""); - 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, " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: \\\"\\\"\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - CHECK(lines.empty()); -} - -void test_tangle_supports_reset_in_scenarios() { - istringstream in(":(scenario does_bar)\nabc def\n===\nefg\n+layer1: pqr\n+layer2: \"\""); - 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\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " CLEAR_TRACE;"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " run(\"efg\\n\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS(\"layer1: pqrlayer2: \\\"\\\"\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - CHECK(lines.empty()); -} - -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<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, " CHECK_TRACE_CONTENTS(\"layer1: pqr\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " CHECK_TRACE_DOESNT_CONTAIN(\"layer1: xyz\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - CHECK(lines.empty()); -} - -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<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, " CHECK_TRACE_DOESNT_CONTAIN(\"layer1: pqr\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, " CHECK_TRACE_DOESNT_CONTAIN(\"layer1: xyz\");"); lines.pop_front(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - CHECK(lines.empty()); -} - -void test_tangle_can_check_for_count_in_scenario() { - istringstream in(":(scenario does_bar)\nabc def\n efg\n$layer1: 2"); - 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, " CHECK_EQ(trace_count(\"layer1\"), 2);"); lines.pop_front(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - CHECK(lines.empty()); -} - -void test_tangle_can_handle_mu_comments_in_scenario() { - istringstream in(":(scenario does_bar)\nabc def\n# comment1\n efg\n # indented comment 2\n+layer1: pqr\n# comment inside expected_trace\n+layer1: xyz\n# comment after expected trace\n-layer1: z\n# comment before trace count\n$layer1: 2\n# comment at end\n\n"); - 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# 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(); - CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); - 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() { - CHECK_EQ(trim(""), ""); - CHECK_EQ(trim(" "), ""); - CHECK_EQ(trim(" "), ""); - CHECK_EQ(trim("a"), "a"); - CHECK_EQ(trim(" a"), "a"); - CHECK_EQ(trim(" a"), "a"); - CHECK_EQ(trim(" ab"), "ab"); - CHECK_EQ(trim("a "), "a"); - CHECK_EQ(trim("a "), "a"); - CHECK_EQ(trim("ab "), "ab"); - CHECK_EQ(trim(" a "), "a"); - CHECK_EQ(trim(" a "), "a"); - CHECK_EQ(trim(" ab "), "ab"); -} - -void test_strip_indent() { - CHECK_EQ(strip_indent("", 0), ""); - CHECK_EQ(strip_indent("", 1), ""); - CHECK_EQ(strip_indent("", 3), ""); - CHECK_EQ(strip_indent(" ", 0), " "); - CHECK_EQ(strip_indent(" a", 0), " a"); - CHECK_EQ(strip_indent(" ", 1), ""); - CHECK_EQ(strip_indent(" a", 1), "a"); - CHECK_EQ(strip_indent(" ", 2), ""); - CHECK_EQ(strip_indent(" a", 2), "a"); - CHECK_EQ(strip_indent(" ", 0), " "); - CHECK_EQ(strip_indent(" a", 0), " a"); - CHECK_EQ(strip_indent(" ", 1), " "); - CHECK_EQ(strip_indent(" a", 1), " a"); - CHECK_EQ(strip_indent(" ", 2), ""); - CHECK_EQ(strip_indent(" a", 2), "a"); - CHECK_EQ(strip_indent(" ", 3), ""); - CHECK_EQ(strip_indent(" a", 3), "a"); -} diff --git a/cpp/tangle/boot.cc b/cpp/tangle/boot.cc deleted file mode 100644 index 86385965..00000000 --- a/cpp/tangle/boot.cc +++ /dev/null @@ -1,51 +0,0 @@ -#define unused __attribute__((unused)) - -#include<assert.h> -#include<cstdio> -#include<cstring> -#include<cstdlib> - -#include<vector> -using std::vector; -#include<list> -using std::list; -#include<stack> -using std::stack; -#include<utility> -using std::pair; -#include<map> -using std::map; -#include<algorithm> - -#include<string> -using std::string; -const size_t NOT_FOUND = string::npos; - -#include<iostream> -using std::istream; -using std::ostream; -using std::iostream; -using std::cin; -using std::cout; -using std::cerr; - -#include<sstream> -using std::istringstream; -using std::ostringstream; - -#include<fstream> -using std::ifstream; -using std::ofstream; - -#include <locale> -using std::isspace; // unicode-aware - - - -#include "type_list" - -#include "function_list" - -#include "file_list" - -#include "test_file_list" diff --git a/cpp/tangle/makefile b/cpp/tangle/makefile deleted file mode 100644 index cf4c3a88..00000000 --- a/cpp/tangle/makefile +++ /dev/null @@ -1,23 +0,0 @@ -tangle: makefile type_list function_list file_list test_file_list test_list - g++ -g -O3 -Wall -Wextra -fno-strict-aliasing boot.cc -o tangle - -type_list: boot.cc [0-9]*.cc - @# assumes struct decl has space before '{' - @grep -h "^struct .* {" [0-9]*.cc |perl -pwe 's/(struct *[^ ]*).*/$$1;/' > type_list - @grep -h typedef [0-9]*.cc >> type_list - -function_list: boot.cc [0-9]*.cc - @# assumes function decl has space before '{' - @grep -h "^[^ #].*) {" [0-9]*.cc |perl -pwe 's/ {.*/;/' > function_list - -file_list: boot.cc [0-9]*.cc - @ls [0-9]*.cc |grep -v "\.test\.cc$$" |perl -pwe 's/.*/#include "$$&"/' > file_list - -test_file_list: [0-9]*.test.cc - @ls [0-9]*.test.cc |perl -pwe 's/.*/#include "$$&"/' > test_file_list - -test_list: [0-9]*.cc - @grep -h "^[[:space:]]*void test_" [0-9]*.cc |perl -pwe 's/^\s*void (.*)\(\) {$$/$$1,/' > test_list - -clean: - -rm tangle *_list |