1- use std:: ops:: { Range , RangeBounds , RangeInclusive } ;
1+ use std:: ops:: { Add , BitOr , Range , RangeBounds , RangeInclusive } ;
22use std:: rc:: { Rc , Weak } ;
33
44#[ cfg( feature = "regex_grammar" ) ]
@@ -8,46 +8,90 @@ use crate::mutators::grammar::regex::grammar_from_regex;
88/// A grammar which can be used for fuzzing.
99///
1010/// See [the module documentation](crate::mutators::grammar) for advice on how to create a grammar.
11- pub enum Grammar {
11+ pub enum GrammarInner {
1212 Literal ( Vec < RangeInclusive < char > > ) ,
13- Alternation ( Vec < Rc < Grammar > > ) ,
14- Concatenation ( Vec < Rc < Grammar > > ) ,
15- Repetition ( Rc < Grammar > , Range < usize > ) ,
16- Recurse ( Weak < Grammar > ) ,
17- Recursive ( Rc < Grammar > ) ,
13+ Alternation ( Vec < Grammar > ) ,
14+ Concatenation ( Vec < Grammar > ) ,
15+ Repetition ( Grammar , Range < usize > ) ,
16+ Recurse ( Weak < GrammarInner > ) ,
17+ Recursive ( Grammar ) ,
18+ }
19+
20+ #[ derive( Debug , Clone ) ]
21+ /// A [`Grammar`] can be transformed into an [`ASTMutator`] (which generates
22+ /// [`String`]s corresponding to the grammar in question) or combined with other
23+ /// grammars to produce a more complicated grammar.
24+ ///
25+ /// For examples on how to use this struct, see the crate documentation
26+ /// ([`super`]).
27+ ///
28+ /// [`ASTMutator`]: crate::mutators::grammar::ASTMutator
29+ pub struct Grammar ( pub ( crate ) Rc < GrammarInner > ) ;
30+
31+ impl From < Rc < GrammarInner > > for Grammar {
32+ fn from ( inner : Rc < GrammarInner > ) -> Self {
33+ Grammar ( inner)
34+ }
35+ }
36+
37+ impl AsRef < GrammarInner > for Grammar {
38+ fn as_ref ( & self ) -> & GrammarInner {
39+ & self . 0
40+ }
41+ }
42+
43+ impl Add for Grammar {
44+ type Output = Grammar ;
45+
46+ /// Calls [`concatenation`] on the two provided grammars.
47+ fn add ( self , rhs : Self ) -> Self :: Output {
48+ concatenation ( [ self , rhs] )
49+ }
50+ }
51+
52+ impl BitOr for Grammar {
53+ type Output = Grammar ;
54+
55+ /// Calls [`alternation`] on the two provided grammars.
56+ fn bitor ( self , rhs : Self ) -> Self :: Output {
57+ alternation ( [ self , rhs] )
58+ }
1859}
1960
2061#[ cfg( feature = "regex_grammar" ) ]
2162#[ doc( cfg( feature = "regex_grammar" ) ) ]
2263#[ no_coverage]
23- pub fn regex ( s : & str ) -> Rc < Grammar > {
64+ pub fn regex ( s : & str ) -> Grammar {
2465 grammar_from_regex ( s)
2566}
2667
2768#[ no_coverage]
28- /// Creates an [`Rc< Grammar> `] which outputs characters in the given range.
69+ /// Creates a [`Grammar`] which outputs characters in the given range.
2970///
3071/// For example, to generate characters in the range 'a' to 'z' (inclusive), one
3172/// could use this code
3273///
3374/// ```
34- /// let a_to_z = literal_ranges('a'..='z');
75+ /// # use fuzzcheck::mutators::grammar::literal_ranges;
76+ /// let a_to_z = literal_ranges(vec!['a'..='b', 'q'..='s', 't'..='w']);
3577/// ```
36- pub fn literal_ranges ( ranges : Vec < RangeInclusive < char > > ) -> Rc < Grammar > {
37- Rc :: new ( Grammar :: Literal ( ranges) )
78+ pub fn literal_ranges ( ranges : Vec < RangeInclusive < char > > ) -> Grammar {
79+ Rc :: new ( GrammarInner :: Literal ( ranges) ) . into ( )
3880}
3981
4082#[ no_coverage]
41- /// Creates an [`Rc< Grammar> `] which matches a single character literal.
83+ /// Creates a [`Grammar`] which matches a single character literal.
4284///
4385/// ```
86+ /// # use fuzzcheck::mutators::grammar::literal;
4487/// let l = literal('l');
4588/// ```
46- pub fn literal ( l : char ) -> Rc < Grammar > {
47- Rc :: new ( Grammar :: Literal ( vec ! [ l..=l] ) )
89+ pub fn literal ( l : char ) -> Grammar {
90+ Rc :: new ( GrammarInner :: Literal ( vec ! [ l..=l] ) ) . into ( )
4891}
92+
4993#[ no_coverage]
50- pub fn literal_range < R > ( range : R ) -> Rc < Grammar >
94+ pub fn literal_range < R > ( range : R ) -> Grammar
5195where
5296 R : RangeBounds < char > ,
5397{
@@ -61,34 +105,61 @@ where
61105 std:: ops:: Bound :: Excluded ( x) => unsafe { char:: from_u32_unchecked ( * x as u32 - 1 ) } ,
62106 std:: ops:: Bound :: Unbounded => panic ! ( "The range must have an upper bound" ) ,
63107 } ;
64- Rc :: new ( Grammar :: Literal ( vec ! [ start..=end] ) )
108+ Rc :: new ( GrammarInner :: Literal ( vec ! [ start..=end] ) ) . into ( )
65109}
66110
67111/// Produces a grammar which will choose between the provided grammars.
112+ ///
113+ /// For example, this grammar
114+ /// ```
115+ /// # use fuzzcheck::mutators::grammar::{Grammar, alternation, regex};
116+ /// let fuzz_or_check: Grammar = alternation([
117+ /// regex("fuzz"),
118+ /// regex("check")
119+ /// ]);
120+ /// ```
121+ /// would output either "fuzz" or "check".
122+ ///
123+ /// It is also possible to use the `|` operator to write alternation grammars.
124+ /// For example, the [`Grammar`] above could be equivalently written as
125+ ///
126+ /// ```
127+ /// # use fuzzcheck::mutators::grammar::{Grammar, regex};
128+ /// let fuzz_or_check: Grammar = regex("fuzz") | regex("check");
129+ /// ```
68130#[ no_coverage]
69- pub fn alternation ( gs : impl IntoIterator < Item = Rc < Grammar > > ) -> Rc < Grammar > {
70- Rc :: new ( Grammar :: Alternation ( gs. into_iter ( ) . collect ( ) ) )
131+ pub fn alternation ( gs : impl IntoIterator < Item = Grammar > ) -> Grammar {
132+ Rc :: new ( GrammarInner :: Alternation ( gs. into_iter ( ) . collect ( ) ) ) . into ( )
71133}
72134
73135/// Produces a grammar which will concatenate the output of all the provided
74136/// grammars together, in order.
75137///
76138/// For example, the grammar
77139/// ```
78- /// concatenation([
140+ /// # use fuzzcheck::mutators::grammar::{concatenation, Grammar, regex};
141+ /// let fuzzcheck: Grammar = concatenation([
79142/// regex("fuzz"),
80143/// regex("check")
81- /// ])
144+ /// ]);
82145/// ```
83146/// would output "fuzzcheck".
147+ ///
148+ /// It is also possible to use the `+` operator to concatenate separate grammars
149+ /// together. For example, the grammar above could be equivalently written as
150+ ///
151+ /// ```
152+ /// # use fuzzcheck::mutators::grammar::{Grammar, regex};
153+ /// let fuzzcheck: Grammar = regex("fuzz") + regex("check");
154+ /// ```
84155#[ no_coverage]
85- pub fn concatenation ( gs : impl IntoIterator < Item = Rc < Grammar > > ) -> Rc < Grammar > {
86- Rc :: new ( Grammar :: Concatenation ( gs. into_iter ( ) . collect ( ) ) )
156+ pub fn concatenation ( gs : impl IntoIterator < Item = Grammar > ) -> Grammar {
157+ Rc :: new ( GrammarInner :: Concatenation ( gs. into_iter ( ) . collect ( ) ) ) . into ( )
87158}
88159
89160#[ no_coverage]
90- /// Repeats the provided grammar some number of times in the given range.
91- pub fn repetition < R > ( gs : Rc < Grammar > , range : R ) -> Rc < Grammar >
161+ /// Repeats the provided [`Grammar`] some number of times in the given range.
162+ pub fn repetition < R > ( gs : Grammar , range : R ) -> Grammar
92163where
93164 R : RangeBounds < usize > ,
94165{
@@ -102,25 +173,26 @@ where
102173 std:: ops:: Bound :: Excluded ( x) => * x,
103174 std:: ops:: Bound :: Unbounded => usize:: MAX ,
104175 } ;
105- Rc :: new ( Grammar :: Repetition ( gs, start..end) )
176+ Rc :: new ( GrammarInner :: Repetition ( gs, start..end) ) . into ( )
106177}
107178
108179#[ no_coverage]
109180/// Used to indicate a point of recursion to Fuzzcheck. Should be combined with
110181/// [`recursive`].
111182///
112183/// See the module documentation ([`super`]) for an example on how to use it.
113- pub fn recurse ( g : & Weak < Grammar > ) -> Rc < Grammar > {
114- Rc :: new ( Grammar :: Recurse ( g. clone ( ) ) )
184+ pub fn recurse ( g : & Weak < GrammarInner > ) -> Grammar {
185+ Rc :: new ( GrammarInner :: Recurse ( g. clone ( ) ) ) . into ( )
115186}
116187
117188#[ no_coverage]
118- /// Creates a recursive grammar . This function should be combined with
189+ /// Creates a recursive [`Grammar`] . This function should be combined with
119190/// [`recurse`] to make recursive calls.
120191///
121192/// See the module documentation ([`super`]) for an example on how to use it.
122- pub fn recursive ( data_fn : impl Fn ( & Weak < Grammar > ) -> Rc < Grammar > ) -> Rc < Grammar > {
123- Rc :: new ( Grammar :: Recursive ( Rc :: new_cyclic ( |g| {
124- Rc :: try_unwrap ( data_fn ( g) ) . unwrap ( )
125- } ) ) )
193+ pub fn recursive ( data_fn : impl Fn ( & Weak < GrammarInner > ) -> Grammar ) -> Grammar {
194+ Rc :: new ( GrammarInner :: Recursive (
195+ Rc :: new_cyclic ( |g| Rc :: try_unwrap ( data_fn ( g) . 0 ) . unwrap ( ) ) . into ( ) ,
196+ ) )
197+ . into ( )
126198}
0 commit comments