pub fn recursive<'a, K, O, F>(f: F) -> PRecursive<'a, K, O>where
K: PartialEq + 'a,
O: 'a,
F: FnOnce(PRecursive<'a, K, O>) -> Box<dyn ParserCore<'a, K, O> + 'a>,Expand description
Creates a new recursive parser by providing a function f that
receives a PRecursive instance and returns the actual parser implementation.
§Type Parameters
'a- Lifetime of the input tokens.K- The token type.O- The output type of the parser.F- A function that takes a recursive parser and returns a boxed parser.
§Arguments
f- A function that receives the recursive parser handle and returns a boxed parser that can recursively call itself.
§Returns
A PRecursive instance implementing ParserCore, which supports
recursive parsing by delegating to the parser created inside f.
§Example
use cypress::prelude::*;
let input = b"(1+(2+3))".into_input();
#[derive(Debug, PartialEq, Clone)]
enum AST {
Num(u32),
Expr(Box<AST>, Box<AST>),
}
let parser = recursive(|expr| {
Box::new(choice!(
pnum().map(|a: u8| AST::Num((a - b'0').into())),
just('(')
.then(expr.clone())
.then(just('+').then(expr))
.then(just(')'))
.map(|(((_, lhs), (_, rhs)), _)| AST::Expr(Box::new(lhs), Box::new(rhs)))
))
});
match parser.parse(input) {
Ok(PSuccess { val, rest: _ }) => assert_eq!(
val,
AST::Expr(
Box::new(AST::Num(1)),
Box::new(AST::Expr(Box::new(AST::Num(2)), Box::new(AST::Num(3))))
)
),
Err(_) => assert!(false),
}Examples found in repository?
examples/foo.rs (lines 90-101)
89fn expr<'a>() -> impl Parser<'a, u8, Expr> {
90 recursive(|expr| {
91 Box::new(
92 choice!(
93 var_assignment(expr.clone()),
94 print(expr),
95 ident().map(Expr::Var),
96 str_().map(Expr::Str),
97 num().map(Expr::Num)
98 )
99 .map(|expr| expr),
100 )
101 })
102}More examples
examples/brainfuck.rs (lines 25-43)
24fn main() {
25 let parser = recursive(|expr| {
26 // Parser for a single instruction (not the whole program)
27 let instr = choice!(
28 select! {
29 '<' => Instruction::Left,
30 '>' => Instruction::Right,
31 '+' => Instruction::Increment,
32 '-' => Instruction::Decrement,
33 ',' => Instruction::Read,
34 '.' => Instruction::Write,
35 },
36 // Now inside Loop, parse *many instructions* again — not the full `expr`
37 expr.many()
38 .between(just('['), just(']'))
39 .map(Instruction::Loop)
40 );
41
42 Box::new(instr)
43 })
44 .many()
45 .until_end();
46
47 let input = b"+++++[>>+<<-]".into_input();
48
49 let expected_bf = vec![
50 Instruction::Increment,
51 Instruction::Increment,
52 Instruction::Increment,
53 Instruction::Increment,
54 Instruction::Increment,
55 Instruction::Loop(vec![
56 Instruction::Right,
57 Instruction::Right,
58 Instruction::Increment,
59 Instruction::Left,
60 Instruction::Left,
61 Instruction::Decrement,
62 ]),
63 ];
64
65 match parser.parse(input) {
66 Ok(PSuccess {
67 val: actual_bf,
68 rest: _,
69 }) => {
70 println!("{:?}", actual_bf);
71 assert_eq!(actual_bf, expected_bf)
72 }
73 Err(e) => println!("{}", e),
74 }
75}examples/control.rs (lines 221-287)
220fn statement_parser<'a>() -> impl Parser<'a, u8, Statement> {
221 recursive(|stmt| {
222 let let_ = (pident("let").padded_by(pinlinews()))
223 .then(
224 choice!(pletter(), just('_'))
225 .many1()
226 .map(|xs| String::from_utf8(xs).unwrap()),
227 )
228 .padded_by(pinlinews())
229 .then(just('=').padded_by(pinlinews()).then(expr_parser()))
230 .map(|((_, name), (_, expr))| Statement::Let(name, expr));
231
232 let letless = choice!(pletter(), just('_'))
233 .many1()
234 .map(|xs| String::from_utf8(xs).unwrap())
235 .then(just('=').padded_by(pinlinews()))
236 .then(expr_parser())
237 .map(|((name, _), expr)| Statement::Let(name, expr));
238
239 let while_ = pident("while")
240 .then(expr_parser().padded_by(pinlinews()))
241 .then(pbetween(
242 just('{').padded_by(pws()),
243 (stmt.clone().padded_by(pinlinews()))
244 .delimited_by(just('\n').many())
245 .padded_by(pinlinews()),
246 just('}').padded_by(pws()),
247 ))
248 .map(|((_, cond), stmts)| Statement::While(cond, stmts));
249
250 let if_ = pident("if")
251 .then(expr_parser().padded_by(pinlinews()))
252 .then(pbetween(
253 just('{').padded_by(pws()),
254 (stmt.clone().padded_by(pinlinews()))
255 .delimited_by(just('\n').many())
256 .padded_by(pinlinews()),
257 just('}').padded_by(pws()),
258 ))
259 .map(|((_, cond), stmts)| Statement::If(cond, stmts, vec![]));
260
261 let if_else_ = pident("if")
262 .then(expr_parser().padded_by(pinlinews()))
263 .then(pbetween(
264 just('{').padded_by(pws()),
265 (stmt.clone().padded_by(pinlinews()))
266 .delimited_by(just('\n').many())
267 .padded_by(pinlinews()),
268 just('}').padded_by(pws()),
269 ))
270 .then(pident("else"))
271 .then(pbetween(
272 just('{').padded_by(pws()),
273 (stmt.clone().padded_by(pinlinews()))
274 .delimited_by(just('\n').many())
275 .padded_by(pinlinews()),
276 just('}').padded_by(pws()),
277 ))
278 .map(|((((_, cond), if_stmts), _), else_stmts)| {
279 Statement::If(cond, if_stmts, else_stmts)
280 });
281
282 let print_ = pident("print")
283 .then(pbetween(just('('), expr_parser(), just(')')))
284 .map(|(_, expr)| Statement::Print(expr));
285
286 Box::new(choice!(let_, letless, while_, if_else_, if_, print_))
287 })
288}