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;
198#[doc(hidden)]
199pub mod diagnostics;
200mod dijkstra;
201#[doc(hidden)]
202pub mod lex_api;
203#[doc(hidden)]
204pub mod parser;
205#[cfg(test)]
206pub mod test_utils;
207
208pub use crate::{
209    ctbuilder::{CTParser, CTParserBuilder, RustEdition, Visibility},
210    lex_api::{LexError, Lexeme, Lexer, LexerTypes, NonStreamingLexer},
211    parser::{LexParseError, Node, ParseError, ParseRepair, RTParserBuilder, RecoveryKind},
212};
213
214pub use crate::parser::action_generictree;
215/// A convenience macro for including statically compiled `.y` files. A file `src/a/b/c.y`
216/// processed by [CTParserBuilder::grammar_in_src_dir] can then be used in a crate with
217/// `lrpar_mod!("a/b/c.y")`.
218///
219/// Note that you can use `lrpar_mod` with [CTParserBuilder::output_path] if, and only if, the
220/// output file was placed in [std::env::var]`("OUT_DIR")` or one of its subdirectories.
221#[macro_export]
222macro_rules! lrpar_mod {
223    ($path:expr) => {
224        include!(concat!(env!("OUT_DIR"), "/", $path, ".rs"));
225    };
226}
227
228#[deprecated(
229    since = "0.13.0",
230    note = "Please import this as `cfgrammar::Span` instead"
231)]
232pub use cfgrammar::Span;
233
234/// This private module with pub items which is directly related to
235/// the "Sealed trait" pattern. These items are used within the current
236/// crate. See `unstable_api` module for enabling usage outside the crate.
237mod unstable {
238    #![allow(unused)]
239    #![allow(unreachable_pub)]
240    pub struct UnstableApi;
241    pub trait UnstableTrait {}
242}
243
244/// A module for lifting restrictions on visibility by enabling unstable features.
245///
246/// See the sources for a complete list of features, and members.
247pub mod unstable_api {
248    /// Unstable functions that take a value `UnstableApi` require
249    /// the "_unstable_api" feature. This feature controls
250    /// whether the value has `pub` visibility outside the crate.
251    #[cfg(feature = "_unstable_api")]
252    pub use crate::unstable::UnstableApi;
253
254    /// This is a a supertrait for traits that are considered to be Unstable.
255    /// Unstable traits do not provide any semver guarantees.
256    ///
257    /// Enabling the `_unsealed_unstable traits` makes this supertrait publicly
258    /// Visible.
259    ///
260    ///
261    /// Declaring an unstable Api within the crate:
262    /// ```ignore_rust
263    /// // Within the crate use `crate::unstable::` .
264    /// pub trait Foo: crate::unstable::UnstableTrait {
265    ///     fn foo(key: crate::unstable::UnstableApi);
266    /// }
267    /// ```
268    ///
269    /// Deriving the trait outside the crate (requires feature `_unsealed_unstable_traits`)
270    /// ```ignore_rust
271    /// struct Bar;
272    /// impl unstable_api::UnstableTrait for Bar{}
273    /// impl Foo for Bar {
274    ///   fn foo(key: unstable_api::UnstableApi) {
275    ///     ...
276    ///   }
277    /// }
278    /// ```
279    ///
280    ///
281    /// Calling an implementation of the trait outside the crate (requires feature `_unstable_api`:
282    /// ```ignore_rust
283    ///   let x: &dyn Foo = ...;
284    ///   x.foo(unstable_api::UnstableApi);
285    /// ```
286    #[cfg(feature = "_unsealed_unstable_traits")]
287    pub use crate::unstable::UnstableTrait;
288
289    /// An value that acts as a key to inform callers that they are
290    /// calling an unstable internal api. This value is public by default.
291    /// Access to it does not require any features to be enabled.
292    ///
293    /// Q. When this should be used?
294    ///
295    /// A. When generated code needs to call internal api within it,
296    /// where you do not want the caller to have to enable any features
297    /// to use the generated code.
298    pub struct InternalPublicApi;
299}