Expand in relational expressions

For example, `a.b in [1, 2]` is expanded to `a.b = 1 or a.b = 2`.
This is done over the AST, not filter text.
This commit is contained in:
Henri DF 2016-02-12 20:30:44 -08:00
parent 3dab9edc9d
commit 79cdf31aa7
2 changed files with 77 additions and 3 deletions

View File

@ -15,12 +15,12 @@ function error_exit_bad
function good function good
{ {
lua test.lua "$1" || error_exit_good "$1" lua test.lua "$1" 2> /dev/null || error_exit_good "$1"
} }
function bad function bad
{ {
lua test.lua "$1" && error_exit_bad "$1" lua test.lua "$1" 2> /dev/null && error_exit_bad "$1"
} }
# Filters # Filters
@ -47,7 +47,6 @@ good "a.b = 'bla'"
good "a.b = not" good "a.b = not"
good "a.b contains bla" good "a.b contains bla"
good "a.b icontains 'bla'" good "a.b icontains 'bla'"
good "a.g in ()"
good "a.g in (1, 'a', b)" good "a.g in (1, 'a', b)"
good "a.g in ( 1 ,, , b)" good "a.g in ( 1 ,, , b)"
good "evt.dir=> and fd.name=*.log" good "evt.dir=> and fd.name=*.log"
@ -55,6 +54,7 @@ good "evt.dir=> and fd.name=/var/log/httpd.log"
good "a.g in (1, 'a', b.c)" good "a.g in (1, 'a', b.c)"
good "a.b = a.a" good "a.b = a.a"
bad "a.g in ()"
bad "(a.b = 1" bad "(a.b = 1"
# Macros # Macros
@ -66,4 +66,6 @@ good "a : evt.dir=>"
good "inbound: (syscall.type=listen and evt.dir='>') or (syscall.type=accept and evt.dir='<')" good "inbound: (syscall.type=listen and evt.dir='>') or (syscall.type=accept and evt.dir='<')"
bad "a:" bad "a:"
echo
echo "All tests passed."
exit 0 exit 0

View File

@ -237,6 +237,74 @@ local G = {
OneWord = V"Name" + V"Number" + V"String" + P(1); OneWord = V"Name" + V"Number" + V"String" + P(1);
} }
function map(f, arr)
local res = {}
for i,v in ipairs(arr) do
res[i] = f(v)
end
return res
end
function foldr(f, acc, arr)
for i,v in pairs(arr) do
acc = f(acc, v)
end
return acc
end
--[[
Traverses the AST and replaces `in` relational expressions with a sequence of ORs.
For example, `a.b in [1, 2]` is expanded to `a.b = 1 or a.b = 2` (in ASTs)
]]--
function expand_in(node)
local t = node.type
if t == "Filter" then
expand_in(node.value)
elseif t == "UnaryBoolOp" then
expand_in(node.argument)
elseif t == "BinaryBoolOp" then
expand_in(node.left)
expand_in(node.right)
elseif t == "BinaryRelOp" and node.operator == "in" then
if (table.maxn(node.right.elements) == 0) then
error ("In list with zero elements")
end
local mapper = function(element)
return {
type = "BinaryRelOp",
operator = "eq",
left = node.left,
right = element
}
end
local equalities = map(mapper, node.right.elements)
local lasteq = equalities[table.maxn(equalities)]
equalities[table.maxn(equalities)] = nil
local folder = function(left, right)
return {
type = "BinaryBoolOp",
operator = "or",
left = left,
right = right
}
end
lasteq = foldr(folder, lasteq, equalities)
node.type=lasteq.type
node.operator=lasteq.operator
node.left=lasteq.left
node.right=lasteq.right
end
end
function print_ast(node, level) function print_ast(node, level)
local t = node.type local t = node.type
local prefix = string.rep(" ", level*2) local prefix = string.rep(" ", level*2)
@ -276,6 +344,10 @@ function parser.parse (subject)
local errorinfo = { subject = subject } local errorinfo = { subject = subject }
lpeg.setmaxstack(1000) lpeg.setmaxstack(1000)
local ast, error_msg = lpeg.match(G, subject, nil, errorinfo) local ast, error_msg = lpeg.match(G, subject, nil, errorinfo)
if (error_msg) then
return ast, error_msg
end
expand_in(ast)
return ast, error_msg return ast, error_msg
end end