summaryrefslogtreecommitdiff
path: root/script/vm
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2022-04-23 06:49:32 +0800
committer最萌小汐 <sumneko@hotmail.com>2022-04-23 06:49:32 +0800
commit86557f99ac61fd23f6bb2184f8b9dfb94a76772e (patch)
tree4031107a835710a2fbf9fd052fb493b3c54f3e08 /script/vm
parente8c06f25c2dc3a6a60e498449f29edc62020c0f9 (diff)
downloadlua-language-server-86557f99ac61fd23f6bb2184f8b9dfb94a76772e.zip
merge if results
Diffstat (limited to 'script/vm')
-rw-r--r--script/vm/compiler.lua6
-rw-r--r--script/vm/node.lua92
-rw-r--r--script/vm/runner.lua159
3 files changed, 194 insertions, 63 deletions
diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua
index 8a01cc18..b3c9d950 100644
--- a/script/vm/compiler.lua
+++ b/script/vm/compiler.lua
@@ -978,12 +978,12 @@ local compilerSwitch = util.switch()
if src.type == 'setlocal' then
if src.value and guide.isLiteral(src.value) then
if src.value.type == 'table' then
- vm.setNode(src, src.value)
+ vm.setNode(src, vm.createNode(src.value), true)
else
- vm.setNode(src, vm.compileNode(src.value))
+ vm.setNode(src, vm.compileNode(src.value), true)
end
else
- vm.setNode(src, node)
+ vm.setNode(src, node, true)
end
return vm.getNode(src)
elseif src.type == 'getlocal' then
diff --git a/script/vm/node.lua b/script/vm/node.lua
index b57fa80b..b759ed72 100644
--- a/script/vm/node.lua
+++ b/script/vm/node.lua
@@ -114,43 +114,86 @@ function mt:isNullable()
end
---@return vm.node
-function mt:copyTruly()
- local newNode = vm.createNode()
- newNode.optional = false
- local hasBoolean, hasTrue
- for _, c in ipairs(self) do
+function mt:setTruly()
+ if self.optional == true then
+ self.optional = nil
+ end
+ local hasBoolean
+ local index = 0
+ while true do
+ index = index + 1
+ local c = self[index]
+ if not c then
+ break
+ end
if c.type == 'nil'
or (c.type == 'boolean' and c[1] == false)
or (c.type == 'doc.type.boolean' and c[1] == false) then
- goto CONTINUE
+ table.remove(self, index)
+ self[c] = nil
+ index = index - 1
end
- if c.type == 'global' and c.cate == 'type' and c.name == 'boolean' then
+ if (c.type == 'global' and c.cate == 'type' and c.name == 'boolean')
+ or (c.type == 'boolean' or c.type == 'doc.type.boolean') then
hasBoolean = true
+ table.remove(self, index)
+ self[c] = nil
+ index = index - 1
+ end
+ end
+ if hasBoolean then
+ self[#self+1] = {
+ type = 'doc.type.boolean',
+ [1] = true,
+ }
+ end
+end
+
+---@return vm.node
+function mt:setFalsy()
+ if self.optional == false then
+ self.optional = nil
+ end
+ local hasBoolean
+ local index = 0
+ while true do
+ index = index + 1
+ local c = self[index]
+ if not c then
+ break
+ end
+ if c.type == 'nil'
+ or (c.type == 'boolean' and c[1] == true)
+ or (c.type == 'doc.type.boolean' and c[1] == true) then
goto CONTINUE
end
- if c.type == 'boolean' or c.type == 'doc.type.boolean' then
- hasTrue = true
+ if (c.type == 'global' and c.cate == 'type' and c.name == 'boolean')
+ or (c.type == 'boolean' or c.type == 'doc.type.boolean') then
+ hasBoolean = true
+ goto CONTINUE
end
- newNode:merge(c)
+ table.remove(self, index)
+ self[c] = nil
+ index = index - 1
::CONTINUE::
end
- if hasBoolean and not hasTrue then
- newNode:merge {
+ if hasBoolean then
+ self[#self+1] = {
type = 'doc.type.boolean',
- [1] = true,
+ [1] = false,
}
end
- return newNode
end
---@param name string
----@return vm.node
-function mt:copyWithout(name)
- local newNode = vm.createNode()
- if self:isOptional() then
- newNode:addOptional()
- end
- for _, c in ipairs(self) do
+function mt:remove(name)
+ local index = 0
+ while true do
+ index = index + 1
+ local c = self[index]
+ if not c then
+ break
+ end
if (c.type == 'global' and c.cate == 'type' and c.name == name)
or (c.type == name)
or (c.type == 'doc.type.integer' and (name == 'number' or name == 'integer'))
@@ -158,12 +201,11 @@ function mt:copyWithout(name)
or (c.type == 'doc.type.table' and name == 'table')
or (c.type == 'doc.type.array' and name == 'table')
or (c.type == 'doc.type.function' and name == 'function') then
- goto CONTINUE
+ table.remove(self, index)
+ self[c] = nil
+ index = index - 1
end
- newNode:merge(c)
- ::CONTINUE::
end
- return newNode
end
---@return fun():vm.object
diff --git a/script/vm/runner.lua b/script/vm/runner.lua
index 54b1d839..7f22996d 100644
--- a/script/vm/runner.lua
+++ b/script/vm/runner.lua
@@ -16,12 +16,15 @@ mt.index = 1
---@field _hasSorted boolean
---@class vm.runner.step
----@field type 'truly' | 'optional' | 'add' | 'remove' | 'object' | 'save' | 'load'
+---@field type 'truly' | 'falsy' | 'add' | 'remove' | 'object' | 'save' | 'load' | 'merge'
---@field pos integer
+---@field order? integer
---@field node? vm.node
---@field object? parser.object
----@field ref? vm.runner.step
---@field name? string
+---@field copy? boolean
+---@field ref1? vm.runner.step
+---@field ref2? vm.runner.step
---@param filter parser.object
---@param pos integer
@@ -29,31 +32,45 @@ function mt:_compileNarrowByFilter(filter, pos)
if not filter then
return
end
+ if filter.type == 'paren' then
+ if filter.exp then
+ self:_compileNarrowByFilter(filter.exp, pos)
+ end
+ return
+ end
if filter.type == 'unary' then
+ if filter.op and filter.op.type == 'not' then
+ local exp = filter[1]
+ if exp and exp.type == 'getlocal' and exp.node == self.loc then
+ self.steps[#self.steps+1] = {
+ type = 'truly',
+ pos = pos,
+ order = 2,
+ }
+ self.steps[#self.steps+1] = {
+ type = 'falsy',
+ pos = pos,
+ order = 4,
+ }
+ end
+ end
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,
+ type = 'falsy',
+ pos = pos,
+ order = 2,
+ }
+ self.steps[#self.steps+1] = {
+ type = 'truly',
+ pos = pos,
+ order = 4,
}
end
end
end
-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
function mt:_compileBlock(block)
if self.blocks[block] then
@@ -67,19 +84,82 @@ function mt:_compileBlock(block)
local parentBlock = guide.getParentBlock(block)
self:_compileBlock(parentBlock)
- if block.type == 'ifblock'
- or block.type == 'elseif' then
- if block[1] then
- self:_compileNarrowByFilter(block.filter, block[1].start)
- end
- end
-
if block.type == 'if' then
- self:_dropBlock(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)
+ 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
+ end
+ for i, final in ipairs(finals) do
+ self.steps[#self.steps+1] = {
+ type = 'merge',
+ ref1 = final,
+ pos = block.finish,
+ order = i,
+ }
+ end
end
if block.type == 'function' then
- self:_dropBlock(block)
+ local savePoint = {
+ type = 'save',
+ copy = true,
+ pos = block.start,
+ }
+ self.steps[#self.steps+1] = savePoint
+ self.steps[#self.steps+1] = {
+ type = 'load',
+ pos = block.finish,
+ ref1 = savePoint,
+ }
end
end
@@ -94,28 +174,37 @@ function mt:_preCompile()
self:_compileBlock(block)
end
table.sort(self.steps, function (a, b)
- return a.pos < b.pos
+ 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 callback fun(src: parser.object, node: vm.node)
function mt:launch(callback)
- local node = vm.getNode(self.loc)
+ local node = vm.getNode(self.loc):copy()
for _, step in ipairs(self.steps) do
+ if step.copy then
+ node = node:copy()
+ end
if step.type == 'truly' then
- node = node:copyTruly()
- elseif step.type == 'optional' then
- node = node:copy():addOptional()
+ node:setTruly()
+ elseif step.type == 'falsy' then
+ node:setFalsy()
elseif step.type == 'add' then
- node = node:copy():merge(globalMgr.getGlobal('type', step.name))
+ node:merge(globalMgr.getGlobal('type', step.name))
elseif step.type == 'remove' then
- node = node:copyWithout(step.name)
+ node:remove(step.name)
elseif step.type == 'object' then
node = callback(step.object, node) or node
elseif step.type == 'save' then
- -- Nothing need to do
+ -- nothing to do
elseif step.type == 'load' then
- node = step.ref.node
+ node = step.ref1.node
+ elseif step.type == 'merge' then
+ node:merge(step.ref1.node)
end
step.node = node
end