574 lines
19 KiB
Forth
574 lines
19 KiB
Forth
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: code-point-utf8 <- pop-grapheme-stack src-stack
|
|
#? print-code-point-utf8 0, g
|
|
#? print-string 0, "\n"
|
|
add-code-point-utf8-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 code-point-utf8) <- get src-stack, data
|
|
var _src-stack-data/eax: (addr array code-point-utf8) <- lookup *src-stack-data-ah
|
|
var src-stack-data/edx: (addr array code-point-utf8) <- 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 code-point-utf8) <- index src-stack-data, i
|
|
add-code-point-utf8-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-code-point-utf8 _self: (addr word) -> _/eax: code-point-utf8 {
|
|
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: code-point-utf8 <- first-code-point-utf8-in-gap-buffer data
|
|
return result
|
|
}
|
|
|
|
fn code-point-utf8-before-cursor _self: (addr word) -> _/eax: code-point-utf8 {
|
|
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: code-point-utf8 <- code-point-utf8-before-cursor-in-gap-buffer data
|
|
return result
|
|
}
|
|
|
|
fn add-code-point-utf8-to-word _self: (addr word), c: code-point-utf8 {
|
|
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-code-point-utf8-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: code-point-utf8 <- 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: code-point-utf8 <- 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: code-point-utf8 {
|
|
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: code-point-utf8 <- 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: code-point-utf8 <- read-code-point-utf8 in-stream-a
|
|
var g/ecx: code-point-utf8 <- copy _g
|
|
# if not space, insert
|
|
compare g, 0x20/space
|
|
{
|
|
break-if-=
|
|
var cursor-word/eax: (addr word) <- lookup *cursor-word-ah
|
|
add-code-point-utf8-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
|
|
}
|
|
}
|