diff options
Diffstat (limited to 'linux/tile/word.mu')
-rw-r--r-- | linux/tile/word.mu | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/linux/tile/word.mu b/linux/tile/word.mu new file mode 100644 index 00000000..b4f5000b --- /dev/null +++ b/linux/tile/word.mu @@ -0,0 +1,573 @@ +fn initialize-word _self: (addr word) { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + allocate data-ah + var data/eax: (addr gap-buffer) <- lookup *data-ah + initialize-gap-buffer data +} + +## some helpers for creating words. mostly for tests + +fn initialize-word-with _self: (addr word), s: (addr array byte) { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + allocate data-ah + var data/eax: (addr gap-buffer) <- lookup *data-ah + initialize-gap-buffer-with data, s +} + +fn allocate-word-with _out: (addr handle word), s: (addr array byte) { + var out/eax: (addr handle word) <- copy _out + allocate out + var out-addr/eax: (addr word) <- lookup *out + initialize-word-with out-addr, s +} + +# just for tests for now +# TODO: handle existing next +# one implication of handles: append must take a handle +fn append-word-with self-h: (handle word), s: (addr array byte) { + var self/eax: (addr word) <- lookup self-h + var next-ah/eax: (addr handle word) <- get self, next + allocate-word-with next-ah, s + var next/eax: (addr word) <- lookup *next-ah + var prev-ah/eax: (addr handle word) <- get next, prev + copy-handle self-h, prev-ah +} + +# just for tests for now +# TODO: handle existing prev +fn prepend-word-with self-h: (handle word), s: (addr array byte) { + var self/eax: (addr word) <- lookup self-h + var prev-ah/eax: (addr handle word) <- get self, prev + allocate-word-with prev-ah, s + var prev/eax: (addr word) <- lookup *prev-ah + var next-ah/eax: (addr handle word) <- get prev, next + copy-handle self-h, next-ah +} + +## real primitives + +fn move-word-contents _src-ah: (addr handle word), _dest-ah: (addr handle word) { + var dest-ah/eax: (addr handle word) <- copy _dest-ah + var _dest/eax: (addr word) <- lookup *dest-ah + var dest/edi: (addr word) <- copy _dest + var src-ah/eax: (addr handle word) <- copy _src-ah + var _src/eax: (addr word) <- lookup *src-ah + var src/esi: (addr word) <- copy _src + cursor-to-start src + var src-data-ah/eax: (addr handle gap-buffer) <- get src, scalar-data + var src-data/eax: (addr gap-buffer) <- lookup *src-data-ah + var src-stack/ecx: (addr grapheme-stack) <- get src-data, right + { + var done?/eax: boolean <- grapheme-stack-empty? src-stack + compare done?, 0/false + break-if-!= + var g/eax: grapheme <- pop-grapheme-stack src-stack +#? print-grapheme 0, g +#? print-string 0, "\n" + add-grapheme-to-word dest, g + loop + } +} + +fn copy-word-contents-before-cursor _src-ah: (addr handle word), _dest-ah: (addr handle word) { + var dest-ah/eax: (addr handle word) <- copy _dest-ah + var _dest/eax: (addr word) <- lookup *dest-ah + var dest/edi: (addr word) <- copy _dest + var src-ah/eax: (addr handle word) <- copy _src-ah + var src/eax: (addr word) <- lookup *src-ah + var src-data-ah/eax: (addr handle gap-buffer) <- get src, scalar-data + var src-data/eax: (addr gap-buffer) <- lookup *src-data-ah + var src-stack/ecx: (addr grapheme-stack) <- get src-data, left + var src-stack-data-ah/eax: (addr handle array grapheme) <- get src-stack, data + var _src-stack-data/eax: (addr array grapheme) <- lookup *src-stack-data-ah + var src-stack-data/edx: (addr array grapheme) <- copy _src-stack-data + var top-addr/ecx: (addr int) <- get src-stack, top + var i/eax: int <- copy 0 + { + compare i, *top-addr + break-if->= + var g/edx: (addr grapheme) <- index src-stack-data, i + add-grapheme-to-word dest, *g + i <- increment + loop + } +} + +fn word-equal? _self: (addr word), s: (addr array byte) -> _/eax: boolean { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var result/eax: boolean <- gap-buffer-equal? data, s + return result +} + +fn word-length _self: (addr word) -> _/eax: int { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var result/eax: int <- gap-buffer-length data + return result +} + +fn final-word _in: (addr handle word), out: (addr handle word) { + var curr-h: (handle word) + var curr-ah/esi: (addr handle word) <- address curr-h + copy-object _in, curr-ah + var curr/eax: (addr word) <- copy 0 + var next/edi: (addr handle word) <- copy 0 + { + curr <- lookup *curr-ah + next <- get curr, next + curr <- lookup *next + compare curr, 0 + break-if-= + copy-object next, curr-ah + loop + } + copy-object curr-ah, out # modify 'out' right at the end, just in case it's same as 'in' +} + +fn first-grapheme _self: (addr word) -> _/eax: grapheme { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var result/eax: grapheme <- first-grapheme-in-gap-buffer data + return result +} + +fn grapheme-before-cursor _self: (addr word) -> _/eax: grapheme { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var result/eax: grapheme <- grapheme-before-cursor-in-gap-buffer data + return result +} + +fn add-grapheme-to-word _self: (addr word), c: grapheme { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + add-grapheme-at-gap data, c +} + +fn cursor-at-start? _self: (addr word) -> _/eax: boolean { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var result/eax: boolean <- gap-at-start? data + return result +} + +fn cursor-at-end? _self: (addr word) -> _/eax: boolean { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var result/eax: boolean <- gap-at-end? data + return result +} + +fn cursor-left _self: (addr word) { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var dummy/eax: grapheme <- gap-left data +} + +fn cursor-right _self: (addr word) { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var dummy/eax: grapheme <- gap-right data +} + +fn cursor-to-start _self: (addr word) { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + gap-to-start data +} + +fn cursor-to-end _self: (addr word) { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + gap-to-end data +} + +fn cursor-index _self: (addr word) -> _/eax: int { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var result/eax: int <- gap-index data + return result +} + +fn delete-before-cursor _self: (addr word) { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + delete-before-gap data +} + +fn pop-after-cursor _self: (addr word) -> _/eax: grapheme { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var result/eax: grapheme <- pop-after-gap data + return result +} + +fn delete-next _self: (addr word) { + var self/esi: (addr word) <- copy _self + var next-ah/edi: (addr handle word) <- get self, next + var next/eax: (addr word) <- lookup *next-ah + compare next, 0 + break-if-= + var next-next-ah/ecx: (addr handle word) <- get next, next + var self-ah/esi: (addr handle word) <- get next, prev + copy-object next-next-ah, next-ah + var new-next/eax: (addr word) <- lookup *next-next-ah + compare new-next, 0 + break-if-= + var dest/eax: (addr handle word) <- get new-next, prev + copy-object self-ah, dest +} + +fn print-word screen: (addr screen), _self: (addr word) { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + render-gap-buffer screen, data +} + +fn print-words-in-reverse screen: (addr screen), _words-ah: (addr handle word) { + var words-ah/eax: (addr handle word) <- copy _words-ah + var words-a/eax: (addr word) <- lookup *words-ah + compare words-a, 0 + break-if-= + # recurse + var next-ah/ecx: (addr handle word) <- get words-a, next + print-words-in-reverse screen, next-ah + # print + print-word screen, words-a + print-string screen, " " +} + +# Gotcha with some word operations: ensure dest-ah isn't in the middle of some +# existing chain of words. There are two pointers to patch, and you'll forget +# to do the other one. +fn copy-words _src-ah: (addr handle word), _dest-ah: (addr handle word) { + var src-ah/eax: (addr handle word) <- copy _src-ah + var src-a/eax: (addr word) <- lookup *src-ah + compare src-a, 0 + break-if-= + # copy + var dest-ah/edi: (addr handle word) <- copy _dest-ah + copy-word src-a, dest-ah + # recurse + var rest: (handle word) + var rest-ah/ecx: (addr handle word) <- address rest + var next-src-ah/esi: (addr handle word) <- get src-a, next + copy-words next-src-ah, rest-ah + chain-words dest-ah, rest-ah +} + +fn copy-words-in-reverse _src-ah: (addr handle word), _dest-ah: (addr handle word) { + var src-ah/eax: (addr handle word) <- copy _src-ah + var _src-a/eax: (addr word) <- lookup *src-ah + var src-a/esi: (addr word) <- copy _src-a + compare src-a, 0 + break-if-= + # recurse + var next-src-ah/ecx: (addr handle word) <- get src-a, next + var dest-ah/edi: (addr handle word) <- copy _dest-ah + copy-words-in-reverse next-src-ah, dest-ah + # + copy-word-at-end src-a, dest-ah +} + +fn copy-word-at-end src: (addr word), _dest-ah: (addr handle word) { + var dest-ah/edi: (addr handle word) <- copy _dest-ah + # if dest is null, copy and return + var dest-a/eax: (addr word) <- lookup *dest-ah + compare dest-a, 0 + { + break-if-!= + copy-word src, dest-ah + return + } + # copy current word + var new: (handle word) + var new-ah/ecx: (addr handle word) <- address new + copy-word src, new-ah + # append it at the end + var curr-ah/edi: (addr handle word) <- copy dest-ah + { + var curr-a/eax: (addr word) <- lookup *curr-ah # curr-a guaranteed not to be null + var next-ah/ecx: (addr handle word) <- get curr-a, next + var next-a/eax: (addr word) <- lookup *next-ah + compare next-a, 0 + break-if-= + curr-ah <- copy next-ah + loop + } + chain-words curr-ah, new-ah +} + +fn append-word-at-end-with _dest-ah: (addr handle word), s: (addr array byte) { + var dest-ah/edi: (addr handle word) <- copy _dest-ah + # if dest is null, copy and return + var dest-a/eax: (addr word) <- lookup *dest-ah + compare dest-a, 0 + { + break-if-!= + allocate-word-with dest-ah, s + return + } + # otherwise append at end + var curr-ah/edi: (addr handle word) <- copy dest-ah + { + var curr-a/eax: (addr word) <- lookup *curr-ah # curr-a guaranteed not to be null + var next-ah/ecx: (addr handle word) <- get curr-a, next + var next-a/eax: (addr word) <- lookup *next-ah + compare next-a, 0 + break-if-= + curr-ah <- copy next-ah + loop + } + append-word-with *curr-ah, s +} + +fn copy-word _src-a: (addr word), _dest-ah: (addr handle word) { + var dest-ah/eax: (addr handle word) <- copy _dest-ah + allocate dest-ah + var _dest-a/eax: (addr word) <- lookup *dest-ah + var dest-a/eax: (addr word) <- copy _dest-a + initialize-word dest-a + var dest/edi: (addr handle gap-buffer) <- get dest-a, scalar-data + var src-a/eax: (addr word) <- copy _src-a + var src/eax: (addr handle gap-buffer) <- get src-a, scalar-data + copy-gap-buffer src, dest +} + +# one implication of handles: append must take a handle +fn append-word _self-ah: (addr handle word) { + var saved-self-storage: (handle word) + var saved-self/eax: (addr handle word) <- address saved-self-storage + copy-object _self-ah, saved-self +#? { +#? print-string 0, "self-ah is " +#? var foo/eax: int <- copy _self-ah +#? print-int32-hex 0, foo +#? print-string 0, "\n" +#? } + var self-ah/esi: (addr handle word) <- copy _self-ah + var _self/eax: (addr word) <- lookup *self-ah + var self/ebx: (addr word) <- copy _self +#? { +#? print-string 0, "0: self is " +#? var self-ah/eax: (addr handle word) <- copy _self-ah +#? var self/eax: (addr word) <- lookup *self-ah +#? var foo/eax: int <- copy self +#? print-int32-hex 0, foo +#? print-string 0, "\n" +#? } + # allocate new handle + var new: (handle word) + var new-ah/ecx: (addr handle word) <- address new + allocate new-ah + var new-addr/eax: (addr word) <- lookup new + initialize-word new-addr +#? { +#? print-string 0, "new is " +#? var foo/eax: int <- copy new-addr +#? print-int32-hex 0, foo +#? print-string 0, "\n" +#? } + # new->next = self->next + var src/esi: (addr handle word) <- get self, next +#? { +#? print-string 0, "src is " +#? var foo/eax: int <- copy src +#? print-int32-hex 0, foo +#? print-string 0, "\n" +#? } + var dest/edi: (addr handle word) <- get new-addr, next + copy-object src, dest + # new->next->prev = new + { + var next-addr/eax: (addr word) <- lookup *src + compare next-addr, 0 + break-if-= +#? { +#? print-string 0, "next-addr is " +#? var foo/eax: int <- copy next-addr +#? print-int32-hex 0, foo +#? print-string 0, "\n" +#? } + dest <- get next-addr, prev +#? #? { +#? #? print-string 0, "self-ah is " +#? #? var foo/eax: int <- copy _self-ah +#? #? print-int32-hex 0, foo +#? #? print-string 0, "\n" +#? #? print-string 0, "2: self is " +#? #? var self-ah/eax: (addr handle word) <- copy _self-ah +#? #? var self/eax: (addr word) <- lookup *self-ah +#? #? var foo/eax: int <- copy self +#? #? print-int32-hex 0, foo +#? #? print-string 0, "\n" +#? #? } +#? { +#? print-string 0, "copying new to " +#? var foo/eax: int <- copy dest +#? print-int32-hex 0, foo +#? print-string 0, "\n" +#? } + copy-object new-ah, dest +#? { +#? print-string 0, "4: self is " +#? var self-ah/eax: (addr handle word) <- copy _self-ah +#? var self/eax: (addr word) <- lookup *self-ah +#? var foo/eax: int <- copy self +#? print-int32-hex 0, foo +#? print-string 0, "\n" +#? } + } + # new->prev = saved-self + dest <- get new-addr, prev +#? { +#? print-string 0, "copying " +#? var self-ah/esi: (addr handle word) <- copy _self-ah +#? var self/eax: (addr word) <- lookup *self-ah +#? var foo/eax: int <- copy self +#? print-int32-hex 0, foo +#? print-string 0, " to " +#? foo <- copy dest +#? print-int32-hex 0, foo +#? print-string 0, "\n" +#? } + var saved-self-ah/eax: (addr handle word) <- address saved-self-storage + copy-object saved-self-ah, dest + # self->next = new + dest <- get self, next + copy-object new-ah, dest +} + +fn chain-words _self-ah: (addr handle word), _next: (addr handle word) { + var self-ah/esi: (addr handle word) <- copy _self-ah + var _self/eax: (addr word) <- lookup *self-ah + var self/ecx: (addr word) <- copy _self + var dest/edx: (addr handle word) <- get self, next + var next-ah/edi: (addr handle word) <- copy _next + copy-object next-ah, dest + var next/eax: (addr word) <- lookup *next-ah + compare next, 0 + break-if-= + dest <- get next, prev + copy-object self-ah, dest +} + +fn emit-word _self: (addr word), out: (addr stream byte) { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + emit-gap-buffer data, out +} + +fn word-to-string _self: (addr word), out: (addr handle array byte) { + var self/esi: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + gap-buffer-to-string data, out +} + +fn word-is-decimal-integer? _self: (addr word) -> _/eax: boolean { + var self/eax: (addr word) <- copy _self + var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data + var data/eax: (addr gap-buffer) <- lookup *data-ah + var result/eax: boolean <- gap-buffer-is-decimal-integer? data + return result +} + +# ABSOLUTELY GHASTLY +fn word-exists? _haystack-ah: (addr handle word), _needle: (addr word) -> _/ebx: boolean { + var needle-name-storage: (handle array byte) + var needle-name-ah/eax: (addr handle array byte) <- address needle-name-storage + word-to-string _needle, needle-name-ah # profligate leak + var _needle-name/eax: (addr array byte) <- lookup *needle-name-ah + var needle-name/edi: (addr array byte) <- copy _needle-name + # base case + var haystack-ah/esi: (addr handle word) <- copy _haystack-ah + var curr/eax: (addr word) <- lookup *haystack-ah + compare curr, 0 + { + break-if-!= + return 0/false + } + # check curr + var curr-name-storage: (handle array byte) + var curr-name-ah/ecx: (addr handle array byte) <- address curr-name-storage + word-to-string curr, curr-name-ah # profligate leak + var curr-name/eax: (addr array byte) <- lookup *curr-name-ah + var found?/eax: boolean <- string-equal? needle-name, curr-name + compare found?, 0 + { + break-if-= + return 1/true + } + # recurse + var curr/eax: (addr word) <- lookup *haystack-ah + var next-haystack-ah/eax: (addr handle word) <- get curr, next + var result/ebx: boolean <- word-exists? next-haystack-ah, _needle + return result +} + +fn word-list-length words: (addr handle word) -> _/eax: int { + var curr-ah/esi: (addr handle word) <- copy words + var result/edi: int <- copy 0 + { + var curr/eax: (addr word) <- lookup *curr-ah + compare curr, 0 + break-if-= + { + var word-len/eax: int <- word-length curr + result <- add word-len + result <- add 1/inter-word-margin + } + curr-ah <- get curr, next + loop + } + return result +} + +# out-ah already has a word allocated and initialized +fn parse-words in: (addr array byte), out-ah: (addr handle word) { + var in-stream: (stream byte 0x100) + var in-stream-a/esi: (addr stream byte) <- address in-stream + write in-stream-a, in + var cursor-word-ah/ebx: (addr handle word) <- copy out-ah + $parse-words:loop: { + var done?/eax: boolean <- stream-empty? in-stream-a + compare done?, 0/false + break-if-!= + var _g/eax: grapheme <- read-grapheme in-stream-a + var g/ecx: grapheme <- copy _g + # if not space, insert + compare g, 0x20/space + { + break-if-= + var cursor-word/eax: (addr word) <- lookup *cursor-word-ah + add-grapheme-to-word cursor-word, g + loop $parse-words:loop + } + # otherwise insert word after and move cursor to it + append-word cursor-word-ah + var cursor-word/eax: (addr word) <- lookup *cursor-word-ah + cursor-to-start cursor-word # reset cursor in each function + cursor-word-ah <- get cursor-word, next + loop + } +} |