about summary refs log tree commit diff stats
path: root/subx
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 /subx
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.
Diffstat (limited to 'subx')
-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