diff options
-rw-r--r-- | src/parse/parsetree.rs | 6 | ||||
-rw-r--r-- | src/sexp/display.rs | 2 | ||||
-rw-r--r-- | src/sexp/mod.rs | 19 | ||||
-rw-r--r-- | src/sexp/step.rs | 24 | ||||
-rw-r--r-- | src/type/check.rs | 22 | ||||
-rw-r--r-- | src/type/display.rs | 19 | ||||
-rw-r--r-- | src/type/mod.rs | 3 | ||||
-rw-r--r-- | src/type/subst.rs | 1 |
8 files changed, 71 insertions, 25 deletions
diff --git a/src/parse/parsetree.rs b/src/parse/parsetree.rs index 28e5044..6dd4e01 100644 --- a/src/parse/parsetree.rs +++ b/src/parse/parsetree.rs @@ -10,6 +10,7 @@ use nom::{ }; use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*}; +use crate::r#type::{Type::*}; #[derive(Debug,PartialEq,Clone)] @@ -113,8 +114,11 @@ 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 == "print" => Ok(Atom(Print)), + Some(Sym(s)) if s == "print" => Ok(Atom(Print)), Some(Sym(s)) if s == "let" => Ok(Atom(Let)), + Some(Sym(s)) if s == "->" => Ok(Atom(Arr)), + Some(Sym(s)) if s == "int" => Ok(Atom(Ty(Integer))), + Some(Sym(s)) if s == "bool" => Ok(Atom(Ty(Boolean))), 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 a978f61..5d78e93 100644 --- a/src/sexp/display.rs +++ b/src/sexp/display.rs @@ -29,6 +29,8 @@ impl fmt::Display for SLeaf { Vector => "vector".to_string(), Print => "print".to_string(), Let => "let".to_string(), + Ty(t) => t.to_string(), + Arr => "->".to_string(), Nil => "()".to_string(), }) } diff --git a/src/sexp/mod.rs b/src/sexp/mod.rs index 296553f..11c185f 100644 --- a/src/sexp/mod.rs +++ b/src/sexp/mod.rs @@ -4,6 +4,8 @@ pub mod util; pub mod subst; pub mod display; +use crate::r#type::Type; + /// A leaf node for S-Expressions. /// /// May represent built-in operators, @@ -33,6 +35,9 @@ pub enum SLeaf { Let, + Ty(Type), + Arr, + Print, Int(i32), @@ -58,6 +63,7 @@ pub enum SExp { use SExp::*; use SLeaf::*; +use crate::sexp::util::*; impl SExp { @@ -71,7 +77,7 @@ impl SExp { SCons(a, b) => SCons(a.clone(), b.clone()).check_let().is_some() || ( - (**a == Atom(Quote) || **a == Atom(Vector)) + (**a == Atom(Quote) || **a == Atom(Vector) || (**a).is_type_lit()) && b.consists_of_values() ), Atom(Var(_)) => false, @@ -85,4 +91,15 @@ impl SExp { _ => false } } + + pub fn is_type_lit(&self) -> bool { + match self { + Atom(Ty(_)) => true, + SCons(a, b) => scons(a.clone(), b.clone()) + .parts() + .into_iter() + .all(|x| x.is_type_lit()), + _ => false + } + } } diff --git a/src/sexp/step.rs b/src/sexp/step.rs index 11df257..c26dce9 100644 --- a/src/sexp/step.rs +++ b/src/sexp/step.rs @@ -1,5 +1,6 @@ use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*}; +use crate::r#type::{Type::*, util::*}; impl SExp { @@ -521,6 +522,29 @@ impl SExp { } }, + // Type arrow + SCons(op, l) if *op == Atom(Arr) => { + let ls = l.parts(); + let t1 = ls.get(0).ok_or("wrong list length".to_string())?; + let t2 = ls.get(1).ok_or("wrong list length".to_string())?; + match (t1.clone().multistep()?, t2.clone().multistep()?) { + (Atom(Ty(a)), Atom(Ty(b))) => Ok(Atom(Ty(arr(a.clone(), b.clone())))), + _ => Err("invalid args".to_string()), + } + }, + + // Type list + SCons(op, l) if (*op).is_type_lit() => { + let mut res = vec![]; + for exp in std::iter::once(*op).chain(l.parts()) { + res.push(match exp.multistep()? { + Atom(Ty(t)) => Ok(t), + e => Err(format!("not a type: {e}")), + }?); + } + Ok(Atom(Ty(List(res)))) + }, + // Print SCons(op, l) if *op == Atom(Print) => { println!("{}", *l); diff --git a/src/type/check.rs b/src/type/check.rs index 874db58..24c255d 100644 --- a/src/type/check.rs +++ b/src/type/check.rs @@ -67,8 +67,6 @@ impl SExp { /// sexp::{SExp::*, SLeaf::*, util::*}, /// }; /// - /// assert_eq!(Atom(Add).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer))); - /// 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))); @@ -112,15 +110,6 @@ impl SExp { /// sexp::{SExp::*, SLeaf::*, util::*}, /// }; /// - /// let err = scons(Mul, scons(1, Nil)).type_check(); - /// match err { - /// Err(InvalidArgList { .. }) => (), - /// _ => panic!( - /// "passing only 1 argument to '*' should result in InvalidArgList error, found '{:?}'", - /// err - /// ), - /// }; - /// /// match scons(Sub, scons(1, scons(2, scons(3, Nil)))).type_check() { /// Err(InvalidArgList { .. }) => (), /// _ => panic!( @@ -178,8 +167,8 @@ impl SExp { Atom(Var(name)) => ctx.get(name) .ok_or(UndefinedVariable(name.to_string())) .cloned(), - Atom(Add) => Ok(arr(List(vec![Integer, Integer]), Integer)), // TODO varlen - Atom(Mul) => Ok(arr(List(vec![Integer, Integer]), Integer)), // TODO varlen + Atom(Add) => Ok(arr(vecof(Integer), Integer)), + Atom(Mul) => Ok(arr(vecof(Integer), Integer)), Atom(Sub) => Ok(arr(List(vec![Integer, Integer]), Integer)), Atom(Div) => Ok(arr(List(vec![Integer, Integer]), Integer)), Atom(Eq | Neq | Lt | Gt | Le | Ge) => @@ -197,7 +186,8 @@ impl SExp { )), Atom(Let) => Ok(LetType), Atom(Print) => Ok(arr(vt("_"), List(vec![]))), - + Atom(Ty(_)) => Ok(TypeLit), + Atom(Arr) => Ok(arr(List(vec![TypeLit, TypeLit]), TypeLit)), SCons(op, l) => { @@ -218,6 +208,10 @@ impl SExp { let opertype = (*op).infer_type(ctx.clone())?; let argstype = (*l).infer_list_type(ctx)?; + if opertype == TypeLit && argstype.aka(&vecof(TypeLit)) { + return Ok(TypeLit); + } + let conv_args = match (opertype.clone(), argstype.clone()) { (Arrow(from, _), a) => match a.clone().into_type(&*from) { Ok(s) => Ok(s), diff --git a/src/type/display.rs b/src/type/display.rs index 72e3693..cd60673 100644 --- a/src/type/display.rs +++ b/src/type/display.rs @@ -10,19 +10,20 @@ impl fmt::Display for Type { /// Examples: /// ```rust /// use myslip::r#type::{Type::*, util::*}; - /// assert_eq!(Integer.to_string(), "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()); + /// assert_eq!(Integer.to_string(), "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 { - Integer => write!(f, "{}", "Int"), - Boolean => write!(f, "{}", "Bool"), + Integer => write!(f, "{}", "int"), + Boolean => write!(f, "{}", "bool"), QuoteTy => write!(f, "{}", "Quote"), VecType => write!(f, "{}", "Vector"), LetType => write!(f, "{}", "Let"), NilType => write!(f, "()"), + TypeLit => write!(f, "[type literal]"), VecOf(ty) => write!(f, "({} ... {})", *ty, *ty), Arrow(a, b) => write!(f, "({} -> {})", a, b), List(types) => write!( @@ -57,7 +58,7 @@ impl fmt::Display for TypeError { /// expected: arr(VarType("?".to_string()), VarType("?".to_string())), /// found: Integer /// }.to_string(), - /// "invalid operator: '1'\nexpected: '(? -> ?)'\nfound: 'Int'".to_string() + /// "invalid operator: '1'\nexpected: '(? -> ?)'\nfound: 'int'".to_string() /// ); /// assert_eq!( /// InvalidArgList { @@ -65,7 +66,7 @@ impl fmt::Display for TypeError { /// expected: List(vec![Integer, Integer]), /// found: List(vec![Integer, Integer, Integer]), /// }.to_string(), - /// "invalid argument list: '(1 2 3)'\nexpected: '(Int Int)'\nfound: '(Int Int Int)'".to_string() + /// "invalid argument list: '(1 2 3)'\nexpected: '(int int)'\nfound: '(int int int)'".to_string() /// ); /// assert_eq!( /// UnboundGeneric(String::from("?")).to_string(), @@ -76,7 +77,7 @@ impl fmt::Display for TypeError { /// argtype: Integer, /// generictype: arr(VarType("T".to_string()), Integer) /// }.to_string(), - /// "incompatible argument type 'Int' and generic operator type '(T -> Int)'".to_string() + /// "incompatible argument type 'int' and generic operator type '(T -> int)'".to_string() /// ); /// ``` fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/type/mod.rs b/src/type/mod.rs index 9c2f89c..c138bba 100644 --- a/src/type/mod.rs +++ b/src/type/mod.rs @@ -17,6 +17,8 @@ pub enum Type { Boolean, + TypeLit, + QuoteTy, //constructor Arrow(Box<Type>, Box<Type>), @@ -111,6 +113,7 @@ impl Type { VecType => Ok(()), LetType => Ok(()), NilType => Ok(()), + TypeLit => Ok(()), 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 ab9d38a..18c9926 100644 --- a/src/type/subst.rs +++ b/src/type/subst.rs @@ -45,6 +45,7 @@ impl Type { VecType => VecType, LetType => LetType, NilType => NilType, + TypeLit => TypeLit, } } |