• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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