• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

shnewto / bnf / 4568677051

pending completion
4568677051

push

github

Jeffrey Crocker
LLVM coverage reporting

2125 of 2200 relevant lines covered (96.59%)

53550.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.73
/src/expression.rs
1
use crate::error::Error;
2
use crate::parsers;
3
use crate::term::Term;
4
use serde::{Deserialize, Serialize};
5
use std::fmt;
6
use std::ops;
7
use std::str::FromStr;
8

9
/// An Expression is comprised of any number of Terms
10
#[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, Hash, PartialEq)]
47,124✔
11
pub struct Expression {
12
    pub(crate) terms: Vec<Term>,
13
}
14

15
impl Expression {
16
    /// Construct a new `Expression`
17
    pub fn new() -> Expression {
5✔
18
        Expression { terms: vec![] }
5✔
19
    }
5✔
20

21
    /// Construct an `Expression` from `Term`s
22
    pub fn from_parts(v: Vec<Term>) -> Expression {
471,804✔
23
        Expression { terms: v }
471,804✔
24
    }
471,804✔
25

26
    /// Add `Term` to `Expression`
27
    pub fn add_term(&mut self, term: Term) {
12✔
28
        self.terms.push(term);
12✔
29
    }
12✔
30

31
    /// Remove `Term` from `Expression`
32
    ///
33
    /// If interested if `Term` was removed, then inspect the returned `Option`.
34
    ///
35
    /// # Example
36
    ///
37
    /// ```
38
    /// use bnf::{Expression, Term};
39
    ///
40
    /// let mut expression = Expression::from_parts(vec![]);
41
    /// let to_remove = Term::Terminal(String::from("a_terminal"));
42
    /// let removed = expression.remove_term(&to_remove);
43
    /// # let removed_clone = removed.clone();
44
    /// match removed {
45
    ///     Some(term) => println!("removed {}", term),
46
    ///     None => println!("term was not in expression, so could not be removed"),
47
    /// }
48
    ///
49
    /// # assert_eq!(removed_clone, None);
50
    /// ```
51
    pub fn remove_term(&mut self, term: &Term) -> Option<Term> {
52
        if let Some(pos) = self.terms.iter().position(|x| *x == *term) {
9✔
53
            Some(self.terms.remove(pos))
1✔
54
        } else {
55
            None
1✔
56
        }
57
    }
2✔
58

59
    /// Get iterator of `Term`s within `Expression`
60
    pub fn terms_iter(&self) -> impl Iterator<Item = &Term> {
18,105✔
61
        crate::slice_iter::SliceIter { slice: &self.terms }
18,105✔
62
    }
18,105✔
63

64
    /// Get mutable iterator of `Term`s within `Expression`
65
    pub fn terms_iter_mut(&mut self) -> impl Iterator<Item = &mut Term> {
7✔
66
        crate::slice_iter::SliceIterMut {
7✔
67
            slice: &mut self.terms,
7✔
68
        }
7✔
69
    }
7✔
70

71
    /// Determine if this expression terminates or not, i.e contains all terminal elements or every
72
    /// non-terminal element in the expression exists in the (optional) list of 'terminating rules'
73
    pub(crate) fn terminates(&self, terminating_rules: Option<&Vec<&Term>>) -> bool {
7,354✔
74
        if !self.terms.iter().any(|t| matches!(t, Term::Nonterminal(_))) {
7,867✔
75
            return true;
1,013✔
76
        }
6,341✔
77

78
        let Some(terminating_rules) = terminating_rules else {
6,341✔
79
            return false;
2,179✔
80
        };
81

82
        let nonterms = self
4,162✔
83
            .terms_iter()
4,162✔
84
            .filter(|t| matches!(t, Term::Nonterminal(_)));
7,674✔
85

86
        for nt in nonterms {
7,003✔
87
            if !terminating_rules.contains(&nt) {
6,069✔
88
                return false;
3,228✔
89
            }
2,841✔
90
        }
91

92
        true
934✔
93
    }
7,354✔
94
}
95

96
impl fmt::Display for Expression {
97
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44,141✔
98
        let display = self
44,141✔
99
            .terms
44,141✔
100
            .iter()
44,141✔
101
            .map(|s| s.to_string())
329,106✔
102
            .collect::<Vec<_>>()
44,141✔
103
            .join(" ");
44,141✔
104

44,141✔
105
        write!(f, "{display}")
44,141✔
106
    }
44,141✔
107
}
108

109
impl FromStr for Expression {
110
    type Err = Error;
111

112
    fn from_str(s: &str) -> Result<Self, Self::Err> {
125✔
113
        match parsers::expression_complete(s) {
125✔
114
            Result::Ok((_, o)) => Ok(o),
123✔
115
            Result::Err(e) => Err(Error::from(e)),
2✔
116
        }
117
    }
125✔
118
}
119

120
impl ops::Add<Expression> for &Expression {
121
    type Output = Expression;
122
    fn add(self, rhs: Expression) -> Self::Output {
1✔
123
        let mut new_expression = Expression::new();
1✔
124
        for t in self.terms_iter() {
1✔
125
            new_expression.add_term(t.clone());
1✔
126
        }
1✔
127
        for t in rhs.terms_iter() {
1✔
128
            new_expression.add_term(t.clone());
1✔
129
        }
1✔
130
        new_expression
1✔
131
    }
1✔
132
}
133

134
impl ops::Add<Term> for &Expression {
135
    type Output = Expression;
136
    fn add(self, rhs: Term) -> Self::Output {
1✔
137
        let mut new_expression = Expression::new();
1✔
138
        for t in self.terms_iter() {
1✔
139
            new_expression.add_term(t.clone());
1✔
140
        }
1✔
141
        new_expression.add_term(rhs);
1✔
142
        new_expression
1✔
143
    }
1✔
144
}
145

146
impl ops::Add<Expression> for Expression {
147
    type Output = Expression;
148
    fn add(mut self, rhs: Expression) -> Self::Output {
1✔
149
        for t in rhs.terms_iter() {
1✔
150
            self.add_term(t.clone());
1✔
151
        }
1✔
152
        self
1✔
153
    }
1✔
154
}
155

156
impl ops::Add<Term> for Expression {
157
    type Output = Expression;
158
    fn add(mut self, rhs: Term) -> Self::Output {
1✔
159
        self.add_term(rhs);
1✔
160
        self
1✔
161
    }
1✔
162
}
163

164
#[cfg(test)]
165
mod tests {
166
    use super::*;
167
    use quickcheck::{Arbitrary, Gen, QuickCheck, TestResult};
168

169
    impl Arbitrary for Expression {
170
        fn arbitrary(g: &mut Gen) -> Self {
44,101✔
171
            let mut terms = Vec::<Term>::arbitrary(g);
44,101✔
172
            // expressions must always have at least one term
44,101✔
173
            if terms.is_empty() {
44,101✔
174
                terms.push(Term::arbitrary(g));
3,080✔
175
            }
41,021✔
176
            Expression { terms }
44,101✔
177
        }
44,101✔
178
    }
179

180
    fn prop_to_string_and_back(expr: Expression) -> TestResult {
100✔
181
        let to_string: String = expr.to_string();
100✔
182
        let from_str: Result<Expression, _> = to_string.parse();
100✔
183
        match from_str {
100✔
184
            Ok(from_expr) => TestResult::from_bool(from_expr == expr),
100✔
185
            _ => TestResult::error(format!("{expr} to string and back should be safe")),
×
186
        }
187
    }
100✔
188

189
    #[test]
1✔
190
    fn to_string_and_back() {
1✔
191
        QuickCheck::new().quickcheck(prop_to_string_and_back as fn(Expression) -> TestResult)
1✔
192
    }
1✔
193

194
    #[test]
1✔
195
    fn new_expressions() {
1✔
196
        let t1: Term = Term::Terminal(String::from("terminal"));
1✔
197
        let nt1: Term = Term::Nonterminal(String::from("nonterminal"));
1✔
198
        let t2: Term = Term::Terminal(String::from("terminal"));
1✔
199
        let nt2: Term = Term::Nonterminal(String::from("nonterminal"));
1✔
200

1✔
201
        let e1: Expression = Expression::from_parts(vec![nt1, t1]);
1✔
202
        let mut e2: Expression = Expression::new();
1✔
203
        e2.add_term(nt2);
1✔
204
        e2.add_term(t2);
1✔
205

1✔
206
        assert_eq!(e1, e2);
1✔
207
    }
1✔
208

209
    #[test]
1✔
210
    fn add_term() {
1✔
211
        let mut terms = vec![
1✔
212
            Term::Terminal(String::from("A")),
1✔
213
            Term::Terminal(String::from("C")),
1✔
214
            Term::Terminal(String::from("G")),
1✔
215
        ];
1✔
216

1✔
217
        let mut dna_expression = Expression::from_parts(terms.clone());
1✔
218
        assert_eq!(dna_expression.terms_iter().count(), terms.len());
1✔
219

220
        // oops forgot "T"
221
        let forgotten = Term::Terminal(String::from("T"));
1✔
222
        dna_expression.add_term(forgotten.clone());
1✔
223
        terms.push(forgotten);
1✔
224
        assert_eq!(dna_expression.terms_iter().count(), terms.len());
1✔
225

226
        // check all terms are there
227
        for term in dna_expression.terms_iter() {
4✔
228
            assert!(terms.contains(term), "{term} was not in terms");
4✔
229
        }
230
    }
1✔
231

232
    #[test]
1✔
233
    fn remove_term() {
1✔
234
        let terms = vec![
1✔
235
            Term::Terminal(String::from("A")),
1✔
236
            Term::Terminal(String::from("C")),
1✔
237
            Term::Terminal(String::from("G")),
1✔
238
            Term::Terminal(String::from("T")),
1✔
239
            Term::Terminal(String::from("Z")),
1✔
240
        ];
1✔
241

1✔
242
        let mut dna_expression = Expression::from_parts(terms.clone());
1✔
243
        assert_eq!(dna_expression.terms_iter().count(), terms.len());
1✔
244

245
        // oops "Z" isn't a dna base
246
        let accident = Term::Terminal(String::from("Z"));
1✔
247
        let removed = dna_expression.remove_term(&accident);
1✔
248

1✔
249
        // the removed element should be the accident
1✔
250
        assert_eq!(Some(accident.clone()), removed);
1✔
251
        // number of terms should have decreased
252
        assert_eq!(dna_expression.terms_iter().count(), terms.len() - 1);
1✔
253
        // the accident should no longer be found in the terms
254
        assert_eq!(
1✔
255
            dna_expression.terms_iter().find(|&term| *term == accident),
4✔
256
            None
1✔
257
        );
1✔
258
    }
1✔
259

260
    #[test]
1✔
261
    fn remove_nonexistent_term() {
1✔
262
        let terms = vec![
1✔
263
            Term::Terminal(String::from("A")),
1✔
264
            Term::Terminal(String::from("C")),
1✔
265
            Term::Terminal(String::from("G")),
1✔
266
            Term::Terminal(String::from("T")),
1✔
267
        ];
1✔
268

1✔
269
        let mut dna_expression = Expression::from_parts(terms.clone());
1✔
270
        assert_eq!(dna_expression.terms_iter().count(), terms.len());
1✔
271

272
        // oops "Z" isn't a dna base
273
        let nonexistent = Term::Terminal(String::from("Z"));
1✔
274
        let removed = dna_expression.remove_term(&nonexistent);
1✔
275

1✔
276
        // the nonexistent term should not be found in the terms
1✔
277
        assert_eq!(
1✔
278
            dna_expression
1✔
279
                .terms_iter()
1✔
280
                .find(|&term| *term == nonexistent),
4✔
281
            None
1✔
282
        );
1✔
283
        // no term should have been removed
284
        assert_eq!(None, removed);
1✔
285
        // number of terms should not have decreased
286
        assert_eq!(dna_expression.terms_iter().count(), terms.len());
1✔
287
    }
1✔
288

289
    #[test]
1✔
290
    fn parse_complete() {
1✔
291
        let expression = Expression::from_parts(vec![
1✔
292
            Term::Nonterminal(String::from("base")),
1✔
293
            Term::Nonterminal(String::from("dna")),
1✔
294
        ]);
1✔
295
        assert_eq!(Ok(expression), Expression::from_str("<base> <dna>"));
1✔
296
    }
1✔
297

298
    #[test]
1✔
299
    fn parse_error() {
1✔
300
        let expression = Expression::from_str("<base> <dna");
1✔
301
        assert!(expression.is_err(), "{expression:?} should be error");
1✔
302

303
        let error = expression.unwrap_err();
1✔
304
        match error {
1✔
305
            Error::ParseError(_) => (),
1✔
306
            _ => panic!("{error} should be should be error"),
×
307
        }
308
    }
1✔
309

310
    #[test]
1✔
311
    fn parse_incomplete() {
1✔
312
        let result = Expression::from_str("");
1✔
313
        assert!(result.is_err(), "{result:?} should be err");
1✔
314
        match result {
1✔
315
            Err(e) => match e {
1✔
316
                Error::ParseError(_) => (),
1✔
317
                e => panic!("should should be Error::ParseError: {e:?}"),
×
318
            },
319
            Ok(s) => panic!("should should be Error::ParseError: {s}"),
×
320
        }
321
    }
1✔
322

323
    #[test]
1✔
324
    fn add_operator() {
1✔
325
        let t1 = Term::Terminal(String::from("terminal"));
1✔
326
        let nt1 = Term::Nonterminal(String::from("nonterminal"));
1✔
327
        let t2 = Term::Terminal(String::from("terminal"));
1✔
328
        let nt2 = Term::Nonterminal(String::from("nonterminal"));
1✔
329
        let t3 = Term::Terminal(String::from("terminal"));
1✔
330
        let nt3 = Term::Nonterminal(String::from("nonterminal"));
1✔
331
        let t4 = Term::Terminal(String::from("terminal"));
1✔
332
        let nt4 = Term::Nonterminal(String::from("nonterminal"));
1✔
333
        let t5 = Term::Terminal(String::from("terminal"));
1✔
334
        let nt5 = Term::Nonterminal(String::from("nonterminal"));
1✔
335

1✔
336
        let e1 = Expression::from_parts(vec![nt1, t1]);
1✔
337
        // &expression + expression
1✔
338
        let e2_1 = Expression::from_parts(vec![nt2]);
1✔
339
        let e2_2 = Expression::from_parts(vec![t2]);
1✔
340
        let e2 = &e2_1 + e2_2;
1✔
341
        // &expression + term
1✔
342
        let e3_1 = Expression::from_parts(vec![nt3]);
1✔
343
        let e3 = &e3_1 + t3;
1✔
344
        // expression + expression
1✔
345
        let e4_1 = Expression::from_parts(vec![nt4]);
1✔
346
        let e4_2 = Expression::from_parts(vec![t4]);
1✔
347
        let e4 = e4_1 + e4_2;
1✔
348
        // expression + term
1✔
349
        let e5_1 = Expression::from_parts(vec![nt5]);
1✔
350
        let e5 = e5_1 + t5;
1✔
351

1✔
352
        assert_eq!(e1, e2);
1✔
353
        assert_eq!(e1, e3);
1✔
354
        assert_eq!(e1, e4);
1✔
355
        assert_eq!(e1, e5);
1✔
356
    }
1✔
357

358
    #[test]
1✔
359
    fn iterate_terms() {
1✔
360
        let expression: Expression = "<b> 'A' <b>".parse().unwrap();
1✔
361
        let terms = expression.terms_iter().cloned().collect::<Vec<_>>();
1✔
362
        assert_eq!(terms, expression.terms);
1✔
363
    }
1✔
364

365
    #[test]
1✔
366
    fn mutate_iterable_terms() {
1✔
367
        let mut expression: Expression = "'END'".parse().unwrap();
1✔
368
        let new_term = Term::Terminal("X".to_string());
1✔
369
        for term in expression.terms_iter_mut() {
1✔
370
            *term = new_term.clone();
1✔
371
        }
1✔
372
        assert_eq!(expression.terms, vec![new_term])
1✔
373
    }
1✔
374

375
    #[test]
1✔
376
    fn does_not_terminate() {
1✔
377
        let mut expression: Expression;
1✔
378

1✔
379
        expression = "<a> <b> <c>".parse().unwrap();
1✔
380
        assert!(!expression.terminates(None));
1✔
381

382
        expression = "'a' <b> <c>".parse().unwrap();
1✔
383
        assert!(!expression.terminates(None));
1✔
384

385
        expression = "<a> 'b' <c>".parse().unwrap();
1✔
386
        assert!(!expression.terminates(None));
1✔
387

388
        expression = "<a> <b> 'c'".parse().unwrap();
1✔
389
        assert!(!expression.terminates(None));
1✔
390

391
        expression = "'a' 'b' <c>".parse().unwrap();
1✔
392
        assert!(!expression.terminates(None));
1✔
393

394
        expression = "'a' <b> 'c'".parse().unwrap();
1✔
395
        assert!(!expression.terminates(None));
1✔
396

397
        expression = "<a> 'b' 'c'".parse().unwrap();
1✔
398
        assert!(!expression.terminates(None));
1✔
399

400
        expression = "'a' <b> <c>".parse().unwrap();
1✔
401
        assert!(!expression.terminates(Some(&vec![
1✔
402
            &Term::from_str("<b>").unwrap(),
1✔
403
            &Term::from_str("<1>").unwrap(),
1✔
404
            &Term::from_str("<2>").unwrap(),
1✔
405
        ])));
1✔
406

407
        expression = "<a> <b> <c>".parse().unwrap();
1✔
408
        assert!(!expression.terminates(Some(&vec![
1✔
409
            &Term::from_str("<c>").unwrap(),
1✔
410
            &Term::from_str("<b>").unwrap(),
1✔
411
            &Term::from_str("<1>").unwrap(),
1✔
412
        ])));
1✔
413
    }
1✔
414

415
    #[test]
1✔
416
    fn does_terminate() {
1✔
417
        let mut expression: Expression = "'a' 'b' 'c'".parse().unwrap();
1✔
418
        assert!(expression.terminates(None));
1✔
419

420
        expression = "'a' 'b'".parse().unwrap();
1✔
421
        assert!(expression.terminates(None));
1✔
422

423
        expression = "'a'".parse().unwrap();
1✔
424
        assert!(expression.terminates(None));
1✔
425

426
        let mut expression: Expression = "'a' 'b' <c>".parse().unwrap();
1✔
427
        assert!(expression.terminates(Some(&vec![&Term::from_str("<c>").unwrap()])));
1✔
428

429
        expression = "'a' <b> <c>".parse().unwrap();
1✔
430
        assert!(expression.terminates(Some(&vec![
1✔
431
            &Term::from_str("<c>").unwrap(),
1✔
432
            &Term::from_str("<b>").unwrap(),
1✔
433
        ])));
1✔
434

435
        expression = "'a' <b> <c>".parse().unwrap();
1✔
436
        assert!(expression.terminates(Some(&vec![
1✔
437
            &Term::from_str("<c>").unwrap(),
1✔
438
            &Term::from_str("<b>").unwrap(),
1✔
439
            &Term::from_str("<1>").unwrap(),
1✔
440
            &Term::from_str("<2>").unwrap(),
1✔
441
        ])));
1✔
442

443
        expression = "<a> <b> <c>".parse().unwrap();
1✔
444
        assert!(expression.terminates(Some(&vec![
1✔
445
            &Term::from_str("<c>").unwrap(),
1✔
446
            &Term::from_str("<b>").unwrap(),
1✔
447
            &Term::from_str("<1>").unwrap(),
1✔
448
            &Term::from_str("<2>").unwrap(),
1✔
449
            &Term::from_str("<a>").unwrap(),
1✔
450
        ],)));
1✔
451
    }
1✔
452
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc