/
check.lua
99 lines (91 loc) · 2.96 KB
/
check.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
-------------------------------
-- Check Commands For Errors --
-------------------------------
-- Checks for things like argument counts and type checking.
local describeArgs = require "describeArgs"
local function collectArguments(command, args)
args = args or {}
if command.arg then
-- TODO: Confirm that commands are uniform, starting from one.
-- TODO: Check type compatibility. Can't use same command for
-- different types.
args[command.arg] = command
end
for _, arg in ipairs(command.args or {}) do
collectArguments(arg, args)
end
return args
end
local function checkParameters(command, expected)
if not command.args then
return
end
for argNum, arg in ipairs(command.args) do
local expectedArg = expected[math.min(argNum, #expected)]
if (arg.callable or false) ~= (expectedArg.callable or false) then
if arg.args then
break
end
if arg.callable then
return ("Didn't expect callable for parameter %s to %s"):format(
argNum, command.command)
else
return ("Expected callable for parameter %s to %s"):format(
argNum, command.command)
end
end
end
end
local function checkCommand(command, about)
local args = describeArgs(about.args)
local argCount = #(command.args or {})
if command.callable and not command.args then
return
end
-- TODO: There needs to be better checking of parameters given to
-- callables.
if argCount < args.needed then
i(command)
return string.format("%s requires %s parameters (%s), got %s",
command.command, args.needed, args.str, argCount)
elseif args.limit and argCount > args.limit then
if args.limit == 0 then
return ("%s doesn't take any parameters, but got %s"):format(
command.command, #command.args)
else
return string.format(
"%s only takes %s parameters (%s), got %s\ntry passing multiple parameters as a [list]",
command.command, args.limit or args.needed, args.str, argCount)
end
end
local expected = {}
for _, arg in ipairs(about.args or {}) do
table.insert(expected, {callable = arg:sub(1, 1) == "!"})
end
return checkParameters(command, expected)
end
local function checkFunction(func, content)
local args = collectArguments(content)
if func.callable and not func.args then
-- A callable: !fun
return
end
if #(func.args or {}) ~= #args then
return ("Expected %s parameters for function %s, got %s"):format(
#(args or {}), func.command, #(func.args or {}))
end
return checkParameters(func, args)
end
local check
function check(command, system)
for _, arg in ipairs(command.args or {}) do
local err = check(arg, system)
if err then return err end
end
if system.functions[command.command] then
return checkFunction(command, system.functions[command.command])
elseif system.commands[command.command] then
return checkCommand(command, system.commands[command.command])
end
end
return check