summaryrefslogtreecommitdiff
path: root/script
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2021-06-17 16:45:53 +0800
committer最萌小汐 <sumneko@hotmail.com>2021-06-17 16:45:53 +0800
commite67dd05a15a76d9ee6addb6519fd98e6527d2b09 (patch)
tree520a569d1a4bb8a3e4e0bbbc219e62bc5ed5a969 /script
parent844bc87bcb11fade43e06b5e8ac8421f2b0d3630 (diff)
downloadlua-language-server-e67dd05a15a76d9ee6addb6519fd98e6527d2b09.zip
stash
Diffstat (limited to 'script')
-rw-r--r--script/core/collector.lua71
-rw-r--r--script/core/noder.lua32
-rw-r--r--script/core/searcher.lua29
-rw-r--r--script/parser/guide.lua6
-rw-r--r--script/vm/docs.lua51
-rw-r--r--script/vm/getDocs.lua86
-rw-r--r--script/vm/globals.lua51
-rw-r--r--script/vm/init.lua2
8 files changed, 138 insertions, 190 deletions
diff --git a/script/core/collector.lua b/script/core/collector.lua
new file mode 100644
index 00000000..763d145b
--- /dev/null
+++ b/script/core/collector.lua
@@ -0,0 +1,71 @@
+local collect = {}
+local subscribed = {}
+
+local m = {}
+
+--- 订阅一个名字
+---@param uri uri
+---@param name string
+---@param value any
+function m.subscribe(uri, name, value)
+ -- 订阅部分
+ local uriSubscribed = subscribed[uri]
+ if not uriSubscribed then
+ uriSubscribed = {}
+ subscribed[uri] = uriSubscribed
+ end
+ uriSubscribed[name] = true
+ -- 收集部分
+ local nameCollect = collect[name]
+ if not nameCollect then
+ nameCollect = {}
+ collect[name] = nameCollect
+ end
+ if value == nil then
+ value = true
+ end
+ nameCollect[uri] = value
+end
+
+--- 丢弃掉某个 uri 中收集的所有信息
+---@param uri uri
+function m.dropUri(uri)
+ local uriSubscribed = subscribed[uri]
+ if not uriSubscribed then
+ return
+ end
+ subscribed[uri] = nil
+ for name in pairs(uriSubscribed) do
+ collect[name][uri] = nil
+ end
+end
+
+--- 是否包含某个名字的订阅
+---@param name string
+---@return boolean
+function m.has(name)
+ local nameCollect = collect[name]
+ if not nameCollect then
+ return false
+ end
+ if next(nameCollect) == nil then
+ return false
+ end
+ return true
+end
+
+--- 迭代某个名字的订阅
+---@param name string
+function m.each(name)
+ local nameCollect = collect[name]
+ if not nameCollect then
+ return function () end
+ end
+ local uri, value
+ return function ()
+ uri, value = next(nameCollect, uri)
+ return value
+ end
+end
+
+return m
diff --git a/script/core/noder.lua b/script/core/noder.lua
index 7ec02c69..43d349ee 100644
--- a/script/core/noder.lua
+++ b/script/core/noder.lua
@@ -1,5 +1,6 @@
-local util = require 'utility'
-local guide = require 'parser.guide'
+local util = require 'utility'
+local guide = require 'parser.guide'
+local collector = require 'core.collector'
local LastIDCache = {}
local FirstIDCache = {}
@@ -516,10 +517,11 @@ local function compileCall(noders, call, sourceID, returnIndex)
pushForward(noders, sourceID, funcXID)
end
+---@param uri uri
---@param noders noders
---@param source parser.guide.object
---@return parser.guide.object[]
-function m.compileNode(noders, source)
+function m.compileNode(uri, noders, source)
local id = getID(source)
bindValue(noders, source, id)
if source.special == 'setmetatable'
@@ -694,6 +696,26 @@ function m.compileNode(noders, source)
)
pushForward(noders, keyID, 'dn:integer')
end
+ if source.type == 'doc.type.name' then
+ collector.subscribe(uri, id, getNode(noders, id))
+ end
+ if source.type == 'doc.class.name' then
+ collector.subscribe(uri, id, getNode(noders, id))
+ collector.subscribe(uri, 'def:' .. id, getNode(noders, id))
+ collector.subscribe(uri, 'def:dn', getNode(noders, id))
+ end
+ if source.type == 'doc.alias.name' then
+ collector.subscribe(uri, id, getNode(noders, id))
+ collector.subscribe(uri, 'def:' .. id, getNode(noders, id))
+ collector.subscribe(uri, 'def:dn', getNode(noders, id))
+ end
+ if guide.isGlobal(source) then
+ collector.subscribe(uri, id, getNode(noders, id))
+ if guide.isSet(source) then
+ collector.subscribe(uri, 'def:' .. id, getNode(noders, id))
+ collector.subscribe(uri, 'def:g', getNode(noders, id))
+ end
+ end
-- 将函数的返回值映射到具体的返回值上
if source.type == 'function' then
local hasDocReturn = {}
@@ -971,10 +993,12 @@ function m.compileNodes(source)
if next(noders) then
return noders
end
+ local uri = guide.getUri(root)
+ collector.dropUri(uri)
log.debug('compileNodes:', guide.getUri(root))
guide.eachSource(root, function (src)
m.pushSource(noders, src)
- m.compileNode(noders, src)
+ m.compileNode(uri, noders, src)
end)
log.debug('compileNodes finish:', guide.getUri(root))
return noders
diff --git a/script/core/searcher.lua b/script/core/searcher.lua
index 972350fd..5a417765 100644
--- a/script/core/searcher.lua
+++ b/script/core/searcher.lua
@@ -1,12 +1,11 @@
-local noder = require 'core.noder'
-local guide = require 'parser.guide'
-local files = require 'files'
-local generic = require 'core.generic'
-local ws = require 'workspace'
-local vm = require 'vm.vm'
-local globals = require 'vm.globals'
-local docs = require 'vm.docs'
-local await = require 'await'
+local noder = require 'core.noder'
+local guide = require 'parser.guide'
+local files = require 'files'
+local generic = require 'core.generic'
+local ws = require 'workspace'
+local vm = require 'vm.vm'
+local await = require 'await'
+local collector = require 'core.collector'
local NONE = {'NONE'}
local LAST = {'LAST'}
@@ -466,10 +465,6 @@ function m.searchRefsByID(status, uri, expect, mode)
end
local function checkGlobal(id, node, field)
- local uris = globals.getUrisByID(id)
- if not uris then
- return
- end
if status.crossed[id] then
return
end
@@ -482,7 +477,7 @@ function m.searchRefsByID(status, uri, expect, mode)
if FOOTPRINT then
status.footprint[#status.footprint+1] = ('checkGlobal:%s + %s, isCall: %s'):format(id, field, isCall, tid)
end
- for guri, def in pairs(uris) do
+ for guri, def in collector.each(id) do
if def then
crossSearch(status, guri, tid, mode, uri)
goto CONTINUE
@@ -506,16 +501,12 @@ function m.searchRefsByID(status, uri, expect, mode)
end
local function checkClass(id, node, field)
- local uris = docs.getUrisByID(id)
- if not uris then
- return
- end
if status.crossed[id] then
return
end
status.crossed[id] = true
local tid = id .. (field or '')
- for guri in pairs(uris) do
+ for guri in collector.each(id) do
if not files.eq(uri, guri) then
crossSearch(status, guri, tid, mode, uri)
end
diff --git a/script/parser/guide.lua b/script/parser/guide.lua
index 8d2708cf..ad07e90e 100644
--- a/script/parser/guide.lua
+++ b/script/parser/guide.lua
@@ -972,9 +972,13 @@ end
---@param source parser.guide.object
---@return boolean
function m.isGlobal(source)
+ if source._isGlobal ~= nil then
+ return source._isGlobal
+ end
if source.type == 'setglobal'
or source.type == 'getglobal' then
if source.node and source.node.tag == '_ENV' then
+ source._isGlobal = true
return true
end
end
@@ -982,8 +986,10 @@ function m.isGlobal(source)
source = source.parent
end
if source.special == '_G' then
+ source._isGlobal = true
return true
end
+ source._isGlobal = false
return false
end
diff --git a/script/vm/docs.lua b/script/vm/docs.lua
deleted file mode 100644
index df87d46a..00000000
--- a/script/vm/docs.lua
+++ /dev/null
@@ -1,51 +0,0 @@
-local files = require 'files'
-local noder = require 'core.noder'
-
-local docsMap = {}
-local subscribeMap = {}
-
-local function popDocs(uri)
- if not subscribeMap[uri] then
- return
- end
- for id in pairs(subscribeMap[uri]) do
- if docsMap[id] then
- docsMap[id][uri] = nil
- end
- end
- subscribeMap[uri] = nil
-end
-
-local function pushDocs(uri)
- subscribeMap[uri] = {}
- local state = files.getState(uri)
- if not state then
- return
- end
- local nodes = noder.compileNodes(state.ast)
- for id in pairs(nodes) do
- if id:sub(1, 3) == 'dn:'
- and noder.getFirstID(id) == id then
- if not docsMap[id] then
- docsMap[id] = {}
- end
- docsMap[id][uri] = true
- subscribeMap[uri][id] = true
- end
- end
-end
-
-files.watch(function (ev, uri)
- if ev == 'update' then
- popDocs(uri)
- pushDocs(uri)
- end
-end)
-
-local m = {}
-
-function m.getUrisByID(id)
- return docsMap[id]
-end
-
-return m
diff --git a/script/vm/getDocs.lua b/script/vm/getDocs.lua
index bf99a247..16b82278 100644
--- a/script/vm/getDocs.lua
+++ b/script/vm/getDocs.lua
@@ -1,51 +1,32 @@
-local files = require 'files'
-local guide = require 'parser.guide'
----@type vm
-local vm = require 'vm.vm'
-local config = require 'config'
-local docs = require 'vm.docs'
-local define = require 'proto.define'
-local noder = require 'core.noder'
-
-local function getDocDefinesInAst(results, root, name)
- for _, doc in ipairs(root.docs) do
- if doc.type == 'doc.class' then
- if not name or name == doc.class[1] then
- results[#results+1] = doc.class
- end
- elseif doc.type == 'doc.alias' then
- if not name or name == doc.alias[1] then
- results[#results+1] = doc.alias
- end
- end
- end
-end
+local files = require 'files'
+local guide = require 'parser.guide'
+local vm = require 'vm.vm'
+local config = require 'config'
+local collector = require 'core.collector'
+local define = require 'proto.define'
+local noder = require 'core.noder'
---获取class与alias
---@param name? string
---@return parser.guide.object[]
function vm.getDocDefines(name)
+ local cache = vm.getCache 'getDocDefines'
+ if cache[name] then
+ return cache[name]
+ end
local results = {}
- if name then
- local id = 'dn:' .. name
- local uris = docs.getUrisByID(id)
- if not uris then
- return results
- end
- for uri in pairs(uris) do
- local state = files.getState(uri)
- if state then
- getDocDefinesInAst(results, state.ast, name)
- end
- end
- else
- for uri in files.eachFile() do
- local state = files.getState(uri)
- if state then
- getDocDefinesInAst(results, state.ast, name)
+ local id = 'def:dn:' .. (name or '')
+ for node in collector.each(id) do
+ if node.sources then
+ for _, source in ipairs(node.sources) do
+ if source.type == 'doc.class.name'
+ or source.type == 'doc.alias.name' then
+ results[#results+1] = source
+ end
end
end
end
+ cache[name] = results
return results
end
@@ -53,31 +34,10 @@ function vm.isDocDefined(name)
if define.BuiltinClass[name] then
return true
end
- local cache = vm.getCache 'isDocDefined'
- if cache[name] ~= nil then
- return cache[name]
- end
- local id = 'dn:' .. name
- local uris = docs.getUrisByID(id)
- if not uris then
- cache[name] = false
- return
- end
- for uri in pairs(uris) do
- local state = files.getState(uri)
- local node = noder.getNodeByID(state.ast, id)
- if node and node.sources then
- for _, source in ipairs(node.sources) do
- local doc = source.parent
- if doc.type == 'doc.class'
- or doc.type == 'doc.alias' then
- cache[name] = true
- return true
- end
- end
- end
+ local id = 'def:dn:' .. name
+ if collector.has(id) then
+ return true
end
- cache[name] = false
return false
end
diff --git a/script/vm/globals.lua b/script/vm/globals.lua
deleted file mode 100644
index 3c74f8b0..00000000
--- a/script/vm/globals.lua
+++ /dev/null
@@ -1,51 +0,0 @@
-local files = require 'files'
-local noder = require 'core.noder'
-
-local globalsMap = {}
-local subscribeMap = {}
-
-local function popGlobals(uri)
- if not subscribeMap[uri] then
- return
- end
- for id in pairs(subscribeMap[uri]) do
- if globalsMap[id] then
- globalsMap[id][uri] = nil
- end
- end
- subscribeMap[uri] = nil
-end
-
-local function pushGlobals(uri)
- subscribeMap[uri] = {}
- local state = files.getState(uri)
- if not state then
- return
- end
- local nodes = noder.compileNodes(state.ast)
- for id in pairs(nodes) do
- if id:sub(1, 2) == 'g:'
- and noder.getFirstID(id) == id then
- if not globalsMap[id] then
- globalsMap[id] = {}
- end
- globalsMap[id][uri] = true
- subscribeMap[uri][id] = true
- end
- end
-end
-
-files.watch(function (ev, uri)
- if ev == 'update' then
- popGlobals(uri)
- pushGlobals(uri)
- end
-end)
-
-local m = {}
-
-function m.getUrisByID(id)
- return globalsMap[id]
-end
-
-return m
diff --git a/script/vm/init.lua b/script/vm/init.lua
index 705a7117..c38f01d5 100644
--- a/script/vm/init.lua
+++ b/script/vm/init.lua
@@ -6,6 +6,4 @@ require 'vm.eachDef'
require 'vm.eachRef'
require 'vm.getLinks'
require 'vm.guideInterface'
-require 'vm.globals'
-require 'vm.docs'
return vm