Compare commits
2 Commits
d8a68bcbf3
...
a9d08a9213
Author | SHA1 | Date | |
---|---|---|---|
|
a9d08a9213 | ||
|
cdbbb8214f |
4
justfile
4
justfile
@ -2,5 +2,5 @@ _default:
|
|||||||
just --list
|
just --list
|
||||||
|
|
||||||
|
|
||||||
test:
|
test *args:
|
||||||
cargo nextest run
|
cargo nextest run {{args}}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{map, seq2};
|
use crate::{map, seq2, surrounded_by};
|
||||||
|
|
||||||
pub type ParseResult<I, O, E> = Result<(O, I), (E, I)>;
|
pub type ParseResult<I, O, E> = Result<(O, I), (E, I)>;
|
||||||
|
|
||||||
@ -24,6 +24,7 @@ pub trait ParserExtension<I, O, E>: Parser<I, O, 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 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>;
|
fn ignore_then<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, O2, E>;
|
||||||
|
fn surrounded_by<O2>(self, surrounding: impl Parser<I, O2, E>) -> impl Parser<I, O, E>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, I, O, E> ParserExtension<I, O, E> for T
|
impl<T, I, O, E> ParserExtension<I, O, E> for T
|
||||||
@ -51,4 +52,7 @@ where
|
|||||||
fn ignore_then<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, O2, E> {
|
fn ignore_then<O2, P: Parser<I, O2, E>>(self, next: P) -> impl Parser<I, O2, E> {
|
||||||
seq2(self, next).map(|(_, next)| next)
|
seq2(self, next).map(|(_, next)| next)
|
||||||
}
|
}
|
||||||
|
fn surrounded_by<O2>(self, surrounding: impl Parser<I, O2, E>) -> impl Parser<I, O, E> {
|
||||||
|
surrounded_by(self, surrounding)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ pub fn identifier(input: &str) -> ParseResult<&str, String, ()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn whitespace(input: &str) -> ParseResult<&str, char, ()> {
|
pub fn whitespace(input: &str) -> ParseResult<&str, char, ()> {
|
||||||
|
println!("whitespace: `{input}`");
|
||||||
match input.chars().next() {
|
match input.chars().next() {
|
||||||
Some(ch) if ch.is_whitespace() => Ok((ch, &input[1..])),
|
Some(ch) if ch.is_whitespace() => Ok((ch, &input[1..])),
|
||||||
_ => Err(((), input)),
|
_ => Err(((), input)),
|
||||||
|
@ -7,6 +7,22 @@ where
|
|||||||
move |input| -> ParseResult<I, O, E> { sequence.parse(input) }
|
move |input| -> ParseResult<I, O, E> { sequence.parse(input) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn surrounded_by<I, O1, O2, E>(
|
||||||
|
main: impl Parser<I, O1, E>,
|
||||||
|
surrounding: impl Parser<I, O2, E>,
|
||||||
|
) -> impl Parser<I, O1, E> {
|
||||||
|
move |input| {
|
||||||
|
println!("surrounded_by");
|
||||||
|
let (_result1, rest1) = surrounding.parse(input)?;
|
||||||
|
println!("A");
|
||||||
|
let (result2, rest2) = main.parse(rest1)?;
|
||||||
|
println!("B");
|
||||||
|
let (_result3, rest3) = surrounding.parse(rest2)?;
|
||||||
|
println!("C");
|
||||||
|
Ok((result2, rest3))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn seq2<I, O1, O2, E>(
|
pub fn seq2<I, O1, O2, E>(
|
||||||
first: impl Parser<I, O1, E>,
|
first: impl Parser<I, O1, E>,
|
||||||
second: impl Parser<I, O2, E>,
|
second: impl Parser<I, O2, E>,
|
||||||
@ -32,3 +48,22 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<P1, P2, P3, I, O1, O2, O3, E> Sequence<I, (O1, O2, O3), E> for (P1, P2, P3)
|
||||||
|
where
|
||||||
|
P1: Parser<I, O1, E>,
|
||||||
|
P2: Parser<I, O2, E>,
|
||||||
|
P3: Parser<I, O3, E>,
|
||||||
|
{
|
||||||
|
fn parse(&self, input: I) -> ParseResult<I, (O1, O2, O3), E> {
|
||||||
|
let p1 = &self.0;
|
||||||
|
let p2 = &self.1;
|
||||||
|
let p3 = &self.2;
|
||||||
|
|
||||||
|
let (result1, rest1) = p1.parse(input)?;
|
||||||
|
let (result2, rest2) = p2.parse(rest1)?;
|
||||||
|
let (result3, rest3) = p3.parse(rest2)?;
|
||||||
|
|
||||||
|
Ok(((result1, result2, result3), rest3))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -67,4 +67,9 @@ fn test_repeated() {
|
|||||||
let output = parser.parse("bongo bongo bongo bongo");
|
let output = parser.parse("bongo bongo bongo bongo");
|
||||||
let output = output.unwrap();
|
let output = output.unwrap();
|
||||||
assert_eq!(output.0, vec!["bongo", "bongo", "bongo", "bongo"]);
|
assert_eq!(output.0, vec!["bongo", "bongo", "bongo", "bongo"]);
|
||||||
|
|
||||||
|
let bongos = repeated(literal("bongo"));
|
||||||
|
let output = bongos.parse("tra la la").unwrap();
|
||||||
|
assert_eq!(output.0.len(), 0);
|
||||||
|
assert_eq!(output.1, "tra la la");
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ fn test_parse_atom() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expr(input: &str) -> ParseResult<&str, Expr, ()> {
|
fn parse_expr(input: &str) -> ParseResult<&str, Expr, ()> {
|
||||||
|
println!("parse_expr: {input}");
|
||||||
choice((parse_list, parse_atom.map(Expr::Atom))).parse(input)
|
choice((parse_list, parse_atom.map(Expr::Atom))).parse(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,9 +61,17 @@ fn parse_list(input: &str) -> ParseResult<&str, Expr, ()> {
|
|||||||
)
|
)
|
||||||
.then_ignore(literal_char(')'))
|
.then_ignore(literal_char(')'))
|
||||||
.map(Expr::List)
|
.map(Expr::List)
|
||||||
|
.surrounded_by(repeated(whitespace))
|
||||||
.parse(input)
|
.parse(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_list() {
|
||||||
|
let output = parse_list.parse("\n(1 2 (1 2) 9999 3)").unwrap();
|
||||||
|
assert_eq!(output.1, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_sexp() {
|
fn test_parse_sexp() {
|
||||||
let output = parse_expr("(add 1 2)").unwrap();
|
let output = parse_expr("(add 1 2)").unwrap();
|
||||||
|
Loading…
Reference in New Issue
Block a user