diff options
author | Case Duckworth | 2024-02-22 00:23:32 -0600 |
---|---|---|
committer | Case Duckworth | 2024-02-22 00:23:32 -0600 |
commit | 5328b62221a3839dca117d71a4703f3ad719c9ce (patch) | |
tree | 7212235f569e765d3a4ebed0e8d21b64d905bf3a | |
parent | Remove spurious require (diff) | |
download | lam-5328b62221a3839dca117d71a4703f3ad719c9ce.tar.gz lam-5328b62221a3839dca117d71a4703f3ad719c9ce.zip |
Add global and types libraries
-rw-r--r-- | eval.lua | 119 | ||||
-rw-r--r-- | global.lua | 141 | ||||
-rw-r--r-- | types.lua | 27 |
3 files changed, 190 insertions, 97 deletions
diff --git a/eval.lua b/eval.lua index d441859..cdf4612 100644 --- a/eval.lua +++ b/eval.lua | |||
@@ -4,23 +4,10 @@ local eval = {} | |||
4 | local read = require "read" | 4 | local read = require "read" |
5 | local util = require "util" | 5 | local util = require "util" |
6 | local pp = require "pp" | 6 | local pp = require "pp" |
7 | local global = require "global" | ||
8 | local types = require("types") | ||
7 | 9 | ||
8 | local function Type (x) | 10 | if not table.unpack then table.unpack = unpack end |
9 | if type(x) == "string" then | ||
10 | return "Symbol" | ||
11 | elseif type(x) == "number" then | ||
12 | return "Number" | ||
13 | elseif getmetatable(x) and getmetatable(x).__type then | ||
14 | return x.__type | ||
15 | elseif type(x) == "table" then | ||
16 | return "List" | ||
17 | else | ||
18 | return type(x) | ||
19 | end | ||
20 | end | ||
21 | |||
22 | local Symbol = tostring | ||
23 | local Number = tonumber | ||
24 | 11 | ||
25 | local function Env(inner, outer) | 12 | local function Env(inner, outer) |
26 | return setmetatable(inner, { __type = "Environment", __index = outer, }) | 13 | return setmetatable(inner, { __type = "Environment", __index = outer, }) |
@@ -48,73 +35,11 @@ local function Proc(params, body, env) | |||
48 | return setmetatable(p, mt) | 35 | return setmetatable(p, mt) |
49 | end | 36 | end |
50 | 37 | ||
51 | local global_env = { | 38 | function eval.eval (x, e) |
52 | -- constants | 39 | e = e or global |
53 | ["#t"] = true, | 40 | if types.lamtype(x) == "Symbol" then |
54 | ["#f"] = false, | 41 | return e[x] |
55 | -- basic math | 42 | elseif types.luatype(x) ~= "table" then |
56 | ["+"] = | ||
57 | function (...) | ||
58 | print(...) | ||
59 | return util.reduce( | ||
60 | {...}, 0, | ||
61 | function (a, b) return a + b end) | ||
62 | end, | ||
63 | ["*"] = | ||
64 | function (...) | ||
65 | return util.reduce( | ||
66 | {...}, 1, | ||
67 | function (a, b) return a * b end) | ||
68 | end, | ||
69 | -- scheme predicates | ||
70 | ["null?"] = | ||
71 | function(x) | ||
72 | return x == {} | ||
73 | end, | ||
74 | ["number?"] = | ||
75 | function(x) | ||
76 | return Type(x) == "Number" | ||
77 | end, | ||
78 | ["symbol?"] = | ||
79 | function(x) | ||
80 | return Type(x) == "Symbol" | ||
81 | end, | ||
82 | -- scheme functions | ||
83 | ["apply"] = | ||
84 | function(fn, ...) | ||
85 | local args = {...} | ||
86 | local last = args[#args] | ||
87 | assert(type(last)=="table", "Bad apply") | ||
88 | table.remove(args) | ||
89 | for _,v in ipairs(last) do | ||
90 | table.insert(args, v) | ||
91 | end | ||
92 | return fn(table.unpack(args)) | ||
93 | end, | ||
94 | ["begin"] = | ||
95 | function(...) | ||
96 | local xs = {...} | ||
97 | return xs[#xs] | ||
98 | end, | ||
99 | ["map"] = | ||
100 | function(fn, ...) | ||
101 | return util.map(fn, {...}) | ||
102 | end, | ||
103 | ["car"] = util.car, | ||
104 | ["cdr"] = util.cdr, | ||
105 | ["list"] = function(...) return {...} end, | ||
106 | } | ||
107 | |||
108 | -- Math | ||
109 | for k, v in pairs(math) do | ||
110 | global_env[k] = v | ||
111 | end | ||
112 | |||
113 | function eval.eval (x, env) | ||
114 | env = env or global_env | ||
115 | if Type(x) == "Symbol" then | ||
116 | return env[x] | ||
117 | elseif type(x) ~= "table" then | ||
118 | return x | 43 | return x |
119 | else | 44 | else |
120 | local op = util.car(x) | 45 | local op = util.car(x) |
@@ -123,20 +48,24 @@ function eval.eval (x, env) | |||
123 | return args[1] | 48 | return args[1] |
124 | elseif op == "define" then | 49 | elseif op == "define" then |
125 | local sym, exp = table.unpack(args) | 50 | local sym, exp = table.unpack(args) |
126 | env[sym] = eval(exp, env) | 51 | e[sym] = eval(exp, e) |
127 | --[[ | 52 | --[[ |
128 | elseif op == "set!" then | 53 | elseif op == "set!" then |
129 | local sym, exp = table.unpack(args) | 54 | local sym, exp = table.unpack(args) |
130 | env[sym] = eval(exp, env) --]] | 55 | e[sym] = eval(exp, e) --]] |
131 | elseif op == "lambda" then | 56 | elseif op == "lambda" then |
132 | local params = util.car(args) | 57 | local params = util.car(args) |
133 | local body = util.cdr(args)[1] | 58 | local body = util.cdr(args) |
134 | return Proc(params, body, env) | 59 | table.insert(body, 1, "begin") |
60 | return Proc(params, | ||
61 | body, | ||
62 | e) | ||
135 | else -- procedure call | 63 | else -- procedure call |
136 | local proc = eval(op, env) | 64 | local proc = eval(op, e) |
137 | local vals = util.map( | 65 | local vals = {} |
138 | function(v) return eval(v, env) end, | 66 | for k, v in pairs(args) do |
139 | args) | 67 | vals[k] = eval(v, e) |
68 | end | ||
140 | return proc(table.unpack(vals)) | 69 | return proc(table.unpack(vals)) |
141 | end | 70 | end |
142 | end | 71 | end |
@@ -144,15 +73,11 @@ end | |||
144 | 73 | ||
145 | --- | 74 | --- |
146 | return setmetatable(eval, { __call = | 75 | return setmetatable(eval, { __call = |
147 | function(_, x, env) | 76 | function(_, x, e) |
148 | local success, result = | 77 | local success, result = |
149 | pcall(eval.eval, x, env) | 78 | pcall(eval.eval, x, e) |
150 | if success then return result | 79 | if success then return result |
151 | else return ("ERROR: " .. result) | 80 | else return ("ERROR: " .. result) |
152 | end | 81 | end |
153 | end | 82 | end |
154 | }) | 83 | }) |
155 | |||
156 | --[[ | ||
157 | (begin (define sq (lambda (x) (* x x))) (define rep (lambda (f) (lambda (x) (f (f x)))))) | ||
158 | -- ]] | ||
diff --git a/global.lua b/global.lua new file mode 100644 index 0000000..3805912 --- /dev/null +++ b/global.lua | |||
@@ -0,0 +1,141 @@ | |||
1 | --- lam.environment | ||
2 | |||
3 | local util = require "util" | ||
4 | local types = require("types") | ||
5 | |||
6 | if not table.unpack then table.unpack = unpack end | ||
7 | |||
8 | local global = { | ||
9 | -- constants | ||
10 | ["#t"] = true, | ||
11 | ["#f"] = false, | ||
12 | } | ||
13 | |||
14 | --- Types --- | ||
15 | |||
16 | for name, func in pairs(types) do | ||
17 | if name == "lamtype" then | ||
18 | global.type = func | ||
19 | else | ||
20 | global[name] = func | ||
21 | end | ||
22 | end | ||
23 | |||
24 | --- Basic functions --- | ||
25 | |||
26 | global.begin = function(...) | ||
27 | local xs = {...} | ||
28 | return xs[#xs] | ||
29 | end | ||
30 | |||
31 | global.car = util.car | ||
32 | global.cdr = util.cdr | ||
33 | |||
34 | global.list = function(...) return {...} end | ||
35 | |||
36 | --- Higher-order functions --- | ||
37 | |||
38 | global.apply = function(fn, ...) | ||
39 | local args = {...} | ||
40 | local last = args[#args] | ||
41 | assert(types.luatype(last) == "table", "Bad apply") | ||
42 | table.remove(args) | ||
43 | for _, v in ipairs(last) do | ||
44 | table.insert(args, v) | ||
45 | end | ||
46 | return fn(table.unpack(args)) | ||
47 | end | ||
48 | |||
49 | global.map = function(fn, list) | ||
50 | return util.map(fn, list) | ||
51 | end | ||
52 | |||
53 | --- Math --- | ||
54 | -- NOTE: we do not have the full numeric tower yet! | ||
55 | |||
56 | for name, func in pairs(math) do | ||
57 | global[name] = func | ||
58 | end | ||
59 | |||
60 | global["+"] = function (...) | ||
61 | return util.reduce({...}, 0, function (a, b) return a + b end) | ||
62 | end | ||
63 | |||
64 | global["-"] = function (...) | ||
65 | local args = {...} | ||
66 | if #args == 0 then | ||
67 | error("Too few arguments: need at least 1") | ||
68 | elseif #args == 1 then | ||
69 | return (-args[1]) | ||
70 | else | ||
71 | local result = args[1] | ||
72 | for v = 2, #args do | ||
73 | result = result - args[v] | ||
74 | end | ||
75 | return result | ||
76 | end | ||
77 | end | ||
78 | |||
79 | global["*"] = function (...) | ||
80 | local result = 1 | ||
81 | for _, v in ipairs({...}) do | ||
82 | if v == 0 then return 0 end | ||
83 | result = result * v | ||
84 | end | ||
85 | return result | ||
86 | end | ||
87 | |||
88 | global["/"] = function (...) | ||
89 | local args = {...} | ||
90 | if #args == 0 then | ||
91 | error("Too few arguments: need at least 1") | ||
92 | elseif #args == 1 then | ||
93 | if args[1] == 0 then error("Division by zero") end | ||
94 | return (1/args[1]) | ||
95 | else | ||
96 | local result = args[1] | ||
97 | for v = 2, #args do | ||
98 | if args[v] == 0 then error("Division by zero") end | ||
99 | result = result / args[v] | ||
100 | end | ||
101 | return result | ||
102 | end | ||
103 | end | ||
104 | |||
105 | global["="] = function (...) | ||
106 | for _, v in ipairs({...}) do | ||
107 | if not a == b then return false end | ||
108 | end | ||
109 | return true | ||
110 | end | ||
111 | |||
112 | global["<"] = function (...) | ||
113 | for _, v in ipairs({...}) do | ||
114 | if not a < b then return false end | ||
115 | end | ||
116 | return true | ||
117 | end | ||
118 | |||
119 | global["<="] = function (...) | ||
120 | for _, v in ipairs({...}) do | ||
121 | if not a <= b then return false end | ||
122 | end | ||
123 | return true | ||
124 | end | ||
125 | |||
126 | global[">"] = function (...) | ||
127 | for _, v in ipairs({...}) do | ||
128 | if not a > b then return false end | ||
129 | end | ||
130 | return true | ||
131 | end | ||
132 | |||
133 | global[">="] = function (...) | ||
134 | for _, v in ipairs({...}) do | ||
135 | if not a >= b then return false end | ||
136 | end | ||
137 | return true | ||
138 | end | ||
139 | |||
140 | --- | ||
141 | return global | ||
diff --git a/types.lua b/types.lua new file mode 100644 index 0000000..dd105cf --- /dev/null +++ b/types.lua | |||
@@ -0,0 +1,27 @@ | |||
1 | --- lam.types | ||
2 | |||
3 | local types = {} | ||
4 | |||
5 | types.luatype = type | ||
6 | |||
7 | function types.lamtype (x) | ||
8 | if types.luatype(x) == "string" then | ||
9 | return "Symbol" | ||
10 | elseif types.luatype(x) == "number" then | ||
11 | return "Number" | ||
12 | elseif getmetatable(x) and getmetatable(x).__type then | ||
13 | return getmetatable(x).__type | ||
14 | elseif types.luatype(x) == "table" then | ||
15 | return "List" | ||
16 | else | ||
17 | return types.luatype(x) | ||
18 | end | ||
19 | end | ||
20 | |||
21 | types["number?"] = function (x) return types.lamtype(x) == "Number" end | ||
22 | types["symbol?"] = function (x) return types.lamtype(x) == "Symbol" end | ||
23 | types["list?"] = function (x) return types.lamtype(x) == "List" end | ||
24 | types["null?"] = function (x) return x == {} end | ||
25 | |||
26 | --- | ||
27 | return types | ||