//! Self-referential parser support through deferred construction. //! //! This module provides the [`Recursive`] wrapper that solves the circular //! dependency problem when building parsers that need to reference themselves //! directly or indirectly. Instead of constructing the parser immediately, //! it defers construction using a closure and caches the result. //! //! Recursive parsers are essential for parsing nested structures like //! arithmetic expressions, JSON objects, or any grammar with recursive //! production rules. use std::cell::OnceCell; use crate::{cache::ParsingCache, parser::Parser, result::ParseResult}; /// A wrapper that enables self-referential parsers by deferring construction. /// /// This solves the circular dependency problem where a parser needs to contain /// itself (directly or indirectly). Instead of creating the parser during /// construction, `Recursive

` creates it lazily on first use and caches it. /// /// # The Problem /// /// Self-referential parsers are common in language grammars but cause compilation issues: /// /// ```compile_fail /// // This won't compile - infinite type size! /// struct Expression { /// parenthesized: Expression, // ERROR: recursive without indirection /// } /// ``` /// /// # The Solution /// /// `Recursive

` breaks the cycle during construction while enabling unlimited recursion at parse time: /// /// ```rust /// use std::io::Cursor; /// use neotoma::{ /// recursive::Recursive, /// parser::{Parser, Source, parse}, /// literal::Literal, /// result::ParseResult, /// cache::ParsingCache /// }; /// /// // Example AST for expressions /// #[derive(Debug, PartialEq, Clone)] /// enum MyAst { /// Atom(String), /// Parenthesized(Box), /// } /// /// #[derive(Clone, Default)] /// struct Expression { /// // This compiles and works! /// parenthesized: Recursive, /// } /// /// impl Parser for Expression { /// type Output = MyAst; /// /// fn read( /// &self, /// source: &mut Source, /// cache: &mut impl ParsingCache, /// context: &mut () /// ) -> ParseResult /// where /// S: neotoma::parser::Parsable, /// { /// // Try to parse parentheses like: (inner_expression) /// let open_paren = Literal::from_str("("); /// if open_paren.parse(source, cache, context).is_ok() { /// // This creates unlimited recursion depth as needed /// let inner = self.parenthesized.parse(source, cache, context)?; /// let close_paren = Literal::from_str(")"); /// close_paren.parse(source, cache, context)?; /// Ok(MyAst::Parenthesized(Box::new(inner))) /// } else { /// // Parse a simple atom (single letter) /// let atom = Literal::from_str("x"); /// atom.parse(source, cache, context)?; /// Ok(MyAst::Atom("x".to_string())) /// } /// } /// } /// /// // Test it works with nested parentheses /// let parser = Expression::default(); /// let cursor = Cursor::new(b"((x))"); /// let mut source = Source::new(cursor); /// /// let result = parse(parser, &mut source).unwrap(); /// assert_eq!(result, MyAst::Parenthesized(Box::new( /// MyAst::Parenthesized(Box::new(MyAst::Atom("x".to_string()))) /// ))); /// ``` /// /// # How it works /// /// 1. **Construction**: `Recursive::new()` creates an empty wrapper (no cycles) /// 2. **First parse**: Creates the wrapped parser using `P::default()` and caches it /// 3. **Subsequent parses**: Reuses the same cached instance for efficiency /// /// This enables parsers that can handle arbitrarily deep nesting (like deeply nested parentheses) /// without construction-time infinite recursion. /// /// # Requirements /// /// The wrapped parser type `P` must implement `Default` so that `Recursive

` can create /// an instance when first needed. pub struct Recursive

{ cached_parser: OnceCell>, } impl

Recursive

where P: Default, { /// Creates a new `Recursive` wrapper that will construct the parser /// using `P::default()` on first use. /// /// The wrapped parser is created lazily - only when first needed during parsing. pub fn new() -> Self { Self { cached_parser: OnceCell::new(), } } /// Gets or creates the cached parser instance. fn get_parser(&self) -> &P { self.cached_parser.get_or_init(|| Box::new(P::default())) } } impl Parser for Recursive

where P: Parser + Default, { type Output = P::Output; fn read( &self, source: &mut crate::parser::Source, cache: &mut impl ParsingCache, context: &mut Ctx, ) -> ParseResult where S: crate::parser::Parsable, { // Delegate to the cached parser instance self.get_parser().read(source, cache, context) } fn id(&self) -> u64 { // Use the same cached instance for consistent ID self.get_parser().id() } } impl

Default for Recursive

{ fn default() -> Self { Self { cached_parser: OnceCell::new(), } } } // Implement Clone by creating a new empty Recursive // (we don't want to share the cached instance between clones) impl

Clone for Recursive

{ fn clone(&self) -> Self { Self::default() } } #[cfg(test)] mod tests { use super::*; use crate::{literal::Literal, parser::Source}; use std::io::Cursor; // Simple test parser that just parses "hello" #[derive(Clone)] struct HelloParser; impl Default for HelloParser { fn default() -> Self { Self } } impl Parser for HelloParser { type Output = String; fn read( &self, source: &mut Source, cache: &mut impl ParsingCache, context: &mut Ctx, ) -> ParseResult where S: crate::parser::Parsable, { let literal = Literal::from_str_const("hello"); literal .parse(source, cache, context) .map(|_| "hello".to_string()) } } #[test] fn recursive_parser_works() { use crate::parser::parse; let recursive = Recursive::::new(); let cursor = Cursor::new(b"hello"); let mut source = Source::new(cursor); let result = parse(recursive, &mut source); assert!(result.is_ok()); assert_eq!(result.unwrap(), "hello"); } #[test] fn recursive_parser_caches_instance() { let recursive = Recursive::::new(); // First access should create the parser let id1 = as crate::parser::Parser<()>>::id(&recursive); // Second access should use the same cached instance let id2 = as crate::parser::Parser<()>>::id(&recursive); assert_eq!(id1, id2, "IDs should be identical for cached instance"); } }