summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2021-05-11 20:29:26 +0800
committer最萌小汐 <sumneko@hotmail.com>2021-05-11 20:29:26 +0800
commit3e0959b8a9f61d1db07f78cc94909d68c191f3bd (patch)
treecd2a7f3a89a66468b8a8210653ff2e5ac7b13689
parentfdf97fa234484054ebdaac283c4690ec716acb14 (diff)
downloadlua-language-server-3e0959b8a9f61d1db07f78cc94909d68c191f3bd.zip
update generic closures
-rw-r--r--script/core/generic.lua129
-rw-r--r--script/core/linker.lua12
-rw-r--r--script/core/searcher.lua26
3 files changed, 108 insertions, 59 deletions
diff --git a/script/core/generic.lua b/script/core/generic.lua
index fe24bcfc..ad91b2f9 100644
--- a/script/core/generic.lua
+++ b/script/core/generic.lua
@@ -28,16 +28,16 @@ local function instantValue(closure, proto)
end
---递归实例化对象
----@param obj parser.guide.object
+---@param proto parser.guide.object
---@return generic.value
-local function createValue(closure, obj, callback, road)
+local function createValue(closure, proto, callback, road)
if callback then
road = road or {}
end
- if obj.type == 'doc.type' then
+ if proto.type == 'doc.type' then
local types = {}
local hasGeneric
- for i, tp in ipairs(obj.types) do
+ for i, tp in ipairs(proto.types) do
local genericValue = createValue(closure, tp, callback, road)
if genericValue then
hasGeneric = true
@@ -49,80 +49,129 @@ local function createValue(closure, obj, callback, road)
if not hasGeneric then
return nil
end
- local value = instantValue(closure, obj)
+ local value = instantValue(closure, proto)
value.types = types
linker.compileLink(value)
return value
end
- if obj.type == 'doc.type.name' then
- if not obj.typeGeneric then
+ if proto.type == 'doc.type.name' then
+ if not proto.typeGeneric then
return nil
end
- local key = obj[1]
- local value = instantValue(closure, obj)
+ local key = proto[1]
+ local value = instantValue(closure, proto)
if callback then
- callback(road, key, obj)
+ callback(road, key, proto)
+ end
+ linker.compileLink(value)
+ return value
+ end
+ if proto.type == 'doc.type.function' then
+ local hasGeneric
+ local args = {}
+ local returns = {}
+ for i, arg in ipairs(proto.args) do
+ local value = instantValue(closure, arg)
+ if value then
+ hasGeneric = true
+ end
+ args[i] = value or arg
+ end
+ for i, rtn in ipairs(proto.returns) do
+ local value = instantValue(closure, rtn)
+ if value then
+ hasGeneric = true
+ end
+ returns[i] = value or rtn
+ end
+ if not hasGeneric then
+ return nil
end
+ local value = instantValue(closure, proto)
+ value.args = args
+ value.returns = returns
+ value.isGeneric = true
linker.compileLink(value)
+ linker.pushSource(value)
return value
end
end
+local function buildValue(road, key, proto, param, upvalues)
+ local paramID
+ if proto.literal then
+ local str = param.type == 'string' and param[1]
+ if not str then
+ return
+ end
+ paramID = 'dn:' .. str
+ else
+ paramID = linker.getID(param)
+ end
+ if not paramID then
+ return
+ end
+ if not upvalues[key] then
+ upvalues[key] = {}
+ end
+ -- TODO
+ upvalues[key][#upvalues[key]+1] = paramID
+end
+
-- 为所有的 param 与 return 创建副本
---@param closure generic.closure
local function buildValues(closure)
local protoFunction = closure.proto
local upvalues = closure.upvalues
local params = closure.call.args
+
if protoFunction.type == 'function' then
for _, doc in ipairs(protoFunction.bindDocs) do
if doc.type == 'doc.param' then
local extends = doc.extends
local index = extends.paramIndex
- closure.params[index] = createValue(closure, extends, function (road, key, proto)
- local param = params[index]
- if not param then
- return
- end
- local paramID
- if proto.literal then
- local str = param.type == 'string' and param[1]
- if not str then
- return
- end
- paramID = 'dn:' .. str
- else
- paramID = linker.getID(param)
- end
- if not paramID then
- return
- end
- if not upvalues[key] then
- upvalues[key] = {}
- end
- -- TODO
- upvalues[key][#upvalues[key]+1] = paramID
- end)
+ local param = params[index]
+ closure.params[index] = param and createValue(closure, extends, function (road, key, proto)
+ buildValue(road, key, proto, param, upvalues)
+ end) or extends
end
end
for _, doc in ipairs(protoFunction.bindDocs) do
if doc.type == 'doc.return' then
for _, rtn in ipairs(doc.returns) do
- closure.returns[rtn.returnIndex] = createValue(closure, rtn)
+ closure.returns[rtn.returnIndex] = createValue(closure, rtn) or rtn
end
end
end
end
- if protoFunction.type == 'doc.function' then
-
+ if protoFunction.type == 'doc.type.function' then
+ for index, arg in ipairs(protoFunction.args) do
+ local extends = arg.extends
+ local param = params[index]
+ closure.params[index] = param and createValue(closure, extends, function (road, key, proto)
+ buildValue(road, key, proto, param, upvalues)
+ end) or extends
+ end
+ for index, rtn in ipairs(protoFunction.returns) do
+ closure.returns[index] = createValue(closure, rtn) or rtn
+ end
end
end
---创建一个闭包
----@param protoFunction parser.guide.object # 原型函数
----@param parentClosure? generic.closure
+---@param proto parser.guide.object|generic.value # 原型函数|泛型值
---@return generic.closure
-function m.createClosure(protoFunction, call, parentClosure)
+function m.createClosure(proto, call)
+ local protoFunction, parentClosure
+ if proto.type == 'function' then
+ if not proto.args or #proto.args == 0 then
+ return nil
+ end
+ protoFunction = proto
+ elseif proto.type == 'generic.value' then
+ protoFunction = proto.proto
+ parentClosure = proto.closure
+ end
---@type generic.closure
local closure = {
type = 'generic.closure',
diff --git a/script/core/linker.lua b/script/core/linker.lua
index cecdc9de..4a031abe 100644
--- a/script/core/linker.lua
+++ b/script/core/linker.lua
@@ -311,9 +311,12 @@ m.RETURN_INDEX_CHAR = RETURN_INDEX_CHAR
m.PARAM_INDEX_CHAR = PARAM_INDEX_CHAR
---添加关联单元
----@param id string
---@param source parser.guide.object
-function m.pushSource(id, source)
+function m.pushSource(source)
+ local id = m.getID(source)
+ if not id then
+ return
+ end
local link = getLink(id)
if not link.sources then
link.sources = {}
@@ -672,10 +675,7 @@ function m.compileLinks(source)
Linkers = {}
root._linkers = Linkers
guide.eachSource(root, function (src)
- local id = getID(src)
- if id then
- m.pushSource(id, src)
- end
+ m.pushSource(src)
m.compileLink(src)
end)
return Linkers
diff --git a/script/core/searcher.lua b/script/core/searcher.lua
index 4150759b..54d95859 100644
--- a/script/core/searcher.lua
+++ b/script/core/searcher.lua
@@ -176,9 +176,7 @@ function m.searchRefsByID(status, uri, expect, mode)
local mark = status.mark
local queueIndex = 0
- -- 缓存过程中的泛型,以泛型关联表为key
- local genericStashMap = {}
- local idStack = {}
+ local callStack = {}
local function search(id, field)
local fieldLen
@@ -253,11 +251,12 @@ function m.searchRefsByID(status, uri, expect, mode)
end
local function findLastCall()
- for i = #idStack, 1, -1 do
- local id = idStack[i]
- local link = linker.getLinkByID(root, id)
- if link.call then
- return link.call
+ for i = #callStack, 1, -1 do
+ local call = callStack[i]
+ if call then
+ -- 标记此处的call失效,等待在堆栈平衡时弹出
+ callStack[i] = false
+ return call
end
end
return nil
@@ -274,9 +273,6 @@ function m.searchRefsByID(status, uri, expect, mode)
if not call then
return
end
- if not call.args or #call.args == 0 then
- return
- end
local closure = generic.createClosure(source, call)
if not closure then
return
@@ -293,7 +289,9 @@ function m.searchRefsByID(status, uri, expect, mode)
end
local link = linker.getLinkByID(root, id)
if link then
- idStack[#idStack+1] = id
+ if link.call then
+ callStack[#callStack+1] = link.call
+ end
if field == nil and link.sources then
for _, source in ipairs(link.sources) do
m.pushResult(status, mode, source)
@@ -314,7 +312,9 @@ function m.searchRefsByID(status, uri, expect, mode)
checkGeneric(link.sources[1], field)
end
- idStack[#idStack] = nil
+ if link.call then
+ callStack[#callStack] = nil
+ end
end
checkLastID(id, field)
end