2020-06-19 01:39:08 -04:00
|
|
|
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::*;
|
|
|
|
|
2020-06-19 12:58:59 -04:00
|
|
|
fn take_until_any<T, Input, Error: ParseError<Input>>(tags: Vec<T>) -> impl Fn(Input) -> IResult<Input, Input, Error>
|
2020-06-19 01:39:08 -04:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-20 04:28:20 -04:00
|
|
|
fn take_all(input: &str) -> IResult<&str, &str> {
|
|
|
|
take_while(|_| true)(input)
|
|
|
|
}
|
|
|
|
|
2020-06-19 01:39:08 -04:00
|
|
|
fn terminal(input: &str) -> IResult<&str, Symbol> {
|
2020-06-20 04:28:20 -04:00
|
|
|
let (input, mut terminal_val) = verify(alt((take_until_any(vec!["[", "//", "^", "\n"]), take_all)), |s: &str| s.len() > 0)(input)?;
|
2020-06-19 01:39:08 -04:00
|
|
|
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)))
|
|
|
|
}
|
|
|
|
|
2020-06-19 12:58:59 -04:00
|
|
|
fn nonterminal(input: &str) -> IResult<&str, Symbol> {
|
|
|
|
map(delimited(tag("["), nonterminal_name, tag("]")), Symbol::NonTerminal)(input)
|
|
|
|
}
|
|
|
|
|
2020-06-19 01:39:08 -04:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2020-06-19 12:58:59 -04:00
|
|
|
fn weight(input: &str) -> IResult<&str, f64> {
|
|
|
|
preceded(tag("^"), alt((rat, double)))(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 eol(input: &str) -> IResult<&str, ()> {
|
|
|
|
map(alt((tag("\n"), all_consuming(take(0usize)))), |_| ())(input)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn empty_lines(input: &str) -> IResult<&str, ()> {
|
|
|
|
map(
|
|
|
|
tuple((
|
|
|
|
many0(tuple((whitespace, opt(comment), tag("\n")))),
|
|
|
|
opt(tuple((whitespace, opt(comment), eol))),
|
|
|
|
)),
|
|
|
|
|_| ()
|
|
|
|
)(input)
|
|
|
|
}
|
|
|
|
|
2020-06-19 01:39:08 -04:00
|
|
|
fn expr(input: &str) -> IResult<&str, (Expr, f64)> {
|
|
|
|
let (input, (_, _, syms, _, weight, _, _, _, _)) = tuple((
|
2020-06-19 12:58:59 -04:00
|
|
|
empty_lines,
|
2020-06-19 01:39:08 -04:00
|
|
|
alt((tag(" "), tag("\t"))),
|
|
|
|
many1(alt((terminal, nonterminal))),
|
|
|
|
whitespace,
|
|
|
|
opt(weight),
|
|
|
|
whitespace,
|
|
|
|
opt(comment),
|
2020-06-19 12:58:59 -04:00
|
|
|
eol,
|
|
|
|
empty_lines,
|
2020-06-19 01:39:08 -04:00
|
|
|
))(input)?;
|
|
|
|
|
|
|
|
Ok((input, (Expr(syms), weight.unwrap_or(1.0))))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn list(input: &str) -> IResult<&str, (String, List)> {
|
|
|
|
let (input, (_, name, _, _, _, exprs)) = tuple((
|
2020-06-19 12:58:59 -04:00
|
|
|
empty_lines,
|
2020-06-19 01:39:08 -04:00
|
|
|
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()))))
|
|
|
|
}
|
|
|
|
|
2020-06-19 12:58:59 -04:00
|
|
|
pub fn load_grammar(input: &str) -> Result<Grammar, Err<(&str, ErrorKind)>> {
|
|
|
|
all_consuming(grammar)(input).map(|(_, g)| g)
|
2020-06-19 01:39:08 -04:00
|
|
|
}
|