use std::convert::{TryInto, TryFrom};
use smallvec::{smallvec, SmallVec};
use std::fmt::{self, Display, Debug, Formatter};
use std::slice::Iter;
use std::ops::{Deref, DerefMut};
use super::{
Value, ValueDesc, ValueEnum, ValId, ValueData,
error::ValueError
};
pub const SMALL_SEXPR_SIZE: usize = 3;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct SexprArgs(pub SmallVec<[ValId; SMALL_SEXPR_SIZE]>);
impl Deref for SexprArgs {
type Target = SmallVec<[ValId; SMALL_SEXPR_SIZE]>;
#[inline(always)] fn deref(&self) -> &Self::Target { &self.0 }
}
impl DerefMut for SexprArgs {
#[inline(always)] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
impl From<SmallVec<[ValId; SMALL_SEXPR_SIZE]>> for SexprArgs {
#[inline] fn from(v: SmallVec<[ValId; SMALL_SEXPR_SIZE]>) -> SexprArgs { SexprArgs(v) }
}
impl SexprArgs {
#[inline(always)] pub fn normalize(self) -> Result<Sexpr, ValueError> { Sexpr::build(self) }
#[inline] pub fn dependencies(&self) -> Iter<ValId> { self.iter() }
}
impl Debug for SexprArgs {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
<Self as Display>::fmt(self, fmt)
}
}
impl Display for SexprArgs {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
write!(fmt, "(")?;
let mut first = true;
for arg in self.iter().rev() {
write!(fmt, "{}{}", if first {""} else {" "}, arg)?;
first = false;
}
write!(fmt, ")")
}
}
impl TryFrom<SexprArgs> for Sexpr {
type Error = ValueError;
fn try_from(args: SexprArgs) -> Result<Sexpr, ValueError> {
args.normalize()
}
}
impl TryFrom<SexprArgs> for ValueEnum {
type Error = ValueError;
fn try_from(args: SexprArgs) -> Result<ValueEnum, ValueError> {
Ok(ValueEnum::from(args.normalize()?))
}
}
impl TryFrom<SexprArgs> for ValueData {
type Error = ValueError;
fn try_from(args: SexprArgs) -> Result<ValueData, ValueError> {
Ok(ValueData::new(ValueEnum::try_from(args)?))
}
}
impl TryFrom<SexprArgs> for ValId {
type Error = ValueError;
fn try_from(args: SexprArgs) -> Result<ValId, ValueError> {
let sexpr: Sexpr = args.try_into()?;
sexpr.try_into()
}
}
impl From<Sexpr> for ValueEnum { fn from(sexpr: Sexpr) -> ValueEnum { ValueEnum::Sexpr(sexpr) } }
impl From<Sexpr> for ValueData {
fn from(sexpr: Sexpr) -> ValueData { ValueData::new(ValueEnum::from(sexpr)) }
}
impl TryFrom<Sexpr> for ValId {
type Error = ValueError;
fn try_from(sexpr: Sexpr) -> Result<ValId, ValueError> { sexpr.to_node() }
}
impl ValueDesc for Sexpr {
type Err = ValueError;
fn to_node<E>(mut self) -> Result<ValId, E> where ValueError: Into<E> {
if self.args.len() == 1 {
Ok(self.args.swap_remove(0))
} else {
ValId::try_new(ValueEnum::Sexpr(self).into()).map_err(|err| err.into())
}
}
}
impl Value for Sexpr {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Sexpr {
args: SexprArgs
}
impl Sexpr {
pub fn node<N: Into<ValId>>(node: N) -> Sexpr {
Self::build_normalized(SexprArgs(smallvec![node.into()]))
}
pub fn build_normalized<V>(args: V) -> Sexpr
where V: Into<SexprArgs> { Sexpr { args: args.into() } }
pub fn build<V>(args: V) -> Result<Sexpr, ValueError>
where V: Into<SexprArgs> {
let mut args: SexprArgs = args.into();
args.try_normalize()?;
Ok(Self::build_normalized(args))
}
#[inline] pub fn dependencies(&self) -> Iter<ValId> { self.args.dependencies() }
}
impl Display for Sexpr {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> { write!(fmt, "{}", self.args) }
}
impl Deref for Sexpr {
type Target = SexprArgs;
#[inline(always)] fn deref(&self) -> &Self::Target { &self.args }
}
#[cfg(test)]
mod tests {
use super::*;
use smallvec::smallvec;
use crate::value::primitive::logical::{BINARY_OPS, UNARY_OPS};
#[test]
fn fully_evaluated_binary_logical_operations_normalize() {
for op in BINARY_OPS {
for i in 0b00..=0b11 {
let l = i & 0b01 != 0;
let r = i & 0b11 != 0;
let unnormalized = SexprArgs(smallvec![
ValId::from(r),
ValId::from(l),
ValId::from(*op)
]);
let mut sexpr = unnormalized.clone();
match sexpr.try_normalize() {
Ok(_) => {},
Err(err) => {
panic!(
"Normalization error for {} [current state = {}]: {:#?}",
unnormalized, sexpr, err
)
}
}
let sexpr = Sexpr::build_normalized(sexpr);
let res = SexprArgs(smallvec![ValId::from(op.apply(l, r))]);
assert!(sexpr.args_jeq(&res), "Invalid result for {}", unnormalized)
}
}
}
#[test]
fn partially_evaluated_binary_logical_operations_normalize() {
for op in BINARY_OPS {
for arg in &[true, false] {
let unnormalized = SexprArgs(smallvec![
ValId::from(*arg),
ValId::from(*op)
]);
let mut sexpr = unnormalized.clone();
match sexpr.try_normalize() {
Ok(_) => {},
Err(err) => {
panic!(
"Normalization error for {} [current state = {}]: {:#?}",
unnormalized, sexpr, err
)
}
}
let sexpr = Sexpr::build_normalized(sexpr);
let res = SexprArgs(smallvec![ValId::from(op.partial_apply(*arg))]);
assert!(sexpr.args_jeq(&res), "Invalid result for {}", unnormalized);
}
}
}
#[test]
fn unary_logical_operations_normalize() {
for op in UNARY_OPS {
for arg in &[true, false] {
let unnormalized = SexprArgs(smallvec![
ValId::from(*arg),
ValId::from(*op)
]);
let mut sexpr = unnormalized.clone();
match sexpr.try_normalize() {
Ok(_) => {},
Err(err) => {
panic!(
"Normalization error for {} [current state = {}]: {:#?}",
unnormalized, sexpr, err
);
}
}
let sexpr = Sexpr::build_normalized(sexpr);
let res = SexprArgs(smallvec![ValId::from(op.apply(*arg))]);
assert!(sexpr.args_jeq(&res), "Invalid result for {}", unnormalized);
}
}
}
}