1use crate::metrics::context::ParsingContext;
6use crate::metrics::variable::VariableName;
7use crate::metrics::{ExpressionTree, Function, MathFunction, MetricValue};
8use anyhow::{Error, format_err};
9use nom::Err::{self, Incomplete};
10use nom::branch::alt;
11use nom::bytes::complete::{is_not, tag, take_while, take_while_m_n};
12use nom::character::complete::{char, none_of, one_of};
13use nom::combinator::{all_consuming, map, opt, peek, recognize};
14use nom::multi::{fold_many0, many0, separated_list0};
15use nom::sequence::{delimited, pair, preceded, separated_pair, terminated};
16use nom::{AsChar, IResult, Input, Parser};
17use nom_language::error::{VerboseError, convert_error};
18
19pub type ParsingResult<'a, O> = IResult<ParsingContext<'a>, O, VerboseError<ParsingContext<'a>>>;
20
21fn whitespace(i: ParsingContext<'_>) -> ParsingResult<'_, ParsingContext<'_>> {
60 take_while(|c| " \n\t".contains(c)).parse(i)
61}
62
63fn spaced<'a, F, O>(
86 parser: F,
87) -> impl Parser<ParsingContext<'a>, Output = O, Error = VerboseError<ParsingContext<'a>>>
88where
89 F: Parser<ParsingContext<'a>, Output = O, Error = VerboseError<ParsingContext<'a>>>,
90{
91 preceded(whitespace, parser)
92}
93
94fn simple_name(i: ParsingContext<'_>) -> ParsingResult<'_, &str> {
97 map(
98 recognize(pair(
99 take_while_m_n(1, 1, |c: char| c.is_ascii() && (c.is_alpha() || c == '_')),
100 take_while(|c: char| c.is_ascii() && (c.is_alphanum() || c == '_')),
101 )),
102 |name: ParsingContext<'_>| name.into_inner(),
103 )
104 .parse(i)
105}
106
107fn name_with_namespace(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
110 map(separated_pair(simple_name, tag("::"), simple_name), move |(s1, s2)| {
111 ExpressionTree::Variable(VariableName::new(format!("{s1}::{s2}")))
112 })
113 .parse(i)
114}
115
116fn name_no_namespace(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
119 map(simple_name, move |s: &str| ExpressionTree::Variable(VariableName::new(s.to_string())))
120 .parse(i)
121}
122
123fn name(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
126 alt((name_with_namespace, name_no_namespace)).parse(i)
127}
128
129fn decimal_literal(i: ParsingContext<'_>) -> ParsingResult<'_, &str> {
134 map(recognize((one_of("0123456789"), many0(one_of("0123456789_")))), |d: ParsingContext<'_>| {
135 d.into_inner()
136 })
137 .parse(i)
138}
139
140fn float_exponent(i: ParsingContext<'_>) -> ParsingResult<'_, &str> {
147 map(
148 recognize((
149 one_of("eE"),
150 opt(one_of("+-")),
151 many0(char('_')),
152 one_of("0123456789"),
153 many0(one_of("0123456789_")),
154 )),
155 |exponent: ParsingContext<'_>| exponent.into_inner(),
156 )
157 .parse(i)
158}
159
160fn double(i: ParsingContext<'_>) -> ParsingResult<'_, f64> {
171 map(
172 recognize((
173 opt(one_of("+-")),
174 alt((
175 recognize((char('.'), decimal_literal, opt(float_exponent))),
176 recognize((decimal_literal, float_exponent)),
177 recognize((decimal_literal, char('.'), decimal_literal, opt(float_exponent))),
178 recognize((decimal_literal, char('.'), peek(none_of("._")))),
179 recognize((decimal_literal, char('.'))),
180 recognize(decimal_literal),
181 )),
182 )),
183 |d: ParsingContext<'_>| d.into_inner().replace("_", "").parse::<f64>().unwrap(),
184 )
185 .parse(i)
186}
187
188fn number(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
195 match double(i) {
196 Ok((remaining, float)) => {
197 let number_len = i.input_len() - remaining.input_len(); match i.take(number_len).into_inner().parse::<i64>() {
199 Ok(int) => Ok((remaining, ExpressionTree::Value(MetricValue::Int(int)))),
200 Err(_) => Ok((remaining, ExpressionTree::Value(MetricValue::Float(float)))),
201 }
202 }
203 Err(error) => Err(error),
204 }
205}
206
207macro_rules! any_string {
208 ($left:expr, $mid:expr, $right:expr, $i:expr) => {{
209 let mid = map(recognize($mid), |s: ParsingContext<'_>| {
210 ExpressionTree::Value(MetricValue::String(s.into_inner().to_string()))
211 });
212 delimited($left, mid, $right).parse($i)
213 }};
214}
215
216fn single_quote_string(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
217 any_string!(char('\''), is_not("'"), char('\''), i)
218}
219
220fn escaped_single_quote_string(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
221 any_string!(tag("\'"), is_not("\'"), tag("\'"), i)
222}
223
224fn double_quote_string(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
225 any_string!(char('\"'), is_not("\""), char('\"'), i)
226}
227
228fn escaped_double_quote_string(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
229 any_string!(tag("\""), is_not("\""), tag("\""), i)
230}
231
232fn string(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
240 alt((
241 single_quote_string,
242 escaped_single_quote_string,
243 double_quote_string,
244 escaped_double_quote_string,
245 ))
246 .parse(i)
247}
248
249macro_rules! function {
250 ($tag:expr, $function:ident) => {
251 (map(spaced(tag($tag)), move |_| Function::$function))
252 };
253}
254
255macro_rules! math {
256 ($tag:expr, $function:ident) => {
257 (map(spaced(tag($tag)), move |_| Function::Math(MathFunction::$function)))
258 };
259}
260
261fn function_name_parser(i: ParsingContext<'_>) -> ParsingResult<'_, Function> {
262 alt((
267 alt((
268 function!("And", And),
269 function!("Or", Or),
270 function!("Not", Not),
271 math!("Max", Max),
272 function!("Minutes", Minutes), math!("Min", Min),
274 function!("SyslogHas", SyslogHas),
275 function!("KlogHas", KlogHas),
276 function!("BootlogHas", BootlogHas),
277 function!("Missing", Missing),
278 function!("UnhandledType", UnhandledType),
279 function!("Problem", Problem),
280 function!("Annotation", Annotation),
281 math!("Abs", Abs),
282 )),
283 alt((
284 function!("Fn", Lambda),
285 function!("Map", Map),
286 function!("Fold", Fold),
287 function!("All", All),
288 function!("Any", Any),
289 function!("Filter", Filter),
290 function!("Apply", Apply),
291 function!("CountChildren", CountChildren),
292 function!("CountProperties", CountProperties),
293 function!("Count", Count),
294 function!("Nanos", Nanos),
295 function!("Micros", Micros),
296 function!("Millis", Millis),
297 function!("Seconds", Seconds),
298 function!("Hours", Hours),
299 function!("Days", Days),
300 function!("Now", Now),
301 function!("Option", OptionF),
302 function!("StringMatches", StringMatches),
303 function!("True", True),
304 function!("False", False),
305 )),
306 ))
307 .parse(i)
308}
309
310fn function_expression(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
311 let open_paren = spaced(char('('));
312 let expressions = separated_list0(spaced(char(',')), expression_top);
313 let close_paren = spaced(char(')'));
314 let function_sequence = (function_name_parser, open_paren, expressions, close_paren);
315 map(function_sequence, move |(function, _, operands, _)| {
316 ExpressionTree::Function(function, operands)
317 })
318 .parse(i)
319}
320
321fn vector_expression(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
322 let open_bracket = spaced(char('['));
323 let expressions = separated_list0(spaced(char(',')), expression_top);
324 let close_bracket = spaced(char(']'));
325 let vector_sequence = (open_bracket, expressions, close_bracket);
326 map(vector_sequence, move |(_, items, _)| ExpressionTree::Vector(items)).parse(i)
327}
328
329fn expression_primitive(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
333 let paren_expr = delimited(char('('), terminated(expression_top, whitespace), char(')'));
334
335 spaced(alt((paren_expr, function_expression, vector_expression, number, string, name))).parse(i)
336}
337
338fn expression_muldiv(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
340 let (i, init) = expression_primitive(i)?;
341 let mut init = Some(init);
342 fold_many0(
343 pair(
344 alt((
345 math!("*", Mul),
346 math!("//?", IntDivChecked),
347 math!("/?", FloatDivChecked),
348 math!("//", IntDiv),
349 math!("/", FloatDiv),
350 )),
351 expression_primitive,
352 ),
353 move || init.take().unwrap(),
354 |acc, (op, expr)| ExpressionTree::Function(op, vec![acc, expr]),
355 )
356 .parse(i)
357}
358
359fn expression_addsub(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
362 let (i, init) = expression_muldiv(i)?;
363 let mut init = Some(init);
364 fold_many0(
365 pair(alt((math!("+", Add), math!("-", Sub))), expression_muldiv),
366 move || init.take().unwrap(),
367 |acc, (op, expr)| ExpressionTree::Function(op, vec![acc, expr]),
368 )
369 .parse(i)
370}
371
372fn expression_top(i: ParsingContext<'_>) -> ParsingResult<'_, ExpressionTree> {
375 let comparison = alt((
378 math!(">=", GreaterEq),
379 math!("<=", LessEq),
380 function!("==", Equals),
381 function!("!=", NotEq),
382 math!(">", Greater),
383 math!("<", Less),
384 ));
385 alt((
386 map((expression_addsub, comparison, expression_addsub), move |(left, op, right)| {
387 ExpressionTree::Function(op, vec![left, right])
388 }),
389 expression_addsub,
390 ))
391 .parse(i)
392}
393
394pub(crate) fn parse_expression(i: &str, namespace: &str) -> Result<ExpressionTree, Error> {
397 let ctx = ParsingContext::new(i, namespace);
398 let mut match_whole = all_consuming(terminated(expression_top, whitespace));
399 match match_whole.parse(ctx) {
400 Err(Err::Error(e)) | Err(Err::Failure(e)) => Err(format_err!(
401 "Expression Error: \n{}",
402 convert_error(
403 ctx.into_inner(),
404 VerboseError {
405 errors: e.errors.into_iter().map(|e| (e.0.into_inner(), e.1)).collect()
406 }
407 )
408 )),
409 Ok((_, result)) => Ok(result),
410 Err(Incomplete(what)) => Err(format_err!("Why did I get an incomplete? {:?}", what)),
411 }
412}
413
414#[cfg(test)]
415mod test {
416 use super::*;
417 use crate::assert_problem;
418 use crate::metrics::{Fetcher, MetricState, TrialDataFetcher};
419 use std::collections::HashMap;
420
421 #[derive(PartialEq, Debug)]
426 enum Res<'a, T> {
427 Ok(&'a str, T),
428 Err(String),
429 }
430
431 fn simplify_fn<'a, T: std::fmt::Debug>(i: &str, r: ParsingResult<'a, T>) -> Res<'a, T> {
432 match r {
433 Err(Err::Error(e)) => Res::Err(format!(
434 "Error: \n{:?}",
435 convert_error(
436 i,
437 VerboseError {
438 errors: e.errors.into_iter().map(|e| (e.0.into_inner(), e.1)).collect()
439 }
440 )
441 )),
442 Err(Err::Failure(e)) => Res::Err(format!(
443 "Failure: \n{:?}",
444 convert_error(
445 i,
446 VerboseError {
447 errors: e.errors.into_iter().map(|e| (e.0.into_inner(), e.1)).collect()
448 }
449 )
450 )),
451 Err(Incomplete(e)) => Res::Err(format!("Incomplete: {e:?}")),
452 Ok((unused, result)) => Res::Ok(unused.into_inner(), result),
453 }
454 }
455
456 macro_rules! get_parse {
457 ($fn:expr, $string:expr) => {
458 simplify_fn($string, $fn(ParsingContext::new($string, "")))
459 };
460 }
461
462 impl<T> Res<'_, T> {
463 fn is_err(&self) -> bool {
464 match self {
465 Res::Err(_) => true,
466 Res::Ok(_, _) => false,
467 }
468 }
469 }
470
471 #[fuchsia::test]
472 fn parse_vectors() {
473 fn v(i: i64) -> ExpressionTree {
474 ExpressionTree::Value(MetricValue::Int(i))
475 }
476
477 assert_eq!(
478 get_parse!(expression_primitive, "[1,2]"),
479 Res::Ok("", ExpressionTree::Vector(vec![v(1), v(2)]))
480 );
481 assert_eq!(
482 get_parse!(expression_primitive, " [ 1 , 2 ] "),
483 Res::Ok(" ", ExpressionTree::Vector(vec![v(1), v(2)]))
484 );
485 assert_eq!(
486 get_parse!(expression_primitive, "[1]"),
487 Res::Ok("", ExpressionTree::Vector(vec![v(1)]))
488 );
489 assert_eq!(
490 get_parse!(expression_primitive, "[]"),
491 Res::Ok("", ExpressionTree::Vector(Vec::new()))
492 );
493 let first = ExpressionTree::Function(Function::Math(MathFunction::Add), vec![v(1), v(2)]);
494 let second = ExpressionTree::Function(Function::Math(MathFunction::Sub), vec![v(2), v(1)]);
495 assert_eq!(
496 get_parse!(expression_primitive, "[1+2, 2-1]"),
497 Res::Ok("", ExpressionTree::Vector(vec![first, second]))
498 );
499 assert!(get_parse!(expression_primitive, "[1+2, 2-1").is_err());
501 assert_eq!(get_parse!(expression_primitive, "1+2, 2-1"), Res::Ok("+2, 2-1", v(1)));
504 assert!(get_parse!(expression_primitive, "]").is_err());
505 assert!(get_parse!(expression_primitive, "[").is_err());
506 }
507
508 #[fuchsia::test]
509 fn parse_numbers() {
510 assert!(get_parse!(number, "f5").is_err());
512 assert!(get_parse!(number, " 1").is_err());
513 assert!(get_parse!(number, "").is_err());
515 assert_eq!(
517 get_parse!(number, "1 "),
518 Res::Ok(" ", ExpressionTree::Value(MetricValue::Int(1)))
519 );
520 assert_eq!(
521 get_parse!(number, "1a"),
522 Res::Ok("a", ExpressionTree::Value(MetricValue::Int(1)))
523 );
524 assert_eq!(
526 get_parse!(number, "234"),
527 Res::Ok("", ExpressionTree::Value(MetricValue::Int(234)))
528 );
529 assert_eq!(
531 get_parse!(number, "234.0"),
532 Res::Ok("", ExpressionTree::Value(MetricValue::Float(234.0)))
533 );
534 assert_eq!(
535 get_parse!(number, "234.0e-5"),
536 Res::Ok("", ExpressionTree::Value(MetricValue::Float(234.0e-5)))
537 );
538 assert_eq!(
540 get_parse!(number, "0"),
541 Res::Ok("", ExpressionTree::Value(MetricValue::Int(0)))
542 );
543 assert_eq!(
544 get_parse!(number, "00234"),
545 Res::Ok("", ExpressionTree::Value(MetricValue::Int(234)))
546 );
547 assert_eq!(
548 get_parse!(number, "+234"),
549 Res::Ok("", ExpressionTree::Value(MetricValue::Int(234)))
550 );
551 assert_eq!(
552 get_parse!(number, "-234"),
553 Res::Ok("", ExpressionTree::Value(MetricValue::Int(-234)))
554 );
555 assert_eq!(
557 get_parse!(number, "0.0"),
558 Res::Ok("", ExpressionTree::Value(MetricValue::Float(0.0)))
559 );
560 assert_eq!(
561 get_parse!(number, "00234.0"),
562 Res::Ok("", ExpressionTree::Value(MetricValue::Float(234.0)))
563 );
564 assert_eq!(
565 get_parse!(number, "+234.0"),
566 Res::Ok("", ExpressionTree::Value(MetricValue::Float(234.0)))
567 );
568 assert_eq!(
569 get_parse!(number, "-234.0"),
570 Res::Ok("", ExpressionTree::Value(MetricValue::Float(-234.0)))
571 );
572 assert_eq!(
574 get_parse!(number, ".1"),
575 Res::Ok("", ExpressionTree::Value(MetricValue::Float(0.1)))
576 );
577 assert_eq!(
578 get_parse!(number, "1."),
579 Res::Ok("", ExpressionTree::Value(MetricValue::Float(1.0)))
580 );
581 assert_eq!(
582 get_parse!(number, "1.a"),
583 Res::Ok("a", ExpressionTree::Value(MetricValue::Float(1.0)))
584 );
585
586 assert_eq!(
587 get_parse!(number, ".12_34___"),
588 Res::Ok("", ExpressionTree::Value(MetricValue::Float(0.1234)))
589 );
590 assert_eq!(
591 get_parse!(number, ".2e__2_"),
592 Res::Ok("", ExpressionTree::Value(MetricValue::Float(20.0)))
593 );
594 assert_eq!(
595 get_parse!(number, "1_234_567___8E-__1_0__"),
596 Res::Ok("", ExpressionTree::Value(MetricValue::Float(0.0012345678)))
597 );
598 assert_eq!(
599 get_parse!(number, "1__234__.12E-3__"),
600 Res::Ok("", ExpressionTree::Value(MetricValue::Float(1.23412)))
601 );
602 assert_eq!(
603 get_parse!(number, "1_2__3__4__"),
604 Res::Ok("", ExpressionTree::Value(MetricValue::Int(1234)))
605 );
606
607 assert!(get_parse!(number, "_100").is_err());
609 }
610
611 #[fuchsia::test]
612 fn parse_string() {
613 assert!(get_parse!(string, "OK").is_err());
615
616 assert!(get_parse!(string, "'OK").is_err());
618
619 assert_eq!(
620 get_parse!(string, "'OK'"),
621 Res::Ok("", ExpressionTree::Value(MetricValue::String("OK".to_string())))
622 );
623 assert_eq!(
624 get_parse!(string, "'OK'a"),
625 Res::Ok("a", ExpressionTree::Value(MetricValue::String("OK".to_string())))
626 );
627 assert_eq!(
628 get_parse!(string, r#""OK""#),
629 Res::Ok("", ExpressionTree::Value(MetricValue::String("OK".to_string())))
630 );
631 assert_eq!(
632 get_parse!(string, "\'OK\'"),
633 Res::Ok("", ExpressionTree::Value(MetricValue::String("OK".to_string())))
634 );
635 assert_eq!(
636 get_parse!(string, "\"OK\""),
637 Res::Ok("", ExpressionTree::Value(MetricValue::String("OK".to_string())))
638 );
639
640 assert_eq!(
642 get_parse!(string, r#"'a"b'"#),
643 Res::Ok("", ExpressionTree::Value(MetricValue::String(r#"a"b"#.to_string())))
644 );
645 assert_eq!(
646 get_parse!(string, r#""a'b""#),
647 Res::Ok("", ExpressionTree::Value(MetricValue::String("a'b".to_string())))
648 );
649
650 assert_eq!(
652 get_parse!(string, "'OK OK'"),
653 Res::Ok("", ExpressionTree::Value(MetricValue::String("OK OK".to_string())))
654 );
655
656 assert_eq!(
658 get_parse!(string, "'123'"),
659 Res::Ok("", ExpressionTree::Value(MetricValue::String("123".to_string())))
660 );
661 }
662
663 macro_rules! variable_expression {
664 ($name:expr) => {
665 ExpressionTree::Variable(VariableName::new($name.to_owned()))
666 };
667 }
668
669 #[fuchsia::test]
670 fn parse_names_no_namespace() {
671 assert_eq!(get_parse!(name_no_namespace, "abc"), Res::Ok("", variable_expression!("abc")));
672 assert_eq!(get_parse!(name_no_namespace, "bc."), Res::Ok(".", variable_expression!("bc")));
673 assert_eq!(
675 get_parse!(name_no_namespace, "bc42."),
676 Res::Ok(".", variable_expression!("bc42"))
677 );
678 assert!(get_parse!(name_no_namespace, "42bc.").is_err());
679 assert_eq!(
680 get_parse!(name_no_namespace, "_bc42_"),
681 Res::Ok("", variable_expression!("_bc42_"))
682 );
683 assert_eq!(
684 get_parse!(name_no_namespace, "_bc42_::abc"),
685 Res::Ok("::abc", variable_expression!("_bc42_"))
686 );
687 assert_eq!(
688 get_parse!(name_no_namespace, "_bc42_:abc"),
689 Res::Ok(":abc", variable_expression!("_bc42_"))
690 );
691 }
692
693 #[fuchsia::test]
694 fn parse_names_with_namespace() {
695 assert_eq!(
696 get_parse!(name_with_namespace, "_bc42_::abc"),
697 Res::Ok("", variable_expression!("_bc42_::abc"))
698 );
699 assert_eq!(
700 get_parse!(name_with_namespace, "_bc42_::abc::def"),
701 Res::Ok("::def", variable_expression!("_bc42_::abc"))
702 );
703 assert!(get_parse!(name_with_namespace, "_bc42_:abc::def").is_err());
704 }
705
706 #[fuchsia::test]
707 fn parse_names() {
708 assert_eq!(
709 get_parse!(name, "_bc42_::abc"),
710 Res::Ok("", variable_expression!("_bc42_::abc"))
711 );
712 assert_eq!(
713 get_parse!(name, "_bc42_:abc::def"),
714 Res::Ok(":abc::def", variable_expression!("_bc42_"))
715 );
716 assert_eq!(
717 get_parse!(name, "_bc42_::abc::def"),
718 Res::Ok("::def", variable_expression!("_bc42_::abc"))
719 );
720 }
721
722 macro_rules! eval {
723 ($e:expr) => {
724 MetricState::evaluate_math($e)
725 };
726 }
727
728 #[fuchsia::test]
729 fn parse_number_types() -> Result<(), Error> {
730 assert_eq!(eval!("2"), MetricValue::Int(2));
731 assert_eq!(eval!("2+3"), MetricValue::Int(5));
732 assert_eq!(eval!("2.0+3"), MetricValue::Float(5.0));
733 assert_eq!(eval!("2+3.0"), MetricValue::Float(5.0));
734 assert_eq!(eval!("2.0+2.0"), MetricValue::Float(4.0));
735
736 Ok(())
737 }
738
739 #[fuchsia::test]
740 fn parse_div_operations() -> Result<(), Error> {
741 assert_eq!(eval!("5.0/2"), MetricValue::Float(2.5));
742 assert_eq!(eval!("-5.0/2"), MetricValue::Float(-2.5));
743 assert_eq!(eval!("5.0/2.0"), MetricValue::Float(2.5));
744 assert_eq!(eval!("-5.0/2.0"), MetricValue::Float(-2.5));
745 assert_eq!(eval!("5/2"), MetricValue::Float(2.5));
746 assert_eq!(eval!("-5/2"), MetricValue::Float(-2.5));
747
748 assert_eq!(eval!("5.0//2"), MetricValue::Float(2.0));
750 assert_eq!(eval!("-5.0//2"), MetricValue::Float(-2.0));
751 assert_eq!(eval!("5.0//2.0"), MetricValue::Float(2.0));
752 assert_eq!(eval!("-5.0//2.0"), MetricValue::Float(-2.0));
753 assert_eq!(eval!("5//2"), MetricValue::Int(2));
754 assert_eq!(eval!("-5//2"), MetricValue::Int(-2));
755
756 assert_eq!(eval!("5000//5.1"), MetricValue::Float(980.0));
758 Ok(())
759 }
760
761 #[fuchsia::test]
762 fn parse_operator_precedence() -> Result<(), Error> {
763 assert_eq!(eval!("2+3*4"), MetricValue::Int(14));
764 assert_eq!(eval!("2+3*4>14-1*1"), MetricValue::Bool(true));
765 assert_eq!(eval!("3*4+2"), MetricValue::Int(14));
766 assert_eq!(eval!("2-3-4"), MetricValue::Int(-5));
767 assert_eq!(eval!("6//3*4"), MetricValue::Int(8));
768 assert_eq!(eval!("6//?3*4"), MetricValue::Int(8));
769 assert_eq!(eval!("6/3*4"), MetricValue::Float(8.0));
770 assert_eq!(eval!("6/?3*4"), MetricValue::Float(8.0));
771 assert_eq!(eval!("8/4/2"), MetricValue::Float(1.0));
772 assert_eq!(eval!("8/4*2"), MetricValue::Float(4.0));
773 assert_eq!(eval!("2-3-4"), MetricValue::Int(-5));
774 assert_eq!(eval!("(2+3)*4"), MetricValue::Int(20));
775 assert_eq!(eval!("2++4"), MetricValue::Int(6));
776 assert_eq!(eval!("2+-4"), MetricValue::Int(-2));
777 assert_eq!(eval!("2-+4"), MetricValue::Int(-2));
778 assert_eq!(eval!("2--4"), MetricValue::Int(6));
779 Ok(())
780 }
781
782 #[fuchsia::test]
783 fn division_by_zero() -> Result<(), Error> {
784 assert_problem!(eval!("4/0"), "ValueError: Division by zero");
785 assert_problem!(eval!("4//0"), "ValueError: Division by zero");
786 assert_problem!(eval!("4/?0"), "Ignore: ValueError: Division by zero");
787 assert_problem!(eval!("4//?0"), "Ignore: ValueError: Division by zero");
788 Ok(())
789 }
790
791 #[fuchsia::test]
792 fn parser_accepts_whitespace() -> Result<(), Error> {
793 assert_eq!(eval!(" 2 + +3 * 4 - 5 // ( -2 + Min ( -2 , 3 ) ) "), MetricValue::Int(15));
794 Ok(())
795 }
796
797 #[fuchsia::test]
798 fn parser_comparisons() -> Result<(), Error> {
799 assert_eq!(
800 format!("{:?}", parse_expression("2>1", "")),
801 "Ok(Function(Math(Greater), [Value(Int(2)), Value(Int(1))]))"
802 );
803 assert_eq!(eval!("2>2"), MetricValue::Bool(false));
804 assert_eq!(eval!("2>=2"), MetricValue::Bool(true));
805 assert_eq!(eval!("2<2"), MetricValue::Bool(false));
806 assert_eq!(eval!("2<=2"), MetricValue::Bool(true));
807 assert_eq!(eval!("2==2"), MetricValue::Bool(true));
808 assert_eq!(eval!("2==2.0"), MetricValue::Bool(true));
809
810 assert_eq!(eval!("'a'=='a'"), MetricValue::Bool(true));
812 assert_eq!(eval!("'a'!='a'"), MetricValue::Bool(false));
813 assert_eq!(eval!("'a'!='b'"), MetricValue::Bool(true));
814
815 assert_eq!(eval!(r#""a"=="a""#), MetricValue::Bool(true));
817 assert_eq!(eval!(r#"'a'=="a""#), MetricValue::Bool(true));
818
819 assert!(parse_expression("2==2==2", "").is_err());
821 Ok(())
822 }
823
824 #[fuchsia::test]
825 fn parser_boolean_functions_value() -> Result<(), Error> {
826 assert_eq!(
827 format!("{:?}", parse_expression("Not(2>1)", "")),
828 "Ok(Function(Not, [Function(Math(Greater), [Value(Int(2)), Value(Int(1))])]))"
829 );
830 assert_eq!(eval!("And(2>1, 2>2)"), MetricValue::Bool(false));
831 assert_eq!(eval!("And(2>2, 2>1)"), MetricValue::Bool(false));
832 assert_eq!(eval!("And(2>2, 2>2)"), MetricValue::Bool(false));
833 assert_eq!(eval!("And(2>1, 2>1)"), MetricValue::Bool(true));
834 assert_eq!(eval!("Or(2>1, 2>2)"), MetricValue::Bool(true));
835 assert_eq!(eval!("Or(2>2, 2>1)"), MetricValue::Bool(true));
836 assert_eq!(eval!("Or(2>2, 2>2)"), MetricValue::Bool(false));
837 assert_eq!(eval!("Or(2>1, 2>1)"), MetricValue::Bool(true));
838 assert_eq!(eval!("Not(2>1)"), MetricValue::Bool(false));
839 assert_eq!(eval!("Not(2>2)"), MetricValue::Bool(true));
840 Ok(())
841 }
842
843 #[fuchsia::test]
844 fn parser_boolean_functions_args() -> Result<(), Error> {
845 assert_eq!(eval!("And(2>1)"), MetricValue::Bool(true));
846 assert_eq!(eval!("And(2>1, 2>1, 2>1)"), MetricValue::Bool(true));
847 assert_problem!(eval!("And()"), "SyntaxError: No operands in boolean expression");
848 assert_eq!(eval!("Or(2>1)"), MetricValue::Bool(true));
849 assert_eq!(eval!("Or(2>1, 2>1, 2>1)"), MetricValue::Bool(true));
850 assert_problem!(eval!("Or()"), "SyntaxError: No operands in boolean expression");
851 assert_problem!(
852 eval!("Not(2>1, 2>1)"),
853 "SyntaxError: Wrong number of arguments (2) for unary bool operator"
854 );
855 assert_problem!(
856 eval!("Not()"),
857 "SyntaxError: Wrong number of arguments (0) for unary bool operator"
858 );
859 Ok(())
860 }
861
862 #[fuchsia::test]
863 fn parser_maxmin_functions() -> Result<(), Error> {
864 assert_eq!(eval!("Max(2, 5, 3, -1)"), MetricValue::Int(5));
865 assert_eq!(eval!("Min(2, 5, 3, -1)"), MetricValue::Int(-1));
866 assert_eq!(eval!("Min(2)"), MetricValue::Int(2));
867 assert_eq!(eval!("Max(2)"), MetricValue::Int(2));
868 assert_problem!(eval!("Max()"), "SyntaxError: No operands in math expression");
869 assert_problem!(eval!("Min()"), "SyntaxError: No operands in math expression");
870 Ok(())
871 }
872
873 #[fuchsia::test]
874 fn parser_time_functions() -> Result<(), Error> {
875 assert_eq!(eval!("Nanos(5)"), MetricValue::Int(5));
876 assert_eq!(eval!("Micros(4)"), MetricValue::Int(4_000));
877 assert_eq!(eval!("Millis(5)"), MetricValue::Int(5_000_000));
878 assert_eq!(eval!("Seconds(2)"), MetricValue::Int(2_000_000_000));
879 assert_eq!(eval!("Minutes(2)"), MetricValue::Int(2_000_000_000 * 60));
880 assert_eq!(eval!("Hours(2)"), MetricValue::Int(2_000_000_000 * 60 * 60));
881 assert_eq!(eval!("Days(2)"), MetricValue::Int(2_000_000_000 * 60 * 60 * 24));
882 assert_eq!(eval!("Seconds(0.5)"), MetricValue::Int(500_000_000));
884 assert_eq!(eval!("Seconds(-0.5)"), MetricValue::Int(-500_000_000));
886 assert_problem!(eval!("Hours()"), "SyntaxError: Time conversion needs 1 numeric argument");
888 assert_problem!(
889 eval!("Hours(2, 3)"),
890 "SyntaxError: Time conversion needs 1 numeric argument"
891 );
892 assert_problem!(
893 eval!("Hours('a')"),
894 "ValueError: Time conversion needs 1 numeric argument, not String(a)"
895 );
896 assert_problem!(eval!("1.0/0.0"), "ValueError: Division by zero");
897 assert_problem!(eval!("Hours(1.0/0.0)"), "ValueError: Division by zero");
898 Ok(())
899 }
900
901 #[fuchsia::test]
902 fn parser_nested_function() -> Result<(), Error> {
903 assert_eq!(eval!("Max(2, Min(4-1, 5))"), MetricValue::Int(3));
904 assert_eq!(eval!("And(Max(1, 2+3)>1, Or(1>2, 2>1))"), MetricValue::Bool(true));
905 Ok(())
906 }
907
908 #[fuchsia::test]
909 fn singleton_vecs_promote() -> Result<(), Error> {
910 assert_eq!(eval!("Max([1+1], Min([4]-1, 4+[1]))"), MetricValue::Int(3));
911 assert_eq!(eval!("And(Max(1, 2+[3])>1, Or([1]>2, [1>2], 2>[1]))"), MetricValue::Bool(true));
912 Ok(())
913 }
914
915 fn b(b: bool) -> MetricValue {
916 MetricValue::Bool(b)
917 }
918
919 fn i(i: i64) -> MetricValue {
920 MetricValue::Int(i)
921 }
922
923 fn v(v: &[MetricValue]) -> MetricValue {
924 MetricValue::Vector(v.to_vec())
925 }
926
927 #[fuchsia::test]
928 fn functional_programming() -> Result<(), Error> {
929 assert_eq!(eval!("Apply(Fn([], 5), [])"), i(5));
930 assert_eq!(eval!("Apply(Fn([a], a+5), [2])"), i(7));
931 assert_eq!(eval!("Apply(Fn([a, b], a*b+5), [2, 3])"), i(11));
932 assert_eq!(eval!("Map(Fn([a], a*2), [1,2,3])"), v(&[i(2), i(4), i(6)]));
933 assert_eq!(
934 eval!("Map(Fn([a, b], [a, b]), [1, 2, 3], [4, 5, 6])"),
935 v(&[v(&[i(1), i(4)]), v(&[i(2), i(5)]), v(&[i(3), i(6)])])
936 );
937 assert_eq!(eval!("Map(Fn([a, b], [a, b]), [1, 2, 3], [4])"), v(&[v(&[i(1), i(4)])]));
938 assert_eq!(
939 eval!("Map(Fn([a, b], [a, b]), [1, 2, 3], 4)"),
940 v(&[v(&[i(1), i(4)]), v(&[i(2), i(4)]), v(&[i(3), i(4)])])
941 );
942 assert_eq!(eval!("Fold(Fn([a, b], a + b), [1, 2, 3])"), i(6));
943 assert_eq!(eval!("Fold(Fn([a, b], a + 1), ['a', 'b', 'c', 'd'], 0)"), i(4));
944 assert_eq!(eval!("Filter(Fn([a], a > 5), [2, 4, 6, 8])"), v(&[i(6), i(8)]));
945 assert_eq!(eval!("Count([1, 'a', 3, 2])"), i(4));
946
947 assert_eq!(eval!("All(Fn([a], a > 5), [2, 4, 6, 8])"), b(false));
948 assert_eq!(eval!("All(Fn([a], a > 1), [2, 4, 6, 8])"), b(true));
949 assert_eq!(eval!("Any(Fn([a], a > 5), [2, 4, 6, 8])"), b(true));
950 assert_eq!(eval!("Any(Fn([a], a > 8), [2, 4, 6, 8])"), b(false));
951 assert_eq!(eval!("Any(Fn([a], a > 8), [])"), b(false));
952 assert_eq!(eval!("All(Fn([a], a > 8), [])"), b(true));
953
954 assert_problem!(
956 eval!("All([2, 4, 6, 8], Fn([a], a > 8))"),
957 "SyntaxError: All needs a function in its first argument"
958 );
959 assert_problem!(eval!("All()"), "SyntaxError: All needs a function in its first argument");
961 assert_problem!(
963 eval!("All(Fn([a], a > 8))"),
964 "SyntaxError: All needs two arguments (function, vector)"
965 );
966 assert_problem!(
968 eval!("All(Fn([a], a > 8), [], [])"),
969 "SyntaxError: All needs two arguments (function, vector)"
970 );
971 assert_problem!(
973 eval!("All(Fn([a], a > 8), 'b')"),
974 "SyntaxError: The second argument passed to All must be a vector"
975 );
976 assert_problem!(eval!("Any(Fn([a], a), [2, 4])"), "ValueError: Int(2) is not boolean");
978 Ok(())
979 }
980
981 #[fuchsia::test]
982 fn booleans() {
983 assert_eq!(eval!("True()"), MetricValue::Bool(true));
984 assert_eq!(eval!("False()"), MetricValue::Bool(false));
985 assert_problem!(
986 eval!("True(1)"),
987 "SyntaxError: Boolean functions don't take any arguments"
988 );
989 }
990
991 #[fuchsia::test]
992 fn test_now() -> Result<(), Error> {
993 let now_expression = parse_expression("Now()", "")?;
994 let values = HashMap::new();
995 let fetcher = Fetcher::TrialData(TrialDataFetcher::new(&values));
996 let files = HashMap::new();
997 let state = MetricState::new(&files, fetcher, Some(2000));
998
999 let time = state.evaluate_expression(&now_expression);
1000 let no_time =
1001 state.evaluate_expression(&parse_expression("Now(5)", "")?);
1002 assert_eq!(time, i(2000));
1003 assert_problem!(no_time, "SyntaxError: Now() requires no operands.");
1004 Ok(())
1005 }
1006
1007 #[fuchsia::test]
1008 fn test_option() {
1009 assert_problem!(eval!("Option()"), "Missing: Every value was missing");
1011 assert_problem!(
1013 eval!("Option(Now(), Now(), Now(), Now())"),
1014 "Missing: Every value was missing"
1015 );
1016 assert_eq!(eval!("Option(5)"), i(5));
1017 assert_eq!(eval!("Option(5, Now())"), i(5));
1018 assert_eq!(eval!("Option(Now(), 5, Now())"), i(5));
1019 assert_eq!(eval!("Option(Now(), Now(), Now(), Now(), 5)"), i(5));
1020 assert_eq!(eval!("Option(Now(), Now(), [], Now())"), MetricValue::Vector(vec![]));
1021 assert_eq!(eval!("Option(Now(), Now(), [], Now(), [5])"), MetricValue::Vector(vec![i(5)]));
1022 assert_eq!(eval!("Option(Now(), Now(), 5, Now(), [5])"), i(5));
1023 assert_eq!(eval!("Option(Now(), Now(), [5], Now(), 5)"), MetricValue::Vector(vec![i(5)]));
1024 }
1025
1026 #[fuchsia::test]
1027 fn test_abs() {
1028 assert_eq!(eval!("Abs(-10)"), i(10));
1029 assert_eq!(eval!("Abs(10)"), i(10));
1030 assert_eq!(eval!("Abs(-1.23)"), MetricValue::Float(1.23));
1031 assert_eq!(eval!("Abs(1.23)"), MetricValue::Float(1.23));
1032
1033 assert_problem!(eval!("Abs(1,2)"), "SyntaxError: Abs requires exactly one operand.");
1034 assert_problem!(eval!("Abs(1,2,3)"), "SyntaxError: Abs requires exactly one operand.");
1035 assert_problem!(eval!("Abs()"), "SyntaxError: Abs requires exactly one operand.");
1036 assert_problem!(
1037 eval!(r#"Abs("quoted-string")"#),
1038 "Missing: String(quoted-string) not numeric"
1039 );
1040 assert_problem!(eval!("Abs(True())"), "Missing: Bool(true) not numeric");
1041 }
1042}