diff options
-rw-r--r-- | script/vm/runner.lua | 182 | ||||
-rw-r--r-- | test/type_inference/init.lua | 31 |
2 files changed, 109 insertions, 104 deletions
diff --git a/script/vm/runner.lua b/script/vm/runner.lua index 721e8c7f..cda66347 100644 --- a/script/vm/runner.lua +++ b/script/vm/runner.lua @@ -22,19 +22,21 @@ mt.index = 1 ---@field node? vm.node ---@field object? parser.object ---@field name? string +---@field tag? string ---@field copy? boolean ---@field ref1? vm.runner.step ---@field ref2? vm.runner.step ----@param filter parser.object ----@param pos integer -function mt:_compileNarrowByFilter(filter, pos) +---@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, pos) + self:_compileNarrowByFilter(filter.exp, outStep, blockStep) end return end @@ -48,13 +50,14 @@ function mt:_compileNarrowByFilter(filter, pos) if exp.type == 'getlocal' and exp.node == self.loc then self.steps[#self.steps+1] = { type = 'truly', - pos = pos, - order = 2, + pos = filter.finish, + ref1 = outStep, } self.steps[#self.steps+1] = { type = 'falsy', - pos = pos, - order = 4, + copy = true, + pos = filter.finish, + ref1 = blockStep, } end end @@ -65,8 +68,8 @@ function mt:_compileNarrowByFilter(filter, pos) return end if filter.op.type == 'and' then - self:_compileNarrowByFilter(filter[1], pos) - self:_compileNarrowByFilter(filter[2], pos) + self:_compileNarrowByFilter(filter[1], outStep, blockStep) + self:_compileNarrowByFilter(filter[2], outStep, blockStep) end if filter.op.type == '==' or filter.op.type == '~=' then @@ -86,28 +89,30 @@ function mt:_compileNarrowByFilter(filter, pos) self.steps[#self.steps+1] = { type = 'remove', name = exp.type, - pos = pos, - order = 2, + pos = filter.finish, + ref1 = outStep, } self.steps[#self.steps+1] = { type = 'as', name = exp.type, - pos = pos, - order = 4, + copy = true, + pos = filter.finish, + ref1 = blockStep, } end if filter.op.type == '~=' then self.steps[#self.steps+1] = { type = 'as', name = exp.type, - pos = pos, - order = 2, + pos = filter.finish, + ref1 = outStep, } self.steps[#self.steps+1] = { type = 'remove', name = exp.type, - pos = pos, - order = 4, + copy = true, + pos = filter.finish, + ref1 = blockStep, } end end @@ -116,13 +121,14 @@ function mt:_compileNarrowByFilter(filter, pos) if filter.type == 'getlocal' and filter.node == self.loc then self.steps[#self.steps+1] = { type = 'falsy', - pos = pos, - order = 2, + pos = filter.finish, + ref1 = outStep, } self.steps[#self.steps+1] = { type = 'truly', - pos = pos, - order = 4, + copy = true, + pos = filter.finish, + ref1 = blockStep, } end end @@ -145,69 +151,39 @@ function mt:_compileBlock(block) ---@type vm.runner.step[] local finals = {} for _, childBlock in ipairs(block) do - if #childBlock > 0 then - local initState = { - type = 'save', - copy = true, - pos = childBlock.start, - order = 1, - } - local outState = { - type = 'save', - copy = true, - pos = childBlock.start, - order = 2, - } - local filterState = { - type = 'save', - copy = true, - pos = childBlock.start, - order = 3, - } - self.steps[#self.steps+1] = initState - self.steps[#self.steps+1] = outState - self.steps[#self.steps+1] = filterState - self.steps[#self.steps+1] = { - type = 'load', - ref1 = outState, - pos = childBlock[1].start - 1, - order = 1, - } - self.steps[#self.steps+1] = { - type = 'load', - ref1 = initState, - pos = childBlock[1].start - 1, - order = 3, - } - self:_compileNarrowByFilter(childBlock.filter, childBlock[1].start - 1) - if childBlock.returns then - self.steps[#self.steps+1] = { - type = 'load', - ref1 = outState, - pos = childBlock.finish, - order = 1, - } - else - local finalState = { - type = 'save', - pos = childBlock.finish, - order = 1, - } - finals[#finals+1] = finalState - self.steps[#self.steps+1] = finalState - self.steps[#self.steps+1] = { - type = 'load', - ref1 = outState, - pos = childBlock.finish, - order = 2, - } - end + local outStep = { + type = 'save', + tag = 'out', + copy = true, + pos = block.start, + order = 1, + } + self.steps[#self.steps+1] = outStep + local blockStep = { + type = 'load', + tag = 'block', + copy = true, + ref = outStep, + pos = childBlock.start, + order = 2, + } + self.steps[#self.steps+1] = blockStep + self:_compileNarrowByFilter(childBlock.filter, outStep, blockStep) + if not childBlock.returns then + finals[#finals+1] = blockStep end + self.steps[#self.steps+1] = { + type = 'load', + tag = 'final', + ref1 = outStep, + pos = childBlock.finish, + order = 1, + } end for i, final in ipairs(finals) do self.steps[#self.steps+1] = { type = 'merge', - ref1 = final, + ref2 = final, pos = block.finish, order = i, } @@ -215,10 +191,16 @@ function mt:_compileBlock(block) end if block.type == 'function' then + self.steps[#self.steps+1] = { + type = 'load', + pos = block.start, + order = 1, + } local savePoint = { - type = 'save', - copy = true, - pos = block.start, + type = 'save', + copy = true, + pos = block.start, + order = 2, } self.steps[#self.steps+1] = savePoint self.steps[#self.steps+1] = { @@ -286,34 +268,52 @@ end ---@param callback fun(src: parser.object, node: vm.node) function mt:launch(callback) - local node = vm.getNode(self.loc):copy() + local topNode = vm.getNode(self.loc):copy() + ---@type vm.runner.step + local context for _, step in ipairs(self.steps) do + local node = (step.ref1 and step.ref1.node) + or (context and context.node) + or topNode if step.copy then node = node:copy() + if context then + context.node = node + end end if step.type == 'truly' then node:setTruly() elseif step.type == 'falsy' then node:setFalsy() elseif step.type == 'as' then - node = vm.createNode(globalMgr.getGlobal('type', step.name)) + topNode = vm.createNode(globalMgr.getGlobal('type', step.name)) + if step.ref1 then + step.ref1.node = topNode + elseif context then + context.node = topNode + end elseif step.type == 'add' then node:merge(globalMgr.getGlobal('type', step.name)) elseif step.type == 'remove' then node:remove(step.name) elseif step.type == 'object' then - node = callback(step.object, node) or node + topNode = callback(step.object, node) or node if step.object.type == 'getlocal' then - node = checkAssert(step.object, node) + topNode = checkAssert(step.object, node) + end + if step.ref1 then + step.ref1.node = topNode + elseif context then + context.node = topNode end elseif step.type == 'save' then - -- nothing to do + step.node = node elseif step.type == 'load' then - node = step.ref1.node + context = step + context.node = node elseif step.type == 'merge' then - node:merge(step.ref1.node) + node:merge(step.ref2.node) end - step.node = node end end diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua index 357dd04b..edb8ff6b 100644 --- a/test/type_inference/init.lua +++ b/test/type_inference/init.lua @@ -1744,18 +1744,15 @@ end ]] --[[ #0 integer? -save 1 #1 integer? --ifblock --block中的初始状态 -save 2 #2 integer? --ifblock --block外的状态 -save 3 #3 integer? --ifblock --filter的状态 -object get #3 integer? --if x then -load 2 #2 integer? --ifblock -falsy 2 #2 ? --ifblock -load 1 #1 integer? --ifblock -truly #1 integer --ifblock -object get #1 integer --print(x) -save 4 #?(1) integer --block中的最终状态 -load 2 #2 ? --ifblock -- block -merge 4 #2 --if 最终状态 +save 1 #1 integer? --ifblock --block外的状态 +load 2 #2 integer? --ifblock --block中的初始状态 +object get #2 integer? --if x then +truly 2 #2 integer --ifblock +falsy 1 #1 ? +object get #2 integer --print(x) +save 3 #?(2) integer --block中的最终状态 +load 1 #2 ? --ifblock -- block +merge 3 #2 --if 最终状态 ]] TEST 'integer?' [[ @@ -1800,7 +1797,7 @@ end print(x) ]] -TEST 'integer?' [[ +TEST 'integer|nil' [[ ---@type integer? local x @@ -1945,3 +1942,11 @@ assert(x == 1) print(<?x?>) ]] + +TEST 'integer' [[ +---@type integer? +local x + +if x and <?x?>.y then +end +]] |