1 local utils
= require('utils')
2 local types
= require('types')
3 local reader
= require('reader')
4 local printer
= require('printer')
5 local readline
= require('readline')
6 local socket
= require('socket')
8 local Nil
, List
, HashMap
, _pr_str
= types
.Nil
, types
.List
, types
.HashMap
, printer
._pr_str
16 utils
.map(function(e
) return _pr_str(e
, true) end,
17 table.pack(...)), " ")
22 utils
.map(function(e
) return _pr_str(e
, false) end,
28 utils
.map(function(e
) return _pr_str(e
, true) end,
29 table.pack(...)), " "))
36 utils
.map(function(e
) return _pr_str(e
, false) end,
37 table.pack(...)), " "))
44 for line
in io
.lines(file
) do
45 lines
[#lines
+1] = line
47 return table.concat(lines
, "\n") .. "\n"
50 function do_readline(prompt
)
51 local line
= readline
.readline(prompt
)
61 function assoc(hm
, ...)
62 return types
._assoc_BANG(types
.copy(hm
), ...)
65 function dissoc(hm
, ...)
66 return types
._dissoc_BANG(types
.copy(hm
), ...)
71 if res
== nil then return Nil
end
77 for k
,v
in pairs(hm
) do
85 for k
,v
in pairs(hm
) do
91 -- sequential functions
94 local new_lst
= lst
:slice(1)
95 table.insert(new_lst
, 1, a
)
96 return List
:new(new_lst
)
100 local arg
= table.pack(...)
103 for j
= 1, #arg
[i
] do
104 table.insert(new_lst
, arg
[i
][j
])
107 return List
:new(new_lst
)
110 function nth(seq
, idx
)
111 if idx
+1 <= #seq
then
114 types
.throw("nth: index out of range")
130 return List
:new(a
:slice(2))
134 function apply(f
, ...)
135 local arg
= table.pack(...)
136 if types
._malfunc_Q(f
) then
139 local args
= concat(types
.slice(arg
, 1, #arg
-1),
141 return f(table.unpack(args
))
145 if types
._malfunc_Q(f
) then
148 return List
:new(utils
.map(f
, lst
))
151 -- metadata functions
154 local m
= getmetatable(obj
)
155 if m
== nil or m
.meta
== nil then return Nil
end
159 function with_meta(obj
, meta
)
160 local new_obj
= types
.copy(obj
)
161 getmetatable(new_obj
).meta
= meta
167 function swap_BANG(atm
,f
,...)
168 if types
._malfunc_Q(f
) then
171 local args
= List
:new(table.pack(...))
172 table.insert(args
, 1, atm
.val
)
173 atm
.val
= f(table.unpack(args
))
177 local function conj(obj
, ...)
178 local arg
= table.pack(...)
179 local new_obj
= types
.copy(obj
)
180 if types
._list_Q(new_obj
) then
181 for i
, v
in ipairs(arg
) do
182 table.insert(new_obj
, 1, v
)
185 for i
, v
in ipairs(arg
) do
186 table.insert(new_obj
, v
)
192 local function seq(obj
, ...)
193 if obj
== Nil
or #obj
== 0 then
195 elseif types
._list_Q(obj
) then
197 elseif types
._vector_Q(obj
) then
199 elseif types
._string_Q(obj
) then
202 chars
[#chars
+1] = string.sub(obj
,i
,i
)
204 return List
:new(chars
)
209 local function lua_to_mal(a
)
212 elseif type(a
) == "boolean" or type(a
) == "number" or type(a
) == "string" then
214 elseif type(a
) == "table" then
215 local first_key
, _
= next(a
)
216 if first_key
== nil then
218 elseif type(first_key
) == "number" then
220 for i
, v
in ipairs(a
) do
221 list
[i
] = lua_to_mal(v
)
223 return List
:new(list
)
226 for k
, v
in pairs(a
) do
227 hashmap
[lua_to_mal(k
)] = lua_to_mal(v
)
229 return HashMap
:new(hashmap
)
235 local function lua_eval(str
)
236 local f
, err
= loadstring("return "..str
)
238 types
.throw("lua-eval: can't load code: "..err
)
240 return lua_to_mal(f())
244 ['='] = types
._equal_Q
,
247 ['nil?'] = function(a
) return a
==Nil
end,
248 ['true?'] = function(a
) return a
==true end,
249 ['false?'] = function(a
) return a
==false end,
250 ['number?'] = function(a
) return types
._number_Q(a
) end,
251 symbol
= function(a
) return types
.Symbol
:new(a
) end,
252 ['symbol?'] = function(a
) return types
._symbol_Q(a
) end,
253 ['string?'] = function(a
) return types
._string_Q(a
) and "\177" ~= string.sub(a
,1,1) end,
254 keyword
= function(a
) return "\177"..a
end,
255 ['keyword?'] = function(a
) return types
._keyword_Q(a
) end,
256 ['fn?'] = function(a
) return types
._fn_Q(a
) end,
257 ['macro?'] = function(a
) return types
._macro_Q(a
) end,
263 ['read-string'] = reader
.read_str
,
264 readline
= do_readline
,
267 ['<'] = function(a
,b
) return a
<b
end,
268 ['<='] = function(a
,b
) return a
<=b
end,
269 ['>'] = function(a
,b
) return a
>b
end,
270 ['>='] = function(a
,b
) return a
>=b
end,
271 ['+'] = function(a
,b
) return a
+b
end,
272 ['-'] = function(a
,b
) return a
-b
end,
273 ['*'] = function(a
,b
) return a
*b
end,
274 ['/'] = function(a
,b
) return math
.floor(a
/b
) end,
275 ['time-ms'] = function() return math
.floor(socket
.gettime() * 1000) end,
277 list
= function(...) return List
:new(table.pack(...)) end,
278 ['list?'] = function(a
) return types
._list_Q(a
) end,
279 vector
= function(...) return types
.Vector
:new(table.pack(...)) end,
280 ['vector?'] = types
._vector_Q
,
281 ['hash-map'] = types
.hash_map
,
282 ['map?'] = types
._hash_map_Q
,
286 ['contains?'] = function(a
,b
) return a
[b
] ~= nil end,
290 ['sequential?'] = types
._sequential_Q
,
296 ['empty?'] = function(a
) return a
==Nil
or #a
== 0 end,
297 count
= function(a
) return #a
end,
304 ['with-meta'] = with_meta
,
305 atom
= function(a
) return types
.Atom
:new(a
) end,
306 ['atom?'] = types
._atom_Q
,
307 deref
= function(a
) return a
.val
end,
308 ['reset!'] = function(a
,b
) a
.val
= b
; return b
end,
309 ['swap!'] = swap_BANG
,
311 ['lua-eval'] = lua_eval
,