summaryrefslogtreecommitdiff
path: root/script/vm
diff options
context:
space:
mode:
Diffstat (limited to 'script/vm')
-rw-r--r--script/vm/function.lua107
1 files changed, 90 insertions, 17 deletions
diff --git a/script/vm/function.lua b/script/vm/function.lua
index 69900141..45f8c0df 100644
--- a/script/vm/function.lua
+++ b/script/vm/function.lua
@@ -1,21 +1,48 @@
---@class vm
local vm = require 'vm.vm'
+---@param arg parser.object
+---@return parser.object?
+local function getDocParam(arg)
+ if not arg.bindDocs then
+ return nil
+ end
+ for _, doc in ipairs(arg.bindDocs) do
+ if doc.type == 'doc.param'
+ and doc.param[1] == arg[1] then
+ return doc
+ end
+ end
+ return nil
+end
+
---@param func parser.object
---@return integer min
---@return integer max
function vm.countParamsOfFunction(func)
local min = 0
local max = 0
- if func.type == 'function'
- or func.type == 'doc.type.function' then
+ if func.type == 'function' then
if func.args then
max = #func.args
- min = max
for i = #func.args, 1, -1 do
local arg = func.args[i]
- if arg.type == '...'
- or (arg.name and arg.name[1] =='...') then
+ if arg.type == '...' then
+ max = math.huge
+ elseif getDocParam(arg)
+ and not vm.compileNode(arg):isNullable() then
+ min = i
+ break
+ end
+ end
+ end
+ end
+ if func.type == 'doc.type.function' then
+ if func.args then
+ max = #func.args
+ for i = #func.args, 1, -1 do
+ local arg = func.args[i]
+ if arg.name and arg.name[1] =='...' then
max = math.huge
elseif not vm.compileNode(arg):isNullable() then
min = i
@@ -27,22 +54,67 @@ function vm.countParamsOfFunction(func)
return min, max
end
+---@param node vm.node
+---@return integer min
+---@return integer max
+function vm.countParamsOfNode(node)
+ local min, max
+ for n in node:eachObject() do
+ if n.type == 'function'
+ or n.type == 'doc.type.function' then
+ local fmin, fmax = vm.countParamsOfFunction(n)
+ if not min or fmin < min then
+ min = fmin
+ end
+ if not max or fmax > max then
+ max = fmax
+ end
+ end
+ end
+ return min or 0, max or math.huge
+end
+
---@param func parser.object
---@return integer min
---@return integer max
function vm.countReturnsOfFunction(func)
if func.type == 'function' then
- if not func.returns then
- return 0, 0
- end
local min, max
- for _, ret in ipairs(func.returns) do
- local rmin, rmax = vm.countList(ret)
- if not min or rmin < min then
- min = rmin
+ if func.returns then
+ for _, ret in ipairs(func.returns) do
+ local rmin, rmax = vm.countList(ret)
+ if not min or rmin < min then
+ min = rmin
+ end
+ if not max or rmax > max then
+ max = rmax
+ end
+ end
+ end
+ if func.bindDocs then
+ local lastReturn
+ local n = 0
+ local dmin, dmax
+ for _, doc in ipairs(func.bindDocs) do
+ if doc.type == 'doc.return' then
+ for _, ret in ipairs(doc) do
+ n = n + 1
+ lastReturn = ret
+ dmax = n
+ if not vm.compileNode(ret):isNullable() then
+ dmin = n
+ end
+ end
+ end
+ end
+ if lastReturn and lastReturn.types[1][1] == '...' then
+ dmax = math.huge
+ end
+ if dmin and (not min or (dmin < min)) then
+ min = dmin
end
- if not max or rmax > max then
- max = rmax
+ if dmax and (not max or (dmax > max)) then
+ max = dmax
end
end
return min, max
@@ -50,7 +122,7 @@ function vm.countReturnsOfFunction(func)
if func.type == 'doc.type.function' then
return vm.countList(func.returns)
end
- return 0, 0
+ error('not a function')
end
---@param func parser.object
@@ -69,7 +141,7 @@ function vm.countReturnsOfCall(func, args)
max = rmax
end
end
- return min or 0, max or 0
+ return min or 0, max or math.huge
end
---@param list parser.object[]?
@@ -83,7 +155,8 @@ function vm.countList(list)
if not lastArg then
return 0, 0
end
- if lastArg.type == '...' then
+ if lastArg.type == '...'
+ or lastArg.type == 'varargs' then
return #list - 1, math.huge
end
if lastArg.type == 'call' then