aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sexp/mod.rs12
-rw-r--r--src/sexp/step.rs34
-rw-r--r--src/sexp/subst.rs9
-rw-r--r--src/sexp/util.rs10
-rw-r--r--src/type/check.rs39
-rw-r--r--src/type/display.rs7
-rw-r--r--src/type/mod.rs2
7 files changed, 89 insertions, 24 deletions
diff --git a/src/sexp/mod.rs b/src/sexp/mod.rs
index 4e3c11c..7aa517b 100644
--- a/src/sexp/mod.rs
+++ b/src/sexp/mod.rs
@@ -59,11 +59,19 @@ use SLeaf::*;
impl SExp {
+ /// Quick test that lets are values
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ /// assert!(scons(Let, scons(var("a"), scons(5, Nil))).is_value())
+ /// ```
pub fn is_value(&self) -> bool {
match self {
SCons(a, b) =>
- (**a == Atom(Quote) || **a == Atom(Vector))
- && b.consists_of_values(),
+ SCons(a.clone(), b.clone()).check_let().is_some() ||
+ (
+ (**a == Atom(Quote) || **a == Atom(Vector))
+ && b.consists_of_values()
+ ),
Atom(Var(_)) => false,
Atom(_) => true,
}
diff --git a/src/sexp/step.rs b/src/sexp/step.rs
index e031fca..816582c 100644
--- a/src/sexp/step.rs
+++ b/src/sexp/step.rs
@@ -240,6 +240,8 @@ impl SExp {
/// ```
///
/// **Let-bindings**
+ ///
+ /// Basic operation:
/// ```rust
/// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
///
@@ -261,7 +263,27 @@ impl SExp {
/// ).step(),
/// Ok(scons(
/// scons(Let, scons(var("x"), scons(5, Nil))), scons(
- /// scons(Add, scons(var("x"), scons(1, Nil))), Nil
+ /// scons(Add, scons(var("x"), scons(4, Nil))), Nil
+ /// )
+ /// ))
+ /// );
+ /// ```
+ ///
+ /// Shadowing:
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ ///
+ /// assert_eq!(
+ /// scons(
+ /// scons(Let, scons(var("x"), scons(4, Nil))),
+ /// scons(
+ /// scons(Let, scons(var("x"), scons(5, Nil))),
+ /// scons(scons(Add, scons(var("x"), scons(4, Nil))), Nil)
+ /// )
+ /// ).step(),
+ /// Ok(scons(
+ /// scons(Let, scons(var("x"), scons(5, Nil))), scons(
+ /// scons(Add, scons(var("x"), scons(4, Nil))), Nil
/// )
/// ))
/// );
@@ -278,6 +300,16 @@ impl SExp {
SCons(op, l) if !(*op).is_value() => Ok(scons(op.step()?, l)),
+ // let binds
+ SCons(op, l) if op.clone().check_let().is_some() => match (*op).check_let() {
+ Some((varname, val)) => Ok(match *l {
+ SCons(a, b) if *b == Atom(Nil) => *a,
+ t => t,
+ }.subst(&varname, &val)),
+ None => panic!("unreachable as per match guard arm"),
+ },
+
+
// op value and a1 .. an values, and b0, b1 .. bn not values
// ---------------------------------------------------------
// (op a1 ... an b) -> (op a1 ... an b0.step() b1 .. bn)
diff --git a/src/sexp/subst.rs b/src/sexp/subst.rs
index 87f9b50..4cfa48d 100644
--- a/src/sexp/subst.rs
+++ b/src/sexp/subst.rs
@@ -17,7 +17,14 @@ impl SExp {
/// ```
pub fn subst(self, name: &str, value: &SExp) -> SExp {
match self {
- SCons(a, b) => scons((*a).subst(name, value), (*b).subst(name, value)),
+ SCons(a, b) => {
+ if let Some((varname, _)) = a.clone().check_let() {
+ if &varname == name {
+ return SCons(a, b);
+ }
+ }
+ scons((*a).subst(name, value), (*b).subst(name, value))
+ },
Atom(Var(x)) if x == name => value.clone(),
t => t,
}
diff --git a/src/sexp/util.rs b/src/sexp/util.rs
index b3edf19..a28aaad 100644
--- a/src/sexp/util.rs
+++ b/src/sexp/util.rs
@@ -76,4 +76,14 @@ impl SExp {
},
}
}
+
+ pub fn check_let(self) -> Option<(String, SExp)> {
+ match &(self.parts())[..] {
+ [l, n, v] if *l == Atom(Let) => match (n.clone(), v.clone()) {
+ (Atom(Var(name)), val) => Some((name, val)),
+ _ => None
+ },
+ _ => None
+ }
+ }
}
diff --git a/src/type/check.rs b/src/type/check.rs
index d0ce807..e536ce7 100644
--- a/src/type/check.rs
+++ b/src/type/check.rs
@@ -1,6 +1,6 @@
use crate::r#type::{Type, TypeError, Type::*, TypeError::*, util::*};
-use crate::sexp::{SExp, SExp::*, SLeaf::*};
+use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*};
use std::collections::HashMap;
impl SExp {
@@ -101,23 +101,6 @@ impl SExp {
/// );
/// ```
///
- /// 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:
@@ -184,7 +167,7 @@ impl SExp {
}
- fn infer_type(&self, ctx: HashMap<String, Type>) -> Result<Type, TypeError> {
+ fn infer_type(&self, mut ctx: HashMap<String, Type>) -> Result<Type, TypeError> {
match self {
@@ -210,13 +193,29 @@ impl SExp {
vecof(vt("T")),
List(vec![VecType, vecof(vt("T"))])
)),
- Atom(Let) => todo!(),
+ Atom(Let) => Ok(LetType),
SCons(op, l) => {
+
+ // Let-expressions
+ if let Some((varname, val)) = (*op).clone().check_let() {
+ let valtype = val.infer_type(ctx.clone())?;
+ ctx.insert(varname, valtype);
+ return match (**l).clone() {
+ SCons(exp, nil) if *nil == Atom(Nil) => *exp,
+ t => t
+ }.infer_type(ctx);
+ }
+ if **op == Atom(Let) {
+ return Err(LetAsOperator(scons(op.clone(), l.clone())));
+ }
+
+ // Normal operation
let opertype = (*op).infer_type(ctx.clone())?;
let argstype = (*l).infer_list_type(ctx)?;
+
let argstype = if opertype == arr(
vecof(vt("T")),
List(vec![VecType, vecof(vt("T"))])
diff --git a/src/type/display.rs b/src/type/display.rs
index fe54941..4a9b54a 100644
--- a/src/type/display.rs
+++ b/src/type/display.rs
@@ -103,6 +103,13 @@ impl fmt::Display for TypeError {
argtype, generictype
)
},
+ LetAsOperator(letexp) => {
+ write!(
+ f,
+ "let used as operator instead of generating an operator: maybe try '({} ...)' instead",
+ letexp
+ )
+ },
OtherError => write!(f, "uncategorized error"),
}
}
diff --git a/src/type/mod.rs b/src/type/mod.rs
index 9e0d9ec..afb5a0b 100644
--- a/src/type/mod.rs
+++ b/src/type/mod.rs
@@ -59,6 +59,8 @@ pub enum TypeError {
generictype: Type,
},
+ LetAsOperator(SExp),
+
OtherError
}