//! # Neotoma - Flexible Parser Combinator Library //! //! Neotoma is a Rust parsing library that provides a flexible, cached parser combinator framework. //! It's designed to parse structured data from any source implementing `Read + Seek` traits, with //! built-in memoization and backtracking capabilities. //! //! ## Key Features //! //! - **Composable parsers**: Build complex parsers from simple building blocks //! - **Automatic memoization**: Built-in caching prevents redundant parsing work //! - **Backtracking support**: Automatic position management for failed parses //! - **UTF-8 aware**: Comprehensive Unicode handling with ASCII optimization //! - **Thread-safe**: Uses efficient synchronization primitives from `parking_lot` //! - **Generic input**: Works with any `Read + Seek` source //! //! ## Quick Start //! //! ```rust //! use neotoma::prelude::*; //! use neotoma::{seq, oneof}; //! use std::io::Cursor; //! //! // Build a parser for "hello" followed by optional whitespace and "world" //! let parser = seq![ //! Literal::from_str("hello"), //! Optional::new(Utf8Class::whitespace()), //! Literal::from_str("world") //! ]; //! //! let input = Cursor::new(b"hello world"); //! let mut source = Source::new(input); //! //! let result = parse(parser, &mut source); //! assert!(result.is_ok()); //! ``` //! //! ## Core Concepts //! //! ### Parser Trait //! All parsers implement the [`Parser`] trait, which provides: //! - `read()`: Implement your parsing logic here //! - `parse()`: Public API that handles caching and backtracking automatically //! - `id()`: Must be overridden for parameterized parsers to avoid cache conflicts //! //! ### Composition //! Build complex parsers using composition macros: //! - [`seq!`] for sequential parsing //! - [`oneof!`] for alternative choices //! //! ### Common Parser Types //! - [`Literal`]: Match exact byte sequences or strings //! - [`Class`]: Match character classes (byte-level) //! - [`Utf8Class`]: Match Unicode character classes //! - [`Repeat`]: Match repeated patterns with optional separators //! - [`Optional`]: Match zero or one occurrence //! //! ## Architecture //! //! The library uses a **Template Method Pattern** for the Parser trait, where `parse()` //! handles caching and backtracking, while implementations provide custom logic in `read()`. //! The caching system uses a **Strategy Pattern** allowing different cache implementations. pub mod cache; pub mod class; pub mod either; pub mod eof; pub mod grammar; pub mod literal; pub mod optional; pub mod parser; pub mod recursive; pub mod repeat; pub mod result; pub mod sequence; pub mod until; pub mod utf8class; pub mod utf8util; // Re-export the most commonly used types and functions at the root level // for better ergonomics // Core parser trait and utilities pub use parser::{Parser, Source, parse}; // Common result types pub use result::{Error, ParseResult}; // Main parser types (used in almost every parser combination) pub use class::Class; pub use literal::Literal; pub use utf8class::Utf8Class; // Common combinators pub use eof::EndOfFile; pub use optional::Optional; pub use recursive::Recursive; pub use repeat::Repeat; // Grammar parsing with named rules and recursion pub use grammar::GrammarParser; // Composition macros are already exported at crate root via #[macro_export] // seq! and oneof! are available directly // Prelude module for glob imports pub mod prelude { //! Commonly used imports for parser development //! //! # Example //! //! ```rust //! use neotoma::prelude::*; //! use neotoma::{seq, oneof}; // Macros are at crate root //! //! // Now you have access to all the commonly used types //! let parser = seq![ //! Literal::from_str("hello"), //! Optional::new(Utf8Class::whitespace()), //! Literal::from_str("world") //! ]; //! ``` pub use crate::{ Class, // Combinators EndOfFile, Error, // Grammar parsing GrammarParser, // Main parser types Literal, Optional, ParseResult, // Core traits and functions Parser, Recursive, Repeat, Source, Utf8Class, // Composition macros (re-exported from crate root) // Note: seq! and oneof! macros are available directly, not as paths // Cache trait for implementing custom parsers cache::ParsingCache, parse, }; } #[cfg(test)] mod tests { use super::*; use std::io::Cursor; // Tests moved from tests/test_root_exports.rs #[test] fn test_root_level_exports_basic() { // Test that we can use the types directly from root let literal = Literal::from_str("test"); let cursor = Cursor::new(b"test"); let mut source = Source::new(cursor); let result = parse(literal, &mut source); assert!(result.is_ok()); } #[test] fn test_root_level_exports_with_macros() { // Test using the seq! macro with root-level imports let parser = seq![ Literal::from_str("Hello"), Optional::new(Utf8Class::whitespace()), Literal::from_str("World") ]; let cursor = Cursor::new(b"Hello World"); let mut source = Source::new(cursor); let result = parse(parser, &mut source); assert!(result.is_ok()); } #[test] fn test_root_level_exports_oneof() { // Test oneof! macro with root-level imports let parser = oneof![Literal::from_str("hello"), Literal::from_str("world")]; let cursor = Cursor::new(b"hello"); let mut source = Source::new(cursor); let result = parse(parser, &mut source); assert!(result.is_ok()); } #[test] fn test_prelude_import() { // Test the prelude module use crate::prelude::*; let parser = seq![Literal::from_str("test"), Optional::new(Utf8Class::alpha())]; let cursor = Cursor::new(b"testx"); let mut source = Source::new(cursor); let result = parse(parser, &mut source); assert!(result.is_ok()); } #[test] fn test_grammar_parser_exported() { // Ensure GrammarParser is available at root level let _parser = GrammarParser::new(); } }