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}