1
- use std:: ops:: { Range , RangeBounds , RangeInclusive } ;
1
+ use std:: ops:: { Add , BitOr , Range , RangeBounds , RangeInclusive } ;
2
2
use std:: rc:: { Rc , Weak } ;
3
3
4
4
#[ cfg( feature = "regex_grammar" ) ]
@@ -8,46 +8,90 @@ use crate::mutators::grammar::regex::grammar_from_regex;
8
8
/// A grammar which can be used for fuzzing.
9
9
///
10
10
/// See [the module documentation](crate::mutators::grammar) for advice on how to create a grammar.
11
- pub enum Grammar {
11
+ pub enum GrammarInner {
12
12
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
+ }
18
59
}
19
60
20
61
#[ cfg( feature = "regex_grammar" ) ]
21
62
#[ doc( cfg( feature = "regex_grammar" ) ) ]
22
63
#[ no_coverage]
23
- pub fn regex ( s : & str ) -> Rc < Grammar > {
64
+ pub fn regex ( s : & str ) -> Grammar {
24
65
grammar_from_regex ( s)
25
66
}
26
67
27
68
#[ 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.
29
70
///
30
71
/// For example, to generate characters in the range 'a' to 'z' (inclusive), one
31
72
/// could use this code
32
73
///
33
74
/// ```
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']);
35
77
/// ```
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 ( )
38
80
}
39
81
40
82
#[ no_coverage]
41
- /// Creates an [`Rc< Grammar> `] which matches a single character literal.
83
+ /// Creates a [`Grammar`] which matches a single character literal.
42
84
///
43
85
/// ```
86
+ /// # use fuzzcheck::mutators::grammar::literal;
44
87
/// let l = literal('l');
45
88
/// ```
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 ( )
48
91
}
92
+
49
93
#[ no_coverage]
50
- pub fn literal_range < R > ( range : R ) -> Rc < Grammar >
94
+ pub fn literal_range < R > ( range : R ) -> Grammar
51
95
where
52
96
R : RangeBounds < char > ,
53
97
{
@@ -61,34 +105,60 @@ where
61
105
std:: ops:: Bound :: Excluded ( x) => unsafe { char:: from_u32_unchecked ( * x as u32 - 1 ) } ,
62
106
std:: ops:: Bound :: Unbounded => panic ! ( "The range must have an upper bound" ) ,
63
107
} ;
64
- Rc :: new ( Grammar :: Literal ( vec ! [ start..=end] ) )
108
+ Rc :: new ( GrammarInner :: Literal ( vec ! [ start..=end] ) ) . into ( )
65
109
}
66
110
67
111
/// 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
+ /// let fuzz_or_check: Grammar = regex("fuzz") | regex("check");
128
+ /// ```
68
129
#[ no_coverage]
69
- pub fn alternation ( gs : impl IntoIterator < Item = Rc < Grammar > > ) -> Rc < Grammar > {
70
- Rc :: new ( Grammar :: Alternation ( gs. into_iter ( ) . collect ( ) ) )
130
+ pub fn alternation ( gs : impl IntoIterator < Item = Grammar > ) -> Grammar {
131
+ Rc :: new ( GrammarInner :: Alternation ( gs. into_iter ( ) . collect ( ) ) ) . into ( )
71
132
}
72
133
73
134
/// Produces a grammar which will concatenate the output of all the provided
74
135
/// grammars together, in order.
75
136
///
76
137
/// For example, the grammar
77
138
/// ```
78
- /// concatenation([
139
+ /// # use fuzzcheck::mutators::grammar::{concatenation, Grammar, regex};
140
+ /// let fuzzcheck: Grammar = concatenation([
79
141
/// regex("fuzz"),
80
142
/// regex("check")
81
- /// ])
143
+ /// ]);
82
144
/// ```
83
145
/// would output "fuzzcheck".
146
+ ///
147
+ /// It is also possible to use the `+` operator to concatenate separate grammars
148
+ /// together. For example, the grammar above could be equivalently written as
149
+ ///
150
+ /// ```
151
+ /// # use fuzzcheck::mutators::grammar::{Grammar, regex};
152
+ /// let fuzzcheck: Grammar = regex("fuzz") + regex("check");
153
+ /// ```
84
154
#[ no_coverage]
85
- pub fn concatenation ( gs : impl IntoIterator < Item = Rc < Grammar > > ) -> Rc < Grammar > {
86
- Rc :: new ( Grammar :: Concatenation ( gs. into_iter ( ) . collect ( ) ) )
155
+ pub fn concatenation ( gs : impl IntoIterator < Item = Grammar > ) -> Grammar {
156
+ Rc :: new ( GrammarInner :: Concatenation ( gs. into_iter ( ) . collect ( ) ) ) . into ( )
87
157
}
88
158
89
159
#[ 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 >
160
+ /// Repeats the provided [`Grammar`] some number of times in the given range.
161
+ pub fn repetition < R > ( gs : Grammar , range : R ) -> Grammar
92
162
where
93
163
R : RangeBounds < usize > ,
94
164
{
@@ -102,25 +172,26 @@ where
102
172
std:: ops:: Bound :: Excluded ( x) => * x,
103
173
std:: ops:: Bound :: Unbounded => usize:: MAX ,
104
174
} ;
105
- Rc :: new ( Grammar :: Repetition ( gs, start..end) )
175
+ Rc :: new ( GrammarInner :: Repetition ( gs, start..end) ) . into ( )
106
176
}
107
177
108
178
#[ no_coverage]
109
179
/// Used to indicate a point of recursion to Fuzzcheck. Should be combined with
110
180
/// [`recursive`].
111
181
///
112
182
/// 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 ( ) ) )
183
+ pub fn recurse ( g : & Weak < GrammarInner > ) -> Grammar {
184
+ Rc :: new ( GrammarInner :: Recurse ( g. clone ( ) ) ) . into ( )
115
185
}
116
186
117
187
#[ no_coverage]
118
- /// Creates a recursive grammar . This function should be combined with
188
+ /// Creates a recursive [`Grammar`] . This function should be combined with
119
189
/// [`recurse`] to make recursive calls.
120
190
///
121
191
/// 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
- } ) ) )
192
+ pub fn recursive ( data_fn : impl Fn ( & Weak < GrammarInner > ) -> Grammar ) -> Grammar {
193
+ Rc :: new ( GrammarInner :: Recursive (
194
+ Rc :: new_cyclic ( |g| Rc :: try_unwrap ( data_fn ( g) . 0 ) . unwrap ( ) ) . into ( ) ,
195
+ ) )
196
+ . into ( )
126
197
}
0 commit comments