use super::ast::Grammar;
use super::bnf_parser::parse_bnf;
pub fn arithmetic_grammar() -> Grammar {
parse_bnf(
r#"
<expr> ::= <term> "+" <expr> | <term> "-" <expr> | <term>
<term> ::= <factor> "*" <term> | <factor> "/" <term> | <factor>
<factor> ::= "(" <expr> ")" | <number>
<number> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
"#,
)
.expect("arithmetic grammar is valid BNF")
}
pub fn simple_ab_grammar() -> Grammar {
parse_bnf(
r#"
<S> ::= "a" <S> "b" | "ab"
"#,
)
.expect("ab grammar is valid BNF")
}
pub fn csv_row_grammar() -> Grammar {
parse_bnf(r#"
<row> ::= <field> "," <row> | <field>
<field> ::= <char> <field> | <char>
<char> ::= "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
"#)
.expect("csv grammar is valid BNF")
}
pub fn json_lite_grammar() -> Grammar {
parse_bnf(r#"
<value> ::= <object> | <array> | <string> | <number> | "true" | "false" | "null"
<object> ::= "{" "}" | "{" <members> "}"
<members> ::= <pair> | <pair> "," <members>
<pair> ::= <string> ":" <value>
<array> ::= "[" "]" | "[" <elements> "]"
<elements> ::= <value> | <value> "," <elements>
<string> ::= "\"" "\"" | "\"" <chars> "\""
<chars> ::= <char> | <char> <chars>
<char> ::= "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<number> ::= <digit> | <digit> <number>
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
"#)
.expect("json_lite grammar is valid BNF")
}
pub fn palindrome_grammar() -> Grammar {
parse_bnf(
r#"
<P> ::= "a" <P> "a" | "b" <P> "b" | "a" | "b" | ""
"#,
)
.expect("palindrome grammar is valid BNF")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn examples_arithmetic_grammar_parses() {
let g = arithmetic_grammar();
assert!(
g.rules.len() >= 10,
"arithmetic grammar should have many rules"
);
let start_name = g.nt_name(g.start()).to_string();
assert_eq!(start_name, "expr");
}
#[test]
fn examples_simple_ab_grammar_parses() {
let g = simple_ab_grammar();
assert!(!g.rules.is_empty());
let start_name = g.nt_name(g.start()).to_string();
assert_eq!(start_name, "S");
}
#[test]
fn examples_csv_row_grammar_parses() {
let g = csv_row_grammar();
assert!(!g.rules.is_empty());
let start_name = g.nt_name(g.start()).to_string();
assert_eq!(start_name, "row");
}
#[test]
fn examples_json_lite_grammar_parses() {
let g = json_lite_grammar();
assert!(!g.rules.is_empty());
}
#[test]
fn examples_palindrome_grammar_parses() {
let g = palindrome_grammar();
assert!(!g.rules.is_empty());
}
#[test]
fn examples_arithmetic_grammar_normalises() {
let mut g = arithmetic_grammar();
let count_before = g.rules.len();
g.normalise_terminals();
assert_eq!(
g.rules.len(),
count_before,
"single-char terminals need no splitting"
);
}
}