use std::borrow::Cow; use std::convert::TryFrom; use std::fmt::{self, Display}; use std::ops::{Add, Div, Mul, Neg, Sub}; use std::rc::Rc; use std::result; use derive_more::{Deref, From, TryInto}; use itertools::Itertools; use super::{Error, Result}; use crate::ast::hir::Expr; use crate::ast::{FunctionType, Ident, Type}; #[derive(Debug, Clone)] pub struct Function<'a> { pub type_: FunctionType<'a>, pub args: Vec>, pub body: Expr<'a, Type<'a>>, } #[derive(From, TryInto)] #[try_into(owned, ref)] pub enum Val<'a> { Int(i64), Float(f64), Bool(bool), String(Cow<'a, str>), Tuple(Vec>), Function(Function<'a>), } impl<'a> TryFrom> for String { type Error = (); fn try_from(value: Val<'a>) -> result::Result { match value { Val::String(s) => Ok(s.into_owned()), _ => Err(()), } } } impl<'a> fmt::Debug for Val<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Val::Int(x) => f.debug_tuple("Int").field(x).finish(), Val::Float(x) => f.debug_tuple("Float").field(x).finish(), Val::Bool(x) => f.debug_tuple("Bool").field(x).finish(), Val::String(s) => f.debug_tuple("String").field(s).finish(), Val::Function(Function { type_, .. }) => { f.debug_struct("Function").field("type_", type_).finish() } Val::Tuple(members) => f.debug_tuple("Tuple").field(members).finish(), } } } impl<'a> PartialEq for Val<'a> { fn eq(&self, other: &Self) -> bool { match (self, other) { (Val::Int(x), Val::Int(y)) => x == y, (Val::Float(x), Val::Float(y)) => x == y, (Val::Bool(x), Val::Bool(y)) => x == y, (Val::Function(_), Val::Function(_)) => false, (_, _) => false, } } } impl<'a> From for Val<'a> { fn from(i: u64) -> Self { Self::from(i as i64) } } impl<'a> Display for Val<'a> { 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), Val::String(s) => write!(f, "{:?}", s), Val::Function(Function { type_, .. }) => write!(f, "<{}>", type_), Val::Tuple(members) => write!(f, "({})", members.iter().join(", ")), } } } impl<'a> Val<'a> { pub fn type_(&self) -> Type { match self { Val::Int(_) => Type::Int, Val::Float(_) => Type::Float, Val::Bool(_) => Type::Bool, Val::String(_) => Type::CString, Val::Function(Function { type_, .. }) => Type::Function(type_.clone()), Val::Tuple(members) => Type::Tuple(members.iter().map(|expr| expr.type_()).collect()), } } pub fn as_type<'b, T>(&'b self) -> Result<&'b T> where T: TypeOf + 'b + Clone, &'b T: TryFrom<&'b Self>, { <&T>::try_from(self).map_err(|_| Error::InvalidType { actual: self.type_().to_owned(), expected: ::type_of(), }) } pub fn as_function<'b>(&'b self, function_type: FunctionType) -> Result<&'b Function<'a>> { match self { Val::Function(f) if f.type_ == function_type => Ok(&f), _ => Err(Error::InvalidType { actual: self.type_().to_owned(), expected: Type::Function(function_type.to_owned()), }), } } pub fn as_tuple(&self) -> Option<&Vec>> { if let Self::Tuple(v) = self { Some(v) } else { None } } pub fn try_into_tuple(self) -> result::Result>, Self> { if let Self::Tuple(v) = self { Ok(v) } else { Err(self) } } } #[derive(Debug, PartialEq, Clone, Deref)] pub struct Value<'a>(Rc>); impl<'a> Display for Value<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl<'a, T> From for Value<'a> where Val<'a>: From, { fn from(x: T) -> Self { Self(Rc::new(x.into())) } } impl<'a> Neg for Value<'a> { type Output = Result>; fn neg(self) -> Self::Output { Ok((-self.as_type::()?).into()) } } impl<'a> Add for Value<'a> { type Output = Result>; fn add(self, rhs: Self) -> Self::Output { Ok((self.as_type::()? + rhs.as_type::()?).into()) } } impl<'a> Sub for Value<'a> { type Output = Result>; fn sub(self, rhs: Self) -> Self::Output { Ok((self.as_type::()? - rhs.as_type::()?).into()) } } impl<'a> Mul for Value<'a> { type Output = Result>; fn mul(self, rhs: Self) -> Self::Output { Ok((self.as_type::()? * rhs.as_type::()?).into()) } } impl<'a> Div for Value<'a> { type Output = Result>; fn div(self, rhs: Self) -> Self::Output { Ok((self.as_type::()? / rhs.as_type::()?).into()) } } pub trait TypeOf { fn type_of() -> Type<'static>; } impl TypeOf for i64 { fn type_of() -> Type<'static> { Type::Int } } impl TypeOf for bool { fn type_of() -> Type<'static> { Type::Bool } } impl TypeOf for f64 { fn type_of() -> Type<'static> { Type::Float } } impl TypeOf for String { fn type_of() -> Type<'static> { Type::CString } }