aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kronqvist <joel.kronqvist@iki.fi>2025-08-14 14:02:27 +0300
committerJoel Kronqvist <joel.kronqvist@iki.fi>2025-08-14 14:02:27 +0300
commit907bd54d19f6bf14a130a136df6f37cc5d256468 (patch)
tree28e282e040d05f107833a48fa27e8498746dfbda
parent52263c39dd6006cce5fc938ec60751ab45b73f8b (diff)
downloadmyslip-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.rs88
-rw-r--r--src/sexp/case.rs2
-rw-r--r--src/sexp/step.rs3
-rw-r--r--src/type/check.rs4
-rw-r--r--src/type/conversion.rs9
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()