Files
2026-03-31 10:27:04 +03:00

203 lines
4.0 KiB
Lua

tinylua = setmetatable({}, { __call = function(self, ...) return self.Wrap(...) end})
local INTERNAL = {}
local META = {}
local function pack(...) -- Convenient argument packer
local len, tbl = select('#', ...), {...}
local packFuncs = {}
function packFuncs.unpack()
return unpack(tbl, 1, len)
end
return setmetatable(tbl, {
__index = function(self, index)
return packFuncs[index] or tbl[index]
end,
__call = function(...)
return len, tbl
end
})
end
local function Wrap(input)
local values = {}
local meta = {}
for ind, val in pairs(input)do
values[(tonumber(ind) and val or ind)] = val
end
for ind, val in pairs(META)do
meta[ind] = val
end
return setmetatable(values, meta)
end
local function performCall(tbl, callback)
local results = {}
local errors = {}
local calls = 0
local iKey, iVal = nil, nil
while true do
local succ, err = pcall(function()
while true do
iKey, iVal = next(tbl, iKey)
if iKey == nil then break end
calls = calls + 1
callback(results, iKey, iVal)
end
end)
if not succ then errors[iKey] = err end
if iKey == nil then break end
end
if table.Count(errors) == calls then
if calls ~= 0 then
local _, error = next(errors, nil)
MsgC(Color(235, 111, 111), "[tinylua] "..error)
else
MsgC(Color(235, 111, 111), "[tinylua] No results!\n")
return
end
end
local result = Wrap(results)
getmetatable(result)["errors"] = errors
return result
end
function META:__index(index)
if INTERNAL[index] then
return function(_, ...)
return INTERNAL[index](self, ...)
end
end
return performCall(self, function(results, source, ent)
local target = ent[index]
if isfunction(target) then
results[source] = function(fArg, ...)
return target(ent, ...)
end
else
results[source] = target
end
end)
end
function META:__newindex(index, value)
performCall(self, function(results, source, ent)
ent[index] = value
end)
end
function META:__call(...)
local args = pack(...)
return performCall(self, function(results, source, ent)
if isfunction(ent) then
local rets = pack(ent(args:unpack()))
if #rets ~= 1 then
for _, ret in pairs(rets) do
table.insert(results, ret)
end
else
results[source] = rets[1]
end
end
end)
end
-- Exposed Functions
tinylua.Wrap = Wrap
-- INTERNAL Extensions
local function makePrefix(input)
if not input:match("\n") and isfunction(CompileString("return "..input, "", false)) then
return "return "..input
end
return input
end
local function buildParser(input)
if isfunction(input) then return input end
local argStr, funcStr = input:match("(.-)->(.+)")
if argStr and funcStr then
local codeFull = string.format("return function(%s)\n%s\nend", argStr, makePrefix(funcStr))
local funcFactory = CompileString(codeFull, "funcfactory")
if getfenv(1) then
setfenv(funcFactory, getfenv(1))
end
if funcFactory then
return funcFactory()
end
end
end
function INTERNAL:map(input)
local eval = buildParser(input)
return performCall(self, function(results, source, ent)
local rets = pack(eval(ent, source))
if #rets ~= 1 then
for _, val in pairs(rets) do
table.insert(results, val)
end
else
results[source] = rets[1]
end
end)
end
function INTERNAL:filter(input)
local eval = buildParser(input)
return performCall(self, function(results, source, ent)
if eval(ent, source) then
results[source] = ent
end
end)
end
function INTERNAL:set(vars, val)
vars = (istable(vars) and vars or {vars})
return performCall(self, function(results, source, ent)
for _, var in ipairs(vars) do
ent[var] = val
end
results[source] = ent
end)
end
function INTERNAL:IsValid()
return false
end
function INTERNAL:keys()
return performCall(self, function(results, source, ent)
results[source] = source
end)
end
function INTERNAL:first()
for _, ent in pairs(self) do
return ent
end
end
function INTERNAL:errors()
return (getmetatable(self).errors or {})
end
function INTERNAL:get()
return table.ClearKeys(self)
end