use crate::compiler::clvm::truthy;
use crate::compiler::prims::primquote;
use crate::compiler::sexp::{AtomValue, NodeSel, SExp, SelectNode, ThisNode};
use std::borrow::Borrow;
use std::rc::Rc;
pub fn change_double_to_single_apply(sexp: Rc<SExp>) -> (bool, Rc<SExp>) {
if let Ok(NodeSel::Cons(
_,
NodeSel::Cons(
NodeSel::Cons(
_,
inner_program,
),
NodeSel::Cons(_, _),
),
)) = NodeSel::Cons(
AtomValue::Here(&[2]),
NodeSel::Cons(
NodeSel::Cons(
AtomValue::Here(&[1]),
ThisNode,
),
NodeSel::Cons(AtomValue::Here(&[1]), ThisNode),
),
)
.select_nodes(sexp.clone())
{
return (true, inner_program);
}
(false, sexp)
}
fn change_apply_double_quote(sexp: Rc<SExp>) -> (bool, Rc<SExp>) {
if let Ok(NodeSel::Cons(
_, NodeSel::Cons(
NodeSel::Cons(
_, NodeSel::Cons(
_, body,
),
),
_,
),
)) = NodeSel::Cons(
AtomValue::Here(&[2]),
NodeSel::Cons(
NodeSel::Cons(
AtomValue::Here(&[1]),
NodeSel::Cons(AtomValue::Here(&[1]), ThisNode),
),
ThisNode,
),
)
.select_nodes(sexp.clone())
{
return (true, Rc::new(primquote(body.loc(), body.clone())));
}
(false, sexp)
}
fn collapse_constant_condition(sexp: Rc<SExp>) -> (bool, Rc<SExp>) {
if let Ok(NodeSel::Cons(
_, NodeSel::Cons(cond, NodeSel::Cons(a, NodeSel::Cons(b, _))),
)) = NodeSel::Cons(
AtomValue::Here(&[3]),
NodeSel::Cons(
ThisNode,
NodeSel::Cons(ThisNode, NodeSel::Cons(ThisNode, ThisNode)),
),
)
.select_nodes(sexp.clone())
{
return NodeSel::Cons(AtomValue::Here(&[1]), ThisNode)
.select_nodes(cond.clone())
.ok()
.map(|NodeSel::Cons(_, cond_quoted)| Some(truthy(cond_quoted)))
.unwrap_or_else(|| if !truthy(cond) { Some(false) } else { None })
.map(|use_cond| if use_cond { (true, a) } else { (true, b) })
.unwrap_or_else(|| (false, sexp));
}
(false, sexp)
}
pub fn remove_double_apply(mut sexp: Rc<SExp>, spine: bool) -> (bool, Rc<SExp>) {
if spine {
if let Ok(NodeSel::Cons(_, _)) =
NodeSel::Cons(AtomValue::Here(&[1]), ThisNode).select_nodes(sexp.clone())
{
return (false, sexp);
}
}
let mut any_transformation = true;
let mut was_transformed = false;
while any_transformation {
if let SExp::Cons(l, a, b) = sexp.borrow() {
let (a_changed, new_a) = remove_double_apply(a.clone(), true);
let (b_changed, new_b) = remove_double_apply(b.clone(), false);
let result = Rc::new(SExp::Cons(l.clone(), new_a, new_b));
if spine {
let (root_transformed_dq, result_dq) = change_apply_double_quote(result);
let (root_transformed_unapply, result_single_apply) =
change_double_to_single_apply(result_dq);
let (constant_collapse, result_end) =
collapse_constant_condition(result_single_apply);
any_transformation = a_changed
|| b_changed
|| root_transformed_dq
|| root_transformed_unapply
|| constant_collapse;
was_transformed |= any_transformation;
sexp = result_end;
} else {
any_transformation = a_changed || b_changed;
was_transformed |= any_transformation;
sexp = result;
}
} else {
break;
}
}
(was_transformed, sexp)
}