diff options
Diffstat (limited to 'eval.lua')
-rw-r--r-- | eval.lua | 102 |
1 files changed, 44 insertions, 58 deletions
diff --git a/eval.lua b/eval.lua index 610b902..4a4ad0e 100644 --- a/eval.lua +++ b/eval.lua | |||
@@ -1,114 +1,100 @@ | |||
1 | --- lam.eval | 1 | --- lam.eval |
2 | 2 | ||
3 | local eval = {} | 3 | local m = {} |
4 | local base = require "base" | 4 | local core = require "core" |
5 | local type = require "type" | 5 | local type = require "type" |
6 | local isNull, isList, isa, List, Cons = | ||
7 | type.isNull, type.isList, type.isa, type.List, type.Cons | ||
8 | local unpack = table.unpack or unpack | ||
9 | 6 | ||
10 | function eval.Env (inner, outer) | 7 | function m.environ (inner, outer) |
11 | local mt = { | 8 | local mt = { |
12 | __type = "Environment", | 9 | __type = "environment", |
13 | __index = outer, | 10 | __index = outer, |
14 | __newindex = | 11 | __newindex = |
15 | function (self, key, value) | 12 | function (self, key, val) |
16 | if rawget(self, key) then | 13 | if rawget(self, key) then |
17 | -- Set the current environment's value | 14 | rawset(self, key, val) |
18 | rawset(self, key, value) | ||
19 | else | 15 | else |
20 | -- Set the outer value | 16 | getmetatable(self).__index[key] = val |
21 | getmetatable(self).__index[key] = value | ||
22 | end | 17 | end |
23 | end, | 18 | end, |
24 | } | 19 | } |
25 | return setmetatable(inner, mt) | 20 | return setmetatable(inner, mt) |
26 | end | 21 | end |
27 | 22 | ||
28 | function eval.Proc (params, body, env) | 23 | function m.procedure (params, body, env) |
29 | local v = { | 24 | local t = { |
30 | params = params, | 25 | params = params, |
31 | body = body, | 26 | body = body, |
32 | env = env, | 27 | env = env, |
33 | } | 28 | } |
34 | local mt = { | 29 | local mt = { |
35 | __type = "Procedure", | 30 | __type = "procedure", |
36 | __call = | 31 | __call = |
37 | function (self, args) | 32 | function (self, args) |
38 | local inner = {} | 33 | local inner = {} |
39 | local p, a = self.params, args | 34 | local p, a = self.params, args |
40 | while p.cdr and a.cdr do | 35 | while p[2] and a[2] do |
41 | inner[p.car] = a.car | 36 | inner[p[1]] = a[1] |
42 | p, a = p.cdr, a.cdr | 37 | p, a = p[2], a[2] |
43 | end | 38 | end |
44 | local b = self.body | 39 | local b = self.body |
45 | local e = eval.Env(inner, self.env) | 40 | local e = m.environ(inner, self.env) |
46 | while not isNull(b.cdr) do | 41 | while not b[2] == type.null do |
47 | eval.eval(b.car, e) | 42 | m.eval(b[1], e) |
48 | b = b.cdr | 43 | b = b[2] |
49 | end | 44 | end |
50 | return eval.eval(b.car, e) | 45 | return m.eval(b[1], e) |
51 | end, | 46 | end, |
52 | } | 47 | } |
53 | return setmetatable(v, mt) | 48 | return setmetatable(t, mt) |
54 | end | 49 | end |
55 | 50 | ||
56 | local specials = { | 51 | local specials = { |
52 | -- each of these takes R (a list of args) and E (an environment) | ||
57 | quote = | 53 | quote = |
58 | function (args, env) | 54 | function (r, e) return r[1] end, |
59 | return args.car | ||
60 | end, | ||
61 | define = | 55 | define = |
62 | function (args, env) | 56 | function (r, e) rawset(e, r[1], m.eval(r[2][1], e)) end, |
63 | rawset(env, args.car, eval(args.cdr.car, env)) | ||
64 | return nil | ||
65 | end, | ||
66 | lambda = | 57 | lambda = |
67 | function (args, env) | 58 | function (r, e) return m.procedure(r[1], r[2], e) end, |
68 | return Proc(args.car, args.cdr, env) | ||
69 | end, | ||
70 | ["set!"] = | 59 | ["set!"] = |
71 | function (args, env) | 60 | function (r, e) e[r[1]] = m.eval(r[2][1], e) end, |
72 | env[args.car] = eval(args.cdr.car, env) | ||
73 | return nil | ||
74 | end, | ||
75 | ["if"] = | 61 | ["if"] = |
76 | function (args, env) | 62 | function (r, e) |
77 | local test, conseq, alt = | 63 | local test, conseq, alt = |
78 | args.car, args.cdr.car, args.cdr.cdr.car | 64 | r[1], r[2][1], r[2][2][1] |
79 | if eval(test) | 65 | if m.eval(test) |
80 | then return eval(conseq) | 66 | then return m.eval(conseq) |
81 | else return eval(alt) | 67 | else return m.eval(alt) |
82 | end | 68 | end |
83 | end, | 69 | end, |
84 | -- TODO: include, import, define-syntax, define-values(?) ... | 70 | -- TODO: include, import, define-syntax, ... |
85 | } | 71 | } |
86 | -- Aliases | 72 | -- Aliases |
87 | specials.lam = specials.lambda | 73 | specials.lam = specials.lambda |
88 | specials.def = specials.define | 74 | specials.def = specials.define |
89 | 75 | ||
90 | function eval.eval (x, env) | 76 | function m.eval (x, env) |
91 | env = env or base.env | 77 | local env = env or core.env |
92 | if isa(x, "Symbol") then | 78 | if type.isa(x, "symbol") then |
93 | return env[x] | 79 | return env[x] |
94 | elseif not isList(x) then | 80 | elseif not type.islist(x) then |
95 | return x | 81 | return x |
96 | else | 82 | else |
97 | local op, args = x.car, x.cdr | 83 | local op, args = x[1], x[2] |
98 | if specials[op] then | 84 | if specials[op] then |
99 | return specials[op](args, env) | 85 | return specials[op](args, env) |
100 | else -- procedure | 86 | else -- procedure call |
101 | local proc = eval.eval(op, env) | 87 | local fn = m.eval(op, env) |
102 | local params = {} | 88 | local params = {} |
103 | local a = args | 89 | local r = args |
104 | while a.cdr do | 90 | while r[2] do |
105 | table.insert(params, eval.eval(a.car, env)) | 91 | table.insert(params, m.eval(r[1], env)) |
106 | a = a.cdr | 92 | r = r[2] |
107 | end | 93 | end |
108 | return proc(List(params)) | 94 | return fn(type.list(params)) |
109 | end | 95 | end |
110 | end | 96 | end |
111 | end | 97 | end |
112 | 98 | ||
113 | --- | 99 | -------- |
114 | return eval | 100 | return m |