diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2022-06-13 22:46:02 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2022-06-13 22:46:02 +0800 |
commit | 32fbab2b26bdb6b4c00ed8f467f12e5161ba4c31 (patch) | |
tree | b109f2746be0693a8967734393cd775a876cdb12 | |
parent | ed16d2f27b0c70d5d845435708da387db485719e (diff) | |
download | lua-language-server-32fbab2b26bdb6b4c00ed8f467f12e5161ba4c31.zip |
new runner
-rw-r--r-- | script/core/completion/completion.lua | 4 | ||||
-rw-r--r-- | script/core/hover/description.lua | 9 | ||||
-rw-r--r-- | script/vm/compiler.lua | 3 | ||||
-rw-r--r-- | script/vm/infer.lua | 5 | ||||
-rw-r--r-- | script/vm/runner-bak.lua | 444 | ||||
-rw-r--r-- | script/vm/runner.lua | 454 | ||||
-rw-r--r-- | script/vm/sign.lua | 4 |
7 files changed, 522 insertions, 401 deletions
diff --git a/script/core/completion/completion.lua b/script/core/completion/completion.lua index d7c210c6..285f5bf2 100644 --- a/script/core/completion/completion.lua +++ b/script/core/completion/completion.lua @@ -1132,7 +1132,7 @@ local function checkTypingEnum(state, position, defs, str, results) or def.type == 'doc.type.integer' or def.type == 'doc.type.boolean' then enums[#enums+1] = { - label = vm.viewObject(def), + label = vm.viewObject(def, state.uri), description = def.comment and def.comment.text, kind = define.CompletionItemKind.EnumMember, } @@ -1427,7 +1427,7 @@ local function tryCallArg(state, position, results) or src.type == 'doc.type.integer' or src.type == 'doc.type.boolean' then enums[#enums+1] = { - label = vm.viewObject(src), + label = vm.viewObject(src, state.uri), description = src.comment, kind = define.CompletionItemKind.EnumMember, } diff --git a/script/core/hover/description.lua b/script/core/hover/description.lua index 3fef1a21..c96aaae3 100644 --- a/script/core/hover/description.lua +++ b/script/core/hover/description.lua @@ -144,7 +144,7 @@ local function tryDocModule(source) return collectRequire('require', source.module, guide.getUri(source)) end -local function buildEnumChunk(docType, name) +local function buildEnumChunk(docType, name, uri) if not docType then return nil end @@ -175,7 +175,7 @@ local function buildEnumChunk(docType, name) (enum.default and '->') or (enum.additional and '+>') or ' |', - vm.viewObject(enum) + vm.viewObject(enum, uri) ) if enum.comment then local first = true @@ -199,6 +199,7 @@ local function getBindEnums(source, docGroup) return end + local uri = guide.getUri(source) local mark = {} local chunks = {} local returnIndex = 0 @@ -209,7 +210,7 @@ local function getBindEnums(source, docGroup) goto CONTINUE end mark[name] = true - chunks[#chunks+1] = buildEnumChunk(doc.extends, name) + chunks[#chunks+1] = buildEnumChunk(doc.extends, name, uri) elseif doc.type == 'doc.return' then for _, rtn in ipairs(doc.returns) do returnIndex = returnIndex + 1 @@ -218,7 +219,7 @@ local function getBindEnums(source, docGroup) goto CONTINUE end mark[name] = true - chunks[#chunks+1] = buildEnumChunk(rtn, name) + chunks[#chunks+1] = buildEnumChunk(rtn, name, uri) end end ::CONTINUE:: diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index 9b871553..0cbe2b7a 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -998,8 +998,7 @@ local compilerSwitch = util.switch() local hasMark = vm.getNode(source):getData 'hasDefined' - local runner = vm.createRunner(source) - runner:launch(function (src, node) + vm.launchRunner(source, function (src, node) if src.type == 'setlocal' then if src.bindDocs then for _, doc in ipairs(src.bindDocs) do diff --git a/script/vm/infer.lua b/script/vm/infer.lua index 712cff10..9bcd3963 100644 --- a/script/vm/infer.lua +++ b/script/vm/infer.lua @@ -417,7 +417,8 @@ function mt:viewClass() end ---@param source parser.object +---@param uri uri ---@return string? -function vm.viewObject(source) - return viewNodeSwitch(source.type, source, {}, guide.getUri(source)) +function vm.viewObject(source, uri) + return viewNodeSwitch(source.type, source, {}, uri) end diff --git a/script/vm/runner-bak.lua b/script/vm/runner-bak.lua new file mode 100644 index 00000000..5535f0ca --- /dev/null +++ b/script/vm/runner-bak.lua @@ -0,0 +1,444 @@ +---@class vm +local vm = require 'vm.vm' +local guide = require 'parser.guide' + +---@class vm.runner-bak +---@field loc parser.object +---@field mainBlock parser.object +---@field blocks table<parser.object, true> +---@field steps vm.runner.step[] +local mt = {} +mt.__index = mt +mt.index = 1 + +---@class parser.object +---@field _casts parser.object[] + +---@class vm.runner.step +---@field type 'truthy' | 'falsy' | 'as' | 'add' | 'remove' | 'object' | 'save' | 'push' | 'merge' | 'cast' +---@field pos integer +---@field order? integer +---@field node? vm.node +---@field object? parser.object +---@field name? string +---@field cast? parser.object +---@field tag? string +---@field copy? boolean +---@field new? boolean +---@field ref1? vm.runner.step +---@field ref2? vm.runner.step + +---@param filter parser.object +---@param outStep vm.runner.step +---@param blockStep vm.runner.step +function mt:_compileNarrowByFilter(filter, outStep, blockStep) + if not filter then + return + end + if filter.type == 'paren' then + if filter.exp then + self:_compileNarrowByFilter(filter.exp, outStep, blockStep) + end + return + end + if filter.type == 'unary' then + if not filter.op + or not filter[1] then + return + end + if filter.op.type == 'not' then + local exp = filter[1] + if exp.type == 'getlocal' and exp.node == self.loc then + self.steps[#self.steps+1] = { + type = 'falsy', + pos = filter.finish, + new = true, + } + self.steps[#self.steps+1] = { + type = 'truthy', + pos = filter.finish, + ref1 = outStep, + } + end + end + elseif filter.type == 'binary' then + if not filter.op + or not filter[1] + or not filter[2] then + return + end + if filter.op.type == 'and' then + local dummyStep = { + type = 'save', + copy = true, + ref1 = outStep, + pos = filter.start - 1, + } + self.steps[#self.steps+1] = dummyStep + self:_compileNarrowByFilter(filter[1], dummyStep, blockStep) + self:_compileNarrowByFilter(filter[2], dummyStep, blockStep) + end + if filter.op.type == 'or' then + self:_compileNarrowByFilter(filter[1], outStep, blockStep) + local dummyStep = { + type = 'push', + copy = true, + ref1 = outStep, + pos = filter.op.finish, + } + self.steps[#self.steps+1] = dummyStep + self:_compileNarrowByFilter(filter[2], outStep, dummyStep) + self.steps[#self.steps+1] = { + type = 'push', + tag = 'or reset', + ref1 = blockStep, + pos = filter.finish, + } + end + if filter.op.type == '==' + or filter.op.type == '~=' then + local loc, exp + for i = 1, 2 do + loc = filter[i] + if loc.type == 'getlocal' and loc.node == self.loc then + exp = filter[i % 2 + 1] + break + end + end + if not loc or not exp then + return + end + if guide.isLiteral(exp) then + if filter.op.type == '==' then + self.steps[#self.steps+1] = { + type = 'remove', + name = exp.type, + pos = filter.finish, + ref1 = outStep, + } + self.steps[#self.steps+1] = { + type = 'as', + name = exp.type, + pos = filter.finish, + new = true, + } + end + if filter.op.type == '~=' then + self.steps[#self.steps+1] = { + type = 'as', + name = exp.type, + pos = filter.finish, + ref1 = outStep, + } + self.steps[#self.steps+1] = { + type = 'remove', + name = exp.type, + pos = filter.finish, + new = true, + } + end + end + end + else + if filter.type == 'getlocal' and filter.node == self.loc then + self.steps[#self.steps+1] = { + type = 'truthy', + pos = filter.finish, + new = true, + } + self.steps[#self.steps+1] = { + type = 'falsy', + pos = filter.finish, + ref1 = outStep, + } + end + end +end + +---@param block parser.object +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 == 'if' then + ---@type vm.runner.step[] + local finals = {} + for i, childBlock in ipairs(block) do + local blockStep = { + type = 'save', + tag = 'block', + copy = true, + pos = childBlock.start, + } + local outStep = { + type = 'save', + tag = 'out', + copy = true, + pos = childBlock.start, + } + self.steps[#self.steps+1] = blockStep + self.steps[#self.steps+1] = outStep + self.steps[#self.steps+1] = { + type = 'push', + ref1 = blockStep, + pos = childBlock.start, + } + self:_compileNarrowByFilter(childBlock.filter, outStep, blockStep) + if not childBlock.hasReturn + and not childBlock.hasGoTo + and not childBlock.hasBreak then + local finalStep = { + type = 'save', + pos = childBlock.finish, + tag = 'final #' .. i, + } + finals[#finals+1] = finalStep + self.steps[#self.steps+1] = finalStep + end + self.steps[#self.steps+1] = { + type = 'push', + tag = 'reset child', + ref1 = outStep, + pos = childBlock.finish, + } + end + self.steps[#self.steps+1] = { + type = 'push', + tag = 'reset if', + pos = block.finish, + copy = true, + } + for _, final in ipairs(finals) do + self.steps[#self.steps+1] = { + type = 'merge', + ref2 = final, + pos = block.finish, + } + end + end + + if block.type == 'function' + or block.type == 'while' + or block.type == 'loop' + or block.type == 'in' + or block.type == 'repeat' + or block.type == 'for' then + local savePoint = { + type = 'save', + copy = true, + pos = block.start, + } + self.steps[#self.steps+1] = { + type = 'push', + copy = true, + pos = block.start, + } + self.steps[#self.steps+1] = savePoint + self.steps[#self.steps+1] = { + type = 'push', + pos = block.finish, + ref1 = savePoint, + } + end +end + +---@return parser.object[] +function mt:_getCasts() + local root = guide.getRoot(self.loc) + if not root._casts then + root._casts = {} + local docs = root.docs + for _, doc in ipairs(docs) do + if doc.type == 'doc.cast' and doc.loc then + root._casts[#root._casts+1] = doc + end + end + end + return root._casts +end + +function mt:_preCompile() + local startPos = self.loc.start + local finishPos = 0 + + for _, ref in ipairs(self.loc.ref) do + self.steps[#self.steps+1] = { + type = 'object', + object = ref, + pos = ref.range or ref.start, + } + if ref.start > finishPos then + finishPos = ref.start + end + local block = guide.getParentBlock(ref) + self:_compileBlock(block) + end + + for i, step in ipairs(self.steps) do + if step.type ~= 'object' then + step.order = i + end + end + + local casts = self:_getCasts() + for _, cast in ipairs(casts) do + if cast.loc[1] == self.loc[1] + and cast.start > startPos + and cast.finish < finishPos + and guide.getLocal(self.loc, self.loc[1], cast.start) == self.loc then + self.steps[#self.steps+1] = { + type = 'cast', + cast = cast, + pos = cast.start, + } + end + end + + table.sort(self.steps, function (a, b) + if a.pos == b.pos then + return (a.order or 0) < (b.order or 0) + else + return a.pos < b.pos + end + end) +end + +---@param loc parser.object +---@param node vm.node +---@return vm.node +local function checkAssert(loc, node) + local parent = loc.parent + if parent.type == 'binary' then + if parent.op and (parent.op.type == '~=' or parent.op.type == '==') then + local exp + for i = 1, 2 do + if parent[i] == loc then + exp = parent[i % 2 + 1] + end + end + if exp and guide.isLiteral(exp) then + local callargs = parent.parent + if callargs.type == 'callargs' + and callargs.parent.node.special == 'assert' + and callargs[1] == parent then + if parent.op.type == '~=' then + node:remove(exp.type) + end + if parent.op.type == '==' then + node = vm.compileNode(exp) + end + end + end + end + end + if parent.type == 'callargs' + and parent.parent.node.special == 'assert' + and parent[1] == loc then + node:setTruthy() + end + return node +end + +---@param callback fun(src: parser.object, node: vm.node) +function mt:launch(callback) + local topNode = vm.getNode(self.loc):copy() + for _, step in ipairs(self.steps) do + local node = step.ref1 and step.ref1.node or topNode + if step.type == 'truthy' then + if step.new then + node = node:copy() + topNode = node + end + node:setTruthy() + elseif step.type == 'falsy' then + if step.new then + node = node:copy() + topNode = node + end + node:setFalsy() + elseif step.type == 'as' then + if step.new then + topNode = vm.createNode(vm.getGlobal('type', step.name)) + else + node:clear() + node:merge(vm.getGlobal('type', step.name)) + end + elseif step.type == 'add' then + if step.new then + node = node:copy() + topNode = node + end + node:merge(vm.getGlobal('type', step.name)) + elseif step.type == 'remove' then + if step.new then + node = node:copy() + topNode = node + end + node:remove(step.name) + elseif step.type == 'object' then + topNode = callback(step.object, node) or node + if step.object.type == 'getlocal' then + topNode = checkAssert(step.object, node) + end + elseif step.type == 'save' then + if step.copy then + node = node:copy() + end + step.node = node + elseif step.type == 'push' then + if step.copy then + node = node:copy() + end + topNode = node + elseif step.type == 'merge' then + node:merge(step.ref2.node) + elseif step.type == 'cast' then + topNode = node:copy() + for _, cast in ipairs(step.cast.casts) do + if cast.mode == '+' then + if cast.optional then + topNode:addOptional() + end + if cast.extends then + topNode:merge(vm.compileNode(cast.extends)) + end + elseif cast.mode == '-' then + if cast.optional then + topNode:removeOptional() + end + if cast.extends then + topNode:removeNode(vm.compileNode(cast.extends)) + end + else + if cast.extends then + topNode:clear() + topNode:merge(vm.compileNode(cast.extends)) + end + end + end + end + end +end + +---@param loc parser.object +---@return vm.runner +function vm.launchRunner(loc) + local self = setmetatable({ + loc = loc, + mainBlock = guide.getParentBlock(loc), + blocks = {}, + steps = {}, + }, mt) + + self:_preCompile() + + return self +end diff --git a/script/vm/runner.lua b/script/vm/runner.lua index 9fe0f172..38b0b66c 100644 --- a/script/vm/runner.lua +++ b/script/vm/runner.lua @@ -2,257 +2,19 @@ local vm = require 'vm.vm' local guide = require 'parser.guide' +---@alias vm.runner.callback fun(src: parser.object, node: vm.node) + ---@class vm.runner ----@field loc parser.object ----@field mainBlock parser.object ----@field blocks table<parser.object, true> ----@field steps vm.runner.step[] +---@field _loc parser.object +---@field _objs parser.object[] +---@field _callback vm.runner.callback local mt = {} mt.__index = mt -mt.index = 1 - ----@class parser.object ----@field _casts parser.object[] - ----@class vm.runner.step ----@field type 'truthy' | 'falsy' | 'as' | 'add' | 'remove' | 'object' | 'save' | 'push' | 'merge' | 'cast' ----@field pos integer ----@field order? integer ----@field node? vm.node ----@field object? parser.object ----@field name? string ----@field cast? parser.object ----@field tag? string ----@field copy? boolean ----@field new? boolean ----@field ref1? vm.runner.step ----@field ref2? vm.runner.step - ----@param filter parser.object ----@param outStep vm.runner.step ----@param blockStep vm.runner.step -function mt:_compileNarrowByFilter(filter, outStep, blockStep) - if not filter then - return - end - if filter.type == 'paren' then - if filter.exp then - self:_compileNarrowByFilter(filter.exp, outStep, blockStep) - end - return - end - if filter.type == 'unary' then - if not filter.op - or not filter[1] then - return - end - if filter.op.type == 'not' then - local exp = filter[1] - if exp.type == 'getlocal' and exp.node == self.loc then - self.steps[#self.steps+1] = { - type = 'falsy', - pos = filter.finish, - new = true, - } - self.steps[#self.steps+1] = { - type = 'truthy', - pos = filter.finish, - ref1 = outStep, - } - end - end - elseif filter.type == 'binary' then - if not filter.op - or not filter[1] - or not filter[2] then - return - end - if filter.op.type == 'and' then - local dummyStep = { - type = 'save', - copy = true, - ref1 = outStep, - pos = filter.start - 1, - } - self.steps[#self.steps+1] = dummyStep - self:_compileNarrowByFilter(filter[1], dummyStep, blockStep) - self:_compileNarrowByFilter(filter[2], dummyStep, blockStep) - end - if filter.op.type == 'or' then - self:_compileNarrowByFilter(filter[1], outStep, blockStep) - local dummyStep = { - type = 'push', - copy = true, - ref1 = outStep, - pos = filter.op.finish, - } - self.steps[#self.steps+1] = dummyStep - self:_compileNarrowByFilter(filter[2], outStep, dummyStep) - self.steps[#self.steps+1] = { - type = 'push', - tag = 'or reset', - ref1 = blockStep, - pos = filter.finish, - } - end - if filter.op.type == '==' - or filter.op.type == '~=' then - local loc, exp - for i = 1, 2 do - loc = filter[i] - if loc.type == 'getlocal' and loc.node == self.loc then - exp = filter[i % 2 + 1] - break - end - end - if not loc or not exp then - return - end - if guide.isLiteral(exp) then - if filter.op.type == '==' then - self.steps[#self.steps+1] = { - type = 'remove', - name = exp.type, - pos = filter.finish, - ref1 = outStep, - } - self.steps[#self.steps+1] = { - type = 'as', - name = exp.type, - pos = filter.finish, - new = true, - } - end - if filter.op.type == '~=' then - self.steps[#self.steps+1] = { - type = 'as', - name = exp.type, - pos = filter.finish, - ref1 = outStep, - } - self.steps[#self.steps+1] = { - type = 'remove', - name = exp.type, - pos = filter.finish, - new = true, - } - end - end - end - else - if filter.type == 'getlocal' and filter.node == self.loc then - self.steps[#self.steps+1] = { - type = 'truthy', - pos = filter.finish, - new = true, - } - self.steps[#self.steps+1] = { - type = 'falsy', - pos = filter.finish, - ref1 = outStep, - } - end - end -end - ----@param block parser.object -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 == 'if' then - ---@type vm.runner.step[] - local finals = {} - for i, childBlock in ipairs(block) do - local blockStep = { - type = 'save', - tag = 'block', - copy = true, - pos = childBlock.start, - } - local outStep = { - type = 'save', - tag = 'out', - copy = true, - pos = childBlock.start, - } - self.steps[#self.steps+1] = blockStep - self.steps[#self.steps+1] = outStep - self.steps[#self.steps+1] = { - type = 'push', - ref1 = blockStep, - pos = childBlock.start, - } - self:_compileNarrowByFilter(childBlock.filter, outStep, blockStep) - if not childBlock.hasReturn - and not childBlock.hasGoTo - and not childBlock.hasBreak then - local finalStep = { - type = 'save', - pos = childBlock.finish, - tag = 'final #' .. i, - } - finals[#finals+1] = finalStep - self.steps[#self.steps+1] = finalStep - end - self.steps[#self.steps+1] = { - type = 'push', - tag = 'reset child', - ref1 = outStep, - pos = childBlock.finish, - } - end - self.steps[#self.steps+1] = { - type = 'push', - tag = 'reset if', - pos = block.finish, - copy = true, - } - for _, final in ipairs(finals) do - self.steps[#self.steps+1] = { - type = 'merge', - ref2 = final, - pos = block.finish, - } - end - end - - if block.type == 'function' - or block.type == 'while' - or block.type == 'loop' - or block.type == 'in' - or block.type == 'repeat' - or block.type == 'for' then - local savePoint = { - type = 'save', - copy = true, - pos = block.start, - } - self.steps[#self.steps+1] = { - type = 'push', - copy = true, - pos = block.start, - } - self.steps[#self.steps+1] = savePoint - self.steps[#self.steps+1] = { - type = 'push', - pos = block.finish, - ref1 = savePoint, - } - end -end +mt._index = 1 ---@return parser.object[] function mt:_getCasts() - local root = guide.getRoot(self.loc) + local root = guide.getRoot(self._loc) if not root._casts then root._casts = {} local docs = root.docs @@ -265,180 +27,94 @@ function mt:_getCasts() return root._casts end -function mt:_preCompile() - local startPos = self.loc.start +function mt:_collect() + local startPos = self._loc.start local finishPos = 0 - for _, ref in ipairs(self.loc.ref) do - self.steps[#self.steps+1] = { - type = 'object', - object = ref, - pos = ref.range or ref.start, - } - if ref.start > finishPos then - finishPos = ref.start + for _, ref in ipairs(self._loc.ref) do + if ref.type == 'getlocal' + or ref.type == 'setlocal' then + self._objs[#self._objs+1] = ref + if ref.start > finishPos then + finishPos = ref.start + end end - local block = guide.getParentBlock(ref) - self:_compileBlock(block) end - for i, step in ipairs(self.steps) do - if step.type ~= 'object' then - step.order = i - end + if #self._objs == 0 then + return end local casts = self:_getCasts() for _, cast in ipairs(casts) do - if cast.loc[1] == self.loc[1] + if cast.loc[1] == self._loc[1] and cast.start > startPos and cast.finish < finishPos - and guide.getLocal(self.loc, self.loc[1], cast.start) == self.loc then - self.steps[#self.steps+1] = { - type = 'cast', - cast = cast, - pos = cast.start, - } + and guide.getLocal(self._loc, self._loc[1], cast.start) == self._loc then + self._objs[#self._objs+1] = cast end end - table.sort(self.steps, function (a, b) - if a.pos == b.pos then - return (a.order or 0) < (b.order or 0) - else - return a.pos < b.pos - end + table.sort(self._objs, function (a, b) + return (a.range or a.start) < (b.range or b.start) end) end ----@param loc parser.object + +---@param pos integer ---@param node vm.node +---@return parser.object ---@return vm.node -local function checkAssert(loc, node) - local parent = loc.parent - if parent.type == 'binary' then - if parent.op and (parent.op.type == '~=' or parent.op.type == '==') then - local exp - for i = 1, 2 do - if parent[i] == loc then - exp = parent[i % 2 + 1] - end - end - if exp and guide.isLiteral(exp) then - local callargs = parent.parent - if callargs.type == 'callargs' - and callargs.parent.node.special == 'assert' - and callargs[1] == parent then - if parent.op.type == '~=' then - node:remove(exp.type) - end - if parent.op.type == '==' then - node = vm.compileNode(exp) - end - end - end +function mt:_fastWard(pos, node) + for i = self._index, #self._objs do + local obj = self._objs[i] + if obj.start > pos then + self._index = i + return obj, node + end + if obj.type == 'getlocal' + or obj.type == 'setlocal' then + node = self._callback(obj, node) or node + else + error('unexpected type: ' .. obj.type) end end - if parent.type == 'callargs' - and parent.parent.node.special == 'assert' - and parent[1] == loc then - node:setTruthy() - end - return node end ----@param callback fun(src: parser.object, node: vm.node) -function mt:launch(callback) - local topNode = vm.getNode(self.loc):copy() - for _, step in ipairs(self.steps) do - local node = step.ref1 and step.ref1.node or topNode - if step.type == 'truthy' then - if step.new then - node = node:copy() - topNode = node - end - node:setTruthy() - elseif step.type == 'falsy' then - if step.new then - node = node:copy() - topNode = node - end - node:setFalsy() - elseif step.type == 'as' then - if step.new then - topNode = vm.createNode(vm.getGlobal('type', step.name)) - else - node:clear() - node:merge(vm.getGlobal('type', step.name)) - end - elseif step.type == 'add' then - if step.new then - node = node:copy() - topNode = node - end - node:merge(vm.getGlobal('type', step.name)) - elseif step.type == 'remove' then - if step.new then - node = node:copy() - topNode = node - end - node:remove(step.name) - elseif step.type == 'object' then - topNode = callback(step.object, node) or node - if step.object.type == 'getlocal' then - topNode = checkAssert(step.object, node) - end - elseif step.type == 'save' then - if step.copy then - node = node:copy() - end - step.node = node - elseif step.type == 'push' then - if step.copy then - node = node:copy() - end - topNode = node - elseif step.type == 'merge' then - node:merge(step.ref2.node) - elseif step.type == 'cast' then - topNode = node:copy() - for _, cast in ipairs(step.cast.casts) do - if cast.mode == '+' then - if cast.optional then - topNode:addOptional() - end - if cast.extends then - topNode:merge(vm.compileNode(cast.extends)) - end - elseif cast.mode == '-' then - if cast.optional then - topNode:removeOptional() - end - if cast.extends then - topNode:removeNode(vm.compileNode(cast.extends)) - end - else - if cast.extends then - topNode:clear() - topNode:merge(vm.compileNode(cast.extends)) - end - end - end +---@param block parser.object +---@param node vm.node +function mt:_launchBlock(block, node) + local top, topNode = self:_fastWard(block.start, node) + if not top then + return + end + for _, action in ipairs(block) do + if action.finish < top.start then + goto CONTINUE + end + top, topNode = self:_fastWard(action.finish, topNode) + if not top then + return end + ::CONTINUE:: end + self:_fastWard(math.huge, topNode) end ---@param loc parser.object ----@return vm.runner -function vm.createRunner(loc) +---@param callback vm.runner.callback +function vm.launchRunner(loc, callback) local self = setmetatable({ - loc = loc, - mainBlock = guide.getParentBlock(loc), - blocks = {}, - steps = {}, + _loc = loc, + _objs = {}, + _callback = callback, }, mt) - self:_preCompile() + self:_collect() + + if #self._objs == 0 then + return + end - return self + self:_launchBlock(guide.getParentBlock(loc), vm.getNode(loc)) end diff --git a/script/vm/sign.lua b/script/vm/sign.lua index fe112bc2..5c17aa3d 100644 --- a/script/vm/sign.lua +++ b/script/vm/sign.lua @@ -111,7 +111,7 @@ function mt:resolve(uri, args, removeGeneric) goto CONTINUE end end - local view = vm.viewObject(obj) + local view = vm.viewObject(obj, uri) if view then knownTypes[view] = true end @@ -130,7 +130,7 @@ function mt:resolve(uri, args, removeGeneric) if argNode:hasFalsy() then goto CONTINUE end - local view = vm.viewObject(n) + local view = vm.viewObject(n, uri) if knownTypes[view] then goto CONTINUE end |