lrpar/
mod.rs

1#![allow(clippy::cognitive_complexity)]
2#![allow(clippy::many_single_char_names)]
3#![allow(clippy::needless_doctest_main)]
4#![allow(clippy::new_without_default)]
5#![allow(clippy::range_plus_one)]
6#![allow(clippy::too_many_arguments)]
7#![allow(clippy::type_complexity)]
8#![allow(clippy::unnecessary_wraps)]
9#![allow(clippy::upper_case_acronyms)]
10#![forbid(unsafe_code)]
11#![deny(unreachable_pub)]
12
13//! `lrpar` provides a Yacc-compatible parser (where grammars can be generated at compile-time or
14//! run-time). It can take in traditional `.y` files and convert them into an idiomatic Rust
15//! parser.
16//!
17//! If you're new to `lrpar`, please read the "quick start guide". The "grmtools book" and API
18//! reference have more detailed information.  You can find the appropriate documentation for the
19//! version of lrpar you are using here:
20//!
21//! | Latest release                          | master |
22//! |-----------------------------------------|--------|
23//! | [Quickstart guide](https://softdevteam.github.io/grmtools/latest_release/book/quickstart.html) | [Quickstart guide](https://softdevteam.github.io/grmtools/master/book/quickstart.html) |
24//! | [grmtools book](https://softdevteam.github.io/grmtools/latest_release/book/) | [grmtools book](https://softdevteam.github.io/grmtools/master/book) |
25//! | [lrpar API](https://docs.rs/lrpar/)     | [lrpar API](https://softdevteam.github.io/grmtools/master/api/lrpar/)         |
26//!
27//! [Documentation for all past and present releases](https://softdevteam.github.io/grmtools/)
28//!
29//!
30//! ## Example
31//!
32//! Let's assume we want to statically generate a parser for a simple calculator language (and
33//! let's also assume we are able to use [`lrlex`](https://crates.io/crates/lrlex) for the lexer).
34//! We need to add a `build.rs` file to our project which statically compiles both the lexer and
35//! parser. While we can perform both steps individually, it's easiest to use `lrlex` which does
36//! both jobs for us in one go. Our `build.rs` file thus looks as follows:
37//!
38//! ```text
39//! use cfgrammar::yacc::YaccKind;
40//! use lrlex::CTLexerBuilder;
41//!
42//! fn main() {
43//!     CTLexerBuilder::new()
44//!         .lrpar_config(|ctp| {
45//!             ctp.yacckind(YaccKind::Grmtools)
46//!                 .grammar_in_src_dir("calc.y")
47//!                 .unwrap()
48//!         })
49//!         .lexer_in_src_dir("calc.l")
50//!         .unwrap()
51//!         .build()
52//!         .unwrap();
53//! }
54//! ```
55//!
56//! where `src/calc.l` is as follows:
57//!
58//! ```text
59//! %%
60//! [0-9]+ "INT"
61//! \+ "+"
62//! \* "*"
63//! \( "("
64//! \) ")"
65//! [\t ]+ ;
66//! ```
67//!
68//! and `src/calc.y` is as follows:
69//!
70//! ```text
71//! %start Expr
72//! %avoid_insert "INT"
73//! %%
74//! Expr -> Result<u64, ()>:
75//!       Expr '+' Term { Ok($1? + $3?) }
76//!     | Term { $1 }
77//!     ;
78//!
79//! Term -> Result<u64, ()>:
80//!       Term '*' Factor { Ok($1? * $3?) }
81//!     | Factor { $1 }
82//!     ;
83//!
84//! Factor -> Result<u64, ()>:
85//!       '(' Expr ')' { $2 }
86//!     | 'INT'
87//!       {
88//!           let v = $1.map_err(|_| ())?;
89//!           parse_int($lexer.span_str(v.span()))
90//!       }
91//!     ;
92//! %%
93//! // Any functions here are in scope for all the grammar actions above.
94//!
95//! fn parse_int(s: &str) -> Result<u64, ()> {
96//!     match s.parse::<u64>() {
97//!         Ok(val) => Ok(val),
98//!         Err(_) => {
99//!             eprintln!("{} cannot be represented as a u64", s);
100//!             Err(())
101//!         }
102//!     }
103//! }
104//! ```
105//!
106//! Because we specified that our Yacc file is in `Grmtools` format, each rule has a
107//! separate Rust type to which all its functions conform (in this case, all the
108//! rules have the same type, but that's not a requirement).
109//!
110//! A simple `src/main.rs` is as follows:
111//!
112//! ```text
113//! use std::io::{self, BufRead, Write};
114//!
115//! use lrlex::lrlex_mod;
116//! use lrpar::lrpar_mod;
117//!
118//! // Using `lrlex_mod!` brings the lexer for `calc.l` into scope. By default the module name
119//! // will be `calc_l` (i.e. the file name, minus any extensions, with a suffix of `_l`).
120//! lrlex_mod!("calc.l");
121//! // Using `lrpar_mod!` brings the parser for `calc.y` into scope. By default the module name
122//! // will be `calc_y` (i.e. the file name, minus any extensions, with a suffix of `_y`).
123//! lrpar_mod!("calc.y");
124//!
125//! fn main() {
126//!     // Get the `LexerDef` for the `calc` language.
127//!     let lexerdef = calc_l::lexerdef();
128//!     let stdin = io::stdin();
129//!     loop {
130//!         print!(">>> ");
131//!         io::stdout().flush().ok();
132//!         match stdin.lock().lines().next() {
133//!             Some(Ok(ref l)) => {
134//!                 if l.trim().is_empty() {
135//!                     continue;
136//!                 }
137//!                 // Now we create a lexer with the `lexer` method with which we can lex an input.
138//!                 let lexer = lexerdef.lexer(l);
139//!                 // Pass the lexer to the parser and lex and parse the input.
140//!                 let (res, errs) = calc_y::parse(&lexer);
141//!                 for e in errs {
142//!                     println!("{}", e.pp(&lexer, &calc_y::token_epp));
143//!                 }
144//!                 match res {
145//!                     Some(Ok(r)) => println!("Result: {}", r),
146//!                     _ => eprintln!("Unable to evaluate expression.")
147//!                 }
148//!             }
149//!             _ => break
150//!         }
151//!     }
152//! }
153//! ```
154//!
155//! We can now `cargo run` our project and evaluate simple expressions:
156//!
157//! ```text
158//! >>> 2 + 3
159//! Result: 5
160//! >>> 2 + 3 * 4
161//! Result: 14
162//! >>> (2 + 3) * 4
163//! Result: 20
164//! ```
165//!
166//! `lrpar` also comes with advanced [error
167//! recovery](https://softdevteam.github.io/grmtools/master/book/errorrecovery.html) built-in:
168//!
169//! ```text
170//! >>> 2 + + 3
171//! Parsing error at line 1 column 5. Repair sequences found:
172//!    1: Delete +
173//!    2: Insert INT
174//! Result: 5
175//! >>> 2 + 3 3
176//! Parsing error at line 1 column 7. Repair sequences found:
177//!    1: Insert *
178//!    2: Insert +
179//!    3: Delete 3
180//! Result: 11
181//! >>> 2 + 3 4 5
182//! Parsing error at line 1 column 7. Repair sequences found:
183//!    1: Insert *, Delete 4
184//!    2: Insert +, Delete 4
185//!    3: Delete 4, Delete 5
186//!    4: Insert +, Shift 4, Delete 5
187//!    5: Insert +, Shift 4, Insert +
188//!    6: Insert *, Shift 4, Delete 5
189//!    7: Insert *, Shift 4, Insert *
190//!    8: Insert *, Shift 4, Insert +
191//!    9: Insert +, Shift 4, Insert *
192//! Result: 17
193//! ```
194
195mod cpctplus;
196#[doc(hidden)]
197pub mod ctbuilder;
198mod dijkstra;
199#[doc(hidden)]
200pub mod lex_api;
201#[doc(hidden)]
202pub mod parser;
203#[cfg(test)]
204pub mod test_utils;
205
206pub use crate::{
207    ctbuilder::{CTParser, CTParserBuilder, RustEdition, Visibility},
208    lex_api::{LexError, Lexeme, Lexer, LexerTypes, NonStreamingLexer},
209    parser::{LexParseError, Node, ParseError, ParseRepair, RTParserBuilder, RecoveryKind},
210};
211
212pub use crate::parser::action_generictree;
213/// A convenience macro for including statically compiled `.y` files. A file `src/a/b/c.y`
214/// processed by [CTParserBuilder::grammar_in_src_dir] can then be used in a crate with
215/// `lrpar_mod!("a/b/c.y")`.
216///
217/// Note that you can use `lrpar_mod` with [CTParserBuilder::output_path] if, and only if, the
218/// output file was placed in [std::env::var]`("OUT_DIR")` or one of its subdirectories.
219#[macro_export]
220macro_rules! lrpar_mod {
221    ($path:expr) => {
222        include!(concat!(env!("OUT_DIR"), "/", $path, ".rs"));
223    };
224}
225
226#[deprecated(
227    since = "0.13.0",
228    note = "Please import this as `cfgrammar::Span` instead"
229)]
230pub use cfgrammar::Span;
231
232/// This private module with pub items which is directly related to
233/// the "Sealed trait" pattern. These items are used within the current
234/// crate. See `unstable_api` module for enabling usage outside the crate.
235mod unstable {
236    #![allow(unused)]
237    #![allow(unreachable_pub)]
238    pub struct UnstableApi;
239    pub trait UnstableTrait {}
240}
241
242/// A module for lifting restrictions on visibility by enabling unstable features.
243///
244/// See the sources for a complete list of features, and members.
245pub mod unstable_api {
246    /// Unstable functions that take a value `UnstableApi` require
247    /// the "_unstable_api" feature. This feature controls
248    /// whether the value has `pub` visibility outside the crate.
249    #[cfg(feature = "_unstable_api")]
250    pub use crate::unstable::UnstableApi;
251
252    /// This is a a supertrait for traits that are considered to be Unstable.
253    /// Unstable traits do not provide any semver guarantees.
254    ///
255    /// Enabling the `_unsealed_unstable traits` makes this supertrait publicly
256    /// Visible.
257    ///
258    ///
259    /// Declaring an unstable Api within the crate:
260    /// ```ignore_rust
261    /// // Within the crate use `crate::unstable::` .
262    /// pub trait Foo: crate::unstable::UnstableTrait {
263    ///     fn foo(key: crate::unstable::UnstableApi);
264    /// }
265    /// ```
266    ///
267    /// Deriving the trait outside the crate (requires feature `_unsealed_unstable_traits`)
268    /// ```ignore_rust
269    /// struct Bar;
270    /// impl unstable_api::UnstableTrait for Bar{}
271    /// impl Foo for Bar {
272    ///   fn foo(key: unstable_api::UnstableApi) {
273    ///     ...
274    ///   }
275    /// }
276    /// ```
277    ///
278    ///
279    /// Calling an implementation of the trait outside the crate (requires feature `_unstable_api`:
280    /// ```ignore_rust
281    ///   let x: &dyn Foo = ...;
282    ///   x.foo(unstable_api::UnstableApi);
283    /// ```
284    #[cfg(feature = "_unsealed_unstable_traits")]
285    pub use crate::unstable::UnstableTrait;
286
287    /// An value that acts as a key to inform callers that they are
288    /// calling an unstable internal api. This value is public by default.
289    /// Access to it does not require any features to be enabled.
290    ///
291    /// Q. When this should be used?
292    ///
293    /// A. When generated code needs to call internal api within it,
294    /// where you do not want the caller to have to enable any features
295    /// to use the generated code.
296    pub struct InternalPublicApi;
297}