summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..5170f97
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,149 @@
+// (C) Copyright 2016 Jethro G. Beekman
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<nom::ErrorKind> for ErrorKind {
+ fn from(k: nom::ErrorKind) -> Self {
+ ErrorKind::Parser(k)
+ }
+}
+
+impl From<u32> 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<I> {
+ /// The remainder of the input stream at the time of the error.
+ pub input: I,
+ /// The error that occurred.
+ pub error: ErrorKind,
+}
+
+impl<I> From<(I, nom::ErrorKind)> for Error<I> {
+ fn from(e: (I, nom::ErrorKind)) -> Self {
+ Self::from((e.0, ErrorKind::from(e.1)))
+ }
+}
+
+impl<I> From<(I, ErrorKind)> for Error<I> {
+ fn from(e: (I, ErrorKind)) -> Self {
+ Self {
+ input: e.0,
+ error: e.1,
+ }
+ }
+}
+
+impl<I> From<::nom::error::Error<I>> for Error<I> {
+ fn from(e: ::nom::error::Error<I>) -> Self {
+ Self {
+ input: e.input,
+ error: e.code.into(),
+ }
+ }
+}
+
+impl<I> ::nom::error::ParseError<I> for Error<I> {
+ 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<I, O> {
+ fn to_cexpr_result(self) -> nom::IResult<I, O, Error<I>>;
+}
+impl<I, O, E> ToCexprResult<I, O> for nom::IResult<I, O, E>
+where
+ Error<I>: From<E>,
+{
+ fn to_cexpr_result(self) -> nom::IResult<I, O, Error<I>> {
+ 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<E>,
+{
+ 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)),
+ }
+}