From c0f84b1ffa18eaf6f399aafe462f2a0f705dd009 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Thu, 7 Dec 2017 16:22:23 -0800 Subject: 4155 --- html/003trace.cc.html | 578 +++++++++++++++++++++++++------------------------- 1 file changed, 290 insertions(+), 288 deletions(-) (limited to 'html/003trace.cc.html') diff --git a/html/003trace.cc.html b/html/003trace.cc.html index 5087f342..f94ed738 100644 --- a/html/003trace.cc.html +++ b/html/003trace.cc.html @@ -178,299 +178,301 @@ if ('onhashchange' in window) { 117 ¦ return *curr_stream; 118 } 119 -120 // be sure to call this before messing with curr_stream or curr_label -121 void newline(); -122 // useful for debugging -123 string readable_contents(string label); // empty label = show everything -124 }; +120 void dump() { +121 ¦ ofstream fout("last_run"); +122 ¦ fout << readable_contents(""); +123 ¦ fout.close(); +124 } 125 -126 :(code) -127 void trace_stream::newline() { -128 if (!curr_stream) return; -129 string curr_contents = curr_stream->str(); -130 if (!curr_contents.empty()) { -131 ¦ past_lines.push_back(trace_line(curr_depth, trim(curr_label), curr_contents)); // preserve indent in contents -132 ¦ if ((!Hide_errors && curr_label == "error") -133 ¦ ¦ ¦ || Dump_trace -134 ¦ ¦ ¦ || (!Dump_label.empty() && curr_label == Dump_label)) -135 ¦ ¦ cerr << curr_label << ": " << curr_contents << '\n'; -136 } -137 delete curr_stream; -138 curr_stream = NULL; -139 curr_label.clear(); -140 curr_depth = Max_depth; -141 } -142 -143 string trace_stream::readable_contents(string label) { -144 ostringstream output; -145 label = trim(label); -146 for (vector<trace_line>::iterator p = past_lines.begin(); p != past_lines.end(); ++p) -147 ¦ if (label.empty() || label == p->label) { -148 ¦ ¦ output << std::setw(4) << p->depth << ' ' << p->label << ": " << p->contents << '\n'; -149 ¦ } -150 return output.str(); -151 } -152 -153 :(before "End Globals") -154 trace_stream* Trace_stream = NULL; -155 int Trace_errors = 0; // used only when Trace_stream is NULL -156 -157 :(before "End Includes") -158 #define CLEAR_TRACE delete Trace_stream, Trace_stream = new trace_stream; -159 -160 // Top-level helper. IMPORTANT: can't nest -161 #define trace(...) !Trace_stream ? cerr /*print nothing*/ : Trace_stream->stream(__VA_ARGS__) +126 // be sure to call this before messing with curr_stream or curr_label +127 void newline(); +128 // useful for debugging +129 string readable_contents(string label); // empty label = show everything +130 }; +131 +132 :(code) +133 void trace_stream::newline() { +134 if (!curr_stream) return; +135 string curr_contents = curr_stream->str(); +136 if (!curr_contents.empty()) { +137 ¦ past_lines.push_back(trace_line(curr_depth, trim(curr_label), curr_contents)); // preserve indent in contents +138 ¦ if ((!Hide_errors && curr_label == "error") +139 ¦ ¦ ¦ || Dump_trace +140 ¦ ¦ ¦ || (!Dump_label.empty() && curr_label == Dump_label)) +141 ¦ ¦ cerr << curr_label << ": " << curr_contents << '\n'; +142 } +143 delete curr_stream; +144 curr_stream = NULL; +145 curr_label.clear(); +146 curr_depth = Max_depth; +147 } +148 +149 string trace_stream::readable_contents(string label) { +150 ostringstream output; +151 label = trim(label); +152 for (vector<trace_line>::iterator p = past_lines.begin(); p != past_lines.end(); ++p) +153 ¦ if (label.empty() || label == p->label) { +154 ¦ ¦ output << std::setw(4) << p->depth << ' ' << p->label << ": " << p->contents << '\n'; +155 ¦ } +156 return output.str(); +157 } +158 +159 :(before "End Globals") +160 trace_stream* Trace_stream = NULL; +161 int Trace_errors = 0; // used only when Trace_stream is NULL 162 -163 // Just for debugging; 'git log' should never show any calls to 'dbg'. -164 #define dbg trace(0, "a") -165 #define DUMP(label) if (Trace_stream) cerr << Trace_stream->readable_contents(label); -166 -167 // Errors are a special layer. -168 #define raise (!Trace_stream ? (scroll_to_bottom_and_close_console(),++Trace_errors,cerr) /*do print*/ : Trace_stream->stream(Error_depth, "error")) -169 // If we aren't yet sure how to deal with some corner case, use assert_for_now -170 // to indicate that it isn't an inviolable invariant. -171 #define assert_for_now assert +163 :(before "End Includes") +164 #define CLEAR_TRACE delete Trace_stream, Trace_stream = new trace_stream; +165 +166 // Top-level helper. IMPORTANT: can't nest +167 #define trace(...) !Trace_stream ? cerr /*print nothing*/ : Trace_stream->stream(__VA_ARGS__) +168 +169 // Just for debugging; 'git log' should never show any calls to 'dbg'. +170 #define dbg trace(0, "a") +171 #define DUMP(label) if (Trace_stream) cerr << Trace_stream->readable_contents(label); 172 -173 //: Automatically close the console in some situations. -174 :(before "End One-time Setup") -175 atexit(scroll_to_bottom_and_close_console); -176 :(code) -177 void scroll_to_bottom_and_close_console() { -178 if (!tb_is_active()) return; -179 // leave the screen in a relatively clean state -180 tb_set_cursor(tb_width()-1, tb_height()-1); -181 cout << "\r\n"; -182 tb_shutdown(); -183 } -184 -185 // Inside tests, fail any tests that displayed (unexpected) errors. -186 // Expected errors in tests should always be hidden and silently checked for. -187 :(before "End Test Teardown") -188 if (Passed && !Hide_errors && trace_contains_errors()) { -189 Passed = false; -190 } -191 :(code) -192 bool trace_contains_errors() { -193 return Trace_errors > 0 || trace_count("error") > 0; -194 } -195 -196 :(before "End Types") -197 struct end {}; -198 :(code) -199 ostream& operator<<(ostream& os, unused end) { -200 if (Trace_stream) Trace_stream->newline(); -201 return os; -202 } -203 -204 :(before "End Globals") -205 bool Save_trace = false; -206 -207 // Trace_stream is a resource, lease_tracer uses RAII to manage it. -208 :(before "End Types") -209 struct lease_tracer { -210 lease_tracer(); -211 ~lease_tracer(); -212 }; -213 :(code) -214 lease_tracer::lease_tracer() { Trace_stream = new trace_stream; } -215 lease_tracer::~lease_tracer() { -216 if (!Trace_stream) return; // in case tests close Trace_stream -217 if (Save_trace) { -218 ¦ ofstream fout("last_trace"); -219 ¦ fout << Trace_stream->readable_contents(""); -220 ¦ fout.close(); -221 } -222 delete Trace_stream, Trace_stream = NULL; -223 } -224 :(before "End Includes") -225 #define START_TRACING_UNTIL_END_OF_SCOPE lease_tracer leased_tracer; -226 :(before "End Test Setup") -227 START_TRACING_UNTIL_END_OF_SCOPE -228 -229 :(before "End Includes") -230 #define CHECK_TRACE_CONTENTS(...) check_trace_contents(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) -231 -232 #define CHECK_TRACE_CONTAINS_ERRORS() CHECK(trace_contains_errors()) -233 #define CHECK_TRACE_DOESNT_CONTAIN_ERRORS() \ -234 if (Passed && trace_contains_errors()) { \ -235 ¦ cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): unexpected errors\n"; \ -236 ¦ DUMP("error"); \ -237 ¦ Passed = false; \ -238 ¦ return; \ -239 } -240 -241 #define CHECK_TRACE_COUNT(label, count) \ -242 if (Passed && trace_count(label) != (count)) { \ -243 ¦ cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): trace_count of " << label << " should be " << count << '\n'; \ -244 ¦ cerr << " got " << trace_count(label) << '\n'; /* multiple eval */ \ -245 ¦ DUMP(label); \ -246 ¦ Passed = false; \ -247 ¦ return; /* Currently we stop at the very first failure. */ \ -248 } -249 -250 #define CHECK_TRACE_DOESNT_CONTAIN(...) CHECK(trace_doesnt_contain(__VA_ARGS__)) +173 // Errors are a special layer. +174 #define raise (!Trace_stream ? (scroll_to_bottom_and_close_console(),++Trace_errors,cerr) /*do print*/ : Trace_stream->stream(Error_depth, "error")) +175 // If we aren't yet sure how to deal with some corner case, use assert_for_now +176 // to indicate that it isn't an inviolable invariant. +177 #define assert_for_now assert +178 +179 //: Automatically close the console in some situations. +180 :(before "End One-time Setup") +181 atexit(scroll_to_bottom_and_close_console); +182 :(code) +183 void scroll_to_bottom_and_close_console() { +184 if (!tb_is_active()) return; +185 // leave the screen in a relatively clean state +186 tb_set_cursor(tb_width()-1, tb_height()-1); +187 cout << "\r\n"; +188 tb_shutdown(); +189 } +190 +191 // Inside tests, fail any tests that displayed (unexpected) errors. +192 // Expected errors in tests should always be hidden and silently checked for. +193 :(before "End Test Teardown") +194 if (Passed && !Hide_errors && trace_contains_errors()) { +195 Passed = false; +196 } +197 :(code) +198 bool trace_contains_errors() { +199 return Trace_errors > 0 || trace_count("error") > 0; +200 } +201 +202 :(before "End Types") +203 struct end {}; +204 :(code) +205 ostream& operator<<(ostream& os, unused end) { +206 if (Trace_stream) Trace_stream->newline(); +207 return os; +208 } +209 +210 :(before "End Globals") +211 bool Save_trace = false; +212 +213 // Trace_stream is a resource, lease_tracer uses RAII to manage it. +214 :(before "End Types") +215 struct lease_tracer { +216 lease_tracer(); +217 ~lease_tracer(); +218 }; +219 :(code) +220 lease_tracer::lease_tracer() { Trace_stream = new trace_stream; } +221 lease_tracer::~lease_tracer() { +222 if (!Trace_stream) return; // in case tests close Trace_stream +223 if (Save_trace) Trace_stream->dump(); +224 delete Trace_stream, Trace_stream = NULL; +225 } +226 :(before "End Includes") +227 #define START_TRACING_UNTIL_END_OF_SCOPE lease_tracer leased_tracer; +228 :(before "End Test Setup") +229 START_TRACING_UNTIL_END_OF_SCOPE +230 +231 :(before "End Includes") +232 #define CHECK_TRACE_CONTENTS(...) check_trace_contents(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) +233 +234 #define CHECK_TRACE_CONTAINS_ERRORS() CHECK(trace_contains_errors()) +235 #define CHECK_TRACE_DOESNT_CONTAIN_ERRORS() \ +236 if (Passed && trace_contains_errors()) { \ +237 ¦ cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): unexpected errors\n"; \ +238 ¦ DUMP("error"); \ +239 ¦ Passed = false; \ +240 ¦ return; \ +241 } +242 +243 #define CHECK_TRACE_COUNT(label, count) \ +244 if (Passed && trace_count(label) != (count)) { \ +245 ¦ cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): trace_count of " << label << " should be " << count << '\n'; \ +246 ¦ cerr << " got " << trace_count(label) << '\n'; /* multiple eval */ \ +247 ¦ DUMP(label); \ +248 ¦ Passed = false; \ +249 ¦ return; /* Currently we stop at the very first failure. */ \ +250 } 251 -252 :(code) -253 bool check_trace_contents(string FUNCTION, string FILE, int LINE, string expected) { -254 if (!Passed) return false; -255 if (!Trace_stream) return false; -256 vector<string> expected_lines = split(expected, "^D"); -257 int curr_expected_line = 0; -258 while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) -259 ¦ ++curr_expected_line; -260 if (curr_expected_line == SIZE(expected_lines)) return true; -261 string label, contents; -262 split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); -263 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -264 ¦ if (label != p->label) continue; -265 ¦ if (contents != trim(p->contents)) continue; -266 ¦ ++curr_expected_line; -267 ¦ while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) -268 ¦ ¦ ++curr_expected_line; -269 ¦ if (curr_expected_line == SIZE(expected_lines)) return true; -270 ¦ split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); -271 } -272 -273 if (line_exists_anywhere(label, contents)) { -274 ¦ cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): line [" << label << ": " << contents << "] out of order in trace:\n"; -275 ¦ DUMP(""); -276 } -277 else { -278 ¦ cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << contents << "] in trace:\n"; -279 ¦ DUMP(label); -280 } -281 Passed = false; -282 return false; -283 } -284 -285 void split_label_contents(const string& s, string* label, string* contents) { -286 static const string delim(": "); -287 size_t pos = s.find(delim); -288 if (pos == string::npos) { -289 ¦ *label = ""; -290 ¦ *contents = trim(s); -291 } -292 else { -293 ¦ *label = trim(s.substr(0, pos)); -294 ¦ *contents = trim(s.substr(pos+SIZE(delim))); -295 } -296 } -297 -298 bool line_exists_anywhere(const string& label, const string& contents) { -299 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -300 ¦ if (label != p->label) continue; -301 ¦ if (contents == trim(p->contents)) return true; -302 } -303 return false; -304 } -305 -306 int trace_count(string label) { -307 return trace_count(label, ""); -308 } -309 -310 int trace_count(string label, string line) { -311 if (!Trace_stream) return 0; -312 long result = 0; -313 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -314 ¦ if (label == p->label) { -315 ¦ ¦ if (line == "" || trim(line) == trim(p->contents)) -316 ¦ ¦ ¦ ++result; -317 ¦ } -318 } -319 return result; -320 } -321 -322 int trace_count_prefix(string label, string prefix) { -323 if (!Trace_stream) return 0; -324 long result = 0; -325 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -326 ¦ if (label == p->label) { -327 ¦ ¦ if (starts_with(trim(p->contents), trim(prefix))) -328 ¦ ¦ ¦ ++result; -329 ¦ } -330 } -331 return result; -332 } -333 -334 bool trace_doesnt_contain(string label, string line) { -335 return trace_count(label, line) == 0; -336 } -337 -338 bool trace_doesnt_contain(string expected) { -339 vector<string> tmp = split_first(expected, ": "); -340 return trace_doesnt_contain(tmp.at(0), tmp.at(1)); -341 } -342 -343 vector<string> split(string s, string delim) { -344 vector<string> result; -345 size_t begin=0, end=s.find(delim); -346 while (true) { -347 ¦ if (end == string::npos) { -348 ¦ ¦ result.push_back(string(s, begin, string::npos)); -349 ¦ ¦ break; -350 ¦ } -351 ¦ result.push_back(string(s, begin, end-begin)); -352 ¦ begin = end+SIZE(delim); -353 ¦ end = s.find(delim, begin); -354 } -355 return result; -356 } -357 -358 vector<string> split_first(string s, string delim) { -359 vector<string> result; -360 size_t end=s.find(delim); -361 result.push_back(string(s, 0, end)); -362 if (end != string::npos) -363 ¦ result.push_back(string(s, end+SIZE(delim), string::npos)); -364 return result; -365 } -366 -367 string trim(const string& s) { -368 string::const_iterator first = s.begin(); -369 while (first != s.end() && isspace(*first)) -370 ¦ ++first; -371 if (first == s.end()) return ""; -372 -373 string::const_iterator last = --s.end(); -374 while (last != s.begin() && isspace(*last)) -375 ¦ --last; -376 ++last; -377 return string(first, last); -378 } -379 -380 :(before "End Includes") -381 #include <vector> -382 using std::vector; -383 #include <list> -384 using std::list; -385 #include <map> -386 using std::map; -387 #include <set> -388 using std::set; -389 -390 #include <sstream> -391 using std::istringstream; -392 using std::ostringstream; -393 -394 #include <fstream> -395 using std::ifstream; -396 using std::ofstream; -397 -398 #include "termbox/termbox.h" +252 #define CHECK_TRACE_DOESNT_CONTAIN(...) CHECK(trace_doesnt_contain(__VA_ARGS__)) +253 +254 :(code) +255 bool check_trace_contents(string FUNCTION, string FILE, int LINE, string expected) { +256 if (!Passed) return false; +257 if (!Trace_stream) return false; +258 vector<string> expected_lines = split(expected, "^D"); +259 int curr_expected_line = 0; +260 while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) +261 ¦ ++curr_expected_line; +262 if (curr_expected_line == SIZE(expected_lines)) return true; +263 string label, contents; +264 split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); +265 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +266 ¦ if (label != p->label) continue; +267 ¦ if (contents != trim(p->contents)) continue; +268 ¦ ++curr_expected_line; +269 ¦ while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) +270 ¦ ¦ ++curr_expected_line; +271 ¦ if (curr_expected_line == SIZE(expected_lines)) return true; +272 ¦ split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); +273 } +274 +275 if (line_exists_anywhere(label, contents)) { +276 ¦ cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): line [" << label << ": " << contents << "] out of order in trace:\n"; +277 ¦ DUMP(""); +278 } +279 else { +280 ¦ cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << contents << "] in trace:\n"; +281 ¦ DUMP(label); +282 } +283 Passed = false; +284 return false; +285 } +286 +287 void split_label_contents(const string& s, string* label, string* contents) { +288 static const string delim(": "); +289 size_t pos = s.find(delim); +290 if (pos == string::npos) { +291 ¦ *label = ""; +292 ¦ *contents = trim(s); +293 } +294 else { +295 ¦ *label = trim(s.substr(0, pos)); +296 ¦ *contents = trim(s.substr(pos+SIZE(delim))); +297 } +298 } +299 +300 bool line_exists_anywhere(const string& label, const string& contents) { +301 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +302 ¦ if (label != p->label) continue; +303 ¦ if (contents == trim(p->contents)) return true; +304 } +305 return false; +306 } +307 +308 int trace_count(string label) { +309 return trace_count(label, ""); +310 } +311 +312 int trace_count(string label, string line) { +313 if (!Trace_stream) return 0; +314 long result = 0; +315 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +316 ¦ if (label == p->label) { +317 ¦ ¦ if (line == "" || trim(line) == trim(p->contents)) +318 ¦ ¦ ¦ ++result; +319 ¦ } +320 } +321 return result; +322 } +323 +324 int trace_count_prefix(string label, string prefix) { +325 if (!Trace_stream) return 0; +326 long result = 0; +327 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +328 ¦ if (label == p->label) { +329 ¦ ¦ if (starts_with(trim(p->contents), trim(prefix))) +330 ¦ ¦ ¦ ++result; +331 ¦ } +332 } +333 return result; +334 } +335 +336 bool trace_doesnt_contain(string label, string line) { +337 return trace_count(label, line) == 0; +338 } +339 +340 bool trace_doesnt_contain(string expected) { +341 vector<string> tmp = split_first(expected, ": "); +342 return trace_doesnt_contain(tmp.at(0), tmp.at(1)); +343 } +344 +345 vector<string> split(string s, string delim) { +346 vector<string> result; +347 size_t begin=0, end=s.find(delim); +348 while (true) { +349 ¦ if (end == string::npos) { +350 ¦ ¦ result.push_back(string(s, begin, string::npos)); +351 ¦ ¦ break; +352 ¦ } +353 ¦ result.push_back(string(s, begin, end-begin)); +354 ¦ begin = end+SIZE(delim); +355 ¦ end = s.find(delim, begin); +356 } +357 return result; +358 } +359 +360 vector<string> split_first(string s, string delim) { +361 vector<string> result; +362 size_t end=s.find(delim); +363 result.push_back(string(s, 0, end)); +364 if (end != string::npos) +365 ¦ result.push_back(string(s, end+SIZE(delim), string::npos)); +366 return result; +367 } +368 +369 string trim(const string& s) { +370 string::const_iterator first = s.begin(); +371 while (first != s.end() && isspace(*first)) +372 ¦ ++first; +373 if (first == s.end()) return ""; +374 +375 string::const_iterator last = --s.end(); +376 while (last != s.begin() && isspace(*last)) +377 ¦ --last; +378 ++last; +379 return string(first, last); +380 } +381 +382 :(before "End Includes") +383 #include <vector> +384 using std::vector; +385 #include <list> +386 using std::list; +387 #include <map> +388 using std::map; +389 #include <set> +390 using std::set; +391 +392 #include <sstream> +393 using std::istringstream; +394 using std::ostringstream; +395 +396 #include <fstream> +397 using std::ifstream; +398 using std::ofstream; 399 -400 :(before "End Globals") -401 //: In future layers we'll use the depth field as follows: -402 //: -403 //: Errors will be depth 0. -404 //: Mu 'applications' will be able to use depths 1-100 as they like. -405 //: Primitive statements will occupy 101-9989 -406 extern const int Initial_callstack_depth = 101; -407 extern const int Max_callstack_depth = 9989; -408 //: Finally, details of primitive Mu statements will occupy depth 9990-9999 -409 //: (more on that later as well) -410 //: -411 //: This framework should help us hide some details at each level, mixing -412 //: static ideas like layers with the dynamic notion of call-stack depth. +400 #include "termbox/termbox.h" +401 +402 :(before "End Globals") +403 //: In future layers we'll use the depth field as follows: +404 //: +405 //: Errors will be depth 0. +406 //: Mu 'applications' will be able to use depths 1-100 as they like. +407 //: Primitive statements will occupy 101-9989 +408 extern const int Initial_callstack_depth = 101; +409 extern const int Max_callstack_depth = 9989; +410 //: Finally, details of primitive Mu statements will occupy depth 9990-9999 +411 //: (more on that later as well) +412 //: +413 //: This framework should help us hide some details at each level, mixing +414 //: static ideas like layers with the dynamic notion of call-stack depth. -- cgit 1.4.1-2-gfad0