summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--script/parser/guide.lua2
-rw-r--r--script/vm/compiler.lua1
-rw-r--r--script/vm/runner.lua136
3 files changed, 90 insertions, 49 deletions
diff --git a/script/parser/guide.lua b/script/parser/guide.lua
index 906a9926..f15e6e72 100644
--- a/script/parser/guide.lua
+++ b/script/parser/guide.lua
@@ -56,6 +56,7 @@ local type = type
---@field init parser.object
---@field step parser.object
---@field redundant { max: integer, passed: integer }
+---@field filter parser.object
---@field _root parser.object
---@class guide
@@ -71,6 +72,7 @@ local blockTypes = {
['repeat'] = true,
['do'] = true,
['function'] = true,
+ ['if'] = true,
['ifblock'] = true,
['elseblock'] = true,
['elseifblock'] = true,
diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua
index 5ed7d069..da45b5d3 100644
--- a/script/vm/compiler.lua
+++ b/script/vm/compiler.lua
@@ -881,6 +881,7 @@ local compilerSwitch = util.switch()
else
vm.setNode(src, node)
end
+ return vm.getNode(src)
elseif src.type == 'getlocal' then
vm.setNode(src, node, true)
end
diff --git a/script/vm/runner.lua b/script/vm/runner.lua
index d0825389..2d3309d5 100644
--- a/script/vm/runner.lua
+++ b/script/vm/runner.lua
@@ -2,87 +2,125 @@
local vm = require 'vm.vm'
local guide = require 'parser.guide'
----@class vm.local-compiler
+---@class vm.runner
---@field loc parser.object
---@field mainBlock parser.object
----@field blocks table<parser.object, table>
+---@field blocks table<parser.object, true>
+---@field steps vm.runner.step[]
local mt = {}
mt.__index = mt
mt.index = 1
-
---@class parser.object
----@field _hasSorted boolean
+---@field _hasSorted boolean
----@param source parser.object
-local function sortRefs(source)
- if source._hasSorted then
- return
+---@class vm.runner.step
+---@field type 'truly' | 'as' | 'object' | 'save' | 'load'
+---@field pos integer
+---@field node? vm.node
+---@field object? parser.object
+---@field ref? vm.runner.step
+
+---@param filter parser.object
+---@param pos integer
+function mt:_compileNarrowByFilter(filter, pos)
+ if filter.type == 'unary' then
+ elseif filter.type == 'binary' then
+ else
+ if filter.type == 'getlocal' and filter.node == self.loc then
+ self.steps[#self.steps+1] = {
+ type = 'truly',
+ pos = pos,
+ }
+ end
end
- source._hasSorted = true
- table.sort(source.ref, function (a, b)
- return (a.range or a.start) < (b.range or b.start)
- end)
end
----@param node vm.node
+function mt:_dropBlock(block)
+ local savePoint = {
+ type = 'save',
+ pos = block.start,
+ }
+ self.steps[#self.steps+1] = savePoint
+ self.steps[#self.steps+1] = {
+ type = 'load',
+ pos = block.finish,
+ ref = savePoint,
+ }
+end
+
---@param block parser.object
----@return vm.node
-function mt:_compileBlock(node, block)
- for _ = 1, 10000 do
- if self.blocks[block]
- or self.mainBlock == block
- or block.type == 'function'
- or block.type == 'main' then
- return node
+function mt:_compileBlock(block)
+ if self.blocks[block] then
+ return
+ end
+ self.blocks[block] = true
+ if block == self.mainBlock then
+ return
+ end
+
+ local parentBlock = guide.getParentBlock(block)
+ self:_compileBlock(parentBlock)
+
+ if block.type == 'ifblock' then
+ if block[1] then
+ self:_compileNarrowByFilter(block.filter, block[1].start)
end
- self.blocks[block] = {}
- block = guide.getParentBlock(block)
end
- error('compile block overstack')
+
+ if block.type == 'if' then
+ self:_dropBlock(block)
+ end
+
+ if block.type == 'function' then
+ self:_dropBlock(block)
+ end
end
----@param node vm.node
----@param currentBlock parser.object
----@param callback fun(src: parser.object, node: vm.node)
----@return vm.node
-function mt:_runBlock(node, currentBlock, callback)
- local currentNode = self:_compileBlock(node, currentBlock)
- for _ = 1, 10000 do
- local ref = self.loc.ref[self.index]
- if not ref
- or ref.start > currentBlock.finish then
- return node
- end
+function mt:_preCompile()
+ for _, ref in ipairs(self.loc.ref) do
+ self.steps[#self.steps+1] = {
+ type = 'object',
+ object = ref,
+ pos = ref.start,
+ }
local block = guide.getParentBlock(ref)
- if block == currentBlock then
- callback(ref, currentNode)
- self.index = self.index + 1
- if ref.type == 'setlocal' then
- currentNode = vm.getNode(ref)
- end
- else
- currentNode = self:_runBlock(currentNode, block, callback)
- end
+ self:_compileBlock(block)
end
- error('run block overstack')
+ table.sort(self.steps, function (a, b)
+ return a.pos < b.pos
+ end)
end
---@param callback fun(src: parser.object, node: vm.node)
function mt:launch(callback)
- self:_runBlock(vm.getNode(self.loc), self.mainBlock, callback)
+ local node = vm.getNode(self.loc)
+ for _, step in ipairs(self.steps) do
+ if step.type == 'truly' then
+ node = node:copyTruly()
+ elseif step.type == 'as' then
+ elseif step.type == 'object' then
+ node = callback(step.object, node) or node
+ elseif step.type == 'save' then
+ -- Nothing need to do
+ elseif step.type == 'load' then
+ node = step.ref.node
+ end
+ step.node = node
+ end
end
---@param loc parser.object
----@return vm.local-compiler
+---@return vm.runner
function vm.createRunner(loc)
local self = setmetatable({
loc = loc,
mainBlock = guide.getParentBlock(loc),
blocks = {},
+ steps = {},
}, mt)
- sortRefs(loc)
+ self:_preCompile()
return self
end