summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--script/parser/compile.lua45
-rw-r--r--script/parser/guide.lua3
-rw-r--r--script/vm/compiler.lua2
-rw-r--r--script/vm/runner.lua392
-rw-r--r--script/vm/tracer.lua2
-rw-r--r--test/tclient/init.lua2
-rw-r--r--test/tclient/tests/recursive-runner.lua3
7 files changed, 21 insertions, 428 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
diff --git a/test/tclient/init.lua b/test/tclient/init.lua
index 5c03ddba..f945d570 100644
--- a/test/tclient/init.lua
+++ b/test/tclient/init.lua
@@ -11,7 +11,7 @@ require 'tclient.tests.jump-source'
require 'tclient.tests.load-relative-library'
require 'tclient.tests.hover-set-local'
require 'tclient.tests.same-prefix'
---require 'tclient.tests.recursive-runner'
+require 'tclient.tests.recursive-runner'
require 'tclient.tests.modify-luarc'
require 'tclient.tests.performance-jass-common'
diff --git a/test/tclient/tests/recursive-runner.lua b/test/tclient/tests/recursive-runner.lua
index ddcdb5d6..e824f23a 100644
--- a/test/tclient/tests/recursive-runner.lua
+++ b/test/tclient/tests/recursive-runner.lua
@@ -174,8 +174,7 @@ end
textDocument = { uri = 'file:///test.lua' },
position = { line = 20, character = 11 },
})
- -- TODO
- --assert(hover1.contents.value:find 'vector3')
+ assert(hover1.contents.value:find 'vector3')
config.set(nil, 'Lua.diagnostics.enable', true)
end)