summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--script/vm/node.lua8
-rw-r--r--script/vm/runner.lua162
-rw-r--r--test/type_inference/init.lua87
3 files changed, 166 insertions, 91 deletions
diff --git a/script/vm/node.lua b/script/vm/node.lua
index d3e407b6..3d1a24bc 100644
--- a/script/vm/node.lua
+++ b/script/vm/node.lua
@@ -47,6 +47,14 @@ function mt:isEmpty()
return #self == 0
end
+function mt:clear()
+ self.optional = nil
+ for i, c in ipairs(self) do
+ self[i] = nil
+ self[c] = nil
+ end
+end
+
---@param n integer
---@return vm.object?
function mt:get(n)
diff --git a/script/vm/runner.lua b/script/vm/runner.lua
index ccb3bcfb..dedc48be 100644
--- a/script/vm/runner.lua
+++ b/script/vm/runner.lua
@@ -16,7 +16,7 @@ mt.index = 1
---@field _hasSorted boolean
---@class vm.runner.step
----@field type 'truthy' | 'falsy' | 'as' | 'add' | 'remove' | 'object' | 'save' | 'load' | 'merge'
+---@field type 'truthy' | 'falsy' | 'as' | 'add' | 'remove' | 'object' | 'save' | 'push' | 'merge'
---@field pos integer
---@field order? integer
---@field node? vm.node
@@ -49,15 +49,18 @@ function mt:_compileNarrowByFilter(filter, outStep, blockStep)
local exp = filter[1]
if exp.type == 'getlocal' and exp.node == self.loc then
self.steps[#self.steps+1] = {
- type = 'truthy',
+ type = 'push',
+ copy = true,
pos = filter.finish,
- ref1 = outStep,
}
self.steps[#self.steps+1] = {
type = 'falsy',
- copy = true,
pos = filter.finish,
- ref1 = blockStep,
+ }
+ self.steps[#self.steps+1] = {
+ type = 'truthy',
+ pos = filter.finish,
+ ref1 = outStep,
}
end
end
@@ -68,31 +71,35 @@ function mt:_compileNarrowByFilter(filter, outStep, blockStep)
return
end
if filter.op.type == 'and' then
- self:_compileNarrowByFilter(filter[1], outStep, blockStep)
- self:_compileNarrowByFilter(filter[2], outStep, blockStep)
- end
- if filter.op.type == 'or' then
local dummyStep = {
- type = 'load',
- tag = 'dummy',
+ type = 'save',
copy = true,
ref1 = outStep,
pos = filter.start - 1,
}
self.steps[#self.steps+1] = dummyStep
- self:_compileNarrowByFilter(filter[1], outStep, dummyStep)
- dummyStep = {
- type = 'load',
- tag = 'dummy',
+ self:_compileNarrowByFilter(filter[1], dummyStep, blockStep)
+ self:_compileNarrowByFilter(filter[2], dummyStep, blockStep)
+ end
+ if filter.op.type == 'or' then
+ local dummyStep = {
+ type = 'save',
+ tag = 'dummy out',
copy = true,
ref1 = outStep,
- pos = filter.op.finish,
+ pos = filter.start - 1,
}
self.steps[#self.steps+1] = dummyStep
+ self:_compileNarrowByFilter(filter[1], dummyStep, blockStep)
+ self.steps[#self.steps+1] = {
+ type = 'push',
+ ref1 = dummyStep,
+ pos = filter.op.finish,
+ }
self:_compileNarrowByFilter(filter[2], outStep, dummyStep)
self.steps[#self.steps+1] = {
- type = 'load',
- tag = 'reset',
+ type = 'push',
+ tag = 'or reset',
ref1 = blockStep,
pos = filter.finish,
}
@@ -113,6 +120,11 @@ function mt:_compileNarrowByFilter(filter, outStep, blockStep)
if guide.isLiteral(exp) then
if filter.op.type == '==' then
self.steps[#self.steps+1] = {
+ type = 'push',
+ copy = true,
+ pos = filter.finish,
+ }
+ self.steps[#self.steps+1] = {
type = 'remove',
name = exp.type,
pos = filter.finish,
@@ -121,13 +133,16 @@ function mt:_compileNarrowByFilter(filter, outStep, blockStep)
self.steps[#self.steps+1] = {
type = 'as',
name = exp.type,
- copy = true,
pos = filter.finish,
- ref1 = blockStep,
}
end
if filter.op.type == '~=' then
self.steps[#self.steps+1] = {
+ type = 'push',
+ copy = true,
+ pos = filter.finish,
+ }
+ self.steps[#self.steps+1] = {
type = 'as',
name = exp.type,
pos = filter.finish,
@@ -136,9 +151,7 @@ function mt:_compileNarrowByFilter(filter, outStep, blockStep)
self.steps[#self.steps+1] = {
type = 'remove',
name = exp.type,
- copy = true,
pos = filter.finish,
- ref1 = blockStep,
}
end
end
@@ -146,15 +159,18 @@ function mt:_compileNarrowByFilter(filter, outStep, blockStep)
else
if filter.type == 'getlocal' and filter.node == self.loc then
self.steps[#self.steps+1] = {
- type = 'falsy',
+ type = 'push',
+ copy = true,
pos = filter.finish,
- ref1 = outStep,
}
self.steps[#self.steps+1] = {
type = 'truthy',
- copy = true,
pos = filter.finish,
- ref1 = blockStep,
+ }
+ self.steps[#self.steps+1] = {
+ type = 'falsy',
+ pos = filter.finish,
+ ref1 = outStep,
}
end
end
@@ -176,39 +192,56 @@ function mt:_compileBlock(block)
if block.type == 'if' then
---@type vm.runner.step[]
local finals = {}
- for _, childBlock in ipairs(block) do
- local outStep = {
+ for i, childBlock in ipairs(block) do
+ local blockStep = {
type = 'save',
- tag = 'out',
+ tag = 'block',
copy = true,
pos = block.start,
}
- self.steps[#self.steps+1] = outStep
- local blockStep = {
- type = 'load',
- tag = 'block',
+ 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
- finals[#finals+1] = blockStep
+ 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 = 'load',
- tag = 'final',
+ type = 'push',
+ tag = 'reset child',
ref1 = outStep,
pos = childBlock.finish,
}
end
- for i, final in ipairs(finals) do
+ 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,
+ type = 'merge',
+ ref2 = final,
+ pos = block.finish,
}
end
end
@@ -219,18 +252,19 @@ function mt:_compileBlock(block)
or block.type == 'in'
or block.type == 'repeat'
or block.type == 'for' then
- self.steps[#self.steps+1] = {
- type = 'load',
- pos = block.start,
- }
local savePoint = {
- type = 'save',
+ 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 = 'load',
+ type = 'push',
pos = block.finish,
ref1 = savePoint,
}
@@ -300,29 +334,15 @@ end
---@param callback fun(src: parser.object, node: vm.node)
function mt:launch(callback)
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
+ local node = step.ref1 and step.ref1.node or topNode
if step.type == 'truthy' then
node:setTruthy()
elseif step.type == 'falsy' then
node:setFalsy()
elseif step.type == 'as' then
- topNode = vm.createNode(globalMgr.getGlobal('type', step.name))
- if step.ref1 then
- step.ref1.node = topNode
- elseif context then
- context.node = topNode
- end
+ node:clear()
+ node:merge(globalMgr.getGlobal('type', step.name))
elseif step.type == 'add' then
node:merge(globalMgr.getGlobal('type', step.name))
elseif step.type == 'remove' then
@@ -332,16 +352,16 @@ function mt:launch(callback)
if step.object.type == 'getlocal' then
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
+ if step.copy then
+ node = node:copy()
+ end
step.node = node
- elseif step.type == 'load' then
- step.node = node
- context = step
+ 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)
end
diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua
index 19f868f4..a6f18f65 100644
--- a/test/type_inference/init.lua
+++ b/test/type_inference/init.lua
@@ -1733,6 +1733,23 @@ if <?x?> then
print(x)
end
]]
+--[[
+context 0 integer?
+
+save copy 'block'
+save copy 'out'
+push 'block'
+get
+push copy
+truthy
+falsy ref 'out'
+get
+save HEAD 'final'
+push 'out'
+
+push copy HEAD
+merge 'final'
+]]
TEST 'integer' [[
---@type integer?
@@ -1742,18 +1759,6 @@ if x then
print(<?x?>)
end
]]
---[[
-#0 integer?
-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?' [[
---@type integer?
@@ -1786,6 +1791,27 @@ if xxx and x then
end
]]
+TEST 'integer?' [[
+---@type integer?
+local x
+
+if xxx and x then
+end
+
+print(<?x?>)
+]]
+
+TEST 'integer?' [[
+---@type integer?
+local x
+
+if xxx and x then
+ return
+end
+
+print(<?x?>)
+]]
+
TEST 'integer' [[
---@type integer?
local x
@@ -1965,15 +1991,36 @@ TEST 'integer' [[
---@type integer?
local x
-if x and <?x?> then
+if x and <?x?>.y then
+end
+]]
+
+TEST 'integer?' [[
+---@type integer?
+local x
+
+if x and x.y then
+end
+
+print(<?x?>)
+]]
+
+TEST 'integer?' [[
+---@type integer?
+local x
+
+if x and x.y then
+ return
end
+
+print(<?x?>)
]]
TEST 'integer' [[
---@type integer?
local x
-if not x or <?x?> then
+if not x or <?x?>.y then
end
]]
@@ -1981,7 +2028,7 @@ TEST 'integer?' [[
---@type integer?
local x
-if not x or XXX then
+if not x or x.y then
print(<?x?>)
end
]]
@@ -1990,7 +2037,7 @@ TEST 'integer?' [[
---@type integer?
local x
-if x or XXX then
+if x or x.y then
print(<?x?>)
end
]]
@@ -1999,7 +2046,7 @@ TEST 'integer?' [[
---@type integer?
local x
-if XXX or x then
+if x.y or x then
print(<?x?>)
end
]]
@@ -2008,16 +2055,16 @@ TEST 'integer?' [[
---@type integer?
local x
-if XXX or not x then
+if x.y or not x then
print(<?x?>)
end
]]
-TEST 'integer' [[
+TEST 'integer?' [[
---@type integer?
local x
-if not x or XXX then
+if not x or x.y then
return
end