CCCPaste

argumenthelper

-- Argument helper v1.0
-- Used to parse programs arguments
-- TODO add auto help generator
-- TODO add arg aliases
require("luautils")
argumenthelper = {}
local arguments = {}

--- Define a new argument. The arguments will be parsed in the order defined
--- inside the types table.  
---@param name string the argument name
---@param fun function a function to execute when the argument is called
---@param argTypes table list of argument types, in order
function argumenthelper.defineArgument(name, fun, argTypes)
    assert(not luautils.containsKey(arguments, name:lower()), "Argument already defined: "..name)
    local newArg = {}
    newArg.fun = fun
    assert(type(argTypes) == "table", "Invalid argument. Not a table.", 2)
    newArg.argTypes = argTypes
    arguments[name:lower()] = newArg
end

-- Cast string argument to actual value
local function castArg(arg, argType)
    local function toboolean(str)
        str = str:lower()
        if str == "true" or str == "1" then
            return true
        elseif str == "false" or str == "0" then
            return false
        else
            return nil
        end
    end

    if argType == "boolean" then
        return toboolean(arg)
    elseif argType == "number" then
        return tonumber(arg)
    elseif argType == "string" or argType == "any" or argType == nil then
        return arg
    end
    error("Invalid argument type: "..argType, 2)
end

--- Parse the passed argument and its values and calls the corresponding function.
--- Returns true if the function actually executed. 
---@param args table the program arguments
---@return boolean true if the function executed or false if no argument is passed
function argumenthelper.parseArgument(args)
    if #args == 0 then return false end

    local name = args[1]
    local argument = arguments[name]
    if not argument then
        error("Invalid or missing argument: " .. name, 2)
    end

    local argTypes = argument.argTypes
    if (#args - 1) < #argTypes then
        error(("Missing one or more values for argument \"%s\", required %d."):format(name, #argTypes), 2)
    end
    local values = {}
    for i, argType in ipairs(argTypes) do
        local argValue = args[i + 1]
        local casted = castArg(argValue, argType)
        if casted == nil then
            error(("Value \"%s\" is not correct type. Expected %s."):format(argValue, argType), 2)
        end
        values[i] = casted
    end

    argument.fun(table.unpack(values))
    return true
end

--[[ function argumenthelper.debugList()
    for key, _ in pairs(arguments) do
        term.write(key..",")
    end
    print()
end ]]