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.
This commit is contained in:
Kartik K. Agaram 2021-07-03 18:27:01 -07:00
parent 7ced4e44dd
commit c95648c960
8 changed files with 206 additions and 23 deletions

View File

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

View File

@ -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)

View File

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

1
400.mu
View File

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

View File

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

View File

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

View File

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

View File

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