1
1
mirror of https://github.com/kanaka/mal.git synced 2024-08-18 02:00:40 +03:00
mal/impls/lua/types.lua

230 lines
4.7 KiB
Lua

local utils = require('utils')
local M = {}
-- type functions
function M._sequential_Q(obj)
return M._list_Q(obj) or M._vector_Q(obj)
end
function M._equal_Q(a,b)
if M._symbol_Q(a) and M._symbol_Q(b) then
return a.val == b.val
elseif M._sequential_Q(a) and M._sequential_Q(b) then
if #a ~= #b then return false end
for i, v in ipairs(a) do
if not M._equal_Q(v,b[i]) then return false end
end
return true
elseif M._hash_map_Q(a) and M._hash_map_Q(b) then
if #a ~= #b then return false end
for k, v in pairs(a) do
if not M._equal_Q(v,b[k]) then return false end
end
return true
else
return a == b
end
end
function M.copy(obj)
if type(obj) == "function" then
return M.FunctionRef:new(obj)
end
if type(obj) ~= "table" then return obj end
-- copy object data
local new_obj = {}
for k,v in pairs(obj) do
new_obj[k] = v
end
-- copy metatable and link to original
local old_mt = getmetatable(obj)
if old_mt ~= nil then
local new_mt = {}
for k,v in pairs(old_mt) do
new_mt[k] = v
end
setmetatable(new_mt, old_mt)
setmetatable(new_obj, new_mt)
end
return new_obj
end
function M.slice(lst, start, last)
if last == nil then last = #lst end
local new_lst = {}
if start <= last then
for i = start, last do
new_lst[#new_lst+1] = lst[i]
end
end
return new_lst
end
-- Error/exceptions
M.MalException = {}
function M.MalException:new(val)
local newObj = {val = val}
self.__index = self
return setmetatable(newObj, self)
end
function M._malexception_Q(obj)
return utils.instanceOf(obj, M.MalException)
end
function M.throw(val)
error(M.MalException:new(val))
end
-- Nil
local NilType = {}
function NilType:new(val)
local newObj = {}
self.__index = self
return setmetatable(newObj, self)
end
M.Nil = NilType:new()
function M._nil_Q(obj)
return obj == Nil
end
-- Numbers
function M._number_Q(obj)
return type(obj) == "number"
end
-- Strings
function M._string_Q(obj)
return type(obj) == "string"
end
-- Symbols
M.Symbol = {}
function M.Symbol:new(val)
local newObj = {val = val}
self.__index = self
return setmetatable(newObj, self)
end
function M._symbol_Q(obj)
return utils.instanceOf(obj, M.Symbol)
end
-- Keywords
function M._keyword_Q(obj)
return M._string_Q(obj) and "\u{029e}" == string.sub(obj,1,2)
end
-- Lists
M.List = {}
function M.List:new(lst)
local newObj = lst and lst or {}
self.__index = self
return setmetatable(newObj, self)
end
function M._list_Q(obj)
return utils.instanceOf(obj, M.List)
end
function M.List:slice(start,last)
return M.List:new(M.slice(self,start,last))
end
-- Vectors
M.Vector = {}
function M.Vector:new(lst)
local newObj = lst and lst or {}
self.__index = self
return setmetatable(newObj, self)
end
function M._vector_Q(obj)
return utils.instanceOf(obj, M.Vector)
end
function M.Vector:slice(start,last)
return M.Vector:new(M.slice(self,start,last))
end
-- Hash Maps
--
M.HashMap = {}
function M.HashMap:new(val)
local newObj = val and val or {}
self.__index = self
return setmetatable(newObj, self)
end
function M.hash_map(...)
return M._assoc_BANG(M.HashMap:new(), ...)
end
function M._hash_map_Q(obj)
return utils.instanceOf(obj, M.HashMap)
end
function M._assoc_BANG(hm, ...)
local arg = table.pack(...)
for i = 1, #arg, 2 do
hm[arg[i]] = arg[i+1]
end
return hm
end
function M._dissoc_BANG(hm, ...)
local arg = table.pack(...)
for i = 1, #arg do
hm[arg[i]] = nil
end
return hm
end
-- Functions
M.MalFunc = {}
function M.MalFunc:new(fn, ast, env, params)
local newObj = {fn = fn, ast = ast, env = env,
params = params, ismacro = false}
self.__index = self
return setmetatable(newObj, self)
end
function M._malfunc_Q(obj)
return utils.instanceOf(obj, M.MalFunc)
end
function M._fn_Q(obj)
return type(obj) == "function" or (M._malfunc_Q(obj) and not obj.ismacro)
end
function M._macro_Q(obj)
return M._malfunc_Q(obj) and obj.ismacro
end
-- Atoms
M.Atom = {}
function M.Atom:new(val)
local newObj = {val = val}
self.__index = self
return setmetatable(newObj, self)
end
function M._atom_Q(obj)
return utils.instanceOf(obj, M.Atom)
end
-- FunctionRefs
M.FunctionRef = {}
function M.FunctionRef:new(fn)
local newObj = {fn = fn}
return setmetatable(newObj, self)
end
function M._functionref_Q(obj)
return utils.instanceOf(obj, M.FunctionRef)
end
function M.FunctionRef:__call(...)
return self.fn(...)
end
return M