lua: add meta support for builtin function
[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
20 else
21 return a == b
22 end
23end
24
25function M.copy(obj)
109678d4
MK
26 if type(obj) == "function" then
27 return M.FunctionRef:new(obj)
28 end
9d42904e
JM
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
49end
50
51function 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
60end
61
62-- Error/exceptions
63
64M.MalException = {}
65function M.MalException:new(val)
66 local newObj = {val = val}
67 self.__index = self
68 return setmetatable(newObj, self)
69end
70function M._malexception_Q(obj)
71 return utils.instanceOf(obj, M.MalException)
72end
73
74function M.throw(val)
75 error(M.MalException:new(val))
76end
77
78-- Nil
79
80local NilType = {}
81function NilType:new(val)
82 local newObj = {}
83 self.__index = self
84 return setmetatable(newObj, self)
85end
86M.Nil = NilType:new()
87function M._nil_Q(obj)
88 return obj == Nil
89end
90
91-- Strings
92function M._string_Q(obj)
93 return type(obj) == "string"
94end
95
96-- Symbols
97
98M.Symbol = {}
99function M.Symbol:new(val)
100 local newObj = {val = val}
101 self.__index = self
102 return setmetatable(newObj, self)
103end
104function M._symbol_Q(obj)
105 return utils.instanceOf(obj, M.Symbol)
106end
107
108-- Keywords
109function M._keyword_Q(obj)
110 return M._string_Q(obj) and "\177" == string.sub(obj,1,1)
111end
112
113
114-- Lists
115
116M.List = {}
117function M.List:new(lst)
118 local newObj = lst and lst or {}
119 self.__index = self
120 return setmetatable(newObj, self)
121end
122function M._list_Q(obj)
123 return utils.instanceOf(obj, M.List)
124end
125function M.List:slice(start,last)
126 return M.List:new(M.slice(self,start,last))
127end
128
129-- Vectors
130
131M.Vector = {}
132function M.Vector:new(lst)
133 local newObj = lst and lst or {}
134 self.__index = self
135 return setmetatable(newObj, self)
136end
137function M._vector_Q(obj)
138 return utils.instanceOf(obj, M.Vector)
139end
140function M.Vector:slice(start,last)
141 return M.Vector:new(M.slice(self,start,last))
142end
143
144-- Hash Maps
145--
146M.HashMap = {}
147function M.HashMap:new(val)
148 local newObj = val and val or {}
149 self.__index = self
150 return setmetatable(newObj, self)
151end
152function M.hash_map(...)
153 return M._assoc_BANG(M.HashMap:new(), unpack(arg))
154end
155function M._hash_map_Q(obj)
156 return utils.instanceOf(obj, M.HashMap)
157end
158function M._assoc_BANG(hm, ...)
159 for i = 1, #arg, 2 do
160 hm[arg[i]] = arg[i+1]
161 end
162 return hm
163end
164function M._dissoc_BANG(hm, ...)
165 for i = 1, #arg do
166 hm[arg[i]] = nil
167 end
168 return hm
169end
170
171-- Functions
172
173M.MalFunc = {}
174function 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)
179end
180function M._malfunc_Q(obj)
181 return utils.instanceOf(obj, M.MalFunc)
182end
183
184-- Atoms
185
186M.Atom = {}
187function M.Atom:new(val)
188 local newObj = {val = val}
189 self.__index = self
190 return setmetatable(newObj, self)
191end
192function M._atom_Q(obj)
193 return utils.instanceOf(obj, M.Atom)
194end
195
109678d4
MK
196-- FunctionRefs
197
198M.FunctionRef = {}
199function M.FunctionRef:new(fn)
200 local newObj = {fn = fn}
201 return setmetatable(newObj, self)
202end
203function M._functionref_Q(obj)
204 return utils.instanceOf(obj, M.FunctionRef)
205end
206function M.FunctionRef:__call(...)
207 return self.fn(...)
208end
209
9d42904e 210return M