| 1 | // (C) Copyright 2016 Jethro G. Beekman |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| 4 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 5 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| 6 | // option. This file may not be copied, modified, or distributed |
| 7 | // except according to those terms. |
| 8 | //! A C expression parser and evaluator. |
| 9 | //! |
| 10 | //! This crate provides methods for parsing and evaluating simple C expressions. In general, the |
| 11 | //! crate can handle most arithmetic expressions that would appear in macros or the definition of |
| 12 | //! constants, as well as string and character constants. |
| 13 | //! |
| 14 | //! The main entry point for is [`token::parse`], which parses a byte string and returns its |
| 15 | //! evaluated value. |
| 16 | #![warn (rust_2018_idioms)] |
| 17 | #![warn (missing_docs)] |
| 18 | #![allow (deprecated)] |
| 19 | |
| 20 | pub mod nom { |
| 21 | //! nom's result types, re-exported. |
| 22 | pub use nom::{error::ErrorKind, error::Error, Err, IResult, Needed}; |
| 23 | } |
| 24 | pub mod expr; |
| 25 | pub mod literal; |
| 26 | pub mod token; |
| 27 | |
| 28 | /// Parsing errors specific to C parsing |
| 29 | #[derive (Debug)] |
| 30 | pub enum ErrorKind { |
| 31 | /// Expected the specified token |
| 32 | ExactToken(token::Kind, &'static [u8]), |
| 33 | /// Expected one of the specified tokens |
| 34 | ExactTokens(token::Kind, &'static [&'static str]), |
| 35 | /// Expected a token of the specified kind |
| 36 | TypedToken(token::Kind), |
| 37 | /// An unknown identifier was encountered |
| 38 | UnknownIdentifier, |
| 39 | /// An invalid literal was encountered. |
| 40 | /// |
| 41 | /// When encountered, this generally means a bug exists in the data that |
| 42 | /// was passed in or the parsing logic. |
| 43 | InvalidLiteral, |
| 44 | /// A full parse was requested, but data was left over after parsing finished. |
| 45 | Partial, |
| 46 | /// An error occurred in an underlying nom parser. |
| 47 | Parser(nom::ErrorKind), |
| 48 | } |
| 49 | |
| 50 | impl From<nom::ErrorKind> for ErrorKind { |
| 51 | fn from(k: nom::ErrorKind) -> Self { |
| 52 | ErrorKind::Parser(k) |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | impl From<u32> for ErrorKind { |
| 57 | fn from(_: u32) -> Self { |
| 58 | ErrorKind::InvalidLiteral |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | /// Parsing errors specific to C parsing. |
| 63 | /// |
| 64 | /// This is a superset of `(I, nom::ErrorKind)` that includes the additional errors specified by |
| 65 | /// [`ErrorKind`]. |
| 66 | #[derive (Debug)] |
| 67 | pub struct Error<I> { |
| 68 | /// The remainder of the input stream at the time of the error. |
| 69 | pub input: I, |
| 70 | /// The error that occurred. |
| 71 | pub error: ErrorKind, |
| 72 | } |
| 73 | |
| 74 | impl<I> From<(I, nom::ErrorKind)> for Error<I> { |
| 75 | fn from(e: (I, nom::ErrorKind)) -> Self { |
| 76 | Self::from((e.0, ErrorKind::from(e.1))) |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | impl<I> From<(I, ErrorKind)> for Error<I> { |
| 81 | fn from(e: (I, ErrorKind)) -> Self { |
| 82 | Self { |
| 83 | input: e.0, |
| 84 | error: e.1, |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | impl<I> From<::nom::error::Error<I>> for Error<I> { |
| 90 | fn from(e: ::nom::error::Error<I>) -> Self { |
| 91 | Self { |
| 92 | input: e.input, |
| 93 | error: e.code.into(), |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | impl<I> ::nom::error::ParseError<I> for Error<I> { |
| 99 | fn from_error_kind(input: I, kind: nom::ErrorKind) -> Self { |
| 100 | Self { |
| 101 | input, |
| 102 | error: kind.into(), |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | fn append(_: I, _: nom::ErrorKind, other: Self) -> Self { |
| 107 | other |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | // in lieu of https://github.com/Geal/nom/issues/1010 |
| 112 | trait ToCexprResult<I, O> { |
| 113 | fn to_cexpr_result(self) -> nom::IResult<I, O, Error<I>>; |
| 114 | } |
| 115 | impl<I, O, E> ToCexprResult<I, O> for nom::IResult<I, O, E> |
| 116 | where |
| 117 | Error<I>: From<E>, |
| 118 | { |
| 119 | fn to_cexpr_result(self) -> nom::IResult<I, O, Error<I>> { |
| 120 | match self { |
| 121 | Ok(v: (I, O)) => Ok(v), |
| 122 | Err(nom::Err::Incomplete(n: Needed)) => Err(nom::Err::Incomplete(n)), |
| 123 | Err(nom::Err::Error(e: E)) => Err(nom::Err::Error(e.into())), |
| 124 | Err(nom::Err::Failure(e: E)) => Err(nom::Err::Failure(e.into())), |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | /// If the input result indicates a succesful parse, but there is data left, |
| 130 | /// return an `Error::Partial` instead. |
| 131 | pub fn assert_full_parse<'i, I: 'i, O, E>( |
| 132 | result: nom::IResult<&'i [I], O, E>, |
| 133 | ) -> nom::IResult<&'i [I], O, Error<&'i [I]>> |
| 134 | where |
| 135 | Error<&'i [I]>: From<E>, |
| 136 | { |
| 137 | match result.to_cexpr_result() { |
| 138 | Ok((rem: &'i [I], output: O)) => { |
| 139 | if rem.is_empty() { |
| 140 | Ok((rem, output)) |
| 141 | } else { |
| 142 | Err(nom::Err::Error((rem, ErrorKind::Partial).into())) |
| 143 | } |
| 144 | } |
| 145 | Err(nom::Err::Incomplete(n: Needed)) => Err(nom::Err::Incomplete(n)), |
| 146 | Err(nom::Err::Failure(e: Error<&'i [I]>)) => Err(nom::Err::Failure(e)), |
| 147 | Err(nom::Err::Error(e: Error<&'i [I]>)) => Err(nom::Err::Error(e)), |
| 148 | } |
| 149 | } |
| 150 | |