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