about summary refs log tree commit diff stats
path: root/eval.lua
diff options
context:
space:
mode:
Diffstat (limited to 'eval.lua')
-rw-r--r--eval.lua88
1 files changed, 53 insertions, 35 deletions
diff --git a/eval.lua b/eval.lua index 53292d0..60369a9 100644 --- a/eval.lua +++ b/eval.lua
@@ -20,7 +20,7 @@ function m.environ (inner, outer)
20 return setmetatable(inner, mt) 20 return setmetatable(inner, mt)
21end 21end
22 22
23local function call_proc (proc, r) 23local function procedure_call (proc, r)
24 local function doargs (p, r, e) 24 local function doargs (p, r, e)
25 if p == type.null and r == type.null then return e end 25 if p == type.null and r == type.null then return e end
26 if type.isa(p, "symbol") then 26 if type.isa(p, "symbol") then
@@ -50,57 +50,75 @@ function m.procedure (params, body, env)
50 } 50 }
51 local mt = { 51 local mt = {
52 __type = "procedure", 52 __type = "procedure",
53 __call = call_proc, 53 __call = procedure_call,
54 } 54 }
55 return setmetatable(t, mt) 55 return setmetatable(t, mt)
56end 56end
57 57
58local function handle_quasiquote (r, e)
59 assert_arity(r, 1, 1)
60 local x = r[1]
61 if not type.islist(x) or x == type.null then
62 return x
63 end
64 local QQ, fin = {}, nil
65 local car, cdr = x[1], x[2]
66 while cdr do
67 if type.islist(car) then
68 if car[1] == "unquote" then
69 table.insert(QQ, m.eval(car[2][1], e))
70 elseif car[1] == "unquote-splicing" then
71 local usl = m.eval(car[2][1], e)
72 if not type.islist(usl) then
73 fin = usl
74 break
75 end
76 while usl[2] do
77 table.insert(QQ, usl[1])
78 usl = usl[2]
79 end
80 end
81 else
82 table.insert(QQ, car)
83 end
84 car, cdr = cdr[1], cdr[2]
85 end
86 return type.list(QQ, fin)
87end
88
58m.specials = { 89m.specials = {
59 -- each of these takes R (a list of args) and E (an environment) 90 -- each of these takes R (a list of args) and E (an environment)
60 quote = function (r, e) return r[1] end, 91 quote =
61 quasiquote =
62 function (r, e) 92 function (r, e)
63 local x = r[1] 93 assert_arity(r, 1, 1)
64 if not type.islist(x) or x == type.null then 94 return r[1]
65 return x
66 end
67 local QQ, fin = {}, nil
68 local car, cdr = x[1], x[2]
69 while cdr do
70 if type.islist(car) then
71 if car[1] == "unquote" then
72 table.insert(QQ,
73 m.eval(car[2][1], e))
74 elseif car[1] == "unquote-splicing" then
75 local usl = m.eval(car[2][1], e)
76 if not type.islist(usl) then
77 fin = usl
78 break
79 end
80 while usl[2] do
81 table.insert(QQ, usl[1])
82 usl = usl[2]
83 end
84 end
85 else
86 table.insert(QQ, car)
87 end
88 car, cdr = cdr[1], cdr[2]
89 end
90 return type.list(QQ, fin)
91 end, 95 end,
96 quasiquote = handle_quasiquote,
92 -- if not inside quasiquote, unquote and unquote-splicing are errors 97 -- if not inside quasiquote, unquote and unquote-splicing are errors
93 unquote = function () error("Unexpected unquote") end, 98 unquote = function () error("Unexpected unquote") end,
94 ["unquote-splicing"] = 99 ["unquote-splicing"] =
95 function () error("Unexpected unquote-splicing") end, 100 function () error("Unexpected unquote-splicing") end,
96 -- define variables 101 -- define variables
97 define = function (r, e) rawset(e, r[1], m.eval(r[2][1], e)) end, 102 define =
98 ["set!"] = function (r, e) e[r[1]] = m.eval(r[2][1], e) end, 103 function (r, e)
104 assert_arity(r, 2, 2)
105 rawset(e, r[1], m.eval(r[2][1], e))
106 end,
107 ["set!"] =
108 function (r, e)
109 assert_arity(r, 2, 2)
110 e[r[1]] = m.eval(r[2][1], e)
111 end,
99 -- y'know, ... lambda 112 -- y'know, ... lambda
100 lambda = function (r, e) return m.procedure(r[1], r[2], e) end, 113 lambda =
114 function (r, e)
115 assert_arity(r, 2)
116 return m.procedure(r[1], r[2], e)
117 end,
101 -- control flow 118 -- control flow
102 ["if"] = 119 ["if"] =
103 function (r, e) 120 function (r, e)
121 assert_arity(r, 3, 3)
104 local test, conseq, alt = 122 local test, conseq, alt =
105 r[1], r[2][1], r[2][2][1] 123 r[1], r[2][1], r[2][2][1]
106 if m.eval(test) 124 if m.eval(test)