diff options
-rw-r--r-- | server/src/matcher/implementation.lua | 433 | ||||
-rw-r--r-- | server/src/matcher/init.lua | 5 | ||||
-rw-r--r-- | server/src/method/initialize.lua | 2 | ||||
-rw-r--r-- | server/src/method/textDocument/implementation.lua | 29 | ||||
-rw-r--r-- | server/test/implementation/arg.lua | 23 | ||||
-rw-r--r-- | server/test/implementation/bug.lua | 15 | ||||
-rw-r--r-- | server/test/implementation/function.lua | 24 | ||||
-rw-r--r-- | server/test/implementation/if.lua | 106 | ||||
-rw-r--r-- | server/test/implementation/init.lua | 59 | ||||
-rw-r--r-- | server/test/implementation/local.lua | 191 | ||||
-rw-r--r-- | server/test/implementation/set.lua | 31 | ||||
-rw-r--r-- | server/test/implementation/table.lua | 6 | ||||
-rw-r--r-- | server/test/main.lua | 1 |
13 files changed, 100 insertions, 825 deletions
diff --git a/server/src/matcher/implementation.lua b/server/src/matcher/implementation.lua index bd28ee3a..bf509ff3 100644 --- a/server/src/matcher/implementation.lua +++ b/server/src/matcher/implementation.lua @@ -1,377 +1,112 @@ -local parser = require 'parser' -local pos -local defs = {} -local scopes -local logics -local result -local namePos -local colonPos - -local DUMMY_TABLE = {} - -local function logicPush() - logics[#logics+1] = 0 -end - -local function logicPop() - logics[#logics] = nil -end - -local function logicAdd() - logics[#logics] = logics[#logics] + 1 -end - -local function logicGet() - local list = {} - for i = 1, #logics do - list[i] = logics[i] - end - return list +local function isContainPos(obj, pos) + return obj.start <= pos and obj.finish + 1 >= pos end -local function scopeInit() - scopes = {{}} -end - -local function scopeGet(name) - for i = #scopes, 1, -1 do - local scope = scopes[i] - local list = scope[name] - if list then - return list +local function findResult(results, pos) + for _, var in ipairs(results.vars) do + for _, info in ipairs(var) do + if isContainPos(info.source, pos) then + return { + type = 'var', + var = var, + } + end end end - return nil -end - -local function scopeSet(obj) - obj.logic = logicGet() - local name = obj[1] - local scope = scopes[#scopes] - local list = scope[name] - if list then - list[#list+1] = obj - else - scope[name] = {obj} - end -end - -local function scopePush() - scopes[#scopes+1] = {} -end - -local function scopePop() - scopes[#scopes] = nil -end - -local function globalSet(obj) - obj.logic = logicGet() - local name = obj[1] - for i = #scopes, 1, -1 do - local scope = scopes[i] - local list = scope[name] - if list then - list[#list+1] = obj - return + for _, dots in ipairs(results.dots) do + for _, info in ipairs(dots) do + if isContainPos(info.source, pos) then + return { + type = 'dots', + dots = dots, + } + end end end - local scope = scopes[1] - scope[name] = {obj} -end - -local function sameLogic(cur, target) - for i = 1, #cur do - if target[i] == nil then - break - end - if cur[i] ~= target[i] then - return false + for _, label in ipairs(results.labels) do + for _, info in ipairs(label) do + if isContainPos(info.source, pos) then + return { + type = 'label', + label = label, + } + end end end - return true + return nil end -local function mustCovered(results, target) - for _, result in ipairs(results) do - local logic = result.logic - if #logic == #target then - local isSame = true - for i = 1, #logic do - if logic[i] ~= target[i] then - isSame = false +local function tryMeta(var) + local keys = {} + repeat + if var.childs.meta then + local metavar = var.childs.meta + for i = #keys, 1, -1 do + local key = keys[i] + metavar = metavar.childs[key] + if not metavar then + return nil end end - if isSame then - return true - end + return metavar end - end - return false + keys[#keys+1] = var.key + var = var.parent + until not var + return nil end -local function checkImplementation(name, p) - if result ~= nil then - return - end - if pos < p or pos > p + #name then - return - end - local list = scopeGet(name) - if list then - local logic = logicGet() - result = {} - for i = #list, 1, -1 do - local obj = list[i] - local name, start, finish = obj[1], obj[2], obj[3] - if not finish then - finish = start + #name - 1 - end - -- 如果不在同一个分支里,则跳过 - if not sameLogic(logic, obj.logic) then - goto CONTINUE - end - -- 如果该分支已经有确定值,则跳过 - if mustCovered(result, obj.logic) then - goto CONTINUE +local function parseResult(result) + local positions = {} + local tp = result.type + if tp == 'var' then + local var = result.var + if var.type == 'local' then + local source = var.source + if not source then + return false end - result[#result+1] = {start, finish, logic = obj.logic} - -- 如果分支长度比自己小,则一定是确信值,不用再继续找了 - if #obj.logic <= #logic then - break - end - ::CONTINUE:: - end - else - result = false - end -end - -function defs.NamePos(p) - namePos = p -end - -function defs.Name(str) - checkImplementation(str, namePos) - return {str, namePos, type = 'name'} -end - -function defs.DOTSPos(p) - namePos = p -end - -function defs.DOTS(str) - checkImplementation(str, namePos) - return {str, namePos, type = 'name'} -end - -function defs.COLONPos(p) - colonPos = p -end - -function defs.ColonName(name) - name.colon = colonPos - return name -end - -function defs.LocalVar(names) - for _, name in ipairs(names) do - scopeSet(name) - end -end - -function defs.LocalSet(names) - for _, name in ipairs(names) do - scopeSet(name) - end -end - -function defs.Set(simples) - for _, simple in ipairs(simples) do - if simple.type == 'simple' and #simple == 1 then - local obj = simple[1] - local name = obj[1] - globalSet(obj) - end - end -end - -function defs.Simple(...) - return { type = 'simple', ... } -end - -function defs.ArgList(...) - if ... == '' then - return DUMMY_TABLE - end - return { type = 'list', ... } -end - -function defs.FuncName(...) - if ... == '' then - return DUMMY_TABLE - end - return { type = 'simple', ... } -end - -function defs.FunctionDef(simple, args) - if #simple == 1 then - globalSet(simple[1]) - end - scopePush() - -- 判断隐藏的局部变量self - if #simple > 0 then - local name = simple[#simple] - if name.colon then - scopeSet {'self', name.colon, name.colon, type = 'name'} - end - end - for _, arg in ipairs(args) do - if arg.type == 'simple' and #arg == 1 then - local name = arg[1] - scopeSet(name) + positions[1] = {source.start, source.finish} end - if arg.type == 'name' then - scopeSet(arg) + for _, info in ipairs(var) do + if info.type == 'set' then + positions[#positions+1] = {info.source.start, info.source.finish} + end end - end -end - -function defs.FunctionLoc(simple, args) - if #simple == 1 then - scopeSet(simple[1]) - end - scopePush() - -- 判断隐藏的局部变量self - if #simple > 0 then - local name = simple[#simple] - if name.colon then - scopeSet {'self', name.colon, name.colon, type = 'name'} + local metavar = tryMeta(var) + if metavar then + for _, info in ipairs(metavar) do + if info.type == 'set' then + positions[#positions+1] = {info.source.start, info.source.finish} + end + end end - end - for _, arg in ipairs(args) do - if arg.type == 'simple' and #arg == 1 then - local name = arg[1] - scopeSet(name) + elseif tp == 'dots' then + local dots = result.dots + for _, info in ipairs(dots) do + if info.type == 'local' then + positions[#positions+1] = {info.source.start, info.source.finish} + end end - if arg.type == 'name' then - scopeSet(arg) + elseif tp == 'label' then + local label = result.label + for _, info in ipairs(label) do + if info.type == 'set' then + positions[#positions+1] = {info.source.start, info.source.finish} + end end + else + error('Unknow result type:' .. result.type) end + return positions end -function defs.Function() - scopePop() -end - -function defs.DoDef() - scopePush() -end - -function defs.Do() - scopePop() -end - -function defs.IfDef() - logicPush() - scopePush() -end - -function defs.If() - scopePop() -end - -function defs.ElseIfDef() - logicAdd() - scopePush() -end - -function defs.ElseIf() - scopePop() -end - -function defs.ElseDef() - logicAdd() - scopePush() -end - -function defs.Else() - scopePop() -end - -function defs.EndIf() - logicPop() -end - -function defs.LoopDef(name) - logicPush() - scopePush() - scopeSet(name) -end - -function defs.Loop() - scopePop() - logicPop() -end - -function defs.LoopStart(name, exp) - return name -end - -function defs.NameList(...) - return { type = 'list', ... } -end - -function defs.SimpleList(...) - return { type = 'list', ... } -end - -function defs.InDef(names) - logicPush() - scopePush() - for _, name in ipairs(names) do - scopeSet(name) - end -end - -function defs.In() - scopePop() - logicPop() -end - -function defs.WhileDef() - logicPush() - scopePush() -end - -function defs.While() - scopePop() - logicPop() -end - -function defs.RepeatDef() - logicPush() - scopePush() -end - -function defs.Until() - scopePop() - logicPop() -end - -return function (buf, pos_) - pos = pos_ - result = nil - logics = {} - scopeInit() - - local suc, err = parser.grammar(buf, 'Lua', defs) - if not suc then - return false, '语法错误', err - end - +return function (results, pos) + local result = findResult(results, pos) if not result then - return false, 'No word' + return nil end - return true, result + local positions = parseResult(result) + return positions end diff --git a/server/src/matcher/init.lua b/server/src/matcher/init.lua index 896e5ed7..14a95ed2 100644 --- a/server/src/matcher/init.lua +++ b/server/src/matcher/init.lua @@ -1,6 +1,7 @@ local api = { - definition = require 'matcher.definition', - compile = require 'matcher.compile', + definition = require 'matcher.definition', + implementation = require 'matcher.implementation', + compile = require 'matcher.compile', } return api diff --git a/server/src/method/initialize.lua b/server/src/method/initialize.lua index ea5bb3c4..866ded66 100644 --- a/server/src/method/initialize.lua +++ b/server/src/method/initialize.lua @@ -5,7 +5,7 @@ return function (lsp, data) -- 支持“转到定义” definitionProvider = true, -- 支持“转到实现” - --implementationProvider = true, + implementationProvider = true, -- 文本同步方式 textDocumentSync = { -- 打开关闭文本时通知 diff --git a/server/src/method/textDocument/implementation.lua b/server/src/method/textDocument/implementation.lua index f035c749..5ae22c6b 100644 --- a/server/src/method/textDocument/implementation.lua +++ b/server/src/method/textDocument/implementation.lua @@ -2,29 +2,24 @@ local parser = require 'parser' local matcher = require 'matcher' return function (lsp, params) + local start_clock = os.clock() local uri = params.textDocument.uri - local text = lsp:loadText(uri) - if not text then - return nil, 'Cannot find file: ' .. uri + local results, lines = lsp:loadText(uri) + if not results then + return {} end - local start_clock = os.clock() -- lua是从1开始的,因此都要+1 - local pos = parser.calcline.position_utf8(text, params.position.line + 1, params.position.character + 1) - local suc, results, info = matcher.implementation(text, pos) - if not suc then - if info then - log.debug(results, uri) - info.lua = nil - log.debug(table.dump(info)) - end + local position = lines:position(params.position.line + 1, params.position.character + 1, 'utf8') + local positions = matcher.implementation(results, position) + if not positions then return {} end local locations = {} - for i, result in ipairs(results) do - local start, finish = result[1], result[2] - local start_row, start_col = parser.calcline.rowcol_utf8(text, start) - local finish_row, finish_col = parser.calcline.rowcol_utf8(text, finish) + for i, position in ipairs(positions) do + local start, finish = position[1], position[2] + local start_row, start_col = lines:rowcol(start, 'utf8') + local finish_row, finish_col = lines:rowcol(finish, 'utf8') locations[i] = { uri = uri, range = { @@ -44,7 +39,7 @@ return function (lsp, params) local response = locations local passed_clock = os.clock() - start_clock if passed_clock >= 0.01 then - log.warn(('[Goto Implementation] takes [%.3f] sec, size [%s] bits.'):format(passed_clock, #text)) + log.warn(('[Goto Implementation] takes [%.3f] sec, size [%s] bits.'):format(passed_clock, #lines.buf)) end return response diff --git a/server/test/implementation/arg.lua b/server/test/implementation/arg.lua deleted file mode 100644 index 2004d666..00000000 --- a/server/test/implementation/arg.lua +++ /dev/null @@ -1,23 +0,0 @@ -TEST [[ -local function xx (<!xx!>) - <?xx?> = 1 -end -]] - -TEST [[ -local function x (x, <!...!>) - x = <?...?> -end -]] - -TEST [[ -function mt<!:!>x() - <?self?> = 1 -end -]] - -TEST [[ -function mt:x(<!self!>) - <?self?> = 1 -end -]] diff --git a/server/test/implementation/bug.lua b/server/test/implementation/bug.lua deleted file mode 100644 index b0e890ca..00000000 --- a/server/test/implementation/bug.lua +++ /dev/null @@ -1,15 +0,0 @@ -TEST [[ -local <!x!> -function _(x) -end -function _() - <?x?> -end -]] - -TEST [[ -function _(<!x!>) - do return end - <?x?> = 1 -end -]] diff --git a/server/test/implementation/function.lua b/server/test/implementation/function.lua deleted file mode 100644 index 90b75da8..00000000 --- a/server/test/implementation/function.lua +++ /dev/null @@ -1,24 +0,0 @@ - -TEST [[ -function <!x!> () end -<?x?> = 1 -]] - -TEST [[ -local function <!x!> () end -<?x?> = 1 -]] - -TEST [[ -local x -local function <!x!> () - <?x?> = 1 -end -]] - -TEST [[ -local x -function <!x!>() -end -<?x?> = 1 -]] diff --git a/server/test/implementation/if.lua b/server/test/implementation/if.lua deleted file mode 100644 index 0da8be1a..00000000 --- a/server/test/implementation/if.lua +++ /dev/null @@ -1,106 +0,0 @@ -TEST [[ -<!x!> = 1 -if 1 then - x = 1 -else - <?x?> = 1 -end -]] - -TEST [[ -<!x!> = 1 -if 1 then - <!x!> = 1 -else - <!x!> = 1 -end -<?x?> = 1 -]] - -TEST [[ -<!x!> = 1 -if 1 then - <!x!> = 1 -elseif 1 then - <!x!> = 1 -else - <!x!> = 1 -end -<?x?> = 1 -]] - -TEST [[ -<!x!> = 1 -if 1 then - <!x!> = 1 -elseif 1 then - <!x!> = 1 - if 1 then - <!x!> = 1 - end -else - <!x!> = 1 -end -<?x?> = 1 -]] - -TEST [[ -<!x!> = 1 -while true do - <!x!> = 1 -end -<?x?> = 1 -]] - -TEST [[ -<!x!> = 1 -for _ in _ do - <!x!> = 1 -end -<?x?> = 1 -]] - -TEST [[ -<!x!> = 1 -for _ = 1, 1 do - <!x!> = 1 -end -<?x?> = 1 -]] - -TEST [[ -x3 = 1 -repeat - <!x3!> = 1 -until <?x3?> == 1 -]] - -TEST [[ -<!x!> = 1 -repeat - <!x!> = 1 -until 1 -<?x?> = 1 -]] - -TEST [[ -<!x!> = 1 -while 1 do - x = 1 - <!x!> = 1 -end -<?x?> = 1 -]] - -TEST [[ -<!x!> = 1 -if 1 then - if 1 then - x = 1 - end -else - if 1 then - <?x?> = 1 - end -end -]] diff --git a/server/test/implementation/init.lua b/server/test/implementation/init.lua deleted file mode 100644 index 94db86fc..00000000 --- a/server/test/implementation/init.lua +++ /dev/null @@ -1,59 +0,0 @@ -local matcher = require 'matcher' -local parser = require 'parser' - -rawset(_G, 'TEST', true) - -local function catch_target(script) - local list = {} - local cur = 1 - while true do - local start, finish = script:find('<!.-!>', cur) - if not start then - break - end - list[#list+1] = { start + 2, finish - 2 } - cur = finish + 1 - end - return list -end - -local function founded(targets, results) - while true do - local target = table.remove(targets) - if not target then - break - end - for i, result in ipairs(results) do - if target[1] == result[1] and target[2] == result[2] then - table.remove(results, i) - goto CONTINUE - end - end - do return false end - ::CONTINUE:: - end - if #results == 0 then - return true - else - return false - end -end - -function TEST(script) - local target = catch_target(script) - local pos = script:find('<?', 1, true) + 2 - local new_script = script:gsub('<[!?]', ' '):gsub('[!?]>', ' ') - local ast, err = parser:ast(new_script) - assert(ast) - local suc, result = matcher.implementation(ast, pos) - assert(suc) - assert(founded(target, result)) -end - -require 'implementation.set' -require 'implementation.local' -require 'implementation.arg' -require 'implementation.function' -require 'implementation.if' ---require 'implementation.table' -require 'implementation.bug' diff --git a/server/test/implementation/local.lua b/server/test/implementation/local.lua deleted file mode 100644 index 7e9b3db0..00000000 --- a/server/test/implementation/local.lua +++ /dev/null @@ -1,191 +0,0 @@ -TEST [[ -local <!x!> -<?x?> = 1 -]] - -TEST [[ -local z, y, <!x!> -<?x?> = 1 -]] - -TEST [[ -local <!x!> = 1 -<?x?> = 1 -]] - -TEST [[ -local z, y, <!x!> = 1 -<?x?> = 1 -]] - -TEST [[ -local x -local <!x!> -<?x?> = 1 -]] - -TEST [[ -local <!x!> -do - <?x?> = 1 -end -]] - -TEST [[ -local <!x!> -do - local x -end -<?x?> = 1 -]] - -TEST [[ -local <!x!> -if <?x?> then - local x -end -]] - -TEST [[ -local <!x2!> -if x2 then - local x2 -elseif <?x2?> then - local x2 -end -]] - -TEST [[ -local <!x!> -if x then - local x -elseif x then - local x -else - local x -end -<?x?> = 1 -]] - -TEST [[ -local <!x!> -if x then - <?x?> = 1 -elseif x then - local x -else - local x -end -]] - -TEST [[ -local <!x!> -for x = 1, 10 do -end -<?x?> = 1 -]] - -TEST [[ -local x -for <!x!> = 1, 10 do - <?x?> = 1 -end -]] - -TEST [[ -local <!x!> -for x in x do -end -<?x?> = 1 -]] - -TEST [[ -local <!x!> -for x in <?x?> do -end -]] - -TEST [[ -local x -for <!x!> in x do - <?x?> = 1 -end -]] - -TEST [[ -local x -for z, y, <!x!> in x do - <?x?> = 1 -end -]] - -TEST [[ -local <!x!> -while <?x?> do -end -]] - -TEST [[ -local <!x!> -while x do - <?x?> = 1 -end -]] - -TEST [[ -local <!x!> -while x do - local x -end -<?x?> = 1 -]] - -TEST [[ -local <!x!> -repeat - <?x?> = 1 -until true -]] - -TEST [[ -local <!x!> -repeat - local x -until true -<?x?> = 1 -]] - -TEST [[ -local <!x!> -repeat -until <?x?> -]] - -TEST [[ -local x -repeat - local <!x!> -until <?x?> -]] - -TEST [[ -local <!x!> -function _() - local x -end -<?x?> = 1 -]] - -TEST [[ -local <!x!> -return function () - <?x?> = 1 -end -]] - -TEST [[ -local <!x!> -local x = function () - <?x?> = 1 -end -]] diff --git a/server/test/implementation/set.lua b/server/test/implementation/set.lua deleted file mode 100644 index 5c4a1a2e..00000000 --- a/server/test/implementation/set.lua +++ /dev/null @@ -1,31 +0,0 @@ -TEST [[ -<!x!> = 1 -<?x?> = 1 -]] - -TEST [[ -global = 1 -do - <!global!> = 2 -end -<?global?> = 3 -]] - -TEST [[ -<!x!> = 1 -do - local x = 1 -end -<?x?> = 1 -]] - -TEST [[ -x = 1 -do - local x = 1 - do - <!x!> = 2 - end - <?x?> = 1 -end -]] diff --git a/server/test/implementation/table.lua b/server/test/implementation/table.lua deleted file mode 100644 index 13a3b555..00000000 --- a/server/test/implementation/table.lua +++ /dev/null @@ -1,6 +0,0 @@ -TEST [[ -local t = { - <!x!> = 1, -} -t.<?x?> = 1 -]] diff --git a/server/test/main.lua b/server/test/main.lua index 089f59b8..58394989 100644 --- a/server/test/main.lua +++ b/server/test/main.lua @@ -21,7 +21,6 @@ local function main() end test 'definition' - --test 'implementation' print('测试完成') end |