dfe10d9d1b8c811623db1cfb4f6436e3e4ead651
[jackhill/mal.git] / lua / types.lua
1 local utils = require('utils')
2
3 local M = {}
4
5 -- type functions
6
7 function M._sequential_Q(obj)
8 return M._list_Q(obj) or M._vector_Q(obj)
9 end
10
11 function M._equal_Q(a,b)
12 if M._symbol_Q(a) and M._symbol_Q(b) then
13 return a.val == b.val
14 elseif M._sequential_Q(a) and M._sequential_Q(b) then
15 if #a ~= #b then return false end
16 for i, v in ipairs(a) do
17 if not M._equal_Q(v,b[i]) then return false end
18 end
19 return true
20 else
21 return a == b
22 end
23 end
24
25 function M.copy(obj)
26 if type(obj) == "function" then
27 return M.FunctionRef:new(obj)
28 end
29 if type(obj) ~= "table" then return obj end
30
31 -- copy object data
32 local new_obj = {}
33 for k,v in pairs(obj) do
34 new_obj[k] = v
35 end
36
37 -- copy metatable and link to original
38 local old_mt = getmetatable(obj)
39 if old_mt ~= nil then
40 local new_mt = {}
41 for k,v in pairs(old_mt) do
42 new_mt[k] = v
43 end
44 setmetatable(new_mt, old_mt)
45 setmetatable(new_obj, new_mt)
46 end
47
48 return new_obj
49 end
50
51 function M.slice(lst, start, last)
52 if last == nil then last = #lst end
53 local new_lst = {}
54 if start <= last then
55 for i = start, last do
56 new_lst[#new_lst+1] = lst[i]
57 end
58 end
59 return new_lst
60 end
61
62 -- Error/exceptions
63
64 M.MalException = {}
65 function M.MalException:new(val)
66 local newObj = {val = val}
67 self.__index = self
68 return setmetatable(newObj, self)
69 end
70 function M._malexception_Q(obj)
71 return utils.instanceOf(obj, M.MalException)
72 end
73
74 function M.throw(val)
75 error(M.MalException:new(val))
76 end
77
78 -- Nil
79
80 local NilType = {}
81 function NilType:new(val)
82 local newObj = {}
83 self.__index = self
84 return setmetatable(newObj, self)
85 end
86 M.Nil = NilType:new()
87 function M._nil_Q(obj)
88 return obj == Nil
89 end
90
91 -- Strings
92 function M._string_Q(obj)
93 return type(obj) == "string"
94 end
95
96 -- Symbols
97
98 M.Symbol = {}
99 function M.Symbol:new(val)
100 local newObj = {val = val}
101 self.__index = self
102 return setmetatable(newObj, self)
103 end
104 function M._symbol_Q(obj)
105 return utils.instanceOf(obj, M.Symbol)
106 end
107
108 -- Keywords
109 function M._keyword_Q(obj)
110 return M._string_Q(obj) and "\177" == string.sub(obj,1,1)
111 end
112
113
114 -- Lists
115
116 M.List = {}
117 function M.List:new(lst)
118 local newObj = lst and lst or {}
119 self.__index = self
120 return setmetatable(newObj, self)
121 end
122 function M._list_Q(obj)
123 return utils.instanceOf(obj, M.List)
124 end
125 function M.List:slice(start,last)
126 return M.List:new(M.slice(self,start,last))
127 end
128
129 -- Vectors
130
131 M.Vector = {}
132 function M.Vector:new(lst)
133 local newObj = lst and lst or {}
134 self.__index = self
135 return setmetatable(newObj, self)
136 end
137 function M._vector_Q(obj)
138 return utils.instanceOf(obj, M.Vector)
139 end
140 function M.Vector:slice(start,last)
141 return M.Vector:new(M.slice(self,start,last))
142 end
143
144 -- Hash Maps
145 --
146 M.HashMap = {}
147 function M.HashMap:new(val)
148 local newObj = val and val or {}
149 self.__index = self
150 return setmetatable(newObj, self)
151 end
152 function M.hash_map(...)
153 return M._assoc_BANG(M.HashMap:new(), unpack(arg))
154 end
155 function M._hash_map_Q(obj)
156 return utils.instanceOf(obj, M.HashMap)
157 end
158 function M._assoc_BANG(hm, ...)
159 for i = 1, #arg, 2 do
160 hm[arg[i]] = arg[i+1]
161 end
162 return hm
163 end
164 function M._dissoc_BANG(hm, ...)
165 for i = 1, #arg do
166 hm[arg[i]] = nil
167 end
168 return hm
169 end
170
171 -- Functions
172
173 M.MalFunc = {}
174 function M.MalFunc:new(fn, ast, env, params)
175 local newObj = {fn = fn, ast = ast, env = env,
176 params = params, ismacro = false}
177 self.__index = self
178 return setmetatable(newObj, self)
179 end
180 function M._malfunc_Q(obj)
181 return utils.instanceOf(obj, M.MalFunc)
182 end
183
184 -- Atoms
185
186 M.Atom = {}
187 function M.Atom:new(val)
188 local newObj = {val = val}
189 self.__index = self
190 return setmetatable(newObj, self)
191 end
192 function M._atom_Q(obj)
193 return utils.instanceOf(obj, M.Atom)
194 end
195
196 -- FunctionRefs
197
198 M.FunctionRef = {}
199 function M.FunctionRef:new(fn)
200 local newObj = {fn = fn}
201 return setmetatable(newObj, self)
202 end
203 function M._functionref_Q(obj)
204 return utils.instanceOf(obj, M.FunctionRef)
205 end
206 function M.FunctionRef:__call(...)
207 return self.fn(...)
208 end
209
210 return M