diff options
-rw-r--r-- | script/vm/node/compiler.lua | 73 | ||||
-rw-r--r-- | script/vm/node/union.lua | 42 | ||||
-rw-r--r-- | script/vm/state.lua | 29 |
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 |