cfg_sequence/
lib.rs

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