├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── context.rs ├── error.rs ├── final_parser.rs ├── lib.rs ├── multi.rs ├── parser_ext.rs └── tag.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Unreleased 4 | 5 | ### Added 6 | 7 | - Added `Parser::opt_precedes` and `Parser::opt_preceded_by` 8 | - Added `ContextError`, an improved version of nom's `ContextError` that allows for any kind of context to be attached 9 | - Added `GenericErrorTree`, a version of `ErrorTree` that is generic over the tag, context, and external error types. `ErrorTree` is now a type alias for this type. 10 | 11 | ### Changed 12 | 13 | - Removed all feature flags for now. They may come back later, but probably not until someone cites a desire for nom-supreme in a no-std context. 14 | - `parse_from_str_cut` now supports any input type, like `parse_from_str`. 15 | 16 | ### Internal 17 | 18 | - Upgrade to brownstone 3, for substantial improvement to array parser implementations 19 | 20 | ### Removed 21 | 22 | - Removed the global `parse_from_str` in favor of `ParserExt::parse_from_str`. 23 | 24 | ## 0.7.0 25 | 26 | ### Changed 27 | 28 | - Add `std` and `error` features 29 | - `mod error` is gated behind `error` and requires `std` 30 | 31 | ## 0.6.0 32 | 33 | ### Changed 34 | 35 | - Add compatibility with Nom 7 36 | - Nom 6 may be dropped in a future release, but for now there haven't been any breaking changes that are relevant to nom-supreme 37 | - The separated_terminated parsers no longer add their own error context 38 | - Minor internal changes to errors 39 | 40 | ## 0.5.0 41 | 42 | ### Changed 43 | 44 | - `parse_from_str` now works with parsers over any input type. 45 | 46 | ## 0.4.6 47 | 48 | ### Added 49 | 50 | - Added `array` and `separated_array` to `ParserExt` 51 | 52 | ### Internal 53 | 54 | - Minor implementation refactors 55 | - Add `brownstone` dependency 56 | 57 | ## 0.4.5 58 | 59 | ### Added 60 | 61 | - Add cutting versions of `Result` combinators, which return `Failure` in the event that the mapping function returns an `Err`. 62 | - Add `map_res_cut` (thanks @loewenheim) 63 | - Add `parse_from_str_cut` 64 | - Reexport `ParserExt` at the toplevel 65 | 66 | ### Fixed 67 | 68 | - Fixed some edge case bugs in error handling in `multi` 69 | 70 | ### Internal 71 | 72 | - Various internal refactorings of stuff in `ParserExt` 73 | - Remove `cascade` dependency 74 | 75 | ## 0.4.4 76 | 77 | ### Added 78 | 79 | - Add `ExtractContext for Result` 80 | - Add `collect_separated_terminated` 81 | 82 | ### Documentation 83 | 84 | - Documentation refactoring in `multi` 85 | 86 | ### Changed 87 | 88 | - Internal code style fixes 89 | - Implementation improvements for parsers in `multi` 90 | 91 | ## 0.4.3 92 | 93 | ### Added 94 | 95 | - Add `with_recognized` combinator to `ParserExt`. 96 | 97 | ## 0.4.2 98 | 99 | ### Added 100 | 101 | - Implement `ErrorConvert` for `ErrorTree`, enabling its use in bit parsers 102 | 103 | ### Documentation 104 | 105 | - Fix broken links in documentation. 106 | - Fix incorrect example parser in `ErrorTree` doctests. 107 | - Add additional example content to `ErrorTree`. 108 | - Add additional example to `ParserExt::parse_from_str`. 109 | 110 | ## 0.4.1 111 | 112 | ### Documentation 113 | 114 | - Fixed major typo in `ErrorTree` documentation. 115 | 116 | ## 0.4.0 117 | 118 | ### Changed 119 | 120 | - Changes to how `ErrorTree` and `Expectation` handle `ErrorKind::Eof`: 121 | - Because `ErrorKind::Eof` is used interchangeably by some nom parsers to refer to either "expected eof" or "*un*expected eof", we examine the input via InputLength to determine which variant is intended 122 | - Removed `Expectation::Byte` and `Expectation::AnyChar`, replaced them with `Expectation::Something`. 123 | - Major changes to `ErrorTree::Stack` 124 | - Now separately represents the context stack and base error as different types. 125 | - Split `BaseErrorKind` into `BaseErrorKind` and 126 | - `BaseErrorKind::External` now reports the error message on an indented line. 127 | 128 | ### Internal 129 | 130 | - Several updates to interior code, unit tests, and doctests, all related to the `ErrorTree` changes. 131 | 132 | ### Documentation 133 | 134 | - Proofread edits of most of the `nom_supreme::error` docs. 135 | - Added several doctests for `ErrorTree`. 136 | 137 | ## 0.3.1 138 | 139 | ### Added 140 | 141 | - `ParserExt::parse_from_str` 142 | 143 | ### Tests 144 | 145 | - Add comprehensive unit tests to `parse_separated_terminated` 146 | 147 | ### Internal 148 | 149 | - Bump to [cool_asserts] 1.0.3 150 | - Reimplement `parse_from_str` based on `ParserExt` 151 | 152 | ## 0.3.0 153 | 154 | ### Added 155 | 156 | - `parse_separated_terminated` now works correctly as documented: it smartly detects when the parser is hanging and bail if necessary. 157 | - `parse_separated_terminated` is now slightly smarter about error cases. If the separator successfully parses a 0-length match, the next item error will include the terminator error as well. 158 | 159 | ## 0.2.0 160 | 161 | ### Added 162 | 163 | - `ParserExt::by_ref`, which borrows a parser so that it can have combinators applied to it without giving up ownership. 164 | 165 | ### Changed 166 | 167 | - **(BREAKING)** Reworked `ParserExt::delimited_by`: 168 | - Removed original `delimited_by` in favor of simply using `.preceded_by(..).terminated(..)`. 169 | - Renamed `ParserExt::delimited_by_both` to `ParserExt::delimited_by`, and added a dedicated parser type, such that it no longer requires `Clone` on the delimiter parser. 170 | 171 | ### Tests 172 | 173 | - Added doctests to all `ParserExt` methods. 174 | 175 | ### Documentation 176 | 177 | - Fixed numerous broken documentation links. 178 | 179 | ## 0.1.4 180 | 181 | ### Added 182 | 183 | - `.peek()` combinator to `ParserExt` 184 | - `.not()` combinator to `ParserExt` 185 | - `Expectation::AnyChar` and `Expectation::Byte` 186 | 187 | ### Fixed 188 | 189 | - Broken doctests 190 | 191 | ## 0.1.3 192 | 193 | No code changes 194 | 195 | ### Documentation 196 | 197 | - `parse_from_str` example now actually shows `parse_from_str` 198 | 199 | ## 0.1.2 200 | 201 | - Changelog started 202 | 203 | [cool_asserts](https://docs.rs/cool_asserts/) 204 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nom-supreme" 3 | version = "0.8.0" 4 | authors = ["Nathan West "] 5 | edition = "2018" 6 | 7 | readme = "README.md" 8 | license = "MPL-2.0" 9 | description = "A collection of excellent utilities for nom" 10 | repository = "https://github.com/Lucretiel/nom-supreme" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | memchr = "2.3.4" 16 | nom = ">=6.0.1, <8.0.0" 17 | brownstone = "3.0.0" 18 | 19 | # Used for printing errors 20 | indent_write = "2.0.0" 21 | joinery = "2.0.0" 22 | 23 | [dev-dependencies] 24 | cool_asserts = "1.0.3" 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nom-supreme 2 | 3 | A collection of utilities for a superior nom experience. See [docs.rs](https://docs.rs/nom-supreme/latest/nom_supreme/) for details. 4 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | //! Enhanced context combinator for nom. 2 | //! 3 | //! This module introduces an updated, [`ContextError`], that allows for 4 | //! arbitrary types of data to be attached as context to errors, rather than 5 | //! requiring `&'static str`. 6 | 7 | use nom::error::{Error, ErrorKind, VerboseError, VerboseErrorKind}; 8 | 9 | /// Updated version of [`nom::error::ContextError`]. Allows for arbitrary 10 | /// context types, rather than requiring `&'static str` 11 | pub trait ContextError: Sized { 12 | /// Create a new error from an input position, a context, and an existing 13 | /// error. This is used by the [`.context`][crate::ParserExt::context] 14 | /// combinator to add friendly information to errors when backtracking 15 | /// through a parse tree. 16 | fn add_context(location: I, ctx: C, other: Self) -> Self; 17 | } 18 | 19 | impl ContextError for () { 20 | fn add_context(_location: I, _ctx: C, _other: Self) -> Self {} 21 | } 22 | 23 | impl ContextError for (I, ErrorKind) { 24 | fn add_context(_location: I, _ctx: C, other: Self) -> Self { 25 | other 26 | } 27 | } 28 | 29 | impl ContextError for Error { 30 | fn add_context(_location: I, _ctx: C, other: Self) -> Self { 31 | other 32 | } 33 | } 34 | 35 | impl ContextError for VerboseError { 36 | fn add_context(location: I, ctx: &'static str, mut other: Self) -> Self { 37 | other 38 | .errors 39 | .push((location, VerboseErrorKind::Context(ctx))); 40 | 41 | other 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | //! An error type, [`ErrorTree`], designed to retain much more useful 2 | //! information about parse failures than the built-in nom error types. 3 | //! Requires the `error` feature to be enabled. 4 | 5 | use std::{ 6 | error::Error, 7 | fmt::{self, Debug, Display, Formatter, Write}, 8 | }; 9 | 10 | use indent_write::fmt::IndentWriter; 11 | use joinery::JoinableIterator; 12 | use nom::{ 13 | error::{ErrorKind as NomErrorKind, FromExternalError, ParseError}, 14 | ErrorConvert, InputLength, 15 | }; 16 | 17 | use crate::{ 18 | context::ContextError, 19 | final_parser::{ExtractContext, RecreateContext}, 20 | tag::TagError, 21 | }; 22 | 23 | /// Enum for generic things that can be expected by nom parsers 24 | /// 25 | /// Certain nom parsers (think [`digit1`], [`tag`], or [`space1`]) are "base 26 | /// level" in the sense that, rather than combining subparsers, they scan for a 27 | /// specific character or specific kind of character. This enum tracks the 28 | /// different kinds of things that can be expected by these base parses. 29 | /// 30 | /// Printing an expectation via [`Display`] will only include the thing that 31 | /// was expected, in a form suitable for being prefixed with "expected" or 32 | /// suffixed with "was expected". 33 | /// 34 | /// This enum is non-exhaustive; it is intended to represent everything parse 35 | /// errors where we know *specifically* what was expected. For instance, 36 | /// [`take_while`] cannot create an [`Expectation`], because it can't 37 | /// meaningfully report what its subparser is expecting. 38 | /// 39 | /// [`digit1`]: nom::character::complete::digit1 40 | /// [`tag`]: crate::tag::complete::tag 41 | /// [`space1`]: nom::character::complete::space1 42 | /// [`take_while`]: nom::bytes::complete::take_while 43 | #[non_exhaustive] 44 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 45 | pub enum Expectation { 46 | /// A tag was expected. 47 | Tag(T), 48 | 49 | /// A specific character was expected. 50 | Char(char), 51 | 52 | /// An ASCII letter (`[a-zA-Z]`) was expected. 53 | Alpha, 54 | 55 | /// A decimal digit (`[0-9]`) was expected. 56 | Digit, 57 | 58 | /// A hexadecimal digit (`[0-9a-fA-F]`) was expected. 59 | HexDigit, 60 | 61 | /// An octal digit (`[0-7]`) was expected. 62 | OctDigit, 63 | 64 | /// An alphanumeric character (`[0-9a-zA-Z]`) was expected. 65 | AlphaNumeric, 66 | 67 | /// A space or tab was expected. 68 | Space, 69 | 70 | /// A space, tab, newline, or carriage return was expected. 71 | Multispace, 72 | 73 | /// `"\r\n"` was expected. 74 | CrLf, 75 | 76 | /// Eof was expected. 77 | Eof, 78 | 79 | /// Expected something; ie, not Eof. 80 | Something, 81 | } 82 | 83 | impl Display for Expectation { 84 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 85 | match *self { 86 | Expectation::Tag(ref tag) => write!(f, "{:?}", tag), 87 | Expectation::Char(c) => write!(f, "{:?}", c), 88 | Expectation::Alpha => write!(f, "an ascii letter"), 89 | Expectation::Digit => write!(f, "an ascii digit"), 90 | Expectation::HexDigit => write!(f, "a hexadecimal digit"), 91 | Expectation::OctDigit => write!(f, "an octal digit"), 92 | Expectation::AlphaNumeric => write!(f, "an ascii alphanumeric character"), 93 | Expectation::Space => write!(f, "a space or tab"), 94 | Expectation::Multispace => write!(f, "whitespace"), 95 | Expectation::Eof => write!(f, "eof"), 96 | Expectation::CrLf => write!(f, "CRLF"), 97 | Expectation::Something => write!(f, "not eof"), 98 | } 99 | } 100 | } 101 | 102 | /// These are the different specific things that can go wrong at a particular 103 | /// location during a nom parse. Many of these are collected into an 104 | /// [`ErrorTree`]. 105 | /// 106 | /// - `T` is the tag type, such as &'static str. 107 | /// - `E` is the external error type, such as `Box`. 108 | #[derive(Debug)] 109 | pub enum BaseErrorKind { 110 | /// Something specific was expected, such as a specific 111 | /// [character][Expectation::Char] or any [digit](Expectation::Digit). 112 | /// See [`Expectation`] for details. 113 | Expected(Expectation), 114 | 115 | /// A nom parser failed. 116 | Kind(NomErrorKind), 117 | 118 | /// An error outside of nom occurred during parsing; for instance, as a 119 | /// result of an error during [`map_res`]. 120 | /// 121 | /// [`map_res`]: crate::parser_ext::ParserExt::map_res 122 | // Design note: I've gone back and forth on whether or not to exclude the 123 | // ErrorKind from this variant. Right now I'm doing so, because it seems 124 | // like in practice it's *always* MapRes. 125 | External(E), 126 | } 127 | 128 | impl Display for BaseErrorKind { 129 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 130 | match *self { 131 | BaseErrorKind::Expected(ref expectation) => write!(f, "expected {}", expectation), 132 | BaseErrorKind::External(ref err) => { 133 | writeln!(f, "external error:")?; 134 | let mut f = IndentWriter::new(" ", f); 135 | write!(f, "{}", err) 136 | } 137 | BaseErrorKind::Kind(kind) => write!(f, "error in {:?}", kind), 138 | } 139 | } 140 | } 141 | 142 | /// Context that can appear in a [stack][GenericErrorTree::Stack], above a base 143 | /// [`ErrorTree`]. Stack contexts are attached by parser combinators to errors 144 | /// from their subparsers during stack unwinding. 145 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 146 | pub enum StackContext { 147 | /// A nom combinator attached an [`ErrorKind`][NomErrorKind] as context 148 | /// for a subparser error. 149 | Kind(NomErrorKind), 150 | 151 | /// The [`context`][crate::parser_ext::ParserExt::context] combinator 152 | /// attached a message as context for a subparser error. 153 | Context(C), 154 | } 155 | 156 | impl Display for StackContext { 157 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 158 | match *self { 159 | StackContext::Kind(kind) => write!(f, "while parsing {:?}", kind), 160 | StackContext::Context(ref ctx) => write!(f, "in section {:?}", ctx), 161 | } 162 | } 163 | } 164 | 165 | /// A comprehensive tree of nom errors describing a parse failure. 166 | /// 167 | /// This Error type is designed to be [`VerboseError`]`++`. While 168 | /// [`VerboseError`] can represent a *stack* of errors, this type can represent 169 | /// a full tree. In addition to representing a particular specific parse error, 170 | /// it can also represent a stack of nested error contexts (for instance, as 171 | /// provided by [`context`][crate::ParserExt::context]), or a list of 172 | /// alternatives that were all tried individually by [`alt`][nom::branch::alt] 173 | /// and all failed. 174 | /// 175 | /// In general, the design goal for this type is to discard as little useful 176 | /// information as possible. That being said, many [`ErrorKind`] variants add 177 | /// very little useful contextual information to error traces; for example, 178 | /// [`ErrorKind::Alt`] doesn't add any interesting context to an 179 | /// [`ErrorTree::Alt`], and its presence in a stack precludes merging together 180 | /// adjacent sets of [`ErrorTree::Alt`] siblings. 181 | /// 182 | /// # Examples 183 | /// 184 | /// ## Base parser errors 185 | /// 186 | /// An `ErrorTree::Base` is an error that occurred at the "bottom" of the stack, 187 | /// from a parser looking for 1 specific kind of thing. 188 | /// 189 | /// ```rust 190 | /// use cool_asserts::assert_matches; 191 | /// use nom::{Parser, Err}; 192 | /// use nom::character::complete::{digit1, char}; 193 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation}; 194 | /// use nom_supreme::parser_ext::ParserExt; 195 | /// 196 | /// let err: Err> = digit1.parse("abc").unwrap_err(); 197 | /// 198 | /// assert_matches!(err, Err::Error(ErrorTree::Base{ 199 | /// location: "abc", 200 | /// kind: BaseErrorKind::Expected(Expectation::Digit), 201 | /// })); 202 | /// 203 | /// let err: Err> = char('a').and(char('b')).parse("acb").unwrap_err(); 204 | /// 205 | /// assert_matches!(err, Err::Error(ErrorTree::Base{ 206 | /// location: "cb", 207 | /// kind: BaseErrorKind::Expected(Expectation::Char('b')), 208 | /// })); 209 | /// ``` 210 | /// 211 | /// ## Stacks 212 | /// 213 | /// An [`ErrorTree::Stack`] is created when a parser combinator—typically 214 | /// [`context`]—attaches additional error context to a subparser error. It can 215 | /// have any [`ErrorTree`] at the base of the stack. 216 | /// 217 | /// ```rust 218 | /// use cool_asserts::assert_matches; 219 | /// use nom::{Parser, Err}; 220 | /// use nom::character::complete::{alpha1, space1, char,}; 221 | /// use nom::sequence::{separated_pair, delimited}; 222 | /// use nom_supreme::parser_ext::ParserExt; 223 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation}; 224 | /// 225 | /// // Parse a single identifier, defined as just a string of letters. 226 | /// let identifier = alpha1.context("identifier"); 227 | /// 228 | /// // Parse a pair of identifiers, separated by whitespace 229 | /// let identifier_pair = separated_pair(identifier, space1, identifier) 230 | /// .context("identifier pair"); 231 | /// 232 | /// // Parse a pair of identifiers in parenthesis. 233 | /// let mut parenthesized = delimited(char('('), identifier_pair, char(')')) 234 | /// .context("parenthesized"); 235 | /// 236 | /// let err: Err> = parenthesized.parse("(abc 123)").unwrap_err(); 237 | /// 238 | /// assert_matches!(err, Err::Error(ErrorTree::Stack { 239 | /// base, 240 | /// contexts, 241 | /// }) => { 242 | /// assert_matches!(*base, ErrorTree::Base { 243 | /// location: "123)", 244 | /// kind: BaseErrorKind::Expected(Expectation::Alpha) 245 | /// }); 246 | /// 247 | /// assert_eq!(contexts, [ 248 | /// ("123)", StackContext::Context("identifier")), 249 | /// ("abc 123)", StackContext::Context("identifier pair")), 250 | /// ("(abc 123)", StackContext::Context("parenthesized")), 251 | /// ]); 252 | /// }); 253 | /// ``` 254 | /// 255 | /// ## Alternatives 256 | /// 257 | /// An [`ErrorTree::Alt`] is created when a series of parsers are all tried, 258 | /// and all of them fail. Most commonly this will happen via the 259 | /// [`alt`][nom::branch::alt] combinator or the equivalent [`.or`] postfix 260 | /// combinator. When all of these subparsers fail, their errors (each 261 | /// individually their own `ErrorTree`) are aggregated into an 262 | /// [`ErrorTree::Alt`], indicating that "any one of these things were 263 | /// expected." 264 | /// 265 | /// ```rust 266 | /// use cool_asserts::assert_matches; 267 | /// use nom::{Parser, Err}; 268 | /// use nom::branch::alt; 269 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation}; 270 | /// use nom_supreme::parser_ext::ParserExt; 271 | /// use nom_supreme::tag::complete::tag; 272 | /// 273 | /// let parse_bool = alt(( 274 | /// tag("true").value(true), 275 | /// tag("false").value(false), 276 | /// )); 277 | /// 278 | /// let mut parse_null_bool = alt(( 279 | /// parse_bool.map(Some), 280 | /// tag("null").value(None), 281 | /// )); 282 | /// 283 | /// assert_eq!(parse_null_bool.parse("true").unwrap(), ("", Some(true))); 284 | /// assert_eq!(parse_null_bool.parse("false").unwrap(), ("", Some(false))); 285 | /// assert_eq!(parse_null_bool.parse("null").unwrap(), ("", None)); 286 | /// 287 | /// let err: Err> = parse_null_bool.parse("123").unwrap_err(); 288 | /// 289 | /// // This error communicates to the caller that any one of "true", "false", 290 | /// // or "null" was expected at that location. 291 | /// assert_matches!(err, Err::Error(ErrorTree::Alt(choices)) => { 292 | /// assert_matches!(choices.as_slice(), [ 293 | /// ErrorTree::Base { 294 | /// location: "123", 295 | /// kind: BaseErrorKind::Expected(Expectation::Tag("true"))}, 296 | /// ErrorTree::Base { 297 | /// location: "123", 298 | /// kind: BaseErrorKind::Expected(Expectation::Tag("false"))}, 299 | /// ErrorTree::Base { 300 | /// location: "123", 301 | /// kind: BaseErrorKind::Expected(Expectation::Tag("null"))}, 302 | /// ]) 303 | /// }); 304 | /// ``` 305 | /// 306 | /// ## Contexts and Alternatives 307 | /// 308 | /// Because [`Stack`] and [`Alt`] recursively contain [`ErrorTree`] errors from 309 | /// subparsers, they can be can combined to create error trees of arbitrary 310 | /// complexity. 311 | /// 312 | /// ```rust 313 | /// use cool_asserts::assert_matches; 314 | /// use nom::{Parser, Err}; 315 | /// use nom::branch::alt; 316 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation}; 317 | /// use nom_supreme::parser_ext::ParserExt; 318 | /// use nom_supreme::tag::complete::tag; 319 | /// 320 | /// let parse_bool = alt(( 321 | /// tag("true").value(true), 322 | /// tag("false").value(false), 323 | /// )).context("bool"); 324 | /// 325 | /// let mut parse_null_bool = alt(( 326 | /// parse_bool.map(Some), 327 | /// tag("null").value(None).context("null"), 328 | /// )).context("null or bool"); 329 | /// 330 | /// assert_eq!(parse_null_bool.parse("true").unwrap(), ("", Some(true))); 331 | /// assert_eq!(parse_null_bool.parse("false").unwrap(), ("", Some(false))); 332 | /// assert_eq!(parse_null_bool.parse("null").unwrap(), ("", None)); 333 | /// 334 | /// let err: Err> = parse_null_bool.parse("123").unwrap_err(); 335 | /// 336 | /// assert_matches!(err, Err::Error(ErrorTree::Stack{base, contexts}) => { 337 | /// assert_eq!(contexts, [("123", StackContext::Context("null or bool"))]); 338 | /// assert_matches!(*base, ErrorTree::Alt(choices) => { 339 | /// assert_matches!(&choices[0], ErrorTree::Stack{base, contexts} => { 340 | /// assert_eq!(contexts, &[("123", StackContext::Context("bool"))]); 341 | /// assert_matches!(&**base, ErrorTree::Alt(choices) => { 342 | /// assert_matches!(&choices[0], ErrorTree::Base { 343 | /// location: "123", 344 | /// kind: BaseErrorKind::Expected(Expectation::Tag("true")) 345 | /// }); 346 | /// assert_matches!(&choices[1], ErrorTree::Base { 347 | /// location: "123", 348 | /// kind: BaseErrorKind::Expected(Expectation::Tag("false")) 349 | /// }); 350 | /// }); 351 | /// }); 352 | /// assert_matches!(&choices[1], ErrorTree::Stack{base, contexts} => { 353 | /// assert_eq!(contexts, &[("123", StackContext::Context("null"))]); 354 | /// assert_matches!(&**base, ErrorTree::Base { 355 | /// location: "123", 356 | /// kind: BaseErrorKind::Expected(Expectation::Tag("null")) 357 | /// }); 358 | /// }); 359 | /// }); 360 | /// }); 361 | /// ``` 362 | /// 363 | /// # Display formatting 364 | /// 365 | /// TODO WRITE THIS SECTION 366 | /// 367 | /// [`.or`]: nom::Parser::or 368 | /// [`Alt`]: GenericErrorTree::Alt 369 | /// [`context`]: nom::error::context 370 | /// [`ErrorKind::Alt`]: nom::error::ErrorKind::Alt 371 | /// [`ErrorKind`]: nom::error::ErrorKind 372 | /// [`ErrorTree::Alt`]: GenericErrorTree::Alt 373 | /// [`ErrorTree::Base`]: GenericErrorTree::Base 374 | /// [`ErrorTree::Stack`]: GenericErrorTree::Stack 375 | /// [`Stack`]: GenericErrorTree::Stack 376 | /// [`VerboseError`]: nom::error::VerboseError 377 | pub type ErrorTree = 378 | GenericErrorTree>; 379 | 380 | /// Generic version of [`ErrorTree`], which allows for arbitrary `Tag`, `Context`, 381 | /// and `ExternalError` types. See [`ErrorTree`] for more extensive docs and 382 | /// examples. 383 | /// 384 | /// - `Tag` is typically something like `&'static str` or `&'static [u8]`. 385 | /// - `Context` is typically `&'static str`, and it must be in order to 386 | /// interoperate with nom's [`context`][nom::error::context] combinator. 387 | /// `nom-supreme` provides a more generic [`.context`][crate::ParserExt::context] 388 | /// combinator that allows for any kind of context to be attached to an error. 389 | /// - `Error` can usually be nothing, as it's unusual for nom parsers to 390 | /// require external errors. `Box` is 391 | /// a common catch-all. 392 | #[derive(Debug)] 393 | pub enum GenericErrorTree { 394 | /// A specific error event at a specific location. Often this will indicate 395 | /// that something like a tag or character was expected at that location. 396 | Base { 397 | /// The location of this error in the input 398 | location: Location, 399 | 400 | /// The specific error that occurred 401 | kind: BaseErrorKind, 402 | }, 403 | 404 | /// A stack indicates a chain of error contexts was provided. The stack 405 | /// should be read "backwards"; that is, errors *earlier* in the `Vec` 406 | /// occurred "sooner" (deeper in the call stack). 407 | Stack { 408 | /// The original error 409 | base: Box, 410 | 411 | /// The stack of contexts attached to that error 412 | contexts: Vec<(Location, StackContext)>, 413 | }, 414 | 415 | /// A series of parsers were tried at the same location (for instance, via 416 | /// the [`alt`](nom::branch::alt) combinator) and all of them failed. All 417 | /// of the errors in this set are "siblings". 418 | Alt(Vec), 419 | // TODO: in a future version of nom-supreme, elaborate on the specific 420 | // type combinations here. For instance: 421 | // - Alt can only contain Stack or Base 422 | // - Stack has a single Base or Alt, followed by a series of contexts 423 | // (Context or Kind) 424 | } 425 | 426 | impl GenericErrorTree { 427 | /// Helper for `map_locations`. Because it operates recursively, this 428 | /// method uses an `&mut impl FnMut`, which can be reborrowed. 429 | fn map_locations_ref( 430 | self, 431 | convert_location: &mut impl FnMut(I) -> I2, 432 | ) -> GenericErrorTree { 433 | // TODO: does the recursive nature of this function present a potential 434 | // security risk? Consider replacing it with a breadth-first algorithm, 435 | // or capping the maximum recursion depth. Note, though, that recursion 436 | // only happens when alternating between different *kinds* of 437 | // ErrorTree; nested groups of Alt or Stack are flattened. 438 | match self { 439 | GenericErrorTree::Base { location, kind } => GenericErrorTree::Base { 440 | location: convert_location(location), 441 | kind, 442 | }, 443 | GenericErrorTree::Stack { base, contexts } => GenericErrorTree::Stack { 444 | base: Box::new(base.map_locations_ref(convert_location)), 445 | contexts: contexts 446 | .into_iter() 447 | .map(|(location, context)| (convert_location(location), context)) 448 | .collect(), 449 | }, 450 | GenericErrorTree::Alt(siblings) => GenericErrorTree::Alt( 451 | siblings 452 | .into_iter() 453 | .map(|err| err.map_locations_ref(convert_location)) 454 | .collect(), 455 | ), 456 | } 457 | } 458 | 459 | /// Convert all of the locations in this error using some kind of mapping 460 | /// function. This is intended to help add additional context that may not 461 | /// have been available when the nom parsers were running, such as line 462 | /// and column numbers. 463 | pub fn map_locations( 464 | self, 465 | mut convert_location: impl FnMut(I) -> I2, 466 | ) -> GenericErrorTree { 467 | self.map_locations_ref(&mut convert_location) 468 | } 469 | } 470 | 471 | impl Display for GenericErrorTree { 472 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 473 | match self { 474 | GenericErrorTree::Base { location, kind } => write!(f, "{} at {:#}", kind, location), 475 | GenericErrorTree::Stack { contexts, base } => { 476 | contexts.iter().rev().try_for_each(|(location, context)| { 477 | writeln!(f, "{} at {:#},", context, location) 478 | })?; 479 | 480 | base.fmt(f) 481 | } 482 | GenericErrorTree::Alt(siblings) => { 483 | writeln!(f, "one of:")?; 484 | let mut f = IndentWriter::new(" ", f); 485 | write!(f, "{}", siblings.iter().join_with(", or\n")) 486 | } 487 | } 488 | } 489 | } 490 | 491 | impl Error 492 | for GenericErrorTree 493 | { 494 | } 495 | 496 | impl ParseError for GenericErrorTree { 497 | /// Create a new error at the given position. Interpret `kind` as an 498 | /// [`Expectation`] if possible, to give a more informative error message. 499 | fn from_error_kind(location: I, kind: NomErrorKind) -> Self { 500 | let kind = match kind { 501 | NomErrorKind::Alpha => BaseErrorKind::Expected(Expectation::Alpha), 502 | NomErrorKind::Digit => BaseErrorKind::Expected(Expectation::Digit), 503 | NomErrorKind::HexDigit => BaseErrorKind::Expected(Expectation::HexDigit), 504 | NomErrorKind::OctDigit => BaseErrorKind::Expected(Expectation::OctDigit), 505 | NomErrorKind::AlphaNumeric => BaseErrorKind::Expected(Expectation::AlphaNumeric), 506 | NomErrorKind::Space => BaseErrorKind::Expected(Expectation::Space), 507 | NomErrorKind::MultiSpace => BaseErrorKind::Expected(Expectation::Multispace), 508 | NomErrorKind::CrLf => BaseErrorKind::Expected(Expectation::CrLf), 509 | 510 | // Problem: ErrorKind::Eof is used interchangeably by various nom 511 | // parsers to mean either "expected Eof" or "expected NOT eof". See 512 | // https://github.com/Geal/nom/issues/1259. For now, we examine the 513 | // input string to guess what the likely intention is. 514 | NomErrorKind::Eof => match location.input_len() { 515 | // The input is at Eof, which means that this refers to an 516 | // *unexpected* eof. 517 | 0 => BaseErrorKind::Expected(Expectation::Something), 518 | 519 | // The input is *not* at eof, which means that this refers to 520 | // an *expected* eof. 521 | _ => BaseErrorKind::Expected(Expectation::Eof), 522 | }, 523 | kind => BaseErrorKind::Kind(kind), 524 | }; 525 | 526 | GenericErrorTree::Base { location, kind } 527 | } 528 | 529 | /// Combine an existing error with a new one. This is how error context is 530 | /// accumulated when backtracing. "other" is the original error, and the 531 | /// inputs new error from higher in the call stack. 532 | /// 533 | /// If `other` is already an `GenericErrorTree::Stack`, the context is added to 534 | /// the stack; otherwise, a new stack is created, with `other` at the root. 535 | fn append(location: I, kind: NomErrorKind, other: Self) -> Self { 536 | let context = (location, StackContext::Kind(kind)); 537 | 538 | match other { 539 | // Don't create a stack of [ErrorKind::Alt, GenericErrorTree::Alt(..)] 540 | alt @ GenericErrorTree::Alt(..) if kind == NomErrorKind::Alt => alt, 541 | 542 | // This is already a stack, so push on to it 543 | GenericErrorTree::Stack { contexts, base } => GenericErrorTree::Stack { 544 | base, 545 | contexts: express!(contexts.push(context)), 546 | }, 547 | 548 | // This isn't a stack; create a new stack 549 | base => GenericErrorTree::Stack { 550 | base: Box::new(base), 551 | contexts: vec![context], 552 | }, 553 | } 554 | } 555 | 556 | /// Create an error indicating an expected character at a given position 557 | fn from_char(location: I, character: char) -> Self { 558 | GenericErrorTree::Base { 559 | location, 560 | kind: BaseErrorKind::Expected(Expectation::Char(character)), 561 | } 562 | } 563 | 564 | /// Combine two errors from branches of alt. If either or both errors are 565 | /// already [`GenericErrorTree::Alt`], the different error sets are merged; 566 | /// otherwise, a new [`GenericErrorTree::Alt`] is created, containing both 567 | /// `self` and `other`. 568 | fn or(self, other: Self) -> Self { 569 | // For now we assume that there's no need to try and preserve 570 | // left-to-right ordering of alternatives. 571 | let siblings = match (self, other) { 572 | (GenericErrorTree::Alt(siblings1), GenericErrorTree::Alt(siblings2)) => { 573 | match siblings1.capacity() >= siblings2.capacity() { 574 | true => express!(siblings1.extend(siblings2)), 575 | false => express!(siblings2.extend(siblings1)), 576 | } 577 | } 578 | (GenericErrorTree::Alt(siblings), err) | (err, GenericErrorTree::Alt(siblings)) => { 579 | express!(siblings.push(err)) 580 | } 581 | (err1, err2) => vec![err1, err2], 582 | }; 583 | 584 | GenericErrorTree::Alt(siblings) 585 | } 586 | } 587 | 588 | impl ContextError for GenericErrorTree { 589 | fn add_context(location: I, ctx: C, other: Self) -> Self { 590 | let context = (location, StackContext::Context(ctx)); 591 | 592 | match other { 593 | // This is already a stack, so push on to it 594 | GenericErrorTree::Stack { contexts, base } => GenericErrorTree::Stack { 595 | base, 596 | contexts: express!(contexts.push(context)), 597 | }, 598 | 599 | // This isn't a stack, create a new stack 600 | base => GenericErrorTree::Stack { 601 | base: Box::new(base), 602 | contexts: vec![context], 603 | }, 604 | } 605 | } 606 | } 607 | 608 | impl nom::error::ContextError for GenericErrorTree { 609 | fn add_context(location: I, ctx: &'static str, other: Self) -> Self { 610 | ContextError::add_context(location, ctx, other) 611 | } 612 | } 613 | 614 | impl FromExternalError for GenericErrorTree 615 | where 616 | E: From, 617 | { 618 | /// Create an error from a given external error, such as from FromStr 619 | fn from_external_error(location: I, _kind: NomErrorKind, e: E2) -> Self { 620 | GenericErrorTree::Base { 621 | location, 622 | kind: BaseErrorKind::External(e.into()), 623 | } 624 | } 625 | } 626 | 627 | impl, C, E> TagError for GenericErrorTree { 628 | fn from_tag(location: I, tag: T) -> Self { 629 | GenericErrorTree::Base { 630 | location, 631 | kind: BaseErrorKind::Expected(match tag.as_ref() { 632 | b"\r\n" => Expectation::CrLf, 633 | _ => Expectation::Tag(tag), 634 | }), 635 | } 636 | } 637 | } 638 | 639 | impl ErrorConvert> 640 | for GenericErrorTree 641 | { 642 | fn convert(self) -> GenericErrorTree<(I, usize), T, C, E> { 643 | self.map_locations(|location| (location, 0)) 644 | } 645 | } 646 | 647 | impl ErrorConvert> 648 | for GenericErrorTree<(I, usize), T, C, E> 649 | { 650 | fn convert(self) -> GenericErrorTree { 651 | self.map_locations(move |(location, _offset)| location) 652 | } 653 | } 654 | 655 | impl ExtractContext> 656 | for GenericErrorTree 657 | where 658 | I: Clone, 659 | I2: RecreateContext, 660 | { 661 | fn extract_context(self, original_input: I) -> GenericErrorTree { 662 | self.map_locations(move |location| I2::recreate_context(original_input.clone(), location)) 663 | } 664 | } 665 | 666 | #[cfg(test)] 667 | mod tests { 668 | use super::*; 669 | 670 | use nom::{ 671 | bits::{bits, complete::take}, 672 | sequence::tuple, 673 | IResult, Parser, 674 | }; 675 | 676 | type BitInput<'a> = (&'a [u8], usize); 677 | 678 | fn parse_bool_bit(input: (&[u8], usize)) -> IResult> { 679 | take(1usize).map(|bit: u8| bit != 0).parse(input) 680 | } 681 | 682 | type Byte = (bool, bool, bool, bool, bool, bool, bool, bool); 683 | 684 | /// Parse 8 bits 685 | fn parse_bits(input: &[u8]) -> IResult<&[u8], Byte, ErrorTree<&[u8]>> { 686 | bits(tuple(( 687 | parse_bool_bit, 688 | parse_bool_bit, 689 | parse_bool_bit, 690 | parse_bool_bit, 691 | parse_bool_bit, 692 | parse_bool_bit, 693 | parse_bool_bit, 694 | parse_bool_bit, 695 | ))) 696 | .parse(input) 697 | } 698 | 699 | /// Test that ErrorTree can be used with a bits parser, which requires 700 | /// ErrorConvert 701 | #[test] 702 | fn error_tree_bits() { 703 | let values = [0b1010_1111, 10]; 704 | let (tail, result) = parse_bits(&values).unwrap(); 705 | 706 | assert_eq!(tail, &[10]); 707 | assert_eq!(result, (true, false, true, false, true, true, true, true)); 708 | } 709 | } 710 | -------------------------------------------------------------------------------- /src/final_parser.rs: -------------------------------------------------------------------------------- 1 | //! Entry point layer into nom parsers. See [`final_parser`] for details. 2 | 3 | use core::fmt::{self, Display, Formatter}; 4 | 5 | use nom::{ 6 | error::{Error, ErrorKind, ParseError}, 7 | Err as NomErr, InputLength, Offset, Parser, 8 | }; 9 | 10 | use nom::error::VerboseError; 11 | 12 | use crate::parser_ext::ParserExt; 13 | 14 | /// Trait for types which represent an absolute location of a parse error in 15 | /// an input 16 | /// 17 | /// This trait is implemented for "full location context" types; that is, for 18 | /// types that capture the exact location (and possibly other related context) 19 | /// of a parse error for the purpose of reporting. Two such types are provided 20 | /// by `nom-supreme`: [`Location`], which captures the line and column number 21 | /// of the error, and [`ByteOffset`], which captures the byte offset of the 22 | /// error. 23 | /// 24 | /// This trait is usually paired with [`ExtractContext`], a trait used by 25 | /// nom error types to convert the stored input tail types into location 26 | /// contexts. [`ExtractContext`] is in turn used by [`final_parser`] to create 27 | /// & return parse errors with the full attached context. 28 | pub trait RecreateContext: Sized { 29 | /// Given the *original* input, as well as the context reported by nom, 30 | /// recreate a context in the original string where the error occurred. 31 | /// 32 | /// This function may return garbage or panic if the tail is not associated 33 | /// with the original input. 34 | fn recreate_context(original_input: I, tail: I) -> Self; 35 | } 36 | 37 | impl RecreateContext for I { 38 | fn recreate_context(_original_input: I, tail: I) -> Self { 39 | tail 40 | } 41 | } 42 | 43 | /// A byte offset into the input where an error may have occurred 44 | /// 45 | /// # `&str` Example 46 | /// 47 | /// ``` 48 | /// use nom_supreme::final_parser::{ByteOffset, RecreateContext}; 49 | /// 50 | /// let original_input = "Hello,\nWorld!\n"; 51 | /// let tail = &original_input[9..]; 52 | /// 53 | /// assert_eq!( 54 | /// ByteOffset::recreate_context(original_input, tail), 55 | /// ByteOffset(9), 56 | /// ); 57 | /// ``` 58 | /// 59 | /// `# &[u8]` Example 60 | /// 61 | /// ``` 62 | /// use nom_supreme::final_parser::{ByteOffset, RecreateContext}; 63 | /// 64 | /// let original_input = b"GET / HTTP/1.1\r\n"; 65 | /// let tail = &original_input[6..]; 66 | /// 67 | /// assert_eq!( 68 | /// ByteOffset::recreate_context(&original_input[..], tail), 69 | /// ByteOffset(6), 70 | /// ); 71 | /// ``` 72 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 73 | pub struct ByteOffset(pub usize); 74 | 75 | impl RecreateContext for ByteOffset { 76 | fn recreate_context(original_input: I, tail: I) -> Self { 77 | ByteOffset(original_input.offset(&tail)) 78 | } 79 | } 80 | 81 | /// A location in a string where an error may have occurred. In keeping with 82 | /// the typical practice from editors and other tools, line and columns are both 83 | /// 1-indexed. 84 | /// 85 | /// # Example 86 | /// 87 | /// ``` 88 | /// use nom_supreme::final_parser::{RecreateContext, Location}; 89 | /// 90 | /// let original_input = "Hello,\nWorld!\n"; 91 | /// let tail = &original_input[9..]; 92 | /// 93 | /// assert_eq!( 94 | /// Location::recreate_context(original_input, tail), 95 | /// Location { line: 2, column: 3 }, 96 | /// ); 97 | /// ``` 98 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 99 | pub struct Location { 100 | /// The line number in the original input where the error occurred 101 | pub line: usize, 102 | 103 | /// The column of the line in the original input where the error occurred 104 | pub column: usize, 105 | } 106 | 107 | impl Location { 108 | /// Given the *original* input string, as well as the context reported by 109 | /// nom, compute the location in the original string where the error 110 | /// occurred. 111 | /// 112 | /// This function will report garbage (and may panic) if the context is not 113 | /// associated with the input 114 | pub fn locate_tail<'a>(original_input: &'a str, tail: &'a str) -> Self { 115 | let offset = original_input.offset(tail); 116 | let input_bytes = original_input.as_bytes(); 117 | let prefix = &input_bytes[..offset]; 118 | 119 | let line_number = memchr::memchr_iter(b'\n', prefix).count() + 1; 120 | 121 | let last_line_start = memchr::memrchr(b'\n', prefix).map(|i| i + 1).unwrap_or(0); 122 | let last_line = &prefix[last_line_start..]; 123 | let column_number = last_line.len() + 1; 124 | 125 | Location { 126 | line: line_number, 127 | column: column_number, 128 | } 129 | } 130 | } 131 | 132 | impl Display for Location { 133 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 134 | if f.alternate() { 135 | write!(f, "line {}, column {}", self.line, self.column) 136 | } else { 137 | write!(f, "{}:{}", self.line, self.column) 138 | } 139 | } 140 | } 141 | 142 | impl RecreateContext<&str> for Location { 143 | fn recreate_context(original_input: &str, tail: &str) -> Self { 144 | Location::locate_tail(original_input, tail) 145 | } 146 | } 147 | 148 | /// Trait for recombining error information with the original input. 149 | /// 150 | /// This trait is used to take the context information attached to nom errors- 151 | /// specifically, the tail of the input indicating the location of the input- 152 | /// and recombine it with the *original* input to produce an error with 153 | /// something more useful for error reporting. 154 | /// 155 | /// Typically, it looks like `ExtractContext> for E`. This 156 | /// indicates that some error type `E`, which is generic over the input type, 157 | /// can be converted into another variant of that error, using `T` instead of 158 | /// `I` to hold the result context. Often this context conversion can happen 159 | /// with [`RecreateContext`]. 160 | pub trait ExtractContext { 161 | /// Given the context attached to a nom error, and given the *original* 162 | /// input to the nom parser, extract more the useful context information. 163 | /// 164 | /// For example, for a string, 1 possible context extraction would be the 165 | /// Location (line and column number) in the original input where the error 166 | /// indicated by self occurred. 167 | fn extract_context(self, original_input: I) -> T; 168 | } 169 | 170 | impl ExtractContext for T { 171 | fn extract_context(self, _original_input: I) {} 172 | } 173 | 174 | impl ExtractContext for (I, ErrorKind) 175 | where 176 | T: RecreateContext, 177 | { 178 | fn extract_context(self, original_input: I) -> (T, ErrorKind) { 179 | let (tail, kind) = self; 180 | (T::recreate_context(original_input, tail), kind) 181 | } 182 | } 183 | 184 | impl ExtractContext> for Error 185 | where 186 | T: RecreateContext, 187 | { 188 | fn extract_context(self, original_input: I) -> Error { 189 | Error::new(T::recreate_context(original_input, self.input), self.code) 190 | } 191 | } 192 | 193 | impl ExtractContext> for VerboseError 194 | where 195 | T: RecreateContext, 196 | I: Clone, 197 | { 198 | fn extract_context(self, original_input: I) -> VerboseError { 199 | VerboseError { 200 | errors: self 201 | .errors 202 | .into_iter() 203 | .map(|(input, kind)| (T::recreate_context(original_input.clone(), input), kind)) 204 | .collect(), 205 | } 206 | } 207 | } 208 | 209 | /// `extract_context` can be used directly on `Result` values that have an 210 | /// error with `ExtractContext` 211 | impl ExtractContext> for Result 212 | where 213 | E1: ExtractContext, 214 | { 215 | fn extract_context(self, original_input: I) -> Result { 216 | self.map_err(move |err| err.extract_context(original_input)) 217 | } 218 | } 219 | 220 | /// Bootstrapping layer for a nom parser. 221 | /// 222 | /// This function is intended to be the entry point into a nom parser; it 223 | /// represents in some sense the "end of composability". It creates a function 224 | /// which applies a parser to an input. The parser is configured such that it 225 | /// must parse the *entire* input, and any "Incomplete" responses are reported 226 | /// as errors. Additionally, if the parser returns an error, the context 227 | /// information in the error is recombined with the original input via 228 | /// `ExtractContext` to create a more useful error. 229 | pub fn final_parser(parser: impl Parser) -> impl FnMut(I) -> Result 230 | where 231 | E: ParseError + ExtractContext, 232 | I: InputLength + Clone, 233 | { 234 | let mut parser = parser.complete().all_consuming(); 235 | 236 | move |input| match parser.parse(input.clone()) { 237 | Ok((_, parsed)) => Ok(parsed), 238 | Err(NomErr::Error(err)) | Err(NomErr::Failure(err)) => Err(err.extract_context(input)), 239 | Err(NomErr::Incomplete(..)) => { 240 | unreachable!("Complete combinator should make this impossible") 241 | } 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | A collection of excellent utilities for nom, including: 3 | 4 | - [`ParserExt`][parser_ext::ParserExt], a trait which makes available 5 | many common nom parser combinators as postfix methods, to complement 6 | those already available on [`nom::Parser`]. 7 | - [`ErrorTree`][error::ErrorTree], a nom error which retains as much 8 | information and context as possible about the details of the failed 9 | parse, with an excellent indenting formatter for printing these failures. 10 | Integrates with the extra error features of `nom-supreme`. 11 | - Improved [`tag`] parsers, which attach the mismatched the error in the 12 | event of a parse failure, similar to 13 | [`char`][nom::character::complete::char]. 14 | - [`parse_separated_terminated`][multi::parse_separated_terminated], the 15 | perfected folding parser for building parse loops. 16 | - [`final_parser`][final_parser::final_parser], which serves as a bridge 17 | between nom-style [`IResult`][nom::IResult] parsers and more typical rust 18 | results. It decorates a nom parser, requiring it to parse all of its 19 | input, not return `Incomplete`. It also uses an 20 | [`ExtractContext`][final_parser::ExtractContext] trait to convert the 21 | error locations in nom errors, which are usually just suffixes of the 22 | input, into more useful locations, such as a line and column number. 23 | */ 24 | 25 | #![deny(missing_docs)] 26 | 27 | /** 28 | Call a method or methods on an object, and then return the original object. 29 | 30 | The input to this macro is the methods calls written in a chaining style: 31 | `express!(vec.push(1).push(2).push(3))`, which is transformed into a series 32 | of calls on the original object, then returning that object. 33 | */ 34 | macro_rules! express { 35 | ($thing:ident $( . $method:ident ( $($args:tt)* ) )*) => {{ 36 | let mut thing = $thing; 37 | $( thing.$method($($args)*); )* 38 | thing 39 | }}; 40 | } 41 | 42 | pub mod context; 43 | pub mod error; 44 | pub mod final_parser; 45 | pub mod multi; 46 | pub mod parser_ext; 47 | pub mod tag; 48 | 49 | pub use parser_ext::ParserExt; 50 | -------------------------------------------------------------------------------- /src/multi.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | Perfected looping parsers designed to behave more reliably and provide more 3 | useful parse errors. 4 | 5 | The combinators in this module all generally follow the same pattern for 6 | parsing in a loop. They parse an item; then, they attempt to parse a 7 | `terminator`. If the `terminator` is found, the parse returns successfully; 8 | otherwise, they attempt to parse a `separator`. If they fail to parse either 9 | a `separator` or a `terminator`, the parse fails; otherwise, it will continue 10 | on to parse the next item. The parsed items are collected together into a final 11 | value; each combinator does this in a slightly different way: 12 | 13 | - [`collect_separated_terminated`] collects the parsed items into a collection 14 | with [`Extend`]. 15 | - [`parse_separated_terminated`] combines the parsed items with a folding 16 | function. 17 | - [`parse_separated_terminated_res`] combines the parsed items with a fallible 18 | folding function; it may return early if the folding function returns an 19 | [`Err`]. 20 | 21 | These combinators always parse at least 1 item. If you want 0 or more things 22 | to be parsed, use [`opt`] or [`alt`] to handle that case. 23 | 24 | These combinators will stop as soon as they find a `terminator`. If you wish 25 | to have a `terminator` parser that is the same as your `separator`, you'll need 26 | to add some extra context to the terminator parser; perhaps a lookahead 27 | with [`peek`]. 28 | 29 | These combinators exists to provide meaningful parse errors. By requiring a 30 | `terminator`, we can ensure that they don't suffer from the normal folding 31 | parser problem of unconditionally returning success because a subparser failure 32 | is interpreted as the end of the loop. This ensures that potentially important 33 | errors aren't thrown away. 34 | 35 | The combinators will attempt to smartly allow 0-length matches. It will allow 36 | subparsers to have 0-length matches, but if a full loop is made without any 37 | progress being made, we assume we've encountered an infinite loop and return 38 | a parse error. 39 | 40 | [`opt`]: crate::parser_ext::ParserExt::opt 41 | [`alt`]: nom::branch::alt 42 | [`peek`]: crate::parser_ext::ParserExt::peek 43 | */ 44 | 45 | use core::{convert::Infallible, iter}; 46 | 47 | use nom::{ 48 | error::{ErrorKind::SeparatedNonEmptyList, FromExternalError, ParseError}, 49 | Err::Error, 50 | InputLength, Parser, 51 | }; 52 | 53 | /** 54 | Parse a series of 1 or more things, separated by `separator`, terminated by 55 | `terminator`, and collect them into a collection using [`Extend`]. 56 | 57 | When this parser is run, it will create a new, empty collection with 58 | [`Default`]. It will then collect each parsed item into the collection with 59 | [`Extend`]. See the [module] docs for details of how this parser parses a sequence. 60 | 61 | See the [module] docs for a detailed description of how this parser parses a sequence. 62 | 63 | # Example 64 | 65 | ``` 66 | use nom_supreme::{ 67 | multi::collect_separated_terminated, 68 | parser_ext::ParserExt, 69 | error::ErrorTree, 70 | }; 71 | use nom::character::complete::{digit1, char, space0}; 72 | use nom::{IResult, Parser, error::ParseError}; 73 | 74 | fn parse_number(input: &str) -> IResult<&str, i32, ErrorTree<&str>> { 75 | digit1 76 | .preceded_by(char('-').opt()) 77 | .recognize() 78 | .parse_from_str() 79 | .parse(input) 80 | } 81 | 82 | // A vector is a square brackets, containing comma separated numbers, with 83 | // whitespace in between 84 | let mut vec_parser = collect_separated_terminated( 85 | // Parse numbers 86 | parse_number.terminated(space0), 87 | 88 | // separated by commas 89 | char(',').terminated(space0), 90 | 91 | // terminated by a close bracket 92 | char(']'), 93 | ) 94 | // Allow for empty vectors 95 | .or(char(']').value(Vec::new())) 96 | .preceded_by(char('[').terminated(space0)); 97 | 98 | let result: IResult<&str, Vec, ErrorTree<&str>> = vec_parser.parse("[1, 2, -3, 4]"); 99 | let vec = result.unwrap().1; 100 | assert_eq!(vec, [1, 2, -3, 4]); 101 | 102 | ``` 103 | 104 | [module]: crate::multi 105 | */ 106 | pub fn collect_separated_terminated< 107 | Input, 108 | ParseOutput, 109 | SepOutput, 110 | TermOutput, 111 | ParseErr, 112 | Collection, 113 | >( 114 | parser: impl Parser, 115 | separator: impl Parser, 116 | terminator: impl Parser, 117 | ) -> impl Parser 118 | where 119 | Input: Clone + InputLength, 120 | ParseErr: ParseError, 121 | Collection: Default + Extend, 122 | { 123 | parse_separated_terminated( 124 | parser, 125 | separator, 126 | terminator, 127 | Collection::default, 128 | // TODO: use extend_one 129 | |collection, item| express!(collection.extend(iter::once(item))), 130 | ) 131 | } 132 | 133 | /** 134 | Parse a series of 1 or more things, separated by `separator`, terminated by 135 | `terminator`, and fold them together using a folding function. 136 | 137 | When this parser is run, it will first create an accumulator value with `init`. 138 | It will then combine it with every parsed item using `fold`, which should 139 | return the new accumulator for each item. See the [module] docs for details 140 | of how this parser parses a sequence. 141 | 142 | [module]: crate::multi 143 | */ 144 | #[inline] 145 | pub fn parse_separated_terminated( 146 | parser: impl Parser, 147 | separator: impl Parser, 148 | terminator: impl Parser, 149 | 150 | init: impl FnMut() -> Accum, 151 | mut fold: impl FnMut(Accum, ParseOutput) -> Accum, 152 | ) -> impl Parser 153 | where 154 | Input: Clone + InputLength, 155 | ParseErr: ParseError, 156 | { 157 | parse_separated_terminated_impl( 158 | parser, 159 | separator, 160 | terminator, 161 | init, 162 | move |accum, item| Ok(fold(accum, item)), 163 | |_input, err: Infallible| match err {}, 164 | ) 165 | } 166 | 167 | /** 168 | Parse a series of 1 or more things, separated by some `separator`, terminated 169 | by some `terminator`, folding them all together with a fallible fold function. 170 | 171 | This function is identical to [`parse_separated_terminated`], except that 172 | the fold function may return an error, which ends the parse early. See its 173 | documentation for more details about the precise behavior of this parser. 174 | */ 175 | #[inline] 176 | pub fn parse_separated_terminated_res< 177 | Input, 178 | ParseOutput, 179 | SepOutput, 180 | TermOutput, 181 | ParseErr, 182 | Accum, 183 | FoldErr, 184 | >( 185 | parser: impl Parser, 186 | separator: impl Parser, 187 | terminator: impl Parser, 188 | 189 | init: impl FnMut() -> Accum, 190 | fold: impl FnMut(Accum, ParseOutput) -> Result, 191 | ) -> impl Parser 192 | where 193 | Input: Clone + InputLength, 194 | ParseErr: ParseError + FromExternalError, 195 | { 196 | parse_separated_terminated_impl(parser, separator, terminator, init, fold, |input, err| { 197 | ParseErr::from_external_error(input, SeparatedNonEmptyList, err) 198 | }) 199 | } 200 | 201 | /// Helper enum for tracking zero length parses. `parse_separated_terminated` 202 | /// allows for subparsers to return zero-length matches, but if *every* 203 | /// subparser does so in a loop, that's reported as an error. 204 | /// 205 | /// This enum specifically tracks the least-recent zero-length parse that has 206 | /// not been succeeded by a non-zero-length parser. 207 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 208 | enum ZeroLengthParseState { 209 | None, 210 | Item, 211 | Separator { terminator_error: E }, 212 | } 213 | 214 | impl ZeroLengthParseState { 215 | fn terminator_error(self) -> Option { 216 | match self { 217 | Self::Separator { terminator_error } => Some(terminator_error), 218 | _ => None, 219 | } 220 | } 221 | } 222 | 223 | /// Shared implementation for parse_separated_terminated_res and 224 | /// parse_separated_terminated. This exists so that we don't have to have an 225 | /// unnecessary bound of FromExternalError on parse_separated_terminated. 226 | #[inline] 227 | fn parse_separated_terminated_impl< 228 | Input, 229 | ParseOutput, 230 | SepOutput, 231 | TermOutput, 232 | ParseErr, 233 | Accum, 234 | FoldErr, 235 | >( 236 | mut parser: impl Parser, 237 | mut separator: impl Parser, 238 | mut terminator: impl Parser, 239 | 240 | mut init: impl FnMut() -> Accum, 241 | mut fold: impl FnMut(Accum, ParseOutput) -> Result, 242 | 243 | mut build_error: impl FnMut(Input, FoldErr) -> ParseErr, 244 | ) -> impl Parser 245 | where 246 | Input: Clone + InputLength, 247 | ParseErr: ParseError, 248 | { 249 | move |mut input: Input| { 250 | let mut accum = init(); 251 | 252 | let mut zero_length_state = ZeroLengthParseState::None; 253 | 254 | loop { 255 | // Try to find a value. To fail to do so at this point is an 256 | // error, since we either just started or successfully parsed a 257 | // separator. 258 | // 259 | // If an error occurs here, also try to attach terminator_error. 260 | // terminator_error is available if the most recent separator parse 261 | // was zero-length, which means that both the terminator and the 262 | // item would be valid parses at this point. 263 | let (tail, value) = match parser.parse(input.clone()) { 264 | Ok(success) => success, 265 | Err(Error(item_error)) => { 266 | break Err(Error(match zero_length_state.terminator_error() { 267 | None => item_error, 268 | Some(terminator_error) => item_error.or(terminator_error), 269 | })) 270 | } 271 | Err(err) => break Err(err), 272 | }; 273 | 274 | // Check zero-length matches 275 | zero_length_state = match (input.input_len() == tail.input_len(), zero_length_state) { 276 | // If both the item and the separator had a zero length match, 277 | // we're hanging. Bail. 278 | // 279 | // It doesn't make sense to include the terminator error here, 280 | // because we *did* successfully parse a separator and an 281 | // item, they just happened to be zero length 282 | (true, ZeroLengthParseState::Separator { .. }) => { 283 | break Err(Error(ParseErr::from_error_kind( 284 | input, 285 | SeparatedNonEmptyList, 286 | ))) 287 | } 288 | 289 | // If only the item had a zero-length match, update the 290 | // state. 291 | (true, _) => ZeroLengthParseState::Item, 292 | 293 | // If the item had a non-zero length match, clear the state 294 | (false, _) => ZeroLengthParseState::None, 295 | }; 296 | 297 | // Advance the loop state 298 | accum = fold(accum, value).map_err(|err| Error(build_error(input, err)))?; 299 | input = tail; 300 | 301 | // Try to find a terminator; if we found it, we're done. If we 302 | // didn't, preserve the error, so that it can be reported as an 303 | // .or() branch with the subsequent separator or item error. 304 | let terminator_error = match terminator.parse(input.clone()) { 305 | // We found a terminator, so we're done 306 | Ok((tail, _)) => break Ok((tail, accum)), 307 | 308 | // No terminator. Keep track of the error in case we also fail 309 | // to find a separator or item. 310 | Err(Error(err)) => err, 311 | 312 | // Other kinds of errors should be returned immediately. 313 | Err(err) => break Err(err), 314 | }; 315 | 316 | // No terminator, so instead try to find a separator 317 | let tail = match separator.parse(input.clone()) { 318 | Ok((tail, _)) => tail, 319 | Err(Error(separator_error)) => { 320 | break Err(Error(separator_error.or(terminator_error))) 321 | } 322 | Err(err) => break Err(err), 323 | }; 324 | 325 | // Check zero-length matches 326 | zero_length_state = match (input.input_len() == tail.input_len(), zero_length_state) { 327 | // If both the separator and the item had a zero length match, 328 | // we're hanging. Bail. 329 | (true, ZeroLengthParseState::Item) => { 330 | break Err(Error(ParseErr::from_error_kind( 331 | input, 332 | SeparatedNonEmptyList, 333 | ))) 334 | } 335 | // If only the separator had a zero-length match, update the 336 | // state. Additionally preserve the terminator error so that 337 | // it can be reported as an alternate if there was an item 338 | // error. 339 | (true, _) => ZeroLengthParseState::Separator { terminator_error }, 340 | 341 | // If the separator had a non-zero length match, clear the 342 | // state 343 | (false, _) => ZeroLengthParseState::None, 344 | }; 345 | 346 | // Advance the loop state 347 | input = tail; 348 | } 349 | } 350 | } 351 | 352 | #[cfg(test)] 353 | mod test_separated_terminated { 354 | use cool_asserts::assert_matches; 355 | use nom::{ 356 | branch::alt, 357 | character::complete::{alpha0, char, digit1, space0}, 358 | error::ErrorKind, 359 | Err, IResult, Parser, 360 | }; 361 | 362 | use crate::error::{BaseErrorKind, ErrorTree, Expectation}; 363 | use crate::parser_ext::ParserExt; 364 | 365 | use super::parse_separated_terminated; 366 | 367 | /// Parse a series of numbers, separated by commas, terminated by a period. 368 | fn parse_number_list(input: &str) -> IResult<&str, Vec, ErrorTree<&str>> { 369 | parse_separated_terminated( 370 | digit1.parse_from_str(), 371 | char(',').delimited_by(space0), 372 | char('.').preceded_by(space0), 373 | Vec::new, 374 | |vec, num| express!(vec.push(num)), 375 | ) 376 | .parse(input) 377 | } 378 | 379 | #[test] 380 | fn basic() { 381 | assert_eq!( 382 | parse_number_list("1, 2, 3, 4, 5.").unwrap(), 383 | ("", vec![1, 2, 3, 4, 5]), 384 | ) 385 | } 386 | 387 | #[test] 388 | fn trailing_input() { 389 | assert_eq!( 390 | parse_number_list("1, 2, 3, 4, 5. 4, 5, 6.").unwrap(), 391 | (" 4, 5, 6.", vec![1, 2, 3, 4, 5]), 392 | ) 393 | } 394 | 395 | #[test] 396 | fn only_one() { 397 | assert_eq!(parse_number_list("10.").unwrap(), ("", vec![10]),) 398 | } 399 | 400 | #[test] 401 | fn at_least_one() { 402 | let err = parse_number_list("abc").unwrap_err(); 403 | 404 | assert_matches!( 405 | err, 406 | Err::Error(ErrorTree::Base { 407 | location: "abc", 408 | kind: BaseErrorKind::Expected(Expectation::Digit) 409 | }) 410 | ); 411 | } 412 | 413 | /// Test that a parse failure from both the separator and the terminator 414 | /// causes an error including both messages 415 | #[test] 416 | fn terminator_separator_miss() { 417 | let err = parse_number_list("10, 20 30.").unwrap_err(); 418 | 419 | let choices = assert_matches!(err, Err::Error(ErrorTree::Alt(choices)) => choices); 420 | assert_matches!( 421 | choices.as_slice(), 422 | [ 423 | ErrorTree::Base { 424 | location: "30.", 425 | kind: BaseErrorKind::Expected(Expectation::Char(',')) 426 | }, 427 | ErrorTree::Base { 428 | location: "30.", 429 | kind: BaseErrorKind::Expected(Expectation::Char('.')) 430 | }, 431 | ] 432 | ); 433 | } 434 | 435 | /// Test that a terminator is required, even at EoF 436 | #[test] 437 | fn required_terminator() { 438 | let err = parse_number_list("1, 2, 3").unwrap_err(); 439 | 440 | let choices = assert_matches!(err, Err::Error(ErrorTree::Alt(choices)) => choices); 441 | assert_matches!( 442 | choices.as_slice(), 443 | [ 444 | ErrorTree::Base { 445 | location: "", 446 | kind: BaseErrorKind::Expected(Expectation::Char(',')) 447 | }, 448 | ErrorTree::Base { 449 | location: "", 450 | kind: BaseErrorKind::Expected(Expectation::Char('.')) 451 | }, 452 | ] 453 | ); 454 | } 455 | 456 | /// Test that a parse failure from the item parser includes only that error 457 | /// if the separator isn't zero-length 458 | #[test] 459 | fn item_error() { 460 | let err = parse_number_list("1, 2, abc.").unwrap_err(); 461 | 462 | assert_matches!( 463 | err, 464 | Err::Error(ErrorTree::Base { 465 | location: "abc.", 466 | kind: BaseErrorKind::Expected(Expectation::Digit), 467 | }) 468 | ); 469 | } 470 | 471 | /// Parse a series of numbers ending in periods, separated by 0 or more 472 | /// whitespace, terminated by a semicolon. Used to test 0-length 473 | /// separator behavior. 474 | fn parse_number_dot_list(input: &str) -> IResult<&str, Vec, ErrorTree<&str>> { 475 | parse_separated_terminated( 476 | digit1.terminated(char('.')).parse_from_str(), 477 | space0, 478 | char(';'), 479 | Vec::new, 480 | |vec, num| express!(vec.push(num)), 481 | ) 482 | .parse(input) 483 | } 484 | 485 | #[test] 486 | fn zero_length_separator() { 487 | assert_eq!( 488 | parse_number_dot_list("1.2. 3.4. 5.; abc").unwrap(), 489 | (" abc", vec![1, 2, 3, 4, 5]) 490 | ); 491 | } 492 | 493 | /// Test that, when a separator matches zero length, and then the item 494 | /// parser fails, the returned error includes both the item error and the 495 | /// terminator error. 496 | #[test] 497 | fn zero_length_separator_item_term_error() { 498 | let err = parse_number_dot_list("1.2.3.abc.;").unwrap_err(); 499 | 500 | let choices = assert_matches!(err, Err::Error(ErrorTree::Alt(choices)) => choices); 501 | assert_matches!( 502 | choices.as_slice(), 503 | [ 504 | ErrorTree::Base { 505 | location: "abc.;", 506 | kind: BaseErrorKind::Expected(Expectation::Digit) 507 | }, 508 | ErrorTree::Base { 509 | location: "abc.;", 510 | kind: BaseErrorKind::Expected(Expectation::Char(';')) 511 | }, 512 | ] 513 | ); 514 | } 515 | 516 | /// Parse a series of runs of 1 or more digits or 0 more more letters, separated by 517 | /// an optional dash, terminated by a semicolon. Used to test 518 | /// infinite loop detection 519 | fn parse_letters_numbers(input: &str) -> IResult<&str, Vec<&str>, ErrorTree<&str>> { 520 | parse_separated_terminated( 521 | alt((digit1, alpha0)), 522 | char('-').opt(), 523 | char(';'), 524 | Vec::new, 525 | |vec, num| express!(vec.push(num)), 526 | ) 527 | .parse(input) 528 | } 529 | 530 | #[test] 531 | fn zero_length_item() { 532 | assert_eq!( 533 | parse_letters_numbers("----; abc").unwrap(), 534 | (" abc", vec!["", "", "", "", ""]) 535 | ) 536 | } 537 | 538 | #[test] 539 | fn zero_length_separators() { 540 | assert_eq!( 541 | parse_letters_numbers("abc123abc123; abc").unwrap(), 542 | (" abc", vec!["abc", "123", "abc", "123"]), 543 | ) 544 | } 545 | 546 | /// Test that both zero-length separators and items are allowed together, 547 | /// as long as the loop makes progress 548 | #[test] 549 | fn zero_length_mixed() { 550 | assert_eq!( 551 | parse_letters_numbers("abc--123abc-123-; abc").unwrap(), 552 | (" abc", vec!["abc", "", "123", "abc", "123", ""]), 553 | ) 554 | } 555 | 556 | /// Test that if the loop makes no progress, that's an error 557 | #[test] 558 | fn infinite_loop_aborts() { 559 | let err = parse_letters_numbers("abc123-.; abc").unwrap_err(); 560 | 561 | assert_matches!( 562 | err, 563 | Err::Error(ErrorTree::Base { 564 | location: ".; abc", 565 | kind: BaseErrorKind::Kind(ErrorKind::SeparatedNonEmptyList) 566 | }) 567 | ); 568 | } 569 | 570 | /// Parse a series of numbers, separated by commas, terminated by optional 571 | /// comma and eof. Used to test that the terminator "wins" when it and the 572 | /// separator can match the same string. 573 | fn parse_comma_separated(input: &str) -> IResult<&str, Vec, ErrorTree<&str>> { 574 | parse_separated_terminated( 575 | digit1.parse_from_str(), 576 | char(','), 577 | char(',').opt().all_consuming(), 578 | Vec::new, 579 | |vec, num| express!(vec.push(num)), 580 | ) 581 | .parse(input) 582 | } 583 | 584 | #[test] 585 | fn empty_terminator_wins() { 586 | assert_eq!( 587 | parse_comma_separated("1,2,3,4").unwrap(), 588 | ("", vec![1, 2, 3, 4]), 589 | ); 590 | } 591 | 592 | #[test] 593 | fn test_terminator_wins() { 594 | assert_eq!( 595 | parse_comma_separated("1,2,3,4,").unwrap(), 596 | ("", vec![1, 2, 3, 4]), 597 | ) 598 | } 599 | } 600 | -------------------------------------------------------------------------------- /src/parser_ext.rs: -------------------------------------------------------------------------------- 1 | //! Extensions to the nom [`Parser`][nom::Parser] trait which add postfix 2 | //! versions of the common combinators. See [`ParserExt`] for details. 3 | 4 | use core::{marker::PhantomData, ops::RangeTo, str::FromStr}; 5 | 6 | use nom::{ 7 | error::{ErrorKind as NomErrorKind, FromExternalError, ParseError}, 8 | Err as NomErr, InputLength, Offset, Parser, Slice, 9 | }; 10 | 11 | use crate::context::ContextError; 12 | 13 | /// No-op function that typechecks that its argument is a parser. Used to 14 | /// ensure there are no accidentally missing type bounds on the `ParserExt` 15 | /// methods 16 | #[inline(always)] 17 | fn must_be_a_parser>(parser: P) -> P { 18 | parser 19 | } 20 | 21 | /// Additional postfix parser combinators, as a complement to [`Parser`]. 22 | /// Mostly these are postfix versions of the combinators in [`nom::combinator`] 23 | /// and [`nom::sequence`], with some additional combinators original to 24 | /// `nom-supreme`. 25 | /// 26 | /// Compatibility note: it is expected that eventually many of these postfix 27 | /// methods will eventually be added directly to the [`Parser`] trait. It will 28 | /// therefore *not* be considered a compatibility break to remove those methods 29 | /// from [`ParserExt`], *if* they have the same name and signature. 30 | pub trait ParserExt: Parser + Sized { 31 | /// Borrow a parser. This allows building parser combinators while still 32 | /// retaining ownership of the original parser. This is necessary because 33 | /// `impl Parser for &mut T` is impossible due to conflicts 34 | /// with `impl Parser for T`. 35 | /// 36 | /// # Example 37 | /// 38 | /// ```rust 39 | /// # use nom::{Err, Parser}; 40 | /// # use nom::error::{Error, ErrorKind}; 41 | /// use nom_supreme::parser_ext::ParserExt; 42 | /// use nom_supreme::tag::complete::tag; 43 | /// 44 | /// let mut parser = tag("Hello"); 45 | /// 46 | /// let mut subparser = parser.by_ref().terminated(tag(", World")); 47 | /// 48 | /// assert_eq!(subparser.parse("Hello, World!"), Ok(("!", "Hello"))); 49 | /// assert_eq!( 50 | /// subparser.parse("Hello"), 51 | /// Err(Err::Error(Error{input: "", code: ErrorKind::Tag})) 52 | /// ); 53 | /// 54 | /// // We still have ownership of the original parser 55 | /// 56 | /// assert_eq!(parser.parse("Hello, World!"), Ok((", World!", "Hello"))); 57 | /// assert_eq!(parser.parse("Hello"), Ok(("", "Hello"))); 58 | /// ``` 59 | #[inline] 60 | #[must_use = "Parsers do nothing unless used"] 61 | fn by_ref(&mut self) -> RefParser { 62 | must_be_a_parser(RefParser { parser: self }) 63 | } 64 | 65 | /// Create a parser that must consume all of the input, or else return an 66 | /// error. 67 | /// 68 | /// # Example 69 | /// 70 | /// ```rust 71 | /// # use nom::{Err, Parser}; 72 | /// # use nom::error::{Error, ErrorKind}; 73 | /// use nom_supreme::parser_ext::ParserExt; 74 | /// use nom_supreme::tag::complete::tag; 75 | /// 76 | /// let mut parser = tag("Hello").all_consuming(); 77 | /// 78 | /// assert_eq!(parser.parse("Hello"), Ok(("", "Hello"))); 79 | /// assert_eq!( 80 | /// parser.parse("World"), 81 | /// Err(Err::Error(Error{input: "World", code: ErrorKind::Tag})) 82 | /// ); 83 | /// assert_eq!( 84 | /// parser.parse("Hello World"), 85 | /// Err(Err::Error(Error{input: " World", code: ErrorKind::Eof})) 86 | /// ); 87 | /// ``` 88 | #[inline] 89 | #[must_use = "Parsers do nothing unless used"] 90 | fn all_consuming(self) -> AllConsuming 91 | where 92 | I: InputLength, 93 | E: ParseError, 94 | { 95 | must_be_a_parser(AllConsuming { parser: self }) 96 | } 97 | 98 | /// Create a parser that transforms `Incomplete` into `Error`. 99 | /// 100 | /// # Example 101 | /// 102 | /// ```rust 103 | /// # use nom::{Err, Parser}; 104 | /// # use nom::error::{Error, ErrorKind}; 105 | /// use nom_supreme::parser_ext::ParserExt; 106 | /// use nom_supreme::tag::streaming::tag; 107 | /// 108 | /// let mut parser = tag("Hello").complete(); 109 | /// 110 | /// assert_eq!(parser.parse("Hello"), Ok(("", "Hello"))); 111 | /// assert_eq!( 112 | /// parser.parse("World"), 113 | /// Err(Err::Error(Error{input: "World", code: ErrorKind::Tag})) 114 | /// ); 115 | /// assert_eq!( 116 | /// parser.parse("Hel"), 117 | /// Err(Err::Error(Error{input: "Hel", code: ErrorKind::Complete})) 118 | /// ); 119 | /// ``` 120 | #[inline] 121 | #[must_use = "Parsers do nothing unless used"] 122 | fn complete(self) -> Complete 123 | where 124 | I: Clone, 125 | E: ParseError, 126 | { 127 | must_be_a_parser(Complete { parser: self }) 128 | } 129 | 130 | /** 131 | Create a parser that transforms `Error` into `Failure`. This will 132 | end the parse immediately, even if there are other branches that 133 | could occur. 134 | 135 | # Example 136 | 137 | ```rust 138 | use cool_asserts::assert_matches; 139 | # use nom::{Err, Parser}; 140 | # use nom::error::{Error, ErrorKind}; 141 | use nom::branch::alt; 142 | use nom::character::complete::char; 143 | use nom_supreme::parser_ext::ParserExt; 144 | use nom_supreme::tag::complete::tag; 145 | use nom_supreme::error::{ErrorTree, BaseErrorKind, Expectation}; 146 | 147 | let mut parser = alt(( 148 | tag("Hello").terminated(char(']')).cut().preceded_by(char('[')), 149 | tag("World").terminated(char(')')).cut().preceded_by(char('(')), 150 | )); 151 | 152 | assert_matches!(parser.parse("[Hello]"), Ok(("", "Hello"))); 153 | assert_matches!(parser.parse("(World)"), Ok(("", "World"))); 154 | 155 | let branches = assert_matches!( 156 | parser.parse("ABC"), 157 | Err(Err::Error(ErrorTree::Alt(branches))) => branches 158 | ); 159 | 160 | assert_matches!( 161 | branches.as_slice(), 162 | [ 163 | ErrorTree::Base { 164 | kind: BaseErrorKind::Expected(Expectation::Char('[')), 165 | location: "ABC", 166 | }, 167 | ErrorTree::Base { 168 | kind: BaseErrorKind::Expected(Expectation::Char('(')), 169 | location: "ABC", 170 | }, 171 | ] 172 | ); 173 | 174 | // Notice in this example that there's no error for [Hello]. The cut after 175 | // [ prevented the other branch from being attempted, and prevented earlier 176 | // errors from being retained 177 | assert_matches!( 178 | parser.parse("(Hello)"), 179 | Err(Err::Failure(ErrorTree::Base { 180 | kind: BaseErrorKind::Expected(Expectation::Tag("World")), 181 | location: "Hello)", 182 | })) 183 | ); 184 | ``` 185 | */ 186 | #[inline] 187 | #[must_use = "Parsers do nothing unless used"] 188 | fn cut(self) -> Cut { 189 | must_be_a_parser(Cut { parser: self }) 190 | } 191 | 192 | /// Create a parser that applies a mapping function `func` to the output 193 | /// of the subparser. Any errors from `func` will be transformed into 194 | /// parse errors via [`FromExternalError`]. 195 | /// 196 | /// # Example 197 | /// 198 | /// ```rust 199 | /// # use nom::{Err, Parser}; 200 | /// # use nom::error::{Error, ErrorKind}; 201 | /// use nom::character::complete::alphanumeric1; 202 | /// use nom_supreme::parser_ext::ParserExt; 203 | /// 204 | /// let mut parser = alphanumeric1.map_res(|s: &str| s.parse()); 205 | /// 206 | /// assert_eq!(parser.parse("10 abc"), Ok((" abc", 10))); 207 | /// assert_eq!( 208 | /// parser.parse("<===>"), 209 | /// Err(Err::Error(Error{input: "<===>", code: ErrorKind::AlphaNumeric})), 210 | /// ); 211 | /// assert_eq!( 212 | /// parser.parse("abc abc"), 213 | /// Err(Err::Error(Error{input: "abc abc", code: ErrorKind::MapRes})), 214 | /// ); 215 | /// ``` 216 | #[inline] 217 | #[must_use = "Parsers do nothing unless used"] 218 | fn map_res(self, func: F) -> MapRes 219 | where 220 | F: FnMut(O) -> Result, 221 | E: FromExternalError, 222 | I: Clone, 223 | { 224 | must_be_a_parser(MapRes { 225 | parser: self, 226 | func, 227 | phantom: PhantomData, 228 | }) 229 | } 230 | 231 | /// Create a parser that applies a mapping function `func` to the output 232 | /// of the subparser. Any errors from `func` will be transformed into 233 | /// parse failures via [`FromExternalError`]. This will 234 | /// end the parse immediately, even if there are other branches that 235 | /// could occur. 236 | /// 237 | /// # Example 238 | /// 239 | /// ```rust 240 | /// # use nom::{Err, Parser}; 241 | /// # use nom::error::{Error, ErrorKind}; 242 | /// use nom::character::complete::alphanumeric1; 243 | /// use nom_supreme::parser_ext::ParserExt; 244 | /// 245 | /// let mut parser = alphanumeric1.map_res_cut(|s: &str| s.parse()); 246 | /// 247 | /// assert_eq!(parser.parse("10 abc"), Ok((" abc", 10))); 248 | /// assert_eq!( 249 | /// parser.parse("<===>"), 250 | /// Err(Err::Error(Error{input: "<===>", code: ErrorKind::AlphaNumeric})), 251 | /// ); 252 | /// assert_eq!( 253 | /// parser.parse("abc abc"), 254 | /// Err(Err::Failure(Error{input: "abc abc", code: ErrorKind::MapRes})), 255 | /// ); 256 | /// ``` 257 | #[inline] 258 | #[must_use = "Parsers do nothing unless used"] 259 | fn map_res_cut(self, func: F) -> MapResCut 260 | where 261 | F: FnMut(O) -> Result, 262 | E: FromExternalError, 263 | I: Clone, 264 | { 265 | must_be_a_parser(MapResCut { 266 | parser: self, 267 | func, 268 | phantom: PhantomData, 269 | }) 270 | } 271 | 272 | /// Make this parser optional; if it fails to parse, instead it returns 273 | /// `None` with the input in the original position. 274 | /// 275 | /// # Example 276 | /// 277 | /// ```rust 278 | /// # use nom::{Err, Parser, IResult}; 279 | /// # use nom::error::{Error, ErrorKind}; 280 | /// use nom_supreme::parser_ext::ParserExt; 281 | /// use nom_supreme::tag::complete::tag; 282 | /// 283 | /// fn parser(input: &str) -> IResult<&str, Option<&str>> { 284 | /// tag("Hello").opt().parse(input) 285 | /// } 286 | /// 287 | /// assert_eq!(parser.parse("Hello, World"), Ok((", World", Some("Hello")))); 288 | /// assert_eq!(parser.parse("World"), Ok(("World", None))); 289 | /// 290 | /// let mut parser = tag("Hello").cut().opt(); 291 | /// assert_eq!( 292 | /// parser.parse("World"), 293 | /// Err(Err::Failure(Error{input: "World", code: ErrorKind::Tag})) 294 | /// ) 295 | /// ``` 296 | #[inline] 297 | #[must_use = "Parsers do nothing unless used"] 298 | fn opt(self) -> Optional 299 | where 300 | I: Clone, 301 | { 302 | must_be_a_parser(Optional { parser: self }) 303 | } 304 | 305 | /// Replace this parser's output with the entire input that was consumed 306 | /// by the parser. 307 | /// 308 | /// # Example 309 | /// 310 | /// ```rust 311 | /// # use nom::{Err, Parser}; 312 | /// # use nom::error::{Error, ErrorKind}; 313 | /// use nom::character::complete::space1; 314 | /// use nom_supreme::parser_ext::ParserExt; 315 | /// use nom_supreme::tag::complete::tag; 316 | /// 317 | /// let mut parser = tag("Hello").delimited_by(space1).recognize(); 318 | /// 319 | /// assert_eq!(parser.parse(" Hello World!"), Ok(("World!", " Hello "))); 320 | /// assert_eq!( 321 | /// parser.parse("Hello"), 322 | /// Err(Err::Error(Error{input: "Hello", code: ErrorKind::Space})) 323 | /// ) 324 | /// ``` 325 | #[inline] 326 | #[must_use = "Parsers do nothing unless used"] 327 | fn recognize(self) -> Recognize 328 | where 329 | I: Clone + Slice> + Offset, 330 | { 331 | must_be_a_parser(Recognize { 332 | parser: self.with_recognized(), 333 | phantom: PhantomData, 334 | }) 335 | } 336 | 337 | /// Return the parsed value, but also return the entire input that was 338 | /// consumed by the parse 339 | /// 340 | /// # Example 341 | /// 342 | /// ```rust 343 | /// # use nom::{Err, Parser}; 344 | /// # use nom::error::{Error, ErrorKind}; 345 | /// use nom::character::complete::space1; 346 | /// use nom_supreme::parser_ext::ParserExt; 347 | /// use nom_supreme::tag::complete::tag; 348 | /// 349 | /// let mut parser = tag("Hello").delimited_by(space1).with_recognized(); 350 | /// 351 | /// assert_eq!(parser.parse(" Hello World!"), Ok(("World!", (" Hello ", "Hello")))); 352 | /// assert_eq!( 353 | /// parser.parse("Hello"), 354 | /// Err(Err::Error(Error{input: "Hello", code: ErrorKind::Space})) 355 | /// ) 356 | /// ``` 357 | #[inline] 358 | #[must_use = "Parsers do nothing unless used"] 359 | fn with_recognized(self) -> WithRecognized 360 | where 361 | I: Clone + Slice> + Offset, 362 | { 363 | must_be_a_parser(WithRecognized { parser: self }) 364 | } 365 | 366 | /// Replace this parser's output with a clone of `value` every time it 367 | /// finishes successfully. 368 | /// 369 | /// # Example 370 | /// 371 | /// ```rust 372 | /// use cool_asserts::assert_matches; 373 | /// # use nom::{Err, Parser}; 374 | /// # use nom::error::{Error, ErrorKind}; 375 | /// use nom::branch::alt; 376 | /// use nom_supreme::parser_ext::ParserExt; 377 | /// use nom_supreme::tag::complete::tag; 378 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind, Expectation}; 379 | /// 380 | /// 381 | /// let mut parser = alt(( 382 | /// tag("true").value(true), 383 | /// tag("false").value(false), 384 | /// )); 385 | /// 386 | /// assert_eq!(parser.parse("true abc").unwrap(), (" abc", true)); 387 | /// assert_eq!(parser.parse("false abc").unwrap(), (" abc", false)); 388 | /// 389 | /// // ErrorTree gives much better error reports for alt and tag. 390 | /// let choices = assert_matches!( 391 | /// parser.parse("null"), 392 | /// Err(Err::Error(ErrorTree::Alt(choices))) => choices 393 | /// ); 394 | /// 395 | /// assert_matches!( 396 | /// choices.as_slice(), 397 | /// [ 398 | /// ErrorTree::Base { 399 | /// kind: BaseErrorKind::Expected(Expectation::Tag("true")), 400 | /// location: "null", 401 | /// }, 402 | /// ErrorTree::Base { 403 | /// kind: BaseErrorKind::Expected(Expectation::Tag("false")), 404 | /// location: "null", 405 | /// }, 406 | /// ] 407 | /// ) 408 | /// ``` 409 | #[inline] 410 | #[must_use = "Parsers do nothing unless used"] 411 | fn value(self, value: T) -> Value { 412 | must_be_a_parser(Value { 413 | parser: self, 414 | value, 415 | phantom: PhantomData, 416 | }) 417 | } 418 | 419 | /// Require the output of this parser to pass a verifier function, or 420 | /// else return a parse error. 421 | /// 422 | /// ```rust 423 | /// # use nom::{Err, Parser}; 424 | /// # use nom::error::{Error, ErrorKind}; 425 | /// use nom::character::complete::alpha1; 426 | /// use nom_supreme::parser_ext::ParserExt; 427 | /// 428 | /// let mut parser = alpha1.verify(|s: &&str| s.len() == 5); 429 | /// 430 | /// assert_eq!(parser.parse("Hello"), Ok(("", "Hello"))); 431 | /// assert_eq!(parser.parse("Hello, World"), Ok((", World", "Hello"))); 432 | /// assert_eq!( 433 | /// parser.parse("abc"), 434 | /// Err(Err::Error(Error{input: "abc", code: ErrorKind::Verify})) 435 | /// ); 436 | /// assert_eq!( 437 | /// parser.parse("abcabcabc"), 438 | /// Err(Err::Error(Error{input: "abcabcabc", code: ErrorKind::Verify})) 439 | /// ); 440 | /// assert_eq!( 441 | /// parser.parse("123"), 442 | /// Err(Err::Error(Error{input: "123", code: ErrorKind::Alpha})) 443 | /// ); 444 | /// ``` 445 | #[inline] 446 | #[must_use = "Parsers do nothing unless used"] 447 | fn verify(self, verifier: F) -> Verify 448 | where 449 | F: Fn(&O) -> bool, 450 | I: Clone, 451 | E: ParseError, 452 | { 453 | must_be_a_parser(Verify { 454 | parser: self, 455 | verifier, 456 | }) 457 | } 458 | 459 | /// Add some context to the parser. This context will be added to any 460 | /// errors that are returned from the parser via [`ContextError`]. 461 | /// 462 | /// # Example 463 | /// 464 | /// ```rust 465 | /// # use nom::{Err, Parser}; 466 | /// # use nom::error::{VerboseError, ErrorKind, VerboseErrorKind}; 467 | /// use nom::sequence::separated_pair; 468 | /// use nom::character::complete::space1; 469 | /// use nom_supreme::parser_ext::ParserExt; 470 | /// use nom_supreme::tag::complete::tag; 471 | /// 472 | /// let mut parser = separated_pair( 473 | /// tag("Hello").context("hello"), 474 | /// space1, 475 | /// tag("World").context("world"), 476 | /// ) 477 | /// .context("hello world"); 478 | /// 479 | /// assert_eq!(parser.parse("Hello World"), Ok(("", ("Hello", "World")))); 480 | /// assert_eq!( 481 | /// parser.parse("Hel"), 482 | /// Err(Err::Error(VerboseError {errors: vec![ 483 | /// ("Hel", VerboseErrorKind::Nom(ErrorKind::Tag)), 484 | /// ("Hel", VerboseErrorKind::Context("hello")), 485 | /// ("Hel", VerboseErrorKind::Context("hello world")), 486 | /// ]})) 487 | /// ); 488 | /// assert_eq!( 489 | /// parser.parse("Hello"), 490 | /// Err(Err::Error(VerboseError {errors: vec![ 491 | /// ("", VerboseErrorKind::Nom(ErrorKind::Space)), 492 | /// ("Hello", VerboseErrorKind::Context("hello world")), 493 | /// ]})) 494 | /// ); 495 | /// assert_eq!( 496 | /// parser.parse("Hello Wor"), 497 | /// Err(Err::Error(VerboseError {errors: vec![ 498 | /// ("Wor", VerboseErrorKind::Nom(ErrorKind::Tag)), 499 | /// ("Wor", VerboseErrorKind::Context("world")), 500 | /// ("Hello Wor", VerboseErrorKind::Context("hello world")), 501 | /// ]})) 502 | /// ); 503 | /// ``` 504 | #[inline] 505 | #[must_use = "Parsers do nothing unless used"] 506 | fn context(self, context: C) -> Context 507 | where 508 | E: ContextError, 509 | I: Clone, 510 | C: Clone, 511 | { 512 | must_be_a_parser(Context { 513 | context, 514 | parser: self, 515 | }) 516 | } 517 | 518 | /// Add a terminator parser. The terminator will run after this parser, 519 | /// returning any errors, but its output will otherwise be discarded. 520 | /// 521 | /// # Example 522 | /// 523 | /// ```rust 524 | /// # use nom::{Err, Parser}; 525 | /// # use nom::error::{Error, ErrorKind}; 526 | /// use nom_supreme::parser_ext::ParserExt; 527 | /// use nom_supreme::tag::complete::tag; 528 | /// 529 | /// let mut parser = tag("Hello").terminated(tag(" World")); 530 | /// 531 | /// assert_eq!(parser.parse("Hello World!"), Ok(("!", "Hello"))); 532 | /// assert_eq!( 533 | /// parser.parse("Hello"), 534 | /// Err(Err::Error(Error{input: "", code: ErrorKind::Tag})) 535 | /// ); 536 | /// ``` 537 | #[inline] 538 | #[must_use = "Parsers do nothing unless used"] 539 | fn terminated(self, terminator: F) -> Terminated 540 | where 541 | F: Parser, 542 | { 543 | must_be_a_parser(Terminated { 544 | parser: self, 545 | terminator, 546 | phantom: PhantomData, 547 | }) 548 | } 549 | 550 | /// Make this parser precede another one. The successor parser will run 551 | /// after this one succeeds, and the successor's output will be returned. 552 | /// 553 | /// # Example 554 | /// 555 | /// ```rust 556 | /// # use nom::{Err, Parser}; 557 | /// # use nom::error::{Error, ErrorKind}; 558 | /// use nom::character::complete::digit1; 559 | /// use nom_supreme::parser_ext::ParserExt; 560 | /// use nom_supreme::tag::complete::tag; 561 | /// 562 | /// let mut parser = tag("Value: ").precedes(digit1); 563 | /// 564 | /// assert_eq!(parser.parse("Value: 25;"), Ok((";", "25"))); 565 | /// assert_eq!( 566 | /// parser.parse("Value: "), 567 | /// Err(Err::Error(Error{input: "", code: ErrorKind::Digit})) 568 | /// ); 569 | /// assert_eq!( 570 | /// parser.parse("25"), 571 | /// Err(Err::Error(Error{input: "25", code: ErrorKind::Tag})) 572 | /// ); 573 | /// ``` 574 | #[inline] 575 | #[must_use = "Parsers do nothing unless used"] 576 | fn precedes(self, successor: F) -> Preceded 577 | where 578 | F: Parser, 579 | { 580 | must_be_a_parser(successor.preceded_by(self)) 581 | } 582 | 583 | /// Make this parser preceded by another one. The `prefix` will run first, 584 | /// and if it succeeds, its output will be discard and this parser will 585 | /// be run. 586 | /// 587 | /// # Example 588 | /// 589 | /// ```rust 590 | /// # use nom::{Err, Parser}; 591 | /// # use nom::error::{Error, ErrorKind}; 592 | /// use nom::character::complete::digit1; 593 | /// use nom_supreme::parser_ext::ParserExt; 594 | /// use nom_supreme::tag::complete::tag; 595 | /// 596 | /// let mut parser = digit1.preceded_by(tag("Value: ")); 597 | /// 598 | /// assert_eq!(parser.parse("Value: 25;"), Ok((";", "25"))); 599 | /// assert_eq!( 600 | /// parser.parse("Value: "), 601 | /// Err(Err::Error(Error{input: "", code: ErrorKind::Digit})) 602 | /// ); 603 | /// assert_eq!( 604 | /// parser.parse("25"), 605 | /// Err(Err::Error(Error{input: "25", code: ErrorKind::Tag})) 606 | /// ); 607 | /// ``` 608 | #[inline] 609 | #[must_use = "Parsers do nothing unless used"] 610 | fn preceded_by(self, prefix: F) -> Preceded 611 | where 612 | F: Parser, 613 | { 614 | must_be_a_parser(Preceded { 615 | parser: self, 616 | prefix, 617 | phantom: PhantomData, 618 | }) 619 | } 620 | 621 | /** 622 | Make this parser optionally precede by another one. `self` will 623 | run first, and then the `successor` will run even if `self` returns an 624 | error. Both outputs will be returned. This is functionally equivalent 625 | to `self.opt().and(successor)`, but it has the added benefit that if 626 | *both* parsers return an error, the error from the `prefix` will be 627 | retained, rather than discarded. 628 | 629 | ```rust 630 | use cool_asserts::assert_matches; 631 | # use nom::{Err, Parser, IResult}; 632 | use nom::character::complete::{digit1, char}; 633 | use nom_supreme::parser_ext::ParserExt; 634 | use nom_supreme::error::{ErrorTree, BaseErrorKind, Expectation}; 635 | 636 | let mut parser = char('-').or(char('+')).opt_precedes(digit1); 637 | 638 | assert_matches!(parser.parse("123"), Ok(("", (None, "123")))); 639 | assert_matches!(parser.parse("-123"), Ok(("", (Some('-'), "123")))); 640 | 641 | let choices = assert_matches!( 642 | parser.parse("abc"), 643 | Err(Err::Error(ErrorTree::Alt(choices))) => choices, 644 | ); 645 | 646 | assert_matches!(choices.as_slice(), [ 647 | ErrorTree::Base { 648 | location: "abc", 649 | kind: BaseErrorKind::Expected(Expectation::Char('-')) 650 | }, 651 | ErrorTree::Base { 652 | location: "abc", 653 | kind: BaseErrorKind::Expected(Expectation::Char('+')) 654 | }, 655 | ErrorTree::Base { 656 | location: "abc", 657 | kind: BaseErrorKind::Expected(Expectation::Digit) 658 | }, 659 | ]); 660 | ``` 661 | */ 662 | fn opt_precedes(self, successor: F) -> OptionalPreceded 663 | where 664 | E: ParseError, 665 | I: Clone, 666 | F: Parser, 667 | { 668 | must_be_a_parser(OptionalPreceded { 669 | prefix: self, 670 | parser: successor, 671 | }) 672 | } 673 | 674 | /** 675 | Make this parser optionally preceded by another one. The `prefix` will 676 | run first, and then this parser will run even if the `prefix` returned 677 | an error. Both outputs will be returned. This is functionally equivalent 678 | to `prefix.opt().and(self)`, but it has the added benefit that if *both* 679 | parsers return an error, the error from the `prefix` will be retained, 680 | rather than discarded. 681 | 682 | ```rust 683 | use cool_asserts::assert_matches; 684 | # use nom::{Err, Parser, IResult}; 685 | use nom::character::complete::{digit1, char}; 686 | use nom_supreme::parser_ext::ParserExt; 687 | use nom_supreme::error::{ErrorTree, BaseErrorKind, Expectation}; 688 | 689 | let mut parser = digit1.opt_preceded_by(char('-')); 690 | 691 | assert_matches!(parser.parse("123"), Ok(("", (None, "123")))); 692 | assert_matches!(parser.parse("-123"), Ok(("", (Some('-'), "123")))); 693 | 694 | let choices = assert_matches!( 695 | parser.parse("abc"), 696 | Err(Err::Error(ErrorTree::Alt(choices))) => choices, 697 | ); 698 | 699 | assert_matches!(choices.as_slice(), [ 700 | ErrorTree::Base { 701 | location: "abc", 702 | kind: BaseErrorKind::Expected(Expectation::Char('-')) 703 | }, 704 | ErrorTree::Base { 705 | location: "abc", 706 | kind: BaseErrorKind::Expected(Expectation::Digit) 707 | }, 708 | ]); 709 | ``` 710 | */ 711 | fn opt_preceded_by(self, prefix: F) -> OptionalPreceded 712 | where 713 | E: ParseError, 714 | I: Clone, 715 | F: Parser, 716 | { 717 | must_be_a_parser(OptionalPreceded { 718 | parser: self, 719 | prefix, 720 | }) 721 | } 722 | 723 | /// Make this parser delimited, requiring a `delimiter` as both a prefix and 724 | /// a suffix. The output of the delimiters is discarded. 725 | /// 726 | /// # Example 727 | /// 728 | /// ```rust 729 | /// # use nom::{Err, Parser}; 730 | /// # use nom::error::{Error, ErrorKind}; 731 | /// use nom::character::complete::{char, digit1}; 732 | /// use nom_supreme::parser_ext::ParserExt; 733 | /// 734 | /// let mut parser = digit1.delimited_by(char('\'')); 735 | /// 736 | /// assert_eq!(parser.parse("'123' '456'"), Ok((" '456'", "123"))); 737 | /// assert_eq!( 738 | /// parser.parse("'' ''"), 739 | /// Err(Err::Error(Error{input: "' ''", code: ErrorKind::Digit})) 740 | /// ); 741 | /// assert_eq!( 742 | /// parser.parse("'123 '"), 743 | /// Err(Err::Error(Error{input: " '", code: ErrorKind::Char})) 744 | /// ); 745 | /// ``` 746 | #[inline] 747 | #[must_use = "Parsers do nothing unless used"] 748 | fn delimited_by(self, delimiter: D) -> Delimited 749 | where 750 | D: Parser, 751 | { 752 | must_be_a_parser(Delimited { 753 | parser: self, 754 | delimiter, 755 | phantom: PhantomData, 756 | }) 757 | } 758 | 759 | /// Make this parser peeking: it runs normally but consumes no input. 760 | /// 761 | /// # Example 762 | /// 763 | /// ```rust 764 | /// # use nom::{Err, Parser}; 765 | /// # use nom::error::{Error, ErrorKind}; 766 | /// use nom_supreme::parser_ext::ParserExt; 767 | /// use nom_supreme::tag::complete::tag; 768 | /// 769 | /// let mut parser = tag("Hello").peek(); 770 | /// 771 | /// assert_eq!(parser.parse("Hello World"), Ok(("Hello World", "Hello"))); 772 | /// assert_eq!( 773 | /// parser.parse("World"), 774 | /// Err(Err::Error(Error{input: "World", code: ErrorKind::Tag})) 775 | /// ); 776 | /// ``` 777 | #[inline] 778 | #[must_use = "Parsers do nothing unless used"] 779 | fn peek(self) -> Peek 780 | where 781 | I: Clone, 782 | { 783 | must_be_a_parser(Peek { parser: self }) 784 | } 785 | 786 | /// Make this parser a negative lookahead: it will succeed if the subparser 787 | /// fails, and fail if the subparser succeeds. 788 | /// 789 | /// # Example 790 | /// 791 | /// ```rust 792 | /// # use nom::{Err, Parser}; 793 | /// # use nom::error::{Error, ErrorKind}; 794 | /// use nom_supreme::parser_ext::ParserExt; 795 | /// use nom_supreme::tag::complete::tag; 796 | /// 797 | /// let mut parser = tag("Hello").not(); 798 | /// 799 | /// assert_eq!(parser.parse("World"), Ok(("World", ()))); 800 | /// assert_eq!( 801 | /// parser.parse("Hello World"), 802 | /// Err(Err::Error(Error{input: "Hello World", code: ErrorKind::Not})), 803 | /// ); 804 | /// ``` 805 | #[inline] 806 | #[must_use = "Parsers do nothing unless used"] 807 | fn not(self) -> Not 808 | where 809 | I: Clone, 810 | E: ParseError, 811 | { 812 | must_be_a_parser(Not { 813 | parser: self, 814 | phantom: PhantomData, 815 | }) 816 | } 817 | 818 | /// Create a parser that parses something via [`FromStr`], using this 819 | /// parser as a recognizer for the string to pass to 820 | /// [`from_str`][FromStr::from_str]. 821 | /// 822 | /// # Example 823 | /// 824 | /// ```rust 825 | /// # use nom::{Err, Parser, IResult}; 826 | /// # use nom::error::{Error, ErrorKind}; 827 | /// use nom::character::complete::digit1; 828 | /// use nom_supreme::parser_ext::ParserExt; 829 | /// 830 | /// let mut parser = digit1.parse_from_str(); 831 | /// 832 | /// assert_eq!(parser.parse("123 abc"), Ok((" abc", 123))); 833 | /// assert_eq!( 834 | /// parser.parse("abc"), 835 | /// Err(Err::Error(Error{input: "abc", code: ErrorKind::Digit})), 836 | /// ); 837 | /// ``` 838 | /// 839 | /// # Parse error example 840 | /// 841 | /// If the [`FromStr`] parser fails, the error is recoverable from via 842 | /// [`FromExternalError`]. In general, though, it's better practice to 843 | /// ensure your recognizer won't allow invalid strings to be forwarded to 844 | /// the [`FromStr`] parser 845 | /// 846 | /// ```rust 847 | /// use std::num::ParseIntError; 848 | /// use cool_asserts::assert_matches; 849 | /// # use nom::{Err, Parser, IResult}; 850 | /// # use nom::error::{ErrorKind}; 851 | /// use nom::character::complete::alphanumeric1; 852 | /// use nom_supreme::parser_ext::ParserExt; 853 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind}; 854 | /// 855 | /// let mut parser = alphanumeric1.parse_from_str(); 856 | /// 857 | /// assert_matches!(parser.parse("123 abc"), Ok((" abc", 123))); 858 | /// assert_matches!( 859 | /// parser.parse("abc"), 860 | /// Err(Err::Error(ErrorTree::Base{ 861 | /// location: "abc", 862 | /// kind: BaseErrorKind::External(err), 863 | /// })) => { 864 | /// let _err: &ParseIntError = err.downcast_ref().unwrap(); 865 | /// }, 866 | /// ); 867 | /// ``` 868 | #[inline] 869 | #[must_use = "Parsers do nothing unless used"] 870 | fn parse_from_str<'a, T>(self) -> FromStrParser 871 | where 872 | Self: Parser, 873 | I: Clone, 874 | T: FromStr, 875 | E: FromExternalError, 876 | { 877 | must_be_a_parser(FromStrParser { 878 | parser: self, 879 | phantom: PhantomData, 880 | }) 881 | } 882 | 883 | /// Create a parser that parses something via [`FromStr`], using this 884 | /// parser as a recognizer for the string to pass to 885 | /// [`from_str`][FromStr::from_str]. This parser transforms any errors 886 | /// from [`FromStr`] into [`Err::Failure`][NomErr::Failure], which will 887 | /// end the overall parse immediately, even if there are other branches 888 | /// that could be tried. 889 | /// 890 | /// # Example 891 | /// 892 | /// ```rust 893 | /// # use nom::{Err, Parser, IResult}; 894 | /// # use nom::error::{Error, ErrorKind}; 895 | /// use nom::character::complete::alphanumeric1; 896 | /// use nom_supreme::parser_ext::ParserExt; 897 | /// 898 | /// let mut parser = alphanumeric1.parse_from_str_cut(); 899 | /// 900 | /// assert_eq!(parser.parse("123 abc"), Ok((" abc", 123))); 901 | /// assert_eq!( 902 | /// parser.parse("<===>"), 903 | /// Err(Err::Error(Error{input: "<===>", code: ErrorKind::AlphaNumeric})), 904 | /// ); 905 | /// assert_eq!( 906 | /// parser.parse("abc"), 907 | /// Err(Err::Failure(Error{input: "abc", code: ErrorKind::MapRes})), 908 | /// ); 909 | /// ``` 910 | /// 911 | /// # Parse error example 912 | /// 913 | /// If the [`FromStr`] parser fails, the error is recoverable from via 914 | /// [`FromExternalError`]. In general, though, it's better practice to 915 | /// ensure your recognizer won't allow invalid strings to be forwarded to 916 | /// the [`FromStr`] parser 917 | /// 918 | /// ```rust 919 | /// use std::num::ParseIntError; 920 | /// use cool_asserts::assert_matches; 921 | /// # use nom::{Err, Parser, IResult}; 922 | /// # use nom::error::{ErrorKind}; 923 | /// use nom::character::complete::alphanumeric1; 924 | /// use nom_supreme::parser_ext::ParserExt; 925 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind}; 926 | /// 927 | /// let mut parser = alphanumeric1.parse_from_str_cut(); 928 | /// 929 | /// assert_matches!(parser.parse("123 abc"), Ok((" abc", 123))); 930 | /// assert_matches!( 931 | /// parser.parse("abc"), 932 | /// Err(Err::Failure(ErrorTree::Base{ 933 | /// location: "abc", 934 | /// kind: BaseErrorKind::External(err), 935 | /// })) => { 936 | /// let _err: &ParseIntError = err.downcast_ref().unwrap(); 937 | /// }, 938 | /// ); 939 | /// ``` 940 | #[inline] 941 | #[must_use = "Parsers do nothing unless used"] 942 | fn parse_from_str_cut<'a, T>(self) -> FromStrCutParser 943 | where 944 | Self: Parser, 945 | I: Clone, 946 | T: FromStr, 947 | E: FromExternalError, 948 | { 949 | must_be_a_parser(FromStrCutParser { 950 | parser: self, 951 | phantom: PhantomData, 952 | }) 953 | } 954 | 955 | /// Create a parser that parses a fixed-size array by running this parser 956 | /// in a loop. 957 | /// 958 | /// The returned parser implements [`Parser`] generically over any 959 | /// `const N: usize`, which means it can be used to parse arrays of any 960 | /// length 961 | /// 962 | /// # Example 963 | /// 964 | /// ```rust 965 | /// use cool_asserts::assert_matches; 966 | /// use nom::character::complete::digit1; 967 | /// # use nom::{Parser, Err, IResult}; 968 | /// # use nom::error::{ErrorKind, Error}; 969 | /// use nom_supreme::ParserExt; 970 | /// use nom_supreme::tag::complete::tag; 971 | /// 972 | /// let mut parser = digit1 973 | /// .terminated(tag(", ")) 974 | /// .parse_from_str() 975 | /// .array(); 976 | /// 977 | /// assert_matches!(parser.parse("123, 456, 789, abc"), Ok(("789, abc", [123, 456]))); 978 | /// assert_matches!(parser.parse("123, 456, 789, abc"), Ok(("abc", [123, 456, 789]))); 979 | /// 980 | /// let res: Result<(&str, [u16; 4]), Err>> = parser.parse("123, 456, 789, abc"); 981 | /// assert_matches!( 982 | /// res, 983 | /// Err(Err::Error(Error{input: "abc", code: ErrorKind::Digit})) 984 | /// ); 985 | /// ``` 986 | /// 987 | /// Note that this parser does not attach any additional context to the 988 | /// error in the event of a parser; consider using [`context`][Self::context] 989 | /// on the item parser or array parser to add additional information about 990 | /// where in the input there was a parse failure. 991 | #[inline] 992 | #[must_use = "Parsers do nothing unless used"] 993 | fn array(self) -> ArrayParser { 994 | ArrayParser { parser: self } 995 | } 996 | 997 | /// Create a parser that parses a fixed-size array by running this parser 998 | /// in a loop, parsing a separator in between each element. 999 | /// 1000 | /// The returned parser implements [`Parser`] generically over any 1001 | /// `const N: usize`, which means it can be used to parse arrays of any 1002 | /// length 1003 | /// 1004 | /// # Example 1005 | /// 1006 | /// ```rust 1007 | /// use std::net::{Ipv4Addr, SocketAddrV4}; 1008 | /// use cool_asserts::assert_matches; 1009 | /// use nom::character::complete::{char, digit1}; 1010 | /// # use nom::{Parser, Err, IResult}; 1011 | /// # use nom::error::{ErrorKind, Error}; 1012 | /// use nom_supreme::ParserExt; 1013 | /// use nom_supreme::tag::complete::tag; 1014 | /// 1015 | /// let mut parser = digit1 1016 | /// .parse_from_str() 1017 | /// .separated_array(char('.')) 1018 | /// .map(Ipv4Addr::from) 1019 | /// .terminated(char(':')) 1020 | /// .and(digit1.parse_from_str()) 1021 | /// .map(|(ip, port)| SocketAddrV4::new(ip, port)); 1022 | /// 1023 | /// let (_tail, socket_addr) = parser.parse("192.168.0.1:80").unwrap(); 1024 | /// assert_eq!(socket_addr.ip().octets(), [192, 168, 0, 1]); 1025 | /// assert_eq!(socket_addr.port(), 80); 1026 | /// 1027 | /// assert_matches!( 1028 | /// parser.parse("192.168.0.abc:80"), 1029 | /// Err(Err::Error(Error{input: "abc:80", code: ErrorKind::Digit})), 1030 | /// ); 1031 | /// 1032 | /// assert_matches!( 1033 | /// parser.parse("192.168.0.1"), 1034 | /// Err(Err::Error(Error{input: "", code: ErrorKind::Char})), 1035 | /// ); 1036 | /// 1037 | /// assert_matches!( 1038 | /// parser.parse("192.168.0.1000:80"), 1039 | /// Err(Err::Error(Error{input: "1000:80", code: ErrorKind::MapRes})), 1040 | /// ); 1041 | /// 1042 | /// assert_matches!( 1043 | /// parser.parse("192.168.10abc"), 1044 | /// Err(Err::Error(Error{input: "abc", code: ErrorKind::Char})), 1045 | /// ); 1046 | /// ``` 1047 | /// 1048 | /// Note that this parser does not attach any additional context to the 1049 | /// error in the event of a parser; consider using [`context`][Self::context] 1050 | /// on the item, separator, or array parsers to add additional information 1051 | /// about where in the input there was a parse failure. 1052 | #[inline] 1053 | #[must_use = "Parsers do nothing unless used"] 1054 | fn separated_array(self, separator: F) -> SeparatedArrayParser 1055 | where 1056 | F: Parser, 1057 | { 1058 | SeparatedArrayParser { 1059 | parser: self, 1060 | separator, 1061 | phantom: PhantomData, 1062 | } 1063 | } 1064 | } 1065 | 1066 | impl ParserExt for P where P: Parser {} 1067 | 1068 | /// Parser wrapping a mutable reference to a subparser. 1069 | #[derive(Debug)] 1070 | pub struct RefParser<'a, P> { 1071 | parser: &'a mut P, 1072 | } 1073 | 1074 | impl<'a, I, O, E, P> Parser for RefParser<'a, P> 1075 | where 1076 | P: Parser, 1077 | { 1078 | #[inline] 1079 | fn parse(&mut self, input: I) -> nom::IResult { 1080 | self.parser.parse(input) 1081 | } 1082 | } 1083 | 1084 | /// Parser which returns an error if the subparser didn't consume the whole 1085 | /// input. 1086 | #[derive(Debug, Clone, Copy)] 1087 | pub struct AllConsuming

{ 1088 | parser: P, 1089 | } 1090 | 1091 | impl Parser for AllConsuming

1092 | where 1093 | P: Parser, 1094 | E: ParseError, 1095 | I: InputLength, 1096 | { 1097 | #[inline] 1098 | fn parse(&mut self, input: I) -> nom::IResult { 1099 | let (tail, value) = self.parser.parse(input)?; 1100 | 1101 | if tail.input_len() > 0 { 1102 | Err(NomErr::Error(E::from_error_kind(tail, NomErrorKind::Eof))) 1103 | } else { 1104 | Ok((tail, value)) 1105 | } 1106 | } 1107 | } 1108 | 1109 | /// Parser which returns an error if the subparser returned 1110 | /// [`Incomplete`][nom::Err::Incomplete]. 1111 | #[derive(Debug, Clone, Copy)] 1112 | pub struct Complete

{ 1113 | parser: P, 1114 | } 1115 | 1116 | impl Parser for Complete

1117 | where 1118 | P: Parser, 1119 | E: ParseError, 1120 | I: Clone, 1121 | { 1122 | #[inline] 1123 | fn parse(&mut self, input: I) -> nom::IResult { 1124 | self.parser 1125 | .parse(input.clone()) 1126 | .map_err(move |err| match err { 1127 | NomErr::Incomplete(..) => { 1128 | // TODO: should this error be reported at the very end 1129 | // of the input? Since the error occurred at the eof? 1130 | NomErr::Error(E::from_error_kind(input, NomErrorKind::Complete)) 1131 | } 1132 | err => err, 1133 | }) 1134 | } 1135 | } 1136 | 1137 | /// Parser which returns a [`Failure`][nom::Err::Failure] if the subparser 1138 | /// returned an error. This prevents other branches from being tried. 1139 | #[derive(Debug, Clone, Copy)] 1140 | pub struct Cut

{ 1141 | parser: P, 1142 | } 1143 | 1144 | impl Parser for Cut

1145 | where 1146 | P: Parser, 1147 | { 1148 | #[inline] 1149 | fn parse(&mut self, input: I) -> nom::IResult { 1150 | self.parser.parse(input).map_err(|err| match err { 1151 | NomErr::Error(err) => NomErr::Failure(err), 1152 | err => err, 1153 | }) 1154 | } 1155 | } 1156 | 1157 | /// Parser which wraps the subparser output in an [`Option`], and returns a 1158 | /// successful [`None`] output if it fails. 1159 | #[derive(Debug, Clone, Copy)] 1160 | pub struct Optional

{ 1161 | parser: P, 1162 | } 1163 | 1164 | impl Parser, E> for Optional

1165 | where 1166 | P: Parser, 1167 | I: Clone, 1168 | { 1169 | #[inline] 1170 | fn parse(&mut self, input: I) -> nom::IResult, E> { 1171 | match self.parser.parse(input.clone()) { 1172 | Ok((tail, value)) => Ok((tail, Some(value))), 1173 | Err(NomErr::Error(_)) => Ok((input, None)), 1174 | Err(e) => Err(e), 1175 | } 1176 | } 1177 | } 1178 | 1179 | /// Parser which, when successful, discards the output of the subparser and 1180 | /// instead returns the consumed input. 1181 | #[derive(Debug, Clone, Copy)] 1182 | pub struct Recognize { 1183 | parser: WithRecognized

, 1184 | phantom: PhantomData, 1185 | } 1186 | 1187 | impl Parser for Recognize 1188 | where 1189 | P: Parser, 1190 | I: Clone + Slice> + Offset, 1191 | { 1192 | #[inline] 1193 | fn parse(&mut self, input: I) -> nom::IResult { 1194 | self.parser 1195 | .parse(input) 1196 | .map(|(tail, (recognized, _))| (tail, recognized)) 1197 | } 1198 | } 1199 | 1200 | /// Parser which, when successful, returns the result of the inner parser and 1201 | /// also the consumed input 1202 | #[derive(Debug, Clone, Copy)] 1203 | pub struct WithRecognized

{ 1204 | parser: P, 1205 | } 1206 | 1207 | impl Parser for WithRecognized

1208 | where 1209 | P: Parser, 1210 | I: Clone + Slice> + Offset, 1211 | { 1212 | #[inline] 1213 | fn parse(&mut self, input: I) -> nom::IResult { 1214 | let (tail, output) = self.parser.parse(input.clone())?; 1215 | let index = input.offset(&tail); 1216 | Ok((tail, (input.slice(..index), output))) 1217 | } 1218 | } 1219 | 1220 | /// Parser which, when successful, discards the output of the subparser and 1221 | /// instead returns a clone of a value. 1222 | #[derive(Debug, Clone, Copy)] 1223 | pub struct Value { 1224 | parser: P, 1225 | value: T, 1226 | phantom: PhantomData, 1227 | } 1228 | 1229 | impl Parser for Value 1230 | where 1231 | P: Parser, 1232 | T: Clone, 1233 | { 1234 | #[inline] 1235 | fn parse(&mut self, input: I) -> nom::IResult { 1236 | self.parser 1237 | .parse(input) 1238 | .map(|(input, _)| (input, self.value.clone())) 1239 | } 1240 | } 1241 | 1242 | /// Parser which checks the output of its subparser against a verifier function. 1243 | #[derive(Debug, Clone, Copy)] 1244 | pub struct Verify { 1245 | parser: P, 1246 | verifier: F, 1247 | } 1248 | 1249 | impl Parser for Verify 1250 | where 1251 | P: Parser, 1252 | E: ParseError, 1253 | F: Fn(&O) -> bool, 1254 | I: Clone, 1255 | { 1256 | #[inline] 1257 | fn parse(&mut self, input: I) -> nom::IResult { 1258 | let (tail, value) = self.parser.parse(input.clone())?; 1259 | 1260 | match (self.verifier)(&value) { 1261 | true => Ok((tail, value)), 1262 | false => Err(NomErr::Error(E::from_error_kind( 1263 | input, 1264 | NomErrorKind::Verify, 1265 | ))), 1266 | } 1267 | } 1268 | } 1269 | 1270 | /// Parser which attaches additional context to any errors returned by the 1271 | /// subparser. 1272 | #[derive(Debug, Clone, Copy)] 1273 | pub struct Context { 1274 | context: C, 1275 | parser: P, 1276 | } 1277 | 1278 | impl Parser for Context 1279 | where 1280 | P: Parser, 1281 | E: ContextError, 1282 | I: Clone, 1283 | C: Clone, 1284 | { 1285 | #[inline] 1286 | fn parse(&mut self, input: I) -> nom::IResult { 1287 | self.parser.parse(input.clone()).map_err(move |err| { 1288 | err.map(move |err| E::add_context(input, self.context.clone(), err)) 1289 | }) 1290 | } 1291 | } 1292 | 1293 | /// Parser which replaces errors coming from the inner parser. 1294 | #[derive(Debug, Clone, Copy)] 1295 | pub struct ReplaceError { 1296 | new_error: E, 1297 | parser: P, 1298 | } 1299 | 1300 | impl Parser for ReplaceError 1301 | where 1302 | P: Parser, 1303 | F: FnMut() -> E, 1304 | { 1305 | fn parse(&mut self, input: I) -> nom::IResult { 1306 | self.parser 1307 | .parse(input) 1308 | .map_err(|err| err.map(|()| (self.new_error)())) 1309 | } 1310 | } 1311 | 1312 | /// Parser which gets and discards an output from a second subparser, 1313 | /// returning the output from the original parser if both were successful. 1314 | #[derive(Debug, Clone, Copy)] 1315 | pub struct Terminated { 1316 | parser: P1, 1317 | terminator: P2, 1318 | phantom: PhantomData, 1319 | } 1320 | 1321 | impl Parser for Terminated 1322 | where 1323 | P1: Parser, 1324 | P2: Parser, 1325 | { 1326 | #[inline] 1327 | fn parse(&mut self, input: I) -> nom::IResult { 1328 | let (input, value) = self.parser.parse(input)?; 1329 | let (input, _) = self.terminator.parse(input)?; 1330 | 1331 | Ok((input, value)) 1332 | } 1333 | } 1334 | 1335 | /// Parser which gets and discards an output from a prefix subparser before 1336 | /// running the main subparser. Returns the output from the main subparser if 1337 | /// both were successful. 1338 | #[derive(Debug, Clone, Copy)] 1339 | pub struct Preceded { 1340 | parser: P1, 1341 | prefix: P2, 1342 | phantom: PhantomData, 1343 | } 1344 | 1345 | impl Parser for Preceded 1346 | where 1347 | P1: Parser, 1348 | P2: Parser, 1349 | { 1350 | #[inline] 1351 | fn parse(&mut self, input: I) -> nom::IResult { 1352 | let (input, _) = self.prefix.parse(input)?; 1353 | self.parser.parse(input) 1354 | } 1355 | } 1356 | 1357 | /// Parser which gets an optional output from a prefix subparser before running 1358 | /// the main subparser. Returns the output even if the prefix subparser returns 1359 | /// error. 1360 | #[derive(Debug, Clone, Copy)] 1361 | pub struct OptionalPreceded { 1362 | parser: P2, 1363 | prefix: P1, 1364 | } 1365 | 1366 | impl Parser, O2), E> for OptionalPreceded 1367 | where 1368 | P1: Parser, 1369 | P2: Parser, 1370 | I: Clone, 1371 | E: ParseError, 1372 | { 1373 | #[inline] 1374 | fn parse(&mut self, input: I) -> nom::IResult, O2), E> { 1375 | match self.prefix.parse(input.clone()) { 1376 | Ok((input, o1)) => self 1377 | .parser 1378 | .parse(input) 1379 | .map(|(tail, o2)| (tail, (Some(o1), o2))), 1380 | Err(NomErr::Error(err1)) => self 1381 | .parser 1382 | .parse(input) 1383 | .map(|(tail, o2)| (tail, (None, o2))) 1384 | .map_err(|err2| err2.map(|err2| err1.or(err2))), 1385 | Err(err) => Err(err), 1386 | } 1387 | } 1388 | } 1389 | 1390 | /// Parser which gets and discards a delimiting value both before and after the 1391 | /// main subparser. Returns the output from the main subparser if all were 1392 | /// successful. 1393 | #[derive(Debug, Clone, Copy)] 1394 | pub struct Delimited { 1395 | parser: P, 1396 | delimiter: D, 1397 | phantom: PhantomData, 1398 | } 1399 | 1400 | impl Parser for Delimited 1401 | where 1402 | P: Parser, 1403 | D: Parser, 1404 | { 1405 | #[inline] 1406 | fn parse(&mut self, input: I) -> nom::IResult { 1407 | let (input, _) = self.delimiter.parse(input)?; 1408 | let (input, value) = self.parser.parse(input)?; 1409 | let (input, _) = self.delimiter.parse(input)?; 1410 | 1411 | Ok((input, value)) 1412 | } 1413 | } 1414 | 1415 | /// Parser which runs a fallible mapping function on the output of the 1416 | /// subparser. Any errors returned by the mapping function are transformed 1417 | /// into a parse error. 1418 | /// 1419 | #[derive(Debug, Clone, Copy)] 1420 | pub struct MapRes { 1421 | parser: P, 1422 | func: F, 1423 | phantom: PhantomData<(O, E2)>, 1424 | } 1425 | 1426 | impl Parser for MapRes 1427 | where 1428 | P: Parser, 1429 | F: FnMut(O) -> Result, 1430 | E: FromExternalError, 1431 | I: Clone, 1432 | { 1433 | #[inline] 1434 | fn parse(&mut self, input: I) -> nom::IResult { 1435 | let (tail, value) = self.parser.parse(input.clone())?; 1436 | 1437 | (self.func)(value) 1438 | .map(move |value| (tail, value)) 1439 | .map_err(move |err| { 1440 | NomErr::Error(E::from_external_error(input, NomErrorKind::MapRes, err)) 1441 | }) 1442 | } 1443 | } 1444 | 1445 | /// Parser which runs a fallible mapping function on the output of the 1446 | /// subparser. Any errors returned by the mapping function are transformed 1447 | /// into a parse failure. 1448 | /// 1449 | #[derive(Debug, Clone, Copy)] 1450 | pub struct MapResCut { 1451 | parser: P, 1452 | func: F, 1453 | phantom: PhantomData<(O, E2)>, 1454 | } 1455 | 1456 | impl Parser for MapResCut 1457 | where 1458 | P: Parser, 1459 | F: FnMut(O) -> Result, 1460 | E: FromExternalError, 1461 | I: Clone, 1462 | { 1463 | #[inline] 1464 | fn parse(&mut self, input: I) -> nom::IResult { 1465 | let (tail, value) = self.parser.parse(input.clone())?; 1466 | 1467 | (self.func)(value) 1468 | .map(move |value| (tail, value)) 1469 | .map_err(move |err| { 1470 | NomErr::Failure(E::from_external_error(input, NomErrorKind::MapRes, err)) 1471 | }) 1472 | } 1473 | } 1474 | /// Parser which runs a subparser but doesn't consume any input 1475 | #[derive(Debug, Clone, Copy)] 1476 | pub struct Peek

{ 1477 | parser: P, 1478 | } 1479 | 1480 | impl Parser for Peek

1481 | where 1482 | P: Parser, 1483 | I: Clone, 1484 | { 1485 | #[inline] 1486 | fn parse(&mut self, input: I) -> nom::IResult { 1487 | self.parser 1488 | .parse(input.clone()) 1489 | .map(|(_, value)| (input, value)) 1490 | } 1491 | } 1492 | 1493 | /// Parser which returns failure if the subparser succeeds, and succeeds if the 1494 | /// subparser fails. 1495 | #[derive(Debug, Clone, Copy)] 1496 | pub struct Not { 1497 | parser: P, 1498 | phantom: PhantomData, 1499 | } 1500 | 1501 | impl Parser for Not 1502 | where 1503 | P: Parser, 1504 | I: Clone, 1505 | E: ParseError, 1506 | { 1507 | #[inline] 1508 | fn parse(&mut self, input: I) -> nom::IResult { 1509 | match self.parser.parse(input.clone()) { 1510 | Ok(..) => Err(NomErr::Error(E::from_error_kind(input, NomErrorKind::Not))), 1511 | Err(NomErr::Error(..)) => Ok((input, ())), 1512 | Err(err) => Err(err), 1513 | } 1514 | } 1515 | } 1516 | 1517 | /// Parser which parses something via [`FromStr`], using a subparser as a 1518 | /// recognizer for the string to pass to [`from_str`][FromStr::from_str]. 1519 | #[derive(Debug, Clone, Copy)] 1520 | pub struct FromStrParser { 1521 | parser: P, 1522 | phantom: PhantomData, 1523 | } 1524 | 1525 | impl<'a, T, I, E, P> Parser for FromStrParser 1526 | where 1527 | P: Parser, 1528 | I: Clone, 1529 | T: FromStr, 1530 | E: FromExternalError, 1531 | { 1532 | #[inline] 1533 | fn parse(&mut self, input: I) -> nom::IResult { 1534 | let (tail, value_str) = self.parser.parse(input.clone())?; 1535 | match value_str.parse() { 1536 | Ok(value) => Ok((tail, value)), 1537 | Err(parse_err) => Err(NomErr::Error(E::from_external_error( 1538 | input, 1539 | NomErrorKind::MapRes, 1540 | parse_err, 1541 | ))), 1542 | } 1543 | } 1544 | } 1545 | 1546 | #[cfg(feature = "error")] 1547 | #[test] 1548 | fn from_str_parser_non_str_input() { 1549 | use core::str::from_utf8; 1550 | 1551 | use cool_asserts::assert_matches; 1552 | use nom::{ 1553 | character::complete::{char, digit1}, 1554 | Err as NomErr, 1555 | }; 1556 | 1557 | use crate::error::{BaseErrorKind, ErrorTree, Expectation}; 1558 | 1559 | let mut parser = digit1 1560 | .opt_preceded_by(char('-')) 1561 | .recognize() 1562 | .map_res(from_utf8) 1563 | .parse_from_str(); 1564 | 1565 | assert_matches!(parser.parse(b"-123"), Ok((b"", -123))); 1566 | 1567 | let branches = assert_matches!(parser.parse(b"abc"), Err(NomErr::Error(ErrorTree::Alt(branches))) => branches); 1568 | 1569 | assert_matches!( 1570 | branches.as_slice(), 1571 | [ 1572 | ErrorTree::Base { 1573 | location: b"abc", 1574 | kind: BaseErrorKind::Expected(Expectation::Char('-')) 1575 | }, 1576 | ErrorTree::Base { 1577 | location: b"abc", 1578 | kind: BaseErrorKind::Expected(Expectation::Digit) 1579 | } 1580 | ] 1581 | ) 1582 | } 1583 | 1584 | /// Parser which parses something via [`FromStr`], using a subparser as a 1585 | /// recognizer for the string to pass to [`from_str`][FromStr::from_str]. 1586 | /// Returns [`Err::Failure`][NomErr::Failure] if the [`FromStr`] parse fails. 1587 | #[derive(Debug, Clone, Copy)] 1588 | pub struct FromStrCutParser { 1589 | parser: P, 1590 | phantom: PhantomData, 1591 | } 1592 | 1593 | impl<'a, I, T, E, P> Parser for FromStrCutParser 1594 | where 1595 | P: Parser, 1596 | I: Clone, 1597 | T: FromStr, 1598 | E: FromExternalError, 1599 | { 1600 | #[inline] 1601 | fn parse(&mut self, input: I) -> nom::IResult { 1602 | let (tail, value_str) = self.parser.parse(input.clone())?; 1603 | match value_str.parse() { 1604 | Ok(value) => Ok((tail, value)), 1605 | Err(parse_err) => Err(NomErr::Failure(E::from_external_error( 1606 | input, 1607 | NomErrorKind::MapRes, 1608 | parse_err, 1609 | ))), 1610 | } 1611 | } 1612 | } 1613 | 1614 | /// Parser which parses an array by running a subparser in a loop a fixed 1615 | /// number of times. 1616 | #[derive(Debug, Clone, Copy)] 1617 | pub struct ArrayParser

{ 1618 | parser: P, 1619 | } 1620 | 1621 | impl Parser for ArrayParser

1622 | where 1623 | P: Parser, 1624 | { 1625 | fn parse(&mut self, mut input: I) -> nom::IResult { 1626 | let array = brownstone::build![{ 1627 | let (tail, value) = self.parser.parse(input)?; 1628 | input = tail; 1629 | value 1630 | }]; 1631 | 1632 | Ok((input, array)) 1633 | } 1634 | } 1635 | 1636 | /// Parser which parses an array by running a subparser in a loop a fixed 1637 | /// number of times, parsing a separator between each item. 1638 | #[derive(Debug, Clone, Copy)] 1639 | pub struct SeparatedArrayParser { 1640 | parser: P1, 1641 | separator: P2, 1642 | phantom: PhantomData, 1643 | } 1644 | 1645 | impl Parser 1646 | for SeparatedArrayParser 1647 | where 1648 | P1: Parser, 1649 | P2: Parser, 1650 | { 1651 | fn parse(&mut self, mut input: I) -> nom::IResult { 1652 | let array = brownstone::build!(|index: usize| { 1653 | let tail = match index { 1654 | 0 => input, 1655 | _ => self.separator.parse(input)?.0, 1656 | }; 1657 | 1658 | let (tail, value) = self.parser.parse(tail)?; 1659 | input = tail; 1660 | value 1661 | }); 1662 | 1663 | Ok((input, array)) 1664 | } 1665 | } 1666 | -------------------------------------------------------------------------------- /src/tag.rs: -------------------------------------------------------------------------------- 1 | //! Enhanced tag parser for nom. 2 | //! 3 | //! This module introduces a new trait, [`TagError`], and variants of `tag` 4 | //! and `tag_case_insensitive` that can use the trait to add to an error the 5 | //! specific tag that was expected. This allows the error message to report 6 | //! something like `Expected tag: "true"` instead of just `Error: Tag`. 7 | 8 | use nom::error::{Error, ErrorKind}; 9 | 10 | use nom::error::{ParseError, VerboseError}; 11 | 12 | /// Similar to [`FromExternalError`][nom::error::FromExternalError] and 13 | /// [`ContextError`][crate::context::ContextError], this trait allows a parser 14 | /// to create an error representing an unmatched tag. This allows error 15 | /// messages to produce more useful context about what went wrong. 16 | pub trait TagError: Sized { 17 | /// Create an error from an expected tag at a location. 18 | fn from_tag(input: I, tag: T) -> Self; 19 | 20 | /// As above, but for a case insensitive tag. By default this just 21 | /// calls [`from_tag`][Self::from_tag] 22 | fn from_tag_no_case(input: I, tag: T) -> Self { 23 | Self::from_tag(input, tag) 24 | } 25 | } 26 | 27 | impl TagError for () { 28 | fn from_tag(_input: I, _tag: T) {} 29 | } 30 | 31 | impl TagError for (I, ErrorKind) { 32 | fn from_tag(input: I, _tag: T) -> Self { 33 | (input, ErrorKind::Tag) 34 | } 35 | } 36 | 37 | impl TagError for Error { 38 | fn from_tag(input: I, _tag: T) -> Self { 39 | Error::new(input, ErrorKind::Tag) 40 | } 41 | } 42 | 43 | impl TagError for VerboseError { 44 | fn from_tag(input: I, _tag: T) -> Self { 45 | VerboseError::from_error_kind(input, ErrorKind::Tag) 46 | } 47 | } 48 | 49 | /// Complete input version of enhanced `tag` parsers 50 | pub mod complete { 51 | use nom::{Compare, CompareResult, Err, IResult, InputLength, InputTake}; 52 | 53 | use super::TagError; 54 | 55 | /// Parser recognizing a fixed pattern, called a tag. If the front of the 56 | /// input data matches the `tag`, that part of the input will be returned. 57 | /// Records the tag in the error in the event of a parse failure via 58 | /// [`TagError`]. 59 | /// 60 | /// # Example 61 | /// 62 | /// ``` 63 | /// # use nom::{IResult, Err, Needed}; 64 | /// use cool_asserts::assert_matches; 65 | /// use nom_supreme::tag::complete::tag; 66 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind, Expectation}; 67 | /// 68 | /// fn parse_hello(s: &str) -> IResult<&str, &str, ErrorTree<&str>> { 69 | /// tag("hello")(s) 70 | /// } 71 | /// 72 | /// assert_matches!( 73 | /// parse_hello("hello, world!"), 74 | /// Ok((", world!", "hello")), 75 | /// ); 76 | /// 77 | /// assert_matches!( 78 | /// parse_hello("something"), 79 | /// Err(Err::Error(ErrorTree::Base { 80 | /// location: "something", 81 | /// kind: BaseErrorKind::Expected(Expectation::Tag("hello")), 82 | /// })) 83 | /// ); 84 | /// 85 | /// assert_matches!( 86 | /// parse_hello("hel"), 87 | /// Err(Err::Error(ErrorTree::Base { 88 | /// location: "hel", 89 | /// kind: BaseErrorKind::Expected(Expectation::Tag("hello")), 90 | /// })) 91 | /// ); 92 | /// ``` 93 | pub fn tag(tag: T) -> impl Clone + Fn(I) -> IResult 94 | where 95 | T: InputLength + Clone, 96 | I: InputTake + Compare, 97 | E: TagError, 98 | { 99 | let tag_len = tag.input_len(); 100 | 101 | move |input: I| match input.compare(tag.clone()) { 102 | CompareResult::Ok => Ok(input.take_split(tag_len)), 103 | _ => Err(Err::Error(E::from_tag(input, tag.clone()))), 104 | } 105 | } 106 | 107 | /// Parser recognizing a fixed pattern, called a tag. If the front of the 108 | /// input data matches the `tag`, case insensitively, that part of the 109 | /// input will be returned. Records the tag in the error in the event of a 110 | /// parse failure via [`TagError`]. 111 | /// 112 | /// # Example 113 | /// 114 | /// ``` 115 | /// # use nom::{IResult, Err, Needed}; 116 | /// use cool_asserts::assert_matches; 117 | /// use nom_supreme::tag::complete::tag_no_case; 118 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind, Expectation}; 119 | /// 120 | /// fn parse_hello(s: &str) -> IResult<&str, &str, ErrorTree<&str>> { 121 | /// tag_no_case("hello")(s) 122 | /// } 123 | /// 124 | /// assert_matches!( 125 | /// parse_hello("HELLO, WORLD!"), 126 | /// Ok((", WORLD!", "HELLO")), 127 | /// ); 128 | /// 129 | /// assert_matches!( 130 | /// parse_hello("something"), 131 | /// Err(Err::Error(ErrorTree::Base { 132 | /// location: "something", 133 | /// kind: BaseErrorKind::Expected(Expectation::Tag("hello")), 134 | /// })) 135 | /// ); 136 | /// 137 | /// assert_matches!( 138 | /// parse_hello("HEL"), 139 | /// Err(Err::Error(ErrorTree::Base { 140 | /// location: "HEL", 141 | /// kind: BaseErrorKind::Expected(Expectation::Tag("hello")), 142 | /// })) 143 | /// ); 144 | /// ``` 145 | pub fn tag_no_case(tag: T) -> impl Clone + Fn(I) -> IResult 146 | where 147 | T: InputLength + Clone, 148 | I: InputTake + Compare, 149 | E: TagError, 150 | { 151 | move |input: I| match input.compare_no_case(tag.clone()) { 152 | CompareResult::Ok => Ok(input.take_split(tag.input_len())), 153 | _ => Err(Err::Error(E::from_tag_no_case(input, tag.clone()))), 154 | } 155 | } 156 | } 157 | 158 | /// Streaming version of enhanced `tag` parsers. 159 | pub mod streaming { 160 | use nom::{Compare, CompareResult, Err, IResult, InputLength, InputTake, Needed}; 161 | 162 | use super::TagError; 163 | 164 | /// Parser recognizing a fixed pattern, called a tag. If the front of the 165 | /// input data matches the `tag`, that part of the input will be returned. 166 | /// Records the tag in the error in the event of a parse failure via 167 | /// [`TagError`]. If there is only a partial match, returns 168 | /// [`Err::Incomplete`][nom::Err::Incomplete]. 169 | /// 170 | /// # Example 171 | /// 172 | /// ``` 173 | /// # use nom::{IResult, Err, Needed}; 174 | /// use cool_asserts::assert_matches; 175 | /// use nom_supreme::tag::streaming::tag; 176 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind, Expectation}; 177 | /// 178 | /// fn parse_hello(s: &str) -> IResult<&str, &str, ErrorTree<&str>> { 179 | /// tag("hello")(s) 180 | /// } 181 | /// 182 | /// assert_matches!( 183 | /// parse_hello("hello, world!"), 184 | /// Ok((", world!", "hello")), 185 | /// ); 186 | /// 187 | /// assert_matches!( 188 | /// parse_hello("something"), 189 | /// Err(Err::Error(ErrorTree::Base { 190 | /// location: "something", 191 | /// kind: BaseErrorKind::Expected(Expectation::Tag("hello")), 192 | /// })) 193 | /// ); 194 | /// 195 | /// assert_matches!( 196 | /// parse_hello("hel"), 197 | /// Err(Err::Incomplete(Needed::Size(n))) if n.get() == 2, 198 | /// ); 199 | /// ``` 200 | pub fn tag(tag: T) -> impl Clone + Fn(I) -> IResult 201 | where 202 | T: InputLength + Clone, 203 | I: InputLength + InputTake + Compare, 204 | E: TagError, 205 | { 206 | let tag_len = tag.input_len(); 207 | 208 | move |input: I| match input.compare(tag.clone()) { 209 | CompareResult::Ok => Ok(input.take_split(tag_len)), 210 | CompareResult::Incomplete => { 211 | Err(Err::Incomplete(Needed::new(tag_len - input.input_len()))) 212 | } 213 | CompareResult::Error => Err(Err::Error(E::from_tag(input, tag.clone()))), 214 | } 215 | } 216 | 217 | /// Parser recognizing a fixed pattern, called a tag. If the front of the 218 | /// input data matches the `tag`, case insensitively, that part of the 219 | /// input will be returned. Records the tag in the error in the event of a 220 | /// parse failure via [`TagError`]. If there is only a partial match, 221 | /// returns [`Err::Incomplete`][[nom::Err::Incomplete]]. 222 | /// 223 | /// # Example 224 | /// 225 | /// ``` 226 | /// # use nom::{IResult, Err, Needed}; 227 | /// use cool_asserts::assert_matches; 228 | /// use nom_supreme::tag::streaming::tag_no_case; 229 | /// use nom_supreme::error::{ErrorTree, BaseErrorKind, Expectation}; 230 | /// 231 | /// fn parse_hello(s: &str) -> IResult<&str, &str, ErrorTree<&str>> { 232 | /// tag_no_case("hello")(s) 233 | /// } 234 | /// 235 | /// assert_matches!( 236 | /// parse_hello("HELLO, WORLD!"), 237 | /// Ok((", WORLD!", "HELLO")), 238 | /// ); 239 | /// 240 | /// assert_matches!( 241 | /// parse_hello("something"), 242 | /// Err(Err::Error(ErrorTree::Base { 243 | /// location: "something", 244 | /// kind: BaseErrorKind::Expected(Expectation::Tag("hello")), 245 | /// })) 246 | /// ); 247 | /// 248 | /// assert_matches!( 249 | /// parse_hello("HEL"), 250 | /// Err(Err::Incomplete(Needed::Size(n))) if n.get() == 2, 251 | /// ); 252 | /// ``` 253 | pub fn tag_no_case(tag: T) -> impl Clone + Fn(I) -> IResult 254 | where 255 | T: InputLength + Clone, 256 | I: InputLength + InputTake + Compare, 257 | E: TagError, 258 | { 259 | let tag_len = tag.input_len(); 260 | 261 | move |input: I| match input.compare_no_case(tag.clone()) { 262 | CompareResult::Ok => Ok(input.take_split(tag_len)), 263 | CompareResult::Incomplete => { 264 | Err(Err::Incomplete(Needed::new(tag_len - input.input_len()))) 265 | } 266 | CompareResult::Error => Err(Err::Error(E::from_tag_no_case(input, tag.clone()))), 267 | } 268 | } 269 | } 270 | --------------------------------------------------------------------------------