shadowplay/puppet_parser/
regex.rs

1use crate::puppet_parser::{range::Range, IResult, Span};
2use nom::branch::alt;
3use nom::bytes::complete::{is_not, tag};
4use nom::character::complete::anychar;
5use nom::combinator::{map, recognize, verify};
6use nom::multi::fold_many0;
7use nom::sequence::{pair, tuple};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10enum StringFragment<'a> {
11    Literal(Span<'a>),
12    EscapedChar(Span<'a>),
13}
14
15fn parse_literal(input: Span) -> IResult<Span> {
16    let not_quote_slash = is_not("/\\");
17    verify(not_quote_slash, |s: &Span| !s.is_empty())(input)
18}
19
20fn parse_escaped_char(input: Span) -> IResult<Span> {
21    recognize(pair(tag("\\"), anychar))(input)
22}
23
24fn parse_fragment(input: Span) -> IResult<StringFragment> {
25    alt((
26        map(parse_literal, StringFragment::Literal),
27        map(parse_escaped_char, StringFragment::EscapedChar),
28    ))(input)
29}
30
31pub fn parse(input: Span) -> IResult<crate::puppet_lang::expression::Regexp<Range>> {
32    let build_regex = fold_many0(parse_fragment, String::new, |mut string, fragment| {
33        match fragment {
34            StringFragment::Literal(s) => string.push_str(&s),
35            StringFragment::EscapedChar(s) => string.push_str(&s),
36        }
37        string
38    });
39
40    map(
41        tuple((tag("/"), build_regex, tag("/"))),
42        |(left_tag, data, right_tag)| crate::puppet_lang::expression::Regexp {
43            data,
44            extra: Range::from((left_tag, right_tag)),
45        },
46    )(input)
47}
48
49#[test]
50fn test() {
51    assert_eq!(
52        parse(Span::new("//")).unwrap().1,
53        crate::puppet_lang::expression::Regexp {
54            data: "".to_owned(),
55            extra: Range::new(0, 1, 1, 1, 1, 2)
56        }
57    );
58    assert_eq!(
59        parse(Span::new("/aaa/")).unwrap().1,
60        crate::puppet_lang::expression::Regexp {
61            data: "aaa".to_owned(),
62            extra: Range::new(0, 1, 1, 4, 1, 5)
63        }
64    );
65    assert_eq!(
66        parse(Span::new("/\\//")).unwrap().1,
67        crate::puppet_lang::expression::Regexp {
68            data: "\\/".to_owned(),
69            extra: Range::new(0, 1, 1, 3, 1, 4)
70        }
71    );
72    assert_eq!(
73        parse(Span::new("/\\d/")).unwrap().1,
74        crate::puppet_lang::expression::Regexp {
75            data: "\\d".to_owned(),
76            extra: Range::new(0, 1, 1, 3, 1, 4)
77        }
78    );
79}