Snap for 10453563 from 3ca89b01f9b42f4acd21200b1770a51266d1cf0d to mainline-art-release

Change-Id: I10aa97edd057ba8e1ed18a9935b4c45a0527383c
diff --git a/Android.bp b/Android.bp
index 616f116..d38f6b3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,8 +1,6 @@
 // This file is generated by cargo2android.py --run.
 // Do not modify this file as changes will be overridden on upgrade.
 
-
-
 package {
     default_applicable_licenses: ["external_rust_crates_pest_derive_license"],
 }
@@ -43,9 +41,13 @@
     name: "libpest_derive",
     crate_name: "pest_derive",
     cargo_env_compat: true,
-    cargo_pkg_version: "2.1.0",
+    cargo_pkg_version: "2.5.5",
     srcs: ["src/lib.rs"],
-    edition: "2015",
+    edition: "2021",
+    features: [
+        "default",
+        "std",
+    ],
     rustlibs: [
         "libpest",
         "libpest_generator",
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..e57f0ca
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,195 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "block-buffer"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.139"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
+
+[[package]]
+name = "once_cell"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
+
+[[package]]
+name = "pest"
+version = "2.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660"
+dependencies = [
+ "thiserror",
+ "ucd-trie",
+]
+
+[[package]]
+name = "pest_derive"
+version = "2.5.5"
+dependencies = [
+ "pest",
+ "pest_generator",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202"
+dependencies = [
+ "pest",
+ "pest_meta",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pest_meta"
+version = "2.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616"
+dependencies = [
+ "once_cell",
+ "pest",
+ "sha2",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.107"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "typenum"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+
+[[package]]
+name = "ucd-trie"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
diff --git a/Cargo.toml b/Cargo.toml
index 47dfec4..57b9dd2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,22 +3,28 @@
 # When uploading crates to the registry Cargo will automatically
 # "normalize" Cargo.toml files for maximal compatibility
 # with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g. crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
 #
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
 
 [package]
+edition = "2021"
+rust-version = "1.56"
 name = "pest_derive"
-version = "2.1.0"
+version = "2.5.5"
 authors = ["DragoČ™ Tiselice <dragostiselice@gmail.com>"]
 description = "pest's derive macro"
-homepage = "https://pest-parser.github.io/"
+homepage = "https://pest.rs/"
 documentation = "https://docs.rs/pest"
 readme = "_README.md"
-keywords = ["pest", "parser", "peg", "grammar"]
+keywords = [
+    "pest",
+    "parser",
+    "peg",
+    "grammar",
+]
 categories = ["parsing"]
 license = "MIT/Apache-2.0"
 repository = "https://github.com/pest-parser/pest"
@@ -26,16 +32,18 @@
 [lib]
 name = "pest_derive"
 proc-macro = true
+
 [dependencies.pest]
-version = "2.1.0"
+version = "2.5.5"
+default-features = false
 
 [dependencies.pest_generator]
-version = "2.1.0"
-[badges.codecov]
-repository = "pest-parser/pest"
+version = "2.5.5"
+default-features = false
 
-[badges.maintenance]
-status = "actively-developed"
-
-[badges.travis-ci]
-repository = "pest-parser/pest"
+[features]
+default = ["std"]
+std = [
+    "pest/std",
+    "pest_generator/std",
+]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 2740871..3ea06f5 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,26 +1,27 @@
 [package]
 name = "pest_derive"
 description = "pest's derive macro"
-version = "2.1.0"
+version = "2.5.5"
+edition = "2021"
 authors = ["DragoČ™ Tiselice <dragostiselice@gmail.com>"]
-homepage = "https://pest-parser.github.io/"
+homepage = "https://pest.rs/"
 repository = "https://github.com/pest-parser/pest"
 documentation = "https://docs.rs/pest"
 keywords = ["pest", "parser", "peg", "grammar"]
 categories = ["parsing"]
 license = "MIT/Apache-2.0"
 readme = "_README.md"
+rust-version = "1.56"
 
 [lib]
 name = "pest_derive"
 proc-macro = true
 
+[features]
+default = ["std"]
+std = ["pest/std", "pest_generator/std"]
+
 [dependencies]
 # for tests, included transitively anyway
-pest = { path = "../pest", version = "2.1.0" }
-pest_generator = { path = "../generator", version = "2.1.0" }
-
-[badges]
-codecov = { repository = "pest-parser/pest" }
-maintenance = { status = "actively-developed" }
-travis-ci = { repository = "pest-parser/pest" }
+pest = { path = "../pest", version = "2.5.5", default-features = false }
+pest_generator = { path = "../generator", version = "2.5.5", default-features = false }
diff --git a/METADATA b/METADATA
index 096be95..06fd504 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/pest_derive
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
 name: "pest_derive"
 description: "pest\'s derive macro"
 third_party {
@@ -7,14 +11,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/pest_derive/pest_derive-2.1.0.crate"
+    value: "https://static.crates.io/crates/pest_derive/pest_derive-2.5.5.crate"
   }
-  version: "2.1.0"
-  # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+  version: "2.5.5"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2022
-    month: 1
-    day: 27
+    year: 2023
+    month: 2
+    day: 16
   }
 }
diff --git a/_README.md b/_README.md
index 2c94a72..da30ab7 100644
--- a/_README.md
+++ b/_README.md
@@ -1,15 +1,18 @@
+
 <p align="center">
   <img src="https://raw.github.com/pest-parser/pest/master/pest-logo.svg?sanitize=true" width="80%"/>
 </p>
 
 # pest. The Elegant Parser
 
-[![Join the chat at https://gitter.im/dragostis/pest](https://badges.gitter.im/dragostis/pest.svg)](https://gitter.im/dragostis/pest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-[![Book](https://img.shields.io/badge/book-WIP-4d76ae.svg)](https://pest-parser.github.io/book)
+[![Join the chat at https://gitter.im/pest-parser/pest](https://badges.gitter.im/dragostis/pest.svg)](https://gitter.im/pest-parser/pest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Book](https://img.shields.io/badge/book-WIP-4d76ae.svg)](https://pest.rs/book)
 [![Docs](https://docs.rs/pest/badge.svg)](https://docs.rs/pest)
 
-[![Build Status](https://travis-ci.org/pest-parser/pest.svg?branch=master)](https://travis-ci.org/pest-parser/pest)
+[![pest Continuous Integration](https://github.com/pest-parser/pest/actions/workflows/ci.yml/badge.svg)](https://github.com/pest-parser/pest/actions/workflows/ci.yml)
 [![codecov](https://codecov.io/gh/pest-parser/pest/branch/master/graph/badge.svg)](https://codecov.io/gh/pest-parser/pest)
+<a href="https://blog.rust-lang.org/2021/11/01/Rust-1.56.1.html"><img alt="Rustc Version 1.56.1+" src="https://img.shields.io/badge/rustc-1.56.1%2B-lightgrey.svg"/></a>
+
 [![Crates.io](https://img.shields.io/crates/d/pest.svg)](https://crates.io/crates/pest)
 [![Crates.io](https://img.shields.io/crates/v/pest.svg)](https://crates.io/crates/pest)
 
@@ -28,25 +31,28 @@
 
 * API reference on [docs.rs]
 * play with grammars and share them on our [fiddle]
-* leave feedback, ask questions, or greet us on [Gitter]
+* find previous common questions answered or ask questions on [GitHub Discussions]
+* leave feedback, ask questions, or greet us on [Gitter] or [Discord]
 
-[book]: https://pest-parser.github.io/book
+[book]: https://pest.rs/book
 [docs.rs]: https://docs.rs/pest
-[fiddle]: https://pest-parser.github.io/#editor
-[Gitter]: https://gitter.im/dragostis/pest
+[fiddle]: https://pest.rs/#editor
+[Gitter]: https://gitter.im/pest-parser/pest
+[Discord]: https://discord.gg/XEGACtWpT2
+[GitHub Discussions]: https://github.com/pest-parser/pest/discussions
 
 ## Example
 
-The following is an example of a grammar for a list of alpha-numeric identifiers
-where the first identifier does not start with a digit:
+The following is an example of a grammar for a list of alphanumeric identifiers
+where all identifiers don't start with a digit:
 
 ```rust
 alpha = { 'a'..'z' | 'A'..'Z' }
 digit = { '0'..'9' }
 
-ident = { (alpha | digit)+ }
+ident = { !digit ~ (alpha | digit)+ }
 
-ident_list = _{ !digit ~ ident ~ (" " ~ ident)+ }
+ident_list = _{ ident ~ (" " ~ ident)* }
           // ^
           // ident_list rule is silent which means it produces no tokens
 ```
@@ -78,6 +84,9 @@
   = expected ident', src/main.rs:12
 ```
 
+These error messages can be obtained from their default `Display` implementation,
+e.g. `panic!("{}", parser_result.unwrap_err())` or `println!("{}", e)`.
+
 ## Pairs API
 
 The grammar can be used to derive a `Parser` implementation automatically.
@@ -99,19 +108,16 @@
 
     // Because ident_list is silent, the iterator will contain idents
     for pair in pairs {
-
-        let span = pair.clone().into_span();
         // A pair is a combination of the rule which matched and a span of input
         println!("Rule:    {:?}", pair.as_rule());
-        println!("Span:    {:?}", span);
-        println!("Text:    {}", span.as_str());
+        println!("Span:    {:?}", pair.as_span());
+        println!("Text:    {}", pair.as_str());
 
         // A pair can be converted to an iterator of the tokens which make it up:
         for inner_pair in pair.into_inner() {
-            let inner_span = inner_pair.clone().into_span();
             match inner_pair.as_rule() {
-                Rule::alpha => println!("Letter:  {}", inner_span.as_str()),
-                Rule::digit => println!("Digit:   {}", inner_span.as_str()),
+                Rule::alpha => println!("Letter:  {}", inner_pair.as_str()),
+                Rule::digit => println!("Digit:   {}", inner_pair.as_str()),
                 _ => unreachable!()
             };
         }
@@ -133,6 +139,25 @@
 Digit:   2
 ```
 
+### Defining multiple parsers in a single file
+The current automatic `Parser` derivation will produce the `Rule` enum
+which would have name conflicts if one tried to define multiple such structs
+that automatically derive `Parser`. One possible way around it is to put each
+parser struct in a separate namespace:
+
+```rust
+mod a {
+    #[derive(Parser)]
+    #[grammar = "a.pest"]
+    pub struct ParserA;
+}
+mod b {
+    #[derive(Parser)]
+    #[grammar = "b.pest"]
+    pub struct ParserB;
+}
+```
+
 ## Other features
 
 * Precedence climbing
@@ -143,15 +168,20 @@
 ## Projects using pest
 
 * [pest_meta](https://github.com/pest-parser/pest/blob/master/meta/src/grammar.pest) (bootstrapped)
+* [AshPaper](https://github.com/shnewto/ashpaper)
 * [brain](https://github.com/brain-lang/brain)
-* [Chelone](https://github.com/Aaronepower/chelone)
+* [cicada](https://github.com/mitnk/cicada)
 * [comrak](https://github.com/kivikakk/comrak)
+* [elastic-rs](https://github.com/cch123/elastic-rs)
 * [graphql-parser](https://github.com/Keats/graphql-parser)
 * [handlebars-rust](https://github.com/sunng87/handlebars-rust)
 * [hexdino](https://github.com/Luz/hexdino)
 * [Huia](https://gitlab.com/jimsy/huia/)
+* [insta](https://github.com/mitsuhiko/insta)
+* [jql](https://github.com/yamafaktory/jql)
 * [json5-rs](https://github.com/callum-oakley/json5-rs)
 * [mt940](https://github.com/svenstaro/mt940-rs)
+* [Myoxine](https://github.com/d3bate/myoxine)
 * [py_literal](https://github.com/jturner314/py_literal)
 * [rouler](https://github.com/jarcane/rouler)
 * [RuSh](https://github.com/lwandrebeck/RuSh)
@@ -160,6 +190,18 @@
 * [tera](https://github.com/Keats/tera)
 * [ui_gen](https://github.com/emoon/ui_gen)
 * [ukhasnet-parser](https://github.com/adamgreig/ukhasnet-parser)
+* [ZoKrates](https://github.com/ZoKrates/ZoKrates)
+* [Vector](https://github.com/timberio/vector)
+* [AutoCorrect](https://github.com/huacnlee/autocorrect)
+* [yaml-peg](https://github.com/aofdev/yaml-peg)
+* [qubit](https://github.com/abhimanyu003/qubit)
+* [caith](https://github.com/Geobert/caith) (a dice roller crate)
+* [Melody](https://github.com/yoav-lavi/melody)
+
+## Minimum Supported Rust Version (MSRV)
+
+This library should always compile with default features on **Rust 1.56.1** 
+or **Rust 1.61** with `const_prec_climber`.
 
 ## Special thanks
 
diff --git a/examples/base.pest b/examples/base.pest
new file mode 100644
index 0000000..c63d48a
--- /dev/null
+++ b/examples/base.pest
@@ -0,0 +1,2 @@
+WHITESPACE   =  _{ " " | "\t" | NEWLINE }
+int          =  @{ (ASCII_NONZERO_DIGIT ~ ASCII_DIGIT+ | ASCII_DIGIT) }
\ No newline at end of file
diff --git a/examples/calc.pest b/examples/calc.pest
new file mode 100644
index 0000000..3834973
--- /dev/null
+++ b/examples/calc.pest
@@ -0,0 +1,13 @@
+ program      =   { SOI ~ expr ~ EOI }
+   expr       =   { prefix* ~ primary ~ postfix* ~ (infix ~ prefix* ~ primary ~ postfix* )* }
+     infix    =  _{ add | sub | mul | div | pow }
+       add    =   { "+" } // Addition
+       sub    =   { "-" } // Subtraction
+       mul    =   { "*" } // Multiplication
+       div    =   { "/" } // Division
+       pow    =   { "^" } // Exponentiation
+     prefix   =  _{ neg }
+       neg    =   { "-" } // Negation
+     postfix  =  _{ fac }
+       fac    =   { "!" } // Factorial
+     primary  =  _{ int | "(" ~ expr ~ ")" }
\ No newline at end of file
diff --git a/examples/calc.rs b/examples/calc.rs
new file mode 100644
index 0000000..7071625
--- /dev/null
+++ b/examples/calc.rs
@@ -0,0 +1,110 @@
+mod parser {
+    use pest_derive::Parser;
+
+    #[derive(Parser)]
+    #[grammar = "../examples/base.pest"]
+    #[grammar = "../examples/calc.pest"]
+    pub struct Parser;
+}
+
+use parser::Rule;
+use pest::{
+    iterators::Pairs,
+    pratt_parser::{Assoc::*, Op, PrattParser},
+    Parser,
+};
+use std::io::{stdin, stdout, Write};
+
+fn parse_to_str(pairs: Pairs<Rule>, pratt: &PrattParser<Rule>) -> String {
+    pratt
+        .map_primary(|primary| match primary.as_rule() {
+            Rule::int => primary.as_str().to_owned(),
+            Rule::expr => parse_to_str(primary.into_inner(), pratt),
+            _ => unreachable!(),
+        })
+        .map_prefix(|op, rhs| match op.as_rule() {
+            Rule::neg => format!("(-{})", rhs),
+            _ => unreachable!(),
+        })
+        .map_postfix(|lhs, op| match op.as_rule() {
+            Rule::fac => format!("({}!)", lhs),
+            _ => unreachable!(),
+        })
+        .map_infix(|lhs, op, rhs| match op.as_rule() {
+            Rule::add => format!("({}+{})", lhs, rhs),
+            Rule::sub => format!("({}-{})", lhs, rhs),
+            Rule::mul => format!("({}*{})", lhs, rhs),
+            Rule::div => format!("({}/{})", lhs, rhs),
+            Rule::pow => format!("({}^{})", lhs, rhs),
+            _ => unreachable!(),
+        })
+        .parse(pairs)
+}
+
+fn parse_to_i32(pairs: Pairs<Rule>, pratt: &PrattParser<Rule>) -> i128 {
+    pratt
+        .map_primary(|primary| match primary.as_rule() {
+            Rule::int => primary.as_str().parse().unwrap(),
+            Rule::expr => parse_to_i32(primary.into_inner(), pratt),
+            _ => unreachable!(),
+        })
+        .map_prefix(|op, rhs| match op.as_rule() {
+            Rule::neg => -rhs,
+            _ => unreachable!(),
+        })
+        .map_postfix(|lhs, op| match op.as_rule() {
+            Rule::fac => (1..lhs + 1).product(),
+            _ => unreachable!(),
+        })
+        .map_infix(|lhs, op, rhs| match op.as_rule() {
+            Rule::add => lhs + rhs,
+            Rule::sub => lhs - rhs,
+            Rule::mul => lhs * rhs,
+            Rule::div => lhs / rhs,
+            Rule::pow => (1..rhs + 1).map(|_| lhs).product(),
+            _ => unreachable!(),
+        })
+        .parse(pairs)
+}
+
+fn main() {
+    let pratt = PrattParser::new()
+        .op(Op::infix(Rule::add, Left) | Op::infix(Rule::sub, Left))
+        .op(Op::infix(Rule::mul, Left) | Op::infix(Rule::div, Left))
+        .op(Op::infix(Rule::pow, Right))
+        .op(Op::postfix(Rule::fac))
+        .op(Op::prefix(Rule::neg));
+
+    let stdin = stdin();
+    let mut stdout = stdout();
+
+    loop {
+        let source = {
+            print!("> ");
+            let _ = stdout.flush();
+            let mut input = String::new();
+            let _ = stdin.read_line(&mut input);
+            input.trim().to_string()
+        };
+
+        let pairs = match parser::Parser::parse(Rule::program, &source) {
+            Ok(mut parse_tree) => {
+                parse_tree
+                    .next()
+                    .unwrap()
+                    .into_inner() // inner of program
+                    .next()
+                    .unwrap()
+                    .into_inner() // inner of expr
+            }
+            Err(err) => {
+                println!("Failed parsing input: {:}", err);
+                continue;
+            }
+        };
+
+        print!("{} => ", source);
+        print!("{} => ", parse_to_str(pairs.clone(), &pratt));
+        println!("{}", parse_to_i32(pairs.clone(), &pratt));
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index f60d5d9..a908897 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,7 +6,12 @@
 // license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. All files in the project carrying such notice may not be copied,
 // modified, or distributed except according to those terms.
-
+#![doc(
+    html_root_url = "https://docs.rs/pest_derive",
+    html_logo_url = "https://raw.githubusercontent.com/pest-parser/pest/master/pest-logo.svg",
+    html_favicon_url = "https://raw.githubusercontent.com/pest-parser/pest/master/pest-logo.svg"
+)]
+#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
 //! # pest. The Elegant Parser
 //!
 //! pest is a general purpose parser written in Rust with a focus on accessibility, correctness,
@@ -24,12 +29,16 @@
 //!
 //! * API reference on [docs.rs]
 //! * play with grammars and share them on our [fiddle]
-//! * leave feedback, ask questions, or greet us on [Gitter]
+//! * find previous common questions answered or ask questions on [GitHub Discussions]
+//! * leave feedback, ask questions, or greet us on [Gitter] or [Discord]
 //!
-//! [book]: https://pest-parser.github.io/book
+//! [book]: https://pest.rs/book
 //! [docs.rs]: https://docs.rs/pest
-//! [fiddle]: https://pest-parser.github.io/#editor
-//! [Gitter]: https://gitter.im/dragostis/pest
+//! [fiddle]: https://pest.rs/#editor
+//! [Gitter]: https://gitter.im/pest-parser/pest
+//! [Discord]: https://discord.gg/XEGACtWpT2
+//! [GitHub Discussions]: https://github.com/pest-parser/pest/discussions
+//!
 //!
 //! ## `.pest` files
 //!
@@ -55,7 +64,7 @@
 //!
 //! Comments start with `//` and end at the end of the line.
 //!
-//! ```ignore
+//! ```text
 //! // a comment
 //! ```
 //!
@@ -143,37 +152,50 @@
 //!
 //! 1. Terminals
 //!
-//!     | Terminal   | Usage                                                          |
-//!     |------------|----------------------------------------------------------------|
-//!     | `"a"`      | matches the exact string `"a"`                                 |
-//!     | `^"a"`     | matches the exact string `"a"` case insensitively (ASCII only) |
-//!     | `'a'..'z'` | matches one character between `'a'` and `'z'`                  |
-//!     | `a`        | matches rule `a`                                               |
+//! | Terminal   | Usage                                                          |
+//! |------------|----------------------------------------------------------------|
+//! | `"a"`      | matches the exact string `"a"`                                 |
+//! | `^"a"`     | matches the exact string `"a"` case insensitively (ASCII only) |
+//! | `'a'..'z'` | matches one character between `'a'` and `'z'`                  |
+//! | `a`        | matches rule `a`                                               |
 //!
 //! Strings and characters follow
 //! [Rust's escape mechanisms](https://doc.rust-lang.org/reference/tokens.html#byte-escapes), while
-//! identifiers can contain alpha-numeric characters and underscores (`_`), as long as they do not
+//! identifiers can contain alphanumeric characters and underscores (`_`), as long as they do not
 //! start with a digit.
 //!
 //! 2. Non-terminals
 //!
-//!     | Non-terminal          | Usage                                                      |
-//!     |-----------------------|------------------------------------------------------------|
-//!     | `(e)`                 | matches `e`                                                |
-//!     | `e1 ~ e2`             | matches the sequence `e1` `e2`                             |
-//!     | <code>e1 \| e2</code> | matches either `e1` or `e2`                                |
-//!     | `e*`                  | matches `e` zero or more times                             |
-//!     | `e+`                  | matches `e` one or more times                              |
-//!     | `e{n}`                | matches `e` exactly `n` times                              |
-//!     | `e{, n}`              | matches `e` at most `n` times                              |
-//!     | `e{n,} `              | matches `e` at least `n` times                             |
-//!     | `e{m, n}`             | matches `e` between `m` and `n` times inclusively          |
-//!     | `e?`                  | optionally matches `e`                                     |
-//!     | `&e`                  | matches `e` without making progress                        |
-//!     | `!e`                  | matches if `e` doesn't match without making progress       |
-//!     | `PUSH(e)`             | matches `e` and pushes it's captured string down the stack |
+//! | Non-terminal          | Usage                                                      |
+//! |-----------------------|------------------------------------------------------------|
+//! | `(e)`                 | matches `e`                                                |
+//! | `e1 ~ e2`             | matches the sequence `e1` `e2`                             |
+//! | <code>e1 \| e2</code> | matches either `e1` or `e2`                                |
+//! | `e*`                  | matches `e` zero or more times                             |
+//! | `e+`                  | matches `e` one or more times                              |
+//! | `e{n}`                | matches `e` exactly `n` times                              |
+//! | `e{, n}`              | matches `e` at most `n` times                              |
+//! | `e{n,}`               | matches `e` at least `n` times                             |
+//! | `e{m, n}`             | matches `e` between `m` and `n` times inclusively          |
+//! | `e?`                  | optionally matches `e`                                     |
+//! | `&e`                  | matches `e` without making progress                        |
+//! | `!e`                  | matches if `e` doesn't match without making progress       |
+//! | `PUSH(e)`             | matches `e` and pushes it's captured string down the stack |
 //!
-//!     where `e`, `e1`, and `e2` are expressions.
+//! where `e`, `e1`, and `e2` are expressions.
+//!
+//! Matching is greedy, without backtracking.  Note the difference in behavior for
+//! these two rules in matching identifiers that don't end in an underscore:
+//!
+//! ```ignore
+//! // input: ab_bb_b
+//!
+//! identifier = @{ "a" ~ ("b"|"_")* ~ "b" }
+//! // matches:      a     b_bb_b       nothing -> error!      
+//!
+//! identifier = @{ "a" ~ ("_"* ~ "b")* }
+//! // matches:      a     b, _bb, _b   in three repetitions
+//! ```
 //!
 //! Expressions can modify the stack only if they match the input. For example,
 //! if `e1` in the compound expression `e1 | e2` does not match the input, then
@@ -181,6 +203,10 @@
 //! `e1` did. Repetitions and optionals (`e*`, `e+`, `e{, n}`, `e{n,}`,
 //! `e{m,n}`, `e?`) can modify the stack each time `e` matches. The `!e` and `&e`
 //! expressions are a special case; they never modify the stack.
+//! Many languages have "keyword" tokens (e.g. if, for, while) as well as general
+//! tokens (e.g. identifier) that matches any word. In order to match a keyword,
+//! generally, you may need to restrict that is not immediately followed by another
+//! letter or digit (otherwise it would be matched as an identifier).
 //!
 //! ## Special rules
 //!
@@ -266,7 +292,7 @@
 //! ```
 //!
 //! For historical reasons, `PEEK_ALL` matches from top to bottom, while `PEEK[start..end]` matches
-//! from bottom to top. There is currectly no syntax to match a slice of the stack top to bottom.
+//! from bottom to top. There is currently no syntax to match a slice of the stack top to bottom.
 //!
 //! ## `Rule`
 //!
@@ -289,13 +315,10 @@
 //! * `ASCII` - matches a character from \x00..\x7f
 //! * `NEWLINE` - matches either "\n" or "\r\n" or "\r"
 
-#![doc(html_root_url = "https://docs.rs/pest_derive")]
-
-extern crate pest_generator;
-extern crate proc_macro;
-
 use proc_macro::TokenStream;
 
+/// The main method that's called by the proc macro
+/// (a wrapper around `pest_generator::derive_parser`)
 #[proc_macro_derive(Parser, attributes(grammar, grammar_inline))]
 pub fn derive_parser(input: TokenStream) -> TokenStream {
     pest_generator::derive_parser(input.into(), true).into()
diff --git a/tests/grammar.pest b/tests/grammar.pest
index 43a7b8c..b24d477 100644
--- a/tests/grammar.pest
+++ b/tests/grammar.pest
@@ -22,6 +22,7 @@
 sequence_nested = { string ~ string }
 sequence_compound_nested = ${ sequence_nested }
 choice = { string | range }
+choice_prefix = { | string | range }
 optional = { string? }
 repeat = { string* }
 repeat_atomic = @{ string* }
@@ -36,6 +37,9 @@
 repeat_max_atomic = @{ string{, 2} }
 soi_at_start = { SOI ~ string }
 repeat_mutate_stack = { (PUSH('a'..'c') ~ ",")* ~ POP ~ POP ~ POP }
+repeat_mutate_stack_pop_all = { (PUSH('a'..'c') ~ ",")* ~ POP_ALL }
+will_fail = { repeat_mutate_stack_pop_all ~ "FAIL" }
+stack_resume_after_fail = { will_fail | repeat_mutate_stack_pop_all }
 peek_ = { PUSH(range) ~ PUSH(range) ~ PEEK ~ PEEK }
 peek_all = { PUSH(range) ~ PUSH(range) ~ PEEK_ALL }
 peek_slice_23 = { PUSH(range) ~ PUSH(range) ~ PUSH(range) ~ PUSH(range) ~ PUSH(range) ~ PEEK[1..-2] }
@@ -59,6 +63,11 @@
 unicode = { XID_START ~ XID_CONTINUE* }
 SYMBOL = { "shadows builtin" }
 
+han = { HAN+ }
+hangul = { HANGUL+ }
+hiragana = { HIRAGANA+ }
+arabic = { ARABIC+ }
+
 WHITESPACE = _{ " " }
 COMMENT = _{ "$"+ }
 
diff --git a/tests/grammar.rs b/tests/grammar.rs
index 799beb7..cf5a4a6 100644
--- a/tests/grammar.rs
+++ b/tests/grammar.rs
@@ -6,6 +6,9 @@
 // license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. All files in the project carrying such notice may not be copied,
 // modified, or distributed except according to those terms.
+#![cfg_attr(not(feature = "std"), no_std)]
+extern crate alloc;
+use alloc::{format, vec::Vec};
 
 #[macro_use]
 extern crate pest;
@@ -13,7 +16,7 @@
 extern crate pest_derive;
 
 #[derive(Parser)]
-#[grammar = "../tests/grammar.pest"]
+#[grammar = "tests/grammar.pest"]
 struct GrammarParser;
 
 #[test]
@@ -246,6 +249,20 @@
 }
 
 #[test]
+fn choice_prefix() {
+    parses_to! {
+        parser: GrammarParser,
+        input: "abc",
+        rule: Rule::choice_prefix,
+        tokens: [
+            choice_prefix(0, 3, [
+                string(0, 3)
+            ])
+        ]
+    };
+}
+
+#[test]
 fn optional_string() {
     parses_to! {
         parser: GrammarParser,
@@ -783,6 +800,20 @@
 }
 
 #[test]
+fn stack_resume_after_fail() {
+    parses_to! {
+        parser: GrammarParser,
+        input: "a,b,c,cba",
+        rule: Rule::stack_resume_after_fail,
+        tokens: [
+            stack_resume_after_fail(0, 9, [
+                repeat_mutate_stack_pop_all(0, 9)
+            ])
+        ]
+    };
+}
+
+#[test]
 fn checkpoint_restore() {
     parses_to! {
         parser: GrammarParser,
diff --git a/tests/grammar_inline.rs b/tests/grammar_inline.rs
index 2cc730a..549a814 100644
--- a/tests/grammar_inline.rs
+++ b/tests/grammar_inline.rs
@@ -4,6 +4,10 @@
 // option. All files in the project carrying such notice may not be copied,
 // modified, or distributed except according to those terms.
 
+#![cfg_attr(not(feature = "std"), no_std)]
+extern crate alloc;
+use alloc::{format, vec::Vec};
+
 #[macro_use]
 extern crate pest;
 #[macro_use]
diff --git a/tests/implicit.pest b/tests/implicit.pest
new file mode 100644
index 0000000..18ebf7e
--- /dev/null
+++ b/tests/implicit.pest
@@ -0,0 +1,14 @@
+program = _{ SOI ~ implicit ~ EOI  }
+implicit= ${ or ~ (WHITESPACE+ ~ or )* }
+
+or  = !{ and ~ (or_op ~ and)+ | and }
+and = { comp ~ (and_op ~ comp)+ | comp }
+comp = { array ~ eq_op ~ array | array }
+
+array = ${ term }
+
+term = _{ ASCII_ALPHANUMERIC+ }
+or_op = { "||" }
+and_op = { "&&" }
+eq_op = { "=" }
+WHITESPACE = _{ " " | "\t" | NEWLINE }
\ No newline at end of file
diff --git a/tests/implicit.rs b/tests/implicit.rs
new file mode 100644
index 0000000..8ad5a7e
--- /dev/null
+++ b/tests/implicit.rs
@@ -0,0 +1,25 @@
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. All files in the project carrying such notice may not be copied,
+// modified, or distributed except according to those terms.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+extern crate alloc;
+extern crate pest;
+extern crate pest_derive;
+
+use pest::Parser;
+use pest_derive::Parser;
+
+#[derive(Parser)]
+#[grammar = "../tests/implicit.pest"]
+struct TestImplicitParser;
+
+#[test]
+fn test_implicit_whitespace() {
+    // this failed to parse due to a bug in the optimizer
+    // see: https://github.com/pest-parser/pest/issues/762#issuecomment-1375374868
+    let successful_parse = TestImplicitParser::parse(Rule::program, "a a");
+    assert!(successful_parse.is_ok());
+}
diff --git a/tests/lists.rs b/tests/lists.rs
index 4ba0eff..3678b60 100644
--- a/tests/lists.rs
+++ b/tests/lists.rs
@@ -7,6 +7,10 @@
 // option. All files in the project carrying such notice may not be copied,
 // modified, or distributed except according to those terms.
 
+#![cfg_attr(not(feature = "std"), no_std)]
+extern crate alloc;
+use alloc::{format, vec::Vec};
+
 #[macro_use]
 extern crate pest;
 #[macro_use]
diff --git a/tests/reporting.rs b/tests/reporting.rs
index aa0a974..8a41bef 100644
--- a/tests/reporting.rs
+++ b/tests/reporting.rs
@@ -7,6 +7,10 @@
 // option. All files in the project carrying such notice may not be copied,
 // modified, or distributed except according to those terms.
 
+#![cfg_attr(not(feature = "std"), no_std)]
+extern crate alloc;
+use alloc::vec;
+
 #[macro_use]
 extern crate pest;
 #[macro_use]