mirror of
https://github.com/falcosecurity/falco.git
synced 2025-07-08 04:09:13 +00:00
Macro expansion
This commit is contained in:
parent
b3f7b1d765
commit
6e2d8679c4
@ -15,12 +15,12 @@ function error_exit_bad
|
|||||||
|
|
||||||
function good
|
function good
|
||||||
{
|
{
|
||||||
lua test.lua "$1" 2> /dev/null || error_exit_good "$1"
|
lua test.lua "a: x.y=1; b: a and z.x exists; c: b; $1" 2> /dev/null || error_exit_good "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
function bad
|
function bad
|
||||||
{
|
{
|
||||||
lua test.lua "$1" 2> /dev/null && error_exit_bad "$1"
|
lua test.lua "a: x.y=1; b: a and z.x exists; c: b; $1" 2> /dev/null && error_exit_bad "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Filters
|
# Filters
|
||||||
@ -41,7 +41,7 @@ good "not not a"
|
|||||||
good "(not not a)"
|
good "(not not a)"
|
||||||
good "not a.b=1"
|
good "not a.b=1"
|
||||||
good "not a.a exists"
|
good "not a.a exists"
|
||||||
good "notz"
|
good "notz: a and b; notz"
|
||||||
good "a.b = bla"
|
good "a.b = bla"
|
||||||
good "a.b = 'bla'"
|
good "a.b = 'bla'"
|
||||||
good "a.b = not"
|
good "a.b = not"
|
||||||
|
@ -168,7 +168,7 @@ end
|
|||||||
local G = {
|
local G = {
|
||||||
V"Start", -- Entry rule
|
V"Start", -- Entry rule
|
||||||
|
|
||||||
Start = (V"MacroDef" / macro + V"Filter" / filter) * -1 + report_error();
|
Start = V"Skip" * (V"MacroDef" / macro + V"Filter" / filter) * -1 + report_error();
|
||||||
|
|
||||||
-- Grammar
|
-- Grammar
|
||||||
Filter = V"OrExpression";
|
Filter = V"OrExpression";
|
||||||
@ -313,8 +313,94 @@ function expand_in(node)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
|
||||||
|
Given a map of macro definitions, traverse AST and replace macro references
|
||||||
|
with their definitions.
|
||||||
|
|
||||||
|
The AST is changed in-place.
|
||||||
|
|
||||||
|
The return value is a boolean which is true if any macro was
|
||||||
|
substitued. This allows a caller to re-traverse until no more macros are
|
||||||
|
found, a simple strategy for recursive resoltuions (e.g. when a macro
|
||||||
|
definition uses another macro).
|
||||||
|
|
||||||
|
--]]
|
||||||
|
function expand_macros(node, defs, changed)
|
||||||
|
if node.type == "Filter" then
|
||||||
|
if (node.value.type == "Macro") then
|
||||||
|
if (defs[node.value.value] == nil) then
|
||||||
|
tostring = require 'ml'.tstring
|
||||||
|
error("Undefined macro '".. node.value.value .. "' used in filter.")
|
||||||
|
end
|
||||||
|
node.value = defs[node.value.value]
|
||||||
|
changed = true
|
||||||
|
end
|
||||||
|
return expand_macros(node.value, defs, changed)
|
||||||
|
|
||||||
|
elseif node.type == "BinaryBoolOp" then
|
||||||
|
|
||||||
|
if (node.left.type == "Macro") then
|
||||||
|
if (defs[node.left.value] == nil) then
|
||||||
|
error("Undefined macro '".. node.left.value .. "' used in filter.")
|
||||||
|
end
|
||||||
|
node.left = defs[node.left.value]
|
||||||
|
changed = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if (node.right.type == "Macro") then
|
||||||
|
if (defs[node.right.value] == nil) then
|
||||||
|
error("Undefined macro ".. node.right.value .. "used in filter.")
|
||||||
|
end
|
||||||
|
node.right = defs[node.right.value]
|
||||||
|
changed = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local changed_left = expand_macros(node.left, defs, false)
|
||||||
|
local changed_right = expand_macros(node.right, defs, false)
|
||||||
|
return changed or changed_left or changed_right
|
||||||
|
|
||||||
|
elseif node.type == "UnaryBoolOp" then
|
||||||
|
if (node.argument.type == "Macro") then
|
||||||
|
if (defs[node.argument.value] == nil) then
|
||||||
|
error("Undefined macro ".. node.argument.value .. "used in filter.")
|
||||||
|
end
|
||||||
|
node.argument = defs[node.argument.value]
|
||||||
|
changed = true
|
||||||
|
end
|
||||||
|
return expand_macros(node.argument, defs, changed)
|
||||||
|
end
|
||||||
|
return changed
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_macros(node, set)
|
||||||
|
if (node.type == "Macro") then
|
||||||
|
set[node.value] = true
|
||||||
|
return set
|
||||||
|
end
|
||||||
|
|
||||||
|
if node.type == "Filter" then
|
||||||
|
return get_macros(node.value, set)
|
||||||
|
end
|
||||||
|
|
||||||
|
if node.type == "BinaryBoolOp" then
|
||||||
|
local left = get_macros(node.left, {})
|
||||||
|
local right = get_macros(node.right, {})
|
||||||
|
|
||||||
|
for m, _ in pairs(left) do set[m] = true end
|
||||||
|
for m, _ in pairs(right) do set[m] = true end
|
||||||
|
|
||||||
|
return set
|
||||||
|
end
|
||||||
|
if node.type == "UnaryBoolOp" then
|
||||||
|
return get_macros(node.argument, set)
|
||||||
|
end
|
||||||
|
return set
|
||||||
|
end
|
||||||
|
|
||||||
function print_ast(node, level)
|
function print_ast(node, level)
|
||||||
local t = node.type
|
local t = node.type
|
||||||
|
level = level or 0
|
||||||
local prefix = string.rep(" ", level*2)
|
local prefix = string.rep(" ", level*2)
|
||||||
level = level + 1
|
level = level + 1
|
||||||
|
|
||||||
@ -345,13 +431,13 @@ function print_ast(node, level)
|
|||||||
error ("Unexpected type: "..t)
|
error ("Unexpected type: "..t)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
compiler.parser.print_ast = print_ast
|
||||||
|
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Parses a single line (which should be either a macro definition or a filter) and returns the AST.
|
Parses a single line (which should be either a macro definition or a filter) and returns the AST.
|
||||||
--]]
|
--]]
|
||||||
function compiler.parser.parseline (subject)
|
function compiler.parser.parse_line (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)
|
||||||
@ -369,22 +455,41 @@ end
|
|||||||
to the line-oriented compiler.
|
to the line-oriented compiler.
|
||||||
--]]
|
--]]
|
||||||
function compiler.init()
|
function compiler.init()
|
||||||
return {}
|
return {macros={}}
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Compiles a digwatch filter or macro
|
Compiles a digwatch filter or macro
|
||||||
--]]
|
--]]
|
||||||
function compiler.compile_line(line, state)
|
function compiler.compile_line(line, state)
|
||||||
ast, error_message = compiler.parser.parseline(line)
|
local ast, error_msg = compiler.parser.parse_line(line)
|
||||||
|
|
||||||
if (error_msg) then
|
if (error_msg) then
|
||||||
return {}, state, error_msg
|
return nil, error_msg
|
||||||
end
|
end
|
||||||
expand_in(ast)
|
|
||||||
-- extract_macros(ast, state)
|
local macros = get_macros(ast.value, {})
|
||||||
-- expand_macros(ast, state)
|
for m, _ in pairs(macros) do
|
||||||
return ast, state, error_msg
|
if state.macros[m] == nil then
|
||||||
|
error ("Undefined macro '"..m.."' used in '"..line.."'")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (ast.type == "MacroDef") then
|
||||||
|
state.macros[ast.name] = ast.value
|
||||||
|
return ast, error_msg
|
||||||
|
elseif (ast.type == "Filter") then
|
||||||
|
expand_in(ast)
|
||||||
|
|
||||||
|
repeat
|
||||||
|
expanded = expand_macros(ast, state.macros, false)
|
||||||
|
until expanded == false
|
||||||
|
|
||||||
|
else
|
||||||
|
error("Unexpected top-level AST type: "..ast.type)
|
||||||
|
end
|
||||||
|
|
||||||
|
return ast, error_msg
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
15
lua/test.lua
15
lua/test.lua
@ -7,9 +7,18 @@ end
|
|||||||
|
|
||||||
local state = compiler.init()
|
local state = compiler.init()
|
||||||
|
|
||||||
local ast, state, error_msg = compiler.compile_line(arg[1], state)
|
local function doit(line)
|
||||||
if not ast then
|
local ast, error_msg = compiler.compile_line(line, state)
|
||||||
os.exit(1)
|
|
||||||
|
if not ast then
|
||||||
|
print("error", error_msg)
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
compiler.parser.print_ast(ast)
|
||||||
|
end
|
||||||
|
for str in string.gmatch(arg[1], "([^;]+)") do
|
||||||
|
doit(str)
|
||||||
end
|
end
|
||||||
|
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
|
Loading…
Reference in New Issue
Block a user