gazelle/lib.rs
1//! A typed LR(1) parser generator for Rust with runtime operator precedence
2//! and a push-based API for natural lexer feedback.
3//!
4//! # Quick start
5//!
6//! Define a grammar with [`gazelle_macros::gazelle!`]. A `prec` terminal carries
7//! [`Precedence`] at parse time, so one rule handles all operator levels:
8//!
9//! ```rust
10//! use gazelle_macros::gazelle;
11//!
12//! gazelle! {
13//! grammar calc {
14//! start expr;
15//! terminals { NUM: _, prec OP: _ }
16//! expr = expr OP expr => binop | NUM => num;
17//! }
18//! }
19//!
20//! struct Eval;
21//!
22//! impl gazelle::ErrorType for Eval {
23//! type Error = core::convert::Infallible;
24//! }
25//!
26//! impl calc::Types for Eval {
27//! type Num = i64;
28//! type Op = char;
29//! type Expr = i64;
30//! }
31//!
32//! impl gazelle::Action<calc::Expr<Self>> for Eval {
33//! fn build(&mut self, node: calc::Expr<Self>) -> Result<i64, Self::Error> {
34//! Ok(match node {
35//! calc::Expr::Binop(l, op, r) => match op {
36//! '+' => l + r, '-' => l - r, '*' => l * r, '/' => l / r,
37//! _ => unreachable!(),
38//! },
39//! calc::Expr::Num(n) => n,
40//! })
41//! }
42//! }
43//! ```
44//!
45//! Then push tokens with precedence and collect the result:
46//!
47//! ```rust,ignore
48//! use gazelle::Precedence;
49//!
50//! let mut parser = calc::Parser::<Eval>::new();
51//! let mut actions = Eval;
52//! // Precedence is supplied per-token — the grammar stays flat:
53//! parser.push(calc::Terminal::Num(1), &mut actions)?;
54//! parser.push(calc::Terminal::Op('+', Precedence::Left(1)), &mut actions)?;
55//! parser.push(calc::Terminal::Num(2), &mut actions)?;
56//! parser.push(calc::Terminal::Op('*', Precedence::Left(2)), &mut actions)?;
57//! parser.push(calc::Terminal::Num(3), &mut actions)?;
58//! let result = parser.finish(&mut actions).map_err(|(p, gazelle::ParseError::Syntax { terminal })| p.format_error(terminal, None, None))?;
59//! assert_eq!(result, 7); // 1 + (2 * 3)
60//! ```
61//!
62//! See `examples/expr_eval.rs` for a complete runnable version.
63//!
64//! # Key features
65//!
66//! - **Runtime operator precedence**: `prec` terminals carry [`Precedence`] at
67//! parse time, so one grammar rule handles any number of operator levels —
68//! including user-defined operators.
69//! - **Push-based parsing**: you drive the loop, so the lexer can inspect
70//! parser state between tokens (solves C's typedef problem).
71//! - **CST/AST continuum**: set associated types to the generated enum for a
72//! full CST, to a custom type for an AST, or to [`Ignore`] to discard.
73//! - **Library API**: build [`CompiledTable`]s programmatically for dynamic
74//! grammars, analyzers, or conflict debuggers.
75
76#![no_std]
77
78extern crate alloc;
79
80#[cfg(feature = "std")]
81extern crate std;
82
83// -- Core modules (always available) --
84pub mod grammar;
85pub mod lexer;
86pub mod runtime;
87pub mod table;
88
89// -- Construction modules --
90pub mod automaton;
91mod lr;
92#[cfg(not(feature = "bootstrap"))]
93#[doc(hidden)]
94pub mod meta;
95#[cfg(not(feature = "bootstrap_regex"))]
96pub mod regex;
97
98#[doc(hidden)]
99#[cfg(feature = "codegen")]
100pub mod codegen;
101
102// Core grammar types (AST)
103pub use grammar::{Alt, Grammar, Rule, SymbolId, Term, TerminalDef};
104
105// Parse table types
106pub use table::{CompiledTable, Conflict, ErrorInfo};
107
108// Runtime parser types
109pub use runtime::{
110 Action, AstNode, Cst, CstParser, ErrorContext, ErrorType, FromAstNode, Ignore, ParseError,
111 ParseTable, Parser, Precedence, RecoveryInfo, Repair, Resolution, Token,
112};
113
114// Lexer DFA
115pub use lexer::{LexerDfa, OwnedLexerDfa};
116
117// Meta-grammar parser
118#[cfg(not(feature = "bootstrap"))]
119pub use meta::parse_grammar;