From 6f551f0be7b14a9b7229649d2ce71fa314595c7e Mon Sep 17 00:00:00 2001
From: arthur-adjedj <arthur.adjedj@gmail.com>
Date: Tue, 1 Nov 2022 10:10:56 +0100
Subject: [PATCH] feat: everything

---
 kernel/src/declaration.rs  |  20 +++++++
 kernel/src/environment.rs  |   7 +--
 kernel/src/lib.rs          |   2 +
 kernel/src/term.rs         |   5 +-
 kernel/src/type_checker.rs |  35 +++++-------
 kernel/src/universe.rs     | 106 ++++++++++++++++++++++++-------------
 6 files changed, 110 insertions(+), 65 deletions(-)
 create mode 100644 kernel/src/declaration.rs

diff --git a/kernel/src/declaration.rs b/kernel/src/declaration.rs
new file mode 100644
index 00000000..81feedda
--- /dev/null
+++ b/kernel/src/declaration.rs
@@ -0,0 +1,20 @@
+use crate::term::Term;
+
+
+/// Declarations constructed through commands. A declaration describes a constant in the environment, whether it's a definition with 
+/// a corresponding term, or an axiom with only a type.
+/// univ_vars corresponds to the number of universe variables bound to the declaration. 
+/// No universe variable can be "free" in a term, meaning that for all Var(i) in ty or term, i<univ_vars.
+/// Additionally, ty and term *should* in theory always have the same number of universe variables, and as such, only a single method is needed.
+/// However, additional checks to ensure this invariant will have to be put in place. For now, when constructing declarations, only the number of 
+/// universes in term are counted. Since ty has to be infered, or at least checked against the infered type before being added, it has to have <= universes than term.
+#[derive(Clone)]
+pub struct Declaration {
+    ty : Term,
+    term : Option<Term>,
+    univ_vars : usize
+}
+
+impl Declaration {
+    
+}
\ No newline at end of file
diff --git a/kernel/src/environment.rs b/kernel/src/environment.rs
index a83244ac..01721aca 100644
--- a/kernel/src/environment.rs
+++ b/kernel/src/environment.rs
@@ -1,11 +1,12 @@
 use crate::error::KernelError;
 use crate::term::Term;
+use crate::declaration::Declaration;
 use derive_more::From;
 use std::collections::{hash_map, HashMap};
 
 /// Global Environment, contains the term and type of every definitions, denoted by their strings.
-#[derive(Clone, Default, Debug, Eq, PartialEq, From)]
-pub struct Environment(HashMap<String, (Term, Term)>);
+#[derive(Clone, Default, From)]
+pub struct Environment(HashMap<String, Declaration>);
 
 impl Environment {
     /// Creates an empty environment.
@@ -16,7 +17,7 @@ impl Environment {
     /// Creates a new environment binding s with (t1,t2)
     pub fn insert(&mut self, s: String, t1: Term, t2: Term) -> Result<&Self, KernelError> {
         if let hash_map::Entry::Vacant(e) = self.0.entry(s.clone()) {
-            e.insert((t1, t2));
+            e.insert(Declaration::make(t1, t2));
             Ok(self)
         } else {
             Err(KernelError::AlreadyDefined(s))
diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs
index 331f2a82..d3642508 100644
--- a/kernel/src/lib.rs
+++ b/kernel/src/lib.rs
@@ -8,6 +8,8 @@ mod environment;
 mod error;
 mod term;
 mod type_checker;
+mod universe;
+mod declaration;
 
 pub use derive_more;
 pub use num_bigint;
diff --git a/kernel/src/term.rs b/kernel/src/term.rs
index a840deaa..4abd8686 100644
--- a/kernel/src/term.rs
+++ b/kernel/src/term.rs
@@ -1,15 +1,12 @@
 use crate::environment::Environment;
+use crate::universe::UniverseLevel;
 use derive_more::{Add, Display, From, Into, Sub};
-use num_bigint::BigUint;
 
 #[derive(
     Add, Copy, Clone, Debug, Default, Display, Eq, PartialEq, From, Into, Sub, PartialOrd, Ord,
 )]
 pub struct DeBruijnIndex(usize);
 
-#[derive(Add, Clone, Debug, Default, Display, Eq, From, Sub, PartialEq, PartialOrd, Ord)]
-pub struct UniverseLevel(BigUint);
-
 #[derive(Clone, Debug, Display, Eq, PartialEq)]
 pub enum Term {
     #[display(fmt = "{}", _0)]
diff --git a/kernel/src/type_checker.rs b/kernel/src/type_checker.rs
index ca4c8cb5..611840a8 100644
--- a/kernel/src/type_checker.rs
+++ b/kernel/src/type_checker.rs
@@ -1,8 +1,7 @@
 use crate::environment::Environment;
 use crate::error::KernelError;
 use crate::term::{DeBruijnIndex, Term};
-use num_bigint::BigUint;
-use std::cmp::max;
+use crate::universe::UniverseLevel;
 use std::ops::Index;
 use Term::*;
 
@@ -47,7 +46,7 @@ impl Term {
     /// The conversion is untyped, meaning that it should **only** be called during type-checking when the two `Term`s are already known to be of the same type and in the same context.
     fn conversion(&self, rhs: &Term, env: &Environment, lvl: DeBruijnIndex) -> bool {
         match (self.whnf(env), rhs.whnf(env)) {
-            (Type(i), Type(j)) => i == j,
+            (Type(i), Type(j)) => i.is_eq(&j),
 
             (Prop, Prop) => true,
 
@@ -100,7 +99,7 @@ impl Term {
                 Prop => Ok(Type(i.clone())),
 
                 // else if u1 = Type(i) and u2 = Type(j), then (x : A) -> B : Type(max(i,j))
-                Type(j) => Ok(Type(max(i.clone(), j.clone()))),
+                Type(j) => Ok(Type(UniverseLevel::Max(box i.clone(), box j.clone()))),
 
                 _ => Err(KernelError::NotUniverse(self.clone())),
             },
@@ -111,8 +110,8 @@ impl Term {
 
     fn _infer(&self, env: &Environment, ctx: &mut Context) -> Result<Term, KernelError> {
         match self {
-            Prop => Ok(Type(BigUint::from(0_u64).into())),
-            Type(i) => Ok(Type(i.clone() + BigUint::from(1_u64).into())),
+            Prop => Ok(Type(UniverseLevel::Zero)),
+            Type(i) => Ok(Type(i.clone() + 1)),
             Var(i) => Ok(ctx.types[ctx.lvl - *i].clone()),
 
             Const(s) => match env.get_type(s) {
@@ -199,16 +198,13 @@ mod tests {
 
     #[test]
     fn simple() {
-        let t1 = App(
-            box Abs(box Type(BigUint::from(0_u64).into()), box Var(1.into())),
-            box Prop,
-        );
+        let t1 = App(box Abs(box Type(0.into()), box Var(1.into())), box Prop);
 
         let t2 = Prop;
         assert!(t1.conversion(&t2, &Environment::new(), 0.into()));
 
         let ty = t1.infer(&Environment::new());
-        assert_eq!(ty, Ok(Type(BigUint::from(0_u64).into())));
+        assert_eq!(ty, Ok(Type(0.into())));
     }
 
     #[test]
@@ -317,7 +313,7 @@ mod tests {
     #[test]
     fn polymorphism() {
         let id = Abs(
-            box Type(BigUint::from(0_u64).into()),
+            box Type(0.into()),
             box Abs(box Var(1.into()), box Var(1.into())),
         );
 
@@ -326,8 +322,8 @@ mod tests {
 
     #[test]
     fn type_type() {
-        assert!(Type(BigUint::from(0_u64).into())
-            .check(&Type(BigUint::from(1_u64).into()), &Environment::new())
+        assert!(Type(0.into())
+            .check(&Type(1.into()), &Environment::new())
             .is_ok());
     }
 
@@ -346,18 +342,15 @@ mod tests {
         assert!(t.infer(&Environment::new()).is_err());
 
         let wf_prod = Prod(box Prop, box Prop);
-        assert!(wf_prod
-            .check(&Type(BigUint::from(0_u64).into()), &Environment::new())
-            .is_ok());
+        println!("{:?}",wf_prod.infer(&Environment::new()));
+        assert!(wf_prod.check(&Type(0.into()), &Environment::new()).is_ok());
 
         let wf_prod = Prod(box Prop, box Var(1.into()));
         assert!(wf_prod.check(&Prop, &Environment::new()).is_ok());
 
         // Type0 -> (A : Prop) ->
         let wf_prod = Prod(box Prop, box Prop);
-        assert!(wf_prod
-            .check(&Type(BigUint::from(0_u64).into()), &Environment::new())
-            .is_ok());
+        assert!(wf_prod.check(&Type(0.into()), &Environment::new()).is_ok());
     }
 
     #[test]
@@ -398,7 +391,7 @@ mod tests {
     #[test]
     fn not_def_eq() {
         assert!(Prop
-            .is_def_eq(&Type(BigUint::from(0_u64).into()), &Environment::new())
+            .is_def_eq(&Type(0.into()), &Environment::new())
             .is_err());
     }
 
diff --git a/kernel/src/universe.rs b/kernel/src/universe.rs
index 85ce34ff..4ffa5a1b 100644
--- a/kernel/src/universe.rs
+++ b/kernel/src/universe.rs
@@ -1,56 +1,88 @@
-use derive_more::{Display};
+use std::ops::Add;
+
+use derive_more::Display;
 
 #[derive(Clone, Debug, Default, Display, PartialEq, Eq)]
 pub enum UniverseLevel {
     #[default]
-    UnivZero,
-    UnivSucc(Box<UniverseLevel>),
-    #[display(fmt = "max {} {}", _0, _1)]
-    UnivMax(Box<UniverseLevel>,Box<UniverseLevel>),
-    UnivVar(usize)
+    Zero,
+    Succ(Box<UniverseLevel>),
+    #[display(fmt = "max ({}) ({})", _0, _1)]
+    Max(Box<UniverseLevel>, Box<UniverseLevel>),
+    Var(usize),
 }
-use UniverseLevel::*;
 
-impl UniverseLevel {
-    fn normalize(self) -> Self {
-        match self {
-            UnivMax(box UnivSucc(u1),box UnivSucc(u2)) => UnivSucc(box UnivMax(u1,u2)),
-            UnivMax(box u1,box UnivZero) | UnivMax(box UnivZero, box u1) => u1,
-            UnivMax(u1, u2) if u1.clone().normalize() == u2.clone().normalize() => u1.clone().normalize(),
-            _ => self
-            }
-        }
-    
-    fn shift(self, n : usize) -> Self{
-        match self {
-            UnivZero => self,
-            UnivSucc(u) => UnivSucc(box u.shift(n)),
-            UnivMax(u1,u2) => UnivMax(box u1.shift(n), box u2.shift(n)),
-            UnivVar(k) if k>n => UnivVar(k-1),
-            _ => self
+//Each declaration in the global context has a number corresponding to its number of universe parameters.
+//things to worry about : how to check conversion between universe polymorphic types ? only check universe_eq between them ? might be incomplete.
+// TODO extend universe checking.
+
+impl Add<usize> for UniverseLevel {
+    type Output = Self;
+
+    fn add(self, n: usize) -> Self {
+        if n == 0 {
+            self
+        } else {
+            Succ(box self.add(n - 1))
         }
     }
+}
 
-    fn substitute(self,n : usize) -> Self {
-        
+impl From<usize> for UniverseLevel {
+    fn from(n: usize) -> Self {
+        if n == 0 {
+            Zero
+        } else {
+            Succ(box (n - 1).into())
+        }
     }
+}
 
-    fn geq(self, u2 : UniverseLevel,n : u64) -> bool {
-        match (self,u2) {
-            (UnivZero,_) if n >=0  => true,
-            (_,_) if self == u2 && n>=0 => true,
-            (UnivSucc(l),_) if l.geq(u2,n-1) => true,
-            (_,UnivSucc(box l)) if self.geq(l,n+1) => true,
-            (_,UnivMax(box l1, box l2)) if self.geq(l1,n) || self.geq(l2,n) => true,
-            (UnivMax(box l1, box l2),_) if l1.geq(u2,n) && l2.geq(u2,n) => true
+use UniverseLevel::*;
 
+impl UniverseLevel {
+    /*fn substitute(self, u: &UniverseLevel, lvl : usize) -> Self {
+        match self {
+            UnivZero => UnivZero,
+            UnivSucc(v) => UnivSucc(box v.substitute(u),lvl),
+            UnivMax(u1, u2) => UnivMax(box u1.substitute(u,lvl), box u2.substitute(u,lvl)),
+            UnivVar(var) if var == lvl => u.clone(),
+            UnivVar(var) if var>lvl => UnivVar(var - 1),
+            _ => self
+        }
+    }*/
 
+    fn geq(&self, u2: &UniverseLevel, n: i64) -> bool {
+        match (self, u2) {
+            (Zero, _) if n >= 0 => true,
+            (_, _) if self == u2 && n >= 0 => true,
+            (Succ(l), _) if l.geq(u2, n - 1) => true,
+            (_, Succ(box l)) if self.geq(l, n + 1) => true,
+            (_, Max(box l1, box l2)) if self.geq(l1, n) || self.geq(l2, n) => true,
+            (Max(box l1, box l2), _) if l1.geq(u2, n) && l2.geq(u2, n) => true,
+            _ => false
         }
     }
 
-
-    pub fn is_eq(self,u2 : UniverseLevel) -> bool {
-        self.geq(u2,0) && u2.geq(self,0)
+    pub fn is_eq(&self, u2: &UniverseLevel) -> bool {
+        self.geq(u2, 0) && u2.geq(self, 0)
     }
+}
 
+#[cfg(test)]
+mod tests {
+    use crate::universe::UniverseLevel::*;
+
+    #[test]
+    fn univ_eq() {
+        assert!(format!("{}",Max(box Zero, box Zero)) == "max (Zero) (Zero)");
+        assert!(&Zero.is_eq(&Default::default()));
+        assert!(!&Zero.is_eq(&Succ(box Zero)));
+        assert!(!&Succ(box Zero).is_eq(&Zero));
+        assert!(&Var(0).is_eq(&Max(box Zero, box Var(0))));
+        assert!(&Max(box Zero, box Var(0)).is_eq(&Var(0)));
+        assert!(&Max(box Var(1), box Var(0)).is_eq(&Max(box Var(0), box Var(1))));
+        assert!(!&Max(box Var(1), box Var(1)).is_eq(&Max(box Var(0), box Var(1))));
+        assert!(&Succ(box Max(box Var(1), box Var(0))).is_eq(&Max(box Succ(box Var(0)), box Succ(box Var(1)))));
+    }
 }
-- 
GitLab