diff options
author | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-14 14:02:27 +0300 |
---|---|---|
committer | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-14 14:02:27 +0300 |
commit | 907bd54d19f6bf14a130a136df6f37cc5d256468 (patch) | |
tree | 28e282e040d05f107833a48fa27e8498746dfbda | |
parent | 52263c39dd6006cce5fc938ec60751ab45b73f8b (diff) | |
download | myslip-907bd54d19f6bf14a130a136df6f37cc5d256468.tar.gz myslip-907bd54d19f6bf14a130a136df6f37cc5d256468.zip |
feat: parsing of new types (T, (int ...), (int bool)) etc. also fixed bug in into_type (it didn't handle lists recursively)
-rw-r--r-- | src/parse/parsetree.rs | 88 | ||||
-rw-r--r-- | src/sexp/case.rs | 2 | ||||
-rw-r--r-- | src/sexp/step.rs | 3 | ||||
-rw-r--r-- | src/type/check.rs | 4 | ||||
-rw-r--r-- | src/type/conversion.rs | 9 |
5 files changed, 92 insertions, 14 deletions
diff --git a/src/parse/parsetree.rs b/src/parse/parsetree.rs index 7f9d9dc..701496b 100644 --- a/src/parse/parsetree.rs +++ b/src/parse/parsetree.rs @@ -4,13 +4,13 @@ use nom::{ IResult, Parser, branch::alt, - multi::many0, + multi::{many0, separated_list1}, bytes::complete::{tag, take_while1}, - character::complete::multispace1, + character::{complete::{multispace0, multispace1}}, }; use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*}; -use crate::r#type::{Type::*}; +use crate::r#type::{Type::*, Type, util::*}; #[derive(Debug,PartialEq,Clone)] @@ -19,6 +19,7 @@ pub enum Token { ParClose, Num(i32), Sym(String), + Type(Type), Whitespace(String), } @@ -31,6 +32,7 @@ impl Display for Token { ParClose => ")".to_string(), Num(x) => x.to_string(), Sym(s) => s.to_string(), + Type(ty) => ty.to_string(), Whitespace(s) => s.to_string(), }) } @@ -40,12 +42,15 @@ use Token::*; use crate::parse::util::*; fn parse_token(s: &str) -> IResult<&str, Token> { + if let Ok(t) = parse_type(s) { + return Ok((t.0, Token::Type(t.1))); + } alt(( - tag("(").map(|_| ParOpen), - tag(")").map(|_| ParClose), - multispace1.map(whitespace), - nom::character::complete::i32.map(Num), - take_while1(|c| !(" \n\t()".contains(c))).map(sym), + tag("(").map(|_| ParOpen), + tag(")").map(|_| ParClose), + multispace1.map(whitespace), + nom::character::complete::i32.map(Num), + take_while1(|c| !(" \n\t()".contains(c))).map(sym), )).parse(s) } @@ -135,6 +140,7 @@ fn tokens_to_ast_inner( Ok(subexp.1) }, Some(Whitespace(_)) => Err("unexpected whitespace".to_string()), + Some(Type(aty)) => Ok(Atom(Ty(aty))), None => Err("unexpected end of input".to_string()), }?); current_token = input.pop_front(); @@ -168,12 +174,76 @@ pub fn parse_to_ast(s: &str) -> Result<SExp, String> { tokens_to_ast(tokens.into()) } +fn parse_type(s: &str) -> IResult<&str, Type> { + + let arrp = ( + tag("("), multispace0, + parse_type, multispace1, + tag("->"), multispace1, + parse_type, multispace0, + tag(")") + ).map(|tup| arr(tup.2, tup.6)); + + let vecp = ( + tag("("), multispace0, + parse_type, multispace1, + tag("..."), multispace0, + tag(")") + ).map(|tup| vecof(tup.2)); + + let listp = ( + tag("("), multispace0, + separated_list1(multispace1, parse_type), + multispace0, tag(")") + ).map(|v| List(v.2)); + + let absp = take_while1(|c| "ABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(c)) + .map(|s: &str| VarType(s.to_string())); + + alt(( + tag("Int").map(|_| Integer), + tag("Bool").map(|_| Boolean), + tag("Nil").map(|_| NilType), + arrp, + vecp, + listp, + absp + )).parse(s) +} + #[cfg(test)] mod private_parsing_tests { use super::{*, parse_token}; #[test] + fn test_parse_type() { + assert_eq!(parse_type("Int"), Ok(("", Integer))); + assert_eq!(parse_type("Bool"), Ok(("", Boolean))); + assert_eq!(parse_type("Nil"), Ok(("", NilType))); + assert_eq!(parse_type("(Int -> Bool)"), Ok(("", arr(Integer, Boolean)))); + assert_eq!( + parse_type("((Int -> Int) -> (Bool -> Bool))"), + Ok(("", arr(arr(Integer, Integer), arr(Boolean, Boolean)))) + ); + assert_eq!(parse_type("(Int ...)"), Ok(("", vecof(Integer)))); + assert_eq!(parse_type("(Bool ...)"), Ok(("", vecof(Boolean)))); + assert_eq!( + parse_type("((Int -> Bool) ...)"), + Ok(("", vecof(arr(Integer, Boolean)))) + ); + assert_eq!( + parse_type("(Int Bool Bool Int)"), + Ok(("", List(vec![Integer, Boolean, Boolean, Integer]))) + ); + assert_eq!( + parse_type("(Int Bool (Bool -> Int) Int)"), + Ok(("", List(vec![Integer, Boolean, arr(Boolean, Integer), Integer]))) + ); + assert_eq!(parse_type("T"), Ok(("", VarType("T".to_string())))); + } + + #[test] fn test_parse_token() { assert_eq!(parse_token("()"), Ok((")", ParOpen))); assert_eq!(parse_token(")"), Ok(("", ParClose))); @@ -183,7 +253,7 @@ mod private_parsing_tests { assert_eq!(parse_token("1 23"), Ok((" 23", Num(1)))); assert_eq!(parse_token("23"), Ok(("", Num(23)))); - assert_eq!(parse_token("Nil a"), Ok((" a", sym("Nil")))); + assert_eq!(parse_token("il a"), Ok((" a", sym("il")))); assert_eq!(parse_token("a"), Ok(("", sym("a")))); assert!(parse_token("").is_err()) diff --git a/src/sexp/case.rs b/src/sexp/case.rs index d78f7ad..40310e4 100644 --- a/src/sexp/case.rs +++ b/src/sexp/case.rs @@ -1,5 +1,5 @@ -use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*}; +use crate::sexp::{SExp, SExp::*, SLeaf::*}; impl SExp { /** diff --git a/src/sexp/step.rs b/src/sexp/step.rs index bae47a5..d35c8af 100644 --- a/src/sexp/step.rs +++ b/src/sexp/step.rs @@ -368,7 +368,6 @@ impl SExp { let (scrutinee, patarms) = scons(op, l).check_case().unwrap(); if !scrutinee.is_value() { return Ok(SExp::back_to_case(scrutinee.step()?, patarms)); - // return scons(Case, scons(scrutinee.step()?)) } let scrutinee = match scrutinee { @@ -646,7 +645,7 @@ impl SExp { }, // Nil in list - SCons(op, l) if *op == Atom(Nil) => { + SCons(op, _) if *op == Atom(Nil) => { Ok(scons(Vector, Nil)) }, diff --git a/src/type/check.rs b/src/type/check.rs index 02b629c..69e9141 100644 --- a/src/type/check.rs +++ b/src/type/check.rs @@ -218,10 +218,10 @@ impl SExp { pub fn type_check(&self) -> Result<Type, TypeError> { let res = self.infer_type(HashMap::new()); match res { - Ok(res) => {println!("maybe unbound: {}", res); match res.is_concrete() { + Ok(res) => match res.is_concrete() { Ok(()) => Ok(res), Err(name) => Err(UnboundGeneric(name)), - }}, + }, e => e, } } diff --git a/src/type/conversion.rs b/src/type/conversion.rs index 5d29ba0..baeab90 100644 --- a/src/type/conversion.rs +++ b/src/type/conversion.rs @@ -94,6 +94,7 @@ impl Type { /// List(vec![Integer, Boolean]).into_type(&vecof(vt("T"))), /// Ok(vecof(vt("T"))) /// ); + /// assert_eq!(List(vec![Boolean, Integer, Integer]).into_type(&List(vec![Boolean, vt("T"), vt("T")])), Ok(List(vec![Boolean, Integer, Integer]))) /// ``` /// /// Though the conversion from (a) to a is also convenient: @@ -115,6 +116,14 @@ impl Type { (List(x), b) if x.len() == 1 && &x[0] == b => Ok(x[0].clone()), + (List(v1), List(v2)) if v1.len() == v2.len() => { + let mut res = vec![]; + for (t1, t2) in v1.into_iter().zip(v2) { + res.push(t1.clone().into_type(&t2)?); + } + Ok(List(res)) + } + (List(v), VecOf(b)) => match v.get(0) { Some(first) => { let cand = v.into_iter() |