1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! A crate for reading files in the TPTP format.
//!
//! Most users will want to use the `TPTPIterator` interface to parse statements from a TPTP file.
//! After you have a parsed statement, you can either manipulate it manually, or use the `Visitor` interface to ease writing traversals.
//! Individual parsers for each item of the TPTP BNF are available: generally this is a one-to-one map, but for efficiency/sanity reasons items like `integer` are not split into `signed_integer` and `unsigned_integer`.
//!
//! Parsers are built with [nom](https://github.com/Geal/nom), and this implementation detail is kept deliberately transparent.
//! If you need it, you can use nom's facilities such as error handling or streaming.
//! All parsers are a function from byte slices to `Result`.
//! The input will never be copied, only references made.
//! The crate is `#![no_std]`, but syntax trees must allocate with the current design so the `alloc` crate is required.
//!
//! Parsers are streaming, so they will signal "incomplete" on EOF, rather than success or failure, until the outcome is known.
//! Most of the time this is obvious, but the behaviour can be surprising.
//! For example, parsing `foo$` as a `lower_word` succeeds, returning the trailing `$` to parse next.
//! However, parsing `foo` is "incomplete" as there might be more input coming.
//!
//! Support for `serde` can be switched on with a feature flag as usual.
//! Structures can then be serialised, but not deseralised due to ownership issues.
//! # Quickstart
//! ```rust
//! use tptp::TPTPIterator;
//! use tptp::visitor::Visitor;
//!
//! struct MyVisitor;
//! impl<'a> Visitor<'a> for MyVisitor {}
//!
//! fn example(bytes: &[u8]) {
//!     let mut visitor = MyVisitor;
//!     let mut parser = TPTPIterator::<()>::new(bytes);
//!     for result in &mut parser {
//!         let input = result.expect("syntax error");
//!         println!("{}", &input);
//!         visitor.visit_tptp_input(&input);
//!     }
//!     assert!(parser.remaining.is_empty());
//! }
//! ```

#![no_std]
extern crate alloc;

#[macro_use]
mod utils;
/// the CNF dialect
pub mod cnf;
/// common syntax across all dialects
pub mod common;
/// the FOF dialect
pub mod fof;
/// top-level inputs, formula annotations, etc.
pub mod top;

#[cfg(test)]
mod tests;
/// visitor pattern
pub mod visitor;

/// an alias for nom's `ParseError`
pub trait Error<'a>: nom::error::ParseError<&'a [u8]> {}
impl<'a, T: nom::error::ParseError<&'a [u8]>> Error<'a> for T {}

/// an alias for nom's `IResult`
pub type Result<'a, T, E> = nom::IResult<&'a [u8], T, E>;

/// syntax items which have an associated parser
pub trait Parse<'a, E: Error<'a>>: Sized {
    fn parse(x: &'a [u8]) -> Result<'a, Self, E>;
}

/// iterator returning `tptp_input`s from a byte slice
pub struct TPTPIterator<'a, E> {
    /// the current position of the iterator in the slice
    pub remaining: &'a [u8],
    _phantom: core::marker::PhantomData<E>,
}

impl<'a, E> TPTPIterator<'a, E> {
    pub fn new(remaining: &'a [u8]) -> Self {
        let _phantom = core::marker::PhantomData;
        Self {
            remaining,
            _phantom,
        }
    }
}

impl<'a, E: Error<'a>> Iterator for TPTPIterator<'a, E> {
    type Item = core::result::Result<top::TPTPInput<'a>, E>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match common::single_ignored::<E>(self.remaining) {
                Ok((remaining, ())) => {
                    self.remaining = remaining;
                }
                Err(nom::Err::Incomplete(_)) => {
                    return None;
                }
                Err(_) => {
                    break;
                }
            }
        }

        match top::TPTPInput::parse(self.remaining) {
            Ok((remaining, input)) => {
                self.remaining = remaining;
                Some(Ok(input))
            }
            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => {
                Some(Err(e))
            }
            Err(nom::Err::Incomplete(_)) => None,
        }
    }
}