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