diff options
Diffstat (limited to 'script')
-rw-r--r-- | script/core/completion/completion.lua | 7 | ||||
-rw-r--r-- | script/core/diagnostics/lowercase-global.lua | 3 | ||||
-rw-r--r-- | script/core/diagnostics/undefined-global.lua | 3 | ||||
-rw-r--r-- | script/core/rename.lua | 5 | ||||
-rw-r--r-- | script/core/semantic-tokens.lua | 3 | ||||
-rw-r--r-- | script/vm/compiler.lua | 69 | ||||
-rw-r--r-- | script/vm/def.lua | 3 | ||||
-rw-r--r-- | script/vm/doc.lua | 5 | ||||
-rw-r--r-- | script/vm/global-manager.lua | 419 | ||||
-rw-r--r-- | script/vm/global.lua | 425 | ||||
-rw-r--r-- | script/vm/init.lua | 5 | ||||
-rw-r--r-- | script/vm/manager.lua | 29 | ||||
-rw-r--r-- | script/vm/ref.lua | 1 | ||||
-rw-r--r-- | script/vm/runner.lua | 7 | ||||
-rw-r--r-- | script/vm/sign.lua | 5 | ||||
-rw-r--r-- | script/vm/type.lua | 11 |
16 files changed, 483 insertions, 517 deletions
diff --git a/script/core/completion/completion.lua b/script/core/completion/completion.lua index 8987592d..8b50f8af 100644 --- a/script/core/completion/completion.lua +++ b/script/core/completion/completion.lua @@ -18,7 +18,6 @@ local lookBackward = require 'core.look-backward' local guide = require 'parser.guide' local await = require 'await' local postfix = require 'core.completion.postfix' -local globalMgr = require 'vm.global-manager' local diagnosticModes = { 'disable-next-line', @@ -351,7 +350,7 @@ local function checkModule(state, word, position, results) local fileName = path:match '[^/\\]*$' local stemName = fileName:gsub('%..+', '') if not locals[stemName] - and not globalMgr.hasGlobalSets(state.uri, 'variable', stemName) + and not vm.hasGlobalSets(state.uri, 'variable', stemName) and not config.get(state.uri, 'Lua.diagnostics.globals')[stemName] and stemName:match '^[%a_][%w_]*$' and matchKey(word, stemName) then @@ -601,14 +600,14 @@ end ---@async local function checkGlobal(state, word, startPos, position, parent, oop, results) local locals = guide.getVisibleLocals(state.ast, position) - local globals = globalMgr.getGlobalSets(state.uri, 'variable') + local globals = vm.getGlobalSets(state.uri, 'variable') checkFieldOfRefs(globals, state, word, startPos, position, parent, oop, results, locals, 'global') end ---@async local function checkField(state, word, start, position, parent, oop, results) if parent.tag == '_ENV' or parent.special == '_G' then - local globals = globalMgr.getGlobalSets(state.uri, 'variable') + local globals = vm.getGlobalSets(state.uri, 'variable') checkFieldOfRefs(globals, state, word, start, position, parent, oop, results) else local refs = vm.getFields(parent) diff --git a/script/core/diagnostics/lowercase-global.lua b/script/core/diagnostics/lowercase-global.lua index 7c5ac720..d03e8c70 100644 --- a/script/core/diagnostics/lowercase-global.lua +++ b/script/core/diagnostics/lowercase-global.lua @@ -3,7 +3,6 @@ local guide = require 'parser.guide' local lang = require 'language' local config = require 'config' local vm = require 'vm' -local globalMgr = require 'vm.global-manager' local function isDocClass(source) if not source.bindDocs then @@ -47,7 +46,7 @@ return function (uri, callback) end if definedGlobal[name] == nil then definedGlobal[name] = false - local global = globalMgr.getGlobal('variable', name) + local global = vm.getGlobal('variable', name) if global then for _, set in ipairs(global:getSets(uri)) do if vm.isMetaFile(guide.getUri(set)) then diff --git a/script/core/diagnostics/undefined-global.lua b/script/core/diagnostics/undefined-global.lua index 139fa74f..bd0aae69 100644 --- a/script/core/diagnostics/undefined-global.lua +++ b/script/core/diagnostics/undefined-global.lua @@ -4,7 +4,6 @@ local lang = require 'language' local config = require 'config' local guide = require 'parser.guide' local await = require 'await' -local globalMgr = require 'vm.global-manager' local requireLike = { ['include'] = true, @@ -41,7 +40,7 @@ return function (uri, callback) return end if cache[key] == nil then - cache[key] = globalMgr.hasGlobalSets(uri, 'variable', key) + cache[key] = vm.hasGlobalSets(uri, 'variable', key) end if cache[key] then return diff --git a/script/core/rename.lua b/script/core/rename.lua index ec21e87c..7599fad6 100644 --- a/script/core/rename.lua +++ b/script/core/rename.lua @@ -3,7 +3,6 @@ local vm = require 'vm' local util = require 'utility' local findSource = require 'core.find-source' local guide = require 'parser.guide' -local globalMgr = require 'vm.global-manager' local Forcing @@ -191,7 +190,7 @@ end ---@async local function ofGlobal(source, newname, callback) local key = guide.getKeyName(source) - local global = globalMgr.getGlobal('variable', key) + local global = vm.getGlobal('variable', key) if not global then return end @@ -214,7 +213,7 @@ end ---@async local function ofDocTypeName(source, newname, callback) local oldname = source[1] - local global = globalMgr.getGlobal('type', oldname) + local global = vm.getGlobal('type', oldname) if not global then return end diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua index bcba27a9..65c72c11 100644 --- a/script/core/semantic-tokens.lua +++ b/script/core/semantic-tokens.lua @@ -7,7 +7,6 @@ local guide = require 'parser.guide' local converter = require 'proto.converter' local config = require 'config' local linkedTable = require 'linked-table' -local globalMgr = require 'vm.global-manager' local Care = util.switch() : case 'getglobal' @@ -21,7 +20,7 @@ local Care = util.switch() local isLib = options.libGlobals[name] if isLib == nil then isLib = false - local global = globalMgr.getGlobal('variable', name) + local global = vm.getGlobal('variable', name) if global then local uri = guide.getUri(source) for _, set in ipairs(global:getSets(uri)) do diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index 4d26ce8c..cb18557b 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -1,7 +1,6 @@ local guide = require 'parser.guide' local util = require 'utility' local localID = require 'vm.local-id' -local globalMgr = require 'vm.global-manager' local signMgr = require 'vm.sign' local config = require 'config' local genericMgr = require 'vm.generic' @@ -53,7 +52,7 @@ local searchFieldSwitch = util.switch() : case 'string' : call(function (suri, source, key, ref, pushResult) -- change to `string: stringlib` ? - local stringlib = globalMgr.getGlobal('type', 'stringlib') + local stringlib = vm.getGlobal('type', 'stringlib') if stringlib then vm.getClassFields(suri, stringlib, key, ref, pushResult) end @@ -118,7 +117,7 @@ local searchFieldSwitch = util.switch() if type(key) ~= 'string' then return end - local global = globalMgr.getGlobal('variable', node.name, key) + local global = vm.getGlobal('variable', node.name, key) if global then for _, set in ipairs(global:getSets(suri)) do pushResult(set) @@ -130,7 +129,7 @@ local searchFieldSwitch = util.switch() end end else - local globals = globalMgr.getFields('variable', node.name) + local globals = vm.getGlobalFields('variable', node.name) for _, global in ipairs(globals) do for _, set in ipairs(global:getSets(suri)) do pushResult(set) @@ -157,7 +156,7 @@ local searchFieldSwitch = util.switch() if type(key) ~= 'string' then return end - local global = globalMgr.getGlobal('variable', node.name, key) + local global = vm.getGlobal('variable', node.name, key) if global then for _, set in ipairs(global:getSets(suri)) do pushResult(set) @@ -167,7 +166,7 @@ local searchFieldSwitch = util.switch() end end else - local globals = globalMgr.getFields('variable', node.name) + local globals = vm.getGlobalFields('variable', node.name) for _, global in ipairs(globals) do for _, set in ipairs(global:getSets(suri)) do pushResult(set) @@ -282,7 +281,7 @@ function vm.getClassFields(suri, object, key, ref, pushResult) end for _, extend in ipairs(set.extends) do if extend.type == 'doc.extends.name' then - local extendType = globalMgr.getGlobal('type', extend[1]) + local extendType = vm.getGlobal('type', extend[1]) if extendType then searchClass(extendType, searchedFields) end @@ -296,12 +295,12 @@ function vm.getClassFields(suri, object, key, ref, pushResult) local function searchGlobal(class) if class.cate == 'type' and class.name == '_G' then if key == nil then - local sets = globalMgr.getGlobalSets(suri, 'variable') + local sets = vm.getGlobalSets(suri, 'variable') for _, set in ipairs(sets) do pushResult(set) end else - local global = globalMgr.getGlobal('variable', key) + local global = vm.getGlobal('variable', key) if global then for _, set in ipairs(global:getSets(suri)) do pushResult(set) @@ -647,7 +646,7 @@ local function selectNode(source, list, index) if exp.type == 'call' then result = getReturn(exp.node, index, exp.args) if not result then - vm.setNode(source, globalMgr.declareGlobal('type', 'unknown')) + vm.setNode(source, vm.declareGlobal('type', 'unknown')) return vm.getNode(source) end else @@ -673,7 +672,7 @@ local function selectNode(source, list, index) end end if not hasKnownType then - rtnNode:merge(globalMgr.declareGlobal('type', 'unknown')) + rtnNode:merge(vm.declareGlobal('type', 'unknown')) end vm.setNode(source, rtnNode) return rtnNode @@ -877,7 +876,7 @@ local function compileLocal(source) end end if not hasDocArg then - vm.setNode(source, globalMgr.declareGlobal('type', 'any')) + vm.setNode(source, vm.declareGlobal('type', 'any')) end end -- for x in ... do @@ -1252,7 +1251,7 @@ local compilerSwitch = util.switch() : case 'loop' : call(function (source) if source.loc then - vm.setNode(source.loc, globalMgr.declareGlobal('type', 'integer')) + vm.setNode(source.loc, vm.declareGlobal('type', 'integer')) end end) : case 'doc.type' @@ -1281,7 +1280,7 @@ local compilerSwitch = util.switch() if not source.node[1] then return end - local global = globalMgr.getGlobal('type', source.node[1]) + local global = vm.getGlobal('type', source.node[1]) if not global then return end @@ -1370,7 +1369,7 @@ local compilerSwitch = util.switch() end) : case 'doc.see.name' : call(function (source) - local type = globalMgr.getGlobal('type', source[1]) + local type = vm.getGlobal('type', source[1]) if type then vm.setNode(source, vm.compileNode(type)) end @@ -1380,7 +1379,7 @@ local compilerSwitch = util.switch() if source.extends then vm.setNode(source, vm.compileNode(source.extends)) else - vm.setNode(source, globalMgr.declareGlobal('type', 'any')) + vm.setNode(source, vm.declareGlobal('type', 'any')) end if source.optional then vm.getNode(source):addOptional() @@ -1401,7 +1400,7 @@ local compilerSwitch = util.switch() if source.op.type == 'not' then local result = vm.test(source[1]) if result == nil then - vm.setNode(source, globalMgr.declareGlobal('type', 'boolean')) + vm.setNode(source, vm.declareGlobal('type', 'boolean')) return else vm.setNode(source, { @@ -1415,13 +1414,13 @@ local compilerSwitch = util.switch() end end if source.op.type == '#' then - vm.setNode(source, globalMgr.declareGlobal('type', 'integer')) + vm.setNode(source, vm.declareGlobal('type', 'integer')) return end if source.op.type == '-' then local v = vm.getNumber(source[1]) if v == nil then - vm.setNode(source, globalMgr.declareGlobal('type', 'number')) + vm.setNode(source, vm.declareGlobal('type', 'number')) return else vm.setNode(source, { @@ -1437,7 +1436,7 @@ local compilerSwitch = util.switch() if source.op.type == '~' then local v = vm.getInteger(source[1]) if v == nil then - vm.setNode(source, globalMgr.declareGlobal('type', 'integer')) + vm.setNode(source, vm.declareGlobal('type', 'integer')) return else vm.setNode(source, { @@ -1488,7 +1487,7 @@ local compilerSwitch = util.switch() if source.op.type == '==' then local result = vm.equal(source[1], source[2]) if result == nil then - vm.setNode(source, globalMgr.declareGlobal('type', 'boolean')) + vm.setNode(source, vm.declareGlobal('type', 'boolean')) return else vm.setNode(source, { @@ -1504,7 +1503,7 @@ local compilerSwitch = util.switch() if source.op.type == '~=' then local result = vm.equal(source[1], source[2]) if result == nil then - vm.setNode(source, globalMgr.declareGlobal('type', 'boolean')) + vm.setNode(source, vm.declareGlobal('type', 'boolean')) return else vm.setNode(source, { @@ -1530,7 +1529,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'integer')) + vm.setNode(source, vm.declareGlobal('type', 'integer')) return end end @@ -1547,7 +1546,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'integer')) + vm.setNode(source, vm.declareGlobal('type', 'integer')) return end end @@ -1564,7 +1563,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'integer')) + vm.setNode(source, vm.declareGlobal('type', 'integer')) return end end @@ -1581,7 +1580,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'integer')) + vm.setNode(source, vm.declareGlobal('type', 'integer')) return end end @@ -1598,7 +1597,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'integer')) + vm.setNode(source, vm.declareGlobal('type', 'integer')) return end end @@ -1616,7 +1615,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'number')) + vm.setNode(source, vm.declareGlobal('type', 'number')) return end end @@ -1634,7 +1633,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'number')) + vm.setNode(source, vm.declareGlobal('type', 'number')) return end end @@ -1652,7 +1651,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'number')) + vm.setNode(source, vm.declareGlobal('type', 'number')) return end end @@ -1669,7 +1668,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'number')) + vm.setNode(source, vm.declareGlobal('type', 'number')) return end end @@ -1687,7 +1686,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'number')) + vm.setNode(source, vm.declareGlobal('type', 'number')) return end end @@ -1704,7 +1703,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'number')) + vm.setNode(source, vm.declareGlobal('type', 'number')) return end end @@ -1722,7 +1721,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'number')) + vm.setNode(source, vm.declareGlobal('type', 'number')) return end end @@ -1759,7 +1758,7 @@ local compilerSwitch = util.switch() }) return else - vm.setNode(source, globalMgr.declareGlobal('type', 'string')) + vm.setNode(source, vm.declareGlobal('type', 'string')) return end end diff --git a/script/vm/def.lua b/script/vm/def.lua index a0cb501e..60dcf03c 100644 --- a/script/vm/def.lua +++ b/script/vm/def.lua @@ -3,7 +3,6 @@ local vm = require 'vm.vm' local util = require 'utility' local guide = require 'parser.guide' local localID = require 'vm.local-id' -local globalMgr = require 'vm.global-manager' local simpleSwitch @@ -104,7 +103,7 @@ local searchFieldSwitch = util.switch() ---@param key string : call(function (suri, obj, key, pushResult) if obj.cate == 'variable' then - local newGlobal = globalMgr.getGlobal('variable', obj.name, key) + local newGlobal = vm.getGlobal('variable', obj.name, key) if newGlobal then for _, set in ipairs(newGlobal:getSets(suri)) do pushResult(set) diff --git a/script/vm/doc.lua b/script/vm/doc.lua index 055b3d49..e2b383b6 100644 --- a/script/vm/doc.lua +++ b/script/vm/doc.lua @@ -3,7 +3,6 @@ local guide = require 'parser.guide' ---@class vm local vm = require 'vm.vm' local config = require 'config' -local globalMgr = require 'vm.global-manager' ---获取class与alias ---@param suri uri @@ -11,13 +10,13 @@ local globalMgr = require 'vm.global-manager' ---@return parser.object[] function vm.getDocSets(suri, name) if name then - local global = globalMgr.getGlobal('type', name) + local global = vm.getGlobal('type', name) if not global then return {} end return global:getSets(suri) else - return globalMgr.getGlobalSets(suri, 'type') + return vm.getGlobalSets(suri, 'type') end end diff --git a/script/vm/global-manager.lua b/script/vm/global-manager.lua deleted file mode 100644 index 5891ba41..00000000 --- a/script/vm/global-manager.lua +++ /dev/null @@ -1,419 +0,0 @@ -local util = require 'utility' -local guide = require 'parser.guide' -local globalBuilder = require 'vm.global' -local signMgr = require 'vm.sign' -local genericMgr = require 'vm.generic' -local localID = require 'vm.local-id' ----@class vm -local vm = require 'vm.vm' - ----@class parser.object ----@field _globalNode? vm.global - ----@class vm.global-manager -local m = {} ----@type table<string, vm.global> -m.globals = {} ----@type table<uri, table<string, boolean>> -m.globalSubs = util.multiTable(2) - -local compilerGlobalSwitch = util.switch() - : case 'local' - : call(function (source) - if source.special ~= '_G' then - return - end - if source.ref then - for _, ref in ipairs(source.ref) do - m.compileObject(ref) - end - end - end) - : case 'getlocal' - : call(function (source) - if source.special ~= '_G' then - return - end - if not source.next then - return - end - m.compileObject(source.next) - end) - : case 'setglobal' - : call(function (source) - local uri = guide.getUri(source) - local name = guide.getKeyName(source) - local global = m.declareGlobal('variable', name, uri) - global:addSet(uri, source) - source._globalNode = global - end) - : case 'getglobal' - : call(function (source) - local uri = guide.getUri(source) - local name = guide.getKeyName(source) - local global = m.declareGlobal('variable', name, uri) - global:addGet(uri, source) - source._globalNode = global - - local nxt = source.next - if nxt then - m.compileObject(nxt) - end - end) - : case 'setfield' - : case 'setmethod' - : case 'setindex' - ---@param source parser.object - : call(function (source) - local name - local keyName = guide.getKeyName(source) - if not keyName then - return - end - if source.node._globalNode then - local parentName = source.node._globalNode:getName() - if parentName == '_G' then - name = keyName - else - name = ('%s%s%s'):format(parentName, vm.ID_SPLITE, keyName) - end - elseif source.node.special == '_G' then - name = keyName - end - if not name then - return - end - local uri = guide.getUri(source) - local global = m.declareGlobal('variable', name, uri) - global:addSet(uri, source) - source._globalNode = global - end) - : case 'getfield' - : case 'getmethod' - : case 'getindex' - ---@param source parser.object - : call(function (source) - local name - local keyName = guide.getKeyName(source) - if not keyName then - return - end - if source.node._globalNode then - local parentName = source.node._globalNode:getName() - if parentName == '_G' then - name = keyName - else - name = ('%s%s%s'):format(parentName, vm.ID_SPLITE, keyName) - end - elseif source.node.special == '_G' then - name = keyName - end - local uri = guide.getUri(source) - local global = m.declareGlobal('variable', name, uri) - global:addGet(uri, source) - source._globalNode = global - - local nxt = source.next - if nxt then - m.compileObject(nxt) - end - end) - : case 'call' - : call(function (source) - if source.node.special == 'rawset' - or source.node.special == 'rawget' then - if not source.args then - return - end - local g = source.args[1] - local key = source.args[2] - if g and key and g.special == '_G' then - local name = guide.getKeyName(key) - if name then - local uri = guide.getUri(source) - local global = m.declareGlobal('variable', name, uri) - if source.node.special == 'rawset' then - global:addSet(uri, source) - source.value = source.args[3] - else - global:addGet(uri, source) - end - source._globalNode = global - - local nxt = source.next - if nxt then - m.compileObject(nxt) - end - end - end - end - end) - : case 'doc.class' - ---@param source parser.object - : call(function (source) - local uri = guide.getUri(source) - local name = guide.getKeyName(source) - local class = m.declareGlobal('type', name, uri) - class:addSet(uri, source) - source._globalNode = class - - if source.signs then - source._sign = signMgr() - for _, sign in ipairs(source.signs) do - source._sign:addSign(vm.compileNode(sign)) - end - if source.extends then - for _, ext in ipairs(source.extends) do - if ext.type == 'doc.type.table' then - ext._generic = genericMgr(ext, source._sign) - end - end - end - end - end) - : case 'doc.alias' - : call(function (source) - local uri = guide.getUri(source) - local name = guide.getKeyName(source) - local alias = m.declareGlobal('type', name, uri) - alias:addSet(uri, source) - source._globalNode = alias - - if source.signs then - source._sign = signMgr() - for _, sign in ipairs(source.signs) do - source._sign:addSign(vm.compileNode(sign)) - end - source.extends._generic = genericMgr(source.extends, source._sign) - end - end) - : case 'doc.type.name' - : call(function (source) - local uri = guide.getUri(source) - local name = source[1] - local type = m.declareGlobal('type', name, uri) - type:addGet(uri, source) - source._globalNode = type - end) - : case 'doc.extends.name' - : call(function (source) - local uri = guide.getUri(source) - local name = source[1] - local class = m.declareGlobal('type', name, uri) - class:addGet(uri, source) - source._globalNode = class - end) - - ----@alias vm.global.cate '"variable"' | '"type"' - ----@param cate vm.global.cate ----@param name string ----@param uri? uri ----@return vm.global -function m.declareGlobal(cate, name, uri) - local key = cate .. '|' .. name - if uri then - m.globalSubs[uri][key] = true - end - if not m.globals[key] then - m.globals[key] = globalBuilder(name, cate) - end - return m.globals[key] -end - ----@param cate vm.global.cate ----@param name string ----@param field? string ----@return vm.global? -function m.getGlobal(cate, name, field) - local key = cate .. '|' .. name - if field then - key = key .. vm.ID_SPLITE .. field - end - return m.globals[key] -end - ----@param cate vm.global.cate ----@param name string ----@return vm.global[] -function m.getFields(cate, name) - local globals = {} - local key = cate .. '|' .. name - - -- TODO: optimize - local clock = os.clock() - for gid, global in pairs(m.globals) do - if gid ~= key - and util.stringStartWith(gid, key) - and gid:sub(#key + 1, #key + 1) == vm.ID_SPLITE - and not gid:find(vm.ID_SPLITE, #key + 2) then - globals[#globals+1] = global - end - end - local cost = os.clock() - clock - if cost > 0.1 then - log.warn('global-manager getFields cost %.3f', cost) - end - - return globals -end - ----@param cate vm.global.cate ----@return vm.global[] -function m.getGlobals(cate) - local globals = {} - - -- TODO: optimize - local clock = os.clock() - for gid, global in pairs(m.globals) do - if util.stringStartWith(gid, cate) - and not gid:find(vm.ID_SPLITE) then - globals[#globals+1] = global - end - end - local cost = os.clock() - clock - if cost > 0.1 then - log.warn('global-manager getGlobals cost %.3f', cost) - end - - return globals -end - ----@param suri uri ----@param cate vm.global.cate ----@return parser.object[] -function m.getGlobalSets(suri, cate) - local globals = m.getGlobals(cate) - local result = {} - for _, global in ipairs(globals) do - local sets = global:getSets(suri) - for _, set in ipairs(sets) do - result[#result+1] = set - end - end - return result -end - ----@param suri uri ----@param cate vm.global.cate ----@param name string ----@return boolean -function m.hasGlobalSets(suri, cate, name) - local global = m.getGlobal(cate, name) - if not global then - return false - end - local sets = global:getSets(suri) - if #sets == 0 then - return false - end - return true -end - ----@param source parser.object -function m.compileObject(source) - if source._globalNode ~= nil then - return - end - source._globalNode = false - compilerGlobalSwitch(source.type, source) -end - ----@param source parser.object -function m.compileSelf(source) - if source.parent.type ~= 'funcargs' then - return - end - ---@type parser.object - local node = source.parent.parent and source.parent.parent.parent and source.parent.parent.parent.node - if not node then - return - end - local fields = localID.getFields(source) - if not fields then - return - end - local nodeLocalID = localID.getID(node) - local globalNode = node._globalNode - if not nodeLocalID and not globalNode then - return - end - for _, field in ipairs(fields) do - if field.type == 'setfield' then - local key = guide.getKeyName(field) - if key then - if nodeLocalID then - local myID = nodeLocalID .. vm.ID_SPLITE .. key - localID.insertLocalID(myID, field) - end - if globalNode then - local myID = globalNode:getName() .. vm.ID_SPLITE .. key - local myGlobal = m.declareGlobal('variable', myID, guide.getUri(node)) - myGlobal:addSet(guide.getUri(node), field) - end - end - end - end -end - ----@param source parser.object -function m.compileAst(source) - local env = guide.getENV(source) - if not env then - return - end - m.compileObject(env) - guide.eachSpecialOf(source, 'rawset', function (src) - m.compileObject(src.parent) - end) - guide.eachSpecialOf(source, 'rawget', function (src) - m.compileObject(src.parent) - end) - guide.eachSourceTypes(source.docs, { - 'doc.class', - 'doc.alias', - 'doc.type.name', - 'doc.extends.name', - }, function (src) - m.compileObject(src) - end) - - --[[ - local mt - function mt:xxx() - self.a = 1 - end - - mt.a --> find this definition - ]] - guide.eachSourceType(source, 'self', function (src) - m.compileSelf(src) - end) -end - ----@return vm.global -function m.getNode(source) - if source.type == 'field' - or source.type == 'method' then - source = source.parent - end - return source._globalNode -end - ----@param uri uri -function m.dropUri(uri) - local globalSub = m.globalSubs[uri] - m.globalSubs[uri] = nil - for key in pairs(globalSub) do - local global = m.globals[key] - if global then - global:dropUri(uri) - if not global:isAlive() then - m.globals[key] = nil - end - end - end -end - -return m diff --git a/script/vm/global.lua b/script/vm/global.lua index f8327843..eea398dc 100644 --- a/script/vm/global.lua +++ b/script/vm/global.lua @@ -1,5 +1,11 @@ local util = require 'utility' local scope = require 'workspace.scope' +local guide = require 'parser.guide' +local files = require 'files' +local signMgr = require 'vm.sign' +local genericMgr = require 'vm.generic' +local localID = require 'vm.local-id' +---@class vm local vm = require 'vm.vm' ---@class vm.global.link @@ -115,10 +121,427 @@ end ---@param cate vm.global.cate ---@return vm.global -return function (name, cate) +local function createGlobal(name, cate) return setmetatable({ name = name, cate = cate, links = util.multiTable(2), }, mt) end + +---@class parser.object +---@field _globalNode vm.global + +---@type table<string, vm.global> +local allGlobals = {} +---@type table<uri, table<string, boolean>> +local globalSubs = util.multiTable(2) + +local compileObject +local compilerGlobalSwitch = util.switch() + : case 'local' + : call(function (source) + if source.special ~= '_G' then + return + end + if source.ref then + for _, ref in ipairs(source.ref) do + compileObject(ref) + end + end + end) + : case 'getlocal' + : call(function (source) + if source.special ~= '_G' then + return + end + if not source.next then + return + end + compileObject(source.next) + end) + : case 'setglobal' + : call(function (source) + local uri = guide.getUri(source) + local name = guide.getKeyName(source) + local global = vm.declareGlobal('variable', name, uri) + global:addSet(uri, source) + source._globalNode = global + end) + : case 'getglobal' + : call(function (source) + local uri = guide.getUri(source) + local name = guide.getKeyName(source) + local global = vm.declareGlobal('variable', name, uri) + global:addGet(uri, source) + source._globalNode = global + + local nxt = source.next + if nxt then + compileObject(nxt) + end + end) + : case 'setfield' + : case 'setmethod' + : case 'setindex' + ---@param source parser.object + : call(function (source) + local name + local keyName = guide.getKeyName(source) + if not keyName then + return + end + if source.node._globalNode then + local parentName = source.node._globalNode:getName() + if parentName == '_G' then + name = keyName + else + name = ('%s%s%s'):format(parentName, vm.ID_SPLITE, keyName) + end + elseif source.node.special == '_G' then + name = keyName + end + if not name then + return + end + local uri = guide.getUri(source) + local global = vm.declareGlobal('variable', name, uri) + global:addSet(uri, source) + source._globalNode = global + end) + : case 'getfield' + : case 'getmethod' + : case 'getindex' + ---@param source parser.object + : call(function (source) + local name + local keyName = guide.getKeyName(source) + if not keyName then + return + end + if source.node._globalNode then + local parentName = source.node._globalNode:getName() + if parentName == '_G' then + name = keyName + else + name = ('%s%s%s'):format(parentName, vm.ID_SPLITE, keyName) + end + elseif source.node.special == '_G' then + name = keyName + end + local uri = guide.getUri(source) + local global = vm.declareGlobal('variable', name, uri) + global:addGet(uri, source) + source._globalNode = global + + local nxt = source.next + if nxt then + compileObject(nxt) + end + end) + : case 'call' + : call(function (source) + if source.node.special == 'rawset' + or source.node.special == 'rawget' then + if not source.args then + return + end + local g = source.args[1] + local key = source.args[2] + if g and key and g.special == '_G' then + local name = guide.getKeyName(key) + if name then + local uri = guide.getUri(source) + local global = vm.declareGlobal('variable', name, uri) + if source.node.special == 'rawset' then + global:addSet(uri, source) + source.value = source.args[3] + else + global:addGet(uri, source) + end + source._globalNode = global + + local nxt = source.next + if nxt then + compileObject(nxt) + end + end + end + end + end) + : case 'doc.class' + ---@param source parser.object + : call(function (source) + local uri = guide.getUri(source) + local name = guide.getKeyName(source) + local class = vm.declareGlobal('type', name, uri) + class:addSet(uri, source) + source._globalNode = class + + if source.signs then + source._sign = signMgr() + for _, sign in ipairs(source.signs) do + source._sign:addSign(vm.compileNode(sign)) + end + if source.extends then + for _, ext in ipairs(source.extends) do + if ext.type == 'doc.type.table' then + ext._generic = genericMgr(ext, source._sign) + end + end + end + end + end) + : case 'doc.alias' + : call(function (source) + local uri = guide.getUri(source) + local name = guide.getKeyName(source) + local alias = vm.declareGlobal('type', name, uri) + alias:addSet(uri, source) + source._globalNode = alias + + if source.signs then + source._sign = signMgr() + for _, sign in ipairs(source.signs) do + source._sign:addSign(vm.compileNode(sign)) + end + source.extends._generic = genericMgr(source.extends, source._sign) + end + end) + : case 'doc.type.name' + : call(function (source) + local uri = guide.getUri(source) + local name = source[1] + local type = vm.declareGlobal('type', name, uri) + type:addGet(uri, source) + source._globalNode = type + end) + : case 'doc.extends.name' + : call(function (source) + local uri = guide.getUri(source) + local name = source[1] + local class = vm.declareGlobal('type', name, uri) + class:addGet(uri, source) + source._globalNode = class + end) + + +---@alias vm.global.cate '"variable"' | '"type"' + +---@param cate vm.global.cate +---@param name string +---@param uri? uri +---@return vm.global +function vm.declareGlobal(cate, name, uri) + local key = cate .. '|' .. name + if uri then + globalSubs[uri][key] = true + end + if not allGlobals[key] then + allGlobals[key] = createGlobal(name, cate) + end + return allGlobals[key] +end + +---@param cate vm.global.cate +---@param name string +---@param field? string +---@return vm.global? +function vm.getGlobal(cate, name, field) + local key = cate .. '|' .. name + if field then + key = key .. vm.ID_SPLITE .. field + end + return allGlobals[key] +end + +---@param cate vm.global.cate +---@param name string +---@return vm.global[] +function vm.getGlobalFields(cate, name) + local globals = {} + local key = cate .. '|' .. name + + local clock = os.clock() + for gid, global in pairs(allGlobals) do + if gid ~= key + and util.stringStartWith(gid, key) + and gid:sub(#key + 1, #key + 1) == vm.ID_SPLITE + and not gid:find(vm.ID_SPLITE, #key + 2) then + globals[#globals+1] = global + end + end + local cost = os.clock() - clock + if cost > 0.1 then + log.warn('global-manager getFields cost %.3f', cost) + end + + return globals +end + +---@param cate vm.global.cate +---@return vm.global[] +function vm.getGlobals(cate) + local globals = {} + + local clock = os.clock() + for gid, global in pairs(allGlobals) do + if util.stringStartWith(gid, cate) + and not gid:find(vm.ID_SPLITE) then + globals[#globals+1] = global + end + end + local cost = os.clock() - clock + if cost > 0.1 then + log.warn('global-manager getGlobals cost %.3f', cost) + end + + return globals +end + +---@param suri uri +---@param cate vm.global.cate +---@return parser.object[] +function vm.getGlobalSets(suri, cate) + local globals = vm.getGlobals(cate) + local result = {} + for _, global in ipairs(globals) do + local sets = global:getSets(suri) + for _, set in ipairs(sets) do + result[#result+1] = set + end + end + return result +end + +---@param suri uri +---@param cate vm.global.cate +---@param name string +---@return boolean +function vm.hasGlobalSets(suri, cate, name) + local global = vm.getGlobal(cate, name) + if not global then + return false + end + local sets = global:getSets(suri) + if #sets == 0 then + return false + end + return true +end + +---@param source parser.object +function compileObject(source) + if source._globalNode ~= nil then + return + end + source._globalNode = false + compilerGlobalSwitch(source.type, source) +end + +---@param source parser.object +local function compileSelf(source) + if source.parent.type ~= 'funcargs' then + return + end + ---@type parser.object + local node = source.parent.parent and source.parent.parent.parent and source.parent.parent.parent.node + if not node then + return + end + local fields = localID.getFields(source) + if not fields then + return + end + local nodeLocalID = localID.getID(node) + local globalNode = node._globalNode + if not nodeLocalID and not globalNode then + return + end + for _, field in ipairs(fields) do + if field.type == 'setfield' then + local key = guide.getKeyName(field) + if key then + if nodeLocalID then + local myID = nodeLocalID .. vm.ID_SPLITE .. key + localID.insertLocalID(myID, field) + end + if globalNode then + local myID = globalNode:getName() .. vm.ID_SPLITE .. key + local myGlobal = vm.declareGlobal('variable', myID, guide.getUri(node)) + myGlobal:addSet(guide.getUri(node), field) + end + end + end + end +end + +---@param source parser.object +local function compileAst(source) + local env = guide.getENV(source) + if not env then + return + end + compileObject(env) + guide.eachSpecialOf(source, 'rawset', function (src) + compileObject(src.parent) + end) + guide.eachSpecialOf(source, 'rawget', function (src) + compileObject(src.parent) + end) + guide.eachSourceTypes(source.docs, { + 'doc.class', + 'doc.alias', + 'doc.type.name', + 'doc.extends.name', + }, function (src) + compileObject(src) + end) + + --[[ + local mt + function mt:xxx() + self.a = 1 + end + + mt.a --> find this definition + ]] + guide.eachSourceType(source, 'self', function (src) + compileSelf(src) + end) +end + +---@param uri uri +local function dropUri(uri) + local globalSub = globalSubs[uri] + globalSubs[uri] = nil + for key in pairs(globalSub) do + local global = allGlobals[key] + if global then + global:dropUri(uri) + if not global:isAlive() then + allGlobals[key] = nil + end + end + end +end + +for uri in files.eachFile() do + local state = files.getState(uri) + if state then + compileAst(state.ast) + end +end + +files.watch(function (ev, uri) + if ev == 'update' then + dropUri(uri) + local state = files.getState(uri) + if state then + compileAst(state.ast) + end + end + if ev == 'remove' then + dropUri(uri) + end +end) diff --git a/script/vm/init.lua b/script/vm/init.lua index 61541c5f..23dd0d54 100644 --- a/script/vm/init.lua +++ b/script/vm/init.lua @@ -1,4 +1,7 @@ local vm = require 'vm.vm' + +---@alias vm.object parser.object | vm.global | vm.generic + require 'vm.compiler' require 'vm.value' require 'vm.node' @@ -9,6 +12,6 @@ require 'vm.doc' require 'vm.type' require 'vm.library' require 'vm.runner' -require 'vm.manager' require 'vm.infer' +require 'vm.global' return vm diff --git a/script/vm/manager.lua b/script/vm/manager.lua deleted file mode 100644 index c75b777f..00000000 --- a/script/vm/manager.lua +++ /dev/null @@ -1,29 +0,0 @@ - -local files = require 'files' -local globalManager = require 'vm.global-manager' - ----@alias vm.object parser.object | vm.global | vm.generic - ----@class vm.state -local m = {} -for uri in files.eachFile() do - local state = files.getState(uri) - if state then - globalManager.compileAst(state.ast) - end -end - -files.watch(function (ev, uri) - if ev == 'update' then - globalManager.dropUri(uri) - local state = files.getState(uri) - if state then - globalManager.compileAst(state.ast) - end - end - if ev == 'remove' then - globalManager.dropUri(uri) - end -end) - -return m diff --git a/script/vm/ref.lua b/script/vm/ref.lua index 29ea27c5..714d3ccd 100644 --- a/script/vm/ref.lua +++ b/script/vm/ref.lua @@ -3,7 +3,6 @@ local vm = require 'vm.vm' local util = require 'utility' local guide = require 'parser.guide' local localID = require 'vm.local-id' -local globalMgr = require 'vm.global-manager' local files = require 'files' local await = require 'await' local progress = require 'progress' diff --git a/script/vm/runner.lua b/script/vm/runner.lua index 7fbde208..9fe0f172 100644 --- a/script/vm/runner.lua +++ b/script/vm/runner.lua @@ -1,7 +1,6 @@ ---@class vm local vm = require 'vm.vm' local guide = require 'parser.guide' -local globalMgr = require 'vm.global-manager' ---@class vm.runner ---@field loc parser.object @@ -367,17 +366,17 @@ function mt:launch(callback) node:setFalsy() elseif step.type == 'as' then if step.new then - topNode = vm.createNode(globalMgr.getGlobal('type', step.name)) + topNode = vm.createNode(vm.getGlobal('type', step.name)) else node:clear() - node:merge(globalMgr.getGlobal('type', step.name)) + node:merge(vm.getGlobal('type', step.name)) end elseif step.type == 'add' then if step.new then node = node:copy() topNode = node end - node:merge(globalMgr.getGlobal('type', step.name)) + node:merge(vm.getGlobal('type', step.name)) elseif step.type == 'remove' then if step.new then node = node:copy() diff --git a/script/vm/sign.lua b/script/vm/sign.lua index ded094d0..c19f72d4 100644 --- a/script/vm/sign.lua +++ b/script/vm/sign.lua @@ -21,7 +21,6 @@ function mt:resolve(uri, args, removeGeneric) if not args then return nil end - local globalMgr = require 'vm.global-manager' local resolved = {} ---@param object parser.object @@ -33,7 +32,7 @@ function mt:resolve(uri, args, removeGeneric) -- 'number' -> `T` for n in node:eachObject() do if n.type == 'string' then - local type = globalMgr.declareGlobal('type', n[1], guide.getUri(n)) + local type = vm.declareGlobal('type', n[1], guide.getUri(n)) resolved[key] = vm.createNode(type, resolved[key]) end end @@ -57,7 +56,7 @@ function mt:resolve(uri, args, removeGeneric) end if n.type == 'global' and n.cate == 'type' then -- ---@field [integer]: number -> T[] - vm.getClassFields(uri, n, globalMgr.declareGlobal('type', 'integer'), false, function (field) + vm.getClassFields(uri, n, vm.declareGlobal('type', 'integer'), false, function (field) resolve(object.node, vm.compileNode(field.extends)) end) end diff --git a/script/vm/type.lua b/script/vm/type.lua index 691490ec..c3264993 100644 --- a/script/vm/type.lua +++ b/script/vm/type.lua @@ -1,4 +1,3 @@ -local globalMgr = require 'vm.global-manager' ---@class vm local vm = require 'vm.vm' @@ -9,10 +8,10 @@ local vm = require 'vm.vm' ---@return boolean function vm.isSubType(uri, child, parent, mark) if type(parent) == 'string' then - parent = vm.createNode(globalMgr.getGlobal('type', parent)) + parent = vm.createNode(vm.getGlobal('type', parent)) end if type(child) == 'string' then - child = vm.createNode(globalMgr.getGlobal('type', child)) + child = vm.createNode(vm.getGlobal('type', child)) end if not child or not parent then @@ -134,7 +133,7 @@ function vm.getTableKey(uri, tnode, vnode) end end if tn.type == 'doc.type.array' then - result:merge(globalMgr.declareGlobal('type', 'integer')) + result:merge(vm.declareGlobal('type', 'integer')) end if tn.type == 'table' then for _, field in ipairs(tn) do @@ -144,10 +143,10 @@ function vm.getTableKey(uri, tnode, vnode) end end if field.type == 'tablefield' then - result:merge(globalMgr.declareGlobal('type', 'string')) + result:merge(vm.declareGlobal('type', 'string')) end if field.type == 'tableexp' then - result:merge(globalMgr.declareGlobal('type', 'integer')) + result:merge(vm.declareGlobal('type', 'integer')) end end end |