pub trait Combinator<I, S>: Parser<I, S>where
Self: Sized,{
Show 14 methods
// Provided methods
fn then<P: Parser<I, S>>(self, other: P) -> All<(Self, P)> { ... }
fn or<P: Parser<I, S>>(self, other: P) -> Any<(Self, P)>
where I: Clone { ... }
fn map<O, F: FnOnce(Self::O) -> O>(self, f: F) -> Map<Self, F> { ... }
fn map_with<O, F: FnOnce(Self::O, &mut S) -> O>(
self,
f: F,
) -> MapWith<Self, F> { ... }
fn filter<F: FnOnce(&Self::O) -> bool>(self, f: F) -> Filter<Self, F> { ... }
fn filter_map<O, F: FnOnce(Self::O) -> Option<O>>(
self,
f: F,
) -> FilterMap<Self, F> { ... }
fn then_ignore<P: Parser<I, S>>(
self,
other: P,
) -> Map<All<(Self, P)>, fn((<Self as Parser<I, S>>::O, <P as Parser<I, S>>::O)) -> Self::O> { ... }
fn ignore_then<P: Parser<I, S>>(
self,
other: P,
) -> Map<All<(Self, P)>, fn((<Self as Parser<I, S>>::O, <P as Parser<I, S>>::O)) -> P::O> { ... }
fn delimited_by<L, R>(
self,
l: L,
r: R,
) -> Map<All<(L, Self, R)>, fn((L::O, Self::O, R::O)) -> Self::O>
where L: Parser<I, S>,
R: Parser<I, S> { ... }
fn repeated<O>(self) -> Repeated<Self, fn() -> O>
where I: Clone,
Self: Clone,
O: Default + Extend<Self::O> { ... }
fn separated_by<Sep, O>(self, sep: Sep) -> SeparatedBy<Self, Sep, fn() -> O>
where I: Clone,
Self: Clone,
Sep: Parser<I, S> + Clone,
O: Default + Extend<Self::O> { ... }
fn opt(self) -> Opt<Self>
where I: Clone { ... }
fn chain<P>(
self,
other: P,
) -> Map<All<(Self, P)>, fn((<Self as Parser<I, S>>::O, <P as Parser<I, S>>::O)) -> Chain<<Self::O as IntoIterator>::IntoIter, <P::O as IntoIterator>::IntoIter>>
where P: Parser<I, S>,
Self::O: IntoIterator,
P::O: IntoIterator<Item = <Self::O as IntoIterator>::Item> { ... }
fn and_then<P: Parser<I, S>, F: FnOnce(Self::O) -> P>(
self,
f: F,
) -> AndThen<Self, F> { ... }
}
Expand description
A combinator combines parsers to form new ones.
Every Parser
implements the Combinator
trait.
To use the Combinator
trait, import it as follows:
use parcours::Combinator;
Provided Methods§
Sourcefn then<P: Parser<I, S>>(self, other: P) -> All<(Self, P)>
fn then<P: Parser<I, S>>(self, other: P) -> All<(Self, P)>
If both parsers yield an output, return the pair of their outputs.
The expression p0.then(p1)
is equivalent to all((p0, p1))
.
However, p0.then(p1).then(p2)
is equivalent to
all((all((p0, p1)), p2))
not
all((p0, p1, p2))
.
That means that if you chain together more than two parsers with then
,
things might get a bit messy, because you get nested tuples.
In that case, using all
directly is preferable.
Examples found in repository?
145fn atomic<'a>() -> impl Parser<&'a [Token], O = Expr> {
146 // succeed if the first element in the slice is the token `tk`
147 let eq = |tk| slice::first_filter(move |t, _| *t == tk);
148 // parentheses
149 let par = lazy!(expr).delimited_by(eq(Token::LPar), eq(Token::RPar));
150 // if the first token is a number, return a number expression, else fail
151 let num = slice::first_filter_map(select!(Token::Num(n) => Expr::Num(*n)));
152 let neg = slice::first_filter(|t, _| *t == Token::Op(Op::Sub));
153 let negs = neg.repeated::<Vec<_>>();
154 negs.then(par.or(num))
155 .map(|(negs, atom)| negs.iter().fold(atom, |acc, _x| Expr::Neg(Box::new(acc))))
156}
157
158/// Parse an expression from a token slice.
159///
160/// An expression is an atomic term followed by
161/// a (possibly empty) sequence of operator-atomic term pairs.
162///
163/// This uses precedence climbing to respect operator precedences.
164fn expr<'a>() -> impl Parser<&'a [Token], O = Expr> {
165 let op = slice::first_filter_map(select!(Token::Op(op) => *op));
166 atomic()
167 .then(op.then(lazy!(atomic)).repeated::<Vec<_>>())
168 // for precedence climbing to work, we have to implement
169 // a few traits for operators and expressions, see below
170 .map(|(head, tail)| prec_climb::climb(head, tail))
171}
More examples
147fn term<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> {
148 let vars = ident()
149 .repeated()
150 .delimited_by(token("|"), token("|").or(expected("identifier or |")));
151 let abst = vars.and_then(|vars: Vec<_>| {
152 // we parse a term with the bound variables put into the state
153 with_vars(vars.clone(), lazy!(term)).map(|t| (Term::Abst(vars, Box::new(t))))
154 });
155 let args = atomic().repeated::<Vec<_>>();
156 let appl = atomic().then(args).map(|(head, args)| {
157 if args.is_empty() {
158 head
159 } else {
160 Term::Appl(Box::new(head), args)
161 }
162 });
163 abst.or(appl).then_ignore(space()).or(expected("term"))
164}
87fn json<'a>() -> impl Parser<&'a str, O = JsonVal<&'a str>> {
88 let str = str().delimited_by(matches("\""), matches("\""));
89
90 let token = |s: &'a str| matches(s).then_ignore(space());
91 let arr = lazy!(json).separated_by(token(","));
92 let arr = arr.delimited_by(token("["), matches("]"));
93 let map = str.clone().then_ignore(token(":")).then(lazy!(json));
94 let map = map.separated_by(token(","));
95 let map = map.delimited_by(token("{"), matches("}"));
96
97 any((
98 arr.map(JsonVal::Arr),
99 map.map(JsonVal::Map),
100 str.map(JsonVal::Str),
101 num().map(JsonVal::Num),
102 matches("true").map(|_| JsonVal::True),
103 matches("false").map(|_| JsonVal::False),
104 matches("null").map(|_| JsonVal::Null),
105 ))
106 .then_ignore(space())
107}
Sourcefn or<P: Parser<I, S>>(self, other: P) -> Any<(Self, P)>where
I: Clone,
fn or<P: Parser<I, S>>(self, other: P) -> Any<(Self, P)>where
I: Clone,
If the first parser succeeds, return its output, otherwise return the output of the second parser.
The expression p0.or(p1)/*...*/.or(pn)
is equivalent to
any((p0, p1,/*..., */pn))
.
However, if more than two parsers are combined,
any
might yield better performance.
Examples found in repository?
145fn atomic<'a>() -> impl Parser<&'a [Token], O = Expr> {
146 // succeed if the first element in the slice is the token `tk`
147 let eq = |tk| slice::first_filter(move |t, _| *t == tk);
148 // parentheses
149 let par = lazy!(expr).delimited_by(eq(Token::LPar), eq(Token::RPar));
150 // if the first token is a number, return a number expression, else fail
151 let num = slice::first_filter_map(select!(Token::Num(n) => Expr::Num(*n)));
152 let neg = slice::first_filter(|t, _| *t == Token::Op(Op::Sub));
153 let negs = neg.repeated::<Vec<_>>();
154 negs.then(par.or(num))
155 .map(|(negs, atom)| negs.iter().fold(atom, |acc, _x| Expr::Neg(Box::new(acc))))
156}
More examples
115fn atomic<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> + Clone {
116 let var = ident().map_with(|v, state: &mut State<'a>| {
117 // find the de Bruijn index of the variable
118 let db = state.vars.iter().rev().position(|b| *b == v);
119 // if the variable was not bound, then record this as error, but then continue,
120 // because such errors are not fatal parsing errors
121 Term::Var(db.unwrap_or_else(|| {
122 state.errs.push(Error::UnboundVar(v));
123 0
124 }))
125 });
126 // here, we see error reporting in action:
127 // if a term that was opened with a parenthesis is not closed by a parenthesis,
128 // we store an error message and fail
129 var.or(lazy!(term).delimited_by(token("("), token(")").or(expected("closing parenthesis"))))
130}
131
132/// Extend the state with variables, parse with `p`, then remove the variables again.
133fn with_vars<'a, I, P>(vars: Vec<&'a str>, p: P) -> impl Parser<I, State<'a>, O = P::O>
134where
135 P: Parser<I, State<'a>>,
136{
137 from_fn(|input, state: &mut State<'a>| {
138 let vars_len = vars.len();
139 state.vars.extend(vars);
140 let y = p.parse(input, state);
141 state.vars.truncate(state.vars.len() - vars_len);
142 y
143 })
144}
145
146/// Parse a term.
147fn term<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> {
148 let vars = ident()
149 .repeated()
150 .delimited_by(token("|"), token("|").or(expected("identifier or |")));
151 let abst = vars.and_then(|vars: Vec<_>| {
152 // we parse a term with the bound variables put into the state
153 with_vars(vars.clone(), lazy!(term)).map(|t| (Term::Abst(vars, Box::new(t))))
154 });
155 let args = atomic().repeated::<Vec<_>>();
156 let appl = atomic().then(args).map(|(head, args)| {
157 if args.is_empty() {
158 head
159 } else {
160 Term::Appl(Box::new(head), args)
161 }
162 });
163 abst.or(appl).then_ignore(space()).or(expected("term"))
164}
Sourcefn map<O, F: FnOnce(Self::O) -> O>(self, f: F) -> Map<Self, F>
fn map<O, F: FnOnce(Self::O) -> O>(self, f: F) -> Map<Self, F>
Apply a function to the output of the parser.
Examples found in repository?
85fn token<'a>() -> impl Parser<&'a str, O = Token> + Clone {
86 // try to match a given binary operator and return it if it is present
87 let match_op = |op: Op| {
88 from_fn(move |input: &str, _| Some((Token::Op(op), input.strip_prefix(op.as_char())?)))
89 };
90 any((
91 // nonempty sequence of digits
92 str::take_while1(|c, _| c.is_ascii_digit()).map(|n| Token::Num(n.parse().unwrap())),
93 str::matches("(").map(|_| Token::LPar),
94 str::matches(")").map(|_| Token::RPar),
95 // for every operator, try to match it
96 any([Op::Add, Op::Sub, Op::Mul, Op::Div, Op::Exp].map(match_op)),
97 ))
98}
99
100/// Parse whitespace.
101fn space<'a>() -> impl Parser<&'a str, O = &'a str> + Clone {
102 str::take_while(|c, _| c.is_ascii_whitespace())
103}
104
105/// Lex.
106fn tokens<'a>() -> impl Parser<&'a str, O = Vec<Token>> + Clone {
107 space().ignore_then(token().then_ignore(space()).repeated())
108}
109
110// We are now done with the lexer.
111// Next up: the parser.
112
113/// Expression.
114#[derive(Debug)]
115enum Expr {
116 /// Number
117 Num(usize),
118 /// Negation
119 Neg(Box<Expr>),
120 /// Combination of two expressions with a binary operator
121 Comb(Box<Expr>, Op, Box<Expr>),
122}
123
124impl Expr {
125 /// Evaluate an expression.
126 fn eval(&self) -> isize {
127 match self {
128 Self::Num(n) => (*n).try_into().unwrap(),
129 Self::Neg(e) => -e.eval(),
130 Self::Comb(l, op, r) => op.eval(l.eval(), r.eval()),
131 }
132 }
133}
134
135/// Parse an atomic expression.
136///
137/// An atomic expression is a (possibly empty) sequence of negations,
138/// followed by a number or a parenthesised expression.
139///
140/// Where the lexer had `&str` as input type,
141/// the parser has the output of the lexer as input type, namely `&[Token]`.
142/// That means that we use
143/// `parcours::slice` functions here instead of
144/// `parcours::str` functions.
145fn atomic<'a>() -> impl Parser<&'a [Token], O = Expr> {
146 // succeed if the first element in the slice is the token `tk`
147 let eq = |tk| slice::first_filter(move |t, _| *t == tk);
148 // parentheses
149 let par = lazy!(expr).delimited_by(eq(Token::LPar), eq(Token::RPar));
150 // if the first token is a number, return a number expression, else fail
151 let num = slice::first_filter_map(select!(Token::Num(n) => Expr::Num(*n)));
152 let neg = slice::first_filter(|t, _| *t == Token::Op(Op::Sub));
153 let negs = neg.repeated::<Vec<_>>();
154 negs.then(par.or(num))
155 .map(|(negs, atom)| negs.iter().fold(atom, |acc, _x| Expr::Neg(Box::new(acc))))
156}
157
158/// Parse an expression from a token slice.
159///
160/// An expression is an atomic term followed by
161/// a (possibly empty) sequence of operator-atomic term pairs.
162///
163/// This uses precedence climbing to respect operator precedences.
164fn expr<'a>() -> impl Parser<&'a [Token], O = Expr> {
165 let op = slice::first_filter_map(select!(Token::Op(op) => *op));
166 atomic()
167 .then(op.then(lazy!(atomic)).repeated::<Vec<_>>())
168 // for precedence climbing to work, we have to implement
169 // a few traits for operators and expressions, see below
170 .map(|(head, tail)| prec_climb::climb(head, tail))
171}
More examples
147fn term<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> {
148 let vars = ident()
149 .repeated()
150 .delimited_by(token("|"), token("|").or(expected("identifier or |")));
151 let abst = vars.and_then(|vars: Vec<_>| {
152 // we parse a term with the bound variables put into the state
153 with_vars(vars.clone(), lazy!(term)).map(|t| (Term::Abst(vars, Box::new(t))))
154 });
155 let args = atomic().repeated::<Vec<_>>();
156 let appl = atomic().then(args).map(|(head, args)| {
157 if args.is_empty() {
158 head
159 } else {
160 Term::Appl(Box::new(head), args)
161 }
162 });
163 abst.or(appl).then_ignore(space()).or(expected("term"))
164}
87fn json<'a>() -> impl Parser<&'a str, O = JsonVal<&'a str>> {
88 let str = str().delimited_by(matches("\""), matches("\""));
89
90 let token = |s: &'a str| matches(s).then_ignore(space());
91 let arr = lazy!(json).separated_by(token(","));
92 let arr = arr.delimited_by(token("["), matches("]"));
93 let map = str.clone().then_ignore(token(":")).then(lazy!(json));
94 let map = map.separated_by(token(","));
95 let map = map.delimited_by(token("{"), matches("}"));
96
97 any((
98 arr.map(JsonVal::Arr),
99 map.map(JsonVal::Map),
100 str.map(JsonVal::Str),
101 num().map(JsonVal::Num),
102 matches("true").map(|_| JsonVal::True),
103 matches("false").map(|_| JsonVal::False),
104 matches("null").map(|_| JsonVal::Null),
105 ))
106 .then_ignore(space())
107}
Sourcefn map_with<O, F: FnOnce(Self::O, &mut S) -> O>(self, f: F) -> MapWith<Self, F>
fn map_with<O, F: FnOnce(Self::O, &mut S) -> O>(self, f: F) -> MapWith<Self, F>
Apply a function to the output of the parser as well as the mutable state.
Examples found in repository?
115fn atomic<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> + Clone {
116 let var = ident().map_with(|v, state: &mut State<'a>| {
117 // find the de Bruijn index of the variable
118 let db = state.vars.iter().rev().position(|b| *b == v);
119 // if the variable was not bound, then record this as error, but then continue,
120 // because such errors are not fatal parsing errors
121 Term::Var(db.unwrap_or_else(|| {
122 state.errs.push(Error::UnboundVar(v));
123 0
124 }))
125 });
126 // here, we see error reporting in action:
127 // if a term that was opened with a parenthesis is not closed by a parenthesis,
128 // we store an error message and fail
129 var.or(lazy!(term).delimited_by(token("("), token(")").or(expected("closing parenthesis"))))
130}
Sourcefn filter<F: FnOnce(&Self::O) -> bool>(self, f: F) -> Filter<Self, F>
fn filter<F: FnOnce(&Self::O) -> bool>(self, f: F) -> Filter<Self, F>
Succeed only if the given function yields true
for the parser output.
Examples found in repository?
More examples
36fn num<'a, S>() -> impl Parser<&'a str, S, O = &'a str> + Clone {
37 // are we reading the first character?
38 let mut first = true;
39 // have we encountered no dot so far?
40 let mut no_dot = true;
41 // have we encountered no exponent character ('e' or 'E') so far?
42 let mut no_exp = true;
43 take_while(move |c, _| match c {
44 b'0'..=b'9' => {
45 first = false;
46 true
47 }
48 b'-' if first => core::mem::replace(&mut first, false),
49 b'.' if !first && no_dot && no_exp => core::mem::replace(&mut no_dot, false),
50 b'e' | b'E' if !first && no_exp => core::mem::replace(&mut no_exp, false),
51 _ => false,
52 })
53 // the last character of a number must always be a digit
54 .filter(|s| match s.bytes().last() {
55 Some(c) => c.is_ascii_digit(),
56 _ => false,
57 })
58}
Sourcefn filter_map<O, F: FnOnce(Self::O) -> Option<O>>(
self,
f: F,
) -> FilterMap<Self, F>
fn filter_map<O, F: FnOnce(Self::O) -> Option<O>>( self, f: F, ) -> FilterMap<Self, F>
If the given function yields Some(y)
for the parser output, succeed with y
, else fail.
Sourcefn then_ignore<P: Parser<I, S>>(
self,
other: P,
) -> Map<All<(Self, P)>, fn((<Self as Parser<I, S>>::O, <P as Parser<I, S>>::O)) -> Self::O>
fn then_ignore<P: Parser<I, S>>( self, other: P, ) -> Map<All<(Self, P)>, fn((<Self as Parser<I, S>>::O, <P as Parser<I, S>>::O)) -> Self::O>
Run two parsers in sequence and discard result of second one.
Examples found in repository?
More examples
84fn ident<'a, S>() -> impl Parser<&'a str, S, O = &'a str> + Clone {
85 let pn = |c: &u8, _: &mut S| !c.is_ascii() || c.is_ascii_alphanumeric();
86 let p0 = |c: char| !c.is_ascii_digit();
87 take_while(pn)
88 .filter(move |s| s.chars().next().map(p0).unwrap_or(false))
89 .then_ignore(space())
90}
91
92/// Parse the given string, potentially followed by whitespace.
93fn token<S>(x: &str) -> impl Parser<&str, S, O = ()> + Clone {
94 matches(x).then_ignore(space())
95}
96
97/// Store the given error `s` if no other error was stored before, then fail.
98///
99/// Here, we use `from_fn` to implement some custom parsing logic
100/// that we cannot express with the normal parser combinators in parcours,
101/// in particular because we access and modify the state here.
102/// Alternatively, we could also implement the `Parser` trait manually,
103/// but this is more verbose than `from_fn`.
104///
105/// We only store an error if no other error was stored before.
106/// This is to prevent cascading errors which might be more confusing than helpful.
107fn expected<'a, O>(s: &'static str) -> impl Parser<&'a str, State<'a>, O = O> + Clone {
108 from_fn(move |input, state: &mut State| {
109 state.expected.get_or_insert((s, input));
110 None
111 })
112}
113
114/// Parse an atomic term, namely either a variable or a term enclosed by parentheses.
115fn atomic<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> + Clone {
116 let var = ident().map_with(|v, state: &mut State<'a>| {
117 // find the de Bruijn index of the variable
118 let db = state.vars.iter().rev().position(|b| *b == v);
119 // if the variable was not bound, then record this as error, but then continue,
120 // because such errors are not fatal parsing errors
121 Term::Var(db.unwrap_or_else(|| {
122 state.errs.push(Error::UnboundVar(v));
123 0
124 }))
125 });
126 // here, we see error reporting in action:
127 // if a term that was opened with a parenthesis is not closed by a parenthesis,
128 // we store an error message and fail
129 var.or(lazy!(term).delimited_by(token("("), token(")").or(expected("closing parenthesis"))))
130}
131
132/// Extend the state with variables, parse with `p`, then remove the variables again.
133fn with_vars<'a, I, P>(vars: Vec<&'a str>, p: P) -> impl Parser<I, State<'a>, O = P::O>
134where
135 P: Parser<I, State<'a>>,
136{
137 from_fn(|input, state: &mut State<'a>| {
138 let vars_len = vars.len();
139 state.vars.extend(vars);
140 let y = p.parse(input, state);
141 state.vars.truncate(state.vars.len() - vars_len);
142 y
143 })
144}
145
146/// Parse a term.
147fn term<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> {
148 let vars = ident()
149 .repeated()
150 .delimited_by(token("|"), token("|").or(expected("identifier or |")));
151 let abst = vars.and_then(|vars: Vec<_>| {
152 // we parse a term with the bound variables put into the state
153 with_vars(vars.clone(), lazy!(term)).map(|t| (Term::Abst(vars, Box::new(t))))
154 });
155 let args = atomic().repeated::<Vec<_>>();
156 let appl = atomic().then(args).map(|(head, args)| {
157 if args.is_empty() {
158 head
159 } else {
160 Term::Appl(Box::new(head), args)
161 }
162 });
163 abst.or(appl).then_ignore(space()).or(expected("term"))
164}
87fn json<'a>() -> impl Parser<&'a str, O = JsonVal<&'a str>> {
88 let str = str().delimited_by(matches("\""), matches("\""));
89
90 let token = |s: &'a str| matches(s).then_ignore(space());
91 let arr = lazy!(json).separated_by(token(","));
92 let arr = arr.delimited_by(token("["), matches("]"));
93 let map = str.clone().then_ignore(token(":")).then(lazy!(json));
94 let map = map.separated_by(token(","));
95 let map = map.delimited_by(token("{"), matches("}"));
96
97 any((
98 arr.map(JsonVal::Arr),
99 map.map(JsonVal::Map),
100 str.map(JsonVal::Str),
101 num().map(JsonVal::Num),
102 matches("true").map(|_| JsonVal::True),
103 matches("false").map(|_| JsonVal::False),
104 matches("null").map(|_| JsonVal::Null),
105 ))
106 .then_ignore(space())
107}
Sourcefn ignore_then<P: Parser<I, S>>(
self,
other: P,
) -> Map<All<(Self, P)>, fn((<Self as Parser<I, S>>::O, <P as Parser<I, S>>::O)) -> P::O>
fn ignore_then<P: Parser<I, S>>( self, other: P, ) -> Map<All<(Self, P)>, fn((<Self as Parser<I, S>>::O, <P as Parser<I, S>>::O)) -> P::O>
Run two parsers in sequence and discard result of first one.
Examples found in repository?
More examples
123fn main() -> std::io::Result<()> {
124 /*
125 let bla = "y̆es";
126 let input = r#"[[1,true , "bla" , 1 , [] ]] []2"#;
127 */
128
129 // read from file if one is provided as argument, else from standard input
130 let mut args = std::env::args();
131 args.next();
132 let input = match args.next() {
133 Some(arg) => std::fs::read_to_string(arg)?,
134 None => std::io::read_to_string(std::io::stdin())?,
135 };
136
137 //let input = many(r#"{"key": 12345}"#, 10_000_000);
138 //println!("{}", input.len());
139
140 // we first have to strip away any space, because that's what the parser expects
141 let out = space().ignore_then(json()).parse(&input, &mut ());
142 println!("Parsed JSON: {:?}", out);
143 Ok(())
144}
Sourcefn delimited_by<L, R>(
self,
l: L,
r: R,
) -> Map<All<(L, Self, R)>, fn((L::O, Self::O, R::O)) -> Self::O>
fn delimited_by<L, R>( self, l: L, r: R, ) -> Map<All<(L, Self, R)>, fn((L::O, Self::O, R::O)) -> Self::O>
Run parsers l
, self
, and r
in sequence and return only the output of self
.
Examples found in repository?
145fn atomic<'a>() -> impl Parser<&'a [Token], O = Expr> {
146 // succeed if the first element in the slice is the token `tk`
147 let eq = |tk| slice::first_filter(move |t, _| *t == tk);
148 // parentheses
149 let par = lazy!(expr).delimited_by(eq(Token::LPar), eq(Token::RPar));
150 // if the first token is a number, return a number expression, else fail
151 let num = slice::first_filter_map(select!(Token::Num(n) => Expr::Num(*n)));
152 let neg = slice::first_filter(|t, _| *t == Token::Op(Op::Sub));
153 let negs = neg.repeated::<Vec<_>>();
154 negs.then(par.or(num))
155 .map(|(negs, atom)| negs.iter().fold(atom, |acc, _x| Expr::Neg(Box::new(acc))))
156}
More examples
87fn json<'a>() -> impl Parser<&'a str, O = JsonVal<&'a str>> {
88 let str = str().delimited_by(matches("\""), matches("\""));
89
90 let token = |s: &'a str| matches(s).then_ignore(space());
91 let arr = lazy!(json).separated_by(token(","));
92 let arr = arr.delimited_by(token("["), matches("]"));
93 let map = str.clone().then_ignore(token(":")).then(lazy!(json));
94 let map = map.separated_by(token(","));
95 let map = map.delimited_by(token("{"), matches("}"));
96
97 any((
98 arr.map(JsonVal::Arr),
99 map.map(JsonVal::Map),
100 str.map(JsonVal::Str),
101 num().map(JsonVal::Num),
102 matches("true").map(|_| JsonVal::True),
103 matches("false").map(|_| JsonVal::False),
104 matches("null").map(|_| JsonVal::Null),
105 ))
106 .then_ignore(space())
107}
115fn atomic<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> + Clone {
116 let var = ident().map_with(|v, state: &mut State<'a>| {
117 // find the de Bruijn index of the variable
118 let db = state.vars.iter().rev().position(|b| *b == v);
119 // if the variable was not bound, then record this as error, but then continue,
120 // because such errors are not fatal parsing errors
121 Term::Var(db.unwrap_or_else(|| {
122 state.errs.push(Error::UnboundVar(v));
123 0
124 }))
125 });
126 // here, we see error reporting in action:
127 // if a term that was opened with a parenthesis is not closed by a parenthesis,
128 // we store an error message and fail
129 var.or(lazy!(term).delimited_by(token("("), token(")").or(expected("closing parenthesis"))))
130}
131
132/// Extend the state with variables, parse with `p`, then remove the variables again.
133fn with_vars<'a, I, P>(vars: Vec<&'a str>, p: P) -> impl Parser<I, State<'a>, O = P::O>
134where
135 P: Parser<I, State<'a>>,
136{
137 from_fn(|input, state: &mut State<'a>| {
138 let vars_len = vars.len();
139 state.vars.extend(vars);
140 let y = p.parse(input, state);
141 state.vars.truncate(state.vars.len() - vars_len);
142 y
143 })
144}
145
146/// Parse a term.
147fn term<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> {
148 let vars = ident()
149 .repeated()
150 .delimited_by(token("|"), token("|").or(expected("identifier or |")));
151 let abst = vars.and_then(|vars: Vec<_>| {
152 // we parse a term with the bound variables put into the state
153 with_vars(vars.clone(), lazy!(term)).map(|t| (Term::Abst(vars, Box::new(t))))
154 });
155 let args = atomic().repeated::<Vec<_>>();
156 let appl = atomic().then(args).map(|(head, args)| {
157 if args.is_empty() {
158 head
159 } else {
160 Term::Appl(Box::new(head), args)
161 }
162 });
163 abst.or(appl).then_ignore(space()).or(expected("term"))
164}
Sourcefn repeated<O>(self) -> Repeated<Self, fn() -> O>
fn repeated<O>(self) -> Repeated<Self, fn() -> O>
Apply the given parser as often as possible.
This collect the outputs of the parser into the type O
.
If you do not want to allocate, you can use ()
as O
.
Examples found in repository?
106fn tokens<'a>() -> impl Parser<&'a str, O = Vec<Token>> + Clone {
107 space().ignore_then(token().then_ignore(space()).repeated())
108}
109
110// We are now done with the lexer.
111// Next up: the parser.
112
113/// Expression.
114#[derive(Debug)]
115enum Expr {
116 /// Number
117 Num(usize),
118 /// Negation
119 Neg(Box<Expr>),
120 /// Combination of two expressions with a binary operator
121 Comb(Box<Expr>, Op, Box<Expr>),
122}
123
124impl Expr {
125 /// Evaluate an expression.
126 fn eval(&self) -> isize {
127 match self {
128 Self::Num(n) => (*n).try_into().unwrap(),
129 Self::Neg(e) => -e.eval(),
130 Self::Comb(l, op, r) => op.eval(l.eval(), r.eval()),
131 }
132 }
133}
134
135/// Parse an atomic expression.
136///
137/// An atomic expression is a (possibly empty) sequence of negations,
138/// followed by a number or a parenthesised expression.
139///
140/// Where the lexer had `&str` as input type,
141/// the parser has the output of the lexer as input type, namely `&[Token]`.
142/// That means that we use
143/// `parcours::slice` functions here instead of
144/// `parcours::str` functions.
145fn atomic<'a>() -> impl Parser<&'a [Token], O = Expr> {
146 // succeed if the first element in the slice is the token `tk`
147 let eq = |tk| slice::first_filter(move |t, _| *t == tk);
148 // parentheses
149 let par = lazy!(expr).delimited_by(eq(Token::LPar), eq(Token::RPar));
150 // if the first token is a number, return a number expression, else fail
151 let num = slice::first_filter_map(select!(Token::Num(n) => Expr::Num(*n)));
152 let neg = slice::first_filter(|t, _| *t == Token::Op(Op::Sub));
153 let negs = neg.repeated::<Vec<_>>();
154 negs.then(par.or(num))
155 .map(|(negs, atom)| negs.iter().fold(atom, |acc, _x| Expr::Neg(Box::new(acc))))
156}
157
158/// Parse an expression from a token slice.
159///
160/// An expression is an atomic term followed by
161/// a (possibly empty) sequence of operator-atomic term pairs.
162///
163/// This uses precedence climbing to respect operator precedences.
164fn expr<'a>() -> impl Parser<&'a [Token], O = Expr> {
165 let op = slice::first_filter_map(select!(Token::Op(op) => *op));
166 atomic()
167 .then(op.then(lazy!(atomic)).repeated::<Vec<_>>())
168 // for precedence climbing to work, we have to implement
169 // a few traits for operators and expressions, see below
170 .map(|(head, tail)| prec_climb::climb(head, tail))
171}
More examples
147fn term<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> {
148 let vars = ident()
149 .repeated()
150 .delimited_by(token("|"), token("|").or(expected("identifier or |")));
151 let abst = vars.and_then(|vars: Vec<_>| {
152 // we parse a term with the bound variables put into the state
153 with_vars(vars.clone(), lazy!(term)).map(|t| (Term::Abst(vars, Box::new(t))))
154 });
155 let args = atomic().repeated::<Vec<_>>();
156 let appl = atomic().then(args).map(|(head, args)| {
157 if args.is_empty() {
158 head
159 } else {
160 Term::Appl(Box::new(head), args)
161 }
162 });
163 abst.or(appl).then_ignore(space()).or(expected("term"))
164}
Sourcefn separated_by<Sep, O>(self, sep: Sep) -> SeparatedBy<Self, Sep, fn() -> O>
fn separated_by<Sep, O>(self, sep: Sep) -> SeparatedBy<Self, Sep, fn() -> O>
Apply the given parser as often as possible, separated by sep
.
a.separated_by(b)
corresponds to the regular expression (a(ba)*)?
.
The output of this parser is the collection of the outputs of a
;
that is, the outputs of b
are discarded.
Trailing b
s are not consumed; for this, use
a.separated_by(b).then_ignore(b.opt())
.
To keep the outputs of b
and demand at least one match of a
,
you may use a.then(b.then(a).repeated())
instead.
Examples found in repository?
87fn json<'a>() -> impl Parser<&'a str, O = JsonVal<&'a str>> {
88 let str = str().delimited_by(matches("\""), matches("\""));
89
90 let token = |s: &'a str| matches(s).then_ignore(space());
91 let arr = lazy!(json).separated_by(token(","));
92 let arr = arr.delimited_by(token("["), matches("]"));
93 let map = str.clone().then_ignore(token(":")).then(lazy!(json));
94 let map = map.separated_by(token(","));
95 let map = map.delimited_by(token("{"), matches("}"));
96
97 any((
98 arr.map(JsonVal::Arr),
99 map.map(JsonVal::Map),
100 str.map(JsonVal::Str),
101 num().map(JsonVal::Num),
102 matches("true").map(|_| JsonVal::True),
103 matches("false").map(|_| JsonVal::False),
104 matches("null").map(|_| JsonVal::Null),
105 ))
106 .then_ignore(space())
107}
Sourcefn opt(self) -> Opt<Self>where
I: Clone,
fn opt(self) -> Opt<Self>where
I: Clone,
If the given parser succeeds, wrap its output in Some
, else return None
.
The resulting parser always succeeds.
Sourcefn chain<P>(
self,
other: P,
) -> Map<All<(Self, P)>, fn((<Self as Parser<I, S>>::O, <P as Parser<I, S>>::O)) -> Chain<<Self::O as IntoIterator>::IntoIter, <P::O as IntoIterator>::IntoIter>>where
P: Parser<I, S>,
Self::O: IntoIterator,
P::O: IntoIterator<Item = <Self::O as IntoIterator>::Item>,
fn chain<P>(
self,
other: P,
) -> Map<All<(Self, P)>, fn((<Self as Parser<I, S>>::O, <P as Parser<I, S>>::O)) -> Chain<<Self::O as IntoIterator>::IntoIter, <P::O as IntoIterator>::IntoIter>>where
P: Parser<I, S>,
Self::O: IntoIterator,
P::O: IntoIterator<Item = <Self::O as IntoIterator>::Item>,
Convert the outputs of the given parsers to iterators and concatenate them.
use parcours::{Parser, Combinator, str::take_while1};
let digit = take_while1(|c, _| c.is_ascii_digit());
let alpha = take_while1(|c, _| c.is_ascii_alphabetic());
let both = digit.opt().chain(alpha.opt()).map(|i| i.collect());
assert_eq!(both.parse("123abc", &mut ()), Some((vec!["123", "abc"], "")))
Sourcefn and_then<P: Parser<I, S>, F: FnOnce(Self::O) -> P>(
self,
f: F,
) -> AndThen<Self, F>
fn and_then<P: Parser<I, S>, F: FnOnce(Self::O) -> P>( self, f: F, ) -> AndThen<Self, F>
Run the first parser, then create a second parser from its output and run it.
Examples found in repository?
147fn term<'a>() -> impl Parser<&'a str, State<'a>, O = Term<'a>> {
148 let vars = ident()
149 .repeated()
150 .delimited_by(token("|"), token("|").or(expected("identifier or |")));
151 let abst = vars.and_then(|vars: Vec<_>| {
152 // we parse a term with the bound variables put into the state
153 with_vars(vars.clone(), lazy!(term)).map(|t| (Term::Abst(vars, Box::new(t))))
154 });
155 let args = atomic().repeated::<Vec<_>>();
156 let appl = atomic().then(args).map(|(head, args)| {
157 if args.is_empty() {
158 head
159 } else {
160 Term::Appl(Box::new(head), args)
161 }
162 });
163 abst.or(appl).then_ignore(space()).or(expected("term"))
164}
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.