Skip to main content

bnf/parsers/
bnf.rs

1use super::Format;
2
3#[non_exhaustive]
4pub struct BNF;
5
6impl Format for BNF {
7    fn nonterminal_delimiter() -> Option<(char, char)> {
8        Some(('<', '>'))
9    }
10    fn production_separator() -> &'static str {
11        "::="
12    }
13    fn alternative_separator() -> char {
14        '|'
15    }
16    fn production_start_char() -> Option<char> {
17        Some('<')
18    }
19}
20
21#[cfg(test)]
22mod tests {
23    use super::BNF;
24    use crate::parsers::*;
25
26    #[test]
27    fn nonterminal_match() {
28        let input = "<nonterminal-pattern>";
29        let expected = Term::Nonterminal("nonterminal-pattern".to_string());
30
31        let (_, actual) = nonterminal::<BNF>(input).unwrap();
32        assert_eq!(expected, actual);
33    }
34
35    #[test]
36    fn expression_match() {
37        let input = r#"<nonterminal-pattern> "terminal-pattern""#;
38        let expected = Expression::from_parts(vec![
39            Term::Nonterminal("nonterminal-pattern".to_string()),
40            Term::Terminal("terminal-pattern".to_string()),
41        ]);
42
43        let (_, actual) = expression::<BNF>(input).unwrap();
44        assert_eq!(expected, actual);
45    }
46
47    #[test]
48    fn production_match() {
49        let input = r#"<nonterminal-pattern> ::= <nonterminal-pattern> "terminal-pattern" | "terminal-pattern";\r\n"#;
50        let expected = Production::from_parts(
51            Term::Nonterminal("nonterminal-pattern".to_string()),
52            vec![
53                Expression::from_parts(vec![
54                    Term::Nonterminal("nonterminal-pattern".to_string()),
55                    Term::Terminal("terminal-pattern".to_string()),
56                ]),
57                Expression::from_parts(vec![Term::Terminal("terminal-pattern".to_string())]),
58            ],
59        );
60
61        let (_, actual) = production::<BNF>(input).unwrap();
62        assert_eq!(expected, actual);
63    }
64
65    #[test]
66    fn grammar_match() {
67        let input = r#"<nonterminal-pattern> ::= <nonterminal-pattern> "terminal-pattern" | "terminal-pattern";\r\n"#;
68        let expected = Grammar::from_parts(vec![Production::from_parts(
69            Term::Nonterminal("nonterminal-pattern".to_string()),
70            vec![
71                Expression::from_parts(vec![
72                    Term::Nonterminal("nonterminal-pattern".to_string()),
73                    Term::Terminal("terminal-pattern".to_string()),
74                ]),
75                Expression::from_parts(vec![Term::Terminal("terminal-pattern".to_string())]),
76            ],
77        )]);
78
79        let (_, actual) = grammar::<BNF>(input).unwrap();
80        assert_eq!(expected, actual);
81    }
82
83    #[test]
84    fn production_with_comment_suffix() {
85        let input = "<a> ::= 'x' ; only a comment\n";
86        let expected = Production::from_parts(
87            Term::Nonterminal("a".to_string()),
88            vec![Expression::from_parts(vec![Term::Terminal(
89                "x".to_string(),
90            )])],
91        );
92
93        let (_, actual) = production::<BNF>(input).unwrap();
94        assert_eq!(expected, actual);
95    }
96
97    #[test]
98    fn grammar_with_comment_only_line() {
99        let input = "<a> ::= 'x'\n; comment\n<b> ::= 'y'\n";
100        let expected = Grammar::from_parts(vec![
101            Production::from_parts(
102                Term::Nonterminal("a".to_string()),
103                vec![Expression::from_parts(vec![Term::Terminal(
104                    "x".to_string(),
105                )])],
106            ),
107            Production::from_parts(
108                Term::Nonterminal("b".to_string()),
109                vec![Expression::from_parts(vec![Term::Terminal(
110                    "y".to_string(),
111                )])],
112            ),
113        ]);
114
115        let (_, actual) = grammar::<BNF>(input).unwrap();
116        assert_eq!(expected, actual);
117    }
118
119    #[test]
120    fn grammar_with_comment_to_eof() {
121        let input = "<a> ::= 'x'\n<b> ::= 'y' ; last line comment";
122        let expected = Grammar::from_parts(vec![
123            Production::from_parts(
124                Term::Nonterminal("a".to_string()),
125                vec![Expression::from_parts(vec![Term::Terminal(
126                    "x".to_string(),
127                )])],
128            ),
129            Production::from_parts(
130                Term::Nonterminal("b".to_string()),
131                vec![Expression::from_parts(vec![Term::Terminal(
132                    "y".to_string(),
133                )])],
134            ),
135        ]);
136
137        let (_, actual) = grammar::<BNF>(input).unwrap();
138        assert_eq!(expected, actual);
139    }
140}