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 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: ::type_of(), }) } } #[derive(Debug, PartialEq, Clone, Deref)] pub struct Value(Rc); impl Display for Value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl From for Value where Val: From, { fn from(x: T) -> Self { Self(Rc::new(x.into())) } } impl Neg for Value { type Output = Result; fn neg(self) -> Self::Output { Ok((-self.into_type::()?).into()) } } impl Add for Value { type Output = Result; fn add(self, rhs: Self) -> Self::Output { Ok((self.into_type::()? + rhs.into_type::()?).into()) } } impl Sub for Value { type Output = Result; fn sub(self, rhs: Self) -> Self::Output { Ok((self.into_type::()? - rhs.into_type::()?).into()) } } impl Mul for Value { type Output = Result; fn mul(self, rhs: Self) -> Self::Output { Ok((self.into_type::()? * rhs.into_type::()?).into()) } } impl Div for Value { type Output = Result; fn div(self, rhs: Self) -> Self::Output { Ok((self.into_type::()? / rhs.into_type::()?).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 } }