mu/shell/global.mu

651 lines
22 KiB
Forth

type global {
name: (handle array byte)
value: (handle cell)
}
type global-table {
data: (handle array global)
final-index: int
}
fn initialize-globals _self: (addr global-table) {
var self/esi: (addr global-table) <- copy _self
var data-ah/eax: (addr handle array global) <- get self, data
populate data-ah, 0x10
append-primitive self, "+"
append-primitive self, "-"
append-primitive self, "*"
append-primitive self, "/"
append-primitive self, "sqrt"
append-primitive self, "car"
append-primitive self, "cdr"
append-primitive self, "cons"
append-primitive self, "="
append-primitive self, "print"
# TODO: isolate screens per-sandbox
var screen-storage: (handle cell)
var screen-ah/ecx: (addr handle cell) <- address screen-storage
new-screen screen-ah, 5/width, 4/height
append-global self, "screen", *screen-ah
}
fn render-globals screen: (addr screen), _self: (addr global-table), xmin: int, ymin: int, xmax: int, ymax: int {
clear-rect screen, xmin, ymin, xmax, ymax, 0x12/bg=almost-black
var self/esi: (addr global-table) <- copy _self
# render primitives
var bottom-line/ecx: int <- copy ymax
bottom-line <- decrement
var data-ah/eax: (addr handle array global) <- get self, data
var data/eax: (addr array global) <- lookup *data-ah
var curr-index/edx: int <- copy 1
var x/edi: int <- copy xmin
{
var curr-offset/ebx: (offset global) <- compute-offset data, curr-index
var curr/ebx: (addr global) <- index data, curr-offset
var continue?/eax: boolean <- primitive-global? curr
compare continue?, 0/false
break-if-=
var curr-name-ah/eax: (addr handle array byte) <- get curr, name
var _curr-name/eax: (addr array byte) <- lookup *curr-name-ah
var curr-name/ebx: (addr array byte) <- copy _curr-name
{
var skip?/eax: boolean <- string-equal? curr-name, "screen"
compare skip?, 0/false
break-if-!=
var tmpx/eax: int <- copy x
tmpx <- draw-text-rightward screen, curr-name, tmpx, xmax, bottom-line, 0x2a/fg=orange, 0x12/bg=almost-black
tmpx <- draw-text-rightward screen, " ", tmpx, xmax, bottom-line, 7/fg=grey, 0x12/bg=almost-black
x <- copy tmpx
}
curr-index <- increment
loop
}
var lowest-index/edi: int <- copy curr-index
var y/ecx: int <- copy ymin
var data-ah/eax: (addr handle array global) <- get self, data
var data/eax: (addr array global) <- lookup *data-ah
var final-index/edx: (addr int) <- get self, final-index
var curr-index/edx: int <- copy *final-index
{
compare curr-index, lowest-index
break-if-<
compare y, ymax
break-if->=
{
var curr-offset/ebx: (offset global) <- compute-offset data, curr-index
var curr/ebx: (addr global) <- index data, curr-offset
var curr-name-ah/eax: (addr handle array byte) <- get curr, name
var _curr-name/eax: (addr array byte) <- lookup *curr-name-ah
var curr-name/edx: (addr array byte) <- copy _curr-name
var skip?/eax: boolean <- string-equal? curr-name, "screen"
compare skip?, 0/false
break-if-!=
var x/eax: int <- copy xmin
x, y <- draw-text-wrapping-right-then-down screen, curr-name, xmin, ymin, xmax, ymax, x, y, 0x2a/fg=orange, 0x12/bg=almost-black
x, y <- draw-text-wrapping-right-then-down screen, " <- ", xmin, ymin, xmax, ymax, x, y, 7/fg=grey, 0x12/bg=almost-black
var curr-value/edx: (addr handle cell) <- get curr, value
var s-storage: (stream byte 0x100)
var s/ebx: (addr stream byte) <- address s-storage
print-cell curr-value, s, 0/no-trace
x, y <- draw-stream-wrapping-right-then-down screen, s, xmin, ymin, xmax, ymax, x, y, 0x3/fg=cyan, 0x12/bg=almost-black
}
curr-index <- decrement
y <- increment
loop
}
}
fn primitive-global? _x: (addr global) -> _/eax: boolean {
var x/eax: (addr global) <- copy _x
var value-ah/eax: (addr handle cell) <- get x, value
var value/eax: (addr cell) <- lookup *value-ah
compare value, 0/null
{
break-if-!=
return 0/false
}
var value-type/eax: (addr int) <- get value, type
compare *value-type, 4/primitive
{
break-if-=
return 0/false
}
return 1/true
}
fn append-primitive _self: (addr global-table), name: (addr array byte) {
var self/esi: (addr global-table) <- copy _self
var final-index-addr/ecx: (addr int) <- get self, final-index
increment *final-index-addr
var curr-index/ecx: int <- copy *final-index-addr
var data-ah/eax: (addr handle array global) <- get self, data
var data/eax: (addr array global) <- lookup *data-ah
var curr-offset/esi: (offset global) <- compute-offset data, curr-index
var curr/esi: (addr global) <- index data, curr-offset
var curr-name-ah/eax: (addr handle array byte) <- get curr, name
copy-array-object name, curr-name-ah
var curr-value-ah/eax: (addr handle cell) <- get curr, value
new-primitive-function curr-value-ah, curr-index
}
fn append-global _self: (addr global-table), name: (addr array byte), value: (handle cell) {
var self/esi: (addr global-table) <- copy _self
var final-index-addr/ecx: (addr int) <- get self, final-index
increment *final-index-addr
var curr-index/ecx: int <- copy *final-index-addr
var data-ah/eax: (addr handle array global) <- get self, data
var data/eax: (addr array global) <- lookup *data-ah
var curr-offset/esi: (offset global) <- compute-offset data, curr-index
var curr/esi: (addr global) <- index data, curr-offset
var curr-name-ah/eax: (addr handle array byte) <- get curr, name
copy-array-object name, curr-name-ah
var curr-value-ah/eax: (addr handle cell) <- get curr, value
copy-handle value, curr-value-ah
}
fn lookup-symbol-in-globals _sym: (addr cell), out: (addr handle cell), _globals: (addr global-table), trace: (addr trace) {
var sym/eax: (addr cell) <- copy _sym
var sym-data-ah/eax: (addr handle stream byte) <- get sym, text-data
var _sym-data/eax: (addr stream byte) <- lookup *sym-data-ah
var sym-data/edx: (addr stream byte) <- copy _sym-data
var globals/esi: (addr global-table) <- copy _globals
{
compare globals, 0
break-if-=
var global-data-ah/eax: (addr handle array global) <- get globals, data
var global-data/eax: (addr array global) <- lookup *global-data-ah
var final-index/ecx: (addr int) <- get globals, final-index
var curr-index/ecx: int <- copy *final-index
{
compare curr-index, 0
break-if-<
var curr-offset/ebx: (offset global) <- compute-offset global-data, curr-index
var curr/ebx: (addr global) <- index global-data, curr-offset
var curr-name-ah/eax: (addr handle array byte) <- get curr, name
var curr-name/eax: (addr array byte) <- lookup *curr-name-ah
var found?/eax: boolean <- stream-data-equal? sym-data, curr-name
{
compare found?, 0/false
break-if-=
var curr-value/eax: (addr handle cell) <- get curr, value
copy-object curr-value, out
return
}
curr-index <- decrement
loop
}
}
# otherwise error "unbound symbol: ", sym
var stream-storage: (stream byte 0x40)
var stream/ecx: (addr stream byte) <- address stream-storage
write stream, "unbound symbol: "
rewind-stream sym-data
write-stream stream, sym-data
trace trace, "error", stream
}
# a little strange; goes from value to name and selects primitive based on name
fn apply-primitive _f: (addr cell), args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), _globals: (addr global-table), trace: (addr trace) {
var f/esi: (addr cell) <- copy _f
var f-index-a/ecx: (addr int) <- get f, index-data
var f-index/ecx: int <- copy *f-index-a
var globals/eax: (addr global-table) <- copy _globals
var global-data-ah/eax: (addr handle array global) <- get globals, data
var global-data/eax: (addr array global) <- lookup *global-data-ah
var f-offset/ecx: (offset global) <- compute-offset global-data, f-index
var f-value/ecx: (addr global) <- index global-data, f-offset
var f-name-ah/ecx: (addr handle array byte) <- get f-value, name
var f-name/eax: (addr array byte) <- lookup *f-name-ah
{
var is-add?/eax: boolean <- string-equal? f-name, "+"
compare is-add?, 0/false
break-if-=
apply-add args-ah, out, env-h, trace
return
}
{
var is-subtract?/eax: boolean <- string-equal? f-name, "-"
compare is-subtract?, 0/false
break-if-=
apply-subtract args-ah, out, env-h, trace
return
}
{
var is-multiply?/eax: boolean <- string-equal? f-name, "*"
compare is-multiply?, 0/false
break-if-=
apply-multiply args-ah, out, env-h, trace
return
}
{
var is-divide?/eax: boolean <- string-equal? f-name, "/"
compare is-divide?, 0/false
break-if-=
apply-divide args-ah, out, env-h, trace
return
}
{
var is-square-root?/eax: boolean <- string-equal? f-name, "sqrt"
compare is-square-root?, 0/false
break-if-=
apply-square-root args-ah, out, env-h, trace
return
}
{
var is-car?/eax: boolean <- string-equal? f-name, "car"
compare is-car?, 0/false
break-if-=
apply-car args-ah, out, env-h, trace
return
}
{
var is-cdr?/eax: boolean <- string-equal? f-name, "cdr"
compare is-cdr?, 0/false
break-if-=
apply-cdr args-ah, out, env-h, trace
return
}
{
var is-cons?/eax: boolean <- string-equal? f-name, "cons"
compare is-cons?, 0/false
break-if-=
apply-cons args-ah, out, env-h, trace
return
}
{
var is-compare?/eax: boolean <- string-equal? f-name, "="
compare is-compare?, 0/false
break-if-=
apply-compare args-ah, out, env-h, trace
return
}
{
var is-print?/eax: boolean <- string-equal? f-name, "print"
compare is-print?, 0/false
break-if-=
apply-print args-ah, out, env-h, trace
return
}
abort "unknown primitive function"
}
fn apply-add _args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply +"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
var _env/eax: (addr cell) <- lookup env-h
var env/edi: (addr cell) <- copy _env
# TODO: check that args is a pair
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "+ needs 2 args but got 0"
return
}
# args->left->value
var first-ah/eax: (addr handle cell) <- get args, left
var first/eax: (addr cell) <- lookup *first-ah
var first-type/ecx: (addr int) <- get first, type
compare *first-type, 1/number
{
break-if-=
error trace, "first arg for + is not a number"
return
}
var first-value/ecx: (addr float) <- get first, number-data
# args->right->left->value
var right-ah/eax: (addr handle cell) <- get args, right
#? dump-cell right-ah
#? abort "aaa"
var right/eax: (addr cell) <- lookup *right-ah
# TODO: check that right is a pair
var second-ah/eax: (addr handle cell) <- get right, left
var second/eax: (addr cell) <- lookup *second-ah
var second-type/edx: (addr int) <- get second, type
compare *second-type, 1/number
{
break-if-=
error trace, "second arg for + is not a number"
return
}
var second-value/edx: (addr float) <- get second, number-data
# add
var result/xmm0: float <- copy *first-value
result <- add *second-value
new-float out, result
}
fn apply-subtract _args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply -"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
var _env/eax: (addr cell) <- lookup env-h
var env/edi: (addr cell) <- copy _env
# TODO: check that args is a pair
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "- needs 2 args but got 0"
return
}
# args->left->value
var first-ah/eax: (addr handle cell) <- get args, left
var first/eax: (addr cell) <- lookup *first-ah
var first-type/ecx: (addr int) <- get first, type
compare *first-type, 1/number
{
break-if-=
error trace, "first arg for - is not a number"
return
}
var first-value/ecx: (addr float) <- get first, number-data
# args->right->left->value
var right-ah/eax: (addr handle cell) <- get args, right
var right/eax: (addr cell) <- lookup *right-ah
# TODO: check that right is a pair
var second-ah/eax: (addr handle cell) <- get right, left
var second/eax: (addr cell) <- lookup *second-ah
var second-type/edx: (addr int) <- get second, type
compare *second-type, 1/number
{
break-if-=
error trace, "second arg for - is not a number"
return
}
var second-value/edx: (addr float) <- get second, number-data
# subtract
var result/xmm0: float <- copy *first-value
result <- subtract *second-value
new-float out, result
}
fn apply-multiply _args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply *"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
var _env/eax: (addr cell) <- lookup env-h
var env/edi: (addr cell) <- copy _env
# TODO: check that args is a pair
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "* needs 2 args but got 0"
return
}
# args->left->value
var first-ah/eax: (addr handle cell) <- get args, left
var first/eax: (addr cell) <- lookup *first-ah
var first-type/ecx: (addr int) <- get first, type
compare *first-type, 1/number
{
break-if-=
error trace, "first arg for * is not a number"
return
}
var first-value/ecx: (addr float) <- get first, number-data
# args->right->left->value
var right-ah/eax: (addr handle cell) <- get args, right
var right/eax: (addr cell) <- lookup *right-ah
# TODO: check that right is a pair
var second-ah/eax: (addr handle cell) <- get right, left
var second/eax: (addr cell) <- lookup *second-ah
var second-type/edx: (addr int) <- get second, type
compare *second-type, 1/number
{
break-if-=
error trace, "second arg for * is not a number"
return
}
var second-value/edx: (addr float) <- get second, number-data
# multiply
var result/xmm0: float <- copy *first-value
result <- multiply *second-value
new-float out, result
}
fn apply-divide _args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply /"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
var _env/eax: (addr cell) <- lookup env-h
var env/edi: (addr cell) <- copy _env
# TODO: check that args is a pair
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "/ needs 2 args but got 0"
return
}
# args->left->value
var first-ah/eax: (addr handle cell) <- get args, left
var first/eax: (addr cell) <- lookup *first-ah
var first-type/ecx: (addr int) <- get first, type
compare *first-type, 1/number
{
break-if-=
error trace, "first arg for / is not a number"
return
}
var first-value/ecx: (addr float) <- get first, number-data
# args->right->left->value
var right-ah/eax: (addr handle cell) <- get args, right
var right/eax: (addr cell) <- lookup *right-ah
# TODO: check that right is a pair
var second-ah/eax: (addr handle cell) <- get right, left
var second/eax: (addr cell) <- lookup *second-ah
var second-type/edx: (addr int) <- get second, type
compare *second-type, 1/number
{
break-if-=
error trace, "second arg for / is not a number"
return
}
var second-value/edx: (addr float) <- get second, number-data
# divide
var result/xmm0: float <- copy *first-value
result <- divide *second-value
new-float out, result
}
fn apply-square-root _args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply sqrt"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
var _env/eax: (addr cell) <- lookup env-h
var env/edi: (addr cell) <- copy _env
# TODO: check that args is a pair
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "sqrt needs 1 args but got 0"
return
}
# args->left->value
var first-ah/eax: (addr handle cell) <- get args, left
var first/eax: (addr cell) <- lookup *first-ah
var first-type/ecx: (addr int) <- get first, type
compare *first-type, 1/number
{
break-if-=
error trace, "arg for sqrt is not a number"
return
}
var first-value/ecx: (addr float) <- get first, number-data
# square-root
var result/xmm0: float <- square-root *first-value
new-float out, result
}
fn apply-car _args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply car"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
var _env/eax: (addr cell) <- lookup env-h
var env/edi: (addr cell) <- copy _env
# TODO: check that args is a pair
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "car needs 1 args but got 0"
return
}
# args->left
var first-ah/eax: (addr handle cell) <- get args, left
var first/eax: (addr cell) <- lookup *first-ah
var first-type/ecx: (addr int) <- get first, type
compare *first-type, 0/pair
{
break-if-=
error trace, "arg for car is not a pair"
return
}
# car
var result/eax: (addr handle cell) <- get first, left
copy-object result, out
}
fn apply-cdr _args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply cdr"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
var _env/eax: (addr cell) <- lookup env-h
var env/edi: (addr cell) <- copy _env
# TODO: check that args is a pair
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "cdr needs 1 args but got 0"
return
}
# args->left
var first-ah/eax: (addr handle cell) <- get args, left
var first/eax: (addr cell) <- lookup *first-ah
var first-type/ecx: (addr int) <- get first, type
compare *first-type, 0/pair
{
break-if-=
error trace, "arg for cdr is not a pair"
return
}
# cdr
var result/eax: (addr handle cell) <- get first, right
copy-object result, out
}
fn apply-cons _args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply cons"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
var _env/eax: (addr cell) <- lookup env-h
var env/edi: (addr cell) <- copy _env
# TODO: check that args is a pair
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "cons needs 2 args but got 0"
return
}
# args->left
var first-ah/ecx: (addr handle cell) <- get args, left
# args->right->left
var right-ah/eax: (addr handle cell) <- get args, right
var right/eax: (addr cell) <- lookup *right-ah
# TODO: check that right is a pair
var second-ah/eax: (addr handle cell) <- get right, left
# cons
new-pair out, *first-ah, *second-ah
}
fn apply-compare _args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply ="
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
var _env/eax: (addr cell) <- lookup env-h
var env/edi: (addr cell) <- copy _env
# TODO: check that args is a pair
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "cons needs 2 args but got 0"
return
}
# args->left
var first-ah/ecx: (addr handle cell) <- get args, left
# args->right->left
var right-ah/eax: (addr handle cell) <- get args, right
var right/eax: (addr cell) <- lookup *right-ah
# TODO: check that right is a pair
var second-ah/edx: (addr handle cell) <- get right, left
# compare
var _first/eax: (addr cell) <- lookup *first-ah
var first/ecx: (addr cell) <- copy _first
var second/eax: (addr cell) <- lookup *second-ah
var match?/eax: boolean <- cell-isomorphic? first, second, trace
compare match?, 0/false
{
break-if-!=
nil out
return
}
new-integer out, 1/true
}
fn apply-print _args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply print"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
var _env/eax: (addr cell) <- lookup env-h
var env/edi: (addr cell) <- copy _env
# TODO: check that args is a pair
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "cons needs 2 args but got 0"
return
}
# screen = args->left
var first-ah/eax: (addr handle cell) <- get args, left
var first/eax: (addr cell) <- lookup *first-ah
var first-type/ecx: (addr int) <- get first, type
compare *first-type, 5/screen
{
break-if-=
error trace, "first arg for 'print' is not a screen"
return
}
var screen-ah/eax: (addr handle screen) <- get first, screen-data
var _screen/eax: (addr screen) <- lookup *screen-ah
var screen/ecx: (addr screen) <- copy _screen
# args->right->left
var right-ah/eax: (addr handle cell) <- get args, right
var right/eax: (addr cell) <- lookup *right-ah
# TODO: check that right is a pair
var second-ah/eax: (addr handle cell) <- get right, left
var stream-storage: (stream byte 0x100)
var stream/edi: (addr stream byte) <- address stream-storage
print-cell second-ah, stream, trace
draw-stream-wrapping-right-then-down-from-cursor-over-full-screen screen, stream, 7/fg, 0/bg
# return what was printed
copy-object second-ah, out
}