about summary refs log tree commit diff
path: root/src/interpreter/value.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/interpreter/value.rs')
-rw-r--r--src/interpreter/value.rs134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs
new file mode 100644
index 000000000000..69e4d4ffeb96
--- /dev/null
+++ b/src/interpreter/value.rs
@@ -0,0 +1,134 @@
+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
+    }
+}