about summary refs log blame commit diff
path: root/src/interpreter/value.rs
blob: 69e4d4ffeb96439ac609ea2e78c5c46142a85612 (plain) (tree)





































































































































                                                                       
use std::convert::TryFrom;
use std::fmt::{self, Display};
use std::ops::{Add, Div, Mul, Neg, Sub};
use std::rc::Rc;

use derive_more::{Deref, From, TryInto};

use super::{Error, Result};
use crate::ast::Type;

#[derive(Debug, PartialEq, From, TryInto)]
#[try_into(owned, ref)]
pub enum Val {
    Int(i64),
    Float(f64),
    Bool(bool),
}

impl From<u64> for Val {
    fn from(i: u64) -> Self {
        Self::from(i as i64)
    }
}

impl Display for Val {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Val::Int(x) => x.fmt(f),
            Val::Float(x) => x.fmt(f),
            Val::Bool(x) => x.fmt(f),
        }
    }
}

impl Val {
    pub fn type_(&self) -> Type {
        match self {
            Val::Int(_) => Type::Int,
            Val::Float(_) => Type::Float,
            Val::Bool(_) => Type::Bool,
        }
    }

    pub fn into_type<'a, T>(&'a self) -> Result<&'a T>
    where
        T: TypeOf + 'a + Clone,
        &'a T: TryFrom<&'a Self>,
    {
        <&T>::try_from(self).map_err(|_| Error::InvalidType {
            actual: self.type_(),
            expected: <T as TypeOf>::type_of(),
        })
    }
}

#[derive(Debug, PartialEq, Clone, Deref)]
pub struct Value(Rc<Val>);

impl Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<T> From<T> for Value
where
    Val: From<T>,
{
    fn from(x: T) -> Self {
        Self(Rc::new(x.into()))
    }
}

impl Neg for Value {
    type Output = Result<Value>;

    fn neg(self) -> Self::Output {
        Ok((-self.into_type::<i64>()?).into())
    }
}

impl Add for Value {
    type Output = Result<Value>;

    fn add(self, rhs: Self) -> Self::Output {
        Ok((self.into_type::<i64>()? + rhs.into_type::<i64>()?).into())
    }
}

impl Sub for Value {
    type Output = Result<Value>;

    fn sub(self, rhs: Self) -> Self::Output {
        Ok((self.into_type::<i64>()? - rhs.into_type::<i64>()?).into())
    }
}

impl Mul for Value {
    type Output = Result<Value>;

    fn mul(self, rhs: Self) -> Self::Output {
        Ok((self.into_type::<i64>()? * rhs.into_type::<i64>()?).into())
    }
}

impl Div for Value {
    type Output = Result<Value>;

    fn div(self, rhs: Self) -> Self::Output {
        Ok((self.into_type::<f64>()? / rhs.into_type::<f64>()?).into())
    }
}

pub trait TypeOf {
    fn type_of() -> Type;
}

impl TypeOf for i64 {
    fn type_of() -> Type {
        Type::Int
    }
}

impl TypeOf for bool {
    fn type_of() -> Type {
        Type::Bool
    }
}

impl TypeOf for f64 {
    fn type_of() -> Type {
        Type::Float
    }
}