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 } }