cfg_sequence/
builder.rs

1//! Sequence rules can be built with the builder pattern.
2
3use std::ops::{Bound, RangeBounds};
4
5use crate::destination::SequenceDestination;
6use crate::{Separator, Sequence};
7use cfg_history::earley::History;
8use cfg_symbol::Symbol;
9
10/// Sequence rule builder.
11pub struct SequenceRuleBuilder<D: SequenceDestination> {
12    lhs: Option<Symbol>,
13    range: Option<(u32, Option<u32>)>,
14    separator: Separator,
15    history: Option<History>,
16    destination: D,
17}
18
19impl<D> SequenceRuleBuilder<D>
20where
21    D: SequenceDestination,
22{
23    /// Creates a sequence rule builder.
24    pub fn new(destination: D) -> Self {
25        SequenceRuleBuilder {
26            lhs: None,
27            range: None,
28            history: None,
29            separator: Separator::Null,
30            destination,
31        }
32    }
33
34    /// Starts building a sequence rule.
35    pub fn sequence(mut self, lhs: Symbol) -> Self {
36        self.lhs = Some(lhs);
37        self.separator = Separator::Null;
38        self
39    }
40
41    /// Assigns the separator symbol and mode of separation.
42    pub fn separator(mut self, sep: Separator) -> Self {
43        self.separator = sep;
44        self
45    }
46
47    /// Sets proper separation with the given separator symbol.
48    pub fn intersperse(self, sym: Symbol) -> Self {
49        self.separator(Separator::Proper(sym))
50    }
51
52    /// Assigns the rule history, which is used on the next call to `rhs`, or overwritten by a call
53    /// to `rhs_with_history`.
54    pub fn history(mut self, history: History) -> Self {
55        self.history = Some(history);
56        self
57    }
58
59    /// Assigns the inclusive range of the number of repetitions.
60    pub fn inclusive(mut self, start: u32, end: Option<u32>) -> Self {
61        self.range = Some((start, end));
62        self
63    }
64
65    /// Adds a sequence rule to the grammar.
66    pub fn rhs(mut self, rhs: Symbol) -> Self {
67        let history = self.history.take();
68        self.rhs_with_history(rhs, history)
69    }
70
71    /// Adds a range to the sequence.
72    pub fn range(self, range: impl RangeBounds<u32>) -> Self {
73        let to_option = |bound: Bound<u32>, diff| match bound {
74            Bound::Included(included) => Some(included),
75            Bound::Excluded(excluded) => Some((excluded as i64 + diff) as u32),
76            Bound::Unbounded => None,
77        };
78        self.inclusive(
79            to_option(range.start_bound().cloned(), 1).unwrap_or(0),
80            to_option(range.end_bound().cloned(), -1),
81        )
82    }
83
84    /// Adds a sequence rule to the grammar.
85    pub fn rhs_with_range(self, rhs: Symbol, range: impl RangeBounds<u32>) -> Self {
86        self.range(range).rhs(rhs)
87    }
88
89    /// Adds a sequence rule to the grammar.
90    pub fn rhs_with_history(mut self, rhs: Symbol, history: Option<History>) -> Self {
91        let (start, end) = self.range.take().expect("expected inclusive(n, m)");
92        self.destination.add_sequence(Sequence {
93            lhs: self.lhs.unwrap(),
94            rhs,
95            start,
96            end,
97            separator: self.separator,
98            history,
99        });
100        self
101    }
102}