diff options
Diffstat (limited to 'eval.lua')
-rw-r--r-- | eval.lua | 126 |
1 files changed, 70 insertions, 56 deletions
diff --git a/eval.lua b/eval.lua index 806148d..6179842 100644 --- a/eval.lua +++ b/eval.lua | |||
@@ -2,21 +2,20 @@ | |||
2 | 2 | ||
3 | local eval = {} | 3 | local eval = {} |
4 | local read = require "read" | 4 | local read = require "read" |
5 | local type = require "type" | ||
5 | local util = require "util" | 6 | local util = require "util" |
6 | local pp = require "pp" | 7 | local unpack = table.unpack or unpack |
7 | local global = require "global" | ||
8 | local types = require "types" | ||
9 | table.unpack = table.unpack or unpack | ||
10 | 8 | ||
11 | --- Environments and Parameters | 9 | function eval.Env (inner, outer) |
12 | -- these aren't in types.lua to avoid a circular dependency | 10 | local mt = { |
13 | 11 | __type = "Environment", | |
14 | local function Env(inner, outer) | 12 | __index = outer, |
15 | return setmetatable(inner, { __type = "Environment", __index = outer, }) | 13 | } |
14 | return setmetatable(inner, mt) | ||
16 | end | 15 | end |
17 | 16 | ||
18 | local function Proc(params, body, env) | 17 | function eval.Proc (params, body, env) |
19 | local p = { | 18 | local v = { |
20 | params = params, | 19 | params = params, |
21 | body = body, | 20 | body = body, |
22 | env = env, | 21 | env = env, |
@@ -24,62 +23,77 @@ local function Proc(params, body, env) | |||
24 | local mt = { | 23 | local mt = { |
25 | __type = "Procedure", | 24 | __type = "Procedure", |
26 | __call = | 25 | __call = |
27 | function (self, ...) | 26 | function (self, args) |
28 | local inner = {} | 27 | local inner = {} |
29 | for _, p in ipairs(self.params) do | 28 | local p, a = self.params, args |
30 | for _, a in ipairs({...}) do | 29 | while p.cdr and a.cdr do |
31 | inner[p] = a | 30 | inner[p.car] = a.car |
32 | end | 31 | p, a = p.cdr, a.cdr |
33 | end | 32 | end |
34 | return eval(self.body, Env(inner, self.env)) | 33 | -- pp.pp(self.body) |
34 | return eval.eval( | ||
35 | self.body, | ||
36 | eval.Env(inner, self.env)) | ||
35 | end, | 37 | end, |
36 | } | 38 | } |
37 | return setmetatable(p, mt) | 39 | return setmetatable(v, mt) |
38 | end | 40 | end |
39 | 41 | ||
40 | function eval.eval (x, e) | 42 | local global = { |
41 | e = e or global | 43 | begin = |
42 | if types.lamtype(x) == "Symbol" then | 44 | function (args) |
43 | return e[x] | 45 | local a = args |
44 | elseif types.luatype(x) ~= "table" then | 46 | while not type.isNull(a.cdr) do |
47 | a = a.cdr | ||
48 | end | ||
49 | return a.car | ||
50 | end, | ||
51 | ["+"] = | ||
52 | function (args) | ||
53 | local acc = 0 | ||
54 | local car, cdr = args.car, args.cdr | ||
55 | while cdr do | ||
56 | acc = acc + car | ||
57 | car, cdr = cdr.car, cdr.cdr | ||
58 | end | ||
59 | return acc | ||
60 | end, | ||
61 | ["-"] = | ||
62 | function (args) | ||
63 | return args.car - args.cdr.car | ||
64 | end, | ||
65 | } | ||
66 | |||
67 | function eval.eval (x, env) | ||
68 | env = env or global | ||
69 | if type.isa(x, "Symbol") then | ||
70 | return env[x] | ||
71 | elseif not type.isList(x) then | ||
45 | return x | 72 | return x |
46 | else | 73 | else |
47 | local op = util.car(x) | 74 | local op, args = x.car, x.cdr |
48 | local args = util.cdr(x) | 75 | if op == "quote" then |
49 | if op == types.Symbol("quote") then | 76 | return args |
50 | return args[1] | 77 | elseif op == "define" then |
51 | elseif op == types.Symbol("define") then | 78 | env[args.car] = eval.eval(args.cdr.car, env) |
52 | local sym, exp = table.unpack(args) | 79 | return nil |
53 | e[sym] = eval(exp, e) | 80 | elseif op == "lambda" then |
54 | --[[ | 81 | return eval.Proc( |
55 | elseif op == "set!" then | 82 | args.car, |
56 | local sym, exp = table.unpack(args) | 83 | type.Cons("begin", args.cdr), |
57 | e[sym] = eval(exp, e) --]] | 84 | env) |
58 | elseif op == types.Symbol("lambda") then | 85 | else -- procedure |
59 | local params = util.car(args) | 86 | local proc = eval.eval(op, env) |
60 | local body = util.cdr(args) | 87 | local params = {} |
61 | table.insert(body, 1, "begin") | 88 | local a = args |
62 | return Proc(params, | 89 | while a.cdr do |
63 | body, | 90 | table.insert(params, eval.eval(a.car, env)) |
64 | e) | 91 | a = a.cdr |
65 | else -- procedure call | ||
66 | local proc = eval(op, e) | ||
67 | local vals = {} | ||
68 | for k, v in pairs(args) do | ||
69 | vals[k] = eval(v, e) | ||
70 | end | 92 | end |
71 | return proc(table.unpack(vals)) | 93 | return proc(type.List(params)) |
72 | end | 94 | end |
73 | end | 95 | end |
74 | end | 96 | end |
75 | 97 | ||
76 | --- | 98 | --- |
77 | return setmetatable(eval, { __call = | 99 | return eval |
78 | function(_, x, e) | ||
79 | local success, result = | ||
80 | pcall(eval.eval, x, e) | ||
81 | if success then return result | ||
82 | else return ("ERROR: " .. result) | ||
83 | end | ||
84 | end | ||
85 | }) | ||