about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-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
   }
 }