diff options
-rw-r--r-- | script/parser/guide.lua | 2 | ||||
-rw-r--r-- | script/vm/compiler.lua | 1 | ||||
-rw-r--r-- | script/vm/runner.lua | 136 |
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 |