about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2019-04-10 17:22:00 -0700
committerKartik Agaram <vc@akkartik.com>2019-04-10 17:22:00 -0700
commit52a2a21c1cdefb241aa0e43b9e0b0a027f6dc511 (patch)
tree6b7c4e48c8442d951e6eaffb2359732a0ed30844
parentfdf84d43d1b1e7f2adf246663af2e3daf9600786 (diff)
downloadmu-52a2a21c1cdefb241aa0e43b9e0b0a027f6dc511.tar.gz
5074
Fail early when writing to a fake file runs out of space. Makes debugging
tests easier.

Reads from files, on the other hand, are only buffering to a temporary
stream, so it makes sense to silently stop when they run out of space.

In the process I uncovered a testing bug in pack.subx: I was missing a
trailing space in the expected result, but the test still passed because
the space was getting truncated. Being principled about aborting on overflow
by default will help avoid such issues.
-rw-r--r--subx/056trace.subx21
-rw-r--r--subx/060read.subx89
-rwxr-xr-xsubx/apps/crenshaw2-1bin17957 -> 18156 bytes
-rw-r--r--subx/apps/crenshaw2-1.subx11
-rwxr-xr-xsubx/apps/crenshaw2-1bbin18516 -> 18715 bytes
-rw-r--r--subx/apps/crenshaw2-1b.subx11
-rwxr-xr-xsubx/apps/factorialbin16875 -> 17018 bytes
-rwxr-xr-xsubx/apps/handlebin17649 -> 17792 bytes
-rwxr-xr-xsubx/apps/hexbin20928 -> 21191 bytes
-rw-r--r--subx/apps/hex.subx19
-rwxr-xr-xsubx/apps/packbin35463 -> 35607 bytes
-rw-r--r--subx/apps/pack.subx264
12 files changed, 290 insertions, 125 deletions
diff --git a/subx/056trace.subx b/subx/056trace.subx
index fac2d4e7..cedc512a 100644
--- a/subx/056trace.subx
+++ b/subx/056trace.subx
@@ -272,7 +272,7 @@ _append-3:  # out : address, outend : address, s : (array byte) -> num_bytes_app
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # . save registers
     51/push-ECX
-    # _append-4(out, outend, &s->data[0], &s->data[s->length]) -> num_bytes_appended/EAX
+    # EAX = _append-4(out, outend, &s->data[0], &s->data[s->length])
     # . . push &s->data[s->length]
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         0/r32/EAX   0x10/disp8      .                 # copy *(EBP+16) to EAX
     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
@@ -322,9 +322,9 @@ $_append-4:loop:
     # if (in >= inend) break
     39/compare                      3/mod/direct    6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # compare ESI with ECX
     7d/jump-if-greater-or-equal  $_append-4:end/disp8
-    # if (out >= outend) break  # for now silently ignore filled up buffer
+    # if (out >= outend) abort  # just to catch test failures fast
     39/compare                      3/mod/direct    7/rm32/EDI    .           .             .           2/r32/EDX   .               .                 # compare EDI with EDX
-    7d/jump-if-greater-or-equal  $_append-4:end/disp8
+    7d/jump-if-greater-or-equal  $_append-4:abort/disp8
     # *out = *in
     8a/copy-byte                    0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/BL    .               .                 # copy byte at *ESI to BL
     88/copy-byte                    0/mod/indirect  7/rm32/EDI    .           .             .           3/r32/BL    .               .                 # copy byte at BL to *EDI
@@ -347,4 +347,19 @@ $_append-4:end:
     5d/pop-to-EBP
     c3/return
 
+$_append-4:abort:
+    # . _write(2/stderr, error)
+    # . . push args
+    68/push  "stream overflow"/imm32
+    68/push  2/imm32/stderr
+    # . . call
+    e8/call  _write/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # . syscall(exit, 1)
+    bb/copy-to-EBX  1/imm32
+    b8/copy-to-EAX  1/imm32/exit
+    cd/syscall  0x80/imm8
+    # never gets here
+
 # . . vim:nowrap:textwidth=0
diff --git a/subx/060read.subx b/subx/060read.subx
index dcce5dda..cedafbf5 100644
--- a/subx/060read.subx
+++ b/subx/060read.subx
@@ -70,7 +70,7 @@ $read:fake:
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
     # EDI = s
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0xc/disp8       .                 # copy *(EBP+12) to ESI
-    # EAX = _append-4(out = &s->data[s->write], outend = &s->data[s->length],
+    # EAX = _buffer-4(out = &s->data[s->write], outend = &s->data[s->length],
     #                 in  = &f->data[f->read],  inend  = &f->data[f->write])
     # . . push &f->data[f->write]
     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
@@ -89,7 +89,7 @@ $read:fake:
     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/EDI  0/index/EAX   .           0/r32/EAX   0xc/disp8       .                 # copy EDI+EAX+12 to EAX
     50/push-EAX
     # . . call
-    e8/call  _append-4/disp32
+    e8/call  _buffer-4/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
     # s->write += EAX
@@ -107,6 +107,91 @@ $read:end:
 
 # - helpers
 
+# '_buffer' is like '_append', but silently stops instead of aborting when it runs out of space
+
+# 3-argument variant of _buffer
+_buffer-3:  # out : address, outend : address, s : (array byte) -> num_bytes_buffered/EAX
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # . save registers
+    51/push-ECX
+    # EAX = _buffer-4(out, outend, &s->data[0], &s->data[s->length])
+    # . . push &s->data[s->length]
+    8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         0/r32/EAX   0x10/disp8      .                 # copy *(EBP+16) to EAX
+    8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+    51/push-ECX
+    # . . push &s->data[0]
+    8d/copy-address                 1/mod/*+disp8   0/rm32/EAX    .           .             .           1/r32/ECX   4/disp8         .                 # copy EAX+4 to ECX
+    51/push-ECX
+    # . . push outend
+    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+    # . . push out
+    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+    # . . call
+    e8/call  _buffer-4/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+$_buffer-3:end:
+    # . restore registers
+    59/pop-to-ECX
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+# 4-argument variant of _buffer
+_buffer-4:  # out : address, outend : address, in : address, inend : address -> num_bytes_buffered/EAX
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # . save registers
+    51/push-ECX
+    52/push-EDX
+    53/push-EBX
+    56/push-ESI
+    57/push-EDI
+    # EAX/num_bytes_buffered = 0
+    b8/copy-to-EAX  0/imm32
+    # EDI = out
+    8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   8/disp8         .                 # copy *(EBP+8) to EDI
+    # EDX = outend
+    8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EBP+12) to EDX
+    # ESI = in
+    8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0x10/disp8      .                 # copy *(EBP+16) to ESI
+    # ECX = inend
+    8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0x14/disp8      .                 # copy *(EBP+20) to ECX
+$_buffer-4:loop:
+    # if (in >= inend) break
+    39/compare                      3/mod/direct    6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # compare ESI with ECX
+    7d/jump-if-greater-or-equal  $_buffer-4:end/disp8
+    # if (out >= outend) break  # for now silently ignore filled up buffer
+    39/compare                      3/mod/direct    7/rm32/EDI    .           .             .           2/r32/EDX   .               .                 # compare EDI with EDX
+    7d/jump-if-greater-or-equal  $_buffer-4:end/disp8
+    # *out = *in
+    8a/copy-byte                    0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/BL    .               .                 # copy byte at *ESI to BL
+    88/copy-byte                    0/mod/indirect  7/rm32/EDI    .           .             .           3/r32/BL    .               .                 # copy byte at BL to *EDI
+    # ++num_bytes_buffered
+    40/increment-EAX
+    # ++in
+    46/increment-ESI
+    # ++out
+    47/increment-EDI
+    eb/jump  $_buffer-4:loop/disp8
+$_buffer-4:end:
+    # . restore registers
+    5f/pop-to-EDI
+    5e/pop-to-ESI
+    5b/pop-to-EBX
+    5a/pop-to-EDX
+    59/pop-to-ECX
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+
 # idea: a clear-if-empty method on streams that clears only if f->read == f->write
 # Unclear how I'd use it, though. Callers seem to need the check anyway.
 # Maybe a better helper would be 'empty-stream?'
diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1
index 71a66394..c30a1910 100755
--- a/subx/apps/crenshaw2-1
+++ b/subx/apps/crenshaw2-1
Binary files differdiff --git a/subx/apps/crenshaw2-1.subx b/subx/apps/crenshaw2-1.subx
index 05fdbbfe..4aa83988 100644
--- a/subx/apps/crenshaw2-1.subx
+++ b/subx/apps/crenshaw2-1.subx
@@ -33,7 +33,7 @@
 Entry:  # run tests if necessary, call 'compile' if not
 
 #?     # for debugging: run a single test; don't bother setting status code
-#?     e8/call test-get-num-reads-single-digit/disp32
+#?     e8/call test-get-num-aborts-on-non-digit-in-Look/disp32
 #?     eb/jump  $main:end/disp8
 
     # . prolog
@@ -594,8 +594,15 @@ _test-error-stream:
     # current read index
     0/imm32
     # length
-    8/imm32
+    0x40/imm32
     # data
     00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
 
 # . . vim:nowrap:textwidth=0
diff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b
index 1528d546..79979b26 100755
--- a/subx/apps/crenshaw2-1b
+++ b/subx/apps/crenshaw2-1b
Binary files differdiff --git a/subx/apps/crenshaw2-1b.subx b/subx/apps/crenshaw2-1b.subx
index ba30ef94..87826588 100644
--- a/subx/apps/crenshaw2-1b.subx
+++ b/subx/apps/crenshaw2-1b.subx
@@ -722,6 +722,7 @@ expected:  # ed : (address exit-descriptor), f : fd or (address stream), s : (ad
     # . . call
     e8/call  stop/disp32
     # should never get past this point
+$expected:dead-end:
     # . epilog
     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
     5d/pop-to-EBP
@@ -743,6 +744,7 @@ get-char:  # f : (address buffered-file) -> <void>
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
     # save EAX to Look
     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/EAX   Look/disp32     .                 # copy EAX to *Look
+$get-char:end:
     # . restore registers
     58/pop-to-EAX
     # . epilog
@@ -791,8 +793,15 @@ _test-error-stream:
     # current read index
     0/imm32
     # length
-    8/imm32
+    0x40/imm32
     # data
     00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
 
 # . . vim:nowrap:textwidth=0
diff --git a/subx/apps/factorial b/subx/apps/factorial
index 30244f79..6ce4fc6b 100755
--- a/subx/apps/factorial
+++ b/subx/apps/factorial
Binary files differdiff --git a/subx/apps/handle b/subx/apps/handle
index 3c80796e..3de933dd 100755
--- a/subx/apps/handle
+++ b/subx/apps/handle
Binary files differdiff --git a/subx/apps/hex b/subx/apps/hex
index 66c66b5b..331997cf 100755
--- a/subx/apps/hex
+++ b/subx/apps/hex
Binary files differdiff --git a/subx/apps/hex.subx b/subx/apps/hex.subx
index 88dc19fd..08aff7e5 100644
--- a/subx/apps/hex.subx
+++ b/subx/apps/hex.subx
@@ -20,7 +20,7 @@
 Entry:  # run tests if necessary, convert stdin if not
 
 #?     # for debugging: run a single test
-#?     e8/call test-skip-until-newline/disp32
+#?     e8/call test-convert-next-octet-aborts-on-single-hex-byte/disp32
 #?     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
 #?     eb/jump  $main:end/disp8
 
@@ -1516,9 +1516,24 @@ _test-error-stream:
     # current read index
     0/imm32
     # length
-    8/imm32
+    0x80/imm32
     # data
     00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
+    00 00 00 00 00 00 00 00  # 8 bytes
 
 # a test buffered file for _test-error-stream
 _test-error-buffered-file:
diff --git a/subx/apps/pack b/subx/apps/pack
index 41593ba3..06d5e32b 100755
--- a/subx/apps/pack
+++ b/subx/apps/pack
Binary files differdiff --git a/subx/apps/pack.subx b/subx/apps/pack.subx
index ae065f61..ef2a52c0 100644
--- a/subx/apps/pack.subx
+++ b/subx/apps/pack.subx
@@ -21,7 +21,7 @@
 Entry:  # run tests if necessary, convert stdin if not
 
     # for debugging: run a single test
-#?     e8/call test-convert-data-trailing-comment/disp32
+#?     e8/call test-emit-non-number-with-all-hex-digits-and-metadata/disp32
 #?     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
 #?     eb/jump  $main:end/disp8
 
@@ -1280,7 +1280,7 @@ test-convert-data-passes-comments-through:
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
     # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
@@ -3573,7 +3573,7 @@ test-convert-instruction-passes-comments-through:
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
     # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
@@ -6604,16 +6604,16 @@ test-emit-number:
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
@@ -6624,27 +6624,27 @@ test-emit-number:
     68/push  _test-slice-three-zero-end/imm32/end
     68/push  _test-slice-three-zero/imm32/start
     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
-    # emit(_test-buffered-file, slice, 1)
+    # emit(_test-output-buffered-file, slice, 1)
     # . . push args
     68/push  1/imm32
     51/push-ECX
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  emit/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # flush(_test-buffered-file)
+    # flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # check-stream-equal(_test-stream, "30 ", msg)
+    # check-stream-equal(_test-output-stream, "30 ", msg)
     # . . push args
     68/push  "F - test-emit-number/1"/imm32
     68/push  "30 "/imm32
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-stream-equal/disp32
     # . . discard args
@@ -6660,16 +6660,16 @@ test-emit-negative-number:
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
@@ -6680,27 +6680,27 @@ test-emit-negative-number:
     68/push  _test-slice-negative-two-end/imm32/end
     68/push  _test-slice-negative-two/imm32/start
     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
-    # emit(_test-buffered-file, slice, 2)
+    # emit(_test-output-buffered-file, slice, 2)
     # . . push args
     68/push  2/imm32
     51/push-ECX
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  emit/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # flush(_test-buffered-file)
+    # flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # check-stream-equal(_test-stream, "fe ff ", msg)
+    # check-stream-equal(_test-output-stream, "fe ff ", msg)
     # . . push args
     68/push  "F - test-emit-number/1"/imm32
     68/push  "fe ff "/imm32
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-stream-equal/disp32
     # . . discard args
@@ -6715,16 +6715,16 @@ test-emit-number-with-metadata:
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
@@ -6735,28 +6735,28 @@ test-emit-number-with-metadata:
     68/push  _test-slice-negative-two-metadata-end/imm32/end
     68/push  _test-slice-negative-two/imm32/start
     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
-    # emit(_test-buffered-file, slice, 2)
+    # emit(_test-output-buffered-file, slice, 2)
     # . . push args
     68/push  2/imm32
     51/push-ECX
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  emit/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # flush(_test-buffered-file)
+    # flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
     # the '/foo' will have no impact on the output
-    # check-stream-equal(_test-stream, "fe ff ", msg)
+    # check-stream-equal(_test-output-stream, "fe ff ", msg)
     # . . push args
     68/push  "F - test-emit-number-with-metadata"/imm32
     68/push  "fe ff "/imm32
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-stream-equal/disp32
     # . . discard args
@@ -6771,16 +6771,16 @@ test-emit-non-number:
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
@@ -6791,27 +6791,27 @@ test-emit-non-number:
     68/push  _test-slice-non-number-word-end/imm32/end
     68/push  _test-slice-non-number-word/imm32/start
     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
-    # emit(_test-buffered-file, slice, 2)
+    # emit(_test-output-buffered-file, slice, 2)
     # . . push args
     68/push  2/imm32
     51/push-ECX
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  emit/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # flush(_test-buffered-file)
+    # flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # check-stream-equal(_test-stream, "xyz", msg)
+    # check-stream-equal(_test-output-stream, "xyz", msg)
     # . . push args
     68/push  "F - test-emit-non-number"/imm32
     68/push  "xyz "/imm32
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-stream-equal/disp32
     # . . discard args
@@ -6826,16 +6826,16 @@ test-emit-non-number-with-metadata:
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
@@ -6846,27 +6846,27 @@ test-emit-non-number-with-metadata:
     68/push  _test-slice-non-number-word-metadata-end/imm32/end
     68/push  _test-slice-non-number-word/imm32/start
     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
-    # emit(_test-buffered-file, slice, 2)
+    # emit(_test-output-buffered-file, slice, 2)
     # . . push args
     68/push  2/imm32
     51/push-ECX
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  emit/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # flush(_test-buffered-file)
+    # flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # check-stream-equal(_test-stream, "xyz/", msg)
+    # check-stream-equal(_test-output-stream, "xyz/", msg)
     # . . push args
     68/push  "F - test-emit-non-number-with-metadata"/imm32
     68/push  "xyz/ "/imm32
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-stream-equal/disp32
     # . . discard args
@@ -6881,16 +6881,16 @@ test-emit-non-number-with-all-hex-digits-and-metadata:
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
@@ -6901,27 +6901,61 @@ test-emit-non-number-with-all-hex-digits-and-metadata:
     68/push  _test-slice-hexlike-non-number-word-metadata-end/imm32/end
     68/push  _test-slice-hexlike-non-number-word/imm32/start
     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
-    # emit(_test-buffered-file, slice, 2)
+    # emit(_test-output-buffered-file, slice, 2)
     # . . push args
     68/push  2/imm32
     51/push-ECX
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  emit/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # flush(_test-buffered-file)
+    # flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # check-stream-equal(_test-stream, "abcd/xyz")
+#?     # dump output {{{
+#?     # . write(2/stderr, "^")
+#?     # . . push args
+#?     68/push  "^"/imm32
+#?     68/push  2/imm32/stderr
+#?     # . . call
+#?     e8/call  write/disp32
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     # . write-stream(2/stderr, _test-output-stream)
+#?     # . . push args
+#?     68/push  _test-output-stream/imm32
+#?     68/push  2/imm32/stderr
+#?     # . . call
+#?     e8/call  write-stream/disp32
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     # . write(2/stderr, "$")
+#?     # . . push args
+#?     68/push  "$"/imm32
+#?     68/push  2/imm32/stderr
+#?     # . . call
+#?     e8/call  write/disp32
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     # . write(2/stderr, "\n")
+#?     # . . push args
+#?     68/push  Newline/imm32
+#?     68/push  2/imm32/stderr
+#?     # . . call
+#?     e8/call  write/disp32
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     # }}}
+    # check-stream-equal(_test-output-stream, "abcd/xyz")
     # . . push args
     68/push  "F - test-emit-non-number-with-all-hex-digits"/imm32
-    68/push  "abcd/xyz"/imm32
-    68/push  _test-stream/imm32
+    68/push  "abcd/xyz "/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-stream-equal/disp32
     # . . discard args
@@ -7226,44 +7260,44 @@ $emit-hex:end:
 
 test-emit-hex-single-byte:
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # emit-hex(_test-buffered-file, 0xab, 1)
+    # emit-hex(_test-output-buffered-file, 0xab, 1)
     # . . push args
     68/push  1/imm32
     68/push  0xab/imm32
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  emit-hex/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # flush(_test-buffered-file)
+    # flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # check-ints-equal(*_test-stream->data, 'ab ', msg)
+    # check-ints-equal(*_test-output-stream->data, 'ab ', msg)
     # . . push args
     68/push  "F - test-emit-hex-single-byte"/imm32
     68/push  0x206261/imm32
-    # . . push *_test-stream->data
-    b8/copy-to-EAX  _test-stream/imm32
+    # . . push *_test-output-stream->data
+    b8/copy-to-EAX  _test-output-stream/imm32
     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           0xc/disp8       .                 # push *(EAX+12)
     # . . call
     e8/call  check-ints-equal/disp32
@@ -7274,43 +7308,43 @@ test-emit-hex-single-byte:
 
 test-emit-hex-multiple-byte:
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # emit-hex(_test-buffered-file, 0x1234, 2)
+    # emit-hex(_test-output-buffered-file, 0x1234, 2)
     # . . push args
     68/push  2/imm32
     68/push  0x1234/imm32
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  emit-hex/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # flush(_test-buffered-file)
+    # flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # check-stream-equal(_test-stream, "34 12 ", msg)
+    # check-stream-equal(_test-output-stream, "34 12 ", msg)
     # . . push args
     68/push  "F - test-emit-hex-multiple-byte/1"/imm32
     68/push  "34 12 "/imm32
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-stream-equal/disp32
     # . . discard args
@@ -7320,43 +7354,43 @@ test-emit-hex-multiple-byte:
 
 test-emit-hex-zero-pad:
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # emit-hex(_test-buffered-file, 0xab, 2)
+    # emit-hex(_test-output-buffered-file, 0xab, 2)
     # . . push args
     68/push  2/imm32
     68/push  0xab/imm32
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  emit-hex/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # flush(_test-buffered-file)
+    # flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # check(_test-stream->data == 'ab 00 ')
+    # check(_test-output-stream->data == 'ab 00 ')
     # . . push args
     68/push  "F - test-emit-hex-zero-pad/1"/imm32
     68/push  "ab 00 "/imm32
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-stream-equal/disp32
     # . . discard args
@@ -7366,43 +7400,43 @@ test-emit-hex-zero-pad:
 
 test-emit-hex-negative:
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # emit-hex(_test-buffered-file, -1, 2)
+    # emit-hex(_test-output-buffered-file, -1, 2)
     # . . push args
     68/push  2/imm32
     68/push  -1/imm32
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  emit-hex/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # flush(_test-buffered-file)
+    # flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # check-stream-equal(_test-stream == "ff ff ")
+    # check-stream-equal(_test-output-stream == "ff ff ")
     # . . push args
     68/push  "F - test-emit-hex-negative/1"/imm32
     68/push  "ff ff "/imm32
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-stream-equal/disp32
     # . . discard args
@@ -7460,16 +7494,16 @@ test-write-stream-data:
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # setup
-    # . clear-stream(_test-stream)
+    # . clear-stream(_test-output-stream)
     # . . push args
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . clear-stream(_test-buffered-file+4)
+    # . clear-stream(_test-output-buffered-file+4)
     # . . push args
-    b8/copy-to-EAX  _test-buffered-file/imm32
+    b8/copy-to-EAX  _test-output-buffered-file/imm32
     05/add-to-EAX  4/imm32
     50/push-EAX
     # . . call
@@ -7492,27 +7526,27 @@ test-write-stream-data:
     e8/call  write/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-    # write-stream-data(_test-buffered-file, _test-tmp-stream)
+    # write-stream-data(_test-output-buffered-file, _test-tmp-stream)
     # . . push args
     68/push  _test-tmp-stream/imm32
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  write-stream-data/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     # check that the write happened as expected
-    # . flush(_test-buffered-file)
+    # . flush(_test-output-buffered-file)
     # . . push args
-    68/push  _test-buffered-file/imm32
+    68/push  _test-output-buffered-file/imm32
     # . . call
     e8/call  flush/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . check-stream-equal(_test-stream, "abcd", msg)
+    # . check-stream-equal(_test-output-stream, "abcd", msg)
     # . . push args
     68/push  "F - test-write-stream-data"/imm32
     68/push  "abcd"/imm32
-    68/push  _test-stream/imm32
+    68/push  _test-output-stream/imm32
     # . . call
     e8/call  check-stream-equal/disp32
     # . . discard args