diff options
-rw-r--r-- | src/parse/parsetree.rs | 12 | ||||
-rw-r--r-- | src/sexp/display.rs | 12 | ||||
-rw-r--r-- | src/sexp/mod.rs | 18 | ||||
-rw-r--r-- | src/sexp/step.rs | 114 | ||||
-rw-r--r-- | src/type/check.rs | 31 | ||||
-rw-r--r-- | src/type/display.rs | 6 | ||||
-rw-r--r-- | src/type/mod.rs | 7 | ||||
-rw-r--r-- | src/type/subst.rs | 2 |
8 files changed, 196 insertions, 6 deletions
diff --git a/src/parse/parsetree.rs b/src/parse/parsetree.rs index 5507b0b..3cdc6fe 100644 --- a/src/parse/parsetree.rs +++ b/src/parse/parsetree.rs @@ -99,6 +99,18 @@ fn tokens_to_ast_inner( Some(Sym(s)) if s == "*" => Ok(Atom(Mul)), Some(Sym(s)) if s == "/" => Ok(Atom(Div)), Some(Sym(s)) if s == "-" => Ok(Atom(Sub)), + Some(Sym(s)) if s == ">" => Ok(Atom(Gt)), + Some(Sym(s)) if s == "<" => Ok(Atom(Lt)), + Some(Sym(s)) if s == ">=" => Ok(Atom(Ge)), + Some(Sym(s)) if s == "<=" => Ok(Atom(Le)), + Some(Sym(s)) if s == "=" => Ok(Atom(Eq)), + Some(Sym(s)) if s == "!=" => Ok(Atom(Neq)), + Some(Sym(s)) if s == "and" => Ok(Atom(And)), + Some(Sym(s)) if s == "or" => Ok(Atom(Or)), + Some(Sym(s)) if s == "not" => Ok(Atom(Not)), + Some(Sym(s)) if s == "xor" => Ok(Atom(Xor)), + Some(Sym(s)) if s == "true" => Ok(Atom(True)), + Some(Sym(s)) if s == "false" => Ok(Atom(False)), Some(Sym(s)) if s == "quote" => Ok(Atom(Quote)), Some(Sym(s)) => Ok(Atom(Var(s))), Some(ParClose) => break, diff --git a/src/sexp/display.rs b/src/sexp/display.rs index 238e8d4..96ce435 100644 --- a/src/sexp/display.rs +++ b/src/sexp/display.rs @@ -11,6 +11,18 @@ impl fmt::Display for SLeaf { Sub => "-".to_string(), Mul => "*".to_string(), Div => "/".to_string(), + Gt => ">".to_string(), + Lt => "<".to_string(), + Ge => ">=".to_string(), + Le => "<=".to_string(), + Eq => "=".to_string(), + Neq => "!=".to_string(), + And => "and".to_string(), + Or => "or".to_string(), + Not => "not".to_string(), + Xor => "xor".to_string(), + True => "true".to_string(), + False => "false".to_string(), Int(x) => x.to_string(), Var(s) => s.to_string(), Quote => "quote".to_string(), diff --git a/src/sexp/mod.rs b/src/sexp/mod.rs index 0fb5e25..60dd3b0 100644 --- a/src/sexp/mod.rs +++ b/src/sexp/mod.rs @@ -12,13 +12,29 @@ pub mod display; #[derive(PartialEq)] #[derive(Clone)] pub enum SLeaf { + Add, Sub, Mul, Div, + Eq, + Neq, + Gt, + Lt, + Ge, + Le, + And, + Or, + Not, + Xor, + Quote, + Int(i32), + True, + False, + Var(String), - Quote, + Nil, } diff --git a/src/sexp/step.rs b/src/sexp/step.rs index ee76ebf..bb3ada5 100644 --- a/src/sexp/step.rs +++ b/src/sexp/step.rs @@ -44,6 +44,7 @@ impl SExp { /// ``` /// /// Also, addition and multiplication can take more than two arguments: + /// (as of 2025-08-05 not allowed by the type system, might change) /// ```rust /// use myslip::sexp::{SExp::*, SLeaf::*, util::*}; /// @@ -84,6 +85,119 @@ impl SExp { /// /// ``` /// + /// **Integer comparisons** + /// + /// ```rust + /// use myslip::sexp::{SExp::*, SLeaf::*, util::*}; + /// + /// assert_eq!( + /// scons(Lt, scons(1, scons(2, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// assert_eq!( + /// scons(Lt, scons(2, scons(2, Nil))).step(), + /// Ok(Atom(False)) + /// ); + /// + /// assert_eq!( + /// scons(Gt, scons(2, scons(1, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// assert_eq!( + /// scons(Lt, scons(1, scons(1, Nil))).step(), + /// Ok(Atom(False)) + /// ); + /// + /// assert_eq!( + /// scons(Le, scons(1, scons(2, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// assert_eq!( + /// scons(Le, scons(2, scons(2, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// assert_eq!( + /// scons(Lt, scons(2, scons(1, Nil))).step(), + /// Ok(Atom(False)) + /// ); + /// + /// assert_eq!( + /// scons(Ge, scons(2, scons(1, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// assert_eq!( + /// scons(Ge, scons(1, scons(1, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// assert_eq!( + /// scons(Lt, scons(1, scons(2, Nil))).step(), + /// Ok(Atom(False)) + /// ); + /// + /// assert_eq!( + /// scons(Eq, scons(1, scons(2, Nil))).step(), + /// Ok(Atom(False)) + /// ); + /// assert_eq!( + /// scons(Eq, scons(2, scons(2, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// + /// assert_eq!( + /// scons(Neq, scons(1, scons(2, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// assert_eq!( + /// scons(Neq, scons(2, scons(2, Nil))).step(), + /// Ok(Atom(False)) + /// ); + /// ``` + /// + /// **Boolean expressions** + /// + /// ```rust + /// use myslip::sexp::{SExp::*, SLeaf::*, util::*}; + /// assert_eq!( + /// scons(And, scons(True, scons(True, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// assert_eq!( + /// scons(And, scons(False, scons(True, Nil))).step(), + /// Ok(Atom(False)) + /// ); + /// + /// assert_eq!( + /// scons(Or, scons(False, scons(True, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// assert_eq!( + /// scons(Or, scons(False, scons(False, Nil))).step(), + /// Ok(Atom(False)) + /// ); + /// + /// assert_eq!( + /// scons(Xor, scons(False, scons(True, Nil))).step(), + /// Ok(Atom(True)) + /// ); + /// assert_eq!( + /// scons(Xor, scons(False, scons(False, Nil))).step(), + /// Ok(Atom(False)) + /// ); + /// assert_eq!( + /// scons(Xor, scons(True, scons(True, Nil))).step(), + /// Ok(Atom(False)) + /// ); + /// + /// assert_eq!( + /// scons(Not, scons(True, Nil)).step(), + /// Ok(Atom(False)) + /// ); + /// assert_eq!( + /// scons(Not, scons(False, Nil)).step(), + /// Ok(Atom(True)) + /// ); + /// ``` + /// /// **Quotes** /// If an s-expression should not be evaluated /// as a function, but it is instead to be treated diff --git a/src/type/check.rs b/src/type/check.rs index 9369d97..e9917c7 100644 --- a/src/type/check.rs +++ b/src/type/check.rs @@ -16,6 +16,7 @@ impl SExp { /// }; /// /// assert_eq!(Atom(Int(1)).type_check(), Ok(Integer)); + /// assert_eq!(Atom(False).type_check(), Ok(Boolean)); /// ``` /// /// Quotes are given list types: @@ -26,8 +27,8 @@ impl SExp { /// }; /// /// assert_eq!( - /// scons(Quote, scons(1, scons(2, Nil))).type_check(), - /// Ok(List(vec![Integer, Integer])) + /// scons(Quote, scons(1, scons(False, Nil))).type_check(), + /// Ok(List(vec![Integer, Boolean])) /// ); /// ``` /// Though so is Nil given too: @@ -54,6 +55,16 @@ impl SExp { /// assert_eq!(Atom(Mul).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer))); /// assert_eq!(Atom(Sub).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer))); /// assert_eq!(Atom(Div).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer))); + /// assert_eq!(Atom(Eq) .type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean))); + /// assert_eq!(Atom(Neq).type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean))); + /// assert_eq!(Atom(Gt) .type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean))); + /// assert_eq!(Atom(Lt) .type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean))); + /// assert_eq!(Atom(Ge) .type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean))); + /// assert_eq!(Atom(Le) .type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean))); + /// assert_eq!(Atom(And).type_check(), Ok(arr(List(vec![Boolean, Boolean]), Boolean))); + /// assert_eq!(Atom(Or) .type_check(), Ok(arr(List(vec![Boolean, Boolean]), Boolean))); + /// assert_eq!(Atom(Xor).type_check(), Ok(arr(List(vec![Boolean, Boolean]), Boolean))); + /// assert_eq!(Atom(Not).type_check(), Ok(arr(Boolean, Boolean))); /// ``` /// /// Though perhaps the most important task of the type system @@ -94,6 +105,10 @@ impl SExp { /// "passing '-' as an argument to '+' should return in InvalidArgList error" /// ), /// }; + /// + /// assert!(scons(And, scons(1, scons(Atom(True), Nil))).type_check().is_err()); + /// assert!(scons(Mul, scons(1, scons(Atom(True), Nil))).type_check().is_err()); + /// assert!(scons(Not, scons(1, Nil)).type_check().is_err()); /// ``` /// /// Also, free variables should result in an error @@ -121,6 +136,8 @@ impl SExp { match self { Atom(Int(_)) => Ok(Integer), + Atom(True) => todo!(), + Atom(False) => todo!(), Atom(Var(name)) => ctx.get(name) .ok_or(UndefinedVariable(name.to_string())) .cloned(), @@ -128,6 +145,16 @@ impl SExp { Atom(Mul) => Ok(arr(List(vec![Integer, Integer]), Integer)), // TODO varlen Atom(Sub) => Ok(arr(List(vec![Integer, Integer]), Integer)), Atom(Div) => Ok(arr(List(vec![Integer, Integer]), Integer)), + Atom(Eq) => todo!(), + Atom(Neq) => todo!(), + Atom(Lt) => todo!(), + Atom(Gt) => todo!(), + Atom(Le) => todo!(), + Atom(Ge) => todo!(), + Atom(Or) => todo!(), + Atom(And) => todo!(), + Atom(Xor) => todo!(), + Atom(Not) => todo!(), Atom(Nil) => Ok(List(vec![])), Atom(Quote) => Ok(arr( VarType("T".to_string()), diff --git a/src/type/display.rs b/src/type/display.rs index 2fca5f9..832b289 100644 --- a/src/type/display.rs +++ b/src/type/display.rs @@ -11,8 +11,9 @@ impl fmt::Display for Type { /// ```rust /// use myslip::r#type::{Type::*, util::*}; /// assert_eq!(Integer.to_string(), "Int".to_string()); - /// assert_eq!(arr(Integer, Integer).to_string(), "(Int -> Int)".to_string()); - /// assert_eq!(List(vec![Integer, Integer, Integer]).to_string(), "(Int Int Int)".to_string()); + /// assert_eq!(Boolean.to_string(), "Bool".to_string()); + /// assert_eq!(arr(Integer, Boolean).to_string(), "(Int -> Bool)".to_string()); + /// assert_eq!(List(vec![Integer, Boolean, Integer]).to_string(), "(Int Bool Int)".to_string()); /// ``` fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -27,6 +28,7 @@ impl fmt::Display for Type { .join(" ") ), VarType(name) => write!(f, "{}", name), + Boolean => todo!(), } } } diff --git a/src/type/mod.rs b/src/type/mod.rs index 8761cee..8977d85 100644 --- a/src/type/mod.rs +++ b/src/type/mod.rs @@ -14,6 +14,8 @@ pub enum Type { Integer, + Boolean, + Arrow(Box<Type>, Box<Type>), List(Vec<Type>), @@ -63,19 +65,21 @@ impl Type { /// use myslip::r#type::{*, Type::*, TypeError::*, util::*}; /// /// assert_eq!(Integer.is_concrete(), Ok(())); + /// assert_eq!(Boolean.is_concrete(), Ok(())); /// assert_eq!( /// VarType("a".to_string()).is_concrete(), /// Err("a".to_string()) /// ); /// /// assert_eq!(arr(Integer, Integer).is_concrete(), Ok(())); + /// assert_eq!(arr(Integer, Boolean).is_concrete(), Ok(())); /// assert_eq!( /// arr(VarType("b".to_string()), Integer).is_concrete(), /// Err("b".to_string()) /// ); /// /// assert_eq!( - /// List(vec![Integer, Integer, arr(Integer, Integer)]).is_concrete(), + /// List(vec![Integer, Boolean, arr(Integer, Integer)]).is_concrete(), /// Ok(()) /// ); /// assert_eq!( @@ -87,6 +91,7 @@ impl Type { pub fn is_concrete(&self) -> Result<(), String> { match self { Integer => Ok(()), + Boolean => todo!(), Arrow(a, b) => b.is_concrete().and_then(|_ok| a.is_concrete()), List(v) => { let mut res = Ok(()); diff --git a/src/type/subst.rs b/src/type/subst.rs index 1774770..79c5fe1 100644 --- a/src/type/subst.rs +++ b/src/type/subst.rs @@ -39,6 +39,8 @@ impl Type { Integer => Integer, + Boolean => Boolean, + } } } |