about summary refs log tree commit diff
path: root/src/interpreter/value.rs
diff options
context:
space:
mode:
authorGriffin Smith <root@gws.fyi>2021-03-08T05·04-0500
committerGriffin Smith <root@gws.fyi>2021-03-08T05·04-0500
commit1ea2d8ba9fef3bee2c757d19d8b42e541e3fe390 (patch)
tree6999d66bb363fce16a078abfc913fa1610c1437c /src/interpreter/value.rs
parent80f8ede0bbc9799d5199707e1e1ad8e80e4ca7ac (diff)
Implement functions, both top-level and anonymous
Implement both top-level and anonymous functions, but not closures in
either case.
Diffstat (limited to 'src/interpreter/value.rs')
-rw-r--r--src/interpreter/value.rs101
1 files changed, 73 insertions, 28 deletions
diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs
index 69e4d4ffeb96..496e9c4230de 100644
--- a/src/interpreter/value.rs
+++ b/src/interpreter/value.rs
@@ -6,108 +6,153 @@ use std::rc::Rc;
 use derive_more::{Deref, From, TryInto};
 
 use super::{Error, Result};
-use crate::ast::Type;
+use crate::ast::{Expr, FunctionType, Ident, Type};
 
-#[derive(Debug, PartialEq, From, TryInto)]
+#[derive(Debug, Clone)]
+pub struct Function<'a> {
+    pub type_: FunctionType,
+    pub args: Vec<Ident<'a>>,
+    pub body: Expr<'a>,
+}
+
+#[derive(From, TryInto)]
 #[try_into(owned, ref)]
-pub enum Val {
+pub enum Val<'a> {
     Int(i64),
     Float(f64),
     Bool(bool),
+    Function(Function<'a>),
+}
+
+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::Function(Function { type_, .. }) => {
+                f.debug_struct("Function").field("type_", type_).finish()
+            }
+        }
+    }
 }
 
-impl From<u64> for Val {
+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<u64> for Val<'a> {
     fn from(i: u64) -> Self {
         Self::from(i as i64)
     }
 }
 
-impl Display for Val {
+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::Function(Function { type_, .. }) => write!(f, "<{}>", type_),
         }
     }
 }
 
-impl Val {
+impl<'a> Val<'a> {
     pub fn type_(&self) -> Type {
         match self {
             Val::Int(_) => Type::Int,
             Val::Float(_) => Type::Float,
             Val::Bool(_) => Type::Bool,
+            Val::Function(Function { type_, .. }) => Type::Function(type_.clone()),
         }
     }
 
-    pub fn into_type<'a, T>(&'a self) -> Result<&'a T>
+    pub fn as_type<'b, T>(&'b self) -> Result<&'b T>
     where
-        T: TypeOf + 'a + Clone,
-        &'a T: TryFrom<&'a Self>,
+        T: TypeOf + 'b + Clone,
+        &'b T: TryFrom<&'b Self>,
     {
         <&T>::try_from(self).map_err(|_| Error::InvalidType {
             actual: self.type_(),
             expected: <T as TypeOf>::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_(),
+                expected: Type::Function(function_type),
+            }),
+        }
+    }
 }
 
 #[derive(Debug, PartialEq, Clone, Deref)]
-pub struct Value(Rc<Val>);
+pub struct Value<'a>(Rc<Val<'a>>);
 
-impl Display for Value {
+impl<'a> Display for Value<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.0.fmt(f)
     }
 }
 
-impl<T> From<T> for Value
+impl<'a, T> From<T> for Value<'a>
 where
-    Val: From<T>,
+    Val<'a>: From<T>,
 {
     fn from(x: T) -> Self {
         Self(Rc::new(x.into()))
     }
 }
 
-impl Neg for Value {
-    type Output = Result<Value>;
+impl<'a> Neg for Value<'a> {
+    type Output = Result<Value<'a>>;
 
     fn neg(self) -> Self::Output {
-        Ok((-self.into_type::<i64>()?).into())
+        Ok((-self.as_type::<i64>()?).into())
     }
 }
 
-impl Add for Value {
-    type Output = Result<Value>;
+impl<'a> Add for Value<'a> {
+    type Output = Result<Value<'a>>;
 
     fn add(self, rhs: Self) -> Self::Output {
-        Ok((self.into_type::<i64>()? + rhs.into_type::<i64>()?).into())
+        Ok((self.as_type::<i64>()? + rhs.as_type::<i64>()?).into())
     }
 }
 
-impl Sub for Value {
-    type Output = Result<Value>;
+impl<'a> Sub for Value<'a> {
+    type Output = Result<Value<'a>>;
 
     fn sub(self, rhs: Self) -> Self::Output {
-        Ok((self.into_type::<i64>()? - rhs.into_type::<i64>()?).into())
+        Ok((self.as_type::<i64>()? - rhs.as_type::<i64>()?).into())
     }
 }
 
-impl Mul for Value {
-    type Output = Result<Value>;
+impl<'a> Mul for Value<'a> {
+    type Output = Result<Value<'a>>;
 
     fn mul(self, rhs: Self) -> Self::Output {
-        Ok((self.into_type::<i64>()? * rhs.into_type::<i64>()?).into())
+        Ok((self.as_type::<i64>()? * rhs.as_type::<i64>()?).into())
     }
 }
 
-impl Div for Value {
-    type Output = Result<Value>;
+impl<'a> Div for Value<'a> {
+    type Output = Result<Value<'a>>;
 
     fn div(self, rhs: Self) -> Self::Output {
-        Ok((self.into_type::<f64>()? / rhs.into_type::<f64>()?).into())
+        Ok((self.as_type::<f64>()? / rhs.as_type::<f64>()?).into())
     }
 }