diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2019-11-19 21:10:55 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2019-11-19 21:10:55 +0800 |
commit | 3958723467b8ddb62e471c01c1bb38950ec3c28f (patch) | |
tree | 08dd3a8bdaf87a230327b8e0ddd09343bb0ed058 /server-beta | |
parent | 5d7bcc1fabcc97afd1151e3d49a22aedb0832659 (diff) | |
download | lua-language-server-3958723467b8ddb62e471c01c1bb38950ec3c28f.zip |
暂存
Diffstat (limited to 'server-beta')
-rw-r--r-- | server-beta/src/await.lua | 11 | ||||
-rw-r--r-- | server-beta/src/core/diagnostics/init.lua | 2 | ||||
-rw-r--r-- | server-beta/src/core/highlight.lua | 3 | ||||
-rw-r--r-- | server-beta/src/searcher/eachRef.lua | 15 | ||||
-rw-r--r-- | server-beta/src/searcher/getValue.lua | 454 | ||||
-rw-r--r-- | server-beta/src/searcher/init.lua | 3 | ||||
-rw-r--r-- | server-beta/src/searcher/isTrue.lua | 52 | ||||
-rw-r--r-- | server-beta/src/searcher/searcher.lua | 6 | ||||
-rw-r--r-- | server-beta/src/searcher/typeInference.lua | 253 | ||||
-rw-r--r-- | server-beta/test/type_inference/init.lua | 4 |
10 files changed, 486 insertions, 317 deletions
diff --git a/server-beta/src/await.lua b/server-beta/src/await.lua index c744e1be..5a960e96 100644 --- a/server-beta/src/await.lua +++ b/server-beta/src/await.lua @@ -31,18 +31,23 @@ end --- 休眠一段时间 ---@param time number -function m.sleep(time, ...) +function m.sleep(time, getVersion) if not coroutine.isyieldable() then if m.errorHandle then m.errorHandle(debug.traceback('Cannot yield')) end return end + local version = getVersion and getVersion() local co = coroutine.running() timer.wait(time, function () - return m.checkResult(co, coroutine.resume(co)) + if version == (getVersion and getVersion()) then + return m.checkResult(co, coroutine.resume(co)) + else + coroutine.close(co) + end end) - return coroutine.yield(...) + return coroutine.yield(getVersion) end --- 等待直到唤醒 diff --git a/server-beta/src/core/diagnostics/init.lua b/server-beta/src/core/diagnostics/init.lua index 2724387d..c5abff25 100644 --- a/server-beta/src/core/diagnostics/init.lua +++ b/server-beta/src/core/diagnostics/init.lua @@ -16,7 +16,7 @@ local function check(uri, name, level, results) results[#results+1] = result end, name) local passed = os.clock() - clock - if passed >= 0.1 then + if passed >= 0.5 then log.warn(('Diagnostics [%s] @ [%s] takes [%.3f] sec!'):format(name, uri, passed)) await.delay() end diff --git a/server-beta/src/core/highlight.lua b/server-beta/src/core/highlight.lua index 9aaf62b8..7ae5333a 100644 --- a/server-beta/src/core/highlight.lua +++ b/server-beta/src/core/highlight.lua @@ -47,6 +47,9 @@ end local function ofIndex(source, uri, callback) local parent = source.parent + if not parent then + return + end if parent.type == 'setindex' or parent.type == 'getindex' or parent.type == 'tableindex' then diff --git a/server-beta/src/searcher/eachRef.lua b/server-beta/src/searcher/eachRef.lua index 9a3fd9f0..d8e3bd6f 100644 --- a/server-beta/src/searcher/eachRef.lua +++ b/server-beta/src/searcher/eachRef.lua @@ -449,6 +449,21 @@ local function eachRef(source, callback) asArg(source, callback) end +--- 判断2个对象是否拥有相同的引用 +function searcher.isSameRef(a, b) + local cache = searcher.cache.eachRef[a] + if cache then + -- 相同引用的source共享同一份cache + return cache == searcher.cache.eachRef[b] + else + return searcher.eachRef(a, function (info) + if info.source == b then + return true + end + end) or false + end +end + --- 获取所有的引用 function searcher.eachRef(source, callback) local cache = searcher.cache.eachRef[source] diff --git a/server-beta/src/searcher/getValue.lua b/server-beta/src/searcher/getValue.lua new file mode 100644 index 00000000..ae28b212 --- /dev/null +++ b/server-beta/src/searcher/getValue.lua @@ -0,0 +1,454 @@ +local searcher = require 'searcher.searcher' +local guide = require 'parser.guide' +local config = require 'config' + +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(a, b) + local t = {} + for i = 1, #a do + t[#t+1] = a[i] + end + for i = 1, #b do + t[#t+1] = b[i] + end + return t +end + +local function checkLiteral(source) + if source.type == 'string' then + return { + type = 'string', + value = source[1], + source = source, + } + elseif source.type == 'nil' then + return { + type = 'nil', + value = NIL, + source = source, + } + elseif source.type == 'boolean' then + return { + type = 'boolean', + value = source[1], + source = source, + } + elseif source.type == 'number' then + if math.type(source[1]) == 'integer' then + return { + type = 'integer', + value = source[1], + source = source, + } + else + return { + type = 'number', + value = source[1], + source = source, + } + end + elseif source.type == 'table' then + return { + type = 'table', + source = source, + } + elseif source.type == 'function' then + return { + 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 isTrue = searcher.isTrue(source[1]) + local value = nil + if isTrue == true then + value = false + elseif isTrue == false then + value = true + end + return { + type = 'boolean', + value = value, + source = source, + } + elseif op.type == '#' then + return { + type = 'integer', + source = source, + } + elseif op.type == '~' then + local l = searcher.getLiteral(source[1], 'integer') + return { + type = 'integer', + value = l and ~l or nil, + source = source, + } + elseif op.type == '-' then + local v = searcher.getLiteral(source[1], 'integer') + if v then + return { + type = 'integer', + value = - v, + source = source, + } + end + v = searcher.getLiteral(source[1], 'number') + return { + 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 = searcher.checkTrue(source[1]) + if isTrue == true then + return searcher.getValue(source[2]) + elseif isTrue == false then + return searcher.getValue(source[1]) + else + return merge( + searcher.getValue(source[1]), + searcher.getValue(source[2]) + ) + end + elseif op.type == 'or' then + local isTrue = searcher.checkTrue(source[1]) + if isTrue == true then + return searcher.getValue(source[1]) + elseif isTrue == false then + return searcher.getValue(source[2]) + else + return merge( + searcher.getValue(source[1]), + searcher.getValue(source[2]) + ) + end + elseif op.type == '==' then + local value = searcher.isSameValue(source[1], source[2]) + if value ~= nil then + return { + type = 'boolean', + value = value, + source = source, + } + end + local isSame = searcher.isSameRef(source[1], source[2]) + if isSame == true then + value = true + else + value = nil + end + return { + type = 'boolean', + value = value, + source = source, + } + elseif op.type == '~=' then + local value = searcher.isSameValue(source[1], source[2]) + if value ~= nil then + return { + type = 'boolean', + value = not value, + source = source, + } + end + local isSame = searcher.isSameRef(source[1], source[2]) + if isSame == true then + value = false + else + value = nil + end + return { + type = 'boolean', + value = value, + source = source, + } + elseif op.type == '<=' then + elseif op.type == '>=' + or op.type == '<' + or op.type == '>' then + return 'boolean' + end + if op.type == '|' + or op.type == '~' + or op.type == '&' + or op.type == '<<' + or op.type == '>>' then + return 'integer' + end + if op.type == '..' then + return 'string' + end + if op.type == '^' + or op.type == '/' then + return 'number' + end + -- 其他数学运算根据2侧的值决定,当2侧的值均为整数时返回整数 + if op.type == '+' + or op.type == '-' + or op.type == '*' + or op.type == '%' + or op.type == '//' then + if hasType('integer', searcher.getValue(source[1])) + and hasType('integer', searcher.getValue(source[2])) then + return 'integer' + else + return 'number' + end + end +end + +local function checkValue(source) + if source.value then + return searcher.getValue(source.value) + end +end + +local function checkCall(result, source) + if not source.parent then + return + end + if source.parent.type ~= 'call' then + return + end + if source.parent.node == source then + merge(result, 'function') + return + end +end + +local function checkNext(result, source) + 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 + merge(result, 'table') + end +end + +local function checkDef(result, source) + searcher.eachDef(source, function (info) + local src = info.source + local tp = searcher.getValue(src) + if tp then + merge(result, tp) + end + end) +end + +local function typeInference(source) + local tp = checkLiteral(source) + or checkValue(source) + or checkUnary(source) + or checkBinary(source) + if tp then + return tp + end + + local result = {} + + checkCall(result, source) + checkNext(result, source) + checkDef(result, source) + + return dump(result) +end + +local function getValue(source) + local result = checkLiteral(source) + if result then + return { result } + end + local results = checkValue(source) + or checkUnary(source) + or checkBinary(source) + if results then + return results + end +end + +function searcher.checkTrue(source) + local values = searcher.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 searcher.eachValueType(source, type, callback) + local values = searcher.getValue(source) + if not values then + return + end + for i = 1, #values do + local v = values[i] + if v.type == type then + local res = callback(v) + if res ~= nil then + return res + end + end + end +end + +--- 获取特定类型的字面量值 +function searcher.getLiteral(source, type) + local values = searcher.getValue(source) + if not values then + return nil + end + for i = 1, #values do + local v = values[i] + if v.type == type and v.value ~= nil then + return v.value + end + end + return nil +end + +function searcher.isSameValue(a, b) + local valuesA = searcher.getValue(a) + local valuesB = searcher.getValue(b) + if valuesA == valuesB and valuesA ~= nil 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 searcher.typeInference(source) + local values = searcher.getValue(source) + if not values then + return 'any' + end + local types = {} + for _ = 1, #values do + local tp = values.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 searcher.getValue(source) + if not source then + return + end + local cache = searcher.cache.getValue[source] + if cache ~= nil then + return cache + end + local unlock = searcher.lock('getValue', source) + if not unlock then + return + end + cache = getValue(source) or false + searcher.cache.getValue[source] = cache + unlock() + return cache +end diff --git a/server-beta/src/searcher/init.lua b/server-beta/src/searcher/init.lua index 1734c2ea..65753ccd 100644 --- a/server-beta/src/searcher/init.lua +++ b/server-beta/src/searcher/init.lua @@ -6,6 +6,5 @@ require 'searcher.getGlobals' require 'searcher.getLinks' require 'searcher.getGlobal' require 'searcher.getLibrary' -require 'searcher.typeInference' -require 'searcher.isTrue' +require 'searcher.getValue' return searcher diff --git a/server-beta/src/searcher/isTrue.lua b/server-beta/src/searcher/isTrue.lua deleted file mode 100644 index ba825d43..00000000 --- a/server-beta/src/searcher/isTrue.lua +++ /dev/null @@ -1,52 +0,0 @@ -local searcher = require 'searcher.searcher' - -local function checkLiteral(source) - if source.type == 'boolean' then - if source[1] == true then - return 'true' - else - return 'false' - end - end - if source.type == 'string' then - return 'true' - end - if source.type == 'number' then - return 'true' - end - if source.type == 'table' then - return 'true' - end - if source.type == 'function' then - return 'true' - end - if source.type == 'nil' then - return 'false' - end -end - -local function isTrue(source) - local res = checkLiteral(source) - if res then - return res - end - return 'unknown' -end - -function searcher.isTrue(source) - if not source then - return - end - local cache = searcher.cache.isTrue[source] - if cache ~= nil then - return cache - end - local unlock = searcher.lock('isTrue', source) - if not unlock then - return - end - cache = isTrue(source) or false - searcher.cache.isTrue[source] = cache - unlock() - return cache -end diff --git a/server-beta/src/searcher/searcher.lua b/server-beta/src/searcher/searcher.lua index 3e12430b..e47e8c54 100644 --- a/server-beta/src/searcher/searcher.lua +++ b/server-beta/src/searcher/searcher.lua @@ -64,8 +64,7 @@ function m.refreshCache() getGlobal = {}, specialName = {}, getLibrary = {}, - typeInfer = {}, - isTrue = {}, + getValue = {}, specials = nil, } m.locked = { @@ -74,8 +73,7 @@ function m.refreshCache() getGlobals = {}, getLinks = {}, getLibrary = {}, - typeInfer = {}, - isTrue = {}, + getValue = {}, } m.cacheTracker[m.cache] = true end diff --git a/server-beta/src/searcher/typeInference.lua b/server-beta/src/searcher/typeInference.lua deleted file mode 100644 index 56f4cc98..00000000 --- a/server-beta/src/searcher/typeInference.lua +++ /dev/null @@ -1,253 +0,0 @@ -local searcher = require 'searcher.searcher' -local guide = require 'parser.guide' -local config = require 'config' - -local typeSort = { - ['boolean'] = 1, - ['string'] = 2, - ['integer'] = 3, - ['number'] = 4, - ['table'] = 5, - ['function'] = 6, - ['nil'] = math.maxinteger, -} - -local function merge(result, tp) - if result[tp] then - return - end - if tp:find('|', 1, true) then - for sub in tp:gmatch '[^|]+' do - if not result[sub] then - result[sub] = true - result[#result+1] = sub - end - end - else - result[tp] = true - result[#result+1] = tp - end -end - -local function hasType(tp, target) - if not target then - return false - end - for sub in target:gmatch '[^|]+' do - if sub == tp then - return true - end - end - return false -end - -local function dump(result) - if #result <= 1 then - return result[1] - end - table.sort(result, 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(result, '|') -end - -local function checkLiteral(source) - if source.type == 'string' then - return 'string' - elseif source.type == 'nil' then - return 'nil' - elseif source.type == 'boolean' then - return 'boolean' - elseif source.type == 'number' then - if math.type(source[1]) == 'integer' then - return 'integer' - else - return 'number' - end - elseif source.type == 'table' then - return 'table' - elseif source.type == 'function' then - return 'function' - end -end - -local function checkUnary(source) - if source.type ~= 'unary' then - return - end - local op = source.op - if op.type == 'not' then - return 'boolean' - elseif op.type == '#' - or op.type == '~' then - return 'integer' - elseif op.type == '-' then - if hasType('integer', searcher.typeInference(source[1])) then - return 'integer' - else - return 'number' - end - end -end - -local function checkBinary(source) - if source.type ~= 'binary' then - return - end - local op = source.op - if op.type == 'and' then - local isTrue = searcher.isTrue(source[1]) - if isTrue == 'true' then - return searcher.typeInference(source[2]) - elseif isTrue == 'false' then - return searcher.typeInference(source[1]) - else - local result = {} - merge(result, searcher.typeInference(source[1])) - merge(result, searcher.typeInference(source[2])) - return dump(result) - end - end - if op.type == 'or' then - local isTrue = searcher.isTrue(source[1]) - if isTrue == 'true' then - return searcher.typeInference(source[1]) - elseif isTrue == 'false' then - return searcher.typeInference(source[2]) - else - local result = {} - merge(result, searcher.typeInference(source[1])) - merge(result, searcher.typeInference(source[2])) - return dump(result) - end - end - if op.type == '==' - or op.type == '~=' - or op.type == '<=' - or op.type == '>=' - or op.type == '<' - or op.type == '>' then - return 'boolean' - end - if op.type == '|' - or op.type == '~' - or op.type == '&' - or op.type == '<<' - or op.type == '>>' then - return 'integer' - end - if op.type == '..' then - return 'string' - end - if op.type == '^' - or op.type == '/' then - return 'number' - end - -- 其他数学运算根据2侧的值决定,当2侧的值均为整数时返回整数 - if op.type == '+' - or op.type == '-' - or op.type == '*' - or op.type == '%' - or op.type == '//' then - if hasType('integer', searcher.typeInference(source[1])) - and hasType('integer', searcher.typeInference(source[2])) then - return 'integer' - else - return 'number' - end - end -end - -local function checkValue(source) - if source.value then - return searcher.typeInference(source.value) - end -end - -local function checkCall(result, source) - if not source.parent then - return - end - if source.parent.type ~= 'call' then - return - end - if source.parent.node == source then - merge(result, 'function') - return - end -end - -local function checkNext(result, source) - 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 - merge(result, 'table') - end -end - -local function checkDef(result, source) - searcher.eachDef(source, function (info) - local src = info.source - local tp = searcher.typeInference(src) - if tp then - merge(result, tp) - end - end) -end - -local function typeInference(source) - local tp = checkLiteral(source) - or checkValue(source) - or checkUnary(source) - or checkBinary(source) - if tp then - return tp - end - - local result = {} - - checkCall(result, source) - checkNext(result, source) - checkDef(result, source) - - return dump(result) -end - -function searcher.typeInference(source) - if not source then - return - end - local cache = searcher.cache.typeInfer[source] - if cache ~= nil then - return cache - end - local unlock = searcher.lock('typeInfer', source) - if not unlock then - return - end - cache = typeInference(source) or false - searcher.cache.typeInfer[source] = cache - unlock() - return cache -end diff --git a/server-beta/test/type_inference/init.lua b/server-beta/test/type_inference/init.lua index 4a9f30aa..fd98e544 100644 --- a/server-beta/test/type_inference/init.lua +++ b/server-beta/test/type_inference/init.lua @@ -30,7 +30,7 @@ function TEST(wanted) files.setText('', newScript) local source = getSource(pos) assert(source) - local result = searcher.typeInference(source) or 'any' + local result = searcher.getValue(source) or 'any' assert(wanted == result) end end @@ -113,7 +113,7 @@ TEST 'integer' [[ <?x?> = ~ y ]] -TEST 'number' [[ +TEST 'integer' [[ local a = true local b = 1 <?x?> = a and b |