//! Parser for Fermented `UnrealScript` (`FerUS`). //! //! Consumes tokens from [`crate::lexer::TokenizedFile`] and allocates AST //! nodes in [`crate::arena::Arena`]. Basic expressions use a Pratt parser; //! the rest rely on recursive descent in [`crate::parser::grammar`].\ //! Non-fatal errors accumulate in `Parser::diagnostics` as //! [`crate::diagnostics::Diagnostic`]; recovery skips to sync points defined by //! [`crate::parser::recovery::SyncLevel`] and synthesizes error nodes while //! keeping the parse going. //! //! Components: //! - `cursor`: token I/O, `peek`/`advance`, and lazy trivia capture; //! - `trivia`: trailing comments and newline counts keyed to //! the previous significant token and BOF; //! - `recovery`: panic-mode skipping and recovery adapters for results; //! - `pretty`: printable trees (`ExprTree`, `StmtTree`) for messages and dumps; //! - `errors`: [`ParseError`] and [`ParseErrorKind`]. //! //! Lifetimes: `'src` ties to lexer slices; `'arena` ties to AST allocation. //! //! Guarantees: //! //! - Parser does not abort on user input. It emits diagnostics and error nodes. //! - Trivia is recorded as you scan and can be queried by formatters/linters. //! - Public surface keeps [`Parser`] small; //! low-level plumbing lives in submodules. use super::lexer; pub use lexer::{TokenData, Tokens}; mod cursor; mod errors; mod grammar; mod recovery; mod trivia; pub use errors::ParseError; pub(crate) use errors::{ParseErrorKind, ParseResult}; pub(crate) use recovery::{ResultRecoveryExt, SyncLevel}; pub(crate) use trivia::{TriviaKind, TriviaToken}; pub type ParseExpressionResult<'src, 'arena> = ParseResult<'src, 'arena, crate::ast::ExpressionRef<'src, 'arena>>; /// A recursive-descent parser over token from [`crate::lexer::TokenizedFile`]. pub struct Parser<'src, 'arena> { arena: &'arena crate::arena::Arena, pub diagnostics: Vec, cursor: cursor::Cursor<'src, 'src>, trivia: trivia::TriviaIndexBuilder<'src>, } impl<'src, 'arena> Parser<'src, 'arena> { pub fn new(file: &'src lexer::TokenizedFile<'src>, arena: &'arena crate::arena::Arena) -> Self { Self { arena, diagnostics: Vec::new(), cursor: cursor::Cursor::new(file), trivia: trivia::TriviaIndexBuilder::default(), } } }