cfg_sequence/
lib.rs

1//! Sequences are similar to regex repetitions with numbering.
2
3#![deny(unsafe_code)]
4#![deny(missing_docs)]
5
6pub mod builder;
7pub mod destination;
8mod ext;
9pub mod rewrite;
10
11pub use crate::ext::CfgSequenceExt;
12
13use std::ops::{Bound, RangeBounds};
14
15use cfg_history::earley::History;
16use cfg_symbol::Symbol;
17
18use self::Separator::*;
19
20/// Sequence rule representation.
21#[derive(Clone, Copy, Debug, Eq, PartialEq)]
22pub struct Sequence {
23    /// The rule's left-hand side.
24    pub lhs: Symbol,
25    /// The rule's right-hand side.
26    pub rhs: Symbol,
27    /// The minimum number of repetitions.
28    pub start: u32,
29    /// Either the inclusive maximum number of repetitions, or `None` if the number of repetitions
30    /// is unlimited.
31    pub end: Option<u32>,
32    /// The way elements are separated in a sequence, or `Null`.
33    pub separator: Separator,
34    /// The history carried with the sequence rule.
35    pub history: Option<History>,
36}
37
38/// The separator symbol and mode of separation in a sequence, or `Null` for no separation.
39#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
40pub enum Separator {
41    /// Separation with the trailing separator included. In other words, all elements are followed
42    /// by the separator.
43    Trailing(Symbol),
44    /// The separator occurs between elements.
45    Proper(Symbol),
46    /// The union of `Trailing` and `Proper`. In other words, the trailing separator may or may not
47    /// be present.
48    Liberal(Symbol),
49    /// No separation.
50    Null,
51}
52
53impl Sequence {
54    /// Assigns the inclusive range of the number of repetitions.
55    pub fn inclusive(mut self, start: u32, end: Option<u32>) -> Self {
56        self.start = start;
57        self.end = end;
58        self
59    }
60
61    /// Assigns the separator symbol and mode of separation.
62    pub fn separator(mut self, sep: Separator) -> Self {
63        self.separator = sep;
64        self
65    }
66
67    /// Adds a range to the sequence.
68    pub fn range(self, range: impl RangeBounds<u32>) -> Self {
69        let to_option = |bound: Bound<u32>, diff| match bound {
70            Bound::Included(included) => Some(included),
71            Bound::Excluded(excluded) => Some((excluded as i64 + diff) as u32),
72            Bound::Unbounded => None,
73        };
74        self.inclusive(
75            to_option(range.start_bound().cloned(), 1).unwrap_or(0),
76            to_option(range.end_bound().cloned(), -1),
77        )
78    }
79}
80
81impl Separator {
82    /// Returns the kind of separation for a prefix sequence.
83    pub fn prefix_separator(self) -> Self {
84        match self {
85            Proper(sep) | Liberal(sep) => Trailing(sep),
86            other => other,
87        }
88    }
89}
90
91impl From<Separator> for Option<Symbol> {
92    fn from(val: Separator) -> Option<Symbol> {
93        match val {
94            Trailing(sep) => Some(sep),
95            _ => None,
96        }
97    }
98}