summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--script/vm/node/compiler.lua73
-rw-r--r--script/vm/node/union.lua42
-rw-r--r--script/vm/state.lua29
3 files changed, 114 insertions, 30 deletions
diff --git a/script/vm/node/compiler.lua b/script/vm/node/compiler.lua
index 71d872b8..422f464e 100644
--- a/script/vm/node/compiler.lua
+++ b/script/vm/node/compiler.lua
@@ -1,20 +1,21 @@
-local guide = require 'parser.guide'
-local util = require 'utility'
-local state = require 'vm.state'
+local guide = require 'parser.guide'
+local util = require 'utility'
+local state = require 'vm.state'
+local union = require 'vm.node.union'
---@class parser.object
---@field _compiledNodes boolean
----@field _compiled any
+---@field _node vm.node
---@field _globalID vm.node.global
---@class vm.node.compiler
local m = {}
----@class vm.node.unknown
-m.UNKNOWN = { type = 'unknown' }
+---@class vm.node.cross
+
m.GLOBAL_SPLITE = '\x1F'
----@alias vm.node vm.node.unknown | vm.node.global | vm.node.class
+---@alias vm.node parser.object | vm.node.union | vm.node.cross
---@param ... string
---@return string
@@ -22,26 +23,49 @@ function m.getGlobalID(...)
return table.concat({...}, m.GLOBAL_SPLITE)
end
+function m.setNode(source, node)
+ local me = source._node
+ if not me then
+ source._node = node
+ return
+ end
+ if me.type == 'union'
+ or me.type == 'cross' then
+ me:merge(source, node)
+ return
+ end
+ source._node = union(source, node)
+end
+
+local function compileValue(uri, source, value)
+ if not value then
+ return
+ end
+ if value.type == 'table'
+ or value.type == 'integer'
+ or value.type == 'number'
+ or value.type == 'string'
+ or value.type == 'function' then
+ state.declareLiteral(uri, value)
+ m.setNode(source, value)
+ end
+end
+
local compilerMap = util.switch()
: case 'local'
: call(function (uri, source)
- local value = source.value
- if not value then
- return
- end
- if value.type == 'table'
- or value.type == 'integer'
- or value.type == 'number'
- or value.type == 'string'
- or value.type == 'function' then
- source._compiled = value
- state.declareLiteral(uri, value)
- state.subscribeLiteral(value, source)
+ compileValue(uri, source, source.value)
+ if source.ref then
+ for _, ref in ipairs(source.ref) do
+ if ref.type == 'setlocal' then
+ compileValue(uri, source, ref.value)
+ end
+ end
end
end)
: case 'getlocal'
: call(function (uri, source)
- source._compiled = m.compileNode(uri, source.node)
+ m.setNode(source, m.compileNode(uri, source.node))
end)
: getMap()
@@ -49,15 +73,16 @@ local compilerMap = util.switch()
---@param source parser.object
---@return vm.node
function m.compileNode(uri, source)
- if source._compiled then
- return source._compiled
+ if source._node then
+ return source._node
end
- source._compiled = m.UNKNOWN
+ source._node = false
local compiler = compilerMap[source.type]
if compiler then
compiler(uri, source)
end
- return source._compiled
+ state.subscribeLiteral(source, source._node)
+ return source._node
end
local compilerGlobalMap = util.switch()
diff --git a/script/vm/node/union.lua b/script/vm/node/union.lua
new file mode 100644
index 00000000..928a9216
--- /dev/null
+++ b/script/vm/node/union.lua
@@ -0,0 +1,42 @@
+local state = require 'vm.state'
+
+---@class vm.node.union
+local mt = {}
+mt.__index = mt
+mt.type = 'union'
+
+---@param source parser.object
+---@param node vm.node
+function mt:merge(source, 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
+
+---@param source parser.object
+---@param node vm.node
+---@return vm.node.union
+return function (source, node)
+ local union = setmetatable({
+ source,
+ }, mt)
+ union:merge(source, node)
+ return union
+end
diff --git a/script/vm/state.lua b/script/vm/state.lua
index 0048649e..15f4af70 100644
--- a/script/vm/state.lua
+++ b/script/vm/state.lua
@@ -1,5 +1,4 @@
local util = require 'utility'
-local guide = require 'parser.guide'
local global = require 'vm.node.global'
---@class vm.state
@@ -16,6 +15,8 @@ m.literals = util.multiTable(2)
m.literalSubs = util.multiTable(2, function ()
return setmetatable({}, util.MODE_K)
end)
+---@type table<parser.object, boolean>
+m.allLiterals = {}
---@param name string
---@param uri uri
@@ -41,14 +42,29 @@ end
---@param uri uri
---@param source parser.object
function m.declareLiteral(uri, source)
+ if m.allLiterals[source] then
+ return
+ end
+ m.allLiterals[source] = true
local literals = m.literals[uri]
literals[#literals+1] = source
end
----@param literal parser.object
----@param source parser.object
-function m.subscribeLiteral(literal, source)
- m.literalSubs[literal][source] = true
+---@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
@@ -61,10 +77,11 @@ 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._compiled = nil
+ source._node = nil
end
end
end