diff options
author | Case Duckworth | 2024-03-21 22:34:12 -0500 |
---|---|---|
committer | Case Duckworth | 2024-03-21 22:34:12 -0500 |
commit | 1d5041ff7bf92458d6d07ac6a03f2747dce9b9b1 (patch) | |
tree | 912c54baf0ac453dc9f77d3dd43ce94b53803503 | |
parent | Implment set! (diff) | |
download | lam-1d5041ff7bf92458d6d07ac6a03f2747dce9b9b1.tar.gz lam-1d5041ff7bf92458d6d07ac6a03f2747dce9b9b1.zip |
Refactor eval
Localize stuff and also break out specials
-rw-r--r-- | eval.lua | 75 |
1 files changed, 48 insertions, 27 deletions
diff --git a/eval.lua b/eval.lua index 9b1c315..39a5bbe 100644 --- a/eval.lua +++ b/eval.lua | |||
@@ -1,13 +1,12 @@ | |||
1 | --- lam.eval | 1 | --- lam.eval |
2 | 2 | ||
3 | local eval = {} | ||
4 | local base = require "base" | 3 | local base = require "base" |
5 | local type = require "type" | 4 | local type = require "type" |
6 | local isNull, isList, isa, List, Cons = | 5 | local isNull, isList, isa, List, Cons = |
7 | type.isNull, type.isList, type.isa, type.List, type.Cons | 6 | type.isNull, type.isList, type.isa, type.List, type.Cons |
8 | local unpack = table.unpack or unpack | 7 | local unpack = table.unpack or unpack |
9 | 8 | ||
10 | function eval.Env (inner, outer) | 9 | local function Env (inner, outer) |
11 | local mt = { | 10 | local mt = { |
12 | __type = "Environment", | 11 | __type = "Environment", |
13 | __index = outer, | 12 | __index = outer, |
@@ -25,7 +24,7 @@ function eval.Env (inner, outer) | |||
25 | return setmetatable(inner, mt) | 24 | return setmetatable(inner, mt) |
26 | end | 25 | end |
27 | 26 | ||
28 | function eval.Proc (params, body, env) | 27 | local function Proc (params, body, env) |
29 | local v = { | 28 | local v = { |
30 | params = params, | 29 | params = params, |
31 | body = body, | 30 | body = body, |
@@ -42,18 +41,51 @@ function eval.Proc (params, body, env) | |||
42 | p, a = p.cdr, a.cdr | 41 | p, a = p.cdr, a.cdr |
43 | end | 42 | end |
44 | local b = self.body | 43 | local b = self.body |
45 | local e = eval.Env(inner, self.env) | 44 | local e = Env(inner, self.env) |
46 | while not isNull(b.cdr) do | 45 | while not isNull(b.cdr) do |
47 | eval.eval(b.car, e) | 46 | eval(b.car, e) |
48 | b = b.cdr | 47 | b = b.cdr |
49 | end | 48 | end |
50 | return eval.eval(b.car, e) | 49 | return eval(b.car, e) |
51 | end, | 50 | end, |
52 | } | 51 | } |
53 | return setmetatable(v, mt) | 52 | return setmetatable(v, mt) |
54 | end | 53 | end |
55 | 54 | ||
56 | function eval.eval (x, env) | 55 | local specials = { |
56 | quote = | ||
57 | function (args, env) | ||
58 | return args.car | ||
59 | end, | ||
60 | define = | ||
61 | function (args, env) | ||
62 | rawset(env, args.car, eval(args.cdr.car, env)) | ||
63 | return nil | ||
64 | end, | ||
65 | lambda = | ||
66 | function (args, env) | ||
67 | return Proc(args.car, args.cdr, env) | ||
68 | end, | ||
69 | ["set!"] = | ||
70 | function (args, env) | ||
71 | env[args.car] = eval(args.cdr.car, env) | ||
72 | return nil | ||
73 | end, | ||
74 | ["if"] = | ||
75 | function (args, env) | ||
76 | local test, conseq, alt = | ||
77 | args.car, args.cdr.car, args.cdr.cdr.car | ||
78 | if eval(test) | ||
79 | then return eval(conseq) | ||
80 | else return eval(alt) | ||
81 | end | ||
82 | end, | ||
83 | } | ||
84 | -- Aliases | ||
85 | specials.lam = specials.lambda | ||
86 | specials.def = specials.define | ||
87 | |||
88 | local function eval (x, env) | ||
57 | env = env or base.env | 89 | env = env or base.env |
58 | if isa(x, "Symbol") then | 90 | if isa(x, "Symbol") then |
59 | return env[x] | 91 | return env[x] |
@@ -61,29 +93,14 @@ function eval.eval (x, env) | |||
61 | return x | 93 | return x |
62 | else | 94 | else |
63 | local op, args = x.car, x.cdr | 95 | local op, args = x.car, x.cdr |
64 | if op == "quote" then | 96 | if specials[op] then |
65 | return args.car | 97 | return specials[op](args, env) |
66 | elseif op == "define" or op == "def" then | ||
67 | rawset(env, args.car, eval.eval(args.cdr.car, env)) | ||
68 | return nil | ||
69 | elseif op == "set!" then | ||
70 | env[args.car] = eval.eval(args.cdr.car, env) | ||
71 | elseif op == "lambda" or op == "lam" then | ||
72 | return eval.Proc(args.car, args.cdr, env) | ||
73 | elseif op == "if" then | ||
74 | assert(not isNull(args.cdr), "Malformed 'if'") | ||
75 | local test, conseq, alt = | ||
76 | args.car, args.cdr.car, args.cdr.cdr.car | ||
77 | if eval.eval(test) | ||
78 | then return eval.eval(conseq) | ||
79 | else return eval.eval(alt) | ||
80 | end | ||
81 | else -- procedure | 98 | else -- procedure |
82 | local proc = eval.eval(op, env) | 99 | local proc = eval(op, env) |
83 | local params = {} | 100 | local params = {} |
84 | local a = args | 101 | local a = args |
85 | while a.cdr do | 102 | while a.cdr do |
86 | table.insert(params, eval.eval(a.car, env)) | 103 | table.insert(params, eval(a.car, env)) |
87 | a = a.cdr | 104 | a = a.cdr |
88 | end | 105 | end |
89 | return proc(List(params)) | 106 | return proc(List(params)) |
@@ -92,4 +109,8 @@ function eval.eval (x, env) | |||
92 | end | 109 | end |
93 | 110 | ||
94 | --- | 111 | --- |
95 | return eval | 112 | return { |
113 | Env = Env, | ||
114 | Proc = Proc, | ||
115 | eval = eval, | ||
116 | } | ||