From 3beb298a6d04f4eade0a85905befb9d0599efde5 Mon Sep 17 00:00:00 2001 From: xenofem Date: Fri, 19 Jun 2020 12:58:59 -0400 Subject: [PATCH] Refactoring and cleanup for parser module --- Cargo.toml | 2 +- src/bin/purrchance.rs | 2 +- src/lib.rs | 31 ++++++++++++++++++---- src/parser.rs | 61 ++++++++++++++++++++++++++----------------- 4 files changed, 65 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0048e0f..2c83773 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "purrchance" -version = "0.2.0" +version = "0.3.0" authors = ["xenofem "] description = "An unofficial Rust implementation of the Perchance grammar engine" repository = "https://git.xeno.science/xenofem/purrchance" diff --git a/src/bin/purrchance.rs b/src/bin/purrchance.rs index 87d1664..38ab7b6 100644 --- a/src/bin/purrchance.rs +++ b/src/bin/purrchance.rs @@ -14,7 +14,7 @@ fn main() { } let raw_grammar = read_to_string(&args[1]).unwrap(); - let grammar = load_grammar(&raw_grammar); + let grammar = load_grammar(&raw_grammar).unwrap(); if args.len() < 3 { eprintln!("{:?}", grammar); exit(0); diff --git a/src/lib.rs b/src/lib.rs index 038fea9..9dd40a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,7 +115,7 @@ mod tests { #[test] fn eval_loaded_grammar() { - let g = load_grammar("test\n foo\n"); + let g = load_grammar("test\n foo\n").unwrap(); let nt = Symbol::NonTerminal(String::from("test")); assert_eq!(nt.eval(&g), Some(String::from("foo"))); } @@ -125,7 +125,7 @@ mod tests { let g = load_grammar("// testing test foo // blah blah -// isn't this fun?"); +// isn't this fun?").unwrap(); let nt = Symbol::NonTerminal(String::from("test")); assert_eq!(nt.eval(&g), Some(String::from("foo"))); } @@ -135,7 +135,7 @@ test let g = load_grammar("// testing test foo ^100 -// isn't this fun?"); +// isn't this fun?").unwrap(); let nt = Symbol::NonTerminal(String::from("test")); assert_eq!(nt.eval(&g), Some(String::from("foo"))); } @@ -146,11 +146,32 @@ test test foo ^1000000 bar ^1/1000000 -"); +").unwrap(); let nt = Symbol::NonTerminal(String::from("test")); assert_eq!(nt.eval(&g), Some(String::from("foo"))); } + #[test] + fn eval_loaded_grammar_comments_fraction_weights_tabs2() { + let g = load_grammar(" +test + bar ^1/1000000 + foo ^1000000 +").unwrap(); + let nt = Symbol::NonTerminal(String::from("test")); + assert_eq!(nt.eval(&g), Some(String::from("foo"))); + } + + #[test] + fn eval_loaded_grammar_comments_fraction_weights3() { + let g = load_grammar(" +test + bar ^1/1000000000 + foo ^1/2 +").unwrap(); + let nt = Symbol::NonTerminal(String::from("test")); + assert_eq!(nt.eval(&g), Some(String::from("foo"))); + } #[test] fn eval_loaded_grammar_multiple_lists() { let g = load_grammar(" @@ -159,7 +180,7 @@ test test1 foo -"); +").unwrap(); let nt = Symbol::NonTerminal(String::from("test")); assert_eq!(nt.eval(&g), Some(String::from("foo"))); } diff --git a/src/parser.rs b/src/parser.rs index 16397ce..84e92a8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -11,24 +11,7 @@ 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((whitespace, opt(comment), tag("\n"))), |_| ())(input) -} - -pub fn take_until_any>(tags: Vec) -> impl Fn(Input) -> IResult +fn take_until_any>(tags: Vec) -> impl Fn(Input) -> IResult where Input: InputTake + FindSubstring, T: InputLength + Clone, @@ -59,6 +42,10 @@ fn nonterminal_name(input: &str) -> IResult<&str, String> { Ok((input, String::from(head.to_owned() + tail))) } +fn nonterminal(input: &str) -> IResult<&str, Symbol> { + map(delimited(tag("["), nonterminal_name, tag("]")), Symbol::NonTerminal)(input) +} + fn rat(input: &str) -> IResult<&str, f64> { let (input, num) = double(input)?; let (input, _) = tag("/")(input)?; @@ -67,17 +54,43 @@ fn rat(input: &str) -> IResult<&str, f64> { Ok((input, num / denom)) } +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) +} + fn expr(input: &str) -> IResult<&str, (Expr, f64)> { let (input, (_, _, syms, _, weight, _, _, _, _)) = tuple(( - many0(empty_line), + empty_lines, alt((tag(" "), tag("\t"))), many1(alt((terminal, nonterminal))), whitespace, opt(weight), whitespace, opt(comment), - tag("\n"), - many0(empty_line), + eol, + empty_lines, ))(input)?; Ok((input, (Expr(syms), weight.unwrap_or(1.0)))) @@ -85,7 +98,7 @@ fn expr(input: &str) -> IResult<&str, (Expr, f64)> { fn list(input: &str) -> IResult<&str, (String, List)> { let (input, (_, name, _, _, _, exprs)) = tuple(( - many0(empty_line), + empty_lines, nonterminal_name, whitespace, opt(comment), @@ -102,6 +115,6 @@ fn grammar(input: &str) -> IResult<&str, Grammar> { Ok((input, Grammar(HashMap::from_iter(lists.into_iter())))) } -pub fn load_grammar(input: &str) -> Grammar { - grammar(input).unwrap().1 +pub fn load_grammar(input: &str) -> Result> { + all_consuming(grammar)(input).map(|(_, g)| g) }