summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2018-12-05 16:45:36 +0800
committer最萌小汐 <sumneko@hotmail.com>2018-12-05 16:45:36 +0800
commit34c2d6ac30f9d990d4008f52c6436aae68fb2844 (patch)
treec17f19ebcedc322fb62fe04fc264e2a04c9383d2
parent7f3aa8ed3eba0f07a4bd258407f3eaa038f2ce6f (diff)
downloadlua-language-server-34c2d6ac30f9d990d4008f52c6436aae68fb2844.zip
转到实现
-rw-r--r--server/src/matcher/implementation.lua433
-rw-r--r--server/src/matcher/init.lua5
-rw-r--r--server/src/method/initialize.lua2
-rw-r--r--server/src/method/textDocument/implementation.lua29
-rw-r--r--server/test/implementation/arg.lua23
-rw-r--r--server/test/implementation/bug.lua15
-rw-r--r--server/test/implementation/function.lua24
-rw-r--r--server/test/implementation/if.lua106
-rw-r--r--server/test/implementation/init.lua59
-rw-r--r--server/test/implementation/local.lua191
-rw-r--r--server/test/implementation/set.lua31
-rw-r--r--server/test/implementation/table.lua6
-rw-r--r--server/test/main.lua1
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