94 lines
2.4 KiB
Rust
94 lines
2.4 KiB
Rust
use crate::parser::{ParseResult, Parser, ParserInput};
|
|
|
|
pub fn literal_char(expected: char) -> impl Fn(&str) -> ParseResult<&str, char, &str> {
|
|
move |input| match input.chars().next() {
|
|
Some(ch) if ch == expected => Ok((expected, &input[ch.len_utf8()..])),
|
|
_ => Err(input),
|
|
}
|
|
}
|
|
|
|
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 one_of<'a>(items: &'static str) -> impl Parser<&'a str, &'a str, &'a str> {
|
|
move |input: &'a str| {
|
|
if let Some(ch) = input.chars().next() {
|
|
if items.contains(ch) {
|
|
let (first, rest) = input.split_at(1);
|
|
return Ok((first, rest));
|
|
}
|
|
}
|
|
Err(input)
|
|
}
|
|
}
|
|
|
|
pub fn pred<P, F, I, O>(parser: P, pred_fn: F) -> impl Parser<I, O, I>
|
|
where
|
|
I: ParserInput,
|
|
P: Parser<I, O, I>,
|
|
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),
|
|
}
|
|
|
|
for next in chars {
|
|
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")));
|
|
}
|
|
}
|