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_grammar::history::HistoryId;
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<HistoryId>,
16    default_history: Option<HistoryId>,
17    destination: D,
18}
19
20impl<D> SequenceRuleBuilder<D>
21where
22    D: SequenceDestination,
23{
24    /// Creates a sequence rule builder.
25    pub fn new(destination: D) -> Self {
26        SequenceRuleBuilder {
27            lhs: None,
28            range: None,
29            history: None,
30            default_history: None,
31            separator: Separator::Null,
32            destination,
33        }
34    }
35
36    /// Sets the default history source.
37    pub fn default_history(self, default_history: HistoryId) -> Self {
38        SequenceRuleBuilder {
39            lhs: self.lhs,
40            range: self.range,
41            history: self.history,
42            default_history: Some(default_history),
43            separator: self.separator,
44            destination: self.destination,
45        }
46    }
47
48    /// Starts building a sequence rule.
49    pub fn sequence(mut self, lhs: Symbol) -> Self {
50        self.lhs = Some(lhs);
51        self.separator = Separator::Null;
52        self
53    }
54
55    /// Assigns the separator symbol and mode of separation.
56    pub fn separator(mut self, sep: Separator) -> Self {
57        self.separator = sep;
58        self
59    }
60
61    /// Sets proper separation with the given separator symbol.
62    pub fn intersperse(self, sym: Symbol) -> Self {
63        self.separator(Separator::Proper(sym))
64    }
65
66    /// Assigns the rule history, which is used on the next call to `rhs`, or overwritten by a call
67    /// to `rhs_with_history`.
68    pub fn history(mut self, history: HistoryId) -> Self {
69        self.history = Some(history);
70        self
71    }
72
73    /// Assigns the inclusive range of the number of repetitions.
74    pub fn inclusive(mut self, start: u32, end: Option<u32>) -> Self {
75        self.range = Some((start, end));
76        self
77    }
78
79    /// Adds a sequence rule to the grammar.
80    pub fn rhs(mut self, rhs: Symbol) -> Self {
81        let history = self.history.take().or(self.default_history);
82        self.rhs_with_history(rhs, history)
83    }
84
85    /// Adds a range to the sequence.
86    pub fn range(self, range: impl RangeBounds<u32>) -> Self {
87        let to_option = |bound: Bound<u32>, diff| match bound {
88            Bound::Included(included) => Some(included),
89            Bound::Excluded(excluded) => Some((excluded as i64 + diff) as u32),
90            Bound::Unbounded => None,
91        };
92        self.inclusive(
93            to_option(range.start_bound().cloned(), 1).unwrap_or(0),
94            to_option(range.end_bound().cloned(), -1),
95        )
96    }
97
98    /// Adds a sequence rule to the grammar.
99    pub fn rhs_with_range(self, rhs: Symbol, range: impl RangeBounds<u32>) -> Self {
100        self.range(range).rhs(rhs)
101    }
102
103    /// Adds a sequence rule to the grammar.
104    pub fn rhs_with_history(mut self, rhs: Symbol, history_id: Option<HistoryId>) -> Self {
105        let (start, end) = self.range.take().expect("expected inclusive(n, m)");
106        self.destination.add_sequence(Sequence {
107            lhs: self.lhs.unwrap(),
108            rhs,
109            start,
110            end,
111            separator: self.separator,
112            history_id,
113        });
114        self
115    }
116}