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,
}
}
}