diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2022-12-16 02:52:27 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2022-12-16 02:52:27 +0800 |
commit | 420197c19e223cf1c3ce33534abb38bba304896b (patch) | |
tree | c20350e1e5f138c466a868cc0d21e747f2255399 /script | |
parent | 3c45587f84aee06d280ca1d5223cf49068a62fb7 (diff) | |
download | lua-language-server-420197c19e223cf1c3ce33534abb38bba304896b.zip |
new tracer
Diffstat (limited to 'script')
-rw-r--r-- | script/parser/compile.lua | 45 | ||||
-rw-r--r-- | script/parser/guide.lua | 3 | ||||
-rw-r--r-- | script/vm/compiler.lua | 2 | ||||
-rw-r--r-- | script/vm/runner.lua | 392 | ||||
-rw-r--r-- | script/vm/tracer.lua | 2 |
5 files changed, 19 insertions, 425 deletions
diff --git a/script/parser/compile.lua b/script/parser/compile.lua index 73aef048..b8040382 100644 --- a/script/parser/compile.lua +++ b/script/parser/compile.lua @@ -3136,22 +3136,6 @@ local function parseGoTo() return action end -local function parseFilter() - local exp = parseExp() - if exp then - local filter = { - type = 'filter', - start = exp.start, - finish = exp.finish, - exp = exp, - } - exp.parent = filter - return filter - else - missExp() - end -end - local function parseIfBlock(parent) local ifLeft = getPosition(Tokens[Index], 'left') local ifRight = getPosition(Tokens[Index] + 1, 'right') @@ -3167,11 +3151,13 @@ local function parseIfBlock(parent) } } skipSpace() - local filter = parseFilter() + local filter = parseExp() if filter then ifblock.filter = filter ifblock.finish = filter.finish filter.parent = ifblock + else + missExp() end skipSpace() local thenToken = Tokens[Index + 1] @@ -3224,11 +3210,13 @@ local function parseElseIfBlock(parent) } Index = Index + 2 skipSpace() - local filter = parseFilter() + local filter = parseExp() if filter then elseifblock.filter = filter elseifblock.finish = filter.finish filter.parent = elseifblock + else + missExp() end skipSpace() local thenToken = Tokens[Index + 1] @@ -3536,16 +3524,15 @@ local function parseWhile() skipSpace() local nextToken = Tokens[Index + 1] - if nextToken == 'do' - or nextToken == 'then' then - missExp() + local filter = nextToken ~= 'do' + and nextToken ~= 'then' + and parseExp() + if filter then + action.filter = filter + action.finish = filter.finish + filter.parent = action else - local filter = parseFilter() - if filter then - action.filter = filter - action.finish = filter.finish - filter.parent = action - end + missExp() end skipSpace() @@ -3624,10 +3611,12 @@ local function parseRepeat() Index = Index + 2 skipSpace() - local filter = parseFilter() + local filter = parseExp() if filter then action.filter = filter filter.parent = action + else + missExp() end else diff --git a/script/parser/guide.lua b/script/parser/guide.lua index c74593a4..147e6237 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -139,8 +139,7 @@ local childMap = { ['getfield'] = {'node', 'field'}, ['list'] = {'#'}, ['binary'] = {1, 2}, - ['unary'] = { 1 }, - ['filter'] = {'exp'}, + ['unary'] = {1}, ['doc'] = {'#'}, ['doc.class'] = {'class', '#extends', '#signs', 'comment'}, diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index e4fb633e..0bac71af 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -972,7 +972,7 @@ local function compileLocal(source) vm.setNode(source, vm.compileNode(source.value)) end end - if not hasMarkValue + if not hasMarkDoc and not hasMarkValue and source.ref then local firstSet diff --git a/script/vm/runner.lua b/script/vm/runner.lua deleted file mode 100644 index 75bb3a7f..00000000 --- a/script/vm/runner.lua +++ /dev/null @@ -1,392 +0,0 @@ ----@class vm -local vm = require 'vm.vm' -local guide = require 'parser.guide' -local linked = require 'linked-table' - ----@alias vm.runner.callback fun(src: parser.object, node?: vm.node) - ----@class vm.runner ----@field _loc parser.object ----@field _casts parser.object[] ----@field _callback vm.runner.callback ----@field _mark table ----@field _has table<parser.object, true> ----@field _main parser.object ----@field _uri uri -local mt = {} -mt.__index = mt -mt._index = 1 - ----@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 - ----@param obj parser.object -function mt:_markHas(obj) - while true do - if self._has[obj] then - return - end - self._has[obj] = true - if obj == self._main then - return - end - obj = obj.parent - end -end - -function mt:collect() - local startPos = self._loc.start - local finishPos = 0 - - for _, ref in ipairs(self._loc.ref) do - if ref.type == 'getlocal' - or ref.type == 'setlocal' then - self:_markHas(ref) - if ref.finish > finishPos then - finishPos = ref.finish - end - 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._casts[#self._casts+1] = cast - end - end -end - ----@param pos integer ----@param topNode vm.node ----@return vm.node -function mt:_fastWardCasts(pos, topNode) - for i = self._index, #self._casts do - local action = self._casts[i] - if action.start > pos then - self._index = i - return topNode - end - topNode = topNode:copy() - for _, cast in ipairs(action.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 - self._index = self._index + 1 - return topNode -end - ----@param action parser.object ----@param topNode vm.node ----@param outNode? vm.node ----@return vm.node topNode ----@return vm.node outNode -function mt:_lookIntoChild(action, topNode, outNode) - if not self._has[action] - or self._mark[action] then - return topNode, topNode or outNode - end - self._mark[action] = true - topNode = self:_fastWardCasts(action.start, topNode) - if action.type == 'getlocal' then - if action.node == self._loc then - self._callback(action, topNode) - if outNode then - topNode = topNode:copy():setTruthy() - outNode = outNode:copy():setFalsy() - end - end - elseif action.type == 'function' then - self:lookIntoBlock(action, topNode:copy()) - elseif action.type == 'unary' then - if not action[1] then - goto RETURN - end - if action.op.type == 'not' then - outNode = outNode or topNode:copy() - outNode, topNode = self:_lookIntoChild(action[1], topNode, outNode) - outNode = outNode:copy() - end - elseif action.type == 'binary' then - if not action[1] or not action[2] then - goto RETURN - end - if action.op.type == 'and' then - topNode = self:_lookIntoChild(action[1], topNode, topNode:copy()) - topNode = self:_lookIntoChild(action[2], topNode, topNode:copy()) - elseif action.op.type == 'or' then - outNode = outNode or topNode:copy() - local topNode1, outNode1 = self:_lookIntoChild(action[1], topNode, outNode) - local topNode2, outNode2 = self:_lookIntoChild(action[2], outNode1, outNode1:copy()) - topNode = vm.createNode(topNode1, topNode2) - outNode = outNode2:copy() - elseif action.op.type == '==' - or action.op.type == '~=' then - local handler, checker - for i = 1, 2 do - if guide.isLiteral(action[i]) then - checker = action[i] - handler = action[3-i] -- Copilot tells me use `3-i` instead of `i%2+1` - end - end - if not handler then - goto RETURN - end - if handler.type == 'getlocal' - and handler.node == self._loc then - -- if x == y then - topNode = self:_lookIntoChild(handler, topNode, outNode) - local checkerNode = vm.compileNode(checker) - local checkerName = vm.getNodeName(checker) - if checkerName then - topNode = topNode:copy() - if action.op.type == '==' then - topNode:narrow(self._uri, checkerName) - if outNode then - outNode:removeNode(checkerNode) - end - else - topNode:removeNode(checkerNode) - if outNode then - outNode:narrow(self._uri, checkerName) - end - end - end - elseif handler.type == 'call' - and checker.type == 'string' - and handler.node.special == 'type' - and handler.args - and handler.args[1] - and handler.args[1].type == 'getlocal' - and handler.args[1].node == self._loc then - -- if type(x) == 'string' then - self:_lookIntoChild(handler, topNode:copy()) - if action.op.type == '==' then - topNode:narrow(self._uri, checker[1]) - if outNode then - outNode:remove(checker[1]) - end - else - topNode:remove(checker[1]) - if outNode then - outNode:narrow(self._uri, checker[1]) - end - end - elseif handler.type == 'getlocal' - and checker.type == 'string' then - local nodeValue = vm.getObjectValue(handler.node) - if nodeValue - and nodeValue.type == 'select' - and nodeValue.sindex == 1 then - local call = nodeValue.vararg - if call - and call.type == 'call' - and call.node.special == 'type' - and call.args - and call.args[1] - and call.args[1].type == 'getlocal' - and call.args[1].node == self._loc then - -- `local tp = type(x);if tp == 'string' then` - if action.op.type == '==' then - topNode:narrow(self._uri, checker[1]) - if outNode then - outNode:remove(checker[1]) - end - else - topNode:remove(checker[1]) - if outNode then - outNode:narrow(self._uri, checker[1]) - end - end - end - end - end - end - elseif action.type == 'loop' - or action.type == 'in' - or action.type == 'repeat' - or action.type == 'for' then - topNode = self:lookIntoBlock(action, topNode:copy()) - elseif action.type == 'while' then - local blockNode, mainNode - if action.filter then - blockNode, mainNode = self:_lookIntoChild(action.filter, topNode:copy(), topNode:copy()) - else - blockNode = topNode:copy() - mainNode = topNode:copy() - end - blockNode = self:lookIntoBlock(action, blockNode:copy()) - topNode = mainNode:merge(blockNode) - if action.filter then - -- look into filter again - guide.eachSource(action.filter, function (src) - self._mark[src] = nil - end) - blockNode, topNode = self:_lookIntoChild(action.filter, topNode:copy(), topNode:copy()) - end - elseif action.type == 'if' then - local hasElse - local mainNode = topNode:copy() - local blockNodes = {} - for _, subBlock in ipairs(action) do - local blockNode = mainNode:copy() - if subBlock.filter then - blockNode, mainNode = self:_lookIntoChild(subBlock.filter, blockNode, mainNode) - else - hasElse = true - mainNode:clear() - end - blockNode = self:lookIntoBlock(subBlock, blockNode:copy()) - local neverReturn = subBlock.hasReturn - or subBlock.hasGoTo - or subBlock.hasBreak - or subBlock.hasError - if not neverReturn then - blockNodes[#blockNodes+1] = blockNode - end - end - if not hasElse and not topNode:hasKnownType() then - mainNode:merge(vm.declareGlobal('type', 'unknown')) - end - for _, blockNode in ipairs(blockNodes) do - mainNode:merge(blockNode) - end - topNode = mainNode - elseif action.type == 'call' then - if action.node.special == 'assert' and action.args and action.args[1] then - topNode = self:_lookIntoChild(action.args[1], topNode, topNode:copy()) - end - elseif action.type == 'paren' then - topNode, outNode = self:_lookIntoChild(action.exp, topNode, outNode) - elseif action.type == 'setlocal' then - if action.node == self._loc then - if action.value then - self:_lookIntoChild(action.value, topNode) - end - topNode = self._callback(action, topNode) - end - elseif action.type == 'local' then - if action.value - and action.ref - and action.value.type == 'select' then - local index = action.value.sindex - local call = action.value.vararg - if index == 1 - and call.type == 'call' - and call.node - and call.node.special == 'type' - and call.args then - local getLoc = call.args[1] - if getLoc - and getLoc.type == 'getlocal' - and getLoc.node == self._loc then - for _, ref in ipairs(action.ref) do - self:_markHas(ref) - end - end - end - end - end - ::RETURN:: - guide.eachChild(action, function (src) - if self._has[src] then - self:_lookIntoChild(src, topNode) - end - end) - return topNode, outNode or topNode -end - ----@param block parser.object ----@param topNode vm.node ----@return vm.node topNode -function mt:lookIntoBlock(block, topNode) - if not self._has[block] then - return topNode - end - for _, action in ipairs(block) do - if self._has[action] then - topNode = self:_lookIntoChild(action, topNode) - end - end - topNode = self:_fastWardCasts(block.finish, topNode) - return topNode -end - ----@alias runner.info { target?: parser.object, loc: parser.object } - ----@async ----@param loc parser.object ----@param start fun() ----@param finish fun() ----@param callback vm.runner.callback -function vm.launchRunner(loc, start, finish, callback) - local locNode = vm.getNode(loc) - if not locNode then - return - end - - local function launch() - start() - if not loc.ref then - finish() - return - end - local main = guide.getParentBlock(loc) - if not main then - finish() - return - end - local self = setmetatable({ - _loc = loc, - _casts = {}, - _mark = {}, - _has = {}, - _main = main, - _uri = guide.getUri(loc), - _callback = callback, - }, mt) - - self:collect() - - self:lookIntoBlock(main, locNode:copy()) - - locNode:setData('runner', nil) - - finish() - end - - launch() -end diff --git a/script/vm/tracer.lua b/script/vm/tracer.lua index 5b3b1b54..85a0faa7 100644 --- a/script/vm/tracer.lua +++ b/script/vm/tracer.lua @@ -201,8 +201,6 @@ function mt:lookIntoChild(action, topNode, outNode) outNode = outNode:copy():setFalsy() end end - elseif action.type == 'filter' then - return self:lookIntoChild(action.exp, topNode, outNode) elseif action.type == 'function' then self:lookIntoBlock(action, 0, topNode:copy()) elseif action.type == 'unary' then |