ask-dracula-rs/src/parse.rs

198 lines
4.2 KiB
Rust

use nom::
{
IResult,
sequence::{delimited, pair, preceded, terminated, tuple},
combinator::{map, recognize},
character::complete::digit1,
branch::alt,
bytes::complete::tag,
};
use foliage::parse::whitespace0;
pub fn recognize_and_keep<I: Clone + nom::Offset + nom::Slice<std::ops::RangeTo<usize>>, O, E: nom::error::ParseError<I>, F>(parser: F) -> impl Fn(I) -> IResult<I, (I, O), E>
where
F: Fn(I) -> IResult<I, O, E>,
{
move |input: I|
{
let i = input.clone();
match parser(i)
{
Ok((i, result)) =>
{
let index = input.offset(&i);
Ok((i, (input.slice(..index), result)))
},
Err(e) => Err(e),
}
}
}
fn formula_statement_kind(i: &str) -> IResult<&str, crate::project::FormulaStatementKind>
{
let foo = delimited
(
whitespace0,
alt
((
map
(
tag("axiom:"),
|_| crate::project::FormulaStatementKind::Axiom,
),
map
(
tag("completion(constraint):"),
|_| crate::project::FormulaStatementKind::Completion(crate::project::CompletionTarget::Constraint),
),
map
(
preceded
(
tag("completion"),
delimited
(
tag("("),
pair
(
terminated
(
foliage::parse::symbolic_identifier,
tag("/"),
),
digit1,
),
tag("):"),
),
),
|(name, arity)|
match arity.parse::<usize>()
{
Ok(arity) => crate::project::FormulaStatementKind::Completion(
crate::project::CompletionTarget::Predicate(foliage::PredicateDeclaration{name, arity})),
Err(error) => panic!("invalid arity “{}”: {}", arity, error),
}
),
map
(
tag("assumption:"),
|_| crate::project::FormulaStatementKind::Assumption,
),
map
(
tag("lemma(forward):"),
|_| crate::project::FormulaStatementKind::Lemma(Some(crate::project::ProofDirection::Forward)),
),
map
(
tag("lemma(backward):"),
|_| crate::project::FormulaStatementKind::Lemma(Some(crate::project::ProofDirection::Backward)),
),
map
(
tag("lemma:"),
|_| crate::project::FormulaStatementKind::Lemma(None),
),
map
(
tag("assertion:"),
|_| crate::project::FormulaStatementKind::Assertion,
),
)),
whitespace0,
)(i);
foo
}
fn formula_statement(i: &str) -> IResult<&str, (crate::project::FormulaStatementKind, foliage::Formula)>
{
terminated
(
pair
(
formula_statement_kind,
foliage::formula,
),
preceded
(
whitespace0,
tag("."),
),
)(i)
}
fn formula_statement_enclosed_by_whitespace(i: &str)
-> IResult<&str, (&str, (&str, (crate::project::FormulaStatementKind, foliage::Formula)), &str)>
{
tuple
((
recognize(whitespace0),
recognize_and_keep(formula_statement),
recognize(whitespace0),
))(i)
}
pub fn project(i: &str) -> IResult<&str, crate::Project>
{
let mut statement_input = i.clone();
let mut blocks = Vec::new();
loop
{
let i_ = statement_input.clone();
match formula_statement_enclosed_by_whitespace(i_)
{
Ok((i, (whitespace_before, (formula_statement_original_text, (formula_statement_kind, formula)), whitespace_after))) =>
{
// Iteration must always consume input (to prevent infinite loops)
if i == statement_input
{
return Err(nom::Err::Error(nom::error::ParseError::from_error_kind(statement_input, nom::error::ErrorKind::Many0)));
}
if !whitespace_before.is_empty()
{
blocks.push(crate::project::Block::Whitespace(whitespace_before.to_string()));
}
let formula_statement = crate::project::FormulaStatement
{
kind: formula_statement_kind,
original_text: formula_statement_original_text.to_string(),
formula,
proven: false,
};
blocks.push(crate::project::Block::FormulaStatement(formula_statement));
if !whitespace_after.is_empty()
{
blocks.push(crate::project::Block::Whitespace(whitespace_after.to_string()));
}
statement_input = i;
},
Err(nom::Err::Error(_)) => break,
Err(e) => return Err(e),
}
}
let i = statement_input;
// Verify that the whole file has been parsed
if i != ""
{
eprintln!("parsing error at:\n{}", i);
return Err(nom::Err::Error(nom::error::ParseError::from_error_kind(statement_input, nom::error::ErrorKind::Many0)));
}
let project = crate::Project
{
blocks,
};
Ok((i, project))
}