1<p align="center"> 2 <img src="https://raw.github.com/pest-parser/pest/master/pest-logo.svg?sanitize=true" width="80%"/> 3</p> 4 5# pest. The Elegant Parser 6 7[](https://gitter.im/dragostis/pest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 8[](https://pest-parser.github.io/book) 9[](https://docs.rs/pest) 10 11[](https://travis-ci.org/pest-parser/pest) 12[](https://codecov.io/gh/pest-parser/pest) 13[](https://crates.io/crates/pest) 14[](https://crates.io/crates/pest) 15 16pest is a general purpose parser written in Rust with a focus on accessibility, 17correctness, and performance. It uses parsing expression grammars 18(or [PEG]) as input, which are similar in spirit to regular expressions, but 19which offer the enhanced expressivity needed to parse complex languages. 20 21[PEG]: https://en.wikipedia.org/wiki/Parsing_expression_grammar 22 23## Getting started 24 25The recommended way to start parsing with pest is to read the official [book]. 26 27Other helpful resources: 28 29* API reference on [docs.rs] 30* play with grammars and share them on our [fiddle] 31* leave feedback, ask questions, or greet us on [Gitter] 32 33[book]: https://pest-parser.github.io/book 34[docs.rs]: https://docs.rs/pest 35[fiddle]: https://pest-parser.github.io/#editor 36[Gitter]: https://gitter.im/dragostis/pest 37 38## Example 39 40The following is an example of a grammar for a list of alpha-numeric identifiers 41where the first identifier does not start with a digit: 42 43```rust 44alpha = { 'a'..'z' | 'A'..'Z' } 45digit = { '0'..'9' } 46 47ident = { (alpha | digit)+ } 48 49ident_list = _{ !digit ~ ident ~ (" " ~ ident)+ } 50 // ^ 51 // ident_list rule is silent which means it produces no tokens 52``` 53 54Grammars are saved in separate .pest files which are never mixed with procedural 55code. This results in an always up-to-date formalization of a language that is 56easy to read and maintain. 57 58## Meaningful error reporting 59 60Based on the grammar definition, the parser also includes automatic error 61reporting. For the example above, the input `"123"` will result in: 62 63``` 64thread 'main' panicked at ' --> 1:1 65 | 661 | 123 67 | ^--- 68 | 69 = unexpected digit', src/main.rs:12 70``` 71while `"ab *"` will result in: 72``` 73thread 'main' panicked at ' --> 1:1 74 | 751 | ab * 76 | ^--- 77 | 78 = expected ident', src/main.rs:12 79``` 80 81## Pairs API 82 83The grammar can be used to derive a `Parser` implementation automatically. 84Parsing returns an iterator of nested token pairs: 85 86```rust 87extern crate pest; 88#[macro_use] 89extern crate pest_derive; 90 91use pest::Parser; 92 93#[derive(Parser)] 94#[grammar = "ident.pest"] 95struct IdentParser; 96 97fn main() { 98 let pairs = IdentParser::parse(Rule::ident_list, "a1 b2").unwrap_or_else(|e| panic!("{}", e)); 99 100 // Because ident_list is silent, the iterator will contain idents 101 for pair in pairs { 102 103 let span = pair.clone().into_span(); 104 // A pair is a combination of the rule which matched and a span of input 105 println!("Rule: {:?}", pair.as_rule()); 106 println!("Span: {:?}", span); 107 println!("Text: {}", span.as_str()); 108 109 // A pair can be converted to an iterator of the tokens which make it up: 110 for inner_pair in pair.into_inner() { 111 let inner_span = inner_pair.clone().into_span(); 112 match inner_pair.as_rule() { 113 Rule::alpha => println!("Letter: {}", inner_span.as_str()), 114 Rule::digit => println!("Digit: {}", inner_span.as_str()), 115 _ => unreachable!() 116 }; 117 } 118 } 119} 120``` 121 122This produces the following output: 123``` 124Rule: ident 125Span: Span { start: 0, end: 2 } 126Text: a1 127Letter: a 128Digit: 1 129Rule: ident 130Span: Span { start: 3, end: 5 } 131Text: b2 132Letter: b 133Digit: 2 134``` 135 136## Other features 137 138* Precedence climbing 139* Input handling 140* Custom errors 141* Runs on stable Rust 142 143## Projects using pest 144 145* [pest_meta](https://github.com/pest-parser/pest/blob/master/meta/src/grammar.pest) (bootstrapped) 146* [brain](https://github.com/brain-lang/brain) 147* [Chelone](https://github.com/Aaronepower/chelone) 148* [comrak](https://github.com/kivikakk/comrak) 149* [graphql-parser](https://github.com/Keats/graphql-parser) 150* [handlebars-rust](https://github.com/sunng87/handlebars-rust) 151* [hexdino](https://github.com/Luz/hexdino) 152* [Huia](https://gitlab.com/jimsy/huia/) 153* [json5-rs](https://github.com/callum-oakley/json5-rs) 154* [mt940](https://github.com/svenstaro/mt940-rs) 155* [py_literal](https://github.com/jturner314/py_literal) 156* [rouler](https://github.com/jarcane/rouler) 157* [RuSh](https://github.com/lwandrebeck/RuSh) 158* [rs_pbrt](https://github.com/wahn/rs_pbrt) 159* [stache](https://github.com/dgraham/stache) 160* [tera](https://github.com/Keats/tera) 161* [ui_gen](https://github.com/emoon/ui_gen) 162* [ukhasnet-parser](https://github.com/adamgreig/ukhasnet-parser) 163 164## Special thanks 165 166A special round of applause goes to prof. Marius Minea for his guidance and all 167pest contributors, some of which being none other than my friends. 168