Compare commits
No commits in common. "51d7380761ffaae00f0df9faabe6af99eb011e4f" and "05c9ada7c6fd6951a4dfadbb9d62d92c9f3f54f5" have entirely different histories.
51d7380761
...
05c9ada7c6
@ -47,28 +47,3 @@ where
|
|||||||
choice_loop(input, &[&self.0, &self.1, &self.2])
|
choice_loop(input, &[&self.0, &self.1, &self.2])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P1, P2, P3, P4, I, O, E> Choice<I, O, E> for (P1, P2, P3, P4)
|
|
||||||
where
|
|
||||||
P1: Parser<I, O, E>,
|
|
||||||
P2: Parser<I, O, E>,
|
|
||||||
P3: Parser<I, O, E>,
|
|
||||||
P4: Parser<I, O, E>,
|
|
||||||
{
|
|
||||||
fn parse_choice(&self, input: I) -> Result<(O, I), (E, I)> {
|
|
||||||
choice_loop(input, &[&self.0, &self.1, &self.2, &self.3])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<P1, P2, P3, P4, P5, I, O, E> Choice<I, O, E> for (P1, P2, P3, P4, P5)
|
|
||||||
where
|
|
||||||
P1: Parser<I, O, E>,
|
|
||||||
P2: Parser<I, O, E>,
|
|
||||||
P3: Parser<I, O, E>,
|
|
||||||
P4: Parser<I, O, E>,
|
|
||||||
P5: Parser<I, O, E>,
|
|
||||||
{
|
|
||||||
fn parse_choice(&self, input: I) -> Result<(O, I), (E, I)> {
|
|
||||||
choice_loop(input, &[&self.0, &self.1, &self.2, &self.3, &self.4])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -22,8 +22,6 @@ pub trait ParserExtension<I, O, E>: Parser<I, O, E> {
|
|||||||
|
|
||||||
fn to<O2: Clone>(self, item: O2) -> impl Parser<I, O2, E>;
|
fn to<O2: Clone>(self, item: O2) -> impl Parser<I, O2, E>;
|
||||||
fn then<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, (O, O2), E>;
|
fn then<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, (O, O2), E>;
|
||||||
fn then_ignore<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, O, E>;
|
|
||||||
fn ignore_then<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, O2, E>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, I, O, E> ParserExtension<I, O, E> for T
|
impl<T, I, O, E> ParserExtension<I, O, E> for T
|
||||||
@ -44,11 +42,4 @@ where
|
|||||||
fn then<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, (O, O2), E> {
|
fn then<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, (O, O2), E> {
|
||||||
seq2(self, next)
|
seq2(self, next)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn then_ignore<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, O, E> {
|
|
||||||
seq2(self, next).map(|(this, _)| this)
|
|
||||||
}
|
|
||||||
fn ignore_then<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, O2, E> {
|
|
||||||
seq2(self, next).map(|(_, next)| next)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -48,13 +48,6 @@ pub fn identifier(input: &str) -> ParseResult<&str, String, ()> {
|
|||||||
Ok((buf, &input[next_index..]))
|
Ok((buf, &input[next_index..]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn whitespace(input: &str) -> ParseResult<&str, char, ()> {
|
|
||||||
match input.chars().next() {
|
|
||||||
Some(ch) if ch.is_whitespace() => Ok((ch, &input[1..])),
|
|
||||||
_ => Err(((), input)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -15,60 +15,23 @@ enum Atom {
|
|||||||
Symbol(String),
|
Symbol(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_bool(input: &str) -> ParseResult<&str, Atom, ()> {
|
#[test]
|
||||||
choice((
|
fn parse_sexp() {
|
||||||
|
let parse_bool = choice((
|
||||||
literal("#t").to(Atom::Bool(true)),
|
literal("#t").to(Atom::Bool(true)),
|
||||||
literal("#f").to(Atom::Bool(false)),
|
literal("#f").to(Atom::Bool(false)),
|
||||||
))
|
));
|
||||||
.parse(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_symbol(input: &str) -> ParseResult<&str, Atom, ()> {
|
let parse_symbol = identifier.map(Atom::Symbol);
|
||||||
identifier.map(Atom::Symbol).parse(input)
|
let parse_number = repeated(one_of("1234567890"))
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_number(input: &str) -> ParseResult<&str, Atom, ()> {
|
|
||||||
repeated(one_of("1234567890"))
|
|
||||||
.at_least(1)
|
.at_least(1)
|
||||||
.map(|n| Atom::Num(n.iter().collect::<String>().parse::<i64>().unwrap()))
|
.map(|n| Atom::Num(n.iter().collect::<String>().parse::<i64>().unwrap()));
|
||||||
.parse(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_atom(input: &str) -> ParseResult<&str, Atom, ()> {
|
let parser = choice((parse_symbol, parse_bool, parse_number));
|
||||||
choice((parse_symbol, parse_bool, parse_number)).parse(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
let output = parser.parse("#t").unwrap();
|
||||||
fn test_parse_atom() {
|
|
||||||
let output = parse_atom.parse("#t").unwrap();
|
|
||||||
assert_eq!(output.0, Atom::Bool(true));
|
assert_eq!(output.0, Atom::Bool(true));
|
||||||
|
|
||||||
let output = parse_atom.parse("384").unwrap();
|
let output = parser.parse("384").unwrap();
|
||||||
assert_eq!(output.0, Atom::Num(384));
|
assert_eq!(output.0, Atom::Num(384));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expr(input: &str) -> ParseResult<&str, Expr, ()> {
|
|
||||||
choice((parse_list, parse_atom.map(Expr::Atom))).parse(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_list(input: &str) -> ParseResult<&str, Expr, ()> {
|
|
||||||
literal_char('(')
|
|
||||||
.ignore_then(repeated(parse_atom.map(Expr::Atom)).separated_by(whitespace.to(())))
|
|
||||||
.then_ignore(literal_char(')'))
|
|
||||||
.map(Expr::List)
|
|
||||||
.parse(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_sexp() {
|
|
||||||
let output = parse_expr("(add 1 2)").unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
output.0,
|
|
||||||
Expr::List(vec![
|
|
||||||
Expr::Atom(Atom::Symbol("add".to_string())),
|
|
||||||
Expr::Atom(Atom::Num(1)),
|
|
||||||
Expr::Atom(Atom::Num(2))
|
|
||||||
])
|
|
||||||
);
|
|
||||||
assert_eq!(output.1, "");
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user