use crate::classic::clvm::__type_compatibility__::{Bytes, BytesFromType};
use crate::classic::clvm::sexp::equal_to;
use clvm_rs::allocator::{Allocator, NodePtr, SExp};
use std::collections::HashMap;
pub const ATOM_MATCH: [u8; 1] = [b'$'];
pub const SEXP_MATCH: [u8; 1] = [b':'];
pub fn unify_bindings(
allocator: &mut Allocator,
bindings: HashMap<String, NodePtr>,
new_key: &[u8],
new_value: NodePtr,
) -> Option<HashMap<String, NodePtr>> {
let new_key_str = Bytes::new(Some(BytesFromType::Raw(new_key.to_vec()))).decode();
match bindings.get(&new_key_str) {
Some(binding) => {
if !equal_to(allocator, *binding, new_value) {
return None;
}
Some(bindings)
}
_ => {
let mut new_bindings = bindings.clone();
new_bindings.insert(new_key_str, new_value);
Some(new_bindings)
}
}
}
pub fn match_sexp(
allocator: &mut Allocator,
pattern: NodePtr,
sexp: NodePtr,
known_bindings: HashMap<String, NodePtr>,
) -> Option<HashMap<String, NodePtr>> {
match (allocator.sexp(pattern), allocator.sexp(sexp)) {
(SExp::Atom(pat_buf), SExp::Atom(sexp_buf)) => {
let sexp_bytes = allocator.buf(&sexp_buf).to_vec();
if allocator.buf(&pat_buf).to_vec() == sexp_bytes {
Some(known_bindings)
} else {
None
}
}
(SExp::Pair(pleft, pright), _) => match (allocator.sexp(pleft), allocator.sexp(pright)) {
(SExp::Atom(pat_left), SExp::Atom(pat_right)) => {
let pat_right_bytes = allocator.buf(&pat_right).to_vec();
let pat_left_bytes = allocator.buf(&pat_left).to_vec();
match allocator.sexp(sexp) {
SExp::Atom(sexp_buf) => {
let sexp_bytes = allocator.buf(&sexp_buf).to_vec();
if pat_left_bytes == ATOM_MATCH.to_vec() {
if pat_right_bytes == ATOM_MATCH.to_vec() {
if sexp_bytes == ATOM_MATCH.to_vec() {
return Some(HashMap::new());
}
return None;
}
return unify_bindings(
allocator,
known_bindings,
&pat_right_bytes,
sexp,
);
}
if pat_left_bytes == SEXP_MATCH.to_vec() {
if pat_right_bytes == SEXP_MATCH.to_vec()
&& sexp_bytes == SEXP_MATCH.to_vec()
{
return Some(HashMap::new());
}
return unify_bindings(
allocator,
known_bindings,
&pat_right_bytes,
sexp,
);
}
None
}
SExp::Pair(sleft, sright) => {
if pat_left_bytes == SEXP_MATCH.to_vec()
&& pat_right_bytes != SEXP_MATCH.to_vec()
{
return unify_bindings(
allocator,
known_bindings,
&pat_right_bytes,
sexp,
);
}
match_sexp(allocator, pleft, sleft, known_bindings).and_then(
|new_bindings| match_sexp(allocator, pright, sright, new_bindings),
)
}
}
}
_ => match allocator.sexp(sexp) {
SExp::Atom(_) => None,
SExp::Pair(sleft, sright) => match_sexp(allocator, pleft, sleft, known_bindings)
.and_then(|new_bindings| match_sexp(allocator, pright, sright, new_bindings)),
},
},
(SExp::Atom(_), _) => None,
}
}