Support comments and don’t touch input more than necessary

This commit is contained in:
Patrick Lühne 2019-11-05 12:44:28 -06:00
parent cc56c493f6
commit b0173a7b9a
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF
6 changed files with 217 additions and 132 deletions

@ -1 +1 @@
Subproject commit 5070965bfee7ad8a0af0d4abc0f8c6d07b7ae5ec Subproject commit 8a7bd651b217a37f6d95faaa2d4bc1221631e88b

View File

@ -19,45 +19,17 @@ impl std::fmt::Display for crate::project::StatementKind
} }
} }
impl std::fmt::Debug for crate::Project impl<'input> std::fmt::Debug for crate::Project<'input>
{ {
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
{ {
let mut line_separator = ""; for block in &self.blocks
let mut section_separator = "";
if let Some(axioms) = self.statements.get(&crate::project::StatementKind::Axiom)
{ {
for axiom in axioms match block
{ {
write!(format, "{}{:?}: {:?}.", line_separator, crate::project::StatementKind::Axiom, axiom)?; crate::project::Block::Whitespace(ref text) => write!(format, "{}", text)?,
line_separator = "\n"; crate::project::Block::Statement(ref statement) =>
} write!(format, "{}", statement.original_text)?,
section_separator = "\n";
}
if let Some(lemmas) = self.statements.get(&crate::project::StatementKind::Lemma)
{
write!(format, "{}", section_separator)?;
for lemma in lemmas
{
write!(format, "{}{:?}: {:?}.", line_separator, crate::project::StatementKind::Lemma, lemma)?;
line_separator = "\n";
}
section_separator = "\n";
}
if let Some(conjectures) = self.statements.get(&crate::project::StatementKind::Conjecture)
{
write!(format, "{}", section_separator)?;
for conjecture in conjectures
{
write!(format, "{}{:?}: {:?}.", line_separator, crate::project::StatementKind::Conjecture, conjecture)?;
line_separator = "\n";
} }
} }
@ -65,7 +37,7 @@ impl std::fmt::Debug for crate::Project
} }
} }
impl std::fmt::Display for crate::Project impl<'input> std::fmt::Display for crate::Project<'input>
{ {
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
{ {

View File

@ -72,12 +72,23 @@ fn collect_predicate_declarations_in_project<'a>(project: &'a crate::Project)
{ {
let mut predicate_declarations = std::collections::HashSet::new(); let mut predicate_declarations = std::collections::HashSet::new();
for (_, formulas) in project.statements.iter() let formulas = project.blocks.iter()
.filter_map(
|block|
match block
{
crate::project::Block::Whitespace(_) => None,
crate::project::Block::Statement(ref statement) =>
match statement.kind
{
crate::project::StatementKind::Axiom => Some(&statement.formula),
_ => None,
}
});
for formula in formulas
{ {
for formula in formulas.iter() collect_predicate_declarations_in_formula(&mut predicate_declarations, formula);
{
collect_predicate_declarations_in_formula(&mut predicate_declarations, formula);
}
} }
predicate_declarations predicate_declarations
@ -193,12 +204,24 @@ fn collect_symbolic_constants_in_project<'a>(project: &'a crate::Project)
{ {
let mut symbolic_constants = std::collections::HashSet::new(); let mut symbolic_constants = std::collections::HashSet::new();
for (_, formulas) in project.statements.iter() // TODO: avoid code duplication
let formulas = project.blocks.iter()
.filter_map(
|block|
match block
{
crate::project::Block::Whitespace(_) => None,
crate::project::Block::Statement(ref statement) =>
match statement.kind
{
crate::project::StatementKind::Axiom => Some(&statement.formula),
_ => None,
}
});
for formula in formulas
{ {
for formula in formulas.iter() collect_symbolic_constants_in_formula(&mut symbolic_constants, formula);
{
collect_symbolic_constants_in_formula(&mut symbolic_constants, formula);
}
} }
symbolic_constants symbolic_constants
@ -209,10 +232,10 @@ struct PredicateDeclarationDisplay<'a>(&'a foliage::PredicateDeclaration);
struct TermDisplay<'a>(&'a foliage::Term); struct TermDisplay<'a>(&'a foliage::Term);
struct FormulaDisplay<'a>(&'a foliage::Formula); struct FormulaDisplay<'a>(&'a foliage::Formula);
struct StatementKindDisplay<'a>(&'a crate::project::StatementKind); struct StatementKindDisplay<'a>(&'a crate::project::StatementKind);
pub struct ProjectDisplay<'a> pub struct ProjectDisplay<'a, 'input>
{ {
project: &'a crate::project::Project, project: &'a crate::project::Project<'input>,
conjecture: (crate::project::StatementKind, &'a foliage::Formula), conjecture: &'a crate::project::Statement<'input>,
} }
impl<'a> DisplayTPTP<'a, VariableDeclarationDisplay<'a>> for foliage::VariableDeclaration impl<'a> DisplayTPTP<'a, VariableDeclarationDisplay<'a>> for foliage::VariableDeclaration
@ -255,8 +278,8 @@ impl<'a> DisplayTPTP<'a, StatementKindDisplay<'a>> for crate::project::Statement
} }
} }
pub fn display_project_with_conjecture_tptp<'a>(project: &'a crate::Project, pub fn display_project_with_conjecture_tptp<'a, 'input>(project: &'a crate::Project<'input>,
conjecture: (crate::project::StatementKind, &'a foliage::Formula)) -> ProjectDisplay<'a> conjecture: &'a crate::project::Statement<'input>) -> ProjectDisplay<'a, 'input>
{ {
ProjectDisplay ProjectDisplay
{ {
@ -554,7 +577,7 @@ impl<'a> std::fmt::Display for StatementKindDisplay<'a>
} }
} }
impl<'a> std::fmt::Debug for ProjectDisplay<'a> impl<'a, 'input> std::fmt::Debug for ProjectDisplay<'a, 'input>
{ {
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
{ {
@ -593,40 +616,49 @@ impl<'a> std::fmt::Debug for ProjectDisplay<'a>
} }
} }
if let Some(axioms) = self.project.statements.get(&crate::project::StatementKind::Axiom) let axioms = self.project.blocks.iter()
{ .filter_map(
write_title(format, "\n\n", "axioms")?; |block|
match block
{
crate::project::Block::Whitespace(_) => None,
crate::project::Block::Statement(ref statement) =>
match statement.kind
{
crate::project::StatementKind::Axiom => Some(statement),
_ => None,
}
});
for axiom in axioms for axiom in axioms
{ {
write!(format, "\ntff({:?}, {:?}).", crate::project::StatementKind::Axiom.display_tptp(), axiom.display_tptp())?; write!(format, "\ntff({:?}, {:?}).", crate::project::StatementKind::Axiom.display_tptp(), axiom.formula.display_tptp())?;
}
} }
match self.conjecture match self.conjecture.kind
{ {
(crate::project::StatementKind::Lemma, ref lemma) => crate::project::StatementKind::Lemma =>
{ {
write_title(format, "\n\n", "lemma")?; write_title(format, "\n\n", "lemma")?;
write!(format, "\ntff({:?}, {:?}).", crate::project::StatementKind::Lemma.display_tptp(), lemma.display_tptp())?; write!(format, "\ntff({:?}, {:?}).", crate::project::StatementKind::Lemma.display_tptp(), self.conjecture.formula.display_tptp())?;
Ok(()) Ok(())
}, },
(crate::project::StatementKind::Conjecture, ref conjecture) => crate::project::StatementKind::Conjecture =>
{ {
write_title(format, "\n\n", "conjecture")?; write_title(format, "\n\n", "conjecture")?;
write!(format, "\ntff({:?}, {:?}).", crate::project::StatementKind::Conjecture.display_tptp(), conjecture.display_tptp())?; write!(format, "\ntff({:?}, {:?}).", crate::project::StatementKind::Conjecture.display_tptp(), self.conjecture.formula.display_tptp())?;
Ok(()) Ok(())
}, },
(crate::project::StatementKind::Axiom, _) => panic!("unexpected axiom"), crate::project::StatementKind::Axiom => panic!("unexpected axiom"),
} }
} }
} }
impl<'a> std::fmt::Display for ProjectDisplay<'a> impl<'a, 'input> std::fmt::Display for ProjectDisplay<'a, 'input>
{ {
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
{ {

View File

@ -19,28 +19,41 @@ fn backup_file_path(file_path: &std::path::Path) -> Result<std::path::PathBuf, a
} }
} }
fn find_conjecture<'a>(project: &'a ask_dracula::Project) -> Option<(ask_dracula::project::StatementKind, &'a foliage::Formula)> fn find_conjecture<'a, 'input>(project: &'a ask_dracula::Project<'input>) -> Option<&'a ask_dracula::project::Statement<'input>>
{ {
if let Some(lemmas) = project.statements.get(&ask_dracula::project::StatementKind::Lemma) for block in &project.blocks
{ {
if let Some(lemma) = lemmas.first() if let ask_dracula::project::Block::Statement(ref statement) = block
{ {
return Some((ask_dracula::project::StatementKind::Lemma, lemma)); if statement.kind == ask_dracula::project::StatementKind::Lemma
} || statement.kind == ask_dracula::project::StatementKind::Conjecture
} {
return Some(statement)
if let Some(conjectures) = project.statements.get(&ask_dracula::project::StatementKind::Conjecture) }
{
if let Some(conjecture) = conjectures.first()
{
return Some((ask_dracula::project::StatementKind::Conjecture, conjecture));
} }
} }
None None
} }
enum VampireResult fn find_conjecture_mut<'a, 'input>(project: &'a mut ask_dracula::Project<'input>) -> Option<&'a mut ask_dracula::project::Statement<'input>>
{
for block in &mut project.blocks
{
if let ask_dracula::project::Block::Statement(ref mut statement) = block
{
if statement.kind == ask_dracula::project::StatementKind::Lemma
|| statement.kind == ask_dracula::project::StatementKind::Conjecture
{
return Some(statement)
}
}
}
None
}
enum ProofResult
{ {
ProofNotFound, ProofNotFound,
Refutation, Refutation,
@ -48,7 +61,7 @@ enum VampireResult
} }
fn run_vampire<I, S>(input: &str, arguments: Option<I>) fn run_vampire<I, S>(input: &str, arguments: Option<I>)
-> Result<VampireResult, ask_dracula::Error> -> Result<ProofResult, ask_dracula::Error>
where I: IntoIterator<Item = S>, S: AsRef<std::ffi::OsStr> where I: IntoIterator<Item = S>, S: AsRef<std::ffi::OsStr>
{ {
let mut vampire = std::process::Command::new("vampire"); let mut vampire = std::process::Command::new("vampire");
@ -59,6 +72,8 @@ fn run_vampire<I, S>(input: &str, arguments: Option<I>)
None => &mut vampire, None => &mut vampire,
}; };
//eprintln!("{}", input);
let mut vampire = vampire let mut vampire = vampire
.stdin(std::process::Stdio::piped()) .stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped())
@ -89,7 +104,7 @@ fn run_vampire<I, S>(input: &str, arguments: Option<I>)
if proof_not_found_regex.is_match(stdout) if proof_not_found_regex.is_match(stdout)
{ {
return Ok(VampireResult::ProofNotFound); return Ok(ProofResult::ProofNotFound);
} }
return Err(ask_dracula::Error::new_run_vampire( return Err(ask_dracula::Error::new_run_vampire(
@ -100,7 +115,7 @@ fn run_vampire<I, S>(input: &str, arguments: Option<I>)
if refutation_regex.is_match(stdout) if refutation_regex.is_match(stdout)
{ {
return Ok(VampireResult::Refutation); return Ok(ProofResult::Refutation);
} }
Err(ask_dracula::Error::new_interpret_vampire_output(stdout.to_string(), stderr.to_string())) Err(ask_dracula::Error::new_interpret_vampire_output(stdout.to_string(), stderr.to_string()))
@ -121,52 +136,60 @@ fn main() -> Result<(), Box<dyn std::error::Error>>
let (_, mut project) = ask_dracula::parse::project(&file_content) let (_, mut project) = ask_dracula::parse::project(&file_content)
.map_err(|_| "couldnt parse input file")?; .map_err(|_| "couldnt parse input file")?;
match find_conjecture(&project) let conjecture = find_conjecture(&project);
let vampire_result = match conjecture
{ {
None => None =>
{ {
eprintln!("no lemma or conjecture found, nothing to do"); eprintln!("no lemma or conjecture found, nothing to do");
return Ok(());
},
Some(ref conjecture) =>
{
eprintln!("verifying conjecture: {}", conjecture.formula);
let tptp_content = format!("{}", ask_dracula::format_tptp::display_project_with_conjecture_tptp(&project, conjecture));
run_vampire(&tptp_content, matches.values_of("vampire_arguments").map(|value| value))?
},
};
let conjecture = find_conjecture_mut(&mut project).unwrap();
match vampire_result
{
ProofResult::ProofNotFound =>
{
println!("proof not found");
Ok(()) Ok(())
}, },
Some((ref statement_kind, ref conjecture)) => ProofResult::Refutation =>
{ {
eprintln!("verifying conjecture: {}", conjecture); println!("conjecture proven");
let tptp_content = format!("{}", ask_dracula::format_tptp::display_project_with_conjecture_tptp(&project, (statement_kind.clone(), conjecture))); conjecture.kind = ask_dracula::project::StatementKind::Axiom;
let replace_statement_kind_regex = regex::Regex::new(r"(conjecture|lemma)").unwrap();
let new_text = replace_statement_kind_regex.replace(conjecture.original_text, "axiom");
conjecture.original_text = &new_text;
match run_vampire(&tptp_content, matches.values_of("vampire_arguments").map(|value| value))? let backup_file_path = backup_file_path(file_path)?;
{
VampireResult::ProofNotFound =>
{
println!("proof not found");
Ok(())
},
VampireResult::Refutation =>
{
println!("conjecture proven");
let axiom = project.statements.get_mut(statement_kind).unwrap().remove(0); // Make backup of old file
project.statements.entry(ask_dracula::project::StatementKind::Axiom).or_insert_with(Vec::new).push(axiom); std::fs::rename(file_path, backup_file_path)
.map_err(|error| ask_dracula::Error::new_write_file(file_path.to_owned(), error))?;
let backup_file_path = backup_file_path(file_path)?; // Write updated version of the file
let file_content = format!("{}", project);
std::fs::write(file_path, &file_content)
.map_err(|error| ask_dracula::Error::new_write_file(file_path.to_owned(), error))?;
// Make backup of old file Ok(())
std::fs::rename(file_path, backup_file_path) },
.map_err(|error| ask_dracula::Error::new_write_file(file_path.to_owned(), error))?; ProofResult::Satisfiable =>
{
// Write updated version of the file println!("conjecture disproven");
let file_content = format!("{}", project); Ok(())
std::fs::write(file_path, &file_content)
.map_err(|error| ask_dracula::Error::new_write_file(file_path.to_owned(), error))?;
Ok(())
},
VampireResult::Satisfiable =>
{
println!("conjecture disproven");
Ok(())
},
}
}, },
} }
} }

View File

@ -1,18 +1,38 @@
use nom:: use nom::
{ {
IResult, IResult,
character::complete::multispace0, sequence::{delimited, pair, preceded, terminated, tuple},
sequence::{delimited, pair, terminated}, combinator::{map, recognize},
combinator::map,
branch::alt, branch::alt,
bytes::complete::tag, 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 statement_kind(i: &str) -> IResult<&str, crate::project::StatementKind> fn statement_kind(i: &str) -> IResult<&str, crate::project::StatementKind>
{ {
let foo = delimited let foo = delimited
( (
multispace0, whitespace0,
alt alt
(( ((
map map
@ -31,7 +51,7 @@ fn statement_kind(i: &str) -> IResult<&str, crate::project::StatementKind>
|_| crate::project::StatementKind::Conjecture, |_| crate::project::StatementKind::Conjecture,
), ),
)), )),
multispace0, whitespace0,
)(i); )(i);
foo foo
@ -46,26 +66,35 @@ fn statement(i: &str) -> IResult<&str, (crate::project::StatementKind, foliage::
statement_kind, statement_kind,
foliage::formula, foliage::formula,
), ),
delimited preceded
( (
multispace0, whitespace0,
tag("."), tag("."),
multispace0,
), ),
)(i) )(i)
} }
fn statement_enclosed_by_whitespace(i: &str) -> IResult<&str, (&str, (&str, (crate::project::StatementKind, foliage::Formula)), &str)>
{
tuple
((
recognize(whitespace0),
recognize_and_keep(statement),
recognize(whitespace0),
))(i)
}
pub fn project(i: &str) -> IResult<&str, crate::Project> pub fn project(i: &str) -> IResult<&str, crate::Project>
{ {
let mut statement_input = i.clone(); let mut statement_input = i.clone();
let mut statements = std::collections::HashMap::new(); let mut blocks = Vec::new();
loop loop
{ {
let i_ = statement_input.clone(); let i_ = statement_input.clone();
match statement(i_) match statement_enclosed_by_whitespace(i_)
{ {
Ok((i, (statement_kind, formula))) => Ok((i, (whitespace_before, (statement_original_text, (statement_kind, formula)), whitespace_after))) =>
{ {
// Iteration must always consume input (to prevent infinite loops) // Iteration must always consume input (to prevent infinite loops)
if i == statement_input if i == statement_input
@ -73,8 +102,24 @@ pub fn project(i: &str) -> IResult<&str, crate::Project>
return Err(nom::Err::Error(nom::error::ParseError::from_error_kind(statement_input, nom::error::ErrorKind::Many0))); return Err(nom::Err::Error(nom::error::ParseError::from_error_kind(statement_input, nom::error::ErrorKind::Many0)));
} }
let statements = statements.entry(statement_kind).or_insert_with(Vec::new); if !whitespace_before.is_empty()
statements.push(formula); {
blocks.push(crate::project::Block::Whitespace(whitespace_before));
}
let statement = crate::project::Statement
{
kind: statement_kind,
original_text: statement_original_text,
formula,
};
blocks.push(crate::project::Block::Statement(statement));
if !whitespace_after.is_empty()
{
blocks.push(crate::project::Block::Whitespace(whitespace_after));
}
statement_input = i; statement_input = i;
}, },
@ -93,7 +138,7 @@ pub fn project(i: &str) -> IResult<&str, crate::Project>
let project = crate::Project let project = crate::Project
{ {
statements, blocks,
}; };
Ok((i, project)) Ok((i, project))

View File

@ -6,7 +6,20 @@ pub enum StatementKind
Conjecture, Conjecture,
} }
pub struct Project pub struct Statement<'input>
{ {
pub statements: std::collections::HashMap<StatementKind, Vec<foliage::Formula>>, pub kind: StatementKind,
pub original_text: &'input str,
pub formula: foliage::Formula,
}
pub enum Block<'input>
{
Statement(Statement<'input>),
Whitespace(&'input str),
}
pub struct Project<'input>
{
pub blocks: Vec<Block<'input>>,
} }