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], 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]>)) => Err(nom::Err::Failure(e)), |
147 | Err(nom::Err::Error(e: Error<&[I]>)) => Err(nom::Err::Error(e)), |
148 | } |
149 | } |
150 | |