diff options
author | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-06 14:15:12 +0300 |
---|---|---|
committer | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-06 14:15:12 +0300 |
commit | 23b2028bdce46d02209fc2df70fc5468a8beffa8 (patch) | |
tree | 31e7a6fae6d5d01759a84334555f4cd1fa26a038 /src | |
parent | 3d7ebeddc46e89c8e058b3f1805f836339a2f9ae (diff) | |
download | myslip-23b2028bdce46d02209fc2df70fc5468a8beffa8.tar.gz myslip-23b2028bdce46d02209fc2df70fc5468a8beffa8.zip |
Added boilerplate and tests for let-binds
Diffstat (limited to 'src')
-rw-r--r-- | src/parse/parsetree.rs | 1 | ||||
-rw-r--r-- | src/sexp/display.rs | 1 | ||||
-rw-r--r-- | src/sexp/mod.rs | 2 | ||||
-rw-r--r-- | src/sexp/step.rs | 30 | ||||
-rw-r--r-- | src/type/check.rs | 38 | ||||
-rw-r--r-- | src/type/display.rs | 1 | ||||
-rw-r--r-- | src/type/mod.rs | 4 | ||||
-rw-r--r-- | src/type/subst.rs | 1 |
8 files changed, 78 insertions, 0 deletions
diff --git a/src/parse/parsetree.rs b/src/parse/parsetree.rs index 13d73ea..75758dc 100644 --- a/src/parse/parsetree.rs +++ b/src/parse/parsetree.rs @@ -113,6 +113,7 @@ fn tokens_to_ast_inner( Some(Sym(s)) if s == "false" => Ok(Atom(False)), Some(Sym(s)) if s == "quote" => Ok(Atom(Quote)), Some(Sym(s)) if s == "vector" => Ok(Atom(Vector)), + Some(Sym(s)) if s == "let" => Ok(Atom(Let)), Some(Sym(s)) => Ok(Atom(Var(s))), Some(ParClose) => break, Some(ParOpen) => { diff --git a/src/sexp/display.rs b/src/sexp/display.rs index 57d1b50..c3db144 100644 --- a/src/sexp/display.rs +++ b/src/sexp/display.rs @@ -27,6 +27,7 @@ impl fmt::Display for SLeaf { Var(s) => s.to_string(), Quote => "quote".to_string(), Vector => "vector".to_string(), + Let => "let".to_string(), Nil => "()".to_string(), }) } diff --git a/src/sexp/mod.rs b/src/sexp/mod.rs index 07d8373..4e3c11c 100644 --- a/src/sexp/mod.rs +++ b/src/sexp/mod.rs @@ -31,6 +31,8 @@ pub enum SLeaf { Quote, Vector, + Let, + Int(i32), True, False, diff --git a/src/sexp/step.rs b/src/sexp/step.rs index 535b183..e031fca 100644 --- a/src/sexp/step.rs +++ b/src/sexp/step.rs @@ -237,6 +237,36 @@ impl SExp { /// scons(2, Nil))).step(), /// Ok(scons(Vector, scons(1, scons(2, Nil)))) /// ); + /// ``` + /// + /// **Let-bindings** + /// ```rust + /// use myslip::sexp::{SExp::*, SLeaf::*, util::*}; + /// + /// assert_eq!( + /// scons( + /// scons(Let, scons(var("x"), scons(5, Nil))), scons( + /// scons(Add, scons(var("x"), scons(1, Nil))), Nil + /// ) + /// ).step(), + /// Ok(scons(Add, scons(5, scons(1, Nil)))) + /// ); + /// assert_eq!( + /// scons( + /// scons(Let, scons(var("y"), scons(4, Nil))), + /// scons( + /// scons(Let, scons(var("x"), scons(5, Nil))), + /// scons(scons(Add, scons(var("x"), scons(var("y"), Nil))), Nil) + /// ) + /// ).step(), + /// Ok(scons( + /// scons(Let, scons(var("x"), scons(5, Nil))), scons( + /// scons(Add, scons(var("x"), scons(1, Nil))), Nil + /// ) + /// )) + /// ); + /// ``` + /// pub fn step(self) -> Result<Self, String> { match self { diff --git a/src/type/check.rs b/src/type/check.rs index df3f4d9..d0ce807 100644 --- a/src/type/check.rs +++ b/src/type/check.rs @@ -81,6 +81,43 @@ impl SExp { /// assert_eq!(Atom(Not).type_check(), Ok(arr(List(vec![Boolean]), Boolean))); /// ``` /// + /// + /// **Let-binding types** + /// + /// Let-bindings are quite interesting. Implementation is still a bit uncertain, + /// but at least we know that + /// ```rust + /// use myslip::{ + /// r#type::{*, Type::*, TypeError::*, util::*}, + /// sexp::{SExp::*, SLeaf::*, util::*}, + /// }; + /// + /// assert_eq!( + /// scons( + /// scons(Let, scons(var("x"), scons(False, Nil))), + /// scons(var("x"), Nil) + /// ).type_check(), + /// Ok(Boolean) + /// ); + /// ``` + /// + /// As such it must be that the type of the let-binding s-expression is st. + /// ```rust + /// use myslip::{ + /// r#type::{*, Type::*, TypeError::*, util::*}, + /// sexp::{SExp::*, SLeaf::*, util::*}, + /// }; + /// + /// assert_eq!( + /// scons(Let, scons(var("x"), scons(1, Nil))).type_check(), + /// Ok(arr(vt("T"), vt("T"))) + /// ); + /// ``` + /// ie. the identity function. + /// + /// No more behavior on typing let can be defined, as typing the let-keyword + /// would require the yet untyped variable to be typed. + /// /// Though perhaps the most important task of the type system /// is to increase safety by being able to warn about errors /// before evaluation. Here are some failing examples: @@ -173,6 +210,7 @@ impl SExp { vecof(vt("T")), List(vec![VecType, vecof(vt("T"))]) )), + Atom(Let) => todo!(), SCons(op, l) => { diff --git a/src/type/display.rs b/src/type/display.rs index 03f8f4b..fe54941 100644 --- a/src/type/display.rs +++ b/src/type/display.rs @@ -21,6 +21,7 @@ impl fmt::Display for Type { Boolean => write!(f, "{}", "Bool"), QuoteTy => write!(f, "{}", "Quote"), VecType => write!(f, "{}", "Vector"), + LetType => write!(f, "{}", "Let"), VecOf(ty) => write!(f, "({} ... {})", *ty, *ty), Arrow(a, b) => write!(f, "({} -> {})", a, b), List(types) => write!( diff --git a/src/type/mod.rs b/src/type/mod.rs index 0cbcf83..9e0d9ec 100644 --- a/src/type/mod.rs +++ b/src/type/mod.rs @@ -25,6 +25,8 @@ pub enum Type { VecOf(Box<Type>), VecType, // constructor + LetType, + /// Type for generics /// and also error messages /// with unknown types @@ -102,6 +104,7 @@ impl Type { Boolean => Ok(()), QuoteTy => Ok(()), VecType => Ok(()), + LetType => Ok(()), Arrow(a, b) => b.is_concrete().and_then(|_ok| a.is_concrete()), List(v) => { let mut res = Ok(()); @@ -114,4 +117,5 @@ impl Type { VarType(s) => Err(s.clone()), } } + } diff --git a/src/type/subst.rs b/src/type/subst.rs index 5f6573f..3ee4260 100644 --- a/src/type/subst.rs +++ b/src/type/subst.rs @@ -43,6 +43,7 @@ impl Type { Boolean => Boolean, QuoteTy => QuoteTy, VecType => VecType, + LetType => LetType, } } |