rott/rottlib/src/parser/mod.rs

77 lines
2.8 KiB
Rust

//! 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>>;
pub(crate) mod diagnostic_labels {
pub(crate) const EXPRESSION_REQUIRED_BY: &str = "expression_required_by";
pub(crate) const EXPRESSION_EXPECTED_AFTER: &str = "expression_expected_after";
}
// TODO: add some kind of bailing for infinite loops
// let remaining_steps = file.token_count().saturating_mul(256).saturating_add(1024);
/// A recursive-descent parser over token from [`crate::lexer::TokenizedFile`].
pub struct Parser<'src, 'arena> {
file: &'src lexer::TokenizedFile<'src>,
arena: &'arena crate::arena::Arena,
pub diagnostics: Vec<crate::diagnostics::Diagnostic>,
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 {
file,
arena,
diagnostics: Vec::new(),
cursor: cursor::Cursor::new(file),
trivia: trivia::TriviaIndexBuilder::default(),
}
}
pub fn file(&self) -> &'src lexer::TokenizedFile<'src> {
self.file
}
}