enh(generic-snmp): Average, Max and Min functions are back

This commit is contained in:
David Boucher 2025-04-21 19:01:12 +02:00
parent 2f3eed6050
commit 535064daa8
4 changed files with 51 additions and 11 deletions

View File

@ -249,9 +249,27 @@ impl<'input> Expr<'input> {
Expr::Fn(func, expr) => {
let v = expr.eval(collect);
match func {
Func::Average => v,
Func::Min => v,
Func::Max => v,
Func::Average => match v {
ExprResult::Scalar(n) => ExprResult::Scalar(n),
ExprResult::Vector(v) => {
let sum = v.iter().sum::<f64>();
ExprResult::Scalar(sum / v.len() as f64)
}
},
Func::Min => match v {
ExprResult::Scalar(n) => ExprResult::Scalar(n),
ExprResult::Vector(v) => {
let min = v.iter().cloned().fold(f64::INFINITY, f64::min);
ExprResult::Scalar(min)
}
},
Func::Max => match v {
ExprResult::Scalar(n) => ExprResult::Scalar(n),
ExprResult::Vector(v) => {
let max = v.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
ExprResult::Scalar(max)
}
},
}
}
}

View File

@ -119,10 +119,12 @@ impl<'input> Iterator for Lexer<'input> {
}
b'(' => {
self.offset = i + 1;
debug!("Token LParen at {}", i);
return Some(Ok((i, Tok::LParen, i + 1)));
}
b')' => {
self.offset = i + 1;
debug!("Token RParen at {}", i);
return Some(Ok((i, Tok::RParen, i + 1)));
}
b'{' => {

View File

@ -211,12 +211,15 @@ mod Test {
#[test]
fn function() {
// let res = grammar::ExprParser::new().parse("Average(1, 2, 3)");
// assert!(res.is_ok());
// assert!(res.unwrap() == 2_f32);
//
// let res = grammar::ExprParser::new().parse("Average(1 + 2 * 2, 3, 4)");
// assert!(res.is_ok());
// assert!(res.unwrap() == 4_f32);
let lexer = lexer::Lexer::new("Average({abc})");
let res = grammar::ExprParser::new().parse(lexer);
assert!(res.is_ok());
let items = HashMap::from([("abc".to_string(), SnmpItem::Nbr(vec![1_f64, 2_f64, 3_f64]))]);
let snmp_result = vec![SnmpResult::new(items)];
let res = res.unwrap().eval(&snmp_result);
match res {
ExprResult::Scalar(n) => assert!(n == 2_f64),
_ => panic!("Expected a scalar value"),
}
}
}

View File

@ -15,12 +15,29 @@ pub Product: Box<ast::Expr<'input>> = {
<v:Term> => <>,
};
pub Function: Box<ast::Expr<'input>> = {
<f:"id"> "(" <a:Var> ")" => {
match f {
b"Average" => return Box::new(ast::Expr::Fn(ast::Func::Average, a)),
b"Max" => return Box::new(ast::Expr::Fn(ast::Func::Max, a)),
b"Min" => return Box::new(ast::Expr::Fn(ast::Func::Min, a)),
// FIXME DBO: This case is an error case...
_ => return a,
}
}
};
pub Term: Box<ast::Expr<'input>> = {
"num" => Box::new(ast::Expr::Number(<>)),
Function => <>,
"(" <v:Expr> ")" => <>,
"{" <"id"> "}" => Box::new(ast::Expr::Id(<>)),
Var => <>,
};
pub Var: Box<ast::Expr<'input>> = {
"{" <"id"> "}" => Box::new(ast::Expr::Id(<>)),
}
extern {
type Location = usize;
type Error = lexer::LexicalError;