diff --git a/Cargo.lock b/Cargo.lock index 7cefadf50..9a7b15865 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "TSPL" -version = "0.0.6" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ed463bdafa4b9eea9fe4120a51abb90289275c4f3411d344de2787567cb6ae" +checksum = "1cf26cc6171f5f62baf926d04bc23eab3412598d76908fff83fda919bba486f0" dependencies = [ "highlight_error", ] diff --git a/Cargo.toml b/Cargo.toml index 0fcf8dde6..428aa7cf1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,6 @@ name = "kind2" path = "src/main.rs" [dependencies] -TSPL = "0.0.6" +TSPL = "0.0.8" highlight_error = "0.1.1" im = "15.1.0" diff --git a/book/Bool.if.kind2 b/book/Bool.if.kind2 index faea44641..7325ec79f 100644 --- a/book/Bool.if.kind2 +++ b/book/Bool.if.kind2 @@ -1,3 +1,3 @@ Bool.if : ∀(b: Bool) ∀(P: *) ∀(t: P) ∀(f: P) P -= λb λP λt λf (~b λx P t f) \ No newline at end of file += λb λP λt λf (~b λx P t f) diff --git a/book/Bool.kind2 b/book/Bool.kind2 index 81540e0c7..62f6c4546 100644 --- a/book/Bool.kind2 +++ b/book/Bool.kind2 @@ -2,6 +2,6 @@ Bool : * = $(self: Bool) ∀(P: ∀(x: Bool) *) - ∀(t: (P Bool.true)) - ∀(f: (P Bool.false)) - (P self) \ No newline at end of file + ∀(true: (P Bool.true)) + ∀(false: (P Bool.false)) + (P self) diff --git a/book/Bool.lemma.notnot.kind2 b/book/Bool.lemma.notnot.kind2 index 8c507ff12..18611d5cb 100644 --- a/book/Bool.lemma.notnot.kind2 +++ b/book/Bool.lemma.notnot.kind2 @@ -1,3 +1,3 @@ Bool.lemma.notnot : ∀(b: Bool) (Equal Bool (Bool.not (Bool.not b)) b) -= λb (~b _ ?a (Equal.refl Bool Bool.false)) \ No newline at end of file += λb (~b _ (Equal.refl Bool Bool.true) (Equal.refl Bool Bool.false)) diff --git a/book/List.kind2 b/book/List.kind2 index b81c1295b..5808c1b6f 100644 --- a/book/List.kind2 +++ b/book/List.kind2 @@ -3,9 +3,6 @@ List = λT $(self: (List T)) ∀(P: ∀(xs: (List T)) *) - ∀(cons: - ∀(head: T) ∀(tail: (List T)) - (P (List.cons T head tail)) - ) + ∀(cons: ∀(head: T) ∀(tail: (List T)) (P (List.cons T head tail))) ∀(nil: (P (List.nil T))) - (P self) \ No newline at end of file + (P self) diff --git a/book/Nat.kind2 b/book/Nat.kind2 index ee66447c4..18e334672 100644 --- a/book/Nat.kind2 +++ b/book/Nat.kind2 @@ -4,4 +4,4 @@ Nat ∀(P: ∀(n: Nat) *) ∀(succ: ∀(n: Nat) (P (Nat.succ n))) ∀(zero: (P Nat.zero)) - (P self) \ No newline at end of file + (P self) diff --git a/book/Sigma.kind2 b/book/Sigma.kind2 index 74790210e..a94d0cce0 100644 --- a/book/Sigma.kind2 +++ b/book/Sigma.kind2 @@ -3,7 +3,5 @@ Sigma = λA λB $(self: (Sigma A B)) ∀(P: ∀(x: (Sigma A B)) *) - ∀(new: - ∀(a: A) ∀(b: (B a)) (P (Sigma.new A B a b)) - ) - (P self) \ No newline at end of file + ∀(new: ∀(a: A) ∀(b: (B a)) (P (Sigma.new A B a b))) + (P self) diff --git a/book/The.kind2 b/book/The.kind2 new file mode 100644 index 000000000..41e47d2b8 --- /dev/null +++ b/book/The.kind2 @@ -0,0 +1,9 @@ +The +: ∀(A: *) + ∀(x: A) + * += λA λx + $(self: (The A x)) + ∀(P: ∀(x: A) ∀(p: (The A x)) *) + ∀(value: ∀(x: A) (P x (The.value A x))) + (P x self) diff --git a/book/The.value.kind2 b/book/The.value.kind2 new file mode 100644 index 000000000..97d3bb55a --- /dev/null +++ b/book/The.value.kind2 @@ -0,0 +1,7 @@ +The.value +: ∀(A: *) + ∀(x: A) + (The A x) += λA λx + ~λP λvalue (value x) + diff --git a/book/Vector.cons.kind2 b/book/Vector.cons.kind2 new file mode 100644 index 000000000..cae946397 --- /dev/null +++ b/book/Vector.cons.kind2 @@ -0,0 +1,3 @@ +Vector.cons +: ∀(T: *) ∀(len: Nat) ∀(head: T) ∀(tail: (Vector T len)) (Vector T (Nat.succ len)) += λT λlen λhead λtail ~λP λcons λnil (cons len head tail) diff --git a/book/Vector.kind2 b/book/Vector.kind2 new file mode 100644 index 000000000..5625284b4 --- /dev/null +++ b/book/Vector.kind2 @@ -0,0 +1,8 @@ +Vector +: ∀(T: *) ∀(len: Nat) * += λT λlen + $(self: (Vector T len)) + ∀(P: ∀(len: Nat) ∀(xs: (Vector T len)) *) + ∀(cons: ∀(len: Nat) ∀(head: T) ∀(tail: (Vector T len)) (P (Nat.succ len) (Vector.cons T len head tail))) + ∀(nil: (P Nat.zero (Vector.nil T))) + (P len self) diff --git a/book/Vector.nil.kind2 b/book/Vector.nil.kind2 new file mode 100644 index 000000000..5eeabecf8 --- /dev/null +++ b/book/Vector.nil.kind2 @@ -0,0 +1,3 @@ +Vector.nil +: ∀(T: *) (Vector T Nat.zero) += λT ~λP λcons λnil nil diff --git a/book/_main.kind2 b/book/_main.kind2 index 3ecec4b01..cda4c7b2d 100644 --- a/book/_main.kind2 +++ b/book/_main.kind2 @@ -1,7 +1,7 @@ _main : use list = (List.cons _ Nat.zero - (List.cons _ (Nat.succ Nat.zero) + (List.cons _ 1 (List.cons _ (Nat.succ (Nat.succ Nat.zero)) (List.nil _)))) (The (List Nat) list) diff --git a/src/book/mod.rs b/src/book/mod.rs index c689d3351..e60781467 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -6,7 +6,6 @@ use std::collections::BTreeSet; mod compile; mod format; mod parse; -mod show; // ::= // DEF_ANN | : = @@ -20,13 +19,17 @@ pub struct Book { impl Book { + pub fn show(&self) -> String { + return self.format().flatten(None); + } + pub fn new() -> Self { Book { defs: BTreeMap::new(), fids: BTreeMap::new(), } } - + pub fn load(name: &str) -> Result { fn load_go(name: &str, book: &mut Book) -> Result<(), String> { //println!("... {}", name); @@ -57,6 +60,9 @@ impl Book { load_go("String", &mut book)?; load_go("String.cons", &mut book)?; load_go("String.nil", &mut book)?; + load_go("Nat", &mut book)?; + load_go("Nat.succ", &mut book)?; + load_go("Nat.zero", &mut book)?; //println!("DONE!"); Ok(book) } diff --git a/src/book/show.rs b/src/book/show.rs deleted file mode 100644 index a325e72bf..000000000 --- a/src/book/show.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::{*}; - -impl Book { - - pub fn show(&self) -> String { - let mut book_str = String::new(); - for (name, term) in &self.defs { - book_str.push_str(&format!("{} = {}\n", name, term.show())); - } - book_str - } - -} diff --git a/src/form/mod.rs b/src/form/mod.rs index e629d241a..88241585a 100644 --- a/src/form/mod.rs +++ b/src/form/mod.rs @@ -1,3 +1,5 @@ +use crate::Term; + // Example: // ["(" "foo" "arg0" "arg1" "arg2" ")"] // Call: @@ -75,45 +77,49 @@ impl Form { } // Flattens the Form structure into a string, respecting indentation and width limits. - pub fn flatten(&self, lim: usize) -> String { + pub fn flatten(&self, lim: Option) -> String { let mut out = String::new(); - self.flatten_into(&mut out, &mut 0, lim); + if let Some(lim) = lim { + self.flatten_into(&mut out, true, &mut 0, lim); + } else { + self.flatten_into(&mut out, false, &mut 0, 0); + } out } // Helper function. - pub fn flatten_into(&self, out: &mut String, tab: &mut usize, lim: usize) { + pub fn flatten_into(&self, out: &mut String, fmt: bool, tab: &mut usize, lim: usize) { match self { Form::Many { style, join, child } => { match style { Style::Call => { - let add_lines = Form::no_lines(&child) && self.width(lim) >= lim; + let add_lines = fmt && Form::no_lines(&child) && self.width(lim) >= lim; for (i, c) in child.iter().enumerate() { if add_lines && i > 0 && i < child.len() - 1 { - Form::Inc.flatten_into(out, tab, lim); + Form::Inc.flatten_into(out, fmt, tab, lim); } if add_lines && i > 0 { - Form::Line.flatten_into(out, tab, lim); + Form::Line.flatten_into(out, fmt, tab, lim); } if !add_lines && i > 0 && i < child.len() - 1 { out.push_str(&join); } - c.flatten_into(out, tab, lim); + c.flatten_into(out, fmt, tab, lim); if add_lines && i > 0 && i < child.len() - 1 { - Form::Dec.flatten_into(out, tab, lim); + Form::Dec.flatten_into(out, fmt, tab, lim); } } }, Style::Pile => { - let add_lines = Form::no_lines(&child) && self.width(lim) >= lim; + let add_lines = fmt && Form::no_lines(&child) && self.width(lim) >= lim; for (i, c) in child.iter().enumerate() { if add_lines && i > 0 { - Form::Line.flatten_into(out, tab, lim); + Form::Line.flatten_into(out, fmt, tab, lim); } if !add_lines && i > 0 { out.push_str(&join); } - c.flatten_into(out, tab, lim); + c.flatten_into(out, fmt, tab, lim); } }, Style::Glue => { @@ -121,7 +127,7 @@ impl Form { if i > 0 { out.push_str(&join); } - c.flatten_into(out, tab, lim); + c.flatten_into(out, fmt, tab, lim); } }, } diff --git a/src/info/mod.rs b/src/info/mod.rs index 1c7defae0..eabd28ed5 100644 --- a/src/info/mod.rs +++ b/src/info/mod.rs @@ -27,7 +27,10 @@ pub enum Info { }, Vague { nam: String, - } + }, + Print { + val: Term, + }, } @@ -55,6 +58,9 @@ impl Info { }, Info::Vague { nam } => { format!("VAGUE: _{}", nam) + }, + Info::Print { val } => { + format!("{}", val.show()) } } } diff --git a/src/info/parse.rs b/src/info/parse.rs index 2a42d9958..ac287edc6 100644 --- a/src/info/parse.rs +++ b/src/info/parse.rs @@ -56,6 +56,13 @@ impl<'i> KindParser<'i> { self.consume("}")?; Ok(Info::Vague { nam }) } + Some('p') => { + self.consume("print")?; + self.consume("{")?; + let val = self.parse_term(0)?; + self.consume("}")?; + Ok(Info::Print { val }) + } _ => self.expected("info type (solve, found, error)"), } } diff --git a/src/info/show.rs b/src/info/show.rs index 0866d4b4a..ba663b604 100644 --- a/src/info/show.rs +++ b/src/info/show.rs @@ -1,5 +1,7 @@ use crate::{*}; +//./mod.rs// + impl Info { pub fn show(&self) -> String { @@ -16,6 +18,9 @@ impl Info { }, Info::Vague { nam } => { format!("#vague{{?{}}}", nam) + }, + Info::Print { val } => { + format!("#print{{{}}}", val.show()) } } } diff --git a/src/kind2.hs b/src/kind2.hs index 85a948012..bb2275e1c 100644 --- a/src/kind2.hs +++ b/src/kind2.hs @@ -36,17 +36,19 @@ data Term | Num Int | Op2 Oper Term Term | Mat String Term Term (Term -> Term) (Term -> Term) - | Txt String | Hol String [Term] | Met Int [Term] | Var String Int | Src Int Term + | Txt String + | Nat Integer data Info = Found String Term [Term] Int | Solve Int Term Int | Error Int Term Term Term Int | Vague String + | Print Term Int data Check = Check Int Term Term Int data State = State (Map Term) [Check] [Info] -- state type @@ -195,7 +197,7 @@ envRewind :: State -> Env Int envRewind state = Env $ \_ -> Done state 0 envSusp :: Check -> Env () -envSusp chk = Env $ \(State fill susp logs) -> Done (State fill (chk : susp) logs) () +envSusp chk = Env $ \(State fill susp logs) -> Done (State fill (listPush chk susp) logs) () envFill :: Int -> Term -> Env () envFill k v = Env $ \(State fill susp logs) -> Done (State (mapSet (key k) v fill) susp logs) () @@ -240,6 +242,7 @@ termReduce fill lv (Use nam val bod) = termReduce fill lv (bod val) termReduce fill lv (Op2 opr fst snd) = termReduceOp2 fill lv opr (termReduce fill lv fst) (termReduce fill lv snd) termReduce fill lv (Mat nam x z s p) = termReduceMat fill lv nam (termReduce fill lv x) z s p termReduce fill lv (Txt txt) = termReduceTxt fill lv txt +termReduce fill lv (Nat val) = termReduceNat fill lv val termReduce fill lv (Src src val) = termReduce fill lv val termReduce fill lv (Met uid spn) = termReduceMet fill lv uid spn termReduce fill lv val = val @@ -292,7 +295,12 @@ termReduceRef fill 1 nam val = Ref nam val termReduceRef fill lv nam val = Ref nam val termReduceTxt :: Map Term -> Int -> String -> Term -termReduceTxt fill lv txt = Txt txt +termReduceTxt fill lv [] = termReduce fill lv xString_nil +termReduceTxt fill lv (x:xs) = termReduce fill lv (App (App xString_cons (Num (ord x))) (Txt xs)) + +termReduceNat :: Map Term -> Int -> Integer -> Term +termReduceNat fill lv 0 = xNat_zero +termReduceNat fill lv n = App xNat_succ (termReduceNat fill lv (n - 1)) -- Normalization -- ------------- @@ -322,6 +330,7 @@ termNormal fill lv term dep = termNormalGo fill lv (termReduce fill lv term) dep termNormalGo fill lv (Op2 opr fst snd) dep = Op2 opr (termNormal fill lv fst dep) (termNormal fill lv snd dep) termNormalGo fill lv (Mat nam x z s p) dep = Mat nam (termNormal fill lv x dep) (termNormal fill lv z dep) (\k -> termNormal fill lv (s (Var (stringConcat nam "-1") dep)) dep) (\k -> termNormal fill lv (p (Var nam dep)) dep) termNormalGo fill lv (Txt val) dep = Txt val + termNormalGo fill lv (Nat val) dep = Nat val termNormalGo fill lv (Var nam idx) dep = Var nam idx termNormalGo fill lv (Src src val) dep = Src src (termNormal fill lv val dep) termNormalGo fill lv (Met uid spn) dep = Met uid spn -- TODO: normalize spine @@ -437,6 +446,8 @@ termIdenticalGo (Mat aNam aX aZ aS aP) (Mat bNam bX bZ bS bP) dep = envPure (iX && iZ && iS && iP) termIdenticalGo (Txt aTxt) (Txt bTxt) dep = envPure (aTxt == bTxt) +termIdenticalGo (Nat aVal) (Nat bVal) dep = + envPure (aVal == bVal) termIdenticalGo (Src aSrc aVal) b dep = termIdentical aVal b dep termIdenticalGo a (Src bSrc bVal) dep = @@ -514,6 +525,7 @@ termUnifySubst lvl neo (Num n) = Num n termUnifySubst lvl neo (Op2 opr fst snd) = Op2 opr (termUnifySubst lvl neo fst) (termUnifySubst lvl neo snd) termUnifySubst lvl neo (Mat nam x z s p) = Mat nam (termUnifySubst lvl neo x) (termUnifySubst lvl neo z) (\k -> termUnifySubst lvl neo (s k)) (\k -> termUnifySubst lvl neo (p k)) termUnifySubst lvl neo (Txt txt) = Txt txt +termUnifySubst lvl neo (Nat val) = Nat val termUnifySubst lvl neo (Var nam idx) = if lvl == idx then neo else Var nam idx termUnifySubst lvl neo (Src src val) = Src src (termUnifySubst lvl neo val) @@ -576,6 +588,8 @@ termInferGo (Num num) dep = do return U60 termInferGo (Txt txt) dep = do return xString +termInferGo (Nat val) dep = do + return xNat termInferGo (Op2 opr fst snd) dep = do envSusp (Check 0 fst U60 dep) envSusp (Check 0 snd U60 dep) @@ -725,6 +739,7 @@ termShow (Mat nam x z s p) dep = p' = termShow (p (Var nam dep)) dep in stringJoin ["#match " , nam' , " = " , x' , " { #0: " , z' , " #+: " , s' , " }: " , p'] termShow (Txt txt) dep = stringJoin [quote , txt , quote] +termShow (Nat val) dep = show val termShow (Hol nam ctx) dep = stringJoin ["?" , nam] termShow (Met uid spn) dep = stringJoin ["(_", termShowSpn (reverse spn) dep, ")"] termShow (Var nam idx) dep = nam @@ -777,10 +792,18 @@ infoShow fill (Solve name term dep) = in stringJoin ["#solve{", show name, " ", term', "}"] infoShow fill (Vague name) = stringJoin ["#vague{", name, "}"] +infoShow fill (Print value dep) = + let val = termShow (termNormal fill 0 value dep) dep + in stringJoin ["#print{", val, "}"] -- API -- --- +-- Normalizes a term +apiNormal :: Term -> IO () +apiNormal term = putStrLn $ infoShow mapNew (Print (termNormal mapNew 2 term 0) 0) + +-- Type-checks a term apiCheck :: Term -> IO () apiCheck term = case envRun $ termCheckDef term of Done state value -> apiPrintLogs state @@ -810,4 +833,4 @@ xtest = Ref "test" $ Ann True val typ where typ = (All "P" Set $ \p -> (All "f" (All "x" p $ \x -> p) $ \f -> (All "x" p $ \x -> p))) val = (Lam "P" $ \p -> (Lam "f" $ \f -> (Lam "x" $ \x -> f))) -xString = undefined +xString = undefined; xString_cons = undefined; xString_nil = undefined; xNat = undefined; xNat_succ = undefined; xNat_zero = undefined diff --git a/src/main.rs b/src/main.rs index 45e89e50e..f9ff798d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ fn generate_check_hs(book: &Book, command: &str, arg: &str) -> String { let book_hs = book.to_hs(); let main_hs = match command { "check" => format!("main = (apiCheck {})\n", Term::to_hs_name(arg)), - "run" => format!("Main = (apiNormal {})\n", Term::to_hs_name(arg)), + "run" => format!("main = (apiNormal {})\n", Term::to_hs_name(arg)), _ => panic!("invalid command"), }; let hs_code = format!("{}\n{}\n{}", kind_hs, book_hs, main_hs); @@ -116,6 +116,12 @@ fn main() { } } +//fn main() { + //env::set_current_dir("./book").expect("Failed to change directory to ./book"); + //let adt = term::sugar::ADT::load("Bool"); + //println!("{:?}", adt); +//} + fn show_help() { eprintln!("Usage: kind2 [check|run] "); std::process::exit(1); diff --git a/src/term/compile.rs b/src/term/compile.rs index 99957eb60..c754f39f6 100644 --- a/src/term/compile.rs +++ b/src/term/compile.rs @@ -1,5 +1,7 @@ use crate::{*}; +//./mod.rs// + impl Oper { pub fn to_ctr(&self) -> &'static str { @@ -176,9 +178,6 @@ impl Term { let p = p.to_hs(cons(&env, nam.clone()), met); format!("(Mat \"{}\" {} {} (\\{} -> {}) (\\{} -> {}))", nam, x, z, Term::to_hs_name(&format!("{}-1", nam)), s, Term::to_hs_name(nam), p) }, - Term::Txt { txt } => { - format!("(Txt \"{}\")", txt.replace("\n", "\\n")) - }, Term::Let { nam, val, bod } => { let val = val.to_hs(env.clone(), met); let bod = bod.to_hs(cons(&env, nam.clone()), met); @@ -206,6 +205,12 @@ impl Term { let val = val.to_hs(env, met); format!("(Src {} {})", src.to_u64(), val) }, + Term::Nat { nat } => { + format!("(Nat {})", nat) + }, + Term::Txt { txt } => { + format!("(Txt \"{}\")", txt.replace("\n", "\\n")) + }, } } diff --git a/src/term/format.rs b/src/term/format.rs index 68aece85b..6440035f1 100644 --- a/src/term/format.rs +++ b/src/term/format.rs @@ -1,9 +1,37 @@ use crate::{*}; + +//CONTEXT: +//./mod.rs// +//./sugar.rs// +//./../book/mod.rs// +//./../../book/Bool.kind2// +//./../../book/Nat.kind2// +//./../../book/List.kind2// +//./../../book/Sigma.kind2// +//./../../book/Monad.kind2// + impl Oper { pub fn format(&self) -> Box
{ - Form::text(self.show()) + Form::text(match self { + Oper::Add => "+", + Oper::Sub => "-", + Oper::Mul => "*", + Oper::Div => "/", + Oper::Mod => "%", + Oper::Eq => "==", + Oper::Ne => "!=", + Oper::Lt => "<", + Oper::Gt => ">", + Oper::Lte => "<=", + Oper::Gte => ">=", + Oper::And => "&", + Oper::Or => "|", + Oper::Xor => "^", + Oper::Lsh => "<<", + Oper::Rsh => ">>", + }) } } @@ -11,10 +39,85 @@ impl Oper { impl Term { pub fn format(&self) -> Box { - self.clean().format_go() + return self.clean().format_go(); } pub fn format_go(&self) -> Box { + if let Some(nat) = self.as_nat() { + return Form::text(&format!("{}", nat)); + } + + if let Some(list) = self.as_list() { + if list.len() == 0 { + return Form::text("[]"); + } else { + return Form::call("", vec![ + Form::text("["), + Form::pile(", ", list.iter().map(|x| x.format_go()).collect()), + Form::text("]"), + ]); + } + } + + //if let Some(adt) = self.as_adt() { + //return Form::glue("", vec![ + //Form::text("data "), + //Form::text("TODO"), + //Form::glue(" ", adt.pars.iter().map(|(x,y)| { + //Form::call("", vec![ + //Form::glue("", vec![ + //Form::text("("), + //Form::text(x), + //Form::text(": "), + //]), + //y.format_go(), + //Form::text(")"), + //]) + //}).collect()), + //Form::call("", vec![ + //Form::text(":"), + //Form::pile(" ", adt.idxs.iter().map(|(x,y)| { + //Form::call("", vec![ + //Form::glue("", vec![ + //Form::text("("), + //Form::text(x), + //Form::text(": "), + //]), + //y.format_go(), + //Form::text(")"), + //]) + //}).collect()), + //]), + //Form::line(), + //Form::glue("", adt.ctrs.iter().map(|ctr| { + //let mut vec = vec![ + //Form::glue("", vec![ + //Form::text("| "), + //Form::text(&ctr.name), + //]) + //]; + //for (x, y) in &ctr.flds { + //vec.push(Form::call("", vec![ + //Form::glue("", vec![ + //Form::text("("), + //Form::text(x), + //Form::text(": "), + //]), + //y.format_go(), + //Form::text(")"), + //])); + //} + //vec.push(Form::call("", vec![ + //Form::glue("", vec![ + //Form::text(":"), + //]), + //ctr.rtyp.format_go(), + //])); + //Form::pile(" ", vec) + //}).collect()), + //]); + //} + match self { Term::All { .. } => { let mut bnd = vec![]; @@ -146,9 +249,6 @@ impl Term { ]), ]) }, - Term::Txt { txt } => { - Form::text(&format!("\"{}\"", txt)) - }, Term::Let { nam, val, bod } => { Form::glue("", vec![ Form::text("let "), @@ -185,6 +285,12 @@ impl Term { Term::Src { src: _, val } => { val.format_go() }, + Term::Txt { txt } => { + Form::text(&format!("\"{}\"", txt)) + }, + Term::Nat { nat } => { + Form::text(&format!("{}", nat)) + }, } } diff --git a/src/term/mod.rs b/src/term/mod.rs index 1a13b0081..1ad091c3b 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -1,10 +1,10 @@ use crate::{*}; use std::collections::BTreeSet; -mod compile; -mod format; -mod parse; -mod show; +pub mod compile; +pub mod format; +pub mod parse; +pub mod sugar; #[derive(Clone, Copy, Debug)] pub enum Oper { @@ -33,8 +33,8 @@ pub struct Src { // NUM | # // OP2 | #( ) // MAT | #match = { #0: ; #+: }: -// MET | ? -// HOL | _ +// HOL | ? +// MET | _ // CHR | '' // STR | "" // LET | let = @@ -52,13 +52,14 @@ pub enum Term { Num { val: u64 }, Op2 { opr: Oper, fst: Box, snd: Box }, Mat { nam: String, x: Box, z: Box, s: Box, p: Box }, - Txt { txt: String }, Let { nam: String, val: Box, bod: Box }, Use { nam: String, val: Box, bod: Box }, Var { nam: String }, Hol { nam: String }, Met {}, Src { src: Src, val: Box }, + Nat { nat: u64 }, + Txt { txt: String }, } impl Src { @@ -95,8 +96,18 @@ pub fn cons(vector: &im::Vector, value: A) -> im::Vector where A: Clone new_vector } +impl Oper { + pub fn show(&self) -> String { + return self.format().flatten(None); + } +} + impl Term { + pub fn show(&self) -> String { + return self.format().flatten(None); + } + pub fn get_free_vars(&self, env: im::Vector, free_vars: &mut BTreeSet) { match self { Term::All { nam, inp, bod } => { @@ -134,6 +145,7 @@ impl Term { s.get_free_vars(cons(&env, format!("{}-1",nam)), free_vars); p.get_free_vars(cons(&env, nam.clone()), free_vars); }, + Term::Nat { nat: _ } => {}, Term::Txt { txt: _ } => {}, Term::Let { nam, val, bod } => { val.get_free_vars(env.clone(), free_vars); @@ -207,6 +219,9 @@ impl Term { let p = p.count_metas(); x + z + s + p }, + Term::Nat { .. } => { + 0 + }, Term::Txt { .. } => { 0 }, @@ -301,6 +316,9 @@ impl Term { p: Box::new(p.clean()), } }, + Term::Nat { nat } => { + Term::Nat { nat: *nat } + }, Term::Txt { txt } => { Term::Txt { txt: txt.clone() } }, diff --git a/src/term/parse.rs b/src/term/parse.rs index 7a03c2c8e..3db38094a 100644 --- a/src/term/parse.rs +++ b/src/term/parse.rs @@ -1,5 +1,13 @@ use crate::{*}; +// FILES FOR CONTEXT: + +//./mod.rs// +//./format.rs// +//./../../../TSPL/src/lib.rs// + +// CURRENT FILE: + impl<'i> KindParser<'i> { pub fn parse_oper(&mut self) -> Result { @@ -35,195 +43,311 @@ impl<'i> KindParser<'i> { pub fn parse_term(&mut self, fid: u64) -> Result { self.skip_trivia(); - match self.peek_one() { - Some('∀') => { - let ini = *self.index() as u64; - self.consume("∀")?; - self.consume("(")?; - let nam = self.parse_name()?; - self.consume(":")?; - let inp = Box::new(self.parse_term(fid)?); - self.consume(")")?; - let bod = Box::new(self.parse_term(fid)?); - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::All { nam, inp, bod }) }) - } - Some('λ') => { - let ini = *self.index() as u64; - self.consume("λ")?; - let nam = self.parse_name()?; - let bod = Box::new(self.parse_term(fid)?); - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Lam { nam, bod }) }) - } - Some('(') => { - let ini = *self.index() as u64; - self.consume("(")?; - let fun = Box::new(self.parse_term(fid)?); - let mut args = Vec::new(); - while self.peek_one() != Some(')') { - args.push(Box::new(self.parse_term(fid)?)); - self.skip_trivia(); - } - self.consume(")")?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - let mut app = fun; - for arg in args { - app = Box::new(Term::App { fun: app, arg }); - } - Ok(Term::Src { src, val: app }) - } - Some('{') => { - let ini = *self.index() as u64; - self.consume("{")?; - let val = Box::new(self.parse_term(fid)?); - self.consume(":")?; - let typ = Box::new(self.parse_term(fid)?); - self.consume("}")?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Ann { chk: true, val, typ }) }) - } - Some('$') => { - let ini = *self.index() as u64; - self.consume("$")?; - self.consume("(")?; - let nam = self.parse_name()?; - self.consume(":")?; - let typ = Box::new(self.parse_term(fid)?); - self.consume(")")?; - let bod = Box::new(self.parse_term(fid)?); - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Slf { nam, typ, bod }) }) - } - Some('~') => { - let ini = *self.index() as u64; - self.consume("~")?; - let val = Box::new(self.parse_term(fid)?); - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Ins { val }) }) - } - Some('*') => { - let ini = *self.index() as u64; - self.consume("*")?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Set) }) - } - Some('#') => { - let ini = *self.index() as u64; - self.consume("#")?; - match self.peek_one() { - Some('U') => { - self.consume("U60")?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::U60) }) - } - Some('(') => { - self.consume("(")?; - let opr = self.parse_oper()?; - let fst = Box::new(self.parse_term(fid)?); - let snd = Box::new(self.parse_term(fid)?); - self.consume(")")?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Op2 { opr, fst, snd }) }) - } - Some('m') => { - self.consume("match")?; - let nam = self.parse_name()?; - self.consume("=")?; - let x = Box::new(self.parse_term(fid)?); - self.consume("{")?; - self.consume("#0")?; - self.consume(":")?; - let z = Box::new(self.parse_term(fid)?); - self.consume("#+")?; - self.consume(":")?; - let s = Box::new(self.parse_term(fid)?); - self.consume("}")?; - self.consume(":")?; - let p = Box::new(self.parse_term(fid)?); - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Mat { nam, x, z, s, p }) }) - } - Some(_) => { - let val = self.parse_u64()?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Num { val }) }) - } - _ => { - self.expected("numeric-expression") - } - } - } - Some('?') => { - let ini = *self.index() as u64; - self.consume("?")?; - let nam = self.parse_name()?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Hol { nam }) }) - } - Some('_') => { - let ini = *self.index() as u64; - self.consume("_")?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Met {}) }) - } - Some('\'') => { - let ini = *self.index() as u64; - let chr = self.parse_quoted_char()?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Num { val: chr as u64 }) }) - } - Some('"') => { - let ini = *self.index() as u64; - let txt = self.parse_quoted_string()?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Txt { txt }) }) - } - _ => { - if self.peek_many(4) == Some("let ") { - let ini = *self.index() as u64; - self.advance_many(4); - let nam = self.parse_name()?; - self.consume("=")?; - let val = Box::new(self.parse_term(fid)?); - let bod = Box::new(self.parse_term(fid)?); - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Let { nam, val, bod }) }) - } else if self.peek_many(4) == Some("use ") { - let ini = *self.index() as u64; - self.advance_many(4); - let nam = self.parse_name()?; - self.consume("=")?; - let val = Box::new(self.parse_term(fid)?); - let bod = Box::new(self.parse_term(fid)?); - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Use { nam, val, bod }) }) - } else { - let ini = *self.index() as u64; - let nam = self.parse_name()?; - let end = *self.index() as u64; - let src = Src::new(fid, ini, end); - Ok(Term::Src { src, val: Box::new(Term::Var { nam }) }) - } - } + //println!("parsing ||{}", self.input[self.index..].replace("\n","")); + + // ALL ::= ∀(: ) + if self.starts_with("∀") { + let ini = *self.index() as u64; + self.consume("∀")?; + self.consume("(")?; + let nam = self.parse_name()?; + self.consume(":")?; + let inp = Box::new(self.parse_term(fid)?); + self.consume(")")?; + let bod = Box::new(self.parse_term(fid)?); + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::All { nam, inp, bod }) }); } + + // LAM ::= λ + if self.starts_with("λ") { + let ini = *self.index() as u64; + self.consume("λ")?; + let nam = self.parse_name()?; + let bod = Box::new(self.parse_term(fid)?); + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Lam { nam, bod }) }); + } + + // APP ::= ( ) + if self.starts_with("(") { + let ini = *self.index() as u64; + self.consume("(")?; + let fun = Box::new(self.parse_term(fid)?); + let mut args = Vec::new(); + while self.peek_one() != Some(')') { + args.push(Box::new(self.parse_term(fid)?)); + self.skip_trivia(); + } + self.consume(")")?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + let mut app = fun; + for arg in args { + app = Box::new(Term::App { fun: app, arg }); + } + return Ok(Term::Src { src, val: app }); + } + + // ANN ::= {: } + if self.starts_with("{") { + let ini = *self.index() as u64; + self.consume("{")?; + let val = Box::new(self.parse_term(fid)?); + self.consume(":")?; + let typ = Box::new(self.parse_term(fid)?); + self.consume("}")?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Ann { chk: true, val, typ }) }); + } + + // SLF ::= $(: ) + if self.starts_with("$") { + let ini = *self.index() as u64; + self.consume("$")?; + self.consume("(")?; + let nam = self.parse_name()?; + self.consume(":")?; + let typ = Box::new(self.parse_term(fid)?); + self.consume(")")?; + let bod = Box::new(self.parse_term(fid)?); + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Slf { nam, typ, bod }) }); + } + + // INS ::= ~ + if self.starts_with("~") { + let ini = *self.index() as u64; + self.consume("~")?; + let val = Box::new(self.parse_term(fid)?); + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Ins { val }) }); + } + + // SET ::= * + if self.starts_with("*") { + let ini = *self.index() as u64; + self.consume("*")?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Set) }); + } + + // U60 ::= #U60 + if self.starts_with("#U60") { + let ini = *self.index() as u64; + self.consume("#U60")?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::U60) }); + } + + // OP2 ::= #( ) + if self.starts_with("#(") { + let ini = *self.index() as u64; + self.consume("#(")?; + let opr = self.parse_oper()?; + let fst = Box::new(self.parse_term(fid)?); + let snd = Box::new(self.parse_term(fid)?); + self.consume(")")?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Op2 { opr, fst, snd }) }); + } + + // MAT ::= #match = { #0: ; #+: }: + // - The matched term is optional. Defaults to `Var { nam: }`. + // - The return type is optional. Defaults to `Met {}`. + if self.starts_with("#match") { + let ini = *self.index() as u64; + self.consume("#match")?; + let nam = self.parse_name()?; + self.skip_trivia(); + let x = if self.peek_one() == Some('=') { + self.consume("=")?; + Box::new(self.parse_term(fid)?) + } else { + Box::new(Term::Var { nam: nam.clone() }) + }; + self.consume("{")?; + self.consume("#0")?; + self.consume(":")?; + let z = Box::new(self.parse_term(fid)?); + self.consume("#+")?; + self.consume(":")?; + let s = Box::new(self.parse_term(fid)?); + self.consume("}")?; + let p = if self.peek_one() == Some(':') { + self.consume(":")?; + Box::new(self.parse_term(fid)?) + } else { + Box::new(Term::Met {}) + }; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Mat { nam, x, z, s, p }) }); + } + + // NUM ::= # + if self.starts_with("#") { + let ini = *self.index() as u64; + self.advance_one(); + let val = self.parse_u64()?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Num { val }) }); + } + + // HOL ::= ? + if self.starts_with("?") { + let ini = *self.index() as u64; + self.advance_one(); + let nam = self.parse_name()?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Hol { nam }) }); + } + + // MET ::= _ + if self.starts_with("_") { + let ini = *self.index() as u64; + self.advance_one(); + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Met {}) }); + } + + // TXT ::= "" + if self.starts_with("\"") { + let ini = *self.index() as u64; + let txt = self.parse_quoted_string()?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Txt { txt }) }); + } + + // LET ::= let = + if self.starts_with("let ") { + let ini = *self.index() as u64; + self.consume("let ")?; + let nam = self.parse_name()?; + self.consume("=")?; + let val = Box::new(self.parse_term(fid)?); + let bod = Box::new(self.parse_term(fid)?); + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Let { nam, val, bod }) }); + } + + // USE ::= use = + if self.starts_with("use ") { + let ini = *self.index() as u64; + self.consume("use ")?; + let nam = self.parse_name()?; + self.consume("=")?; + let val = Box::new(self.parse_term(fid)?); + let bod = Box::new(self.parse_term(fid)?); + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Use { nam, val, bod }) }); + } + + // CHR ::= '' + if self.starts_with("'") { + let ini = *self.index() as u64; + let chr = self.parse_quoted_char()?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Num { val: chr as u64 }) }); + } + + // LST ::= [ , ... ] + if self.starts_with("[") { + let ini = *self.index() as u64; + self.consume("[")?; + let mut list = Vec::new(); + while self.peek_one() != Some(']') { + list.push(Box::new(self.parse_term(fid)?)); + self.skip_trivia(); + if self.peek_one() == Some(',') { + self.consume(",")?; + } + } + self.consume("]")?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + let val = Box::new(build_list(list)); + return Ok(Term::Src { src, val }); + } + + // NAT ::= + if self.peek_one().map_or(false, |c| c.is_ascii_digit()) { + let ini = *self.index() as u64; + let nat = self.parse_u64()?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Nat { nat }) }); + } + + // MAT ::= match = { : <...> }: + // The ADT match syntax is similar to the numeric match syntax, including the same optionals, + // but it allows any number of : cases. Also, similarly to the List syntax, there + // is no built-in "Mat" syntax on the Term type, so we must convert it to an applicative form: + // match x = val { + // List.cons: x.head + // List.nil: #0 + // }: #U60 + // Would be converted to: + // (~val _ (λx.head λx.tail x.tail) 0) + // Which is the same as: + // (APP (APP (APP (INS (VAR "val")) MET) (LAM "x.head" (LAM "x.tail" (VAR "x.head")))) (NUM 0)) + // Note that, in our notation, fields are NOT written by the user. For example, this is WRONG: + // match x = val { + // (List.cons head tail): head + // List.nil: #0 + // }: #U60 + // Instead, we write only the constructors, and infer the fields from the datatype. To make + // this possible, we need to FIND the datatype that is currently matched. To do so, we get the + // first constructor name, remove the last `.part` (ex: `Foo.Bar.Tic.tac` will become + // `Foo.Bar.Tic`), and call the function `ADT::load(name: &str) -> ADT`. This will return a + // struct including the type's constructors and fields. We can then use it to create the + // lambdas when desugaring. For example, in the case above, the `λx.head` and `λx.tail` lambdas + // were created on the `List.cons` case, because the matched name is `x`, and the cons + // constructor has a `head` and a `tail` field. + + // VAR ::= + let ini = *self.index() as u64; + let nam = self.parse_name()?; + let end = *self.index() as u64; + let src = Src::new(fid, ini, end); + return Ok(Term::Src { src, val: Box::new(Term::Var { nam }) }); + } } + +// Builds a chain of applications of List.cons and List.nil from a Vec> +fn build_list(list: Vec>) -> Term { + let mut term = Term::App { + fun: Box::new(Term::Var { nam: "List.nil".to_string() }), + arg: Box::new(Term::Met {}), + }; + for item in list.into_iter().rev() { + term = Term::App { + fun: Box::new(Term::App { + fun: Box::new(Term::App { + fun: Box::new(Term::Var { nam: "List.cons".to_string() }), + arg: Box::new(Term::Met {}), + }), + arg: item, + }), + arg: Box::new(term), + }; + } + term +} diff --git a/src/term/show.rs b/src/term/show.rs deleted file mode 100644 index 020b3aa0c..000000000 --- a/src/term/show.rs +++ /dev/null @@ -1,109 +0,0 @@ -use crate::{*}; - -impl Oper { - - pub fn show(&self) -> &'static str { - match self { - Oper::Add => "+", - Oper::Sub => "-", - Oper::Mul => "*", - Oper::Div => "/", - Oper::Mod => "%", - Oper::Eq => "==", - Oper::Ne => "!=", - Oper::Lt => "<", - Oper::Gt => ">", - Oper::Lte => "<=", - Oper::Gte => ">=", - Oper::And => "&", - Oper::Or => "|", - Oper::Xor => "^", - Oper::Lsh => "<<", - Oper::Rsh => ">>", - } - } - -} - -impl Term { - - pub fn show(&self) -> String { - match self { - Term::All { nam, inp, bod } => { - let inp = inp.show(); - let bod = bod.show(); - format!("∀({}: {}) {}", nam, inp, bod) - }, - Term::Lam { nam, bod } => { - let bod = bod.show(); - format!("λ{} {}", nam, bod) - }, - Term::App { fun, arg } => { - let fun = fun.show(); - let arg = arg.show(); - format!("({} {})", fun, arg) - }, - Term::Ann { chk: _, val, typ } => { - let val = val.show(); - let typ = typ.show(); - format!("{{{}: {}}}", val, typ) - }, - Term::Slf { nam, typ, bod } => { - let typ = typ.show(); - let bod = bod.show(); - format!("$({}: {}) {}", nam, typ, bod) - }, - Term::Ins { val } => { - let val = val.show(); - format!("~{}", val) - }, - Term::Set => { - "*".to_string() - }, - Term::U60 => { - "#U60".to_string() - }, - Term::Num { val } => { - format!("#{}", val) - }, - Term::Op2 { opr, fst, snd } => { - let fst = fst.show(); - let snd = snd.show(); - format!("#({} {} {})", opr.show(), fst, snd) - }, - Term::Mat { nam, x, z, s, p } => { - let x = x.show(); - let z = z.show(); - let s = s.show(); - let p = p.show(); - format!("#match {} = {} {{ #0: {}; #+: {} }}: {}", nam, x, z, s, p) - }, - Term::Txt { txt } => { - format!("\"{}\"", txt) - }, - Term::Let { nam, val, bod } => { - let val = val.show(); - let bod = bod.show(); - format!("let {} = {} in {}", nam, val, bod) - }, - Term::Use { nam, val, bod } => { - let val = val.show(); - let bod = bod.show(); - format!("use {} = {} in {}", nam, val, bod) - }, - Term::Hol { nam } => { - format!("?{}", nam) - }, - Term::Met {} => { - format!("_") - }, - Term::Var { nam } => { - nam.clone() - }, - Term::Src { src: _, val } => { - val.show() - }, - } - } - -}