Compare commits

..

133 commits
🎋 ... 🐉

Author SHA1 Message Date
3ab8669404 some refactoring in tests 2024-06-04 21:49:08 +02:00
2bfe3250cf remove Tighten stuff 2024-06-04 21:49:08 +02:00
f00c802336 functions returning subsings are also subsings 2024-06-02 17:35:56 +02:00
68c414a941 add vec.map 2024-06-02 17:34:58 +02:00
7b3ccfc45a comment out a partial definition in list.quox 2024-06-02 17:34:52 +02:00
519cc4779a add xtt2 and hofmann's quotient types to bib 2024-06-02 17:34:12 +02:00
3e23929b5f export infix 2024-05-27 21:29:37 +02:00
01e16e20e5 more bib stuff 2024-05-27 21:29:37 +02:00
5bf40755b5 beginning of quox stdlib 2024-05-27 21:29:27 +02:00
863849e4c4 clean up subsing η stuff 2024-05-13 01:23:14 +02:00
8fae67d4d5 check the new test actually fails in the right way 2024-05-12 20:32:32 +02:00
d276a66abd slightly improve a log message 2024-05-12 20:30:26 +02:00
b556c2f099 fix some comments 2024-05-12 20:30:18 +02:00
d2a117fe61 fix function η with subsingleton types 2024-05-12 20:30:04 +02:00
c9f66bb6af minor refactor 2024-04-18 11:49:19 +02:00
7f72ed56fb add test for regularity 2024-04-15 22:58:28 +02:00
67c825ab39 add coercion regularity to the equality checker (not to whnf) 2024-04-15 22:58:17 +02:00
ddc2422ffb fix .gitignore 2024-04-15 22:27:55 +02:00
3f7031c613 pack bump 2024-04-15 20:54:23 +02:00
8823154973 add golden test stuff 2024-04-14 20:49:10 +02:00
b7dc5ffdc4 add check for #[main] type 2024-04-14 16:20:40 +02:00
dd697ba56e add CheckBuiltin 2024-04-14 16:20:25 +02:00
32b9fe124f minor tweaks in Q.Typing.Context 2024-04-14 15:48:10 +02:00
95a0b38d74 update pretty-printing tests 2024-04-12 22:00:08 +02:00
7883a3cae7 pretty printing fixes 2024-04-12 21:54:25 +02:00
a1d8fd4ab5 %inline 2024-04-12 21:53:54 +02:00
9d60f366cf add #![log] pragma 2024-04-12 21:53:54 +02:00
f56f594839 push multiple loglevel changes at once 2024-04-12 21:53:54 +02:00
fca75377a0 MakeName ⇒ MkName for consistency 2024-04-12 21:53:50 +02:00
11b0ab6a25 remove default from FromParser.fromParserPure and Main.step 2024-04-07 03:20:42 +02:00
7a0bc73d25 approximate log stack in handleLogDiscard 2024-04-06 20:14:24 +02:00
567176e076 log refactors 2024-04-05 18:43:00 +02:00
3b6ae36e4e add logging to core 2024-04-04 19:26:41 +02:00
861bd55f94 add log effects to FromParser 2024-04-04 19:26:41 +02:00
e6ad16813e add log effects to executable 2024-04-04 19:26:41 +02:00
78555711ce add Q.Log 2024-04-04 19:26:41 +02:00
ec839a1d48 big Main refactor 2024-04-04 19:26:41 +02:00
727f968afb add delimited continuations to bib 2024-04-04 19:26:30 +02:00
41c8a92c97 bib fixes 2024-04-04 19:26:13 +02:00
efddb1aea1 skip broken pretty-printing tests till i fix them 2024-03-27 18:21:45 +01:00
8cba73f741 bump pack collection 2024-03-27 18:21:26 +01:00
582666a254 comments in infer for coercions 2024-03-21 21:29:13 +01:00
a9e8f14ad5 fix a small bug in Q.Whnf.Coercion 2024-03-21 21:29:01 +01:00
a8ac6f11f7 fix a quantity in CaseBox 2024-02-28 16:49:15 +01:00
b67162bda1 fix the other similar loops
closes #38, again
2024-02-24 16:04:38 +01:00
24ae5b85a2 fix a broken test???? 2024-02-24 15:45:04 +01:00
325e128063 add η for False and True 2024-02-10 11:39:07 +01:00
642ac25a71 happy new year [pack update. also idris 0.7.0] 2024-02-10 10:14:22 +01:00
05a688d49e reject "" in NatExtra.fromHex 2024-02-10 10:14:22 +01:00
1c8c50f3e2 remove some unneeded Ord impls 2024-02-10 10:14:22 +01:00
f337625801 remove most noLocs 2024-02-10 10:14:22 +01:00
1f01cec322 refactor Main a whole lot 2024-02-10 10:14:22 +01:00
103f019dbd move NDefinition to Quox.Definition and add an untyped one 2024-02-10 10:14:22 +01:00
2cafb35bc1 fix some comments 2024-02-10 10:14:22 +01:00
47069a9316 fill a stray hole 2024-02-10 10:14:22 +01:00
fb14b756c7 add algebraic ornaments to bib 2024-02-10 10:14:22 +01:00
81783dbae0 fix typechecker loop when coercing boxes
closes #38
2024-02-10 10:07:06 +01:00
a14c4ca1cb never inline let bindings from the original source 2023-12-21 18:04:12 +01:00
b7074720ad pretty printing fixes 2023-12-21 18:03:57 +01:00
48a050491c fix several quantity issues
- contents of box intro
- definition of let
- non-recursive ℕ case
- also make a few var names more consistent
2023-12-21 18:01:17 +01:00
aa4ead592a allow "let x : A = e in s" with type annotation 2023-12-21 17:54:31 +01:00
54db7e27ef make #[fail] run in the current namespace 2023-12-21 17:53:46 +01:00
7afcbfe258 recognise nats other than 0 in eq checker 2023-12-21 17:48:12 +01:00
0fdd4741be print quantity on let 2023-12-07 01:43:39 +01:00
03c197bd04 add local bindings to context
- without this, inside the body of `let x = e in …`, the typechecker
  would forget that `x = e`
- now bound variables can reduce, if they have a definition, so RedexTest
  needs to take the context too
2023-12-07 01:43:39 +01:00
cdf1ec6deb fix a comment 2023-12-04 23:38:17 +01:00
08a8c694b1 a usage in hello.quox. why not 2023-12-04 23:36:30 +01:00
8b8129027d update syntax.ebnf 2023-12-04 23:35:54 +01:00
e48f03a61c multiple semi-sep binds in a let 2023-12-04 23:27:59 +01:00
415a823dec comment out an unfinished definition lmao 2023-12-04 22:49:32 +01:00
b1699ce022 add let to the core 2023-12-04 22:47:52 +01:00
68d8019f00 add let to frontend syntax 2023-12-04 18:56:45 +01:00
59e7a457a6 let case be the head of an application too 2023-12-04 18:28:57 +01:00
4291afd51b allow fst/snd to take multiple arguments
also succ though that won't be well typed
2023-12-04 18:21:28 +01:00
e2ad18ff1f hello.quox tweaks 2023-11-16 18:33:03 +01:00
310822ffa5 remove old replaced stuff 2023-11-16 18:32:38 +01:00
d115672d49 example stuff 2023-11-10 15:07:19 +01:00
cc78ccd940 fix some parenthesisation 2023-11-06 22:11:11 +01:00
50984aa1aa refactor #[attribute] stuff 2023-11-05 20:49:02 +01:00
246d80eea2 add io.quox 2023-11-05 15:48:01 +01:00
c48b7be559 add html output highlighting 2023-11-05 15:47:52 +01:00
040a1862c3 refactor scheme prelude 2023-11-05 15:45:33 +01:00
bf8cced888 swap some delim/syntax highlighting around 2023-11-05 15:45:07 +01:00
04af7ae942 highlight the @ in dim apps as a delim 2023-11-05 15:44:44 +01:00
d9cdf1306d fix IsReserved
IsReserved should be true for e.g. "λ" but not "fun", since only the
first can show up in the lexer output
2023-11-05 15:43:20 +01:00
6c8ebfb804 fix some comments 2023-11-05 15:41:21 +01:00
da3cd404f3 handle when getTermCols returns 0 2023-11-05 15:40:19 +01:00
f58fa5218f subscript numbers are no longer special 2023-11-05 15:39:52 +01:00
580fbc8fd8 add misc.refl, misc.sing, nat.minus 2023-11-05 15:38:38 +01:00
e211887a34 string/nat lit stuff 2023-11-05 15:38:13 +01:00
3b9a339e5e rename "Tag" highlight to "Constant" 2023-11-05 14:30:40 +01:00
2f8a2d2cd2 fix typo in error 2023-11-04 17:45:55 +01:00
b6c435049d escape strings in scheme
the characters \, ", and everything below space or above ~ are replaced
with a \xdd;-style escape inside string literals
2023-11-03 20:17:35 +01:00
90cdcfe4da add \n and \t escapes to the lexer 2023-11-03 20:07:59 +01:00
d4639a35c6 add hello.quox to examples 2023-11-03 18:05:54 +01:00
b7e1f37b5b add some #[compile-scheme] 2023-11-03 18:05:54 +01:00
5dfefe443c more tidying of outputs 2023-11-03 18:05:54 +01:00
0514fff481 represent ℕ constants directly
instead of as huge `succ (succ (succ ⋯))` terms
2023-11-03 18:05:54 +01:00
fa7f82ae5a rename Nat to NAT in AST 2023-11-03 18:05:54 +01:00
e0ed37720f always vsep scheme lets, otherwise they are unreadable 2023-11-03 18:05:54 +01:00
4cc50c6bcd highlight errors even if real output is to a file
(unless told not to)
2023-11-03 18:05:54 +01:00
050346e344 add postulate, #[compile-scheme], #[main] 2023-11-03 18:05:54 +01:00
cc0bade747 scheme output 2023-11-03 18:05:54 +01:00
cd08a0fd98 more erasure 2023-11-03 18:05:54 +01:00
1f14e4ab9e automate more option stuff
if the elaborator writes it then it will be kept up to date
automatically
2023-11-03 18:05:54 +01:00
314e7f036d make nat elimination with erased IH non-recursive at runtime 2023-11-03 18:05:54 +01:00
6ab9637ab5 don't keep erased applications actually 2023-11-03 18:05:54 +01:00
b6fd1e921e pretty printing improvements 2023-11-03 18:05:54 +01:00
f4a45b6c52 keep the Except effect at the start of the list 2023-11-03 18:05:54 +01:00
8e0d66cab8 more erasure 2023-11-03 18:05:54 +01:00
ea74c148b7 some of this EffExtra stuff doesn't work 2023-11-03 18:05:54 +01:00
83ab871d61 new main 2023-11-03 18:05:54 +01:00
421eb220fd erasure refactor 2023-11-03 18:05:54 +01:00
fbb862c88b %default total 2023-11-03 18:05:54 +01:00
b651ed5447 LoadFile does the parsing 2023-11-03 18:05:54 +01:00
d6985cad55 tweak the pretty printer stuff slightly 2023-11-03 18:05:54 +01:00
52e54dcc3c add PrettyVal stuff for parser AST 2023-11-03 18:05:54 +01:00
0c1df54d62 improve handling of context lengths 2023-11-03 18:05:54 +01:00
2e9183bc14 add prettyDef 2023-11-03 18:05:54 +01:00
428397f42b erasure to untyped syntax 2023-11-03 18:05:54 +01:00
0b7bd0ef46 add locations and substitutions to untyped syntax 2023-11-03 18:05:54 +01:00
9cbd998d6f simplify isEmpty and isSubSing 2023-11-03 18:05:54 +01:00
6896c8fcc4 rename SQtys to sg (σ) 2023-11-03 18:05:54 +01:00
be8797a3ef untyped λ calculus syntax 2023-11-03 18:05:54 +01:00
bf605486f0 example updates
- misc.All doesn't need to be a ★¹
- add pair.map-fst and pair.map-snd
- add bool.dup!
- tweak quantities in eta.from-false
- add fail.quox to all.quox
- add qty.quox
2023-11-03 18:05:35 +01:00
69f032584e fix constructor name in comment 2023-11-03 17:56:42 +01:00
9ecaaf72bd bump pack collection 2023-10-22 19:18:38 +02:00
f04c4619ef detect reserved words inside names like 'a.λ.b' 2023-09-24 17:36:26 +02:00
d4de74eab6 change it to #[..] since # is also reserved 2023-09-22 18:38:40 +02:00
bcfb0d81b8 update tests 2023-09-22 18:38:32 +02:00
8395bec4cb check for duplicate cases in enum matches 2023-09-22 18:37:53 +02:00
6153b4f7f8 add a couple of failing examples 2023-09-22 14:03:22 +02:00
d4cfbd4045 add @[fail] modifier to declarations
- `@[fail] def foo = ...` succeeds if `foo` has some error.
- `@[fail "scope"] def foo = ...` succeeds if `foo` has some error
  containing the word "scope" somewhere
- `@[fail] namespace foo { }` works too and the error must be anywhere
  in the namespace
2023-09-22 14:03:22 +02:00
135 changed files with 8806 additions and 2621 deletions

2
.gitignore vendored
View file

@ -5,3 +5,5 @@ result
*~ *~
quox quox
quox-tests quox-tests
golden-tests/tests/*/output
golden-tests/tests/*/*.ss

View file

@ -6,3 +6,5 @@ load "nat.quox"
load "pair.quox" load "pair.quox"
load "list.quox" load "list.quox"
load "eta.quox" load "eta.quox"
load "fail.quox"
load "qty.quox"

View file

@ -18,8 +18,13 @@ def if2 : 0.(A B : ★) → (b : Bool) → ω.A → ω.B → if¹ ★ b A B =
def0 T : Bool → ★ = λ b ⇒ if¹ ★ b True False; def0 T : Bool → ★ = λ b ⇒ if¹ ★ b True False;
def boolω : Bool → [ω.Bool] = def dup! : (b : Bool) → [ω. Sing Bool b] =
λ b ⇒ if [ω.Bool] b ['true] ['false]; λ b ⇒ if-dep (λ b ⇒ [ω. Sing Bool b]) b
[('true, [δ _ ⇒ 'true])]
[('false, [δ _ ⇒ 'false])];
def dup : Bool → [ω. Bool] =
λ b ⇒ appω (Sing Bool b) Bool (sing.val Bool b) (dup! b);
def true-not-false : Not ('true ≡ 'false : Bool) = def true-not-false : Not ('true ≡ 'false : Bool) =
λ eq ⇒ coe (𝑖 ⇒ T (eq @𝑖)) 'true; λ eq ⇒ coe (𝑖 ⇒ T (eq @𝑖)) 'true;

View file

@ -18,8 +18,8 @@ def0 pair : (A : ★) → (B : A → ★) → (P : Σ A B → ★) → (e : Σ A
λ A B P e p ⇒ p λ A B P e p ⇒ p
-- not exactly η, but kinda related -- not exactly η, but kinda related
def0 from-false : (A : ★) → (P : (False → A) → ★) → (f : False → A) → def0 from-false : (A : ★) → (P : (0.False → A) → ★) → (f : 0.False → A) →
P (λ x ⇒ void A x) → P f = P (void A) → P f =
λ A P f p ⇒ p λ A P f p ⇒ p
} }

16
examples/fail.quox Normal file
View file

@ -0,0 +1,16 @@
#[fail "but cases for"]
def missing-b : {a, b} → {a} =
λ x ⇒ case x return {a} of { 'a ⇒ 'a }
#[fail "duplicate arms"]
def repeat-enum-case : {a} → {a} =
λ x ⇒ case x return {a} of { 'a ⇒ 'a; 'a ⇒ 'a }
#[fail "duplicate tags"]
def repeat-enum-type : {a, a} = 'a
#[fail "double-def.X has already been defined"]
namespace double-def {
def0 X : ★ = {a}
def0 X : ★ = {a}
}

26
examples/hello.quox Normal file
View file

@ -0,0 +1,26 @@
def0 Unit : ★ = {tt}
def drop-unit : 0.(A : ★) → Unit → A → A =
λ A u x ⇒ case u return A of {'tt ⇒ x}
def0 IO : ★ → ★ = λ A ⇒ IOState → A × IOState
def bind : 0.(A B : ★) → IO A → (A → IO B) → IO B =
λ A B m k s0 ⇒
case m s0 return B × IOState of { (x, s1) ⇒ k x s1 }
def seq : IO Unit → IO Unit → IO Unit =
λ a b ⇒ bind Unit Unit a (λ u ⇒ drop-unit (IO Unit) u b)
#[compile-scheme "(lambda (n) (builtin-io (printf \"~d~n\" n) 'tt))"]
postulate print- : → IO Unit
#[compile-scheme "(lambda (s) (builtin-io (printf \"~s~n\" s) 'tt))"]
postulate print : String → IO Unit
load "nat.quox"
#[main]
def main : IO Unit =
let1 sixty-nine = nat.plus 60 9 in
seq (print- sixty-nine) (print "(nice)")

31
examples/io.quox Normal file
View file

@ -0,0 +1,31 @@
load "misc.quox"
namespace io {
def0 IORes : ★ → ★ = λ A ⇒ A × IOState
def0 IO : ★ → ★ = λ A ⇒ IOState → IORes A
def pure : 0.(A : ★) → A → IO A = λ A x s ⇒ (x, s)
def bind : 0.(A B : ★) → IO A → (A → IO B) → IO B =
λ A B m k s0 ⇒
case m s0 return IORes B of { (x, s1) ⇒ k x s1 }
def seq : 0.(B : ★) → IO True → IO B → IO B =
λ B x y ⇒ bind True B x (λ u ⇒ case u return IO B of { 'true ⇒ y })
def seq' : IO True → IO True → IO True = seq True
#[compile-scheme "(lambda (str) (builtin-io (display str) 'true))"]
postulate print : String → IO True
def newline = print "\n"
def println : String → IO True =
λ str ⇒ seq' (print str) newline
#[compile-scheme "(builtin-io (get-line (current-input-port)))"]
postulate readln : IO String
}

View file

@ -24,6 +24,7 @@ def elim : 0.(A : ★) → 0.(P : (n : ) → Vec n A → ★) →
} }
}; };
#[compile-scheme "(lambda% (n xs) xs)"]
def up : 0.(A : ★) → (n : ) → Vec n A → Vec¹ n A = def up : 0.(A : ★) → (n : ) → Vec n A → Vec¹ n A =
λ A n ⇒ λ A n ⇒
case n return n' ⇒ Vec n' A → Vec¹ n' A of { case n return n' ⇒ Vec n' A → Vec¹ n' A of {
@ -63,6 +64,7 @@ def elim : 0.(A : ★) → 0.(P : List A → ★) →
}; };
-- [fixme] List A <: List¹ A should be automatic, imo -- [fixme] List A <: List¹ A should be automatic, imo
#[compile-scheme "(lambda (xs) xs)"]
def up : 0.(A : ★) → List A → List¹ A = def up : 0.(A : ★) → List A → List¹ A =
λ A xs ⇒ λ A xs ⇒
case xs return List¹ A of { (len, elems) ⇒ case xs return List¹ A of { (len, elems) ⇒

View file

@ -6,7 +6,7 @@ def0 Not : ★ → ★ = λ A ⇒ ω.A → False
def void : 0.(A : ★) → 0.False → A = def void : 0.(A : ★) → 0.False → A =
λ A v ⇒ case0 v return A of { } λ A v ⇒ case0 v return A of { }
def0 All : (A : ★) → (0.A → ★) → ★¹ = def0 All : (A : ★) → (0.A → ★) → ★ =
λ A P ⇒ (x : A) → P x λ A P ⇒ (x : A) → P x
def0 cong : def0 cong :
@ -14,6 +14,11 @@ def0 cong :
(x y : A) → (xy : x ≡ y : A) → Eq (𝑖 ⇒ P (xy @𝑖)) (p x) (p y) = (x y : A) → (xy : x ≡ y : A) → Eq (𝑖 ⇒ P (xy @𝑖)) (p x) (p y) =
λ A P p x y xy ⇒ δ 𝑖 ⇒ p (xy @𝑖) λ A P p x y xy ⇒ δ 𝑖 ⇒ p (xy @𝑖)
def0 cong' :
(A B : ★) → (f : A → B) →
(x y : A) → (xy : x ≡ y : A) → f x ≡ f y : B =
λ A B ⇒ cong A (λ _ ⇒ B)
def0 coherence : def0 coherence :
(A B : ★) → (AB : A ≡ B : ★) → (x : A) → (A B : ★) → (AB : A ≡ B : ★) → (x : A) →
Eq (𝑖 ⇒ AB @𝑖) x (coe (𝑖 ⇒ AB @𝑖) x) = Eq (𝑖 ⇒ AB @𝑖) x (coe (𝑖 ⇒ AB @𝑖) x) =
@ -32,6 +37,8 @@ def funext :
(All A (eq-f A P p q)) → p ≡ q : All A P = (All A (eq-f A P p q)) → p ≡ q : All A P =
λ A P p q eq ⇒ δ 𝑖 ⇒ λ x ⇒ eq x @𝑖 λ A P p q eq ⇒ δ 𝑖 ⇒ λ x ⇒ eq x @𝑖
def refl : 0.(A : ★) → (x : A) → x ≡ x : A = λ A x ⇒ δ _ ⇒ x
def sym : 0.(A : ★) → 0.(x y : A) → (x ≡ y : A) → y ≡ x : A = def sym : 0.(A : ★) → 0.(x y : A) → (x ≡ y : A) → y ≡ x : A =
λ A x y eq ⇒ δ 𝑖 ⇒ comp A (eq @0) @𝑖 { 0 𝑗 ⇒ eq @𝑗; 1 _ ⇒ eq @0 } λ A x y eq ⇒ δ 𝑖 ⇒ comp A (eq @0) @𝑖 { 0 𝑗 ⇒ eq @𝑗; 1 _ ⇒ eq @0 }
@ -51,6 +58,9 @@ def0 HEq : (A B : ★) → A → B → ★¹ =
def0 Sing : (A : ★) → A → ★ = def0 Sing : (A : ★) → A → ★ =
λ A x ⇒ (val : A) × [0. val ≡ x : A] λ A x ⇒ (val : A) × [0. val ≡ x : A]
def sing : 0.(A : ★) → (x : A) → Sing A x =
λ A x ⇒ (x, [δ _ ⇒ x])
namespace sing { namespace sing {
def val : 0.(A : ★) → 0.(x : A) → Sing A x → A = def val : 0.(A : ★) → 0.(x : A) → Sing A x → A =

View file

@ -4,11 +4,27 @@ load "either.quox";
namespace nat { namespace nat {
def elim-0-1 :
0.(P : → ★) →
ω.(P 0) → ω.(P 1) →
ω.(0.(n : ) → P n → P (succ n)) →
(n : ) → P n =
λ P p0 p1 ps n ⇒
case n return n' ⇒ P n' of {
zero ⇒ p0;
succ n' ⇒
case n' return n'' ⇒ P (succ n'') of {
zero ⇒ p1;
succ n'', IH ⇒ ps (succ n'') IH
}
}
#[compile-scheme "(lambda (n) (cons n 'erased))"]
def dup! : (n : ) → [ω. Sing n] = def dup! : (n : ) → [ω. Sing n] =
λ n ⇒ λ n ⇒
case n return n' ⇒ [ω. Sing n'] of { case n return n' ⇒ [ω. Sing n'] of {
zero ⇒ [(zero, [δ _ ⇒ zero])]; zero ⇒ [(zero, [δ _ ⇒ zero])];
succ n, 1.d ⇒ succ n, d ⇒
appω (Sing n) (Sing (succ n)) appω (Sing n) (Sing (succ n))
(sing.app n (λ n ⇒ succ n)) d (sing.app n (λ n ⇒ succ n)) d
}; };
@ -16,18 +32,20 @@ def dup! : (n : ) → [ω. Sing n] =
def dup : → [ω.] = def dup : → [ω.] =
λ n ⇒ appω (Sing n) (sing.val n) (dup! n); λ n ⇒ appω (Sing n) (sing.val n) (dup! n);
#[compile-scheme "(lambda% (m n) (+ m n))"]
def plus : = def plus : =
λ m n ⇒ λ m n ⇒
case m return of { case m return of {
zero ⇒ n; zero ⇒ n;
succ _, 1.p ⇒ succ p succ _, p ⇒ succ p
}; };
#[compile-scheme "(lambda% (m n) (* m n))"]
def timesω : → ω. = def timesω : → ω. =
λ m n ⇒ λ m n ⇒
case m return of { case m return of {
zero ⇒ zero; zero ⇒ zero;
succ _, 1.t ⇒ plus n t succ _, t ⇒ plus n t
}; };
def times : = def times : =
@ -41,6 +59,14 @@ def pred-succ : ω.(n : ) → pred (succ n) ≡ n : =
def0 succ-inj : (m n : ) → succ m ≡ succ n : → m ≡ n : = def0 succ-inj : (m n : ) → succ m ≡ succ n : → m ≡ n : =
λ m n eq ⇒ δ 𝑖 ⇒ pred (eq @𝑖); λ m n eq ⇒ δ 𝑖 ⇒ pred (eq @𝑖);
#[compile-scheme "(lambda% (m n) (max 0 (- m n)))"]
def minus : =
λ m n ⇒
(case n return of {
zero ⇒ λ m ⇒ m;
succ _, f ⇒ λ m ⇒ f (pred m)
}) m;
def0 IsSucc : → ★ = def0 IsSucc : → ★ =
λ n ⇒ case n return ★ of { zero ⇒ False; succ _ ⇒ True }; λ n ⇒ case n return ★ of { zero ⇒ False; succ _ ⇒ True };
@ -67,6 +93,7 @@ def0 not-succ-self : (m : ) → Not (m ≡ succ m : ) =
} }
#[compile-scheme "(lambda% (m n) (if (= m n) Yes No))"]
def eq? : DecEq = def eq? : DecEq =
λ m ⇒ λ m ⇒
caseω m caseω m
@ -94,25 +121,45 @@ def eqb : ω. → ω. → Bool = λ m n ⇒ dec.bool (m ≡ n : ) (eq?
def0 plus-zero : (m : ) → m ≡ plus m 0 : = def0 plus-zero : (m : ) → m ≡ plus m 0 : =
λ m ⇒ λ m ⇒
case m return m' ⇒ m' ≡ plus m' 0 : of { case m return m' ⇒ m' ≡ plus m' 0 : of {
zero ⇒ δ _ ⇒ zero; zero ⇒ δ _ ⇒ 0;
succ _, ω.ih ⇒ δ 𝑖 ⇒ succ (ih @𝑖) succ m', ih ⇒ δ 𝑖 ⇒ succ (ih @𝑖)
}; };
def0 plus-succ : (m n : ) → succ (plus m n) ≡ plus m (succ n) : = def0 plus-succ : (m n : ) → succ (plus m n) ≡ plus m (succ n) : =
λ m n ⇒ λ m n ⇒
case m return m' ⇒ succ (plus m' n) ≡ plus m' (succ n) : of { case m return m' ⇒ succ (plus m' n) ≡ plus m' (succ n) : of {
zero ⇒ δ _ ⇒ succ n; zero ⇒ δ _ ⇒ succ n;
succ _, ω.ih ⇒ δ 𝑖 ⇒ succ (ih @𝑖) succ _, ih ⇒ δ 𝑖 ⇒ succ (ih @𝑖)
}; };
def0 plus-comm : (m n : ) → plus m n ≡ plus n m : = def0 plus-comm : (m n : ) → plus m n ≡ plus n m : =
λ m n ⇒ λ m n ⇒
case m return m' ⇒ plus m' n ≡ plus n m' : of { case m return m' ⇒ plus m' n ≡ plus n m' : of {
zero ⇒ plus-zero n; zero ⇒ plus-zero n;
succ m', ω.ih ⇒ succ m', ih ⇒
trans (succ (plus m' n)) (succ (plus n m')) (plus n (succ m')) trans (succ (plus m' n)) (succ (plus n m')) (plus n (succ m'))
𝑖 ⇒ succ (ih @𝑖)) 𝑖 ⇒ succ (ih @𝑖))
(plus-succ n m') (plus-succ n m')
}; };
def0 times-zero : (m : ) → 0 ≡ timesω m 0 : =
λ m ⇒
case m return m' ⇒ 0 ≡ timesω m' 0 : of {
zero ⇒ δ _ ⇒ zero;
succ m', ih ⇒ ih
};
{-
-- unfinished
def0 times-succ : (m n : ) → plus m (timesω m n) ≡ timesω m (succ n) : =
λ m n ⇒
case m
return m' ⇒ plus m' (timesω m' n) ≡ timesω m' (succ n) :
of {
zero ⇒ δ _ ⇒ 0;
succ m', ih ⇒
δ 𝑖 ⇒ plus (succ n) (ih @𝑖)
};
-}
} }

View file

@ -28,7 +28,7 @@ def curry :
λ A B C f x y ⇒ f (x, y); λ A B C f x y ⇒ f (x, y);
def curry' : def curry' :
0.(A B C : ★) → ((A × B) → C) → A → B → C = 0.(A B C : ★) → (A × B → C) → A → B → C =
λ A B C ⇒ curry A (λ _ ⇒ B) (λ _ ⇒ C); λ A B C ⇒ curry A (λ _ ⇒ B) (λ _ ⇒ C);
def0 fst-snd : def0 fst-snd :
@ -54,13 +54,19 @@ def map :
0.(A A' : ★) → 0.(A A' : ★) →
0.(B : A → ★) → 0.(B' : A' → ★) → 0.(B : A → ★) → 0.(B' : A' → ★) →
(f : A → A') → (g : 0.(x : A) → (B x) → B' (f x)) → (f : A → A') → (g : 0.(x : A) → (B x) → B' (f x)) →
(Σ A B) → Σ A' B' = Σ A B → Σ A' B' =
λ A A' B B' f g p ⇒ λ A A' B B' f g p ⇒
case p return Σ A' B' of { (x, y) ⇒ (f x, g x y) }; case p return Σ A' B' of { (x, y) ⇒ (f x, g x y) };
def map' : 0.(A A' B B' : ★) → (A → A') → (B → B') → (A × B) → A' × B' = def map' : 0.(A A' B B' : ★) → (A → A') → (B → B') → (A × B) → A' × B' =
λ A A' B B' f g ⇒ map A A' (λ _ ⇒ B) (λ _ ⇒ B') f (λ _ ⇒ g); λ A A' B B' f g ⇒ map A A' (λ _ ⇒ B) (λ _ ⇒ B') f (λ _ ⇒ g);
def map-fst : 0.(A A' B : ★) → (A → A') → A × B → A' × B =
λ A A' B f ⇒ map' A A' B B f (λ x ⇒ x);
def map-snd : 0.(A B B' : ★) → (B → B') → A × B → A × B' =
λ A B B' f ⇒ map' A A B B' (λ x ⇒ x) f;
} }
def0 Σ = pair.Σ; def0 Σ = pair.Σ;

77
examples/qty.quox Normal file
View file

@ -0,0 +1,77 @@
def0 Qty : ★ = {"zero", one, any}
def dup : Qty → [ω.Qty] =
λ π ⇒ case π return [ω.Qty] of {
'zero ⇒ ['zero];
'one ⇒ ['one];
'any ⇒ ['any];
}
def drop : 0.(A : ★) → Qty → A → A =
λ A π x ⇒ case π return A of {
'zero ⇒ x;
'one ⇒ x;
'any ⇒ x;
}
def if-zero : 0.(A : ★) → Qty → ω.A → ω.A → A =
λ A π z nz ⇒
case π return A of { 'zero ⇒ z; 'one ⇒ nz; 'any ⇒ nz }
def plus : Qty → Qty → Qty =
λ π ρ
case π return Qty of {
'zero ⇒ ρ;
'one ⇒ if-zero Qty ρ 'one 'any;
'any ⇒ drop Qty ρ 'any;
}
def times : Qty → Qty → Qty =
λ π ρ
case π return Qty of {
'zero ⇒ drop Qty ρ 'zero;
'one ⇒ ρ;
'any ⇒ if-zero Qty ρ 'zero 'any;
}
def0 FUN : Qty → (A : ★) → (A → ★) → ★ =
λ π A B ⇒
case π return ★ of {
'zero ⇒ 0.(x : A) → B x;
'one ⇒ 1.(x : A) → B x;
'any ⇒ ω.(x : A) → B x;
}
def0 Fun : Qty → ★ → ★ → ★ =
λ π A B ⇒ FUN π A (λ _ ⇒ B)
def0 Box : Qty → ★ → ★ =
λ π A ⇒
case π return ★ of {
'zero ⇒ [0.A];
'one ⇒ [1.A];
'any ⇒ [ω.A];
}
def0 unbox : (π : Qty) → (A : ★) → Box π A → A =
λ π A ⇒
case π return π' ⇒ Box π' A → A of {
'zero ⇒ λ x ⇒ case x return A of { [x] ⇒ x };
'one ⇒ λ x ⇒ case x return A of { [x] ⇒ x };
'any ⇒ λ x ⇒ case x return A of { [x] ⇒ x };
}
def0 unbox0 = unbox 'zero
def0 unbox1 = unbox 'one
def0 unboxω = unbox 'any
def apply : (π : Qty) → 0.(A : ★) → 0.(B : A → ★) →
FUN π A B → (x : Box π A) → B (unbox π A x) =
λ π A B ⇒
case π
return π' ⇒ FUN π' A B → (x : Box π' A) → B (unbox π' A x)
of {
'zero ⇒ λ f x ⇒ case x return x' ⇒ B (unbox0 A x') of { [x] ⇒ f x };
'one ⇒ λ f x ⇒ case x return x' ⇒ B (unbox1 A x') of { [x] ⇒ f x };
'any ⇒ λ f x ⇒ case x return x' ⇒ B (unboxω A x') of { [x] ⇒ f x };
}

164
exe/CompileMonad.idr Normal file
View file

@ -0,0 +1,164 @@
module CompileMonad
import Quox.Syntax as Q
import Quox.Definition as Q
import Quox.Untyped.Syntax as U
import Quox.Parser
import Quox.Untyped.Erase
import Quox.Untyped.Scheme
import Quox.Pretty
import Quox.Log
import Options
import Output
import Error
import System.File
import Data.IORef
import Data.Maybe
import Control.Eff
%default total
%hide Doc.(>>=)
%hide Core.(>>=)
%hide FromParser.Error
%hide Erase.Error
%hide Lexer.Error
%hide Parser.Error
public export
record State where
constructor MkState
seen : IORef SeenSet
defs : IORef Q.Definitions
ns : IORef Mods
suf : IORef NameSuf
%name CompileMonad.State state
export %inline
newState : HasIO io => io State
newState = pure $ MkState {
seen = !(newIORef empty),
defs = !(newIORef empty),
ns = !(newIORef [<]),
suf = !(newIORef 0)
}
public export
data CompileTag = OPTS | STATE
public export
Compile : List (Type -> Type)
Compile =
[Except Error,
ReaderL STATE State, ReaderL OPTS Options, Log,
LoadFile, IO]
export %inline
handleLog : IORef LevelStack -> OpenFile -> LogL x a -> IOErr Error a
handleLog ref f l = case f of
OConsole ch => handleLogIO (const $ pure ()) ref (consoleHandle ch) l
OFile _ h => handleLogIO (const $ pure ()) ref h l
ONone => do
lvls <- readIORef ref
lenRef <- newIORef (length lvls)
res <- handleLogDiscardIO lenRef l
writeIORef ref $ fixupDiscardedLog !(readIORef lenRef) lvls
pure res
private %inline
withLogFile : Options ->
(IORef LevelStack -> OpenFile -> IO (Either Error a)) ->
IO (Either Error a)
withLogFile opts act = do
lvlStack <- newIORef $ singleton opts.logLevels
withOutFile CErr opts.logFile fromError $ act lvlStack
where
fromError : String -> FileError -> IO (Either Error a)
fromError file err = pure $ Left $ WriteError file err
export covering %inline
runCompile : Options -> State -> Eff Compile a -> IO (Either Error a)
runCompile opts state act = do
withLogFile opts $ \lvls, logFile =>
fromIOErr $ runEff act $ with Union.(::)
[handleExcept (\e => ioLeft e),
handleReaderConst state,
handleReaderConst opts,
handleLog lvls logFile,
handleLoadFileIOE loadError ParseError state.seen opts.include,
liftIO]
private %inline
rethrowFileC : String -> Either FileError a -> Eff Compile a
rethrowFileC f = rethrow . mapFst (WriteError f)
export %inline
outputStr : OpenFile -> Lazy String -> Eff Compile ()
outputStr ONone _ = pure ()
outputStr (OConsole COut) str = putStr str
outputStr (OConsole CErr) str = fPutStr stderr str >>= rethrowFileC "<stderr>"
outputStr (OFile f h) str = fPutStr h str >>= rethrowFileC f
export %inline
outputDocs : OpenFile ->
({opts : LayoutOpts} -> Eff Pretty (List (Doc opts))) ->
Eff Compile ()
outputDocs file docs = do
opts <- askAt OPTS
for_ (runPretty opts (toOutFile file) docs) $ \x =>
outputStr file $ render (Opts opts.width) x
export %inline
outputDoc : OpenFile ->
({opts : LayoutOpts} -> Eff Pretty (Doc opts)) -> Eff Compile ()
outputDoc file doc = outputDocs file $ singleton <$> doc
public export
data StopTag = STOP
public export
CompileStop : List (Type -> Type)
CompileStop = FailL STOP :: Compile
export %inline
withEarlyStop : Eff CompileStop () -> Eff Compile ()
withEarlyStop = ignore . runFailAt STOP
export %inline
stopHere : Has (FailL STOP) fs => Eff fs ()
stopHere = failAt STOP
export %inline
liftFromParser : Eff FromParserIO a -> Eff Compile a
liftFromParser act =
runEff act $ with Union.(::)
[handleExcept $ \err => throw $ FromParserError err,
handleStateIORef !(asksAt STATE defs),
handleStateIORef !(asksAt STATE ns),
handleStateIORef !(asksAt STATE suf),
\g => send g,
\g => send g]
export %inline
liftErase : Q.Definitions -> Eff Erase a -> Eff Compile a
liftErase defs act =
runEff act
[handleExcept $ \err => throw $ EraseError err,
handleStateIORef !(asksAt STATE suf),
\g => send g]
export %inline
liftScheme : Eff Scheme a -> Eff Compile (a, List Id)
liftScheme act = do
runEff [|MkPair act (getAt MAIN)|]
[handleStateIORef !(newIORef empty),
handleStateIORef !(newIORef [])]

49
exe/Error.idr Normal file
View file

@ -0,0 +1,49 @@
module Error
import Quox.Pretty
import Quox.Parser
import Quox.Untyped.Erase
import Quox.Untyped.Scheme
import Options
import Output
import System.File
public export
data Error =
ParseError String Parser.Error
| FromParserError FromParser.Error
| EraseError Erase.Error
| WriteError FilePath FileError
| NoMain
| MultipleMains (List Scheme.Id)
%hide FromParser.Error
%hide Erase.Error
%hide Lexer.Error
%hide Parser.Error
export
loadError : Loc -> FilePath -> FileError -> Error
loadError loc file err = FromParserError $ LoadError loc file err
export
prettyError : {opts : LayoutOpts} -> Error -> Eff Pretty (Doc opts)
prettyError (ParseError file e) = prettyParseError file e
prettyError (FromParserError e) = FromParser.prettyError True e
prettyError (EraseError e) = Erase.prettyError True e
prettyError NoMain = pure "no #[main] function given"
prettyError (MultipleMains xs) =
pure $ sep ["multiple #[main] functions given:",
separateLoose "," !(traverse prettyId xs)]
prettyError (WriteError file e) = pure $
hangSingle 2 (text "couldn't write file \{file}:") (pshow e)
export
dieError : Options -> Error -> IO a
dieError opts e =
die (Opts opts.width) $
runPretty ({outFile := Console} opts) Console $
prettyError e

View file

@ -1,46 +1,118 @@
module Main module Main
import Quox.Syntax import Quox.Syntax as Q
import Quox.Definition as Q
import Quox.Untyped.Syntax as U
import Quox.Parser import Quox.Parser
import Quox.Definition import Quox.Untyped.Erase
import Quox.Untyped.Scheme
import Quox.Pretty import Quox.Pretty
import Quox.Log
import Options
import Output
import Error
import CompileMonad
import System import System
import System.File
import Data.IORef import Data.IORef
import Data.SortedSet
import Control.Eff import Control.Eff
private %default total
Opts : LayoutOpts
Opts = Opts 80 %hide Doc.(>>=)
%hide Core.(>>=)
%hide FromParser.Error
%hide Erase.Error
%hide Lexer.Error
%hide Parser.Error
private private
putDoc : Doc Opts -> IO () Step : Type -> Type -> Type
putDoc = putStr . render Opts Step a b = OpenFile -> a -> Eff Compile b
private private
die : Doc Opts -> IO a step : ConsoleChannel -> Phase -> OutFile -> Step a b -> a -> Eff CompileStop b
die err = do putDoc err; exitFailure step console phase file act x = do
opts <- askAt OPTS
res <- withOutFile console file fromError $ \h => lift $ act h x
when (opts.until == Just phase) stopHere
pure res
where
fromError : String -> FileError -> Eff CompileStop c
fromError file err = throw $ WriteError file err
private
prettySig : Name -> Definition -> Eff Pretty (Doc Opts)
prettySig name def = do
qty <- prettyQty def.qty.qty
name <- prettyFree name
type <- prettyTerm [<] [<] def.type
hangDSingle (hsep [hcat [qty, !dotD, name], !colonD]) type
export private covering
parse : Step String PFile
parse h file = do
Just ast <- loadFile noLoc file
| Nothing => pure []
outputStr h $ show ast
pure ast
private covering
check : Step PFile (List Q.NDefinition)
check h decls =
map concat $ for decls $ \decl => do
defs <- liftFromParser $ fromPTopLevel decl
outputDocs h $ traverse (\(x, d) => prettyDef x d) defs
pure defs
private covering
erase : Step (List Q.NDefinition) (List U.NDefinition)
erase h defList =
for defList $ \(x, def) => do
def <- liftErase defs $ eraseDef defs x def
outputDoc h $ U.prettyDef x def
pure (x, def)
where defs = SortedMap.fromList defList
private covering
scheme : Step (List U.NDefinition) (List Sexp, List Id)
scheme h defs = do
sexps' <- for defs $ \(x, d) => do
(msexp, mains) <- liftScheme $ defToScheme x d
outputDoc h $ case msexp of
Just s => prettySexp s
Nothing => pure $ hsep [";;", prettyName x, "erased"]
pure (msexp, mains)
pure $ bimap catMaybes concat $ unzip sexps'
private covering
output : Step (List Sexp, List Id) ()
output h (sexps, mains) = do
main <- case mains of
[m] => pure m
[] => throw NoMain
_ => throw $ MultipleMains mains
lift $ outputDocs h $ do
res <- traverse prettySexp sexps
runner <- makeRunMain main
pure $ text Scheme.prelude :: res ++ [runner]
private covering
processFile : String -> Eff Compile ()
processFile file = withEarlyStop $ pipeline !(askAt OPTS) file where
pipeline : Options -> String -> Eff CompileStop ()
pipeline opts =
step CErr Parse opts.dump.parse Main.parse >=>
step CErr Check opts.dump.check Main.check >=>
step CErr Erase opts.dump.erase Main.erase >=>
step CErr Scheme opts.dump.scheme Main.scheme >=>
step COut End opts.outFile Main.output
export covering
main : IO () main : IO ()
main = do main = do
seen <- newIORef SortedSet.empty (_, opts, files) <- options
defs <- newIORef SortedMap.empty case !(runCompile opts !newState $ traverse_ processFile files) of
suf <- newIORef 0 Right () => pure ()
for_ (drop 1 !getArgs) $ \file => do Left e => dieError opts e
putStrLn "checking \{file}"
Right res <- fromParserIO ["."] seen suf defs $ loadProcessFile noLoc file
| Left err => die $ runPrettyColor $ prettyError True err
for_ res $ \(name, def) => putDoc $ runPrettyColor $ prettySig name def
----------------------------------- -----------------------------------
{- {-
@ -55,6 +127,13 @@ text _ =
#" /_/"#, #" /_/"#,
""] ""]
-- ["",
-- #" __ _ _ _ _____ __"#,
-- #"/ _` | || / _ \ \ /"#,
-- #"\__, |\_,_\___/_\_\"#,
-- #" |_|"#,
-- ""]
private private
qtuwu : PrettyOpts -> List String qtuwu : PrettyOpts -> List String
qtuwu opts = qtuwu opts =

258
exe/Options.idr Normal file
View file

@ -0,0 +1,258 @@
module Options
import Quox.Pretty
import Quox.Log
import Data.DPair
import Data.SortedMap
import System
import System.Console.GetOpt
import System.File
import System.Term
import Derive.Prelude
%default total
%language ElabReflection
public export
data OutFile = File String | Console | NoOut
%name OutFile f
%runElab derive "OutFile" [Eq, Show]
public export
data Phase = Parse | Check | Erase | Scheme | End
%name Phase p
%runElab derive "Phase" [Eq, Show]
||| a list of all intermediate `Phase`s (excluding `End`)
public export %inline
allPhases : List Phase
allPhases = %runElab do
cs <- getCons $ fst !(lookupName "Phase")
traverse (check . var) $ fromMaybe [] $ init' cs
||| `Guess` is `Term` for a terminal and `NoHL` for a file
public export
data HLType = Guess | NoHL | Term | Html
%runElab derive "HLType" [Eq, Show]
public export
record Dump where
constructor MkDump
parse, check, erase, scheme : OutFile
%name Dump dump
%runElab derive "Dump" [Show]
public export
record Options where
constructor MkOpts
include : List String
dump : Dump
outFile : OutFile
until : Maybe Phase
hlType : HLType
flavor : Pretty.Flavor
width : Nat
logLevels : LogLevels
logFile : OutFile
%name Options opts
%runElab derive "Options" [Show]
export
defaultWidth : IO Nat
defaultWidth = do
w <- cast {to = Nat} <$> getTermCols
pure $ if w == 0 then 80 else w
export
defaultOpts : IO Options
defaultOpts = pure $ MkOpts {
include = ["."],
dump = MkDump NoOut NoOut NoOut NoOut,
outFile = Console,
until = Nothing,
hlType = Guess,
flavor = Unicode,
width = !defaultWidth,
logLevels = defaultLogLevels,
logFile = Console
}
private
data HelpType = Common | All
private
data OptAction = ShowHelp HelpType | Err String | Ok (Options -> Options)
%name OptAction act
private
toOutFile : String -> OutFile
toOutFile "" = NoOut
toOutFile "-" = Console
toOutFile f = File f
private
toPhase : String -> OptAction
toPhase str =
let lstr = toLower str in
case find (\p => toLower (show p) == lstr) allPhases of
Just p => Ok $ setPhase p
Nothing => Err "unknown phase name \{show str}\nphases: \{phaseNames}"
where
phaseNames = joinBy ", " $ map (toLower . show) allPhases
defConsole : OutFile -> OutFile
defConsole NoOut = Console
defConsole f = f
setPhase : Phase -> Options -> Options
setPhase Parse = {until := Just Parse, dump.parse $= defConsole}
setPhase Check = {until := Just Check, dump.check $= defConsole}
setPhase Erase = {until := Just Erase, dump.erase $= defConsole}
setPhase Scheme = {until := Just Scheme, dump.scheme $= defConsole}
setPhase End = id
private
toWidth : String -> OptAction
toWidth s = case parsePositive s of
Just n => Ok {width := n}
Nothing => Err "invalid width: \{show s}"
private
toHLType : String -> OptAction
toHLType str = case toLower str of
"none" => Ok {hlType := NoHL}
"term" => Ok {hlType := Term}
"html" => Ok {hlType := Html}
_ => Err "unknown highlighting type \{show str}\ntypes: term, html, none"
||| like ghc, `-i ""` clears the search path;
||| `-i a:b:c` adds `a`, `b`, `c` to the end
private
dirListFlag : String -> List String -> List String
dirListFlag "" val = []
dirListFlag dirs val = val ++ toList (split (== ':') dirs)
private
splitLogFlag : String -> Either String (List (Maybe LogCategory, LogLevel))
splitLogFlag = traverse flag1 . toList . split (== ':') where
parseLogCategory : String -> Either String LogCategory
parseLogCategory cat = do
let Just cat = toLogCategory cat
| _ => let catList = joinBy ", " logCategories in
Left "unknown log category. categories are:\n\{catList}"
pure cat
parseLogLevel : String -> Either String LogLevel
parseLogLevel lvl = do
let Just lvl = parsePositive lvl
| _ => Left "log level \{lvl} not a number"
let Just lvl = toLogLevel lvl
| _ => Left "log level \{show lvl} out of range 0\{show maxLogLevel}"
pure lvl
flag1 : String -> Either String (Maybe LogCategory, LogLevel)
flag1 str = do
let (first, second) = break (== '=') str
case strM second of
StrCons '=' lvl => do
cat <- parseLogCategory first
lvl <- parseLogLevel lvl
pure (Just cat, lvl)
StrNil => (Nothing,) <$> parseLogLevel first
_ => Left "invalid log flag \{str}"
private
setLogFlag : LogLevels -> (Maybe LogCategory, LogLevel) -> LogLevels
setLogFlag lvls (Nothing, lvl) = {defLevel := lvl} lvls
setLogFlag lvls (Just name, lvl) = {levels $= ((name, lvl) ::)} lvls
private
logFlag : String -> OptAction
logFlag str = case splitLogFlag str of
Left err => Err err
Right flags => Ok $ \o => {logLevels := foldl setLogFlag o.logLevels flags} o
private
commonOptDescrs' : List (OptDescr OptAction)
commonOptDescrs' = [
MkOpt ['i'] ["include"]
(ReqArg (\is => Ok {include $= dirListFlag is}) "<dir>:<dir>...")
"add directories to look for source files",
MkOpt ['o'] ["output"] (ReqArg (\s => Ok {outFile := toOutFile s}) "<file>")
"output file (\"-\" for stdout, \"\" for no output)",
MkOpt ['P'] ["phase"] (ReqArg toPhase "<phase>")
"stop after the given phase",
MkOpt ['l'] ["log"] (ReqArg logFlag "[<cat>=]<n>:...")
"set log level",
MkOpt ['L'] ["log-file"] (ReqArg (\s => Ok {logFile := toOutFile s}) "<file>")
"set log output file"
]
private
extraOptDescrs : List (OptDescr OptAction)
extraOptDescrs = [
MkOpt [] ["unicode"] (NoArg $ Ok {flavor := Unicode})
"use unicode syntax when printing (default)",
MkOpt [] ["ascii"] (NoArg $ Ok {flavor := Ascii})
"use ascii syntax when printing",
MkOpt [] ["width"] (ReqArg toWidth "<width>")
"max output width (defaults to terminal width)",
MkOpt [] ["color", "colour"] (ReqArg toHLType "<type>")
"select highlighting type",
MkOpt [] ["dump-parse"]
(ReqArg (\s => Ok {dump.parse := toOutFile s}) "<file>")
"dump AST",
MkOpt [] ["dump-check"]
(ReqArg (\s => Ok {dump.check := toOutFile s}) "<file>")
"dump typechecker output",
MkOpt [] ["dump-erase"]
(ReqArg (\s => Ok {dump.erase := toOutFile s}) "<file>")
"dump erasure output",
MkOpt [] ["dump-scheme"]
(ReqArg (\s => Ok {dump.scheme := toOutFile s}) "<file>")
"dump scheme output (without prelude)"
]
private
helpOptDescrs : List (OptDescr OptAction)
helpOptDescrs = [
MkOpt ['h'] ["help"] (NoArg $ ShowHelp Common) "show common options",
MkOpt [] ["help-all"] (NoArg $ ShowHelp All) "show all options"
]
commonOptDescrs = commonOptDescrs' ++ helpOptDescrs
allOptDescrs = commonOptDescrs' ++ extraOptDescrs ++ helpOptDescrs
export
usageHeader : String
usageHeader = trim """
quox [options] [file.quox ...]
rawr
"""
export
usage : List (OptDescr _) -> IO a
usage ds = do
ignore $ fPutStr stderr $ usageInfo usageHeader ds
exitSuccess
private
applyAction : Options -> OptAction -> IO Options
applyAction opts (ShowHelp Common) = usage commonOptDescrs
applyAction opts (ShowHelp All) = usage allOptDescrs
applyAction opts (Err err) = die err
applyAction opts (Ok f) = pure $ f opts
export
options : IO (String, Options, List String)
options = do
app :: args <- getArgs
| [] => die "couldn't get command line arguments"
let res = getOpt Permute allOptDescrs args
unless (null res.errors) $
die $ trim $ concat res.errors
unless (null res.unrecognized) $
die "unrecognised options: \{joinBy ", " res.unrecognized}"
opts <- foldlM applyAction !defaultOpts res.options
pure (app, opts, res.nonOptions)

59
exe/Output.idr Normal file
View file

@ -0,0 +1,59 @@
module Output
import Quox.Pretty
import Options
import System.File
import System
public export
data ConsoleChannel = COut | CErr
export
consoleHandle : ConsoleChannel -> File
consoleHandle COut = stdout
consoleHandle CErr = stderr
public export
data OpenFile = OConsole ConsoleChannel | OFile String File | ONone
export
toOutFile : OpenFile -> OutFile
toOutFile (OConsole _) = Console
toOutFile (OFile f _) = File f
toOutFile ONone = NoOut
export
withFile : HasIO m => String -> (String -> FileError -> m a) ->
(OpenFile -> m a) -> m a
withFile f catch act = Prelude.do
res <- withFile f WriteTruncate pure (Prelude.map Right . act . OFile f)
either (catch f) pure res
export
withOutFile : HasIO m => ConsoleChannel -> OutFile ->
(String -> FileError -> m a) -> (OpenFile -> m a) -> m a
withOutFile _ (File f) catch act = withFile f catch act
withOutFile ch Console catch act = act $ OConsole ch
withOutFile _ NoOut catch act = act ONone
private
hlFor : HLType -> OutFile -> HL -> Highlight
hlFor Guess Console = highlightSGR
hlFor Guess _ = noHighlight
hlFor NoHL _ = noHighlight
hlFor Term _ = highlightSGR
hlFor Html _ = highlightHtml
export
runPretty : Options -> OutFile -> Eff Pretty a -> a
runPretty opts file act =
runPrettyWith Outer opts.flavor (hlFor opts.hlType file) 2 act
export
die : HasIO io => (opts : LayoutOpts) -> Doc opts -> io a
die opts err = do
ignore $ fPutStr stderr $ render opts err
exitFailure

View file

@ -1,7 +1,7 @@
package quox package quox
version = 0 version = 0
depends = base, contrib, elab-util, sop, quox-lib depends = base, contrib, elab-util, pretty-show, quox-lib
executable = quox executable = quox
main = Main main = Main

15
golden-tests/Tests.idr Normal file
View file

@ -0,0 +1,15 @@
module Tests
import Test.Golden
import Language.Reflection
import System
import System.Path
%language ElabReflection
projDir = %runElab idrisDir ProjectDir
testDir = projDir </> "tests"
tests = testsInDir { poolName = "quox golden tests", dirName = testDir }
main = runner [!tests]

View file

@ -0,0 +1,4 @@
package quox-golden-tests
depends = quox, contrib, test
executable = quox-golden-tests
main = Tests

10
golden-tests/run-tests.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
set -e
quox="$PWD/../exe/build/exec/quox"
run_tests="$PWD/build/exec/quox-golden-tests"
test -f "$quox" || pack build quox
test -f "$run_tests" || pack build quox-golden-tests
"$run_tests" "$quox" "$@"

View file

View file

View file

@ -0,0 +1,2 @@
. ../lib.sh
scheme "$1" empty.quox

View file

@ -0,0 +1,33 @@
-- inspired by https://github.com/agda/agda/issues/2556
postulate0 A : ★
def0 ZZ : ★ = 0 ≡ 0 :
def reflZ : ZZ = δ _ ⇒ 0
namespace erased {
def0 ZZA : ★ = 0.ZZ → A
def propeq : (x : ZZA) → x ≡ (λ _ ⇒ x reflZ) : ZZA =
λ x ⇒ δ _ ⇒ x
def defeq : 0.(P : ZZA → ★) → 0.(x : ZZA) → P (λ _ ⇒ x reflZ) → P x =
λ P x p ⇒ p
}
namespace unrestricted {
def0 ZZA : ★ = ω.ZZ → A
def defeq : 0.(P : ZZA → ★) → 0.(x : ZZA) → P (λ _ ⇒ x reflZ) → P x =
λ P x p ⇒ p
}
namespace linear {
def0 ZZA : ★ = 1.ZZ → A
#[fail "λ _ ⇒ x reflZ is not equal to x"]
def defeq : 0.(P : ZZA → ★) → 0.(x : ZZA) → P (λ _ ⇒ x reflZ) → P x =
λ P x p ⇒ p
}

View file

@ -0,0 +1,9 @@
0.A : ★
0.ZZ : ★
ω.reflZ : ZZ
0.erased.ZZA : ★
ω.erased.propeq : 1.(x : erased.ZZA) → x ≡ (λ _ ⇒ x reflZ) : erased.ZZA
ω.erased.defeq : 0.(P : 1.erased.ZZA → ★) → 0.(x : erased.ZZA) → 1.(P (λ _ ⇒ (x reflZ))) → P x
0.unrestricted.ZZA : ★
ω.unrestricted.defeq : 0.(P : 1.unrestricted.ZZA → ★) → 0.(x : unrestricted.ZZA) → 1.(P (λ _ ⇒ (x reflZ))) → P x
0.linear.ZZA : ★

View file

@ -0,0 +1,2 @@
. ../lib.sh
check "$1" eta-sing.quox

View file

@ -0,0 +1,3 @@
no location:
couldn't load file nonexistent.quox
File Not Found

View file

@ -0,0 +1,2 @@
. ../lib.sh
check "$1" nonexistent.quox

View file

@ -0,0 +1,12 @@
0.IO : 1.★ → ★
ω.print : 1.String → IO {ok}
ω.main : IO {ok}
IO = □
print = scheme:(lambda (str) (builtin-io (display str) (newline)))
#[main] main = print "hello 🐉"
;; IO erased
(define print
(lambda (str) (builtin-io (display str) (newline))))
(define main
(print "hello \x1f409;"))
hello 🐉

View file

@ -0,0 +1,7 @@
def0 IO : ★ → ★ = λ A ⇒ IOState → A × IOState
#[compile-scheme "(lambda (str) (builtin-io (display str) (newline)))"]
postulate print : String → IO {ok}
#[main]
def main = print "hello 🐉"

View file

@ -0,0 +1,2 @@
. ../lib.sh
compile_run "$1" hello.quox hello.ss

View file

@ -0,0 +1,3 @@
ill-typed-main.quox:1:11-1:12:
when checking a function declared as #[main] has type 1.IOState → {𝑎} × IOState
expected a function type, but got

View file

@ -0,0 +1,2 @@
#[main]
def main : = 5

View file

@ -0,0 +1,2 @@
. ../lib.sh
check "$1" ill-typed-main.quox

View file

@ -0,0 +1,2 @@
0.IsProp : 1.★ → ★
0.feq : 1.(A : ★) → 1.(f : IsProp A) → 1.(g : IsProp A) → f ≡ g : IsProp A

View file

@ -0,0 +1,4 @@
def0 IsProp : ★ → ★ = λ A ⇒ (x y : A) → x ≡ y : A
def0 feq : (A : ★) → (f g : IsProp A) → f ≡ g : IsProp A =
λ A f g ⇒ δ _ ⇒ f

View file

@ -0,0 +1,2 @@
. ../lib.sh
check "$1" isprop-subsing.quox

View file

@ -0,0 +1,4 @@
ω.five :
five = 5
(define five
5)

View file

@ -0,0 +1 @@
def five : = 5

View file

@ -0,0 +1,2 @@
. ../lib.sh
scheme "$1" five.quox

18
golden-tests/tests/lib.sh Normal file
View file

@ -0,0 +1,18 @@
FLAGS="--dump-check - --dump-erase - --dump-scheme - --color=none --width=100000"
check() {
$1 $FLAGS "$2" -P check 2>&1
}
erase() {
$1 $FLAGS "$2" -P erase 2>&1
}
scheme() {
$1 $FLAGS "$2" -P scheme 2>&1
}
compile_run() {
$1 $FLAGS "$2" -o "$3" 2>&1
chezscheme --program "$3"
}

View file

@ -0,0 +1,16 @@
0.lib.IO : 1.★ → ★
ω.lib.print : 1.String → lib.IO {ok}
ω.lib.main : lib.IO {ok}
ω.main : lib.IO {ok}
lib.IO = □
lib.print = scheme:(lambda (str) (builtin-io (display str) (newline)))
lib.main = lib.print "hello 🐉"
#[main] main = lib.main
;; lib.IO erased
(define lib.print
(lambda (str) (builtin-io (display str) (newline))))
(define lib.main
(lib.print "hello \x1f409;"))
(define main
lib.main)
hello 🐉

View file

@ -0,0 +1,8 @@
namespace lib {
def0 IO : ★ → ★ = λ A ⇒ IOState → A × IOState
#[compile-scheme "(lambda (str) (builtin-io (display str) (newline)))"]
postulate print : String → IO {ok}
def main = print "hello 🐉"
}

View file

@ -0,0 +1,4 @@
load "lib.quox"
#[main]
def main = lib.main

View file

@ -0,0 +1,2 @@
. ../lib.sh
compile_run "$1" main.quox load.ss

View file

@ -0,0 +1 @@
0.reggie : 1.(A : ★) → 1.(AA : A ≡ A : ★) → 1.(s : A) → 1.(P : 1.A → ★) → 1.(P (coe (𝑖 ⇒ AA @𝑖) @0 @1 s)) → P s

View file

@ -0,0 +1,12 @@
-- this definition depends on coercion regularity in xtt. which is this
-- (adapted to quox):
--
-- Ψ | Γ ⊢ 0 · A0/𝑖 = A1/𝑖 ⇐ ★
-- ---------------------------------------------------------
-- Ψ | Γ ⊢ π · coe (𝑖 ⇒ A) @p @q s ⇝ (s ∷ A1/𝑖) ⇒ A1/𝑖
--
-- otherwise, the types P (coe ⋯ s) and P s are incompatible
def0 reggie : (A : ★) → (AA : A ≡ A : ★) → (s : A) →
(P : A → ★) → P (coe (𝑖 ⇒ AA @𝑖) s) → P s =
λ A AA s P p ⇒ p

View file

@ -0,0 +1,2 @@
. ../lib.sh
check "$1" regularity.quox

View file

@ -0,0 +1,9 @@
-- non-dependent coe should reduce to its body
def five : = 5
def five? : = coe 5
def eq : five ≡ five? : = δ _ ⇒ 5
def subst1 : 0.(P : → ★) → P five → P five? = λ P p ⇒ p
def subst2 : 0.(P : → ★) → P five? → P five = λ P p ⇒ p

View file

@ -0,0 +1,5 @@
ω.five :
ω.five? :
ω.eq : five ≡ five? :
ω.subst1 : 0.(P : 1. → ★) → 1.(P five) → P five?
ω.subst2 : 0.(P : 1. → ★) → 1.(P five?) → P five

View file

@ -0,0 +1,2 @@
. ../lib.sh
check "$1" coe.quox

View file

@ -62,3 +62,21 @@ export %inline HasST (STErr e) where liftST = STE . map Right
export export
stLeft : e -> STErr e s a stLeft : e -> STErr e s a
stLeft e = STE $ pure $ Left e stLeft e = STE $ pure $ Left e
parameters {auto _ : HasST m}
export %inline
newSTRef' : a -> m s (STRef s a)
newSTRef' x = liftST $ newSTRef x
export %inline
readSTRef' : STRef s a -> m s a
readSTRef' r = liftST $ readSTRef r
export %inline
writeSTRef' : STRef s a -> a -> m s ()
writeSTRef' r x = liftST $ writeSTRef r x
export %inline
modifySTRef' : STRef s a -> (a -> a) -> m s ()
modifySTRef' r f = liftST $ modifySTRef r f

View file

@ -3,8 +3,8 @@ module Quox.BoolExtra
import public Data.Bool import public Data.Bool
infixr 5 `andM` export infixr 5 `andM`
infixr 4 `orM` export infixr 4 `orM`
public export public export
andM, orM : Monad m => m Bool -> m Bool -> m Bool andM, orM : Monad m => m Bool -> m Bool -> m Bool

View file

@ -166,3 +166,10 @@ isWhitespace ch = ch == '\t' || ch == '\r' || ch == '\n' || isSeparator ch
export export
%foreign "scheme:string-normalize-nfc" %foreign "scheme:string-normalize-nfc"
normalizeNfc : String -> String normalizeNfc : String -> String
export
isCodepoint : Int -> Bool
isCodepoint n =
n <= 0x10FFFF &&
not (n >= 0xD800 && n <= 0xDBFF || n >= 0xDC00 && n <= 0xDFFF)

33
lib/Quox/CheckBuiltin.idr Normal file
View file

@ -0,0 +1,33 @@
||| check that special functions (e.g. `main`) have the expected type
module Quox.CheckBuiltin
import Quox.Syntax
import Quox.Typing
import Quox.Whnf
%default total
export covering
expectSingleEnum : Definitions -> TyContext d n -> SQty -> Loc ->
Term d n -> Eff Whnf ()
expectSingleEnum defs ctx sg loc s = do
let err = delay $ ExpectedSingleEnum loc ctx.names s
cases <- wrapErr (const err) $ expectEnum defs ctx sg loc s
unless (length (SortedSet.toList cases) == 1) $ throw err
||| `main` should have a type `1.IOState → {𝑎} × IOState`,
||| for some (single) tag `𝑎`
export covering
expectMainType : Definitions -> Term 0 0 -> Eff Whnf ()
expectMainType defs ty =
wrapErr (WrongBuiltinType Main) $ do
let ctx = TyContext.empty
(qty, arg, res) <- expectPi defs ctx SZero ty.loc ty
expectEqualQ ty.loc qty One
expectIOState defs ctx SZero arg.loc arg
let ctx = extendTy qty res.name arg ctx
(ret, st) <- expectSig defs ctx SZero res.loc res.term
expectSingleEnum defs ctx SZero ret.loc ret
let ctx = extendTy qty st.name ret ctx
expectIOState defs ctx SZero st.loc st.term

View file

@ -158,12 +158,12 @@ getWith : (forall from, to. tm from -> Shift from to -> tm to) ->
Context tm len -> Var len -> tm len Context tm len -> Var len -> tm len
getWith shft = getShiftWith shft SZ getWith shft = getShiftWith shft SZ
infixl 8 !! export infixl 8 !!
public export %inline public export %inline
(!!) : CanShift tm => Context tm len -> Var len -> tm len (!!) : CanShift tm => Context tm len -> Var len -> tm len
(!!) = getWith (//) (!!) = getWith (//)
infixl 8 !!! export infixl 8 !!!
public export %inline public export %inline
(!!!) : Context' tm len -> Var len -> tm (!!!) : Context' tm len -> Var len -> tm
(!!!) = getWith const (!!!) = getWith const
@ -206,7 +206,7 @@ parameters {auto _ : Applicative f}
traverse' : (a -> f b) -> Telescope' a from to -> f (Telescope' b from to) traverse' : (a -> f b) -> Telescope' a from to -> f (Telescope' b from to)
traverse' f = traverse f traverse' f = traverse f
infixl 3 `app` export infixl 3 `app`
||| like `(<*>)` but with effects ||| like `(<*>)` but with effects
export export
app : Telescope (\n => tm1 n -> f (tm2 n)) from to -> app : Telescope (\n => tm1 n -> f (tm2 n)) from to ->

View file

@ -5,7 +5,9 @@ import public Quox.Syntax
import Quox.Displace import Quox.Displace
import public Data.SortedMap import public Data.SortedMap
import public Quox.Loc import public Quox.Loc
import Quox.Pretty
import Control.Eff import Control.Eff
import Data.Singleton
import Decidable.Decidable import Decidable.Decidable
@ -24,18 +26,24 @@ namespace DefBody
public export public export
record Definition where record Definition where
constructor MkDef constructor MkDef
qty : GQty qty : GQty
type0 : Term 0 0 type0 : Term 0 0
body0 : DefBody body0 : DefBody
loc_ : Loc scheme : Maybe String
isMain : Bool
loc_ : Loc
public export %inline public export %inline
mkPostulate : GQty -> (type0 : Term 0 0) -> Loc -> Definition mkPostulate : GQty -> (type0 : Term 0 0) -> Maybe String -> Bool -> Loc ->
mkPostulate qty type0 loc_ = MkDef {qty, type0, body0 = Postulate, loc_} Definition
mkPostulate qty type0 scheme isMain loc_ =
MkDef {qty, type0, body0 = Postulate, scheme, isMain, loc_}
public export %inline public export %inline
mkDef : GQty -> (type0, term0 : Term 0 0) -> Loc -> Definition mkDef : GQty -> (type0, term0 : Term 0 0) -> Maybe String -> Bool -> Loc ->
mkDef qty type0 term0 loc_ = MkDef {qty, type0, body0 = Concrete term0, loc_} Definition
mkDef qty type0 term0 scheme isMain loc_ =
MkDef {qty, type0, body0 = Concrete term0, scheme, isMain, loc_}
export Located Definition where def.loc = def.loc_ export Located Definition where def.loc = def.loc_
export Relocatable Definition where setLoc loc = {loc_ := loc} export Relocatable Definition where setLoc loc = {loc_ := loc}
@ -62,6 +70,18 @@ parameters {d, n : Nat}
toElim : Definition -> Universe -> Maybe $ Elim d n toElim : Definition -> Universe -> Maybe $ Elim d n
toElim def u = pure $ Ann !(def.termAt u) (def.typeAt u) def.loc toElim def u = pure $ Ann !(def.termAt u) (def.typeAt u) def.loc
public export
(.typeWith) : Definition -> Singleton d -> Singleton n -> Term d n
g.typeWith (Val d) (Val n) = g.type
public export
(.typeWithAt) : Definition -> Singleton d -> Singleton n -> Universe -> Term d n
g.typeWithAt d n u = displace u $ g.typeWith d n
public export
(.termWith) : Definition -> Singleton d -> Singleton n -> Maybe (Term d n)
g.termWith (Val d) (Val n) = g.term
public export %inline public export %inline
isZero : Definition -> Bool isZero : Definition -> Bool
@ -69,12 +89,16 @@ isZero g = g.qty == GZero
public export public export
data DefEnvTag = DEFS NDefinition : Type
NDefinition = (Name, Definition)
public export public export
Definitions : Type Definitions : Type
Definitions = SortedMap Name Definition Definitions = SortedMap Name Definition
public export
data DefEnvTag = DEFS
public export public export
DefsReader : Type -> Type DefsReader : Type -> Type
DefsReader = ReaderL DEFS Definitions DefsReader = ReaderL DEFS Definitions
@ -83,7 +107,21 @@ public export
DefsState : Type -> Type DefsState : Type -> Type
DefsState = StateL DEFS Definitions DefsState = StateL DEFS Definitions
public export %inline public export %inline
lookupElim : {d, n : Nat} -> Name -> Universe -> Definitions -> Maybe (Elim d n) lookupElim : {d, n : Nat} -> Name -> Universe -> Definitions -> Maybe (Elim d n)
lookupElim x u defs = toElim !(lookup x defs) u lookupElim x u defs = toElim !(lookup x defs) u
public export %inline
lookupElim0 : Name -> Universe -> Definitions -> Maybe (Elim 0 0)
lookupElim0 = lookupElim
export
prettyDef : {opts : LayoutOpts} -> Name -> Definition -> Eff Pretty (Doc opts)
prettyDef name def = withPrec Outer $ do
qty <- prettyQty def.qty.qty
dot <- dotD
name <- prettyFree name
colon <- colonD
type <- prettyTerm [<] [<] def.type
hangDSingle (hsep [hcat [qty, dot, name], colon]) type

View file

@ -16,6 +16,7 @@ parameters (k : Universe)
namespace Term namespace Term
doDisplace (TYPE l loc) = TYPE (k + l) loc doDisplace (TYPE l loc) = TYPE (k + l) loc
doDisplace (IOState loc) = IOState loc
doDisplace (Pi qty arg res loc) = doDisplace (Pi qty arg res loc) =
Pi qty (doDisplace arg) (doDisplaceS res) loc Pi qty (doDisplace arg) (doDisplaceS res) loc
doDisplace (Lam body loc) = Lam (doDisplaceS body) loc doDisplace (Lam body loc) = Lam (doDisplaceS body) loc
@ -26,11 +27,15 @@ parameters (k : Universe)
doDisplace (Eq ty l r loc) = doDisplace (Eq ty l r loc) =
Eq (doDisplaceDS ty) (doDisplace l) (doDisplace r) loc Eq (doDisplaceDS ty) (doDisplace l) (doDisplace r) loc
doDisplace (DLam body loc) = DLam (doDisplaceDS body) loc doDisplace (DLam body loc) = DLam (doDisplaceDS body) loc
doDisplace (Nat loc) = Nat loc doDisplace (NAT loc) = NAT loc
doDisplace (Zero loc) = Zero loc doDisplace (Nat n loc) = Nat n loc
doDisplace (Succ p loc) = Succ (doDisplace p) loc doDisplace (Succ p loc) = Succ (doDisplace p) loc
doDisplace (STRING loc) = STRING loc
doDisplace (Str s loc) = Str s loc
doDisplace (BOX qty ty loc) = BOX qty (doDisplace ty) loc doDisplace (BOX qty ty loc) = BOX qty (doDisplace ty) loc
doDisplace (Box val loc) = Box (doDisplace val) loc doDisplace (Box val loc) = Box (doDisplace val) loc
doDisplace (Let qty rhs body loc) =
Let qty (doDisplace rhs) (doDisplaceS body) loc
doDisplace (E e) = E (doDisplace e) doDisplace (E e) = E (doDisplace e)
doDisplace (CloT (Sub t th)) = doDisplace (CloT (Sub t th)) =
CloT (Sub (doDisplace t) (assert_total $ map doDisplace th)) CloT (Sub (doDisplace t) (assert_total $ map doDisplace th))

View file

@ -36,6 +36,15 @@ gets : Has (State s) fs => (s -> a) -> Eff fs a
gets = getsAt () gets = getsAt ()
export %inline
stateAt : (0 lbl : tag) -> Has (StateL lbl s) fs => (s -> (a, s)) -> Eff fs a
stateAt lbl f = do (res, x) <- getsAt lbl f; putAt lbl x $> res
export %inline
state : Has (State s) fs => (s -> (a, s)) -> Eff fs a
state = stateAt ()
export export
handleStateIORef : HasIO m => IORef st -> StateL lbl st a -> m a handleStateIORef : HasIO m => IORef st -> StateL lbl st a -> m a
handleStateIORef r Get = readIORef r handleStateIORef r Get = readIORef r
@ -47,7 +56,6 @@ handleStateSTRef r Get = liftST $ readSTRef r
handleStateSTRef r (Put s) = liftST $ writeSTRef r s handleStateSTRef r (Put s) = liftST $ writeSTRef r s
public export public export
data Length : List a -> Type where data Length : List a -> Type where
Z : Length [] Z : Length []
@ -69,25 +77,23 @@ subsetTail : Length xs => (0 x : a) -> Subset xs (x :: xs)
subsetTail _ = subsetWith S subsetTail _ = subsetWith S
export
catchMaybeAt : (0 lbl : tag) -> (Has (ExceptL lbl e) fs, Length fs) =>
(e -> Eff fs a) -> Eff fs a -> Eff fs a
catchMaybeAt lbl hnd act =
catchAt lbl hnd $ lift @{subsetTail $ ExceptL lbl e} act
export %inline
catchMaybe : (Has (Except e) fs, Length fs) =>
(e -> Eff fs a) -> Eff fs a -> Eff fs a
catchMaybe = catchMaybeAt ()
export export
wrapErrAt : (0 lbl : tag) -> (Has (ExceptL lbl e) fs, Length fs) => rethrowAtWith : (0 lbl : tag) -> Has (ExceptL lbl e') fs =>
(e -> e) -> Eff fs a -> Eff fs a (e -> e') -> Either e a -> Eff fs a
wrapErrAt lbl wrap = catchMaybeAt lbl (\ex => throwAt lbl $ wrap ex) rethrowAtWith lbl f = rethrowAt lbl . mapFst f
export %inline export
wrapErr : (Has (Except e) fs, Length fs) => (e -> e) -> Eff fs a -> Eff fs a rethrowWith : Has (Except e') fs => (e -> e') -> Either e a -> Eff fs a
wrapErr = wrapErrAt () rethrowWith = rethrowAtWith ()
export
wrapErr : Length fs => (e -> e') ->
Eff (ExceptL lbl e :: fs) a ->
Eff (ExceptL lbl e' :: fs) a
wrapErr f act =
catchAt lbl (throwAt lbl . f) @{S Z} $
lift @{subsetTail _} act
export export
@ -99,6 +105,10 @@ export
handleReaderConst : Applicative m => r -> ReaderL lbl r a -> m a handleReaderConst : Applicative m => r -> ReaderL lbl r a -> m a
handleReaderConst x Ask = pure x handleReaderConst x Ask = pure x
export
handleWriterSTRef : HasST m => STRef s (SnocList w) -> WriterL lbl w a -> m s a
handleWriterSTRef ref (Tell w) = liftST $ modifySTRef ref (:< w)
public export public export
record IOErr e a where record IOErr e a where

View file

@ -2,9 +2,13 @@ module Quox.Equal
import Quox.BoolExtra import Quox.BoolExtra
import public Quox.Typing import public Quox.Typing
import Data.Maybe
import Quox.EffExtra
import Quox.FreeVars import Quox.FreeVars
import Quox.Pretty
import Quox.EffExtra
import Data.List1
import Data.Maybe
import Data.Either
%default total %default total
@ -15,17 +19,21 @@ EqModeState = State EqMode
public export public export
Equal : List (Type -> Type) Equal : List (Type -> Type)
Equal = [ErrorEff, DefsReader, NameGen] Equal = [ErrorEff, DefsReader, NameGen, Log]
public export public export
EqualInner : List (Type -> Type) EqualInner : List (Type -> Type)
EqualInner = [ErrorEff, NameGen, EqModeState] EqualInner = [ErrorEff, NameGen, EqModeState, Log]
export %inline export %inline
mode : Has EqModeState fs => Eff fs EqMode mode : Has EqModeState fs => Eff fs EqMode
mode = get mode = get
private %inline
withEqual : Has EqModeState fs => Eff fs a -> Eff fs a
withEqual = local_ Equal
parameters (loc : Loc) (ctx : EqContext n) parameters (loc : Loc) (ctx : EqContext n)
private %inline private %inline
@ -45,22 +53,26 @@ public export %inline
sameTyCon : (s, t : Term d n) -> sameTyCon : (s, t : Term d n) ->
(0 ts : So (isTyConE s)) => (0 tt : So (isTyConE t)) => (0 ts : So (isTyConE s)) => (0 tt : So (isTyConE t)) =>
Bool Bool
sameTyCon (TYPE {}) (TYPE {}) = True sameTyCon (TYPE {}) (TYPE {}) = True
sameTyCon (TYPE {}) _ = False sameTyCon (TYPE {}) _ = False
sameTyCon (Pi {}) (Pi {}) = True sameTyCon (IOState {}) (IOState {}) = True
sameTyCon (Pi {}) _ = False sameTyCon (IOState {}) _ = False
sameTyCon (Sig {}) (Sig {}) = True sameTyCon (Pi {}) (Pi {}) = True
sameTyCon (Sig {}) _ = False sameTyCon (Pi {}) _ = False
sameTyCon (Enum {}) (Enum {}) = True sameTyCon (Sig {}) (Sig {}) = True
sameTyCon (Enum {}) _ = False sameTyCon (Sig {}) _ = False
sameTyCon (Eq {}) (Eq {}) = True sameTyCon (Enum {}) (Enum {}) = True
sameTyCon (Eq {}) _ = False sameTyCon (Enum {}) _ = False
sameTyCon (Nat {}) (Nat {}) = True sameTyCon (Eq {}) (Eq {}) = True
sameTyCon (Nat {}) _ = False sameTyCon (Eq {}) _ = False
sameTyCon (BOX {}) (BOX {}) = True sameTyCon (NAT {}) (NAT {}) = True
sameTyCon (BOX {}) _ = False sameTyCon (NAT {}) _ = False
sameTyCon (E {}) (E {}) = True sameTyCon (STRING {}) (STRING {}) = True
sameTyCon (E {}) _ = False sameTyCon (STRING {}) _ = False
sameTyCon (BOX {}) (BOX {}) = True
sameTyCon (BOX {}) _ = False
sameTyCon (E {}) (E {}) = True
sameTyCon (E {}) _ = False
||| true if a type is known to be empty. ||| true if a type is known to be empty.
@ -70,30 +82,43 @@ sameTyCon (E {}) _ = False
||| * `[π.A]` is empty if `A` is. ||| * `[π.A]` is empty if `A` is.
||| * that's it. ||| * that's it.
public export covering public export covering
isEmpty : {n : Nat} -> Definitions -> EqContext n -> SQty -> Term 0 n -> isEmpty :
Eff EqualInner Bool {default 30 logLevel : Nat} -> (0 _ : So (isLogLevel logLevel)) =>
isEmpty defs ctx sg ty0 = do Definitions -> EqContext n -> SQty -> Term 0 n -> Eff EqualInner Bool
private covering
isEmptyNoLog :
Definitions -> EqContext n -> SQty -> Term 0 n -> Eff EqualInner Bool
isEmpty defs ctx sg ty = do
sayMany "equal" ty.loc
[logLevel :> "isEmpty",
95 :> hsep ["ctx =", runPretty $ prettyEqContext ctx],
95 :> hsep ["sg =", runPretty $ prettyQty sg.qty],
logLevel :> hsep ["ty =", runPretty $ prettyTerm [<] ctx.tnames ty]]
res <- isEmptyNoLog defs ctx sg ty
say "equal" logLevel ty.loc $ hsep ["isEmpty ⇝", pshow res]
pure res
isEmptyNoLog defs ctx sg ty0 = do
Element ty0 nc <- whnf defs ctx sg ty0.loc ty0 Element ty0 nc <- whnf defs ctx sg ty0.loc ty0
let Left y = choose $ isTyConE ty0
| Right n => pure False
case ty0 of case ty0 of
TYPE {} => pure False TYPE {} => pure False
IOState {} => pure False
Pi {arg, res, _} => pure False Pi {arg, res, _} => pure False
Sig {fst, snd, _} => Sig {fst, snd, _} =>
isEmpty defs ctx sg fst `orM` isEmpty defs ctx sg fst {logLevel = 90} `orM`
isEmpty defs (extendTy0 snd.name fst ctx) sg snd.term isEmpty defs (extendTy0 snd.name fst ctx) sg snd.term {logLevel = 90}
Enum {cases, _} => Enum {cases, _} =>
pure $ null cases pure $ null cases
Eq {} => pure False Eq {} => pure False
Nat {} => pure False NAT {} => pure False
BOX {ty, _} => isEmpty defs ctx sg ty STRING {} => pure False
E (Ann {tm, _}) => isEmpty defs ctx sg tm BOX {ty, _} => isEmpty defs ctx sg ty {logLevel = 90}
E _ => pure False E _ => pure False
Lam {} => pure False
Pair {} => pure False
Tag {} => pure False
DLam {} => pure False
Zero {} => pure False
Succ {} => pure False
Box {} => pure False
||| true if a type is known to be a subsingleton purely by its form. ||| true if a type is known to be a subsingleton purely by its form.
||| a subsingleton is a type with only zero or one possible values. ||| a subsingleton is a type with only zero or one possible values.
@ -106,32 +131,43 @@ isEmpty defs ctx sg ty0 = do
||| * an enum type is a subsingleton if it has zero or one tags. ||| * an enum type is a subsingleton if it has zero or one tags.
||| * a box type is a subsingleton if its content is ||| * a box type is a subsingleton if its content is
public export covering public export covering
isSubSing : {n : Nat} -> Definitions -> EqContext n -> SQty -> Term 0 n -> isSubSing :
Eff EqualInner Bool {default 30 logLevel : Nat} -> (0 _ : So (isLogLevel logLevel)) =>
isSubSing defs ctx sg ty0 = do Definitions -> EqContext n -> SQty -> Term 0 n -> Eff EqualInner Bool
private covering
isSubSingNoLog :
Definitions -> EqContext n -> SQty -> Term 0 n -> Eff EqualInner Bool
isSubSing defs ctx sg ty = do
sayMany "equal" ty.loc
[logLevel :> "isSubSing",
95 :> hsep ["ctx =", runPretty $ prettyEqContext ctx],
95 :> hsep ["sg =", runPretty $ prettyQty sg.qty],
logLevel :> hsep ["ty =", runPretty $ prettyTerm [<] ctx.tnames ty]]
res <- isSubSingNoLog defs ctx sg ty
say "equal" logLevel ty.loc $ hsep ["isSubsing ⇝", pshow res]
pure res
isSubSingNoLog defs ctx sg ty0 = do
Element ty0 nc <- whnf defs ctx sg ty0.loc ty0 Element ty0 nc <- whnf defs ctx sg ty0.loc ty0
let Left y = choose $ isTyConE ty0 | _ => pure False
case ty0 of case ty0 of
TYPE {} => pure False TYPE {} => pure False
IOState {} => pure False
Pi {arg, res, _} => Pi {arg, res, _} =>
isEmpty defs ctx sg arg `orM` isEmpty defs ctx sg arg {logLevel = 90} `orM`
isSubSing defs (extendTy0 res.name arg ctx) sg res.term isSubSing defs (extendTy0 res.name arg ctx) sg res.term {logLevel = 90}
Sig {fst, snd, _} => Sig {fst, snd, _} =>
isSubSing defs ctx sg fst `andM` isSubSing defs ctx sg fst {logLevel = 90} `andM`
isSubSing defs (extendTy0 snd.name fst ctx) sg snd.term isSubSing defs (extendTy0 snd.name fst ctx) sg snd.term {logLevel = 90}
Enum {cases, _} => Enum {cases, _} =>
pure $ length (SortedSet.toList cases) <= 1 pure $ length (SortedSet.toList cases) <= 1
Eq {} => pure True Eq {} => pure True
Nat {} => pure False NAT {} => pure False
BOX {ty, _} => isSubSing defs ctx sg ty STRING {} => pure False
E (Ann {tm, _}) => isSubSing defs ctx sg tm BOX {ty, _} => isSubSing defs ctx sg ty {logLevel = 90}
E _ => pure False E _ => pure False
Lam {} => pure False
Pair {} => pure False
Tag {} => pure False
DLam {} => pure False
Zero {} => pure False
Succ {} => pure False
Box {} => pure False
||| the left argument if the current mode is `Super`; otherwise the right one. ||| the left argument if the current mode is `Super`; otherwise the right one.
@ -141,12 +177,21 @@ bigger l r = gets $ \case Super => l; _ => r
export export
ensureTyCon : Has ErrorEff fs => ensureTyCon, ensureTyConNoLog :
(loc : Loc) -> (ctx : EqContext n) -> (t : Term 0 n) -> (Has Log fs, Has ErrorEff fs) =>
Eff fs (So (isTyConE t)) (loc : Loc) -> (ctx : EqContext n) -> (t : Term 0 n) ->
ensureTyCon loc ctx t = case nchoose $ isTyConE t of Eff fs (So (isTyConE t))
Left y => pure y ensureTyConNoLog loc ctx ty = do
Right n => throw $ NotType loc (toTyContext ctx) (t // shift0 ctx.dimLen) case nchoose $ isTyConE ty of
Left y => pure y
Right n => throw $ NotType loc (toTyContext ctx) (ty // shift0 ctx.dimLen)
ensureTyCon loc ctx ty = do
sayMany "equal" ty.loc
[60 :> "ensureTyCon",
95 :> hsep ["ctx =", runPretty $ prettyEqContext ctx],
60 :> hsep ["ty =", runPretty $ prettyTerm [<] ctx.tnames ty]]
ensureTyConNoLog loc ctx ty
namespace Term namespace Term
@ -174,30 +219,48 @@ compareType : Definitions -> EqContext n -> (s, t : Term 0 n) ->
Eff EqualInner () Eff EqualInner ()
private
0 NotRedexEq : {isRedex : RedexTest tm} -> CanWhnf tm isRedex =>
Definitions -> EqContext n -> SQty -> Pred (tm 0 n)
NotRedexEq defs ctx sg t = NotRedex defs (toWhnfContext ctx) sg t
namespace Term namespace Term
private covering private covering
compare0' : (defs : Definitions) -> EqContext n -> (sg : SQty) -> compare0' : (defs : Definitions) -> (ctx : EqContext n) -> (sg : SQty) ->
(ty, s, t : Term 0 n) -> (ty, s, t : Term 0 n) ->
(0 _ : NotRedex defs SZero ty) => (0 _ : So (isTyConE ty)) => (0 _ : NotRedexEq defs ctx SZero ty) =>
(0 _ : NotRedex defs sg s) => (0 _ : NotRedex defs sg t) => (0 _ : So (isTyConE ty)) =>
(0 _ : NotRedexEq defs ctx sg s) =>
(0 _ : NotRedexEq defs ctx sg t) =>
Eff EqualInner () Eff EqualInner ()
compare0' defs ctx sg (TYPE {}) s t = compareType defs ctx s t compare0' defs ctx sg (TYPE {}) s t = compareType defs ctx s t
compare0' defs ctx sg ty@(Pi {qty, arg, res, _}) s t = local_ Equal $ compare0' defs ctx sg ty@(IOState {}) s t =
-- Γ ⊢ e = f ⇒ IOState
-- ----------------------
-- Γ ⊢ e = f ⇐ IOState
--
-- (no canonical values, ofc)
case (s, t) of
(E e, E f) => ignore $ Elim.compare0 defs ctx sg e f
(E _, _) => wrongType t.loc ctx ty t
_ => wrongType s.loc ctx ty s
compare0' defs ctx sg ty@(Pi {qty, arg, res, _}) s t = withEqual $
-- Γ ⊢ A empty -- Γ ⊢ A empty
-- ------------------------------------------- -- -------------------------------------------
-- Γ ⊢ (λ x ⇒ s) = (λ x ⇒ t) : (π·x : A) → B -- Γ ⊢ (λ x ⇒ s) = (λ x ⇒ t) ⇐ π.(x : A) → B
if !(isEmpty' arg) then pure () else if !(isEmpty defs ctx sg arg) then pure () else
case (s, t) of case (s, t) of
-- Γ, x : A ⊢ s = t : B -- Γ, x : A ⊢ s = t B
-- ------------------------------------------- -- -------------------------------------------
-- Γ ⊢ (λ x ⇒ s) = (λ x ⇒ t) : (π·x : A) → B -- Γ ⊢ (λ x ⇒ s) = (λ x ⇒ t) ⇐ π.(x : A) → B
(Lam b1 {}, Lam b2 {}) => (Lam b1 {}, Lam b2 {}) =>
compare0 defs ctx' sg res.term b1.term b2.term compare0 defs ctx' sg res.term b1.term b2.term
-- Γ, x : A ⊢ s = e x : B -- Γ, x : A ⊢ s = e x B
-- ----------------------------------- -- -----------------------------------
-- Γ ⊢ (λ x ⇒ s) = e : (π·x : A) → B -- Γ ⊢ (λ x ⇒ s) = e ⇐ π.(x : A) → B
(E e, Lam b {}) => eta s.loc e b (E e, Lam b {}) => eta s.loc e b
(Lam b {}, E e) => eta s.loc e b (Lam b {}, E e) => eta s.loc e b
@ -207,9 +270,6 @@ namespace Term
(E _, t) => wrongType t.loc ctx ty t (E _, t) => wrongType t.loc ctx ty t
(s, _) => wrongType s.loc ctx ty s (s, _) => wrongType s.loc ctx ty s
where where
isEmpty' : Term 0 n -> Eff EqualInner Bool
isEmpty' t = let Val n = ctx.termLen in isEmpty defs ctx sg arg
ctx' : EqContext (S n) ctx' : EqContext (S n)
ctx' = extendTy qty res.name arg ctx ctx' = extendTy qty res.name arg ctx
@ -217,16 +277,18 @@ namespace Term
toLamBody e = E $ App (weakE 1 e) (BVT 0 e.loc) e.loc toLamBody e = E $ App (weakE 1 e) (BVT 0 e.loc) e.loc
eta : Loc -> Elim 0 n -> ScopeTerm 0 n -> Eff EqualInner () eta : Loc -> Elim 0 n -> ScopeTerm 0 n -> Eff EqualInner ()
eta loc e (S _ (N _)) = clashT loc ctx ty s t eta loc e (S _ (N b)) =
eta _ e (S _ (Y b)) = compare0 defs ctx' sg res.term (toLamBody e) b if !(pure (qty /= One) `andM` isSubSing defs ctx sg arg)
then compare0 defs ctx' sg res.term (toLamBody e) (weakT 1 b)
else clashT loc ctx ty s t
eta _ e (S _ (Y b)) =
compare0 defs ctx' sg res.term (toLamBody e) b
compare0' defs ctx sg ty@(Sig {fst, snd, _}) s t = local_ Equal $ compare0' defs ctx sg ty@(Sig {fst, snd, _}) s t = withEqual $
case (s, t) of case (s, t) of
-- Γ ⊢ s₁ = t₁ : A Γ ⊢ s₂ = t₂ : B{s₁/x} -- Γ ⊢ s₁ = t₁ ⇐ A Γ ⊢ s₂ = t₂ ⇐ B{s₁/x}
-- -------------------------------------------- -- --------------------------------------------
-- Γ ⊢ (s₁, t₁) = (s₂,t₂) : (x : A) × B -- Γ ⊢ (s₁, t₁) = (s₂,t₂) ⇐ (x : A) × B
--
-- [todo] η for π ≥ 0 maybe
(Pair sFst sSnd {}, Pair tFst tSnd {}) => do (Pair sFst sSnd {}, Pair tFst tSnd {}) => do
compare0 defs ctx sg fst sFst tFst compare0 defs ctx sg fst sFst tFst
compare0 defs ctx sg (sub1 snd (Ann sFst fst fst.loc)) sSnd tSnd compare0 defs ctx sg (sub1 snd (Ann sFst fst fst.loc)) sSnd tSnd
@ -248,15 +310,16 @@ namespace Term
compare0 defs ctx sg (sub1 snd (Ann s fst s.loc)) (E $ Snd e e.loc) t compare0 defs ctx sg (sub1 snd (Ann s fst s.loc)) (E $ Snd e e.loc) t
SOne => clashT loc ctx ty s t SOne => clashT loc ctx ty s t
compare0' defs ctx sg ty@(Enum {}) s t = local_ Equal $ compare0' defs ctx sg ty@(Enum cases _) s t = withEqual $
-- η for empty & singleton enums
if length (SortedSet.toList cases) <= 1 then pure () else
case (s, t) of case (s, t) of
-- -------------------- -- --------------------
-- Γ ⊢ `t = `t : {ts} -- Γ ⊢ 't = 't ⇐ {ts}
-- --
-- t ∈ ts is in the typechecker, not here, ofc -- t ∈ ts is in the typechecker, not here, ofc
(Tag t1 {}, Tag t2 {}) => (Tag t1 {}, Tag t2 {}) => unless (t1 == t2) $ clashT s.loc ctx ty s t
unless (t1 == t2) $ clashT s.loc ctx ty s t (E e, E f) => ignore $ Elim.compare0 defs ctx sg e f
(E e, E f) => ignore $ Elim.compare0 defs ctx sg e f
(Tag {}, E _) => clashT s.loc ctx ty s t (Tag {}, E _) => clashT s.loc ctx ty s t
(E _, Tag {}) => clashT s.loc ctx ty s t (E _, Tag {}) => clashT s.loc ctx ty s t
@ -269,44 +332,59 @@ namespace Term
-- ✨ uip ✨ -- ✨ uip ✨
-- --
-- ---------------------------- -- ----------------------------
-- Γ ⊢ e = f : Eq [i ⇒ A] s t -- Γ ⊢ e = f Eq [i ⇒ A] s t
pure () pure ()
compare0' defs ctx sg nat@(Nat {}) s t = local_ Equal $ compare0' defs ctx sg nat@(NAT {}) s t = withEqual $
case (s, t) of case (s, t) of
-- --------------- -- ---------------
-- Γ ⊢ 0 = 0 : -- Γ ⊢ n = n ⇐
(Zero {}, Zero {}) => pure () (Nat x {}, Nat y {}) => unless (x == y) $ clashT s.loc ctx nat s t
-- Γ ⊢ s = t : -- Γ ⊢ s = t
-- ------------------------- -- -------------------------
-- Γ ⊢ succ s = succ t : -- Γ ⊢ succ s = succ t ⇐
(Succ s' {}, Succ t' {}) => compare0 defs ctx sg nat s' t' (Succ s' {}, Succ t' {}) => compare0 defs ctx sg nat s' t'
(Nat (S x) {}, Succ t' {}) => compare0 defs ctx sg nat (Nat x s.loc) t'
(Succ s' {}, Nat (S y) {}) => compare0 defs ctx sg nat s' (Nat y t.loc)
(E e, E f) => ignore $ Elim.compare0 defs ctx sg e f (E e, E f) => ignore $ Elim.compare0 defs ctx sg e f
(Zero {}, Succ {}) => clashT s.loc ctx nat s t (Nat 0 {}, Succ {}) => clashT s.loc ctx nat s t
(Zero {}, E _) => clashT s.loc ctx nat s t (Nat 0 {}, E _) => clashT s.loc ctx nat s t
(Succ {}, Zero {}) => clashT s.loc ctx nat s t (Succ {}, Nat 0 {}) => clashT s.loc ctx nat s t
(Succ {}, E _) => clashT s.loc ctx nat s t (Succ {}, E _) => clashT s.loc ctx nat s t
(E _, Zero {}) => clashT s.loc ctx nat s t (E _, Nat 0 {}) => clashT s.loc ctx nat s t
(E _, Succ {}) => clashT s.loc ctx nat s t (E _, Succ {}) => clashT s.loc ctx nat s t
(Zero {}, t) => wrongType t.loc ctx nat t (Nat {}, t) => wrongType t.loc ctx nat t
(Succ {}, t) => wrongType t.loc ctx nat t (Succ {}, t) => wrongType t.loc ctx nat t
(E _, t) => wrongType t.loc ctx nat t (E _, t) => wrongType t.loc ctx nat t
(s, _) => wrongType s.loc ctx nat s (s, _) => wrongType s.loc ctx nat s
compare0' defs ctx sg bty@(BOX q ty {}) s t = local_ Equal $ compare0' defs ctx sg str@(STRING {}) s t = withEqual $
case (s, t) of case (s, t) of
-- Γ ⊢ s = t : A (Str x _, Str y _) => unless (x == y) $ clashT s.loc ctx str s t
(E e, E f) => ignore $ Elim.compare0 defs ctx sg e f
(Str {}, E _) => clashT s.loc ctx str s t
(E _, Str {}) => clashT s.loc ctx str s t
(Str {}, _) => wrongType t.loc ctx str t
(E _, _) => wrongType t.loc ctx str t
_ => wrongType s.loc ctx str s
compare0' defs ctx sg bty@(BOX q ty {}) s t = withEqual $
case (s, t) of
-- Γ ⊢ s = t ⇐ A
-- ----------------------- -- -----------------------
-- Γ ⊢ [s] = [t] : [π.A] -- Γ ⊢ [s] = [t] [π.A]
(Box s _, Box t _) => compare0 defs ctx sg ty s t (Box s _, Box t _) => compare0 defs ctx sg ty s t
-- Γ ⊢ s = (case1 e return A of {[x] ⇒ x}) ⇐ A -- Γ ⊢ σ⨴ρ · s = (case1 e return A of {[x] ⇒ x}) ⇐ A
-- ----------------------------------------------- -- -----------------------------------------------------
-- Γ ⊢ [s] = e ⇐ [ρ.A] -- Γ ⊢ σ · [s] = e ⇐ [ρ.A]
(Box s loc, E f) => eta s f (Box s loc, E f) => eta s f
(E e, Box t loc) => eta t e (E e, Box t loc) => eta t e
@ -320,7 +398,7 @@ namespace Term
eta s e = do eta s e = do
nm <- mnb "inner" e.loc nm <- mnb "inner" e.loc
let e = CaseBox One e (SN ty) (SY [< nm] (BVT 0 nm.loc)) e.loc let e = CaseBox One e (SN ty) (SY [< nm] (BVT 0 nm.loc)) e.loc
compare0 defs ctx sg ty s (E e) compare0 defs ctx (sg `subjMult` q) ty s (E e)
compare0' defs ctx sg ty@(E _) s t = do compare0' defs ctx sg ty@(E _) s t = do
-- a neutral type can only be inhabited by neutral values -- a neutral type can only be inhabited by neutral values
@ -331,9 +409,10 @@ namespace Term
private covering private covering
compareType' : (defs : Definitions) -> EqContext n -> (s, t : Term 0 n) -> compareType' : (defs : Definitions) -> (ctx : EqContext n) ->
(0 _ : NotRedex defs SZero s) => (0 _ : So (isTyConE s)) => (s, t : Term 0 n) ->
(0 _ : NotRedex defs SZero t) => (0 _ : So (isTyConE t)) => (0 _ : NotRedexEq defs ctx SZero s) => (0 _ : So (isTyConE s)) =>
(0 _ : NotRedexEq defs ctx SZero t) => (0 _ : So (isTyConE t)) =>
(0 _ : So (sameTyCon s t)) => (0 _ : So (sameTyCon s t)) =>
Eff EqualInner () Eff EqualInner ()
-- equality is the same as subtyping, except with the -- equality is the same as subtyping, except with the
@ -344,11 +423,15 @@ compareType' defs ctx a@(TYPE k {}) (TYPE l {}) =
-- Γ ⊢ Type 𝓀 <: Type -- Γ ⊢ Type 𝓀 <: Type
expectModeU a.loc !mode k l expectModeU a.loc !mode k l
compareType' defs ctx a@(IOState {}) (IOState {}) =
-- Γ ⊢ IOState <: IOState
pure ()
compareType' defs ctx (Pi {qty = sQty, arg = sArg, res = sRes, loc}) compareType' defs ctx (Pi {qty = sQty, arg = sArg, res = sRes, loc})
(Pi {qty = tQty, arg = tArg, res = tRes, _}) = do (Pi {qty = tQty, arg = tArg, res = tRes, _}) = do
-- Γ ⊢ A₁ :> A₂ Γ, x : A₁ ⊢ B₁ <: B₂ -- Γ ⊢ A₁ :> A₂ Γ, x : A₁ ⊢ B₁ <: B₂
-- ---------------------------------------- -- ----------------------------------------
-- Γ ⊢ (π·x : A₁) → B₁ <: (π·x : A₂) → B₂ -- Γ ⊢ π.(x : A₁) → B₁ <: π.(x : A₂) → B₂
expectEqualQ loc sQty tQty expectEqualQ loc sQty tQty
local flip $ compareType defs ctx sArg tArg -- contra local flip $ compareType defs ctx sArg tArg -- contra
compareType defs (extendTy0 sRes.name sArg ctx) sRes.term tRes.term compareType defs (extendTy0 sRes.name sArg ctx) sRes.term tRes.term
@ -370,7 +453,7 @@ compareType' defs ctx (Eq {ty = sTy, l = sl, r = sr, _})
compareType defs (extendDim sTy.name Zero ctx) sTy.zero tTy.zero compareType defs (extendDim sTy.name Zero ctx) sTy.zero tTy.zero
compareType defs (extendDim sTy.name One ctx) sTy.one tTy.one compareType defs (extendDim sTy.name One ctx) sTy.one tTy.one
ty <- bigger sTy tTy ty <- bigger sTy tTy
local_ Equal $ do withEqual $ do
Term.compare0 defs ctx SZero ty.zero sl tl Term.compare0 defs ctx SZero ty.zero sl tl
Term.compare0 defs ctx SZero ty.one sr tr Term.compare0 defs ctx SZero ty.one sr tr
@ -382,11 +465,16 @@ compareType' defs ctx s@(Enum tags1 {}) t@(Enum tags2 {}) = do
-- a runtime coercion -- a runtime coercion
unless (tags1 == tags2) $ clashTy s.loc ctx s t unless (tags1 == tags2) $ clashTy s.loc ctx s t
compareType' defs ctx (Nat {}) (Nat {}) = compareType' defs ctx (NAT {}) (NAT {}) =
-- ------------ -- ------------
-- Γ ⊢ <: -- Γ ⊢ <:
pure () pure ()
compareType' defs ctx (STRING {}) (STRING {}) =
-- ------------
-- Γ ⊢ String <: String
pure ()
compareType' defs ctx (BOX pi a loc) (BOX rh b {}) = do compareType' defs ctx (BOX pi a loc) (BOX rh b {}) = do
expectEqualQ loc pi rh expectEqualQ loc pi rh
compareType defs ctx a b compareType defs ctx a b
@ -402,9 +490,39 @@ lookupFree : Has ErrorEff fs =>
Definitions -> EqContext n -> Name -> Universe -> Loc -> Definitions -> EqContext n -> Name -> Universe -> Loc ->
Eff fs (Term 0 n) Eff fs (Term 0 n)
lookupFree defs ctx x u loc = lookupFree defs ctx x u loc =
let Val n = ctx.termLen in case lookup x defs of
maybe (throw $ NotInScope loc x) (\d => pure $ d.typeAt u) $ Nothing => throw $ NotInScope loc x
lookup x defs Just d => pure $ d.typeWithAt [|Z|] ctx.termLen u
export
typecaseTel : (k : TyConKind) -> BContext (arity k) -> Universe ->
CtxExtension d n (arity k + n)
typecaseTel k xs u = case k of
KTYPE => [<]
KIOState => [<]
-- A : ★ᵤ, B : 0.A → ★ᵤ
KPi =>
let [< a, b] = xs in
[< (Zero, a, TYPE u a.loc),
(Zero, b, Arr Zero (BVT 0 b.loc) (TYPE u b.loc) b.loc)]
KSig =>
let [< a, b] = xs in
[< (Zero, a, TYPE u a.loc),
(Zero, b, Arr Zero (BVT 0 b.loc) (TYPE u b.loc) b.loc)]
KEnum => [<]
-- A₀ : ★ᵤ, A₁ : ★ᵤ, A : (A₀ ≡ A₁ : ★ᵤ), L : A₀, R : A₀
KEq =>
let [< a0, a1, a, l, r] = xs in
[< (Zero, a0, TYPE u a0.loc),
(Zero, a1, TYPE u a1.loc),
(Zero, a, Eq0 (TYPE u a.loc) (BVT 1 a.loc) (BVT 0 a.loc) a.loc),
(Zero, l, BVT 2 l.loc),
(Zero, r, BVT 2 r.loc)]
KNat => [<]
KString => [<]
-- A : ★ᵤ
KBOX => let [< a] = xs in [< (Zero, a, TYPE u a.loc)]
namespace Elim namespace Elim
@ -418,25 +536,29 @@ namespace Elim
EqualElim : List (Type -> Type) EqualElim : List (Type -> Type)
EqualElim = InnerErrEff :: EqualInner EqualElim = InnerErrEff :: EqualInner
private covering private covering %inline
computeElimTypeE : (defs : Definitions) -> EqContext n -> (sg : SQty) -> computeElimTypeE : (defs : Definitions) -> (ctx : EqContext n) ->
(e : Elim 0 n) -> (0 ne : NotRedex defs sg e) => (sg : SQty) ->
(e : Elim 0 n) -> (0 ne : NotRedexEq defs ctx sg e) =>
Eff EqualElim (Term 0 n) Eff EqualElim (Term 0 n)
computeElimTypeE defs ectx sg e = computeElimTypeE defs ectx sg e = lift $
let Val n = ectx.termLen in computeElimType defs (toWhnfContext ectx) sg e
lift $ computeElimType defs (toWhnfContext ectx) sg e
private private %inline
putError : Has InnerErrEff fs => Error -> Eff fs () putError : Has InnerErrEff fs => Error -> Eff fs ()
putError err = modifyAt InnerErr (<|> Just err) putError err = modifyAt InnerErr (<|> Just err)
private private %inline
try : Eff EqualInner () -> Eff EqualElim () try : Eff EqualInner () -> Eff EqualElim ()
try act = lift $ catch putError $ lift act {fs' = EqualElim} try act = lift $ catch putError $ lift act {fs' = EqualElim}
private %inline
succeeds : Eff EqualInner a -> Eff EqualElim Bool
succeeds act = lift $ map isRight $ runExcept act
private covering %inline private covering %inline
clashE : (defs : Definitions) -> EqContext n -> (sg : SQty) -> clashE : (defs : Definitions) -> (ctx : EqContext n) -> (sg : SQty) ->
(e, f : Elim 0 n) -> (0 nf : NotRedex defs sg f) => (e, f : Elim 0 n) -> (0 nf : NotRedexEq defs ctx sg f) =>
Eff EqualElim (Term 0 n) Eff EqualElim (Term 0 n)
clashE defs ctx sg e f = do clashE defs ctx sg e f = do
putError $ ClashE e.loc ctx !mode e f putError $ ClashE e.loc ctx !mode e f
@ -453,62 +575,68 @@ namespace Elim
(def : Term 0 n) -> (def : Term 0 n) ->
Eff EqualElim () Eff EqualElim ()
compareArm {b1 = Nothing, b2 = Nothing, _} = pure () compareArm {b1 = Nothing, b2 = Nothing, _} = pure ()
compareArm defs ctx k ret u b1 b2 def = compareArm defs ctx k ret u b1 b2 def = do
let def = SN def in let def = SN def
compareArm_ defs ctx k ret u (fromMaybe def b1) (fromMaybe def b2) left = fromMaybe def b1; right = fromMaybe def b2
where names = (fromMaybe def $ b1 <|> b2).names
compareArm_ : Definitions -> EqContext n -> (k : TyConKind) -> try $ compare0 defs (extendTyN (typecaseTel k names u) ctx)
(ret : Term 0 n) -> (u : Universe) -> SZero (weakT (arity k) ret) left.term right.term
(b1, b2 : TypeCaseArmBody k 0 n) ->
Eff EqualElim ()
compareArm_ defs ctx KTYPE ret u b1 b2 =
try $ Term.compare0 defs ctx SZero ret b1.term b2.term
compareArm_ defs ctx KPi ret u b1 b2 = do
let [< a, b] = b1.names
ctx = extendTyN0
[< (a, TYPE u a.loc),
(b, Arr Zero (BVT 0 b.loc) (TYPE u b.loc) b.loc)] ctx
try $ Term.compare0 defs ctx SZero (weakT 2 ret) b1.term b2.term
compareArm_ defs ctx KSig ret u b1 b2 = do
let [< a, b] = b1.names
ctx = extendTyN0
[< (a, TYPE u a.loc),
(b, Arr Zero (BVT 0 b.loc) (TYPE u b.loc) b.loc)] ctx
try $ Term.compare0 defs ctx SZero (weakT 2 ret) b1.term b2.term
compareArm_ defs ctx KEnum ret u b1 b2 =
try $ Term.compare0 defs ctx SZero ret b1.term b2.term
compareArm_ defs ctx KEq ret u b1 b2 = do
let [< a0, a1, a, l, r] = b1.names
ctx = extendTyN0
[< (a0, TYPE u a0.loc),
(a1, TYPE u a1.loc),
(a, Eq0 (TYPE u a.loc) (BVT 1 a0.loc) (BVT 0 a1.loc) a.loc),
(l, BVT 2 a0.loc),
(r, BVT 2 a1.loc)] ctx
try $ Term.compare0 defs ctx SZero (weakT 5 ret) b1.term b2.term
compareArm_ defs ctx KNat ret u b1 b2 =
try $ Term.compare0 defs ctx SZero ret b1.term b2.term
compareArm_ defs ctx KBOX ret u b1 b2 = do
let ctx = extendTy0 b1.name (TYPE u b1.name.loc) ctx
try $ Term.compare0 defs ctx SZero (weakT 1 ret) b1.term b1.term
private covering private covering
compare0Inner : Definitions -> EqContext n -> (sg : SQty) -> compare0Inner : Definitions -> EqContext n -> (sg : SQty) ->
(e, f : Elim 0 n) -> Eff EqualElim (Term 0 n) (e, f : Elim 0 n) -> Eff EqualElim (Term 0 n)
private covering private covering
compare0Inner' : (defs : Definitions) -> EqContext n -> (sg : SQty) -> compare0Inner' : (defs : Definitions) -> (ctx : EqContext n) -> (sg : SQty) ->
(e, f : Elim 0 n) -> (e, f : Elim 0 n) ->
(0 ne : NotRedex defs sg e) -> (0 nf : NotRedex defs sg f) -> (0 ne : NotRedexEq defs ctx sg e) ->
(0 nf : NotRedexEq defs ctx sg f) ->
Eff EqualElim (Term 0 n) Eff EqualElim (Term 0 n)
-- (no neutral dim apps or comps in a closed dctx)
compare0Inner' _ _ _ (DApp _ (K {}) _) _ ne _ =
void $ absurd $ noOr2 $ noOr2 ne
compare0Inner' _ _ _ _ (DApp _ (K {}) _) _ nf =
void $ absurd $ noOr2 $ noOr2 nf
compare0Inner' _ _ _ (Comp {r = K {}, _}) _ ne _ = void $ absurd $ noOr2 ne
compare0Inner' _ _ _ (Comp {r = B i _, _}) _ _ _ = absurd i
compare0Inner' _ _ _ _ (Comp {r = K {}, _}) _ nf = void $ absurd $ noOr2 nf
-- Ψ | Γ ⊢ Ap₁/𝑖 <: Bp₂/𝑖
-- Ψ | Γ ⊢ Aq₁/𝑖 <: Bq₂/𝑖
-- Ψ | Γ ⊢ s <: t ⇐ Bp₂/𝑖
-- -----------------------------------------------------------
-- Ψ | Γ ⊢ coe [𝑖 ⇒ A] @p₁ @q₁ s
-- <: coe [𝑖 ⇒ B] @p₂ @q₂ t ⇒ Bq₂/𝑖
compare0Inner' defs ctx sg (Coe ty1 p1 q1 val1 _)
(Coe ty2 p2 q2 val2 _) ne nf = do
let ty1p = dsub1 ty1 p1; ty2p = dsub1 ty2 p2
ty1q = dsub1 ty1 q1; ty2q = dsub1 ty2 q2
(ty_p, ty_q) <- bigger (ty1p, ty1q) (ty2p, ty2q)
try $ do
compareType defs ctx ty1p ty2p
compareType defs ctx ty1q ty2q
Term.compare0 defs ctx sg ty_p val1 val2
pure $ ty_q
-- an adaptation of the rule
--
-- Ψ | Γ ⊢ A0/𝑖 = A1/𝑖 ⇐ ★
-- -----------------------------------------------------
-- Ψ | Γ ⊢ coe (𝑖 ⇒ A) @p @q s ⇝ (s ∷ A1/𝑖) ⇒ A1/𝑖
--
-- it's here so that whnf doesn't have to depend on the equality checker
compare0Inner' defs ctx sg (Coe ty p q val loc) f _ _ =
if !(succeeds $ withEqual $ compareType defs ctx ty.zero ty.one)
then compare0Inner defs ctx sg (Ann val (dsub1 ty q) loc) f
else clashE defs ctx sg (Coe ty p q val loc) f
-- symmetric version of the above
compare0Inner' defs ctx sg e (Coe ty p q val loc) _ _ =
if !(succeeds $ withEqual $ compareType defs ctx ty.zero ty.one)
then compare0Inner defs ctx sg e (Ann val (dsub1 ty q) loc)
else clashE defs ctx sg e (Coe ty p q val loc)
compare0Inner' defs ctx sg e@(F {}) f _ _ = do compare0Inner' defs ctx sg e@(F {}) f _ _ = do
if e == f then computeElimTypeE defs ctx sg f if e == f then computeElimTypeE defs ctx sg f
else clashE defs ctx sg e f else clashE defs ctx sg e f
@ -537,7 +665,7 @@ namespace Elim
-- = caseπ f return R of { (x, y) ⇒ t } ⇒ Q[e/p] -- = caseπ f return R of { (x, y) ⇒ t } ⇒ Q[e/p]
compare0Inner' defs ctx sg (CasePair epi e eret ebody eloc) compare0Inner' defs ctx sg (CasePair epi e eret ebody eloc)
(CasePair fpi f fret fbody floc) ne nf = (CasePair fpi f fret fbody floc) ne nf =
local_ Equal $ do withEqual $ do
ety <- compare0Inner defs ctx sg e f ety <- compare0Inner defs ctx sg e f
(fst, snd) <- expectSig defs ctx sg eloc ety (fst, snd) <- expectSig defs ctx sg eloc ety
let [< x, y] = ebody.names let [< x, y] = ebody.names
@ -556,7 +684,7 @@ namespace Elim
-- ------------------------------ -- ------------------------------
-- Ψ | Γ ⊢ fst e = fst f ⇒ A -- Ψ | Γ ⊢ fst e = fst f ⇒ A
compare0Inner' defs ctx sg (Fst e eloc) (Fst f floc) ne nf = compare0Inner' defs ctx sg (Fst e eloc) (Fst f floc) ne nf =
local_ Equal $ do withEqual $ do
ety <- compare0Inner defs ctx sg e f ety <- compare0Inner defs ctx sg e f
fst <$> expectSig defs ctx sg eloc ety fst <$> expectSig defs ctx sg eloc ety
compare0Inner' defs ctx sg e@(Fst {}) f _ _ = compare0Inner' defs ctx sg e@(Fst {}) f _ _ =
@ -566,7 +694,7 @@ namespace Elim
-- ------------------------------------ -- ------------------------------------
-- Ψ | Γ ⊢ snd e = snd f ⇒ B[fst e/x] -- Ψ | Γ ⊢ snd e = snd f ⇒ B[fst e/x]
compare0Inner' defs ctx sg (Snd e eloc) (Snd f floc) ne nf = compare0Inner' defs ctx sg (Snd e eloc) (Snd f floc) ne nf =
local_ Equal $ do withEqual $ do
ety <- compare0Inner defs ctx sg e f ety <- compare0Inner defs ctx sg e f
(_, tsnd) <- expectSig defs ctx sg eloc ety (_, tsnd) <- expectSig defs ctx sg eloc ety
pure $ sub1 tsnd (Fst e eloc) pure $ sub1 tsnd (Fst e eloc)
@ -581,7 +709,7 @@ namespace Elim
-- = caseπ f return R of { '𝐚ᵢ ⇒ tᵢ } ⇒ Q[e/x] -- = caseπ f return R of { '𝐚ᵢ ⇒ tᵢ } ⇒ Q[e/x]
compare0Inner' defs ctx sg (CaseEnum epi e eret earms eloc) compare0Inner' defs ctx sg (CaseEnum epi e eret earms eloc)
(CaseEnum fpi f fret farms floc) ne nf = (CaseEnum fpi f fret farms floc) ne nf =
local_ Equal $ do withEqual $ do
ety <- compare0Inner defs ctx sg e f ety <- compare0Inner defs ctx sg e f
try $ try $
compareType defs (extendTy0 eret.name ety ctx) eret.term fret.term compareType defs (extendTy0 eret.name ety ctx) eret.term fret.term
@ -604,16 +732,16 @@ namespace Elim
-- ⇒ Q[e/x] -- ⇒ Q[e/x]
compare0Inner' defs ctx sg (CaseNat epi epi' e eret ezer esuc eloc) compare0Inner' defs ctx sg (CaseNat epi epi' e eret ezer esuc eloc)
(CaseNat fpi fpi' f fret fzer fsuc floc) ne nf = (CaseNat fpi fpi' f fret fzer fsuc floc) ne nf =
local_ Equal $ do withEqual $ do
ety <- compare0Inner defs ctx sg e f ety <- compare0Inner defs ctx sg e f
let [< p, ih] = esuc.names let [< p, ih] = esuc.names
try $ do try $ do
compareType defs (extendTy0 eret.name ety ctx) eret.term fret.term compareType defs (extendTy0 eret.name ety ctx) eret.term fret.term
Term.compare0 defs ctx sg Term.compare0 defs ctx sg
(sub1 eret (Ann (Zero ezer.loc) (Nat ezer.loc) ezer.loc)) (sub1 eret (Ann (Zero ezer.loc) (NAT ezer.loc) ezer.loc))
ezer fzer ezer fzer
Term.compare0 defs Term.compare0 defs
(extendTyN [< (epi, p, Nat p.loc), (epi', ih, eret.term)] ctx) sg (extendTyN [< (epi, p, NAT p.loc), (epi', ih, eret.term)] ctx) sg
(substCaseSuccRet esuc.names eret) esuc.term fsuc.term (substCaseSuccRet esuc.names eret) esuc.term fsuc.term
expectEqualQ e.loc epi fpi expectEqualQ e.loc epi fpi
expectEqualQ e.loc epi' fpi' expectEqualQ e.loc epi' fpi'
@ -628,7 +756,7 @@ namespace Elim
-- = caseπ f return R of { [x] ⇒ t } ⇒ Q[e/x] -- = caseπ f return R of { [x] ⇒ t } ⇒ Q[e/x]
compare0Inner' defs ctx sg (CaseBox epi e eret ebody eloc) compare0Inner' defs ctx sg (CaseBox epi e eret ebody eloc)
(CaseBox fpi f fret fbody floc) ne nf = (CaseBox fpi f fret fbody floc) ne nf =
local_ Equal $ do withEqual $ do
ety <- compare0Inner defs ctx sg e f ety <- compare0Inner defs ctx sg e f
(q, ty) <- expectBOX defs ctx sg eloc ety (q, ty) <- expectBOX defs ctx sg eloc ety
try $ do try $ do
@ -640,12 +768,6 @@ namespace Elim
pure $ sub1 eret e pure $ sub1 eret e
compare0Inner' defs ctx sg e@(CaseBox {}) f _ _ = clashE defs ctx sg e f compare0Inner' defs ctx sg e@(CaseBox {}) f _ _ = clashE defs ctx sg e f
-- (no neutral dim apps in a closed dctx)
compare0Inner' _ _ _ (DApp _ (K {}) _) _ ne _ =
void $ absurd $ noOr2 $ noOr2 ne
compare0Inner' _ _ _ _ (DApp _ (K {}) _) _ nf =
void $ absurd $ noOr2 $ noOr2 nf
-- Ψ | Γ ⊢ s <: t : B -- Ψ | Γ ⊢ s <: t : B
-- -------------------------------- -- --------------------------------
-- Ψ | Γ ⊢ (s ∷ A) <: (t ∷ B) ⇒ B -- Ψ | Γ ⊢ (s ∷ A) <: (t ∷ B) ⇒ B
@ -656,34 +778,11 @@ namespace Elim
try $ Term.compare0 defs ctx sg ty s t try $ Term.compare0 defs ctx sg ty s t
pure ty pure ty
-- Ψ | Γ ⊢ Ap₁/𝑖 <: Bp₂/𝑖
-- Ψ | Γ ⊢ Aq₁/𝑖 <: Bq₂/𝑖
-- Ψ | Γ ⊢ s <: t ⇐ Bp₂/𝑖
-- -----------------------------------------------------------
-- Ψ | Γ ⊢ coe [𝑖 ⇒ A] @p₁ @q₁ s
-- <: coe [𝑖 ⇒ B] @p₂ @q₂ t ⇒ Bq₂/𝑖
compare0Inner' defs ctx sg (Coe ty1 p1 q1 val1 _)
(Coe ty2 p2 q2 val2 _) ne nf = do
let ty1p = dsub1 ty1 p1; ty2p = dsub1 ty2 p2
ty1q = dsub1 ty1 q1; ty2q = dsub1 ty2 q2
(ty_p, ty_q) <- bigger (ty1p, ty1q) (ty2p, ty2q)
try $ do
compareType defs ctx ty1p ty2p
compareType defs ctx ty1q ty2q
Term.compare0 defs ctx sg ty_p val1 val2
pure $ ty_q
compare0Inner' defs ctx sg e@(Coe {}) f _ _ = clashE defs ctx sg e f
-- (no neutral compositions in a closed dctx)
compare0Inner' _ _ _ (Comp {r = K {}, _}) _ ne _ = void $ absurd $ noOr2 ne
compare0Inner' _ _ _ (Comp {r = B i _, _}) _ _ _ = absurd i
compare0Inner' _ _ _ _ (Comp {r = K {}, _}) _ nf = void $ absurd $ noOr2 nf
-- (type case equality purely structural) -- (type case equality purely structural)
compare0Inner' defs ctx sg (TypeCase ty1 ret1 arms1 def1 eloc) compare0Inner' defs ctx sg (TypeCase ty1 ret1 arms1 def1 eloc)
(TypeCase ty2 ret2 arms2 def2 floc) ne _ = (TypeCase ty2 ret2 arms2 def2 floc) ne _ =
case sg `decEq` SZero of case sg `decEq` SZero of
Yes Refl => local_ Equal $ do Yes Refl => withEqual $ do
ety <- compare0Inner defs ctx SZero ty1 ty2 ety <- compare0Inner defs ctx SZero ty1 ty2
u <- expectTYPE defs ctx SZero eloc ety u <- expectTYPE defs ctx SZero eloc ety
try $ do try $ do
@ -713,7 +812,6 @@ namespace Elim
clashE defs ctx sg e f clashE defs ctx sg e f
compare0Inner defs ctx sg e f = do compare0Inner defs ctx sg e f = do
let Val n = ctx.termLen
Element e ne <- whnf defs ctx sg e.loc e Element e ne <- whnf defs ctx sg e.loc e
Element f nf <- whnf defs ctx sg f.loc f Element f nf <- whnf defs ctx sg f.loc f
ty <- compare0Inner' defs ctx sg e f ne nf ty <- compare0Inner' defs ctx sg e f ne nf
@ -724,30 +822,84 @@ namespace Elim
namespace Term namespace Term
compare0 defs ctx sg ty s t = export covering %inline
compare0NoLog :
Definitions -> EqContext n -> SQty -> (ty, s, t : Term 0 n) ->
Eff EqualInner ()
compare0NoLog defs ctx sg ty s t =
wrapErr (WhileComparingT ctx !mode sg ty s t) $ do wrapErr (WhileComparingT ctx !mode sg ty s t) $ do
let Val n = ctx.termLen
Element ty' _ <- whnf defs ctx SZero ty.loc ty Element ty' _ <- whnf defs ctx SZero ty.loc ty
Element s' _ <- whnf defs ctx sg s.loc s Element s' _ <- whnf defs ctx sg s.loc s
Element t' _ <- whnf defs ctx sg t.loc t Element t' _ <- whnf defs ctx sg t.loc t
tty <- ensureTyCon ty.loc ctx ty' tty <- ensureTyCon ty.loc ctx ty'
compare0' defs ctx sg ty' s' t' compare0' defs ctx sg ty' s' t'
compare0 defs ctx sg ty s t = do
sayMany "equal" s.loc
[30 :> "Term.compare0",
30 :> hsep ["mode =", pshow !mode],
95 :> hsep ["ctx =", runPretty $ prettyEqContext ctx],
95 :> hsep ["sg =", runPretty $ prettyQty sg.qty],
31 :> hsep ["ty =", runPretty $ prettyTerm [<] ctx.tnames ty],
30 :> hsep ["s =", runPretty $ prettyTerm [<] ctx.tnames s],
30 :> hsep ["t =", runPretty $ prettyTerm [<] ctx.tnames t]]
compare0NoLog defs ctx sg ty s t
namespace Elim namespace Elim
compare0 defs ctx sg e f = do export covering %inline
compare0NoLog :
Definitions -> EqContext n -> SQty -> (e, f : Elim 0 n) ->
Eff EqualInner (Term 0 n)
compare0NoLog defs ctx sg e f = do
(ty, err) <- runStateAt InnerErr Nothing $ compare0Inner defs ctx sg e f (ty, err) <- runStateAt InnerErr Nothing $ compare0Inner defs ctx sg e f
maybe (pure ty) throw err maybe (pure ty) throw err
compareType defs ctx s t = do compare0 defs ctx sg e f = do
let Val n = ctx.termLen sayMany "equal" e.loc
[30 :> "Elim.compare0",
30 :> hsep ["mode =", pshow !mode],
95 :> hsep ["ctx =", runPretty $ prettyEqContext ctx],
95 :> hsep ["sg =", runPretty $ prettyQty sg.qty],
30 :> hsep ["e =", runPretty $ prettyElim [<] ctx.tnames e],
30 :> hsep ["f =", runPretty $ prettyElim [<] ctx.tnames f]]
ty <- compare0NoLog defs ctx sg e f
say "equal" 31 e.loc $
hsep ["Elim.compare0 ⇝", runPretty $ prettyTerm [<] ctx.tnames ty]
pure ty
export covering %inline
compareTypeNoLog :
Definitions -> EqContext n -> (s, t : Term 0 n) -> Eff EqualInner ()
compareTypeNoLog defs ctx s t = do
Element s' _ <- whnf defs ctx SZero s.loc s Element s' _ <- whnf defs ctx SZero s.loc s
Element t' _ <- whnf defs ctx SZero t.loc t Element t' _ <- whnf defs ctx SZero t.loc t
ts <- ensureTyCon s.loc ctx s' ts <- ensureTyCon s.loc ctx s'
tt <- ensureTyCon t.loc ctx t' tt <- ensureTyCon t.loc ctx t'
st <- either pure (const $ clashTy s.loc ctx s' t') $ let Left _ = choose $ sameTyCon s' t' | _ => clashTy s.loc ctx s' t'
nchoose $ sameTyCon s' t'
compareType' defs ctx s' t' compareType' defs ctx s' t'
compareType defs ctx s t = do
sayMany "equal" s.loc
[30 :> "compareType",
30 :> hsep ["mode =", pshow !mode],
95 :> hsep ["ctx =", runPretty $ prettyEqContext ctx],
30 :> hsep ["s =", runPretty $ prettyTerm [<] ctx.tnames s],
30 :> hsep ["t =", runPretty $ prettyTerm [<] ctx.tnames t]]
compareTypeNoLog defs ctx s t
private
getVars : TyContext d _ -> FreeVars d -> List BindName
getVars ctx (FV fvs) = case ctx.dctx of
ZeroIsOne => []
C eqs => toList $ getVars' ctx.dnames eqs fvs
where
getVars' : BContext d' -> DimEq' d' -> FreeVars' d' -> SnocList BindName
getVars' (names :< name) (eqs :< eq) (fvs :< fv) =
let rest = getVars' names eqs fvs in
case eq of Nothing => rest :< name
Just _ => rest
getVars' [<] [<] [<] = [<]
parameters (loc : Loc) (ctx : TyContext d n) parameters (loc : Loc) (ctx : TyContext d n)
parameters (mode : EqMode) parameters (mode : EqMode)
@ -756,10 +908,12 @@ parameters (loc : Loc) (ctx : TyContext d n)
fromInner = lift . map fst . runState mode fromInner = lift . map fst . runState mode
private private
eachFace : Applicative f => FreeVars d -> eachCorner : Has Log fs => Loc -> FreeVars d ->
(EqContext n -> DSubst d 0 -> f ()) -> f () (EqContext n -> DSubst d 0 -> Eff fs ()) -> Eff fs ()
eachFace fvs act = eachCorner loc fvs act = do
let Val d = ctx.dimLen in say "equal" 50 loc $
let vars = map prettyBind' (getVars ctx fvs) in
hsep $ "eachCorner: split on" :: if null vars then ["(none)"] else vars
for_ (splits loc ctx.dctx fvs) $ \th => for_ (splits loc ctx.dctx fvs) $ \th =>
act (makeEqContext ctx th) th act (makeEqContext ctx th) th
@ -769,32 +923,36 @@ parameters (loc : Loc) (ctx : TyContext d n)
Definitions -> EqContext n -> DSubst d 0 -> Eff EqualInner () Definitions -> EqContext n -> DSubst d 0 -> Eff EqualInner ()
private private
runCompare : FreeVars d -> CompareAction d n -> Eff Equal () runCompare : Loc -> FreeVars d -> CompareAction d n -> Eff Equal ()
runCompare fvs act = fromInner $ eachFace fvs $ act !(askAt DEFS) runCompare loc fvs act = fromInner $ eachCorner loc fvs $ act !(askAt DEFS)
private private
fdvAll : HasFreeDVars t => List (t d n) -> FreeVars d foldMap1 : Semigroup b => (a -> b) -> List1 a -> b
fdvAll ts = foldMap1 f = foldl1By (\x, y => x <+> f y) f
let Val d = ctx.dimLen; Val n = ctx.termLen in foldMap fdv ts
private
fdvAll : HasFreeDVars t => (xs : List (t d n)) -> (0 _ : NonEmpty xs) =>
FreeVars d
fdvAll (x :: xs) = foldMap1 (fdvWith ctx.dimLen ctx.termLen) (x ::: xs)
namespace Term namespace Term
export covering export covering
compare : SQty -> (ty, s, t : Term d n) -> Eff Equal () compare : SQty -> (ty, s, t : Term d n) -> Eff Equal ()
compare sg ty s t = runCompare (fdvAll [ty, s, t]) $ \defs, ectx, th => compare sg ty s t = runCompare s.loc (fdvAll [ty, s, t]) $
compare0 defs ectx sg (ty // th) (s // th) (t // th) \defs, ectx, th => compare0 defs ectx sg (ty // th) (s // th) (t // th)
export covering export covering
compareType : (s, t : Term d n) -> Eff Equal () compareType : (s, t : Term d n) -> Eff Equal ()
compareType s t = runCompare (fdvAll [s, t]) $ \defs, ectx, th => compareType s t = runCompare s.loc (fdvAll [s, t]) $
compareType defs ectx (s // th) (t // th) \defs, ectx, th => compareType defs ectx (s // th) (t // th)
namespace Elim namespace Elim
||| you don't have to pass the type in but the arguments must still be ||| you don't have to pass the type in but the arguments must still be
||| of the same type!! ||| of the same type!!
export covering export covering
compare : SQty -> (e, f : Elim d n) -> Eff Equal () compare : SQty -> (e, f : Elim d n) -> Eff Equal ()
compare sg e f = runCompare (fdvAll [e, f]) $ \defs, ectx, th => compare sg e f = runCompare e.loc (fdvAll [e, f]) $
ignore $ compare0 defs ectx sg (e // th) (f // th) \defs, ectx, th => ignore $ compare0 defs ectx sg (e // th) (f // th)
namespace Term namespace Term
export covering %inline export covering %inline

View file

@ -93,6 +93,14 @@ interface HasFreeDVars (0 tm : TermLike) where
constructor HFDV constructor HFDV
fdv : {d, n : Nat} -> tm d n -> FreeVars d fdv : {d, n : Nat} -> tm d n -> FreeVars d
public export %inline
fvWith : HasFreeVars tm => Singleton n -> tm n -> FreeVars n
fvWith (Val n) = fv
public export %inline
fdvWith : HasFreeDVars tm => Singleton d -> Singleton n -> tm d n -> FreeVars d
fdvWith (Val d) (Val n) = fdv
export export
Fdv : (0 tm : TermLike) -> {n : Nat} -> Fdv : (0 tm : TermLike) -> {n : Nat} ->
HasFreeDVars tm => HasFreeVars (\d => tm d n) HasFreeDVars tm => HasFreeVars (\d => tm d n)
@ -172,23 +180,27 @@ export HasFreeVars (Elim d)
export export
HasFreeVars (Term d) where HasFreeVars (Term d) where
fv (TYPE {}) = none fv (TYPE {}) = none
fv (Pi {arg, res, _}) = fv arg <+> fv res fv (IOState {}) = none
fv (Lam {body, _}) = fv body fv (Pi {arg, res, _}) = fv arg <+> fv res
fv (Sig {fst, snd, _}) = fv fst <+> fv snd fv (Lam {body, _}) = fv body
fv (Pair {fst, snd, _}) = fv fst <+> fv snd fv (Sig {fst, snd, _}) = fv fst <+> fv snd
fv (Enum {}) = none fv (Pair {fst, snd, _}) = fv fst <+> fv snd
fv (Tag {}) = none fv (Enum {}) = none
fv (Eq {ty, l, r, _}) = fvD ty <+> fv l <+> fv r fv (Tag {}) = none
fv (DLam {body, _}) = fvD body fv (Eq {ty, l, r, _}) = fvD ty <+> fv l <+> fv r
fv (Nat {}) = none fv (DLam {body, _}) = fvD body
fv (Zero {}) = none fv (NAT {}) = none
fv (Succ {p, _}) = fv p fv (Nat {}) = none
fv (BOX {ty, _}) = fv ty fv (Succ {p, _}) = fv p
fv (Box {val, _}) = fv val fv (STRING {}) = none
fv (E e) = fv e fv (Str {}) = none
fv (CloT s) = fv s fv (BOX {ty, _}) = fv ty
fv (DCloT s) = fv s.term fv (Box {val, _}) = fv val
fv (Let {rhs, body, _}) = fv rhs <+> fv body
fv (E e) = fv e
fv (CloT s) = fv s
fv (DCloT s) = fv s.term
export export
HasFreeVars (Elim d) where HasFreeVars (Elim d) where
@ -217,27 +229,27 @@ HasFreeVars (Elim d) where
private private
expandDShift : {d1 : Nat} -> Shift d1 d2 -> Context' (Dim d2) d1 expandDShift : {d1 : Nat} -> Shift d1 d2 -> Loc -> Context' (Dim d2) d1
expandDShift by = tabulateLT d1 (\i => BV i noLoc // by) expandDShift by loc = tabulateLT d1 (\i => BV i loc // by)
private private
expandDSubst : {d1 : Nat} -> DSubst d1 d2 -> Context' (Dim d2) d1 expandDSubst : {d1 : Nat} -> DSubst d1 d2 -> Loc -> Context' (Dim d2) d1
expandDSubst (Shift by) = expandDShift by expandDSubst (Shift by) loc = expandDShift by loc
expandDSubst (t ::: th) = expandDSubst th :< t expandDSubst (t ::: th) loc = expandDSubst th loc :< t
private private
fdvSubst' : {d1, d2, n : Nat} -> HasFreeDVars tm => fdvSubst' : {d1, d2, n : Nat} -> (Located2 tm, HasFreeDVars tm) =>
tm d1 n -> DSubst d1 d2 -> FreeVars d2 tm d1 n -> DSubst d1 d2 -> FreeVars d2
fdvSubst' t th = fdvSubst' t th =
fold $ zipWith maybeOnly (fdv t).vars (expandDSubst th) fold $ zipWith maybeOnly (fdv t).vars (expandDSubst th t.loc)
where where
maybeOnly : {d : Nat} -> Bool -> Dim d -> FreeVars d maybeOnly : {d : Nat} -> Bool -> Dim d -> FreeVars d
maybeOnly True (B i _) = only i maybeOnly True (B i _) = only i
maybeOnly _ _ = none maybeOnly _ _ = none
private private
fdvSubst : {d, n : Nat} -> HasFreeDVars tm => fdvSubst : {d, n : Nat} -> (Located2 tm, HasFreeDVars tm) =>
WithSubst (\d => tm d n) Dim d -> FreeVars d WithSubst (\d => tm d n) Dim d -> FreeVars d
fdvSubst (Sub t th) = let Val from = getFrom th in fdvSubst' t th fdvSubst (Sub t th) = let Val from = getFrom th in fdvSubst' t th
@ -247,23 +259,27 @@ export HasFreeDVars Elim
export export
HasFreeDVars Term where HasFreeDVars Term where
fdv (TYPE {}) = none fdv (TYPE {}) = none
fdv (Pi {arg, res, _}) = fdv arg <+> fdvT res fdv (IOState {}) = none
fdv (Lam {body, _}) = fdvT body fdv (Pi {arg, res, _}) = fdv arg <+> fdvT res
fdv (Sig {fst, snd, _}) = fdv fst <+> fdvT snd fdv (Lam {body, _}) = fdvT body
fdv (Pair {fst, snd, _}) = fdv fst <+> fdv snd fdv (Sig {fst, snd, _}) = fdv fst <+> fdvT snd
fdv (Enum {}) = none fdv (Pair {fst, snd, _}) = fdv fst <+> fdv snd
fdv (Tag {}) = none fdv (Enum {}) = none
fdv (Eq {ty, l, r, _}) = fdv @{DScope} ty <+> fdv l <+> fdv r fdv (Tag {}) = none
fdv (DLam {body, _}) = fdv @{DScope} body fdv (Eq {ty, l, r, _}) = fdv @{DScope} ty <+> fdv l <+> fdv r
fdv (Nat {}) = none fdv (DLam {body, _}) = fdv @{DScope} body
fdv (Zero {}) = none fdv (NAT {}) = none
fdv (Succ {p, _}) = fdv p fdv (Nat {}) = none
fdv (BOX {ty, _}) = fdv ty fdv (Succ {p, _}) = fdv p
fdv (Box {val, _}) = fdv val fdv (STRING {}) = none
fdv (E e) = fdv e fdv (Str {}) = none
fdv (CloT s) = fdv s @{WithSubst} fdv (BOX {ty, _}) = fdv ty
fdv (DCloT s) = fdvSubst s fdv (Box {val, _}) = fdv val
fdv (Let {rhs, body, _}) = fdv rhs <+> fdvT body
fdv (E e) = fdv e
fdv (CloT s) = fdv s @{WithSubst}
fdv (DCloT s) = fdvSubst s
export export
HasFreeDVars Elim where HasFreeDVars Elim where

View file

@ -1,6 +1,7 @@
||| file locations ||| file locations
module Quox.Loc module Quox.Loc
import Quox.PrettyValExtra
import public Text.Bounded import public Text.Bounded
import Data.SortedMap import Data.SortedMap
import Derive.Prelude import Derive.Prelude
@ -12,12 +13,12 @@ public export
FileName : Type FileName : Type
FileName = String FileName = String
%runElab derive "Bounds" [Ord] %runElab derive "Bounds" [Ord, PrettyVal]
public export public export
data Loc_ = NoLoc | YesLoc FileName Bounds data Loc_ = NoLoc | YesLoc FileName Bounds
%name Loc_ loc %name Loc_ loc
%runElab derive "Loc_" [Eq, Ord, Show] %runElab derive "Loc_" [Eq, Ord, Show, PrettyVal]
||| a wrapper for locations which are always considered equal ||| a wrapper for locations which are always considered equal
@ -39,6 +40,18 @@ public export %inline
makeLoc : FileName -> Bounds -> Loc makeLoc : FileName -> Bounds -> Loc
makeLoc = L .: YesLoc makeLoc = L .: YesLoc
public export %inline
loc : FileName -> (sl, sc, el, ec : Int) -> Loc
loc file sl sc el ec = makeLoc file $ MkBounds sl sc el ec
export
PrettyVal Loc where
prettyVal (L NoLoc) = Con "noLoc" []
prettyVal (L (YesLoc file (MkBounds sl sc el ec))) =
Con "loc" [prettyVal file,
prettyVal sl, prettyVal sc,
prettyVal el, prettyVal ec]
export export
onlyStart_ : Loc_ -> Loc_ onlyStart_ : Loc_ -> Loc_
@ -95,7 +108,7 @@ extendL : Loc -> Loc -> Loc
extendL l1 l2 = l1 `extend'` l2.bounds extendL l1 l2 = l1 `extend'` l2.bounds
infixr 1 `or_`, `or` export infixr 1 `or_`, `or`
export %inline export %inline
or_ : Loc_ -> Loc_ -> Loc_ or_ : Loc_ -> Loc_ -> Loc_
or_ l1@(YesLoc {}) _ = l1 or_ l1@(YesLoc {}) _ = l1
@ -105,6 +118,11 @@ export %inline
or : Loc -> Loc -> Loc or : Loc -> Loc -> Loc
or (L l1) (L l2) = L $ l1 `or_` l2 or (L l1) (L l2) = L $ l1 `or_` l2
export %inline
extendOr : Loc -> Loc -> Loc
extendOr l1 l2 = (l1 `extendL` l2) `or` l2
public export public export
interface Located a where (.loc) : a -> Loc interface Located a where (.loc) : a -> Loc
@ -113,9 +131,22 @@ public export
0 Located1 : (a -> Type) -> Type 0 Located1 : (a -> Type) -> Type
Located1 f = forall x. Located (f x) Located1 f = forall x. Located (f x)
public export
0 Located2 : (a -> b -> Type) -> Type
Located2 f = forall x, y. Located (f x y)
public export public export
interface Located a => Relocatable a where setLoc : Loc -> a -> a interface Located a => Relocatable a where setLoc : Loc -> a -> a
public export public export
0 Relocatable1 : (a -> Type) -> Type 0 Relocatable1 : (a -> Type) -> Type
Relocatable1 f = forall x. Relocatable (f x) Relocatable1 f = forall x. Relocatable (f x)
public export
0 Relocatable2 : (a -> b -> Type) -> Type
Relocatable2 f = forall x, y. Relocatable (f x y)
export
locs : Located a => Foldable t => t a -> Loc
locs = foldl (\loc, y => loc `extendOr` y.loc) noLoc

317
lib/Quox/Log.idr Normal file
View file

@ -0,0 +1,317 @@
module Quox.Log
import Quox.Loc
import Quox.Pretty
import Quox.PrettyValExtra
import Data.So
import Data.DPair
import Data.Maybe
import Data.List1
import Control.Eff
import Control.Monad.ST.Extra
import Data.IORef
import System.File
import Derive.Prelude
%default total
%language ElabReflection
public export %inline
maxLogLevel : Nat
maxLogLevel = 100
public export %inline
logCategories : List String
logCategories = ["whnf", "equal", "check"]
public export %inline
isLogLevel : Nat -> Bool
isLogLevel l = l <= maxLogLevel
public export
IsLogLevel : Nat -> Type
IsLogLevel l = So $ isLogLevel l
public export %inline
isLogCategory : String -> Bool
isLogCategory cat = cat `elem` logCategories
public export
IsLogCategory : String -> Type
IsLogCategory cat = So $ isLogCategory cat
-- Q: why are you using `So` instead of `LT` and `Elem`
-- A: ① proof search gives up before finding a proof of e.g. ``99 `LT` 100``
-- (i.e. `LTESucc⁹⁹ LTEZero`)
-- ② the proofs aren't looked at in any way, i just wanted to make sure the
-- list of categories was consistent everywhere
||| a verbosity level from 0100. higher is noisier. each log entry has a
||| verbosity level above which it will be printed, chosen, uh, based on vibes.
public export
LogLevel : Type
LogLevel = Subset Nat IsLogLevel
||| a logging category, like "check" (type checking), "whnf", or whatever.
public export
LogCategory : Type
LogCategory = Subset String IsLogCategory
public export %inline
toLogLevel : Nat -> Maybe LogLevel
toLogLevel l =
case choose $ isLogLevel l of
Left y => Just $ Element l y
Right _ => Nothing
public export %inline
toLogCategory : String -> Maybe LogCategory
toLogCategory c =
case choose $ isLogCategory c of
Left y => Just $ Element c y
Right _ => Nothing
||| verbosity levels for each category, if they differ from the default
public export
LevelMap : Type
LevelMap = List (LogCategory, LogLevel)
-- Q: why `List` instead of `SortedMap`
-- A: oof ouch my constant factors (maybe this one was more obvious)
public export
record LogLevels where
constructor MkLogLevels
defLevel : LogLevel
levels : LevelMap
%name LogLevels lvls
%runElab derive "LogLevels" [Eq, Show, PrettyVal]
public export
LevelStack : Type
LevelStack = List LogLevels
public export %inline
defaultLevel : LogLevel
defaultLevel = Element 0 Oh
export %inline
defaultLogLevels : LogLevels
defaultLogLevels = MkLogLevels defaultLevel []
export %inline
initStack : LevelStack
initStack = []
export %inline
getLevel1 : LogCategory -> LogLevels -> LogLevel
getLevel1 cat (MkLogLevels def lvls) = fromMaybe def $ lookup cat lvls
export %inline
getLevel : LogCategory -> LevelStack -> LogLevel
getLevel cat (lvls :: _) = getLevel1 cat lvls
getLevel cat [] = defaultLevel
export %inline
getCurLevels : LevelStack -> LogLevels
getCurLevels (lvls :: _) = lvls
getCurLevels [] = defaultLogLevels
public export
LogDoc : Type
LogDoc = Doc (Opts {lineLength = 80})
private %inline
replace : Eq a => a -> b -> List (a, b) -> List (a, b)
replace k v kvs = (k, v) :: filter (\y => fst y /= k) kvs
private %inline
mergeLeft : Eq a => List (a, b) -> List (a, b) -> List (a, b)
mergeLeft l r = foldl (\lst, (k, v) => replace k v lst) r l
public export
data PushArg =
SetDefault LogLevel
| SetCat LogCategory LogLevel
| SetAll LogLevel
%runElab derive "PushArg" [Eq, Ord, Show, PrettyVal]
%name PushArg push
export %inline
applyPush : LogLevels -> PushArg -> LogLevels
applyPush lvls (SetDefault def) = {defLevel := def} lvls
applyPush lvls (SetCat cat lvl) = {levels $= replace cat lvl} lvls
applyPush lvls (SetAll lvl) = MkLogLevels lvl []
export %inline
fromPush : PushArg -> LogLevels
fromPush = applyPush defaultLogLevels
public export
record LogMsg where
constructor (:>)
level : Nat
{auto 0 levelOk : IsLogLevel level}
message : Lazy LogDoc
export infix 0 :>
%name Log.LogMsg msg
public export
data LogL : (lbl : tag) -> Type -> Type where
||| print some log messages
SayMany : (cat : LogCategory) -> (loc : Loc) ->
(msgs : List LogMsg) -> LogL lbl ()
||| set some verbosity levels
Push : (push : List PushArg) -> LogL lbl ()
||| restore the previous verbosity levels.
||| returns False if the stack was already empty
Pop : LogL lbl Bool
||| returns the current verbosity levels
CurLevels : LogL lbl LogLevels
public export
Log : Type -> Type
Log = LogL ()
parameters (0 lbl : tag) {auto _ : Has (LogL lbl) fs}
public export %inline
sayManyAt : (cat : String) -> (0 catOk : IsLogCategory cat) =>
Loc -> List LogMsg -> Eff fs ()
sayManyAt cat loc msgs {catOk} =
send $ SayMany {lbl} (Element cat catOk) loc msgs
public export %inline
sayAt : (cat : String) -> (0 catOk : IsLogCategory cat) =>
(lvl : Nat) -> (0 lvlOk : IsLogLevel lvl) =>
Loc -> Lazy LogDoc -> Eff fs ()
sayAt cat lvl loc msg = sayManyAt cat loc [lvl :> msg]
public export %inline
pushAt : List PushArg -> Eff fs ()
pushAt lvls = send $ Push {lbl} lvls
public export %inline
push1At : PushArg -> Eff fs ()
push1At lvl = pushAt [lvl]
public export %inline
popAt : Eff fs Bool
popAt = send $ Pop {lbl}
public export %inline
curLevelsAt : Eff fs LogLevels
curLevelsAt = send $ CurLevels {lbl}
parameters {auto _ : Has Log fs}
public export %inline
sayMany : (cat : String) -> (0 catOk : IsLogCategory cat) =>
Loc -> List LogMsg -> Eff fs ()
sayMany = sayManyAt ()
public export %inline
say : (cat : String) -> (0 _ : IsLogCategory cat) =>
(lvl : Nat) -> (0 _ : IsLogLevel lvl) =>
Loc -> Lazy LogDoc -> Eff fs ()
say = sayAt ()
public export %inline
push : List PushArg -> Eff fs ()
push = pushAt ()
public export %inline
push1 : PushArg -> Eff fs ()
push1 = push1At ()
public export %inline
pop : Eff fs Bool
pop = popAt ()
public export %inline
curLevels : Eff fs LogLevels
curLevels = curLevelsAt ()
||| handles a `Log` effect with an existing `State` and `Writer`
export %inline
handleLogSW : (0 s : ts) -> (0 w : tw) ->
Has (StateL s LevelStack) fs => Has (WriterL w LogDoc) fs =>
LogL tag a -> Eff fs a
handleLogSW s w = \case
Push push => modifyAt s $ \lst =>
foldl applyPush (fromMaybe defaultLogLevels (head' lst)) push :: lst
Pop => stateAt s $ maybe (False, []) (True,) . tail'
SayMany cat loc msgs => do
catLvl <- getsAt s $ fst . getLevel cat
let loc = runPretty $ prettyLoc loc
for_ msgs $ \(lvl :> msg) => when (lvl <= catLvl) $ tellAt w $
hcat [loc, text cat.fst, "@", pshow lvl, ":"] <++> msg
CurLevels =>
getsAt s getCurLevels
export %inline
handleLogSW_ : LogL tag a -> Eff [State LevelStack, Writer LogDoc] a
handleLogSW_ = handleLogSW () ()
export %inline
handleLogIO : HasIO m => MonadRec m =>
(FileError -> m ()) -> IORef LevelStack -> File ->
LogL tag a -> m a
handleLogIO th lvls h act =
runEff (handleLogSW_ act) [handleStateIORef lvls, handleWriter {m} printMsg]
where printMsg : LogDoc -> m ()
printMsg msg = fPutStr h (render _ msg) >>= either th pure
export %inline
handleLogST : HasST m => MonadRec (m s) =>
STRef s (SnocList LogDoc) -> STRef s LevelStack ->
LogL tag a -> m s a
handleLogST docs lvls act =
runEff (handleLogSW_ act) [handleStateSTRef lvls, handleWriterSTRef docs]
export %inline
handleLogDiscard : (0 s : ts) -> Has (StateL s Nat) fs =>
LogL tag a -> Eff fs a
handleLogDiscard s = \case
Push _ => modifyAt s S
Pop => stateAt s $ \k => (k > 0, pred k)
SayMany {} => pure ()
CurLevels => pure defaultLogLevels
export %inline
handleLogDiscard_ : LogL tag a -> Eff [State Nat] a
handleLogDiscard_ = handleLogDiscard ()
export %inline
handleLogDiscardST : HasST m => MonadRec (m s) => STRef s Nat ->
LogL tag a -> m s a
handleLogDiscardST ref act =
runEff (handleLogDiscard_ act) [handleStateSTRef ref]
export %inline
handleLogDiscardIO : HasIO m => MonadRec m => IORef Nat ->
LogL tag a -> m a
handleLogDiscardIO ref act =
runEff (handleLogDiscard_ act) [handleStateIORef ref]
||| approximate the push/pop effects in a discarded log by trimming a stack or
||| repeating its most recent element
export %inline
fixupDiscardedLog : Nat -> LevelStack -> LevelStack
fixupDiscardedLog want lvls =
let len = length lvls in
case compare len want of
EQ => lvls
GT => drop (len `minus` want) lvls
LT => let new = fromMaybe defaultLogLevels $ head' lvls in
replicate (want `minus` len) new ++ lvls

View file

@ -2,6 +2,7 @@ module Quox.Name
import Quox.Loc import Quox.Loc
import Quox.CharExtra import Quox.CharExtra
import Quox.PrettyValExtra
import public Data.SnocList import public Data.SnocList
import Data.List import Data.List
import Control.Eff import Control.Eff
@ -23,7 +24,7 @@ data BaseName
= UN String -- user-given name = UN String -- user-given name
| MN String NameSuf -- machine-generated name | MN String NameSuf -- machine-generated name
| Unused -- "_" | Unused -- "_"
%runElab derive "BaseName" [Eq, Ord] %runElab derive "BaseName" [Eq, Ord, PrettyVal]
export export
baseStr : BaseName -> String baseStr : BaseName -> String
@ -42,14 +43,14 @@ Mods = SnocList String
public export public export
record Name where record Name where
constructor MakeName constructor MkName
mods : Mods mods : Mods
base : BaseName base : BaseName
%runElab derive "Name" [Eq, Ord] %runElab derive "Name" [Eq, Ord]
public export %inline public export %inline
unq : BaseName -> Name unq : BaseName -> Name
unq = MakeName [<] unq = MkName [<]
||| add some namespaces to the beginning of a name ||| add some namespaces to the beginning of a name
public export %inline public export %inline
@ -63,31 +64,31 @@ PBaseName = String
public export public export
record PName where record PName where
constructor MakePName constructor MkPName
mods : Mods mods : Mods
base : PBaseName base : PBaseName
%runElab derive "PName" [Eq, Ord] %runElab derive "PName" [Eq, Ord, PrettyVal]
export %inline export %inline
fromPName : PName -> Name fromPName : PName -> Name
fromPName p = MakeName p.mods $ UN p.base fromPName p = MkName p.mods $ UN p.base
export %inline export %inline
toPName : Name -> PName toPName : Name -> PName
toPName p = MakePName p.mods $ baseStr p.base toPName p = MkPName p.mods $ baseStr p.base
export %inline export %inline
fromPBaseName : PBaseName -> Name fromPBaseName : PBaseName -> Name
fromPBaseName = MakeName [<] . UN fromPBaseName = MkName [<] . UN
export export
Show PName where Show PName where
show (MakePName mods base) = show (MkPName mods base) =
show $ concat $ intersperse "." $ toList $ mods :< base show $ concat $ intersperse "." $ toList $ mods :< base
export Show Name where show = show . toPName export Show Name where show = show . toPName
export FromString PName where fromString = MakePName [<] export FromString PName where fromString = MkPName [<]
export FromString Name where fromString = fromPBaseName export FromString Name where fromString = fromPBaseName
@ -97,7 +98,7 @@ record BindName where
constructor BN constructor BN
val : BaseName val : BaseName
loc_ : Loc loc_ : Loc
%runElab derive "BindName" [Eq, Ord, Show] %runElab derive "BindName" [Eq, Ord, Show, PrettyVal]
export Located BindName where n.loc = n.loc_ export Located BindName where n.loc = n.loc_
export Relocatable BindName where setLoc loc (BN x _) = BN x loc export Relocatable BindName where setLoc loc (BN x _) = BN x loc
@ -115,7 +116,7 @@ export
fromListP : List1 String -> PName fromListP : List1 String -> PName
fromListP (x ::: xs) = go [<] x xs where fromListP (x ::: xs) = go [<] x xs where
go : SnocList String -> String -> List String -> PName go : SnocList String -> String -> List String -> PName
go mods x [] = MakePName mods x go mods x [] = MkPName mods x
go mods x (y :: ys) = go (mods :< x) y ys go mods x (y :: ys) = go (mods :< x) y ys
export %inline export %inline

View file

@ -4,6 +4,7 @@ import public Data.Nat
import Data.Nat.Division import Data.Nat.Division
import Data.SnocList import Data.SnocList
import Data.Vect import Data.Vect
import Data.String
%default total %default total
@ -52,6 +53,42 @@ parameters {base : Nat} {auto 0 _ : base `GTE` 2} (chars : Vect base Char)
showAtBase : Nat -> String showAtBase : Nat -> String
showAtBase = pack . showAtBase' [] showAtBase = pack . showAtBase' []
export namespace Nat
showHex : Nat -> String export
showHex = showAtBase $ fromList $ unpack "0123456789ABCDEF" showHex : Nat -> String
showHex = showAtBase $ fromList $ unpack "0123456789abcdef"
namespace Int
export
showHex : Int -> String
showHex x =
if x < 0 then "-" ++ Nat.showHex (cast (-x)) else Nat.showHex (cast x)
namespace Int
export
fromHexit : Char -> Maybe Int
fromHexit c =
if c >= '0' && c <= '9' then Just $ ord c - ord '0'
else if c >= 'a' && c <= 'f' then Just $ ord c - ord 'a' + 10
else if c >= 'A' && c <= 'F' then Just $ ord c - ord 'A' + 10
else Nothing
private
fromHex' : Int -> String -> Maybe Int
fromHex' acc str = case strM str of
StrNil => Just acc
StrCons c cs => fromHex' (16 * acc + !(fromHexit c)) (assert_smaller str cs)
export %inline
fromHex : String -> Maybe Int
fromHex str = do guard $ str /= ""; fromHex' 0 str
namespace Nat
export
fromHexit : Char -> Maybe Nat
fromHexit = map cast . Int.fromHexit
export %inline
fromHex : String -> Maybe Nat
fromHex = map cast . Int.fromHex

View file

@ -43,7 +43,7 @@ parameters {0 a, b : Bool}
noOr2 = snd . noOr noOr2 = snd . noOr
infixr 1 `orNo` export infixr 1 `orNo`
export %inline export %inline
orNo : No a -> No b -> No (a || b) orNo : No a -> No b -> No (a || b)
orNo Ah Ah = Ah orNo Ah Ah = Ah

View file

@ -1,76 +0,0 @@
||| "order preserving embeddings", for recording a correspondence between
||| a smaller scope and part of a larger one.
module Quox.OPE
import Quox.NatExtra
import Data.Nat
%default total
public export
data OPE : Nat -> Nat -> Type where
Id : OPE n n
Drop : OPE m n -> OPE m (S n)
Keep : OPE m n -> OPE (S m) (S n)
%name OPE p, q
public export %inline Injective Drop where injective Refl = Refl
public export %inline Injective Keep where injective Refl = Refl
public export
opeZero : {n : Nat} -> OPE 0 n
opeZero {n = 0} = Id
opeZero {n = S n} = Drop opeZero
public export
(.) : OPE m n -> OPE n p -> OPE m p
p . Id = p
Id . q = q
p . Drop q = Drop $ p . q
Drop p . Keep q = Drop $ p . q
Keep p . Keep q = Keep $ p . q
public export
toLTE : {m : Nat} -> OPE m n -> m `LTE` n
toLTE Id = reflexive
toLTE (Drop p) = lteSuccRight $ toLTE p
toLTE (Keep p) = LTESucc $ toLTE p
public export
keepN : (n : Nat) -> OPE a b -> OPE (n + a) (n + b)
keepN 0 p = p
keepN (S n) p = Keep $ keepN n p
public export
dropInner' : LTE' m n -> OPE m n
dropInner' LTERefl = Id
dropInner' (LTESuccR p) = Drop $ dropInner' $ force p
public export
dropInner : {n : Nat} -> LTE m n -> OPE m n
dropInner = dropInner' . fromLte
public export
dropInnerN : (m : Nat) -> OPE n (m + n)
dropInnerN 0 = Id
dropInnerN (S m) = Drop $ dropInnerN m
public export
interface Tighten t where
tighten : OPE m n -> t n -> Maybe (t m)
parameters {auto _ : Tighten t}
export %inline
tightenInner : {n : Nat} -> m `LTE` n -> t n -> Maybe (t m)
tightenInner = tighten . dropInner
export %inline
tightenN : (m : Nat) -> t (m + n) -> Maybe (t n)
tightenN m = tighten $ dropInnerN m
export %inline
tighten1 : t (S n) -> Maybe (t n)
tighten1 = tightenN 1

View file

@ -3,10 +3,12 @@ module Quox.Parser.FromParser
import public Quox.Parser.FromParser.Error as Quox.Parser.FromParser import public Quox.Parser.FromParser.Error as Quox.Parser.FromParser
import Quox.Pretty
import Quox.Parser.Syntax import Quox.Parser.Syntax
import Quox.Parser.Parser import Quox.Parser.Parser
import public Quox.Parser.LoadFile import public Quox.Parser.LoadFile
import Quox.Typechecker import Quox.Typechecker
import Quox.CheckBuiltin
import Data.List import Data.List
import Data.Maybe import Data.Maybe
@ -18,6 +20,7 @@ import System.File
import System.Path import System.Path
import Data.IORef import Data.IORef
%hide Typing.Error %hide Typing.Error
%hide Lexer.Error %hide Lexer.Error
%hide Parser.Error %hide Parser.Error
@ -25,28 +28,55 @@ import Data.IORef
%default total %default total
public export
NDefinition : Type
NDefinition = (Name, Definition)
public export public export
data StateTag = NS | SEEN data StateTag = NS | SEEN
public export public export
FromParserPure : List (Type -> Type) FromParserPure : List (Type -> Type)
FromParserPure = [Except Error, DefsState, StateL NS Mods, NameGen] FromParserPure = [Except Error, DefsState, StateL NS Mods, NameGen, Log]
public export public export
FromParserIO : List (Type -> Type) FromParserIO : List (Type -> Type)
FromParserIO = LoadFile :: FromParserPure FromParserIO = FromParserPure ++ [LoadFile]
public export
record PureParserResult a where
constructor MkPureParserResult
val : a
suf : NameSuf
defs : Definitions
log : SnocList LogDoc
logLevels : LevelStack
export
fromParserPure : Mods -> NameSuf -> Definitions -> LevelStack ->
Eff FromParserPure a -> Either Error (PureParserResult a)
fromParserPure ns suf defs lvls act = runSTErr $ do
suf <- newSTRef' suf
defs <- newSTRef' defs
log <- newSTRef' [<]
lvls <- newSTRef' lvls
res <- runEff act $ with Union.(::)
[handleExcept $ \e => stLeft e,
handleStateSTRef defs,
handleStateSTRef !(newSTRef' ns),
handleStateSTRef suf,
handleLogST log lvls]
pure $ MkPureParserResult {
val = res,
suf = !(readSTRef' suf),
defs = !(readSTRef' defs),
log = !(readSTRef' log),
logLevels = !(readSTRef' lvls)
}
parameters {auto _ : Functor m} (b : Var n -> m a) (f : PName -> m a) parameters {auto _ : Functor m} (b : Var n -> m a) (f : PName -> m a)
(xs : Context' PatVar n) (xs : Context' PatVar n)
private private
fromBaseName : PBaseName -> m a fromBaseName : PBaseName -> m a
fromBaseName x = maybe (f $ MakePName [<] x) b $ fromBaseName x = maybe (f $ MkPName [<] x) b $
Context.find (\y => y.name == Just x) xs Context.find (\y => y.name == Just x) xs
private private
@ -111,6 +141,9 @@ mutual
TYPE k loc => TYPE k loc =>
pure $ TYPE k loc pure $ TYPE k loc
IOState loc =>
pure $ IOState loc
Pi pi x s t loc => Pi pi x s t loc =>
Pi (fromPQty pi) Pi (fromPQty pi)
<$> fromPTermWith ds ns s <$> fromPTermWith ds ns s
@ -151,13 +184,16 @@ mutual
map E $ CaseEnum (fromPQty pi) map E $ CaseEnum (fromPQty pi)
<$> fromPTermElim ds ns tag <$> fromPTermElim ds ns tag
<*> fromPTermTScope ds ns [< r] ret <*> fromPTermTScope ds ns [< r] ret
<*> assert_total fromPTermEnumArms ds ns arms <*> assert_total fromPTermEnumArms loc ds ns arms
<*> pure loc <*> pure loc
Nat loc => pure $ Nat loc NAT loc => pure $ NAT loc
Zero loc => pure $ Zero loc Nat n loc => pure $ Nat n loc
Succ n loc => [|Succ (fromPTermWith ds ns n) (pure loc)|] Succ n loc => [|Succ (fromPTermWith ds ns n) (pure loc)|]
STRING loc => pure $ STRING loc
Str str loc => pure $ Str str loc
Case pi nat (r, ret) (CaseNat zer (s, pi', ih, suc) _) loc => Case pi nat (r, ret) (CaseNat zer (s, pi', ih, suc) _) loc =>
map E $ CaseNat (fromPQty pi) (fromPQty pi') map E $ CaseNat (fromPQty pi) (fromPQty pi')
<$> fromPTermElim ds ns nat <$> fromPTermElim ds ns nat
@ -166,12 +202,11 @@ mutual
<*> fromPTermTScope ds ns [< s, ih] suc <*> fromPTermTScope ds ns [< s, ih] suc
<*> pure loc <*> pure loc
Enum strs loc => Enum strs loc => do
let set = SortedSet.fromList strs in let set = SortedSet.fromList strs
if length strs == length (SortedSet.toList set) then unless (length strs == length (SortedSet.toList set)) $
pure $ Enum set loc throw $ DuplicatesInEnumType loc strs
else pure $ Enum set loc
throw $ DuplicatesInEnum loc strs
Tag str loc => pure $ Tag str loc Tag str loc => pure $ Tag str loc
@ -228,13 +263,22 @@ mutual
<*> fromPTermDScope ds ns [< j1] val1 <*> fromPTermDScope ds ns [< j1] val1
<*> pure loc <*> pure loc
Let (qty, x, rhs) body loc =>
Let (fromPQty qty)
<$> fromPTermElim ds ns rhs
<*> fromPTermTScope ds ns [< x] body
<*> pure loc
private private
fromPTermEnumArms : Context' PatVar d -> Context' PatVar n -> fromPTermEnumArms : Loc -> Context' PatVar d -> Context' PatVar n ->
List (PTagVal, PTerm) -> List (PTagVal, PTerm) ->
Eff FromParserPure (CaseEnumArms d n) Eff FromParserPure (CaseEnumArms d n)
fromPTermEnumArms ds ns = fromPTermEnumArms loc ds ns arms = do
map SortedMap.fromList . res <- SortedMap.fromList <$>
traverse (bitraverse (pure . fromPTagVal) (fromPTermWith ds ns)) traverse (bitraverse (pure . fromPTagVal) (fromPTermWith ds ns)) arms
unless (length (keys res) == length arms) $
throw $ DuplicatesInEnumCase loc (map (fromPTagVal . fst) arms)
pure res
private private
fromPTermElim : Context' PatVar d -> Context' PatVar n -> fromPTermElim : Context' PatVar d -> Context' PatVar n ->
@ -253,7 +297,7 @@ mutual
if all isUnused xs then if all isUnused xs then
SN <$> fromPTermWith ds ns t SN <$> fromPTermWith ds ns t
else else
ST (fromSnocVect $ map fromPatVar xs) <$> fromPTermWith ds (ns ++ xs) t SY (fromSnocVect $ map fromPatVar xs) <$> fromPTermWith ds (ns ++ xs) t
private private
fromPTermDScope : {s : Nat} -> Context' PatVar d -> Context' PatVar n -> fromPTermDScope : {s : Nat} -> Context' PatVar d -> Context' PatVar n ->
@ -261,9 +305,9 @@ mutual
Eff FromParserPure (DScopeTermN s d n) Eff FromParserPure (DScopeTermN s d n)
fromPTermDScope ds ns xs t = fromPTermDScope ds ns xs t =
if all isUnused xs then if all isUnused xs then
SN <$> fromPTermWith ds ns t SN {f = \d => Term d n} <$> fromPTermWith ds ns t
else else
DST (fromSnocVect $ map fromPatVar xs) <$> fromPTermWith (ds ++ xs) ns t SY (fromSnocVect $ map fromPatVar xs) <$> fromPTermWith (ds ++ xs) ns t
export %inline export %inline
@ -272,8 +316,8 @@ fromPTerm = fromPTermWith [<] [<]
export export
globalPQty : Has (Except Error) fs => (q : Qty) -> Loc -> Eff fs GQty globalPQty : Has (Except Error) fs => PQty -> Eff fs GQty
globalPQty pi loc = case toGlobal pi of globalPQty (PQ pi loc) = case toGlobal pi of
Just g => pure g Just g => pure g
Nothing => throw $ QtyNotGlobal loc pi Nothing => throw $ QtyNotGlobal loc pi
@ -287,51 +331,95 @@ liftTC : Eff TC a -> Eff FromParserPure a
liftTC tc = runEff tc $ with Union.(::) liftTC tc = runEff tc $ with Union.(::)
[handleExcept $ \e => throw $ WrapTypeError e, [handleExcept $ \e => throw $ WrapTypeError e,
handleReaderConst !(getAt DEFS), handleReaderConst !(getAt DEFS),
\g => send g,
\g => send g] \g => send g]
private private
addDef : Has DefsState fs => Name -> GQty -> Term 0 0 -> Term 0 0 -> Loc -> liftWhnf : Eff Whnf a -> Eff FromParserPure a
Eff fs NDefinition liftWhnf tc = runEff tc $ with Union.(::)
addDef name gqty type term loc = do [handleExcept $ \e => throw $ WrapTypeError e,
let def = mkDef gqty type term loc \g => send g,
\g => send g]
private
addDef : Has DefsState fs => Name -> Definition -> Eff fs NDefinition
addDef name def = do
modifyAt DEFS $ insert name def modifyAt DEFS $ insert name def
pure (name, def) pure (name, def)
export covering export covering
fromPDef : PDefinition -> Eff FromParserPure NDefinition fromPDef : PDefinition -> Eff FromParserPure NDefinition
fromPDef (MkPDef qty pname ptype pterm defLoc) = do fromPDef def = do
name <- fromPBaseNameNS pname name <- fromPBaseNameNS def.name
gqty <- globalPQty qty.val qty.loc defs <- getAt DEFS
when (isJust $ lookup name defs) $ do
throw $ AlreadyExists def.loc name
gqty <- globalPQty def.qty
let sqty = globalToSubj gqty let sqty = globalToSubj gqty
type <- traverse fromPTerm ptype case def.body of
term <- fromPTerm pterm PConcrete ptype pterm => do
case type of type <- traverse fromPTerm ptype
Just type => do term <- fromPTerm pterm
ignore $ liftTC $ do type <- case type of
checkTypeC empty type Nothing Just type => do
checkC empty sqty term type ignore $ liftTC $ do
addDef name gqty type term defLoc checkTypeC empty type Nothing
Nothing => do checkC empty sqty term type
let E elim = term pure type
| _ => throw $ AnnotationNeeded term.loc empty term Nothing => do
res <- liftTC $ inferC empty sqty elim let E elim = term
addDef name gqty res.type term defLoc | _ => throw $ AnnotationNeeded term.loc empty term
res <- liftTC $ inferC empty sqty elim
pure res.type
when def.main $ liftWhnf $ expectMainType defs type
addDef name $ mkDef gqty type term def.scheme def.main def.loc
PPostulate ptype => do
type <- fromPTerm ptype
addDef name $ mkPostulate gqty type def.scheme def.main def.loc
public export
data HasFail = NoFail | AnyFail | FailWith String
export covering
expectFail : Loc -> Eff FromParserPure a -> Eff FromParserPure Error
expectFail loc act = do
gen <- getAt GEN; defs <- getAt DEFS; ns <- getAt NS; lvl <- curLevels
case fromParserPure ns gen defs (singleton lvl) act of
Left err => pure err
Right _ => throw $ ExpectedFail loc
export covering
maybeFail : Monoid a =>
PFail -> Loc -> Eff FromParserPure a -> Eff FromParserPure a
maybeFail PSucceed _ act = act
maybeFail PFailAny loc act = expectFail loc act $> neutral
maybeFail (PFailMatch str) loc act = do
err <- expectFail loc act
let msg = runPretty $ prettyError False err {opts = Opts 10_000} -- w/e
if str `isInfixOf` renderInfinite msg
then pure neutral
else throw $ WrongFail str err loc
export covering export covering
fromPDecl : PDecl -> Eff FromParserPure (List NDefinition) fromPDecl : PDecl -> Eff FromParserPure (List NDefinition)
fromPDecl (PDef def) = singleton <$> fromPDef def fromPDecl (PDef def) =
maybeFail def.fail def.loc $ singleton <$> fromPDef def
fromPDecl (PNs ns) = fromPDecl (PNs ns) =
maybeFail ns.fail ns.loc $
localAt NS (<+> ns.name) $ concat <$> traverse fromPDecl ns.decls localAt NS (<+> ns.name) $ concat <$> traverse fromPDecl ns.decls
fromPDecl (PPrag prag) =
case prag of
PLogPush p _ => Log.push p $> []
PLogPop _ => Log.pop $> []
mutual mutual
export covering export covering
loadProcessFile : Loc -> String -> Eff FromParserIO (List NDefinition) loadProcessFile : Loc -> String -> Eff FromParserIO (List NDefinition)
loadProcessFile loc file = loadProcessFile loc file =
case !(loadFile loc file) of case !(loadFile loc file) of
Just inp => do Just tl => concat <$> traverse fromPTopLevel tl
tl <- either (throw . WrapParseError file) pure $ lexParseInput file inp
concat <$> traverse fromPTopLevel tl
Nothing => pure [] Nothing => pure []
||| populates the `defs` field of the state ||| populates the `defs` field of the state
@ -339,32 +427,3 @@ mutual
fromPTopLevel : PTopLevel -> Eff FromParserIO (List NDefinition) fromPTopLevel : PTopLevel -> Eff FromParserIO (List NDefinition)
fromPTopLevel (PD decl) = lift $ fromPDecl decl fromPTopLevel (PD decl) = lift $ fromPDecl decl
fromPTopLevel (PLoad file loc) = loadProcessFile loc file fromPTopLevel (PLoad file loc) = loadProcessFile loc file
export
fromParserPure : NameSuf -> Definitions ->
Eff FromParserPure a ->
Either Error (a, NameSuf, Definitions)
fromParserPure suf defs act = runSTErr $ do
suf <- liftST $ newSTRef suf
defs <- liftST $ newSTRef defs
res <- runEff act $ with Union.(::)
[handleExcept (\e => stLeft e),
handleStateSTRef defs,
handleStateSTRef !(liftST $ newSTRef [<]),
handleStateSTRef suf]
pure (res, !(liftST $ readSTRef suf), !(liftST $ readSTRef defs))
export covering
fromParserIO : (MonadRec io, HasIO io) =>
IncludePath -> IORef SeenSet ->
IORef NameSuf -> IORef Definitions ->
Eff FromParserIO a -> io (Either Error a)
fromParserIO inc seen suf defs act = liftIO $ fromIOErr $ do
runEff act $ with Union.(::)
[handleLoadFileIOE LoadError seen inc,
handleExcept (\e => ioLeft e),
handleStateIORef defs,
handleStateIORef !(newIORef [<]),
handleStateIORef suf]

View file

@ -7,6 +7,8 @@ import System.File
import Quox.Pretty import Quox.Pretty
%default total
%hide Text.PrettyPrint.Prettyprinter.Doc.infixr.(<++>) %hide Text.PrettyPrint.Prettyprinter.Doc.infixr.(<++>)
@ -22,26 +24,34 @@ ParseError = Parser.Error
public export public export
data Error = data Error =
AnnotationNeeded Loc (NameContexts d n) (Term d n) AnnotationNeeded Loc (NameContexts d n) (Term d n)
| DuplicatesInEnum Loc (List TagVal) | DuplicatesInEnumType Loc (List TagVal)
| DuplicatesInEnumCase Loc (List TagVal)
| TermNotInScope Loc Name | TermNotInScope Loc Name
| DimNotInScope Loc PBaseName | DimNotInScope Loc PBaseName
| QtyNotGlobal Loc Qty | QtyNotGlobal Loc Qty
| DimNameInTerm Loc PBaseName | DimNameInTerm Loc PBaseName
| DisplacedBoundVar Loc PName | DisplacedBoundVar Loc PName
| WrapTypeError TypeError | WrapTypeError TypeError
| AlreadyExists Loc Name
| LoadError Loc FilePath FileError | LoadError Loc FilePath FileError
| ExpectedFail Loc
| SchemeOnNamespace Loc Mods
| MainOnNamespace Loc Mods
| WrongFail String Error Loc
| WrapParseError String ParseError | WrapParseError String ParseError
export export
prettyLexError : {opts : _} -> String -> LexError -> Eff Pretty (Doc opts) prettyLexError : {opts : _} -> String -> LexError -> Eff Pretty (Doc opts)
prettyLexError file (Err reason line col char) = do prettyLexError file (Err reason line col char) = do
let loc = makeLoc file (MkBounds line col line col)
reason <- case reason of reason <- case reason of
EndInput => pure "unexpected end of input" Other msg => pure $ text msg
NoRuleApply => pure $ text "unrecognised character: \{show char}" NoRuleApply => case char of
Just char => pure $ text "unrecognised character: \{show char}"
Nothing => pure $ text "unexpected end of input"
ComposeNotClosing (sl, sc) (el, ec) => pure $ ComposeNotClosing (sl, sc) (el, ec) => pure $
hsep ["unterminated token at", !(prettyBounds (MkBounds sl sc el ec))] hsep ["unterminated token at", !(prettyBounds (MkBounds sl sc el ec))]
let loc = makeLoc file (MkBounds line col line col)
pure $ vappend !(prettyLoc loc) reason pure $ vappend !(prettyLoc loc) reason
export export
@ -62,19 +72,23 @@ prettyParseError file (ParseError errs) =
traverse (map ("-" <++>) . prettyParseError1 file) (toList errs) traverse (map ("-" <++>) . prettyParseError1 file) (toList errs)
parameters (showContext : Bool) parameters {opts : LayoutOpts} (showContext : Bool)
export export
prettyError : {opts : _} -> Error -> Eff Pretty (Doc opts) prettyError : Error -> Eff Pretty (Doc opts)
prettyError (AnnotationNeeded loc ctx tm) = prettyError (AnnotationNeeded loc ctx tm) =
[|vappend (prettyLoc loc) [|vappend (prettyLoc loc)
(hangD "type annotation needed on" (hangD "type annotation needed on"
!(prettyTerm ctx.dnames ctx.tnames tm))|] !(prettyTerm ctx.dnames ctx.tnames tm))|]
-- [todo] print the original PTerm instead -- [todo] print the original PTerm instead
prettyError (DuplicatesInEnum loc tags) = prettyError (DuplicatesInEnumType loc tags) =
[|vappend (prettyLoc loc) [|vappend (prettyLoc loc)
(hangD "duplicate tags in enum type" !(prettyEnum tags))|] (hangD "duplicate tags in enum type" !(prettyEnum tags))|]
prettyError (DuplicatesInEnumCase loc tags) =
[|vappend (prettyLoc loc)
(hangD "duplicate arms in enum case" !(prettyEnum tags))|]
prettyError (DimNotInScope loc i) = prettyError (DimNotInScope loc i) =
[|vappend (prettyLoc loc) [|vappend (prettyLoc loc)
(pure $ hsep ["dimension", !(hl DVar $ text i), "not in scope"])|] (pure $ hsep ["dimension", !(hl DVar $ text i), "not in scope"])|]
@ -101,10 +115,32 @@ parameters (showContext : Bool)
prettyError (WrapTypeError err) = prettyError (WrapTypeError err) =
Typing.prettyError showContext $ trimContext 2 err Typing.prettyError showContext $ trimContext 2 err
prettyError (AlreadyExists loc name) = pure $
vsep [!(prettyLoc loc),
sep [!(prettyFree name), "has already been defined"]]
prettyError (LoadError loc file err) = pure $ prettyError (LoadError loc file err) = pure $
vsep [!(prettyLoc loc), vsep [!(prettyLoc loc),
"couldn't load file" <++> text file, "couldn't load file" <++> text file,
text $ show err] text $ show err]
prettyError (ExpectedFail loc) = pure $
vsep [!(prettyLoc loc), "expected error"]
prettyError (SchemeOnNamespace loc ns) = pure $
vsep [!(prettyLoc loc),
hsep ["namespace", !(hl Free $ text $ joinBy "." $ toList ns),
"cannot have #[compile-scheme] attached"]]
prettyError (MainOnNamespace loc ns) = pure $
vsep [!(prettyLoc loc),
hsep ["namespace", !(hl Free $ text $ joinBy "." $ toList ns),
"cannot have #[main] attached"]]
prettyError (WrongFail str err loc) = pure $
vsep [!(prettyLoc loc),
"wrong error, expected to match", !(hl Constant $ text "\"\{str}\""),
"but got", !(prettyError err)]
prettyError (WrapParseError file err) = prettyError (WrapParseError file err) =
prettyParseError file err prettyParseError file err

View file

@ -1,6 +1,7 @@
module Quox.Parser.Lexer module Quox.Parser.Lexer
import Quox.CharExtra import Quox.CharExtra
import Quox.NatExtra
import Quox.Name import Quox.Name
import Data.String.Extra import Data.String.Extra
import Data.SortedMap import Data.SortedMap
@ -19,7 +20,7 @@ import Derive.Prelude
||| @ Reserved reserved token ||| @ Reserved reserved token
||| @ Name name, possibly qualified ||| @ Name name, possibly qualified
||| @ Nat nat literal ||| @ Nat nat literal
||| @ String string literal ||| @ Str string literal
||| @ Tag tag literal ||| @ Tag tag literal
||| @ TYPE "Type" or "★" with ascii nat directly after ||| @ TYPE "Type" or "★" with ascii nat directly after
||| @ Sup superscript or ^ number (displacement, or universe for ★) ||| @ Sup superscript or ^ number (displacement, or universe for ★)
@ -34,16 +35,27 @@ data Token =
| Sup Nat | Sup Nat
%runElab derive "Token" [Eq, Ord, Show] %runElab derive "Token" [Eq, Ord, Show]
-- token or whitespace ||| token or whitespace
||| @ Skip whitespace, comments, etc
||| @ Invalid a token which failed a post-lexer check
||| (e.g. a qualified name containing a keyword)
||| @ T a well formed token
public export public export
0 TokenW : Type data ExtToken = Skip | Invalid String String | T Token
TokenW = Maybe Token %runElab derive "ExtToken" [Eq, Ord, Show]
public export
data ErrorReason =
NoRuleApply
| ComposeNotClosing (Int, Int) (Int, Int)
| Other String
%runElab derive "ErrorReason" [Eq, Ord, Show]
public export public export
record Error where record Error where
constructor Err constructor Err
reason : StopReason reason : ErrorReason
line, col : Int line, col : Int
||| `Nothing` if the error is at the end of the input ||| `Nothing` if the error is at the end of the input
char : Maybe Char char : Maybe Char
@ -52,77 +64,118 @@ record Error where
private private
skip : Lexer -> Tokenizer TokenW skip : Lexer -> Tokenizer ExtToken
skip t = match t $ const Nothing skip t = match t $ const Skip
private private
match : Lexer -> (String -> Token) -> Tokenizer TokenW tmatch : Lexer -> (String -> Token) -> Tokenizer ExtToken
match t f = Tokenizer.match t (Just . f) tmatch t f = match t (T . f)
%hide Tokenizer.match
private
name : Tokenizer TokenW
name = match name $ Name . fromListP . split (== '.') . normalizeNfc
||| [todo] escapes other than `\"` and (accidentally) `\\`
export export
fromStringLit : String -> String fromStringLit : (String -> Token) -> String -> ExtToken
fromStringLit = pack . go . unpack . drop 1 . dropLast 1 where fromStringLit f str =
go : List Char -> List Char case go $ unpack $ drop 1 $ dropLast 1 str of
go [] = [] Left err => Invalid err str
go ['\\'] = ['\\'] -- i guess??? Right ok => T $ f $ pack ok
go ('\\' :: c :: cs) = c :: go cs where
go (c :: cs) = c :: go cs Interpolation Char where interpolate = singleton
go, hexEscape : List Char -> Either String (List Char)
go [] = Right []
go ['\\'] = Left "string ends with \\"
go ('\\' :: 'n' :: cs) = ('\n' ::) <$> go cs
go ('\\' :: 't' :: cs) = ('\t' ::) <$> go cs
go ('\\' :: 'x' :: cs) = hexEscape cs
go ('\\' :: 'X' :: cs) = hexEscape cs
go ('\\' :: '\\' :: cs) = ('\\' ::) <$> go cs
go ('\\' :: '"' :: cs) = ('"' ::) <$> go cs
-- [todo] others
go ('\\' :: c :: _) = Left "unknown escape '\{c}'"
go (c :: cs) = (c ::) <$> go cs
hexEscape cs =
case break (== ';') cs of
(hs, ';' :: rest) => do
let hs = pack hs
let Just c = Int.fromHex hs
| Nothing => Left #"invalid hex string "\#{hs}" in escape"#
if isCodepoint c
then (chr c ::) <$> go (assert_smaller cs rest)
else Left "codepoint \{hs} out of range"
_ => Left "unterminated hex escape"
private private
string : Tokenizer TokenW string : Tokenizer ExtToken
string = match stringLit (Str . fromStringLit) string = match stringLit $ fromStringLit Str
%hide binLit
%hide octLit
%hide hexLit
private private
nat : Tokenizer TokenW nat : Tokenizer ExtToken
nat = match (some (range '0' '9')) (Nat . cast) nat = match hexLit fromHexLit
<|> tmatch decLit fromDecLit
where
withUnderscores : Lexer -> Lexer
withUnderscores l = l <+> many (opt (is '_') <+> l)
withoutUnderscores : String -> String
withoutUnderscores = pack . go . unpack where
go : List Char -> List Char
go [] = []
go ('_' :: cs) = go cs
go (c :: cs) = c :: go cs
decLit =
withUnderscores (range '0' '9') <+> reject idContEnd
hexLit =
approx "0x" <+>
withUnderscores (range '0' '9' <|> range 'a' 'f' <|> range 'A' 'F') <+>
reject idContEnd
fromDecLit : String -> Token
fromDecLit = Nat . cast . withoutUnderscores
fromHexLit : String -> ExtToken
fromHexLit str =
maybe (Invalid "invalid hex sequence" str) (T . Nat) $
fromHex $ withoutUnderscores $ drop 2 str
private private
tag : Tokenizer TokenW tag : Tokenizer ExtToken
tag = match (is '\'' <+> name) (Tag . drop 1) tag = tmatch (is '\'' <+> name) (Tag . drop 1)
<|> match (is '\'' <+> stringLit) (Tag . fromStringLit . drop 1) <|> match (is '\'' <+> stringLit) (fromStringLit Tag . drop 1)
private %inline
fromSub : Char -> Char
fromSub c = case c of
'' => '0'; '' => '1'; '' => '2'; '' => '3'; '' => '4'
'' => '5'; '' => '6'; '' => '7'; '' => '8'; '' => '9'; _ => c
private %inline private %inline
fromSup : Char -> Char fromSup : Char -> Char
fromSup c = case c of fromSup c = case c of
'' => '0'; '¹' => '1'; '²' => '2'; '³' => '3'; '' => '4' '' => '0'; '¹' => '1'; '²' => '2'; '³' => '3'; '' => '4'
'' => '5'; '' => '6'; '' => '7'; '' => '8'; '' => '9'; _ => c '' => '5'; '' => '6'; '' => '7'; '' => '8'; '' => '9'; _ => c
private %inline
subToNat : String -> Nat
subToNat = cast . pack . map fromSub . unpack
private %inline private %inline
supToNat : String -> Nat supToNat : String -> Nat
supToNat = cast . pack . map fromSup . unpack supToNat = cast . pack . map fromSup . unpack
-- ★0, Type0. base ★/Type is a Reserved -- ★0, Type0. base ★/Type is a Reserved and ★¹/Type¹ are sequences of two tokens
private private
universe : Tokenizer TokenW universe : Tokenizer ExtToken
universe = universeWith "" <|> universeWith "Type" where universe = universeWith "" <|> universeWith "Type" where
universeWith : String -> Tokenizer TokenW universeWith : String -> Tokenizer ExtToken
universeWith pfx = universeWith pfx =
let len = length pfx in let len = length pfx in
match (exact pfx <+> digits) (TYPE . cast . drop len) tmatch (exact pfx <+> digits) (TYPE . cast . drop len)
private private
sup : Tokenizer TokenW sup : Tokenizer ExtToken
sup = match (some $ pred isSupDigit) (Sup . supToNat) sup = tmatch (some $ pred isSupDigit) (Sup . supToNat)
<|> match (is '^' <+> digits) (Sup . cast . drop 1) <|> tmatch (is '^' <+> digits) (Sup . cast . drop 1)
private %inline private %inline
@ -134,9 +187,11 @@ namespace Reserved
||| description of a reserved symbol ||| description of a reserved symbol
||| @ Word a reserved word (must not be followed by letters, digits, etc) ||| @ Word a reserved word (must not be followed by letters, digits, etc)
||| @ Sym a reserved symbol (must not be followed by symbolic chars) ||| @ Sym a reserved symbol (must not be followed by symbolic chars)
||| @ Punc a character that doesn't show up in names (brackets, etc) ||| @ Punc a character that doesn't show up in names (brackets, etc);
||| also a sequence ending in one of those, like `#[`, since the
||| difference relates to lookahead
public export public export
data Reserved1 = Word String | Sym String | Punc Char data Reserved1 = Word String | Sym String | Punc String
%runElab derive "Reserved1" [Eq, Ord, Show] %runElab derive "Reserved1" [Eq, Ord, Show]
||| description of a token that might have unicode & ascii-only aliases ||| description of a token that might have unicode & ascii-only aliases
@ -145,17 +200,14 @@ namespace Reserved
%runElab derive "Reserved" [Eq, Ord, Show] %runElab derive "Reserved" [Eq, Ord, Show]
public export public export
Sym1, Word1 : String -> Reserved Sym1, Word1, Punc1 : String -> Reserved
Sym1 = Only . Sym Sym1 = Only . Sym
Word1 = Only . Word Word1 = Only . Word
public export
Punc1 : Char -> Reserved
Punc1 = Only . Punc Punc1 = Only . Punc
public export public export
resString1 : Reserved1 -> String resString1 : Reserved1 -> String
resString1 (Punc x) = singleton x resString1 (Punc x) = x
resString1 (Word w) = w resString1 (Word w) = w
resString1 (Sym s) = s resString1 (Sym s) = s
@ -166,17 +218,23 @@ resString : Reserved -> String
resString (Only r) = resString1 r resString (Only r) = resString1 r
resString (r `Or` _) = resString1 r resString (r `Or` _) = resString1 r
||| return both representative strings for a token description
public export
resString2 : Reserved -> List String
resString2 (Only r) = [resString1 r]
resString2 (r `Or` s) = [resString1 r, resString1 s]
private private
resTokenizer1 : Reserved1 -> String -> Tokenizer TokenW resTokenizer1 : Reserved1 -> String -> Tokenizer ExtToken
resTokenizer1 r str = resTokenizer1 r str =
let res : String -> Token := const $ Reserved str in let res : String -> Token := const $ Reserved str in
case r of Word w => match (exact w <+> reject idContEnd) res case r of Word w => tmatch (exact w <+> reject idContEnd) res
Sym s => match (exact s <+> reject symCont) res Sym s => tmatch (exact s <+> reject symCont) res
Punc x => match (is x) res Punc x => tmatch (exact x) res
||| match a reserved token ||| match a reserved token
export export
resTokenizer : Reserved -> Tokenizer TokenW resTokenizer : Reserved -> Tokenizer ExtToken
resTokenizer (Only r) = resTokenizer1 r (resString1 r) resTokenizer (Only r) = resTokenizer1 r (resString1 r)
resTokenizer (r `Or` s) = resTokenizer (r `Or` s) =
resTokenizer1 r (resString1 r) <|> resTokenizer1 s (resString1 r) resTokenizer1 r (resString1 r) <|> resTokenizer1 s (resString1 r)
@ -188,8 +246,8 @@ resTokenizer (r `Or` s) =
public export public export
reserved : List Reserved reserved : List Reserved
reserved = reserved =
[Punc1 '(', Punc1 ')', Punc1 '[', Punc1 ']', Punc1 '{', Punc1 '}', [Punc1 "(", Punc1 ")", Punc1 "[", Punc1 "]", Punc1 "{", Punc1 "}",
Punc1 ',', Punc1 ';', Punc1 ",", Punc1 ";", Punc1 "#[", Punc1 "#![",
Sym1 "@", Sym1 "@",
Sym1 ":", Sym1 ":",
Sym "" `Or` Sym "=>", Sym "" `Or` Sym "=>",
@ -197,12 +255,15 @@ reserved =
Sym "×" `Or` Sym "**", Sym "×" `Or` Sym "**",
Sym "" `Or` Sym "==", Sym "" `Or` Sym "==",
Sym "" `Or` Sym "::", Sym "" `Or` Sym "::",
Punc1 '.', Punc1 ".",
Word1 "case", Word1 "case",
Word1 "case0", Word1 "case1", Word1 "case0", Word1 "case1",
Word "caseω" `Or` Word "case#", Word "caseω" `Or` Word "case#",
Word1 "return", Word1 "return",
Word1 "of", Word1 "of",
Word1 "let", Word1 "in",
Word1 "let0", Word1 "let1",
Word "letω" `Or` Word "let#",
Word1 "fst", Word1 "snd", Word1 "fst", Word1 "snd",
Word1 "_", Word1 "_",
Word1 "Eq", Word1 "Eq",
@ -211,35 +272,71 @@ reserved =
Word "ω" `Or` Sym "#", Word "ω" `Or` Sym "#",
Sym "" `Or` Word "Type", Sym "" `Or` Word "Type",
Word "" `Or` Word "Nat", Word "" `Or` Word "Nat",
Word1 "IOState",
Word1 "String",
Word1 "zero", Word1 "succ", Word1 "zero", Word1 "succ",
Word1 "coe", Word1 "comp", Word1 "coe", Word1 "comp",
Word1 "def", Word1 "def",
Word1 "def0", Word1 "def0",
Word "defω" `Or` Word "def#", Word "defω" `Or` Word "def#",
Word1 "postulate",
Word1 "postulate0",
Word "postulateω" `Or` Word "postulate#",
Sym1 "=", Sym1 "=",
Word1 "load", Word1 "load",
Word1 "namespace"] Word1 "namespace"]
public export
reservedStrings : List String
reservedStrings = map resString reserved
public export
allReservedStrings : List String
allReservedStrings = foldMap resString2 reserved
||| `IsReserved str` is true if `Reserved str` might actually show up in ||| `IsReserved str` is true if `Reserved str` might actually show up in
||| the token stream ||| the token stream
public export public export
IsReserved : String -> Type IsReserved : String -> Type
IsReserved str = str `Elem` map resString reserved IsReserved str = So (str `elem` reservedStrings)
private
name : Tokenizer ExtToken
name =
match name $ \str =>
let parts = split (== '.') $ normalizeNfc str in
case find (`elem` allReservedStrings) (toList parts) of
Nothing => T $ Name $ fromListP parts
Just w => Invalid "reserved word '\{w}' inside name \{str}" str
export export
tokens : Tokenizer TokenW tokens : Tokenizer ExtToken
tokens = choice $ tokens = choice $
map skip [pred isWhitespace, map skip [pred isWhitespace,
lineComment (exact "--" <+> reject symCont), lineComment (exact "--" <+> reject symCont),
blockComment (exact "{-") (exact "-}")] <+> blockComment (exact "{-") (exact "-}")] <+>
[universe] <+> -- ★ᵢ takes precedence over bare ★ [universe] <+> -- Type<i> takes precedence over bare Type
map resTokenizer reserved <+> map resTokenizer reserved <+>
[sup, nat, string, tag, name] [sup, nat, string, tag, name]
export
check : Alternative f =>
WithBounds ExtToken -> Either Error (f (WithBounds Token))
check (MkBounded val irr bounds@(MkBounds line col _ _)) = case val of
Skip => Right empty
T tok => Right $ pure $ MkBounded tok irr bounds
Invalid msg tok => Left $ Err (Other msg) line col (index 0 tok)
export
toErrorReason : StopReason -> Maybe ErrorReason
toErrorReason EndInput = Nothing
toErrorReason NoRuleApply = Just NoRuleApply
toErrorReason (ComposeNotClosing s e) = Just $ ComposeNotClosing s e
export export
lex : String -> Either Error (List (WithBounds Token)) lex : String -> Either Error (List (WithBounds Token))
lex str = lex str =
let (res, reason, line, col, str) = lex tokens str in let (res, reason, line, col, str) = lex tokens str in
case reason of case toErrorReason reason of
EndInput => Right $ mapMaybe sequence res Nothing => concatMap check res @{MonoidApplicative}
_ => Left $ Err {reason, line, col, char = index 0 str} Just e => Left $ Err {reason = e, line, col, char = index 0 str}

View file

@ -1,5 +1,7 @@
module Quox.Parser.LoadFile module Quox.Parser.LoadFile
import public Quox.Parser.Syntax
import Quox.Parser.Parser
import Quox.Loc import Quox.Loc
import Quox.EffExtra import Quox.EffExtra
import Data.IORef import Data.IORef
@ -20,7 +22,7 @@ data LoadFileL : (lbl : k) -> Type -> Type where
[search lbl] [search lbl]
Seen : FilePath -> LoadFileL lbl Bool Seen : FilePath -> LoadFileL lbl Bool
SetSeen : FilePath -> LoadFileL lbl () SetSeen : FilePath -> LoadFileL lbl ()
DoLoad : Loc -> FilePath -> LoadFileL lbl String DoLoad : Loc -> FilePath -> LoadFileL lbl PFile
public export public export
LoadFile : Type -> Type LoadFile : Type -> Type
@ -47,11 +49,11 @@ setSeen = setSeenAt ()
export export
doLoadAt : (0 lbl : k) -> Has (LoadFileL lbl) fs => doLoadAt : (0 lbl : k) -> Has (LoadFileL lbl) fs =>
Loc -> FilePath -> Eff fs String Loc -> FilePath -> Eff fs PFile
doLoadAt lbl loc file = send $ DoLoad {lbl} loc file doLoadAt lbl loc file = send $ DoLoad {lbl} loc file
export %inline export %inline
doLoad : Has LoadFile fs => Loc -> FilePath -> Eff fs String doLoad : Has LoadFile fs => Loc -> FilePath -> Eff fs PFile
doLoad = doLoadAt () doLoad = doLoadAt ()
@ -63,10 +65,6 @@ public export
IncludePath : Type IncludePath : Type
IncludePath = List String IncludePath = List String
public export
ErrorWrapper : Type -> Type
ErrorWrapper e = Loc -> FilePath -> FileError -> e
export covering export covering
readFileFrom : HasIO io => IncludePath -> FilePath -> readFileFrom : HasIO io => IncludePath -> FilePath ->
io (Either FileError String) io (Either FileError String)
@ -76,23 +74,27 @@ readFileFrom inc f =
Nothing => pure $ Left $ FileNotFound Nothing => pure $ Left $ FileNotFound
export covering export covering
handleLoadFileIOE : ErrorWrapper e -> handleLoadFileIOE : (Loc -> FilePath -> FileError -> e) ->
(FilePath -> Parser.Error -> e) ->
IORef SeenSet -> IncludePath -> IORef SeenSet -> IncludePath ->
LoadFileL lbl a -> IOErr e a LoadFileL lbl a -> IOErr e a
handleLoadFileIOE inj seen inc = \case handleLoadFileIOE injf injp seen inc = \case
Seen f => contains f <$> readIORef seen Seen f => contains f <$> readIORef seen
SetSeen f => modifyIORef seen $ insert f SetSeen f => modifyIORef seen $ insert f
DoLoad l f => readFileFrom inc f >>= either (ioLeft . inj l f) pure DoLoad l f =>
case !(readFileFrom inc f) of
Left err => ioLeft $ injf l f err
Right str => either (ioLeft . injp f) pure $ lexParseInput f str
export export
loadFileAt : (0 lbl : k) -> Has (LoadFileL lbl) fs => loadFileAt : (0 lbl : k) -> Has (LoadFileL lbl) fs =>
Loc -> FilePath -> Eff fs (Maybe String) Loc -> FilePath -> Eff fs (Maybe PFile)
loadFileAt lbl loc file = loadFileAt lbl loc file =
if !(seenAt lbl file) if !(seenAt lbl file)
then pure Nothing then pure Nothing
else Just <$> doLoadAt lbl loc file <* setSeenAt lbl file else Just <$> doLoadAt lbl loc file <* setSeenAt lbl file
export export
loadFile : Has LoadFile fs => Loc -> FilePath -> Eff fs (Maybe String) loadFile : Has LoadFile fs => Loc -> FilePath -> Eff fs (Maybe PFile)
loadFile = loadFileAt () loadFile = loadFileAt ()

View file

@ -124,7 +124,7 @@ qname = terminalMatch "name" `(Name n) `(n)
||| unqualified name ||| unqualified name
export export
baseName : Grammar True PBaseName baseName : Grammar True PBaseName
baseName = terminalMatch "unqualified name" `(Name (MakePName [<] b)) `(b) baseName = terminalMatch "unqualified name" `(Name (MkPName [<] b)) `(b)
||| dimension constant (0 or 1) ||| dimension constant (0 or 1)
export export
@ -149,6 +149,12 @@ export
qty : FileName -> Grammar True PQty qty : FileName -> Grammar True PQty
qty fname = withLoc fname [|PQ qtyVal|] qty fname = withLoc fname [|PQ qtyVal|]
export
exactName : String -> Grammar True ()
exactName name = terminal "expected '\{name}'" $ \case
Name (MkPName [<] x) => guard $ x == name
_ => Nothing
||| pattern var (unqualified name or _) ||| pattern var (unqualified name or _)
export export
@ -280,19 +286,81 @@ export
universe1 : Grammar True Universe universe1 : Grammar True Universe
universe1 = universeTok <|> res "" *> option 0 super universe1 = universeTok <|> res "" *> option 0 super
||| argument/atomic term: single-token terms, or those with delimiters e.g.
||| `[t]` public export
PCaseArm : Type
PCaseArm = (PCasePat, PTerm)
export
caseArm : FileName -> Grammar True PCaseArm
caseArm fname =
[|(,) (casePat fname) (needRes "" *> assert_total term fname)|]
export
checkCaseArms : Loc -> List PCaseArm -> Grammar False PCaseBody
checkCaseArms loc [] = pure $ CaseEnum [] loc
checkCaseArms loc ((PPair x y _, rhs) :: rest) =
if null rest then pure $ CasePair (x, y) rhs loc
else fatalError "unexpected pattern after pair"
checkCaseArms loc ((PTag tag _, rhs1) :: rest) = do
let rest = for rest $ \case
(PTag tag _, rhs) => Just (tag, rhs)
_ => Nothing
maybe (fatalError "expected all patterns to be tags")
(\rest => pure $ CaseEnum ((tag, rhs1) :: rest) loc) rest
checkCaseArms loc ((PZero _, rhs1) :: rest) = do
let [(PSucc p q ih _, rhs2)] = rest
| _ => fatalError "expected succ pattern after zero"
pure $ CaseNat rhs1 (p, q, ih, rhs2) loc
checkCaseArms loc ((PSucc p q ih _, rhs1) :: rest) = do
let [(PZero _, rhs2)] = rest
| _ => fatalError "expected zero pattern after succ"
pure $ CaseNat rhs2 (p, q, ih, rhs1) loc
checkCaseArms loc ((PBox x _, rhs) :: rest) =
if null rest then pure $ CaseBox x rhs loc
else fatalError "unexpected pattern after box"
export
caseBody : FileName -> Grammar True PCaseBody
caseBody fname = do
body <- bounds $ delimSep "{" "}" ";" $ caseArm fname
let loc = makeLoc fname body.bounds
checkCaseArms loc body.val
export
caseReturn : FileName -> Grammar True (PatVar, PTerm)
caseReturn fname = do
x <- patVar fname <* resC "" <|> unused fname
ret <- assert_total term fname
pure (x, ret)
export
caseTerm : FileName -> Grammar True PTerm
caseTerm fname = withLoc fname $ do
qty <- caseIntro fname; commit
head <- mustWork $ assert_total term fname; needRes "return"
ret <- mustWork $ caseReturn fname; needRes "of"
body <- mustWork $ caseBody fname
pure $ Case qty head ret body
||| argument/atomic term: single-token terms, or those with delimiters
||| e.g. `[t]`. includes `case` because the end delimiter is the `}`.
export export
termArg : FileName -> Grammar True PTerm termArg : FileName -> Grammar True PTerm
termArg fname = withLoc fname $ termArg fname = withLoc fname $
[|TYPE universe1|] [|TYPE universe1|]
<|> IOState <$ res "IOState"
<|> [|Enum enumType|] <|> [|Enum enumType|]
<|> [|Tag tag|] <|> [|Tag tag|]
<|> const <$> boxTerm fname <|> const <$> boxTerm fname
<|> Nat <$ res "" <|> NAT <$ res ""
<|> Zero <$ res "zero" <|> Nat 0 <$ res "zero"
<|> [|fromNat nat|] <|> [|Nat nat|]
<|> STRING <$ res "String"
<|> [|Str strLit|]
<|> [|V qname displacement|] <|> [|V qname displacement|]
<|> const <$> caseTerm fname
<|> const <$> tupleTerm fname <|> const <$> tupleTerm fname
export export
@ -372,11 +440,24 @@ eqTerm : FileName -> Grammar True PTerm
eqTerm fname = withLoc fname $ eqTerm fname = withLoc fname $
resC "Eq" *> mustWork [|Eq (typeLine fname) (termArg fname) (termArg fname)|] resC "Eq" *> mustWork [|Eq (typeLine fname) (termArg fname) (termArg fname)|]
private
appArg : Loc -> PTerm -> Either PDim PTerm -> PTerm
appArg loc f (Left p) = DApp f p loc
appArg loc f (Right s) = App f s loc
||| a dimension argument with an `@` prefix, or
||| a term argument with no prefix
export
anyArg : FileName -> Grammar True (Either PDim PTerm)
anyArg fname = dimArg fname <||> termArg fname
export export
resAppTerm : FileName -> (word : String) -> (0 _ : IsReserved word) => resAppTerm : FileName -> (word : String) -> (0 _ : IsReserved word) =>
(PTerm -> Loc -> PTerm) -> Grammar True PTerm (PTerm -> Loc -> PTerm) -> Grammar True PTerm
resAppTerm fname word f = withLoc fname $ resAppTerm fname word f = withLoc fname $ do
resC word *> mustWork [|f (termArg fname)|] head <- withLoc fname $ resC word *> mustWork [|f (termArg fname)|]
args <- many $ anyArg fname
pure $ \loc => foldl (appArg loc) head args
export export
succTerm : FileName -> Grammar True PTerm succTerm : FileName -> Grammar True PTerm
@ -390,21 +471,12 @@ export
sndTerm : FileName -> Grammar True PTerm sndTerm : FileName -> Grammar True PTerm
sndTerm fname = resAppTerm fname "snd" Snd sndTerm fname = resAppTerm fname "snd" Snd
||| a dimension argument with an `@` prefix, or
||| a term argument with no prefix
export
anyArg : FileName -> Grammar True (Either PDim PTerm)
anyArg fname = dimArg fname <||> termArg fname
export export
normalAppTerm : FileName -> Grammar True PTerm normalAppTerm : FileName -> Grammar True PTerm
normalAppTerm fname = withLoc fname $ do normalAppTerm fname = withLoc fname $ do
head <- termArg fname head <- termArg fname
args <- many $ anyArg fname args <- many $ anyArg fname
pure $ \loc => foldl (ap loc) head args pure $ \loc => foldl (appArg loc) head args
where ap : Loc -> PTerm -> Either PDim PTerm -> PTerm
ap loc f (Left p) = DApp f p loc
ap loc f (Right s) = App f s loc
||| application term `f x @y z`, or other terms that look like application ||| application term `f x @y z`, or other terms that look like application
||| like `succ` or `coe`. ||| like `succ` or `coe`.
@ -512,105 +584,284 @@ where
makePi q doms cod loc = makePi q doms cod loc =
foldr (\(q, x, s), t => Pi q x s t loc) cod $ toDoms (toQty q) doms foldr (\(q, x, s), t => Pi q x s t loc) cod $ toDoms (toQty q) doms
public export
PCaseArm : Type
PCaseArm = (PCasePat, PTerm)
export export
caseArm : FileName -> Grammar True PCaseArm letIntro : FileName -> Grammar True (Maybe PQty)
caseArm fname = letIntro fname =
[|(,) (casePat fname) (needRes "" *> assert_total term fname)|] withLoc fname (Just . PQ Zero <$ res "let0")
<|> withLoc fname (Just . PQ One <$ res "let1")
<|> withLoc fname (Just . PQ Any <$ res "letω")
<|> Nothing <$ resC "let"
private
letBinder : FileName -> Maybe PQty -> Grammar True (PQty, PatVar, PTerm)
letBinder fname mq = do
qty <- letQty fname mq
x <- patVar fname
type <- optional $ resC ":" *> term fname
rhs <- resC "=" *> term fname
pure (qty, x, makeLetRhs rhs type)
where
letQty : FileName -> Maybe PQty -> Grammar False PQty
letQty fname Nothing = qty fname <* mustWork (resC ".") <|> defLoc fname (PQ One)
letQty fname (Just q) = pure q
makeLetRhs : PTerm -> Maybe PTerm -> PTerm
makeLetRhs tm ty = maybe tm (\t => Ann tm t (extendL tm.loc t.loc)) ty
export export
checkCaseArms : Loc -> List PCaseArm -> Grammar False PCaseBody letTerm : FileName -> Grammar True PTerm
checkCaseArms loc [] = pure $ CaseEnum [] loc letTerm fname = withLoc fname $ do
checkCaseArms loc ((PPair x y _, rhs) :: rest) = qty <- letIntro fname
if null rest then pure $ CasePair (x, y) rhs loc binds <- sepEndBy1 (res ";") $ assert_total letBinder fname qty
else fatalError "unexpected pattern after pair" mustWork $ resC "in"
checkCaseArms loc ((PTag tag _, rhs1) :: rest) = do body <- assert_total term fname
let rest = for rest $ \case pure $ \loc => foldr (\b, s => Let b s loc) body binds
(PTag tag _, rhs) => Just (tag, rhs)
_ => Nothing
maybe (fatalError "expected all patterns to be tags")
(\rest => pure $ CaseEnum ((tag, rhs1) :: rest) loc) rest
checkCaseArms loc ((PZero _, rhs1) :: rest) = do
let [(PSucc p q ih _, rhs2)] = rest
| _ => fatalError "expected succ pattern after zero"
pure $ CaseNat rhs1 (p, q, ih, rhs2) loc
checkCaseArms loc ((PSucc p q ih _, rhs1) :: rest) = do
let [(PZero _, rhs2)] = rest
| _ => fatalError "expected zero pattern after succ"
pure $ CaseNat rhs2 (p, q, ih, rhs1) loc
checkCaseArms loc ((PBox x _, rhs) :: rest) =
if null rest then pure $ CaseBox x rhs loc
else fatalError "unexpected pattern after box"
export
caseBody : FileName -> Grammar True PCaseBody
caseBody fname = do
body <- bounds $ delimSep "{" "}" ";" $ caseArm fname
let loc = makeLoc fname body.bounds
checkCaseArms loc body.val
export
caseReturn : FileName -> Grammar True (PatVar, PTerm)
caseReturn fname = do
x <- patVar fname <* resC "" <|> unused fname
ret <- assert_total term fname
pure (x, ret)
export
caseTerm : FileName -> Grammar True PTerm
caseTerm fname = withLoc fname $ do
qty <- caseIntro fname; commit
head <- mustWork $ assert_total term fname; needRes "return"
ret <- mustWork $ caseReturn fname; needRes "of"
body <- mustWork $ caseBody fname
pure $ Case qty head ret body
-- export
-- term : FileName -> Grammar True PTerm -- term : FileName -> Grammar True PTerm
term fname = lamTerm fname term fname = lamTerm fname
<|> caseTerm fname
<|> piTerm fname <|> piTerm fname
<|> sigmaTerm fname <|> sigmaTerm fname
<|> letTerm fname
export export
decl : FileName -> Grammar True PDecl attr' : FileName -> (o : String) -> (0 _ : IsReserved o) =>
Grammar True PAttr
attr' fname o = withLoc fname $ do
resC o
name <- baseName
args <- many $ termArg fname
mustWork $ resC "]"
pure $ PA name args
export %inline
attr : FileName -> Grammar True PAttr
attr fname = attr' fname "#["
||| `def` alone means `defω`
export export
defIntro : FileName -> Grammar True PQty findDups : List PAttr -> List String
defIntro fname = findDups attrs =
withLoc fname (PQ Zero <$ resC "def0") SortedSet.toList $ snd $ foldl check (empty, empty) attrs
<|> withLoc fname (PQ Any <$ resC "defω") where
<|> do pos <- bounds $ resC "def" Seen = SortedSet String; Dups = SortedSet String
check : (Seen, Dups) -> PAttr -> (Seen, Dups)
check (seen, dups) (PA a _ _) =
(insert a seen, if contains a seen then insert a dups else dups)
export
noDups : List PAttr -> Grammar False ()
noDups attrs = do
let dups = findDups attrs
when (not $ null dups) $
fatalError "duplicate attribute names: \{joinBy "," dups}"
export
attrList : FileName -> Grammar False (List PAttr)
attrList fname = do
res <- many $ attr fname
noDups res $> res
public export
data AttrMatch a =
Matched a
| NoMatch String (List String)
| Malformed String String
export
Functor AttrMatch where
map f (Matched x) = Matched $ f x
map f (NoMatch s w) = NoMatch s w
map f (Malformed a e) = Malformed a e
export
(<|>) : AttrMatch a -> AttrMatch a -> AttrMatch a
Matched x <|> _ = Matched x
NoMatch {} <|> y = y
Malformed a e <|> _ = Malformed a e
export
isFail : PAttr -> List String -> AttrMatch PFail
isFail (PA "fail" [] _) _ = Matched PFailAny
isFail (PA "fail" [Str s _] _) _ = Matched $ PFailMatch s
isFail (PA "fail" _ _) _ = Malformed "fail" "be absent or a string literal"
isFail a w = NoMatch a.name w
export
isMain : PAttr -> List String -> AttrMatch ()
isMain (PA "main" [] _) _ = Matched ()
isMain (PA "main" _ _) _ = Malformed "main" "have no arguments"
isMain a w = NoMatch a.name w
export
isScheme : PAttr -> List String -> AttrMatch String
isScheme (PA "compile-scheme" [Str s _] _) _ = Matched s
isScheme (PA "compile-scheme" _ _) _ =
Malformed "compile-scheme" "be a string literal"
isScheme a w = NoMatch a.name w
export
matchAttr : String -> AttrMatch a -> Either String a
matchAttr _ (Matched x) = Right x
matchAttr d (NoMatch a w) = Left $ unlines
["unrecognised \{d} attribute \{a}", "expected one of: \{show w}"]
matchAttr _ (Malformed a s) = Left $ unlines
["invalid \{a} attribute", "(should \{s})"]
export
mkPDef : List PAttr -> PQty -> PBaseName -> PBody ->
Either String (Loc -> PDefinition)
mkPDef attrs qty name body = do
let start = MkPDef qty name body PSucceed False Nothing noLoc
res <- foldlM addAttr start attrs
pure $ \l => {loc_ := l} (the PDefinition res)
where
data PDefAttr = DefFail PFail | DefMain | DefScheme String
isDefAttr : PAttr -> Either String PDefAttr
isDefAttr attr =
let defAttrs = ["fail", "main", "compile-scheme"] in
matchAttr "definition" $
DefFail <$> isFail attr defAttrs
<|> DefMain <$ isMain attr defAttrs
<|> DefScheme <$> isScheme attr defAttrs
addAttr : PDefinition -> PAttr -> Either String PDefinition
addAttr def attr =
case !(isDefAttr attr) of
DefFail f => pure $ {fail := f} def
DefMain => pure $ {main := True} def
DefScheme str => pure $ {scheme := Just str} def
export
mkPNamespace : List PAttr -> Mods -> List PDecl ->
Either String (Loc -> PNamespace)
mkPNamespace attrs name decls = do
let start = MkPNamespace name decls PSucceed noLoc
res <- foldlM addAttr start attrs
pure $ \l => {loc_ := l} (the PNamespace res)
where
isNsAttr a = matchAttr "namespace" $ isFail a ["fail"]
addAttr : PNamespace -> PAttr -> Either String PNamespace
addAttr ns attr = pure $ {fail := !(isNsAttr attr)} ns
||| `def` alone means `defω`; same for `postulate`
export
defIntro' : (bare, zero, omega : String) ->
(0 _ : IsReserved bare) =>
(0 _ : IsReserved zero) =>
(0 _ : IsReserved omega) =>
FileName -> Grammar True PQty
defIntro' bare zero omega fname =
withLoc fname (PQ Zero <$ resC zero)
<|> withLoc fname (PQ Any <$ resC omega)
<|> do pos <- bounds $ resC bare
let any = PQ Any $ makeLoc fname pos.bounds let any = PQ Any $ makeLoc fname pos.bounds
option any $ qty fname <* needRes "." option any $ qty fname <* needRes "."
export export
definition : FileName -> Grammar True PDefinition defIntro : FileName -> Grammar True PQty
definition fname = withLoc fname $ do defIntro = defIntro' "def" "def0" "defω"
export
postulateIntro : FileName -> Grammar True PQty
postulateIntro = defIntro' "postulate" "postulate0" "postulateω"
export
postulate : FileName -> List PAttr -> Grammar True PDefinition
postulate fname attrs = withLoc fname $ do
qty <- postulateIntro fname
name <- baseName
type <- resC ":" *> mustWork (term fname)
optRes ";"
either fatalError pure $ mkPDef attrs qty name $ PPostulate type
export
concrete : FileName -> List PAttr -> Grammar True PDefinition
concrete fname attrs = withLoc fname $ do
qty <- defIntro fname qty <- defIntro fname
name <- baseName name <- baseName
type <- optional $ resC ":" *> mustWork (term fname) type <- optional $ resC ":" *> mustWork (term fname)
term <- needRes "=" *> mustWork (term fname) term <- needRes "=" *> mustWork (term fname)
optRes ";" optRes ";"
pure $ MkPDef qty name type term either fatalError pure $ mkPDef attrs qty name $ PConcrete type term
export export
namespace_ : FileName -> Grammar True PNamespace definition : FileName -> List PAttr -> Grammar True PDefinition
namespace_ fname = withLoc fname $ do definition fname attrs =
ns <- resC "namespace" *> qname; needRes "{" try (postulate fname attrs) <|> concrete fname attrs
decls <- nsInner; optRes ";"
pure $ MkPNamespace (ns.mods :< ns.base) decls export
nsname : Grammar True Mods
nsname = do ns <- qname; pure $ ns.mods :< ns.base
export
pragma : FileName -> Grammar True PPragma
pragma fname = do
a <- attr' fname "#!["
either fatalError pure $ case a.name of
"log" => logArgs a.args a.loc
_ => Left $
#"unrecognised pragma "\#{a.name}"\n"# ++
#"known pragmas: ["log"]"#
where
levelOOB : Nat -> Either String a
levelOOB n = Left $
"log level \{show n} out of bounds\n" ++
"expected number in range 0\{show maxLogLevel} inclusive"
toLevel : Nat -> Either String LogLevel
toLevel lvl = maybe (levelOOB lvl) Right $ toLogLevel lvl
unknownCat : String -> Either String a
unknownCat cat = Left $
"unknown log category \{show cat}\n" ++
"known categories: \{show $ ["all", "default"] ++ logCategories}"
toCat : String -> Either String LogCategory
toCat cat = maybe (unknownCat cat) Right $ toLogCategory cat
fromPair : PTerm -> Either String (String, Nat)
fromPair (Pair (V (MkPName [<] x) Nothing _) (Nat n _) _) = Right (x, n)
fromPair _ = Left "invalid argument to log pragma"
logCatArg : (String, Nat) -> Either String Log.PushArg
logCatArg ("default", lvl) = [|SetDefault $ toLevel lvl|]
logCatArg ("all", lvl) = [|SetAll $ toLevel lvl|]
logCatArg (cat, lvl) = [|SetCat (toCat cat) (toLevel lvl)|]
logArgs : List PTerm -> Loc -> Either String PPragma
logArgs [] _ = Left "missing arguments to log pragma"
logArgs [V "pop" Nothing _] loc = Right $ PLogPop loc
logArgs other loc = do
args <- traverse (logCatArg <=< fromPair) other
pure $ PLogPush args loc
export
decl : FileName -> Grammar True PDecl
export
namespace_ : FileName -> List PAttr -> Grammar True PNamespace
namespace_ fname attrs = withLoc fname $ do
ns <- resC "namespace" *> nsname; needRes "{"
decls <- nsInner
either fatalError pure $ mkPNamespace attrs ns decls
where where
nsInner : Grammar True (List PDecl) nsInner : Grammar True (List PDecl)
nsInner = [] <$ resC "}" nsInner = [] <$ resC "}"
<|> [|(assert_total decl fname <* commit) :: assert_total nsInner|] <|> [|(assert_total decl fname <* commit) :: assert_total nsInner|]
decl fname = [|PDef $ definition fname|] <|> [|PNs $ namespace_ fname|] export
declBody : FileName -> List PAttr -> Grammar True PDecl
declBody fname attrs =
[|PDef $ definition fname attrs|] <|> [|PNs $ namespace_ fname attrs|]
-- decl : FileName -> Grammar True PDecl
decl fname =
(attrList fname >>= declBody fname)
<|> PPrag <$> pragma fname
export export
load : FileName -> Grammar True PTopLevel load : FileName -> Grammar True PTopLevel
@ -622,7 +873,7 @@ topLevel : FileName -> Grammar True PTopLevel
topLevel fname = load fname <|> [|PD $ decl fname|] topLevel fname = load fname <|> [|PD $ decl fname|]
export export
input : FileName -> Grammar False (List PTopLevel) input : FileName -> Grammar False PFile
input fname = [] <$ eof input fname = [] <$ eof
<|> [|(topLevel fname <* commit) :: assert_total input fname|] <|> [|(topLevel fname <* commit) :: assert_total input fname|]
@ -631,5 +882,5 @@ lexParseTerm : FileName -> String -> Either Error PTerm
lexParseTerm = lexParseWith . term lexParseTerm = lexParseWith . term
export export
lexParseInput : FileName -> String -> Either Error (List PTopLevel) lexParseInput : FileName -> String -> Either Error PFile
lexParseInput = lexParseWith . input lexParseInput = lexParseWith . input

View file

@ -3,6 +3,8 @@ module Quox.Parser.Syntax
import public Quox.Loc import public Quox.Loc
import public Quox.Syntax import public Quox.Syntax
import public Quox.Definition import public Quox.Definition
import Quox.PrettyValExtra
import public Quox.Log
import Derive.Prelude import Derive.Prelude
%hide TT.Name %hide TT.Name
@ -14,9 +16,9 @@ import Derive.Prelude
public export public export
data PatVar = Unused Loc | PV PBaseName Loc data PatVar = Unused Loc | PV PBaseName Loc
%name PatVar v %name PatVar v
%runElab derive "PatVar" [Eq, Ord, Show] %runElab derive "PatVar" [Eq, Ord, Show, PrettyVal]
export export %inline
Located PatVar where Located PatVar where
(Unused loc).loc = loc (Unused loc).loc = loc
(PV _ loc).loc = loc (PV _ loc).loc = loc
@ -38,17 +40,17 @@ record PQty where
val : Qty val : Qty
loc_ : Loc loc_ : Loc
%name PQty qty %name PQty qty
%runElab derive "PQty" [Eq, Ord, Show] %runElab derive "PQty" [Eq, Ord, Show, PrettyVal]
export Located PQty where q.loc = q.loc_ export %inline Located PQty where q.loc = q.loc_
namespace PDim namespace PDim
public export public export
data PDim = K DimConst Loc | V PBaseName Loc data PDim = K DimConst Loc | V PBaseName Loc
%name PDim p, q %name PDim p, q
%runElab derive "PDim" [Eq, Ord, Show] %runElab derive "PDim" [Eq, Ord, Show, PrettyVal]
export export %inline
Located PDim where Located PDim where
(K _ loc).loc = loc (K _ loc).loc = loc
(V _ loc).loc = loc (V _ loc).loc = loc
@ -56,7 +58,7 @@ Located PDim where
public export public export
data PTagVal = PT TagVal Loc data PTagVal = PT TagVal Loc
%name PTagVal tag %name PTagVal tag
%runElab derive "PTagVal" [Eq, Ord, Show] %runElab derive "PTagVal" [Eq, Ord, Show, PrettyVal]
namespace PTerm namespace PTerm
@ -66,6 +68,8 @@ namespace PTerm
data PTerm = data PTerm =
TYPE Universe Loc TYPE Universe Loc
| IOState Loc
| Pi PQty PatVar PTerm PTerm Loc | Pi PQty PatVar PTerm PTerm Loc
| Lam PatVar PTerm Loc | Lam PatVar PTerm Loc
| App PTerm PTerm Loc | App PTerm PTerm Loc
@ -82,8 +86,11 @@ namespace PTerm
| DLam PatVar PTerm Loc | DLam PatVar PTerm Loc
| DApp PTerm PDim Loc | DApp PTerm PDim Loc
| Nat Loc | NAT Loc
| Zero Loc | Succ PTerm Loc | Nat Nat Loc | Succ PTerm Loc
| STRING Loc -- "String" is a reserved word in idris
| Str String Loc
| BOX PQty PTerm Loc | BOX PQty PTerm Loc
| Box PTerm Loc | Box PTerm Loc
@ -94,6 +101,8 @@ namespace PTerm
| Coe (PatVar, PTerm) PDim PDim PTerm Loc | Coe (PatVar, PTerm) PDim PDim PTerm Loc
| Comp (PatVar, PTerm) PDim PDim PTerm PDim | Comp (PatVar, PTerm) PDim PDim PTerm PDim
(PatVar, PTerm) (PatVar, PTerm) Loc (PatVar, PTerm) (PatVar, PTerm) Loc
| Let (PQty, PatVar, PTerm) PTerm Loc
%name PTerm s, t %name PTerm s, t
public export public export
@ -104,35 +113,43 @@ namespace PTerm
| CaseBox PatVar PTerm Loc | CaseBox PatVar PTerm Loc
%name PCaseBody body %name PCaseBody body
%runElab deriveMutual ["PTerm", "PCaseBody"] [Eq, Ord, Show] public export %inline
Zero : Loc -> PTerm
Zero = Nat 0
export %runElab deriveMutual ["PTerm", "PCaseBody"] [Eq, Ord, Show, PrettyVal]
export %inline
Located PTerm where Located PTerm where
(TYPE _ loc).loc = loc (TYPE _ loc).loc = loc
(Pi _ _ _ _ loc).loc = loc (IOState loc).loc = loc
(Lam _ _ loc).loc = loc (Pi _ _ _ _ loc).loc = loc
(App _ _ loc).loc = loc (Lam _ _ loc).loc = loc
(Sig _ _ _ loc).loc = loc (App _ _ loc).loc = loc
(Pair _ _ loc).loc = loc (Sig _ _ _ loc).loc = loc
(Fst _ loc).loc = loc (Pair _ _ loc).loc = loc
(Snd _ loc).loc = loc (Fst _ loc).loc = loc
(Case _ _ _ _ loc).loc = loc (Snd _ loc).loc = loc
(Enum _ loc).loc = loc (Case _ _ _ _ loc).loc = loc
(Tag _ loc).loc = loc (Enum _ loc).loc = loc
(Eq _ _ _ loc).loc = loc (Tag _ loc).loc = loc
(DLam _ _ loc).loc = loc (Eq _ _ _ loc).loc = loc
(DApp _ _ loc).loc = loc (DLam _ _ loc).loc = loc
(Nat loc).loc = loc (DApp _ _ loc).loc = loc
(Zero loc).loc = loc (NAT loc).loc = loc
(Succ _ loc).loc = loc (Nat _ loc).loc = loc
(BOX _ _ loc).loc = loc (Succ _ loc).loc = loc
(Box _ loc).loc = loc (STRING loc).loc = loc
(V _ _ loc).loc = loc (Str _ loc).loc = loc
(Ann _ _ loc).loc = loc (BOX _ _ loc).loc = loc
(Coe _ _ _ _ loc).loc = loc (Box _ loc).loc = loc
(Comp _ _ _ _ _ _ _ loc).loc = loc (V _ _ loc).loc = loc
(Ann _ _ loc).loc = loc
(Coe _ _ _ _ loc).loc = loc
(Comp _ _ _ _ _ _ _ loc).loc = loc
(Let _ _ loc).loc = loc
export export %inline
Located PCaseBody where Located PCaseBody where
(CasePair _ _ loc).loc = loc (CasePair _ _ loc).loc = loc
(CaseEnum _ loc).loc = loc (CaseEnum _ loc).loc = loc
@ -140,18 +157,45 @@ Located PCaseBody where
(CaseBox _ _ loc).loc = loc (CaseBox _ _ loc).loc = loc
public export
data PBody = PConcrete (Maybe PTerm) PTerm | PPostulate PTerm
%name PBody body
%runElab derive "PBody" [Eq, Ord, Show, PrettyVal]
public export
data PFail =
PSucceed
| PFailAny
| PFailMatch String
%runElab derive "PFail" [Eq, Ord, Show, PrettyVal]
public export public export
record PDefinition where record PDefinition where
constructor MkPDef constructor MkPDef
qty : PQty qty : PQty
name : PBaseName name : PBaseName
type : Maybe PTerm body : PBody
term : PTerm fail : PFail
loc_ : Loc main : Bool
scheme : Maybe String
loc_ : Loc
%name PDefinition def %name PDefinition def
%runElab derive "PDefinition" [Eq, Ord, Show] %runElab derive "PDefinition" [Eq, Ord, Show, PrettyVal]
export Located PDefinition where def.loc = def.loc_ export %inline Located PDefinition where def.loc = def.loc_
public export
data PPragma =
PLogPush (List Log.PushArg) Loc
| PLogPop Loc
%name PPragma prag
%runElab derive "PPragma" [Eq, Ord, Show, PrettyVal]
export %inline
Located PPragma where
(PLogPush _ loc).loc = loc
(PLogPop loc).loc = loc
mutual mutual
public export public export
@ -159,35 +203,49 @@ mutual
constructor MkPNamespace constructor MkPNamespace
name : Mods name : Mods
decls : List PDecl decls : List PDecl
fail : PFail
loc_ : Loc loc_ : Loc
%name PNamespace ns %name PNamespace ns
public export public export
data PDecl = data PDecl =
PDef PDefinition PDef PDefinition
| PNs PNamespace | PNs PNamespace
| PPrag PPragma
%name PDecl decl %name PDecl decl
%runElab deriveMutual ["PNamespace", "PDecl"] [Eq, Ord, Show] %runElab deriveMutual ["PNamespace", "PDecl"] [Eq, Ord, Show, PrettyVal]
export Located PNamespace where ns.loc = ns.loc_ export %inline Located PNamespace where ns.loc = ns.loc_
export export %inline
Located PDecl where Located PDecl where
(PDef def).loc = def.loc (PDef d).loc = d.loc
(PNs ns).loc = ns.loc (PNs ns).loc = ns.loc
(PPrag prag).loc = prag.loc
public export public export
data PTopLevel = PD PDecl | PLoad String Loc data PTopLevel = PD PDecl | PLoad String Loc
%name PTopLevel t %name PTopLevel t
%runElab derive "PTopLevel" [Eq, Ord, Show] %runElab derive "PTopLevel" [Eq, Ord, Show, PrettyVal]
export export %inline
Located PTopLevel where Located PTopLevel where
(PD decl).loc = decl.loc (PD decl).loc = decl.loc
(PLoad _ loc).loc = loc (PLoad _ loc).loc = loc
public export public export
fromNat : Nat -> Loc -> PTerm record PAttr where
fromNat 0 loc = Zero loc constructor PA
fromNat (S k) loc = Succ (fromNat k loc) loc name : PBaseName
args : List PTerm
loc_ : Loc
%name PAttr attr
%runElab derive "PAttr" [Eq, Ord, Show, PrettyVal]
export %inline Located PAttr where attr.loc = attr.loc_
public export
PFile : Type
PFile = List PTopLevel

View file

@ -41,7 +41,7 @@ data HL
| Dim | DVar | DVarErr | Dim | DVar | DVarErr
| Qty | Universe | Qty | Universe
| Syntax | Syntax
| Tag | Constant
%runElab derive "HL" [Eq, Ord, Show] %runElab derive "HL" [Eq, Ord, Show]
@ -86,20 +86,38 @@ toSGR DVarErr = [SetForeground BrightGreen, SetStyle SingleUnderline]
toSGR Qty = [SetForeground BrightMagenta] toSGR Qty = [SetForeground BrightMagenta]
toSGR Universe = [SetForeground BrightRed] toSGR Universe = [SetForeground BrightRed]
toSGR Syntax = [SetForeground BrightCyan] toSGR Syntax = [SetForeground BrightCyan]
toSGR Tag = [SetForeground BrightRed] toSGR Constant = [SetForeground BrightRed]
export %inline export %inline
highlightSGR : HL -> Highlight highlightSGR : HL -> Highlight
highlightSGR h = MkHighlight (escapeSGR $ toSGR h) (escapeSGR [Reset]) highlightSGR h = MkHighlight (escapeSGR $ toSGR h) (escapeSGR [Reset])
export %inline
toClass : HL -> String
toClass Delim = "dl"
toClass Free = "fr"
toClass TVar = "tv"
toClass TVarErr = "tv err"
toClass Dim = "dc"
toClass DVar = "dv"
toClass DVarErr = "dv err"
toClass Qty = "qt"
toClass Universe = "un"
toClass Syntax = "sy"
toClass Constant = "co"
export %inline
highlightHtml : HL -> Highlight
highlightHtml h = MkHighlight #"<span class="\#{toClass h}">"# "</span>"
export %inline
runPrettyHL : (HL -> Highlight) -> Eff Pretty a -> a
runPrettyHL f = runPrettyWith Outer Unicode f 2
export %inline export %inline
runPretty : Eff Pretty a -> a runPretty : Eff Pretty a -> a
runPretty = runPrettyWith Outer Unicode noHighlight 2 runPretty = runPrettyHL noHighlight
export %inline
runPrettyColor : Eff Pretty a -> a
runPrettyColor = runPrettyWith Outer Unicode highlightSGR 2
export %inline export %inline
@ -115,11 +133,14 @@ export %inline
hangD : {opts : LayoutOpts} -> Doc opts -> Doc opts -> Eff Pretty (Doc opts) hangD : {opts : LayoutOpts} -> Doc opts -> Doc opts -> Eff Pretty (Doc opts)
hangD d1 d2 = pure $ hangSep !(askAt INDENT) d1 d2 hangD d1 d2 = pure $ hangSep !(askAt INDENT) d1 d2
export %inline
hangSingle : {opts : LayoutOpts} -> Nat -> Doc opts -> Doc opts -> Doc opts
hangSingle n d1 d2 = ifMultiline (d1 <++> d2) (vappend d1 (indent n d2))
export %inline export %inline
hangDSingle : {opts : LayoutOpts} -> Doc opts -> Doc opts -> hangDSingle : {opts : LayoutOpts} -> Doc opts -> Doc opts ->
Eff Pretty (Doc opts) Eff Pretty (Doc opts)
hangDSingle d1 d2 = hangDSingle d1 d2 = pure $ hangSingle !(askAt INDENT) d1 d2
pure $ ifMultiline (d1 <++> d2) (vappend d1 !(indentD d2))
export export
@ -188,11 +209,24 @@ parameters {opts : LayoutOpts} {auto _ : Foldable t}
separateTight : Doc opts -> t (Doc opts) -> Doc opts separateTight : Doc opts -> t (Doc opts) -> Doc opts
separateTight d = sep . exceptLast (<+> d) . toList separateTight d = sep . exceptLast (<+> d) . toList
export
hseparateTight : Doc opts -> t (Doc opts) -> Doc opts
hseparateTight d = hsep . exceptLast (<+> d) . toList
export
vseparateTight : Doc opts -> t (Doc opts) -> Doc opts
vseparateTight d = vsep . exceptLast (<+> d) . toList
export export
fillSeparateTight : Doc opts -> t (Doc opts) -> Doc opts fillSeparateTight : Doc opts -> t (Doc opts) -> Doc opts
fillSeparateTight d = fillSep . exceptLast (<+> d) . toList fillSeparateTight d = fillSep . exceptLast (<+> d) . toList
export %inline
pshow : {opts : LayoutOpts} -> Show a => a -> Doc opts
pshow = text . show
export %inline export %inline
ifUnicode : (uni, asc : Lazy a) -> Eff Pretty a ifUnicode : (uni, asc : Lazy a) -> Eff Pretty a
ifUnicode uni asc = ifUnicode uni asc =
@ -232,46 +266,51 @@ prettyDBind = hl DVar . prettyBind'
export %inline export %inline
typeD, arrowD, darrowD, timesD, lamD, eqndD, dlamD, annD, natD, typeD, ioStateD, arrowD, darrowD, timesD, lamD, eqndD, dlamD, annD, natD,
eqD, colonD, commaD, semiD, caseD, typecaseD, returnD, stringD, eqD, colonD, commaD, semiD, atD, caseD, typecaseD, returnD, ofD, dotD,
ofD, dotD, zeroD, succD, coeD, compD, undD, cstD, pipeD, fstD, sndD : zeroD, succD, coeD, compD, undD, cstD, pipeD, fstD, sndD, letD, inD :
{opts : LayoutOpts} -> Eff Pretty (Doc opts) {opts : LayoutOpts} -> Eff Pretty (Doc opts)
typeD = hl Syntax . text =<< ifUnicode "" "Type" typeD = hl Syntax . text =<< ifUnicode "" "Type"
arrowD = hl Delim . text =<< ifUnicode "" "->" ioStateD = hl Syntax $ text "IOState"
darrowD = hl Delim . text =<< ifUnicode "" "=>" arrowD = hl Syntax . text =<< ifUnicode "" "->"
timesD = hl Delim . text =<< ifUnicode "×" "**" darrowD = hl Syntax . text =<< ifUnicode "" "=>"
timesD = hl Syntax . text =<< ifUnicode "×" "**"
lamD = hl Syntax . text =<< ifUnicode "λ" "fun" lamD = hl Syntax . text =<< ifUnicode "λ" "fun"
eqndD = hl Delim . text =<< ifUnicode "" "==" eqndD = hl Syntax . text =<< ifUnicode "" "=="
dlamD = hl Syntax . text =<< ifUnicode "δ" "dfun" dlamD = hl Syntax . text =<< ifUnicode "δ" "dfun"
annD = hl Delim . text =<< ifUnicode "" "::" annD = hl Syntax . text =<< ifUnicode "" "::"
natD = hl Syntax . text =<< ifUnicode "" "Nat" natD = hl Syntax . text =<< ifUnicode "" "Nat"
eqD = hl Syntax $ text "Eq" stringD = hl Syntax $ text "String"
colonD = hl Delim $ text ":" eqD = hl Syntax $ text "Eq"
commaD = hl Delim $ text "," colonD = hl Syntax $ text ":"
semiD = hl Delim $ text ";" commaD = hl Syntax $ text ","
caseD = hl Syntax $ text "case" semiD = hl Delim $ text ";"
typecaseD = hl Syntax $ text "type-case" atD = hl Delim $ text "@"
ofD = hl Syntax $ text "of" caseD = hl Syntax $ text "case"
returnD = hl Syntax $ text "return" typecaseD = hl Syntax $ text "type-case"
dotD = hl Delim $ text "." ofD = hl Syntax $ text "of"
zeroD = hl Syntax $ text "zero" returnD = hl Syntax $ text "return"
succD = hl Syntax $ text "succ" dotD = hl Delim $ text "."
coeD = hl Syntax $ text "coe" zeroD = hl Constant $ text "zero"
compD = hl Syntax $ text "comp" succD = hl Constant $ text "succ"
undD = hl Syntax $ text "_" coeD = hl Syntax $ text "coe"
cstD = hl Syntax $ text "=" compD = hl Syntax $ text "comp"
pipeD = hl Syntax $ text "|" undD = hl Syntax $ text "_"
fstD = hl Syntax $ text "fst" cstD = hl Syntax $ text "="
sndD = hl Syntax $ text "snd" pipeD = hl Delim $ text "|"
fstD = hl Syntax $ text "fst"
sndD = hl Syntax $ text "snd"
letD = hl Syntax $ text "let"
inD = hl Syntax $ text "in"
export export
prettyApp : {opts : LayoutOpts} -> Nat -> Doc opts -> prettyApp : {opts : LayoutOpts} -> Nat -> Doc opts ->
List (Doc opts) -> Doc opts List (Doc opts) -> Doc opts
prettyApp ind f args = prettyApp ind f args =
hsep (f :: args) ifMultiline
<|> hsep [f, vsep args] (hsep (f :: args))
<|> vsep (f :: map (indent ind) args) (f <++> vsep args <|> vsep (f :: map (indent ind) args))
export export
prettyAppD : {opts : LayoutOpts} -> Doc opts -> List (Doc opts) -> prettyAppD : {opts : LayoutOpts} -> Doc opts -> List (Doc opts) ->
@ -312,4 +351,14 @@ prettyLoc (L (YesLoc file b)) =
export export
prettyTag : {opts : _} -> String -> Eff Pretty (Doc opts) prettyTag : {opts : _} -> String -> Eff Pretty (Doc opts)
prettyTag tag = hl Tag $ text $ "'" ++ quoteTag tag prettyTag tag = hl Constant $ text $ "'" ++ quoteTag tag
export
prettyStrLit : {opts : _} -> String -> Eff Pretty (Doc opts)
prettyStrLit s =
let s = concatMap esc1 $ unpack s in
hl Constant $ hcat ["\"", text s, "\""]
where
esc1 : Char -> String
esc1 '"' = "\""; esc1 '\\' = "\\"
esc1 c = singleton c

View file

@ -0,0 +1,20 @@
module Quox.PrettyValExtra
import Data.DPair
import Derive.Prelude
import public Text.Show.Value
import public Text.Show.PrettyVal
import public Text.Show.PrettyVal.Derive
%language ElabReflection
%runElab derive "SnocList" [PrettyVal]
export %inline
PrettyVal a => PrettyVal (Subset a p) where
prettyVal (Element x _) = Con "Element" [prettyVal x, Con "_" []]
export %inline
(forall x. PrettyVal (p x)) => PrettyVal (Exists p) where
prettyVal (Evidence _ p) = Con "Evidence" [Con "_" [], prettyVal p]

View file

@ -38,3 +38,22 @@ export %inline
export %inline %hint export %inline %hint
ShowScoped : (forall n. Show (f n)) => Show (Scoped s f n) ShowScoped : (forall n. Show (f n)) => Show (Scoped s f n)
ShowScoped = deriveShow ShowScoped = deriveShow
||| scope which ignores all its binders
public export %inline
SN : Located1 f => {s : Nat} -> f n -> Scoped s f n
SN body = S (replicate s $ BN Unused body.loc) $ N body
||| scope which uses its binders
public export %inline
SY : BContext s -> f (s + n) -> Scoped s f n
SY ns = S ns . Y
public export %inline
name : Scoped 1 f n -> BindName
name (S [< x] _) = x
public export %inline
(.name) : Scoped 1 f n -> BindName
s.name = name s

View file

@ -6,4 +6,5 @@ import public Quox.Syntax.Qty
import public Quox.Syntax.Shift import public Quox.Syntax.Shift
import public Quox.Syntax.Subst import public Quox.Syntax.Subst
import public Quox.Syntax.Term import public Quox.Syntax.Term
import public Quox.Syntax.Builtin
import public Quox.Var import public Quox.Var

View file

@ -0,0 +1,27 @@
module Quox.Syntax.Builtin
import Derive.Prelude
import Quox.PrettyValExtra
import Quox.Pretty
import Quox.Syntax.Term
%default total
%language ElabReflection
public export
data Builtin
= Main
%runElab derive "Builtin" [Eq, Ord, Show, PrettyVal]
public export
builtinDesc : Builtin -> String
builtinDesc Main = "a function declared as #[main]"
public export
builtinTypeDoc : {opts : LayoutOpts} -> Builtin -> Eff Pretty (Doc opts)
builtinTypeDoc Main =
prettyTerm [<] [<] $
Pi One (IOState noLoc)
(SN $ Sig (Enum (fromList [!(ifUnicode "𝑎" "a")]) noLoc)
(SN (IOState noLoc)) noLoc) noLoc

View file

@ -6,6 +6,7 @@ import Quox.Var
import Quox.Syntax.Subst import Quox.Syntax.Subst
import Quox.Pretty import Quox.Pretty
import Quox.Context import Quox.Context
import Quox.PrettyValExtra
import Decidable.Equality import Decidable.Equality
import Control.Function import Control.Function
@ -18,7 +19,7 @@ import Derive.Prelude
public export public export
data DimConst = Zero | One data DimConst = Zero | One
%name DimConst e %name DimConst e
%runElab derive "DimConst" [Eq, Ord, Show] %runElab derive "DimConst" [Eq, Ord, Show, PrettyVal]
||| `ends l r e` returns `l` if `e` is `Zero`, or `r` if it is `One`. ||| `ends l r e` returns `l` if `e` is `Zero`, or `r` if it is `One`.
public export public export

View file

@ -59,10 +59,15 @@ Traversable (IfConsistent eqs) where
traverse f Nothing = pure Nothing traverse f Nothing = pure Nothing
traverse f (Just x) = Just <$> f x traverse f (Just x) = Just <$> f x
public export
ifConsistentElse : Applicative f => (eqs : DimEq d) ->
f a -> f () -> f (IfConsistent eqs a)
ifConsistentElse ZeroIsOne yes no = Nothing <$ no
ifConsistentElse (C _) yes no = Just <$> yes
public export public export
ifConsistent : Applicative f => (eqs : DimEq d) -> f a -> f (IfConsistent eqs a) ifConsistent : Applicative f => (eqs : DimEq d) -> f a -> f (IfConsistent eqs a)
ifConsistent ZeroIsOne act = pure Nothing ifConsistent eqs act = ifConsistentElse eqs act (pure ())
ifConsistent (C _) act = Just <$> act
public export public export
toMaybe : IfConsistent eqs a -> Maybe a toMaybe : IfConsistent eqs a -> Maybe a
@ -71,13 +76,13 @@ toMaybe (Just x) = Just x
export export
fromGround' : Context' DimConst d -> DimEq' d fromGround' : BContext d -> Context' DimConst d -> DimEq' d
fromGround' [<] = [<] fromGround' [<] [<] = [<]
fromGround' (ctx :< e) = fromGround' ctx :< Just (K e noLoc) fromGround' (xs :< x) (ctx :< e) = fromGround' xs ctx :< Just (K e x.loc)
export export
fromGround : Context' DimConst d -> DimEq d fromGround : BContext d -> Context' DimConst d -> DimEq d
fromGround = C . fromGround' fromGround = C .: fromGround'
public export %inline public export %inline
@ -118,7 +123,7 @@ equal ZeroIsOne p q = True
equal (C eqs) p q = get eqs p == get eqs q equal (C eqs) p q = get eqs p == get eqs q
infixl 7 :<? export infixl 7 :<?
export %inline export %inline
(:<?) : DimEq d -> Maybe (Dim d) -> DimEq (S d) (:<?) : DimEq d -> Maybe (Dim d) -> DimEq (S d)
ZeroIsOne :<? d = ZeroIsOne ZeroIsOne :<? d = ZeroIsOne
@ -237,9 +242,20 @@ setSelf (B i _) (C eqs) with (compareP i i) | (compare i.nat i.nat)
_ | IsGT gt | GT = absurd gt _ | IsGT gt | GT = absurd gt
private %inline
dimEqPrec : BContext d -> Maybe (DimEq' d) -> PPrec
dimEqPrec vars eqs =
if length vars <= 1 && maybe True null eqs then Arg else Outer
private private
prettyDVars : {opts : _} -> BContext d -> Eff Pretty (SnocList (Doc opts)) prettyDVars' : {opts : _} -> BContext d -> Eff Pretty (SnocList (Doc opts))
prettyDVars = traverse prettyDBind . toSnocList' prettyDVars' = traverse prettyDBind . toSnocList'
export
prettyDVars : {opts : _} -> BContext d -> Eff Pretty (Doc opts)
prettyDVars vars =
parensIfM (dimEqPrec vars Nothing) $
fillSeparateTight !commaD $ !(prettyDVars' vars)
private private
prettyCst : {opts : _} -> BContext d -> Dim d -> Dim d -> Eff Pretty (Doc opts) prettyCst : {opts : _} -> BContext d -> Dim d -> Dim d -> Eff Pretty (Doc opts)
@ -256,16 +272,16 @@ prettyCsts dnames (eqs :< Just q) =
export export
prettyDimEq' : {opts : _} -> BContext d -> DimEq' d -> Eff Pretty (Doc opts) prettyDimEq' : {opts : _} -> BContext d -> DimEq' d -> Eff Pretty (Doc opts)
prettyDimEq' dnames eqs = do prettyDimEq' vars eqs = do
vars <- prettyDVars dnames vars' <- prettyDVars' vars
eqs <- prettyCsts dnames eqs eqs' <- prettyCsts vars eqs
let prec = if length vars <= 1 && null eqs then Arg else Outer parensIfM (dimEqPrec vars (Just eqs)) $
parensIfM prec $ fillSeparateTight !commaD $ toList vars ++ toList eqs fillSeparateTight !commaD $ vars' ++ eqs'
export export
prettyDimEq : {opts : _} -> BContext d -> DimEq d -> Eff Pretty (Doc opts) prettyDimEq : {opts : _} -> BContext d -> DimEq d -> Eff Pretty (Doc opts)
prettyDimEq dnames ZeroIsOne = do prettyDimEq dnames ZeroIsOne = do
vars <- prettyDVars dnames vars <- prettyDVars' dnames
cst <- prettyCst [<] (K Zero noLoc) (K One noLoc) cst <- prettyCst [<] (K Zero noLoc) (K One noLoc)
pure $ separateTight !commaD $ vars :< cst pure $ separateTight !commaD $ vars :< cst
prettyDimEq dnames (C eqs) = prettyDimEq' dnames eqs prettyDimEq dnames (C eqs) = prettyDimEq' dnames eqs

View file

@ -6,6 +6,7 @@ module Quox.Syntax.Qty
import Quox.Pretty import Quox.Pretty
import Quox.Decidable import Quox.Decidable
import Quox.PrettyValExtra
import Data.DPair import Data.DPair
import Derive.Prelude import Derive.Prelude
@ -20,7 +21,7 @@ import Derive.Prelude
||| - ω (or #): don't care. an ω variable *can* also be used 0/1 time ||| - ω (or #): don't care. an ω variable *can* also be used 0/1 time
public export public export
data Qty = Zero | One | Any data Qty = Zero | One | Any
%runElab derive "Qty" [Eq, Ord, Show] %runElab derive "Qty" [Eq, Ord, Show, PrettyVal]
%name Qty.Qty pi, rh %name Qty.Qty pi, rh
@ -79,7 +80,7 @@ lub p q = if p == q then p else Any
||| for the subject of a typing judgment. see @qtt, §2.3 for more detail ||| for the subject of a typing judgment. see @qtt, §2.3 for more detail
public export public export
data SQty = SZero | SOne data SQty = SZero | SOne
%runElab derive "SQty" [Eq, Ord, Show] %runElab derive "SQty" [Eq, Ord, Show, PrettyVal]
%name Qty.SQty sg %name Qty.SQty sg
||| "σ ⨴ π" ||| "σ ⨴ π"
@ -96,7 +97,7 @@ subjMult sg _ = sg
||| at runtime at all or not ||| at runtime at all or not
public export public export
data GQty = GZero | GAny data GQty = GZero | GAny
%runElab derive "GQty" [Eq, Ord, Show] %runElab derive "GQty" [Eq, Ord, Show, PrettyVal]
%name GQty rh %name GQty rh
public export public export

View file

@ -227,7 +227,7 @@ compViaNatCorrect by (SS bz) =
%transform "Shift.(.)" Shift.(.) = compViaNat %transform "Shift.(.)" Shift.(.) = compViaNat
infixl 8 // export infixl 8 //
public export public export
interface CanShift f where interface CanShift f where
(//) : f from -> Shift from to -> f to (//) : f from -> Shift from to -> f to

View file

@ -20,7 +20,7 @@ data Subst : (Nat -> Type) -> Nat -> Nat -> Type where
(:::) : (t : Lazy (env to)) -> Subst env from to -> Subst env (S from) to (:::) : (t : Lazy (env to)) -> Subst env from to -> Subst env (S from) to
%name Subst th, ph, ps %name Subst th, ph, ps
infixr 7 !::: export infixr 7 !:::
||| in case the automatic laziness insertion gets confused ||| in case the automatic laziness insertion gets confused
public export public export
(!:::) : env to -> Subst env from to -> Subst env (S from) to (!:::) : env to -> Subst env from to -> Subst env (S from) to
@ -42,7 +42,7 @@ export Ord (f to) => Ord (Subst f from to) where compare = compare `on` repr
export Show (f to) => Show (Subst f from to) where show = show . repr export Show (f to) => Show (Subst f from to) where show = show . repr
infixl 8 // export infixl 8 //
public export public export
interface FromVar term => CanSubstSelf term where interface FromVar term => CanSubstSelf term where
(//) : term from -> Lazy (Subst term from to) -> term to (//) : term from -> Lazy (Subst term from to) -> term to
@ -96,18 +96,18 @@ map f (t ::: th) = f t ::: map f th
public export %inline public export %inline
push : CanSubstSelf f => Subst f from to -> Subst f (S from) (S to) push : CanSubstSelf f => Loc -> Subst f from to -> Subst f (S from) (S to)
push th = fromVar VZ ::: (th . shift 1) push loc th = fromVarLoc VZ loc ::: (th . shift 1)
-- [fixme] a better way to do this? -- [fixme] a better way to do this?
public export public export
pushN : CanSubstSelf f => (s : Nat) -> pushN : CanSubstSelf f => (s : Nat) -> Loc ->
Subst f from to -> Subst f (s + from) (s + to) Subst f from to -> Subst f (s + from) (s + to)
pushN 0 th = th pushN 0 _ th = th
pushN (S s) th = pushN (S s) loc th =
rewrite plusSuccRightSucc s from in rewrite plusSuccRightSucc s from in
rewrite plusSuccRightSucc s to in rewrite plusSuccRightSucc s to in
pushN s $ fromVar VZ ::: (th . shift 1) pushN s loc $ fromVarLoc VZ loc ::: (th . shift 1)
public export public export
drop1 : Subst f (S from) to -> Subst f from to drop1 : Subst f (S from) to -> Subst f from to

View file

@ -3,4 +3,3 @@ module Quox.Syntax.Term
import public Quox.Syntax.Term.Base import public Quox.Syntax.Term.Base
import public Quox.Syntax.Term.Subst import public Quox.Syntax.Term.Subst
import public Quox.Syntax.Term.Pretty import public Quox.Syntax.Term.Pretty
import public Quox.Syntax.Term.Tighten

View file

@ -47,8 +47,6 @@ TagVal : Type
TagVal = String TagVal = String
infixl 8 :#
infixl 9 :@, :%
mutual mutual
public export public export
TSubst : TSubstLike TSubst : TSubstLike
@ -61,6 +59,10 @@ mutual
||| type of types ||| type of types
TYPE : (l : Universe) -> (loc : Loc) -> Term d n TYPE : (l : Universe) -> (loc : Loc) -> Term d n
||| IO state token. this is a builtin because otherwise #[main] being a
||| builtin makes no sense
IOState : (loc : Loc) -> Term d n
||| function type ||| function type
Pi : (qty : Qty) -> (arg : Term d n) -> Pi : (qty : Qty) -> (arg : Term d n) ->
(res : ScopeTerm d n) -> (loc : Loc) -> Term d n (res : ScopeTerm d n) -> (loc : Loc) -> Term d n
@ -83,15 +85,21 @@ mutual
DLam : (body : DScopeTerm d n) -> (loc : Loc) -> Term d n DLam : (body : DScopeTerm d n) -> (loc : Loc) -> Term d n
||| natural numbers (temporary until 𝐖 gets added) ||| natural numbers (temporary until 𝐖 gets added)
Nat : (loc : Loc) -> Term d n NAT : (loc : Loc) -> Term d n
-- [todo] can these be elims? Nat : (val : Nat) -> (loc : Loc) -> Term d n
Zero : (loc : Loc) -> Term d n
Succ : (p : Term d n) -> (loc : Loc) -> Term d n Succ : (p : Term d n) -> (loc : Loc) -> Term d n
||| strings
STRING : (loc : Loc) -> Term d n
Str : (str : String) -> (loc : Loc) -> Term d n
||| "box" (package a value up with a certain quantity) ||| "box" (package a value up with a certain quantity)
BOX : (qty : Qty) -> (ty : Term d n) -> (loc : Loc) -> Term d n BOX : (qty : Qty) -> (ty : Term d n) -> (loc : Loc) -> Term d n
Box : (val : Term d n) -> (loc : Loc) -> Term d n Box : (val : Term d n) -> (loc : Loc) -> Term d n
Let : (qty : Qty) -> (rhs : Elim d n) ->
(body : ScopeTerm d n) -> (loc : Loc) -> Term d n
||| elimination ||| elimination
E : (e : Elim d n) -> Term d n E : (e : Elim d n) -> Term d n
@ -226,118 +234,6 @@ mutual
ShowElim : Show (Elim d n) ShowElim : Show (Elim d n)
ShowElim = assert_total {a = Show (Elim d n)} deriveShow ShowElim = assert_total {a = Show (Elim d n)} deriveShow
||| scope which ignores all its binders
public export %inline
SN : {s : Nat} -> f n -> Scoped s f n
SN = S (replicate s $ BN Unused noLoc) . N
||| scope which uses its binders
public export %inline
SY : BContext s -> f (s + n) -> Scoped s f n
SY ns = S ns . Y
public export %inline
name : Scoped 1 f n -> BindName
name (S [< x] _) = x
public export %inline
(.name) : Scoped 1 f n -> BindName
s.name = name s
||| more convenient Pi
public export %inline
PiY : (qty : Qty) -> (x : BindName) ->
(arg : Term d n) -> (res : Term d (S n)) -> (loc : Loc) -> Term d n
PiY {qty, x, arg, res, loc} = Pi {qty, arg, res = SY [< x] res, loc}
||| more convenient Lam
public export %inline
LamY : (x : BindName) -> (body : Term d (S n)) -> (loc : Loc) -> Term d n
LamY {x, body, loc} = Lam {body = SY [< x] body, loc}
public export %inline
LamN : (body : Term d n) -> (loc : Loc) -> Term d n
LamN {body, loc} = Lam {body = SN body, loc}
||| non dependent function type
public export %inline
Arr : (qty : Qty) -> (arg, res : Term d n) -> (loc : Loc) -> Term d n
Arr {qty, arg, res, loc} = Pi {qty, arg, res = SN res, loc}
||| more convenient Sig
public export %inline
SigY : (x : BindName) -> (fst : Term d n) ->
(snd : Term d (S n)) -> (loc : Loc) -> Term d n
SigY {x, fst, snd, loc} = Sig {fst, snd = SY [< x] snd, loc}
||| non dependent pair type
public export %inline
And : (fst, snd : Term d n) -> (loc : Loc) -> Term d n
And {fst, snd, loc} = Sig {fst, snd = SN snd, loc}
||| more convenient Eq
public export %inline
EqY : (i : BindName) -> (ty : Term (S d) n) ->
(l, r : Term d n) -> (loc : Loc) -> Term d n
EqY {i, ty, l, r, loc} = Eq {ty = SY [< i] ty, l, r, loc}
||| more convenient DLam
public export %inline
DLamY : (i : BindName) -> (body : Term (S d) n) -> (loc : Loc) -> Term d n
DLamY {i, body, loc} = DLam {body = SY [< i] body, loc}
public export %inline
DLamN : (body : Term d n) -> (loc : Loc) -> Term d n
DLamN {body, loc} = DLam {body = SN body, loc}
||| non dependent equality type
public export %inline
Eq0 : (ty, l, r : Term d n) -> (loc : Loc) -> Term d n
Eq0 {ty, l, r, loc} = Eq {ty = SN ty, l, r, loc}
||| same as `F` but as a term
public export %inline
FT : Name -> Universe -> Loc -> Term d n
FT x u loc = E $ F x u loc
||| same as `B` but as a term
public export %inline
BT : Var n -> (loc : Loc) -> Term d n
BT i loc = E $ B i loc
||| abbreviation for a bound variable like `BV 4` instead of
||| `B (VS (VS (VS (VS VZ))))`
public export %inline
BV : (i : Nat) -> (0 _ : LT i n) => (loc : Loc) -> Elim d n
BV i loc = B (V i) loc
||| same as `BV` but as a term
public export %inline
BVT : (i : Nat) -> (0 _ : LT i n) => (loc : Loc) -> Term d n
BVT i loc = E $ BV i loc
public export
makeNat : Nat -> Loc -> Term d n
makeNat 0 loc = Zero loc
makeNat (S k) loc = Succ (makeNat k loc) loc
public export %inline
enum : List TagVal -> Loc -> Term d n
enum ts loc = Enum (SortedSet.fromList ts) loc
public export %inline
typeCase : Elim d n -> Term d n ->
List (TypeCaseArm d n) -> Term d n -> Loc -> Elim d n
typeCase ty ret arms def loc = TypeCase ty ret (fromList arms) def loc
public export %inline
typeCase1Y : Elim d n -> Term d n ->
(k : TyConKind) -> BContext (arity k) -> Term d (arity k + n) ->
(loc : Loc) ->
{default (Nat loc) def : Term d n} ->
Elim d n
typeCase1Y ty ret k ns body loc = typeCase ty ret [(k ** SY ns body)] def loc
export export
Located (Elim d n) where Located (Elim d n) where
@ -361,6 +257,7 @@ Located (Elim d n) where
export export
Located (Term d n) where Located (Term d n) where
(TYPE _ loc).loc = loc (TYPE _ loc).loc = loc
(IOState loc).loc = loc
(Pi _ _ _ loc).loc = loc (Pi _ _ _ loc).loc = loc
(Lam _ loc).loc = loc (Lam _ loc).loc = loc
(Sig _ _ loc).loc = loc (Sig _ _ loc).loc = loc
@ -369,11 +266,14 @@ Located (Term d n) where
(Tag _ loc).loc = loc (Tag _ loc).loc = loc
(Eq _ _ _ loc).loc = loc (Eq _ _ _ loc).loc = loc
(DLam _ loc).loc = loc (DLam _ loc).loc = loc
(Nat loc).loc = loc (NAT loc).loc = loc
(Zero loc).loc = loc (Nat _ loc).loc = loc
(STRING loc).loc = loc
(Str _ loc).loc = loc
(Succ _ loc).loc = loc (Succ _ loc).loc = loc
(BOX _ _ loc).loc = loc (BOX _ _ loc).loc = loc
(Box _ loc).loc = loc (Box _ loc).loc = loc
(Let _ _ _ loc).loc = loc
(E e).loc = e.loc (E e).loc = e.loc
(CloT (Sub t _)).loc = t.loc (CloT (Sub t _)).loc = t.loc
(DCloT (Sub t _)).loc = t.loc (DCloT (Sub t _)).loc = t.loc
@ -421,6 +321,7 @@ Relocatable (Elim d n) where
export export
Relocatable (Term d n) where Relocatable (Term d n) where
setLoc loc (TYPE l _) = TYPE l loc setLoc loc (TYPE l _) = TYPE l loc
setLoc loc (IOState _) = IOState loc
setLoc loc (Pi qty arg res _) = Pi qty arg res loc setLoc loc (Pi qty arg res _) = Pi qty arg res loc
setLoc loc (Lam body _) = Lam body loc setLoc loc (Lam body _) = Lam body loc
setLoc loc (Sig fst snd _) = Sig fst snd loc setLoc loc (Sig fst snd _) = Sig fst snd loc
@ -429,11 +330,14 @@ Relocatable (Term d n) where
setLoc loc (Tag tag _) = Tag tag loc setLoc loc (Tag tag _) = Tag tag loc
setLoc loc (Eq ty l r _) = Eq ty l r loc setLoc loc (Eq ty l r _) = Eq ty l r loc
setLoc loc (DLam body _) = DLam body loc setLoc loc (DLam body _) = DLam body loc
setLoc loc (Nat _) = Nat loc setLoc loc (NAT _) = NAT loc
setLoc loc (Zero _) = Zero loc setLoc loc (Nat n _) = Nat n loc
setLoc loc (Succ p _) = Succ p loc setLoc loc (Succ p _) = Succ p loc
setLoc loc (STRING _) = STRING loc
setLoc loc (Str s _) = Str s loc
setLoc loc (BOX qty ty _) = BOX qty ty loc setLoc loc (BOX qty ty _) = BOX qty ty loc
setLoc loc (Box val _) = Box val loc setLoc loc (Box val _) = Box val loc
setLoc loc (Let qty rhs body _) = Let qty rhs body loc
setLoc loc (E e) = E $ setLoc loc e setLoc loc (E e) = E $ setLoc loc e
setLoc loc (CloT (Sub term subst)) = CloT $ Sub (setLoc loc term) subst setLoc loc (CloT (Sub term subst)) = CloT $ Sub (setLoc loc term) subst
setLoc loc (DCloT (Sub term subst)) = DCloT $ Sub (setLoc loc term) subst setLoc loc (DCloT (Sub term subst)) = DCloT $ Sub (setLoc loc term) subst
@ -446,3 +350,103 @@ Relocatable1 f => Relocatable (ScopedBody s f n) where
export export
Relocatable1 f => Relocatable (Scoped s f n) where Relocatable1 f => Relocatable (Scoped s f n) where
setLoc loc (S names body) = S (setLoc loc <$> names) (setLoc loc body) setLoc loc (S names body) = S (setLoc loc <$> names) (setLoc loc body)
||| more convenient Pi
public export %inline
PiY : (qty : Qty) -> (x : BindName) ->
(arg : Term d n) -> (res : Term d (S n)) -> (loc : Loc) -> Term d n
PiY {qty, x, arg, res, loc} = Pi {qty, arg, res = SY [< x] res, loc}
||| more convenient Lam
public export %inline
LamY : (x : BindName) -> (body : Term d (S n)) -> (loc : Loc) -> Term d n
LamY {x, body, loc} = Lam {body = SY [< x] body, loc}
public export %inline
LamN : (body : Term d n) -> (loc : Loc) -> Term d n
LamN {body, loc} = Lam {body = SN body, loc}
||| non dependent function type
public export %inline
Arr : (qty : Qty) -> (arg, res : Term d n) -> (loc : Loc) -> Term d n
Arr {qty, arg, res, loc} = Pi {qty, arg, res = SN res, loc}
||| more convenient Sig
public export %inline
SigY : (x : BindName) -> (fst : Term d n) ->
(snd : Term d (S n)) -> (loc : Loc) -> Term d n
SigY {x, fst, snd, loc} = Sig {fst, snd = SY [< x] snd, loc}
||| non dependent pair type
public export %inline
And : (fst, snd : Term d n) -> (loc : Loc) -> Term d n
And {fst, snd, loc} = Sig {fst, snd = SN snd, loc}
||| more convenient Eq
public export %inline
EqY : (i : BindName) -> (ty : Term (S d) n) ->
(l, r : Term d n) -> (loc : Loc) -> Term d n
EqY {i, ty, l, r, loc} = Eq {ty = SY [< i] ty, l, r, loc}
||| more convenient DLam
public export %inline
DLamY : (i : BindName) -> (body : Term (S d) n) -> (loc : Loc) -> Term d n
DLamY {i, body, loc} = DLam {body = SY [< i] body, loc}
public export %inline
DLamN : (body : Term d n) -> (loc : Loc) -> Term d n
DLamN {body, loc} = DLam {body = SN body, loc}
||| more convenient Coe
public export %inline
CoeY : (i : BindName) -> (ty : Term (S d) n) ->
(p, q : Dim d) -> (val : Term d n) -> (loc : Loc) -> Elim d n
CoeY {i, ty, p, q, val, loc} = Coe {ty = SY [< i] ty, p, q, val, loc}
||| non dependent equality type
public export %inline
Eq0 : (ty, l, r : Term d n) -> (loc : Loc) -> Term d n
Eq0 {ty, l, r, loc} = Eq {ty = SN ty, l, r, loc}
||| same as `F` but as a term
public export %inline
FT : Name -> Universe -> Loc -> Term d n
FT x u loc = E $ F x u loc
||| same as `B` but as a term
public export %inline
BT : Var n -> (loc : Loc) -> Term d n
BT i loc = E $ B i loc
||| abbreviation for a bound variable like `BV 4` instead of
||| `B (VS (VS (VS (VS VZ))))`
public export %inline
BV : (i : Nat) -> (0 _ : LT i n) => (loc : Loc) -> Elim d n
BV i loc = B (V i) loc
||| same as `BV` but as a term
public export %inline
BVT : (i : Nat) -> (0 _ : LT i n) => (loc : Loc) -> Term d n
BVT i loc = E $ BV i loc
public export %inline
Zero : Loc -> Term d n
Zero = Nat 0
public export %inline
enum : List TagVal -> Loc -> Term d n
enum ts loc = Enum (SortedSet.fromList ts) loc
public export %inline
typeCase : Elim d n -> Term d n ->
List (TypeCaseArm d n) -> Term d n -> Loc -> Elim d n
typeCase ty ret arms def loc = TypeCase ty ret (fromList arms) def loc
public export %inline
typeCase1Y : Elim d n -> Term d n ->
(k : TyConKind) -> BContext (arity k) -> Term d (arity k + n) ->
(loc : Loc) ->
{default (NAT loc) def : Term d n} ->
Elim d n
typeCase1Y ty ret k ns body loc = typeCase ty ret [(k ** SY ns body)] def loc

View file

@ -30,14 +30,6 @@ BTelescope : Nat -> Nat -> Type
BTelescope = Telescope' BindName BTelescope = Telescope' BindName
private
subscript : String -> String
subscript = pack . map sub . unpack where
sub : Char -> Char
sub c = case c of
'0' => ''; '1' => ''; '2' => ''; '3' => ''; '4' => ''
'5' => ''; '6' => ''; '7' => ''; '8' => ''; '9' => ''; _ => c
private private
superscript : String -> String superscript : String -> String
superscript = pack . map sup . unpack where superscript = pack . map sup . unpack where
@ -209,8 +201,7 @@ prettyTArg dnames tnames s =
private private
prettyDArg : {opts : _} -> BContext d -> Dim d -> Eff Pretty (Doc opts) prettyDArg : {opts : _} -> BContext d -> Dim d -> Eff Pretty (Doc opts)
prettyDArg dnames p = prettyDArg dnames p = [|atD <+> withPrec Arg (prettyDim dnames p)|]
map (text "@" <+>) $ withPrec Arg $ prettyDim dnames p
private private
splitApps : Elim d n -> (Elim d n, List (Either (Dim d) (Term d n))) splitApps : Elim d n -> (Elim d n, List (Either (Dim d) (Term d n)))
@ -238,7 +229,6 @@ prettyDTApps dnames tnames f xs = do
private private
record CaseArm opts d n where record CaseArm opts d n where
constructor MkCaseArm constructor MkCaseArm
{0 dinner, ninner : Nat}
pat : Doc opts pat : Doc opts
dbinds : BTelescope d dinner -- 🍴 dbinds : BTelescope d dinner -- 🍴
tbinds : BTelescope n ninner tbinds : BTelescope n ninner
@ -251,12 +241,11 @@ parameters {opts : LayoutOpts} (dnames : BContext d) (tnames : BContext n)
body <- withPrec Outer $ assert_total body <- withPrec Outer $ assert_total
prettyTerm (dnames . dbinds) (tnames . tbinds) body prettyTerm (dnames . dbinds) (tnames . tbinds) body
header <- (pat <++>) <$> darrowD header <- (pat <++>) <$> darrowD
pure $ hsep [header, body] <|> vsep [header, !(indentD body)] pure $ ifMultiline (header <++> body) (vsep [header, !(indentD body)])
private private
prettyCaseBody : List (CaseArm opts d n) -> Eff Pretty (Doc opts) prettyCaseBody : List (CaseArm opts d n) -> Eff Pretty (List (Doc opts))
prettyCaseBody xs = prettyCaseBody xs = traverse prettyCaseArm xs
braces . separateTight !semiD =<< traverse prettyCaseArm xs
private private
prettyCompPat : {opts : _} -> DimConst -> BindName -> Eff Pretty (Doc opts) prettyCompPat : {opts : _} -> DimConst -> BindName -> Eff Pretty (Doc opts)
@ -288,7 +277,7 @@ prettyEnum : {opts : _} -> List String -> Eff Pretty (Doc opts)
prettyEnum cases = prettyEnum cases =
tightBraces =<< tightBraces =<<
fillSeparateTight !commaD <$> fillSeparateTight !commaD <$>
traverse (hl Tag . Doc.text . quoteTag) cases traverse (hl Constant . Doc.text . quoteTag) cases
private private
prettyCaseRet : {opts : _} -> prettyCaseRet : {opts : _} ->
@ -299,7 +288,7 @@ prettyCaseRet dnames tnames body = withPrec Outer $ case body of
S [< x] (Y tm) => do S [< x] (Y tm) => do
header <- [|prettyTBind x <++> darrowD|] header <- [|prettyTBind x <++> darrowD|]
body <- assert_total prettyTerm dnames (tnames :< x) tm body <- assert_total prettyTerm dnames (tnames :< x) tm
pure $ hsep [header, body] <|> vsep [header, !(indentD body)] hangDSingle header body
private private
prettyCase_ : {opts : _} -> prettyCase_ : {opts : _} ->
@ -307,10 +296,16 @@ prettyCase_ : {opts : _} ->
Doc opts -> Elim d n -> ScopeTerm d n -> List (CaseArm opts d n) -> Doc opts -> Elim d n -> ScopeTerm d n -> List (CaseArm opts d n) ->
Eff Pretty (Doc opts) Eff Pretty (Doc opts)
prettyCase_ dnames tnames intro head ret body = do prettyCase_ dnames tnames intro head ret body = do
head <- assert_total prettyElim dnames tnames head head <- withPrec Outer $ assert_total prettyElim dnames tnames head
ret <- prettyCaseRet dnames tnames ret ret <- prettyCaseRet dnames tnames ret
body <- prettyCaseBody dnames tnames body bodys <- prettyCaseBody dnames tnames body
parensIfM Outer $ sep [intro <++> head, !returnD <++> ret, !ofD <++> body] return <- returnD; of_ <- ofD
lb <- hl Delim "{"; rb <- hl Delim "}"; semi <- semiD
ind <- askAt INDENT
parensIfM Outer $ ifMultiline
(hsep [intro, head, return, ret, of_, lb, hseparateTight semi bodys, rb])
(vsep [intro <++> head, return <++> ret, of_ <++> lb,
indent ind $ vseparateTight semi bodys, rb])
private private
prettyCase : {opts : _} -> prettyCase : {opts : _} ->
@ -321,6 +316,62 @@ prettyCase dnames tnames qty head ret body =
prettyCase_ dnames tnames ![|caseD <+> prettyQty qty|] head ret body prettyCase_ dnames tnames ![|caseD <+> prettyQty qty|] head ret body
private
LetBinder : Nat -> Nat -> Type
LetBinder d n = (Qty, BindName, Elim d n)
private
LetExpr : Nat -> Nat -> Nat -> Type
LetExpr d n n' = (Telescope (LetBinder d) n n', Term d n')
-- [todo] factor out this and the untyped version somehow
export
splitLet : Telescope (LetBinder d) n n' -> Term d n' -> Exists (LetExpr d n)
splitLet ys t@(Let qty rhs body _) =
splitLet (ys :< (qty, body.name, rhs)) (assert_smaller t body.term)
splitLet ys t =
Evidence _ (ys, t)
private covering
prettyLets : {opts : LayoutOpts} ->
BContext d -> BContext a -> Telescope (LetBinder d) a b ->
Eff Pretty (SnocList (Doc opts))
prettyLets dnames xs lets = snd <$> go lets where
peelAnn : forall d, n. Elim d n -> Maybe (Term d n, Term d n)
peelAnn (Ann tm ty _) = Just (tm, ty)
peelAnn e = Nothing
letHeader : Qty -> BindName -> Eff Pretty (Doc opts)
letHeader qty x = do
lett <- [|letD <+> prettyQty qty|]
x <- prettyTBind x
pure $ lett <++> x
letBody : forall n. BContext n ->
Doc opts -> Elim d n -> Eff Pretty (Doc opts)
letBody tnames hdr e = case peelAnn e of
Just (tm, ty) => do
ty <- withPrec Outer $ assert_total prettyTerm dnames tnames ty
tm <- withPrec Outer $ assert_total prettyTerm dnames tnames tm
colon <- colonD; eq <- cstD; d <- askAt INDENT
pure $ hangSingle d (hangSingle d hdr (colon <++> ty)) (eq <++> tm)
Nothing => do
e <- withPrec Outer $ assert_total prettyElim dnames tnames e
eq <- cstD; d <- askAt INDENT
inn <- inD
pure $ ifMultiline
(hsep [hdr, eq, e, inn])
(vsep [hdr, indent d $ hsep [eq, e, inn]])
go : forall b. Telescope (LetBinder d) a b ->
Eff Pretty (BContext b, SnocList (Doc opts))
go [<] = pure (xs, [<])
go (lets :< (qty, x, rhs)) = do
(ys, docs) <- go lets
doc <- letBody ys !(letHeader qty x) rhs
pure (ys :< x, docs :< doc)
private private
isDefaultDir : Dim d -> Dim d -> Bool isDefaultDir : Dim d -> Dim d -> Bool
isDefaultDir (K Zero _) (K One _) = True isDefaultDir (K Zero _) (K One _) = True
@ -338,6 +389,7 @@ prettyTyCasePat : {opts : _} ->
(k : TyConKind) -> BContext (arity k) -> (k : TyConKind) -> BContext (arity k) ->
Eff Pretty (Doc opts) Eff Pretty (Doc opts)
prettyTyCasePat KTYPE [<] = typeD prettyTyCasePat KTYPE [<] = typeD
prettyTyCasePat KIOState [<] = ioStateD
prettyTyCasePat KPi [< a, b] = prettyTyCasePat KPi [< a, b] =
parens . hsep =<< sequence [prettyTBind a, arrowD, prettyTBind b] parens . hsep =<< sequence [prettyTBind a, arrowD, prettyTBind b]
prettyTyCasePat KSig [< a, b] = prettyTyCasePat KSig [< a, b] =
@ -346,6 +398,7 @@ prettyTyCasePat KEnum [<] = hl Syntax $ text "{}"
prettyTyCasePat KEq [< a0, a1, a, l, r] = prettyTyCasePat KEq [< a0, a1, a, l, r] =
hsep <$> sequence (eqD :: map prettyTBind [a0, a1, a, l, r]) hsep <$> sequence (eqD :: map prettyTBind [a0, a1, a, l, r])
prettyTyCasePat KNat [<] = natD prettyTyCasePat KNat [<] = natD
prettyTyCasePat KString [<] = stringD
prettyTyCasePat KBOX [< a] = bracks =<< prettyTBind a prettyTyCasePat KBOX [< a] = bracks =<< prettyTBind a
@ -379,13 +432,13 @@ prettyDisp u = map Just $ hl Universe =<<
ifUnicode (text $ superscript $ show u) (text $ "^" ++ show u) ifUnicode (text $ superscript $ show u) (text $ "^" ++ show u)
prettyTerm dnames tnames (TYPE l _) = prettyTerm dnames tnames (TYPE l _) = do
case !(askAt FLAVOR) of type <- hl Syntax . text =<< ifUnicode "" "Type"
Unicode => do level <- prettyDisp l
star <- hl Syntax "" pure $ maybe type (type <+>) level
level <- hl Universe $ text $ superscript $ show l
pure $ hcat [star, level] prettyTerm dnames tnames (IOState _) =
Ascii => [|hl Syntax "Type" <++> hl Universe (text $ show l)|] ioStateD
prettyTerm dnames tnames (Pi qty arg res _) = prettyTerm dnames tnames (Pi qty arg res _) =
parensIfM Outer =<< do parensIfM Outer =<< do
@ -430,7 +483,7 @@ prettyTerm dnames tnames (Eq (S _ (N ty)) l r _) =
pure $ sep [l <++> !eqndD, r <++> !colonD, ty] pure $ sep [l <++> !eqndD, r <++> !colonD, ty]
prettyTerm dnames tnames (Eq ty l r _) = prettyTerm dnames tnames (Eq ty l r _) =
parensIfM Arg =<< do parensIfM App =<< do
ty <- prettyTypeLine dnames tnames ty ty <- prettyTypeLine dnames tnames ty
l <- withPrec Arg $ prettyTerm dnames tnames l l <- withPrec Arg $ prettyTerm dnames tnames l
r <- withPrec Arg $ prettyTerm dnames tnames r r <- withPrec Arg $ prettyTerm dnames tnames r
@ -439,20 +492,14 @@ prettyTerm dnames tnames (Eq ty l r _) =
prettyTerm dnames tnames s@(DLam {}) = prettyTerm dnames tnames s@(DLam {}) =
prettyLambda dnames tnames s prettyLambda dnames tnames s
prettyTerm dnames tnames (Nat _) = natD prettyTerm dnames tnames (NAT _) = natD
prettyTerm dnames tnames (Zero _) = hl Syntax "0" prettyTerm dnames tnames (Nat n _) = hl Syntax $ pshow n
prettyTerm dnames tnames (Succ p _) = do prettyTerm dnames tnames (Succ p _) =
succD <- succD parensIfM App =<<
let succ : Doc opts -> Eff Pretty (Doc opts) prettyAppD !succD [!(withPrec Arg $ prettyTerm dnames tnames p)]
succ t = prettyAppD succD [t]
toNat : Term d n -> Eff Pretty (Either (Doc opts) Nat) prettyTerm dnames tnames (STRING _) = stringD
toNat s with (pushSubsts' s) prettyTerm dnames tnames (Str s _) = prettyStrLit s
_ | Zero _ = pure $ Right 0
_ | Succ d _ = bitraverse succ (pure . S) =<<
toNat (assert_smaller s d)
_ | s' = map Left . withPrec Arg $
prettyTerm dnames tnames $ assert_smaller s s'
either succ (hl Syntax . text . show . S) =<< toNat p
prettyTerm dnames tnames (BOX qty ty _) = prettyTerm dnames tnames (BOX qty ty _) =
bracks . hcat =<< bracks . hcat =<<
@ -462,7 +509,18 @@ prettyTerm dnames tnames (BOX qty ty _) =
prettyTerm dnames tnames (Box val _) = prettyTerm dnames tnames (Box val _) =
bracks =<< withPrec Outer (prettyTerm dnames tnames val) bracks =<< withPrec Outer (prettyTerm dnames tnames val)
prettyTerm dnames tnames (E e) = prettyElim dnames tnames e prettyTerm dnames tnames (Let qty rhs body _) = do
let Evidence _ (lets, body) = splitLet [< (qty, body.name, rhs)] body.term
heads <- prettyLets dnames tnames lets
let tnames = tnames . map (\(_, x, _) => x) lets
body <- withPrec Outer $ assert_total prettyTerm dnames tnames body
let lines = toList $ heads :< body
pure $ ifMultiline (hsep lines) (vsep lines)
prettyTerm dnames tnames (E e) =
case the (Elim d n) (pushSubsts' e) of
Ann tm _ _ => assert_total prettyTerm dnames tnames tm
_ => assert_total prettyElim dnames tnames e
prettyTerm dnames tnames t0@(CloT (Sub t ph)) = prettyTerm dnames tnames t0@(CloT (Sub t ph)) =
prettyTerm dnames tnames $ assert_smaller t0 $ pushSubstsWith' id ph t prettyTerm dnames tnames $ assert_smaller t0 $ pushSubstsWith' id ph t
@ -525,9 +583,12 @@ prettyElim dnames tnames e@(DApp {}) =
prettyDTApps dnames tnames f xs prettyDTApps dnames tnames f xs
prettyElim dnames tnames (Ann tm ty _) = prettyElim dnames tnames (Ann tm ty _) =
parensIfM Outer =<< case the (Term d n) (pushSubsts' tm) of
hangDSingle !(withPrec AnnL [|prettyTerm dnames tnames tm <++> annD|]) E e => assert_total prettyElim dnames tnames e
!(withPrec Outer (prettyTerm dnames tnames ty)) _ => do
tm <- withPrec AnnL $ assert_total prettyTerm dnames tnames tm
ty <- withPrec Outer $ assert_total prettyTerm dnames tnames ty
parensIfM Outer =<< hangDSingle (tm <++> !annD) ty
prettyElim dnames tnames (Coe ty p q val _) = prettyElim dnames tnames (Coe ty p q val _) =
parensIfM App =<< do parensIfM App =<< do
@ -539,7 +600,7 @@ prettyElim dnames tnames (Coe ty p q val _) =
prettyElim dnames tnames e@(Comp ty p q val r zero one _) = prettyElim dnames tnames e@(Comp ty p q val r zero one _) =
parensIfM App =<< do parensIfM App =<< do
ty <- prettyTypeLine dnames tnames $ assert_smaller e $ SN ty ty <- assert_total $ prettyTypeLine dnames tnames $ SN ty
pq <- sep <$> sequence [prettyDArg dnames p, prettyDArg dnames q] pq <- sep <$> sequence [prettyDArg dnames p, prettyDArg dnames q]
val <- prettyTArg dnames tnames val val <- prettyTArg dnames tnames val
r <- prettyDArg dnames r r <- prettyDArg dnames r

View file

@ -56,12 +56,12 @@ namespace DSubst.DScopeTermN
(//) : {s : Nat} -> (//) : {s : Nat} ->
DScopeTermN s d1 n -> Lazy (DSubst d1 d2) -> DScopeTermN s d1 n -> Lazy (DSubst d1 d2) ->
DScopeTermN s d2 n DScopeTermN s d2 n
S ns (Y body) // th = S ns $ Y $ body // pushN s th S ns (Y body) // th = S ns $ Y $ body // pushN s (locs $ toList' ns) th
S ns (N body) // th = S ns $ N $ body // th S ns (N body) // th = S ns $ N $ body // th
export %inline FromVar (Elim d) where fromVarLoc = B export %inline FromVar (Elim d) where fromVarLoc = B
export %inline FromVar (Term d) where fromVarLoc = E .: fromVar export %inline FromVar (Term d) where fromVarLoc = E .: fromVarLoc
||| does the minimal reasonable work: ||| does the minimal reasonable work:
@ -104,7 +104,7 @@ namespace ScopeTermN
(//) : {s : Nat} -> (//) : {s : Nat} ->
ScopeTermN s d n1 -> Lazy (TSubst d n1 n2) -> ScopeTermN s d n1 -> Lazy (TSubst d n1 n2) ->
ScopeTermN s d n2 ScopeTermN s d n2
S ns (Y body) // th = S ns $ Y $ body // pushN s th S ns (Y body) // th = S ns $ Y $ body // pushN s (locs $ toList' ns) th
S ns (N body) // th = S ns $ N $ body // th S ns (N body) // th = S ns $ N $ body // th
namespace DScopeTermN namespace DScopeTermN
@ -134,6 +134,15 @@ public export %inline
dweakT : (by : Nat) -> Term d n -> Term (by + d) n dweakT : (by : Nat) -> Term d n -> Term (by + d) n
dweakT by t = t // shift by dweakT by t = t // shift by
public export %inline
dweakS : (by : Nat) -> ScopeTermN s d n -> ScopeTermN s (by + d) n
dweakS by t = t // shift by
public export %inline
dweakDS : {s : Nat} -> (by : Nat) ->
DScopeTermN s d n -> DScopeTermN s (by + d) n
dweakDS by t = t // shift by
public export %inline public export %inline
dweakE : (by : Nat) -> Elim d n -> Elim (by + d) n dweakE : (by : Nat) -> Elim d n -> Elim (by + d) n
dweakE by t = t // shift by dweakE by t = t // shift by
@ -143,6 +152,15 @@ public export %inline
weakT : (by : Nat) -> Term d n -> Term d (by + n) weakT : (by : Nat) -> Term d n -> Term d (by + n)
weakT by t = t // shift by weakT by t = t // shift by
public export %inline
weakS : {s : Nat} -> (by : Nat) -> ScopeTermN s d n -> ScopeTermN s d (by + n)
weakS by t = t // shift by
public export %inline
weakDS : {s : Nat} -> (by : Nat) ->
DScopeTermN s d n -> DScopeTermN s d (by + n)
weakDS by t = t // shift by
public export %inline public export %inline
weakE : (by : Nat) -> Elim d n -> Elim d (by + n) weakE : (by : Nat) -> Elim d n -> Elim d (by + n)
weakE by t = t // shift by weakE by t = t // shift by
@ -189,11 +207,11 @@ dsub1 t p = dsubN t [< p]
public export %inline public export %inline
(.zero) : DScopeTerm d n -> {default noLoc loc : Loc} -> Term d n (.zero) : (body : DScopeTerm d n) -> {default body.loc loc : Loc} -> Term d n
body.zero = dsub1 body $ K Zero loc body.zero = dsub1 body $ K Zero loc
public export %inline public export %inline
(.one) : DScopeTerm d n -> {default noLoc loc : Loc} -> Term d n (.one) : (body : DScopeTerm d n) -> {default body.loc loc : Loc} -> Term d n
body.one = dsub1 body $ K One loc body.one = dsub1 body $ K One loc
@ -249,83 +267,118 @@ mutual
isCloE (DCloE {}) = True isCloE (DCloE {}) = True
isCloE _ = False isCloE _ = False
mutual export
export PushSubsts Elim Subst.isCloE where
PushSubsts Term Subst.isCloT where pushSubstsWith th ph (F x u loc) =
pushSubstsWith th ph (TYPE l loc) = nclo $ F x u loc
nclo $ TYPE l loc pushSubstsWith th ph (B i loc) =
pushSubstsWith th ph (Pi qty a body loc) = let res = getLoc ph i loc in
nclo $ Pi qty (a // th // ph) (body // th // ph) loc case nchoose $ isCloE res of
pushSubstsWith th ph (Lam body loc) = Left yes => assert_total pushSubsts res
nclo $ Lam (body // th // ph) loc Right no => Element res no
pushSubstsWith th ph (Sig a b loc) = pushSubstsWith th ph (App f s loc) =
nclo $ Sig (a // th // ph) (b // th // ph) loc nclo $ App (f // th // ph) (s // th // ph) loc
pushSubstsWith th ph (Pair s t loc) = pushSubstsWith th ph (CasePair pi p r b loc) =
nclo $ Pair (s // th // ph) (t // th // ph) loc nclo $ CasePair pi (p // th // ph) (r // th // ph) (b // th // ph) loc
pushSubstsWith th ph (Enum tags loc) = pushSubstsWith th ph (Fst pair loc) =
nclo $ Enum tags loc nclo $ Fst (pair // th // ph) loc
pushSubstsWith th ph (Tag tag loc) = pushSubstsWith th ph (Snd pair loc) =
nclo $ Tag tag loc nclo $ Snd (pair // th // ph) loc
pushSubstsWith th ph (Eq ty l r loc) = pushSubstsWith th ph (CaseEnum pi t r arms loc) =
nclo $ Eq (ty // th // ph) (l // th // ph) (r // th // ph) loc nclo $ CaseEnum pi (t // th // ph) (r // th // ph)
pushSubstsWith th ph (DLam body loc) = (map (\b => b // th // ph) arms) loc
nclo $ DLam (body // th // ph) loc pushSubstsWith th ph (CaseNat pi pi' n r z s loc) =
pushSubstsWith _ _ (Nat loc) = nclo $ CaseNat pi pi' (n // th // ph) (r // th // ph)
nclo $ Nat loc (z // th // ph) (s // th // ph) loc
pushSubstsWith _ _ (Zero loc) = pushSubstsWith th ph (CaseBox pi x r b loc) =
nclo $ Zero loc nclo $ CaseBox pi (x // th // ph) (r // th // ph) (b // th // ph) loc
pushSubstsWith th ph (Succ n loc) = pushSubstsWith th ph (DApp f d loc) =
nclo $ Succ (n // th // ph) loc nclo $ DApp (f // th // ph) (d // th) loc
pushSubstsWith th ph (BOX pi ty loc) = pushSubstsWith th ph (Ann s a loc) =
nclo $ BOX pi (ty // th // ph) loc nclo $ Ann (s // th // ph) (a // th // ph) loc
pushSubstsWith th ph (Box val loc) = pushSubstsWith th ph (Coe ty p q val loc) =
nclo $ Box (val // th // ph) loc nclo $ Coe (ty // th // ph) (p // th) (q // th) (val // th // ph) loc
pushSubstsWith th ph (E e) = pushSubstsWith th ph (Comp ty p q val r zero one loc) =
let Element e nc = pushSubstsWith th ph e in nclo $ E e nclo $ Comp (ty // th // ph) (p // th) (q // th)
pushSubstsWith th ph (CloT (Sub s ps)) = (val // th // ph) (r // th)
pushSubstsWith th (comp th ps ph) s (zero // th // ph) (one // th // ph) loc
pushSubstsWith th ph (DCloT (Sub s ps)) = pushSubstsWith th ph (TypeCase ty ret arms def loc) =
pushSubstsWith (ps . th) ph s nclo $ TypeCase (ty // th // ph) (ret // th // ph)
(map (\t => t // th // ph) arms) (def // th // ph) loc
pushSubstsWith th ph (CloE (Sub e ps)) =
pushSubstsWith th (comp th ps ph) e
pushSubstsWith th ph (DCloE (Sub e ps)) =
pushSubstsWith (ps . th) ph e
export export
PushSubsts Elim Subst.isCloE where PushSubsts Term Subst.isCloT where
pushSubstsWith th ph (F x u loc) = pushSubstsWith th ph (TYPE l loc) =
nclo $ F x u loc nclo $ TYPE l loc
pushSubstsWith th ph (B i loc) = pushSubstsWith th ph (IOState loc) =
let res = getLoc ph i loc in nclo $ IOState loc
case nchoose $ isCloE res of pushSubstsWith th ph (Pi qty a body loc) =
Left yes => assert_total pushSubsts res nclo $ Pi qty (a // th // ph) (body // th // ph) loc
Right no => Element res no pushSubstsWith th ph (Lam body loc) =
pushSubstsWith th ph (App f s loc) = nclo $ Lam (body // th // ph) loc
nclo $ App (f // th // ph) (s // th // ph) loc pushSubstsWith th ph (Sig a b loc) =
pushSubstsWith th ph (CasePair pi p r b loc) = nclo $ Sig (a // th // ph) (b // th // ph) loc
nclo $ CasePair pi (p // th // ph) (r // th // ph) (b // th // ph) loc pushSubstsWith th ph (Pair s t loc) =
pushSubstsWith th ph (Fst pair loc) = nclo $ Pair (s // th // ph) (t // th // ph) loc
nclo $ Fst (pair // th // ph) loc pushSubstsWith th ph (Enum tags loc) =
pushSubstsWith th ph (Snd pair loc) = nclo $ Enum tags loc
nclo $ Snd (pair // th // ph) loc pushSubstsWith th ph (Tag tag loc) =
pushSubstsWith th ph (CaseEnum pi t r arms loc) = nclo $ Tag tag loc
nclo $ CaseEnum pi (t // th // ph) (r // th // ph) pushSubstsWith th ph (Eq ty l r loc) =
(map (\b => b // th // ph) arms) loc nclo $ Eq (ty // th // ph) (l // th // ph) (r // th // ph) loc
pushSubstsWith th ph (CaseNat pi pi' n r z s loc) = pushSubstsWith th ph (DLam body loc) =
nclo $ CaseNat pi pi' (n // th // ph) (r // th // ph) nclo $ DLam (body // th // ph) loc
(z // th // ph) (s // th // ph) loc pushSubstsWith _ _ (NAT loc) =
pushSubstsWith th ph (CaseBox pi x r b loc) = nclo $ NAT loc
nclo $ CaseBox pi (x // th // ph) (r // th // ph) (b // th // ph) loc pushSubstsWith _ _ (Nat n loc) =
pushSubstsWith th ph (DApp f d loc) = nclo $ Nat n loc
nclo $ DApp (f // th // ph) (d // th) loc pushSubstsWith th ph (Succ n loc) =
pushSubstsWith th ph (Ann s a loc) = nclo $ Succ (n // th // ph) loc
nclo $ Ann (s // th // ph) (a // th // ph) loc pushSubstsWith _ _ (STRING loc) =
pushSubstsWith th ph (Coe ty p q val loc) = nclo $ STRING loc
nclo $ Coe (ty // th // ph) (p // th) (q // th) (val // th // ph) loc pushSubstsWith _ _ (Str s loc) =
pushSubstsWith th ph (Comp ty p q val r zero one loc) = nclo $ Str s loc
nclo $ Comp (ty // th // ph) (p // th) (q // th) pushSubstsWith th ph (BOX pi ty loc) =
(val // th // ph) (r // th) nclo $ BOX pi (ty // th // ph) loc
(zero // th // ph) (one // th // ph) loc pushSubstsWith th ph (Box val loc) =
pushSubstsWith th ph (TypeCase ty ret arms def loc) = nclo $ Box (val // th // ph) loc
nclo $ TypeCase (ty // th // ph) (ret // th // ph) pushSubstsWith th ph (E e) =
(map (\t => t // th // ph) arms) (def // th // ph) loc let Element e nc = pushSubstsWith th ph e in nclo $ E e
pushSubstsWith th ph (CloE (Sub e ps)) = pushSubstsWith th ph (Let qty rhs body loc) =
pushSubstsWith th (comp th ps ph) e nclo $ Let qty (rhs // th // ph) (body // th // ph) loc
pushSubstsWith th ph (DCloE (Sub e ps)) = pushSubstsWith th ph (CloT (Sub s ps)) =
pushSubstsWith (ps . th) ph e pushSubstsWith th (comp th ps ph) s
pushSubstsWith th ph (DCloT (Sub s ps)) =
pushSubstsWith (ps . th) ph s
||| heterogeneous comp, in terms of Comp and Coe
public export %inline
CompH' : (ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) ->
(r : Dim d) -> (zero, one : DScopeTerm d n) -> (loc : Loc) -> Elim d n
CompH' {ty, p, q, val, r, zero, one, loc} =
let ty' = SY ty.names $ ty.term // (B VZ ty.name.loc ::: shift 2) in
Comp {
ty = dsub1 ty q, p, q,
val = E $ Coe ty p q val val.loc, r,
zero = SY zero.names $ E $
Coe ty' (B VZ zero.loc) (weakD 1 q) zero.term zero.loc,
one = SY one.names $ E $
Coe ty' (B VZ one.loc) (weakD 1 q) one.term one.loc,
loc
}
||| heterogeneous comp, in terms of Comp and Coe
public export %inline
CompH : (i : BindName) -> (ty : Term (S d) n) ->
(p, q : Dim d) -> (val : Term d n) -> (r : Dim d) ->
(j0 : BindName) -> (zero : Term (S d) n) ->
(j1 : BindName) -> (one : Term (S d) n) ->
(loc : Loc) -> Elim d n
CompH {i, ty, p, q, val, r, j0, zero, j1, one, loc} =
CompH' {ty = SY [< i] ty, p, q, val, r,
zero = SY [< j0] zero, one = SY [< j1] one, loc}

View file

@ -1,361 +0,0 @@
module Quox.Syntax.Term.Tighten
import Quox.Syntax.Term.Base
import Quox.Syntax.Term.Subst
import public Quox.OPE
import Quox.No
%default total
export
Tighten Dim where
tighten p (K e loc) = pure $ K e loc
tighten p (B i loc) = B <$> tighten p i <*> pure loc
export
tightenScope : (forall m, n. OPE m n -> f n -> Maybe (f m)) ->
{s : Nat} -> OPE m n -> Scoped s f n -> Maybe (Scoped s f m)
tightenScope f p (S names (Y body)) = SY names <$> f (keepN s p) body
tightenScope f p (S names (N body)) = S names . N <$> f p body
export
tightenDScope : {0 f : Nat -> Nat -> Type} ->
(forall m, n, k. OPE m n -> f n k -> Maybe (f m k)) ->
OPE m n -> Scoped s (f n) k -> Maybe (Scoped s (f m) k)
tightenDScope f p (S names (Y body)) = SY names <$> f p body
tightenDScope f p (S names (N body)) = S names . N <$> f p body
mutual
private
tightenT : OPE n1 n2 -> Term d n2 -> Maybe (Term d n1)
tightenT p s =
let Element s' _ = pushSubsts s in
tightenT' p $ assert_smaller s s'
private
tightenE : OPE n1 n2 -> Elim d n2 -> Maybe (Elim d n1)
tightenE p e =
let Element e' _ = pushSubsts e in
tightenE' p $ assert_smaller e e'
private
tightenT' : OPE n1 n2 -> (t : Term d n2) -> (0 nt : NotClo t) =>
Maybe (Term d n1)
tightenT' p (TYPE l loc) = pure $ TYPE l loc
tightenT' p (Pi qty arg res loc) =
Pi qty <$> tightenT p arg <*> tightenS p res <*> pure loc
tightenT' p (Lam body loc) =
Lam <$> tightenS p body <*> pure loc
tightenT' p (Sig fst snd loc) =
Sig <$> tightenT p fst <*> tightenS p snd <*> pure loc
tightenT' p (Pair fst snd loc) =
Pair <$> tightenT p fst <*> tightenT p snd <*> pure loc
tightenT' p (Enum cases loc) =
pure $ Enum cases loc
tightenT' p (Tag tag loc) =
pure $ Tag tag loc
tightenT' p (Eq ty l r loc) =
Eq <$> tightenDS p ty <*> tightenT p l <*> tightenT p r <*> pure loc
tightenT' p (DLam body loc) =
DLam <$> tightenDS p body <*> pure loc
tightenT' p (Nat loc) =
pure $ Nat loc
tightenT' p (Zero loc) =
pure $ Zero loc
tightenT' p (Succ s loc) =
Succ <$> tightenT p s <*> pure loc
tightenT' p (BOX qty ty loc) =
BOX qty <$> tightenT p ty <*> pure loc
tightenT' p (Box val loc) =
Box <$> tightenT p val <*> pure loc
tightenT' p (E e) =
assert_total $ E <$> tightenE p e
private
tightenE' : OPE n1 n2 -> (e : Elim d n2) -> (0 ne : NotClo e) =>
Maybe (Elim d n1)
tightenE' p (F x u loc) =
pure $ F x u loc
tightenE' p (B i loc) =
B <$> tighten p i <*> pure loc
tightenE' p (App fun arg loc) =
App <$> tightenE p fun <*> tightenT p arg <*> pure loc
tightenE' p (CasePair qty pair ret body loc) =
CasePair qty <$> tightenE p pair
<*> tightenS p ret
<*> tightenS p body
<*> pure loc
tightenE' p (Fst pair loc) =
Fst <$> tightenE p pair <*> pure loc
tightenE' p (Snd pair loc) =
Snd <$> tightenE p pair <*> pure loc
tightenE' p (CaseEnum qty tag ret arms loc) =
CaseEnum qty <$> tightenE p tag
<*> tightenS p ret
<*> traverse (tightenT p) arms
<*> pure loc
tightenE' p (CaseNat qty qtyIH nat ret zero succ loc) =
CaseNat qty qtyIH
<$> tightenE p nat
<*> tightenS p ret
<*> tightenT p zero
<*> tightenS p succ
<*> pure loc
tightenE' p (CaseBox qty box ret body loc) =
CaseBox qty <$> tightenE p box
<*> tightenS p ret
<*> tightenS p body
<*> pure loc
tightenE' p (DApp fun arg loc) =
DApp <$> tightenE p fun <*> pure arg <*> pure loc
tightenE' p (Ann tm ty loc) =
Ann <$> tightenT p tm <*> tightenT p ty <*> pure loc
tightenE' p (Coe ty q0 q1 val loc) =
Coe <$> tightenDS p ty
<*> pure q0 <*> pure q1
<*> tightenT p val
<*> pure loc
tightenE' p (Comp ty q0 q1 val r zero one loc) =
Comp <$> tightenT p ty
<*> pure q0 <*> pure q1
<*> tightenT p val
<*> pure r
<*> tightenDS p zero
<*> tightenDS p one
<*> pure loc
tightenE' p (TypeCase ty ret arms def loc) =
TypeCase <$> tightenE p ty
<*> tightenT p ret
<*> traverse (tightenS p) arms
<*> tightenT p def
<*> pure loc
export
tightenS : {s : Nat} -> OPE m n ->
ScopeTermN s f n -> Maybe (ScopeTermN s f m)
tightenS = assert_total $ tightenScope tightenT
export
tightenDS : OPE m n -> DScopeTermN s f n -> Maybe (DScopeTermN s f m)
tightenDS = assert_total $ tightenDScope tightenT {f = \n, d => Term d n}
export Tighten (Elim d) where tighten p e = tightenE p e
export Tighten (Term d) where tighten p t = tightenT p t
mutual
export
dtightenT : OPE d1 d2 -> Term d2 n -> Maybe (Term d1 n)
dtightenT p s =
let Element s' _ = pushSubsts s in
dtightenT' p $ assert_smaller s s'
export
dtightenE : OPE d1 d2 -> Elim d2 n -> Maybe (Elim d1 n)
dtightenE p e =
let Element e' _ = pushSubsts e in
dtightenE' p $ assert_smaller e e'
private
dtightenT' : OPE d1 d2 -> (t : Term d2 n) -> (0 nt : NotClo t) =>
Maybe (Term d1 n)
dtightenT' p (TYPE l loc) =
pure $ TYPE l loc
dtightenT' p (Pi qty arg res loc) =
Pi qty <$> dtightenT p arg <*> dtightenS p res <*> pure loc
dtightenT' p (Lam body loc) =
Lam <$> dtightenS p body <*> pure loc
dtightenT' p (Sig fst snd loc) =
Sig <$> dtightenT p fst <*> dtightenS p snd <*> pure loc
dtightenT' p (Pair fst snd loc) =
Pair <$> dtightenT p fst <*> dtightenT p snd <*> pure loc
dtightenT' p (Enum cases loc) =
pure $ Enum cases loc
dtightenT' p (Tag tag loc) =
pure $ Tag tag loc
dtightenT' p (Eq ty l r loc) =
Eq <$> dtightenDS p ty <*> dtightenT p l <*> dtightenT p r <*> pure loc
dtightenT' p (DLam body loc) =
DLam <$> dtightenDS p body <*> pure loc
dtightenT' p (Nat loc) =
pure $ Nat loc
dtightenT' p (Zero loc) =
pure $ Zero loc
dtightenT' p (Succ s loc) =
Succ <$> dtightenT p s <*> pure loc
dtightenT' p (BOX qty ty loc) =
BOX qty <$> dtightenT p ty <*> pure loc
dtightenT' p (Box val loc) =
Box <$> dtightenT p val <*> pure loc
dtightenT' p (E e) =
assert_total $ E <$> dtightenE p e
export
dtightenE' : OPE d1 d2 -> (e : Elim d2 n) -> (0 ne : NotClo e) =>
Maybe (Elim d1 n)
dtightenE' p (F x u loc) =
pure $ F x u loc
dtightenE' p (B i loc) =
pure $ B i loc
dtightenE' p (App fun arg loc) =
App <$> dtightenE p fun <*> dtightenT p arg <*> pure loc
dtightenE' p (CasePair qty pair ret body loc) =
CasePair qty <$> dtightenE p pair
<*> dtightenS p ret
<*> dtightenS p body
<*> pure loc
dtightenE' p (Fst pair loc) =
Fst <$> dtightenE p pair <*> pure loc
dtightenE' p (Snd pair loc) =
Snd <$> dtightenE p pair <*> pure loc
dtightenE' p (CaseEnum qty tag ret arms loc) =
CaseEnum qty <$> dtightenE p tag
<*> dtightenS p ret
<*> traverse (dtightenT p) arms
<*> pure loc
dtightenE' p (CaseNat qty qtyIH nat ret zero succ loc) =
CaseNat qty qtyIH
<$> dtightenE p nat
<*> dtightenS p ret
<*> dtightenT p zero
<*> dtightenS p succ
<*> pure loc
dtightenE' p (CaseBox qty box ret body loc) =
CaseBox qty <$> dtightenE p box
<*> dtightenS p ret
<*> dtightenS p body
<*> pure loc
dtightenE' p (DApp fun arg loc) =
DApp <$> dtightenE p fun <*> tighten p arg <*> pure loc
dtightenE' p (Ann tm ty loc) =
Ann <$> dtightenT p tm <*> dtightenT p ty <*> pure loc
dtightenE' p (Coe ty q0 q1 val loc) =
[|Coe (dtightenDS p ty) (tighten p q0) (tighten p q1) (dtightenT p val)
(pure loc)|]
dtightenE' p (Comp ty q0 q1 val r zero one loc) =
[|Comp (dtightenT p ty) (tighten p q0) (tighten p q1)
(dtightenT p val) (tighten p r)
(dtightenDS p zero) (dtightenDS p one) (pure loc)|]
dtightenE' p (TypeCase ty ret arms def loc) =
[|TypeCase (dtightenE p ty) (dtightenT p ret)
(traverse (dtightenS p) arms) (dtightenT p def) (pure loc)|]
export
dtightenS : OPE d1 d2 -> ScopeTermN s d2 n -> Maybe (ScopeTermN s d1 n)
dtightenS = assert_total $ tightenDScope dtightenT {f = Term}
export
dtightenDS : {s : Nat} -> OPE d1 d2 ->
DScopeTermN s d2 n -> Maybe (DScopeTermN s d1 n)
dtightenDS = assert_total $ tightenScope dtightenT
export Tighten (\d => Term d n) where tighten p t = dtightenT p t
export Tighten (\d => Elim d n) where tighten p e = dtightenE p e
parameters {auto _ : Tighten f} {s : Nat}
export
squeeze : Scoped s f n -> (BContext s, Either (f (s + n)) (f n))
squeeze (S ns (N t)) = (ns, Right t)
squeeze (S ns (Y t)) = (ns, maybe (Left t) Right $ tightenN s t)
export
squeeze' : Scoped s f n -> Scoped s f n
squeeze' t = let (ns, res) = squeeze t in S ns $ either Y N res
parameters {0 f : Nat -> Nat -> Type}
{auto tt : Tighten (\d => f d n)} {s : Nat}
export
dsqueeze : Scoped s (\d => f d n) d ->
(BContext s, Either (f (s + d) n) (f d n))
dsqueeze = squeeze
export
dsqueeze' : Scoped s (\d => f d n) d -> Scoped s (\d => f d n) d
dsqueeze' = squeeze'
-- versions of SY, etc, that try to tighten and use SN automatically
public export %inline
ST : Tighten f => {s : Nat} -> BContext s -> f (s + n) -> Scoped s f n
ST names body = squeeze' $ SY names body
public export %inline
DST : {s : Nat} -> BContext s -> Term (s + d) n -> DScopeTermN s d n
DST names body = dsqueeze' {f = Term} $ SY names body
public export %inline
PiT : (qty : Qty) -> (x : BindName) ->
(arg : Term d n) -> (res : Term d (S n)) -> (loc : Loc) -> Term d n
PiT {qty, x, arg, res, loc} = Pi {qty, arg, res = ST [< x] res, loc}
public export %inline
LamT : (x : BindName) -> (body : Term d (S n)) -> (loc : Loc) -> Term d n
LamT {x, body, loc} = Lam {body = ST [< x] body, loc}
public export %inline
SigT : (x : BindName) -> (fst : Term d n) ->
(snd : Term d (S n)) -> (loc : Loc) -> Term d n
SigT {x, fst, snd, loc} = Sig {fst, snd = ST [< x] snd, loc}
public export %inline
EqT : (i : BindName) -> (ty : Term (S d) n) ->
(l, r : Term d n) -> (loc : Loc) -> Term d n
EqT {i, ty, l, r, loc} = Eq {ty = DST [< i] ty, l, r, loc}
public export %inline
DLamT : (i : BindName) -> (body : Term (S d) n) -> (loc : Loc) -> Term d n
DLamT {i, body, loc} = DLam {body = DST [< i] body, loc}
public export %inline
CoeT : (i : BindName) -> (ty : Term (S d) n) ->
(p, q : Dim d) -> (val : Term d n) -> (loc : Loc) -> Elim d n
CoeT {i, ty, p, q, val, loc} = Coe {ty = DST [< i] ty, p, q, val, loc}
public export %inline
typeCase1T : Elim d n -> Term d n ->
(k : TyConKind) -> BContext (arity k) -> Term d (arity k + n) ->
(loc : Loc) ->
{default (Nat loc) def : Term d n} ->
Elim d n
typeCase1T ty ret k ns body loc {def} =
typeCase ty ret [(k ** ST ns body)] def loc
public export %inline
CompH' : (ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) ->
(r : Dim d) -> (zero, one : DScopeTerm d n) -> (loc : Loc) -> Elim d n
CompH' {ty, p, q, val, r, zero, one, loc} =
let ty' = DST ty.names $ ty.term // (B VZ ty.name.loc ::: shift 2) in
Comp {
ty = dsub1 ty q, p, q,
val = E $ Coe ty p q val val.loc, r,
zero = DST zero.names $ E $
Coe ty' (B VZ zero.loc) (weakD 1 q) zero.term zero.loc,
one = DST one.names $ E $
Coe ty' (B VZ one.loc) (weakD 1 q) one.term one.loc,
loc
}
||| heterogeneous composition, using Comp and Coe (and subst)
|||
||| comp [i ⇒ A] @p @q s @r { 0 j ⇒ t₀; 1 j ⇒ t₁ }
||| ≔
||| comp [Aq/i] @p @q (coe [i ⇒ A] @p @q s) @r {
||| 0 j ⇒ coe [i ⇒ A] @j @q t₀;
||| 1 j ⇒ coe [i ⇒ A] @j @q t₁
||| }
public export %inline
CompH : (i : BindName) -> (ty : Term (S d) n) ->
(p, q : Dim d) -> (val : Term d n) -> (r : Dim d) ->
(j0 : BindName) -> (zero : Term (S d) n) ->
(j1 : BindName) -> (one : Term (S d) n) ->
(loc : Loc) ->
Elim d n
CompH {i, ty, p, q, val, r, j0, zero, j1, one, loc} =
CompH' {ty = DST [< i] ty, p, q, val, r,
zero = DST [< j0] zero, one = DST [< j1] one, loc}

View file

@ -9,7 +9,8 @@ import Generics.Derive
public export public export
data TyConKind = KTYPE | KPi | KSig | KEnum | KEq | KNat | KBOX data TyConKind =
KTYPE | KIOState | KPi | KSig | KEnum | KEq | KNat | KString | KBOX
%name TyConKind k %name TyConKind k
%runElab derive "TyConKind" [Eq.Eq, Ord.Ord, Show.Show, Generic, Meta, DecEq] %runElab derive "TyConKind" [Eq.Eq, Ord.Ord, Show.Show, Generic, Meta, DecEq]
@ -25,10 +26,12 @@ allKinds = %runElab do
||| in `type-case`, how many variables are bound in this branch ||| in `type-case`, how many variables are bound in this branch
public export %inline public export %inline
arity : TyConKind -> Nat arity : TyConKind -> Nat
arity KTYPE = 0 arity KTYPE = 0
arity KPi = 2 arity KIOState = 0
arity KSig = 2 arity KPi = 2
arity KEnum = 0 arity KSig = 2
arity KEq = 5 arity KEnum = 0
arity KNat = 0 arity KEq = 5
arity KBOX = 1 arity KNat = 0
arity KString = 0
arity KBOX = 1

View file

@ -3,6 +3,7 @@ module Quox.Typechecker
import public Quox.Typing import public Quox.Typing
import public Quox.Equal import public Quox.Equal
import Quox.Displace import Quox.Displace
import Quox.Pretty
import Data.List import Data.List
import Data.SnocVect import Data.SnocVect
@ -14,7 +15,7 @@ import Quox.EffExtra
public export public export
0 TC : List (Type -> Type) 0 TC : List (Type -> Type)
TC = [ErrorEff, DefsReader, NameGen] TC = [ErrorEff, DefsReader, NameGen, Log]
parameters (loc : Loc) parameters (loc : Loc)
@ -41,34 +42,24 @@ lubs ctx [] = zeroFor ctx
lubs ctx (x :: xs) = lubs1 $ x ::: xs lubs ctx (x :: xs) = lubs1 $ x ::: xs
export private
typecaseTel : (k : TyConKind) -> BContext (arity k) -> Universe -> prettyTermTC : {opts : LayoutOpts} ->
CtxExtension d n (arity k + n) TyContext d n -> Term d n -> Eff Pretty (Doc opts)
typecaseTel k xs u = case k of prettyTermTC ctx s = prettyTerm ctx.dnames ctx.tnames s
KTYPE => [<]
-- A : ★ᵤ, B : 0.A → ★ᵤ
KPi =>
let [< a, b] = xs in
[< (Zero, a, TYPE u a.loc),
(Zero, b, Arr Zero (BVT 0 b.loc) (TYPE u b.loc) b.loc)]
KSig =>
let [< a, b] = xs in
[< (Zero, a, TYPE u a.loc),
(Zero, b, Arr Zero (BVT 0 b.loc) (TYPE u b.loc) b.loc)]
KEnum => [<]
-- A₀ : ★ᵤ, A₁ : ★ᵤ, A : (A₀ ≡ A₁ : ★ᵤ), L : A₀, R : A₀
KEq =>
let [< a0, a1, a, l, r] = xs in
[< (Zero, a0, TYPE u a0.loc),
(Zero, a1, TYPE u a1.loc),
(Zero, a, Eq0 (TYPE u a.loc) (BVT 1 a.loc) (BVT 0 a.loc) a.loc),
(Zero, l, BVT 2 l.loc),
(Zero, r, BVT 2 r.loc)]
KNat => [<]
-- A : ★ᵤ
KBOX => let [< a] = xs in [< (Zero, a, TYPE u a.loc)]
private
checkLogs : String -> TyContext d n -> SQty ->
Term d n -> Maybe (Term d n) -> Eff TC ()
checkLogs fun ctx sg subj ty = do
let tyDoc = delay $ maybe (text "none") (runPretty . prettyTermTC ctx) ty
sayMany "check" subj.loc
[10 :> text fun,
95 :> hsep ["ctx =", runPretty $ prettyTyContext ctx],
95 :> hsep ["sg =", runPretty $ prettyQty sg.qty],
10 :> hsep ["subj =", runPretty $ prettyTermTC ctx subj],
10 :> hsep ["ty =", tyDoc]]
mutual mutual
||| "Ψ | Γ ⊢ σ · s ⇐ A ⊳ Σ" ||| "Ψ | Γ ⊢ σ · s ⇐ A ⊳ Σ"
||| |||
@ -81,7 +72,11 @@ mutual
export covering %inline export covering %inline
check : (ctx : TyContext d n) -> SQty -> Term d n -> Term d n -> check : (ctx : TyContext d n) -> SQty -> Term d n -> Term d n ->
Eff TC (CheckResult ctx.dctx n) Eff TC (CheckResult ctx.dctx n)
check ctx sg subj ty = ifConsistent ctx.dctx $ checkC ctx sg subj ty check ctx sg subj ty =
ifConsistentElse ctx.dctx
(do checkLogs "check" ctx sg subj (Just ty)
checkC ctx sg subj ty)
(say "check" 20 subj.loc "check: 0=1")
||| "Ψ | Γ ⊢₀ s ⇐ A" ||| "Ψ | Γ ⊢₀ s ⇐ A"
||| |||
@ -112,7 +107,12 @@ mutual
||| universe doesn't matter, only that a term is _a_ type, so it is optional. ||| universe doesn't matter, only that a term is _a_ type, so it is optional.
export covering %inline export covering %inline
checkType : TyContext d n -> Term d n -> Maybe Universe -> Eff TC () checkType : TyContext d n -> Term d n -> Maybe Universe -> Eff TC ()
checkType ctx subj l = ignore $ ifConsistent ctx.dctx $ checkTypeC ctx subj l checkType ctx subj l = do
let univ = TYPE <$> l <*> pure noLoc
ignore $ ifConsistentElse ctx.dctx
(do checkLogs "checkType" ctx SZero subj univ
checkTypeC ctx subj l)
(say "check" 20 subj.loc "checkType: 0=1")
export covering %inline export covering %inline
checkTypeC : TyContext d n -> Term d n -> Maybe Universe -> Eff TC () checkTypeC : TyContext d n -> Term d n -> Maybe Universe -> Eff TC ()
@ -135,7 +135,11 @@ mutual
export covering %inline export covering %inline
infer : (ctx : TyContext d n) -> SQty -> Elim d n -> infer : (ctx : TyContext d n) -> SQty -> Elim d n ->
Eff TC (InferResult ctx.dctx d n) Eff TC (InferResult ctx.dctx d n)
infer ctx sg subj = ifConsistent ctx.dctx $ inferC ctx sg subj infer ctx sg subj = do
ifConsistentElse ctx.dctx
(do checkLogs "infer" ctx sg (E subj) Nothing
inferC ctx sg subj)
(say "check" 20 subj.loc "infer: 0=1")
||| `infer`, assuming the dimension context is consistent ||| `infer`, assuming the dimension context is consistent
export covering %inline export covering %inline
@ -164,6 +168,8 @@ mutual
check' ctx sg t@(TYPE {}) ty = toCheckType ctx sg t ty check' ctx sg t@(TYPE {}) ty = toCheckType ctx sg t ty
check' ctx sg t@(IOState {}) ty = toCheckType ctx sg t ty
check' ctx sg t@(Pi {}) ty = toCheckType ctx sg t ty check' ctx sg t@(Pi {}) ty = toCheckType ctx sg t ty
check' ctx sg (Lam body loc) ty = do check' ctx sg (Lam body loc) ty = do
@ -214,25 +220,39 @@ mutual
-- then Ψ | Γ ⊢ σ · (δ i ⇒ t) ⇐ Eq [i ⇒ A] l r ⊳ Σ -- then Ψ | Γ ⊢ σ · (δ i ⇒ t) ⇐ Eq [i ⇒ A] l r ⊳ Σ
pure qout pure qout
check' ctx sg t@(Nat {}) ty = toCheckType ctx sg t ty check' ctx sg t@(NAT {}) ty = toCheckType ctx sg t ty
check' ctx sg (Zero {}) ty = do check' ctx sg (Nat {}) ty = do
expectNat !(askAt DEFS) ctx SZero ty.loc ty expectNAT !(askAt DEFS) ctx SZero ty.loc ty
pure $ zeroFor ctx pure $ zeroFor ctx
check' ctx sg (Succ n {}) ty = do check' ctx sg (Succ n {}) ty = do
expectNat !(askAt DEFS) ctx SZero ty.loc ty expectNAT !(askAt DEFS) ctx SZero ty.loc ty
checkC ctx sg n ty checkC ctx sg n ty
check' ctx sg t@(STRING {}) ty = toCheckType ctx sg t ty
check' ctx sg t@(Str s {}) ty = do
expectSTRING !(askAt DEFS) ctx SZero ty.loc ty
pure $ zeroFor ctx
check' ctx sg t@(BOX {}) ty = toCheckType ctx sg t ty check' ctx sg t@(BOX {}) ty = toCheckType ctx sg t ty
check' ctx sg (Box val loc) ty = do check' ctx sg (Box val loc) ty = do
(q, ty) <- expectBOX !(askAt DEFS) ctx SZero ty.loc ty (q, ty) <- expectBOX !(askAt DEFS) ctx SZero ty.loc ty
-- if Ψ | Γ ⊢ σ · s ⇐ A ⊳ Σ -- if Ψ | Γ ⊢ σ ⨴ π · s ⇐ A ⊳ Σ
valout <- checkC ctx sg val ty valout <- checkC ctx (subjMult sg q) val ty
-- then Ψ | Γ ⊢ σ · [s] ⇐ [π.A] ⊳ πΣ -- then Ψ | Γ ⊢ σ · [s] ⇐ [π.A] ⊳ πΣ
pure $ q * valout pure $ q * valout
check' ctx sg (Let qty rhs body loc) ty = do
eres <- inferC ctx (subjMult sg qty) rhs
let sqty = sg.qty * qty
qout <- checkC (extendTyLet sqty body.name eres.type (E rhs) ctx)
sg body.term (weakT 1 ty)
>>= popQ loc sqty
pure $ qty * eres.qout + qout
check' ctx sg (E e) ty = do check' ctx sg (E e) ty = do
-- if Ψ | Γ ⊢ σ · e ⇒ A' ⊳ Σ -- if Ψ | Γ ⊢ σ · e ⇒ A' ⊳ Σ
infres <- inferC ctx sg e infres <- inferC ctx sg e
@ -252,6 +272,9 @@ mutual
Just l => unless (k < l) $ throw $ BadUniverse loc k l Just l => unless (k < l) $ throw $ BadUniverse loc k l
Nothing => pure () Nothing => pure ()
checkType' ctx (IOState loc) u = pure ()
-- Ψ | Γ ⊢₀ IOState ⇒ Type
checkType' ctx (Pi qty arg res _) u = do checkType' ctx (Pi qty arg res _) u = do
-- if Ψ | Γ ⊢₀ A ⇐ Type -- if Ψ | Γ ⊢₀ A ⇐ Type
checkTypeC ctx arg u checkTypeC ctx arg u
@ -292,19 +315,28 @@ mutual
checkType' ctx t@(DLam {}) u = checkType' ctx t@(DLam {}) u =
throw $ NotType t.loc ctx t throw $ NotType t.loc ctx t
checkType' ctx (Nat {}) u = pure () checkType' ctx (NAT {}) u = pure ()
checkType' ctx t@(Zero {}) u = throw $ NotType t.loc ctx t checkType' ctx t@(Nat {}) u = throw $ NotType t.loc ctx t
checkType' ctx t@(Succ {}) u = throw $ NotType t.loc ctx t checkType' ctx t@(Succ {}) u = throw $ NotType t.loc ctx t
checkType' ctx (STRING loc) u = pure ()
-- Ψ | Γ ⊢₀ STRING ⇒ Type
checkType' ctx t@(Str {}) u = throw $ NotType t.loc ctx t
checkType' ctx (BOX q ty _) u = checkType ctx ty u checkType' ctx (BOX q ty _) u = checkType ctx ty u
checkType' ctx t@(Box {}) u = throw $ NotType t.loc ctx t checkType' ctx t@(Box {}) u = throw $ NotType t.loc ctx t
checkType' ctx (Let qty rhs body loc) u = do
expectEqualQ loc qty Zero
ety <- inferC ctx SZero rhs
checkType (extendTy Zero body.name ety.type ctx) body.term u
checkType' ctx (E e) u = do checkType' ctx (E e) u = do
-- if Ψ | Γ ⊢₀ E ⇒ Type -- if Ψ | Γ ⊢₀ E ⇒ Type
infres <- inferC ctx SZero e infres <- inferC ctx SZero e
-- if Ψ | Γ ⊢ Type <: Type 𝓀 -- if Ψ | Γ ⊢ Type <: Type 𝓀
case u of case u of
Just u => lift $ subtype e.loc ctx infres.type (TYPE u noLoc) Just u => lift $ subtype e.loc ctx infres.type (TYPE u e.loc)
Nothing => ignore $ expectTYPE !(askAt DEFS) ctx SZero e.loc infres.type Nothing => ignore $ expectTYPE !(askAt DEFS) ctx SZero e.loc infres.type
-- then Ψ | Γ ⊢₀ E ⇐ Type 𝓀 -- then Ψ | Γ ⊢₀ E ⇐ Type 𝓀
@ -328,8 +360,10 @@ mutual
-- if σ ≤ π -- if σ ≤ π
expectCompatQ loc sg.qty g.qty.qty expectCompatQ loc sg.qty g.qty.qty
-- then Ψ | Γ ⊢ σ · x ⇒ A ⊳ 𝟎 -- then Ψ | Γ ⊢ σ · x ⇒ A ⊳ 𝟎
let Val d = ctx.dimLen; Val n = ctx.termLen pure $ InfRes {
pure $ InfRes {type = g.typeAt u, qout = zeroFor ctx} type = g.typeWithAt ctx.dimLen ctx.termLen u,
qout = zeroFor ctx
}
infer' ctx sg (B i _) = infer' ctx sg (B i _) =
-- if x : A ∈ Γ -- if x : A ∈ Γ
@ -337,8 +371,8 @@ mutual
pure $ lookupBound sg.qty i ctx.tctx pure $ lookupBound sg.qty i ctx.tctx
where where
lookupBound : forall n. Qty -> Var n -> TContext d n -> InferResult' d n lookupBound : forall n. Qty -> Var n -> TContext d n -> InferResult' d n
lookupBound pi VZ (ctx :< type) = lookupBound pi VZ (ctx :< var) =
InfRes {type = weakT 1 type, qout = zeroFor ctx :< pi} InfRes {type = weakT 1 var.type, qout = zeroFor ctx :< pi}
lookupBound pi (VS i) (ctx :< _) = lookupBound pi (VS i) (ctx :< _) =
let InfRes {type, qout} = lookupBound pi i ctx in let InfRes {type, qout} = lookupBound pi i ctx in
InfRes {type = weakT 1 type, qout = qout :< Zero} InfRes {type = weakT 1 type, qout = qout :< Zero}
@ -426,39 +460,43 @@ mutual
-- if Ψ | Γ ⊢ σ · n ⇒ ⊳ Σn -- if Ψ | Γ ⊢ σ · n ⇒ ⊳ Σn
nres <- inferC ctx sg n nres <- inferC ctx sg n
let nat = nres.type let nat = nres.type
expectNat !(askAt DEFS) ctx SZero n.loc nat expectNAT !(askAt DEFS) ctx SZero n.loc nat
-- if Ψ | Γ, n : ⊢₀ A ⇐ Type -- if Ψ | Γ, n : ⊢₀ A ⇐ Type
checkTypeC (extendTy Zero ret.name nat ctx) ret.term Nothing checkTypeC (extendTy Zero ret.name nat ctx) ret.term Nothing
-- if Ψ | Γ ⊢ σ · zer ⇐ A[0 ∷ /n] ⊳ Σz -- if Ψ | Γ ⊢ σ · zer ⇐ A[0 ∷ /n] ⊳ Σz
zerout <- checkC ctx sg zer $ sub1 ret $ Ann (Zero zer.loc) nat zer.loc zerout <- checkC ctx sg zer $ sub1 ret $ Ann (Zero zer.loc) nat zer.loc
-- if Ψ | Γ, n : , ih : A ⊢ σ · suc ⇐ A[succ p ∷ /n] ⊳ Σs, ρ₁.p, ρ₂.ih -- if Ψ | Γ, n : , ih : A ⊢ σ · suc ⇐ A[succ p ∷ /n] ⊳ Σs, ρ.p, ς.ih
-- with ρ₂ ≤ π'σ, (ρ₁ + ρ₂) ≤ πσ -- with ς ≤ π'σ, (ρ + ς) ≤ πσ
let [< p, ih] = suc.names let [< p, ih] = suc.names
pisg = pi * sg.qty pisg = pi * sg.qty
sucCtx = extendTyN [< (pisg, p, Nat p.loc), (pi', ih, ret.term)] ctx sucCtx = extendTyN [< (pisg, p, NAT p.loc), (pi', ih, ret.term)] ctx
sucType = substCaseSuccRet suc.names ret sucType = substCaseSuccRet suc.names ret
sucout :< qp :< qih <- checkC sucCtx sg suc.term sucType sucout :< qp :< qih <- checkC sucCtx sg suc.term sucType
expectCompatQ loc qih (pi' * sg.qty) expectCompatQ loc qih (pi' * sg.qty)
-- [fixme] better error here -- [fixme] better error here
expectCompatQ loc (qp + qih) pisg expectCompatQ loc (qp + qih) pisg
-- then Ψ | Γ ⊢ caseπ ⋯ ⇒ A[n] ⊳ πΣn + Σz + ωΣs -- if ς = 0, then Σb = lubs(Σz, Σs), otherwise Σb = Σz + ωςΣs
let bodyout = case qih of
Zero => lubs ctx [zerout, sucout]
_ => zerout + Any * sucout
-- then Ψ | Γ ⊢ caseπ ⋯ ⇒ A[n] ⊳ πΣn + Σb
pure $ InfRes { pure $ InfRes {
type = sub1 ret n, type = sub1 ret n,
qout = pi * nres.qout + zerout + Any * sucout qout = pi * nres.qout + bodyout
} }
infer' ctx sg (CaseBox pi box ret body loc) = do infer' ctx sg (CaseBox pi box ret body loc) = do
-- if Ψ | Γ ⊢ σ · b ⇒ [ρ.A] ⊳ Σ₁ -- if Ψ | Γ ⊢ σ · b ⇒ [ρ.A] ⊳ Σ₁
boxres <- inferC ctx sg box boxres <- inferC ctx sg box
(q, ty) <- expectBOX !(askAt DEFS) ctx SZero box.loc boxres.type (rh, ty) <- expectBOX !(askAt DEFS) ctx SZero box.loc boxres.type
-- if Ψ | Γ, x : [ρ.A] ⊢₀ R ⇐ Type -- if Ψ | Γ, x : [ρ.A] ⊢₀ R ⇐ Type
checkTypeC (extendTy Zero ret.name boxres.type ctx) ret.term Nothing checkTypeC (extendTy Zero ret.name boxres.type ctx) ret.term Nothing
-- if Ψ | Γ, x : A ⊢ t ⇐ R[[x] ∷ [ρ.A/x]] ⊳ Σ₂, ς·x -- if Ψ | Γ, x : A ⊢ σ · t ⇐ R[[x] ∷ [ρ.A/x]] ⊳ Σ₂, ς·x
-- with ς ≤ ρπσ -- with ς ≤ ρπσ
let qpisg = q * pi * sg.qty let rhpisg = rh * pi * sg.qty
bodyCtx = extendTy qpisg body.name ty ctx bodyCtx = extendTy rhpisg body.name ty ctx
bodyType = substCaseBoxRet body.name ty ret bodyType = substCaseBoxRet body.name ty ret
bodyout <- checkC bodyCtx sg body.term bodyType >>= popQ loc qpisg bodyout <- checkC bodyCtx sg body.term bodyType >>= popQ loc rhpisg
-- then Ψ | Γ ⊢ caseπ ⋯ ⇒ R[b/x] ⊳ Σ₁ + Σ₂ -- then Ψ | Γ ⊢ caseπ ⋯ ⇒ R[b/x] ⊳ Σ₁ + Σ₂
pure $ InfRes { pure $ InfRes {
type = sub1 ret box, type = sub1 ret box,
@ -473,23 +511,34 @@ mutual
pure $ InfRes {type = dsub1 ty dim, qout} pure $ InfRes {type = dsub1 ty dim, qout}
infer' ctx sg (Coe ty p q val loc) = do infer' ctx sg (Coe ty p q val loc) = do
-- if Ψ, 𝑖 | Γ ⊢₀ A ⇐ Type _
checkType (extendDim ty.name ctx) ty.term Nothing checkType (extendDim ty.name ctx) ty.term Nothing
-- if Ψ | Γ ⊢ σ · s ⇐ Ap/𝑖 ⊳ Σ
qout <- checkC ctx sg val $ dsub1 ty p qout <- checkC ctx sg val $ dsub1 ty p
-- then Ψ | Γ ⊢ σ · coe (𝑖 ⇒ A) @p @q s ⇒ Aq/𝑖 ⊳ Σ
pure $ InfRes {type = dsub1 ty q, qout} pure $ InfRes {type = dsub1 ty q, qout}
infer' ctx sg (Comp ty p q val r (S [< j0] val0) (S [< j1] val1) loc) = do infer' ctx sg (Comp ty p q val r (S [< j0] val0) (S [< j1] val1) loc) = do
-- if Ψ | Γ ⊢₀ A ⇐ Type _
checkType ctx ty Nothing checkType ctx ty Nothing
-- if Ψ | Γ ⊢ σ · s ⇐ A ⊳ Σ
qout <- checkC ctx sg val ty qout <- checkC ctx sg val ty
-- if Ψ, 𝑗, 𝑖=0 | Γ ⊢ σ · t₀ ⇐ A ⊳ Σ₀
-- Ψ, 𝑗, 𝑖=0, 𝑗=p | Γ ⊢ t₀ = s ⇐ A
let ty' = dweakT 1 ty; val' = dweakT 1 val; p' = weakD 1 p let ty' = dweakT 1 ty; val' = dweakT 1 val; p' = weakD 1 p
ctx0 = extendDim j0 $ eqDim r (K Zero j0.loc) ctx ctx0 = extendDim j0 $ eqDim r (K Zero j0.loc) ctx
val0 = getTerm val0 val0 = getTerm val0
qout0 <- check ctx0 sg val0 ty' qout0 <- check ctx0 sg val0 ty'
lift $ equal loc (eqDim (B VZ p.loc) p' ctx0) sg ty' val0 val' lift $ equal loc (eqDim (B VZ p.loc) p' ctx0) sg ty' val0 val'
-- if Ψ, 𝑗, 𝑖=1 | Γ ⊢ σ · t₁ ⇐ A ⊳ Σ₁
-- Ψ, 𝑗, 𝑖=1, 𝑗=p | Γ ⊢ t₁ = s ⇐ A
let ctx1 = extendDim j1 $ eqDim r (K One j1.loc) ctx let ctx1 = extendDim j1 $ eqDim r (K One j1.loc) ctx
val1 = getTerm val1 val1 = getTerm val1
qout1 <- check ctx1 sg val1 ty' qout1 <- check ctx1 sg val1 ty'
-- if Σ = Σ₀ = Σ₁
lift $ equal loc (eqDim (B VZ p.loc) p' ctx1) sg ty' val1 val' lift $ equal loc (eqDim (B VZ p.loc) p' ctx1) sg ty' val1 val'
let qouts = qout :: catMaybes [toMaybe qout0, toMaybe qout1] let qouts = qout :: catMaybes [toMaybe qout0, toMaybe qout1]
-- then Ψ | Γ ⊢ comp A @p @q s @r {0 𝑗 ⇒ t₀; 1 𝑗 ⇒ t₁} ⇒ A ⊳ Σ
pure $ InfRes {type = ty, qout = lubs ctx qouts} pure $ InfRes {type = ty, qout = lubs ctx qouts}
infer' ctx sg (TypeCase ty ret arms def loc) = do infer' ctx sg (TypeCase ty ret arms def loc) = do

View file

@ -7,6 +7,7 @@ import public Quox.Typing.Error as Typing
import public Quox.Syntax import public Quox.Syntax
import public Quox.Definition import public Quox.Definition
import public Quox.Whnf import public Quox.Whnf
import public Quox.Pretty
import Language.Reflection import Language.Reflection
import Control.Eff import Control.Eff
@ -46,16 +47,15 @@ lookupFree x loc defs = maybe (throw $ NotInScope loc x) pure $ lookup x defs
public export public export
substCasePairRet : BContext 2 -> Term d n -> ScopeTerm d n -> Term d (2 + n) substCasePairRet : BContext 2 -> Term d n -> ScopeTerm d n -> Term d (2 + n)
substCasePairRet [< x, y] dty retty = substCasePairRet [< x, y] dty retty =
let tm = Pair (BVT 1 x.loc) (BVT 0 y.loc) $ x.loc `extendL` y.loc let tm = Pair (BVT 1 x.loc) (BVT 0 y.loc) $ x.loc `extendL` y.loc
arg = Ann tm (dty // fromNat 2) tm.loc arg = Ann tm (dty // fromNat 2) tm.loc in
in
retty.term // (arg ::: shift 2) retty.term // (arg ::: shift 2)
public export public export
substCaseSuccRet : BContext 2 -> ScopeTerm d n -> Term d (2 + n) substCaseSuccRet : BContext 2 -> ScopeTerm d n -> Term d (2 + n)
substCaseSuccRet [< p, ih] retty = substCaseSuccRet [< p, ih] retty =
let arg = Ann (Succ (BVT 1 p.loc) p.loc) (Nat noLoc) $ p.loc `extendL` ih.loc let loc = p.loc `extendL` ih.loc
in arg = Ann (Succ (BVT 1 p.loc) p.loc) (NAT p.loc) loc in
retty.term // (arg ::: shift 2) retty.term // (arg ::: shift 2)
public export public export
@ -65,23 +65,31 @@ substCaseBoxRet x dty retty =
retty.term // (arg ::: shift 1) retty.term // (arg ::: shift 1)
parameters (defs : Definitions) {auto _ : (Has ErrorEff fs, Has NameGen fs)} private
0 ExpectErrorConstructor : Type
ExpectErrorConstructor =
forall d, n. Loc -> NameContexts d n -> Term d n -> Error
parameters (defs : Definitions)
{auto _ : (Has ErrorEff fs, Has NameGen fs, Has Log fs)}
namespace TyContext namespace TyContext
parameters (ctx : TyContext d n) (sg : SQty) (loc : Loc) parameters (ctx : TyContext d n) (sg : SQty) (loc : Loc)
export covering export covering
whnf : {0 isRedex : RedexTest tm} -> CanWhnf tm isRedex => whnf : {0 isRedex : RedexTest tm} -> CanWhnf tm isRedex =>
tm d n -> Eff fs (NonRedex tm d n defs sg) tm d n -> Eff fs (NonRedex tm d n defs (toWhnfContext ctx) sg)
whnf tm = do whnf tm = do
let Val n = ctx.termLen; Val d = ctx.dimLen let Val n = ctx.termLen; Val d = ctx.dimLen
res <- lift $ runExcept $ whnf defs (toWhnfContext ctx) sg tm res <- lift $ runExcept $ whnf defs (toWhnfContext ctx) sg tm
rethrow res rethrow res
private covering %macro private covering %macro
expect : (forall d, n. Loc -> NameContexts d n -> Term d n -> Error) -> expect : ExpectErrorConstructor -> TTImp -> TTImp ->
TTImp -> TTImp -> Elab (Term d n -> Eff fs a) Elab (Term d n -> Eff fs a)
expect k l r = do expect err pat rhs = Prelude.do
f <- check `(\case ~(l) => Just ~(r); _ => Nothing) match <- check `(\case ~(pat) => Just ~(rhs); _ => Nothing)
pure $ \t => maybe (throw $ k loc ctx.names t) pure . f . fst =<< whnf t pure $ \term => do
res <- whnf term
maybe (throw $ err loc ctx.names term) pure $ match $ fst res
export covering %inline export covering %inline
expectTYPE : Term d n -> Eff fs Universe expectTYPE : Term d n -> Eff fs Universe
@ -104,32 +112,40 @@ parameters (defs : Definitions) {auto _ : (Has ErrorEff fs, Has NameGen fs)}
expectEq = expect ExpectedEq `(Eq {ty, l, r, _}) `((ty, l, r)) expectEq = expect ExpectedEq `(Eq {ty, l, r, _}) `((ty, l, r))
export covering %inline export covering %inline
expectNat : Term d n -> Eff fs () expectNAT : Term d n -> Eff fs ()
expectNat = expect ExpectedNat `(Nat {}) `(()) expectNAT = expect ExpectedNAT `(NAT {}) `(())
export covering %inline
expectSTRING : Term d n -> Eff fs ()
expectSTRING = expect ExpectedSTRING `(STRING {}) `(())
export covering %inline export covering %inline
expectBOX : Term d n -> Eff fs (Qty, Term d n) expectBOX : Term d n -> Eff fs (Qty, Term d n)
expectBOX = expect ExpectedBOX `(BOX {qty, ty, _}) `((qty, ty)) expectBOX = expect ExpectedBOX `(BOX {qty, ty, _}) `((qty, ty))
export covering %inline
expectIOState : Term d n -> Eff fs ()
expectIOState = expect ExpectedIOState `(IOState {}) `(())
namespace EqContext namespace EqContext
parameters (ctx : EqContext n) (sg : SQty) (loc : Loc) parameters (ctx : EqContext n) (sg : SQty) (loc : Loc)
export covering export covering
whnf : {0 isRedex : RedexTest tm} -> CanWhnf tm isRedex => whnf : {0 isRedex : RedexTest tm} -> CanWhnf tm isRedex =>
tm 0 n -> Eff fs (NonRedex tm 0 n defs sg) tm 0 n -> Eff fs (NonRedex tm 0 n defs (toWhnfContext ctx) sg)
whnf tm = do whnf tm = do
let Val n = ctx.termLen
res <- lift $ runExcept $ whnf defs (toWhnfContext ctx) sg tm res <- lift $ runExcept $ whnf defs (toWhnfContext ctx) sg tm
rethrow res rethrow res
private covering %macro private covering %macro
expect : (forall d, n. Loc -> NameContexts d n -> Term d n -> Error) -> expect : ExpectErrorConstructor -> TTImp -> TTImp ->
TTImp -> TTImp -> Elab (Term 0 n -> Eff fs a) Elab (Term 0 n -> Eff fs a)
expect k l r = do expect err pat rhs = do
f <- check `(\case ~(l) => Just ~(r); _ => Nothing) match <- check `(\case ~(pat) => Just ~(rhs); _ => Nothing)
pure $ \t => pure $ \term => do
let err = throw $ k loc ctx.names (t // shift0 ctx.dimLen) in res <- whnf term
maybe err pure . f . fst =<< whnf t let t0 = delay $ term // shift0 ctx.dimLen
maybe (throw $ err loc ctx.names t0) pure $ match $ fst res
export covering %inline export covering %inline
expectTYPE : Term 0 n -> Eff fs Universe expectTYPE : Term 0 n -> Eff fs Universe
@ -152,9 +168,17 @@ parameters (defs : Definitions) {auto _ : (Has ErrorEff fs, Has NameGen fs)}
expectEq = expect ExpectedEq `(Eq {ty, l, r, _}) `((ty, l, r)) expectEq = expect ExpectedEq `(Eq {ty, l, r, _}) `((ty, l, r))
export covering %inline export covering %inline
expectNat : Term 0 n -> Eff fs () expectNAT : Term 0 n -> Eff fs ()
expectNat = expect ExpectedNat `(Nat {}) `(()) expectNAT = expect ExpectedNAT `(NAT {}) `(())
export covering %inline
expectSTRING : Term 0 n -> Eff fs ()
expectSTRING = expect ExpectedSTRING `(STRING {}) `(())
export covering %inline export covering %inline
expectBOX : Term 0 n -> Eff fs (Qty, Term 0 n) expectBOX : Term 0 n -> Eff fs (Qty, Term 0 n)
expectBOX = expect ExpectedBOX `(BOX {qty, ty, _}) `((qty, ty)) expectBOX = expect ExpectedBOX `(BOX {qty, ty, _}) `((qty, ty))
export covering %inline
expectIOState : Term 0 n -> Eff fs ()
expectIOState = expect ExpectedIOState `(IOState {}) `(())

View file

@ -14,9 +14,41 @@ public export
QContext : Nat -> Type QContext : Nat -> Type
QContext = Context' Qty QContext = Context' Qty
public export
record LocalVar d n where
constructor MkLocal
type : Term d n
term : Maybe (Term d n) -- if from a `let`
%runElab deriveIndexed "LocalVar" [Show]
namespace LocalVar
export %inline
letVar : (type, term : Term d n) -> LocalVar d n
letVar type term = MkLocal {type, term = Just term}
export %inline
lamVar : (type : Term d n) -> LocalVar d n
lamVar type = MkLocal {type, term = Nothing}
export %inline
mapVar : (Term d n -> Term d' n') -> LocalVar d n -> LocalVar d' n'
mapVar f = {type $= f, term $= map f}
export %inline
subD : DSubst d1 d2 -> LocalVar d1 n -> LocalVar d2 n
subD th = mapVar (// th)
export %inline
weakD : LocalVar d n -> LocalVar (S d) n
weakD = subD $ shift 1
export %inline CanShift (LocalVar d) where l // by = mapVar (// by) l
export %inline CanDSubst LocalVar where l // by = mapVar (// by) l
export %inline CanTSubst LocalVar where l // by = mapVar (// by) l
public export public export
TContext : TermLike TContext : TermLike
TContext d = Context (Term d) TContext d = Context (LocalVar d)
public export public export
QOutput : Nat -> Type QOutput : Nat -> Type
@ -33,7 +65,7 @@ record TyContext d n where
{auto dimLen : Singleton d} {auto dimLen : Singleton d}
{auto termLen : Singleton n} {auto termLen : Singleton n}
dctx : DimEq d dctx : DimEq d
dnames : BContext d dnames : BContext d -- only used for printing
tctx : TContext d n tctx : TContext d n
tnames : BContext n -- only used for printing tnames : BContext n -- only used for printing
qtys : QContext n -- only used for printing qtys : QContext n -- only used for printing
@ -58,6 +90,8 @@ record EqContext n where
public export public export
record WhnfContext d n where record WhnfContext d n where
constructor MkWhnfContext constructor MkWhnfContext
{auto dimLen : Singleton d}
{auto termLen : Singleton n}
dnames : BContext d dnames : BContext d
tnames : BContext n tnames : BContext n
tctx : TContext d n tctx : TContext d n
@ -65,15 +99,11 @@ record WhnfContext d n where
%runElab deriveIndexed "WhnfContext" [Show] %runElab deriveIndexed "WhnfContext" [Show]
namespace TContext namespace TContext
export %inline
pushD : TContext d n -> TContext (S d) n
pushD tel = map (// shift 1) tel
export %inline export %inline
zeroFor : Context tm n -> QOutput n zeroFor : Context tm n -> QOutput n
zeroFor ctx = Zero <$ ctx zeroFor ctx = Zero <$ ctx
private public export
extendLen : Telescope a n1 n2 -> Singleton n1 -> Singleton n2 extendLen : Telescope a n1 n2 -> Singleton n1 -> Singleton n2
extendLen [<] x = x extendLen [<] x = x
extendLen (tel :< _) x = [|S $ extendLen tel x|] extendLen (tel :< _) x = [|S $ extendLen tel x|]
@ -87,32 +117,54 @@ public export
CtxExtension0 : Nat -> Nat -> Nat -> Type CtxExtension0 : Nat -> Nat -> Nat -> Type
CtxExtension0 d = Telescope ((BindName,) . Term d) CtxExtension0 d = Telescope ((BindName,) . Term d)
public export
CtxExtensionLet : Nat -> Nat -> Nat -> Type
CtxExtensionLet d = Telescope ((Qty, BindName,) . LocalVar d)
public export
CtxExtensionLet0 : Nat -> Nat -> Nat -> Type
CtxExtensionLet0 d = Telescope ((BindName,) . LocalVar d)
namespace TyContext namespace TyContext
public export %inline public export %inline
empty : TyContext 0 0 empty : TyContext 0 0
empty = empty = MkTyContext {
MkTyContext {dctx = new, dnames = [<], tctx = [<], tnames = [<], qtys = [<]} dctx = new, dnames = [<], tctx = [<], tnames = [<], qtys = [<]
}
public export %inline public export %inline
null : TyContext d n -> Bool null : TyContext d n -> Bool
null ctx = null ctx.dnames && null ctx.tnames null ctx = null ctx.dnames && null ctx.tnames
export %inline export %inline
extendTyN : CtxExtension d n1 n2 -> TyContext d n1 -> TyContext d n2 extendTyLetN : CtxExtensionLet d n1 n2 -> TyContext d n1 -> TyContext d n2
extendTyN xss (MkTyContext {termLen, dctx, dnames, tctx, tnames, qtys}) = extendTyLetN xss (MkTyContext {termLen, dctx, dnames, tctx, tnames, qtys}) =
let (qs, xs, ss) = unzip3 xss in let (qs, xs, ls) = unzip3 xss in
MkTyContext { MkTyContext {
dctx, dnames, dctx, dnames,
termLen = extendLen xss termLen, termLen = extendLen xss termLen,
tctx = tctx . ss, tctx = tctx . ls,
tnames = tnames . xs, tnames = tnames . xs,
qtys = qtys . qs qtys = qtys . qs
} }
export %inline
extendTyN : CtxExtension d n1 n2 -> TyContext d n1 -> TyContext d n2
extendTyN = extendTyLetN . map (\(q, x, s) => (q, x, lamVar s))
export %inline
extendTyLetN0 : CtxExtensionLet0 d n1 n2 -> TyContext d n1 -> TyContext d n2
extendTyLetN0 xss = extendTyLetN (map (Zero,) xss)
export %inline export %inline
extendTyN0 : CtxExtension0 d n1 n2 -> TyContext d n1 -> TyContext d n2 extendTyN0 : CtxExtension0 d n1 n2 -> TyContext d n1 -> TyContext d n2
extendTyN0 xss = extendTyN (map (Zero,) xss) extendTyN0 xss = extendTyN (map (Zero,) xss)
export %inline
extendTyLet : Qty -> BindName -> Term d n -> Term d n ->
TyContext d n -> TyContext d (S n)
extendTyLet q x s e = extendTyLetN [< (q, x, letVar s e)]
export %inline export %inline
extendTy : Qty -> BindName -> Term d n -> TyContext d n -> TyContext d (S n) extendTy : Qty -> BindName -> Term d n -> TyContext d n -> TyContext d (S n)
extendTy q x s = extendTyN [< (q, x, s)] extendTy q x s = extendTyN [< (q, x, s)]
@ -128,7 +180,7 @@ namespace TyContext
dctx = dctx :<? Nothing, dctx = dctx :<? Nothing,
dnames = dnames :< x, dnames = dnames :< x,
dimLen = [|S dimLen|], dimLen = [|S dimLen|],
tctx = pushD tctx, tctx = map weakD tctx,
tnames, qtys tnames, qtys
} }
@ -167,7 +219,7 @@ makeEqContext' ctx th = MkEqContext {
termLen = ctx.termLen, termLen = ctx.termLen,
dassign = makeDAssign th, dassign = makeDAssign th,
dnames = ctx.dnames, dnames = ctx.dnames,
tctx = map (// th) ctx.tctx, tctx = map (subD th) ctx.tctx,
tnames = ctx.tnames, tnames = ctx.tnames,
qtys = ctx.qtys qtys = ctx.qtys
} }
@ -189,21 +241,34 @@ namespace EqContext
null ctx = null ctx.dnames && null ctx.tnames null ctx = null ctx.dnames && null ctx.tnames
export %inline export %inline
extendTyN : CtxExtension 0 n1 n2 -> EqContext n1 -> EqContext n2 extendTyLetN : CtxExtensionLet 0 n1 n2 -> EqContext n1 -> EqContext n2
extendTyN xss (MkEqContext {termLen, dassign, dnames, tctx, tnames, qtys}) = extendTyLetN xss (MkEqContext {termLen, dassign, dnames, tctx, tnames, qtys}) =
let (qs, xs, ss) = unzip3 xss in let (qs, xs, ls) = unzip3 xss in
MkEqContext { MkEqContext {
termLen = extendLen xss termLen, termLen = extendLen xss termLen,
tctx = tctx . ss, tctx = tctx . ls,
tnames = tnames . xs, tnames = tnames . xs,
qtys = qtys . qs, qtys = qtys . qs,
dassign, dnames dassign, dnames
} }
export %inline
extendTyN : CtxExtension 0 n1 n2 -> EqContext n1 -> EqContext n2
extendTyN = extendTyLetN . map (\(q, x, s) => (q, x, lamVar s))
export %inline
extendTyLetN0 : CtxExtensionLet0 0 n1 n2 -> EqContext n1 -> EqContext n2
extendTyLetN0 xss = extendTyLetN (map (Zero,) xss)
export %inline export %inline
extendTyN0 : CtxExtension0 0 n1 n2 -> EqContext n1 -> EqContext n2 extendTyN0 : CtxExtension0 0 n1 n2 -> EqContext n1 -> EqContext n2
extendTyN0 xss = extendTyN (map (Zero,) xss) extendTyN0 xss = extendTyN (map (Zero,) xss)
export %inline
extendTyLet : Qty -> BindName -> Term 0 n -> Term 0 n ->
EqContext n -> EqContext (S n)
extendTyLet q x s e = extendTyLetN [< (q, x, letVar s e)]
export %inline export %inline
extendTy : Qty -> BindName -> Term 0 n -> EqContext n -> EqContext (S n) extendTy : Qty -> BindName -> Term 0 n -> EqContext n -> EqContext (S n)
extendTy q x s = extendTyN [< (q, x, s)] extendTy q x s = extendTyN [< (q, x, s)]
@ -222,8 +287,8 @@ namespace EqContext
toTyContext : (e : EqContext n) -> TyContext e.dimLen n toTyContext : (e : EqContext n) -> TyContext e.dimLen n
toTyContext (MkEqContext {dimLen, dassign, dnames, tctx, tnames, qtys}) = toTyContext (MkEqContext {dimLen, dassign, dnames, tctx, tnames, qtys}) =
MkTyContext { MkTyContext {
dctx = fromGround dassign, dctx = fromGround dnames dassign,
tctx = map (// shift0 dimLen) tctx, tctx = map (subD $ shift0 dimLen) tctx,
dnames, tnames, qtys dnames, tnames, qtys
} }
@ -232,18 +297,44 @@ namespace EqContext
toWhnfContext (MkEqContext {tnames, tctx, _}) = toWhnfContext (MkEqContext {tnames, tctx, _}) =
MkWhnfContext {dnames = [<], tnames, tctx} MkWhnfContext {dnames = [<], tnames, tctx}
export
injElim : WhnfContext d n -> Elim 0 0 -> Elim d n
injElim ctx e =
let Val d = ctx.dimLen; Val n = ctx.termLen in
e // shift0 d // shift0 n
namespace WhnfContext namespace WhnfContext
public export %inline public export %inline
empty : WhnfContext 0 0 empty : WhnfContext 0 0
empty = MkWhnfContext [<] [<] [<] empty = MkWhnfContext [<] [<] [<]
export
extendTy' : BindName -> LocalVar d n -> WhnfContext d n -> WhnfContext d (S n)
extendTy' x var (MkWhnfContext {termLen, dnames, tnames, tctx}) =
MkWhnfContext {
dnames,
termLen = [|S termLen|],
tnames = tnames :< x,
tctx = tctx :< var
}
export %inline
extendTy : BindName -> Term d n -> WhnfContext d n -> WhnfContext d (S n)
extendTy x ty ctx = extendTy' x (lamVar ty) ctx
export %inline
extendTyLet : BindName -> (type, term : Term d n) ->
WhnfContext d n -> WhnfContext d (S n)
extendTyLet x type term ctx = extendTy' x (letVar {type, term}) ctx
export export
extendDimN : {s : Nat} -> BContext s -> WhnfContext d n -> extendDimN : {s : Nat} -> BContext s -> WhnfContext d n ->
WhnfContext (s + d) n WhnfContext (s + d) n
extendDimN ns (MkWhnfContext {dnames, tnames, tctx}) = extendDimN ns (MkWhnfContext {dnames, tnames, tctx, dimLen}) =
MkWhnfContext { MkWhnfContext {
dimLen = [|Val s + dimLen|],
dnames = dnames ++ toSnocVect' ns, dnames = dnames ++ toSnocVect' ns,
tctx = dweakT s <$> tctx, tctx = map (subD $ shift s) tctx,
tnames tnames
} }
@ -255,14 +346,25 @@ namespace WhnfContext
private private
prettyTContextElt : {opts : _} -> prettyTContextElt : {opts : _} ->
BContext d -> BContext n -> BContext d -> BContext n ->
Qty -> BindName -> Term d n -> Eff Pretty (Doc opts) Doc opts -> BindName -> LocalVar d n ->
prettyTContextElt dnames tnames q x s = Eff Pretty (Doc opts)
pure $ hsep [hcat [!(prettyQty q), !dotD, !(prettyTBind x)], !colonD, prettyTContextElt dnames tnames q x s = do
!(withPrec Outer $ prettyTerm dnames tnames s)] dot <- dotD
x <- prettyTBind x; colon <- colonD
ty <- withPrec Outer $ prettyTerm dnames tnames s.type; eq <- cstD
tm <- traverse (withPrec Outer . prettyTerm dnames tnames) s.term
d <- askAt INDENT
let qx = hcat [q, dot, x]
pure $ case tm of
Nothing =>
ifMultiline (hsep [qx, colon, ty]) (vsep [qx, indent d $ colon <++> ty])
Just tm =>
ifMultiline (hsep [qx, colon, ty, eq, tm])
(vsep [qx, indent d $ colon <++> ty, indent d $ eq <++> tm])
private private
prettyTContext' : {opts : _} -> prettyTContext' : {opts : _} ->
BContext d -> QContext n -> BContext n -> BContext d -> Context' (Doc opts) n -> BContext n ->
TContext d n -> Eff Pretty (SnocList (Doc opts)) TContext d n -> Eff Pretty (SnocList (Doc opts))
prettyTContext' _ [<] [<] [<] = pure [<] prettyTContext' _ [<] [<] [<] = pure [<]
prettyTContext' dnames (qtys :< q) (tnames :< x) (tys :< t) = prettyTContext' dnames (qtys :< q) (tnames :< x) (tys :< t) =
@ -273,8 +375,11 @@ export
prettyTContext : {opts : _} -> prettyTContext : {opts : _} ->
BContext d -> QContext n -> BContext n -> BContext d -> QContext n -> BContext n ->
TContext d n -> Eff Pretty (Doc opts) TContext d n -> Eff Pretty (Doc opts)
prettyTContext dnames qtys tnames tys = prettyTContext dnames qtys tnames tys = do
separateTight !commaD <$> prettyTContext' dnames qtys tnames tys comma <- commaD
qtys <- traverse prettyQty qtys
sepSingle . exceptLast (<+> comma) . toList <$>
prettyTContext' dnames qtys tnames tys
export export
prettyTyContext : {opts : _} -> TyContext d n -> Eff Pretty (Doc opts) prettyTyContext : {opts : _} -> TyContext d n -> Eff Pretty (Doc opts)
@ -282,9 +387,16 @@ prettyTyContext (MkTyContext dctx dnames tctx tnames qtys) =
case dctx of case dctx of
C [<] => prettyTContext dnames qtys tnames tctx C [<] => prettyTContext dnames qtys tnames tctx
_ => pure $ _ => pure $
sep [!(prettyDimEq dnames dctx) <++> !pipeD, sepSingle [!(prettyDimEq dnames dctx) <++> !pipeD,
!(prettyTContext dnames qtys tnames tctx)] !(prettyTContext dnames qtys tnames tctx)]
export export
prettyEqContext : {opts : _} -> EqContext n -> Eff Pretty (Doc opts) prettyEqContext : {opts : _} -> EqContext n -> Eff Pretty (Doc opts)
prettyEqContext ctx = prettyTyContext $ toTyContext ctx prettyEqContext ctx = prettyTyContext $ toTyContext ctx
export
prettyWhnfContext : {opts : _} -> WhnfContext d n -> Eff Pretty (Doc opts)
prettyWhnfContext ctx =
let Val n = ctx.termLen in
sepSingle . exceptLast (<+> comma) . toList <$>
prettyTContext' ctx.dnames (replicate n "_") ctx.tnames ctx.tctx

View file

@ -2,6 +2,7 @@ module Quox.Typing.Error
import Quox.Loc import Quox.Loc
import Quox.Syntax import Quox.Syntax
import Quox.Syntax.Builtin
import Quox.Typing.Context import Quox.Typing.Context
import Quox.Typing.EqMode import Quox.Typing.EqMode
import Quox.Pretty import Quox.Pretty
@ -13,6 +14,8 @@ import Derive.Prelude
%language ElabReflection %language ElabReflection
%hide TT.Name %hide TT.Name
%default total
public export public export
record NameContexts d n where record NameContexts d n where
@ -60,17 +63,19 @@ namespace WhnfContext
public export public export
data Error data Error
= ExpectedTYPE Loc (NameContexts d n) (Term d n) = ExpectedTYPE Loc (NameContexts d n) (Term d n)
| ExpectedPi Loc (NameContexts d n) (Term d n) | ExpectedPi Loc (NameContexts d n) (Term d n)
| ExpectedSig Loc (NameContexts d n) (Term d n) | ExpectedSig Loc (NameContexts d n) (Term d n)
| ExpectedEnum Loc (NameContexts d n) (Term d n) | ExpectedEnum Loc (NameContexts d n) (Term d n)
| ExpectedEq Loc (NameContexts d n) (Term d n) | ExpectedEq Loc (NameContexts d n) (Term d n)
| ExpectedNat Loc (NameContexts d n) (Term d n) | ExpectedNAT Loc (NameContexts d n) (Term d n)
| ExpectedBOX Loc (NameContexts d n) (Term d n) | ExpectedSTRING Loc (NameContexts d n) (Term d n)
| BadUniverse Loc Universe Universe | ExpectedBOX Loc (NameContexts d n) (Term d n)
| TagNotIn Loc TagVal (SortedSet TagVal) | ExpectedIOState Loc (NameContexts d n) (Term d n)
| BadCaseEnum Loc (SortedSet TagVal) (SortedSet TagVal) | BadUniverse Loc Universe Universe
| BadQtys Loc String (TyContext d n) (List (QOutput n, Term d n)) | TagNotIn Loc TagVal (SortedSet TagVal)
| BadCaseEnum Loc (SortedSet TagVal) (SortedSet TagVal)
| BadQtys Loc String (TyContext d n) (List (QOutput n, Term d n))
-- first term arg of ClashT is the type -- first term arg of ClashT is the type
| ClashT Loc (EqContext n) EqMode (Term 0 n) (Term 0 n) (Term 0 n) | ClashT Loc (EqContext n) EqMode (Term 0 n) (Term 0 n) (Term 0 n)
@ -83,6 +88,9 @@ data Error
| NotType Loc (TyContext d n) (Term d n) | NotType Loc (TyContext d n) (Term d n)
| WrongType Loc (EqContext n) (Term 0 n) (Term 0 n) | WrongType Loc (EqContext n) (Term 0 n) (Term 0 n)
| WrongBuiltinType Builtin Error
| ExpectedSingleEnum Loc (NameContexts d n) (Term d n)
| MissingEnumArm Loc TagVal (List TagVal) | MissingEnumArm Loc TagVal (List TagVal)
-- extra context -- extra context
@ -119,26 +127,30 @@ ErrorEff = Except Error
export export
Located Error where Located Error where
(ExpectedTYPE loc _ _).loc = loc (ExpectedTYPE loc _ _).loc = loc
(ExpectedPi loc _ _).loc = loc (ExpectedPi loc _ _).loc = loc
(ExpectedSig loc _ _).loc = loc (ExpectedSig loc _ _).loc = loc
(ExpectedEnum loc _ _).loc = loc (ExpectedEnum loc _ _).loc = loc
(ExpectedEq loc _ _).loc = loc (ExpectedEq loc _ _).loc = loc
(ExpectedNat loc _ _).loc = loc (ExpectedNAT loc _ _).loc = loc
(ExpectedBOX loc _ _).loc = loc (ExpectedSTRING loc _ _).loc = loc
(BadUniverse loc _ _).loc = loc (ExpectedBOX loc _ _).loc = loc
(TagNotIn loc _ _).loc = loc (ExpectedIOState loc _ _).loc = loc
(BadCaseEnum loc _ _).loc = loc (BadUniverse loc _ _).loc = loc
(BadQtys loc _ _ _).loc = loc (TagNotIn loc _ _).loc = loc
(ClashT loc _ _ _ _ _).loc = loc (BadCaseEnum loc _ _).loc = loc
(ClashTy loc _ _ _ _).loc = loc (BadQtys loc _ _ _).loc = loc
(ClashE loc _ _ _ _).loc = loc (ClashT loc _ _ _ _ _).loc = loc
(ClashU loc _ _ _).loc = loc (ClashTy loc _ _ _ _).loc = loc
(ClashQ loc _ _).loc = loc (ClashE loc _ _ _ _).loc = loc
(NotInScope loc _).loc = loc (ClashU loc _ _ _).loc = loc
(NotType loc _ _).loc = loc (ClashQ loc _ _).loc = loc
(WrongType loc _ _ _).loc = loc (NotInScope loc _).loc = loc
(MissingEnumArm loc _ _).loc = loc (NotType loc _ _).loc = loc
(WrongType loc _ _ _).loc = loc
(WrongBuiltinType _ err).loc = err.loc
(ExpectedSingleEnum loc _ _).loc = loc
(MissingEnumArm loc _ _).loc = loc
(WhileChecking _ _ _ _ err).loc = err.loc (WhileChecking _ _ _ _ err).loc = err.loc
(WhileCheckingTy _ _ _ err).loc = err.loc (WhileCheckingTy _ _ _ err).loc = err.loc
(WhileInferring _ _ _ err).loc = err.loc (WhileInferring _ _ _ err).loc = err.loc
@ -246,162 +258,186 @@ where
hangDSingle "with quantities" $ hangDSingle "with quantities" $
separateTight !commaD $ toSnocList' !(traverse prettyQty qs)] separateTight !commaD $ toSnocList' !(traverse prettyQty qs)]
export parameters {opts : LayoutOpts} (showContext : Bool)
prettyErrorNoLoc : {opts : _} -> (showContext : Bool) -> Error -> export
Eff Pretty (Doc opts) inContext' : Bool -> a -> (a -> Eff Pretty (Doc opts)) ->
prettyErrorNoLoc showContext = \case Doc opts -> Eff Pretty (Doc opts)
ExpectedTYPE _ ctx s => inContext' null ctx f doc =
hangDSingle "expected a type universe, but got" if showContext && not null then
!(prettyTerm ctx.dnames ctx.tnames s) vappend doc <$> hangDSingle "in context" !(f ctx)
else pure doc
ExpectedPi _ ctx s =>
hangDSingle "expected a function type, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedSig _ ctx s =>
hangDSingle "expected a pair type, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedEnum _ ctx s =>
hangDSingle "expected an enumeration type, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedEq _ ctx s =>
hangDSingle "expected an enumeration type, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedNat _ ctx s =>
hangDSingle
("expected the type" <++>
!(prettyTerm [<] [<] $ Nat noLoc) <+> ", but got")
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedBOX _ ctx s =>
hangDSingle "expected a box type, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
BadUniverse _ k l => pure $
sep ["the universe level" <++> !(prettyUniverse k),
"is not strictly less than" <++> !(prettyUniverse l)]
TagNotIn _ tag set =>
hangDSingle (hsep ["the tag", !(prettyTag tag), "is not contained in"])
!(prettyTerm [<] [<] $ Enum set noLoc)
BadCaseEnum _ head body => sep <$> sequence
[hangDSingle "case expression has head of type"
!(prettyTerm [<] [<] $ Enum head noLoc),
hangDSingle "but cases for"
!(prettyTerm [<] [<] $ Enum body noLoc)]
BadQtys _ what ctx arms =>
hangDSingle (text "inconsistent variable usage in \{what}") $
sep !(printCaseQtys ctx ctx.tnames arms)
ClashT _ ctx mode ty s t =>
inEContext ctx . sep =<< sequence
[hangDSingle "the term" !(prettyTerm [<] ctx.tnames s),
hangDSingle (text "is not \{prettyMode mode}")
!(prettyTerm [<] ctx.tnames t),
hangDSingle "at type" !(prettyTerm [<] ctx.tnames ty)]
ClashTy _ ctx mode a b =>
inEContext ctx . sep =<< sequence
[hangDSingle "the type" !(prettyTerm [<] ctx.tnames a),
hangDSingle (text "is not \{prettyMode mode}")
!(prettyTerm [<] ctx.tnames b)]
ClashE _ ctx mode e f =>
inEContext ctx . sep =<< sequence
[hangDSingle "the term" !(prettyElim [<] ctx.tnames e),
hangDSingle (text "is not \{prettyMode mode}")
!(prettyElim [<] ctx.tnames f)]
ClashU _ mode k l => pure $
sep ["the universe level" <++> !(prettyUniverse k),
text "is not \{prettyModeU mode}" <++> !(prettyUniverse l)]
ClashQ _ pi rh => pure $
sep ["the quantity" <++> !(prettyQty pi),
"is not equal to" <++> !(prettyQty rh)]
NotInScope _ x => pure $
hsep [!(prettyFree x), "is not in scope"]
NotType _ ctx s =>
inTContext ctx . sep =<< sequence
[hangDSingle "the term" !(prettyTerm ctx.dnames ctx.tnames s),
pure "is not a type"]
WrongType _ ctx ty s =>
inEContext ctx . sep =<< sequence
[hangDSingle "the term" !(prettyTerm [<] ctx.tnames s),
hangDSingle "cannot have type" !(prettyTerm [<] ctx.tnames ty)]
MissingEnumArm _ tag tags => pure $
sep [hsep ["the tag", !(prettyTag tag), "is not contained in"],
!(prettyTerm [<] [<] $ Enum (fromList tags) noLoc)]
WhileChecking ctx sg s a err =>
[|vappendBlank
(inTContext ctx . sep =<< sequence
[hangDSingle "while checking" !(prettyTerm ctx.dnames ctx.tnames s),
hangDSingle "has type" !(prettyTerm ctx.dnames ctx.tnames a),
hangDSingle "with quantity" !(prettyQty sg.qty)])
(prettyErrorNoLoc showContext err)|]
WhileCheckingTy ctx a k err =>
[|vappendBlank
(inTContext ctx . sep =<< sequence
[hangDSingle "while checking" !(prettyTerm ctx.dnames ctx.tnames a),
pure $ text $ isTypeInUniverse k])
(prettyErrorNoLoc showContext err)|]
WhileInferring ctx sg e err =>
[|vappendBlank
(inTContext ctx . sep =<< sequence
[hangDSingle "while inferring the type of"
!(prettyElim ctx.dnames ctx.tnames e),
hangDSingle "with quantity" !(prettyQty sg.qty)])
(prettyErrorNoLoc showContext err)|]
WhileComparingT ctx mode sg a s t err =>
[|vappendBlank
(inEContext ctx . sep =<< sequence
[hangDSingle "while checking that" !(prettyTerm [<] ctx.tnames s),
hangDSingle (text "is \{prettyMode mode}")
!(prettyTerm [<] ctx.tnames t),
hangDSingle "at type" !(prettyTerm [<] ctx.tnames a),
hangDSingle "with quantity" !(prettyQty sg.qty)])
(prettyErrorNoLoc showContext err)|]
WhileComparingE ctx mode sg e f err =>
[|vappendBlank
(inEContext ctx . sep =<< sequence
[hangDSingle "while checking that" !(prettyElim [<] ctx.tnames e),
hangDSingle (text "is \{prettyMode mode}")
!(prettyElim [<] ctx.tnames f),
hangDSingle "with quantity" !(prettyQty sg.qty)])
(prettyErrorNoLoc showContext err)|]
where
vappendBlank : Doc opts -> Doc opts -> Doc opts
vappendBlank a b = flush a `vappend` b
export %inline
inTContext : TyContext d n -> Doc opts -> Eff Pretty (Doc opts) inTContext : TyContext d n -> Doc opts -> Eff Pretty (Doc opts)
inTContext ctx doc = inTContext ctx = inContext' (null ctx) ctx prettyTyContext
if showContext && not (null ctx) then
pure $ vappend doc (sep ["in context", !(prettyTyContext ctx)])
else pure doc
export %inline
inEContext : EqContext n -> Doc opts -> Eff Pretty (Doc opts) inEContext : EqContext n -> Doc opts -> Eff Pretty (Doc opts)
inEContext ctx doc = inEContext ctx = inContext' (null ctx) ctx prettyEqContext
if showContext && not (null ctx) then
pure $ vappend doc (sep ["in context", !(prettyEqContext ctx)])
else pure doc
export export
prettyError : {opts : _} -> (showContext : Bool) -> prettyErrorNoLoc : Error -> Eff Pretty (Doc opts)
Error -> Eff Pretty (Doc opts) prettyErrorNoLoc err0 = case err0 of
prettyError showContext err = sep <$> sequence ExpectedTYPE _ ctx s =>
[prettyLoc err.loc, indentD =<< prettyErrorNoLoc showContext err] hangDSingle "expected a type universe, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedPi _ ctx s =>
hangDSingle "expected a function type, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedSig _ ctx s =>
hangDSingle "expected a pair type, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedEnum _ ctx s =>
hangDSingle "expected an enumeration type, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedEq _ ctx s =>
hangDSingle "expected an equality type, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedNAT _ ctx s =>
hangDSingle
("expected the type" <++>
!(prettyTerm [<] [<] $ NAT noLoc) <+> ", but got")
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedSTRING _ ctx s =>
hangDSingle
("expected the type" <++>
!(prettyTerm [<] [<] $ STRING noLoc) <+> ", but got")
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedBOX _ ctx s =>
hangDSingle "expected a box type, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
ExpectedIOState _ ctx s =>
hangDSingle "expected IOState, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
BadUniverse _ k l => pure $
sep ["the universe level" <++> !(prettyUniverse k),
"is not strictly less than" <++> !(prettyUniverse l)]
TagNotIn _ tag set =>
hangDSingle (hsep ["the tag", !(prettyTag tag), "is not contained in"])
!(prettyTerm [<] [<] $ Enum set noLoc)
BadCaseEnum _ head body => sep <$> sequence
[hangDSingle "case expression has head of type"
!(prettyTerm [<] [<] $ Enum head noLoc),
hangDSingle "but cases for"
!(prettyTerm [<] [<] $ Enum body noLoc)]
BadQtys _ what ctx arms =>
hangDSingle (text "inconsistent variable usage in \{what}") $
sep !(printCaseQtys ctx ctx.tnames arms)
ClashT _ ctx mode ty s t =>
inEContext ctx . sep =<< sequence
[hangDSingle "the term" !(prettyTerm [<] ctx.tnames s),
hangDSingle (text "is not \{prettyMode mode}")
!(prettyTerm [<] ctx.tnames t),
hangDSingle "at type" !(prettyTerm [<] ctx.tnames ty)]
ClashTy _ ctx mode a b =>
inEContext ctx . sep =<< sequence
[hangDSingle "the type" !(prettyTerm [<] ctx.tnames a),
hangDSingle (text "is not \{prettyMode mode}")
!(prettyTerm [<] ctx.tnames b)]
ClashE _ ctx mode e f =>
inEContext ctx . sep =<< sequence
[hangDSingle "the term" !(prettyElim [<] ctx.tnames e),
hangDSingle (text "is not \{prettyMode mode}")
!(prettyElim [<] ctx.tnames f)]
ClashU _ mode k l => pure $
sep ["the universe level" <++> !(prettyUniverse k),
text "is not \{prettyModeU mode}" <++> !(prettyUniverse l)]
ClashQ _ pi rh => pure $
sep ["the quantity" <++> !(prettyQty pi),
"is not equal to" <++> !(prettyQty rh)]
NotInScope _ x => pure $
hsep [!(prettyFree x), "is not in scope"]
NotType _ ctx s =>
inTContext ctx . sep =<< sequence
[hangDSingle "the term" !(prettyTerm ctx.dnames ctx.tnames s),
pure "is not a type"]
WrongType _ ctx ty s =>
inEContext ctx . sep =<< sequence
[hangDSingle "the term" !(prettyTerm [<] ctx.tnames s),
hangDSingle "cannot have type" !(prettyTerm [<] ctx.tnames ty)]
WrongBuiltinType b err => pure $
vappend
(sep [sep ["when checking", text $ builtinDesc b],
sep ["has type", !(builtinTypeDoc b)]])
!(prettyErrorNoLoc err)
ExpectedSingleEnum _ ctx s =>
hangDSingle "expected an enumeration type with one case, but got"
!(prettyTerm ctx.dnames ctx.tnames s)
MissingEnumArm _ tag tags => pure $
sep [hsep ["the tag", !(prettyTag tag), "is not contained in"],
!(prettyTerm [<] [<] $ Enum (fromList tags) noLoc)]
WhileChecking ctx sg s a err =>
[|vappendBlank
(inTContext ctx . sep =<< sequence
[hangDSingle "while checking" !(prettyTerm ctx.dnames ctx.tnames s),
hangDSingle "has type" !(prettyTerm ctx.dnames ctx.tnames a),
hangDSingle "with quantity" !(prettyQty sg.qty)])
(prettyErrorNoLoc err)|]
WhileCheckingTy ctx a k err =>
[|vappendBlank
(inTContext ctx . sep =<< sequence
[hangDSingle "while checking" !(prettyTerm ctx.dnames ctx.tnames a),
pure $ text $ isTypeInUniverse k])
(prettyErrorNoLoc err)|]
WhileInferring ctx sg e err =>
[|vappendBlank
(inTContext ctx . sep =<< sequence
[hangDSingle "while inferring the type of"
!(prettyElim ctx.dnames ctx.tnames e),
hangDSingle "with quantity" !(prettyQty sg.qty)])
(prettyErrorNoLoc err)|]
WhileComparingT ctx mode sg a s t err =>
[|vappendBlank
(inEContext ctx . sep =<< sequence
[hangDSingle "while checking that" !(prettyTerm [<] ctx.tnames s),
hangDSingle (text "is \{prettyMode mode}")
!(prettyTerm [<] ctx.tnames t),
hangDSingle "at type" !(prettyTerm [<] ctx.tnames a),
hangDSingle "with quantity" !(prettyQty sg.qty)])
(prettyErrorNoLoc err)|]
WhileComparingE ctx mode sg e f err =>
[|vappendBlank
(inEContext ctx . sep =<< sequence
[hangDSingle "while checking that" !(prettyElim [<] ctx.tnames e),
hangDSingle (text "is \{prettyMode mode}")
!(prettyElim [<] ctx.tnames f),
hangDSingle "with quantity" !(prettyQty sg.qty)])
(prettyErrorNoLoc err)|]
where
vappendBlank : Doc opts -> Doc opts -> Doc opts
vappendBlank a b = flush a `vappend` b
export
prettyError : Error -> Eff Pretty (Doc opts)
prettyError err = hangDSingle
!(prettyLoc err.loc)
!(indentD =<< prettyErrorNoLoc err)

568
lib/Quox/Untyped/Erase.idr Normal file
View file

@ -0,0 +1,568 @@
module Quox.Untyped.Erase
import Quox.Definition as Q
import Quox.Pretty
import Quox.Syntax.Term.Base as Q
import Quox.Syntax.Term.Subst
import Quox.Typing
import Quox.Untyped.Syntax as U
import Quox.Whnf
import Quox.EffExtra
import Data.List1
import Data.Singleton
import Data.SnocVect
import Language.Reflection
%default total
%language ElabReflection
%hide TT.Name
%hide AppView.(.head)
public export
data IsErased = Erased | Kept
public export
isErased : Qty -> IsErased
isErased Zero = Erased
isErased One = Kept
isErased Any = Kept
public export
ErasureContext : Nat -> Nat -> Type
ErasureContext = TyContext
public export
TypeError : Type
TypeError = Typing.Error.Error
%hide Typing.Error.Error
public export
data Error =
CompileTimeOnly (ErasureContext d n) (Q.Term d n)
| WrapTypeError TypeError
| Postulate Loc Name
| WhileErasing Name Q.Definition Error
| MainIsErased Loc Name
%name Error err
private %inline
notInScope : Loc -> Name -> Error
notInScope = WrapTypeError .: NotInScope
export
Located Error where
(CompileTimeOnly _ s).loc = s.loc
(WrapTypeError err).loc = err.loc
(Postulate loc _).loc = loc
(WhileErasing _ def e).loc = e.loc `or` def.loc
(MainIsErased loc _).loc = loc
parameters {opts : LayoutOpts} (showContext : Bool)
export
prettyErrorNoLoc : Error -> Eff Pretty (Doc opts)
prettyErrorNoLoc (CompileTimeOnly ctx s) =
inTContext showContext ctx $
sep ["the term", !(prettyTerm ctx.dnames ctx.tnames s),
"only exists at compile time"]
prettyErrorNoLoc (WrapTypeError err) =
prettyErrorNoLoc showContext err
prettyErrorNoLoc (Postulate _ x) =
pure $ sep [!(prettyFree x), "is a postulate with no definition"]
prettyErrorNoLoc (WhileErasing x def err) = pure $
vsep [hsep ["while erasing the definition", !(prettyFree x)],
!(prettyErrorNoLoc err)]
prettyErrorNoLoc (MainIsErased _ x) =
pure $ hsep [!(prettyFree x), "is marked #[main] but is erased"]
export
prettyError : Error -> Eff Pretty (Doc opts)
prettyError err = sep <$> sequence
[prettyLoc err.loc, indentD =<< prettyErrorNoLoc err]
public export
Erase : List (Type -> Type)
Erase = [Except Error, NameGen, Log]
export
liftWhnf : Eff Whnf a -> Eff Erase a
liftWhnf act = lift $ wrapErr WrapTypeError act
export covering
computeElimType : Q.Definitions -> ErasureContext d n -> SQty ->
Elim d n -> Eff Erase (Term d n)
computeElimType defs ctx sg e = do
let ctx = toWhnfContext ctx
liftWhnf $ do
Element e _ <- whnf defs ctx sg e
computeElimType defs ctx sg e
private %macro
wrapExpect : TTImp ->
Elab (Q.Definitions -> TyContext d n -> Loc ->
Term d n -> Eff Erase a)
wrapExpect f_ = do
f <- check `(\x => ~(f_) x)
pure $ \defs, ctx, loc, s => liftWhnf $ f defs ctx SZero loc s
public export
record EraseElimResult d n where
constructor EraRes
type : Lazy (Q.Term d n)
term : U.Term n
export covering
eraseTerm' : (defs : Q.Definitions) -> (ctx : ErasureContext d n) ->
(ty, tm : Q.Term d n) ->
(0 _ : NotRedex defs (toWhnfContext ctx) SZero ty) =>
Eff Erase (U.Term n)
-- "Ψ | Γ | Σ ⊢ s ⤋ s' ⇐ A" for `s' <- eraseTerm (Ψ,Γ,Σ) A s`
--
-- in the below comments, Ψ, Γ, Σ are implicit and
-- only their extensions are written
export covering
eraseTerm : Q.Definitions -> ErasureContext d n ->
(ty, tm : Q.Term d n) -> Eff Erase (U.Term n)
eraseTerm defs ctx ty tm = do
Element ty _ <- liftWhnf $ Interface.whnf defs (toWhnfContext ctx) SZero ty
eraseTerm' defs ctx ty tm
-- "Ψ | Γ | Σ ⊢ e ⤋ e' ⇒ A" for `EraRes A e' <- eraseElim (Ψ,Γ,Σ) e`
export covering
eraseElim : Q.Definitions -> ErasureContext d n -> (tm : Q.Elim d n) ->
Eff Erase (EraseElimResult d n)
eraseTerm' defs ctx _ s@(TYPE {}) =
throw $ CompileTimeOnly ctx s
eraseTerm' defs ctx _ s@(IOState {}) =
throw $ CompileTimeOnly ctx s
eraseTerm' defs ctx _ s@(Pi {}) =
throw $ CompileTimeOnly ctx s
-- x : A | 0.x ⊢ s ⤋ s' ⇐ B
-- -------------------------------------
-- (λ x ⇒ s) ⤋ s'[⌷/x] ⇐ 0.(x : A) → B
--
-- x : A | π.x ⊢ s ⤋ s' ⇐ B π ≠ 0
-- ----------------------------------------
-- (λ x ⇒ s) ⤋ (λ x ⇒ s') ⇐ π.(x : A) → B
eraseTerm' defs ctx ty (Lam body loc) = do
let x = body.name
(qty, arg, res) <- wrapExpect `(expectPi) defs ctx loc ty
body <- eraseTerm defs (extendTy qty x arg ctx) res.term body.term
pure $ case isErased qty of
Kept => U.Lam x body loc
Erased => sub1 (Erased loc) body
eraseTerm' defs ctx _ s@(Sig {}) =
throw $ CompileTimeOnly ctx s
-- s ⤋ s' ⇐ A t ⤋ t' ⇐ B[s/x]
-- ---------------------------------
-- (s, t) ⤋ (s', t') ⇐ (x : A) × B
eraseTerm' defs ctx ty (Pair fst snd loc) = do
(a, b) <- wrapExpect `(expectSig) defs ctx loc ty
let b = sub1 b (Ann fst a a.loc)
fst <- eraseTerm defs ctx a fst
snd <- eraseTerm defs ctx b snd
pure $ Pair fst snd loc
eraseTerm' defs ctx _ s@(Enum {}) =
throw $ CompileTimeOnly ctx s
-- '𝐚 ⤋ '𝐚 ⇐ {⋯}
eraseTerm' defs ctx _ (Tag tag loc) =
pure $ Tag tag loc
eraseTerm' defs ctx ty s@(Eq {}) =
throw $ CompileTimeOnly ctx s
-- 𝑖 ⊢ s ⤋ s' ⇐ A
-- ---------------------------------
-- (δ 𝑖 ⇒ s) ⤋ s' ⇐ Eq (𝑖 ⇒ A) l r
eraseTerm' defs ctx ty (DLam body loc) = do
a <- fst <$> wrapExpect `(expectEq) defs ctx loc ty
eraseTerm defs (extendDim body.name ctx) a.term body.term
eraseTerm' defs ctx _ s@(NAT {}) =
throw $ CompileTimeOnly ctx s
-- n ⤋ n ⇐
eraseTerm' _ _ _ (Nat n loc) =
pure $ Nat n loc
-- s ⤋ s' ⇐
-- -----------------------
-- succ s ⤋ succ s' ⇐
eraseTerm' defs ctx ty (Succ p loc) = do
p <- eraseTerm defs ctx ty p
pure $ Succ p loc
eraseTerm' defs ctx ty s@(STRING {}) =
throw $ CompileTimeOnly ctx s
-- s ⤋ s ⇐ String
eraseTerm' _ _ _ (Str s loc) =
pure $ Str s loc
eraseTerm' defs ctx ty s@(BOX {}) =
throw $ CompileTimeOnly ctx s
-- [s] ⤋ ⌷ ⇐ [0.A]
--
-- π ≠ 0 s ⤋ s' ⇐ A
-- --------------------
-- [s] ⤋ s' ⇐ [π.A]
eraseTerm' defs ctx ty (Box val loc) = do
(qty, a) <- wrapExpect `(expectBOX) defs ctx loc ty
case isErased qty of
Erased => pure $ Erased loc
Kept => eraseTerm defs ctx a val
-- s ⤋ s' ⇐ A
-- ---------------------------------
-- let0 x = e in s ⤋ s'[⌷/x] ⇐ A
--
-- e ⤋ e' ⇒ E π ≠ 0
-- x : E ≔ e ⊢ s ⤋ s' ⇐ A
-- -------------------------------------
-- letπ x = e in s ⤋ let x = e' in s'
eraseTerm' defs ctx ty (Let pi e s loc) = do
let x = s.name
case isErased pi of
Erased => do
ety <- computeElimType defs ctx SZero e
s' <- eraseTerm defs (extendTyLet pi x ety (E e) ctx) (weakT 1 ty) s.term
pure $ sub1 (Erased e.loc) s'
Kept => do
EraRes ety e' <- eraseElim defs ctx e
s' <- eraseTerm defs (extendTyLet pi x ety (E e) ctx) (weakT 1 ty) s.term
pure $ Let True x e' s' loc
-- e ⤋ e' ⇒ B
-- ------------
-- e ⤋ e' ⇐ A
eraseTerm' defs ctx ty (E e) =
term <$> eraseElim defs ctx e
eraseTerm' defs ctx ty (CloT (Sub term th)) =
eraseTerm defs ctx ty $ pushSubstsWith' id th term
eraseTerm' defs ctx ty (DCloT (Sub term th)) =
eraseTerm defs ctx ty $ pushSubstsWith' th id term
-- defω x : A = s
-- ----------------
-- x ⤋ x ⇒ A
eraseElim defs ctx e@(F x u loc) = do
let Just def = lookup x defs
| Nothing => throw $ notInScope loc x
case isErased def.qty.qty of
Erased => throw $ CompileTimeOnly ctx $ E e
Kept => pure $ EraRes (def.typeWith ctx.dimLen ctx.termLen) $ F x loc
-- π.x ∈ Σ π ≠ 0
-- -----------------
-- x ⤋ x ⇒ A
eraseElim defs ctx e@(B i loc) = do
case isErased $ ctx.qtys !!! i of
Erased => throw $ CompileTimeOnly ctx $ E e
Kept => pure $ EraRes (ctx.tctx !! i).type $ B i loc
-- f ⤋ f' ⇒ π.(x : A) → B s ⤋ s' ⇒ A π ≠ 0
-- ---------------------------------------------
-- f s ⤋ f' s' ⇒ B[s/x]
--
-- f ⤋ f' ⇒ 0.(x : A) → B
-- -------------------------
-- f s ⤋ f' ⇒ B[s/x]
eraseElim defs ctx (App fun arg loc) = do
efun <- eraseElim defs ctx fun
(qty, targ, tres) <- wrapExpect `(expectPi) defs ctx loc efun.type
let ty = sub1 tres (Ann arg targ arg.loc)
case isErased qty of
Erased => pure $ EraRes ty efun.term
Kept => do arg <- eraseTerm defs ctx targ arg
pure $ EraRes ty $ App efun.term arg loc
-- e ⇒ (x : A) × B
-- x : A, y : B | ρ.x, ρ.y ⊢ s ⤋ s' ⇐ R[((x,y) ∷ (x : A) × B)/z]
-- -------------------------------------------------------------------
-- (case0 e return z ⇒ R of {(x, y) ⇒ s}) ⤋ s'[⌷/x, ⌷/y] ⇒ R[e/z]
--
-- e ⤋ e' ⇒ (x : A) × B ρ ≠ 0
-- x : A, y : B | ρ.x, ρ.y ⊢ s ⤋ s' ⇐ R[((x,y) ∷ (x : A) × B)/z]
-- ----------------------------------------------------------------------------
-- (caseρ e return z ⇒ R of {(x, y) ⇒ s}) ⤋
-- ⤋
-- let xy = e' in let x = fst xy in let y = snd xy in s' ⇒ R[e/z]
eraseElim defs ctx (CasePair qty pair ret body loc) = do
let [< x, y] = body.names
case isErased qty of
Kept => do
EraRes ety eterm <- eraseElim defs ctx pair
let ty = sub1 (ret // shift 2) $
Ann (Pair (BVT 0 loc) (BVT 1 loc) loc) (weakT 2 ety) loc
(tfst, tsnd) <- wrapExpect `(expectSig) defs ctx loc ety
let ctx' = extendTyN [< (qty, x, tfst), (qty, y, tsnd.term)] ctx
body' <- eraseTerm defs ctx' ty body.term
p <- mnb "p" loc
pure $ EraRes (sub1 ret pair) $
Let False p eterm
(Let False x (Fst (B VZ loc) loc)
(Let False y (Snd (B (VS VZ) loc) loc)
(body' // (B VZ loc ::: B (VS VZ) loc ::: shift 3))
loc) loc) loc
Erased => do
ety <- computeElimType defs ctx SOne pair
let ty = sub1 (ret // shift 2) $
Ann (Pair (BVT 0 loc) (BVT 1 loc) loc) (weakT 2 ety) loc
(tfst, tsnd) <- wrapExpect `(expectSig) defs ctx loc ety
let ctx' = extendTyN0 [< (x, tfst), (y, tsnd.term)] ctx
body' <- eraseTerm defs ctx' ty body.term
pure $ EraRes (sub1 ret pair) $ subN [< Erased loc, Erased loc] body'
-- e ⤋ e' ⇒ (x : A) × B
-- ----------------------
-- fst e ⤋ fst e' ⇒ A
eraseElim defs ctx (Fst pair loc) = do
epair <- eraseElim defs ctx pair
a <- fst <$> wrapExpect `(expectSig) defs ctx loc epair.type
pure $ EraRes a $ Fst epair.term loc
-- e ⤋ e' ⇒ (x : A) × B
-- -----------------------------
-- snd e ⤋ snd e' ⇒ B[fst e/x]
eraseElim defs ctx (Snd pair loc) = do
epair <- eraseElim defs ctx pair
b <- snd <$> wrapExpect `(expectSig) defs ctx loc epair.type
pure $ EraRes (sub1 b (Fst pair loc)) $ Snd epair.term loc
-- caseρ e return z ⇒ R of {} ⤋ absurd ⇒ R[e/z]
--
-- s ⤋ s' ⇐ R[𝐚∷{𝐚}/z]
-- -----------------------------------------------
-- case0 e return z ⇒ R of {𝐚 ⇒ s} ⤋ s' ⇒ R[e/z]
--
-- e ⤋ e' ⇒ A sᵢ ⤋ s'ᵢ ⇐ R[𝐚ᵢ/z] ρ ≠ 0 i ≠ 0
-- -------------------------------------------------------------------
-- caseρ e return z ⇒ R of {𝐚ᵢ ⇒ sᵢ} ⤋ case e of {𝐚ᵢ ⇒ s'ᵢ} ⇒ R[e/z]
eraseElim defs ctx e@(CaseEnum qty tag ret arms loc) = do
let ty = sub1 ret tag
case isErased qty of
Erased => case SortedMap.toList arms of
[] => pure $ EraRes ty $ Absurd loc
[(t, rhs)] => do
let ty' = sub1 ret (Ann (Tag t loc) (enum [t] loc) loc)
rhs' <- eraseTerm defs ctx ty' rhs
pure $ EraRes ty rhs'
_ => throw $ CompileTimeOnly ctx $ E e
Kept => case List1.fromList $ SortedMap.toList arms of
Nothing => pure $ EraRes ty $ Absurd loc
Just arms => do
etag <- eraseElim defs ctx tag
arms <- for arms $ \(t, rhs) => do
let ty' = sub1 ret (Ann (Tag t loc) etag.type loc)
rhs' <- eraseTerm defs ctx ty' rhs
pure (t, rhs')
pure $ EraRes ty $ CaseEnum etag.term arms loc
-- n ⤋ n' ⇒ z ⤋ z' ⇐ R[zero∷/z] ς ≠ 0
-- m : , ih : R[m/z] | ρ.m, ς.ih ⊢ s ⤋ s' ⇐ R[(succ m)∷ℕ/z]
-- -----------------------------------------------------------
-- caseρ n return z ⇒ R of {0 ⇒ z; succ m, ς.ih ⇒ s}
-- ⤋
-- case n' of {0 ⇒ z'; succ m, ih ⇒ s'} ⇒ R[n/z]
--
-- n ⤋ n' ⇒ z ⤋ z' ⇐ R[zero∷/z]
-- m : , ih : R[m/z] | ρ.m, 0.ih ⊢ s ⤋ s' ⇐ R[(succ m)∷ℕ/z]
-- -----------------------------------------------------------
-- caseρ n return z ⇒ R of {0 ⇒ z; succ m, 0.ih ⇒ s}
-- ⤋
-- case n' of {0 ⇒ z'; succ m ⇒ s'[⌷/ih]} ⇒ R[n/z]
eraseElim defs ctx (CaseNat qty qtyIH nat ret zero succ loc) = do
let ty = sub1 ret nat
enat <- eraseElim defs ctx nat
zero <- eraseTerm defs ctx (sub1 ret (Ann (Zero loc) (NAT loc) loc)) zero
let [< p, ih] = succ.names
succ' <- eraseTerm defs
(extendTyN [< (qty, p, NAT loc),
(qtyIH, ih, sub1 (ret // shift 1) (BV 0 loc))] ctx)
(sub1 (ret // shift 2) (Ann (Succ (BVT 1 loc) loc) (NAT loc) loc))
succ.term
let succ = case isErased qtyIH of
Kept => NSRec p ih succ'
Erased => NSNonrec p (sub1 (Erased loc) succ')
pure $ EraRes ty $ CaseNat enat.term zero succ loc
-- b ⤋ b' ⇒ [π.A] πρ ≠ 0 x : A | πρ.x ⊢ s ⤋ s' ⇐ R[[x]∷[π.A]/z]
-- ------------------------------------------------------------------
-- caseρ b return z ⇒ R of {[x] ⇒ s} ⤋ let x = b' in s' ⇒ R[b/z]
--
-- b ⇒ [π.A] x : A | 0.x ⊢ s ⤋ s' ⇐ R[[x]∷[0.A]/z] πρ = 0
-- -------------------------------------------------------------
-- caseρ b return z ⇒ R of {[x] ⇒ s} ⤋ s'[⌷/x] ⇒ R[b/z]
eraseElim defs ctx (CaseBox qty box ret body loc) = do
tbox <- computeElimType defs ctx SOne box
(pi, tinner) <- wrapExpect `(expectBOX) defs ctx loc tbox
let ctx' = extendTy (pi * qty) body.name tinner ctx
bty = sub1 (ret // shift 1) $
Ann (Box (BVT 0 loc) loc) (weakT 1 tbox) loc
case isErased $ qty * pi of
Kept => do
ebox <- eraseElim defs ctx box
ebody <- eraseTerm defs ctx' bty body.term
pure $ EraRes (sub1 ret box) $ Let False body.name ebox.term ebody loc
Erased => do
body' <- eraseTerm defs ctx' bty body.term
pure $ EraRes (sub1 ret box) $ body' // one (Erased loc)
-- f ⤋ f' ⇒ Eq (𝑖 ⇒ A) l r
-- ------------------------------
-- f @r ⤋ f' ⇒ Ar/𝑖
eraseElim defs ctx (DApp fun arg loc) = do
efun <- eraseElim defs ctx fun
a <- fst <$> wrapExpect `(expectEq) defs ctx loc efun.type
pure $ EraRes (dsub1 a arg) efun.term
-- s ⤋ s' ⇐ A
-- ----------------
-- s ∷ A ⤋ s' ⇒ A
eraseElim defs ctx (Ann tm ty loc) =
EraRes ty <$> eraseTerm defs ctx ty tm
-- s ⤋ s' ⇐ Ap/𝑖
-- -----------------------------------
-- coe (𝑖 ⇒ A) @p @q s ⤋ s' ⇒ Aq/𝑖
eraseElim defs ctx (Coe ty p q val loc) = do
val <- eraseTerm defs ctx (dsub1 ty p) val
pure $ EraRes (dsub1 ty q) val
-- s ⤋ s' ⇐ A
-- --------------------------------
-- comp A @p @q s @r {⋯} ⤋ s' ⇒ A
eraseElim defs ctx (Comp ty p q val r zero one loc) =
EraRes ty <$> eraseTerm defs ctx ty val
eraseElim defs ctx t@(TypeCase ty ret arms def loc) =
throw $ CompileTimeOnly ctx $ E t
eraseElim defs ctx (CloE (Sub term th)) =
eraseElim defs ctx $ pushSubstsWith' id th term
eraseElim defs ctx (DCloE (Sub term th)) =
eraseElim defs ctx $ pushSubstsWith' th id term
export
uses : Var n -> Term n -> Nat
uses i (F {}) = 0
uses i (B j _) = if i == j then 1 else 0
uses i (Lam x body _) = uses (VS i) body
uses i (App fun arg _) = uses i fun + uses i arg
uses i (Pair fst snd _) = uses i fst + uses i snd
uses i (Fst pair _) = uses i pair
uses i (Snd pair _) = uses i pair
uses i (Tag tag _) = 0
uses i (CaseEnum tag cases _) =
uses i tag + foldl max 0 (map (assert_total uses i . snd) cases)
uses i (Absurd {}) = 0
uses i (Nat {}) = 0
uses i (Succ nat _) = uses i nat
uses i (CaseNat nat zer suc _) = uses i nat + max (uses i zer) (uses' suc)
where uses' : CaseNatSuc n -> Nat
uses' (NSRec _ _ s) = uses (VS (VS i)) s
uses' (NSNonrec _ s) = uses (VS i) s
uses i (Str {}) = 0
uses i (Let _ x rhs body _) = uses i rhs + uses (VS i) body
uses i (Erased {}) = 0
export
inlineable : U.Term n -> Bool
inlineable (F {}) = True
inlineable (B {}) = True
inlineable (Tag {}) = True
inlineable (Nat {}) = True
inlineable (Str {}) = True
inlineable (Absurd {}) = True
inlineable (Erased {}) = True
inlineable _ = False
export
droppable : U.Term n -> Bool
droppable (F {}) = True
droppable (B {}) = True
droppable (Fst e _) = droppable e
droppable (Snd e _) = droppable e
droppable (Tag {}) = True
droppable (Nat {}) = True
droppable (Str {}) = True
droppable (Absurd {}) = True
droppable (Erased {}) = True
droppable _ = False
export
trimLets : U.Term n -> U.Term n
trimLets (F x loc) = F x loc
trimLets (B i loc) = B i loc
trimLets (Lam x body loc) = Lam x (trimLets body) loc
trimLets (App fun arg loc) = App (trimLets fun) (trimLets arg) loc
trimLets (Pair fst snd loc) = Pair (trimLets fst) (trimLets snd) loc
trimLets (Fst pair loc) = Fst (trimLets pair) loc
trimLets (Snd pair loc) = Snd (trimLets pair) loc
trimLets (Tag tag loc) = Tag tag loc
trimLets (CaseEnum tag cases loc) =
let tag = trimLets tag
cases = map (map $ \c => trimLets $ assert_smaller cases c) cases in
if droppable tag && length cases == 1
then snd cases.head
else CaseEnum tag cases loc
trimLets (Absurd loc) = Absurd loc
trimLets (Nat n loc) = Nat n loc
trimLets (Succ nat loc) = Succ (trimLets nat) loc
trimLets (CaseNat nat zer suc loc) =
CaseNat (trimLets nat) (trimLets zer) (trimLets' suc) loc
where trimLets' : CaseNatSuc n -> CaseNatSuc n
trimLets' (NSRec x ih s) = NSRec x ih $ trimLets s
trimLets' (NSNonrec x s) = NSNonrec x $ trimLets s
trimLets (Str s loc) = Str s loc
trimLets (Let True x rhs body loc) =
Let True x (trimLets rhs) (trimLets body) loc
trimLets (Let False x rhs body loc) =
let rhs' = trimLets rhs
body' = trimLets body
uses = uses VZ body in
if inlineable rhs' || uses == 1 || (droppable rhs' && uses == 0)
then sub1 rhs' body'
else Let False x rhs' body' loc
trimLets (Erased loc) = Erased loc
export covering
eraseDef : Q.Definitions -> Name -> Q.Definition -> Eff Erase U.Definition
eraseDef defs name def@(MkDef qty type body scheme isMain loc) =
wrapErr (WhileErasing name def) $
case isErased qty.qty of
Erased => do
when isMain $ throw $ MainIsErased loc name
pure ErasedDef
Kept =>
case scheme of
Just str => pure $ SchemeDef isMain str
Nothing => case body of
Postulate => throw $ Postulate loc name
Concrete body => KeptDef isMain . trimLets <$>
eraseTerm defs empty type body

378
lib/Quox/Untyped/Scheme.idr Normal file
View file

@ -0,0 +1,378 @@
module Quox.Untyped.Scheme
import Quox.Name
import Quox.Context
import Quox.Untyped.Syntax
import Quox.Pretty
import Quox.EffExtra
import Quox.CharExtra
import Quox.NatExtra
import Data.DPair
import Data.List1
import Data.String
import Data.SortedSet
import Data.Vect
import Derive.Prelude
%default total
%language ElabReflection
%hide TT.Name
export
isSchemeInitial : Char -> Bool
isSchemeInitial c =
let gc = genCat c in
isLetter gc || isSymbol gc && c /= '|' ||
gc == Number Letter ||
gc == Number Other ||
gc == Mark NonSpacing ||
gc == Punctuation Dash ||
gc == Punctuation Connector ||
gc == Punctuation Other && c /= '\'' && c /= '\\' ||
gc == Other PrivateUse ||
(c `elem` unpack "!$%&*/:<=>?~_^")
export
isSchemeSubsequent : Char -> Bool
isSchemeSubsequent c =
let gc = genCat c in
isSchemeInitial c ||
isNumber gc ||
isMark gc ||
(c `elem` unpack ".+-@")
export
isSchemeId : String -> Bool
isSchemeId str =
str == "1+" || str == "1-" ||
case unpack str of
[] => False
c :: cs => isSchemeInitial c && all isSchemeSubsequent cs
export
escId : String -> String
escId str =
let str' = concatMap doEsc $ unpack str in
if isSchemeId str' then str' else "|\{str}|"
where
doEsc : Char -> String
doEsc '\\' = "\\\\"
doEsc '|' = "\\|"
doEsc '\'' = "^"
doEsc c = singleton c
public export
data Id = I String Nat
%runElab derive "Id" [Eq, Ord]
export
prettyId' : {opts : LayoutOpts} -> Id -> Doc opts
prettyId' (I str 0) = text $ escId str
prettyId' (I str k) = text $ escId "\{str}:\{show k}"
export
prettyId : {opts : LayoutOpts} -> Id -> Eff Pretty (Doc opts)
prettyId x = hl TVar $ prettyId' x
public export
data StateTag = AVOID | MAIN
public export
Scheme : List (Type -> Type)
Scheme = [StateL AVOID (SortedSet Id), StateL MAIN (List Id)]
-- names to avoid, and functions with #[main] (should only be one)
public export
data Sexp =
V Id
| L (List Sexp)
| Q Sexp
| N Nat
| S String
| Lambda (List Id) Sexp
| LambdaC (List Id) Sexp -- curried lambda
| Let Id Sexp Sexp
| Case Sexp (List1 (List Sexp, Sexp))
| Define Id Sexp
| Literal String
export
FromString Sexp where fromString s = V $ I s 0
private
makeIdBase : Mods -> String -> String
makeIdBase mods str = joinBy "." $ toList $ mods :< str
export
makeId : Name -> Id
makeId (MkName mods (UN str)) = I (makeIdBase mods str) 0
makeId (MkName mods (MN str k)) = I (makeIdBase mods str) 0
makeId (MkName mods Unused) = I (makeIdBase mods "_") 0
export
makeIdB : BindName -> Id
makeIdB (BN name _) = makeId $ MkName [<] name
private
bump : Id -> Id
bump (I x i) = I x (S i)
export covering
getFresh : SortedSet Id -> Id -> Id
getFresh used x =
if contains x used then getFresh used (bump x) else x
export covering
freshIn : Id -> (Id -> Eff Scheme a) -> Eff Scheme a
freshIn x k =
let x = getFresh !(getAt AVOID) x in
localAt AVOID (insert x) $ k x
export covering
freshInB : BindName -> (Id -> Eff Scheme a) -> Eff Scheme a
freshInB x = freshIn (makeIdB x)
export covering
freshInBT : Telescope' BindName m n ->
(Telescope' Id m n -> Eff Scheme a) ->
Eff Scheme a
freshInBT xs act = do
let (xs', used') = go (map makeIdB xs) !(getAt AVOID)
localAt_ AVOID used' $ act xs'
where
go : forall n. Telescope' Id m n ->
SortedSet Id -> (Telescope' Id m n, SortedSet Id)
go [<] used = ([<], used)
go (xs :< x) used =
let x = getFresh used x
(xs, used) = go xs (insert x used)
in
(xs :< x, used)
export covering
freshInBC : Context' BindName n -> (Context' Id n -> Eff Scheme a) ->
Eff Scheme a
freshInBC = freshInBT
export covering
toScheme : Context' Id n -> Term n -> Eff Scheme Sexp
toScheme xs (F x _) = pure $ V $ makeId x
toScheme xs (B i _) = pure $ V $ xs !!! i
toScheme xs (Lam x body _) =
let Evidence n' (ys, body) = splitLam [< x] body in
freshInBT ys $ \ys => do
pure $ LambdaC (toList' ys) !(toScheme (xs . ys) body)
toScheme xs (App fun arg _) = do
let (fun, args) = splitApp fun
fun <- toScheme xs fun
args <- traverse (toScheme xs) args
arg <- toScheme xs arg
pure $ if null args
then L [fun, arg]
else L $ "%" :: fun :: toList (args :< arg)
toScheme xs (Pair fst snd _) =
pure $ L ["cons", !(toScheme xs fst), !(toScheme xs snd)]
toScheme xs (Fst pair _) =
pure $ L ["car", !(toScheme xs pair)]
toScheme xs (Snd pair _) =
pure $ L ["cdr", !(toScheme xs pair)]
toScheme xs (Tag tag _) =
pure $ Q $ fromString tag
toScheme xs (CaseEnum tag cases _) =
Case <$> toScheme xs tag
<*> for cases (\(t, rhs) => ([fromString t],) <$> toScheme xs rhs)
toScheme xs (Absurd _) =
pure $ Q "absurd"
toScheme xs (Nat n _) =
pure $ N n
toScheme xs (Succ nat _) =
pure $ L ["+", !(toScheme xs nat), N 1]
toScheme xs (CaseNat nat zer (NSRec p ih suc) _) =
freshInBC [< p, ih] $ \[< p, ih] =>
pure $
L ["case-nat-rec",
Lambda [] !(toScheme xs zer),
Lambda [p, ih] !(toScheme (xs :< p :< ih) suc),
!(toScheme xs nat)]
toScheme xs (Str s _) = pure $ S s
toScheme xs (CaseNat nat zer (NSNonrec p suc) _) =
freshInB p $ \p =>
pure $
L ["case-nat-nonrec",
Lambda [] !(toScheme xs zer),
Lambda [p] !(toScheme (xs :< p) suc),
!(toScheme xs nat)]
toScheme xs (Let _ x rhs body _) =
freshInB x $ \x =>
pure $ Let x !(toScheme xs rhs) !(toScheme (xs :< x) body)
toScheme xs (Erased _) =
pure $ Q "erased"
export
prelude : String
prelude = """
#!r6rs
(import (rnrs))
; curried lambda
(define-syntax lambda%
(syntax-rules ()
[(_ (x . xs) . body) (lambda (x) (lambda% xs . body))]
[(_ () . body) (begin . body)]))
; curried application
(define-syntax %
(syntax-rules ()
[(_ e0 e1 . es) (% (e0 e1) . es)]
[(_ e) e]))
; curried function definition
(define-syntax define%
(syntax-rules ()
[(_ (f . xs) . body) (define f (lambda% xs . body))]
[(_ f . body) (define f . body)]))
(define-syntax builtin-io
(syntax-rules ()
[(_ . body) (lambda (s) (cons (begin . body) s))]))
(define (case-nat-rec z s n)
(do [(i 0 (+ i 1)) (acc (z) (s i acc))]
[(= i n) acc]))
(define (case-nat-nonrec z s n)
(if (= n 0) (z) (s (- n 1))))
(define (run-main f) (f 'io-state))
"""
export
escape : String -> String
escape = foldMap esc1 . unpack where
esc1 : Char -> String
esc1 c =
if c == '\\' || c == '"' then
"\\" ++ singleton c
else if c < ' ' || c > '~' then
"\\x" ++ showHex (ord c) ++ ";"
else singleton c
export covering
defToScheme : Name -> Definition -> Eff Scheme (Maybe Sexp)
defToScheme x ErasedDef = pure Nothing
defToScheme x (KeptDef isMain def) = do
let x = makeId x
when isMain $ modifyAt MAIN (x ::)
modifyAt AVOID $ insert x
pure $ Just $ Define x !(toScheme [<] def)
defToScheme x (SchemeDef isMain str) = do
let x = makeId x
when isMain $ modifyAt MAIN (x ::)
modifyAt AVOID $ insert x
pure $ Just $ Define x $ Literal str
orIndent : {opts : LayoutOpts} -> Doc opts -> Doc opts -> Eff Pretty (Doc opts)
orIndent a b = do
one <- parens $ a <++> b
two <- parens $ a `vappend` indent 2 b
pure $ ifMultiline one two
export covering
prettySexp : {opts : LayoutOpts} -> Sexp -> Eff Pretty (Doc opts)
private covering
prettyLambda : {opts : LayoutOpts} ->
String -> List Id -> Sexp -> Eff Pretty (Doc opts)
prettyLambda lam xs e =
orIndent
(hsep [!(hl Syntax $ text lam), !(prettySexp $ L $ map V xs)])
!(prettySexp e)
private covering
prettyBind : {opts : LayoutOpts} -> (Id, Sexp) -> Eff Pretty (Doc opts)
prettyBind (x, e) = parens $ sep [!(prettyId x), !(prettySexp e)]
private covering
prettyLet : {opts : LayoutOpts} ->
SnocList (Id, Sexp) -> Sexp -> Eff Pretty (Doc opts)
prettyLet ps (Let x rhs body) = prettyLet (ps :< (x, rhs)) body
prettyLet ps e =
orIndent
(hsep [!(hl Syntax "let*"),
!(bracks . vsep . toList =<< traverse prettyBind ps)])
!(prettySexp e)
private covering
prettyDefine : {opts : LayoutOpts} ->
String -> Either Id (List Id) -> Sexp -> Eff Pretty (Doc opts)
prettyDefine def xs body =
parens $ vappend
(hsep [!(hl Syntax $ text def),
!(either prettyId (prettySexp . L . map V) xs)])
(indent 2 !(prettySexp body))
prettySexp (V x) = prettyId x
prettySexp (L []) = hl Delim "()"
prettySexp (L (x :: xs)) = do
d <- prettySexp x
ds <- traverse prettySexp xs
parens $ ifMultiline
(hsep $ d :: ds)
(hsep [d, vsep ds] <|> vsep (d :: map (indent 2) ds))
prettySexp (Q (V x)) = hl Constant $ "'" <+> prettyId' x
prettySexp (Q x) = pure $ hcat [!(hl Constant "'"), !(prettySexp x)]
prettySexp (N n) = hl Constant $ pshow n
prettySexp (S s) = prettyStrLit $ escape s
prettySexp (Lambda xs e) = prettyLambda "lambda" xs e
prettySexp (LambdaC xs e) = prettyLambda "lambda%" xs e
prettySexp (Let x rhs e) = prettyLet [< (x, rhs)] e
prettySexp (Case h as) = do
header' <- prettySexp h
case_ <- caseD
let header = ifMultiline (case_ <++> header')
(case_ `vappend` indent 2 header')
arms <- traverse prettyCase $ toList as
pure $ ifMultiline
(parens $ header <++> hsep arms)
(parens $ vsep $ header :: map (indent 2) arms)
where
prettyCase : (List Sexp, Sexp) -> Eff Pretty (Doc opts)
prettyCase (ps, e) = bracks $
ifMultiline
(hsep [!(parens . hsep =<< traverse prettySexp ps), !(prettySexp e)])
(vsep [!(parens . sep =<< traverse prettySexp ps), !(prettySexp e)])
prettySexp (Define x e) = case e of
LambdaC xs e => prettyDefine "define%" (Right $ x :: xs) e
Lambda xs e => prettyDefine "define" (Right $ x :: xs) e
_ => prettyDefine "define" (Left x) e
prettySexp (Literal sexp) =
pure $ text sexp
export covering
makeRunMain : {opts : LayoutOpts} -> Id -> Eff Pretty (Doc opts)
makeRunMain x = prettySexp $ L ["run-main", V x]

308
lib/Quox/Untyped/Syntax.idr Normal file
View file

@ -0,0 +1,308 @@
module Quox.Untyped.Syntax
import Quox.Var
import Quox.Context
import Quox.Name
import Quox.Pretty
import Quox.Syntax.Subst
import Data.Vect
import Data.DPair
import Data.SortedMap
import Data.SnocVect
import Derive.Prelude
%hide TT.Name
%default total
%language ElabReflection
public export
data Term : Nat -> Type
public export
data CaseNatSuc : Nat -> Type
data Term where
F : (x : Name) -> Loc -> Term n
B : (i : Var n) -> Loc -> Term n
Lam : (x : BindName) -> (body : Term (S n)) -> Loc -> Term n
App : (fun, arg : Term n) -> Loc -> Term n
Pair : (fst, snd : Term n) -> Loc -> Term n
Fst : (pair : Term n) -> Loc -> Term n
Snd : (pair : Term n) -> Loc -> Term n
Tag : (tag : String) -> Loc -> Term n
CaseEnum : (tag : Term n) -> (cases : List1 (String, Term n)) -> Loc -> Term n
||| empty match
Absurd : Loc -> Term n
Nat : (val : Nat) -> Loc -> Term n
Succ : (nat : Term n) -> Loc -> Term n
CaseNat : (nat : Term n) -> (zer : Term n) -> (suc : CaseNatSuc n) ->
Loc -> Term n
Str : (str : String) -> Loc -> Term n
||| bool is true if the let comes from the original source code
Let : (real : Bool) -> (x : BindName) -> (rhs : Term n) ->
(body : Term (S n)) -> Loc -> Term n
Erased : Loc -> Term n
%name Term s, t, u
data CaseNatSuc where
NSRec : (x, ih : BindName) -> Term (2 + n) -> CaseNatSuc n
NSNonrec : (x : BindName) -> Term (S n) -> CaseNatSuc n
%name CaseNatSuc suc
%runElab deriveParam $
map (\ty => PI ty allIndices [Eq, Ord, Show]) ["Term", "CaseNatSuc"]
export
Located (Term n) where
(F _ loc).loc = loc
(B _ loc).loc = loc
(Lam _ _ loc).loc = loc
(App _ _ loc).loc = loc
(Pair _ _ loc).loc = loc
(Fst _ loc).loc = loc
(Snd _ loc).loc = loc
(Tag _ loc).loc = loc
(CaseEnum _ _ loc).loc = loc
(Absurd loc).loc = loc
(Nat _ loc).loc = loc
(Succ _ loc).loc = loc
(CaseNat _ _ _ loc).loc = loc
(Str _ loc).loc = loc
(Let _ _ _ _ loc).loc = loc
(Erased loc).loc = loc
public export
data Definition =
ErasedDef
| KeptDef Bool (Term 0)
| SchemeDef Bool String
-- bools are presence of #[main] flag
public export
0 Definitions : Type
Definitions = SortedMap Name Definition
public export
0 NDefinition : Type
NDefinition = (Name, Definition)
export covering
prettyTerm : {opts : LayoutOpts} -> BContext n ->
Term n -> Eff Pretty (Doc opts)
export covering
prettyArg : {opts : LayoutOpts} -> BContext n -> Term n -> Eff Pretty (Doc opts)
prettyArg xs arg = withPrec Arg $ prettyTerm xs arg
export covering
prettyApp_ : {opts : LayoutOpts} -> BContext n ->
Doc opts -> SnocList (Term n) -> Eff Pretty (Doc opts)
prettyApp_ xs fun args =
parensIfM App =<<
prettyAppD fun (toList !(traverse (prettyArg xs) args))
export covering %inline
prettyApp : {opts : LayoutOpts} -> BContext n ->
Term n -> SnocList (Term n) -> Eff Pretty (Doc opts)
prettyApp xs fun args =
prettyApp_ xs !(prettyArg xs fun) args
public export
record PrettyCaseArm a n where
constructor MkPrettyCaseArm
lhs : a
{len : Nat}
vars : Vect len BindName
rhs : Term (len + n)
export covering
prettyCase : {opts : LayoutOpts} -> BContext n ->
(a -> Eff Pretty (Doc opts)) ->
Term n -> List (PrettyCaseArm a n) ->
Eff Pretty (Doc opts)
prettyCase xs f head arms =
parensIfM Outer =<< do
header <- hsep <$> sequence [caseD, prettyTerm xs head, ofD]
cases <- for arms $ \(MkPrettyCaseArm lhs ys rhs) => do
lhs <- hsep <$> sequence [f lhs, darrowD]
rhs <- withPrec Outer $ prettyTerm (xs <>< ys) rhs
hangDSingle lhs rhs
lb <- hl Delim "{"; sc <- semiD; rb <- hl Delim "}"; d <- askAt INDENT
pure $ ifMultiline
(hsep [header, lb, separateTight sc cases, rb])
(vsep [hsep [header, lb], indent d $ vsep (map (<+> sc) cases), rb])
private
sucPat : {opts : LayoutOpts} -> BindName -> Eff Pretty (Doc opts)
sucPat x = pure $ !succD <++> !(prettyTBind x)
export
splitApp : Term n -> (Term n, SnocList (Term n))
splitApp (App f x _) = mapSnd (:< x) $ splitApp f
splitApp f = (f, [<])
export
splitPair : Term n -> List (Term n)
splitPair (Pair s t _) = s :: splitPair t
splitPair t = [t]
export
splitLam : Telescope' BindName a b -> Term b ->
Exists $ \c => (Telescope' BindName a c, Term c)
splitLam ys (Lam x body _) = splitLam (ys :< x) body
splitLam ys t = Evidence _ (ys, t)
export
splitLet : Telescope (\i => (BindName, Term i)) a b -> Term b ->
Exists $ \c => (Telescope (\i => (BindName, Term i)) a c, Term c)
splitLet ys (Let _ x rhs body _) = splitLet (ys :< (x, rhs)) body
splitLet ys t = Evidence _ (ys, t)
private covering
prettyLets : {opts : LayoutOpts} ->
BContext a -> Telescope (\i => (BindName, Term i)) a b ->
Eff Pretty (SnocList (Doc opts))
prettyLets xs lets = sequence $ snd $ go lets where
go : forall b. Telescope (\i => (BindName, Term i)) a b ->
(BContext b, SnocList (Eff Pretty (Doc opts)))
go [<] = (xs, [<])
go (lets :< (x, rhs)) =
let (ys, docs) = go lets
doc = do
x <- prettyTBind x
rhs <- withPrec Outer $ prettyTerm ys rhs
hangDSingle (hsep [!letD, x, !cstD]) (hsep [rhs, !inD]) in
(ys :< x, docs :< doc)
private
sucCaseArm : {opts : LayoutOpts} ->
CaseNatSuc n -> Eff Pretty (PrettyCaseArm (Doc opts) n)
sucCaseArm (NSRec x ih s) = pure $
MkPrettyCaseArm (!(sucPat x) <+> !commaD <++> !(prettyTBind ih)) [x, ih] s
sucCaseArm (NSNonrec x s) = pure $
MkPrettyCaseArm !(sucPat x) [x] s
prettyTerm _ (F x _) = prettyFree x
prettyTerm xs (B i _) = prettyTBind $ xs !!! i
prettyTerm xs (Lam x body _) =
parensIfM Outer =<< do
let Evidence n' (ys, body) = splitLam [< x] body
vars <- hsep . toList' <$> traverse prettyTBind ys
body <- withPrec Outer $ prettyTerm (xs . ys) body
hangDSingle (hsep [!lamD, vars, !darrowD]) body
prettyTerm xs (App fun arg _) = do
let (fun, args) = splitApp fun
prettyApp xs fun (args :< arg)
prettyTerm xs (Pair fst snd _) =
parens . separateTight !commaD =<<
traverse (withPrec Outer . prettyTerm xs) (fst :: splitPair snd)
prettyTerm xs (Fst pair _) = prettyApp_ xs !fstD [< pair]
prettyTerm xs (Snd pair _) = prettyApp_ xs !sndD [< pair]
prettyTerm xs (Tag tag _) = prettyTag tag
prettyTerm xs (CaseEnum tag cases _) =
prettyCase xs prettyTag tag $
map (\(t, rhs) => MkPrettyCaseArm t [] rhs) $ toList cases
prettyTerm xs (Absurd _) = hl Syntax "absurd"
prettyTerm xs (Nat n _) = hl Constant $ pshow n
prettyTerm xs (Succ nat _) = prettyApp_ xs !succD [< nat]
prettyTerm xs (CaseNat nat zer suc _) =
prettyCase xs pure nat [MkPrettyCaseArm !zeroD [] zer, !(sucCaseArm suc)]
prettyTerm xs (Str s _) =
prettyStrLit s
prettyTerm xs (Let _ x rhs body _) =
parensIfM Outer =<< do
let Evidence n' (lets, body) = splitLet [< (x, rhs)] body
heads <- prettyLets xs lets
body <- withPrec Outer $ prettyTerm (xs . map fst lets) body
let lines = toList $ heads :< body
pure $ ifMultiline (hsep lines) (vsep lines)
prettyTerm _ (Erased _) =
hl Syntax =<< ifUnicode "" "[]"
export covering
prettyDef : {opts : LayoutOpts} -> Name ->
Definition -> Eff Pretty (Doc opts)
prettyDef name ErasedDef =
pure $ hsep [!(prettyFree name), !cstD, !(prettyTerm [<] $ Erased noLoc)]
prettyDef name (KeptDef isMain rhs) = do
name <- prettyFree name {opts}
eq <- cstD
rhs <- withPrec Outer $ prettyTerm [<] rhs
let header = if isMain then text "#[main]" <++> name else name
hangDSingle (header <++> eq) rhs
prettyDef name (SchemeDef isMain str) = do
name <- prettyFree name {opts}
eq <- cstD
let rhs = text $ "scheme:" ++ str
let header = if isMain then text "#[main]" <++> name else name
hangDSingle (header <++> eq) rhs
public export
USubst : Nat -> Nat -> Type
USubst = Subst Term
public export FromVar Term where fromVarLoc = B
public export
CanSubstSelf Term where
s // th = case s of
F x loc =>
F x loc
B i loc =>
getLoc th i loc
Lam x body loc =>
Lam x (assert_total $ body // push x.loc th) loc
App fun arg loc =>
App (fun // th) (arg // th) loc
Pair fst snd loc =>
Pair (fst // th) (snd // th) loc
Fst pair loc =>
Fst (pair // th) loc
Snd pair loc =>
Snd (pair // th) loc
Tag tag loc =>
Tag tag loc
CaseEnum tag cases loc =>
CaseEnum (tag // th) (map (assert_total mapSnd (// th)) cases) loc
Absurd loc =>
Absurd loc
Nat n loc =>
Nat n loc
Succ nat loc =>
Succ (nat // th) loc
CaseNat nat zer suc loc =>
CaseNat (nat // th) (zer // th) (assert_total substSuc suc th) loc
Str s loc =>
Str s loc
Let u x rhs body loc =>
Let u x (rhs // th) (assert_total $ body // push x.loc th) loc
Erased loc =>
Erased loc
where
substSuc : forall from, to.
CaseNatSuc from -> USubst from to -> CaseNatSuc to
substSuc (NSRec x ih t) th = NSRec x ih $ t // pushN 2 x.loc th
substSuc (NSNonrec x t) th = NSNonrec x $ t // push x.loc th
public export
subN : SnocVect s (Term n) -> Term (s + n) -> Term n
subN th t = t // fromSnocVect th
public export
sub1 : Term n -> Term (S n) -> Term n
sub1 e = subN [< e]

View file

@ -2,7 +2,6 @@ module Quox.Var
import public Quox.Loc import public Quox.Loc
import public Quox.Name import public Quox.Name
import Quox.OPE
import Data.Nat import Data.Nat
import Data.List import Data.List
@ -141,9 +140,6 @@ weakIsSpec p i = toNatInj $ trans (weakCorrect p i) (sym $ weakSpecCorrect p i)
public export public export
interface FromVar f where %inline fromVarLoc : Var n -> Loc -> f n interface FromVar f where %inline fromVarLoc : Var n -> Loc -> f n
public export %inline
fromVar : FromVar f => Var n -> {default noLoc loc : Loc} -> f n
fromVar x = fromVarLoc x loc
public export FromVar Var where fromVarLoc x _ = x public export FromVar Var where fromVarLoc x _ = x
@ -293,12 +289,3 @@ decEqFromBool i j =
%transform "Var.decEq" varDecEq = decEqFromBool %transform "Var.decEq" varDecEq = decEqFromBool
public export %inline DecEq (Var n) where decEq = varDecEq public export %inline DecEq (Var n) where decEq = varDecEq
export
Tighten Var where
tighten Id i = Just i
tighten (Drop p) VZ = Nothing
tighten (Drop p) (VS i) = tighten p i
tighten (Keep p) VZ = Just VZ
tighten (Keep p) (VS i) = VS <$> tighten p i

View file

@ -14,7 +14,7 @@ coeScoped : {s : Nat} -> DScopeTerm d n -> Dim d -> Dim d -> Loc ->
coeScoped ty p q loc (S names (N body)) = coeScoped ty p q loc (S names (N body)) =
S names $ N $ E $ Coe ty p q body loc S names $ N $ E $ Coe ty p q body loc
coeScoped ty p q loc (S names (Y body)) = coeScoped ty p q loc (S names (Y body)) =
ST names $ E $ Coe (weakDS s ty) p q body loc SY names $ E $ Coe (weakDS s ty) p q body loc
where where
weakDS : (by : Nat) -> DScopeTerm d n -> DScopeTerm d (by + n) weakDS : (by : Nat) -> DScopeTerm d n -> DScopeTerm d (by + n)
weakDS by (S names (Y body)) = S names $ Y $ weakT by body weakDS by (S names (Y body)) = S names $ Y $ weakT by body
@ -23,12 +23,12 @@ where
parameters {auto _ : CanWhnf Term Interface.isRedexT} parameters {auto _ : CanWhnf Term Interface.isRedexT}
{auto _ : CanWhnf Elim Interface.isRedexE} {auto _ : CanWhnf Elim Interface.isRedexE}
{d, n : Nat} (defs : Definitions) (ctx : WhnfContext d n) (sg : SQty) (defs : Definitions) (ctx : WhnfContext d n) (sg : SQty)
||| reduce a function application `App (Coe ty p q val) s loc` ||| reduce a function application `App (Coe ty p q val) s loc`
export covering export covering
piCoe : (ty : DScopeTerm d n) -> (p, q : Dim d) -> piCoe : (ty : DScopeTerm d n) -> (p, q : Dim d) ->
(val, s : Term d n) -> Loc -> (val, s : Term d n) -> Loc ->
Eff Whnf (Subset (Elim d n) (No . isRedexE defs sg)) Eff Whnf (Subset (Elim d n) (No . isRedexE defs ctx sg))
piCoe sty@(S [< i] ty) p q val s loc = do piCoe sty@(S [< i] ty) p q val s loc = do
-- (coe [i ⇒ π.(x : A) → B] @p @q t) s ⇝ -- (coe [i ⇒ π.(x : A) → B] @p @q t) s ⇝
-- coe [i ⇒ B[𝒔i/x] @p @q ((t ∷ (π.(x : A) → B)p/i) 𝒔p) -- coe [i ⇒ B[𝒔i/x] @p @q ((t ∷ (π.(x : A) → B)p/i) 𝒔p)
@ -38,18 +38,18 @@ parameters {auto _ : CanWhnf Term Interface.isRedexT}
let ctx1 = extendDim i ctx let ctx1 = extendDim i ctx
Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty
(arg, res) <- tycasePi defs ctx1 ty (arg, res) <- tycasePi defs ctx1 ty
let s0 = CoeT i arg q p s s.loc let s0 = CoeY i arg q p s s.loc
body = E $ App (Ann val (ty // one p) val.loc) (E s0) loc body = E $ App (Ann val (ty // one p) val.loc) (E s0) loc
s1 = CoeT i (arg // (BV 0 i.loc ::: shift 2)) (weakD 1 q) (BV 0 i.loc) s1 = CoeY i (arg // (BV 0 i.loc ::: shift 2)) (weakD 1 q) (BV 0 i.loc)
(s // shift 1) s.loc (s // shift 1) s.loc
whnf defs ctx sg $ CoeT i (sub1 res s1) p q body loc whnf defs ctx sg $ CoeY i (sub1 res s1) p q body loc
||| reduce a pair elimination `CasePair pi (Coe ty p q val) ret body loc` ||| reduce a pair elimination `CasePair pi (Coe ty p q val) ret body loc`
export covering export covering
sigCoe : (qty : Qty) -> sigCoe : (qty : Qty) ->
(ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) -> (ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) ->
(ret : ScopeTerm d n) -> (body : ScopeTermN 2 d n) -> Loc -> (ret : ScopeTerm d n) -> (body : ScopeTermN 2 d n) -> Loc ->
Eff Whnf (Subset (Elim d n) (No . isRedexE defs sg)) Eff Whnf (Subset (Elim d n) (No . isRedexE defs ctx sg))
sigCoe qty sty@(S [< i] ty) p q val ret body loc = do sigCoe qty sty@(S [< i] ty) p q val ret body loc = do
-- caseπ (coe [i ⇒ (x : A) × B] @p @q s) return z ⇒ C of { (a, b) ⇒ e } -- caseπ (coe [i ⇒ (x : A) × B] @p @q s) return z ⇒ C of { (a, b) ⇒ e }
-- ⇝ -- ⇝
@ -63,18 +63,18 @@ parameters {auto _ : CanWhnf Term Interface.isRedexT}
Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty
(tfst, tsnd) <- tycaseSig defs ctx1 ty (tfst, tsnd) <- tycaseSig defs ctx1 ty
let [< x, y] = body.names let [< x, y] = body.names
a' = CoeT i (weakT 2 tfst) p q (BVT 1 noLoc) x.loc a' = CoeY i (weakT 2 tfst) p q (BVT 1 x.loc) x.loc
tsnd' = tsnd.term // tsnd' = tsnd.term //
(CoeT i (weakT 2 $ tfst // (B VZ noLoc ::: shift 2)) (CoeY i (weakT 2 $ tfst // (B VZ tsnd.loc ::: shift 2))
(weakD 1 p) (B VZ noLoc) (BVT 1 noLoc) y.loc ::: shift 2) (weakD 1 p) (B VZ i.loc) (BVT 1 tsnd.loc) y.loc ::: shift 2)
b' = CoeT i tsnd' p q (BVT 0 noLoc) y.loc b' = CoeY i tsnd' p q (BVT 0 y.loc) y.loc
whnf defs ctx sg $ CasePair qty (Ann val (ty // one p) val.loc) ret whnf defs ctx sg $ CasePair qty (Ann val (ty // one p) val.loc) ret
(ST body.names $ body.term // (a' ::: b' ::: shift 2)) loc (SY body.names $ body.term // (a' ::: b' ::: shift 2)) loc
||| reduce a pair projection `Fst (Coe ty p q val) loc` ||| reduce a pair projection `Fst (Coe ty p q val) loc`
export covering export covering
fstCoe : (ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) -> fstCoe : (ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) ->
Loc -> Eff Whnf (Subset (Elim d n) (No . isRedexE defs sg)) Loc -> Eff Whnf (Subset (Elim d n) (No . isRedexE defs ctx sg))
fstCoe sty@(S [< i] ty) p q val loc = do fstCoe sty@(S [< i] ty) p q val loc = do
-- fst (coe (𝑖 ⇒ (x : A) × B) @p @q s) -- fst (coe (𝑖 ⇒ (x : A) × B) @p @q s)
-- ⇝ -- ⇝
@ -85,13 +85,13 @@ parameters {auto _ : CanWhnf Term Interface.isRedexT}
Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty
(tfst, _) <- tycaseSig defs ctx1 ty (tfst, _) <- tycaseSig defs ctx1 ty
whnf defs ctx sg $ whnf defs ctx sg $
Coe (ST [< i] tfst) p q Coe (SY [< i] tfst) p q
(E (Fst (Ann val (ty // one p) val.loc) val.loc)) loc (E (Fst (Ann val (ty // one p) val.loc) val.loc)) loc
||| reduce a pair projection `Snd (Coe ty p q val) loc` ||| reduce a pair projection `Snd (Coe ty p q val) loc`
export covering export covering
sndCoe : (ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) -> sndCoe : (ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) ->
Loc -> Eff Whnf (Subset (Elim d n) (No . isRedexE defs sg)) Loc -> Eff Whnf (Subset (Elim d n) (No . isRedexE defs ctx sg))
sndCoe sty@(S [< i] ty) p q val loc = do sndCoe sty@(S [< i] ty) p q val loc = do
-- snd (coe (𝑖 ⇒ (x : A) × B) @p @q s) -- snd (coe (𝑖 ⇒ (x : A) × B) @p @q s)
-- ⇝ -- ⇝
@ -103,8 +103,8 @@ parameters {auto _ : CanWhnf Term Interface.isRedexT}
Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty
(tfst, tsnd) <- tycaseSig defs ctx1 ty (tfst, tsnd) <- tycaseSig defs ctx1 ty
whnf defs ctx sg $ whnf defs ctx sg $
Coe (ST [< i] $ sub1 tsnd $ Coe (SY [< i] $ sub1 tsnd $
Coe (ST [< !(fresh i)] $ tfst // (BV 0 i.loc ::: shift 2)) Coe (SY [< !(fresh i)] $ tfst // (BV 0 i.loc ::: shift 2))
(weakD 1 p) (BV 0 loc) (weakD 1 p) (BV 0 loc)
(E (Fst (Ann (dweakT 1 val) ty val.loc) val.loc)) loc) (E (Fst (Ann (dweakT 1 val) ty val.loc) val.loc)) loc)
p q p q
@ -115,11 +115,11 @@ parameters {auto _ : CanWhnf Term Interface.isRedexT}
export covering export covering
eqCoe : (ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) -> eqCoe : (ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) ->
(r : Dim d) -> Loc -> (r : Dim d) -> Loc ->
Eff Whnf (Subset (Elim d n) (No . isRedexE defs sg)) Eff Whnf (Subset (Elim d n) (No . isRedexE defs ctx sg))
eqCoe sty@(S [< j] ty) p q val r loc = do eqCoe sty@(S [< j] ty) p q val r loc = do
-- (coe [j ⇒ Eq [i ⇒ A] L R] @p @q eq) @r -- (coe [j ⇒ Eq [i ⇒ A] L R] @p @q eq) @r
-- ⇝ -- ⇝
-- comp [j ⇒ Ar/i] @p @q (eq ∷ (Eq [i ⇒ A] L R)p/j) -- comp [j ⇒ Ar/i] @p @q ((eq ∷ (Eq [i ⇒ A] L R)p/j) @r)
-- @r { 0 j ⇒ L; 1 j ⇒ R } -- @r { 0 j ⇒ L; 1 j ⇒ R }
let ctx1 = extendDim j ctx let ctx1 = extendDim j ctx
Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty
@ -133,7 +133,7 @@ parameters {auto _ : CanWhnf Term Interface.isRedexT}
boxCoe : (qty : Qty) -> boxCoe : (qty : Qty) ->
(ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) -> (ty : DScopeTerm d n) -> (p, q : Dim d) -> (val : Term d n) ->
(ret : ScopeTerm d n) -> (body : ScopeTerm d n) -> Loc -> (ret : ScopeTerm d n) -> (body : ScopeTerm d n) -> Loc ->
Eff Whnf (Subset (Elim d n) (No . isRedexE defs sg)) Eff Whnf (Subset (Elim d n) (No . isRedexE defs ctx sg))
boxCoe qty sty@(S [< i] ty) p q val ret body loc = do boxCoe qty sty@(S [< i] ty) p q val ret body loc = do
-- caseπ (coe [i ⇒ [ρ. A]] @p @q s) return z ⇒ C of { [a] ⇒ e } -- caseπ (coe [i ⇒ [ρ. A]] @p @q s) return z ⇒ C of { [a] ⇒ e }
-- ⇝ -- ⇝
@ -141,34 +141,48 @@ parameters {auto _ : CanWhnf Term Interface.isRedexT}
let ctx1 = extendDim i ctx let ctx1 = extendDim i ctx
Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty Element ty tynf <- whnf defs ctx1 SZero $ getTerm ty
ta <- tycaseBOX defs ctx1 ty ta <- tycaseBOX defs ctx1 ty
let a' = CoeT i (weakT 1 ta) p q (BVT 0 noLoc) body.name.loc let xloc = body.name.loc
let a' = CoeY i (weakT 1 ta) p q (BVT 0 xloc) xloc
whnf defs ctx sg $ CaseBox qty (Ann val (ty // one p) val.loc) ret whnf defs ctx sg $ CaseBox qty (Ann val (ty // one p) val.loc) ret
(ST body.names $ body.term // (a' ::: shift 1)) loc (SY body.names $ body.term // (a' ::: shift 1)) loc
-- new params block to call the above functions at different `n`
parameters {auto _ : CanWhnf Term Interface.isRedexT}
{auto _ : CanWhnf Elim Interface.isRedexE}
(defs : Definitions) (ctx : WhnfContext d n) (sg : SQty)
||| pushes a coercion inside a whnf-ed term ||| pushes a coercion inside a whnf-ed term
export covering export covering
pushCoe : BindName -> pushCoe : BindName ->
(ty : Term (S d) n) -> (p, q : Dim d) -> (s : Term d n) -> Loc -> (ty : Term (S d) n) -> (p, q : Dim d) -> (s : Term d n) -> Loc ->
(0 pc : So (canPushCoe sg ty s)) => (0 pc : So (canPushCoe sg ty s)) =>
Eff Whnf (NonRedex Elim d n defs sg) Eff Whnf (NonRedex Elim d n defs ctx sg)
pushCoe i ty p q s loc = pushCoe i ty p q s loc =
case ty of case ty of
-- (coe ★ᵢ @_ @_ s) ⇝ (s ∷ ★ᵢ) -- (coe ★ᵢ @_ @_ s) ⇝ (s ∷ ★ᵢ)
TYPE l tyLoc => TYPE l tyLoc =>
whnf defs ctx sg $ Ann s (TYPE l tyLoc) loc whnf defs ctx sg $ Ann s (TYPE l tyLoc) loc
-- η expand it so that whnf for App can deal with it -- (coe IOState @_ @_ s) ⇝ (s ∷ IOState)
IOState tyLoc =>
whnf defs ctx sg $ Ann s (IOState tyLoc) loc
-- η expand, then simplify the Coe/App in the body
-- --
-- (coe (𝑖 ⇒ π.(x : A) → B) @p @q s) -- (coe (𝑖 ⇒ π.(x : A) → B) @p @q s)
-- ⇝ -- ⇝
-- (λ y ⇒ (coe (𝑖 ⇒ π.(x : A) → B) @p @q s) y) ∷ (π.(x : A) → B)q/𝑖 -- (λ y ⇒ (coe (𝑖 ⇒ π.(x : A) → B) @p @q s) y) ∷ (π.(x : A) → B)q/𝑖
Pi {} => -- ⇝ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
let inner = Coe (SY [< i] ty) p q s loc in -- (λ y ⇒ ⋯) ∷ (π.(x : A) → B)q/𝑖 -- see `piCoe`
--
-- do the piCoe step here because otherwise equality checking keeps
-- doing the η forever
Pi {arg, res = S [< x] _, _} => do
let ctx' = extendTy x (arg // one p) ctx
body <- piCoe defs ctx' sg
(weakDS 1 $ SY [< i] ty) p q (weakT 1 s) (BVT 0 loc) loc
whnf defs ctx sg $ whnf defs ctx sg $
Ann (LamY !(mnb "y" loc) Ann (LamY x (E body.fst) loc) (ty // one q) loc
(E $ App (weakE 1 inner) (BVT 0 loc) loc) loc)
(ty // one q) loc
-- no η!!! -- no η!!!
-- push into a pair constructor, otherwise still stuck -- push into a pair constructor, otherwise still stuck
@ -181,12 +195,12 @@ parameters {auto _ : CanWhnf Term Interface.isRedexT}
-- ∷ ((x : A) × B)q/𝑖 -- ∷ ((x : A) × B)q/𝑖
Sig tfst tsnd tyLoc => do Sig tfst tsnd tyLoc => do
let Pair fst snd sLoc = s let Pair fst snd sLoc = s
fst' = CoeT i tfst p q fst fst.loc fst' = CoeY i tfst p q fst fst.loc
fstInSnd = fstInSnd =
CoeT !(fresh i) CoeY !(fresh i)
(tfst // (BV 0 loc ::: shift 2)) (tfst // (BV 0 loc ::: shift 2))
(weakD 1 p) (BV 0 loc) (dweakT 1 s) fst.loc (weakD 1 p) (BV 0 loc) (dweakT 1 fst) fst.loc
snd' = CoeT i (sub1 tsnd fstInSnd) p q snd snd.loc snd' = CoeY i (sub1 tsnd fstInSnd) p q snd snd.loc
whnf defs ctx sg $ whnf defs ctx sg $
Ann (Pair (E fst') (E snd') sLoc) (ty // one q) loc Ann (Pair (E fst') (E snd') sLoc) (ty // one q) loc
@ -194,35 +208,45 @@ parameters {auto _ : CanWhnf Term Interface.isRedexT}
Enum cases tyLoc => Enum cases tyLoc =>
whnf defs ctx sg $ Ann s (Enum cases tyLoc) loc whnf defs ctx sg $ Ann s (Enum cases tyLoc) loc
-- η expand, same as for Π -- η expand/simplify, same as for Π
-- --
-- (coe (𝑖 ⇒ Eq (𝑗 ⇒ A) l r) @p @q s) -- (coe (𝑖 ⇒ Eq (𝑗 ⇒ A) l r) @p @q s)
-- ⇝ -- ⇝
-- (δ 𝑘 ⇒ (coe (𝑖 ⇒ Eq (𝑗 ⇒ A) l r) @p @q s) @𝑘) ∷ (Eq (𝑗 ⇒ A) l r)q/𝑖 -- (δ 𝑘 ⇒ (coe (𝑖 ⇒ Eq (𝑗 ⇒ A) l r) @p @q s) @𝑘) ∷ (Eq (𝑗 ⇒ A) l r)q/𝑖
Eq {} => -- ⇝ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
let inner = Coe (SY [< i] ty) p q s loc in -- (δ 𝑘 ⇒ ⋯) ∷ (Eq (𝑗 ⇒ A) l r)q/𝑖 -- see `eqCoe`
--
-- do the eqCoe step here because otherwise equality checking keeps
-- doing the η forever
Eq {ty = S [< j] _, _} => do
let ctx' = extendDim j ctx
body <- eqCoe defs ctx' sg
(dweakDS 1 $ S [< i] $ Y ty) (weakD 1 p) (weakD 1 q)
(dweakT 1 s) (BV 0 loc) loc
whnf defs ctx sg $ whnf defs ctx sg $
Ann (DLamY !(mnb "k" loc) Ann (DLamY i (E body.fst) loc) (ty // one q) loc
(E $ DApp (dweakE 1 inner) (BV 0 loc) loc) loc)
(ty // one q) loc
-- (coe @_ @_ s) ⇝ (s ∷ ) -- (coe @_ @_ s) ⇝ (s ∷ )
Nat tyLoc => NAT tyLoc =>
whnf defs ctx sg $ Ann s (Nat tyLoc) loc whnf defs ctx sg $ Ann s (NAT tyLoc) loc
-- η expand -- (coe String @_ @_ s) ⇝ (s ∷ String)
STRING tyLoc =>
whnf defs ctx sg $ Ann s (STRING tyLoc) loc
-- η expand/simplify
-- --
-- (coe (𝑖 ⇒ [π. A]) @p @q s) -- (coe (𝑖 ⇒ [π.A]) @p @q s)
-- ⇝ -- ⇝
-- [case1 coe (𝑖 ⇒ [π. A]) @p @q s return Aq/𝑖 of {[x] ⇒ x}] -- [case coe (𝑖 ⇒ [π.A]) @p @q s return Aq/𝑖 of {[x] ⇒ x}]
-- ∷ [π. A]q/𝑖 --
BOX qty inner tyLoc => -- [case1 s ∷ [π.A]p/𝑖 ⋯] ∷ [π.A]q/𝑖 -- see `boxCoe`
let inner = CaseBox { --
qty = One, -- do the eqCoe step here because otherwise equality checking keeps
box = Coe (SY [< i] ty) p q s loc, -- doing the η forever
ret = SN $ ty // one q, BOX qty inner tyLoc => do
body = SY [< !(mnb "x" loc)] $ BVT 0 loc, body <- boxCoe defs ctx sg qty
loc (SY [< i] ty) p q s
} (SN $ inner // one q)
in (SY [< !(mnb "inner" loc)] (BVT 0 loc)) loc
whnf defs ctx sg $ Ann (Box (E inner) loc) (ty // one q) loc whnf defs ctx sg $ Ann (Box (E body.fst) loc) (ty // one q) loc

View file

@ -2,6 +2,7 @@ module Quox.Whnf.ComputeElimType
import Quox.Whnf.Interface import Quox.Whnf.Interface
import Quox.Displace import Quox.Displace
import Quox.Pretty
%default total %default total
@ -11,35 +12,43 @@ import Quox.Displace
||| - assumes the elim is already typechecked ||| - assumes the elim is already typechecked
||| - the return value is not reduced ||| - the return value is not reduced
export covering export covering
computeElimType : CanWhnf Term Interface.isRedexT => computeElimType :
CanWhnf Elim Interface.isRedexE => CanWhnf Term Interface.isRedexT =>
{d, n : Nat} -> CanWhnf Elim Interface.isRedexE =>
(defs : Definitions) -> WhnfContext d n -> (pi : SQty) -> (defs : Definitions) -> (ctx : WhnfContext d n) -> (0 sg : SQty) ->
(e : Elim d n) -> (0 ne : No (isRedexE defs pi e)) => (e : Elim d n) -> (0 ne : No (isRedexE defs ctx sg e)) =>
Eff Whnf (Term d n) Eff Whnf (Term d n)
||| computes a type and then reduces it to whnf ||| computes a type and then reduces it to whnf
export covering export covering
computeWhnfElimType0 : CanWhnf Term Interface.isRedexT => computeWhnfElimType0 :
CanWhnf Elim Interface.isRedexE => CanWhnf Term Interface.isRedexT =>
{d, n : Nat} -> CanWhnf Elim Interface.isRedexE =>
(defs : Definitions) -> WhnfContext d n -> (pi : SQty) -> (defs : Definitions) -> (ctx : WhnfContext d n) -> (0 sg : SQty) ->
(e : Elim d n) -> (0 ne : No (isRedexE defs pi e)) => (e : Elim d n) -> (0 ne : No (isRedexE defs ctx sg e)) =>
Eff Whnf (Term d n) Eff Whnf (Term d n)
computeElimType defs ctx pi e {ne} =
private covering
computeElimTypeNoLog, computeWhnfElimType0NoLog :
CanWhnf Term Interface.isRedexT =>
CanWhnf Elim Interface.isRedexE =>
(defs : Definitions) -> WhnfContext d n -> (0 sg : SQty) ->
(e : Elim d n) -> (0 ne : No (isRedexE defs ctx sg e)) =>
Eff Whnf (Term d n)
computeElimTypeNoLog defs ctx sg e =
case e of case e of
F x u loc => do F x u loc => do
let Just def = lookup x defs let Just def = lookup x defs
| Nothing => throw $ NotInScope loc x | Nothing => throw $ NotInScope loc x
pure $ def.typeAt u pure $ def.typeWithAt ctx.dimLen ctx.termLen u
B i _ => B i _ =>
pure $ ctx.tctx !! i pure (ctx.tctx !! i).type
App f s loc => App f s loc =>
case !(computeWhnfElimType0 defs ctx pi f {ne = noOr1 ne}) of case !(computeWhnfElimType0NoLog defs ctx sg f {ne = noOr1 ne}) of
Pi {arg, res, _} => pure $ sub1 res $ Ann s arg loc Pi {arg, res, _} => pure $ sub1 res $ Ann s arg loc
ty => throw $ ExpectedPi loc ctx.names ty ty => throw $ ExpectedPi loc ctx.names ty
@ -47,12 +56,12 @@ computeElimType defs ctx pi e {ne} =
pure $ sub1 ret pair pure $ sub1 ret pair
Fst pair loc => Fst pair loc =>
case !(computeWhnfElimType0 defs ctx pi pair {ne = noOr1 ne}) of case !(computeWhnfElimType0NoLog defs ctx sg pair {ne = noOr1 ne}) of
Sig {fst, _} => pure fst Sig {fst, _} => pure fst
ty => throw $ ExpectedSig loc ctx.names ty ty => throw $ ExpectedSig loc ctx.names ty
Snd pair loc => Snd pair loc =>
case !(computeWhnfElimType0 defs ctx pi pair {ne = noOr1 ne}) of case !(computeWhnfElimType0NoLog defs ctx sg pair {ne = noOr1 ne}) of
Sig {snd, _} => pure $ sub1 snd $ Fst pair loc Sig {snd, _} => pure $ sub1 snd $ Fst pair loc
ty => throw $ ExpectedSig loc ctx.names ty ty => throw $ ExpectedSig loc ctx.names ty
@ -66,7 +75,7 @@ computeElimType defs ctx pi e {ne} =
pure $ sub1 ret box pure $ sub1 ret box
DApp {fun = f, arg = p, loc} => DApp {fun = f, arg = p, loc} =>
case !(computeWhnfElimType0 defs ctx pi f {ne = noOr1 ne}) of case !(computeWhnfElimType0NoLog defs ctx sg f {ne = noOr1 ne}) of
Eq {ty, _} => pure $ dsub1 ty p Eq {ty, _} => pure $ dsub1 ty p
t => throw $ ExpectedEq loc ctx.names t t => throw $ ExpectedEq loc ctx.names t
@ -82,5 +91,20 @@ computeElimType defs ctx pi e {ne} =
TypeCase {ret, _} => TypeCase {ret, _} =>
pure ret pure ret
computeWhnfElimType0 defs ctx pi e = computeElimType defs ctx sg e {ne} = do
computeElimType defs ctx pi e >>= whnf0 defs ctx pi let Val n = ctx.termLen
sayMany "whnf" e.loc
[90 :> "computeElimType",
95 :> hsep ["ctx =", runPretty $ prettyWhnfContext ctx],
90 :> hsep ["e =", runPretty $ prettyElim ctx.dnames ctx.tnames e]]
res <- computeElimTypeNoLog defs ctx sg e {ne}
say "whnf" 91 e.loc $
hsep ["computeElimType ⇝",
runPretty $ prettyTerm ctx.dnames ctx.tnames res]
pure res
computeWhnfElimType0 defs ctx sg e =
computeElimType defs ctx sg e >>= whnf0 defs ctx SZero
computeWhnfElimType0NoLog defs ctx sg e {ne} =
computeElimTypeNoLog defs ctx sg e {ne} >>= whnf0 defs ctx SZero

Some files were not shown because too many files have changed in this diff Show more