summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--script/parser/guide.lua1
-rw-r--r--script/parser/luadoc.lua5
-rw-r--r--script/vm/compiler.lua37
-rw-r--r--script/vm/generic-manager.lua33
-rw-r--r--script/vm/generic.lua29
-rw-r--r--test/definition/luadoc.lua2
6 files changed, 80 insertions, 27 deletions
diff --git a/script/parser/guide.lua b/script/parser/guide.lua
index e877ddce..831534a7 100644
--- a/script/parser/guide.lua
+++ b/script/parser/guide.lua
@@ -28,7 +28,6 @@ local type = type
---@field extends parser.object[]
---@field types parser.object[]
---@field fields parser.object[]
----@field typeGeneric table<integer, parser.object[]>
---@field tkey parser.object
---@field tvalue parser.object
---@field tindex integer
diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua
index a47ebe34..5bc566f2 100644
--- a/script/parser/luadoc.lua
+++ b/script/parser/luadoc.lua
@@ -1263,7 +1263,7 @@ local function bindGeneric(binded)
if doc.type == 'doc.generic' then
for _, obj in ipairs(doc.generics) do
local name = obj.generic[1]
- generics[name] = {}
+ generics[name] = true
end
elseif doc.type == 'doc.param'
or doc.type == 'doc.return'
@@ -1271,8 +1271,7 @@ local function bindGeneric(binded)
guide.eachSourceType(doc, 'doc.type.name', function (src)
local name = src[1]
if generics[name] then
- generics[name][#generics[name]+1] = src
- src.typeGeneric = generics
+ src.type = 'doc.generic.name'
end
end)
end
diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua
index d6987295..da4ea7b4 100644
--- a/script/vm/compiler.lua
+++ b/script/vm/compiler.lua
@@ -172,10 +172,19 @@ local function getReturn(func, index, source, args)
if node then
for cnode in m.eachNode(node) do
if cnode.type == 'function' then
- return getReturnOfFunction(cnode, index)
+ local returnNode = getReturnOfFunction(cnode, index)
+ if returnNode and returnNode.type == 'generic' then
+ local argNodes = {}
+ for i, arg in ipairs(args) do
+ argNodes[i] = m.compileNode(arg)
+ end
+ returnNode = returnNode:resolve(argNodes)
+ end
+ m.setNode(source, returnNode)
end
end
end
+ return nodeCache[source]
end
local function bindDocs(source)
@@ -286,12 +295,17 @@ local function getFunctionGeneric(func)
if doc.type == 'doc.generic' then
if not func._generic then
func._generic = genericMgr(func)
- for _, obj in ipairs(doc) do
- func._generic:addSign(obj[1])
- end
end
end
end
+ if not func._generic then
+ return false
+ end
+ for _, doc in ipairs(func.bindDocs) do
+ if doc.type == 'doc.param' then
+ func._generic:addSign(doc.extends)
+ end
+ end
return func._generic
end
@@ -399,16 +413,15 @@ local compilerMap = util.switch()
hasMarkDoc = true
local hasGeneric
if generic then
- guide.eachSourceType(rtn, 'doc.type.name', function (src)
- if src.typeGeneric then
- hasGeneric = true
- end
+ guide.eachSourceType(rtn, 'doc.generic.name', function (src)
+ hasGeneric = true
end)
end
+ local rtnNode = m.compileNode(rtn)
if hasGeneric then
- m.setNode(source, generic:getChild(rtn))
+ m.setNode(source, generic:getChild(rtnNode))
else
- m.setNode(source, m.compileNode(rtn))
+ m.setNode(source, rtnNode)
end
end
end
@@ -434,6 +447,10 @@ local compilerMap = util.switch()
m.setNode(source, m.compileNode(typeUnit))
end
end)
+ : case 'doc.generic.name'
+ : call(function (source)
+ m.setNode(source, source)
+ end)
: case 'doc.field'
: call(function (source)
m.setNode(source, m.compileNode(source.extends))
diff --git a/script/vm/generic-manager.lua b/script/vm/generic-manager.lua
index b41b1e61..dbee5dae 100644
--- a/script/vm/generic-manager.lua
+++ b/script/vm/generic-manager.lua
@@ -2,28 +2,47 @@ local createGeneric = require 'vm.generic'
---@class vm.node.generic-manager
---@field parent parser.object
----@field signMap table<string, vm.node>
----@field signList string[]
+---@field signList parser.object[]
local mt = {}
mt.__index = mt
mt.type = 'generic-manager'
----@param key string
+---@param key parser.object
function mt:addSign(key)
self.signList[#self.signList+1] = key
end
----@param proto parser.object
-function mt:getChild(proto)
- local generic = createGeneric(self, proto)
+---@param node vm.node
+function mt:getChild(node)
+ local generic = createGeneric(self, node)
return generic
end
+---@param argNodes vm.node[]
+---@return table<string, vm.node>
+function mt:resolve(argNodes)
+ local resolved = {}
+ for i, node in ipairs(argNodes) do
+ local sign = self.signList[i]
+ if not sign then
+ break
+ end
+ for _, typeUnit in ipairs(sign.types) do
+ if typeUnit.type == 'doc.generic.name' then
+ local key = typeUnit[1]
+ if not resolved[key] then
+ resolved[key] = node
+ end
+ end
+ end
+ end
+ return resolved
+end
+
---@return vm.node.generic-manager
return function (parent)
local genericMgr = setmetatable({
parent = parent,
- signMap = {},
signList = {},
}, mt)
return genericMgr
diff --git a/script/vm/generic.lua b/script/vm/generic.lua
index 8b298508..86fd193a 100644
--- a/script/vm/generic.lua
+++ b/script/vm/generic.lua
@@ -1,16 +1,35 @@
---@class vm.node.generic
---@field parent vm.node.generic-manager
----@field proto parser.object
+---@field node vm.node
local mt = {}
mt.__index = mt
mt.type = 'generic'
+---@param node vm.node
+---@param resolved table<string, vm.node>
+---@return vm.node
+local function cloneObject(node, resolved)
+ if node.type == 'doc.generic.name' then
+ local key = node[1]
+ return resolved[key]
+ end
+ return nil
+end
+
+---@param argNodes vm.node[]
+---@return parser.object
+function mt:resolve(argNodes)
+ local resolved = self.parent:resolve(argNodes)
+ local newProto = cloneObject(self.node, resolved)
+ return newProto
+end
+
---@param parent vm.node.generic-manager
----@param proto parser.object
-return function (parent, proto)
+---@param node vm.node
+return function (parent, node)
local generic = setmetatable({
- parent = parent,
- proto = proto,
+ parent = parent,
+ node = node,
}, mt)
return generic
end
diff --git a/test/definition/luadoc.lua b/test/definition/luadoc.lua
index 61477b0d..74770794 100644
--- a/test/definition/luadoc.lua
+++ b/test/definition/luadoc.lua
@@ -235,7 +235,7 @@ TEST [[
---@return T
local function f(p) end
-local k = <!{}!>
+local k = <!function () end!>
local <?<!r!>?> = f(k)
]]