about summary refs log tree commit diff stats
path: root/types.lua
blob: e4813b27d29febc765d8eaf7cc53f297dc883202 (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
100
101
102
103
104
105
106
107
108
109
110
111
112
--- lam.types

local types = {}
local util = require "util"
table.unpack = table.unpack or unpack

--- Converting between types

types.globalns = {}		-- namespace

types.Symbol =
	function (name, ns, aliases)
		ns = ns or types.globalns
		aliases = aliases or {}
		if ns[name] then return ns[name] end
		local sym = { name = name, aliases = aliases }
		ns[name] = sym
		for _,a in ipairs(aliases) do
			ns[a] = sym
		end
		local mt = {
			__type = "Symbol",
			__tostring = function (self) return self.name end,
		}
		return setmetatable(sym, mt)
	end

types.Number = tonumber

types.String =
	function (str)
		local s = {
			value = str,
			escape =
				function(self)
					return self:gsub("\"", "\\\"")
				end,
		}
		local mt = {
			__type = "String",
			__tostring =
				function (self)
					return string.format(
						"\"%s\"",
						self:escape())
				end,
		}
		return setmetatable(s, mt)
	end

types.Cons =
	function (a, b)
		assert(a ~= nil and b ~= nil,
			"Need two non-nil arguments in a pair")
		local s = { a, b }
		local mt = {
			__type = "Pair",
			__tostring =
				function (p)
					local out = {}
					local car, cdr = p[1], p[2]
					while cdr do
						table.insert(out, tostring(car))
						if type(cdr) == "table" then
							car = cdr[1]
							cdr = cdr[2]
						else
							table.insert(out, ".")
							table.insert(out, cdr)
							break
						end
					end
					return "("..table.concat(out, " ")..")"
				end

		}
		return setmetatable(s, mt)
	end

types.List =
	function (tbl)
		local function tolist(base, items)
			if #items == 0 then return base end
			return tolist(
				types.Cons(table.remove(items), base),
				items)
		end
		return tolist({}, tbl)
	end

--- Determining types

types.lamtype =
	function (x)
		if type(x) == "number" then
			return "Number"
		elseif getmetatable(x) and getmetatable(x).__type then
			return getmetatable(x).__type
		else
			return type(x)
		end
	end

--- Type predicates

types.isa =
	function (x, t)
		return types.lamtype(x) == t
	end

---
return types