diff options
-rw-r--r-- | script/parser/luadoc.lua | 4 | ||||
-rw-r--r-- | script/vm/init.lua | 2 | ||||
-rw-r--r-- | script/vm/local-compiler.lua | 68 | ||||
-rw-r--r-- | script/vm/node.lua | 32 | ||||
-rw-r--r-- | script/vm/runner.lua | 88 | ||||
-rw-r--r-- | test/type_inference/init.lua | 34 |
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?>) +]] |