From c95648c96093ce0d44c21191bab0ee2c9b04becc Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sat, 3 Jul 2021 18:27:01 -0700 Subject: [PATCH] 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. --- 112read-byte.subx | 1 + 113write-stream.subx | 47 ++++++++++++++++ 310copy-bytes.subx | 6 ++- 400.mu | 1 + shell/evaluate.mu | 41 +++++++++++--- shell/primitives.mu | 124 +++++++++++++++++++++++++++++++++++++++---- shell/print.mu | 7 ++- shell/tokenize.mu | 2 +- 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 { @@ -461,6 +471,20 @@ fn apply-primitive _f: (addr cell), args-ah: (addr handle cell), out: (addr hand apply-write args-ah, out, trace 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 @@ -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 } }