diff --git a/experimental/src/compute/ast.rs b/experimental/src/compute/ast.rs index 9b8b4cffc..458de5b9b 100644 --- a/experimental/src/compute/ast.rs +++ b/experimental/src/compute/ast.rs @@ -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::(); + 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) + } + }, } } } diff --git a/experimental/src/compute/lexer.rs b/experimental/src/compute/lexer.rs index d7ffd2098..b2d20574e 100644 --- a/experimental/src/compute/lexer.rs +++ b/experimental/src/compute/lexer.rs @@ -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'{' => { diff --git a/experimental/src/compute/mod.rs b/experimental/src/compute/mod.rs index ba50e7471..0b288bdef 100644 --- a/experimental/src/compute/mod.rs +++ b/experimental/src/compute/mod.rs @@ -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"), + } } } diff --git a/experimental/src/grammar.lalrpop b/experimental/src/grammar.lalrpop index 7924053b1..fe3f4a881 100644 --- a/experimental/src/grammar.lalrpop +++ b/experimental/src/grammar.lalrpop @@ -15,12 +15,29 @@ pub Product: Box> = { => <>, }; +pub Function: Box> = { + "(" ")" => { + 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> = { "num" => Box::new(ast::Expr::Number(<>)), + Function => <>, "(" ")" => <>, - "{" <"id"> "}" => Box::new(ast::Expr::Id(<>)), + Var => <>, }; +pub Var: Box> = { + "{" <"id"> "}" => Box::new(ast::Expr::Id(<>)), +} + extern { type Location = usize; type Error = lexer::LexicalError;