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