summaryrefslogtreecommitdiff
path: root/script/vm
diff options
context:
space:
mode:
Diffstat (limited to 'script/vm')
-rw-r--r--script/vm/eachDef.lua11
-rw-r--r--script/vm/getDef.lua175
-rw-r--r--script/vm/getDocs.lua3
-rw-r--r--script/vm/getGlobals.lua1
-rw-r--r--script/vm/getRef.lua (renamed from script/vm/eachRef.lua)1
-rw-r--r--script/vm/global-node.lua142
-rw-r--r--script/vm/init.lua5
-rw-r--r--script/vm/local-id.lua116
-rw-r--r--script/vm/node/class.lua11
-rw-r--r--script/vm/node/compiler.lua190
-rw-r--r--script/vm/node/global.lua79
-rw-r--r--script/vm/node/union.lua49
-rw-r--r--script/vm/state.lua80
-rw-r--r--script/vm/vm.lua3
14 files changed, 846 insertions, 20 deletions
diff --git a/script/vm/eachDef.lua b/script/vm/eachDef.lua
deleted file mode 100644
index ea14ed9f..00000000
--- a/script/vm/eachDef.lua
+++ /dev/null
@@ -1,11 +0,0 @@
----@class vm
-local vm = require 'vm.vm'
-local searcher = require 'core.searcher'
-
-function vm.getDefs(source, field)
- return searcher.requestDefinition(source, field)
-end
-
-function vm.getAllDefs(source, field)
- return searcher.requestAllDefinition(source, field)
-end
diff --git a/script/vm/getDef.lua b/script/vm/getDef.lua
new file mode 100644
index 00000000..df180420
--- /dev/null
+++ b/script/vm/getDef.lua
@@ -0,0 +1,175 @@
+---@class vm
+local vm = require 'vm.vm'
+local util = require 'utility'
+local compiler = require 'vm.node.compiler'
+local guide = require 'parser.guide'
+local localID = require 'vm.local-id'
+local globalNode = require 'vm.global-node'
+
+local simpleMap
+
+local function searchGetLocal(source, node, pushResult)
+ local key = guide.getKeyName(source)
+ for _, ref in ipairs(node.node.ref) do
+ if ref.type == 'getlocal'
+ and guide.isSet(ref.next)
+ and guide.getKeyName(ref.next) == key then
+ pushResult(ref.next)
+ end
+ end
+end
+
+simpleMap = util.switch()
+ : case 'local'
+ : call(function (source, pushResult)
+ pushResult(source)
+ if source.ref then
+ for _, ref in ipairs(source.ref) do
+ if ref.type == 'setlocal' then
+ pushResult(ref)
+ end
+ end
+ end
+
+ if source.dummy then
+ for _, res in ipairs(vm.getDefs(source.method.node)) do
+ pushResult(res)
+ end
+ end
+ end)
+ : case 'getlocal'
+ : case 'setlocal'
+ : call(function (source, pushResult)
+ simpleMap['local'](source.node, pushResult)
+ end)
+ : case 'field'
+ : call(function (source, pushResult)
+ local parent = source.parent
+ simpleMap[parent.type](parent, pushResult)
+ end)
+ : case 'setfield'
+ : case 'getfield'
+ : call(function (source, pushResult)
+ local node = source.node
+ if node.type == 'getlocal' then
+ searchGetLocal(source, node, pushResult)
+ return
+ end
+ end)
+ : case 'getindex'
+ : case 'setindex'
+ : call(function (source, pushResult)
+ local node = source.node
+ if node.type == 'getlocal' then
+ searchGetLocal(source, node, pushResult)
+ end
+ end)
+ : getMap()
+
+local searchFieldMap = util.switch()
+ : case 'table'
+ : call(function (node, key, pushResult)
+ for _, field in ipairs(node) do
+ if field.type == 'tablefield'
+ or field.type == 'tableindex' then
+ if guide.getKeyName(field) == key then
+ pushResult(field)
+ end
+ end
+ end
+ end)
+ : getMap()
+
+local nodeMap;nodeMap = util.switch()
+ : case 'field'
+ : call(function (source, pushResult)
+ local parent = source.parent
+ nodeMap[parent.type](parent, pushResult)
+ end)
+ : case 'getfield'
+ : case 'setfield'
+ : case 'getmethod'
+ : case 'setmethod'
+ : case 'getindex'
+ : case 'setindex'
+ : call(function (source, pushResult)
+ local node = compiler.compileNode(source.node)
+ if not node then
+ return
+ end
+ if searchFieldMap[node.type] then
+ searchFieldMap[node.type](node, guide.getKeyName(source), pushResult)
+ end
+ end)
+ : getMap()
+
+ ---@param source parser.object
+ ---@param pushResult fun(src: parser.object)
+local function searchBySimple(source, pushResult)
+ local simple = simpleMap[source.type]
+ if simple then
+ simple(source, pushResult)
+ end
+end
+
+---@param source parser.object
+---@param pushResult fun(src: parser.object)
+local function searchByGlobal(source, pushResult)
+ local global = globalNode.getNode(source)
+ if not global then
+ return
+ end
+ for _, src in ipairs(global:getSets()) do
+ pushResult(src)
+ end
+end
+
+---@param source parser.object
+---@param pushResult fun(src: parser.object)
+local function searchByID(source, pushResult)
+ local idSources = localID.getSources(source)
+ if not idSources then
+ return
+ end
+ for _, src in ipairs(idSources) do
+ if guide.isSet(src) then
+ pushResult(src)
+ end
+ end
+end
+
+---@param source parser.object
+---@param pushResult fun(src: parser.object)
+local function searchByNode(source, pushResult)
+ local node = nodeMap[source.type]
+ if node then
+ node(source, pushResult)
+ end
+end
+
+---@param source parser.object
+---@return parser.object[]
+function vm.getDefs(source)
+ local results = {}
+ local mark = {}
+
+ local function pushResult(src)
+ if not mark[src] then
+ mark[src] = true
+ results[#results+1] = src
+ end
+ end
+
+ searchBySimple(source, pushResult)
+ searchByGlobal(source, pushResult)
+ searchByID(source, pushResult)
+ searchByNode(source, pushResult)
+
+ return results
+end
+
+---@param source parser.object
+---@return parser.object[]
+function vm.getAllDefs(source)
+ return vm.getDefs(source)
+end
diff --git a/script/vm/getDocs.lua b/script/vm/getDocs.lua
index 4aeda446..4204d785 100644
--- a/script/vm/getDocs.lua
+++ b/script/vm/getDocs.lua
@@ -5,11 +5,10 @@ local vm = require 'vm.vm'
local config = require 'config'
local collector = require 'core.collector' 'searcher'
local define = require 'proto.define'
-local noder = require 'core.noder'
---获取class与alias
---@param name? string
----@return parser.guide.object[]
+---@return parser.object[]
function vm.getDocDefines(uri, name)
if type(name) ~= 'string' then
return {}
diff --git a/script/vm/getGlobals.lua b/script/vm/getGlobals.lua
index 8af21d45..2ba734ba 100644
--- a/script/vm/getGlobals.lua
+++ b/script/vm/getGlobals.lua
@@ -2,7 +2,6 @@ local collector = require 'core.collector' 'searcher'
local guide = require 'parser.guide'
---@class vm
local vm = require 'vm.vm'
-local noder = require 'core.noder'
function vm.hasGlobalSets(uri, name)
local id
diff --git a/script/vm/eachRef.lua b/script/vm/getRef.lua
index 899c04c6..ded95b61 100644
--- a/script/vm/eachRef.lua
+++ b/script/vm/getRef.lua
@@ -1,6 +1,5 @@
---@class vm
local vm = require 'vm.vm'
-local searcher = require 'core.searcher'
function vm.getRefs(source, field)
return searcher.requestReference(source, field)
diff --git a/script/vm/global-node.lua b/script/vm/global-node.lua
new file mode 100644
index 00000000..6235ff6b
--- /dev/null
+++ b/script/vm/global-node.lua
@@ -0,0 +1,142 @@
+local util = require 'utility'
+local guide = require 'parser.guide'
+local globalBuilder = require 'vm.node.global'
+
+---@class parser.object
+---@field _globalNode vm.node.global
+
+---@class vm.global-node
+local m = {}
+---@type table<string, vm.node.global>
+m.globals = util.defaultTable(globalBuilder)
+---@type table<uri, table<string, boolean>>
+m.globalSubs = util.defaultTable(function ()
+ return {}
+end)
+
+m.ID_SPLITE = '\x1F'
+
+local compilerGlobalMap = util.switch()
+ : case 'local'
+ : call(function (uri, source)
+ if source.tag ~= '_ENV' then
+ return
+ end
+ if source.ref then
+ for _, ref in ipairs(source.ref) do
+ m.compileNode(uri, ref)
+ end
+ end
+ end)
+ : case 'setglobal'
+ : call(function (uri, source)
+ local name = guide.getKeyName(source)
+ source._globalNode = m.declareGlobal(name, uri, source)
+ end)
+ : case 'getglobal'
+ : call(function (uri, source)
+ local name = guide.getKeyName(source)
+ local global = m.getGlobal(name)
+ global:addGet(uri, source)
+ source._globalNode = global
+
+ local nxt = source.next
+ if nxt then
+ m.compileNode(uri, nxt)
+ end
+ end)
+ : case 'setfield'
+ : case 'setmethod'
+ : case 'setindex'
+ ---@param uri uri
+ ---@param source parser.object
+ : call(function (uri, source)
+ local parent = source.node._globalNode
+ if not parent then
+ return
+ end
+ local name = parent:getName() .. m.ID_SPLITE .. guide.getKeyName(source)
+ source._globalNode = m.declareGlobal(name, uri, source)
+ end)
+ : case 'getfield'
+ : case 'getmethod'
+ : case 'getindex'
+ ---@param uri uri
+ ---@param source parser.object
+ : call(function (uri, source)
+ local parent = source.node._globalNode
+ if not parent then
+ return
+ end
+ local name = parent:getName() .. m.ID_SPLITE .. guide.getKeyName(source)
+ local global = m.getGlobal(name)
+ global:addGet(uri, source)
+ source._globalNode = global
+
+ local nxt = source.next
+ if nxt then
+ m.compileNode(uri, nxt)
+ end
+ end)
+ : getMap()
+
+
+---@param name string
+---@param uri uri
+---@param source parser.object
+---@return vm.node.global
+function m.declareGlobal(name, uri, source)
+ m.globalSubs[uri][name] = true
+ local node = m.globals[name]
+ node:addSet(uri, source)
+ return node
+end
+
+---@param name string
+---@param uri? uri
+---@return vm.node.global
+function m.getGlobal(name, uri)
+ if uri then
+ m.globalSubs[uri][name] = true
+ end
+ return m.globals[name]
+end
+
+---@param source parser.object
+function m.compileNode(uri, source)
+ if source._globalNode ~= nil then
+ return
+ end
+ source._globalNode = false
+ local compiler = compilerGlobalMap[source.type]
+ if compiler then
+ compiler(uri, source)
+ end
+end
+
+---@param source parser.object
+function m.compileAst(source)
+ local uri = guide.getUri(source)
+ local env = guide.getENV(source)
+ m.compileNode(uri, env)
+end
+
+---@return vm.node.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 name in pairs(globalSub) do
+ m.globals[name]:dropUri(uri)
+ end
+end
+
+return m
diff --git a/script/vm/init.lua b/script/vm/init.lua
index 935f39e3..5a5de99e 100644
--- a/script/vm/init.lua
+++ b/script/vm/init.lua
@@ -1,8 +1,9 @@
local vm = require 'vm.vm'
+require 'vm.state'
require 'vm.getGlobals'
require 'vm.getDocs'
require 'vm.getLibrary'
-require 'vm.eachDef'
-require 'vm.eachRef'
+require 'vm.getDef'
+require 'vm.getRef'
require 'vm.getLinks'
return vm
diff --git a/script/vm/local-id.lua b/script/vm/local-id.lua
new file mode 100644
index 00000000..8487d96a
--- /dev/null
+++ b/script/vm/local-id.lua
@@ -0,0 +1,116 @@
+local util = require 'utility'
+local guide = require 'parser.guide'
+
+---@class parser.object
+---@field _localID string
+---@field _localIDs table<string, parser.object[]>
+
+---@class vm.local-id
+local m = {}
+
+m.ID_SPLITE = '\x1F'
+
+local compileMap = util.switch()
+ : case 'local'
+ : call(function (source)
+ if not source.ref then
+ return
+ end
+ for _, ref in ipairs(source.ref) do
+ m.compileLocalID(ref)
+ end
+ end)
+ : case 'getlocal'
+ : call(function (source)
+ source._localID = ('%d'):format(source.node.start)
+ m.compileLocalID(source.next)
+ end)
+ : case 'getfield'
+ : case 'setfield'
+ : call(function (source)
+ local parentID = source.node._localID
+ if not parentID then
+ return
+ end
+ source._localID = parentID .. m.ID_SPLITE .. guide.getKeyName(source)
+ source.field._localID = source._localID
+ if source.type == 'getfield' then
+ m.compileLocalID(source.next)
+ end
+ end)
+ : getMap()
+
+local leftMap = util.switch()
+ : case 'field'
+ : call(function (source)
+ return m.getLocal(source.parent)
+ end)
+ : case 'getfield'
+ : case 'setfield'
+ : call(function (source)
+ return m.getLocal(source.node)
+ end)
+ : case 'getlocal'
+ : call(function (source)
+ return source.node
+ end)
+ : getMap()
+
+---@param source parser.object
+---@return parser.object?
+function m.getLocal(source)
+ local getLeft = leftMap[source.type]
+ if getLeft then
+ return getLeft(source)
+ end
+ return nil
+end
+
+function m.compileLocalID(source)
+ if not source then
+ return
+ end
+ source._localID = false
+ local compiler = compileMap[source.type]
+ if not compiler then
+ return
+ end
+ compiler(source)
+ local root = guide.getRoot(source)
+ if not root._localIDs then
+ root._localIDs = util.multiTable(2)
+ end
+ local sources = root._localIDs[source._localID]
+ sources[#sources+1] = source
+end
+
+---@param source parser.object
+---@return string|boolean
+function m.getID(source)
+ if source._localID ~= nil then
+ return source._localID
+ end
+ source._localID = false
+ local loc = m.getLocal(source)
+ if not loc then
+ return source._localID
+ end
+ m.compileLocalID(loc)
+ return source._localID
+end
+
+---@param source parser.object
+---@return parser.object[]?
+function m.getSources(source)
+ local id = m.getID(source)
+ if not id then
+ return nil
+ end
+ local root = guide.getRoot(source)
+ if not root._localIDs then
+ return nil
+ end
+ return root._localIDs[id]
+end
+
+return m
diff --git a/script/vm/node/class.lua b/script/vm/node/class.lua
new file mode 100644
index 00000000..ee8b1ca8
--- /dev/null
+++ b/script/vm/node/class.lua
@@ -0,0 +1,11 @@
+---@class vm.node.class
+local mt = {}
+mt.__index = mt
+mt.type = 'class'
+
+---@return vm.node.class
+return function ()
+ local class = setmetatable({
+ }, mt)
+ return class
+end
diff --git a/script/vm/node/compiler.lua b/script/vm/node/compiler.lua
new file mode 100644
index 00000000..dfe4bc0c
--- /dev/null
+++ b/script/vm/node/compiler.lua
@@ -0,0 +1,190 @@
+local guide = require 'parser.guide'
+local util = require 'utility'
+local state = require 'vm.state'
+local union = require 'vm.node.union'
+local localID = require 'vm.local-id'
+
+---@class parser.object
+---@field _compiledNodes boolean
+---@field _node vm.node
+
+---@class vm.node.compiler
+local m = {}
+
+---@class vm.node.cross
+
+---@alias vm.node parser.object | vm.node.union | vm.node.cross | vm.node.global
+
+function m.setNode(source, node)
+ if not node then
+ return
+ end
+ local me = source._node
+ if not me then
+ source._node = node
+ return
+ end
+ if me.type == 'union'
+ or me.type == 'cross' then
+ me:merge(node)
+ return
+ end
+ source._node = union(me, node)
+end
+
+function m.eachNode(node)
+ if node.type == 'union' then
+ return node:eachNode()
+ end
+ local first = true
+ return function ()
+ if first then
+ first = false
+ return node
+ end
+ return nil
+ end
+end
+
+local function getReturnOfFunction(func, index)
+ if not func._returns then
+ func._returns = util.defaultTable(function ()
+ return {
+ type = 'function.return',
+ parent = func,
+ index = index,
+ }
+ end)
+ end
+ return m.compileNode(func._returns[index])
+end
+
+local function getReturn(func, index)
+ local node = m.compileNode(func)
+ if not node then
+ return
+ end
+ for cnode in m.eachNode(node) do
+ if cnode.type == 'function' then
+ return getReturnOfFunction(cnode, index)
+ end
+ end
+end
+
+local function compileByLocalID(source)
+ local sources = localID.getSources(source)
+ if not sources then
+ return
+ end
+ for _, src in ipairs(sources) do
+ if src.value then
+ m.setNode(source, m.compileNode(src.value))
+ end
+ end
+end
+
+local searchFieldMap = util.switch()
+ : case 'table'
+ : call(function (node, key, pushResult)
+ for _, field in ipairs(node) do
+ if field.type == 'tablefield'
+ or field.type == 'tableindex' then
+ if guide.getKeyName(field) == key then
+ pushResult(field)
+ end
+ end
+ end
+ end)
+ : getMap()
+
+local function compileByParentNode(source)
+ local parentNode = m.compileNode(source.node)
+ if not parentNode then
+ return
+ end
+ local key = guide.getKeyName(source)
+ local f = searchFieldMap[parentNode.type]
+ if f then
+ f(parentNode, key, function (field)
+ m.setNode(source, m.compileNode(field.value))
+ end)
+ end
+end
+
+local compilerMap = util.switch()
+ : case 'boolean'
+ : case 'table'
+ : case 'integer'
+ : case 'number'
+ : case 'string'
+ : case 'function'
+ : call(function (source)
+ m.setNode(source, state.declareLiteral(source))
+ end)
+ : case 'local'
+ : call(function (source)
+ if source.value then
+ m.setNode(source, m.compileNode(source.value))
+ end
+ if source.ref then
+ for _, ref in ipairs(source.ref) do
+ if ref.type == 'setlocal' then
+ m.setNode(source, m.compileNode(ref.value))
+ end
+ end
+ end
+ end)
+ : case 'getlocal'
+ : call(function (source)
+ m.setNode(source, m.compileNode(source.node))
+ end)
+ : case 'setfield'
+ : case 'setmethod'
+ : case 'setindex'
+ : call(function (source)
+ compileByLocalID(source)
+ end)
+ : case 'getfield'
+ : case 'getmethod'
+ : case 'getindex'
+ : call(function (source)
+ compileByLocalID(source)
+ compileByParentNode(source)
+ end)
+ : case 'function.return'
+ : call(function (source)
+ local func = source.parent
+ local index = source.index
+ if func.returns then
+ for _, rtn in ipairs(func.returns) do
+ if rtn[index] then
+ m.setNode(source, m.compileNode(rtn[index]))
+ end
+ end
+ end
+ end)
+ : case 'select'
+ : call(function (source, value)
+ local vararg = value.vararg
+ if vararg.type == 'call' then
+ m.setNode(source, getReturn(vararg.node, value.sindex))
+ end
+ end)
+ : getMap()
+
+---@param source parser.object
+---@return vm.node
+function m.compileNode(source)
+ if source._node then
+ return source._node
+ end
+ source._node = false
+ local compiler = compilerMap[source.type]
+ if compiler then
+ compiler(source)
+ end
+ state.subscribeLiteral(source, source._node)
+ return source._node
+end
+
+return m
diff --git a/script/vm/node/global.lua b/script/vm/node/global.lua
new file mode 100644
index 00000000..499e526b
--- /dev/null
+++ b/script/vm/node/global.lua
@@ -0,0 +1,79 @@
+local util = require 'utility'
+
+---@class vm.node.global.link
+---@field gets parser.object[]
+---@field sets parser.object[]
+
+---@class vm.node.global
+---@field links table<uri, vm.node.global.link>
+---@field setsCache parser.object[]
+---@field getsCache parser.object[]
+local mt = {}
+mt.__index = mt
+mt.type = 'global'
+mt.name = ''
+
+---@param uri uri
+---@param source parser.object
+function mt:addSet(uri, source)
+ local link = self.links[uri]
+ link.sets[#link.sets+1] = source
+end
+
+---@param uri uri
+---@param source parser.object
+function mt:addGet(uri, source)
+ local link = self.links[uri]
+ link.gets[#link.gets+1] = source
+end
+
+---@return parser.object[]
+function mt:getSets()
+ if not self.setsCache then
+ self.setsCache = {}
+ for _, link in pairs(self.links) do
+ for _, source in ipairs(link.sets) do
+ self.setsCache[#self.setsCache+1] = source
+ end
+ end
+ end
+ return self.setsCache
+end
+
+---@return parser.object[]
+function mt:getGets()
+ if not self.getsCache then
+ self.getsCache = {}
+ for _, link in pairs(self.links) do
+ for _, source in ipairs(link.gets) do
+ self.getsCache[#self.getsCache+1] = source
+ end
+ end
+ end
+ return self.getsCache
+end
+
+---@param uri uri
+function mt:dropUri(uri)
+ self.links[uri] = nil
+ self.setsCache = nil
+ self.getsCache = nil
+end
+
+---@return string
+function mt:getName()
+ return self.name
+end
+
+---@return vm.node.global
+return function (name)
+ return setmetatable({
+ name = name,
+ links = util.defaultTable(function ()
+ return {
+ sets = {},
+ gets = {},
+ }
+ end),
+ }, mt)
+end
diff --git a/script/vm/node/union.lua b/script/vm/node/union.lua
new file mode 100644
index 00000000..a8c917d9
--- /dev/null
+++ b/script/vm/node/union.lua
@@ -0,0 +1,49 @@
+local state = require 'vm.state'
+
+---@class vm.node.union
+local mt = {}
+mt.__index = mt
+mt.type = 'union'
+
+---@param node vm.node
+function mt:merge(node)
+ if not node then
+ return
+ end
+ if node.type == 'union' then
+ for _, c in ipairs(node) do
+ self[#self+1] = c
+ end
+ else
+ self[#self+1] = node
+ end
+end
+
+---@param source parser.object
+function mt:subscribeLiteral(source)
+ for _, c in ipairs(self) do
+ state.subscribeLiteral(source, c)
+ if c.type == 'cross' then
+ c:subscribeLiteral(source)
+ end
+ end
+end
+
+function mt:eachNode()
+ local i = 0
+ return function ()
+ i = i + 1
+ return self[i]
+ end
+end
+
+---@param me parser.object
+---@param node vm.node
+---@return vm.node.union
+return function (me, node)
+ local union = setmetatable({
+ [1] = me,
+ }, mt)
+ union:merge(node)
+ return union
+end
diff --git a/script/vm/state.lua b/script/vm/state.lua
new file mode 100644
index 00000000..b0689384
--- /dev/null
+++ b/script/vm/state.lua
@@ -0,0 +1,80 @@
+local util = require 'utility'
+local files = require 'files'
+local globalNode = require 'vm.global-node'
+local guide = require 'parser.guide'
+
+---@class vm.state
+local m = {}
+---@type table<uri, parser.object[]>
+m.literals = util.multiTable(2)
+---@type table<parser.object, table<parser.object, boolean>>
+m.literalSubs = util.multiTable(2, function ()
+ return setmetatable({}, util.MODE_K)
+end)
+---@type table<parser.object, boolean>
+m.allLiterals = {}
+
+---@param source parser.object
+function m.declareLiteral(source)
+ if m.allLiterals[source] then
+ return
+ end
+ m.allLiterals[source] = true
+ local uri = guide.getUri(source)
+ local literals = m.literals[uri]
+ literals[#literals+1] = source
+end
+
+---@param source parser.object
+---@param node vm.node
+function m.subscribeLiteral(source, node)
+ if not node then
+ return
+ end
+ if node.type == 'union'
+ or node.type == 'cross' then
+ node:subscribeLiteral(source)
+ return
+ end
+ if not m.allLiterals[source] then
+ return
+ end
+ m.literalSubs[node][source] = true
+end
+
+---@param uri uri
+function m.dropUri(uri)
+ local literals = m.literals[uri]
+ m.literals[uri] = nil
+ for _, literal in ipairs(literals) do
+ m.allLiterals[literal] = nil
+ local literalSubs = m.literalSubs[literal]
+ m.literalSubs[literal] = nil
+ for source in pairs(literalSubs) do
+ source._node = nil
+ end
+ end
+end
+
+for uri in files.eachFile() do
+ local state = files.getState(uri)
+ if state then
+ globalNode.compileAst(state.ast)
+ end
+end
+
+files.watch(function (ev, uri)
+ if ev == 'update' then
+ local state = files.getState(uri)
+ if state then
+ globalNode.compileAst(state.ast)
+ end
+ end
+ if ev == 'remove' then
+ m.dropUri(uri)
+ globalNode.dropUri(uri)
+ end
+end)
+
+
+return m
diff --git a/script/vm/vm.lua b/script/vm/vm.lua
index aa18ea73..ff893f24 100644
--- a/script/vm/vm.lua
+++ b/script/vm/vm.lua
@@ -1,11 +1,8 @@
local guide = require 'parser.guide'
-local util = require 'utility'
local files = require 'files'
local timer = require 'timer'
local setmetatable = setmetatable
-local running = coroutine.running
-local ipairs = ipairs
local log = log
local xpcall = xpcall
local mathHuge = math.huge