if not sorcery then sorcery = {DEBUG=true} end
sorcery.register = {}
sorcery.registry = {
defercheck = function() return true end
-- used to warn about deferments that have not been discharged by a certain threshold
}
sorcery.registry.mk = function(name,db)
local reg = {}
if db == nil then
-- predefined db
db = sorcery.data[name]
elseif db == false then -- auxiliary db, stored in registry itself
reg.db = {}
db = reg.db
end
local dat = {
iters = {};
state = {};
defer = {};
}
reg.invoke = function(fnid,tgtid)
local fno = dat.iters[fnid]
if not fno then return false end
local runid = fnid .. '@' ..tgtid
if dat.state[runid] then return true end
if fno.deps then for k,f in pairs(fno.deps) do
if reg.invoke(f,tgtid) == false then return false end
end end
fno.fn(tgtid, db[tgtid])
dat.state[runid] = true
return true
end
reg.foreach = function(ident,deps,fn)
dat.iters[ident] = {deps = deps, fn = fn}
for k in pairs(db) do
if reg.invoke(ident,k) == false then
-- not all dependencies are available
-- to run yet; must defer until then
dat.defer[#dat.defer+1] = ident
return false
end
end
for i,dfn in pairs(dat.defer) do
local deferred = dat.iters[dfn]
for _,d in pairs(deferred.deps) do
if not dat.iters[d] then goto skipdfmt end
end
-- a deferred function can now be run, do so
table.remove(dat.defer,i)
reg.foreach(dfn,deferred.deps,deferred.fn)
::skipdfmt::end
return true
end
reg.link = function(key,value)
-- support simple arrays as well as kv stores
if value == nil then
value = key
key = #db+1
end
db[key] = value
for id in pairs(dat.iters) do
reg.invoke(id,key)
end
end
reg.meld = function(tbl)
for k,v in pairs(tbl) do reg.link(k,v) end
end
sorcery.register[name] = reg
local nextfn = sorcery.registry.defercheck
sorcery.registry.defercheck = function()
if #dat.defer ~= 0 then
print('WARNING: ' .. tostring(#dat.defer) .. ' deferred iterator(s) have not yet been discharged for registry “' .. name .. '”')
local log = sorcery.log and function(text)
sorcery.log('registry',text)
end or print
for i,v in pairs(dat.defer) do
log('\t' .. tostring(i) .. ') ' .. v)
end
log('there is likely a missing dependency or dependency ordering problem. also make sure you have spelled the names of the iterator dependencies correctly')
return false
end
nextfn()
end
return reg
end
if sorcery.DEBUG then
local function dump(tbl,indent)
indent = indent or 0
local space = string.rep(' ',indent*4)
for k,v in pairs(tbl) do
if type(v) == 'table' then
print(string.format('%s%s = {',space,k))
dump(v,indent + 1)
print(string.format('%s}', space))
else
print(string.format('%s%s = %q',space,k,tostring(v)))
end
end
end
local metals = {
oregonium = {desc = 'Oregonium'};
nevadite = {desc = 'Nevadite'};
}
local myreg = sorcery.registry.mk('metals',metals)
sorcery.register.metals.link('californium', {
desc = "Californium";
})
sorcery.register.metals.foreach('sorcery:mkingot',{'sorcery:mkfrag'}, function(k,v)
local ingot = 'sorcery:' .. k .. '_ingot'
print('registered',ingot)
v.parts = v.parts or {}
v.parts.ingot = ingot;
end)
sorcery.registry.defercheck()
sorcery.register.metals.link('washingtonium', {
desc = "Washingtonium";
})
sorcery.register.metals.foreach('sorcery:mkfrag',{}, function(k,v)
local fragment = 'sorcery:' .. k .. '_fragment'
print('registered',fragment)
v.parts = v.parts or {}
v.parts.fragment = fragment;
end)
sorcery.register.metals.link('biloxite', {
desc = "Biloxite";
})
dump(metals)
if sorcery.registry.defercheck() then
print('lingering deferments!')
else
print('all good!')
end
end