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
}