From 5e94769ed2c1342962a44d1dcf14abc9d4bc570e Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sun, 16 Oct 2022 19:07:58 -0700 Subject: [PATCH] primitives mod --- src/lib.rs | 43 ++-------------------------- src/primitives.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++ src/sequence.rs | 3 +- 3 files changed, 77 insertions(+), 42 deletions(-) create mode 100644 src/primitives.rs diff --git a/src/lib.rs b/src/lib.rs index 89ed7e9..cf5a928 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,17 +2,11 @@ #![allow(dead_code)] //TODO eventually turn this off mod bnf; mod parser; +mod primitives; mod sequence; use parser::{ParseResult, Parser}; -fn literal(expected: &'static str) -> impl Fn(&str) -> ParseResult<&str, &str, &str> { - move |input| match input.get(0..expected.len()) { - Some(next) if next == expected => Ok((expected, &input[expected.len()..])), - _ => Err(input), - } -} - fn map(parser: P, map_fn: F) -> impl Parser where P: Parser, @@ -75,28 +69,6 @@ where }) } -/// Parses a standard identifier in a programming language -fn identifier(input: &str) -> ParseResult<&str, String, &str> { - let mut chars = input.chars(); - let mut buf = String::new(); - - match chars.next() { - Some(ch) if ch.is_alphabetic() => buf.push(ch), - _ => return Err(input), - } - - while let Some(next) = chars.next() { - if next.is_alphanumeric() { - buf.push(next); - } else { - break; - } - } - - let next_index = buf.len(); - Ok((buf, &input[next_index..])) -} - fn any_char(input: &str) -> ParseResult<&str, char, &str> { match input.chars().next() { Some(ch) => Ok((ch, &input[ch.len_utf8()..])), @@ -119,6 +91,7 @@ where #[cfg(test)] mod tests { use super::*; + use crate::primitives::literal; use std::assert_matches::assert_matches; use std::collections::HashMap; @@ -128,12 +101,6 @@ mod tests { assert_matches!(output.unwrap(), ("a", " yolo")); } - #[test] - fn test_identifier() { - assert_matches!(identifier("bongo1beans"), Ok((s, "")) if s == "bongo1beans"); - assert_matches!(identifier("2bongo1beans"), Err("2bongo1beans")); - } - #[test] fn test_map() { let lit_a = literal("a"); @@ -150,12 +117,6 @@ mod tests { assert_matches!(p.parse(input), Ok((v, "ecks")) if v.len() == 1); } - #[test] - fn test_pred() { - let p = pred(any_char, |c| *c == 'f'); - assert_eq!(p.parse("frog"), Ok(('f', "rog"))); - } - #[test] fn test_choice() { let p = choice(literal("gnostika").to(1), one_or_more(literal(" ")).to(2)); diff --git a/src/primitives.rs b/src/primitives.rs new file mode 100644 index 0000000..2bce7ec --- /dev/null +++ b/src/primitives.rs @@ -0,0 +1,73 @@ +use crate::parser::{ParseResult, Parser}; + +pub fn literal(expected: &'static str) -> impl Fn(&str) -> ParseResult<&str, &str, &str> { + move |input| match input.get(0..expected.len()) { + Some(next) if next == expected => Ok((expected, &input[expected.len()..])), + _ => Err(input), + } +} + +pub fn any_char(input: &str) -> ParseResult<&str, char, &str> { + match input.chars().next() { + Some(ch) => Ok((ch, &input[ch.len_utf8()..])), + None => Err(input), + } +} + +pub fn pred(parser: P, pred_fn: F) -> impl Parser +where + P: Parser, + F: Fn(&O) -> bool, +{ + move |input| { + parser.parse(input).and_then(|(result, rest)| { + if pred_fn(&result) { + Ok((result, rest)) + } else { + Err(rest) + } + }) + } +} + +/// Parses a standard identifier in a programming language +pub fn identifier(input: &str) -> ParseResult<&str, String, &str> { + let mut chars = input.chars(); + let mut buf = String::new(); + + match chars.next() { + Some(ch) if ch.is_alphabetic() => buf.push(ch), + _ => return Err(input), + } + + while let Some(next) = chars.next() { + if next.is_alphanumeric() { + buf.push(next); + } else { + break; + } + } + + let next_index = buf.len(); + Ok((buf, &input[next_index..])) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_identifier() { + assert_eq!( + identifier("bongo1beans").unwrap(), + (("bongo1beans".to_string(), "")) + ); + assert_eq!(identifier("2bongo1beans"), Err("2bongo1beans")); + } + + #[test] + fn test_pred() { + let p = pred(any_char, |c| *c == 'f'); + assert_eq!(p.parse("frog"), Ok(('f', "rog"))); + } +} diff --git a/src/sequence.rs b/src/sequence.rs index b1eb37a..8b75a6f 100644 --- a/src/sequence.rs +++ b/src/sequence.rs @@ -110,7 +110,8 @@ where #[cfg(test)] mod test { use super::*; - use crate::{identifier, literal, zero_or_more}; + use crate::primitives::{identifier, literal}; + use crate::zero_or_more; use std::assert_matches::assert_matches; #[test]