aboutsummaryrefslogtreecommitdiff
path: root/src/type
diff options
context:
space:
mode:
Diffstat (limited to 'src/type')
-rw-r--r--src/type/check.rs39
-rw-r--r--src/type/display.rs7
-rw-r--r--src/type/mod.rs2
3 files changed, 28 insertions, 20 deletions
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
}