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
|
-- lib/lace/engine.lua
--
-- Lua Access Control Engine -- Ruleset runtime engine
--
-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
--
-- For licence terms, see COPYING
--
local function _error(str, words)
return { msg = str, words = words }
end
local function _dlace(ctx)
local ret = ctx[".lace"] or {}
ctx[".lace"] = ret
return ret
end
local function set_define(exec_context, name, defn)
local dlace = _dlace(exec_context)
dlace.defs = dlace.defs or {}
if dlace.defs[name] then
return false, _error("Attempted to redefine " .. name, {2})
end
dlace.defs[name] = defn
return true
end
local function test_define(exec_context, name)
local dlace = _dlace(exec_context)
dlace.defs = dlace.defs or {}
local defn = dlace.defs[name]
if not defn then
return nil, _error("Unknown definition: " .. name)
end
-- Otherwise we evaluate the definition and return it
return defn.fn(exec_context, unpack(defn.args))
end
local function internal_run_ruleset(ruleset, exec_context)
-- We iterate the ruleset, returning the first time
-- a rule either errors, or returns a stopping result
local dlace = _dlace(exec_context)
dlace.ruleset = ruleset
for i = 1, #ruleset.rules do
local rule = ruleset.rules[i]
dlace.linenr = rule.linenr
local result, msg = rule.fn(exec_context, unpack(rule.args))
if not result then
return false, msg
elseif result ~= true then
-- Explicit result, return it
return result, msg
end
end
dlace.linenr = nil
-- Internally we use the empty string to indicate no result.
return ""
end
local function run_ruleset(ruleset, exec_context)
local ok, ret, msg = xpcall(function()
return internal_run_ruleset(ruleset, exec_context)
end, debug.traceback)
if not ok then
return nil, ret
end
if ret == "" then
-- Empty string indicates no error but no result, we don't like
-- that here so we return an error
return false, "Ruleset did not explicitly allow or deny"
end
return ret, msg
end
return {
internal_run = internal_run_ruleset,
run = run_ruleset,
test = test_define,
define = set_define,
}
|