203 lines
4.0 KiB
Lua
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
|