9 -- {car={num=3.4}, cdr=nil}
11 -- should {} mean anything special? currently just '(nil)
13 return x
== nil or x
.num
or x
.char
or x
.str
or x
.sym
16 function car(x
) return x
.car
end
17 function cdr(x
) return x
.cdr
end
18 function cons(x
, y
) return {car
=x
, cdr
=y
} end
21 if x
== nil then return y
== nil end
23 if done
[x
] then return done
[x
] == y
end
26 if not atom(y
) then return nil end
27 for k
, v
in pairs(x
) do
28 if y
[k
] ~= v
then return nil end
32 for k
, v
in pairs(x
) do
33 if not iso(y
[k
], v
) then return nil end
35 for k
, v
in pairs(y
) do
36 if not iso(x
[k
], v
) then return nil end
41 -- primitives; feel free to add more
42 -- format: lisp name = lua function that implements it
54 function lookup(env
, s
)
55 if env
[s
] then return env
[s
] end
56 if env
.next then return lookup(env
.next, s
) end
61 return x
and x
.sym
== s
64 return lookup(env
, x
.sym
)
67 -- otherwise x is a pair
68 elseif symeq(x
.car
, 'quote') then
70 elseif unary_functions
[x
.car
.sym
] then
71 return eval_unary(x
, env
)
72 elseif binary_functions
[x
.car
.sym
] then
73 return eval_binary(x
, env
)
74 -- special forms that don't always eval all their args
75 elseif symeq(x
.car
, 'if') then
76 return eval_if(x
, env
)
77 elseif symeq(x
.car
.car
, 'fn') then
78 return eval_fn(x
, env
)
79 elseif symeq(x
.car
.car
, 'label') then
80 return eval_label(x
, env
)
84 function eval_unary(x
, env
)
85 return unary_functions
[x
.car
.sym
](eval(x
.cdr
.car
, env
))
88 function eval_binary(x
, env
)
89 return binary_functions
[x
.car
.sym
](eval(x
.cdr
.car
, env
),
90 eval(x
.cdr
.cdr
.car
, env
))
93 function eval_if(x
, env
)
94 -- syntax: (if check b1 b2)
95 local check
= x
.cdr
.car
96 local b1
= x
.cdr
.cdr
.car
97 local b2
= x
.cdr
.cdr
.cdr
.car
98 if eval(check
, env
) then
105 function eval_fn(x
, env
)
106 -- syntax: ((fn params body*) args*)
109 local params
= callee
.cdr
.car
110 local body
= callee
.cdr
.cdr
111 return eval_exprs(body
,
112 bind_env(params
, args
, env
))
115 function bind_env(params
, args
, env
)
116 if params
== nil then return env
end
117 local result
= {next=env
}
119 result
[params
.car
.sym
] = eval(args
.car
, env
)
122 if params
== nil then break end
127 function eval_exprs(xs
, env
)
130 result
= eval(xs
.car
, env
)
136 function eval_label(x
, env
)
137 -- syntax: ((label f (fn params body*)) args*)
140 local f
= callee
.cdr
.car
141 local fn
= callee
.cdr
.cdr
.car
142 return eval({car
=fn
, cdr
=args
},
143 bind_env({f
}, {callee
}, env
))
147 function num(n
) return {num
=n
} end
148 function char(c
) return {char
=c
} end
149 function str(s
) return {str
=s
} end
150 function sym(s
) return {sym
=s
} end
152 -- gotcha: no element in arg can be nil; that short-circuits the ipairs below
155 for _
, x
in ipairs({...}) do
175 elseif x
== true then
180 io
.write("\\"..x
.char
)
182 io
.write('"'..x
.str
..'"')
185 elseif x
.cdr
== nil then
189 elseif atom(x
.cdr
) then
200 if x
== nil then break end
218 p(iso(cons(x
, nil), cons(x
, nil)))
219 p(iso(list(x
), list(x
)))
220 p(iso(list(x
, x
), list(x
)))
221 p(iso(list(x
, x
), list(x
, x
)))
222 p(iso(x
, cons(x
, nil)))
224 p (list(sym("cons"), num(42), num(1)))
225 p(eval(list(sym("cons"), num(42), num(1)), {}))
227 -- ((fn () 42)) => 42
228 -- can't use list here because of the gotcha above
229 assert(iso(eval(cons(cons(sym('fn'), cons(nil, cons(num(42))))), {}), num(42)))
230 -- ((fn (a) (cons a 1)) 42) => '(42 . 1)
231 assert(iso(eval(cons(cons(sym('fn'), cons(cons(sym('a')), cons(cons(sym('cons'), cons(sym('a'), cons(num(1))))))), cons(num(42)))), cons(num(42), num(1))))