diff options
Diffstat (limited to 'server-beta/src/vm/getValue.lua')
-rw-r--r-- | server-beta/src/vm/getValue.lua | 895 |
1 files changed, 0 insertions, 895 deletions
diff --git a/server-beta/src/vm/getValue.lua b/server-beta/src/vm/getValue.lua deleted file mode 100644 index ee486a54..00000000 --- a/server-beta/src/vm/getValue.lua +++ /dev/null @@ -1,895 +0,0 @@ -local vm = require 'vm.vm' - -local typeSort = { - ['boolean'] = 1, - ['string'] = 2, - ['integer'] = 3, - ['number'] = 4, - ['table'] = 5, - ['function'] = 6, - ['nil'] = math.maxinteger, -} - -NIL = setmetatable({'<nil>'}, { __tostring = function () return 'nil' end }) - -local function merge(t, b) - if not t then - t = {} - end - if not b then - return t - end - for i = 1, #b do - local o = b[i] - if not t[o] then - t[o] = true - t[#t+1] = o - end - end - return t -end - -local function alloc(o) - -- TODO - assert(o.type) - if type(o.type) == 'table' then - local values = {} - for i = 1, #o.type do - local sub = { - type = o.type[i], - value = o.value, - source = o.source, - } - values[i] = sub - values[sub] = true - end - return values - else - return { - [1] = o, - [o] = true, - } - end -end - -local function insert(t, o) - if not o then - return - end - if not t[o] then - t[o] = true - t[#t+1] = o - end - return t -end - -local function checkLiteral(source) - if source.type == 'string' then - return alloc { - type = 'string', - value = source[1], - source = source, - } - elseif source.type == 'nil' then - return alloc { - type = 'nil', - value = NIL, - source = source, - } - elseif source.type == 'boolean' then - return alloc { - type = 'boolean', - value = source[1], - source = source, - } - elseif source.type == 'number' then - if math.type(source[1]) == 'integer' then - return alloc { - type = 'integer', - value = source[1], - source = source, - } - else - return alloc { - type = 'number', - value = source[1], - source = source, - } - end - elseif source.type == 'table' then - return alloc { - type = 'table', - source = source, - } - elseif source.type == 'function' then - return alloc { - type = 'function', - source = source, - } - end -end - -local function checkUnary(source) - if source.type ~= 'unary' then - return - end - local op = source.op - if op.type == 'not' then - local checkTrue = vm.checkTrue(source[1]) - local value = nil - if checkTrue == true then - value = false - elseif checkTrue == false then - value = true - end - return alloc { - type = 'boolean', - value = value, - source = source, - } - elseif op.type == '#' then - return alloc { - type = 'integer', - source = source, - } - elseif op.type == '~' then - local l = vm.getLiteral(source[1], 'integer') - return alloc { - type = 'integer', - value = l and ~l or nil, - source = source, - } - elseif op.type == '-' then - local v = vm.getLiteral(source[1], 'integer') - if v then - return alloc { - type = 'integer', - value = - v, - source = source, - } - end - v = vm.getLiteral(source[1], 'number') - return alloc { - type = 'number', - value = v and -v or nil, - source = source, - } - end -end - -local function checkBinary(source) - if source.type ~= 'binary' then - return - end - local op = source.op - if op.type == 'and' then - local isTrue = vm.checkTrue(source[1]) - if isTrue == true then - return vm.getValue(source[2]) - elseif isTrue == false then - return vm.getValue(source[1]) - else - return merge( - vm.getValue(source[1]), - vm.getValue(source[2]) - ) - end - elseif op.type == 'or' then - local isTrue = vm.checkTrue(source[1]) - if isTrue == true then - return vm.getValue(source[1]) - elseif isTrue == false then - return vm.getValue(source[2]) - else - return merge( - vm.getValue(source[1]), - vm.getValue(source[2]) - ) - end - elseif op.type == '==' then - local value = vm.isSameValue(source[1], source[2]) - if value ~= nil then - return alloc { - type = 'boolean', - value = value, - source = source, - } - end - local isSame = vm.isSameRef(source[1], source[2]) - if isSame == true then - value = true - else - value = nil - end - return alloc { - type = 'boolean', - value = value, - source = source, - } - elseif op.type == '~=' then - local value = vm.isSameValue(source[1], source[2]) - if value ~= nil then - return alloc { - type = 'boolean', - value = not value, - source = source, - } - end - local isSame = vm.isSameRef(source[1], source[2]) - if isSame == true then - value = false - else - value = nil - end - return alloc { - type = 'boolean', - value = value, - source = source, - } - elseif op.type == '<=' then - local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number') - local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number') - local v - if v1 and v2 then - v = v1 <= v2 - end - return alloc { - type = 'boolean', - value = v, - source = source, - } - elseif op.type == '>=' then - local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number') - local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number') - local v - if v1 and v2 then - v = v1 >= v2 - end - return alloc { - type = 'boolean', - value = v, - source = source, - } - elseif op.type == '<' then - local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number') - local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number') - local v - if v1 and v2 then - v = v1 < v2 - end - return alloc { - type = 'boolean', - value = v, - source = source, - } - elseif op.type == '>' then - local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number') - local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number') - local v - if v1 and v2 then - v = v1 > v2 - end - return alloc { - type = 'boolean', - value = v, - source = source, - } - elseif op.type == '|' then - local v1 = vm.getLiteral(source[1], 'integer') - local v2 = vm.getLiteral(source[2], 'integer') - local v - if v1 and v2 then - v = v1 | v2 - end - return alloc { - type = 'integer', - value = v, - source = source, - } - elseif op.type == '~' then - local v1 = vm.getLiteral(source[1], 'integer') - local v2 = vm.getLiteral(source[2], 'integer') - local v - if v1 and v2 then - v = v1 ~ v2 - end - return alloc { - type = 'integer', - value = v, - source = source, - } - elseif op.type == '&' then - local v1 = vm.getLiteral(source[1], 'integer') - local v2 = vm.getLiteral(source[2], 'integer') - local v - if v1 and v2 then - v = v1 & v2 - end - return alloc { - type = 'integer', - value = v, - source = source, - } - elseif op.type == '<<' then - local v1 = vm.getLiteral(source[1], 'integer') - local v2 = vm.getLiteral(source[2], 'integer') - local v - if v1 and v2 then - v = v1 << v2 - end - return alloc { - type = 'integer', - value = v, - source = source, - } - elseif op.type == '>>' then - local v1 = vm.getLiteral(source[1], 'integer') - local v2 = vm.getLiteral(source[2], 'integer') - local v - if v1 and v2 then - v = v1 >> v2 - end - return alloc { - type = 'integer', - value = v, - source = source, - } - elseif op.type == '..' then - local v1 = vm.getLiteral(source[1], 'string') - local v2 = vm.getLiteral(source[2], 'string') - local v - if v1 and v2 then - v = v1 .. v2 - end - return alloc { - type = 'string', - value = v, - source = source, - } - elseif op.type == '^' then - local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number') - local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number') - local v - if v1 and v2 then - v = v1 ^ v2 - end - return alloc { - type = 'number', - value = v, - source = source, - } - elseif op.type == '/' then - local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number') - local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number') - local v - if v1 and v2 then - v = v1 > v2 - end - return alloc { - type = 'number', - value = v, - source = source, - } - -- 其他数学运算根据2侧的值决定,当2侧的值均为整数时返回整数 - elseif op.type == '+' then - local v1 = vm.getLiteral(source[1], 'integer') - local v2 = vm.getLiteral(source[2], 'integer') - if v1 and v2 then - return alloc { - type = 'integer', - value = v1 + v2, - source = source, - } - end - v1 = v1 or vm.getLiteral(source[1], 'number') - v2 = v2 or vm.getLiteral(source[1], 'number') - return alloc { - type = 'number', - value = (v1 and v2) and (v1 + v2) or nil, - source = source, - } - elseif op.type == '-' then - local v1 = vm.getLiteral(source[1], 'integer') - local v2 = vm.getLiteral(source[2], 'integer') - if v1 and v2 then - return alloc { - type = 'integer', - value = v1 - v2, - source = source, - } - end - v1 = v1 or vm.getLiteral(source[1], 'number') - v2 = v2 or vm.getLiteral(source[1], 'number') - return alloc { - type = 'number', - value = (v1 and v2) and (v1 - v2) or nil, - source = source, - } - elseif op.type == '*' then - local v1 = vm.getLiteral(source[1], 'integer') - local v2 = vm.getLiteral(source[2], 'integer') - if v1 and v2 then - return alloc { - type = 'integer', - value = v1 * v2, - source = source, - } - end - v1 = v1 or vm.getLiteral(source[1], 'number') - v2 = v2 or vm.getLiteral(source[1], 'number') - return alloc { - type = 'number', - value = (v1 and v2) and (v1 * v2) or nil, - source = source, - } - elseif op.type == '%' then - local v1 = vm.getLiteral(source[1], 'integer') - local v2 = vm.getLiteral(source[2], 'integer') - if v1 and v2 then - return alloc { - type = 'integer', - value = v1 % v2, - source = source, - } - end - v1 = v1 or vm.getLiteral(source[1], 'number') - v2 = v2 or vm.getLiteral(source[1], 'number') - return alloc { - type = 'number', - value = (v1 and v2) and (v1 % v2) or nil, - source = source, - } - elseif op.type == '//' then - local v1 = vm.getLiteral(source[1], 'integer') - local v2 = vm.getLiteral(source[2], 'integer') - if v1 and v2 then - return alloc { - type = 'integer', - value = v1 // v2, - source = source, - } - end - v1 = v1 or vm.getLiteral(source[1], 'number') - v2 = v2 or vm.getLiteral(source[1], 'number') - return alloc { - type = 'number', - value = (v1 and v2) and (v1 // v2) or nil, - source = source, - } - end -end - -local function checkValue(source) - if source.value then - return vm.getValue(source.value) - end - if source.type == 'paren' then - return vm.getValue(source.exp) - end -end - -local function hasTypeInResults(results, type) - for i = 1, #results do - if results[i].type == type then - return true - end - end - return false -end - -local function inferByCall(results, source) - if #results ~= 0 then - return - end - if not source.parent then - return - end - if source.parent.type ~= 'call' then - return - end - if source.parent.node == source then - insert(results, { - type = 'function', - source = source, - }) - return - end -end - -local function inferByGetTable(results, source) - if #results ~= 0 then - return - end - local next = source.next - if not next then - return - end - if next.type == 'getfield' - or next.type == 'getindex' - or next.type == 'getmethod' - or next.type == 'setfield' - or next.type == 'setindex' - or next.type == 'setmethod' then - insert(results, { - type = 'table', - source = source, - }) - end -end - -local function checkDef(results, source) - vm.eachDef(source, function (info) - local src = info.source - local tp = vm.getValue(src) - if tp then - merge(results, tp) - end - end) -end - -local function checkLibrary(source) - local lib = vm.getLibrary(source) - if not lib then - return nil - end - return alloc { - type = lib.type, - value = lib.value, - source = vm.librarySource(lib), - } -end - -local function checkLibraryReturn(source) - if source.type ~= 'select' then - return nil - end - local index = source.index - local call = source.vararg - if call.type ~= 'call' then - return nil - end - local func = call.node - local lib = vm.getLibrary(func) - if not lib then - return nil - end - if lib.type ~= 'function' then - return nil - end - if not lib.returns then - return nil - end - local rtn = lib.returns[index] - if not rtn then - return nil - end - return alloc { - type = rtn.type, - value = rtn.value, - source = vm.librarySource(rtn), - } -end - -local function checkLibraryArg(source) - local args = source.parent - if not args then - return - end - if args.type ~= 'callargs' then - return - end - local call = args.parent - if not call then - return - end - local func = call.node - local index - for i = 1, #args do - if args[i] == source then - index = i - break - end - end - if not index then - return - end - local lib = vm.getLibrary(func) - local arg = lib and lib.args and lib.args[index] - if not arg then - return - end - if arg.type == '...' then - return - end - return alloc { - type = arg.type, - value = arg.value, - source = vm.librarySource(arg), - } -end - -local function inferByUnary(results, source) - if #results ~= 0 then - return - end - local parent = source.parent - if not parent or parent.type ~= 'unary' then - return - end - local op = parent.op - if op.type == '#' then - insert(results, { - type = 'string', - source = vm.librarySource(source) - }) - insert(results, { - type = 'table', - source = vm.librarySource(source) - }) - elseif op.type == '~' then - insert(results, { - type = 'integer', - source = vm.librarySource(source) - }) - elseif op.type == '-' then - insert(results, { - type = 'number', - source = vm.librarySource(source) - }) - end -end - -local function inferByBinary(results, source) - if #results ~= 0 then - return - end - local parent = source.parent - if not parent or parent.type ~= 'binary' then - return - end - local op = parent.op - if op.type == '<=' - or op.type == '>=' - or op.type == '<' - or op.type == '>' - or op.type == '^' - or op.type == '/' - or op.type == '+' - or op.type == '-' - or op.type == '*' - or op.type == '%' then - insert(results, { - type = 'number', - source = vm.librarySource(source) - }) - elseif op.type == '|' - or op.type == '~' - or op.type == '&' - or op.type == '<<' - or op.type == '>>' - -- 整数的可能性比较高 - or op.type == '//' then - insert(results, { - type = 'integer', - source = vm.librarySource(source) - }) - elseif op.type == '..' then - insert(results, { - type = 'string', - source = vm.librarySource(source) - }) - end -end - -local function inferBySetOfLocal(results, source) - if source.ref then - for i = 1, #source.ref do - local ref = source.ref[i] - if ref.type == 'setlocal' then - break - end - merge(results, vm.getValue(ref)) - end - end -end - -local function inferBySet(results, source) - if #results ~= 0 then - return - end - if source.type == 'local' then - inferBySetOfLocal(results, source) - elseif source.type == 'setlocal' - or source.type == 'getlocal' then - inferBySetOfLocal(results, source.node) - end -end - -local function getValue(source) - local results = checkLiteral(source) - or checkValue(source) - or checkUnary(source) - or checkBinary(source) - or checkLibrary(source) - or checkLibraryReturn(source) - or checkLibraryArg(source) - if results then - return results - end - - results = {} - checkDef(results, source) - inferBySet(results, source) - inferByCall(results, source) - inferByGetTable(results, source) - inferByUnary(results, source) - inferByBinary(results, source) - - if #results == 0 then - return nil - end - - return results -end - -function vm.checkTrue(source) - local values = vm.getValue(source) - if not values then - return - end - -- 当前认为的结果 - local current - for i = 1, #values do - -- 新的结果 - local new - local v = values[i] - if v.type == 'nil' then - new = false - elseif v.type == 'boolean' then - if v.value == true then - new = true - elseif v.value == false then - new = false - end - end - if new ~= nil then - if current == nil then - current = new - else - -- 如果2个结果完全相反,则返回 nil 表示不确定 - if new ~= current then - return nil - end - end - end - end - return current -end - ---- 获取特定类型的字面量值 -function vm.getLiteral(source, type) - local values = vm.getValue(source) - if not values then - return nil - end - for i = 1, #values do - local v = values[i] - if v.value ~= nil then - if type == nil or v.type == type then - return v.value - end - end - end - return nil -end - -function vm.isSameValue(a, b) - local valuesA = vm.getValue(a) - local valuesB = vm.getValue(b) - if not valuesA or not valuesB then - return false - end - if valuesA == valuesB then - return true - end - local values = {} - for i = 1, #valuesA do - local value = valuesA[i] - local literal = value.value - if literal then - values[literal] = false - end - end - for i = 1, #valuesB do - local value = valuesA[i] - local literal = value.value - if literal then - if values[literal] == nil then - return false - end - values[literal] = true - end - end - for k, v in pairs(values) do - if v == false then - return false - end - end - return true -end - ---- 是否包含某种类型 -function vm.hasType(source, type) - local values = vm.getValue(source) - if not values then - return false - end - for i = 1, #values do - local value = values[i] - if value.type == type then - return true - end - end - return false -end - -function vm.viewType(values) - if not values then - return 'any' - end - local types = {} - for i = 1, #values do - local tp = values[i].type - if not types[tp] then - types[tp] = true - types[#types+1] = tp - end - end - if #types == 0 then - return 'any' - end - if #types == 1 then - return types[1] - end - table.sort(types, function (a, b) - local sa = typeSort[a] - local sb = typeSort[b] - if sa and sb then - return sa < sb - end - if not sa and not sb then - return a < b - end - if sa and not sb then - return true - end - if not sa and sb then - return false - end - return false - end) - return table.concat(types, '|') -end - -function vm.getType(source) - local values = vm.getValue(source) - return vm.viewType(values) -end - -function vm.getValue(source) - if not source then - return - end - local cache = vm.cache.getValue[source] - if cache ~= nil then - return cache - end - local unlock = vm.lock('getValue', source) - if not unlock then - return - end - cache = getValue(source) or false - vm.cache.getValue[source] = cache - unlock() - return cache -end |