diff options
author | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-05 18:07:50 +0300 |
---|---|---|
committer | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-05 18:07:50 +0300 |
commit | d64165e9e6af92bfe350e5d2cc46545b28dbb5c0 (patch) | |
tree | d7a6abb03a83ad08194b94db7b82a6c5f32b4819 | |
parent | 1e712e91edea0735c5eb440af26ac6d4454e70a9 (diff) | |
download | myslip-d64165e9e6af92bfe350e5d2cc46545b28dbb5c0.tar.gz myslip-d64165e9e6af92bfe350e5d2cc46545b28dbb5c0.zip |
Added vectors and tests for their evaluation and typing
-rw-r--r-- | src/parse/parsetree.rs | 39 | ||||
-rw-r--r-- | src/sexp/display.rs | 1 | ||||
-rw-r--r-- | src/sexp/mod.rs | 2 | ||||
-rw-r--r-- | src/sexp/step.rs | 17 | ||||
-rw-r--r-- | src/type/check.rs | 17 | ||||
-rw-r--r-- | src/type/display.rs | 1 | ||||
-rw-r--r-- | src/type/mod.rs | 6 | ||||
-rw-r--r-- | src/type/subst.rs | 2 | ||||
-rw-r--r-- | src/type/util.rs | 3 |
9 files changed, 69 insertions, 19 deletions
diff --git a/src/parse/parsetree.rs b/src/parse/parsetree.rs index 3cdc6fe..13d73ea 100644 --- a/src/parse/parsetree.rs +++ b/src/parse/parsetree.rs @@ -94,25 +94,26 @@ fn tokens_to_ast_inner( loop { elements.push(match current_token { - Some(Num(x)) => Ok(Atom(Int(x))), - Some(Sym(s)) if s == "+" => Ok(Atom(Add)), - 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(Num(x)) => Ok(Atom(Int(x))), + Some(Sym(s)) if s == "+" => Ok(Atom(Add)), + 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)) if s == "vector" => Ok(Atom(Vector)), + Some(Sym(s)) => Ok(Atom(Var(s))), Some(ParClose) => break, Some(ParOpen) => { let subexp = tokens_to_ast_inner( diff --git a/src/sexp/display.rs b/src/sexp/display.rs index 96ce435..57d1b50 100644 --- a/src/sexp/display.rs +++ b/src/sexp/display.rs @@ -26,6 +26,7 @@ impl fmt::Display for SLeaf { Int(x) => x.to_string(), Var(s) => s.to_string(), Quote => "quote".to_string(), + Vector => "vector".to_string(), Nil => "()".to_string(), }) } diff --git a/src/sexp/mod.rs b/src/sexp/mod.rs index 60dd3b0..3f17b79 100644 --- a/src/sexp/mod.rs +++ b/src/sexp/mod.rs @@ -27,7 +27,9 @@ pub enum SLeaf { Or, Not, Xor, + Quote, + Vector, Int(i32), True, diff --git a/src/sexp/step.rs b/src/sexp/step.rs index d66b1bd..535b183 100644 --- a/src/sexp/step.rs +++ b/src/sexp/step.rs @@ -220,6 +220,23 @@ impl SExp { /// Ok(scons(Quote, scons(1, scons(2, Nil)))) /// ); /// ``` + /// + /// **Vectors** + /// + /// The same as quotes functionally, but they require + /// the elements to be of the same type. + /// ```rust + /// use myslip::sexp::{SExp::*, SLeaf::*, util::*}; + /// assert_eq!( + /// scons(Vector, scons(1, scons(2, Nil))).step(), + /// Ok(scons(Vector, scons(1, scons(2, Nil)))) + /// ); + /// assert_eq!( + /// scons(Vector, scons( + /// scons(Sub, scons(2, scons(1, Nil))), + /// scons(2, Nil))).step(), + /// Ok(scons(Vector, scons(1, scons(2, Nil)))) + /// ); pub fn step(self) -> Result<Self, String> { match self { diff --git a/src/type/check.rs b/src/type/check.rs index c3bdcb4..10ef8b4 100644 --- a/src/type/check.rs +++ b/src/type/check.rs @@ -44,6 +44,20 @@ impl SExp { /// ); /// ``` /// + /// Vectors are kind of special... + /// ```rust + /// use myslip::{ + /// r#type::{*, Type::*, TypeError::*, util::*}, + /// sexp::{SExp::*, SLeaf::*, util::*}, + /// }; + /// + /// assert_eq!( + /// scons(Vector, scons(1, scons(3, Nil))).type_check(), + /// Ok(vecof(Integer)) + /// ); + /// ``` + /// ...so please don't ask what their type is. + /// /// Some common operators get arrow types: /// ```rust /// use myslip::{ @@ -109,6 +123,8 @@ impl SExp { /// 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()); + /// + /// assert!(scons(Vector, scons(1, scons(True, Nil))).type_check().is_err()); /// ``` /// /// Also, free variables should result in an error @@ -153,6 +169,7 @@ impl SExp { vt("T"), List(vec![QuoteTy, vt("T")]) )), + Atom(Vector) => todo!(), SCons(op, l) => { let opertype = (*op).infer_type(ctx.clone())?; diff --git a/src/type/display.rs b/src/type/display.rs index 8eb0647..6c3177a 100644 --- a/src/type/display.rs +++ b/src/type/display.rs @@ -20,6 +20,7 @@ impl fmt::Display for Type { Integer => write!(f, "{}", "Int"), Boolean => write!(f, "{}", "Bool"), QuoteTy => write!(f, "{}", "Quote"), + VecOf(ty) => write!(f, "({} ... {})", *ty, *ty), Arrow(a, b) => write!(f, "({} -> {})", a, b), List(types) => write!( f, diff --git a/src/type/mod.rs b/src/type/mod.rs index e29e069..01aed40 100644 --- a/src/type/mod.rs +++ b/src/type/mod.rs @@ -22,6 +22,8 @@ pub enum Type { List(Vec<Type>), + VecOf(Box<Type>), + /// Type for generics /// and also error messages /// with unknown types @@ -89,6 +91,9 @@ impl Type { /// .is_concrete(), /// Err("a".to_string()) /// ); + /// + /// assert_eq!(vecof(vt("a")).is_concrete(), Err("a".to_string())); + /// assert_eq!(vecof(Integer).is_concrete(), Ok(())); /// ``` pub fn is_concrete(&self) -> Result<(), String> { match self { @@ -103,6 +108,7 @@ impl Type { } res }, + VecOf(ty) => (*ty).is_concrete(), VarType(s) => Err(s.clone()), } } diff --git a/src/type/subst.rs b/src/type/subst.rs index d63f71b..12a9f15 100644 --- a/src/type/subst.rs +++ b/src/type/subst.rs @@ -33,6 +33,8 @@ impl Type { .collect() ), + VecOf(ty) => vecof((*ty).subst(name, value)), + VarType(s) if s == name => value.clone(), VarType(s) => VarType(s), diff --git a/src/type/util.rs b/src/type/util.rs index 9be8c6e..85e64f1 100644 --- a/src/type/util.rs +++ b/src/type/util.rs @@ -9,3 +9,6 @@ pub fn vt(name: &str) -> Type { VarType(name.to_string()) } +pub fn vecof(ty: impl Into<Box<Type>>) -> Type { + VecOf(ty.into()) +} |