7759 - changing course; delete the postfix shell
It might be too ambitious for an initial Mu system, and I also want to watch my novelty budget. I also have great doubts about the ability of this live-updating postfix system to scale to interesting programs. Conditionals, loops, multi-line functions, all this requires further work. Instead, I'm going to recenter around Mu's original goals: - saying no to most features - encouraging/teaching testing - traces as a unifying metaphor In particular, instead of a live-updating system, the new debug loop will be: - generate a trace - browse the trace - modify the program - generate a trace - ... The only persistence we'll need here is a way to track what the programmer has drilled into in the trace. That might have some commonalities with the old system of expanded words.
This commit is contained in:
parent
bcb2190ec3
commit
4a37291e2d
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,275 +0,0 @@
|
|||
type line {
|
||||
name: (handle array byte)
|
||||
data: (handle word)
|
||||
cursor: (handle word)
|
||||
next: (handle line)
|
||||
prev: (handle line)
|
||||
}
|
||||
|
||||
# initialize line with a single empty word
|
||||
fn initialize-line _line: (addr line) {
|
||||
var line/esi: (addr line) <- copy _line
|
||||
var word-ah/eax: (addr handle word) <- get line, data
|
||||
allocate word-ah
|
||||
var cursor-ah/ecx: (addr handle word) <- get line, cursor
|
||||
copy-object word-ah, cursor-ah
|
||||
var word/eax: (addr word) <- lookup *word-ah
|
||||
initialize-word word
|
||||
}
|
||||
|
||||
fn num-words-in-line _in: (addr line) -> _/eax: int {
|
||||
var in/esi: (addr line) <- copy _in
|
||||
var curr-ah/ecx: (addr handle word) <- get in, data
|
||||
var result/edi: int <- copy 0
|
||||
{
|
||||
var curr/eax: (addr word) <- lookup *curr-ah
|
||||
compare curr, 0
|
||||
break-if-=
|
||||
curr-ah <- get curr, next
|
||||
result <- increment
|
||||
loop
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fn line-list-length lines: (addr handle line) -> _/eax: int {
|
||||
var curr-ah/esi: (addr handle line) <- copy lines
|
||||
var result/edi: int <- copy 0
|
||||
{
|
||||
var curr/eax: (addr line) <- lookup *curr-ah
|
||||
compare curr, 0
|
||||
break-if-=
|
||||
curr-ah <- get curr, next
|
||||
result <- increment
|
||||
loop
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fn render-line screen: (addr screen), _line: (addr line), x: int, y: int, render-cursor?: boolean -> _/eax: int {
|
||||
var line/eax: (addr line) <- copy _line
|
||||
var first-word-ah/esi: (addr handle word) <- get line, data
|
||||
# cursor-word
|
||||
var cursor-word/edi: int <- copy 0
|
||||
compare render-cursor?, 0/false
|
||||
{
|
||||
break-if-=
|
||||
var cursor-word-ah/eax: (addr handle word) <- get line, cursor
|
||||
var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah
|
||||
cursor-word <- copy _cursor-word
|
||||
}
|
||||
#
|
||||
var result/eax: int <- render-words screen, first-word-ah, x, y, cursor-word
|
||||
return result
|
||||
}
|
||||
|
||||
fn parse-line in: (addr array byte), _out: (addr line) {
|
||||
var out/edi: (addr line) <- copy _out
|
||||
initialize-line out
|
||||
var dest/eax: (addr handle word) <- get out, data
|
||||
parse-words in, dest
|
||||
}
|
||||
|
||||
#? fn main {
|
||||
#? # line = [aaa, bbb, ccc, ddd]
|
||||
#? var line-storage: line
|
||||
#? var w-ah/eax: (addr handle word) <- get line-storage, data
|
||||
#? allocate-word-with w-ah, "aaa"
|
||||
#? append-word-at-end-with w-ah, "bbb"
|
||||
#? append-word-at-end-with w-ah, "ccc"
|
||||
#? append-word-at-end-with w-ah, "ddd"
|
||||
#? var cursor-ah/ecx: (addr handle word) <- get line-storage, cursor
|
||||
#? var w/eax: (addr word) <- lookup *w-ah
|
||||
#? var next-ah/eax: (addr handle word) <- get w, next
|
||||
#? copy-object next-ah, cursor-ah
|
||||
#? var line-addr/eax: (addr line) <- address line-storage
|
||||
#? var dummy/eax: int <- render-line 0/screen, line-addr, 0/x, 0/y, 1/render-cursor
|
||||
#? }
|
||||
|
||||
fn render-line-with-stack screen: (addr screen), _line: (addr line), x: int, y: int, render-cursor?: boolean -> _/eax: int, _/ecx: int {
|
||||
var line/esi: (addr line) <- copy _line
|
||||
# cursor-word
|
||||
var cursor-word/edi: int <- copy 0
|
||||
compare render-cursor?, 0/false
|
||||
{
|
||||
break-if-=
|
||||
var cursor-word-ah/eax: (addr handle word) <- get line, cursor
|
||||
var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah
|
||||
cursor-word <- copy _cursor-word
|
||||
}
|
||||
#
|
||||
var curr-word-ah/eax: (addr handle word) <- get line, data
|
||||
var _curr-word/eax: (addr word) <- lookup *curr-word-ah
|
||||
var curr-word/edx: (addr word) <- copy _curr-word
|
||||
var new-x/eax: int <- copy x # increases each iteration
|
||||
var new-y/ebx: int <- copy y # compute max across all iterations
|
||||
{
|
||||
compare curr-word, 0
|
||||
break-if-=
|
||||
var curr-y/ecx: int <- copy 0
|
||||
new-x, curr-y <- render-word-with-stack-and-cursor screen, line, curr-word, new-x, y, cursor-word
|
||||
compare curr-y, new-y
|
||||
{
|
||||
break-if-<=
|
||||
new-y <- copy curr-y
|
||||
}
|
||||
new-x <- add 1/inter-word-spacing
|
||||
# update
|
||||
var next-word-ah/eax: (addr handle word) <- get curr-word, next
|
||||
var next-word/eax: (addr word) <- lookup *next-word-ah
|
||||
curr-word <- copy next-word
|
||||
loop
|
||||
}
|
||||
return new-x, new-y
|
||||
}
|
||||
|
||||
fn render-word-with-stack-and-cursor screen: (addr screen), line: (addr line), curr-word: (addr word), x: int, y: int, _cursor-word-addr: int -> _/eax: int, _/ecx: int {
|
||||
# print curr-word, with cursor if necessary
|
||||
var render-cursor?/eax: boolean <- copy 0/false
|
||||
var cursor-word-addr/ecx: int <- copy _cursor-word-addr
|
||||
{
|
||||
compare cursor-word-addr, curr-word
|
||||
break-if-!=
|
||||
render-cursor? <- copy 1/true
|
||||
}
|
||||
var new-x/eax: int <- render-word screen, curr-word, x, y, render-cursor?
|
||||
add-to x, 1/word-stack-indent
|
||||
var new-x-saved/edx: int <- copy new-x
|
||||
add-to y, 2/word-stack-spacing
|
||||
# compute stack until word
|
||||
var stack-storage: value-stack
|
||||
var stack/edi: (addr value-stack) <- address stack-storage
|
||||
evaluate line, curr-word, stack
|
||||
# render stack
|
||||
var new-y/ecx: int <- copy 0
|
||||
new-x, new-y <- render-value-stack screen, stack, x, y
|
||||
#? draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, new-x, 0xc/fg, 0/bg
|
||||
#? draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, new-y, 3/fg, 0/bg
|
||||
compare new-x, new-x-saved
|
||||
{
|
||||
break-if->=
|
||||
new-x <- copy new-x-saved
|
||||
}
|
||||
#? draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, new-x, 7/fg, 0/bg
|
||||
return new-x, new-y
|
||||
}
|
||||
|
||||
fn test-render-line-with-stack-singleton {
|
||||
var line-storage: line
|
||||
var line/esi: (addr line) <- address line-storage
|
||||
parse-line "1", line
|
||||
# setup: screen
|
||||
var screen-on-stack: screen
|
||||
var screen/edi: (addr screen) <- address screen-on-stack
|
||||
initialize-screen screen, 0x20, 4
|
||||
#
|
||||
var new-x/eax: int <- copy 0
|
||||
var new-y/ecx: int <- copy 0
|
||||
new-x, new-y <- render-line-with-stack screen, line, 0/x, 0/y, 0/no-cursor
|
||||
check-screen-row screen, 0/y, "1 ", "F - test-render-line-with-stack-singleton/0"
|
||||
check-screen-row screen, 1/y, " ", "F - test-render-line-with-stack-singleton/1"
|
||||
# ___
|
||||
check-screen-row screen, 2/y, " 1 ", "F - test-render-line-with-stack-singleton/2"
|
||||
check-screen-row screen, 3/y, " ", "F - test-render-line-with-stack-singleton/3"
|
||||
# not bothering to test hash colors for numbers
|
||||
}
|
||||
|
||||
fn test-render-line-with-stack {
|
||||
var line-storage: line
|
||||
var line/esi: (addr line) <- address line-storage
|
||||
parse-line "1 2", line
|
||||
# setup: screen
|
||||
var screen-on-stack: screen
|
||||
var screen/edi: (addr screen) <- address screen-on-stack
|
||||
initialize-screen screen, 0x20, 8
|
||||
#
|
||||
var new-x/eax: int <- copy 0
|
||||
var new-y/ecx: int <- copy 0
|
||||
new-x, new-y <- render-line-with-stack screen, line, 0/x, 0/y, 0/no-cursor
|
||||
check-screen-row screen, 0/y, "1 2 ", "F - test-render-line-with-stack/0"
|
||||
check-screen-row screen, 1/y, " ", "F - test-render-line-with-stack/1"
|
||||
# ___ ___
|
||||
check-screen-row screen, 2/y, " 1 2 ", "F - test-render-line-with-stack/2"
|
||||
check-screen-row screen, 3/y, " 1 ", "F - test-render-line-with-stack/3"
|
||||
check-screen-row screen, 4/y, " ", "F - test-render-line-with-stack/4"
|
||||
# not bothering to test hash colors for numbers
|
||||
}
|
||||
|
||||
# { } groups have no effect on the stack by default.
|
||||
fn test-render-line-with-stack-groups {
|
||||
var line-storage: line
|
||||
var line/esi: (addr line) <- address line-storage
|
||||
parse-line "{ 1 2 }", line
|
||||
# setup: screen
|
||||
var screen-on-stack: screen
|
||||
var screen/edi: (addr screen) <- address screen-on-stack
|
||||
initialize-screen screen, 0x20, 8
|
||||
#
|
||||
var new-x/eax: int <- copy 0
|
||||
var new-y/ecx: int <- copy 0
|
||||
new-x, new-y <- render-line-with-stack screen, line, 0/x, 0/y, 0/no-cursor
|
||||
check-screen-row screen, 0/y, "{ 1 2 } ", "F - test-render-line-with-stack-groups/0"
|
||||
check-screen-row screen, 1/y, " ", "F - test-render-line-with-stack-groups/1"
|
||||
# ___ ___
|
||||
check-screen-row screen, 2/y, " 1 2 ", "F - test-render-line-with-stack-groups/2"
|
||||
check-screen-row screen, 3/y, " 1 ", "F - test-render-line-with-stack-groups/3"
|
||||
check-screen-row screen, 4/y, " ", "F - test-render-line-with-stack-groups/4"
|
||||
}
|
||||
|
||||
# break skips rest of the containing group
|
||||
#? fn test-render-line-with-break {
|
||||
#? var line-storage: line
|
||||
#? var line/esi: (addr line) <- address line-storage
|
||||
#? parse-line "{ 1 break 2 }", line
|
||||
#? # setup: screen
|
||||
#? var screen-on-stack: screen
|
||||
#? var screen/edi: (addr screen) <- address screen-on-stack
|
||||
#? initialize-screen screen, 0x20, 8
|
||||
#? #
|
||||
#? var new-x/eax: int <- copy 0
|
||||
#? var new-y/ecx: int <- copy 0
|
||||
#? new-x, new-y <- render-line-with-stack screen, line, 0/x, 0/y, 0/no-cursor
|
||||
#? check-screen-row screen, 0/y, "{ 1 break 2 } ", "F - test-render-line-with-break/0"
|
||||
#? check-screen-row screen, 1/y, " ", "F - test-render-line-with-break/1"
|
||||
#? # ___
|
||||
#? check-screen-row screen, 2/y, " 1 ", "F - test-render-line-with-break/2"
|
||||
#? #? check-screen-row screen, 3/y, " ", "F - test-render-line-with-break/3"
|
||||
#? }
|
||||
|
||||
fn edit-line _self: (addr line), key: byte {
|
||||
var self/esi: (addr line) <- copy _self
|
||||
var cursor-word-ah/edx: (addr handle word) <- get self, cursor
|
||||
var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah
|
||||
var cursor-word/ecx: (addr word) <- copy _cursor-word
|
||||
compare key, 0x20/space
|
||||
$edit-line:space: {
|
||||
break-if-!=
|
||||
append-word cursor-word-ah
|
||||
var next-word-ah/eax: (addr handle word) <- get cursor-word, next
|
||||
copy-object next-word-ah, cursor-word-ah
|
||||
return
|
||||
}
|
||||
# otherwise insert key within current word
|
||||
var g/edx: grapheme <- copy key
|
||||
add-grapheme-to-word cursor-word, g
|
||||
# silently ignore other hotkeys
|
||||
}
|
||||
|
||||
fn main {
|
||||
var line-storage: line
|
||||
var line/esi: (addr line) <- address line-storage
|
||||
initialize-line line
|
||||
{
|
||||
clear-screen 0/screen
|
||||
var dummy1/eax: int <- copy 0
|
||||
var dummy2/ecx: int <- copy 0
|
||||
dummy1, dummy2 <- render-line-with-stack 0/screen, line, 2/x, 2/y, 1/show-cursor
|
||||
{
|
||||
var key/eax: byte <- read-key 0/keyboard
|
||||
compare key, 0
|
||||
loop-if-=
|
||||
edit-line line, key
|
||||
}
|
||||
loop
|
||||
}
|
||||
}
|
|
@ -1,241 +0,0 @@
|
|||
# value stacks encode the result of a program at a single point in time
|
||||
# they are typically rendered vertically
|
||||
|
||||
type value-stack {
|
||||
data: (handle array value)
|
||||
top: int
|
||||
}
|
||||
|
||||
fn initialize-value-stack _self: (addr value-stack), n: int {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var d/edi: (addr handle array value) <- get self, data
|
||||
populate d, n
|
||||
var top/eax: (addr int) <- get self, top
|
||||
copy-to *top, 0
|
||||
}
|
||||
|
||||
fn clear-value-stack _self: (addr value-stack) {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top/eax: (addr int) <- get self, top
|
||||
copy-to *top, 0
|
||||
}
|
||||
|
||||
fn push-number-to-value-stack _self: (addr value-stack), _val: float {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top-addr/ecx: (addr int) <- get self, top
|
||||
var data-ah/edx: (addr handle array value) <- get self, data
|
||||
var data/eax: (addr array value) <- lookup *data-ah
|
||||
var top/edx: int <- copy *top-addr
|
||||
var dest-offset/edx: (offset value) <- compute-offset data, top
|
||||
var dest-addr/edx: (addr value) <- index data, dest-offset
|
||||
var dest-addr2/eax: (addr float) <- get dest-addr, number-data
|
||||
var val/xmm0: float <- copy _val
|
||||
copy-to *dest-addr2, val
|
||||
increment *top-addr
|
||||
var type-addr/eax: (addr int) <- get dest-addr, type
|
||||
copy-to *type-addr, 0/number
|
||||
}
|
||||
|
||||
fn push-int-to-value-stack _self: (addr value-stack), _val: int {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top-addr/ecx: (addr int) <- get self, top
|
||||
var data-ah/edx: (addr handle array value) <- get self, data
|
||||
var data/eax: (addr array value) <- lookup *data-ah
|
||||
var top/edx: int <- copy *top-addr
|
||||
var dest-offset/edx: (offset value) <- compute-offset data, top
|
||||
var dest-addr/edx: (addr value) <- index data, dest-offset
|
||||
var dest-addr2/eax: (addr float) <- get dest-addr, number-data
|
||||
var val/xmm0: float <- convert _val
|
||||
copy-to *dest-addr2, val
|
||||
increment *top-addr
|
||||
var type-addr/eax: (addr int) <- get dest-addr, type
|
||||
copy-to *type-addr, 0/number
|
||||
}
|
||||
|
||||
fn push-string-to-value-stack _self: (addr value-stack), val: (handle array byte) {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top-addr/ecx: (addr int) <- get self, top
|
||||
var data-ah/edx: (addr handle array value) <- get self, data
|
||||
var data/eax: (addr array value) <- lookup *data-ah
|
||||
var top/edx: int <- copy *top-addr
|
||||
var dest-offset/edx: (offset value) <- compute-offset data, top
|
||||
var dest-addr/edx: (addr value) <- index data, dest-offset
|
||||
var dest-addr2/eax: (addr handle array byte) <- get dest-addr, text-data
|
||||
copy-handle val, dest-addr2
|
||||
var dest-addr3/eax: (addr int) <- get dest-addr, type
|
||||
copy-to *dest-addr3, 1/string
|
||||
increment *top-addr
|
||||
}
|
||||
|
||||
fn push-array-to-value-stack _self: (addr value-stack), val: (handle array value) {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top-addr/ecx: (addr int) <- get self, top
|
||||
var data-ah/edx: (addr handle array value) <- get self, data
|
||||
var data/eax: (addr array value) <- lookup *data-ah
|
||||
var top/edx: int <- copy *top-addr
|
||||
var dest-offset/edx: (offset value) <- compute-offset data, top
|
||||
var dest-addr/edx: (addr value) <- index data, dest-offset
|
||||
var dest-addr2/eax: (addr handle array value) <- get dest-addr, array-data
|
||||
copy-handle val, dest-addr2
|
||||
# update type
|
||||
var dest-addr3/eax: (addr int) <- get dest-addr, type
|
||||
copy-to *dest-addr3, 2/array
|
||||
increment *top-addr
|
||||
}
|
||||
|
||||
fn push-boolean-to-value-stack _self: (addr value-stack), _val: boolean {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top-addr/ecx: (addr int) <- get self, top
|
||||
var data-ah/edx: (addr handle array value) <- get self, data
|
||||
var data/eax: (addr array value) <- lookup *data-ah
|
||||
var top/edx: int <- copy *top-addr
|
||||
var dest-offset/edx: (offset value) <- compute-offset data, top
|
||||
var dest-addr/edx: (addr value) <- index data, dest-offset
|
||||
var dest-addr2/eax: (addr boolean) <- get dest-addr, boolean-data
|
||||
var val/esi: boolean <- copy _val
|
||||
copy-to *dest-addr2, val
|
||||
increment *top-addr
|
||||
var type-addr/eax: (addr int) <- get dest-addr, type
|
||||
copy-to *type-addr, 3/boolean
|
||||
}
|
||||
|
||||
fn push-value-stack _self: (addr value-stack), val: (addr value) {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top-addr/ecx: (addr int) <- get self, top
|
||||
var data-ah/edx: (addr handle array value) <- get self, data
|
||||
var data/eax: (addr array value) <- lookup *data-ah
|
||||
var top/edx: int <- copy *top-addr
|
||||
var dest-offset/edx: (offset value) <- compute-offset data, top
|
||||
var dest-addr/edx: (addr value) <- index data, dest-offset
|
||||
copy-object val, dest-addr
|
||||
increment *top-addr
|
||||
}
|
||||
|
||||
fn pop-number-from-value-stack _self: (addr value-stack) -> _/xmm0: float {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top-addr/ecx: (addr int) <- get self, top
|
||||
{
|
||||
compare *top-addr, 0
|
||||
break-if->
|
||||
abort "pop number: empty stack"
|
||||
}
|
||||
decrement *top-addr
|
||||
var data-ah/edx: (addr handle array value) <- get self, data
|
||||
var data/eax: (addr array value) <- lookup *data-ah
|
||||
var top/edx: int <- copy *top-addr
|
||||
var dest-offset/edx: (offset value) <- compute-offset data, top
|
||||
var result-addr/eax: (addr value) <- index data, dest-offset
|
||||
var result-addr2/eax: (addr float) <- get result-addr, number-data
|
||||
return *result-addr2
|
||||
}
|
||||
|
||||
fn pop-boolean-from-value-stack _self: (addr value-stack) -> _/eax: boolean {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top-addr/ecx: (addr int) <- get self, top
|
||||
{
|
||||
compare *top-addr, 0
|
||||
break-if->
|
||||
abort "pop boolean: empty stack"
|
||||
}
|
||||
decrement *top-addr
|
||||
var data-ah/edx: (addr handle array value) <- get self, data
|
||||
var data/eax: (addr array value) <- lookup *data-ah
|
||||
var top/edx: int <- copy *top-addr
|
||||
var dest-offset/edx: (offset value) <- compute-offset data, top
|
||||
var result-addr/eax: (addr value) <- index data, dest-offset
|
||||
var result-addr2/eax: (addr boolean) <- get result-addr, boolean-data
|
||||
return *result-addr2
|
||||
}
|
||||
|
||||
fn value-stack-empty? _self: (addr value-stack) -> _/eax: boolean {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top/eax: (addr int) <- get self, top
|
||||
compare *top, 0
|
||||
{
|
||||
break-if-!=
|
||||
return 1/true
|
||||
}
|
||||
return 0/false
|
||||
}
|
||||
|
||||
fn value-stack-length _self: (addr value-stack) -> _/eax: int {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var top-addr/eax: (addr int) <- get self, top
|
||||
return *top-addr
|
||||
}
|
||||
|
||||
fn test-boolean {
|
||||
var stack-storage: value-stack
|
||||
var stack/esi: (addr value-stack) <- address stack-storage
|
||||
push-boolean-to-value-stack stack, 0/false
|
||||
var result/eax: boolean <- pop-boolean-from-value-stack stack
|
||||
check-not result, "F - test-boolean/false"
|
||||
push-boolean-to-value-stack stack, 1/true
|
||||
var result/eax: boolean <- pop-boolean-from-value-stack stack
|
||||
check result, "F - test-boolean/true"
|
||||
}
|
||||
|
||||
fn dump-stack _self: (addr value-stack) {
|
||||
var self/esi: (addr value-stack) <- copy _self
|
||||
var data-ah/eax: (addr handle array value) <- get self, data
|
||||
var _data/eax: (addr array value) <- lookup *data-ah
|
||||
var data/edi: (addr array value) <- copy _data
|
||||
var top-addr/ecx: (addr int) <- get self, top
|
||||
var top/ecx: int <- copy *top-addr
|
||||
top <- decrement
|
||||
var y/edx: int <- copy 0xa
|
||||
var dummy/eax: int <- draw-text-rightward-over-full-screen 0/screen, "==", 0/x, 9/y, 0xc/red, 0/bg
|
||||
{
|
||||
compare top, 0
|
||||
break-if-<
|
||||
var dest-offset/eax: (offset value) <- compute-offset data, top
|
||||
var curr/eax: (addr value) <- index data, dest-offset
|
||||
var dummy/eax: int <- render-value 0/screen, curr, 0/x, y, 0/no-color
|
||||
top <- decrement
|
||||
y <- increment
|
||||
loop
|
||||
}
|
||||
}
|
||||
|
||||
fn render-value-stack screen: (addr screen), _self: (addr value-stack), x: int, y: int -> _/eax: int, _/ecx: int {
|
||||
var self/ecx: (addr value-stack) <- copy _self
|
||||
var data-ah/eax: (addr handle array value) <- get self, data
|
||||
var _data/eax: (addr array value) <- lookup *data-ah
|
||||
var data/edi: (addr array value) <- copy _data
|
||||
var top-addr/eax: (addr int) <- get self, top
|
||||
var curr-idx/ecx: int <- copy *top-addr
|
||||
curr-idx <- decrement
|
||||
var new-x/edx: int <- copy 0
|
||||
{
|
||||
compare curr-idx, 0
|
||||
break-if-<
|
||||
var dest-offset/eax: (offset value) <- compute-offset data, curr-idx
|
||||
var curr/eax: (addr value) <- index data, dest-offset
|
||||
var curr-x/eax: int <- render-value screen, curr, x, y, 1/top-level
|
||||
{
|
||||
compare curr-x, new-x
|
||||
break-if-<=
|
||||
new-x <- copy curr-x
|
||||
}
|
||||
curr-idx <- decrement
|
||||
increment y
|
||||
loop
|
||||
}
|
||||
return new-x, y
|
||||
}
|
||||
|
||||
fn test-render-value-stack {
|
||||
var stack-storage: value-stack
|
||||
var stack/esi: (addr value-stack) <- address stack-storage
|
||||
push-int-to-value-stack stack, 3
|
||||
# setup: screen
|
||||
var screen-on-stack: screen
|
||||
var screen/edi: (addr screen) <- address screen-on-stack
|
||||
initialize-screen screen, 0x20, 4
|
||||
#
|
||||
var final-x/eax: int <- copy 0
|
||||
var final-y/ecx: int <- copy 0
|
||||
final-x, final-y <- render-value-stack screen, stack, 0/x, 0/y
|
||||
check-ints-equal final-y, 1, "F - test-render-value-stack y"
|
||||
check-ints-equal final-x, 3, "F - test-render-value-stack x"
|
||||
}
|
|
@ -1,718 +0,0 @@
|
|||
type word {
|
||||
scalar-data: (handle gap-buffer)
|
||||
next: (handle word)
|
||||
prev: (handle word)
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
{
|
||||
compare self, 0
|
||||
break-if-!=
|
||||
return 0/false
|
||||
}
|
||||
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 words-equal? _self: (addr word), _w: (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 data/ecx: (addr gap-buffer) <- copy _data
|
||||
var w/eax: (addr word) <- copy _w
|
||||
var w-data-ah/eax: (addr handle gap-buffer) <- get w, scalar-data
|
||||
var w-data/eax: (addr gap-buffer) <- lookup *w-data-ah
|
||||
var result/eax: boolean <- gap-buffers-equal? data, w-data
|
||||
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 skip-one-word _in: (addr handle word), out: (addr handle word) {
|
||||
var in/eax: (addr handle word) <- copy _in
|
||||
var curr/eax: (addr word) <- lookup *in
|
||||
var next/eax: (addr handle word) <- get curr, next
|
||||
copy-object next, out # modify 'out' right at the end, just in case it's same as 'in'
|
||||
}
|
||||
|
||||
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 <- index-of-gap 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 render-word screen: (addr screen), _self: (addr word), x: int, y: int, render-cursor?: boolean -> _/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 <- render-gap-buffer screen, data, x, y, render-cursor?
|
||||
return result
|
||||
}
|
||||
|
||||
fn render-words screen: (addr screen), _words-ah: (addr handle word), x: int, y: int, cursor-word-addr: int -> _/eax: int {
|
||||
var words-ah/eax: (addr handle word) <- copy _words-ah
|
||||
var _words-a/eax: (addr word) <- lookup *words-ah
|
||||
var words-a/ecx: (addr word) <- copy _words-a
|
||||
compare words-a, 0
|
||||
{
|
||||
break-if-!=
|
||||
return x
|
||||
}
|
||||
# print
|
||||
var render-cursor?/edx: boolean <- copy 0/false
|
||||
{
|
||||
compare cursor-word-addr, words-a
|
||||
break-if-!=
|
||||
render-cursor? <- copy 1/true
|
||||
}
|
||||
var next-x/eax: int <- render-word screen, words-a, x, y, render-cursor?
|
||||
var space/edx: grapheme <- copy 0x20/space
|
||||
draw-grapheme screen, space, next-x, y, 3/fg=cyan, 0/bg
|
||||
next-x <- increment
|
||||
# recurse
|
||||
var next-ah/ecx: (addr handle word) <- get words-a, next
|
||||
next-x <- render-words screen, next-ah, next-x, y, cursor-word-addr
|
||||
return next-x
|
||||
}
|
||||
|
||||
fn test-render-words {
|
||||
# words = [aaa, bbb, ccc, ddd]
|
||||
var w-storage: (handle word)
|
||||
var w-ah/esi: (addr handle word) <- address w-storage
|
||||
allocate-word-with w-ah, "aaa"
|
||||
append-word-at-end-with w-ah, "bbb"
|
||||
append-word-at-end-with w-ah, "ccc"
|
||||
append-word-at-end-with w-ah, "ddd"
|
||||
# setup: screen
|
||||
var screen-on-stack: screen
|
||||
var screen/edi: (addr screen) <- address screen-on-stack
|
||||
initialize-screen screen, 0x20, 4
|
||||
#
|
||||
var _w/eax: (addr word) <- lookup *w-ah
|
||||
var w/ecx: (addr word) <- copy _w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "aaa bbb ccc ddd ", "F - test-render-words/0"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words/0 cursor"
|
||||
# - start moving cursor left through final word
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "aaa bbb ccc ddd ", "F - test-render-words/0"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words/1 cursor"
|
||||
#
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "aaa bbb ccc ddd ", "F - test-render-words/0"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words/2 cursor"
|
||||
#
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "aaa bbb ccc ddd ", "F - test-render-words/0"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "| ", "F - test-render-words/3 cursor"
|
||||
# further moves left within the word change nothing
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "aaa bbb ccc ddd ", "F - test-render-words/0"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "| ", "F - test-render-words/4 cursor"
|
||||
# - switch to next word
|
||||
var w2-ah/eax: (addr handle word) <- get w, next
|
||||
var _w/eax: (addr word) <- lookup *w2-ah
|
||||
var w/ecx: (addr word) <- copy _w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "aaa bbb ccc ddd ", "F - test-render-words/0"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words/5 cursor"
|
||||
# now speed up a little
|
||||
cursor-left w
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "aaa bbb ccc ddd ", "F - test-render-words/0"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words/6 cursor"
|
||||
#
|
||||
var w2-ah/eax: (addr handle word) <- get w, next
|
||||
var _w/eax: (addr word) <- lookup *w2-ah
|
||||
var w/ecx: (addr word) <- copy _w
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "aaa bbb ccc ddd ", "F - test-render-words/0"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words/7 cursor"
|
||||
}
|
||||
|
||||
fn render-words-in-reverse screen: (addr screen), _words-ah: (addr handle word), x: int, y: int, cursor-word-addr: int -> _/eax: int {
|
||||
var words-ah/eax: (addr handle word) <- copy _words-ah
|
||||
var _words-a/eax: (addr word) <- lookup *words-ah
|
||||
var words-a/ecx: (addr word) <- copy _words-a
|
||||
compare words-a, 0
|
||||
{
|
||||
break-if-!=
|
||||
return x
|
||||
}
|
||||
# recurse
|
||||
var next-ah/eax: (addr handle word) <- get words-a, next
|
||||
var next-x/eax: int <- render-words-in-reverse screen, next-ah, x, y, cursor-word-addr
|
||||
# print
|
||||
var render-cursor?/edx: boolean <- copy 0/false
|
||||
{
|
||||
compare cursor-word-addr, words-a
|
||||
break-if-!=
|
||||
render-cursor? <- copy 1/true
|
||||
}
|
||||
next-x <- render-word screen, words-a, next-x, y, render-cursor?
|
||||
var space/ecx: grapheme <- copy 0x20/space
|
||||
draw-grapheme screen, space, next-x, y, 3/fg=cyan, 0/bg
|
||||
next-x <- increment
|
||||
return next-x
|
||||
}
|
||||
|
||||
fn test-render-words-in-reverse {
|
||||
# words = [aaa, bbb, ccc, ddd]
|
||||
var w-storage: (handle word)
|
||||
var w-ah/esi: (addr handle word) <- address w-storage
|
||||
allocate-word-with w-ah, "aaa"
|
||||
append-word-at-end-with w-ah, "bbb"
|
||||
append-word-at-end-with w-ah, "ccc"
|
||||
append-word-at-end-with w-ah, "ddd"
|
||||
# setup: screen
|
||||
var screen-on-stack: screen
|
||||
var screen/edi: (addr screen) <- address screen-on-stack
|
||||
initialize-screen screen, 0x20, 4
|
||||
#
|
||||
var _w/eax: (addr word) <- lookup *w-ah
|
||||
var w/ecx: (addr word) <- copy _w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "ddd ccc bbb aaa ", "F - test-render-words-in-reverse/0"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words-in-reverse/0 cursor"
|
||||
# - start moving cursor left through final word
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "ddd ccc bbb aaa ", "F - test-render-words-in-reverse/1"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words-in-reverse/1 cursor"
|
||||
#
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "ddd ccc bbb aaa ", "F - test-render-words-in-reverse/2"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words-in-reverse/2 cursor"
|
||||
#
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "ddd ccc bbb aaa ", "F - test-render-words-in-reverse/3"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words-in-reverse/3 cursor"
|
||||
# further moves left within the word change nothing
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "ddd ccc bbb aaa ", "F - test-render-words-in-reverse/4"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words-in-reverse/4 cursor"
|
||||
# - switch to next word
|
||||
var w2-ah/eax: (addr handle word) <- get w, next
|
||||
var _w/eax: (addr word) <- lookup *w2-ah
|
||||
var w/ecx: (addr word) <- copy _w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "ddd ccc bbb aaa ", "F - test-render-words-in-reverse/5"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words-in-reverse/5 cursor"
|
||||
# now speed up a little
|
||||
cursor-left w
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "ddd ccc bbb aaa ", "F - test-render-words-in-reverse/6"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words-in-reverse/6 cursor"
|
||||
#
|
||||
var w2-ah/eax: (addr handle word) <- get w, next
|
||||
var _w/eax: (addr word) <- lookup *w2-ah
|
||||
var w/ecx: (addr word) <- copy _w
|
||||
cursor-left w
|
||||
var cursor-word/eax: int <- copy w
|
||||
var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
|
||||
check-screen-row screen, 0/y, "ddd ccc bbb aaa ", "F - test-render-words-in-reverse/7"
|
||||
check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-words-in-reverse/7 cursor"
|
||||
}
|
||||
|
||||
# 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
|
||||
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
|
||||
# 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
|
||||
# new->next = self->next
|
||||
var src/esi: (addr handle word) <- get self, next
|
||||
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-=
|
||||
dest <- get next-addr, prev
|
||||
copy-object new-ah, dest
|
||||
}
|
||||
# new->prev = saved-self
|
||||
dest <- get new-addr, prev
|
||||
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-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
|
||||
}
|
||||
|
||||
fn word-exists? haystack: (addr word), needle: (addr word) -> _/eax: boolean {
|
||||
# base case
|
||||
compare haystack, 0
|
||||
{
|
||||
break-if-!=
|
||||
return 0/false
|
||||
}
|
||||
# check current word
|
||||
var found?/eax: boolean <- words-equal? haystack, needle
|
||||
compare found?, 0/false
|
||||
{
|
||||
break-if-=
|
||||
return 1/true
|
||||
}
|
||||
# recurse
|
||||
var curr/eax: (addr word) <- copy haystack
|
||||
var next-ah/eax: (addr handle word) <- get curr, next
|
||||
var next/eax: (addr word) <- lookup *next-ah
|
||||
var result/eax: boolean <- word-exists? next, needle
|
||||
return result
|
||||
}
|
||||
|
||||
fn test-word-exists? {
|
||||
var needle-storage: word
|
||||
var needle/esi: (addr word) <- address needle-storage
|
||||
initialize-word-with needle, "abc"
|
||||
var w-storage: (handle word)
|
||||
var w-ah/edi: (addr handle word) <- address w-storage
|
||||
allocate w-ah
|
||||
var _w/eax: (addr word) <- lookup *w-ah
|
||||
var w/ecx: (addr word) <- copy _w
|
||||
initialize-word-with w, "aaa"
|
||||
#
|
||||
var result/eax: boolean <- word-exists? w, w
|
||||
check result, "F - test-word-exists? reflexive"
|
||||
result <- word-exists? w, needle
|
||||
check-not result, "F - test-word-exists? 1"
|
||||
append-word-at-end-with w-ah, "bbb"
|
||||
result <- word-exists? w, needle
|
||||
check-not result, "F - test-word-exists? 2"
|
||||
append-word-at-end-with w-ah, "abc"
|
||||
result <- word-exists? w, needle
|
||||
check result, "F - test-word-exists? 3"
|
||||
append-word-at-end-with w-ah, "ddd"
|
||||
result <- word-exists? w, needle
|
||||
check result, "F - test-word-exists? 4"
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue