diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2022-04-23 06:49:32 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2022-04-23 06:49:32 +0800 |
commit | 86557f99ac61fd23f6bb2184f8b9dfb94a76772e (patch) | |
tree | 4031107a835710a2fbf9fd052fb493b3c54f3e08 /script/vm | |
parent | e8c06f25c2dc3a6a60e498449f29edc62020c0f9 (diff) | |
download | lua-language-server-86557f99ac61fd23f6bb2184f8b9dfb94a76772e.zip |
merge if results
Diffstat (limited to 'script/vm')
-rw-r--r-- | script/vm/compiler.lua | 6 | ||||
-rw-r--r-- | script/vm/node.lua | 92 | ||||
-rw-r--r-- | script/vm/runner.lua | 159 |
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 |