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 { from(k: nom::ErrorKind) -> Self51 fn from(k: nom::ErrorKind) -> Self { 52 ErrorKind::Parser(k) 53 } 54 } 55 56 impl From<u32> for ErrorKind { from(_: u32) -> Self57 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> { from(e: (I, nom::ErrorKind)) -> Self75 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> { from(e: (I, ErrorKind)) -> Self81 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> { from(e: ::nom::error::Error<I>) -> Self90 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> { from_error_kind(input: I, kind: nom::ErrorKind) -> Self99 fn from_error_kind(input: I, kind: nom::ErrorKind) -> Self { 100 Self { 101 input, 102 error: kind.into(), 103 } 104 } 105 append(_: I, _: nom::ErrorKind, other: Self) -> Self106 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> { to_cexpr_result(self) -> nom::IResult<I, O, Error<I>>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 { to_cexpr_result(self) -> nom::IResult<I, O, Error<I>>119 fn to_cexpr_result(self) -> nom::IResult<I, O, Error<I>> { 120 match self { 121 Ok(v) => Ok(v), 122 Err(nom::Err::Incomplete(n)) => Err(nom::Err::Incomplete(n)), 123 Err(nom::Err::Error(e)) => Err(nom::Err::Error(e.into())), 124 Err(nom::Err::Failure(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. assert_full_parse<'i, I: 'i, O, E>( result: nom::IResult<&'i [I], O, E>, ) -> nom::IResult<&'i [I], O, Error<&'i [I]>> where Error<&'i [I]>: From<E>,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, output)) => { 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)) => Err(nom::Err::Incomplete(n)), 146 Err(nom::Err::Failure(e)) => Err(nom::Err::Failure(e)), 147 Err(nom::Err::Error(e)) => Err(nom::Err::Error(e)), 148 } 149 } 150