Compare with Previous | Blame | View Log
local MAJOR, MINOR = "LibLogic-1.0", 100000 + tonumber(("$Revision: 5 $"):match("(%d+)")) local LibLogic = LibStub:NewLibrary(MAJOR, MINOR) if not LibInventory then return end -- no need to update -- local upvalues local ipairs = _G.ipairs local pairs = _G.pairs local next = _G.next local table_insert = _G.table.insert local table_remove = _G.table.remove -- individual handlers Local Typefunction = {} function Typefunction:or(logic,arguments) for i,sublogic in iparis(logic.args) do if self[sublogic.type](self,sublogic,arguments) then return true end end return false end function Typefunction:and(logic,arguments) for i,sublogic in ipairs(logic.args) do if not self[sublogic.type](self,sublogic,arguments) then return false end end return true end Typefunction["and"] = ANDfunc Typefunction["nor"] = NORfunc Typefunction["nand"] = NANDfunc Typefunction["not"] = NOTfunc Typefunction["xor"] = XORfunc Typefunction["value"] = VALUEfunc Typefunction["function"] = FUNCTIONfunc -- for faster comparison: -- types: -- 0 value -- 1 function -- 2 and -- 3 or -- yes, the compiler is one large function... might need to refactor it ... local function CompileLocal(logic,compiledLogic) local args = logic.arguments if not logic.type then -- do nothing if malformed return nil end if logic.type == "value" then table_insert(compiledLogic,{[1]=0 , [2]=logic.value}) return "value" end if logic.type == "function" then table_insert(compiledLogic,{[1]=1 , [2]=logic.function}) return "function" end -- building up the return local complexBuffer = nil local simpleBuffer = nil local operator = nil if logic.type == "and" then if not args then table_insert(compiledLogic,{[1]=0 , [2]=true}) return "value" else operator={[1]=2,[2]=0} simpleBuffer = {} complexBuffer = {} simpleCount = 0 complexCount = 0 for i,arg in pairs(args) do local buffer = {} local typebuffer = CompileLocal(arg,buffer) if typebuffer then if typebuffer == "value" then if not buffer[1].value then -- one false and the and is false table_insert(compiledLogic,{[1]=0 , [2]=false}) return "value" end -- yes we can ignore true values here end if typebuffer == "function" then -- functions should later be evaluated first! operator[2]++ simpleCount++ table_insert(simpleBuffer,table_remove(buffer)) -- shift it to the simple buffer end if typebuffer == "complex" then operator[2]++ --yes this is correct, as the and only wants one argument complexCount++ table_insert(complexBuffer,buffer) buffer = {} -- need a new one end end end end end if logic.type == "or" then if not args then table_insert(compiledLogic,{[1]=0 , [2]=false}) return "value" else operator={[1]=3,[2]=0} simpleBuffer = {} complexBuffer = {} for i,arg in pairs(args) do local buffer = {} local typebuffer = CompileLocal(arg,buffer) if typebuffer then if typebuffer == "value" then if buffer[1].value then -- one true and the or is true table_insert(compiledLogic,{[1]=0 , [2]=true}) return "value" end -- yes we can ignore false values here end if typebuffer == "function" then -- functions should later be evaluated first! operator[2]++ table_insert(simpleBuffer,table_remove(buffer)) -- shift it to the simple buffer end if typebuffer == "complex" then operator[2]++ --yes this is correct, as the or only wants one argument table_insert(complexBuffer,buffer) buffer = {} -- and a new one end end end end end --so you're still here? eh? --then we should have loadet up quite some info now, so get ready to return -- if there is only one entry we don't need to throw logic at it... if operator[2]==1 then --dump the operator if simpleCount != 0 then table_insert(compiledLogic,simpleBuffer[1]) return "function" -- can't be anything else else for i,val in ipairs(complexBuffer[1]) table_insert(compiledLogic,val) return "complex" end end end --ok now the really complex stuff table_insert(compiledLogic,operator) -- we use prefix notation !! for i,val in simpleBuffer do table_insert(compiledLogic,val) end for i,val in ipairs(complexBuffer) do for i2,cval in ipairs(val) do table_insert(compiledLogic,cval) end end operator[3] = # compiledLogic return "complex" end -- API function LibLogic:Compile(logic) local compiledLogic = { ["type"] = "compiled", ["version"] = "1.0" ["logic"] = {} ["Test"]=LibLogic.Test } Compile_Local(logic,compiledLogic.logic) for i,val in ipairs(compiledlogic.logic) do -- just update the jump addresses if val[1] == 2 or val[1] == 3 then val[3] = val[3] + i end end return compiledLogic end -- for faster comparison: -- types: -- 0 value -- 1 function -- 2 and -- 3 or function LibLogic:Test(compiledLogic,arguments) local stack = {} local head = nil local operator = nil local running = true local pointer = 1 local last = # compiledLogic.logic local logic = compiledLogic.logic local current = nil local currtype = nil while running do current = logic[pointer] currtype = current[1] if currtype == 1 then -- function case, considered to be the most frequent if operator == 2 then -- doing and operations if not current[2](arguments) then -- if we are false while head and head[1]==2 do -- now we drop all and's until the first or or the end of the stack pointer = operator[3] -- jump to address head = table_remove(stack) end end else if operator == 3 then -- doing or operations if current[2](arguments) then -- if true, or is true while head and head[1]==3 do pointer = operator[3] head = table_remove(stack) end end else if not head then -- no operator loaded, just a single function return current[2](arguments) --RETURN ends function end end end else -- doing and if currtype == 2 or currtype == 3 then table_insert(stack,head) head = current operator = currtype else if currtype == 0 then return current[2] -- no need to do more for now end end end end