7863 - shell: anonymous fn calls

This commit is contained in:
Kartik K. Agaram 2021-03-07 11:05:03 -08:00
parent 5b50feaeee
commit d2b7e3f44f
2 changed files with 99 additions and 12 deletions

View File

@ -162,9 +162,85 @@ fn apply-function params-ah: (addr handle cell), args-ah: (addr handle cell), _b
# `out` contains result of evaluating final expression
}
# Bind params to corresponding args and add the bindings to old-env. Return
# the result in env-ah.
#
# We never modify old-env, but we point to it. This way other parts of the
# interpreter can continue using old-env, and everything works harmoniously
# even though no cells are copied around.
#
# env should always be a DAG (ignoring internals of values). It doesn't have
# to be a tree (some values may be shared), but there are also no cycles.
#
# Learn more: https://en.wikipedia.org/wiki/Persistent_data_structure
fn push-bindings _params-ah: (addr handle cell), _args-ah: (addr handle cell), old-env-h: (handle cell), env-ah: (addr handle cell), trace: (addr trace) {
# no bindings for now
copy-handle old-env-h, env-ah
var params-ah/edx: (addr handle cell) <- copy _params-ah
var args-ah/ebx: (addr handle cell) <- copy _args-ah
var _params/eax: (addr cell) <- lookup *params-ah
var params/esi: (addr cell) <- copy _params
{
var params-is-nil?/eax: boolean <- is-nil? params
compare params-is-nil?, 0/false
break-if-=
# nil is a literal
trace-text trace, "eval", "done with push-bindings"
copy-handle old-env-h, env-ah
trace-higher trace
return
}
# Params can only be symbols or pairs. Args can be anything.
# trace "pushing bindings from " params " to " args {{{
{
var stream-storage: (stream byte 0x40)
var stream/ecx: (addr stream byte) <- address stream-storage
write stream, "pushing bindings from "
print-cell params-ah, stream, 0/no-trace
write stream, " to "
print-cell args-ah, stream, 0/no-trace
trace trace, "eval", stream
}
# }}}
trace-lower trace
var params-type/eax: (addr int) <- get params, type
compare *params-type, 2/symbol
{
break-if-!=
trace-text trace, "eval", "symbol; binding to all remaining args"
# create a new binding
var new-binding-storage: (handle cell)
var new-binding-ah/eax: (addr handle cell) <- address new-binding-storage
new-pair new-binding-ah, *params-ah, *args-ah
# push it to env
new-pair env-ah, *new-binding-ah, old-env-h
trace-higher trace
return
}
compare *params-type, 0/pair
{
break-if-=
error trace, "cannot bind a non-symbol"
trace-higher trace
return
}
var _args/eax: (addr cell) <- lookup *args-ah
var args/edi: (addr cell) <- copy _args
# params is now a pair, so args must be also
var args-type/eax: (addr int) <- get args, type
compare *args-type, 0/pair
{
break-if-=
error trace, "args not in a proper list"
trace-higher trace
return
}
var intermediate-env-storage: (handle cell)
var intermediate-env-ah/edx: (addr handle cell) <- address intermediate-env-storage
var first-param-ah/eax: (addr handle cell) <- get params, left
var first-arg-ah/ecx: (addr handle cell) <- get args, left
push-bindings first-param-ah, first-arg-ah, old-env-h, intermediate-env-ah, trace
var remaining-params-ah/eax: (addr handle cell) <- get params, right
var remaining-args-ah/ecx: (addr handle cell) <- get args, right
push-bindings remaining-params-ah, remaining-args-ah, *intermediate-env-ah, env-ah, trace
}
fn apply-primitive _f: (addr cell), args-ah: (addr handle cell), out: (addr handle cell), env-h: (handle cell), trace: (addr trace) {

View File

@ -79,16 +79,6 @@ fn print-list _in: (addr cell), out: (addr stream byte), trace: (addr trace) {
write out, "("
$print-list:loop: {
var left/ecx: (addr handle cell) <- get curr, left
{
var left-addr/eax: (addr cell) <- lookup *left
var left-is-nil?/eax: boolean <- is-nil? left-addr
compare left-is-nil?, 0/false
{
break-if-=
trace-text trace, "print", "left is null"
break $print-list:loop
}
}
print-cell left, out, trace
var right/ecx: (addr handle cell) <- get curr, right
var right-addr/eax: (addr cell) <- lookup *right
@ -251,6 +241,27 @@ fn test-print-cell-list {
check-stream-equal out, "(64 abc)", "F - test-print-cell-list"
}
fn test-print-cell-list-of-nil {
# list = cons "abc", nil
var left-storage: (handle cell)
var left/ecx: (addr handle cell) <- address left-storage
allocate-pair left
var nil-storage: (handle cell)
var nil/edx: (addr handle cell) <- address nil-storage
allocate-pair nil
var list-storage: (handle cell)
var list/esi: (addr handle cell) <- address list-storage
new-pair list, *left, *nil
# list = cons 64, list
new-integer left, 0x40
new-pair list, *left, *list
#
var out-storage: (stream byte 0x40)
var out/edi: (addr stream byte) <- address out-storage
print-cell list, out, 0/no-trace
check-stream-equal out, "(64 ())", "F - test-print-cell-list-nil"
}
fn test-print-dotted-list {
# list = cons 64, "abc"
var left-storage: (handle cell)