Reverting to a simpler CPS style.

This commit is contained in:
Elf M. Sternberg 2015-06-10 17:28:47 -07:00
parent 74579b9fa0
commit 647dfbbc14
2 changed files with 87 additions and 44 deletions

1
LisperatorLanguage Symbolic link
View File

@ -0,0 +1 @@
/home/elf/Wiki/LisperatorLanguage

View File

@ -1,20 +1,36 @@
{listToString, listToVector, pairp, cons, car, cdr, caar, cddr, cdar, cadr, caadr, cadar, caddr, nilp, nil, setcdr, metacadr} = require "cons-lists/lists" {listToString, listToVector, pairp, cons, car, cdr, caar, cddr, cdar, cadr, caadr, cadar, caddr, nilp, nil, setcdr, metacadr} = require "cons-lists/lists"
print = require "../chapter1/print" print = require "../chapter1/print"
# Debugging tool. cadddr = metacadr('cadddr')
{inspect} = require "util" {inspect} = require "util"
env_init = nil cpsdecorate = (fn) ->
env_global = env_init (args...) ->
callback = args[args.length - 1]
tocall = args[0 ... (args.length-1)]
callback fn.apply(@, args)
ntype = (node) -> car node ntype = (node) -> car node
nvalu = (node) -> cadr node nvalu = (node) -> cadr node
[listToString, listToVector, pairp, cons, car, cdr,
caar, cddr, cdar, cadr, caadr, cadar, caddr, nilp,
nil, setcdr, metacadr, ntype, nvalu] = [listToString,
listToVector, pairp, cons, car, cdr, caar, cddr,
cdar, cadr, caadr, cadar, caddr, nilp, nil, setcdr,
metacadr, ntype, nvalu].map(cpsdecorate)
# Debugging tool.
env_init = nil
env_global = env_init
# Takes a name and a value and pushes those onto the global environment. # Takes a name and a value and pushes those onto the global environment.
definitial = (name, value = nil) -> definitial = (name, value = nil, callback) ->
env_global = (cons (cons name, value), env_global) cons name, value, (ls) ->
name cons ls, env_global, callback
# Takes a name, a native function, and the expected arity of that # Takes a name, a native function, and the expected arity of that
# function, and returns the global environment with new a (native) # function, and returns the global environment with new a (native)
@ -94,29 +110,30 @@ invoke = (fn, arg) -> (fn arg)
# are hard-coding what ought to be a macro, namely the threading macro # are hard-coding what ought to be a macro, namely the threading macro
# often named "->" # often named "->"
eprogn = (exps, env) -> eprogn = (exps, env, callback) ->
if (pairp exps) if (pairp exps)
if pairp (cdr exps) if pairp (cdr exps)
evaluate (car exps), env evaluate (car exps), env, (c) ->
eprogn (cdr exps), env eprogn (cdr exps), env, callback
else else
evaluate (car exps), env evaluate (car exps), env, callback
else else
nil nil
# Evaluates a list of expressions and returns a list of resolved # Evaluates a list of expressions and returns a list of resolved
# values. # values.
evlis = (exps, env) -> evlis = (exps, env, callback) ->
if (pairp exps) callback if (pairp exps)
(cons (evaluate (car exps), env), (evlis (cdr exps), env)) if (pairp cdr exps)
evaluate (cons (evaluate (car exps), env), (evlis (cdr exps), env))
else else
nil nil
# Locates a named reference in the environment and returns its value. # Locates a named reference in the environment and returns its value.
lookup = (id, env) -> lookup = (id, env, callback) ->
if (pairp env) callback if (pairp env)
if (caar env) == id if (caar env) == id
cdar env cdar env
else else
@ -127,8 +144,8 @@ lookup = (id, env) ->
# Locates a named reference in the environment and replaces its value # Locates a named reference in the environment and replaces its value
# with a new value. # with a new value.
update = (id, env, value) -> update = (id, env, value, callback ) ->
if (pairp env) callback if (pairp env)
if (caar env) == id if (caar env) == id
setcdr value, (car env) setcdr value, (car env)
value value
@ -141,45 +158,70 @@ update = (id, env, value) ->
# interpreter core. I can't help but think that this design precludes # interpreter core. I can't help but think that this design precludes
# pluggable interpreter core. # pluggable interpreter core.
astSymbolsToLispSymbols = (node) -> # Yeah, for the CPS edition, this is WAY cheating:
astSymbolsToLispSymbols = (node, callback) ->
return nil if nilp node return nil if nilp node
throw "Not a list of variable names" if not (ntype(node) is 'list') throw "Not a list of variable names" if not (ntype(node) is 'list')
handler = (node) -> handler = (node) ->
return nil if nilp node return nil if nilp node
cons (nvalu car node), (handler cdr node) cons (nvalu car node), (handler cdr node)
handler(nvalu node) callback handler(nvalu node)
# Takes an AST node and evaluates it and its contents, returning the # Takes an AST node and evaluates it and its contents, returning the
# final value of the calculation. A node may be ("list" (... contents # final value of the calculation. A node may be ("list" (... contents
# ...)) or ("number" 42) or ("symbol" x), etc. # ...)) or ("number" 42) or ("symbol" x), etc.
cadddr = metacadr('cadddr')
evaluate = (e, env) -> ceq = (l, r, thencallback, elsecallback) ->
[type, exp] = [(ntype e), (nvalu e)] (if l is r then thencallback else elsecallback)()
if type == "symbol"
return lookup exp, env cin = (l, r, thencallback, elsecallback) ->
else if type in ["number", "string", "boolean", "vector"] (if l in r then thencallback else elsecallback)()
return exp
else if type == "list" cswitch = (key, ops, callback) ->
head = car exp return ops[key](callback) if key of ops
if (ntype head) == 'symbol' return ops['_default'](callback) if '_default' of ops
switch (nvalu head) throw new Error("Can't handle invocation of #{key}")
when "quote" then cdr exp
when "if" cpsevaluate = (exp, env, callback) ->
unless (evaluate (cadr exp), env) == the_false_value cdr exp, (envexp) ->
evaluate (caddr exp), env evlis envexp, env, (newenv) ->
else car exp, (fnhandle) ->
evaluate (cadddr exp), env evaluate fnhandle, env, callback
when "begin" then eprogn (cdr exp), env
when "set!" then update (nvalu cadr exp), env, (evaluate (caddr exp), env) syntax =
when "lambda" then make_function (astSymbolsToLispSymbols cadr exp), (cddr exp), env "quote": (callback) -> cdr exp, callback
else invoke (evaluate (car exp), env), (evlis (cdr exp), env) "if": (callback) ->
else cadr exp, (e) ->
invoke (evaluate (car exp), env), (evlis (cdr exp), env) evaluate e, env, (c) ->
else cif(c, the_false_value,
throw new Error("Can't handle a #{type}") (-> cadddr exp, (e) -> evaluate e, env, callback),
(-> caddr exp, (e) -> evaluate e, env, callback))
"begin": (callback) -> cdr exp, ((e) -> eprogn e, env, callback)
"set!": (callback) -> cadr exp, (e) ->
nvalu e, (n) ->
caddr exp, (r) ->
evaluate r, env, (r2) ->
update n, env, r2, callback
"lambda": (callback) -> cddr expr, (body) ->
cadr exp, (astSymbols) ->
astSymbolsToLispSymbols astSymbols, (lispSymbols) ->
make_function lispSymbols, body, env, callback
"_default": (callback) -> cpsevaluate exp, env, callback
evaluate = (e, env, callback) ->
ntype e, (type) ->
nvalu e, (exp) ->
ceq type, "symbol", (-> lookup exp, env, callback), ->
cin type, ["number", "string", "boolean", "vector"], (-> callback exp), (->
ceq type, "list", (->
car exp, (head) ->
ntype head, (h) -> ceq h, "symbol", -> nvalu head, (hv) ->
cswitch hv, syntax, callback
), -> cpsevaluate exp, env, callback
), -> throw new Error("Can't handle a #{type}")
module.exports = (c) -> evaluate c, env_global module.exports = (c) -> evaluate c, env_global