1use nom::branch::alt;
5use nom::bytes::complete::tag;
6use nom::combinator::{cut, map};
7use nom::sequence::preceded;
8use nom::Parser;
9
10use crate::error::{Error, ErrorKind};
11use crate::expression::common::range;
12use crate::expression::for_expression::{
13 for_expression_non_ambiguous, for_expression_with_expr_selection,
14};
15use crate::expression::primary_expression::primary_expression;
16use crate::expression::{Expression, ExpressionKind};
17use crate::nom_recipes::{rtrim, textual_tag as ttag};
18use crate::regex::{regex, Regex};
19use crate::string::string_identifier;
20use crate::types::{Input, ParseResult};
21
22pub(crate) fn boolean_expression(mut input: Input) -> ParseResult<Expression> {
24 let start = input.pos();
36
37 if input.expr_recursion_counter >= super::MAX_EXPR_RECURSION {
38 return Err(nom::Err::Failure(Error::new(
39 input.get_span_from(start),
40 ErrorKind::ExprTooDeep,
41 )));
42 }
43
44 input.expr_recursion_counter += 1;
45 let (mut input, res) = expression_and(input)?;
46
47 match rtrim(ttag("or")).parse(input) {
48 Ok((mut input, _)) => {
49 let mut ops = vec![res];
50 loop {
51 let (mut i2, elem) = cut(expression_and).parse(input)?;
52 ops.push(elem);
53 match rtrim(ttag("or"))(i2) {
54 Ok((i3, _)) => input = i3,
55 Err(_) => {
56 i2.expr_recursion_counter -= 1;
57 return Ok((
58 i2,
59 Expression {
60 expr: ExpressionKind::Or(ops),
61 span: i2.get_span_from(start),
62 },
63 ));
64 }
65 }
66 }
67 }
68 Err(_) => {
69 input.expr_recursion_counter -= 1;
70 Ok((input, res))
71 }
72 }
73}
74
75fn expression_and(input: Input) -> ParseResult<Expression> {
77 let start = input.pos();
78 let (input, res) = expression_not(input)?;
79
80 match rtrim(ttag("and")).parse(input) {
81 Ok((mut input, _)) => {
82 let mut ops = vec![res];
83 loop {
84 let (i2, elem) = cut(expression_not).parse(input)?;
85 ops.push(elem);
86 match rtrim(ttag("and"))(i2) {
87 Ok((i3, _)) => input = i3,
88 Err(_) => {
89 return Ok((
90 i2,
91 Expression {
92 expr: ExpressionKind::And(ops),
93 span: i2.get_span_from(start),
94 },
95 ))
96 }
97 }
98 }
99 }
100 Err(_) => Ok((input, res)),
101 }
102}
103
104fn expression_not(mut input: Input) -> ParseResult<Expression> {
106 let mut start = input.pos();
107 let mut ops = Vec::new();
108 while let Ok((i, op)) = rtrim(alt((ttag("not"), ttag("defined")))).parse(input) {
110 ops.push((
111 if op == "not" {
112 ExpressionKind::Not
113 } else {
114 ExpressionKind::Defined
115 },
116 start,
117 ));
118 input = i;
119 start = i.pos();
120 }
121
122 let (input, mut expr) = expression_item(input)?;
123 while let Some((op, start)) = ops.pop() {
124 expr = Expression {
125 expr: op(Box::new(expr)),
126 span: input.get_span_from(start),
127 };
128 }
129
130 Ok((input, expr))
131}
132
133fn expression_item(input: Input) -> ParseResult<Expression> {
135 match alt((
136 for_expression_non_ambiguous,
138 variable_expression,
140 ))
141 .parse(input)
142 {
143 Ok((input, expr)) => return Ok((input, expr)),
144 Err(nom::Err::Failure(e)) => return Err(nom::Err::Failure(e)),
145 Err(_) => (),
146 }
147
148 let start = input.pos();
150 let (input, expr) = primary_expression_eq_all(input)?;
151
152 for_expression_with_expr_selection(expr, start, input)
156}
157
158enum EqExprBuilder {
159 Regex(fn(Expression, Regex) -> ExpressionKind),
160 Expr(fn(Expression, Expression) -> ExpressionKind),
161}
162
163fn primary_expression_eq_all(input: Input) -> ParseResult<Expression> {
166 let start = input.pos();
167 let (mut input, mut res) = primary_expression_cmp(input)?;
168
169 while let Ok((i, op)) = rtrim(alt((
170 map(tag("=="), |_| {
171 EqExprBuilder::Expr(|a, b| ExpressionKind::Eq(Box::new(a), Box::new(b)))
172 }),
173 map(tag("!="), |_| {
174 EqExprBuilder::Expr(|a, b| ExpressionKind::NotEq(Box::new(a), Box::new(b)))
175 }),
176 map(ttag("contains"), |_| {
177 EqExprBuilder::Expr(|a, b| ExpressionKind::Contains {
178 haystack: Box::new(a),
179 needle: Box::new(b),
180 case_insensitive: false,
181 })
182 }),
183 map(ttag("icontains"), |_| {
184 EqExprBuilder::Expr(|a, b| ExpressionKind::Contains {
185 haystack: Box::new(a),
186 needle: Box::new(b),
187 case_insensitive: true,
188 })
189 }),
190 map(ttag("startswith"), |_| {
191 EqExprBuilder::Expr(|a, b| ExpressionKind::StartsWith {
192 expr: Box::new(a),
193 prefix: Box::new(b),
194 case_insensitive: false,
195 })
196 }),
197 map(ttag("istartswith"), |_| {
198 EqExprBuilder::Expr(|a, b| ExpressionKind::StartsWith {
199 expr: Box::new(a),
200 prefix: Box::new(b),
201 case_insensitive: true,
202 })
203 }),
204 map(ttag("endswith"), |_| {
205 EqExprBuilder::Expr(|a, b| ExpressionKind::EndsWith {
206 expr: Box::new(a),
207 suffix: Box::new(b),
208 case_insensitive: false,
209 })
210 }),
211 map(ttag("iendswith"), |_| {
212 EqExprBuilder::Expr(|a, b| ExpressionKind::EndsWith {
213 expr: Box::new(a),
214 suffix: Box::new(b),
215 case_insensitive: true,
216 })
217 }),
218 map(ttag("iequals"), |_| {
219 EqExprBuilder::Expr(|a, b| ExpressionKind::IEquals(Box::new(a), Box::new(b)))
220 }),
221 map(ttag("matches"), |_| {
222 EqExprBuilder::Regex(|a, b| ExpressionKind::Matches(Box::new(a), b))
223 }),
224 )))
225 .parse(input)
226 {
227 match op {
228 EqExprBuilder::Expr(builder) => {
229 let (i2, new_expr) = cut(primary_expression_cmp).parse(i)?;
230 input = i2;
231 res = Expression {
232 expr: builder(res, new_expr),
233 span: input.get_span_from(start),
234 }
235 }
236 EqExprBuilder::Regex(builder) => {
237 let (i2, regex) = cut(regex).parse(i)?;
238 input = i2;
239 res = Expression {
240 expr: builder(res, regex),
241 span: input.get_span_from(start),
242 }
243 }
244 }
245 }
246 Ok((input, res))
247}
248
249fn primary_expression_cmp(input: Input) -> ParseResult<Expression> {
251 let start = input.pos();
252 let (mut input, mut res) = primary_expression(input)?;
253
254 while let Ok((i, op)) = rtrim(alt((tag("<="), tag(">="), tag("<"), tag(">")))).parse(input) {
255 let (i2, right_elem) = cut(primary_expression).parse(i)?;
256 input = i2;
257 let op = op.cursor();
258 let less_than = op.bytes().next() == Some(b'<');
259 let can_be_equal = op.len() == 2;
260 res = Expression {
261 expr: ExpressionKind::Cmp {
262 left: Box::new(res),
263 right: Box::new(right_elem),
264 less_than,
265 can_be_equal,
266 },
267 span: input.get_span_from(start),
268 };
269 }
270 Ok((input, res))
271}
272
273fn variable_expression(input: Input) -> ParseResult<Expression> {
275 let start = input.pos();
276 let (input, variable_name) = string_identifier(input)?;
277
278 if let Ok((input2, expr)) = preceded(rtrim(ttag("at")), primary_expression).parse(input) {
280 Ok((
281 input2,
282 Expression {
283 expr: ExpressionKind::VariableAt {
284 variable_name,
285 variable_name_span: input.get_span_from(start),
286 offset: Box::new(expr),
287 },
288 span: input2.get_span_from(start),
289 },
290 ))
291 } else if let Ok((input2, (from, to))) = preceded(rtrim(tag("in")), range).parse(input) {
293 Ok((
294 input2,
295 Expression {
296 expr: ExpressionKind::VariableIn {
297 variable_name,
298 variable_name_span: input.get_span_from(start),
299 from,
300 to,
301 },
302 span: input2.get_span_from(start),
303 },
304 ))
305 } else {
307 Ok((
308 input,
309 Expression {
310 expr: ExpressionKind::Variable(variable_name),
311 span: input.get_span_from(start),
312 },
313 ))
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320 use crate::{
321 expression::{Identifier, MAX_EXPR_RECURSION},
322 regex::{self, Literal},
323 test_helpers::{parse, parse_check, parse_err, parse_err_type, test_public_type},
324 };
325 use std::ops::Range;
326
327 #[track_caller]
328 fn test_precedence<F, F2>(
329 higher_op: &str,
330 lower_op: &str,
331 higher_constructor: F,
332 lower_constructor: F2,
333 ) where
334 F: FnOnce(Box<Expression>, Box<Expression>) -> ExpressionKind,
335 F2: FnOnce(Box<Expression>, Box<Expression>) -> ExpressionKind,
336 {
337 let input = format!("0 {lower_op} 1 {higher_op} 2");
338
339 parse(
340 boolean_expression,
341 &input,
342 "",
343 Expression {
344 expr: lower_constructor(
345 Box::new(Expression {
346 expr: ExpressionKind::Integer(0),
347 span: 0..1,
348 }),
349 Box::new(Expression {
350 expr: higher_constructor(
351 Box::new(Expression {
352 expr: ExpressionKind::Integer(1),
353 span: Range {
354 start: 3 + lower_op.len(),
355 end: 4 + lower_op.len(),
356 },
357 }),
358 Box::new(Expression {
359 expr: ExpressionKind::Integer(2),
360 span: Range {
361 start: 6 + lower_op.len() + higher_op.len(),
362 end: 7 + lower_op.len() + higher_op.len(),
363 },
364 }),
365 ),
366 span: Range {
367 start: 3 + lower_op.len(),
368 end: 7 + lower_op.len() + higher_op.len(),
369 },
370 }),
371 ),
372 span: Range {
373 start: 0,
374 end: 7 + lower_op.len() + higher_op.len(),
375 },
376 },
377 );
378 }
379
380 #[test]
381 fn test_variable_expression() {
382 parse(
383 variable_expression,
384 "$a at 100 b",
385 "b",
386 Expression {
387 expr: ExpressionKind::VariableAt {
388 variable_name: "a".to_owned(),
389 variable_name_span: 0..2,
390 offset: Box::new(Expression {
391 expr: ExpressionKind::Integer(100),
392 span: 6..9,
393 }),
394 },
395 span: 0..9,
396 },
397 );
398 parse(
399 variable_expression,
400 "$_ in (0.. 50) b",
401 "b",
402 Expression {
403 expr: ExpressionKind::VariableIn {
404 variable_name: "_".to_owned(),
405 variable_name_span: 0..2,
406 from: Box::new(Expression {
407 expr: ExpressionKind::Integer(0),
408 span: 7..8,
409 }),
410 to: Box::new(Expression {
411 expr: ExpressionKind::Integer(50),
412 span: 11..13,
413 }),
414 },
415 span: 0..14,
416 },
417 );
418 parse(
419 variable_expression,
420 "$ in (-10..-5)",
421 "",
422 Expression {
423 expr: ExpressionKind::VariableIn {
424 variable_name: String::new(),
425 variable_name_span: 0..1,
426 from: Box::new(Expression {
427 expr: ExpressionKind::Neg(Box::new(Expression {
428 expr: ExpressionKind::Integer(10),
429 span: 7..9,
430 })),
431 span: 6..9,
432 }),
433 to: Box::new(Expression {
434 expr: ExpressionKind::Neg(Box::new(Expression {
435 expr: ExpressionKind::Integer(5),
436 span: 12..13,
437 })),
438 span: 11..13,
439 }),
440 },
441 span: 0..14,
442 },
443 );
444 parse(
445 variable_expression,
446 "$c in (-10..-5",
447 "in (-10..-5",
448 Expression {
449 expr: ExpressionKind::Variable("c".to_owned()),
450 span: 0..2,
451 },
452 );
453
454 parse_err(variable_expression, "");
455 parse_err(variable_expression, "b");
456 parse_err(variable_expression, "50");
457 }
458
459 #[test]
461 fn test_bool_operators() {
462 parse(
463 boolean_expression,
464 "true and false b",
465 "b",
466 Expression {
467 expr: ExpressionKind::And(vec![
468 Expression {
469 expr: ExpressionKind::Boolean(true),
470 span: 0..4,
471 },
472 Expression {
473 expr: ExpressionKind::Boolean(false),
474 span: 9..14,
475 },
476 ]),
477 span: 0..14,
478 },
479 );
480 parse(
481 boolean_expression,
482 "not true or defined $b",
483 "",
484 Expression {
485 expr: ExpressionKind::Or(vec![
486 Expression {
487 expr: ExpressionKind::Not(Box::new(Expression {
488 expr: ExpressionKind::Boolean(true),
489 span: 4..8,
490 })),
491 span: 0..8,
492 },
493 Expression {
494 expr: ExpressionKind::Defined(Box::new(Expression {
495 expr: ExpressionKind::Variable("b".to_owned()),
496 span: 20..22,
497 })),
498 span: 12..22,
499 },
500 ]),
501 span: 0..22,
502 },
503 );
504 parse(
505 boolean_expression,
506 "not not true",
507 "",
508 Expression {
509 expr: ExpressionKind::Not(Box::new(Expression {
510 expr: ExpressionKind::Not(Box::new(Expression {
511 expr: ExpressionKind::Boolean(true),
512 span: 8..12,
513 })),
514 span: 4..12,
515 })),
516 span: 0..12,
517 },
518 );
519 parse(
520 boolean_expression,
521 "false or false or true",
522 "",
523 Expression {
524 expr: ExpressionKind::Or(vec![
525 Expression {
526 expr: ExpressionKind::Boolean(false),
527 span: 0..5,
528 },
529 Expression {
530 expr: ExpressionKind::Boolean(false),
531 span: 9..14,
532 },
533 Expression {
534 expr: ExpressionKind::Boolean(true),
535 span: 18..22,
536 },
537 ]),
538 span: 0..22,
539 },
540 );
541 parse(
542 boolean_expression,
543 "false and false and true",
544 "",
545 Expression {
546 expr: ExpressionKind::And(vec![
547 Expression {
548 expr: ExpressionKind::Boolean(false),
549 span: 0..5,
550 },
551 Expression {
552 expr: ExpressionKind::Boolean(false),
553 span: 10..15,
554 },
555 Expression {
556 expr: ExpressionKind::Boolean(true),
557 span: 20..24,
558 },
559 ]),
560 span: 0..24,
561 },
562 );
563
564 parse_err(boolean_expression, "false and /a");
565 parse_err(boolean_expression, "false or /a");
566 }
567
568 #[test]
569 fn test_rest_operators() {
570 #[track_caller]
571 fn test_op<F>(op: &str, constructor: F)
572 where
573 F: FnOnce(Box<Expression>, Box<Expression>) -> ExpressionKind,
574 {
575 let input = format!("\"a\" {op} \"b\" b");
576
577 parse(
578 boolean_expression,
579 &input,
580 "b",
581 Expression {
582 expr: constructor(
583 Box::new(Expression {
584 expr: ExpressionKind::Bytes(b"a".to_vec()),
585 span: 0..3,
586 }),
587 Box::new(Expression {
588 expr: ExpressionKind::Bytes(b"b".to_vec()),
589 span: Range {
590 start: 5 + op.len(),
591 end: 8 + op.len(),
592 },
593 }),
594 ),
595 span: Range {
596 start: 0,
597 end: 8 + op.len(),
598 },
599 },
600 );
601 }
602
603 test_op("==", ExpressionKind::Eq);
604 test_op("!=", ExpressionKind::NotEq);
605 test_op("contains", |a, b| ExpressionKind::Contains {
606 haystack: a,
607 needle: b,
608 case_insensitive: false,
609 });
610 test_op("icontains", |a, b| ExpressionKind::Contains {
611 haystack: a,
612 needle: b,
613 case_insensitive: true,
614 });
615 test_op("startswith", |a, b| ExpressionKind::StartsWith {
616 expr: a,
617 prefix: b,
618 case_insensitive: false,
619 });
620 test_op("istartswith", |a, b| ExpressionKind::StartsWith {
621 expr: a,
622 prefix: b,
623 case_insensitive: true,
624 });
625 test_op("endswith", |a, b| ExpressionKind::EndsWith {
626 expr: a,
627 suffix: b,
628 case_insensitive: false,
629 });
630 test_op("iendswith", |a, b| ExpressionKind::EndsWith {
631 expr: a,
632 suffix: b,
633 case_insensitive: true,
634 });
635 test_op("iequals", ExpressionKind::IEquals);
636
637 test_op("<", |a, b| ExpressionKind::Cmp {
638 left: a,
639 right: b,
640 less_than: true,
641 can_be_equal: false,
642 });
643 test_op("<=", |a, b| ExpressionKind::Cmp {
644 left: a,
645 right: b,
646 less_than: true,
647 can_be_equal: true,
648 });
649 test_op(">", |a, b| ExpressionKind::Cmp {
650 left: a,
651 right: b,
652 less_than: false,
653 can_be_equal: false,
654 });
655 test_op(">=", |a, b| ExpressionKind::Cmp {
656 left: a,
657 right: b,
658 less_than: false,
659 can_be_equal: true,
660 });
661 }
662
663 #[test]
664 fn test_matches() {
665 parse(
666 boolean_expression,
667 "\"a\" matches /b/i b",
668 "b",
669 Expression {
670 expr: ExpressionKind::Matches(
671 Box::new(Expression {
672 expr: ExpressionKind::Bytes(b"a".to_vec()),
673 span: 0..3,
674 }),
675 Regex {
676 ast: regex::Node::Literal(Literal {
677 byte: b'b',
678 span: 13..14,
679 escaped: false,
680 }),
681 case_insensitive: true,
682 dot_all: false,
683 span: 12..16,
684 },
685 ),
686 span: 0..16,
687 },
688 );
689
690 parse_err(boolean_expression, "\"a\" matches");
691 parse_err(boolean_expression, "\"a\" matches 1");
692 }
693
694 #[test]
695 fn test_expression_precedence_cmp_eq() {
696 let build_cmp = |less_than, can_be_equal| {
697 move |a, b| ExpressionKind::Cmp {
698 left: a,
699 right: b,
700 less_than,
701 can_be_equal,
702 }
703 };
704
705 test_precedence("<", "==", build_cmp(true, false), ExpressionKind::Eq);
707 test_precedence("<=", "==", build_cmp(true, true), ExpressionKind::Eq);
708 test_precedence(">", "==", build_cmp(false, false), ExpressionKind::Eq);
709 test_precedence(">=", "==", build_cmp(false, true), ExpressionKind::Eq);
710 test_precedence("<", "!=", build_cmp(true, false), ExpressionKind::NotEq);
711 test_precedence("<", "contains", build_cmp(true, false), |a, b| {
712 ExpressionKind::Contains {
713 haystack: a,
714 needle: b,
715 case_insensitive: false,
716 }
717 });
718 test_precedence("<", "icontains", build_cmp(true, false), |a, b| {
719 ExpressionKind::Contains {
720 haystack: a,
721 needle: b,
722 case_insensitive: true,
723 }
724 });
725 test_precedence("<", "startswith", build_cmp(true, false), |a, b| {
726 ExpressionKind::StartsWith {
727 expr: a,
728 prefix: b,
729 case_insensitive: false,
730 }
731 });
732 test_precedence("<", "istartswith", build_cmp(true, false), |a, b| {
733 ExpressionKind::StartsWith {
734 expr: a,
735 prefix: b,
736 case_insensitive: true,
737 }
738 });
739 test_precedence("<", "endswith", build_cmp(true, false), |a, b| {
740 ExpressionKind::EndsWith {
741 expr: a,
742 suffix: b,
743 case_insensitive: false,
744 }
745 });
746 test_precedence("<", "iendswith", build_cmp(true, false), |a, b| {
747 ExpressionKind::EndsWith {
748 expr: a,
749 suffix: b,
750 case_insensitive: true,
751 }
752 });
753 test_precedence(
754 "<",
755 "iequals",
756 build_cmp(true, false),
757 ExpressionKind::IEquals,
758 );
759 }
760
761 #[test]
762 fn test_expression_precedence_eq_and_or() {
763 parse(
765 boolean_expression,
766 "not true or false and true",
767 "",
768 Expression {
769 expr: ExpressionKind::Or(vec![
770 Expression {
771 expr: ExpressionKind::Not(Box::new(Expression {
772 expr: ExpressionKind::Boolean(true),
773 span: 4..8,
774 })),
775 span: 0..8,
776 },
777 Expression {
778 expr: ExpressionKind::And(vec![
779 Expression {
780 expr: ExpressionKind::Boolean(false),
781 span: 12..17,
782 },
783 Expression {
784 expr: ExpressionKind::Boolean(true),
785 span: 22..26,
786 },
787 ]),
788 span: 12..26,
789 },
790 ]),
791 span: 0..26,
792 },
793 );
794
795 test_precedence("==", "and", ExpressionKind::Eq, |a, b| {
797 ExpressionKind::And(vec![*a, *b])
798 });
799 test_precedence("!=", "and", ExpressionKind::NotEq, |a, b| {
800 ExpressionKind::And(vec![*a, *b])
801 });
802 }
803
804 #[test]
805 fn test_expression() {
806 parse(
807 boolean_expression,
808 "true b",
809 "b",
810 Expression {
811 expr: ExpressionKind::Boolean(true),
812 span: 0..4,
813 },
814 );
815 parse(
816 boolean_expression,
817 "((false))",
818 "",
819 Expression {
820 expr: ExpressionKind::Boolean(false),
821 span: 2..7,
822 },
823 );
824 parse(
825 boolean_expression,
826 "not true b",
827 "b",
828 Expression {
829 expr: ExpressionKind::Not(Box::new(Expression {
830 expr: ExpressionKind::Boolean(true),
831 span: 4..8,
832 })),
833 span: 0..8,
834 },
835 );
836 parse(
837 boolean_expression,
838 "not defined $a c",
839 "c",
840 Expression {
841 expr: ExpressionKind::Not(Box::new(Expression {
842 expr: ExpressionKind::Defined(Box::new(Expression {
843 expr: ExpressionKind::Variable("a".to_owned()),
844 span: 12..14,
845 })),
846 span: 4..14,
847 })),
848 span: 0..14,
849 },
850 );
851 parse(
852 boolean_expression,
853 "defined not $a c",
854 "c",
855 Expression {
856 expr: ExpressionKind::Defined(Box::new(Expression {
857 expr: ExpressionKind::Not(Box::new(Expression {
858 expr: ExpressionKind::Variable("a".to_owned()),
859 span: 12..14,
860 })),
861 span: 8..14,
862 })),
863 span: 0..14,
864 },
865 );
866
867 parse(
869 boolean_expression,
870 "5 b",
871 "b",
872 Expression {
873 expr: ExpressionKind::Integer(5),
874 span: 0..1,
875 },
876 );
877
878 parse_err(boolean_expression, " ");
879 parse_err(boolean_expression, "(");
880 parse_err(boolean_expression, "()");
881 parse_err(boolean_expression, "not");
882 parse_err(boolean_expression, "defined");
883 parse_err(boolean_expression, "1 == ");
884 parse_err(boolean_expression, "1 <= ");
885 parse_err(boolean_expression, "1 | ");
886 parse_err(boolean_expression, "1 & ");
887 parse_err(boolean_expression, "1 ^ ");
888 parse_err(boolean_expression, "1 << ");
889 parse_err(boolean_expression, "1 + ");
890 parse_err(boolean_expression, "1 * ");
891 parse_err(boolean_expression, "1 + -");
892 }
893
894 #[test]
895 fn test_textual_tag() {
896 parse_err(boolean_expression, "(1ora)");
899 parse_err(boolean_expression, "(1anda)");
900 parse_check(boolean_expression, "nota", |e| {
901 assert_eq!(
902 e.expr,
903 ExpressionKind::Identifier(Identifier {
904 name: "nota".to_owned(),
905 name_span: 0..4,
906 operations: vec![]
907 }),
908 );
909 });
910 parse_check(boolean_expression, "defineda", |e| {
911 assert_eq!(
912 e.expr,
913 ExpressionKind::Identifier(Identifier {
914 name: "defineda".to_owned(),
915 name_span: 0..8,
916 operations: vec![]
917 }),
918 );
919 });
920 parse_check(boolean_expression, "truea", |e| {
921 assert_eq!(
922 e.expr,
923 ExpressionKind::Identifier(Identifier {
924 name: "truea".to_owned(),
925 name_span: 0..5,
926 operations: vec![]
927 }),
928 );
929 });
930 parse_check(boolean_expression, "falsea", |e| {
931 assert_eq!(
932 e.expr,
933 ExpressionKind::Identifier(Identifier {
934 name: "falsea".to_owned(),
935 name_span: 0..6,
936 operations: vec![]
937 }),
938 );
939 });
940
941 parse_err(boolean_expression, "(a containsb)");
942 parse_err(boolean_expression, "(a icontainsb)");
943 parse_err(boolean_expression, "(a startswitha)");
944 parse_err(boolean_expression, "(a istartswitha)");
945 parse_err(boolean_expression, "(a endswitha)");
946 parse_err(boolean_expression, "(a iendswitha)");
947 parse_err(boolean_expression, "(a iequalsa)");
948
949 parse_err(boolean_expression, "($a atb)");
950
951 parse(
953 boolean_expression,
954 "0==0",
955 "",
956 Expression {
957 expr: ExpressionKind::Eq(
958 Box::new(Expression {
959 expr: ExpressionKind::Integer(0),
960 span: 0..1,
961 }),
962 Box::new(Expression {
963 expr: ExpressionKind::Integer(0),
964 span: 3..4,
965 }),
966 ),
967 span: 0..4,
968 },
969 );
970 parse(
971 boolean_expression,
972 "1!=2",
973 "",
974 Expression {
975 expr: ExpressionKind::NotEq(
976 Box::new(Expression {
977 expr: ExpressionKind::Integer(1),
978 span: 0..1,
979 }),
980 Box::new(Expression {
981 expr: ExpressionKind::Integer(2),
982 span: 3..4,
983 }),
984 ),
985 span: 0..4,
986 },
987 );
988 }
989
990 #[test]
991 fn test_stack_overflow_1() {
992 let mut v = String::new();
995 for _ in 0..100_000 {
996 v.push_str("for any of them : ( ");
997 }
998 v.push_str("true");
999 for _ in 0..100_000 {
1000 v.push_str(" ) ");
1001 }
1002
1003 parse_err_type(
1004 boolean_expression,
1005 &v,
1006 &Error::new(400..400, ErrorKind::ExprTooDeep),
1007 );
1008
1009 let mut v = String::new();
1011 let nb = MAX_EXPR_RECURSION - 2;
1012 for _ in 0..nb {
1013 v.push_str("for any of them : ( ");
1014 }
1015 v.push_str("true");
1016 for _ in 0..nb {
1017 v.push_str(" ) ");
1018 }
1019
1020 v.push_str(" and ");
1021
1022 for _ in 0..nb {
1023 v.push_str("for any of them : ( ");
1024 }
1025 v.push_str("true");
1026 for _ in 0..nb {
1027 v.push_str(" ) ");
1028 }
1029
1030 let input = Input::new(&v);
1031 let _res = boolean_expression(input).unwrap();
1032 assert_eq!(input.expr_recursion_counter, 0);
1033 }
1034
1035 #[test]
1036 fn test_stack_overflow_2() {
1037 let mut v = String::new();
1040 for _ in 0..100_000 {
1041 v.push_str("a.b(");
1042 }
1043 v.push_str("true");
1044 for _ in 0..100_000 {
1045 v.push(')');
1046 }
1047
1048 parse_err_type(
1049 boolean_expression,
1050 &v,
1051 &Error::new(40..40, ErrorKind::ExprTooDeep),
1052 );
1053
1054 let mut v = String::new();
1056 let nb = MAX_EXPR_RECURSION / 2 - 1;
1059 for _ in 0..nb {
1060 v.push_str("a.b(");
1061 }
1062 v.push_str("true");
1063 for _ in 0..nb {
1064 v.push(')');
1065 }
1066
1067 let input = Input::new(&v);
1068 let _res = boolean_expression(input).unwrap();
1069 assert_eq!(input.expr_recursion_counter, 0);
1070 }
1071
1072 #[test]
1073 fn test_public_types() {
1074 test_public_type(boolean_expression(Input::new("a == 2")).unwrap());
1075 }
1076}