summaryrefslogtreecommitdiff
path: root/script
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2022-06-15 17:40:43 +0800
committer最萌小汐 <sumneko@hotmail.com>2022-06-15 17:40:43 +0800
commitb22505b90c6df5fadfcad08bee82ec2f6d91bbaa (patch)
treecb45d1189a2b87d11f98d05ae22d51b45ce388a5 /script
parente6b82117616e5d055399aa1568fee90a99ba8d64 (diff)
downloadlua-language-server-b22505b90c6df5fadfcad08bee82ec2f6d91bbaa.zip
resolve #1105 infer type by `type(x)`
Diffstat (limited to 'script')
-rw-r--r--script/vm/node.lua26
-rw-r--r--script/vm/runner.lua58
2 files changed, 64 insertions, 20 deletions
diff --git a/script/vm/node.lua b/script/vm/node.lua
index 5086f66d..1b3ea45c 100644
--- a/script/vm/node.lua
+++ b/script/vm/node.lua
@@ -224,6 +224,32 @@ function mt:remove(name)
return self
end
+---@param name string
+function mt:narrow(name)
+ if name ~= 'nil' and self.optional == true then
+ self.optional = nil
+ end
+ for index = #self, 1, -1 do
+ local c = self[index]
+ 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'))
+ or (c.type == 'doc.type.boolean' and name == 'boolean')
+ 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
+ end
+ table.remove(self, index)
+ self[c] = nil
+ ::CONTINUE::
+ end
+ if #self == 0 then
+ self[#self+1] = vm.getGlobal('type', name)
+ end
+ return self
+end
+
---@param node vm.node
function mt:removeNode(node)
for _, c in ipairs(node) do
diff --git a/script/vm/runner.lua b/script/vm/runner.lua
index 2e362871..e6f34656 100644
--- a/script/vm/runner.lua
+++ b/script/vm/runner.lua
@@ -208,30 +208,48 @@ function mt:_lookInto(action, topNode, outNode)
outNode = outNode2
elseif action.op.type == '=='
or action.op.type == '~=' then
- local loc, checker
+ local exp, checker
for i = 1, 2 do
- if action[i].type == 'getlocal' and action[i].node == self._loc then
- loc = action[i]
- checker = action[3-i] -- Copilot tells me use `3-i` instead of `i%2+1`
- elseif action[2].type == 'getlocal' and action[2].node == self._loc then
- loc = action[3-i]
+ if guide.isLiteral(action[i]) then
checker = action[i]
+ exp = action[3-i] -- Copilot tells me use `3-i` instead of `i%2+1`
end
end
- if loc then
- self:_fastWard(loc.finish, topNode:copy())
- if guide.isLiteral(checker) then
- local checkerNode = vm.compileNode(checker)
- if action.op.type == '==' then
- topNode = checkerNode
- if outNode then
- outNode:removeNode(topNode)
- end
- else
- topNode:removeNode(checkerNode)
- if outNode then
- outNode = checkerNode
- end
+ if not exp then
+ goto RETURN
+ end
+ if exp.type == 'getlocal'
+ and exp.node == self._loc then
+ self:_fastWard(exp.finish, topNode:copy())
+ local checkerNode = vm.compileNode(checker)
+ if action.op.type == '==' then
+ topNode = checkerNode
+ if outNode then
+ outNode:removeNode(topNode)
+ end
+ else
+ topNode:removeNode(checkerNode)
+ if outNode then
+ outNode = checkerNode
+ end
+ end
+ elseif exp.type == 'call'
+ and checker.type == 'string'
+ and exp.node.special == 'type'
+ and exp.args
+ and exp.args[1]
+ and exp.args[1].type == 'getlocal'
+ and exp.args[1].node == self._loc then
+ self:_fastWard(exp.finish, topNode:copy())
+ if action.op.type == '==' then
+ topNode:narrow(checker[1])
+ if outNode then
+ outNode:remove(checker[1])
+ end
+ else
+ topNode:remove(checker[1])
+ if outNode then
+ outNode:narrow(checker[1])
end
end
end