diff options
Diffstat (limited to 'script/vm')
-rw-r--r-- | script/vm/function.lua | 107 |
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 |