about summary refs log tree commit diff stats
path: root/112read-byte.subx
diff options
context:
space:
mode:
Diffstat (limited to '112read-byte.subx')
-rw-r--r--112read-byte.subx309
1 files changed, 7 insertions, 302 deletions
diff --git a/112read-byte.subx b/112read-byte.subx
index 7510a9e8..0c9af75b 100644
--- a/112read-byte.subx
+++ b/112read-byte.subx
@@ -1,32 +1,7 @@
-# read-byte-buffered: one higher-level abstraction atop 'read'.
+# Read a single byte from a stream.
 #
-# There are many situations where 'read' is a lot to manage, and we need
-# to abstract some details away. One of them is when we want to read a file
-# character by character. In this situation we follow C's FILE data structure,
-# which manages the underlying file descriptor together with the buffer it
-# reads into. We call our version 'buffered-file'. Should be useful with other
-# primitives as well, in later layers.
-
-== data
-
-# The buffered file for standard input. Also illustrates the layout for
-# buffered-file: a pointer to the backing store, followed by a 'buffer' stream
-Stdin:  # buffered-file
-    # file descriptor or (addr stream byte)
-    0/imm32  # standard input
-$Stdin->buffer:
-    # inlined fields for a stream
-    #   current write index
-    0/imm32
-    #   current read index
-    0/imm32
-    #   size
-    8/imm32
-    #   data
-    00 00 00 00 00 00 00 00  # 8 bytes
-
-# TODO: 8 bytes is too small. We'll need to grow the buffer for efficiency. But
-# I don't want to type in 1024 bytes here.
+# We need to do this in machine code because streams need to be opaque types,
+# and we don't yet support opaque types in Mu.
 
 == code
 #   instruction                     effective address                                                   register    displacement    immediate
@@ -34,241 +9,6 @@ $Stdin->buffer:
 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
 
 # Return next byte value in eax, with top 3 bytes cleared.
-# On reaching end of file, return 0xffffffff (Eof).
-read-byte-buffered:  # f: (addr buffered-file) -> byte-or-Eof/eax: byte
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # . save registers
-    51/push-ecx
-    56/push-esi
-    # esi = f
-    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
-    # ecx = f->read
-    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(esi+8) to ecx
-    # if (f->read >= f->write) populate stream from file
-    3b/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # compare ecx with *(esi+4)
-    7c/jump-if-<  $read-byte-buffered:from-stream/disp8
-    # . clear-stream(stream = f+4)
-    # . . push args
-    8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy esi+4 to eax
-    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
-    # . f->read must now be 0; update its cache at ecx
-    31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
-    # . eax = read(f->fd, stream = f+4)
-    # . . push args
-    50/push-eax
-    ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
-    # . . call
-    e8/call  read/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # if (eax == 0) return 0xffffffff
-    3d/compare-eax-and  0/imm32
-    75/jump-if-!=  $read-byte-buffered:from-stream/disp8
-    b8/copy-to-eax  0xffffffff/imm32/Eof
-    eb/jump  $read-byte-buffered:end/disp8
-$read-byte-buffered:from-stream:
-    # byte-or-Eof = f->data[f->read]
-    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
-    8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/AL    0x10/disp8      .                 # copy byte at *(esi+ecx+16) to AL
-    # ++f->read
-    ff          0/subop/increment   1/mod/*+disp8   6/rm32/esi    .           .             .           .           8/disp8         .                 # increment *(esi+8)
-$read-byte-buffered:end:
-    # . restore registers
-    5e/pop-to-esi
-    59/pop-to-ecx
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-# - tests
-
-test-read-byte-buffered-single:
-    # - check that read-byte-buffered returns first byte of 'file'
-    # setup
-    # . clear-stream(_test-stream)
-    # . . push args
-    68/push  _test-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->buffer)
-    # . . push args
-    68/push  $_test-buffered-file->buffer/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . write(_test-stream, "Ab")
-    # . . push args
-    68/push  "Ab"/imm32
-    68/push  _test-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # read-byte-buffered(_test-buffered-file)
-    # . . push args
-    68/push  _test-buffered-file/imm32
-    # . . call
-    e8/call  read-byte-buffered/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 'A', msg)
-    # . . push args
-    68/push  "F - test-read-byte-buffered-single"/imm32
-    68/push  0x41/imm32
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . end
-    c3/return
-
-test-read-byte-buffered-multiple:
-    # - call read-byte-buffered twice, check that second call returns second byte
-    # setup
-    # . clear-stream(_test-stream)
-    # . . push args
-    68/push  _test-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->buffer)
-    # . . push args
-    68/push  $_test-buffered-file->buffer/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . write(_test-stream, "Ab")
-    # . . push args
-    68/push  "Ab"/imm32
-    68/push  _test-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # read-byte-buffered(_test-buffered-file)
-    # . . push args
-    68/push  _test-buffered-file/imm32
-    # . . call
-    e8/call  read-byte-buffered/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # read-byte-buffered(_test-buffered-file)
-    # . . push args
-    68/push  _test-buffered-file/imm32
-    # . . call
-    e8/call  read-byte-buffered/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 'b', msg)
-    # . . push args
-    68/push  "F - test-read-byte-buffered-multiple"/imm32
-    68/push  0x62/imm32
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . end
-    c3/return
-
-test-read-byte-buffered-end-of-file:
-    # - call read-byte-buffered on an empty 'file', check that it returns Eof
-    # setup
-    # . clear-stream(_test-stream)
-    # . . push args
-    68/push  _test-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->buffer)
-    # . . push args
-    68/push  $_test-buffered-file->buffer/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # read-byte-buffered(_test-buffered-file)
-    # . . push args
-    68/push  _test-buffered-file/imm32
-    # . . call
-    e8/call  read-byte-buffered/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 0xffffffff, msg)
-    # . . push args
-    68/push  "F - test-read-byte-buffered-end-of-file"/imm32
-    68/push  0xffffffff/imm32/Eof
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . end
-    c3/return
-
-test-read-byte-buffered-refills-buffer:
-    # - consume buffered-file's buffer, check that next read-byte-buffered still works
-    # setup
-    # . clear-stream(_test-stream)
-    # . . push args
-    68/push  _test-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->buffer)
-    # . . push args
-    68/push  $_test-buffered-file->buffer/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . write(_test-stream, "Abcdefgh")
-    # . . push args
-    68/push  "Abcdefgh"/imm32
-    68/push  _test-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # pretend buffer is full
-    # . _test-buffered-file->read = 6  # >= _test-buffered-file->size
-    b8/copy-to-eax  _test-buffered-file/imm32
-    c7          0/subop/copy        1/mod/*+disp8   0/rm32/eax    .           .             .           .           8/disp8         6/imm32           # copy to *(eax+8)
-    # read-byte-buffered(_test-buffered-file)
-    # . . push args
-    68/push  _test-buffered-file/imm32
-    # . . call
-    e8/call  read-byte-buffered/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 'A', msg)
-    # . . push args
-    68/push  "F - test-read-byte-buffered-refills-buffer"/imm32
-    68/push  0x41/imm32
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . end
-    c3/return
-
-# Return next byte value in eax, with top 3 bytes cleared.
 # Abort on reaching end of stream.
 read-byte:  # s: (addr stream byte) -> result/eax: byte
     # . prologue
@@ -299,35 +39,14 @@ $read-byte:end:
     c3/return
 
 $read-byte:abort:
-    # . _write(2/stderr, error)
-    # . . push args
-    68/push  "read-byte: empty stream\n"/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
-    e8/call  syscall_exit/disp32
+    (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "read-byte: empty stream" 3 0)  # 3=cyan
+    {
+      eb/jump loop/disp8
+    }
     # never gets here
 
 == data
 
-# a test buffered file for _test-stream
-_test-buffered-file:  # buffered-file
-    # file descriptor or (addr stream byte)
-    _test-stream/imm32
-$_test-buffered-file->buffer:
-    # current write index
-    0/imm32
-    # current read index
-    0/imm32
-    # size
-    6/imm32
-    # data
-    00 00 00 00 00 00  # 6 bytes
-
 _test-input-stream:  # (stream byte)
     # current write index
     0/imm32
@@ -401,18 +120,4 @@ _test-input-stream:  # (stream byte)
     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 
-# a test buffered file for _test-input-stream
-_test-input-buffered-file:  # buffered-file
-    # file descriptor or (addr stream byte)
-    _test-input-stream/imm32
-$_test-input-buffered-file->buffer:
-    # current write index
-    0/imm32
-    # current read index
-    0/imm32
-    # size
-    6/imm32
-    # data
-    00 00 00 00 00 00  # 6 bytes
-
 # . . vim:nowrap:textwidth=0