diff --git a/Cargo.toml b/Cargo.toml index 0a57fd3..429541c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,8 @@ edition = "2018" name = "laddertypes" version = "0.1.0" +[dependencies] +tiny-ansi = { version = "0.1.0", optional = true } + +[features] +pretty = ["dep:tiny-ansi"] diff --git a/src/dict.rs b/src/dict.rs index 83b63ee..a28573c 100644 --- a/src/dict.rs +++ b/src/dict.rs @@ -1,8 +1,11 @@ -use crate::bimap::Bimap; +use crate::{ + bimap::Bimap, + sugar::SUGARID_LIMIT +}; //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ -#[derive(Eq, PartialEq, Hash, Clone, Debug)] +#[derive(Eq, PartialEq, Hash, Clone, Copy, Debug)] pub enum TypeID { Fun(u64), Var(u64) @@ -20,11 +23,19 @@ pub struct TypeDict { impl TypeDict { pub fn new() -> Self { - TypeDict { + let mut dict = TypeDict { typenames: Bimap::new(), type_lit_counter: 0, type_var_counter: 0, - } + }; + + dict.add_typename("Seq".into()); + dict.add_typename("Enum".into()); + dict.add_typename("Struct".into()); + + assert_eq!( dict.type_lit_counter, SUGARID_LIMIT ); + + dict } pub fn add_varname(&mut self, tn: String) -> TypeID { @@ -54,6 +65,10 @@ impl TypeDict { pub fn get_typeid(&self, tn: &String) -> Option<TypeID> { self.typenames.mλ.get(tn).cloned() } + + pub fn get_varname(&self, var_id: u64) -> Option<String> { + self.typenames.my.get(&TypeID::Var(var_id)).cloned() + } } //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> diff --git a/src/lexer.rs b/src/lexer.rs index 8c56a0d..62b8efe 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -6,9 +6,9 @@ pub enum LadderTypeToken { Symbol( String ), Char( char ), Num( i64 ), - Open, - Close, - Ladder, + Open, OpenSeq, OpenStruct, + Close, CloseSeq, CloseStruct, + Ladder, Enum } #[derive(PartialEq, Eq, Clone, Debug)] @@ -75,6 +75,11 @@ where It: Iterator<Item = char> match c { '<' => { self.chars.next(); return Some(Ok(LadderTypeToken::Open)); }, '>' => { self.chars.next(); return Some(Ok(LadderTypeToken::Close)); }, + '[' => { self.chars.next(); return Some(Ok(LadderTypeToken::OpenSeq)); }, + ']' => { self.chars.next(); return Some(Ok(LadderTypeToken::CloseSeq)); }, + '{' => { self.chars.next(); return Some(Ok(LadderTypeToken::OpenStruct)); }, + '}' => { self.chars.next(); return Some(Ok(LadderTypeToken::CloseStruct)); }, + '|' => { self.chars.next(); return Some(Ok(LadderTypeToken::Enum)); }, '~' => { self.chars.next(); return Some(Ok(LadderTypeToken::Ladder)); }, '\'' => { self.chars.next(); state = LexerState::Char(None); }, c => { diff --git a/src/lib.rs b/src/lib.rs index 1a270cc..a23069f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,9 @@ pub mod term; pub mod lexer; pub mod parser; pub mod unparser; +pub mod sugar; pub mod curry; +pub mod sugar; pub mod lnf; pub mod subtype; pub mod unification; @@ -13,9 +15,12 @@ pub mod unification; #[cfg(test)] mod test; +#[cfg(feature = "pretty")] +mod pretty; + pub use { dict::*, term::*, - unification::* + sugar::*, + unification::*, }; - diff --git a/src/parser.rs b/src/parser.rs index 85ff9b4..87ed5c1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,6 +3,7 @@ use { crate::{ dict::*, term::*, + sugar::*, lexer::* } }; @@ -21,7 +22,7 @@ pub enum ParseError { //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ impl TypeDict { - pub fn parse(&mut self, s: &str) -> Result<TypeTerm, ParseError> { + pub fn parse(&mut self, s: &str) -> Result<SugaredTypeTerm, ParseError> { let mut tokens = LadderTypeLexer::from(s.chars()).peekable(); match self.parse_ladder(&mut tokens) { @@ -36,7 +37,7 @@ impl TypeDict { } } - fn parse_app<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<TypeTerm, ParseError> + fn parse_app<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<SugaredTypeTerm, ParseError> where It: Iterator<Item = char> { let mut args = Vec::new(); @@ -44,7 +45,11 @@ impl TypeDict { match tok { Ok(LadderTypeToken::Close) => { tokens.next(); - return Ok(TypeTerm::App(args)); + return Ok(SugaredTypeTerm::App(args)); + } + Ok(LadderTypeToken::CloseSeq) | + Ok(LadderTypeToken::CloseStruct) => { + return Err(ParseError::UnexpectedToken) } _ => { match self.parse_ladder(tokens) { @@ -57,29 +62,59 @@ impl TypeDict { Err(ParseError::UnexpectedEnd) } - fn parse_rung<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<TypeTerm, ParseError> + fn parse_seq<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<SugaredTypeTerm, ParseError> + where It: Iterator<Item = char> + { + let mut pattern = Vec::new(); + while let Some(tok) = tokens.peek() { + match tok { + Ok(LadderTypeToken::CloseSeq) => { + tokens.next(); + return Ok(SugaredTypeTerm::Seq(pattern)); + } + Ok(LadderTypeToken::Close) | + Ok(LadderTypeToken::CloseStruct) => { + return Err(ParseError::UnexpectedToken) + } + _ => { + match self.parse_ladder(tokens) { + Ok(a) => { pattern.push(a); } + Err(err) => { return Err(err); } + } + } + } + } + Err(ParseError::UnexpectedEnd) + } + + fn parse_rung<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<SugaredTypeTerm, ParseError> where It: Iterator<Item = char> { match tokens.next() { Some(Ok(LadderTypeToken::Open)) => self.parse_app(tokens), + Some(Ok(LadderTypeToken::OpenSeq)) => self.parse_app(tokens), + Some(Ok(LadderTypeToken::OpenStruct)) => self.parse_app(tokens), + Some(Ok(LadderTypeToken::Enum)) => self.parse_app(tokens), Some(Ok(LadderTypeToken::Close)) => Err(ParseError::UnexpectedClose), + Some(Ok(LadderTypeToken::CloseStruct)) => Err(ParseError::UnexpectedToken), + Some(Ok(LadderTypeToken::CloseSeq)) => Err(ParseError::UnexpectedToken), Some(Ok(LadderTypeToken::Ladder)) => Err(ParseError::UnexpectedLadder), Some(Ok(LadderTypeToken::Symbol(s))) => - Ok(TypeTerm::TypeID( + Ok(SugaredTypeTerm::TypeID( if let Some(tyid) = self.get_typeid(&s) { tyid } else { self.add_typename(s) } )), - Some(Ok(LadderTypeToken::Char(c))) => Ok(TypeTerm::Char(c)), - Some(Ok(LadderTypeToken::Num(n))) => Ok(TypeTerm::Num(n)), + Some(Ok(LadderTypeToken::Char(c))) => Ok(SugaredTypeTerm::Char(c)), + Some(Ok(LadderTypeToken::Num(n))) => Ok(SugaredTypeTerm::Num(n)), Some(Err(err)) => Err(ParseError::LexError(err)), None => Err(ParseError::UnexpectedEnd) } } - fn parse_ladder<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<TypeTerm, ParseError> + fn parse_ladder<It>(&mut self, tokens: &mut Peekable<LadderTypeLexer<It>>) -> Result<SugaredTypeTerm, ParseError> where It: Iterator<Item = char> { let mut rungs = Vec::new(); @@ -115,7 +150,7 @@ impl TypeDict { match rungs.len() { 0 => Err(ParseError::UnexpectedEnd), 1 => Ok(rungs[0].clone()), - _ => Ok(TypeTerm::Ladder(rungs)), + _ => Ok(SugaredTypeTerm::Ladder(rungs)), } } } diff --git a/src/pretty.rs b/src/pretty.rs new file mode 100644 index 0000000..1a4aa60 --- /dev/null +++ b/src/pretty.rs @@ -0,0 +1,148 @@ +use { + crate::TypeDict, + crate::sugar::SugaredTypeTerm, + tiny_ansi::TinyAnsi +}; + +impl SugaredTypeTerm { + pub fn pretty(&self, dict: &TypeDict, indent: u64) -> String { + let indent_width = 4; + match self { + SugaredTypeTerm::TypeID(id) => { + format!("{}", dict.get_typename(id).unwrap_or("??".bright_red())).bright_blue() + }, + + SugaredTypeTerm::Num(n) => { + format!("{}", n).bright_cyan() + } + + SugaredTypeTerm::Char(c) => { + format!("'{}'", c) + } + + SugaredTypeTerm::Univ(t) => { + format!("{} {} . {}", + "∀".yellow().bold(), + dict.get_varname(0).unwrap_or("??".into()).bright_blue(), + t.pretty(dict,indent) + ) + } + + SugaredTypeTerm::Spec(args) => { + let mut s = String::new(); + s.push_str(&"<".yellow().bold()); + for i in 0..args.len() { + let arg = &args[i]; + if i > 0 { + s.push(' '); + } + s.push_str( &arg.pretty(dict,indent+1) ); + } + s.push_str(&">".yellow().bold()); + s + } + + SugaredTypeTerm::Struct(args) => { + let mut s = String::new(); + s.push_str(&"{".yellow().bold()); + for arg in args { + s.push('\n'); + for x in 0..(indent+1)*indent_width { + s.push(' '); + } + s.push_str(&arg.pretty(dict, indent + 1)); + s.push_str(&";\n".bright_yellow()); + } + + s.push('\n'); + for x in 0..indent*indent_width { + s.push(' '); + } + s.push_str(&"}".yellow().bold()); + s + } + + SugaredTypeTerm::Enum(args) => { + let mut s = String::new(); + s.push_str(&"(".yellow().bold()); + for i in 0..args.len() { + let arg = &args[i]; + s.push('\n'); + for x in 0..(indent+1)*indent_width { + s.push(' '); + } + if i > 0 { + s.push_str(&"| ".yellow().bold()); + } + s.push_str(&arg.pretty(dict, indent + 1)); + } + + s.push('\n'); + for x in 0..indent*indent_width { + s.push(' '); + } + s.push_str(&")".yellow().bold()); + s + } + + SugaredTypeTerm::Seq(args) => { + let mut s = String::new(); + s.push_str(&"[ ".yellow().bold()); + for i in 0..args.len() { + let arg = &args[i]; + if i > 0 { + s.push(' '); + } + s.push_str(&arg.pretty(dict, indent+1)); + } + s.push_str(&" ]".yellow().bold()); + s + } + + SugaredTypeTerm::Morph(args) => { + let mut s = String::new(); + for arg in args { + s.push_str(&" ~~morph~~> ".bright_yellow()); + s.push_str(&arg.pretty(dict, indent)); + } + s + } + + SugaredTypeTerm::Func(args) => { + let mut s = String::new(); + for i in 0..args.len() { + let arg = &args[i]; + if i > 0{ + s.push('\n'); + for x in 0..(indent*indent_width) { + s.push(' '); + } + s.push_str(&"--> ".bright_yellow()); + } else { +// s.push_str(" "); + } + s.push_str(&arg.pretty(dict, indent)); + } + s + } + + SugaredTypeTerm::Ladder(rungs) => { + let mut s = String::new(); + for i in 0..rungs.len() { + let rung = &rungs[i]; + if i > 0{ + s.push('\n'); + for x in 0..(indent*indent_width) { + s.push(' '); + } + s.push_str(&"~ ".yellow()); + } + s.push_str(&rung.pretty(dict, indent)); + } + s + } + } + } +} + + diff --git a/src/term.rs b/src/term.rs index f5e8f5f..29c7d27 100644 --- a/src/term.rs +++ b/src/term.rs @@ -57,7 +57,7 @@ impl TypeTerm { pub fn repr_as(&mut self, t: impl Into<TypeTerm>) -> &mut Self { match self { TypeTerm::Ladder(rungs) => { - rungs.push(t.into()); + rungs.push(t.into()); } _ => { diff --git a/src/test/mod.rs b/src/test/mod.rs index d116412..ea52c7d 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -2,6 +2,7 @@ pub mod lexer; pub mod parser; pub mod curry; +pub mod sugar; pub mod lnf; pub mod subtype; pub mod substitution; diff --git a/src/test/parser.rs b/src/test/parser.rs index 1166229..49deb7c 100644 --- a/src/test/parser.rs +++ b/src/test/parser.rs @@ -1,6 +1,6 @@ use { - crate::{term::*, dict::*, parser::*} + crate::{term::*, dict::*, parser::*, sugar::SUGARID_LIMIT} }; //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ @@ -17,7 +17,7 @@ fn test_parser_id() { ); assert_eq!( - Ok(TypeTerm::TypeID(TypeID::Fun(0))), + Ok(TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0))), dict.parse("A") ); } @@ -43,16 +43,16 @@ fn test_parser_app() { assert_eq!( TypeDict::new().parse("<A B>"), Ok(TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), - TypeTerm::TypeID(TypeID::Fun(1)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+1)), ])) ); assert_eq!( TypeDict::new().parse("<A B C>"), Ok(TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), - TypeTerm::TypeID(TypeID::Fun(1)), - TypeTerm::TypeID(TypeID::Fun(2)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+1)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+2)), ])) ); } @@ -78,16 +78,16 @@ fn test_parser_ladder() { assert_eq!( TypeDict::new().parse("A~B"), Ok(TypeTerm::Ladder(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), - TypeTerm::TypeID(TypeID::Fun(1)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+1)), ])) ); assert_eq!( TypeDict::new().parse("A~B~C"), Ok(TypeTerm::Ladder(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), - TypeTerm::TypeID(TypeID::Fun(1)), - TypeTerm::TypeID(TypeID::Fun(2)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+1)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+2)), ])) ); } @@ -98,12 +98,12 @@ fn test_parser_ladder_outside() { TypeDict::new().parse("<A B>~C"), Ok(TypeTerm::Ladder(vec![ TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), - TypeTerm::TypeID(TypeID::Fun(1)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+1)), ]), - TypeTerm::TypeID(TypeID::Fun(2)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+2)), ])) - ); + ); } #[test] @@ -111,10 +111,10 @@ fn test_parser_ladder_inside() { assert_eq!( TypeDict::new().parse("<A B~C>"), Ok(TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), TypeTerm::Ladder(vec![ - TypeTerm::TypeID(TypeID::Fun(1)), - TypeTerm::TypeID(TypeID::Fun(2)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+1)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+2)), ]) ])) ); @@ -125,12 +125,12 @@ fn test_parser_ladder_between() { assert_eq!( TypeDict::new().parse("<A B~<C D>>"), Ok(TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), TypeTerm::Ladder(vec![ - TypeTerm::TypeID(TypeID::Fun(1)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+1)), TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(2)), - TypeTerm::TypeID(TypeID::Fun(3)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+2)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+3)), ]) ]) ])) @@ -156,48 +156,48 @@ fn test_parser_ladder_large() { Ok( TypeTerm::Ladder(vec![ TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), TypeTerm::Ladder(vec![ - TypeTerm::TypeID(TypeID::Fun(1)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+1)), TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(2)), - TypeTerm::TypeID(TypeID::Fun(3)) + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+2)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+3)) ]), TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(4)), - TypeTerm::TypeID(TypeID::Fun(5)) + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+4)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+5)) ]), - TypeTerm::TypeID(TypeID::Fun(6)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+6)), TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(7)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+7)), TypeTerm::Num(10), - TypeTerm::TypeID(TypeID::Fun(8)) + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+8)) ]), TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), TypeTerm::Ladder(vec![ TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(9)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+9)), TypeTerm::Num(10) ]), - TypeTerm::TypeID(TypeID::Fun(10)) + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+10)) ]) ]) ]) ]), TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(11)), - TypeTerm::TypeID(TypeID::Fun(10)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+11)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+10)), TypeTerm::Char(':') ]), TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), - TypeTerm::TypeID(TypeID::Fun(10)) + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+10)) ]), - TypeTerm::TypeID(TypeID::Fun(12)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+12)), TypeTerm::App(vec![ - TypeTerm::TypeID(TypeID::Fun(0)), - TypeTerm::TypeID(TypeID::Fun(13)) + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+0)), + TypeTerm::TypeID(TypeID::Fun(SUGARID_LIMIT+13)) ]) ]) ) diff --git a/src/test/sugar.rs b/src/test/sugar.rs new file mode 100644 index 0000000..c6a9768 --- /dev/null +++ b/src/test/sugar.rs @@ -0,0 +1,10 @@ + +#[test] +fn test_sugar() { + + let mut dict = crate::TypeDict::new(); + + +} + + diff --git a/src/test/unification.rs b/src/test/unification.rs index 34d355d..19c6768 100644 --- a/src/test/unification.rs +++ b/src/test/unification.rs @@ -13,8 +13,8 @@ fn test_unify(ts1: &str, ts2: &str, expect_unificator: bool) { dict.add_varname(String::from("V")); dict.add_varname(String::from("W")); - let mut t1 = dict.parse(ts1).unwrap(); - let mut t2 = dict.parse(ts2).unwrap(); + let mut t1 = dict.parse(ts1).unwrap().desugar(); + let mut t2 = dict.parse(ts2).unwrap().desugar(); let σ = crate::unify( &t1, &t2 ); if expect_unificator {