84 lines
2.2 KiB
Plaintext
84 lines
2.2 KiB
Plaintext
; A small interpreter over dyn values: a program is nested vectors whose
|
|
; first element is a keyword naming the operation, variables are keywords,
|
|
; and environments are dyn maps chained through a :parent key.
|
|
|
|
defclass(lambda, [param body env])
|
|
|
|
defgeneric(describe, [v], dyn)
|
|
|
|
defmethod(describe, lambda, [f]):
|
|
"a function of one argument"
|
|
|
|
defmulti(kind, [v], dyn, type-of(v))
|
|
|
|
defmethod(kind, :int, [v]):
|
|
"number"
|
|
|
|
defmethod(kind, :vec, [v]):
|
|
"form"
|
|
|
|
defmethod(kind, :else, [v]):
|
|
"value"
|
|
|
|
once steps = 0
|
|
|
|
fn lookup(env, name) -> dyn
|
|
if env == nil
|
|
println("unbound", name)
|
|
return 0
|
|
if has-key?(env, name) then get(env, name) else lookup(get(env, :parent), name)
|
|
|
|
fn extend(env, name, value) -> dyn
|
|
{:parent env name value}
|
|
|
|
fn eval(e, env) -> dyn
|
|
steps += 1
|
|
match type-of(e)
|
|
:keyword -> lookup(env, e)
|
|
:vec -> eval-form(e, env)
|
|
_ -> e
|
|
|
|
fn eval-form(e, env) -> dyn
|
|
let op = e[0]
|
|
match op
|
|
:+ -> eval(e[1], env) + eval(e[2], env)
|
|
:- -> eval(e[1], env) - eval(e[2], env)
|
|
:* -> eval(e[1], env) * eval(e[2], env)
|
|
:< -> eval(e[1], env) < eval(e[2], env)
|
|
:if ->
|
|
if eval(e[1], env) then eval(e[2], env) else eval(e[3], env)
|
|
:let ->
|
|
let v = eval(e[2], env)
|
|
let inner = extend(env, e[1], v)
|
|
; A function sees its own name, so it can call itself.
|
|
if type-of(v) == :lambda
|
|
put(v, :env, inner)
|
|
eval(e[3], inner)
|
|
:fn -> lambda(e[1], e[2], env)
|
|
:do ->
|
|
let last = nil
|
|
for i in range(1, length(e))
|
|
last = eval(e[i], env)
|
|
last
|
|
_ ->
|
|
let f = eval(op, env)
|
|
let arg = eval(e[1], env)
|
|
eval(get(f, :body), extend(get(f, :env), get(f, :param), arg))
|
|
|
|
fn run(program) -> ()
|
|
steps = 0
|
|
let result = eval(program, {:parent nil})
|
|
println(kind(program), "=>", result, "in", steps, "steps")
|
|
|
|
fn main() -> i32
|
|
run(42)
|
|
run([:+ 1 [:* 2 3]])
|
|
run([:let :x 5 [:if [:< :x 3] :small [:* :x :x]]])
|
|
let fact = [:let :fact [:fn :n [:if [:< :n 2] 1 [:* :n [:fact [:- :n 1]]]]] [:fact 6]]
|
|
run(fact)
|
|
run([:let :k 10 [:let :add-k [:fn :y [:+ :y :k]] [:do [:add-k 1] [:add-k 32]]]])
|
|
let f = eval([:fn :x :x], {:parent nil})
|
|
println(describe(f), "/", kind(f), "/", type-of(f))
|
|
run([:let :greeting "hello" :greeting])
|
|
0
|