454 lines
15 KiB
Forth
454 lines
15 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"
|
|
}
|
|
|
|
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 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
|
|
}
|
|
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
|
|
}
|