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, 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> ::nom::error::ParseError<I> for Error<I> {
from_error_kind(input: I, kind: nom::ErrorKind) -> Self90     fn from_error_kind(input: I, kind: nom::ErrorKind) -> Self {
91         Self {
92             input,
93             error: kind.into(),
94         }
95     }
96 
append(_: I, _: nom::ErrorKind, other: Self) -> Self97     fn append(_: I, _: nom::ErrorKind, other: Self) -> Self {
98         other
99     }
100 }
101 
102 // in lieu of https://github.com/Geal/nom/issues/1010
103 trait ToCexprResult<I, O> {
to_cexpr_result(self) -> nom::IResult<I, O, Error<I>>104     fn to_cexpr_result(self) -> nom::IResult<I, O, Error<I>>;
105 }
106 impl<I, O, E> ToCexprResult<I, O> for nom::IResult<I, O, E>
107 where
108     Error<I>: From<E>,
109 {
to_cexpr_result(self) -> nom::IResult<I, O, Error<I>>110     fn to_cexpr_result(self) -> nom::IResult<I, O, Error<I>> {
111         match self {
112             Ok(v) => Ok(v),
113             Err(nom::Err::Incomplete(n)) => Err(nom::Err::Incomplete(n)),
114             Err(nom::Err::Error(e)) => Err(nom::Err::Error(e.into())),
115             Err(nom::Err::Failure(e)) => Err(nom::Err::Failure(e.into())),
116         }
117     }
118 }
119 
120 /// If the input result indicates a succesful parse, but there is data left,
121 /// 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>,122 pub fn assert_full_parse<'i, I: 'i, O, E>(
123     result: nom::IResult<&'i [I], O, E>,
124 ) -> nom::IResult<&'i [I], O, Error<&'i [I]>>
125 where
126     Error<&'i [I]>: From<E>,
127 {
128     match result.to_cexpr_result() {
129         Ok((rem, output)) => {
130             if rem.is_empty() {
131                 Ok((rem, output))
132             } else {
133                 Err(nom::Err::Error((rem, ErrorKind::Partial).into()))
134             }
135         }
136         Err(nom::Err::Incomplete(n)) => Err(nom::Err::Incomplete(n)),
137         Err(nom::Err::Failure(e)) => Err(nom::Err::Failure(e)),
138         Err(nom::Err::Error(e)) => Err(nom::Err::Error(e)),
139     }
140 }
141