1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
use super::*; use std::iter::FromIterator; use nom::{Err, error::{ErrorKind, ParseError}}; use nom::{FindSubstring, InputLength, InputTake, IResult}; use nom::branch::*; use nom::bytes::complete::*; use nom::combinator::*; use nom::multi::*; use nom::number::complete::*; use nom::sequence::*; fn nonterminal(input: &str) -> IResult<&str, Symbol> { map(delimited(tag("["), nonterminal_name, tag("]")), Symbol::NonTerminal)(input) } fn weight(input: &str) -> IResult<&str, f64> { preceded(tag("^"), alt((double, rat)))(input) } fn comment(input: &str) -> IResult<&str, ()> { map(tuple((tag("//"), is_not("\n"))), |_| ())(input) } fn whitespace(input: &str) -> IResult<&str, ()> { map(take_while(|c| (c == ' ' || c == '\t')), |_| ())(input) } fn empty_line(input: &str) -> IResult<&str, ()> { map(tuple((opt(comment), tag("\n"))), |_| ())(input) } pub fn take_until_any<T, Input, Error: ParseError<Input>>(tags: Vec<T>) -> impl Fn(Input) -> IResult<Input, Input, Error> where Input: InputTake + FindSubstring<T>, T: InputLength + Clone, { move |i: Input| { let min_index = tags.iter().filter_map(|tag| i.find_substring(tag.clone())).min(); let res: IResult<_, _, Error> = match min_index { None => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))), Some(index) => Ok(i.take_split(index)), }; res } } fn terminal(input: &str) -> IResult<&str, Symbol> { let (input, mut terminal_val) = verify(take_until_any(vec!["[", "//", "^", "\n"]), |s: &str| s.len() > 0)(input)?; if !input.starts_with("[") { terminal_val = terminal_val.trim_end(); } Ok((input, Symbol::Terminal(String::from(terminal_val)))) } fn nonterminal_name(input: &str) -> IResult<&str, String> { let (input, head) = take_while_m_n(1, 1, |c: char| (c.is_alphabetic() || c == '_'))(input)?; let (input, tail) = take_while(|c: char| (c.is_alphanumeric() || c == '_'))(input)?; Ok((input, String::from(head.to_owned() + tail))) } fn rat(input: &str) -> IResult<&str, f64> { let (input, num) = double(input)?; let (input, _) = tag("/")(input)?; let (input, denom) = verify(double, |&f| f != 0.0)(input)?; Ok((input, num / denom)) } fn expr(input: &str) -> IResult<&str, (Expr, f64)> { let (input, (_, _, syms, _, weight, _, _, _, _)) = tuple(( many0(empty_line), alt((tag(" "), tag("\t"))), many1(alt((terminal, nonterminal))), whitespace, opt(weight), whitespace, opt(comment), tag("\n"), many0(empty_line), ))(input)?; Ok((input, (Expr(syms), weight.unwrap_or(1.0)))) } fn list(input: &str) -> IResult<&str, (String, List)> { let (input, (_, name, _, _, _, exprs)) = tuple(( many0(empty_line), nonterminal_name, whitespace, opt(comment), tag("\n"), many1(expr), ))(input)?; Ok((input, (name, List(exprs)))) } fn grammar(input: &str) -> IResult<&str, Grammar> { let (input, lists) = many1(list)(input)?; Ok((input, Grammar(HashMap::from_iter(lists.into_iter())))) } pub fn load_grammar(input: &str) -> Grammar { grammar(input).unwrap().1 }