about summary refs log tree commit diff stats
path: root/src/command
ModeNameSize
-rw-r--r--cmd_ac.c162555log stats plain blame
-rw-r--r--cmd_ac.h2415log stats plain blame
-rw-r--r--cmd_defs.c138935log stats plain blame
-rw-r--r--cmd_defs.h2026log stats plain blame
-rw-r--r--cmd_funcs.c351785log stats plain blame
-rw-r--r--cmd_funcs.h17310log stats plain blame
a> 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - 003trace.cc</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v1">
<meta name="syntax" content="cpp">
<meta name="settings" content="use_css,pre_wrap,no_foldcolumn,expand_tabs,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
body { font-family: monospace; color: #eeeeee; background-color: #080808; }
* { font-size: 1.05em; }
.PreProc { color: #c000c0; }
.cSpecial { color: #008000; }
.Constant { color: #00a0a0; }
.Comment { color: #9090ff; }
.Delimiter { color: #a04060; }
.Identifier { color: #804000; }
-->
</style>

<script type='text/javascript'>
<!--

-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<span class="Comment">//: The goal of this skeleton is to make programs more easy to understand and</span>
<span class="Comment">//: more malleable, easy to rewrite in radical ways without accidentally</span>
<span class="Comment">//: breaking some corner case. Tests further both goals. They help</span>
<span class="Comment">//: understandability by letting one make small changes and get feedback. What</span>
<span class="Comment">//: if I wrote this line like so? What if I removed this function call, is it</span>
<span class="Comment">//: really necessary? Just try it, see if the tests pass. Want to explore</span>
<span class="Comment">//: rewriting this bit in this way? Tests put many refactorings on a firmer</span>
<span class="Comment">//: footing.</span>
<span class="Comment">//:</span>
<span class="Comment">//: But the usual way we write tests seems incomplete. Refactorings tend to</span>
<span class="Comment">//: work in the small, but don't help with changes to function boundaries. If</span>
<span class="Comment">//: you want to extract a new function you have to manually test-drive it to</span>
<span class="Comment">//: create tests for it. If you want to inline a function its tests are no</span>
<span class="Comment">//: longer valid. In both cases you end up having to reorganize code as well as</span>
<span class="Comment">//: tests, an error-prone activity.</span>
<span class="Comment">//:</span>
<span class="Comment">//: This file tries to fix this problem by supporting domain-driven testing</span>
<span class="Comment">//: We try to focus on the domain of inputs the program should work on. All</span>
<span class="Comment">//: tests invoke the program in a single way: by calling run() with different</span>
<span class="Comment">//: inputs. The program operates on the input and logs _facts_ it deduces to a</span>
<span class="Comment">//: trace:</span>
<span class="Comment">//:   trace(&quot;label&quot;) &lt;&lt; &quot;fact 1: &quot; &lt;&lt; val;</span>
<span class="Comment">//:</span>
<span class="Comment">//: The tests check for facts:</span>
<span class="Comment">//:   :(scenario foo)</span>
<span class="Comment">//:   34  # call run() with this input</span>
<span class="Comment">//:   +label: fact 1: 34  # trace should have logged this at the end</span>
<span class="Comment">//:   -label: fact 1: 35  # trace should never contain such a line</span>
<span class="Comment">//:</span>
<span class="Comment">//: Since we never call anything but the run() function directly, we never have</span>
<span class="Comment">//: to rewrite the tests when we reorganize the internals of the program. We</span>
<span class="Comment">//: just have to make sure our rewrite deduces the same facts about the domain,</span>
<span class="Comment">//: and that's something we're going to have to do anyway.</span>
<span class="Comment">//:</span>
<span class="Comment">//: To avoid the combinatorial explosion of integration tests, we organize the</span>
<span class="Comment">//: program into different layers, and each fact is logged to the trace with a</span>
<span class="Comment">//: specific label. Individual tests can focus on specific labels. In essence,</span>
<span class="Comment">//: validating the facts logged with a specific label is identical to calling</span>
<span class="Comment">//: some internal subsystem.</span>
<span class="Comment">//:</span>
<span class="Comment">//: Traces interact salubriously with layers. Thanks to our ordering</span>
<span class="Comment">//: directives, each layer can contain its own tests. They may rely on other</span>
<span class="Comment">//: layers, but when a test fails its usually due to breakage in the same</span>
<span class="Comment">//: layer. When multiple tests fail, it's usually useful to debug the very</span>
<span class="Comment">//: first test to fail. This is in contrast with the traditional approach,</span>
<span class="Comment">//: where changes can cause breakages in faraway subsystems, and picking the</span>
<span class="Comment">//: right test to debug can be an important skill to pick up.</span>
<span class="Comment">//:</span>
<span class="Comment">//: To build robust tests, trace facts about your domain rather than details of</span>
<span class="Comment">//: how you computed them.</span>
<span class="Comment">//:</span>
<span class="Comment">//: More details: <a href="http://akkartik.name/blog/tracing-tests">http://akkartik.name/blog/tracing-tests</a></span>
<span class="Comment">//:</span>
<span class="Comment">//: ---</span>
<span class="Comment">//:</span>
<span class="Comment">//: Between layers and domain-driven testing, programming starts to look like a</span>
<span class="Comment">//: fundamentally different activity. Instead of a) superficial, b) local rules</span>
<span class="Comment">//: on c) code [like <a href="http://blog.bbv.ch/2013/06/05/clean-code-cheat-sheet],">http://blog.bbv.ch/2013/06/05/clean-code-cheat-sheet],</a></span>
<span class="Comment">//: we allow programmers to engage with the a) deep, b) global structure of the</span>
<span class="Comment">//: c) domain. If you can systematically track discontinuities in the domain</span>
<span class="Comment">//: you don't care if the code used gotos as long as it passed the tests. If</span>
<span class="Comment">//: tests become more robust to run it becomes easier to try out radically</span>
<span class="Comment">//: different implementations for the same program. If code is super-easy to</span>
<span class="Comment">//: rewrite, it becomes less important what indentation style it uses, or that</span>
<span class="Comment">//: the objects are appropriately encapsulated, or that the functions are</span>
<span class="Comment">//: referentially transparent.</span>
<span class="Comment">//:</span>
<span class="Comment">//: Instead of plumbing, programming becomes building and gradually refining a</span>
<span class="Comment">//: map of the environment the program must operate under. Whether a program is</span>
<span class="Comment">//: 'correct' at a given point in time is a red herring; what matters is</span>
<span class="Comment">//: avoiding regression by monotonically nailing down the more 'eventful' parts</span>
<span class="Comment">//: of the terrain. It helps readers new and old and rewards curiosity to</span>
<span class="Comment">//: organize large programs in self-similar hiearchies of example scenarios</span>
<span class="Comment">//: colocated with the code that makes them work.</span>
<span class="Comment">//:</span>
<span class="Comment">//:   &quot;Programming properly should be regarded as an activity by which</span>
<span class="Comment">//:   programmers form a mental model, rather than as production of a program.&quot;</span>
<span class="Comment">//:   -- Peter Naur (<a href="http://alistair.cockburn.us/ASD+book+extract%3A+%22Naur,+Ehn,+Musashi%22)">http://alistair.cockburn.us/ASD+book+extract%3A+%22Naur,+Ehn,+Musashi%22)</a></span>

<span class="Delimiter">:(before &quot;int main&quot;)</span>
<span class="Comment">// End Tracing  // hack to ensure most code in this layer comes before anything else</span>

<span class="Delimiter">:(before &quot;End Types&quot;)</span>
struct trace_line <span class="Delimiter">{</span>
  int depth<span class="Delimiter">;</span>  <span class="Comment">// optional field just to help browse traces later</span>
  string label<span class="Delimiter">;</span>
  string contents<span class="Delimiter">;</span>
  trace_line<span class="Delimiter">(</span>string l<span class="Delimiter">,</span> string c<span class="Delimiter">)</span> :depth<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">),</span> label<span class="Delimiter">(</span>l<span class="Delimiter">),</span> contents<span class="Delimiter">(</span>c<span class="Delimiter">)</span> <span class="Delimiter">{}</span>
  trace_line<span class="Delimiter">(</span>int d<span class="Delimiter">,</span> string l<span class="Delimiter">,</span> string c<span class="Delimiter">)</span> :depth<span class="Delimiter">(</span>d<span class="Delimiter">),</span> label<span class="Delimiter">(</span>l<span class="Delimiter">),</span> contents<span class="Delimiter">(</span>c<span class="Delimiter">)</span> <span class="Delimiter">{}</span>
<span class="Delimiter">};</span>

<span class="Delimiter">:(before &quot;End Globals&quot;)</span>
const int Max_depth = <span class="Constant">9999</span><span class="Delimiter">;</span>
const int Error_depth = <span class="Constant">0</span><span class="Delimiter">;</span>  <span class="Comment">// definitely always print errors</span>
const int App_depth = <span class="Constant">2</span><span class="Delimiter">;</span>  <span class="Comment">// temporarily where all mu code will trace to</span>
<span class="Delimiter">:(before &quot;End Tracing&quot;)</span>
bool Hide_errors = <span class="Constant">false</span><span class="Delimiter">;</span>
<span class="Delimiter">:(before &quot;End Setup&quot;)</span>
Hide_errors = <span class="Constant">false</span><span class="Delimiter">;</span>

<span class="Delimiter">:(before &quot;End Tracing&quot;)</span>
struct trace_stream <span class="Delimiter">{</span>
  vector&lt;trace_line&gt; past_lines<span class="Delimiter">;</span>
  <span class="Comment">// accumulator for current line</span>
  ostringstream* curr_stream<span class="Delimiter">;</span>
  string curr_label<span class="Delimiter">;</span>
  int curr_depth<span class="Delimiter">;</span>
  int callstack_depth<span class="Delimiter">;</span>
  int collect_depth<span class="Delimiter">;</span>
  ofstream null_stream<span class="Delimiter">;</span>  <span class="Comment">// never opens a file, so writes silently fail</span>
  trace_stream<span class="Delimiter">()</span> :curr_stream<span class="Delimiter">(</span><span class="Constant">NULL</span><span class="Delimiter">),</span> curr_depth<span class="Delimiter">(</span>Max_depth<span class="Delimiter">),</span> callstack_depth<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">),</span> collect_depth<span class="Delimiter">(</span>Max_depth<span class="Delimiter">)</span> <span class="Delimiter">{}</span>
  ~trace_stream<span class="Delimiter">()</span> <span class="Delimiter">{</span> if <span class="Delimiter">(</span>curr_stream<span class="Delimiter">)</span> delete curr_stream<span class="Delimiter">;</span> <span class="Delimiter">}</span>

  ostream&amp; stream<span class="Delimiter">(</span>string label<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Identifier">return</span> stream<span class="Delimiter">(</span>Max_depth<span class="Delimiter">,</span> label<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>

  ostream&amp; stream<span class="Delimiter">(</span>int depth<span class="Delimiter">,</span> string label<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    if <span class="Delimiter">(</span>depth &gt; collect_depth<span class="Delimiter">)</span> <span class="Identifier">return</span> null_stream<span class="Delimiter">;</span>
    curr_stream = new ostringstream<span class="Delimiter">;</span>
    curr_label = label<span class="Delimiter">;</span>
    curr_depth = depth<span class="Delimiter">;</span>
    <span class="Identifier">return</span> *curr_stream<span class="Delimiter">;</span>
  <span class="Delimiter">}</span>

  <span class="Comment">// be sure to call this before messing with curr_stream or curr_label</span>
  void newline<span class="Delimiter">()</span> <span class="Delimiter">{</span>
    if <span class="Delimiter">(</span>!curr_stream<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
    string curr_contents = curr_stream<span class="Delimiter">-&gt;</span>str<span class="Delimiter">();</span>
    if <span class="Delimiter">(</span>curr_contents<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
    past_lines<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>trace_line<span class="Delimiter">(</span>curr_depth<span class="Delimiter">,</span> trim<span class="Delimiter">(</span>curr_label<span class="Delimiter">),</span> curr_contents<span class="Delimiter">));</span>  <span class="Comment">// preserve indent in contents</span>
    if <span class="Delimiter">(</span>!Hide_errors &amp;&amp; curr_label == <span class="Constant">&quot;error&quot;</span><span class="Delimiter">)</span>
      cerr &lt;&lt; curr_label &lt;&lt; <span class="Constant">&quot;: &quot;</span> &lt;&lt; curr_contents &lt;&lt; <span class="cSpecial">'\n'</span><span class="Delimiter">;</span>
    delete curr_stream<span class="Delimiter">;</span>
    curr_stream = <span class="Constant">NULL</span><span class="Delimiter">;</span>
    curr_label<span class="Delimiter">.</span>clear<span class="Delimiter">();</span>
    curr_depth = Max_depth<span class="Delimiter">;</span>
  <span class="Delimiter">}</span>

  <span class="Comment">// useful for debugging</span>
  string readable_contents<span class="Delimiter">(</span>string label<span class="Delimiter">)</span> <span class="Delimiter">{</span>  <span class="Comment">// empty label = show everything</span>
    ostringstream output<span class="Delimiter">;</span>
    label = trim<span class="Delimiter">(</span>label<span class="Delimiter">);</span>
    for <span class="Delimiter">(</span>vector&lt;trace_line&gt;::iterator p = past_lines<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != past_lines<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span>
      if <span class="Delimiter">(</span>label<span class="Delimiter">.</span>empty<span class="Delimiter">()</span> || label == p<span class="Delimiter">-&gt;</span>label<span class="Delimiter">)</span> <span class="Delimiter">{</span>
        output &lt;&lt; std::setw<span class="Delimiter">(</span><span class="Constant">4</span><span class="Delimiter">)</span> &lt;&lt; p<span class="Delimiter">-&gt;</span>depth &lt;&lt; <span class="Constant">' '</span> &lt;&lt; p<span class="Delimiter">-&gt;</span>label &lt;&lt; <span class="Constant">&quot;: &quot;</span> &lt;&lt; p<span class="Delimiter">-&gt;</span>contents &lt;&lt; <span class="cSpecial">'\n'</span><span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
    <span class="Identifier">return</span> output<span class="Delimiter">.</span>str<span class="Delimiter">();</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">};</span>

^L

trace_stream* Trace_stream = <span class="Constant">NULL</span><span class="Delimiter">;</span>

<span class="Comment">// Top-level helper. IMPORTANT: can't nest</span>
<span class="PreProc">#define trace(</span><span class="Delimiter">...</span><span class="PreProc">)  !Trace_stream ? cerr </span><span class="Comment">/*</span><span class="Comment">print nothing</span><span class="Comment">*/</span><span class="PreProc"> : Trace_stream</span><span class="Delimiter">-&gt;</span><span class="PreProc">stream(__VA_ARGS__)</span>

<span class="Comment">// Errors are a special layer.</span>
<span class="PreProc">#define raise_error  (!Trace_stream ? (tb_shutdown()</span><span class="Delimiter">,</span><span class="PreProc">cerr) </span><span class="Comment">/*</span><span class="Comment">do print</span><span class="Comment">*/</span><span class="PreProc"> : Trace_stream</span><span class="Delimiter">-&gt;</span><span class="PreProc">stream(Error_depth</span><span class="Delimiter">,</span><span class="PreProc"> </span><span class="Constant">&quot;error&quot;</span><span class="PreProc">))</span>
<span class="Comment">// Inside tests, fail any tests that displayed (unexpected) errors.</span>
<span class="Comment">// Expected errors in tests should always be hidden and silently checked for.</span>
<span class="Delimiter">:(before &quot;End Test Teardown&quot;)</span>
if <span class="Delimiter">(</span>Passed &amp;&amp; !Hide_errors &amp;&amp; trace_count<span class="Delimiter">(</span><span class="Constant">&quot;error&quot;</span><span class="Delimiter">)</span> &gt; <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
  Passed = <span class="Constant">false</span><span class="Delimiter">;</span>
  ++Num_failures<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="Delimiter">:(before &quot;End Types&quot;)</span>
struct end <span class="Delimiter">{};</span>
<span class="Delimiter">:(before &quot;End Tracing&quot;)</span>
ostream&amp; operator&lt;&lt;<span class="Delimiter">(</span>ostream&amp; os<span class="Delimiter">,</span> unused end<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  if <span class="Delimiter">(</span>Trace_stream<span class="Delimiter">)</span> Trace_stream<span class="Delimiter">-&gt;</span>newline<span class="Delimiter">();</span>
  <span class="Identifier">return</span> os<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="PreProc">#define CLEAR_TRACE  </span>delete<span class="PreProc"> Trace_stream</span><span class="Delimiter">,</span><span class="PreProc"> Trace_stream = </span>new<span class="PreProc"> trace_stream</span><span class="Delimiter">;</span>

<span class="PreProc">#define DUMP(label)  </span>if<span class="PreProc"> (Trace_stream) cerr &lt;&lt; Trace_stream</span><span class="Delimiter">-&gt;</span><span class="PreProc">readable_contents(label)</span><span class="Delimiter">;</span>

<span class="Comment">// All scenarios save their traces in the repo, just like code. This gives</span>
<span class="Comment">// future readers more meat when they try to make sense of a new project.</span>
static string Trace_dir = <span class="Constant">&quot;.traces/&quot;</span><span class="Delimiter">;</span>
string Trace_file<span class="Delimiter">;</span>

<span class="Comment">// Trace_stream is a resource, lease_tracer uses RAII to manage it.</span>
struct lease_tracer <span class="Delimiter">{</span>
  lease_tracer<span class="Delimiter">()</span> <span class="Delimiter">{</span> Trace_stream = new trace_stream<span class="Delimiter">;</span> <span class="Delimiter">}</span>
  ~lease_tracer<span class="Delimiter">()</span> <span class="Delimiter">{</span>
    if <span class="Delimiter">(</span>!Trace_stream<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>  <span class="Comment">// in case tests close Trace_stream</span>
    if <span class="Delimiter">(</span>!Trace_file<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Delimiter">{</span>
      ofstream fout<span class="Delimiter">((</span>Trace_dir+Trace_file<span class="Delimiter">).</span>c_str<span class="Delimiter">());</span>
      fout &lt;&lt; Trace_stream<span class="Delimiter">-&gt;</span>readable_contents<span class="Delimiter">(</span><span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span>
      fout<span class="Delimiter">.</span>close<span class="Delimiter">();</span>
    <span class="Delimiter">}</span>
    delete Trace_stream<span class="Delimiter">,</span> Trace_stream = <span class="Constant">NULL</span><span class="Delimiter">,</span> Trace_file = <span class="Constant">&quot;&quot;</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">};</span>

<span class="PreProc">#define START_TRACING_UNTIL_END_OF_SCOPE  lease_tracer leased_tracer</span><span class="Delimiter">;</span>
<span class="Delimiter">:(before &quot;End Test Setup&quot;)</span>
START_TRACING_UNTIL_END_OF_SCOPE

<span class="Delimiter">:(before &quot;End Includes&quot;)</span>
<span class="PreProc">#define CHECK_TRACE_CONTENTS(</span><span class="Delimiter">...</span><span class="PreProc">)  check_trace_contents(__FUNCTION__</span><span class="Delimiter">,</span><span class="PreProc"> </span><span class="Constant">__FILE__</span><span class="Delimiter">,</span><span class="PreProc"> </span><span class="Constant">__LINE__</span><span class="Delimiter">,</span><span class="PreProc"> __VA_ARGS__)</span>

<span class="Delimiter">:(before &quot;End Tracing&quot;)</span>
bool check_trace_contents<span class="Delimiter">(</span>string FUNCTION<span class="Delimiter">,</span> string FILE<span class="Delimiter">,</span> int LINE<span class="Delimiter">,</span> string expected<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  if <span class="Delimiter">(</span>!Trace_stream<span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
  vector&lt;string&gt; expected_lines = split<span class="Delimiter">(</span>expected<span class="Delimiter">,</span> <span class="Constant">&quot;^D&quot;</span><span class="Delimiter">);</span>
  long long int curr_expected_line = <span class="Constant">0</span><span class="Delimiter">;</span>
  while <span class="Delimiter">(</span>curr_expected_line &lt; SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">)</span> &amp;&amp; expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>empty<span class="Delimiter">())</span>
    ++curr_expected_line<span class="Delimiter">;</span>
  if <span class="Delimiter">(</span>curr_expected_line == SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">))</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span>
  string label<span class="Delimiter">,</span> contents<span class="Delimiter">;</span>
  split_label_contents<span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">),</span> &amp;label<span class="Delimiter">,</span> &amp;contents<span class="Delimiter">);</span>
  for <span class="Delimiter">(</span>vector&lt;trace_line&gt;::iterator p = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    if <span class="Delimiter">(</span>label != p<span class="Delimiter">-&gt;</span>label<span class="Delimiter">)</span>
      <span class="Identifier">continue</span><span class="Delimiter">;</span>

    if <span class="Delimiter">(</span>contents != trim<span class="Delimiter">(</span>p<span class="Delimiter">-&gt;</span>contents<span class="Delimiter">))</span>
      <span class="Identifier">continue</span><span class="Delimiter">;</span>

    ++curr_expected_line<span class="Delimiter">;</span>
    while <span class="Delimiter">(</span>curr_expected_line &lt; SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">)</span> &amp;&amp; expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>empty<span class="Delimiter">())</span>
      ++curr_expected_line<span class="Delimiter">;</span>
    if <span class="Delimiter">(</span>curr_expected_line == SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">))</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span>
    split_label_contents<span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">),</span> &amp;label<span class="Delimiter">,</span> &amp;contents<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>

  ++Num_failures<span class="Delimiter">;</span>
  cerr &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span> &lt;&lt; FUNCTION &lt;&lt; <span class="Constant">&quot;(&quot;</span> &lt;&lt; FILE &lt;&lt; <span class="Constant">&quot;:&quot;</span> &lt;&lt; LINE &lt;&lt; <span class="Constant">&quot;): missing [&quot;</span> &lt;&lt; contents &lt;&lt; <span class="Constant">&quot;] in trace:</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span>
  DUMP<span class="Delimiter">(</span>label<span class="Delimiter">);</span>
  Passed = <span class="Constant">false</span><span class="Delimiter">;</span>
  <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>

void split_label_contents<span class="Delimiter">(</span>const string&amp; s<span class="Delimiter">,</span> string* label<span class="Delimiter">,</span> string* contents<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  static const string delim<span class="Delimiter">(</span><span class="Constant">&quot;: &quot;</span><span class="Delimiter">);</span>
  size_t pos = s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<span class="Delimiter">);</span>
  if <span class="Delimiter">(</span>pos == string::npos<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    *label = <span class="Constant">&quot;&quot;</span><span class="Delimiter">;</span>
    *contents = trim<span class="Delimiter">(</span>s<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
  else <span class="Delimiter">{</span>
    *label = trim<span class="Delimiter">(</span>s<span class="Delimiter">.</span>substr<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">,</span> pos<span class="Delimiter">));</span>
    *contents = trim<span class="Delimiter">(</span>s<span class="Delimiter">.</span>substr<span class="Delimiter">(</span>pos+SIZE<span class="Delimiter">(</span>delim<span class="Delimiter">)));</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">}</span>

^L

int trace_count<span class="Delimiter">(</span>string label<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Identifier">return</span> trace_count<span class="Delimiter">(</span>label<span class="Delimiter">,</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>

int trace_count<span class="Delimiter">(</span>string label<span class="Delimiter">,</span> string line<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  if <span class="Delimiter">(</span>!Trace_stream<span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">0</span><span class="Delimiter">;</span>
  long result = <span class="Constant">0</span><span class="Delimiter">;</span>
  for <span class="Delimiter">(</span>vector&lt;trace_line&gt;::iterator p = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    if <span class="Delimiter">(</span>label == p<span class="Delimiter">-&gt;</span>label<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      if <span class="Delimiter">(</span>line == <span class="Constant">&quot;&quot;</span> || trim<span class="Delimiter">(</span>line<span class="Delimiter">)</span> == trim<span class="Delimiter">(</span>p<span class="Delimiter">-&gt;</span>contents<span class="Delimiter">))</span>
        ++result<span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
  <span class="Delimiter">}</span>
  <span class="Identifier">return</span> result<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="PreProc">#define CHECK_TRACE_CONTAINS_ERROR()  CHECK(trace_count(</span><span class="Constant">&quot;error&quot;</span><span class="PreProc">) &gt; </span><span class="Constant">0</span><span class="PreProc">)</span>
<span class="PreProc">#define CHECK_TRACE_DOESNT_CONTAIN_ERROR() \</span>
<span class="PreProc">  </span>if<span class="PreProc"> (trace_count(</span><span class="Constant">&quot;error&quot;</span><span class="PreProc">) &gt; </span><span class="Constant">0</span><span class="PreProc">) </span><span class="Delimiter">{</span><span class="PreProc"> \</span>
<span class="PreProc">    ++Num_failures</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    cerr &lt;&lt; </span><span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span><span class="PreProc"> &lt;&lt; __FUNCTION__ &lt;&lt; </span><span class="Constant">&quot;(&quot;</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">__FILE__</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">&quot;:&quot;</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">__LINE__</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">&quot;): unexpected errors</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    DUMP(</span><span class="Constant">&quot;error&quot;</span><span class="PreProc">)</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    Passed = </span><span class="Constant">false</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    </span><span class="Identifier">return</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">  </span><span class="Delimiter">}</span>

<span class="PreProc">#define CHECK_TRACE_COUNT(label</span><span class="Delimiter">,</span><span class="PreProc"> count) \</span>
<span class="PreProc">  </span>if<span class="PreProc"> (trace_count(label) != (count)) </span><span class="Delimiter">{</span><span class="PreProc"> \</span>
<span class="PreProc">    ++Num_failures</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    cerr &lt;&lt; </span><span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span><span class="PreProc"> &lt;&lt; __FUNCTION__ &lt;&lt; </span><span class="Constant">&quot;(&quot;</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">__FILE__</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">&quot;:&quot;</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">__LINE__</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">&quot;): trace_count of &quot;</span><span class="PreProc"> &lt;&lt; label &lt;&lt; </span><span class="Constant">&quot; should be &quot;</span><span class="PreProc"> &lt;&lt; count &lt;&lt; </span><span class="cSpecial">'\n'</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    cerr &lt;&lt; </span><span class="Constant">&quot;  got &quot;</span><span class="PreProc"> &lt;&lt; trace_count(label) &lt;&lt; </span><span class="cSpecial">'\n'</span><span class="Delimiter">;</span><span class="PreProc">  </span><span class="Comment">/*</span><span class="Comment"> multiple eval </span><span class="Comment">*/</span><span class="PreProc"> \</span>
<span class="PreProc">    DUMP(label)</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    Passed = </span><span class="Constant">false</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    </span><span class="Identifier">return</span><span class="Delimiter">;</span><span class="PreProc">  </span><span class="Comment">/*</span><span class="Comment"> Currently we stop at the very first failure. </span><span class="Comment">*/</span><span class="PreProc"> \</span>
<span class="PreProc">  </span><span class="Delimiter">}</span>

bool trace_doesnt_contain<span class="Delimiter">(</span>string label<span class="Delimiter">,</span> string line<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Identifier">return</span> trace_count<span class="Delimiter">(</span>label<span class="Delimiter">,</span> line<span class="Delimiter">)</span> == <span class="Constant">0</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>

bool trace_doesnt_contain<span class="Delimiter">(</span>string expected<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  vector&lt;string&gt; tmp = split_first<span class="Delimiter">(</span>expected<span class="Delimiter">,</span> <span class="Constant">&quot;: &quot;</span><span class="Delimiter">);</span>
  <span class="Identifier">return</span> trace_doesnt_contain<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">),</span> tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">));</span>
<span class="Delimiter">}</span>

<span class="PreProc">#define CHECK_TRACE_DOESNT_CONTAIN(</span><span class="Delimiter">...</span><span class="PreProc">)  CHECK(trace_doesnt_contain(__VA_ARGS__))</span>

^L

vector&lt;string&gt; split<span class="Delimiter">(</span>string s<span class="Delimiter">,</span> string delim<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  vector&lt;string&gt; result<span class="Delimiter">;</span>
  size_t begin=<span class="Constant">0</span><span class="Delimiter">,</span> end=s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<span class="Delimiter">);</span>
  while <span class="Delimiter">(</span><span class="Constant">true</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
    if <span class="Delimiter">(</span>end == string::npos<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>string<span class="Delimiter">(</span>s<span class="Delimiter">,</span> begin<span class="Delimiter">,</span> string::npos<span class="Delimiter">));</span>
      <span class="Identifier">break</span><span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>string<span class="Delimiter">(</span>s<span class="Delimiter">,</span> begin<span class="Delimiter">,</span> end-begin<span class="Delimiter">));</span>
    begin = end+SIZE<span class="Delimiter">(</span>delim<span class="Delimiter">);</span>
    end = s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<span class="Delimiter">,</span> begin<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
  <span class="Identifier">return</span> result<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

vector&lt;string&gt; split_first<span class="Delimiter">(</span>string s<span class="Delimiter">,</span> string delim<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  vector&lt;string&gt; result<span class="Delimiter">;</span>
  size_t end=s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<span class="Delimiter">);</span>
  result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>string<span class="Delimiter">(</span>s<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">,</span> end<span class="Delimiter">));</span>
  if <span class="Delimiter">(</span>end != string::npos<span class="Delimiter">)</span>
    result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>string<span class="Delimiter">(</span>s<span class="Delimiter">,</span> end+SIZE<span class="Delimiter">(</span>delim<span class="Delimiter">),</span> string::npos<span class="Delimiter">));</span>
  <span class="Identifier">return</span> result<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

string trim<span class="Delimiter">(</span>const string&amp; s<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  string::const_iterator first = s<span class="Delimiter">.</span>begin<span class="Delimiter">();</span>
  while <span class="Delimiter">(</span>first != s<span class="Delimiter">.</span>end<span class="Delimiter">()</span> &amp;&amp; isspace<span class="Delimiter">(</span>*first<span class="Delimiter">))</span>
    ++first<span class="Delimiter">;</span>
  if <span class="Delimiter">(</span>first == s<span class="Delimiter">.</span>end<span class="Delimiter">())</span> <span class="Identifier">return</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">;</span>

  string::const_iterator last = --s<span class="Delimiter">.</span>end<span class="Delimiter">();</span>
  while <span class="Delimiter">(</span>last != s<span class="Delimiter">.</span>begin<span class="Delimiter">()</span> &amp;&amp; isspace<span class="Delimiter">(</span>*last<span class="Delimiter">))</span>
    --last<span class="Delimiter">;</span>
  ++last<span class="Delimiter">;</span>
  <span class="Identifier">return</span> string<span class="Delimiter">(</span>first<span class="Delimiter">,</span> last<span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Delimiter">:(before &quot;End Includes&quot;)</span>
<span class="PreProc">#include</span><span class="Constant">&lt;vector&gt;</span>
using std::vector<span class="Delimiter">;</span>
<span class="PreProc">#include</span><span class="Constant">&lt;list&gt;</span>
using std::list<span class="Delimiter">;</span>
<span class="PreProc">#include</span><span class="Constant">&lt;map&gt;</span>
using std::map<span class="Delimiter">;</span>
<span class="PreProc">#include</span><span class="Constant">&lt;set&gt;</span>
using std::set<span class="Delimiter">;</span>
<span class="PreProc">#include</span><span class="Constant">&lt;algorithm&gt;</span>

<span class="PreProc">#include</span><span class="Constant">&lt;sstream&gt;</span>
using std::istringstream<span class="Delimiter">;</span>
using std::ostringstream<span class="Delimiter">;</span>

<span class="PreProc">#include</span><span class="Constant">&lt;fstream&gt;</span>
using std::ifstream<span class="Delimiter">;</span>
using std::ofstream<span class="Delimiter">;</span>

<span class="PreProc">#include</span><span class="Constant">&quot;termbox/termbox.h&quot;</span>

<span class="PreProc">#define unused  __attribute__((unused))</span>

<span class="Delimiter">:(before &quot;End Globals&quot;)</span>
<span class="Comment">//: In future layers we'll use the depth field as follows:</span>
<span class="Comment">//:</span>
<span class="Comment">//: Errors will be depth 0.</span>
<span class="Comment">//: Mu 'applications' will be able to use depths 1-100 as they like.</span>
<span class="Comment">//: Primitive statements will occupy 101-9989</span>
const int Initial_callstack_depth = <span class="Constant">101</span><span class="Delimiter">;</span>
const int Max_callstack_depth = <span class="Constant">9989</span><span class="Delimiter">;</span>
<span class="Comment">//: Finally, details of primitive mu statements will occupy depth 9990-9999 (more on that later as well)</span>
<span class="Comment">//:</span>
<span class="Comment">//: This framework should help us hide some details at each level, mixing</span>
<span class="Comment">//: static ideas like layers with the dynamic notion of call-stack depth.</span>
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->