// (C) Copyright 2016 Jethro G. Beekman // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! A C expression parser and evaluator. //! //! This crate provides methods for parsing and evaluating simple C expressions. In general, the //! crate can handle most arithmetic expressions that would appear in macros or the definition of //! constants, as well as string and character constants. //! //! The main entry point for is [`token::parse`], which parses a byte string and returns its //! evaluated value. #![warn(rust_2018_idioms)] #![warn(missing_docs)] #![allow(deprecated)] pub mod nom { //! nom's result types, re-exported. pub use nom::{error::ErrorKind, error::Error, Err, IResult, Needed}; } pub mod expr; pub mod literal; pub mod token; /// Parsing errors specific to C parsing #[derive(Debug)] pub enum ErrorKind { /// Expected the specified token ExactToken(token::Kind, &'static [u8]), /// Expected one of the specified tokens ExactTokens(token::Kind, &'static [&'static str]), /// Expected a token of the specified kind TypedToken(token::Kind), /// An unknown identifier was encountered UnknownIdentifier, /// An invalid literal was encountered. /// /// When encountered, this generally means a bug exists in the data that /// was passed in or the parsing logic. InvalidLiteral, /// A full parse was requested, but data was left over after parsing finished. Partial, /// An error occurred in an underlying nom parser. Parser(nom::ErrorKind), } impl From for ErrorKind { fn from(k: nom::ErrorKind) -> Self { ErrorKind::Parser(k) } } impl From for ErrorKind { fn from(_: u32) -> Self { ErrorKind::InvalidLiteral } } /// Parsing errors specific to C parsing. /// /// This is a superset of `(I, nom::ErrorKind)` that includes the additional errors specified by /// [`ErrorKind`]. #[derive(Debug)] pub struct Error { /// The remainder of the input stream at the time of the error. pub input: I, /// The error that occurred. pub error: ErrorKind, } impl From<(I, nom::ErrorKind)> for Error { fn from(e: (I, nom::ErrorKind)) -> Self { Self::from((e.0, ErrorKind::from(e.1))) } } impl From<(I, ErrorKind)> for Error { fn from(e: (I, ErrorKind)) -> Self { Self { input: e.0, error: e.1, } } } impl From<::nom::error::Error> for Error { fn from(e: ::nom::error::Error) -> Self { Self { input: e.input, error: e.code.into(), } } } impl ::nom::error::ParseError for Error { fn from_error_kind(input: I, kind: nom::ErrorKind) -> Self { Self { input, error: kind.into(), } } fn append(_: I, _: nom::ErrorKind, other: Self) -> Self { other } } // in lieu of https://github.com/Geal/nom/issues/1010 trait ToCexprResult { fn to_cexpr_result(self) -> nom::IResult>; } impl ToCexprResult for nom::IResult where Error: From, { fn to_cexpr_result(self) -> nom::IResult> { match self { Ok(v) => Ok(v), Err(nom::Err::Incomplete(n)) => Err(nom::Err::Incomplete(n)), Err(nom::Err::Error(e)) => Err(nom::Err::Error(e.into())), Err(nom::Err::Failure(e)) => Err(nom::Err::Failure(e.into())), } } } /// If the input result indicates a succesful parse, but there is data left, /// return an `Error::Partial` instead. pub fn 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, { match result.to_cexpr_result() { Ok((rem, output)) => { if rem.is_empty() { Ok((rem, output)) } else { Err(nom::Err::Error((rem, ErrorKind::Partial).into())) } } Err(nom::Err::Incomplete(n)) => Err(nom::Err::Incomplete(n)), Err(nom::Err::Failure(e)) => Err(nom::Err::Failure(e)), Err(nom::Err::Error(e)) => Err(nom::Err::Error(e)), } }