83 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.
class lambda(param, body, env)
generic describe(v) -> dyn
method describe(f: lambda)
"a function of one argument"
multi kind(v) -> dyn = type-of(v)
method kind(v) when :int
"number"
method kind(v) when :vec = "form"
method kind(v) when :else
"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)
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