//! 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 ` can create
/// an instance when first needed.
pub struct Recursive {
cached_parser: OnceCell 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
where
P: Parser 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(
/// &self,
/// source: &mut Source,
/// cache: &mut impl ParsingCache,
/// context: &mut ()
/// ) -> ParseResult(
&self,
source: &mut crate::parser::Source,
cache: &mut impl ParsingCache,
context: &mut Ctx,
) -> ParseResult(
&self,
source: &mut Source,
cache: &mut impl ParsingCache,
context: &mut Ctx,
) -> ParseResult