prattle/
lib.rs

1// lib.rs - MIT License
2//  MIT License
3//  Copyright (c) 2018 Tyler Laing (ZerothLaw)
4// 
5//  Permission is hereby granted, free of charge, to any person obtaining a copy
6//  of this software and associated documentation files (the "Software"), to deal
7//  in the Software without restriction, including without limitation the rights
8//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9//  copies of the Software, and to permit persons to whom the Software is
10//  furnished to do so, subject to the following conditions:
11// 
12//  The above copyright notice and this permission notice shall be included in all
13//  copies or substantial portions of the Software.
14// 
15//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21//  SOFTWARE.
22
23//! # Introduction
24//! 
25//! This crate implements a configurable and general-purpose Pratt parser.
26//! 
27//! A Pratt parser is also known as a Top-Down Operator Precedence parser, 
28//! aka TDOP parser. The general algorithm was discovered and outlined by 
29//! Vaughn Pratt in 1973 in his paper[1]. 
30//! 
31//! It differs from recursive-descent classes of parsers by associating
32//! parsing rules to tokens rather than grammar rules. 
33//! 
34//! This is especially valuable when parsing expression grammars with 
35//! operator precedence without significant descent and type costs. 
36//! 
37//! Consider the following expression: 
38//!
39//! > a + b * c
40//! 
41//! So which variables are to be associated with which operators? 
42//! A recursive-descent parser would need to implement two layers of 
43//! grammar rules which are recursive with each other. This leads to 
44//! potential infinite loops if your parser follows the wrong rule and
45//! doesn't backtrack effectively. 
46//! 
47//! Whereas with a Pratt Parser, you need just three rules and three 
48//! binding powers:
49//! null denotation of Variable => Node::Simple(token);
50//! left denotation of Add => Node::Composite(token: token, children: vec![node, 
51//!     parser.parse_expr(5)]);
52//! left denotation of Mul => Node::Composite(token: token, children: vec![node, 
53//!     parser.parse_expr(10)]);
54//! lbp of Variable = 0;
55//! lbp of Add = 5;
56//! lbp of Mul = 10;
57//! 
58//! And now it will correctly associate 'b' and 'c' tokens with the mul operator, and 
59//! then the result of that with the 'a' token and the add operator. 
60//! 
61//! It also executes with far fewer parse calls, creating a minimal stack depth 
62//! during execution. 
63//! 
64//! ## Example
65//! 
66//! ```rust
67//! use std::fmt::{Display, Formatter, Error};
68//! 
69//! extern crate prattle;
70//! use prattle::prelude::*;
71//! 
72//! #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
73//! enum CToken {
74//!     Var(String), 
75//!     Add, 
76//!     Mul
77//! }
78//! 
79//! impl Display for CToken {
80//!     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
81//!         write!(f, "{:?}", self)
82//!     }
83//! }
84//! 
85//! fn main() {
86//!     let mut spec = ParserSpec::new();
87//! 
88//!     spec.add_null_assoc(
89//!         CToken::Var("".to_string()),
90//!         PrecedenceLevel::Root, 
91//!         |parser: &mut dyn Parser<CToken>, token, _| {
92//!             Ok(Node::Simple(token.clone()))
93//!         }
94//!     );
95//!     spec.add_left_assoc(
96//!         CToken::Add, 
97//!         PrecedenceLevel::First, 
98//!         |parser, token, lbp, node| {
99//!             Ok(Node::Composite{token: token.clone(), children: vec![
100//!                 node, 
101//!                 parser.parse_expr(lbp)?]})
102//!     });
103//!     spec.add_left_assoc(
104//!         CToken::Mul, 
105//!         PrecedenceLevel::Second, 
106//!         |parser, token, lbp, node| {
107//!             Ok(Node::Composite{token: token.clone(), children: vec![
108//!                 node, 
109//!                 parser.parse_expr(lbp)?]})
110//!     });
111//! 
112//!     let lexer = LexerVec::new(vec![
113//!         CToken::Var("a".to_string()),
114//!         CToken::Add, 
115//!         CToken::Var("b".to_string()), 
116//!         CToken::Mul, 
117//!         CToken::Var("c".to_string())
118//!     ]);
119//! 
120//!     let mut parser = GeneralParser::new(spec, lexer);
121//! 
122//!     let res = parser.parse();
123//!     println!("{:?}", res);
124//! }
125//! ```
126//! 
127//! ## Capabilities
128//! 
129//! This crate enables a very fast and simple parser, with simple rules, that is 
130//! easy to understand and maintain. Most of the work is in implementing the
131//! required traits on your Token type. 
132//! 
133//! ## More complex examples
134//! 
135//! Run: 
136//! > cargo run --example token_spec
137//! 
138//! examples/token_spec.rs shows an example of how to implement the traits for 
139//! the token type so it can be used to lookup the parse rules (uses HashMap).
140//! 
141//! ## Citations
142//! > [1] Vaughan R. Pratt. 1973. Top down operator precedence. In Proceedings
143//! > of the 1st annual ACM SIGACT-SIGPLAN symposium on Principles of 
144//! > programming languages (POPL '73). ACM, New York, NY, USA, 41-51. 
145//! > DOI=http://dx.doi.org/10.1145/512927.512931
146//! 
147
148#[macro_use] extern crate failure;
149
150#[macro_use] pub mod macros;
151
152pub mod errors;
153pub mod lexer;
154pub mod node;
155pub mod parser;
156pub mod precedence;
157pub mod spec;
158pub mod token;
159
160/// Handy prelude mod containing everything you need to get started. 
161pub mod prelude {
162    pub use errors::ParseError;
163    pub use lexer::{Lexer, LexerVec};
164    pub use node::Node;
165    pub use parser::{Parser, GeneralParser};
166    pub use precedence::PrecedenceLevel;
167    pub use spec::{ParserSpec, SpecificationError};
168    pub use token::Token;
169}
170
171//Little container mod for type aliases that are convenient and short
172pub mod types {
173    use super::prelude::*;
174    pub type NullDenotation<T> = fn(&mut dyn Parser<T>, T, PrecedenceLevel) -> Result<Node<T>, ParseError<T>>;
175    pub type LeftDenotation<T> = fn(&mut dyn Parser<T>, T, PrecedenceLevel, Node<T>) -> Result<Node<T>, ParseError<T>>;
176
177    pub type NullInfo<T> = (PrecedenceLevel, NullDenotation<T>);
178    pub type LeftInfo<T> = (PrecedenceLevel, PrecedenceLevel, LeftDenotation<T>);
179}