summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--script/parser/luadoc.lua4
-rw-r--r--script/vm/init.lua2
-rw-r--r--script/vm/local-compiler.lua68
-rw-r--r--script/vm/node.lua32
-rw-r--r--script/vm/runner.lua88
-rw-r--r--test/type_inference/init.lua34
6 files changed, 156 insertions, 72 deletions
diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua
index 7c669d1f..d329985f 100644
--- a/script/parser/luadoc.lua
+++ b/script/parser/luadoc.lua
@@ -709,6 +709,10 @@ function parseType(parent)
if not result.start then
result.start = getFinish()
end
+ if checkToken('symbol', '?', 1) then
+ nextToken()
+ result.optional = true
+ end
result.finish = getFinish()
result.firstFinish = result.finish
diff --git a/script/vm/init.lua b/script/vm/init.lua
index 61c52c65..aa55a6c7 100644
--- a/script/vm/init.lua
+++ b/script/vm/init.lua
@@ -8,6 +8,6 @@ require 'vm.field'
require 'vm.doc'
require 'vm.type'
require 'vm.library'
-require 'vm.local-compiler'
+require 'vm.runner'
require 'vm.manager'
return vm
diff --git a/script/vm/local-compiler.lua b/script/vm/local-compiler.lua
deleted file mode 100644
index 844acc18..00000000
--- a/script/vm/local-compiler.lua
+++ /dev/null
@@ -1,68 +0,0 @@
----@class vm
-local vm = require 'vm.vm'
-local guide = require 'parser.guide'
-
----@class vm.local-compiler
----@field loc parser.object
----@field mainFunc parser.object
-local mt = {}
-mt.__index = mt
-mt.index = 1
-
-
----@class parser.object
----@field _hasSorted boolean
-
----@param source parser.object
-local function sortRefs(source)
- if source._hasSorted then
- return
- end
- source._hasSorted = true
- table.sort(source.ref, function (a, b)
- return (a.range or a.start) < (b.range or b.start)
- end)
-end
-
----@param node vm.node
----@param currentFunc parser.object
----@param callback fun(src: parser.object, node: vm.node)
-function mt:_runFunction(node, currentFunc, callback)
- while true do
- local ref = self.loc.ref[self.index]
- if not ref then
- break
- end
- if ref.start > currentFunc.finish then
- break
- end
- local func = guide.getParentFunction(ref)
- if func == currentFunc then
- callback(ref, node)
- self.index = self.index + 1
- if ref.type == 'setlocal' then
- node = vm.getNode(ref)
- end
- else
- self:_runFunction(node, func, callback)
- end
- end
-end
-
----@param callback fun(src: parser.object, node: vm.node)
-function mt:launch(callback)
- self:_runFunction(vm.getNode(self.loc), self.mainFunc, callback)
-end
-
----@param loc parser.object
----@return vm.local-compiler
-function vm.createRunner(loc)
- local self = setmetatable({
- loc = loc,
- mainFunc = guide.getParentFunction(loc),
- }, mt)
-
- sortRefs(loc)
-
- return self
-end
diff --git a/script/vm/node.lua b/script/vm/node.lua
index 99bc3340..a4e22b68 100644
--- a/script/vm/node.lua
+++ b/script/vm/node.lua
@@ -93,8 +93,34 @@ function mt:isFalsy()
return false
end
-function mt:removeFalsy()
-
+---@return vm.node
+function mt:copyTruly()
+ local newNode = vm.createNode()
+ newNode.optional = false
+ local hasBoolean, hasTrue
+ for _, c in ipairs(self) do
+ 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
+ end
+ if c.type == 'global' and c.cate == 'type' and c.name == 'boolean' then
+ hasBoolean = true
+ goto CONTINUE
+ end
+ if c.type == 'boolean' or c.type == 'doc.type.boolean' then
+ hasTrue = true
+ end
+ newNode:merge(c)
+ ::CONTINUE::
+ end
+ if hasBoolean and not hasTrue then
+ newNode:merge {
+ type = 'doc.type.boolean',
+ [1] = true,
+ }
+ end
+ return newNode
end
---@return fun():vm.object
@@ -130,7 +156,7 @@ function vm.setNode(source, node, cover)
me:merge(node)
else
if node.type == 'vm.node' then
- vm.nodeCache[source] = node
+ vm.nodeCache[source] = node:copy()
else
vm.nodeCache[source] = vm.createNode(node)
end
diff --git a/script/vm/runner.lua b/script/vm/runner.lua
new file mode 100644
index 00000000..d0825389
--- /dev/null
+++ b/script/vm/runner.lua
@@ -0,0 +1,88 @@
+---@class vm
+local vm = require 'vm.vm'
+local guide = require 'parser.guide'
+
+---@class vm.local-compiler
+---@field loc parser.object
+---@field mainBlock parser.object
+---@field blocks table<parser.object, table>
+local mt = {}
+mt.__index = mt
+mt.index = 1
+
+
+---@class parser.object
+---@field _hasSorted boolean
+
+---@param source parser.object
+local function sortRefs(source)
+ if source._hasSorted then
+ return
+ end
+ source._hasSorted = true
+ table.sort(source.ref, function (a, b)
+ return (a.range or a.start) < (b.range or b.start)
+ end)
+end
+
+---@param node vm.node
+---@param block parser.object
+---@return vm.node
+function mt:_compileBlock(node, block)
+ for _ = 1, 10000 do
+ if self.blocks[block]
+ or self.mainBlock == block
+ or block.type == 'function'
+ or block.type == 'main' then
+ return node
+ end
+ self.blocks[block] = {}
+ block = guide.getParentBlock(block)
+ end
+ error('compile block overstack')
+end
+
+---@param node vm.node
+---@param currentBlock parser.object
+---@param callback fun(src: parser.object, node: vm.node)
+---@return vm.node
+function mt:_runBlock(node, currentBlock, callback)
+ local currentNode = self:_compileBlock(node, currentBlock)
+ for _ = 1, 10000 do
+ local ref = self.loc.ref[self.index]
+ if not ref
+ or ref.start > currentBlock.finish then
+ return node
+ end
+ local block = guide.getParentBlock(ref)
+ if block == currentBlock then
+ callback(ref, currentNode)
+ self.index = self.index + 1
+ if ref.type == 'setlocal' then
+ currentNode = vm.getNode(ref)
+ end
+ else
+ currentNode = self:_runBlock(currentNode, block, callback)
+ end
+ end
+ error('run block overstack')
+end
+
+---@param callback fun(src: parser.object, node: vm.node)
+function mt:launch(callback)
+ self:_runBlock(vm.getNode(self.loc), self.mainBlock, callback)
+end
+
+---@param loc parser.object
+---@return vm.local-compiler
+function vm.createRunner(loc)
+ local self = setmetatable({
+ loc = loc,
+ mainBlock = guide.getParentBlock(loc),
+ blocks = {},
+ }, mt)
+
+ sortRefs(loc)
+
+ return self
+end
diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua
index 91fc0eb8..97d684dc 100644
--- a/test/type_inference/init.lua
+++ b/test/type_inference/init.lua
@@ -1656,3 +1656,37 @@ end
x = '1'
x = 1
]]
+
+TEST 'integer?' [[
+---@type integer?
+local <?x?>
+]]
+
+TEST 'integer?' [[
+---@type integer?
+local x
+
+if <?x?> then
+ print(x)
+end
+]]
+
+TEST 'integer' [[
+---@type integer?
+local x
+
+if x then
+ print(<?x?>)
+end
+]]
+
+TEST 'integer?' [[
+---@type integer?
+local x
+
+if x then
+ print(x)
+end
+
+print(<?x?>)
+]]