about summary refs log tree commit diff stats
path: root/eval.lua
blob: 61798429fa90d4a18767b1a1c9b83024d9564359 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
--- lam.eval

local eval = {}
local read = require "read"
local type = require "type"
local util = require "util"
local unpack = table.unpack or unpack

function eval.Env (inner, outer)
	local mt = {
		__type = "Environment",
		__index = outer,
	}
	return setmetatable(inner, mt)
end

function eval.Proc (params, body, env)
	local v = {
		params = params,
		body = body,
		env = env,
	}
	local mt = {
		__type = "Procedure",
		__call =
			function (self, args)
				local inner = {}
				local p, a = self.params, args
				while p.cdr and a.cdr do
					inner[p.car] = a.car
					p, a = p.cdr, a.cdr
				end
				-- pp.pp(self.body)
				return eval.eval(
					self.body,
					eval.Env(inner, self.env))
			end,
	}
	return setmetatable(v, mt)
end

local global = {
	begin =
		function (args)
			local a = args
			while not type.isNull(a.cdr) do
				a = a.cdr
			end
			return a.car
		end,
	["+"] =
		function (args)
			local acc = 0
			local car, cdr = args.car, args.cdr
			while cdr do
				acc = acc + car
				car, cdr = cdr.car, cdr.cdr
			end
			return acc
		end,
	["-"] =
		function (args)
			return args.car - args.cdr.car
		end,
}

function eval.eval (x, env)
	env = env or global
	if type.isa(x, "Symbol") then
		return env[x]
	elseif not type.isList(x) then
		return x
	else
		local op, args = x.car, x.cdr
		if op == "quote" then
			return args
		elseif op == "define" then
			env[args.car] = eval.eval(args.cdr.car, env)
			return nil
		elseif op == "lambda" then
			return eval.Proc(
				args.car,
				type.Cons("begin", args.cdr),
				env)
		else		-- procedure
			local proc = eval.eval(op, env)
			local params = {}
			local a = args
			while a.cdr do
				table.insert(params, eval.eval(a.car, env))
				a = a.cdr
			end
			return proc(type.List(params))
		end
	end
end

---
return eval