diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2020-08-17 15:40:39 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2020-08-17 15:40:39 +0800 |
commit | d44427e14c09bbe29c147841723deb39301da298 (patch) | |
tree | 49beba7b9060b7cbae6a11db2412c6f8f8608944 /script-beta | |
parent | dea8e5a934ffe566ec26ee2e0fabc1e5406a4b22 (diff) | |
download | lua-language-server-d44427e14c09bbe29c147841723deb39301da298.zip |
整理代码
Diffstat (limited to 'script-beta')
-rw-r--r-- | script-beta/parser/guide.lua | 2 | ||||
-rw-r--r-- | script-beta/vm/getInfer.lua | 609 |
2 files changed, 1 insertions, 610 deletions
diff --git a/script-beta/parser/guide.lua b/script-beta/parser/guide.lua index f74dc56c..4a627217 100644 --- a/script-beta/parser/guide.lua +++ b/script-beta/parser/guide.lua @@ -2349,7 +2349,7 @@ function m.inferCheckBinary(status, source) elseif op.type == '^' then local v1 = m.getInferLiteral(status, source[1], 'integer') or m.getInferLiteral(status, source[1], 'number') - local v2 = m.getInferLiteral(source[2], 'integer') + local v2 = m.getInferLiteral(status, source[2], 'integer') or m.getInferLiteral(status, source[2], 'number') local v if v1 and v2 then diff --git a/script-beta/vm/getInfer.lua b/script-beta/vm/getInfer.lua index 3357b912..7eb65df4 100644 --- a/script-beta/vm/getInfer.lua +++ b/script-beta/vm/getInfer.lua @@ -1,620 +1,11 @@ local vm = require 'vm.vm' -local util = require 'utility' local guide = require 'parser.guide' -local library = require 'library' -local select = select - -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 == 'integer' then - return alloc { - type = 'integer', - source = source, - } - elseif source.type == 'table' then - return alloc { - type = 'table', - source = source, - } - elseif source.type == 'function' then - return alloc { - type = 'function', - source = source, - } - elseif source.type == '...' then - return alloc { - type = '...', - source = source, - } - end -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 inferByDef(results, source) - local defs = vm.getDefs(source) - for _, src in ipairs(defs) do - local tp = vm.inferValue(src, false) - if tp then - merge(results, tp) - end - end -end - -local function checkLibraryTypes(source) - if type(source.type) ~= 'table' then - return nil - end - local results = {} - for i = 1, #source.type do - insert(results, { - type = source.type[i], - source = source, - }) - end - return results -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 = lib, - } -end - -local function checkSpecialReturn(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.special == 'require' then - local modName = call.args[1] - if modName and modName.type == 'string' then - lib = library.library[modName[1]] - if lib then - return alloc { - type = lib.type, - value = lib.value, - source = lib, - } - end - end - end - return nil -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 - if not rtn.type then - return nil - end - if rtn.type == '...' or rtn.type == 'any' then - return - end - return alloc { - type = rtn.type, - value = rtn.value, - source = rtn, - } -end - -local function inferByLibraryArg(results, 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 not arg.type then - return - end - if arg.type == '...' or arg.type == 'any' then - return - end - return insert(results, { - type = arg.type, - value = arg.value, - source = arg, - }) -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 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 - -- 会受顺序影响,不检查了 - --if hasTypeInResults(results, 'string') - --or hasTypeInResults(results, 'integer') then - -- return - --end - insert(results, { - type = 'string', - source = source - }) - insert(results, { - type = 'table', - source = source - }) - elseif op.type == '~' then - insert(results, { - type = 'integer', - source = source - }) - elseif op.type == '-' then - insert(results, { - type = 'number', - source = 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 = 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 = source - }) - elseif op.type == '..' then - insert(results, { - type = 'string', - source = source - }) - end -end - -local function inferBySetOfLocal(results, source) - if source.ref then - for i = 1, math.min(#source.ref, 100) do - local ref = source.ref[i] - if ref.type == 'setlocal' then - break - end - merge(results, vm.getInfers(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 - merge(results, vm.getInfers(source.node)) - end -end - -local function mergeFunctionReturns(results, source, index) - local returns = source.returns - if not returns then - return - end - for i = 1, #returns do - local rtn = returns[i] - if rtn[index] then - merge(results, vm.getInfers(rtn[index])) - end - end -end - -local function inferByCallReturn(results, source) - if source.type ~= 'select' then - return - end - if not source.vararg or source.vararg.type ~= 'call' then - return - end - local node = source.vararg.node - local nodeValues = vm.getInfers(node) - if not nodeValues then - return - end - local index = source.index - for i = 1, #nodeValues do - local value = nodeValues[i] - local src = value.source - if src.type == 'function' then - mergeFunctionReturns(results, src, index) - end - end -end - -local function inferByPCallReturn(results, source) - if source.type ~= 'select' then - return - end - local call = source.vararg - if not call or call.type ~= 'call' then - return - end - local node = call.node - local lib = vm.getLibrary(node) - if not lib then - return - end - local func, index - if lib.name == 'pcall' then - func = call.args[1] - index = source.index - 1 - elseif lib.name == 'xpcall' then - func = call.args[1] - index = source.index - 2 - else - return - end - local funcValues = vm.getInfers(func) - if not funcValues then - return - end - for i = 1, #funcValues do - local value = funcValues[i] - local src = value.source - if src.type == 'function' then - mergeFunctionReturns(results, src, index) - end - end -end - -function vm.inferValue(source, infer) - source = guide.getObjectValue(source) or source - local results = checkLiteral(source) - or checkUnary(source) - or checkBinary(source) - or checkLibraryTypes(source) - or checkLibrary(source) - or checkSpecialReturn(source) - or checkLibraryReturn(source) - if results then - return results - end - if not infer then - return - end - - results = {} - inferByLibraryArg(results, source) - inferByDef(results, source) - inferBySet(results, source) - inferByCall(results, source) - inferByGetTable(results, source) - inferByUnary(results, source) - inferByBinary(results, source) - inferByCallReturn(results, source) - inferByPCallReturn(results, source) - - if #results == 0 then - return nil - end - - return results -end - -function vm.checkTrue(source) - local values = vm.getInfers(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.getInfers(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.getInfers(a) - local valuesB = vm.getInfers(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 infers = vm.getInfers(source) - if not infers then - return false - end for i = 1, #infers do local infer = infers[i] if infer.type == type then |