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