2015-01-09 08:25:40 +03:00
|
|
|
local utils = require('utils')
|
|
|
|
local types = require('types')
|
|
|
|
local reader = require('reader')
|
|
|
|
local printer = require('printer')
|
|
|
|
local readline = require('readline')
|
|
|
|
|
2016-06-12 04:30:44 +03:00
|
|
|
local Nil, List, HashMap, _pr_str = types.Nil, types.List, types.HashMap, printer._pr_str
|
2015-01-09 08:25:40 +03:00
|
|
|
|
|
|
|
local M = {}
|
|
|
|
|
|
|
|
-- string functions
|
|
|
|
|
|
|
|
function pr_str(...)
|
2024-08-21 22:12:34 +03:00
|
|
|
return printer._pr_seq(table.pack(...), true, " ")
|
2015-01-09 08:25:40 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
function str(...)
|
2024-08-21 22:12:34 +03:00
|
|
|
return printer._pr_seq(table.pack(...), false, "")
|
2015-01-09 08:25:40 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
function prn(...)
|
2024-08-21 22:12:34 +03:00
|
|
|
print(printer._pr_seq(table.pack(...), true, " "))
|
2015-03-01 00:58:35 +03:00
|
|
|
io.flush()
|
2015-01-09 08:25:40 +03:00
|
|
|
return Nil
|
|
|
|
end
|
|
|
|
|
|
|
|
function println(...)
|
2024-08-21 22:12:34 +03:00
|
|
|
print(printer._pr_seq(table.pack(...), false, " "))
|
2015-03-01 00:58:35 +03:00
|
|
|
io.flush()
|
2015-01-09 08:25:40 +03:00
|
|
|
return Nil
|
|
|
|
end
|
|
|
|
|
|
|
|
function slurp(file)
|
|
|
|
local lines = {}
|
|
|
|
for line in io.lines(file) do
|
|
|
|
lines[#lines+1] = line
|
|
|
|
end
|
|
|
|
return table.concat(lines, "\n") .. "\n"
|
|
|
|
end
|
|
|
|
|
|
|
|
function do_readline(prompt)
|
|
|
|
local line = readline.readline(prompt)
|
|
|
|
if line == nil then
|
|
|
|
return Nil
|
|
|
|
else
|
|
|
|
return line
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- hash map functions
|
|
|
|
|
|
|
|
function assoc(hm, ...)
|
2019-01-28 22:31:28 +03:00
|
|
|
return types._assoc_BANG(types.copy(hm), ...)
|
2015-01-09 08:25:40 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
function dissoc(hm, ...)
|
2019-01-28 22:31:28 +03:00
|
|
|
return types._dissoc_BANG(types.copy(hm), ...)
|
2015-01-09 08:25:40 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
function get(hm, key)
|
|
|
|
local res = hm[key]
|
|
|
|
if res == nil then return Nil end
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
|
|
|
|
function keys(hm)
|
|
|
|
local res = {}
|
|
|
|
for k,v in pairs(hm) do
|
|
|
|
res[#res+1] = k
|
|
|
|
end
|
|
|
|
return List:new(res)
|
|
|
|
end
|
|
|
|
|
|
|
|
function vals(hm)
|
|
|
|
local res = {}
|
|
|
|
for k,v in pairs(hm) do
|
|
|
|
res[#res+1] = v
|
|
|
|
end
|
|
|
|
return List:new(res)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- sequential functions
|
|
|
|
|
|
|
|
function cons(a,lst)
|
|
|
|
local new_lst = lst:slice(1)
|
|
|
|
table.insert(new_lst, 1, a)
|
|
|
|
return List:new(new_lst)
|
|
|
|
end
|
|
|
|
|
|
|
|
function concat(...)
|
2019-01-28 22:31:28 +03:00
|
|
|
local arg = table.pack(...)
|
2015-01-09 08:25:40 +03:00
|
|
|
local new_lst = {}
|
|
|
|
for i = 1, #arg do
|
|
|
|
for j = 1, #arg[i] do
|
|
|
|
table.insert(new_lst, arg[i][j])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return List:new(new_lst)
|
|
|
|
end
|
|
|
|
|
2020-07-21 19:01:48 +03:00
|
|
|
function vec(a)
|
2024-08-22 03:04:34 +03:00
|
|
|
return types.Vector:new(types.copy(a))
|
2020-07-21 19:01:48 +03:00
|
|
|
end
|
|
|
|
|
2015-01-09 08:25:40 +03:00
|
|
|
function nth(seq, idx)
|
|
|
|
if idx+1 <= #seq then
|
|
|
|
return seq[idx+1]
|
|
|
|
else
|
|
|
|
types.throw("nth: index out of range")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function first(a)
|
|
|
|
if #a == 0 then
|
|
|
|
return Nil
|
|
|
|
else
|
|
|
|
return a[1]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-01-30 05:47:14 +03:00
|
|
|
function rest(a)
|
|
|
|
if a == Nil then
|
|
|
|
return List:new()
|
|
|
|
else
|
|
|
|
return List:new(a:slice(2))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-01-09 08:25:40 +03:00
|
|
|
function apply(f, ...)
|
2019-01-28 22:31:28 +03:00
|
|
|
local arg = table.pack(...)
|
2015-01-09 08:25:40 +03:00
|
|
|
if types._malfunc_Q(f) then
|
|
|
|
f = f.fn
|
|
|
|
end
|
|
|
|
local args = concat(types.slice(arg, 1, #arg-1),
|
|
|
|
arg[#arg])
|
2019-01-28 22:31:28 +03:00
|
|
|
return f(table.unpack(args))
|
2015-01-09 08:25:40 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
function map(f, lst)
|
|
|
|
if types._malfunc_Q(f) then
|
|
|
|
f = f.fn
|
|
|
|
end
|
|
|
|
return List:new(utils.map(f, lst))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- metadata functions
|
|
|
|
|
|
|
|
function meta(obj)
|
|
|
|
local m = getmetatable(obj)
|
|
|
|
if m == nil or m.meta == nil then return Nil end
|
|
|
|
return m.meta
|
|
|
|
end
|
|
|
|
|
|
|
|
function with_meta(obj, meta)
|
|
|
|
local new_obj = types.copy(obj)
|
|
|
|
getmetatable(new_obj).meta = meta
|
|
|
|
return new_obj
|
|
|
|
end
|
|
|
|
|
|
|
|
-- atom functions
|
|
|
|
|
|
|
|
function swap_BANG(atm,f,...)
|
|
|
|
if types._malfunc_Q(f) then
|
|
|
|
f = f.fn
|
|
|
|
end
|
2019-01-28 22:31:28 +03:00
|
|
|
local args = List:new(table.pack(...))
|
2015-01-09 08:25:40 +03:00
|
|
|
table.insert(args, 1, atm.val)
|
2019-01-28 22:31:28 +03:00
|
|
|
atm.val = f(table.unpack(args))
|
2015-01-09 08:25:40 +03:00
|
|
|
return atm.val
|
|
|
|
end
|
|
|
|
|
2015-07-22 11:56:32 +03:00
|
|
|
local function conj(obj, ...)
|
2019-01-28 22:31:28 +03:00
|
|
|
local arg = table.pack(...)
|
2015-07-22 11:56:32 +03:00
|
|
|
local new_obj = types.copy(obj)
|
|
|
|
if types._list_Q(new_obj) then
|
|
|
|
for i, v in ipairs(arg) do
|
|
|
|
table.insert(new_obj, 1, v)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
for i, v in ipairs(arg) do
|
|
|
|
table.insert(new_obj, v)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return new_obj
|
|
|
|
end
|
|
|
|
|
2016-02-13 06:00:53 +03:00
|
|
|
local function seq(obj, ...)
|
|
|
|
if obj == Nil or #obj == 0 then
|
|
|
|
return Nil
|
|
|
|
elseif types._list_Q(obj) then
|
|
|
|
return obj
|
|
|
|
elseif types._vector_Q(obj) then
|
|
|
|
return List:new(obj)
|
|
|
|
elseif types._string_Q(obj) then
|
|
|
|
local chars = {}
|
|
|
|
for i = 1, #obj do
|
|
|
|
chars[#chars+1] = string.sub(obj,i,i)
|
|
|
|
end
|
|
|
|
return List:new(chars)
|
|
|
|
end
|
|
|
|
return Nil
|
|
|
|
end
|
|
|
|
|
2016-06-12 04:30:44 +03:00
|
|
|
local function lua_to_mal(a)
|
|
|
|
if a == nil then
|
|
|
|
return Nil
|
|
|
|
elseif type(a) == "boolean" or type(a) == "number" or type(a) == "string" then
|
|
|
|
return a
|
|
|
|
elseif type(a) == "table" then
|
|
|
|
local first_key, _ = next(a)
|
|
|
|
if first_key == nil then
|
|
|
|
return List:new({})
|
|
|
|
elseif type(first_key) == "number" then
|
|
|
|
local list = {}
|
|
|
|
for i, v in ipairs(a) do
|
|
|
|
list[i] = lua_to_mal(v)
|
|
|
|
end
|
|
|
|
return List:new(list)
|
|
|
|
else
|
|
|
|
local hashmap = {}
|
|
|
|
for k, v in pairs(a) do
|
|
|
|
hashmap[lua_to_mal(k)] = lua_to_mal(v)
|
|
|
|
end
|
|
|
|
return HashMap:new(hashmap)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return tostring(a)
|
|
|
|
end
|
|
|
|
|
|
|
|
local function lua_eval(str)
|
2020-05-16 05:09:09 +03:00
|
|
|
local f, err = load("return "..str)
|
2016-06-12 04:30:44 +03:00
|
|
|
if err then
|
|
|
|
types.throw("lua-eval: can't load code: "..err)
|
|
|
|
end
|
|
|
|
return lua_to_mal(f())
|
|
|
|
end
|
|
|
|
|
2015-01-09 08:25:40 +03:00
|
|
|
M.ns = {
|
|
|
|
['='] = types._equal_Q,
|
|
|
|
throw = types.throw,
|
|
|
|
|
|
|
|
['nil?'] = function(a) return a==Nil end,
|
|
|
|
['true?'] = function(a) return a==true end,
|
|
|
|
['false?'] = function(a) return a==false end,
|
2017-10-11 11:28:04 +03:00
|
|
|
['number?'] = function(a) return types._number_Q(a) end,
|
2015-01-09 08:25:40 +03:00
|
|
|
symbol = function(a) return types.Symbol:new(a) end,
|
|
|
|
['symbol?'] = function(a) return types._symbol_Q(a) end,
|
2024-08-21 19:59:10 +03:00
|
|
|
['string?'] = function(a) return types._string_Q(a) end,
|
2020-05-16 05:09:09 +03:00
|
|
|
keyword = function(a)
|
|
|
|
if types._keyword_Q(a) then
|
|
|
|
return a
|
|
|
|
else
|
2024-08-21 19:59:10 +03:00
|
|
|
return types._keyword_from_lua_string(a)
|
2020-05-16 05:09:09 +03:00
|
|
|
end
|
|
|
|
end,
|
2015-01-09 08:25:40 +03:00
|
|
|
['keyword?'] = function(a) return types._keyword_Q(a) end,
|
2017-10-11 11:28:04 +03:00
|
|
|
['fn?'] = function(a) return types._fn_Q(a) end,
|
|
|
|
['macro?'] = function(a) return types._macro_Q(a) end,
|
2015-01-09 08:25:40 +03:00
|
|
|
|
|
|
|
['pr-str'] = pr_str,
|
|
|
|
str = str,
|
|
|
|
prn = prn,
|
|
|
|
println = println,
|
|
|
|
['read-string'] = reader.read_str,
|
|
|
|
readline = do_readline,
|
|
|
|
slurp = slurp,
|
|
|
|
|
|
|
|
['<'] = function(a,b) return a<b end,
|
|
|
|
['<='] = function(a,b) return a<=b end,
|
|
|
|
['>'] = function(a,b) return a>b end,
|
|
|
|
['>='] = function(a,b) return a>=b end,
|
|
|
|
['+'] = function(a,b) return a+b end,
|
|
|
|
['-'] = function(a,b) return a-b end,
|
|
|
|
['*'] = function(a,b) return a*b end,
|
|
|
|
['/'] = function(a,b) return math.floor(a/b) end,
|
2020-05-17 20:23:54 +03:00
|
|
|
['time-ms'] = function() return math.floor(os.clock()*1000000) end,
|
2015-01-09 08:25:40 +03:00
|
|
|
|
2019-01-28 22:31:28 +03:00
|
|
|
list = function(...) return List:new(table.pack(...)) end,
|
2015-01-09 08:25:40 +03:00
|
|
|
['list?'] = function(a) return types._list_Q(a) end,
|
2019-01-28 22:31:28 +03:00
|
|
|
vector = function(...) return types.Vector:new(table.pack(...)) end,
|
2015-01-09 08:25:40 +03:00
|
|
|
['vector?'] = types._vector_Q,
|
|
|
|
['hash-map'] = types.hash_map,
|
|
|
|
['map?'] = types._hash_map_Q,
|
|
|
|
assoc = assoc,
|
|
|
|
dissoc = dissoc,
|
|
|
|
get = get,
|
|
|
|
['contains?'] = function(a,b) return a[b] ~= nil end,
|
|
|
|
keys = keys,
|
|
|
|
vals = vals,
|
|
|
|
|
|
|
|
['sequential?'] = types._sequential_Q,
|
|
|
|
cons = cons,
|
|
|
|
concat = concat,
|
2020-07-21 19:01:48 +03:00
|
|
|
vec = vec,
|
2015-01-09 08:25:40 +03:00
|
|
|
nth = nth,
|
|
|
|
first = first,
|
2016-01-30 05:47:14 +03:00
|
|
|
rest = rest,
|
2015-01-09 08:25:40 +03:00
|
|
|
['empty?'] = function(a) return a==Nil or #a == 0 end,
|
|
|
|
count = function(a) return #a end,
|
|
|
|
apply = apply,
|
|
|
|
map = map,
|
2015-07-22 11:56:32 +03:00
|
|
|
conj = conj,
|
2016-02-13 06:00:53 +03:00
|
|
|
seq = seq,
|
2015-01-09 08:25:40 +03:00
|
|
|
|
|
|
|
meta = meta,
|
|
|
|
['with-meta'] = with_meta,
|
|
|
|
atom = function(a) return types.Atom:new(a) end,
|
|
|
|
['atom?'] = types._atom_Q,
|
|
|
|
deref = function(a) return a.val end,
|
|
|
|
['reset!'] = function(a,b) a.val = b; return b end,
|
|
|
|
['swap!'] = swap_BANG,
|
2016-06-12 04:30:44 +03:00
|
|
|
|
|
|
|
['lua-eval'] = lua_eval,
|
2015-01-09 08:25:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return M
|
|
|
|
|