about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-07-03 18:27:01 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-07-03 18:27:01 -0700
commitc95648c96093ce0d44c21191bab0ee2c9b04becc (patch)
treeeb58e435a158100b99e152199b193acc53df4ab3
parent7ced4e44ddb6e15152eb8bcef9dda68aba53710b (diff)
downloadmu-c95648c96093ce0d44c21191bab0ee2c9b04becc.tar.gz
reading from streams
The Mu shell has no string literals, only streams. No random access,
only sequential access. But I've been playing fast and loose with its
read pointer until now. Hopefully things are cleaned up now.
-rw-r--r--112read-byte.subx1
-rw-r--r--113write-stream.subx47
-rw-r--r--310copy-bytes.subx6
-rw-r--r--400.mu1
-rw-r--r--shell/evaluate.mu41
-rw-r--r--shell/primitives.mu124
-rw-r--r--shell/print.mu7
-rw-r--r--shell/tokenize.mu2
8 files changed, 206 insertions, 23 deletions
diff --git a/112read-byte.subx b/112read-byte.subx
index 1a18fc04..93503d8b 100644
--- a/112read-byte.subx
+++ b/112read-byte.subx
@@ -47,6 +47,7 @@ $read-byte:abort:
 _test-input-stream:  # (stream byte)
     # current write index
     0/imm32
+$_test-input-stream->read:
     # current read index
     0/imm32
     # size
diff --git a/113write-stream.subx b/113write-stream.subx
index 7dd93fba..4478179b 100644
--- a/113write-stream.subx
+++ b/113write-stream.subx
@@ -158,6 +158,53 @@ test-write-stream-appends:
     # . end
     c3/return
 
+# like write-stream, but don't update s->read
+# is there a better name for this?
+write-stream-immutable:  # f: (addr stream byte), s: (addr stream byte)
+    # . prologue
+    55/push-ebp
+    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+    # . save registers
+    50/push-eax
+    56/push-esi
+    57/push-edi
+    # edi = f
+    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+    # esi = s
+    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
+    # eax = _append-4(&f->data[f->write], &f->data[f->size], &s->data[s->read], &s->data[s->write])
+    # . . push &s->data[s->write]
+    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
+    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
+    50/push-eax
+    # . . push &s->data[s->read]
+    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
+    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
+    50/push-eax
+    # . . push &f->data[f->size]
+    8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   8/disp8         .                 # copy *(edi+8) to eax
+    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
+    # . . push &f->data[f->write]
+    8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy *edi to eax
+    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
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+    # f->write += eax
+    01/add                          0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # add eax to *edi
+$write-stream-immutable:end:
+    # . restore registers
+    5f/pop-to-edi
+    5e/pop-to-esi
+    58/pop-to-eax
+    # . epilogue
+    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+    5d/pop-to-ebp
+    c3/return
+
 == data
 
 _test-stream2:  # (stream byte)
diff --git a/310copy-bytes.subx b/310copy-bytes.subx
index 2586a53f..64b8148a 100644
--- a/310copy-bytes.subx
+++ b/310copy-bytes.subx
@@ -102,6 +102,8 @@ test-stream-to-array:
     (write _test-input-stream "abc")
     # skip something
     (read-byte _test-input-stream)  # => eax
+    8b/-> *$_test-input-stream->read 0/r32/eax
+    (check-ints-equal %eax 1 "F - test-stream-to-array/pre")
     # var out/ecx: (handle array byte)
     68/push 0/imm32
     68/push 0/imm32
@@ -109,7 +111,9 @@ test-stream-to-array:
     #
     (stream-to-array _test-input-stream %ecx)
     (lookup *ecx *(ecx+4))  # => eax
-    (check-strings-equal %eax "bc")
+    (check-strings-equal %eax "bc" "F - test-stream-to-array")
+    8b/-> *$_test-input-stream->read 0/r32/eax
+    (check-ints-equal %eax 1 "F - test-stream-to-array/read-pointer-not-perturbed")
     # . epilogue
     89/<- %esp 5/r32/ebp
     5d/pop-to-ebp
diff --git a/400.mu b/400.mu
index ab1c6dc0..e6cb48c2 100644
--- a/400.mu
+++ b/400.mu
@@ -57,6 +57,7 @@ sig try-write f: (addr stream byte), s: (addr array byte) -> _/eax: boolean
 sig stream-size f: (addr stream byte) -> _/eax: int
 sig space-remaining-in-stream f: (addr stream byte) -> _/eax: int
 sig write-stream f: (addr stream byte), s: (addr stream byte)
+sig write-stream-immutable f: (addr stream byte), s: (addr stream byte)
 sig read-byte s: (addr stream byte) -> _/eax: byte
 sig append-byte f: (addr stream byte), n: int  # really just a byte, but I want to pass in literal numbers
 #sig to-hex-char in/eax: int -> out/eax: int
diff --git a/shell/evaluate.mu b/shell/evaluate.mu
index b27405e0..923bd0e4 100644
--- a/shell/evaluate.mu
+++ b/shell/evaluate.mu
@@ -1277,14 +1277,9 @@ fn cell-isomorphic? _a: (addr cell), _b: (addr cell), trace: (addr trace) -> _/e
     trace-text trace, "eval", "=> true (numbers)"
     return 1/true
   }
-  $cell-isomorphic?:text-data: {
-    {
-      compare b-type, 2/symbol
-      break-if-=
-      compare b-type, 3/stream
-      break-if-=
-      break $cell-isomorphic?:text-data
-    }
+  {
+    compare b-type, 2/symbol
+    break-if-!=
     var b-val-ah/eax: (addr handle stream byte) <- get b, text-data
     var _b-val/eax: (addr stream byte) <- lookup *b-val-ah
     var b-val/ecx: (addr stream byte) <- copy _b-val
@@ -1309,6 +1304,36 @@ fn cell-isomorphic? _a: (addr cell), _b: (addr cell), trace: (addr trace) -> _/e
     }
     return match?
   }
+  {
+    compare b-type, 3/stream
+    break-if-!=
+    var a-val-ah/eax: (addr handle stream byte) <- get a, text-data
+    var a-val/eax: (addr stream byte) <- lookup *a-val-ah
+    var a-data-h: (handle array byte)
+    var a-data-ah/edx: (addr handle array byte) <- address a-data-h
+    stream-to-array a-val, a-data-ah
+    var _a-data/eax: (addr array byte) <- lookup *a-data-ah
+    var a-data/edx: (addr array byte) <- copy _a-data
+    var b-val-ah/eax: (addr handle stream byte) <- get b, text-data
+    var b-val/eax: (addr stream byte) <- lookup *b-val-ah
+    var b-data-h: (handle array byte)
+    var b-data-ah/ecx: (addr handle array byte) <- address b-data-h
+    stream-to-array b-val, b-data-ah
+    var b-data/eax: (addr array byte) <- lookup *b-data-ah
+    var match?/eax: boolean <- string-equal? a-data, b-data
+    trace-higher trace
+    {
+      compare match?, 0/false
+      break-if-=
+      trace-text trace, "eval", "=> true (streams)"
+    }
+    {
+      compare match?, 0/false
+      break-if-!=
+      trace-text trace, "eval", "=> false (streams)"
+    }
+    return match?
+  }
   # if objects are primitive functions, compare index-data
   compare b-type, 4/primitive
   {
diff --git a/shell/primitives.mu b/shell/primitives.mu
index c78b44e0..6dc61c23 100644
--- a/shell/primitives.mu
+++ b/shell/primitives.mu
@@ -45,6 +45,8 @@ fn initialize-primitives _self: (addr global-table) {
   # for streams
   append-primitive self, "stream"
   append-primitive self, "write"
+  append-primitive self, "read"
+  append-primitive self, "rewind"
   # misc
   append-primitive self, "abort"
   # keep sync'd with render-primitives
@@ -54,7 +56,7 @@ fn initialize-primitives _self: (addr global-table) {
 # evaluate all their arguments.
 fn render-primitives screen: (addr screen), xmin: int, xmax: int, ymax: int {
   var y/ecx: int <- copy ymax
-  y <- subtract 0xf/primitives-border
+  y <- subtract 0x11/primitives-border
   clear-rect screen, xmin, y, xmax, ymax, 0xdc/bg=green-bg
   y <- increment
   var right-min/edx: int <- copy xmax
@@ -96,7 +98,7 @@ fn render-primitives screen: (addr screen), xmin: int, xmax: int, ymax: int {
 #?     loop-if-=
 #?   }
   y <- copy ymax
-  y <- subtract 0xe/primitives-border
+  y <- subtract 0x10/primitives-border
   var left-max/edx: int <- copy xmax
   left-max <- subtract 0x20/primitives-divider
   var tmpx/eax: int <- copy xmin
@@ -151,6 +153,14 @@ fn render-primitives screen: (addr screen), xmin: int, xmax: int, ymax: int {
   var tmpx/eax: int <- copy xmin
   tmpx <- draw-text-rightward screen, "  write", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
   tmpx <- draw-text-rightward screen, ": stream grapheme -> stream", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
+  y <- increment
+  var tmpx/eax: int <- copy xmin
+  tmpx <- draw-text-rightward screen, "  rewind clear", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
+  tmpx <- draw-text-rightward screen, ": stream", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
+  y <- increment
+  var tmpx/eax: int <- copy xmin
+  tmpx <- draw-text-rightward screen, "  read", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
+  tmpx <- draw-text-rightward screen, ": stream -> grapheme", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
 }
 
 fn primitive-global? _x: (addr global) -> _/eax: boolean {
@@ -462,6 +472,20 @@ fn apply-primitive _f: (addr cell), args-ah: (addr handle cell), out: (addr hand
     return
   }
   {
+    var rewind?/eax: boolean <- string-equal? f-name, "rewind"
+    compare rewind?, 0/false
+    break-if-=
+    apply-rewind args-ah, out, trace
+    return
+  }
+  {
+    var read?/eax: boolean <- string-equal? f-name, "read"
+    compare read?, 0/false
+    break-if-=
+    apply-read args-ah, out, trace
+    return
+  }
+  {
     var abort?/eax: boolean <- string-equal? f-name, "abort"
     compare abort?, 0/false
     break-if-=
@@ -1584,17 +1608,25 @@ fn apply-clear _args-ah: (addr handle cell), out: (addr handle cell), trace: (ad
   var first-ah/eax: (addr handle cell) <- get args, left
   var first/eax: (addr cell) <- lookup *first-ah
   var first-type/ecx: (addr int) <- get first, type
-  compare *first-type, 5/screen
+  compare *first-type, 3/stream
   {
     break-if-=
-    error trace, "first arg for 'clear' is not a screen"
+    var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
+    var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
+    var stream-data/ebx: (addr stream byte) <- copy _stream-data
+    clear-stream stream-data
     return
   }
-  var screen-ah/eax: (addr handle screen) <- get first, screen-data
-  var _screen/eax: (addr screen) <- lookup *screen-ah
-  var screen/ecx: (addr screen) <- copy _screen
-  #
-  clear-screen screen
+  compare *first-type, 5/screen
+  {
+    break-if-!=
+    var screen-ah/eax: (addr handle screen) <- get first, screen-data
+    var _screen/eax: (addr screen) <- lookup *screen-ah
+    var screen/ecx: (addr screen) <- copy _screen
+    clear-screen screen
+    return
+  }
+  error trace, "first arg for 'clear' is not a screen or a stream"
 }
 
 fn apply-up _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
@@ -2024,6 +2056,80 @@ fn apply-write _args-ah: (addr handle cell), out: (addr handle cell), trace: (ad
   copy-object first-ah, out
 }
 
+fn apply-rewind _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
+  trace-text trace, "eval", "apply 'rewind'"
+  var args-ah/eax: (addr handle cell) <- copy _args-ah
+  var _args/eax: (addr cell) <- lookup *args-ah
+  var args/esi: (addr cell) <- copy _args
+  {
+    var args-type/ecx: (addr int) <- get args, type
+    compare *args-type, 0/pair
+    break-if-=
+    error trace, "args to 'rewind' are not a list"
+    return
+  }
+  var empty-args?/eax: boolean <- nil? args
+  compare empty-args?, 0/false
+  {
+    break-if-=
+    error trace, "'rewind' needs 1 arg but got 0"
+    return
+  }
+  # stream = args->left
+  var first-ah/edx: (addr handle cell) <- get args, left
+  var first/eax: (addr cell) <- lookup *first-ah
+  var first-type/ecx: (addr int) <- get first, type
+  compare *first-type, 3/stream
+  {
+    break-if-=
+    error trace, "first arg for 'rewind' is not a stream"
+    return
+  }
+  var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
+  var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
+  var stream-data/ebx: (addr stream byte) <- copy _stream-data
+  rewind-stream stream-data
+  copy-object first-ah, out
+}
+
+fn apply-read _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
+  trace-text trace, "eval", "apply 'read'"
+  var args-ah/eax: (addr handle cell) <- copy _args-ah
+  var _args/eax: (addr cell) <- lookup *args-ah
+  var args/esi: (addr cell) <- copy _args
+  {
+    var args-type/ecx: (addr int) <- get args, type
+    compare *args-type, 0/pair
+    break-if-=
+    error trace, "args to 'read' are not a list"
+    return
+  }
+  var empty-args?/eax: boolean <- nil? args
+  compare empty-args?, 0/false
+  {
+    break-if-=
+    error trace, "'read' needs 1 arg but got 0"
+    return
+  }
+  # stream = args->left
+  var first-ah/edx: (addr handle cell) <- get args, left
+  var first/eax: (addr cell) <- lookup *first-ah
+  var first-type/ecx: (addr int) <- get first, type
+  compare *first-type, 3/stream
+  {
+    break-if-=
+    error trace, "first arg for 'read' is not a stream"
+    return
+  }
+  var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
+  var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
+  var stream-data/ebx: (addr stream byte) <- copy _stream-data
+#?   rewind-stream stream-data
+  var result-grapheme/eax: grapheme <- read-grapheme stream-data
+  var result/eax: int <- copy result-grapheme
+  new-integer out, result
+}
+
 fn apply-lines _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
   trace-text trace, "eval", "apply 'lines'"
   var args-ah/eax: (addr handle cell) <- copy _args-ah
diff --git a/shell/print.mu b/shell/print.mu
index 6db5a25d..0469c002 100644
--- a/shell/print.mu
+++ b/shell/print.mu
@@ -160,7 +160,7 @@ fn print-symbol _in: (addr cell), out: (addr stream byte), trace: (addr trace) {
     error trace, "print-symbol: no space"
     return
   }
-  write-stream out, data
+  write-stream-immutable out, data
   # trace
   var should-trace?/eax: boolean <- should-trace? trace
   compare should-trace?, 0/false
@@ -179,7 +179,6 @@ fn print-stream _in: (addr cell), out: (addr stream byte), trace: (addr trace) {
   var data-ah/eax: (addr handle stream byte) <- get in, text-data
   var _data/eax: (addr stream byte) <- lookup *data-ah
   var data/esi: (addr stream byte) <- copy _data
-  rewind-stream data
   var _required-space/eax: int <- stream-size data
   var required-space/ecx: int <- copy _required-space
   required-space <- add 2  # for []
@@ -192,7 +191,7 @@ fn print-stream _in: (addr cell), out: (addr stream byte), trace: (addr trace) {
     return
   }
   write out, "["
-  write-stream out, data
+  write-stream-immutable out, data
   write out, "]"
   # trace
   var should-trace?/eax: boolean <- should-trace? trace
@@ -202,7 +201,7 @@ fn print-stream _in: (addr cell), out: (addr stream byte), trace: (addr trace) {
   var stream-storage: (stream byte 0x40)
   var stream/ecx: (addr stream byte) <- address stream-storage
   write stream, "=> stream "
-  write-stream stream, data
+  write-stream-immutable stream, data
   trace trace, "print", stream
 }
 
diff --git a/shell/tokenize.mu b/shell/tokenize.mu
index 6ebf5e46..e097e460 100644
--- a/shell/tokenize.mu
+++ b/shell/tokenize.mu
@@ -638,7 +638,7 @@ fn next-stream-token in: (addr gap-buffer), _out: (addr token), trace: (addr tra
     var stream/esi: (addr stream byte) <- address stream-storage
     write stream, "=> "
     rewind-stream out-data
-    write-stream stream, out-data
+    write-stream-immutable stream, out-data
     trace trace, "tokenize", stream
   }
 }