pomsky_syntax/exprs/
repetition.rs

1use crate::{Span, error::RepetitionError};
2
3use super::Rule;
4
5#[derive(Debug, Clone)]
6#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
7pub struct Repetition {
8    pub rule: Rule,
9    pub kind: RepetitionKind,
10    pub quantifier: Quantifier,
11    pub span: Span,
12}
13
14impl Repetition {
15    pub(crate) fn new(
16        rule: Rule,
17        kind: RepetitionKind,
18        quantifier: Quantifier,
19        span: Span,
20    ) -> Self {
21        Repetition { rule, kind, quantifier, span }
22    }
23
24    #[cfg(feature = "dbg")]
25    pub(super) fn pretty_print(&self, buf: &mut crate::PrettyPrinter) {
26        self.rule.pretty_print(buf, true);
27        match self.kind {
28            RepetitionKind { lower_bound, upper_bound: None } => {
29                buf.push('{');
30                buf.write_fmt(lower_bound);
31                buf.push(',');
32                buf.push('}');
33            }
34            RepetitionKind { lower_bound, upper_bound: Some(upper_bound) }
35                if lower_bound == upper_bound =>
36            {
37                buf.push('{');
38                buf.write_fmt(lower_bound);
39                buf.push('}');
40            }
41            RepetitionKind { lower_bound, upper_bound: Some(upper_bound) } => {
42                buf.push('{');
43                buf.write_fmt(lower_bound);
44                buf.push(',');
45                buf.write_fmt(upper_bound);
46                buf.push('}');
47            }
48        }
49        match self.quantifier {
50            Quantifier::Greedy => buf.push_str(" greedy"),
51            Quantifier::Lazy => buf.push_str(" lazy"),
52            _ => {}
53        }
54    }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, Copy)]
58#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
59pub enum Quantifier {
60    Greedy,
61    Lazy,
62    DefaultGreedy,
63    DefaultLazy,
64}
65
66/// A repetition in its most canonical form, `{x,y}`.
67///
68/// For example:
69///
70///  * `'x'?` is equivalent to `'x'{0,1}`
71///  * `'x'+` is equivalent to `'x'{1,}`
72///  * `'x'*` is equivalent to `'x'{0,}`
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
74pub struct RepetitionKind {
75    /// The lower bound, e.g. `{4,}`
76    pub lower_bound: u32,
77
78    /// The upper bound, e.g. `{0,7}`. `None` means infinity.
79    pub upper_bound: Option<u32>,
80}
81
82#[cfg(feature = "arbitrary")]
83impl arbitrary::Arbitrary<'_> for RepetitionKind {
84    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
85        let lower = u.int_in_range(0u8..=40)?;
86        if u.arbitrary()? {
87            let upper = u.int_in_range(lower..=lower + 40)?;
88            Ok(RepetitionKind { lower_bound: lower as u32, upper_bound: Some(upper as u32) })
89        } else {
90            Ok(RepetitionKind { lower_bound: lower as u32, upper_bound: None })
91        }
92    }
93}
94
95impl RepetitionKind {
96    pub(crate) fn zero_inf() -> Self {
97        RepetitionKind { lower_bound: 0, upper_bound: None }
98    }
99
100    pub(crate) fn one_inf() -> Self {
101        RepetitionKind { lower_bound: 1, upper_bound: None }
102    }
103
104    pub(crate) fn zero_one() -> Self {
105        RepetitionKind { lower_bound: 0, upper_bound: Some(1) }
106    }
107
108    pub(crate) fn fixed(n: u32) -> Self {
109        RepetitionKind { lower_bound: n, upper_bound: Some(n) }
110    }
111}
112
113impl TryFrom<(u32, Option<u32>)> for RepetitionKind {
114    type Error = RepetitionError;
115
116    fn try_from((lower_bound, upper_bound): (u32, Option<u32>)) -> Result<Self, Self::Error> {
117        if lower_bound > upper_bound.unwrap_or(u32::MAX) {
118            return Err(RepetitionError::NotAscending);
119        }
120
121        Ok(RepetitionKind { lower_bound, upper_bound })
122    }
123}