diff options
-rw-r--r-- | script/parser/guide.lua | 9 | ||||
-rw-r--r-- | script/vm/compiler.lua | 85 | ||||
-rw-r--r-- | script/vm/generic-manager.lua | 30 | ||||
-rw-r--r-- | script/vm/generic.lua | 16 | ||||
-rw-r--r-- | script/vm/local-manager.lua | 5 | ||||
-rw-r--r-- | script/vm/union.lua | 3 |
6 files changed, 115 insertions, 33 deletions
diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 730a099d..e877ddce 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -41,7 +41,6 @@ local type = type ---@field closure parser.object ---@field proto parser.object ---@field exp parser.object ----@field isGeneric boolean ---@field alias parser.object ---@field class parser.object ---@field vararg parser.object @@ -648,10 +647,10 @@ function m.eachSourceBetween(ast, start, finish, callback) end local function getSourceTypeCache(ast) - local cache = ast.typeCache + local cache = ast._typeCache if not cache then cache = {} - ast.typeCache = cache + ast._typeCache = cache m.eachSource(ast, function (source) local tp = source.type if not tp then @@ -694,10 +693,10 @@ end --- 遍历所有的source function m.eachSource(ast, callback) - local cache = ast.eachCache + local cache = ast._eachCache if not cache then cache = { ast } - ast.eachCache = cache + ast._eachCache = cache local mark = {} local index = 1 while true do diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index b814cdbc..d6987295 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -1,9 +1,10 @@ -local guide = require 'parser.guide' -local util = require 'utility' -local union = require 'vm.union' -local localID = require 'vm.local-id' -local localMgr = require 'vm.local-manager' -local globalMgr = require 'vm.global-manager' +local guide = require 'parser.guide' +local util = require 'utility' +local union = require 'vm.union' +local localID = require 'vm.local-id' +local localMgr = require 'vm.local-manager' +local globalMgr = require 'vm.global-manager' +local genericMgr = require 'vm.generic-manager' ---@class parser.object ---@field _compiledNodes boolean @@ -12,28 +13,27 @@ local globalMgr = require 'vm.global-manager' ---@class vm.node.compiler local m = {} ----@class vm.node.cross +local nodeCache = {} ----@alias vm.node parser.object | vm.node.union | vm.node.cross | vm.node.global +---@alias vm.node parser.object | vm.node.union | vm.node.global | vm.node.generic function m.setNode(source, node) if not node then return end - local me = source._node + local me = nodeCache[source] if not me then - source._node = node + nodeCache[source] = node return end if me == node then return end - if me.type == 'union' - or me.type == 'cross' then + if me.type == 'union' then me:merge(node) return end - source._node = union(me, node) + nodeCache[source] = union(me, node) end function m.eachNode(node) @@ -161,7 +161,7 @@ local function getReturnOfSetMetaTable(source, args) m.setNode(source, m.compileNode(src)) end) end - return source._node + return nodeCache[source] end local function getReturn(func, index, source, args) @@ -272,6 +272,29 @@ local function selectNode(source, list, index) return m.compileNode(exp) end +---@class parser.object +---@field _generic? vm.node.generic-manager + +---@param func parser.object +---@return vm.node.generic-manager? +local function getFunctionGeneric(func) + if func._generic ~= nil then + return func._generic + end + func._generic = false + for _, doc in ipairs(func.bindDocs) do + 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 + return func._generic +end + local compilerMap = util.switch() : case 'boolean' : case 'table' @@ -281,12 +304,12 @@ local compilerMap = util.switch() : case 'doc.type.function' : case 'doc.type.table' : call(function (source) - localMgr.declareLocal(source) + --localMgr.declareLocal(source) m.setNode(source, source) end) : case 'function' : call(function (source) - localMgr.declareLocal(source) + --localMgr.declareLocal(source) m.setNode(source, source) if source.bindDocs then @@ -299,6 +322,7 @@ local compilerMap = util.switch() end) : case 'local' : call(function (source) + --localMgr.declareLocal(source) m.setNode(source, source) local hasMarkDoc if source.bindDocs then @@ -367,12 +391,25 @@ local compilerMap = util.switch() local index = source.index local hasMarkDoc if func.bindDocs then + local generic = getFunctionGeneric(func) for _, doc in ipairs(func.bindDocs) do if doc.type == 'doc.return' then for _, rtn in ipairs(doc.returns) do if rtn.returnIndex == index then hasMarkDoc = true - m.setNode(source, m.compileNode(rtn)) + local hasGeneric + if generic then + guide.eachSourceType(rtn, 'doc.type.name', function (src) + if src.typeGeneric then + hasGeneric = true + end + end) + end + if hasGeneric then + m.setNode(source, generic:getChild(rtn)) + else + m.setNode(source, m.compileNode(rtn)) + end end end end @@ -481,16 +518,20 @@ end ---@param source parser.object ---@return vm.node function m.compileNode(source) - if source._node ~= nil then - return source._node + if nodeCache[source] ~= nil then + return nodeCache[source] end - source._node = false + nodeCache[source] = false compileByGlobal(source) compileByNode(source) - localMgr.subscribeLocal(source, source._node) + --localMgr.subscribeLocal(source, source._node) + + return nodeCache[source] +end - return source._node +function m.clearNodeCache() + nodeCache = {} end return m diff --git a/script/vm/generic-manager.lua b/script/vm/generic-manager.lua new file mode 100644 index 00000000..b41b1e61 --- /dev/null +++ b/script/vm/generic-manager.lua @@ -0,0 +1,30 @@ +local createGeneric = require 'vm.generic' + +---@class vm.node.generic-manager +---@field parent parser.object +---@field signMap table<string, vm.node> +---@field signList string[] +local mt = {} +mt.__index = mt +mt.type = 'generic-manager' + +---@param key string +function mt:addSign(key) + self.signList[#self.signList+1] = key +end + +---@param proto parser.object +function mt:getChild(proto) + local generic = createGeneric(self, proto) + return generic +end + +---@return vm.node.generic-manager +return function (parent) + local genericMgr = setmetatable({ + parent = parent, + signMap = {}, + signList = {}, + }, mt) + return genericMgr +end diff --git a/script/vm/generic.lua b/script/vm/generic.lua new file mode 100644 index 00000000..8b298508 --- /dev/null +++ b/script/vm/generic.lua @@ -0,0 +1,16 @@ +---@class vm.node.generic +---@field parent vm.node.generic-manager +---@field proto parser.object +local mt = {} +mt.__index = mt +mt.type = 'generic' + +---@param parent vm.node.generic-manager +---@param proto parser.object +return function (parent, proto) + local generic = setmetatable({ + parent = parent, + proto = proto, + }, mt) + return generic +end diff --git a/script/vm/local-manager.lua b/script/vm/local-manager.lua index bae22318..318dd4bc 100644 --- a/script/vm/local-manager.lua +++ b/script/vm/local-manager.lua @@ -29,12 +29,11 @@ function m.subscribeLocal(source, node) if not node then return end - if node.type == 'union' - or node.type == 'cross' then + if node.type == 'union' then node:subscribeLocal(source) return end - if not m.allLocals[source] then + if not m.allLocals[node] then return end m.localSubs[node][source] = true diff --git a/script/vm/union.lua b/script/vm/union.lua index f0c259df..97ab333f 100644 --- a/script/vm/union.lua +++ b/script/vm/union.lua @@ -29,9 +29,6 @@ end function mt:subscribeLocal(source) for _, c in ipairs(self) do localMgr.subscribeLocal(source, c) - if c.type == 'cross' then - c:subscribeLocal(source) - end end end |