rain-lang 0.0.1

An implementation of an RVSDG in Rust with a concept of lifetimes
Documentation
/*!
Expression nodes
*/
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
};
//use crate::util::AlwaysOk;

/// The size of a small S-expression
pub const SMALL_SEXPR_SIZE: usize = 3;

/// Potentially un-normalized S-expression arguments
#[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 {
    /// Normalize this S-expression
    #[inline(always)] pub fn normalize(self) -> Result<Sexpr, ValueError> { Sexpr::build(self) }
    /// Get the dependencies of this argument set
    #[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 {}

/// An S-expression node
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Sexpr {
    args: SexprArgs
}

impl Sexpr {
    /// Build a sexpr contaning a single node
    pub fn node<N: Into<ValId>>(node: N) -> Sexpr {
        Self::build_normalized(SexprArgs(smallvec![node.into()]))
    }
    /// Build an S-expression from a vector of arguments, asserting they are normalized.
    /// It is a logic error if they are not.
    pub fn build_normalized<V>(args: V) -> Sexpr
    where V: Into<SexprArgs> { Sexpr { args: args.into() } }
    /// Build an S-expression from a vector of arguments
    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))
    }
    /// Get the dependencies of this argument set
    #[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);
            }
        }
    }
}