use indexmap::{IndexMap, IndexSet};
use crate::ast::{Identifier, QualIdentifier, SortedVar, Symbol, Term, VarBinding};
use crate::error::SolverError::{self, *};
use crate::solver::Solver;
use crate::private::a_sort::get_sort_object;
use crate::ast::L;
pub(crate) fn assert_(
term: &L<Term>,
solver: &mut Solver
) -> Result<String, SolverError> {
let mut variables = IndexMap::new();
let new_term = annotate_term(term, &mut variables, solver)?;
solver.assertions_to_ground.push(new_term);
Ok("".to_string())
}
pub(crate) fn annotate_term(
term: &L<Term>,
variables: &mut IndexMap<Symbol, Term>,
solver: &Solver
) -> Result<L<Term>, SolverError> {
match term {
L(Term::SpecConstant(_), _) => Ok(term.clone()),
L(Term::Identifier(ref qual_identifier), start) => {
match qual_identifier {
QualIdentifier::Identifier(L(Identifier::Simple(ref symbol), _)) => {
match variables.get(symbol) {
Some(Term::XSortedVar(_, ref sort, ref sort_object)) =>
Ok(L(Term::XSortedVar(symbol.clone(), sort.clone(), sort_object.clone()), *start)),
Some(Term::XLetVar(_, ref expr)) => Ok(L(Term::XLetVar(symbol.clone(), expr.clone()), *start)),
Some(_) => Err(InternalError(952656363)), None =>
Ok(term.clone()) }
},
_ => Ok(term.clone()),
}
},
L(Term::Application(qual_identifier, terms), start) => {
let and: QualIdentifier = QualIdentifier::new(&Symbol("and".to_string()), None);
let or: QualIdentifier = QualIdentifier::new(&Symbol("or".to_string()), None);
let not: QualIdentifier = QualIdentifier::new(&Symbol("not".to_string()), None);
match qual_identifier.to_string().as_str() {
"=>" => {
let new_terms = terms.iter().enumerate()
.map( | (i, t) | if i < terms.len()-1 {
L(Term::Application(not.clone(), vec![t.clone()]), *start)
} else {
t.clone()
}).collect::<Vec<_>>();
let new_term = L(Term::Application(or.clone(), new_terms), *start);
annotate_term(&new_term, variables, solver)
}
"not" => {
assert_eq!(terms.len(), 1);
match terms.get(0) {
Some(sub_term) => {
match sub_term {
L(Term::Application(sub_identifier, sub_terms), start) => {
match sub_identifier.to_string().as_str() {
"and" => {
let new_terms = sub_terms.iter()
.map( | t | L(Term::Application(not.clone(), vec![t.clone()]), t.start()))
.collect::<IndexSet<_>>();
let new_term = L(Term::Application(or.clone(), new_terms.iter().cloned().collect()), *start);
annotate_term(&new_term, variables, solver)
},
"or" => {
let new_terms = sub_terms.iter()
.map( | t | L(Term::Application(not.clone(), vec![t.clone()]), t.start()))
.collect::<IndexSet<_>>();
let new_term = L(Term::Application(and.clone(), new_terms.iter().cloned().collect()), *start);
annotate_term(&new_term, variables, solver)
},
_ => {
let new_term = annotate_term(sub_term, variables, solver)?;
Ok(L(Term::Application(qual_identifier.clone(), vec![new_term]), *start))
}
}
}
_ => {
let new_term = annotate_term(sub_term, variables, solver)?;
Ok(L(Term::Application(qual_identifier.clone(), vec![new_term]), sub_term.start()))
}
}
}
None => Err(InternalError(4266))
}
}
"and" => {
let mut new_sub_terms = vec![];
for sub_term in terms {
let sub_term = annotate_term(sub_term, variables, solver)?;
if let L(Term::Application(ref sub_identifier, ref sub_terms2), _) = sub_term {
if sub_identifier.to_string() == "and" {
new_sub_terms.append(&mut sub_terms2.clone());
} else {
new_sub_terms.push(sub_term);
}
} else {
new_sub_terms.push(sub_term);
}
};
Ok(L(Term::Application(and.clone(), new_sub_terms), *start))
}
"or" => {
let mut new_sub_terms = vec![];
for sub_term in terms {
let sub_term = annotate_term(sub_term, variables, solver)?;
if let L(Term::Application(ref sub_identifier, ref sub_terms2), _) = sub_term {
if sub_identifier.to_string() == "or" {
new_sub_terms.append(&mut sub_terms2.clone());
} else {
new_sub_terms.push(sub_term);
}
} else {
new_sub_terms.push(sub_term);
}
};
Ok(L(Term::Application(or.clone(), new_sub_terms), *start))
}
_ => {
let new_terms = terms.iter()
.map(|t| annotate_term(t, variables, solver))
.collect::<Result<Vec<_>, _>>()?;
Ok(L(Term::Application(qual_identifier.clone(), new_terms), *start))
}
}
},
L(Term::Let(var_bindings, term), start) => {
let mut new_variables = variables.clone();
let mut new_var_bindings = vec![];
for VarBinding(symbol, binding) in var_bindings {
let binding = annotate_term(&binding, variables, solver)?;
let sorted_var = Term::XLetVar(symbol.clone(), Box::new(binding.clone()));
new_variables.insert(symbol.clone(), sorted_var);
new_var_bindings.push(VarBinding(symbol.clone(), binding))
};
let new_term = annotate_term(term, &mut new_variables, solver)?;
Ok(L(Term::Let(new_var_bindings, Box::new(new_term)), *start))
},
L(Term::Forall(sorted_vars, term), start) => {
let new_term =
process_quantification(sorted_vars, term, variables, solver)?;
Ok(L(Term::Forall(sorted_vars.clone(), Box::new(new_term)), *start))
},
L(Term::Exists(sorted_vars, term), start) => {
let new_term =
process_quantification(sorted_vars, term, variables, solver)?;
Ok(L(Term::Exists(sorted_vars.clone(), Box::new(new_term)), *start))
},
L(Term::Match(_, _), _) => {
todo!("need to decide how to ground match term")
},
L(Term::Annotation(term, attributes), start) => {
let new_term = annotate_term(&term, variables, solver)?;
Ok(L(Term::Annotation(Box::new(new_term), attributes.clone()), *start))
},
L(Term::XSortedVar(_, _, _), _)
| L(Term::XLetVar(_, _), _) =>
Err(InternalError(812685563)), }
}
fn process_quantification (
sorted_vars: &Vec<SortedVar>,
term: &Box<L<Term>>,
variables: &mut IndexMap<Symbol, Term>,
solver: &Solver
) -> Result<L<Term>, SolverError> {
let mut new_variables = variables.clone();
for SortedVar(symbol, sort) in sorted_vars {
match get_sort_object(sort, solver) {
Some(sort_object) => {
let sorted_var = Term::XSortedVar(symbol.clone(), sort.clone(), sort_object.clone());
new_variables.insert(symbol.clone(), sorted_var);
},
None => return Err(InternalError(2486645)),
}
};
let new_term = annotate_term(term, &mut new_variables, solver)?;
Ok(new_term)
}