You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
248 lines
6.7 KiB
248 lines
6.7 KiB
|
5 years ago
|
--[[
|
||
|
|
Condition.lua
|
||
|
|
@Author : DengSir (tdaddon@163.com)
|
||
|
|
@Link : https://dengsir.github.io
|
||
|
|
]]
|
||
|
|
|
||
|
|
local ns = select(2, ...)
|
||
|
|
local Util = ns.Util
|
||
|
|
local Addon = ns.Addon
|
||
|
|
local Condition = {} ns.Condition = Condition
|
||
|
|
|
||
|
|
Condition.apis = {}
|
||
|
|
Condition.opts = setmetatable({
|
||
|
|
__default = {
|
||
|
|
owner = true,
|
||
|
|
pet = true,
|
||
|
|
arg = true,
|
||
|
|
type = 'compare',
|
||
|
|
}
|
||
|
|
}, {
|
||
|
|
__newindex = function(t, k, v)
|
||
|
|
rawset(t, k, setmetatable(v, {__index = t.__default}))
|
||
|
|
end,
|
||
|
|
__index = function(t)
|
||
|
|
return t.__default
|
||
|
|
end,
|
||
|
|
})
|
||
|
|
|
||
|
|
local opTabler = {
|
||
|
|
compare = {
|
||
|
|
['='] = function(a, b) return a == b end,
|
||
|
|
['=='] = function(a, b) return a == b end,
|
||
|
|
['!='] = function(a, b) return a ~= b end,
|
||
|
|
['>'] = function(a, b) return a > b end,
|
||
|
|
['<'] = function(a, b) return a < b end,
|
||
|
|
['>='] = function(a, b) return a >= b end,
|
||
|
|
['<='] = function(a, b) return a <= b end,
|
||
|
|
['~'] = function(a, v) return v[a] end,
|
||
|
|
['!~'] = function(a, v) return not v[a] end,
|
||
|
|
},
|
||
|
|
boolean = {
|
||
|
|
['='] = function(a) return a end,
|
||
|
|
['!'] = function(a) return not a end,
|
||
|
|
},
|
||
|
|
equality = {
|
||
|
|
['='] = function(a, b) return a == b end,
|
||
|
|
['=='] = function(a, b) return a == b end,
|
||
|
|
['!='] = function(a, b) return a ~= b end,
|
||
|
|
['~'] = function(a, v) return v[a] end,
|
||
|
|
['!~'] = function(a, v) return not v[a] end,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
local multiTabler = {
|
||
|
|
['~'] = true,
|
||
|
|
['!~'] = true,
|
||
|
|
}
|
||
|
|
|
||
|
|
local parses = {
|
||
|
|
'valueParse',
|
||
|
|
'argParse',
|
||
|
|
}
|
||
|
|
|
||
|
|
local function trynumber(value)
|
||
|
|
return tonumber(value) or value
|
||
|
|
end
|
||
|
|
|
||
|
|
local function trynil(value)
|
||
|
|
return value ~= '' and value or nil
|
||
|
|
end
|
||
|
|
|
||
|
|
function Addon:RegisterCondition(name, opts, api)
|
||
|
|
if opts then
|
||
|
|
if opts.type and not opTabler[opts.type] then
|
||
|
|
error([[Bad argument opts.type (expect compare/boolean/equality)]], 2)
|
||
|
|
end
|
||
|
|
|
||
|
|
for i, v in ipairs(parses) do
|
||
|
|
if opts[v] and type(opts[v]) ~= 'function' then
|
||
|
|
error(format([[Bad argument opts.%s (expect function)]], v), 2)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
Condition.apis[name] = api
|
||
|
|
Condition.opts[name] = opts
|
||
|
|
end
|
||
|
|
|
||
|
|
function Condition:Run(condition)
|
||
|
|
if not condition then
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
if type(condition) == 'string' then
|
||
|
|
return self:RunCondition(condition)
|
||
|
|
elseif type(condition) == 'table' then
|
||
|
|
for _, v in ipairs(condition) do
|
||
|
|
if not self:Run(v) then
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return true
|
||
|
|
else
|
||
|
|
Util.assert(false, 'Invalid Condition: `%s` (type error)', condition)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function Condition:RunCondition(condition)
|
||
|
|
local owner, pet, cmd, arg, op, value = self:ParseCondition(condition)
|
||
|
|
|
||
|
|
local fn = self.apis[cmd]
|
||
|
|
local opts = self.opts[cmd]
|
||
|
|
if not fn then
|
||
|
|
error('Big Bang !!!!!!')
|
||
|
|
end
|
||
|
|
|
||
|
|
if opts.pet == true and not pet then
|
||
|
|
return opTabler[opts.type][op](false)
|
||
|
|
end
|
||
|
|
if opts.arg == true and not arg then
|
||
|
|
return opTabler[opts.type][op](false)
|
||
|
|
end
|
||
|
|
return opTabler[opts.type][op](fn(owner, pet, arg), value)
|
||
|
|
end
|
||
|
|
|
||
|
|
function Condition:ParsePet(str)
|
||
|
|
if not str then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local owner, pet = Util.ParseQuote(str)
|
||
|
|
owner = Util.ParsePetOwner(owner)
|
||
|
|
if not owner then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
petInputed = not not pet
|
||
|
|
pet = Util.ParsePetIndex(owner, pet)
|
||
|
|
return owner, pet, petInputed
|
||
|
|
end
|
||
|
|
|
||
|
|
function Condition:ParseCmd(major, minor)
|
||
|
|
if not major then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local cmd, arg = Util.ParseQuote(major)
|
||
|
|
return minor and format('%s.%s', cmd, minor) or cmd, arg, not not arg
|
||
|
|
end
|
||
|
|
|
||
|
|
function Condition:ParseApi(str)
|
||
|
|
if not str then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local inQuote = false
|
||
|
|
local args = {''}
|
||
|
|
|
||
|
|
for char in str:gmatch('.') do
|
||
|
|
if char == '.' and not inQuote then
|
||
|
|
tinsert(args, '')
|
||
|
|
else
|
||
|
|
args[#args] = args[#args] .. char
|
||
|
|
end
|
||
|
|
|
||
|
|
if char == '(' then
|
||
|
|
inQuote = true
|
||
|
|
elseif char == ')' then
|
||
|
|
inQuote = false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local owner, pet, petInputed = self:ParsePet(args[1])
|
||
|
|
local cmd, arg, argInputed = self:ParseCmd(unpack(args, owner and 2 or 1))
|
||
|
|
|
||
|
|
return owner, pet, cmd, arg, petInputed, argInputed
|
||
|
|
end
|
||
|
|
|
||
|
|
function Condition:ParseCondition(condition)
|
||
|
|
local non, args, op, value = condition:match('^(!?)([^!=<>~]+)%s*([!=<>~]*)%s*(.*)$')
|
||
|
|
|
||
|
|
Util.assert(non, 'Invalid Condition: `%s` (Can`t parse)', condition)
|
||
|
|
|
||
|
|
local owner, pet, cmd, arg, petInputed, argInputed = self:ParseApi(args:trim())
|
||
|
|
|
||
|
|
Util.assert(cmd, 'Invalid Condition: `%s` (Can`t parse)', condition)
|
||
|
|
Util.assert(self.apis[cmd], 'Invalid Condition: `%s` (Not found cmd: `%s`)', condition, cmd)
|
||
|
|
|
||
|
|
op = trynil(op)
|
||
|
|
value = trynil(value)
|
||
|
|
non = trynil(non)
|
||
|
|
|
||
|
|
local opts = self.opts[cmd]
|
||
|
|
|
||
|
|
if opts.type == 'compare' or opts.type == 'equality' then
|
||
|
|
Util.assert(not non, 'Invalid Condition: `%s` (Not need non)', condition)
|
||
|
|
Util.assert(op, 'Invalid Condition: `%s` (Require op)', condition)
|
||
|
|
Util.assert(value, 'Invalid Condition: `%s` (Require value)', condition)
|
||
|
|
elseif opts.type == 'boolean' then
|
||
|
|
Util.assert(not op, 'Invalid Condition: `%s` (Not need op)', condition)
|
||
|
|
Util.assert(not value, 'Invalid Condition: `%s` (Not need value)', condition)
|
||
|
|
|
||
|
|
value = nil
|
||
|
|
op = non or '='
|
||
|
|
else
|
||
|
|
Util.assert(true)
|
||
|
|
end
|
||
|
|
|
||
|
|
Util.assert(opTabler[opts.type][op], 'Invalid Condition: `%s` (Invalid op)', condition)
|
||
|
|
|
||
|
|
if value then
|
||
|
|
if multiTabler[op] then
|
||
|
|
local values = {strsplit(',', value)}
|
||
|
|
value = {}
|
||
|
|
|
||
|
|
for i, v in ipairs(values) do
|
||
|
|
v = trynumber(v:trim())
|
||
|
|
if opts.valueParse then
|
||
|
|
v = Util.assert(opts.valueParse(v), 'Invalid Condition: `%s` (Error value)', condition)
|
||
|
|
end
|
||
|
|
value[v] = true
|
||
|
|
end
|
||
|
|
else
|
||
|
|
value = trynumber(value)
|
||
|
|
if opts.valueParse then
|
||
|
|
value = Util.assert(opts.valueParse(value), 'Invalid Condition: `%s` (Error value)', condition)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if not opts.owner then
|
||
|
|
Util.assert(not owner, 'Invalid Condition: `%s` (Not need owner)', condition)
|
||
|
|
end
|
||
|
|
|
||
|
|
if not opts.pet then
|
||
|
|
Util.assert(not petInputed, 'Invalid Condition: `%s` (Not need pet)', condition)
|
||
|
|
end
|
||
|
|
|
||
|
|
if not opts.arg then
|
||
|
|
Util.assert(not argInputed, 'Invalid Condition: `%s` (Not need arg)', condition)
|
||
|
|
else
|
||
|
|
arg = trynumber(arg)
|
||
|
|
if opts.argParse then
|
||
|
|
arg = opts.argParse(owner, pet, arg)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return owner, pet, cmd, arg, op, value
|
||
|
|
end
|