diff options
Diffstat (limited to 'script')
-rw-r--r-- | script/core/generic.lua | 93 | ||||
-rw-r--r-- | script/core/linker.lua | 32 | ||||
-rw-r--r-- | script/core/searcher.lua | 127 |
3 files changed, 129 insertions, 123 deletions
diff --git a/script/core/generic.lua b/script/core/generic.lua index 19c445cd..8c05d0df 100644 --- a/script/core/generic.lua +++ b/script/core/generic.lua @@ -1,7 +1,9 @@ +local linker = require "core.linker" ---@class generic.value ---@field type string ---@field closure generic.closure ---@field proto parser.guide.object +---@field parent parser.guide.object ---@class generic.closure ---@field type string @@ -12,12 +14,15 @@ local m = {} +---@param closure generic.closure +---@param proto parser.guide.object local function instantValue(closure, proto) ---@type generic.value local value = { type = 'generic.value', closure = closure, proto = proto, + parent = proto.parent, } return value end @@ -25,12 +30,15 @@ end ---递归实例化对象 ---@param obj parser.guide.object ---@return generic.value -local function createValue(closure, obj) +local function createValue(closure, obj, callback, road) + if callback then + road = road or {} + end if obj.type == 'doc.type' then local types = {} local hasGeneric for i, tp in ipairs(obj.types) do - local genericValue = createValue(tp) + local genericValue = createValue(closure, tp, callback, road) if genericValue then hasGeneric = true types[i] = genericValue @@ -38,13 +46,59 @@ local function createValue(closure, obj) types[i] = tp end end - if hasGeneric then - local value = instantValue(closure, obj) - value.types = types - return value - else + if not hasGeneric then return nil end + local value = instantValue(closure, obj) + value.types = types + linker.compileLink(value) + return value + end + if obj.type == 'doc.type.name' then + if not obj.typeGeneric then + return nil + end + local key = obj[1] + local value = instantValue(closure, obj) + if callback then + callback(road, key) + end + linker.compileLink(value) + return value + end +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) + local paramID = linker.getID(params[index]) + if not paramID then + return + end + if not upvalues[key] then + upvalues[key] = {} + end + -- TODO + upvalues[key][#upvalues[key]+1] = paramID + end) + elseif doc.type == 'doc.return' then + for _, rtn in ipairs(doc.returns) do + closure.returns[rtn.returnIndex] = createValue(closure, rtn) + end + end + end + end + if protoFunction.type == 'doc.function' then + end end @@ -56,34 +110,21 @@ function m.createClosure(protoFunction, call, parentClosure) ---@type generic.closure local closure = { type = 'generic.closure', - parent = parentClosure, + parent = protoFunction.parent, proto = protoFunction, call = call, upvalues = parentClosure and parentClosure.upvalues or {}, params = {}, returns = {}, } + buildValues(closure) - -- 立刻解决所有的泛型 - -- 对每个参数进行核对,存入泛型表 - -- 为所有的 param 与 return 创建副本 - -- 如果return中有function,也要递归创建闭包 - if protoFunction.type == 'function' then - for _, doc in ipairs(protoFunction.bindDocs) do - if doc.type == 'doc.param' then - local extends = doc.extends - closure.params[extends.paramIndex] = createValue(closure, extends) - elseif doc.type == 'doc.return' then - for _, rtn in ipairs(doc.returns) do - closure.returns[rtn.returnIndex] = createValue(closure, rtn) - end - end - end - end - if protoFunction.type == 'doc.function' then - + if #closure.returns == 0 then + return nil end + linker.compileLink(closure) + return closure end diff --git a/script/core/linker.lua b/script/core/linker.lua index 5ca11087..fd7f886e 100644 --- a/script/core/linker.lua +++ b/script/core/linker.lua @@ -569,11 +569,41 @@ function m.compileLink(source) end end if doc.type == 'doc.generic' then - source._isGeneric = true + source.isGeneric = true end end end end + if source.type == 'generic.closure' then + for i, rtn in ipairs(source.returns) do + local closureID = ('%s%s%s'):format( + id, + RETURN_INDEX_CHAR, + i + ) + local returnID = getID(rtn) + pushForward(closureID, returnID) + pushBackward(returnID, closureID) + end + end + if source.type == 'generic.value' then + local proto = source.proto + local closure = source.closure + local upvalues = closure.upvalues + if proto.type == 'doc.type.name' then + local key = proto[1] + for _, paramID in ipairs(upvalues[key]) do + pushForward(id, paramID) + pushBackward(paramID, id) + end + end + if proto.type == 'doc.type' then + for _, tp in ipairs(source.types) do + pushForward(id, getID(tp)) + pushBackward(getID(tp), id) + end + end + end end ---根据ID来获取所有的link diff --git a/script/core/searcher.lua b/script/core/searcher.lua index db581e9c..4150759b 100644 --- a/script/core/searcher.lua +++ b/script/core/searcher.lua @@ -1,6 +1,7 @@ -local linker = require 'core.linker' -local guide = require 'parser.guide' -local files = require 'files' +local linker = require 'core.linker' +local guide = require 'parser.guide' +local files = require 'files' +local generic = require 'core.generic' local function checkFunctionReturn(source) if source.parent @@ -240,113 +241,48 @@ function m.searchRefsByID(status, uri, expect, mode) search(parentID, linker.SPLIT_CHAR .. linker.RETURN_INDEX_CHAR .. returnIndex) end - local function findCallParam(key, index) - for i = #idStack, 1, -1 do - local id = idStack[i] - local link = linker.getLinkByID(root, id) - if not link then - goto CONTINUE - end - local call = link.call - if not call then - goto CONTINUE - end - local args = call.args - if not args then - goto CONTINUE - end - do return args[index] end - ::CONTINUE:: + local function isCallID(field) + if not field then + return false end + if field:sub(1, 1) == linker.SPLIT_CHAR + and field:sub(2, 2) == linker.RETURN_INDEX_CHAR then + return true + end + return false end - local function getGenericID(typeUnit, index) - local key = typeUnit[1] - local generics = typeUnit.typeGeneric[key] - local callParam = findCallParam(key, index) - if not callParam then - return nil - end - if typeUnit.literal then - if callParam.type == 'string' then - return generics, ('dn:%s'):format(callParam[1] or '') + 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 end - else - return generics, linker.getID(callParam) end return nil end - local function genericStashParam(docType, index) - if #idStack == 0 then + local function checkGeneric(source, field) + if not source.isGeneric then return end - for _, typeUnit in ipairs(docType.types) do - if typeUnit.typeGeneric then - local generics, id = getGenericID(typeUnit, index) - if id then - genericStashMap[generics] = id - end - end - -- 支持 V[] - if typeUnit.type == 'doc.type.array' then - if typeUnit.node.typeGeneric then - local generics, id = getGenericID(typeUnit.node, index) - if id then - genericStashMap[generics] = id .. linker.SPLIT_CHAR - end - end - end - -- 支持 table<number, V> - if typeUnit.type == 'doc.type.table' then - if typeUnit.value then - for _, typeUnit2 in ipairs(typeUnit.value.types) do - if typeUnit2.typeGeneric then - local generics, id = getGenericID(typeUnit2, index) - if id then - genericStashMap[generics] = id .. linker.SPLIT_CHAR - end - end - end - end - end - end - end - - -- TODO 这里的实现是有问题的,在多次穿透泛型时可能出错,不过错就错吧,让用户自己写注解 - local function genericStash(source) - if source.type ~= 'function' - and source.type ~= 'doc.type.function' then + if not isCallID(field) then return end - if source.type == 'function' then - if not source.docParamMap then - return - end - for index, param in ipairs(source.args) do - local docParam = param.docParam - if docParam then - genericStashParam(docParam.extends, index) - end - end - end - if source.type == 'doc.type.function' then - for index, param in ipairs(source.args) do - genericStashParam(param.extends, index) - end + local call = findLastCall() + if not call then + return end - end - - local function genericResolve(source, field) - if not source.typeGeneric then + if not call.args or #call.args == 0 then return end - local key = source[1] - local generics = source.typeGeneric[key] - local paramID = genericStashMap[generics] - if paramID then - searchID(paramID, field) + local closure = generic.createClosure(source, call) + if not closure then + return end + local id = linker.getID(closure) + searchID(id, field) end local stepCount = 0 @@ -375,8 +311,7 @@ function m.searchRefsByID(status, uri, expect, mode) end if link.sources then - genericStash(link.sources[1]) - genericResolve(link.sources[1], field) + checkGeneric(link.sources[1], field) end idStack[#idStack] = nil |